一,regmap
对于spi和i2c,读写寄存器的框架不同,但设备本质一样,因此就有了regmap模型来对其进行简化,提供同一的接口函数来访问寄存器,而且使用很方便,使用时间,调用regmap的读写寄存器函数即可。
整体框架:
- struct regmap *regmap;
- struct regmap_config regmap_config;
- /*对于spi的设备,之前的读写还需要对t->tx_buf,t->rx_buf等进行操作,再t放到message
- 中,最后再利用spi_sync发送,比较麻烦*/
- 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);//调用regmap的读函数
- return (u8)data;
- }
-
- void icm20608c_write_one_reg66(struct icm20608c_dev *dev,u8 reg,unsigned char data)
- {
- regmap_write(dev->regmap,reg,data);//调用regmap的写函数
- }
-
- static int icm20608c_probe(struct spi_device *spi)
- {
- int ret = 0;
- icm20608c.regmap_config.reg_bits = 8;//寄存器大小为8bit
- icm20608c.regmap_config.val_bits = 8;//寄存器数据值8bit
- //icm20608c.regmap_config.read_flag_mask = 0x80;//读掩码
- icm20608c.regmap = regmap_init_spi(spi,&icm20608c.regmap_config);//关键就是这个 函 数,将regmap_config和spi设备关联起来,创建出regmap
- if(IS_ERR(icm20608c.regmap))
- {
- return PTR_ERR(icm20608c.regmap);
- }
- ........
- }
-
- static int icm20608c_remove(struct spi_device *spi)
- {
- .........
- regmap_exit(icm20608c.regmap);
- return 0;
- }
复制代码 二,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背面的为驱动私有数据预留的内存地区的指针。
- struct icm20608c_dev {
- struct spi_device *spi;
- struct regmap *regmap;
- struct regmap_config regmap_config;
- struct mutex lock;
- };
- /*完成设备号注册 节点注册 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;
- }
复制代码 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时间,在最前面。


在文件中显示顺序:

- #define ICM20608_CHAN(_type, _channel2, _index) \
- { \
- .type = _type, \
- .modified = 1, \
- .channel2 = _channel2, \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_CALIBBIAS), \
- .scan_index = _index, \
- .scan_type = { \
- .sign = 's', \
- .realbits = 16, \
- .storagebits = 16, \
- .shift = 0, \
- .endianness = IIO_BE, \
- }, \
- }
- enum inv_icm20608_scan {
- INV_ICM20608_SCAN_ACCL_X,
- INV_ICM20608_SCAN_ACCL_Y,
- INV_ICM20608_SCAN_ACCL_Z,
- INV_ICM20608_SCAN_TEMP,
- INV_ICM20608_SCAN_GYRO_X,
- INV_ICM20608_SCAN_GYRO_Y,
- INV_ICM20608_SCAN_GYRO_Z,
- INV_ICM20608_SCAN_TIMESTAMP,
- };
- static const struct iio_chan_spec icm20608_channels[] = {
- {
- .type = IIO_TEMP,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
- |BIT(IIO_CHAN_INFO_OFFSET)
- |BIT(IIO_CHAN_INFO_SCALE),
- .scan_index = INV_ICM20608_SCAN_TEMP,
- .scan_type = {
- .sign = 's',
- .realbits = 16,
- .storagebits = 16,
- .shift = 0,
- .endianness = IIO_BE,
- },
- },
- ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_X,INV_ICM20608_SCAN_GYRO_X),
- ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_Y,INV_ICM20608_SCAN_GYRO_Y),
- ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_Z,INV_ICM20608_SCAN_GYRO_Z),
- ICM20608_CHAN(IIO_ACCEL,IIO_MOD_X,INV_ICM20608_SCAN_ACCL_X),
- ICM20608_CHAN(IIO_ACCEL,IIO_MOD_Y,INV_ICM20608_SCAN_ACCL_Y),
- ICM20608_CHAN(IIO_ACCEL,IIO_MOD_Z,INV_ICM20608_SCAN_ACCL_Z),
- };
复制代码 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(加快度量程)。
- static const int gyro_scale_icm20608[] = {7629, 15258, 30517, 61035};
- static const int accel_scale_icm20608[] = {61035, 122070, 244140, 488281};
- 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);
- }
- /*计算出要读寄存器的位置,根据带入的axis计算偏移地址+reg*/
- 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;
- }
复制代码 实现:
- #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) \
- { \
- .type = _type, \
- .modified = 1, \
- .channel2 = _channel2, \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_CALIBBIAS), \
- .scan_index = _index, \
- .scan_type = { \
- .sign = 's', \
- .realbits = 16, \
- .storagebits = 16, \
- .shift = 0, \
- .endianness = IIO_BE, \
- }, \
- }
- enum inv_icm20608_scan {
- INV_ICM20608_SCAN_ACCL_X,
- INV_ICM20608_SCAN_ACCL_Y,
- INV_ICM20608_SCAN_ACCL_Z,
- INV_ICM20608_SCAN_TEMP,
- INV_ICM20608_SCAN_GYRO_X,
- INV_ICM20608_SCAN_GYRO_Y,
- INV_ICM20608_SCAN_GYRO_Z,
- INV_ICM20608_SCAN_TIMESTAMP,
- };
- static const struct iio_chan_spec icm20608_channels[] = {
- {
- .type = IIO_TEMP,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
- |BIT(IIO_CHAN_INFO_OFFSET)
- |BIT(IIO_CHAN_INFO_SCALE),
- .scan_index = INV_ICM20608_SCAN_TEMP,
- .scan_type = {
- .sign = 's',
- .realbits = 16,
- .storagebits = 16,
- .shift = 0,
- .endianness = IIO_BE,
- },
- },
- ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_X,INV_ICM20608_SCAN_GYRO_X),
- ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_Y,INV_ICM20608_SCAN_GYRO_Y),
- ICM20608_CHAN(IIO_ANGL_VEL,IIO_MOD_Z,INV_ICM20608_SCAN_GYRO_Z),
- ICM20608_CHAN(IIO_ACCEL,IIO_MOD_X,INV_ICM20608_SCAN_ACCL_X),
- ICM20608_CHAN(IIO_ACCEL,IIO_MOD_Y,INV_ICM20608_SCAN_ACCL_Y),
- ICM20608_CHAN(IIO_ACCEL,IIO_MOD_Z,INV_ICM20608_SCAN_ACCL_Z),
- };
- 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企服之家,中国第一个企服评测及商务社交产业平台。 |