Chinaunix首页 | 论坛 | 博客
  • 博客访问: 41888
  • 博文数量: 42
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 32
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-30 10:34
文章分类
文章存档

2014年(42)

我的朋友

分类: LINUX

2014-11-19 19:07:47

原文地址:linux中的IIC设备驱动 作者:小超hide

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文件中:
  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中这是一种很常见的驱动模式
阅读(244) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~