Linux驱动开辟-①regmap②IIO子体系

饭宝  论坛元老 | 2025-4-18 07:19:16 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1645|帖子 1645|积分 4935

一,regmap

  对于spi和i2c,读写寄存器的框架不同,但设备本质一样,因此就有了regmap模型来对其进行简化,提供同一的接口函数来访问寄存器,而且使用很方便,使用时间,调用regmap的读写寄存器函数即可。

整体框架:
  1.     struct regmap *regmap;
  2.     struct regmap_config regmap_config;
  3.          /*对于spi的设备,之前的读写还需要对t->tx_buf,t->rx_buf等进行操作,再t放到message
  4.          中,最后再利用spi_sync发送,比较麻烦*/
  5.         static  unsigned  char icm20608c_read_one_reg(struct icm20608c_dev *dev,u8 reg)
  6.         {
  7.             u8 ret;
  8.             unsigned int data;
  9.             ret = regmap_read(dev->regmap,reg,&data);//调用regmap的读函数
  10.             return (u8)data;
  11.         }
  12.        
  13.         void icm20608c_write_one_reg66(struct icm20608c_dev *dev,u8 reg,unsigned char data)
  14.         {
  15.             regmap_write(dev->regmap,reg,data);//调用regmap的写函数
  16.         }
  17.        
  18.         static int icm20608c_probe(struct spi_device *spi)
  19.         {
  20.             int ret = 0;
  21.             icm20608c.regmap_config.reg_bits = 8;//寄存器大小为8bit
  22.             icm20608c.regmap_config.val_bits = 8;//寄存器数据值8bit
  23.             //icm20608c.regmap_config.read_flag_mask = 0x80;//读掩码
  24.             icm20608c.regmap = regmap_init_spi(spi,&icm20608c.regmap_config);//关键就是这个                    函        数,将regmap_config和spi设备关联起来,创建出regmap
  25.             if(IS_ERR(icm20608c.regmap))
  26.             {
  27.                 return PTR_ERR(icm20608c.regmap);
  28.             }
  29.     ........
  30.         }
  31.          
  32.         static int icm20608c_remove(struct spi_device *spi)
  33.         {
  34.                         .........
  35.             regmap_exit(icm20608c.regmap);
  36.             return 0;
  37.         }  
复制代码
二,IIO子体系

  Linux驱动喜欢把步伐分层,而且一类的放到一起,IIO子体系就是针对ADC传感器,将好比加快度计,光传感器,气压计,磁力计等等设备,用一样的驱动模型。
  布局体iio_dev来表示具体的IIO设备,整体的驱动框架,照旧要看设备,好比spi设备,创建的就是spi_driver。重要包含三个内容:①在probe函数中,申请iio_dev内存,进行初始化,注册iio_dev。②iio_chan_spec对通道的建立,好比icm20608设备,有加快度xyz轴,陀螺仪xyz轴和温度,一共七个数据,因此要建立七个通道,在文件中显示,包含:加快度+x或y或z轴+什么数据,好比原始数据,量程等。③iio_info操纵函数中,read_raw和write_raw函数具体的实现,具体怎么样实现,照旧依靠regmap_read和regmap_write函数,对寄存器进行操纵。
2.1初始化相干工作

  留意,如今不建立全局变量了,之前会这样写:struct icm20608c_dev icm20608,从而在整个驱动中,直接调用icm20608。好比在remove函数中,想进行注销工作,先indio_dev = spi_get_drvdata(spi);获取indio_dev,再得到dev = iio_priv(indio_dev);,即原来没改过的icm20608地址。
  初始化工作中,devm_iio_device_alloc(&spi->dev, sizeof(*dev)) 做了两件事①分配一个struct iio_dev布局的内存,②额外分配sizeof(*dev)巨细的内存空间(这里是struct icm20608c_dev的巨细。

  iio_priv(indio_dev)是一个宏,它返回的是紧跟在iio_dev布局体背面的私有数据地区的指针,dev = iio_priv(indio_dev)获取的是紧跟在iio_dev背面的为驱动私有数据预留的内存地区的指针。
  1. struct icm20608c_dev {
  2.     struct spi_device *spi;
  3.     struct regmap *regmap;
  4.     struct regmap_config regmap_config;
  5.     struct mutex lock;
  6. };
  7. /*完成设备号注册 节点注册 spi设备初始化*/
  8. static int icm20608c_probe(struct spi_device *spi)
  9. {
  10.     int ret = 0;
  11.     struct icm20608c_dev *dev;
  12.     struct iio_dev *indio_dev;
  13.     /*1.iio_dev申请内存*/
  14.     indio_dev = devm_iio_device_alloc(&spi->dev,sizeof(*dev));
  15.     if(!indio_dev)
  16.     {
  17.         return ret;
  18.     }
  19.     /*2.获取icm20608c_dev结构体地址*/
  20.     dev = iio_priv(indio_dev);
  21.     dev->spi = spi;
  22.     spi_set_drvdata(spi,indio_dev);
  23.     mutex_init(&dev->lock);
  24.     /*3.初始化iio_dev成员变量*/
  25.     indio_dev->dev.parent = &spi->dev;
  26.     indio_dev->info = &icm20608c_info;
  27.     indio_dev->name = ICMC20608C_NAME;
  28.     indio_dev->modes = INDIO_DIRECT_MODE;
  29.     indio_dev->channels = icm20608_channels;
  30.     indio_dev->num_channels = ARRAY_SIZE(icm20608_channels);
  31.     /*4.注册iio_dev*/
  32.     ret = iio_device_register(indio_dev);
  33.     if(ret<0)
  34.     {
  35.         return ret;
  36.     }
  37.     /*5.初始化regmap_config并且注册*/
  38.     dev->regmap_config.reg_bits = 8;//寄存器大小为8bit
  39.     dev->regmap_config.val_bits = 8;//寄存器数据值8bit
  40.     //dev.regmap_config.read_flag_mask = 0x80;//读掩码
  41.     dev->regmap = regmap_init_spi(spi,&dev->regmap_config);
  42.     if(IS_ERR(dev->regmap))
  43.     {
  44.         goto regmap_error;
  45.         return PTR_ERR(dev->regmap);
  46.     }
  47.     /*6.初始化SPI设备*/
  48.     spi->mode = SPI_MODE_0;//时钟模式
  49.     spi_setup(spi);
  50.     /*7.寄存器初始化内容*/
  51.     icm20608c_reg_init(dev);
  52.     printk("probe success \r\n");
  53.     return 0;
  54. regmap_error:
  55.     iio_device_unregister(indio_dev);   
  56.     return ret;
  57. }
  58. static int icm20608c_remove(struct spi_device *spi)
  59. {
  60.     /*这段代码,为了获取icm20608c_dev的地址和iio_dev地址,以便进行解除*/
  61.     struct icm20608c_dev *dev;
  62.     struct iio_dev *indio_dev;
  63.     indio_dev = spi_get_drvdata(spi);
  64.     dev = iio_priv(indio_dev);
  65.     /*删除regmap,注销iio_dev*/
  66.     regmap_exit(dev->regmap);
  67.     iio_device_unregister(indio_dev);   
  68.     printk("remove success \r\n");
  69.     return 0;
  70. }
复制代码
2.2 通道

  这个 ICM20608_CHAN(_type, _channel2, _index)宏,就相当于给带入里面的数进行赋值,创建出一个通道布局体,_type是表示各种数据,好比加快度IIO_ACCEL,当modified=1,channel2 为通道修饰符,表示对这个_type还有更具体的形貌。  info_mask_shared_by_type 为相同type范例通道共有的(但是名字要一样,好比都是加快度范例,in_accel_sacle),info_mask_separate 为这个通道私有的(好比in_accel_x_raw),具体在文件中的顺序,依靠scan_index,为0时间,在最前面。


在文件中显示顺序:

  1. #define ICM20608_CHAN(_type, _channel2, _index)                    \
  2.         {                                                             \
  3.                 .type = _type,                                        \
  4.                 .modified = 1,                                        \
  5.                 .channel2 = _channel2,                                \
  6.                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
  7.                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |              \
  8.                                       BIT(IIO_CHAN_INFO_CALIBBIAS),   \
  9.                 .scan_index = _index,                                 \
  10.                 .scan_type = {                                        \
  11.                                 .sign = 's',                          \
  12.                                 .realbits = 16,                       \
  13.                                 .storagebits = 16,                    \
  14.                                 .shift = 0,                           \
  15.                                 .endianness = IIO_BE,                 \
  16.                              },                                       \
  17.         }
  18. enum inv_icm20608_scan {
  19.         INV_ICM20608_SCAN_ACCL_X,
  20.         INV_ICM20608_SCAN_ACCL_Y,
  21.         INV_ICM20608_SCAN_ACCL_Z,
  22.         INV_ICM20608_SCAN_TEMP,
  23.         INV_ICM20608_SCAN_GYRO_X,
  24.         INV_ICM20608_SCAN_GYRO_Y,
  25.         INV_ICM20608_SCAN_GYRO_Z,
  26.         INV_ICM20608_SCAN_TIMESTAMP,
  27. };
  28. static const struct iio_chan_spec icm20608_channels[] = {
  29.     {
  30.         .type = IIO_TEMP,
  31.         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
  32.                             |BIT(IIO_CHAN_INFO_OFFSET)
  33.                             |BIT(IIO_CHAN_INFO_SCALE),
  34.         .scan_index = INV_ICM20608_SCAN_TEMP,
  35.         .scan_type = {
  36.                 .sign = 's',
  37.                 .realbits = 16,
  38.                 .storagebits = 16,
  39.                 .shift = 0,
  40.                 .endianness = IIO_BE,
  41.             },
  42.     },
  43.     ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_X,INV_ICM20608_SCAN_GYRO_X),
  44.     ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_Y,INV_ICM20608_SCAN_GYRO_Y),
  45.     ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_Z,INV_ICM20608_SCAN_GYRO_Z),
  46.     ICM20608_CHAN(IIO_ACCEL,IIO_MOD_X,INV_ICM20608_SCAN_ACCL_X),
  47.     ICM20608_CHAN(IIO_ACCEL,IIO_MOD_Y,INV_ICM20608_SCAN_ACCL_Y),
  48.     ICM20608_CHAN(IIO_ACCEL,IIO_MOD_Z,INV_ICM20608_SCAN_ACCL_Z),   
  49. };
复制代码
2.3 读实现

  icm20608c_read_raw的返回值,决定读到的数据值,返回值IIO_VAL_INT为1,读到的数据按照整形返回,只有val,没有val2,返回值IIO_VAL_INT_PLUS_MICRO为2,按照val+val2/1000000反馈, 返回值IIO_VAL_INT_PLUS_NANO为2,按照val+val2/1000000000,返回值为负,读取错误。
  对于IIO_CHAN_INFO_SCALE量程数据的读取,读到寄存器值为00 01 10 11,要进行转换成实际值,转换关系有数组gyro_scale_icm20608和accel_scale_icm20608构建,最后进行输出。
  终极得到的真实数据,好比重力加快度=in_accel_z_raw(读取的值)×in_accel_scale(加快度量程)。
  1. static const int gyro_scale_icm20608[] = {7629, 15258, 30517, 61035};
  2. static const int accel_scale_icm20608[] = {61035, 122070, 244140, 488281};
  3. static  unsigned  char icm20608c_read_one_reg(struct icm20608c_dev *dev,u8 reg)
  4. {
  5.     u8 ret;
  6.     unsigned int data;
  7.     ret = regmap_read(dev->regmap,reg,&data);
  8.     return (u8)data;
  9. }
  10. void icm20608c_write_one_reg66(struct icm20608c_dev *dev,u8 reg,unsigned char data)
  11. {
  12.     regmap_write(dev->regmap,reg,data);
  13. }
  14. /*计算出要读寄存器的位置,根据带入的axis计算偏移地址+reg*/
  15. static int icm20608_sensor_show(struct icm20608c_dev *dev, int reg,int axis,int *val)
  16. {
  17.         int ind, result;
  18.         __be16 d;
  19.         ind = (axis - IIO_MOD_X) * 2;
  20.         result = regmap_bulk_read(dev->regmap, reg + ind, (u8 *)&d, 2);
  21.         if (result)
  22.                 return -EINVAL;
  23.         *val = (short)be16_to_cpup(&d);
  24.         return IIO_VAL_INT;
  25. }
  26. static int icm20608c_read_raw(struct iio_dev *indio_dev,
  27.                             struct iio_chan_spec const *chan,
  28.                             int *val, int *val2, long mask)
  29. {  
  30.     int ret = 0;
  31.     unsigned char regdata = 0;
  32.     struct  icm20608c_dev *dev = iio_priv(indio_dev);
  33.     switch(mask){
  34.     case IIO_CHAN_INFO_RAW://原始值
  35.         mutex_lock(&dev->lock);
  36.         switch(chan->type){
  37.             case IIO_TEMP:
  38.                 ret = icm20608_sensor_show(dev, ICM20_TEMP_OUT_H, IIO_MOD_X, val);//IIO_MOD_X意思是就从这个ICM20_TEMP_OUT_H开始
  39.                 break;
  40.             case IIO_ACCEL:
  41.                 ret = icm20608_sensor_show(dev, ICM20_ACCEL_XOUT_H, chan->channel2, val);
  42.                 break;
  43.             case IIO_ANGL_VEL:
  44.                 ret = icm20608_sensor_show(dev, ICM20_GYRO_XOUT_H, chan->channel2, val);
  45.                 break;
  46.             default:
  47.                 ret = -EINVAL;
  48.                 break;
  49.         }
  50.         mutex_unlock(&dev->lock);
  51.         return ret;
  52.     case IIO_CHAN_INFO_CALIBBIAS://校准值      
  53.         switch(chan->type)
  54.         {   //对于加速度和陀螺仪的校准值,首先是校准值寄存器位置不同,其次是分为x,y,z
  55.             case IIO_ACCEL:
  56.                 mutex_lock(&dev->lock);
  57.                 ret = icm20608_sensor_show(dev, ICM20_XA_OFFSET_H, chan->channel2, val);
  58.                 mutex_unlock(&dev->lock);  
  59.                 break;
  60.             case IIO_ANGL_VEL:
  61.                 mutex_lock(&dev->lock);
  62.                 ret = icm20608_sensor_show(dev, ICM20_XG_OFFS_USRH, chan->channel2, val);
  63.                 mutex_unlock(&dev->lock);                 
  64.                 break;
  65.             default:
  66.                 ret = -EINVAL;
  67.                 break;
  68.         }
  69.         break;
  70.     case IIO_CHAN_INFO_SCALE://度量
  71.                 switch (chan->type) {
  72.                 case IIO_ANGL_VEL:
  73.                         mutex_lock(&dev->lock);
  74.                         regdata = (icm20608c_read_one_reg(dev, ICM20_GYRO_CONFIG) & 0X18) >> 3;
  75.                         *val  = 0;
  76.                         *val2 = gyro_scale_icm20608[regdata];
  77.                         mutex_unlock(&dev->lock);
  78.                         return IIO_VAL_INT_PLUS_MICRO;        /* 值为val+val2/1000000 */
  79.                 case IIO_ACCEL:
  80.                         mutex_lock(&dev->lock);
  81.                         regdata = (icm20608c_read_one_reg(dev, ICM20_ACCEL_CONFIG) & 0X18) >> 3;
  82.                         *val = 0;
  83.                         *val2 = accel_scale_icm20608[regdata];;
  84.                         mutex_unlock(&dev->lock);
  85.                         return IIO_VAL_INT_PLUS_NANO;/* 值为val+val2/1000000000 */
  86.                 case IIO_TEMP:                                       
  87.                         *val = ICM20608_TEMP_SCALE/ 1000000;
  88.                         *val2 = ICM20608_TEMP_SCALE % 1000000;
  89.                         return IIO_VAL_INT_PLUS_MICRO;        /* 值为val+val2/1000000 */
  90.                 default:
  91.                         return -EINVAL;
  92.                 }
  93.                 return ret;
  94.     case IIO_CHAN_INFO_OFFSET://温度传感器offset值
  95.         switch(chan->type)
  96.         {
  97.             case IIO_TEMP:
  98.                 *val =  ICM20608_TEMP_OFFSET;               
  99.                 break;
  100.             default:
  101.                 ret = -EINVAL;     
  102.         }
  103.         return ret;     
  104.     default:
  105.         break;
  106.     }
  107.     printk("icm20608c_read_raw\r\n");
  108.     return ret;
  109. }
复制代码
实现:
  1. #include <linux/spi/spi.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/ide.h>#include <linux/errno.h>#include <linux/platform_device.h>#include <linux/gpio.h>#include <linux/device.h>#include <asm/uaccess.h>#include <linux/cdev.h>#include <linux/regmap.h>#include <linux/iio/iio.h>#include <linux/iio/sysfs.h>#include <linux/iio/buffer.h>#include <linux/iio/trigger.h>#include <linux/iio/triggered_buffer.h>#include <linux/iio/trigger_consumer.h>#include <linux/unaligned/be_byteshift.h>#include "666.h"#define ICMC20608C_NAME  "icm20608c"#define ICM20608_TEMP_OFFSET             0#define ICM20608_TEMP_SCALE                     326800000struct icm20608c_dev {    struct spi_device *spi;    struct regmap *regmap;    struct regmap_config regmap_config;    struct mutex lock;};static const int gyro_scale_icm20608[] = {7629, 15258, 30517, 61035};static const int accel_scale_icm20608[] = {61035, 122070, 244140, 488281};#define ICM20608_CHAN(_type, _channel2, _index)                    \
  2.         {                                                             \
  3.                 .type = _type,                                        \
  4.                 .modified = 1,                                        \
  5.                 .channel2 = _channel2,                                \
  6.                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
  7.                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |              \
  8.                                       BIT(IIO_CHAN_INFO_CALIBBIAS),   \
  9.                 .scan_index = _index,                                 \
  10.                 .scan_type = {                                        \
  11.                                 .sign = 's',                          \
  12.                                 .realbits = 16,                       \
  13.                                 .storagebits = 16,                    \
  14.                                 .shift = 0,                           \
  15.                                 .endianness = IIO_BE,                 \
  16.                              },                                       \
  17.         }
  18. enum inv_icm20608_scan {
  19.         INV_ICM20608_SCAN_ACCL_X,
  20.         INV_ICM20608_SCAN_ACCL_Y,
  21.         INV_ICM20608_SCAN_ACCL_Z,
  22.         INV_ICM20608_SCAN_TEMP,
  23.         INV_ICM20608_SCAN_GYRO_X,
  24.         INV_ICM20608_SCAN_GYRO_Y,
  25.         INV_ICM20608_SCAN_GYRO_Z,
  26.         INV_ICM20608_SCAN_TIMESTAMP,
  27. };
  28. static const struct iio_chan_spec icm20608_channels[] = {
  29.     {
  30.         .type = IIO_TEMP,
  31.         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
  32.                             |BIT(IIO_CHAN_INFO_OFFSET)
  33.                             |BIT(IIO_CHAN_INFO_SCALE),
  34.         .scan_index = INV_ICM20608_SCAN_TEMP,
  35.         .scan_type = {
  36.                 .sign = 's',
  37.                 .realbits = 16,
  38.                 .storagebits = 16,
  39.                 .shift = 0,
  40.                 .endianness = IIO_BE,
  41.             },
  42.     },
  43.     ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_X,INV_ICM20608_SCAN_GYRO_X),
  44.     ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_Y,INV_ICM20608_SCAN_GYRO_Y),
  45.     ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_Z,INV_ICM20608_SCAN_GYRO_Z),
  46.     ICM20608_CHAN(IIO_ACCEL,IIO_MOD_X,INV_ICM20608_SCAN_ACCL_X),
  47.     ICM20608_CHAN(IIO_ACCEL,IIO_MOD_Y,INV_ICM20608_SCAN_ACCL_Y),
  48.     ICM20608_CHAN(IIO_ACCEL,IIO_MOD_Z,INV_ICM20608_SCAN_ACCL_Z),   
  49. };
  50. static  unsigned  char icm20608c_read_one_reg(struct icm20608c_dev *dev,u8 reg){    u8 ret;    unsigned int data;    ret = regmap_read(dev->regmap,reg,&data);    return (u8)data;}void icm20608c_write_one_reg66(struct icm20608c_dev *dev,u8 reg,unsigned char data){    regmap_write(dev->regmap,reg,data);}static int icm20608_sensor_show(struct icm20608c_dev *dev, int reg,int axis,int *val){        int ind, result;        __be16 d;        ind = (axis - IIO_MOD_X) * 2;        result = regmap_bulk_read(dev->regmap, reg + ind, (u8 *)&d, 2);        if (result)                return -EINVAL;        *val = (short)be16_to_cpup(&d);        return IIO_VAL_INT;}static int icm20608c_read_raw(struct iio_dev *indio_dev,                            struct iio_chan_spec const *chan,                            int *val, int *val2, long mask){      int ret = 0;    unsigned char regdata = 0;    struct  icm20608c_dev *dev = iio_priv(indio_dev);    switch(mask){    case IIO_CHAN_INFO_RAW://原始值        mutex_lock(&dev->lock);        switch(chan->type){            case IIO_TEMP:                ret = icm20608_sensor_show(dev, ICM20_TEMP_OUT_H, IIO_MOD_X, val);//IIO_MOD_X意思是就从这个ICM20_TEMP_OUT_H开始                break;            case IIO_ACCEL:                ret = icm20608_sensor_show(dev, ICM20_ACCEL_XOUT_H, chan->channel2, val);                break;            case IIO_ANGL_VEL:                ret = icm20608_sensor_show(dev, ICM20_GYRO_XOUT_H, chan->channel2, val);                break;            default:                ret = -EINVAL;                break;        }        mutex_unlock(&dev->lock);        return ret;    case IIO_CHAN_INFO_CALIBBIAS://校准值              switch(chan->type)        {   //对于加快度和陀螺仪的校准值,起首是校准值寄存器位置不同,其次是分为x,y,z            case IIO_ACCEL:                mutex_lock(&dev->lock);                ret = icm20608_sensor_show(dev, ICM20_XA_OFFSET_H, chan->channel2, val);                mutex_unlock(&dev->lock);                  break;            case IIO_ANGL_VEL:                mutex_lock(&dev->lock);                ret = icm20608_sensor_show(dev, ICM20_XG_OFFS_USRH, chan->channel2, val);                mutex_unlock(&dev->lock);                                 break;            default:                ret = -EINVAL;                break;         }         break;    case IIO_CHAN_INFO_SCALE://度量                switch (chan->type) {                case IIO_ANGL_VEL:                        mutex_lock(&dev->lock);                        regdata = (icm20608c_read_one_reg(dev, ICM20_GYRO_CONFIG) & 0X18) >> 3;                        *val  = 0;                        *val2 = gyro_scale_icm20608[regdata];                        mutex_unlock(&dev->lock);                        return IIO_VAL_INT_PLUS_MICRO;        /* 值为val+val2/1000000 */                case IIO_ACCEL:                        mutex_lock(&dev->lock);                        regdata = (icm20608c_read_one_reg(dev, ICM20_ACCEL_CONFIG) & 0X18) >> 3;                        *val = 0;                        *val2 = accel_scale_icm20608[regdata];;                        mutex_unlock(&dev->lock);                        return IIO_VAL_INT_PLUS_NANO;/* 值为val+val2/1000000000 */                case IIO_TEMP:                                                                *val = ICM20608_TEMP_SCALE/ 1000000;                        *val2 = ICM20608_TEMP_SCALE % 1000000;                        return IIO_VAL_INT_PLUS_MICRO;        /* 值为val+val2/1000000 */                default:                        return -EINVAL;                }                return ret;    case IIO_CHAN_INFO_OFFSET://温度传感器offset值        switch(chan->type)        {            case IIO_TEMP:                *val =  ICM20608_TEMP_OFFSET;                               break;            default:                ret = -EINVAL;             }        return ret;         default:        break;    }    printk("icm20608c_read_raw\r\n");    return ret;}static int icm20608c_write_raw(struct iio_dev *indio_dev,                             struct iio_chan_spec const *chan,                             int val, int val2, long mask){    int ret = 0;    printk("icm20608c_write_raw\r\n");    return ret;}static int icm20608c_write_raw_get_fmt(struct iio_dev *indio_dev,                               struct iio_chan_spec const *chan,                               long mask){    int ret = 0;    return ret;}/*文件操纵函数*/static struct iio_info icm20608c_info = {    .read_raw = icm20608c_read_raw,    .write_raw = icm20608c_write_raw,    .write_raw_get_fmt = &icm20608c_write_raw_get_fmt,};/*寄存器初始化*/static void icm20608c_reg_init( struct icm20608c_dev *dev){    u8 value = 0,ret = 0;    icm20608c_write_one_reg66(dev, ICM20_PWR_MGMT_1,0x80);    mdelay(50);    icm20608c_write_one_reg66(dev, ICM20_PWR_MGMT_1,0x01);    mdelay(50);    ret = icm20608c_read_one_reg(dev, ICM20_PWR_MGMT_1);    printk("ICM20_PWR_MGMT_1 = %X\r\n", ret);    value = icm20608c_read_one_reg(dev, ICM20_WHO_AM_I);    printk("ICM20608 ID = %X\r\n", value);    icm20608c_write_one_reg66(dev, ICM20_SMPLRT_DIV, 0x00);     icm20608c_write_one_reg66(dev, ICM20_GYRO_CONFIG, 0x18);     icm20608c_write_one_reg66(dev, ICM20_ACCEL_CONFIG, 0x18);     icm20608c_write_one_reg66(dev, ICM20_CONFIG, 0x04);     icm20608c_write_one_reg66(dev, ICM20_ACCEL_CONFIG2, 0x04);    icm20608c_write_one_reg66(dev, ICM20_PWR_MGMT_2, 0x00);     icm20608c_write_one_reg66(dev, ICM20_LP_MODE_CFG, 0x00);     icm20608c_write_one_reg66(dev, ICM20_FIFO_EN, 0x00); };const struct of_device_id of_icm20608c_table[]={    {.compatible = "wyt,icm20608"},    {}};const struct spi_device_id icm20608c_table[]={    {"icm20608c",0},    { }};/*完成设备号注册 节点注册 spi设备初始化*/static int icm20608c_probe(struct spi_device *spi){    int ret = 0;    struct icm20608c_dev *dev;    struct iio_dev *indio_dev;    /*1.iio_dev申请内存*/    indio_dev = devm_iio_device_alloc(&spi->dev,sizeof(*dev));    if(!indio_dev)    {        return ret;    }    /*2.获取icm20608c_dev布局体地址*/    dev = iio_priv(indio_dev);    dev->spi = spi;    spi_set_drvdata(spi,indio_dev);    mutex_init(&dev->lock);    /*3.初始化iio_dev成员变量*/    indio_dev->dev.parent = &spi->dev;    indio_dev->info = &icm20608c_info;    indio_dev->name = ICMC20608C_NAME;    indio_dev->modes = INDIO_DIRECT_MODE;    indio_dev->channels = icm20608_channels;    indio_dev->num_channels = ARRAY_SIZE(icm20608_channels);    /*4.注册iio_dev*/    ret = iio_device_register(indio_dev);    if(ret<0)    {        return ret;    }    /*5.初始化regmap_config而且注册*/    dev->regmap_config.reg_bits = 8;//寄存器巨细为8bit    dev->regmap_config.val_bits = 8;//寄存器数据值8bit    //dev.regmap_config.read_flag_mask = 0x80;//读掩码    dev->regmap = regmap_init_spi(spi,&dev->regmap_config);    if(IS_ERR(dev->regmap))    {        goto regmap_error;        return PTR_ERR(dev->regmap);    }    /*6.初始化SPI设备*/    spi->mode = SPI_MODE_0;//时钟模式    spi_setup(spi);    /*7.寄存器初始化内容*/    icm20608c_reg_init(dev);    printk("probe success \r\n");    return 0;regmap_error:    iio_device_unregister(indio_dev);        return ret;}static int icm20608c_remove(struct spi_device *spi){    /*这段代码,为了获取icm20608c_dev的地址和iio_dev地址,以便进行解除*/    struct icm20608c_dev *dev;    struct iio_dev *indio_dev;    indio_dev = spi_get_drvdata(spi);    dev = iio_priv(indio_dev);    /*删除regmap,注销iio_dev*/    regmap_exit(dev->regmap);    iio_device_unregister(indio_dev);        printk("remove success \r\n");    return 0;}static struct spi_driver icm20608c_driver={    .probe = icm20608c_probe,    .remove = icm20608c_remove,    .driver = {        .name = "icm20608c_spi_driver",        .of_match_table = of_icm20608c_table,    },    .id_table = icm20608c_table,};static int __init  icm20608c_init(void){    return spi_register_driver(&icm20608c_driver);}static void __exit icm20608c_exit(void){    spi_unregister_driver(&icm20608c_driver);}/*驱动入口*/module_init(icm20608c_init);module_exit(icm20608c_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("WYT");
复制代码
over

驱动部门总体上都结束了,基本上是字符设备的驱动编写,块设备写一个RAM的,网络设备简单看了看框架,照旧要干点项目,背面从100节视频今后,就开始不想学了,背面的章节都是搭建一些情况和软件,也不消动手敲了,这两天把这个集会整完,把操纵体系学完。五月开始,找点项目干干,感觉照旧没学到什么东西啊!!!!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

饭宝

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表