linux中的IIC设备驱动

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文件中:
  1. //In machine init code:
  2. 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,有的平台有多路)
  1. #define I2C_CAM_SLAVE_ADDRESS        0x42 //device address

  2. //自己构建的平台数据结构
  3. struct i2c_slave_platform_data cam_pdata = {
  4.     //your code
  5. };

  6. //i2c_board_info
  7. static struct i2c_board_info __initdata cam_i2c_board_info[] = {
  8.     {
  9.         I2C_BOARD_INFO("i2c_dev_name", (I2C_CAM_SLAVE_ADDRESS >> 1)),
  10.         .platform_data = (void *)&cam_pdata,
  11.         .irq = IRQ_CAM,
  12.     },    
  13.     {
  14.         //other i2c device code
  15.     },
  16. };
这样就完成了IIC设备在这个平台的IIC总线上的注册

在驱动文件中:
  1. //in init code:
  2. i2c_add_driver(&i2c_driver_cam);

  3. struct i2c_driver i2c_driver_cam = {
  4.     .driver = {
  5.          .name = "i2c_dev_name",
  6.          },
  7.     .id_table = cam_i2c_id_table,
  8.     .probe = cam_i2c_probe,
  9.     .remove = cam_i2c_remove,
  10.     .command = cam_i2c_command,
  11. };

  12. struct i2c_device_id cam_i2c_id_table[] = {
  13.     {"i2c_dev_name", 0},
  14.     {}
  15. };
“i2c_dev_name”是一个字符串,代表IIC的设备名,要保持一致才能成功注册

定义一个全局变量,用于获得i2c_client
  1. static struct i2c_client *this_client;

  2. //probe
  3. static int cam_i2c_probe(struct i2c_client *client, const struct i2c_device_id *dev_id)
  4. {
  5.     struct cam_data *ddata;

  6.     if(dev_id)
  7.     {
  8.         printk("cam_i2c_probe, dev_id.name (%s) \r\n",dev_id->name);        
  9.     }

  10.     //检查IIC设备的功能
  11.     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  12.         err = -ENODEV;
  13.         goto exit_check_functionality_failed;
  14.     }

  15.     ddata = kzalloc(sizeof(struct cam_data), GFP_KERNEL);
  16.     if (!akm) {
  17.         err = -ENOMEM;
  18.         goto exit_alloc_data_failed;
  19.     }

  20.     i2c_set_clientdata(client, ddata);
  21.     this_client = client; //将client赋给全局变量

  22.     //other init code

  23.     return 0;
  24. }

  25. //remove
  26. static int cam_i2c_remove(struct i2c_client *client)
  27. {
  28.     struct cam_data *ddata = i2c_get_clientdata(client);

  29.     //remove code    

  30.     return 0;
  31. }
i2c_command函数一般用不到,不用实现

IIC的读写函数:
  1. //IIC write
  2. static int CamI2C_WriteData(char *txData, int length)
  3. {
  4.     struct i2c_msg msg[] = {
  5.         {
  6.          .addr = this_client->addr,
  7.          .flags = 0,
  8.          .len = length,
  9.          .buf = txData,
  10.          },
  11.     };

  12.     if (i2c_transfer(this_client->adapter, msg, 1) < 0) {
  13.         printk(KERN_ERR "CamI2C_WriteData: transfer error\n");
  14.         return -EIO;
  15.     } else
  16.         return 0;
  17. }    

  18. //IIC Read
  19. static int CAMI2C_ReadData(char *rxData, int length)
  20. {
  21.     struct i2c_msg msgs[] = {
  22.         {
  23.          .addr = this_client->addr,
  24.          .flags = 0,
  25.          .len = 1,
  26.          .buf = rxData,
  27.         },
  28.         {
  29.          .addr = this_client->addr,
  30.          .flags = I2C_M_RD,
  31.          .len = length,
  32.          .buf = rxData,
  33.         },
  34.     };


  35.     if (i2c_transfer(this_client->adapter, msgs, 2) < 0) {
  36.         printk(KERN_ERR "CAMI2C_RxData: transfer error\n");
  37.         return -EIO;
  38.     } else
  39.         return 0;
  40. }

如果IIC设备支持smbus,可以使用smbus方式:
  1. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
  2.     printk(KERN_ERR "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
  3.     return -EIO;
  4. }

  5. //smbus read
  6. static int Read_Data(struct i2c_client *client, const unsigned char reg)
  7. {
  8.     unsigned char ret = i2c_smbus_read_byte_data(client, reg);
  9.     return ret;
  10. }

  11. //smbus write
  12. static int Write_Data(struct i2c_client *client, const unsigned char reg, const unsigned char data)
  13. {
  14.     return i2c_smbus_write_bype_data(client, reg, data);
  15. }

如果是16位数据,同样有i2c_smbus_read_word_data和i2c_smbus_read_word_data

在sensor设备驱动中,IIC只是做为一条总线传输数据,驱动的主体部分主要还是由input子层来完成的,在android中这是一种很常见的驱动模式
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Linux硬件I2C驱动代码的示例: ```c #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> static struct i2c_client *my_i2c_client; static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { // 初始化I2C设备 my_i2c_client = client; // 进行设备初始化和配置 return 0; } static int my_i2c_remove(struct i2c_client *client) { // 进行设备的移除操作 return 0; } static const struct i2c_device_id my_i2c_id[] = { { "my_i2c_device", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, my_i2c_id); static struct i2c_driver my_i2c_driver = { .driver = { .name = "my_i2c_driver", .owner = THIS_MODULE, }, .probe = my_i2c_probe, .remove = my_i2c_remove, .id_table = my_i2c_id, }; static int __init my_i2c_init(void) { // 注册I2C驱动程序 return i2c_add_driver(&my_i2c_driver); } static void __exit my_i2c_exit(void) { // 移除I2C驱动程序 i2c_del_driver(&my_i2c_driver); } module_init(my_i2c_init); module_exit(my_i2c_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("My I2C Driver"); ``` 上述代码是一个简单的Linux硬件I2C驱动程序的例程。在`my_i2c_probe`函数,你可以进行设备的初始化和配置操作。在`my_i2c_remove`函数,你可以进行设备的移除操作。你还需要根据实际需求在代码进行适当的修改。 在模块初始化函数`my_i2c_init`,我们使用`i2c_add_driver`函数来注册I2C驱动程序。在模块退出函数`my_i2c_exit`,我们使用`i2c_del_driver`函数来移除I2C驱动程序。 请注意,以上代码仅为示例,你需要根据实际硬件和需求进行相应的修改和配置。确保你已经正确配置了内核选项和设备树以支持硬件I2C,并将驱动程序编译为内核模块或静态链接到内核
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值