56 linux内核里声明I2C设备的方法
来源:互联网 发布:统计师的python日记 编辑:程序博客网 时间:2024/05/18 03:53
I2C控制器驱动好后,由i2c_adapter对象来描述, 我们只需通过函数调用控制器来实现数据传输就可以了。
但i2c控制器上接的i2c设备,需要我们来声明才可以.
在linux内核里,每个i2c_client对象表示一个i2c硬件设备
"include/linux/i2c.h"struct i2c_client { unsigned short flags; //没用. 如设备地址为10位,则设I2C_CLIENT_TEN unsigned short addr; //i2c设备地址 char name[I2C_NAME_SIZE]; //设备的名字 struct i2c_adapter *adapter; //此指针指向此设备在具体i2c控制器的i2c_adapter对象 struct i2c_driver *driver; //指向匹配上的i2c设备驱动 struct device dev; //基于device结构体扩展面来, 驱动模型. 也可以用dev.platform_data来给设备驱动提供硬件资源 int irq; //中断号 struct list_head detected;};
但比较坑的事情是通常情况下不会直接用i2c_client结构体声明对象来描述设备,因描述设备时它的adapter成员根本没法指定具体的i2c_adapter对象的地址.所以内核里的做法是,先用struct i2c_board_info来描述设备, 等控制器驱动好后,也就是i2c_adapter对象都搞好后,再根据i2c_board_info对象的内容生成i2c_client对象,并指定i2c_client对象的adapter指向对应的i2c_adapter对象地址.
struct i2c_board_info { char type[I2C_NAME_SIZE]; //就是i2c_client的name unsigned short flags; // i2c_client的flags unsigned short addr; // i2c_client的addr void *platform_data; // i2c_client的dev.platform_data struct dev_archdata *archdata; struct device_node *of_node; //用于设备树 int irq; // i2c_client的irq};
///////////////////////// i2c设备的描述方法////////////////
可参考内核源码目录下Documentation/i2c/instantiating-devices文档
1) 通过指定控制器号来声明i2c设备(最常用的方法)
先声明一个i2c_board_info对象表示一个i2c硬件设备. struct i2c_board_info info = { I2C_BOARD_INFO("24c02", 0x50), //名为24c02, 设备地址为0x50 .platform_data = NULL, }; 如此i2c设备是接着第9个控制器(即i2c_adapter的nr成员值为9): i2c_register_board_info(9, &info, 1); //注册i2c_board_info对象 ///////////////根据i2c_board_info对象生成i2c_client对象的过程//// int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { ... for (status = 0; len; len--, info++) { struct i2c_devinfo *devinfo; //注册i2c_board_info对象后,再用i2c_devinfo对象来记录i2c_board_info对象的地址 devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); ... devinfo->busnum = busnum; //指定i2c_board_info对象是用于哪个控制器的 devinfo->board_info = *info; list_add_tail(&devinfo->list, &__i2c_board_list); //再把i2c_devinfo对象加入链表__i2c_board_list里。 也就是可通过此链表获取出所有的i2c_board_info对象的内容 ... } } //然后查看在什么地址遍历链表__i2c_board_list, 可发现在"drivers/i2c/i2c-core.c" 783 static void i2c_scan_static_board_info(struct i2c_adapter *adapter) 784 { 785 struct i2c_devinfo *devinfo; ... //遍历链表,并根据指定的控制器号调用i2c_new_device创建i2c_client对象 788 list_for_each_entry(devinfo, &__i2c_board_list, list) { 789 if (devinfo->busnum == adapter->nr 790 && !i2c_new_device(adapter, 791 &devinfo->board_info)) ... 797 } 506 struct i2c_client * 507 i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) 508 { 509 struct i2c_client *client; 510 int status; 511 512 client = kzalloc(sizeof *client, GFP_KERNEL); ... 516 client->adapter = adap;//指定对应的i2c_adapter对象的地址 517 518 client->dev.platform_data = info->platform_data; 519 520 if (info->archdata) 521 client->dev.archdata = *info->archdata; 522 523 client->flags = info->flags; 524 client->addr = info->addr; 525 client->irq = info->irq; 526 527 strlcpy(client->name, info->type, sizeof(client->name)); ... 542 client->dev.parent = &client->adapter->dev; 543 client->dev.bus = &i2c_bus_type; // i2c_client对象是挂载到i2c总线下的, 所以每个i2c设备描述好后可在"/sys/bus/i2c/devices"目录下查看到 544 client->dev.type = &i2c_client_type; 545 client->dev.of_node = info->of_node; ... 551 status = device_register(&client->dev); //注册设备,驱动模型. 552 if (status) //i2c_scan_static_board_info函数是用于根据i2c_board_info生成i2c_client对象,但这个函数是在i2c控制器注册时被调用的. 所以必须在i2c控制器注册前描述好i2c_board_info并i2c_register_board_info注册好i2c_board_info对象才可以 822 static int i2c_register_adapter(struct i2c_adapter *adap) 823 { ... 870 if (adap->nr < __i2c_first_dynamic_bus_num) 871 i2c_scan_static_board_info(adap);
///////////////////////////////////
"arch/arm/mach-sunxi/sun8i.c" 524 MACHINE_START(SUNXI, "sun8i") 525 .atag_offset = 0x100, 526 .init_machine = sunxi_dev_init, //这个是板上设备初始化函数, 可以sunxi_dev_init函数里实现i2c_board_info对象的准备 527 .init_early = sunxi_init_early, //是更前面的初始化函数 //在第9个控制器里增加三个设备 451 struct i2c_board_info infos[] = { 452 {I2C_BOARD_INFO("haha", 0x33)}, 453 {I2C_BOARD_INFO("nono", 0x44)}, 454 {I2C_BOARD_INFO("what", 0x55)}, 455 }; 456 457 static void __init sunxi_dev_init(void) 458 { 459 i2c_register_board_info(9, infos, ARRAY_SIZE(infos)); //重编内核镜像好,控制器驱动好后,在"/sys/bus/i2c/device"目录下应用9-0033, 9-0044等子目录的出现
///////////////////////////////////////////////////////////
2) 直接使用i2c_new_device函数来创建出i2c_client对象
struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info); //调用此函数需要控制器对应的i2c_adapter对象的地址, 还需要一个i2c_board_info对象 struct i2c_adapter *i2c_adap; i2c_adap = i2c_get_adapter(2); //可调用此函数获取第2个控制器的i2c_adapter对象的地址 此方法可以写成模块,动态加载 test.c #include <linux/init.h> #include <linux/module.h> #include <linux/i2c.h> struct i2c_board_info info = { .type = "myi2c_dev", .addr = 0x67, }; struct i2c_client *cli; static int __init test_init(void) { struct i2c_adapter *adap; adap = i2c_get_adapter(9); cli = i2c_new_device(adap, &info); return 0; } static void __exit test_exit(void) { i2c_unregister_device(cli); //反注册i2c设备 } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL");
///////////////////////////////////////////////////////////
3) 使用i2c_new_probed_device函数来创建存在的i2c设备对象
此方法会让控制器发设备地址,检查应答信号确认设备是否存在,如存在,则创建i2c_client对象
struct i2c_client *i2c_new_probed_device(struct i2c_adapter *adap, struct i2c_board_info *info, unsigned short const *addr_list, int (*probe)(struct i2c_adapter *, unsigned short addr)) //adap为要检查设备的控制器的i2c_adapter对象地址, info为创建设备对象时准备的信息, // addr_list是一个要检查的设备地址数组,以I2C_CLIENT_END结尾. 控制器会按数组里的顺序发出设备地址,直到有应答信号时,创建i2c_client对象,并返回对象的地址. // probe函数指针为NULL.当为NULL时会使用默认的检查方法
test.c #include <linux/init.h> #include <linux/module.h> #include <linux/i2c.h> struct i2c_board_info info = { .type = "myi2c_dev", .addr = 0x67, }; struct i2c_client *cli = NULL; unsigned short addrs[] = {0x11, 0x22, 0x50, 0x66, 0x77, I2C_CLIENT_END}; static int __init test_init(void) { struct i2c_adapter *adap; adap = i2c_get_adapter(9); cli = i2c_new_probed_device(adap, &info, addrs, NULL); if (NULL == cli) return -ENODEV; printk("cli->addr = %x\n", cli->addr); return 0; } static void __exit test_exit(void) { i2c_unregister_device(cli); //反注册i2c设备 } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL");
//////////////////////////////////////利用此方法还可以检查出控制器上接的设备,输出存在的设备的地址test.c
#include <linux/init.h> #include <linux/module.h> #include <linux/i2c.h> unsigned short addrs[129]; struct i2c_client *cli = NULL; static int __init test_init(void) { struct i2c_adapter *adapter; struct i2c_board_info myinfo; int i; unsigned short *addr; //准备好从0~128的设备地址 for (i = 0; i < ARRAY_SIZE(addrs); i++) addrs[i] = i; addrs[i] = I2C_CLIENT_END; adapter = i2c_get_adapter(9); memset(&myinfo, 0, sizeof(myinfo)); strcpy(myinfo.type , "mydev"); //准备i2c_board_info信息 addr = addrs; while (1) { cli = i2c_new_probed_device(adapter, &myinfo, addr, NULL); if (cli) { printk("addr: %x found\n", cli->addr); addr += cli->addr; continue; } break; } return 0; } static void __exit test_exit(void) { if (cli) i2c_unregister_device(cli); } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL");
///////////////////////////////////////////////////////
4) 使用”/sys/bus/i2c/devices/i2c-0/new_device”的属性文件接口
echo "aaa 0x50" > /sys/bus/i2c/devices/i2c-0/new_device //这种方法只适用于简单的设备。这类型设备不会有中断号,也不需要提供额外的硬件资源.
- 56 linux内核里声明I2C设备的方法
- Linux 内核的I2C设备
- 20 设备树里声明i2c设备
- LINUX I2C设备驱动的编写方法
- Linux里SPI与I2C创建设备的流程
- 54 OrangePi linux内核里的i2c控制器驱动
- 57 linux内核的i2c设备驱动模型
- amlogic平台android 系统linux内核中添加i2c设备实现i2c的读写
- Linux内核---32.I2C设备驱动分析
- 在内核里写i2c设备驱动的两种方式
- linux内核模型---总线,设备,驱动在展讯平台上I2C设备的实例解析
- Linux i2c设备的驱动程序
- linux i2c子系统代码分析9---i2c设备的注册方法
- 44 linux内核里的platform设备驱动模型
- 67 linux内核里的framebuffer设备驱动模型
- Linux系统I2C设备驱动编写方法
- Linux内核里写i2c client 驱动的两种方式
- 55 linux内核里基于GPIO口的I2C控制器驱动
- JVM调优的文档
- ABAP数字类型合法性检查函数NUMERIC_CHECK
- 编程渣渣的蜗牛爬笔记 多行注释
- 支付宝 微信支付 curl: (60) SSL certificate problem: unable to get local issuer certificate 错误
- core-site.xml参数配置详情
- 56 linux内核里声明I2C设备的方法
- js -- 打开新窗口(window.open)、关闭窗口(window.close)
- mapred-site.xml参数配置详情
- JAVA 基础
- PYTHON 抓去京东,百度的数据
- java 获取代理的真实ip
- 命名管道理解与简单C实现
- mySQL存储千万条数据
- Java操作文件输出为字符串以及字符串输出为文件