欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

从驱动程序到应用程序的 I2C(中型)

最编程 2024-03-13 12:56:32
...

Linux中对I2C的支持非常全面,既提供了内核态的访问方式,也提供了用户态的访问方法。

Linux中对I2C的支持可以分为两个层面,一个是adapteralgorithm,对应的是i2c控制器;再一个是driverclient.Linux内核提供了丰富的接口来实添加i2c设备驱动。要添加一个i2c设备驱动,需要几个固定的步骤。首先,需要往i2c设备列表里添加一组设备ID foo_idtable

static struct i2c_device_id foo_idtable[] = {

{ "foo", my_id_for_foo },

{ "bar", my_id_for_bar },

{ }

};


MODULE_DEVICE_TABLE(i2c, foo_idtable);

然后填充i2c driver的数据结构:

static struct i2c_driver foo_driver = {

.driver = {

.name   = "foo",

.pm = &foo_pm_ops,  /* optional */

},


.id_table   = foo_idtable,

.probe      = foo_probe,

.remove     = foo_remove,

/* if device autodetection is needed: */

.class      = I2C_CLASS_SOMETHING,

.detect     = foo_detect,

.address_list  = normal_i2c,


.shutdown   = foo_shutdown, /* optional */

.command    = foo_command,  /* optional, deprecated */

}


剩下的就是逐一初始化foo_probe()foo_remove()foo_detect()等函数。一旦准备好了相应的client结构,就可以实现foo_read_valule()foo_write_value()函数,当然这两者都是基于底层公共的i2c/smbus读写函数:i2c_smbus_read/write_byte_data/word()去实现。


如果确实有i2c设备挂载在某个i2c总线上,可以通过填充i2c_board_info数据结构来构造这个设备的实例,然后调用i2c_new_device()来探测实际接入的i2c设备。当然也可能事先无法确认系统上有什么类型的i2c设备,这个时候需要定义一个call back函数,放在probe()后面,让它去确认是否有指定类型的i2c设备挂在系统上。使用完设备后,可以调用i2c_unregister_device()来注销之前注册的设备。当然执行这些所有操作的前提是设备对应的驱动已经被初始化好并且加载到内核,可以参考下面的代码来实现初始化和退出操作:

static int __init foo_init(void)

{  

return i2c_add_driver(&foo_driver);

}

module_init(foo_init);


static void __exit foo_cleanup(void)

{  

i2c_del_driver(&foo_driver);

}

module_exit(foo_cleanup);


The module_i2c_driver() macro can be used to reduce above code.


module_i2c_driver(foo_driver);


如果驱动中,需要向设备发送或者从设备接受数据,可以调用:

int i2c_master_send(struct i2c_client *client, const char *buf, int count);

int i2c_master_recv(struct i2c_client *client, char *buf, int count);

这两组函数来实现,更多的函数在linux/i2c.h中有说明。



当然linux内核中也提供了设备作为从设备的驱动,这中情况下的系统层次图如下所示:

e.g. sysfs      I2C slave events        I/O registers

+-----------+  v    +---------+     v     +--------+  v  +------------+

| Userspace +........+ Backend +-----------+ Driver +-----+ Controller |

+-----------+       +---------+           +--------+     +------------+

| |

----------------------------------------------------------------+-- I2C

--------------------------------------------------------------+---- Bus


不同于PCI/USB设备,I2C没有提供硬件上自动枚举的能力,因此在初始化i2c设备之前需要显式地指定设备的地址。内核提供了多个显式初始化一个i2c设备的方法:

1、通过bus number声明一个i2c设备:

这种情况尤其适用于i2c作为系统总线的嵌入式系统,以omp2 h4为例,用户需要注册i2c board info:

Example (from omap2 h4):


static struct i2c_board_info h4_i2c_board_info[] __initdata = {

{  

I2C_BOARD_INFO("isp1301_omap", 0x2d),

.irq        = OMAP_GPIO_IRQ(125),

},

{  /* EEPROM on mainboard */

I2C_BOARD_INFO("24c01", 0x52),

.platform_data = &m24c01,

},

{  /* EEPROM on cpu card */

I2C_BOARD_INFO("24c01", 0x57),

.platform_data = &m24c01,

},

};


static void __init omap_h4_init(void)

{

(...)

i2c_register_board_info(1, h4_i2c_board_info,

ARRAY_SIZE(h4_i2c_board_info));

(...)

}


2、通过设备树申明一个i2c设备:

这种方式需要把心建的设备节点挂在master conrollor对应的设备树上,也就是说它必须是master controller的子节点,如下面的例子所示:

i2c1: i2c@400a0000 {

/* ... master properties skipped ... */

clock-frequency = <100000>;


flash@50 {

compatible = "atmel,24c256";

reg = <0x50>;

};


pca9532: gpio@60 {

compatible = "nxp,pca9532";

gpio-controller;

#gpio-cells = <2>;

上一篇: linux 驱动程序移植--总线设备驱动程序

下一篇: 昂达 BIOS ACPI

推荐阅读