linux中的IIC驱动很庞大,驱动中随处可见
智能手机和平板电脑上用的sensor几乎都是IIC设备,比如:camera,电容触摸屏,重力/加速度sensor,环境光sensor,指南针sensor
IIC驱动主要分为Master和Slave,Master就是主机控制器,像S3C2440内部的IIC控制器就是一个Master
Slave就是IIC从机设备,它要被挂接到Master上才能工作
Master驱动这里就不说了,每种带有IIC控制器的处理器都有相应的驱动,假设我的内核已经支持了Master的IIC驱动
最近在android下调camera驱动,下面整理一下IIC设备驱动的写法,编写camera驱动的IIC部分,IIC设备驱动的写法很灵活,这里只介绍最简单基本的框架
首先在每个驱动文件中都要包含IIC的头文件
#include
重要的结构体有:
i2c_board_info i2c_client i2c_msg
主要的函数:
i2c_register_board_info
i2c_add_driver
i2c_check_functionality
i2c_transfer
在bsp文件中:
- //In machine init code:
- i2c_register_board_info(i2c_bus_num, cam_i2c_board_info, ARRAY_SIZE(cam_i2c_board_info));
i2c_bus_num是指定设备挂接在哪个IIC总线上,用0,1,2....数字表示(有的平台只有一路IIC,有的平台有多路)
- #define I2C_CAM_SLAVE_ADDRESS 0x42 //device address
- //自己构建的平台数据结构
- struct i2c_slave_platform_data cam_pdata = {
- //your code
- };
- //i2c_board_info
- static struct i2c_board_info __initdata cam_i2c_board_info[] = {
- {
- I2C_BOARD_INFO("i2c_dev_name", (I2C_CAM_SLAVE_ADDRESS >> 1)),
- .platform_data = (void *)&cam_pdata,
- .irq = IRQ_CAM,
- },
- {
- //other i2c device code
- },
- };
这样就完成了IIC设备在这个平台的IIC总线上的注册
在驱动文件中:
- //in init code:
- i2c_add_driver(&i2c_driver_cam);
- struct i2c_driver i2c_driver_cam = {
- .driver = {
- .name = "i2c_dev_name",
- },
- .id_table = cam_i2c_id_table,
- .probe = cam_i2c_probe,
- .remove = cam_i2c_remove,
- .command = cam_i2c_command,
- };
- struct i2c_device_id cam_i2c_id_table[] = {
- {"i2c_dev_name", 0},
- {}
- };
“i2c_dev_name”是一个字符串,代表IIC的设备名,要保持一致才能成功注册
定义一个全局变量,用于获得i2c_client
- static struct i2c_client *this_client;
- //probe
- static int cam_i2c_probe(struct i2c_client *client, const struct i2c_device_id *dev_id)
- {
- struct cam_data *ddata;
- if(dev_id)
- {
- printk("cam_i2c_probe, dev_id.name (%s) \r\n",dev_id->name);
- }
- //检查IIC设备的功能
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- err = -ENODEV;
- goto exit_check_functionality_failed;
- }
- ddata = kzalloc(sizeof(struct cam_data), GFP_KERNEL);
- if (!akm) {
- err = -ENOMEM;
- goto exit_alloc_data_failed;
- }
- i2c_set_clientdata(client, ddata);
- this_client = client; //将client赋给全局变量
- //other init code
- return 0;
- }
- //remove
- static int cam_i2c_remove(struct i2c_client *client)
- {
- struct cam_data *ddata = i2c_get_clientdata(client);
- //remove code
- return 0;
- }
i2c_command函数一般用不到,不用实现
IIC的读写函数:
- //IIC write
- static int CamI2C_WriteData(char *txData, int length)
- {
- struct i2c_msg msg[] = {
- {
- .addr = this_client->addr,
- .flags = 0,
- .len = length,
- .buf = txData,
- },
- };
- if (i2c_transfer(this_client->adapter, msg, 1) < 0) {
- printk(KERN_ERR "CamI2C_WriteData: transfer error\n");
- return -EIO;
- } else
- return 0;
- }
- //IIC Read
- static int CAMI2C_ReadData(char *rxData, int length)
- {
- struct i2c_msg msgs[] = {
- {
- .addr = this_client->addr,
- .flags = 0,
- .len = 1,
- .buf = rxData,
- },
- {
- .addr = this_client->addr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = rxData,
- },
- };
- if (i2c_transfer(this_client->adapter, msgs, 2) < 0) {
- printk(KERN_ERR "CAMI2C_RxData: transfer error\n");
- return -EIO;
- } else
- return 0;
- }
如果IIC设备支持smbus,可以使用smbus方式:
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- printk(KERN_ERR "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
- return -EIO;
- }
- //smbus read
- static int Read_Data(struct i2c_client *client, const unsigned char reg)
- {
- unsigned char ret = i2c_smbus_read_byte_data(client, reg);
- return ret;
- }
- //smbus write
- static int Write_Data(struct i2c_client *client, const unsigned char reg, const unsigned char data)
- {
- return i2c_smbus_write_bype_data(client, reg, data);
- }
如果是16位数据,同样有i2c_smbus_read_word_data和i2c_smbus_read_word_data
在sensor设备驱动中,IIC只是做为一条总线传输数据,驱动的主体部分主要还是由input子层来完成的,在android中这是一种很常见的驱动模式
阅读(1191) | 评论(0) | 转发(0) |