IT评测·应用市场-qidao123.com技术社区
标题:
Linux驱动开辟-①regmap②IIO子体系
[打印本页]
作者:
饭宝
时间:
2025-4-18 07:19
标题:
Linux驱动开辟-①regmap②IIO子体系
一,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企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4