设备树学习之(七)I2C设备的注册过程分析
2017-05-03 15:07
375 查看
开发板:tiny4412SDK + S702 + 4GB Flash
要移植的内核版本:Linux-4.4.0 (支持device tree)
u-boot版本:友善之臂自带的 U-Boot 2010.12
busybox版本:busybox 1.25
目标:
设备树中普通的节点都被注册为平台设备驱动中的“设备”,也就是注册到 platform_bus_type 的,但是 i2c spi 设备等,它们都是注册到 i2c_bus_type spi_bus_type 的,那么内核在解析设备树的过程中是如何处理的呢?本文分析设备树解析过程中 i2c 设备的注册过程。掌握设备树中 i2c 设备的表示方式。
在内核中,i2c 控制器驱动内核已经支持的非常好了,我们做的只需要写设备驱动程序,经过粗略分析,在设备树中,内核是这样处理控制器驱动程序和设备驱动程序之间的关系的。控制器驱动为父节点,设备驱动为子节点,在注册控制器驱动时顺便会遍历子节点,将设备程序注册进去。下面分析代码。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
父节点为 i2c 控制器,子节点为挂载该控制器总线上的设备。
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
i2c_bus_type 的匹配过程:
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
结论:
2
3
4
5
6
1
2
3
4
5
6
compatible = “exynos4210-hdmiphy”;如果有“,”取“,”之后的内容,如果没有取全部作为 i2c_client 的名字。
要移植的内核版本:Linux-4.4.0 (支持device tree)
u-boot版本:友善之臂自带的 U-Boot 2010.12
busybox版本:busybox 1.25
目标:
设备树中普通的节点都被注册为平台设备驱动中的“设备”,也就是注册到 platform_bus_type 的,但是 i2c spi 设备等,它们都是注册到 i2c_bus_type spi_bus_type 的,那么内核在解析设备树的过程中是如何处理的呢?本文分析设备树解析过程中 i2c 设备的注册过程。掌握设备树中 i2c 设备的表示方式。
在内核中,i2c 控制器驱动内核已经支持的非常好了,我们做的只需要写设备驱动程序,经过粗略分析,在设备树中,内核是这样处理控制器驱动程序和设备驱动程序之间的关系的。控制器驱动为父节点,设备驱动为子节点,在注册控制器驱动时顺便会遍历子节点,将设备程序注册进去。下面分析代码。
i2c@138E0000 { #address-cells = <0x1>; #size-cells = <0x0>; compatible = "samsung,s3c2440-hdmiphy-i2c"; reg = <0x138e0000 0x100>; interrupts = <0x0 0x5d 0x0>; clocks = <0x7 0x145>; clock-names = "i2c"; status = "disabled"; hdmiphy@38 { compatible = "exynos4210-hdmiphy"; reg = <0x38>; linux,phandle = <0x30>; phandle = <0x30>; }; };1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
父节点为 i2c 控制器,子节点为挂载该控制器总线上的设备。
"samsung,s3c2440-hdmiphy-i2c" 对应的驱动程序中必然会注册控制器驱动 ret = i2c_add_numbered_adapter(&i2c->adap); //注册控制器驱动 if (adap->nr == -1) /* -1 means dynamically assign bus id */ return i2c_add_adapter(adap); return __i2c_add_numbered_adapter(adap); i2c_register_adapter of_i2c_register_devices(adap); for_each_available_child_of_node(adap->dev.of_node, node) { if (of_node_test_and_set_flag(node, OF_POPULATED)) continue; of_i2c_register_device(adap, node);1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, struct device_node *node) { struct i2c_client *result; struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; const __be32 *addr_be; u32 addr; int len; of_modalias_node(node, info.type, sizeof(info.type)) addr_be = of_get_property(node, "reg", &len); addr = be32_to_cpup(addr_be); if (addr & I2C_TEN_BIT_ADDRESS) { addr &= ~I2C_TEN_BIT_ADDRESS; info.flags |= I2C_CLIENT_TEN; } if (addr & I2C_OWN_SLAVE_ADDRESS) { addr &= ~I2C_OWN_SLAVE_ADDRESS; info.flags |= I2C_CLIENT_SLAVE; } i2c_check_addr_validity(addr, info.flags)) info.addr = addr; info.of_node = of_node_get(node); info.archdata = &dev_ad; if (of_get_property(node, "wakeup-source", NULL)) info.flags |= I2C_CLIENT_WAKE; result = i2c_new_device(adap, &info); return result; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// info.type == strlcpy(modalias, p ? p + 1 : compatible, len);//如果有“,”取“,”之后的内容,如果没有取全部 int of_modalias_node(struct device_node *node, char *modalias, int len) { const char *compatible, *p; int cplen; compatible = of_get_property(node, "compatible", &cplen); if (!compatible || strlen(compatible) > cplen) return -ENODEV; p = strchr(compatible, ','); strlcpy(modalias, p ? p + 1 : compatible, len);//如果有“,”取“,”之后的内容,如果没有取全部 return 0; }1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); match 函数: static int i2c_device_match(struct device *dev, struct device_driver *drv) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; if (!client) return 0; driver = to_i2c_driver(drv); /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; return 0; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
i2c_bus_type 的匹配过程:
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, const struct i2c_client *client) { while (id->name[0]) { if (strcmp(client->name, id->name) == 0) return id; id++; } return NULL; }1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
结论:
hdmiphy@38 { compatible = "exynos4210-hdmiphy"; reg = <0x38>; linux,phandle = <0x30>; phandle = <0x30>; };1
2
3
4
5
6
1
2
3
4
5
6
compatible = “exynos4210-hdmiphy”;如果有“,”取“,”之后的内容,如果没有取全部作为 i2c_client 的名字。
相关文章推荐
- 设备树学习之(七)I2C设备的注册过程分析
- 设备树学习之(七)I2C设备的注册过程分析
- linux-i2c驱动 之 i2c设备层的注册过程probe函数如何被调用分析
- 设备树学习之(九)SPI设备注册过程
- 设备树学习之(九)SPI设备注册过程
- 设备树学习之(九)SPI设备注册过程
- PCI设备的注册过程分析
- u-boot2013.01 使用设备树,设备树获得bootargs过程分析
- Linux下i2c设备的注册过程
- linux powerpc i2c驱动 之 i2c设备层的注册过程
- PCI设备的注册过程分析1
- linux powerpc i2c驱动 之 i2c设备层的注册过程
- linux I2C设备写操作错误的分析过程
- 今天我以fb设备的注册过程来分析platform设备的添加流程
- linux i2c子系统代码分析9---i2c设备的注册方法
- linux powerpc i2c驱动 之 i2c设备层的注册过程
- Linux PowerPC I2C驱动 之 I2C设备层的注册过程
- davinci i2c 设备注册的过程 笔记
- Lucene学习总结之五:Lucene段合并(merge)过程分析
- Lucene学习总结之四:Lucene索引过程分析(2)