国家级示范校建设网站,58同城企业网站怎么做的,上海 网站平台开发,创建网站需要哪些工作实验目的
由于LS2K0300久久派开发板4.19内核还没有现成可用的ADC驱动#xff0c;但是龙芯官方的5.10内核已经提供了ADC驱动#xff0c;想要在4.19内核使用ADC就要参考5.10内核移植驱动#xff0c;本次实验主要是关于ADC驱动的移植和使用
驱动移植
主要的驱动代码主要有3个…实验目的
由于LS2K0300久久派开发板4.19内核还没有现成可用的ADC驱动但是龙芯官方的5.10内核已经提供了ADC驱动想要在4.19内核使用ADC就要参考5.10内核移植驱动本次实验主要是关于ADC驱动的移植和使用
驱动移植
主要的驱动代码主要有3个loongson-2k300-adc.c、loongson-2k300-adc-core.c、loongson-2k300-adc-core.h位于drivers/iio/adc目录下
loongson-2k300-adc.c
这个是platform_driver代码部分
#include linux/module.h
#include linux/of.h
#include linux/platform_device.h
#include linux/io.h
#include linux/iio/iio.h
#include linux/iio/sysfs.h
#include linux/delay.h
#include loongson-2k300-adc-core.h#define ADC_DATA_MASK 0x0FFF#define ADC_MAX_VOLTAGE 1800
#define ADC_SCALE 4096struct ls2k300_adc_data {void __iomem *base;spinlock_t read_raw_lock; // 添加读取的自旋锁 扫描模式单次读取时使用
};// 这里是有节点可以读取的关键
#define LS2K300_CHANNEL(num) { \.type IIO_VOLTAGE, \.indexed 1, \.channel num, \.address ADC_DR, \.info_mask_separate BIT(IIO_CHAN_INFO_RAW), \.info_mask_shared_by_type BIT(IIO_CHAN_INFO_SCALE), \.scan_index num, \.scan_type { \.sign s, \.realbits 12, \.storagebits 16, \.shift 12, \.endianness IIO_CPU, \}, \
}static const struct iio_chan_spec ls2k300_adc_channels[] {IIO_CHAN_SOFT_TIMESTAMP(8),LS2K300_CHANNEL(0),LS2K300_CHANNEL(1),LS2K300_CHANNEL(2),LS2K300_CHANNEL(3),LS2K300_CHANNEL(4),LS2K300_CHANNEL(5),LS2K300_CHANNEL(6),LS2K300_CHANNEL(7),// 注入通道// { .type IIO_VOLTAGE, .differential 1, .channel 0, .address ADC_JDR1 },// { .type IIO_VOLTAGE, .differential 1, .channel 1, .address ADC_JDR2 },// { .type IIO_VOLTAGE, .differential 1, .channel 2, .address ADC_JDR3 },// { .type IIO_VOLTAGE, .differential 1, .channel 3, .address ADC_JDR4 },
};// sysfs 下的节点读取时的具体调用函数
static int ls2k300_adc_read_raw(struct iio_dev *indio_dev,struct iio_chan_spec const *chan,int *val, int *val2, long mask)
{struct ls2k300_adc_data *data iio_priv(indio_dev);unsigned int reg_offset;unsigned long flags;switch (mask) {case IIO_CHAN_INFO_RAW:// 针对 in_voltagex_raw 节点if (chan-differential) {reg_offset chan-address;} else {reg_offset chan-address;}// 由于规则通道组只有一个通道所以这里需要用锁来限定一段时间只能读取一个通道的值。spin_lock_irqsave(data-read_raw_lock, flags);ADC_RegularChannelConfig(data-base, chan-channel, 1, ADC_SampleTime_64Cycles);adc_software_start_conv_trigger(data-base, ENABLE, 0);adc_eoc_check_conv_end(data-base);*val ioread16(data-base reg_offset) ADC_DATA_MASK;spin_unlock_irqrestore(data-read_raw_lock, flags);return IIO_VAL_INT;case IIO_CHAN_INFO_SCALE:// 针对 in_voltagex_scale 节点*val ADC_MAX_VOLTAGE;*val2 ADC_SCALE;// 返回的值就是 val1 / val2 的那个小数值// scale * raw 就是对应的电压值单位mVreturn IIO_VAL_FRACTIONAL;default:return -EINVAL;}
}static const struct iio_info ls2k300_adc_info {.read_raw ls2k300_adc_read_raw,
};static int ls2k300_adc_probe(struct platform_device *pdev)
{adc_init_info adc_init_struct;struct iio_dev *indio_dev;struct ls2k300_adc_data *data;struct resource *res;int ret;indio_dev devm_iio_device_alloc(pdev-dev, sizeof(*data));if (!indio_dev) {dev_err(pdev-dev, devm_iio_device_alloc failed! probe failed!\n);return -ENOMEM;}data iio_priv(indio_dev);res platform_get_resource(pdev, IORESOURCE_MEM, 0);data-base devm_ioremap_resource(pdev-dev, res);if (IS_ERR(data-base)) {dev_err(pdev-dev, devm_ioremap_resource failed! probe failed! (base: %.llx)\n, (unsigned long long)data-base);return PTR_ERR(data-base);}// 配置 ADC CR1 和 CR2 等寄存器具体配置根据需要调整// 不使用 DMA, 扫描模式, 单次规则序列转化数为1, 也就是每次都等待读取完毕。// EOC中断和JEOC中断没开adc_struct_init(adc_init_struct);adc_init_struct.ADC_Mode ADC_Mode_Independent;adc_init_struct.ADC_ScanConvMode ENABLE;adc_init_struct.ADC_ContinuousConvMode DISABLE;adc_init_struct.ADC_ExternalTrigConv ADC_ExternalTrigConv_None;adc_init_struct.ADC_DataAlign ADC_DataAlign_Right;adc_init_struct.ADC_NbrOfChannel 1; //规则通道数量 为 1这是一个一个的触发 扫描模式的单次扫描adc_init_struct.ADC_ClkDivider 1; //Loongson Featureadc_init_struct.ADC_JTrigMod 0; //Loongson Featureadc_init_struct.ADC_ADCEdge 0; //Loongson Featureadc_init_struct.ADC_DiffMod 0; //Loongson Featureadc_init(data-base, adc_init_struct);adc_dev_enable(data-base, ENABLE);// iio 框架信息注册indio_dev-dev.parent pdev-dev;indio_dev-info ls2k300_adc_info;indio_dev-name pdev-name;indio_dev-modes INDIO_DIRECT_MODE;indio_dev-channels ls2k300_adc_channels;indio_dev-num_channels ARRAY_SIZE(ls2k300_adc_channels);spin_lock_init(data-read_raw_lock); // 初始化自旋锁ret iio_device_register(indio_dev);if (ret) {dev_err(pdev-dev, iio_device_register failed! probe failed! (ret: %d)\n, ret);return ret;}platform_set_drvdata(pdev, indio_dev);dev_info(pdev-dev, ADC Device registered successfully\n);return 0;
}static int ls2k300_adc_remove(struct platform_device *pdev)
{struct iio_dev *indio_dev platform_get_drvdata(pdev);iio_device_unregister(indio_dev);return 0;
}static const struct of_device_id ls2k300_adc_of_match[] {{ .compatible ls2k300-adc, },{ }
};
MODULE_DEVICE_TABLE(of, ls2k300_adc_of_match);static struct platform_driver ls2k300_adc_driver {.driver {.name ls2k300_adc,.of_match_table ls2k300_adc_of_match,},.probe ls2k300_adc_probe,.remove ls2k300_adc_remove,
};
module_platform_driver(ls2k300_adc_driver);MODULE_AUTHOR(oujintao qujintaoloongson.cn);
MODULE_DESCRIPTION(2k300 ADC IIO driver);
MODULE_LICENSE(GPL);loongson-2k300-adc-core.c
这个是关于ADC的操作部分驱动代码主要是读写寄存器
#include linux/module.h
#include linux/delay.h
#include loongson-2k300-adc-core.h#define ADC_DATA_MASK 0x0FFF/*******************************************************************************
* Function Name : adc_init
* Description : Initializes the ADCx peripheral according to the specified parameters
* in the ADC_InitStruct.
* Input : - ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
* - ADC_InitStruct: pointer to an adc_init_info structure that
* contains the configuration information for the specified
* ADC peripheral.
* Output : None
* Return : None
******************************************************************************/
void adc_init(adc_reg_map* ADCx, adc_init_info* ADC_InitStruct)
{unsigned int temp_val_1 0;unsigned int temp_val_2 0;/*---------------------------- ADCx CR1 Configuration -----------------*//* Get the ADCx CR1 value */temp_val_1 ADCx-CR1;/* Clear DUALMOD and SCAN bits */temp_val_1 CR1_CLEAR_MASK;/* Configure ADCx: Dual mode and scan conversion mode *//* Set DUALMOD bits according to ADC_Mode value *//* Set SCAN bit according to ADC_ScanConvMode value */temp_val_1 | (unsigned int)(ADC_InitStruct-ADC_Mode | ((unsigned int)ADC_InitStruct-ADC_ScanConvMode 8) |((unsigned int)((ADC_InitStruct-ADC_ClkDivider)0x3f) 24) |((unsigned int)ADC_InitStruct-ADC_DiffMod 20) |((unsigned int)ADC_InitStruct-ADC_OutPhaseSel 30)); //ygtemp_val_1 | 1 CR1_EOC_IE_OFFSET;temp_val_1 ^ 1 CR1_EOC_IE_OFFSET;temp_val_1 | ADC_InitStruct-ADC_Int_EOC CR1_EOC_IE_OFFSET;temp_val_1 | 1 CR1_J_EOC_IE_OFFSET;temp_val_1 ^ 1 CR1_J_EOC_IE_OFFSET;temp_val_1 | ADC_InitStruct-ADC_Int_JEOC CR1_J_EOC_IE_OFFSET;/* Write to ADCx CR1 */ADCx-CR1 temp_val_1;/*---------------------------- ADCx CR2 Configuration -----------------*//* Get the ADCx CR2 value */temp_val_1 ADCx-CR2;/* Clear CONT, ALIGN and EXTSEL bits */temp_val_1 CR2_CLEAR_MASK;/* Configure ADCx: external trigger event and continuous conversion mode *//* Set ALIGN bit according to ADC_DataAlign value *//* Set EXTSEL bits according to ADC_ExternalTrigConv value *//* Set CONT bit according to ADC_ContinuousConvMode value */temp_val_1 | (unsigned int)(ADC_InitStruct-ADC_DataAlign | ADC_InitStruct-ADC_ExternalTrigConv |((unsigned int)ADC_InitStruct-ADC_ContinuousConvMode 1) |((unsigned int)ADC_InitStruct-ADC_JTrigMod 24) | //yg((unsigned int)(((ADC_InitStruct-ADC_ClkDivider)6)0xf) 26) |((unsigned int)ADC_InitStruct-ADC_ADCEdge 30) |((unsigned int)ADC_InitStruct-ADC_ClkMask 31)) ; //yg/* Write to ADCx CR2 */ADCx-CR2 temp_val_1;/*---------------------------- ADCx SQR1 Configuration -----------------*//* Get the ADCx SQR1 value */temp_val_1 ADCx-SQR1;/* Clear L bits */temp_val_1 SQR1_CLEAR_MASK;/* Configure ADCx: regular channel sequence length *//* Set L bits according to ADC_NbrOfChannel value */temp_val_2 | (ADC_InitStruct-ADC_NbrOfChannel - 1);temp_val_1 | ((unsigned int)temp_val_2 20);/* Write to ADCx SQR1 */ADCx-SQR1 temp_val_1;
}/*******************************************************************************
* Function Name : adc_struct_init
* Description : Fills each ADC_InitStruct member with its default value.
* Input : ADC_InitStruct : pointer to an adc_init_info structure
* which will be initialized.
* Output : None
* Return : None
*******************************************************************************/
void adc_struct_init(adc_init_info* ADC_InitStruct)
{/* Reset ADC init structure parameters values *//* Initialize the ADC_Mode member */ADC_InitStruct-ADC_Mode ADC_Mode_Independent;/* initialize the ADC_ScanConvMode member */ADC_InitStruct-ADC_ScanConvMode DISABLE;/* Initialize the ADC_ContinuousConvMode member */ADC_InitStruct-ADC_ContinuousConvMode DISABLE;/* Initialize the ADC_ExternalTrigConv member */ADC_InitStruct-ADC_ExternalTrigConv ADC_ExternalTrigConv_T1_CC1;/* Initialize the ADC_DataAlign member */ADC_InitStruct-ADC_DataAlign ADC_DataAlign_Right;/* Initialize the ADC_NbrOfChannel member */ADC_InitStruct-ADC_NbrOfChannel 1;/* Initialize the ADC_ClkDivider member */ADC_InitStruct-ADC_ClkDivider 0xff;/* Initialize the ADC_JTrigMod member */ADC_InitStruct-ADC_JTrigMod 0;/* Initialize the ADC_ADCEdge member */ADC_InitStruct-ADC_ADCEdge 0;/* Initialize the ADC_DIFFMOD member */ADC_InitStruct-ADC_DiffMod 0;/* Initialize the ADC_OutPhaseSel member */ADC_InitStruct-ADC_OutPhaseSel 0;/* Initialize the ADC_ClkMask member */ADC_InitStruct-ADC_ClkMask 0;/* Initialize CR1 EOC disable */ADC_InitStruct-ADC_Int_EOC DISABLE;/* Initialize CR1 EOC disable */ADC_InitStruct-ADC_Int_JEOC DISABLE;
}void ADC_RegularChannelConfig(adc_reg_map* ADCx, unsigned char ADC_Channel, unsigned char Rank, unsigned char ADC_SampleTime)
{unsigned int temp_val_1 0, temp_val_2 0;/* if ADC_Channel_10 ... ADC_Channel_17 is selected */if (ADC_Channel ADC_Channel_9) {/* Get the old register value */temp_val_1 ADCx-SMPR1;/* Calculate the mask to clear */temp_val_2 SMPR1_SMP_MASK (3 * (ADC_Channel - 10));/* Clear the old discontinuous mode channel count */temp_val_1 ~temp_val_2;/* Calculate the mask to set */temp_val_2 (unsigned int)ADC_SampleTime (3 * (ADC_Channel - 10));/* Set the discontinuous mode channel count */temp_val_1 | temp_val_2;/* Store the new register value */ADCx-SMPR1 temp_val_1;} else { /* ADC_Channel include in ADC_Channel_[0..9] *//* Get the old register value */temp_val_1 ADCx-SMPR2;/* Calculate the mask to clear */temp_val_2 SMPR2_SMP_MASK (3 * ADC_Channel);/* Clear the old discontinuous mode channel count */temp_val_1 ~temp_val_2;/* Calculate the mask to set */temp_val_2 (unsigned int)ADC_SampleTime (3 * ADC_Channel);/* Set the discontinuous mode channel count */temp_val_1 | temp_val_2;/* Store the new register value */ADCx-SMPR2 temp_val_1;}/* For Rank 1 to 6 */if (Rank 7) {/* Get the old register value */temp_val_1 ADCx-SQR3;/* Calculate the mask to clear */temp_val_2 SQR3_SQ_MASK (5 * (Rank - 1));/* Clear the old SQx bits for the selected rank */temp_val_1 ~temp_val_2;/* Calculate the mask to set */temp_val_2 (unsigned int)ADC_Channel (5 * (Rank - 1));/* Set the SQx bits for the selected rank */temp_val_1 | temp_val_2;/* Store the new register value */ADCx-SQR3 temp_val_1;} else if (Rank 13) { /* For Rank 7 to 12 *//* Get the old register value */temp_val_1 ADCx-SQR2;/* Calculate the mask to clear */temp_val_2 SQR2_SQ_MASK (5 * (Rank - 7));/* Clear the old SQx bits for the selected rank */temp_val_1 ~temp_val_2;/* Calculate the mask to set */temp_val_2 (unsigned int)ADC_Channel (5 * (Rank - 7));/* Set the SQx bits for the selected rank */temp_val_1 | temp_val_2;/* Store the new register value */ADCx-SQR2 temp_val_1;} else { /* For Rank 13 to 16 *//* Get the old register value */temp_val_1 ADCx-SQR1;/* Calculate the mask to clear */temp_val_2 SQR1_SQ_MASK (5 * (Rank - 13));/* Clear the old SQx bits for the selected rank */temp_val_1 ~temp_val_2;/* Calculate the mask to set */temp_val_2 (unsigned int)ADC_Channel (5 * (Rank - 13));/* Set the SQx bits for the selected rank */temp_val_1 | temp_val_2;/* Store the new register value */ADCx-SQR1 temp_val_1;}
}/*******************************************************************************
* Function Name : adc_dev_enable
* Description : Enables or disables the specified ADC peripheral.
* Input : - ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
* - state: new state of the ADCx peripheral. This parameter
* can be: ENABLE or DISABLE.
* Output : None
* Return : None
*******************************************************************************/
void adc_dev_enable(adc_reg_map* ADCx, FunctionalState state)
{unsigned int temp;if (state ENABLE) {temp ADCx-CR2;temp | 1 CR2_ADON_OFFSET;temp ^ 1 CR2_ADON_OFFSET;temp | (state CR2_ADON_OFFSET);ADCx-CR2 temp;// 触发复位校准和AD校准ADCx-CR2 temp;temp ADCx-CR2;temp | (state 2) | (state 3);ADCx-CR2 temp;
#if 0while (1) {temp ADCx-CR2;temp 1 2;if (!temp)break;}
#elsendelay(1000000);
#endif} else {temp ADCx-CR2;temp | 1 CR2_ADON_OFFSET;temp ^ 1 CR2_ADON_OFFSET;ADCx-CR2 temp;}
}/*******************************************************************************
* Function Name : adc_software_start_conv_trigger
* Description : Enables or disables the selected ADC software start conversion .
* Input : - ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
* - state: new state of the selected ADC software start conversion.
* This parameter can be: ENABLE or DISABLE.
* Output : None
* Return : None
*******************************************************************************/
void adc_software_start_conv_trigger(adc_reg_map* ADCx, FunctionalState state, unsigned char J_channel)
{unsigned int temp;unsigned char EOC_offset;unsigned char start_offset;unsigned char exttrig_offset;EOC_offset J_channel ? SR_J_EOC_OFFSET : SR_EOC_OFFSET;start_offset J_channel ? CR2_EXTTRIG_SW_J_START_OFFSET : CR2_EXTTRIG_SW_START_OFFSET;exttrig_offset J_channel ? CR2_J_EXTTRIG_OFFSET : CR2_EXTTRIG_OFFSET;if (state ENABLE) {temp ADCx-CR2;temp | 1 exttrig_offset;ADCx-CR2 temp;// 先把 EOC 清除temp ADCx-SR;temp | 1 EOC_offset;temp ^ 1 EOC_offset;ADCx-SR temp;ADCx-CR2 | 1 start_offset;} else {/* Disable the selected ADC conversion on external event and stop the selected ADC conversion */temp ADCx-CR2;temp | 1 start_offset;temp ^ 1 start_offset;ADCx-CR2 temp;}
}void adc_eoc_check_conv_end(adc_reg_map* ADCx)
{int max_loop;unsigned int temp;max_loop 0;while (1) {temp ADCx-SR;temp 1 1;ndelay(10);max_loop;if (temp 2)break;if (max_loop 10000) {pr_info(adc_eoc_check_conv_end eoc wait timeout\n);break;}}
}loongson-2k300-adc-core.h
头文件部分主要是定义一些ADC相关的寄存器宏和结构体
#ifndef __LOONGSON_2K300_ADC_CORE_H__
#define __LOONGSON_2K300_ADC_CORE_H__typedef enum FunctionalState {DISABLE 0,ENABLE,
} FunctionalState;// ADC register offsets
#define ADC_SR 0x00
#define ADC_CR1 0x04
#define ADC_CR2 0x08
#define ADC_SMPR1 0x0C
#define ADC_SMPR2 0x10
#define ADC_JOFR1 0x14
#define ADC_JOFR2 0x18
#define ADC_JOFR3 0x1C
#define ADC_JOFR4 0x20
#define ADC_HTR 0x24
#define ADC_LTR 0x28
#define ADC_SQR1 0x2C
#define ADC_SQR2 0x30
#define ADC_SQR3 0x34
#define ADC_JSQR 0x38
#define ADC_JDR1 0x3C
#define ADC_JDR2 0x40
#define ADC_JDR3 0x44
#define ADC_JDR4 0x48
#define ADC_DR 0x4Ctypedef struct
{volatile unsigned int SR;volatile unsigned int CR1;volatile unsigned int CR2;volatile unsigned int SMPR1;volatile unsigned int SMPR2;volatile unsigned int JOFR1;volatile unsigned int JOFR2;volatile unsigned int JOFR3;volatile unsigned int JOFR4;volatile unsigned int HTR;volatile unsigned int LTR;volatile unsigned int SQR1;volatile unsigned int SQR2;volatile unsigned int SQR3;volatile unsigned int JSQR;volatile unsigned int JDR1;volatile unsigned int JDR2;volatile unsigned int JDR3;volatile unsigned int JDR4;volatile unsigned int DR;
} adc_reg_map;/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name : stm32f10x_adc.h
* Author : MCD Application Team
* Version : V2.0.3
* Date : 09/22/2008
* Description : This file contains all the functions prototypes for the
* ADC firmware library.
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************//* Define to prevent recursive inclusion -------------------------------------*/#define ADC_RCG (12)/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* ADC DISCNUM mask */
// #define CR1_DISCNUM_Reset ((unsigned int)0xFFFF1FFF)// /* ADC DISCEN mask */
// #define CR1_DISCEN_Set ((unsigned int)0x00000800)
// #define CR1_DISCEN_Reset ((unsigned int)0xFFFFF7FF)// /* ADC JAUTO mask */
// #define CR1_JAUTO_Set ((unsigned int)0x00000400)
// #define CR1_JAUTO_Reset ((unsigned int)0xFFFFFBFF)// /* ADC JDISCEN mask */
// #define CR1_JDISCEN_Set ((unsigned int)0x00001000)
// #define CR1_JDISCEN_Reset ((unsigned int)0xFFFFEFFF)// /* ADC AWDCH mask */
// #define CR1_AWDCH_Reset ((unsigned int)0xFFFFFFE0)// /* ADC Analog watchdog enable mode mask */
// #define CR1_AWDMode_Reset ((unsigned int)0xFF3FFDFF)// /* CR1 register Mask */
#define CR1_CLEAR_MASK ((unsigned int)0xFFF0FEFF)//
#define SR_EOC_OFFSET 0x1
#define SR_J_EOC_OFFSET 0x2//
#define CR1_EOC_IE_OFFSET 0x5
#define CR1_J_EOC_IE_OFFSET 0x7/* ADC ADON mask */
#define CR2_ADON_OFFSET 0x0/* ADC reset */
// #define CR2_ADC_Reset ((unsigned int)0x80000000)// /* ADC DMA mask */
// #define CR2_DMA_Set ((unsigned int)0x00000100)
// #define CR2_DMA_Reset ((unsigned int)0xFFFFFEFF)// /* ADC RSTCAL mask */
// #define CR2_RSTCAL_Set ((unsigned int)0x00000008)// /* ADC CAL mask */
// #define CR2_CAL_Set ((unsigned int)0x00000004)// /* ADC SWSTART mask */
// #define CR2_SWSTART_Set ((unsigned int)0x00400000)// /* ADC EXTTRIG mask */
// #define CR2_EXTTRIG_Set ((unsigned int)0x00100000)
// #define CR2_EXTTRIG_Reset ((unsigned int)0xFFEFFFFF)/* ADC Software start mask */
#define CR2_EXTTRIG_SW_START_OFFSET 22
#define CR2_EXTTRIG_SW_J_START_OFFSET 21
#define CR2_EXTTRIG_OFFSET 20
#define CR2_J_EXTTRIG_OFFSET 15
// #define CR2_EXTTRIG_SWSTART_Set ((unsigned int)0x00500000)
// #define CR2_EXTTRIG_SWSTART_Reset ((unsigned int)0xFFAFFFFF)/* ADC JEXTSEL mask */
// #define CR2_JEXTSEL_Reset ((unsigned int)0xFFFF8FFF)// /* ADC JEXTTRIG mask */
// #define CR2_JEXTTRIG_Set ((unsigned int)0x00008000)
// #define CR2_JEXTTRIG_Reset ((unsigned int)0xFFFF7FFF)// /* ADC JSWSTART mask */
// #define CR2_JSWSTART_Set ((unsigned int)0x00200000)// /* ADC injected software start mask */
// #define CR2_JEXTTRIG_JSWSTART_Set ((unsigned int)0x00208000)
// #define CR2_JEXTTRIG_JSWSTART_Reset ((unsigned int)0xFFDF7FFF)// /* ADC TSPD mask */
// #define CR2_TSVREFE_Set ((unsigned int)0x00800000)
// #define CR2_TSVREFE_Reset ((unsigned int)0xFF7FFFFF)// /* CR2 register Mask */
#define CR2_CLEAR_MASK ((unsigned int)0xFFF1F7FD)// /* ADC SQx mask */
#define SQR3_SQ_MASK 0x1F
#define SQR2_SQ_MASK 0x1F
#define SQR1_SQ_MASK 0x1F// /* SQR1 register Mask */
#define SQR1_CLEAR_MASK ((unsigned int)0xFF0FFFFF)// /* ADC JSQx mask */
// #define JSQR_JSQ_Set ((unsigned int)0x0000001F)// /* ADC JL mask */
// #define JSQR_JL_Set ((unsigned int)0x00300000)
// #define JSQR_JL_Reset ((unsigned int)0xFFCFFFFF)// /* ADC SMPx mask */
#define SMPR1_SMP_MASK 0x7
#define SMPR2_SMP_MASK 0x7// /* ADC JDRx registers offset */
// #define JDR_Offset ((unsigned char)0x28)// #define DISABLE 0
// #define ENABLE 1/* Includes ------------------------------------------------------------------*/
// #include ../i2c/ls2k0300_map.h/* Exported types ------------------------------------------------------------*/
/* ADC Init structure definition */
typedef struct
{unsigned int ADC_Mode;int ADC_ScanConvMode; //CR1 scanint ADC_ContinuousConvMode;//CR2 contunsigned int ADC_ExternalTrigConv;//CR2 extselunsigned int ADC_DataAlign;//CR2 alignunsigned char ADC_NbrOfChannel;//SQR1 lunsigned short ADC_ClkDivider;//CR1 clkdivunsigned char ADC_JTrigMod;//CR2 jtrigmodunsigned char ADC_ADCEdge;//CR2 adcedgeunsigned char ADC_DiffMod;//CR1 diffmodunsigned char ADC_OutPhaseSel;//CR1 opsunsigned char ADC_ClkMask;//CR2 clkmaskunsigned char ADC_Int_EOC; // CR1 EOC enable ?unsigned char ADC_Int_JEOC; // CR1 JEOC enable ?
}adc_init_info;/* Exported constants --------------------------------------------------------*//* ADC dual mode -------------------------------------------------------------*/
#define ADC_Mode_Independent ((unsigned int)0x00000000)
#define ADC_Mode_RegInjecSimult ((unsigned int)0x00010000)
#define ADC_Mode_RegSimult_AlterTrig ((unsigned int)0x00020000)
#define ADC_Mode_InjecSimult_FastInterl ((unsigned int)0x00030000)
#define ADC_Mode_InjecSimult_SlowInterl ((unsigned int)0x00040000)
#define ADC_Mode_InjecSimult ((unsigned int)0x00050000)
#define ADC_Mode_RegSimult ((unsigned int)0x00060000)
#define ADC_Mode_FastInterl ((unsigned int)0x00070000)
#define ADC_Mode_SlowInterl ((unsigned int)0x00080000)
#define ADC_Mode_AlterTrig ((unsigned int)0x00090000)#define IS_ADC_MODE(MODE) (((MODE) ADC_Mode_Independent) || \((MODE) ADC_Mode_RegInjecSimult) || \((MODE) ADC_Mode_RegSimult_AlterTrig) || \((MODE) ADC_Mode_InjecSimult_FastInterl) || \((MODE) ADC_Mode_InjecSimult_SlowInterl) || \((MODE) ADC_Mode_InjecSimult) || \((MODE) ADC_Mode_RegSimult) || \((MODE) ADC_Mode_FastInterl) || \((MODE) ADC_Mode_SlowInterl) || \((MODE) ADC_Mode_AlterTrig))/* ADC extrenal trigger sources for regular channels conversion --------------*/
/* for ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T1_CC1 ((unsigned int)0x00000000)
#define ADC_ExternalTrigConv_T1_CC2 ((unsigned int)0x00020000)
#define ADC_ExternalTrigConv_T2_CC2 ((unsigned int)0x00060000)
#define ADC_ExternalTrigConv_T3_TRGO ((unsigned int)0x00080000)
#define ADC_ExternalTrigConv_T4_CC4 ((unsigned int)0x000A0000)
#define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO ((unsigned int)0x000C0000)
/* for ADC1, ADC2 and ADC3 */
#define ADC_ExternalTrigConv_T1_CC3 ((unsigned int)0x00040000)
#define ADC_ExternalTrigConv_None ((unsigned int)0x000E0000)
/* for ADC3 */
#define ADC_ExternalTrigConv_T3_CC1 ((unsigned int)0x00000000)
#define ADC_ExternalTrigConv_T2_CC3 ((unsigned int)0x00020000)
#define ADC_ExternalTrigConv_T8_CC1 ((unsigned int)0x00060000)
#define ADC_ExternalTrigConv_T8_TRGO ((unsigned int)0x00080000)
#define ADC_ExternalTrigConv_T5_CC1 ((unsigned int)0x000A0000)
#define ADC_ExternalTrigConv_T5_CC3 ((unsigned int)0x000C0000)#define IS_ADC_EXT_TRIG(REGTRIG) (((REGTRIG) ADC_ExternalTrigConv_T1_CC1) || \((REGTRIG) ADC_ExternalTrigConv_T1_CC2) || \((REGTRIG) ADC_ExternalTrigConv_T1_CC3) || \((REGTRIG) ADC_ExternalTrigConv_T2_CC2) || \((REGTRIG) ADC_ExternalTrigConv_T3_TRGO) || \((REGTRIG) ADC_ExternalTrigConv_T4_CC4) || \((REGTRIG) ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO) || \((REGTRIG) ADC_ExternalTrigConv_None) || \((REGTRIG) ADC_ExternalTrigConv_T3_CC1) || \((REGTRIG) ADC_ExternalTrigConv_T2_CC3) || \((REGTRIG) ADC_ExternalTrigConv_T8_CC1) || \((REGTRIG) ADC_ExternalTrigConv_T8_TRGO) || \((REGTRIG) ADC_ExternalTrigConv_T5_CC1) || \((REGTRIG) ADC_ExternalTrigConv_T5_CC3))/* ADC data align ------------------------------------------------------------*/
#define ADC_DataAlign_Right ((unsigned int)0x00000000)
#define ADC_DataAlign_Left ((unsigned int)0x00000800)#define IS_ADC_DATA_ALIGN(ALIGN) (((ALIGN) ADC_DataAlign_Right) || \((ALIGN) ADC_DataAlign_Left))/* ADC channels --------------------------------------------------------------*/
#define ADC_Channel_0 ((unsigned char)0x00)
#define ADC_Channel_1 ((unsigned char)0x01)
#define ADC_Channel_2 ((unsigned char)0x02)
#define ADC_Channel_3 ((unsigned char)0x03)
#define ADC_Channel_4 ((unsigned char)0x08)
#define ADC_Channel_5 ((unsigned char)0x09)
#define ADC_Channel_6 ((unsigned char)0x0a)
#define ADC_Channel_7 ((unsigned char)0x0b)
#define ADC_Channel_8 ((unsigned char)0x18)
#define ADC_Channel_9 ((unsigned char)0x19)
#define ADC_Channel_10 ((unsigned char)0x1A)
#define ADC_Channel_11 ((unsigned char)0x1B)
#define ADC_Channel_12 ((unsigned char)0x1C)
#define ADC_Channel_13 ((unsigned char)0x1D)
#define ADC_Channel_14 ((unsigned char)0x1E)
#define ADC_Channel_15 ((unsigned char)0x1F)
#define ADC_Channel_16 ((unsigned char)0x10)
#define ADC_Channel_17 ((unsigned char)0x11)#define IS_ADC_CHANNEL(CHANNEL) (((CHANNEL) ADC_Channel_0) || ((CHANNEL) ADC_Channel_1) || \((CHANNEL) ADC_Channel_2) || ((CHANNEL) ADC_Channel_3) || \((CHANNEL) ADC_Channel_4) || ((CHANNEL) ADC_Channel_5) || \((CHANNEL) ADC_Channel_6) || ((CHANNEL) ADC_Channel_7) || \((CHANNEL) ADC_Channel_8) || ((CHANNEL) ADC_Channel_9) || \((CHANNEL) ADC_Channel_10) || ((CHANNEL) ADC_Channel_11) || \((CHANNEL) ADC_Channel_12) || ((CHANNEL) ADC_Channel_13) || \((CHANNEL) ADC_Channel_14) || ((CHANNEL) ADC_Channel_15) || \((CHANNEL) ADC_Channel_16) || ((CHANNEL) ADC_Channel_17))/* ADC sampling times --------------------------------------------------------*/
#define ADC_SampleTime_1Cycles ((unsigned char)0x00)
#define ADC_SampleTime_2Cycles ((unsigned char)0x01)
#define ADC_SampleTime_4Cycles ((unsigned char)0x02)
#define ADC_SampleTime_8Cycles ((unsigned char)0x03)
#define ADC_SampleTime_16Cycles ((unsigned char)0x04)
#define ADC_SampleTime_32Cycles ((unsigned char)0x05)
#define ADC_SampleTime_64Cycles ((unsigned char)0x06)
#define ADC_SampleTime_128Cycles ((unsigned char)0x07)#define IS_ADC_SAMPLE_TIME(TIME) (((TIME) ADC_SampleTime_1Cycles5) || \((TIME) ADC_SampleTime_2Cycles5) || \((TIME) ADC_SampleTime_4Cycles5) || \((TIME) ADC_SampleTime_8Cycles5) || \((TIME) ADC_SampleTime_16Cycles5) || \((TIME) ADC_SampleTime_32Cycles5) || \((TIME) ADC_SampleTime_64Cycles5) || \((TIME) ADC_SampleTime_128Cycles5))/* ADC extrenal trigger sources for injected channels conversion -------------*/
/* For ADC1 and ADC2 */
#define ADC_ExternalTrigInjecConv_T2_TRGO ((unsigned int)0x00002000)
#define ADC_ExternalTrigInjecConv_T2_CC1 ((unsigned int)0x00003000)
#define ADC_ExternalTrigInjecConv_T3_CC4 ((unsigned int)0x00004000)
#define ADC_ExternalTrigInjecConv_T4_TRGO ((unsigned int)0x00005000)
#define ADC_ExternalTrigInjecConv_Ext_IT15_TIM8_CC4 ((unsigned int)0x00006000)
/* For ADC1, ADC2 and ADC3 */
#define ADC_ExternalTrigInjecConv_T1_TRGO ((unsigned int)0x00000000)
#define ADC_ExternalTrigInjecConv_T1_CC4 ((unsigned int)0x00001000)
#define ADC_ExternalTrigInjecConv_None ((unsigned int)0x00007000)
/* For ADC3 */
#define ADC_ExternalTrigInjecConv_T4_CC3 ((unsigned int)0x00002000)
#define ADC_ExternalTrigInjecConv_T8_CC2 ((unsigned int)0x00003000)
#define ADC_ExternalTrigInjecConv_T8_CC4 ((unsigned int)0x00004000)
#define ADC_ExternalTrigInjecConv_T5_TRGO ((unsigned int)0x00005000)
#define ADC_ExternalTrigInjecConv_T5_CC4 ((unsigned int)0x00006000)#define IS_ADC_EXT_INJEC_TRIG(INJTRIG) (((INJTRIG) ADC_ExternalTrigInjecConv_T1_TRGO) || \((INJTRIG) ADC_ExternalTrigInjecConv_T1_CC4) || \((INJTRIG) ADC_ExternalTrigInjecConv_T2_TRGO) || \((INJTRIG) ADC_ExternalTrigInjecConv_T2_CC1) || \((INJTRIG) ADC_ExternalTrigInjecConv_T3_CC4) || \((INJTRIG) ADC_ExternalTrigInjecConv_T4_TRGO) || \((INJTRIG) ADC_ExternalTrigInjecConv_Ext_IT15_TIM8_CC4) || \((INJTRIG) ADC_ExternalTrigInjecConv_None) || \((INJTRIG) ADC_ExternalTrigInjecConv_T4_CC3) || \((INJTRIG) ADC_ExternalTrigInjecConv_T8_CC2) || \((INJTRIG) ADC_ExternalTrigInjecConv_T8_CC4) || \((INJTRIG) ADC_ExternalTrigInjecConv_T5_TRGO) || \((INJTRIG) ADC_ExternalTrigInjecConv_T5_CC4))/* ADC injected channel selection --------------------------------------------*/
#define ADC_InjectedChannel_1 ((unsigned char)0x14)
#define ADC_InjectedChannel_2 ((unsigned char)0x18)
#define ADC_InjectedChannel_3 ((unsigned char)0x1C)
#define ADC_InjectedChannel_4 ((unsigned char)0x20)#define IS_ADC_INJECTED_CHANNEL(CHANNEL) (((CHANNEL) ADC_InjectedChannel_1) || \((CHANNEL) ADC_InjectedChannel_2) || \((CHANNEL) ADC_InjectedChannel_3) || \((CHANNEL) ADC_InjectedChannel_4))/* ADC analog watchdog selection ---------------------------------------------*/
#define ADC_AnalogWatchdog_SingleRegEnable ((unsigned int)0x00800200)
#define ADC_AnalogWatchdog_SingleInjecEnable ((unsigned int)0x00400200)
#define ADC_AnalogWatchdog_SingleRegOrInjecEnable ((unsigned int)0x00C00200)
#define ADC_AnalogWatchdog_AllRegEnable ((unsigned int)0x00800000)
#define ADC_AnalogWatchdog_AllInjecEnable ((unsigned int)0x00400000)
#define ADC_AnalogWatchdog_AllRegAllInjecEnable ((unsigned int)0x00C00000)
#define ADC_AnalogWatchdog_None ((unsigned int)0x00000000)#define IS_ADC_ANALOG_WATCHDOG(WATCHDOG) (((WATCHDOG) ADC_AnalogWatchdog_SingleRegEnable) || \((WATCHDOG) ADC_AnalogWatchdog_SingleInjecEnable) || \((WATCHDOG) ADC_AnalogWatchdog_SingleRegOrInjecEnable) || \((WATCHDOG) ADC_AnalogWatchdog_AllRegEnable) || \((WATCHDOG) ADC_AnalogWatchdog_AllInjecEnable) || \((WATCHDOG) ADC_AnalogWatchdog_AllRegAllInjecEnable) || \((WATCHDOG) ADC_AnalogWatchdog_None))/* ADC interrupts definition -------------------------------------------------*/
#define ADC_IT_EOC ((unsigned short)0x0220)
#define ADC_IT_AWD ((unsigned short)0x0140)
#define ADC_IT_JEOC ((unsigned short)0x0480)#define IS_ADC_IT(IT) ((((IT) (unsigned short)0xF81F) 0x00) ((IT) ! 0x00))
#define IS_ADC_GET_IT(IT) (((IT) ADC_IT_EOC) || ((IT) ADC_IT_AWD) || \((IT) ADC_IT_JEOC))/* ADC flags definition ------------------------------------------------------*/
#define ADC_FLAG_AWD ((unsigned char)0x01)
#define ADC_FLAG_EOC ((unsigned char)0x02)
#define ADC_FLAG_JEOC ((unsigned char)0x04)
#define ADC_FLAG_JSTRT ((unsigned char)0x08)
#define ADC_FLAG_STRT ((unsigned char)0x10)#define IS_ADC_CLEAR_FLAG(FLAG) ((((FLAG) (unsigned char)0xE0) 0x00) ((FLAG) ! 0x00))
#define IS_ADC_GET_FLAG(FLAG) (((FLAG) ADC_FLAG_AWD) || ((FLAG) ADC_FLAG_EOC) || \((FLAG) ADC_FLAG_JEOC) || ((FLAG) ADC_FLAG_JSTRT) || \((FLAG) ADC_FLAG_STRT))/* ADC thresholds ------------------------------------------------------------*/
#define IS_ADC_THRESHOLD(THRESHOLD) ((THRESHOLD) 0xFFF)/* ADC injected offset -------------------------------------------------------*/
#define IS_ADC_OFFSET(OFFSET) ((OFFSET) 0xFFF)/* ADC injected length -------------------------------------------------------*/
#define IS_ADC_INJECTED_LENGTH(LENGTH) (((LENGTH) 0x1) ((LENGTH) 0x4))/* ADC injected rank ---------------------------------------------------------*/
#define IS_ADC_INJECTED_RANK(RANK) (((RANK) 0x1) ((RANK) 0x4))/* ADC regular length --------------------------------------------------------*/
#define IS_ADC_REGULAR_LENGTH(LENGTH) (((LENGTH) 0x1) ((LENGTH) 0x10))/* ADC regular rank ----------------------------------------------------------*/
#define IS_ADC_REGULAR_RANK(RANK) (((RANK) 0x1) ((RANK) 0x10))/* ADC regular discontinuous mode number -------------------------------------*/
#define IS_ADC_REGULAR_DISC_NUMBER(NUMBER) (((NUMBER) 0x1) ((NUMBER) 0x8))//Loongson Feature
#define RCH0 ADC_Channel_0
#define RCH1 ADC_Channel_1
#define RCH2 ADC_Channel_2
#define RCH3 ADC_Channel_3
#define RCH4 ADC_Channel_4
#define RCH5 ADC_Channel_5
#define RCH6 ADC_Channel_6
#define RCH7 ADC_Channel_7//Loongson Feature
#define JCH0 ADC_Channel_0
#define JCH1 ADC_Channel_1
#define JCH2 ADC_Channel_2
#define JCH3 ADC_Channel_3void adc_init(adc_reg_map* ADCx, adc_init_info* ADC_InitStruct);
void adc_struct_init(adc_init_info* ADC_InitStruct);
void ADC_RegularChannelConfig(adc_reg_map* ADCx, unsigned char ADC_Channel, unsigned char Rank, unsigned char ADC_SampleTime);
void adc_dev_enable(adc_reg_map* ADCx, FunctionalState state);
void adc_software_start_conv_trigger(adc_reg_map* ADCx, FunctionalState state, unsigned char J_channel);
void adc_eoc_check_conv_end(adc_reg_map* ADCx);#endif /* __LOONGSON_2K300_ADC_CORE_H__ */Kconfig
需要在drivers/iio/adc下的Kconfig加入以下代码
config LS_2K300_ADCtristate ls2k300 driverselect IIO_BUFFERselect IIO_TRIGGERED_BUFFERhelploongson 2k300 ADC driverMakefile
需要在drivers/iio/adc下的Makefile加入以下代码
obj-$(CONFIG_LS_2K300_ADC) loongson-2k300-adc.o loongson-2k300-adc-core.oloongson_2k0300.dtsi
dtsi文件下加入以下代码
adc: adc0x1611c000 {compatible ls2k300-adc;reg 0 0x1611c000 0 0x50;status disabled;num-channels 0;
};loongson_2k0300_pai_99.dts
dts设备树下加入adc节点
adc {status okay;
};.config
在内核根目录下的配置文件加入以下开关
CONFIG_IIOy
CONFIG_LS_2K300_ADCy修改完毕后重新编译内核将内核部署到开发板/boot目录下重启开发板发现/sys/bus/iio/devices/iio/device0目录下已经生成了相应的in_voltageX_raw节点 接口
久久派上集成8路12位ADC采样接口 支持单端采样 也支持差分采样 参考电压Vref为1.8V
PIN信号定义备注1P3V33.3V 电源输出2GND0地线3ADC 通道 40/4 通道可以独立采样 也可以作为差分采样4ADC 通道 00/4 通道可以独立采样 也可以作为差分采样5ADC 通道 11/5 通道可以独立采样 也可以作为差分采样6ADC 通道 51/5 通道可以独立采样 也可以作为差分采样7ADC 通道 22/6 通道可以独立采样 也可以作为差分采样8ADC 通道 62/6 通道可以独立采样 也可以作为差分采样9ADC 通道 33/7 通道可以独立采样 也可以作为差分采样10ADC 通道 73/7 通道可以独立采样 也可以作为差分采样
原理图如下J1针脚处可见ADC并不是按顺序分布的 测试
以读取ADC0通道为例测试命令如下其中raw为ADC原始数据scale为单位分辨率所占的电压值两者相乘可得到实际电压值
raw$(cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw)
scale$(cat /sys/bus/iio/devices/iio\:device0/in_voltage_scale)
echo vol_raw : $raw,vol_scale:$scale使用电位器调节到1.8V左右和读取的数值较为接近0.439453125 * 4095 / 1000约等于1.8V 参考
linux-5.10: linux for loongson2 (gitee.com)