//zz//#######################################################################
zz-linux-i2c驱动分析am335x框架调用150103d.txt
框架,调用流程
zz-Write:
@2015-1-2 23:19:50
@2015-1-3 10:38:54
@2015-1-4 00:12:33
@2015-1-4 00:26:50
@
REF:
ti-sdk-am335x-evm-06.00.00.00-Linux-x86-Install.bin
linux-3.2.0-psp04.06ti-zz150103a.zip
linux下I2C驱动架构全面分析
http://blog.csdn.net/wangpengqi/article/details/17711165
i2c--2.6.34文档:如何枚举产生i2c_client
http://blog.csdn.net/yuanlulu/article/details/6557901
linux I2C 驱动之----i2c_client 的注册
http://blog.csdn.net/tanxjian/article/details/7479444
KeyWord:
// i2c 设备接口层,供上层应用读写
app => i2c_client i2c_driver-> read/write/ioctl => i2c-core
// i2c 总线接口层,通过linux架构操作硬件
=> i2c_adapter i2c_algorithm
=> hardware adapter[i] 芯片i2c接口寄存器组 ==> i2c slave devices 外设
四个重要的 i2c 结构体类型
i2c_driver i2c_client i2c_adapter i2c_algorithm
linux内核 i2c 相关驱动源码位置
drivers/i2c/
i2c-dev.c
i2c_dev_init() => i2cdev_fops linux设备文件通过此 => 调用 i2c-core => i2c架构 ??
i2c-core.c
与具体芯片平台无关的函数,linux-i2c驱动框架常用函数
algos/
busses/
i2c-s3c2410.c 平台mini2440相关的 platform_driver
i2c-omap.c 平台am335x相关 platform_driver
chips/
i2c_driver 由外设决定缺省放这里,实际是在 drivers/misc/eeprom/at24.c
arch/arm/mach-omap2/board-am335xevm.c
i2c_board_info am335x_i2c1_boardinfo[] (for i2c_client)
arch/arm/plat-omap/i2c.c
platform_device omap_i2c_devices[] (for i2c platform_device)
arch/arm/mach-s3c2440/mach-mini2440.c
platform_device s3c_device_i2c0 (for i2c platform_device)
//zz//#######################################################################
1.
i2c 从应用层到外部设备的操作顺序.
应用程序读写 i2c (外设相关的)设备文件
内核提供一套接口,向下操作寄存器完成和外设的通信,发送/接收数据
// i2c 设备接口层,供上层应用读写
app => i2c_client i2c_driver-> read/write/ioctl => i2c-core
// i2c 总线接口层,通过linux架构操作硬件
=> i2c_adapter i2c_algorithm
=> hardware adapter[i] 芯片i2c接口寄存器组 ==> i2c slave devices 外设
//zz//#######################################################################
2.
四个重要的 i2c 结构体类型
注意与 platform_ 平台设备(大部分设备的入口点,i2c也是)不是一个东西:
对于 am335x i2c 使用平台设备的方式来注册到内核的,这是 am335x i2c 驱动的开始点
平台设备的驱动:
drivers/i2c/busses/i2c-omap.c
platform_driver omap_i2c_driver
.driver.name = "omap_i2c"
.id_table 没设置
平台设备的设备:
arch/arm/plat-omap/i2c.c
platform_device omap_i2c_devices[]
char name[] = "omap_i2c";
1)
i2c_driver
外设相关的驱动
struct list_head clients; //结构体内有存放支持的 i2c_client 外设的链表
例如 rtc-ds1307 芯片用的i2c接口,
drivers/rtc/rtc-ds1307.c
例如 at24(系列)的i2c接口外部设备分析如下
drivers/misc/eeprom/at24.c
i2c_driver at24_driver
{
.probe = at24_probe //探针函数
.driver
.name = "at24"
.id_tble = {"",..} //支持的外设设备的 .name 表
.attach_adapter = //为空则 __attach_adapter() 时候不调用
}
注册时候的调用流程:
/drivers/misc/eeprom/at24.c
module_init() => at24_init()
i2c_add_driver() => i2c_register_driver()
i2c_register_driver() 注册时候,设置.driver.bus = & i2c_bus_type (全局的 并且 .name="i2c")
bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
驱动与总线上的设备逐个匹配,调用 __attach_adapter() => .attach_adapter(i2c_driver 此函数指针不为NULL则调用),对总线 i2c_bus_type 上的每个设备都进行匹配
2)
i2c_client
struct list_head detected; //结构体内有链表,存放什么?
使用 i2c_board_info 结构体信息来创建 i2c_client(不是直接定义)
i2c_register_board_info(busnum,i2c_board_info *,num);
busnum 为适配器号,num为(指针所指数组)要注册的数量
i2c_board_info
{
.name = "??" //外设的名字
.addr = 0x?? //外设的i2c总线上相应的设备地址
}
am335x 是使用 i2c_board_info 注册的
am335x_evm_init() => am335x_evm_i2c_init() => gen_purp_evm_dev_cfg[] i2c1_init()
=> omap_register_i2c_bus(2, 100,am335x_i2c1_boardinfo,ARRAY_SIZE(..));
第一个参数 2 ,表示注册到第二个 i2c 口,因为是从1开始 => 对应 i2c1 接口(adapter)
=> i2c_register_board_info(bus_id, info, len) => list_add_tail(&devinfo->list, &__i2c_board_list);
以上完成,静态注册i2c设备到芯片的i2c接口上,即向 i2c1接口(i2c_adapter) 中添加一个 外设(i2c_client)
__i2c_board_list 是个全局的链表头,存放芯片所有i2c接口(i2c_adapter)支持的所有 i2c_client 信息
devinfo->busnum = bus_id 就是 i2c接口号(i2c_adapter)
各 i2c_adapter 上挂载的 i2c 设备,都放这个链表中,但链表上 devinfo 是有记录 i2c_client 在哪个 i2c_adapter 上的
但是 mini2440 没看到这样注册,那是怎么注册的呢?
根本没注册,从应用层app看,所有i2c外设都用的 i2c-0 这个设备节点文件;
相当于app层操作适配器而非设备来访问外设的
注意:
wds韦东山及linux-2.6.34网友教程说动态(insmod *.ko)创建 i2c_client
枚举设备 i2c_new_device() 或者 i2c_new_probed_device()
利用 i2c_driver 的 .attach_adapter(或.detect)
=> i2c_probe(adapter, &addr_data, at24cxx_detect); 这种方式动态添加 i2c_client
3)
i2c_adapter
struct list_head userspace_clients; //结构体的内链表,存放支持的 i2c_client
芯片 i2c 接口,每个i2c口(两个引脚+寄存器组)对应为一个 i2c_adapter
drivers/i2c/busses/i2c-omap.c
platform_driver omap_i2c_driver
.name = "omap_i2c"
.probe = omap_i2c_probe()
{
//zz// 获取 platform_device 资源及中断/am335x的寄存器地址
platform_get_resource(pdev, IORESOURCE_MEM, 0);
platform_get_resource(pdev, IORESOURCE_IRQ, 0);
omap_i2c_init(dev);
request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
//zz// 指定通讯协议,使用 omap-am335x 平台的,寄存器的操作在 algo 的函数中实现的
adap->algo = &omap_i2c_algo;
i2c_add_numbered_adapter(adap);
drivers/i2c/i2c-core.c
i2c_register_adapter(adap);
{
//zz// i2c adapter dev file is: "i2c-0" "i2c-1" ..
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
//zz// 设置总线类型为 i2c_bus_type (.name = "i2c")
adap->dev.bus = &i2c_bus_type;
//zz// i2c_driver 匹配 i2c_adapter
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
}
}
4)
i2c_algorithm
芯片平台相关的底层通讯协议,本结构放在 i2c_adapter 的函数指针成员变量中
芯片内含n个 i2c引脚+寄存器组 => 对应n个 i2c_adapter 结构
用来操作寄存器实现 i2c 发送接收
drivers/i2c/busses/i2c-omap.c
i2c_algorithm omap_i2c_algo
{
//zz// am335x 实际操作i2cx寄存器进行通信的函数(最底层,寄存器控制i2c总线数据流)
.master_xfer = omap_i2c_xfer()
//zz// 本 algo 支持的操作;返回 i2c_adapter,i2c_algorithm 支持的操作,位表示的
// 返回值可用于检测位 I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL 等功能是否支持
.functionality = omap_i2c_func()
}
5)
以上4种结构体类型的定义都在
include/linux/i2c.h
如下结构体类型,用于 adapter->algo->master_xfer() 发送接收i2c总线上的数据用的
struct i2c_msg {
u16 addr; //要操作的外设的内部地址
u16 flags; //1读或0写操作
u16 len; //数据的长度和缓冲区指针
u8 *buf;
};
//zz//#######################################################################
3.
linux内核 i2c 相关驱动源码位置
1)
四个重要结构体,定义相关的变量所在文件位置
芯片平台相关的(i2c 硬件寄存器)适配器操作驱动 platfor_driver驱动安装
i2c外部设备相关的驱动 i2c_driver 的定义
drivers/i2c/
i2c-dev.c
i2c_dev_init() => i2cdev_fops linux设备文件通过
=> 调用 i2c-core => i2c架构 4结构体类型 => 访问i2c外设??
i2cdev_open() 从设备节点获得 i2c_client => i2c_adapter 等等
i2c-core.c
与具体芯片平台无关的函数,linux-i2c驱动框架常用函数
i2c_add_numbered_adapter() i2c_register_adapter() 添加注册适配器
i2c_register_driver() __attach_adapter() 注册i2c_driver 及其结构中关联适配器的函数(共用)
i2c_detect() 适配器与驱动匹配
algos/
busses/
i2c-s3c2410.c 平台mini2440相关的 platform_driver .name是"s3c2410-i2c"
i2c-omap.c 平台am335x相关 platform_driver
chips/
设备芯片相关的 i2c_driver..
但实际不在这里,而是在 drivers/misc/eeprom/at24.c 中的 i2c_driver at24_driver
2)
对于 am335x i2c 使用平台设备的方式来注册到内核的,这是 am335x i2c 驱动的开始点
注意与 platform_ 平台设备(大部分设备的入口点,i2c也是)不是一个东西
平台设备的名字,平台驱动的名字都是 "omap_i2c",这样才能匹配上
平台设备的驱动:
drivers/i2c/busses/i2c-omap.c
platform_driver omap_i2c_driver
.driver.name = "omap_i2c"
.id_table 没设置
平台设备的设备:
arch/arm/plat-omap/i2c.c
platform_device omap_i2c_devices[]
char name[] = "omap_i2c";
#define I2C_DEV_BUILDER(bus_id, res, data)
{
.id = (bus_id),
.name = name,
.resource = (res),
.dev
.platform_data = (data)
..
}
platform_device omap_i2c_devices[] =
{
I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]),
};
zz-linux-i2c驱动分析am335x框架调用150103d.txt
框架,调用流程
zz-Write:
@2015-1-2 23:19:50
@2015-1-3 10:38:54
@2015-1-4 00:12:33
@2015-1-4 00:26:50
@
REF:
ti-sdk-am335x-evm-06.00.00.00-Linux-x86-Install.bin
linux-3.2.0-psp04.06ti-zz150103a.zip
linux下I2C驱动架构全面分析
http://blog.csdn.net/wangpengqi/article/details/17711165
i2c--2.6.34文档:如何枚举产生i2c_client
http://blog.csdn.net/yuanlulu/article/details/6557901
linux I2C 驱动之----i2c_client 的注册
http://blog.csdn.net/tanxjian/article/details/7479444
KeyWord:
// i2c 设备接口层,供上层应用读写
app => i2c_client i2c_driver-> read/write/ioctl => i2c-core
// i2c 总线接口层,通过linux架构操作硬件
=> i2c_adapter i2c_algorithm
=> hardware adapter[i] 芯片i2c接口寄存器组 ==> i2c slave devices 外设
四个重要的 i2c 结构体类型
i2c_driver i2c_client i2c_adapter i2c_algorithm
linux内核 i2c 相关驱动源码位置
drivers/i2c/
i2c-dev.c
i2c_dev_init() => i2cdev_fops linux设备文件通过此 => 调用 i2c-core => i2c架构 ??
i2c-core.c
与具体芯片平台无关的函数,linux-i2c驱动框架常用函数
algos/
busses/
i2c-s3c2410.c 平台mini2440相关的 platform_driver
i2c-omap.c 平台am335x相关 platform_driver
chips/
i2c_driver 由外设决定缺省放这里,实际是在 drivers/misc/eeprom/at24.c
arch/arm/mach-omap2/board-am335xevm.c
i2c_board_info am335x_i2c1_boardinfo[] (for i2c_client)
arch/arm/plat-omap/i2c.c
platform_device omap_i2c_devices[] (for i2c platform_device)
arch/arm/mach-s3c2440/mach-mini2440.c
platform_device s3c_device_i2c0 (for i2c platform_device)
//zz//#######################################################################
1.
i2c 从应用层到外部设备的操作顺序.
应用程序读写 i2c (外设相关的)设备文件
内核提供一套接口,向下操作寄存器完成和外设的通信,发送/接收数据
// i2c 设备接口层,供上层应用读写
app => i2c_client i2c_driver-> read/write/ioctl => i2c-core
// i2c 总线接口层,通过linux架构操作硬件
=> i2c_adapter i2c_algorithm
=> hardware adapter[i] 芯片i2c接口寄存器组 ==> i2c slave devices 外设
//zz//#######################################################################
2.
四个重要的 i2c 结构体类型
注意与 platform_ 平台设备(大部分设备的入口点,i2c也是)不是一个东西:
对于 am335x i2c 使用平台设备的方式来注册到内核的,这是 am335x i2c 驱动的开始点
平台设备的驱动:
drivers/i2c/busses/i2c-omap.c
platform_driver omap_i2c_driver
.driver.name = "omap_i2c"
.id_table 没设置
平台设备的设备:
arch/arm/plat-omap/i2c.c
platform_device omap_i2c_devices[]
char name[] = "omap_i2c";
1)
i2c_driver
外设相关的驱动
struct list_head clients; //结构体内有存放支持的 i2c_client 外设的链表
例如 rtc-ds1307 芯片用的i2c接口,
drivers/rtc/rtc-ds1307.c
例如 at24(系列)的i2c接口外部设备分析如下
drivers/misc/eeprom/at24.c
i2c_driver at24_driver
{
.probe = at24_probe //探针函数
.driver
.name = "at24"
.id_tble = {"",..} //支持的外设设备的 .name 表
.attach_adapter = //为空则 __attach_adapter() 时候不调用
}
注册时候的调用流程:
/drivers/misc/eeprom/at24.c
module_init() => at24_init()
i2c_add_driver() => i2c_register_driver()
i2c_register_driver() 注册时候,设置.driver.bus = & i2c_bus_type (全局的 并且 .name="i2c")
bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
驱动与总线上的设备逐个匹配,调用 __attach_adapter() => .attach_adapter(i2c_driver 此函数指针不为NULL则调用),对总线 i2c_bus_type 上的每个设备都进行匹配
2)
i2c_client
struct list_head detected; //结构体内有链表,存放什么?
使用 i2c_board_info 结构体信息来创建 i2c_client(不是直接定义)
i2c_register_board_info(busnum,i2c_board_info *,num);
busnum 为适配器号,num为(指针所指数组)要注册的数量
i2c_board_info
{
.name = "??" //外设的名字
.addr = 0x?? //外设的i2c总线上相应的设备地址
}
am335x 是使用 i2c_board_info 注册的
am335x_evm_init() => am335x_evm_i2c_init() => gen_purp_evm_dev_cfg[] i2c1_init()
=> omap_register_i2c_bus(2, 100,am335x_i2c1_boardinfo,ARRAY_SIZE(..));
第一个参数 2 ,表示注册到第二个 i2c 口,因为是从1开始 => 对应 i2c1 接口(adapter)
=> i2c_register_board_info(bus_id, info, len) => list_add_tail(&devinfo->list, &__i2c_board_list);
以上完成,静态注册i2c设备到芯片的i2c接口上,即向 i2c1接口(i2c_adapter) 中添加一个 外设(i2c_client)
__i2c_board_list 是个全局的链表头,存放芯片所有i2c接口(i2c_adapter)支持的所有 i2c_client 信息
devinfo->busnum = bus_id 就是 i2c接口号(i2c_adapter)
各 i2c_adapter 上挂载的 i2c 设备,都放这个链表中,但链表上 devinfo 是有记录 i2c_client 在哪个 i2c_adapter 上的
但是 mini2440 没看到这样注册,那是怎么注册的呢?
根本没注册,从应用层app看,所有i2c外设都用的 i2c-0 这个设备节点文件;
相当于app层操作适配器而非设备来访问外设的
注意:
wds韦东山及linux-2.6.34网友教程说动态(insmod *.ko)创建 i2c_client
枚举设备 i2c_new_device() 或者 i2c_new_probed_device()
利用 i2c_driver 的 .attach_adapter(或.detect)
=> i2c_probe(adapter, &addr_data, at24cxx_detect); 这种方式动态添加 i2c_client
3)
i2c_adapter
struct list_head userspace_clients; //结构体的内链表,存放支持的 i2c_client
芯片 i2c 接口,每个i2c口(两个引脚+寄存器组)对应为一个 i2c_adapter
drivers/i2c/busses/i2c-omap.c
platform_driver omap_i2c_driver
.name = "omap_i2c"
.probe = omap_i2c_probe()
{
//zz// 获取 platform_device 资源及中断/am335x的寄存器地址
platform_get_resource(pdev, IORESOURCE_MEM, 0);
platform_get_resource(pdev, IORESOURCE_IRQ, 0);
omap_i2c_init(dev);
request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
//zz// 指定通讯协议,使用 omap-am335x 平台的,寄存器的操作在 algo 的函数中实现的
adap->algo = &omap_i2c_algo;
i2c_add_numbered_adapter(adap);
drivers/i2c/i2c-core.c
i2c_register_adapter(adap);
{
//zz// i2c adapter dev file is: "i2c-0" "i2c-1" ..
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
//zz// 设置总线类型为 i2c_bus_type (.name = "i2c")
adap->dev.bus = &i2c_bus_type;
//zz// i2c_driver 匹配 i2c_adapter
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
}
}
4)
i2c_algorithm
芯片平台相关的底层通讯协议,本结构放在 i2c_adapter 的函数指针成员变量中
芯片内含n个 i2c引脚+寄存器组 => 对应n个 i2c_adapter 结构
用来操作寄存器实现 i2c 发送接收
drivers/i2c/busses/i2c-omap.c
i2c_algorithm omap_i2c_algo
{
//zz// am335x 实际操作i2cx寄存器进行通信的函数(最底层,寄存器控制i2c总线数据流)
.master_xfer = omap_i2c_xfer()
//zz// 本 algo 支持的操作;返回 i2c_adapter,i2c_algorithm 支持的操作,位表示的
// 返回值可用于检测位 I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL 等功能是否支持
.functionality = omap_i2c_func()
}
5)
以上4种结构体类型的定义都在
include/linux/i2c.h
如下结构体类型,用于 adapter->algo->master_xfer() 发送接收i2c总线上的数据用的
struct i2c_msg {
u16 addr; //要操作的外设的内部地址
u16 flags; //1读或0写操作
u16 len; //数据的长度和缓冲区指针
u8 *buf;
};
//zz//#######################################################################
3.
linux内核 i2c 相关驱动源码位置
1)
四个重要结构体,定义相关的变量所在文件位置
芯片平台相关的(i2c 硬件寄存器)适配器操作驱动 platfor_driver驱动安装
i2c外部设备相关的驱动 i2c_driver 的定义
drivers/i2c/
i2c-dev.c
i2c_dev_init() => i2cdev_fops linux设备文件通过
=> 调用 i2c-core => i2c架构 4结构体类型 => 访问i2c外设??
i2cdev_open() 从设备节点获得 i2c_client => i2c_adapter 等等
i2c-core.c
与具体芯片平台无关的函数,linux-i2c驱动框架常用函数
i2c_add_numbered_adapter() i2c_register_adapter() 添加注册适配器
i2c_register_driver() __attach_adapter() 注册i2c_driver 及其结构中关联适配器的函数(共用)
i2c_detect() 适配器与驱动匹配
algos/
busses/
i2c-s3c2410.c 平台mini2440相关的 platform_driver .name是"s3c2410-i2c"
i2c-omap.c 平台am335x相关 platform_driver
chips/
设备芯片相关的 i2c_driver..
但实际不在这里,而是在 drivers/misc/eeprom/at24.c 中的 i2c_driver at24_driver
2)
对于 am335x i2c 使用平台设备的方式来注册到内核的,这是 am335x i2c 驱动的开始点
注意与 platform_ 平台设备(大部分设备的入口点,i2c也是)不是一个东西
平台设备的名字,平台驱动的名字都是 "omap_i2c",这样才能匹配上
平台设备的驱动:
drivers/i2c/busses/i2c-omap.c
platform_driver omap_i2c_driver
.driver.name = "omap_i2c"
.id_table 没设置
平台设备的设备:
arch/arm/plat-omap/i2c.c
platform_device omap_i2c_devices[]
char name[] = "omap_i2c";
#define I2C_DEV_BUILDER(bus_id, res, data)
{
.id = (bus_id),
.name = name,
.resource = (res),
.dev
.platform_data = (data)
..
}
platform_device omap_i2c_devices[] =
{
I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]),
};
//zz//#######################################################################