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 <linux/i2c.h>
重要的结构体有:
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中这是一种很常见的驱动模式