赞
踩
代码编写过程
1.在对应的.dts中的i2c中写入设备数据即i2c(硬件模块)设备名和i2c设备(硬件)地址
2.在自己的驱动代码中填入i2c设备信息名字即可
3.在自己的驱动代码中添加i2c_add_driver代码即可,再通过驱动代码的proe添加设备号来实现文件操作符初始化
4.在字符驱动read,write或者ioctl中填入i2c_transfer(client->adapter, &msg, num);来读写信息
注意:msg.flags = 1;为读出信息 msg.flags = 0;为写入信息
&i2c1 { <--i2c0或者i2c1或者i2c2要自己找有没有这个设备
clock-frequency = <100000>; <--100000Hz 为 100kHz
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay"; <--okay代表启动i2c
否则disable为关闭
...
ap3216c@1e { <--自己填 设备名@设备硬件地址
compatible = "ap3216c"; <--设备名
reg = <0x1e>; <--设备硬件地址
};
};
/* 设备树匹配列表 */ static const struct of_device_id ap3216c_of_match[] = { <-- 自己创建 { .compatible = "alientek,ap3216c" }, <--在这里填入 { /* Sentinel */ } }; /* i2c驱动结构体 */ static struct i2c_driver ap3216c_driver = { <-- 自己创建 .probe = ap3216c_probe, .remove = ap3216c_remove, .driver = { .owner = THIS_MODULE, .name = "ap3216c", .of_match_table = ap3216c_of_match, <--在这里填入 }, .id_table = ap3216c_id, };
代码编写过程
1.在平台总线系统上,写入i2c设备信息名字和硬件地址
2.在自己的驱动代码中填入i2c设备信息名字即可
3.在自己的驱动代码中添加i2c_add_driver代码即可,再通过驱动代码的proe添加设备号来实现文件操作符初始化
4.在字符驱动read,write或者ioctl中填入i2c_transfer(client->adapter, &msg, num);来读写信息
注意:msg.flags = 1;为读出信息 msg.flags = 0;为写入信息
开发者在 mach-s5pv210 或者 mach-xxxx 上写入对应的信息在
i2c_board_info 结构体中的 smdkv210_i2c_devs‘x’ (x=0,1,..,n表示第几个i2c) 中
例:
static struct i2c_board_info smdkv210_i2c_devs0[] __initdata = {
{ I2C_BOARD_INFO("at24co2a", 0x50), }, /* Samsung S524AD0XD1 */
{ I2C_BOARD_INFO("wm8580", 0x1b), },
};
还有
const struct i2c_device_id at24_table[] = { {"at24co2a",0x1234}, | | 必须和平台总线上信息一致 随便填写 {"at24co4a",0x1134}, {"at24co8a",0x1244}, }; struct i2c_driver at24_driver = { .probe = at24_i2c_drv_probe, .remove = at24_i2c_drv_remove, .driver = { .name = "s5pv210_e2prom", }, .id_table = at24_table, --> const struct i2c_device_id at24_table[] };
而不是通过平台总线初始化代码platform_driver_register(&at24_driver)
1.因为已经通过arch/arm/mach-s5pv210/mach-smdkv210.c,
文件中的static void __init smdkv210_machine_init(void)代码块里的,
1.i2c_register_board_info(0, smdkv210_i2c_devs0,ARRAY_SIZE(smdkv210_i2c_devs0));
注册里i2c的信息到i2c的i2c-core中,产生数据链表。
2.platform_add_devices中的代码块,里的platform_device_register(devs[i])注册到了平台总线。
2.产生:i2c文件中数据链表和i2c的总线信息
3.现在只需要通过i2c_add_driver在i2c里添加设备的驱动信息即刻,注册i2c的适配器来供设备驱动使用适配器,
4.不然只有平台总线的i2c设备信息(/sys/bus/i2c/devices/中),而没有i2c适配器的功能。
例如:
static int __init at24_i2c_drv_init(void)
{
return i2c_add_driver(&at24_driver);
(执行过程中会在/sys/bus/platform/drivers下创建目录)
}
代码: static struct i2c_board_info smdkv210_i2c_devs0[] __initdata = { <--i2c0 { I2C_BOARD_INFO("24c08", 0x50),}, /* Samsung S524AD0XD1 */ { I2C_BOARD_INFO("wm8580", 0x1b),}, 例: { I2C_BOARD_INFO("at24c02a", 0x50),} ^ ^ | | 设备名字 设备地址(硬件) 注意:在平台总线中驱动代码的设备名称必须和当前文件的设备名称(id_table里的,而不是i2c_driver里的name)一致 否则匹配不成功! }; static struct i2c_board_info smdkv210_i2c_devs1[] __initdata = { <--i2c1 /* To Be Updated */ }; static struct i2c_board_info smdkv210_i2c_devs1[] __initdata = { <--i2c2 /* To Be Updated */ }; ^ | 注:这里有3个i2c:i2c0,i2c1,i2c2 static void __init smdkv210_machine_init(void) { ...... s3c_i2c1_set_platdata(NULL); s3c_i2c2_set_platdata(NULL); i2c_register_board_info(0, smdkv210_i2c_devs0, ARRAY_SIZE(smdkv210_i2c_devs0)); | | | i2c适配器0号 //将上面配置好的smdkv210_i2c_devs0传入到i2c适配器0号 | int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { | int status; i2c0的多少个设备:ARRAY_SIZ(smdkv210_i2c_devs0) down_write(&__i2c_board_lock); .... for (status = 0; len; len--, info++) { struct i2c_devinfo *devinfo; //devinfo --i2c的设备信息动态空间 devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); if (!devinfo) { pr_debug("i2c-core: can't register boardinfo!\n"); status = -ENOMEM; break; } devinfo->busnum = busnum; 全部i2c的板载所有设备信息 devinfo->board_info = *info; | list_add_tail(&devinfo->list, &__i2c_board_list); } ... } i2c_register_board_info(1, smdkv210_i2c_devs1, ARRAY_SIZE(smdkv210_i2c_devs1)); i2c_register_board_info(2, smdkv210_i2c_devs2, ARRAY_SIZE(smdkv210_i2c_devs2)); ...... }
farsight@ubuntu:~/2012/linux/linux-3.0.8$ make -j2 zImage
farsight@ubuntu:~/2012/linux/linux-3.0.8$ cp -raf arch/arm/boot/zImage /tftpboot/
postcore_initcall(i2c_init); 入口函数 | static int __init i2c_init (void) | { retval = bus_register(&i2c_bus_type); 注册一个总线 | struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, }; retval = i2c_add_driver(&dummy_driver); i2c系统不做任何处理 | static struct i2c_driver dummy_driver = { .driver.name = "dummy", .probe = dummy_probe, .remove = dummy_remove, .id_table = dummy_id, }; | i2c_register_driver(THIS_MODULE, driver) | driver_register }
subsys_initcall(i2c_adap_s3c_init); 适配器层入口函数 | static int __init i2c_adap_s3c_init(void) | platform_driver_register | s3c24xx_i2c_probe { pdata = pdev->dev.platform_data; //给struct s3c24xx_i2c分配空间,s3c24xx_i2c里面有struct i2c_adapter,所以struct i2c_adapter对象也被分配了空间 i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL); //初始化struct i2c_adapter i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &s3c24xx_i2c_algorithm; i2c->adap.retries = 2; i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; //打开i2c的时钟 i2c->clk = clk_get(&pdev->dev, "i2c"); clk_enable(i2c->clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c->ioarea = request_mem_region(res->start, resource_size(res),pdev->name); i2c->regs = ioremap(res->start, resource_size(res)); //初始化i2c控制器 ret = s3c24xx_i2c_init(i2c); i2c->irq = ret = platform_get_irq(pdev, 0); ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED, dev_name(&pdev->dev), i2c); i2c->adap.nr = pdata->bus_num; ret = \ i2c_add_numbered_adapter(&i2c->adap); } i2c_add_numbered_adapter | i2c_add_adapter | --------------------------------------------------------- | __i2c_add_numbered_adapter | | | | | i2c_register_adapter | | | | | i2c_scan_static_board_info | | | | | list_for_each_entry | | | | | | | __i2c_board_list | | | | --------------------------------------------------------- | if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info)) | //创建struct i2c_client ,即用户调用适配器 client = kzalloc(sizeof *client, GFP_KERNEL); client->adapter = adap; client->dev.platform_data = info->platform_data; client->flags = info->flags; client->addr = info->addr; client->irq = info->irq; client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),client->addr); status = device_register(&client->dev);
static void __init smdkv210_machine_init(void) | { i2c_register_board_info(0, smdkv210_i2c_devs0, ARRAY_SIZE(smdkv210_i2c_devs0)); | static struct i2c_board_info smdkv210_i2c_devs0[] __initdata = { { I2C_BOARD_INFO("at24co2a", 0x50), }, /* Samsung S524AD0XD1 */ { I2C_BOARD_INFO("wm8580", 0x1b), }, }; ^ | 系统会这里自动导入自己写的i2c设备的信息到i2c板载链表上 | { devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); devinfo->busnum = busnum; devinfo->board_info = *info; list_add_tail(&devinfo->list, &__i2c_board_list); ^ | 系统导入i2c设备信息到链表中 } ... platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices)); | | static struct platform_device *smdkv210_devices[] __initdata = { ... &s3c_device_i2c0, | struct platform_device s3c_device_i2c0 = { .name = "s3c2410-i2c", #ifdef CONFIG_S3C_DEV_I2C1 .id = 0, #else .id = -1, #endif .num_resources = ARRAY_SIZE(s3c_i2c_resource), | static struct resource s3c_i2c_resource[] = { [0] = { .start = S3C_PA_IIC, .end = S3C_PA_IIC + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_IIC, .end = IRQ_IIC, .flags = IORESOURCE_IRQ, ^ | 系统导入对应的i2c的寄存器信息 }, }; .resource = s3c_i2c_resource, }; &s3c_device_i2c1, &s3c_device_i2c2, ... }; }
ls /sys/bus/i2c/devices/
|
0-001b(i2c0:从机设备地址1b) 0-0050 (0:i2c0 - 0050(设备硬件地址))
例:1-0058(i2c1:从机设备地址58)
2-0058(i2c2:从机设备地址58)
ls /sys/bus/i2c/devices/0-0050
|
name
|
"at24c02a"
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。