I2C硬件介绍

I2C接口

I2C驱动架构

I2C驱动分为三部分(驱动架构路径drivers/i2c,结构体定义路径include/linux/i2c.h):
image.png

  • I2C核心:总线驱动和设备驱动的注册注销,I2C通信
  • I2C总线驱动:适配I2C硬件。主要包括I2C适配器i2c_adapter,通信数据结构i2c_algorithm和内部产生通信信号的函数
    • i2c_adapter对应于物理上的一个适配器i2c_algorithm对应一套通信方法。适配器需要i2c_algorithm里的函数指针控制适配器产生特定的访问周期。
    • master_xfer函数用于产生I2C访问周期需要的信号,以i2c_msg表示

image.png

  • I2C设备驱动:也叫客户驱动,负责提供用户程序需要的设备操作接口。主要包含数据结构i2c_driveri2c_client
    • i2c_driver对应于一套驱动方法,其主要成员函数是probe、 remove、 suspend、 resume等。成员struct i2c_device_id是该驱动所支持的I2C设备的ID表,是一对多的关系,可以通过i2c_match_id找到对应设备
    • i2c_client对应于真实的物理设备, 每个I2C设备都需要一个i2c_client来描述。一个i2c_adpater也可以被多个i2c_client依附,i2c_client包含它所依附的i2c_adpater指针

image.png

I2C core

核心层提供了一组接口函数,用于联系总线和设备层,一般不需要修改,只需要知道何时调用如下函数:

  1. 增加删除i2c_adapter

    1. int i2c_add_adapter(struct i2c_adapter *adapter);
    2. void i2c_del_driver(struct i2c_driver *driver);
  2. 增加删除i2c_driver ```c extern int i2c_register_driver(struct module owner, struct i2c_driver driver); extern void i2c_del_driver(struct i2c_driver *driver);

/ use a define to avoid include chaining to get THIS_MODULE /

define i2c_add_driver(driver) \

  1. i2c_register_driver(THIS_MODULE, driver)
  1. 3. 数据发送和接收函数
  2. ```c
  3. int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
  4. int i2c_master_recv(const struct i2c_client *client, char *buf, int count);
  5. int i2c_master_send(const struct i2c_client *client, const char *buf, int count);

I2C总线驱动

i2c总线适配器本身也是连接在platform总线上,所以总线驱动需要注册到platform_driver上,然后再通过I2C本身的架构与设备驱动通信。为特定的I2C适配器实现通信方法, 主要是实现i2c_algorithmfunctionality函数和master_xfer函数。

如下为I2C总线驱动基本的模板:

  1. static int xxx_i2c_probe(struct platform_device *pdev)
  2. {
  3. struct i2c_adapter *adap;
  4. //初始化I2C adapter所使用的硬件资源,如IO地址,中断号,时钟等
  5. xxx_adpater_hw_init();
  6. adap->dev.parent = &pdev->dev;
  7. adap->dev.of_node = pdev->dev.of_node;
  8. adap->algo = xxx_i2c_algo //指定实现通信方法的i2c_algorithm
  9. //添加adapter到I2C驱动核心中
  10. rc = i2c_add_adapter(adap);
  11. ...
  12. }
  13. static int xxx_i2c_remove(struct platform_device *pdev)
  14. {
  15. //释放硬件资源
  16. xxx_adpater_hw_free();
  17. //从核心删除adapter
  18. i2c_del_adapter(&dev->adapter);
  19. return 0;
  20. }
  21. static const struct of_device_id xxx_i2c_of_match[] = {
  22. {
  23. .compatible = "vendor,xxx-i2c",
  24. },
  25. {},
  26. };
  27. MODULE_DEVICE_TABLE(of, xxx_i2c_of_match);
  28. static struct platform_driver xxx_i2c_driver = {
  29. .driver = {
  30. .name = "xxx-i2c",
  31. .owner = THIS_MODULE,
  32. .of_match_table = xxx_i2c_of_match,
  33. },
  34. .probe = xxx_i2c_probe,
  35. .remove = xxx_i2c_remove,
  36. };
  37. module_platform_driver(xxx_i2c_driver);//注册到platform总线

I2C设备驱动

设备驱动要使用i2c_driver和i2c_client数据结构并填充i2c_driver中的成员函数。i2c_client一般被包含在设备的
私有信息结构体yyy_data中
, 而i2c_driver则适合被定义为全局变量并初始化。

  1. static struct i2c_driver yyy_driver = {
  2. .driver = {
  3. .name = "yyy",
  4. },
  5. .probe = yyy_probe,
  6. .remove = yyy_remove,
  7. .id_table = yyy_id,
  8. };
  9. static int __init yyy_init(void)
  10. {
  11. return i2c_add_driver(&yyy_driver);//注册到核心
  12. }
  13. module_initcall(yyy_init);
  14. static void __exit yyy_exit(void)
  15. {
  16. i2c_del_driver(&yyy_driver);//从核心删除
  17. }
  18. 11module_exit(yyy_exit);