Linux下I2C驱动架构
如上图所示,每条I2C总线会对应一个adapter,而每条I2C总线上则可以有多个client,在linux kernel中,通过I2C core层将I2C client与I2C adapter关联起来,Linux 中I2C驱动代码位于drivers/i2c目录。 Linux中I2C可以分为三个层次,分别为I2C core层、I2C adapter driver层、I2C device driver层。
I2C core层
I2C core是用于维护Linux的I2C核心部分,提供了核心的数据结构,I2C适配器驱动和设备驱动的注册、注销管理等API,同时还提供了I2C总线读写访问的一般接口(具体的实现在与I2C控制器相关的I2C adapter中实现)。 该层为硬件平台无关层,向下屏蔽了物理总线适配器的差异,定义了统一的访问策略和接口;向上则提供了统一的接口,以便I2C设备驱动可以通过总线适配器进行数据收发。 Linux中,I2C core层的代码位于driver/i2c/i2c-core.c。由于该层是平台无关层,本文将不再叙述,有兴趣可以查阅相关资料。
I2C adapter driver层 I2C adapterdriver层即I2C适配器驱动层,每种处理器平台都有自己的适配器驱动,属于平台移植相关层。它的职责是为系统中每条I2C总线实现相应的读写方法。但是适配器驱动本身并不会进行任何的通讯,而是等待设备驱动调用其函数。 在系统开机时,I2C适配器驱动被首先装载。一个适配器驱动用于支持一条特定的I2C总线的读写。一个适配器驱动通常需要两个模块,一个structi2c_adapter和一个struct i2c_algorithm来描述。
i2c adapter 构造一个对I2C core层接口的数据结构,并通过相应的接口函数向I2C core注册一个适配器。i2c_algorithm主要实现对I2C总线访问的算法,master_xfer和smbus_xfer即I2C adapter底层对I2C总线读写方法的实现,相关的数据结构如下:
01. /*
02. * The following structs are for those who like to implement new busdrivers:
03. * i2c_algorithm is the interface to a class of hardware solutions which can
04. * be addressed using the same bus algorithms - i.e. bit-banging or thePCF8584
05. * to name two of the most common.
06. */
07.struct i2c_algorithm {
08. /* If an adapter algorithm can't do I2C-level access, setmaster_xfer
09. to NULL. If an adapter algorithm can doSMBus access, set
10. smbus_xfer. If set to NULL, the SMBusprotocol is simulated
11. using common I2C messages */
12. /* master_xfer should return the number of messagessuccessfully
13. processed, or a negative value on error*/
14. int (*master_xfer)(struct i2c_adapter *adap, structi2c_msg *msgs,
15. int num);
16. int (*smbus_xfer) (struct i2c_adapter *adap, u16addr,
17. unsigned short flags, char read_write,
18. u8 command, int size, union i2c_smbus_data *data);
19. /* To determine what the adapter supports */
20. u32 (*functionality) (struct i2c_adapter *);
21.};
主要就是master_xfer方法,其和具体的总线控制器相关,不同的CPU在实现上会有差异。
01./*
02. * i2c_adapter is the structure used to identify a physical i2c bus along
03. * with the access algorithms necessary to access it.
04. */
05.struct i2c_adapter {
06. struct module *owner;
07. unsigned int id;
08. unsigned int class; /* classes to allow probing for */
09. const struct i2c_algorithm *algo; /* the algorithm toaccess the bus */
10. void *algo_data;
11. /* data fields that are valid for all devices */
12. struct rt_mutex bus_lock;
13. inttimeout; /*in jiffies */
14. int retries;
15. struct device dev; /* theadapter device */
16. int nr;
17. char name[48];
18. struct completion dev_released;
19. struct list_head userspace_clients;
20.};
Algo是和底层硬件的接口,标识了具体的物理总线传输的实现。
Userspace_clients为使用该总线的client链表。
Nr为该适配器也就是某条I2C总线占据的全局编号。
bus_lock总线的互斥锁,防止总线冲突。
Linux中,I2C adapter driver层的代码位于drivers/i2c/busses目录。
I2C device driver层
I2C device driver层为用户接口层,其为用户提供了通过I2C总线访问具体设备的接口。
I2C的device driver层可以用两个模块来描述,struct i2c_driver和struct i2c_client。
i2c_client和i2c_driver分别构造对I2C core层接口的数据结构,并且通过相关的接口函数向 I2C Core注册I2C设备驱动。相关的数据结构如下:
01./**
02. * struct i2c_driver - represent an I2C device driver
03. * @class: What kind of i2c device we instantiate (for detect)
04. * @attach_adapter: Callback for bus addition (for legacy drivers)
05. * @detach_adapter: Callback for bus removal (for legacy drivers)
06. * @probe: Callback for device binding
07. * @remove: Callback for device unbinding
08. * @shutdown: Callback for device shutdown
09. * @suspend: Callback for device suspend
10. * @resume: Callback for device resume
11. * @command: Callback for bus-wide signaling (optional)
12. * @driver: Device driver model driver
13. * @id_table: List of I2C devices supported by this driver
14. * @detect: Callback for device detection
15. * @address_list: The I2C addresses to probe (for detect)
16. * @clients: List of detected clients we created (for i2c-core use only)
17. *
18. * The driver.owner field should be set to the module owner of this driver.
19. * The driver.name field should be set to the name of this driver.
20. *
21. * For automatic device detection, both @detect and @address_data must
22. * be defined. @class should also be set, otherwise only devices forced
23. * with module parameters will be created. The detect function must
24. * fill at least the name field of the i2c_board_info structure it is
25. * handed upon successful detection, and possibly also the flags field.
26. *
27. * If @detect is missing, the driver will still work fine for enumerated
28. * devices. Detected devices simply won't be supported. This is expected
29. * for the many I2C/SMBus devices which can't be detected reliably, and
30. * the ones which can always be enumerated in practice.
31. *
32. * The i2c_client structure which is handed to the @detect callback is
33. * not a real i2c_client. It is initialized just enough so that you can
34. * call i2c_smbus_read_byte_data and friends on it. Don't do anything
35. * else with it. In particular, calling dev_dbg and friends on it is
36. * not allowed.
37. */
38.struct i2c_driver {
39. unsigned int class;
40. /* Notifies the driver that a new bus has appeared or isabout to be
41. * removed. You should avoid using this if you can,it will probably
42. * be removed in a near future.
43. */
44. int (*attach_adapter)(struct i2c_adapter *);
45. int (*detach_adapter)(struct i2c_adapter *);
46. /* Standard driver model interfaces */
47. int (*probe)(struct i2c_client *, const structi2c_device_id *);
48. int (*remove)(struct i2c_client *);
49. /* driver model interfaces that don't relate toenumeration */
50. void (*shutdown)(struct i2c_client *);
51. int (*suspend)(struct i2c_client *, pm_message_tmesg);
52. int (*resume)(struct i2c_client *);
53. /* Alert callback, for example for the SMBus alertprotocol.
54. * The format and meaning of the data value dependson the protocol.
55. * For the SMBus alert protocol, there is a singlebit of data passed
56. * as the alert response's low bit ("eventflag").
57. */
58. void (*alert)(struct i2c_client *, unsigned intdata);
59. /* a ioctl like command that can be used to performspecific functions
60. * with the device.
61. */
62. int (*command)(struct i2c_client *client, unsigned intcmd, void *arg);
63. struct device_driver driver;
64. const struct i2c_device_id *id_table;
65. /* Device detection callback for automatic devicecreation */
66. int (*detect)(struct i2c_client *, struct i2c_board_info*);
67. const unsigned short *address_list;
68. struct list_head clients;
69.};
Driver是为device服务的,i2c_driver注册时会扫描i2c bus上的设备,进行驱动和设备的绑定。主要有两种接口attach_adapter和probe,二者分别针对旧的和新式的驱动。
通常来说i2c_client对应着I2C总线上某个特定的slave或者是user space的某个用户对应,而此时的slave可以动态变化。
Linux中,I2C device driver层的代码位于drivers/i2c/chips目录。
dm6467I2C adapter驱动
在Linux内核中,I2C adapter驱动位于drivers/i2c/busses目录下,DM6467 的I2C adapter驱动程序为drivers/i2c/busses/i2c-davinci.c
I2C adapter驱动,本质上就是实现了具体的总线传输算法并向核心层注册适配器。该驱动的注册采用Platform驱动和设备机制。
I2C adapter的Platform device
DM6467中Platform device的注册的代码位于内核的arch/arm/mach-davinci/devices.c
01.在arch/arm/mach-davinci/devices.c中。Platmform device 定义如下:
02.32 static struct resource i2c_resources[] = {
03. 33 {
04.34 .start =DAVINCI_I2C_BASE,
05.35 .end =DAVINCI_I2C_BASE + 0x40,
06.36 .flags = IORESOURCE_MEM,
07. 37 },
08. 38 {
09.39 .start = IRQ_I2C,
10.40 .flags =IORESOURCE_IRQ,
11. 41 },
12. 42 };
13. 43
14. 44 static struct davinci_i2c_platform_data dm644x_i2c_data = {
15. 45 .bus_freq = 20,
16. 46 .bus_delay = 100,
17. 47 };
18. 48
19. 49 static struct davinci_i2c_platform_data dm355_i2c_data = {
20. 50 .bus_freq = 20,
21. 51 .bus_delay = 100,
22. 52 };
23. 53
24. 54 static struct davinci_i2c_platform_data dm646x_i2c_data = {
25. 55 .bus_freq = 100,
26. 56 .bus_delay = 0,
27. 57 };
28. 58
29. 59 static struct platform_device i2c_device = {
30. 60 .name ="i2c_davinci",
31. 61 .id =1,
32. 62 .dev ={
33.63 .platform_data = &dm355_i2c_data,
34. 64 },
35. 65 .num_resources =ARRAY_SIZE(i2c_resources),
36. 66 .resource = i2c_resources,
37. 67 };
38.
39.i2c_resources[] 定义了I2C的地址范围、中断号等相关信息,
40.platform_device i2c_device 初始化的时候初始化了dm355的数据,在davinci_init_cpu_i2c中再给i2c_device.dev.platform_data赋值为dm6467的数据。
41.
42.132 static struct platform_device *devices[] __initdata = {
43.133 &i2c_device,
44.134 &watchdog_device,
45.135 &usb_device,
46.136 };
47.
48.
49.138 static void __init davinci_init_cpu_i2c(void)
50.139 {
51.140 if (cpu_is_davinci_dm644x())
52.141 i2c_device.dev.platform_data = &dm644x_i2c_data;
53.142 else if(cpu_is_davinci_dm6467())
54.143 i2c_device.dev.platform_data = &dm646x_i2c_data;
55.144
56.145 /* all others default touse dm355 because dm355 uses the max speed */
57.146 }
58.147
59.
60.最后在davinci_init_devices中调用drivers/base/platform.c提供的导出函数platform_add_devices添加设备。
61.160 static int __init davinci_init_devices(void)
62.161 {
63.162 davinci_init_cpu_i2c();
64.163 davinci_init_cpu_usb();
65.164 platform_add_devices(devices, ARRAY_SIZE(devices));
66.165 return 0;
67.166 }
68.167 arch_initcall(davinci_init_devices);
69.
70.
71.
72.
73.
74.latform_add_devices函数具体如下:
75.110 int platform_add_devices(struct platform_device **devs, int num)
76.111 {
77.112 int i, ret = 0;
78.113
79.114 for (i = 0; i < num;i++) {
80.115 ret = platform_device_register(devs[i]);
81.116 if (ret) {
82.117 while (--i >= 0)
83.118 platform_device_unregister(devs[i]);
84.119 break;
85.120 }
86.121 }
87.122
88.123 return ret;
89.124 }
90.125 EXPORT_SYMBOL_GPL(platform_add_devices);
注册完成后,中断号及寄存器的基地址等信息会在设备树中描述了,此后只需利用 platform_get_resource等标准接口自动获取即可,实现了驱动和资源的分离。
01.platform_get_resource如下:
02.30 /**
03.31 * platform_get_resource - get aresource for a device
04.32 * @dev: platform device
05.33 * @type: resource type
06.34 * @num: resource index
07.35 */
08.36 struct resource*
09.37 platform_get_resource(struct platform_device *dev, unsigned inttype,
10.38 unsigned int num)
11.39 {
12.40 int i;
13.41
14.42 for (i = 0; i <dev->num_resources; i++) {
15.43 struct resource *r = &dev->resource[i];
16.44
17.45 if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
18.46 IORESOURCE_IRQ|IORESOURCE_DMA))
19.47 == type)
20.48 if (num-- == 0)
21.49 return r;
22.50 }
23.51 return NULL;
24.52 }
I2C adapter的Platformdriver
dm6467中Platform driver的注册的代码位于内核的ddrivers/i2c/busses/i2c-davinci.c中,该驱动的注册目的是初始化dm6467的I2C adapter,提供I2C总线传输的具体实现,并且向I2C core注册I2C adapter。
Platform driver的定义
在drivers/i2c/busses/i2c-davinci.c中Platform driver的定义 如下:
01.599static struct platform_driver davinci_i2c_driver = {
02.600 .probe =davinci_i2c_probe,
03.601 .remove =davinci_i2c_remove,
04.602 .driver = {
05.603 .name = "i2c_davinci",
06.604 .owner = THIS_MODULE,
07.605 },
08.606 };
09.其注册方法如下:
10.608 /* I2C may be needed to bring up other drivers */
11.609 static int __init davinci_i2c_init_driver(void)
12.610 {
13.611 returnplatform_driver_register(&davinci_i2c_driver);
14.612 }
15.613 subsys_initcall(davinci_i2c_init_driver);
通过platform_driver_register()函数注册Platformdriver davinci_i2c_driver时,会扫描platform bus上的所有设备,由于匹配因子是name即"i2c_davinci",而之前已经将name为"i2c_davinci"的Platform device注册到platform bus上,因此匹配成功,调用函数davinci_i2c_probe将设备和驱动绑定起来。
davinci_i2c_probe的过程如下:
通过platform_get_resource获*mem,*irq, 资源,分配内存,初始化struct davinci_i2c_dev,申请i2c_davinci_isr中断,初始化 struct i2c_adapter,并通过i2c-core提供的i2c_add_adapter注册i2c_adapter。具体如下:
01.487 static int davinci_i2c_probe(struct platform_device *pdev)
02.488 {
03.489 struct davinci_i2c_dev*dev;
04.490 struct i2c_adapter*adap;
05.491 struct resource *mem,*irq, *ioarea;
06.492 int r;
07.493
08.494 /* NOTE: driver uses thestatic register mapping */
09.495 mem =platform_get_resource(pdev, IORESOURCE_MEM, 0);
10.496 if (!mem) {
11.497 dev_err(&pdev->dev, "no mem resource?\n");
12.498 return -ENODEV;
13.499 }
14.500
15.501 irq =platform_get_resource(pdev, IORESOURCE_IRQ, 0);
16.502 if (!irq) {
17.503 dev_err(&pdev->dev, "no irq resource?\n");
18.504 return -ENODEV;
19.505 }
20.506
21.507 ioarea =request_mem_region(mem->start, (mem->end - mem->start) + 1,
22.508 pdev->name);
23.509 if (!ioarea) {
24.510 dev_err(&pdev->dev, "I2C region already claimed\n");
25.511 return -EBUSY;
26.512 }
27.513
28.514 dev =kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL);
29.515 if (!dev) {
30.516 r = -ENOMEM;
31.517 goto err_release_region;
32.518 }
33.519
34.520 dev->dev =get_device(&pdev->dev);
35.521 dev->irq =irq->start;
36.522 platform_set_drvdata(pdev, dev);
37.523
38.524 dev->clk =clk_get(&pdev->dev, "I2CCLK");
39.525 if (IS_ERR(dev->clk)){
40.526 r = -ENODEV;
41.527 goto err_free_mem;
42.528 }
43.529 clk_enable(dev->clk);
44.530
45.531 dev->base = (void__iomem *)IO_ADDRESS(mem->start);
46.532 i2c_davinci_init(dev);
47.533
48.534 r =request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev);
49.535 if (r) {
50.536 dev_err(&pdev->dev, "failure requesting irq %i\n",dev->irq);
51.537 goto err_unuse_clocks;
52.538 }
53.539
54.540 adap = &dev->adapter;
55.541 i2c_set_adapdata(adap,dev);
56.542 adap->owner =THIS_MODULE;
57.543 adap->class =I2C_CLASS_HWMON;
58.544 strlcpy(adap->name,"DaVinci I2C adapter", sizeof(adap->name));
59.545 adap->algo =&i2c_davinci_algo;
60.546 adap->dev.parent =&pdev->dev;
61.547
62.548 /* FIXME */
63.549 adap->timeout =1;
64.550 adap->retries =1;
65.551
66.552 adap->nr =pdev->id;
67.553 r = i2c_add_adapter(adap);
68.554 if (r) {
69.555 dev_err(&pdev->dev, "failure adding adapter\n");
70.556 goto err_free_irq;
71.557 }
72.558
73.559 return 0;
74.560
75.561 err_free_irq:
76.562 free_irq(dev->irq,dev);
77.563 err_unuse_clocks:
78.564 clk_disable(dev->clk);
79.565 clk_put(dev->clk);
80.566 dev->clk =NULL;
81.567 err_free_mem:
82.568 platform_set_drvdata(pdev, NULL);
83.569 put_device(&pdev->dev);
84.570 kfree(dev);
85.571 err_release_region:
86.572 release_mem_region(mem->start, (mem->end - mem->start) + 1);
87.573
88.574 return r;
89.575 }
这里定义了I2C adapter的中断处理函数i2c_davinci_isr(),该函数对I2C控制器的中断事件进行响应,主要实现了对I2C数据收发中断事件的处理。
结构i2c_davinci_algo 是adapter的I2C算法, i2c_davinci_xfer提供了I2C数据传输的实现。
482 static struct i2c_algorithm i2c_davinci_algo = {
483 .master_xfer = i2c_davinci_xfer,
484 .functionality =i2c_davinci_func,
485 };
64 EXPORT_SYMBOL(davinci_i2c_read);
89 EXPORT_SYMBOL(davinci_i2c_write);
161 EXPORT_SYMBOL(davinci_i2c_expander_op);