设备树 — platform_device和platform_driver如何让匹配

  4.x的内核都是已经支持设备树的,所以platform bus也是做了一些调整。

  主要是在匹配函数里面的支持设备树。

1

2

3

4

5

6

7

8

struct bus_type platform_bus_type = {

    .name       = "platform",

    .dev_groups = platform_dev_groups,

    .match      = platform_match,

    .uevent     = platform_uevent,

    .dma_configure  = platform_dma_configure,

    .pm     = &platform_dev_pm_ops,

};

  

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

39

40

41

/**

 * platform_match - bind platform device to platform driver.

 * @dev: device.

 * @drv: driver.

 *

 * Platform device IDs are assumed to be encoded like this:

 * "<name><instance>", where <name> is a short description of the type of

 * device, like "pci" or "floppy", and <instance> is the enumerated

 * instance of the device, like '0' or '42'.  Driver IDs are simply

 * "<name>".  So, extract the <name> from the platform_device structure,

 * and compare it against the name of the driver. Return whether they match

 * or not.

 */

static int platform_match(struct device *dev, struct device_driver *drv)

{

    struct platform_device *pdev = to_platform_device(dev);

    struct platform_driver *pdrv = to_platform_driver(drv);

  

    /* When driver_override is set, only bind to the matching driver */

    /* 针对特殊情况,dev中的driver_override被设置,则只匹配和driver_override名字相同的驱动程序 */

    if (pdev->driver_override)

        return !strcmp(pdev->driver_override, drv->name);

  

    /* Attempt an OF style match first,设备树方式匹配 */

    if (of_driver_match_device(dev, drv))

        return 1;

  

    /* Then try ACPI style match */

    /* 高级配置和电源管理之类的匹配,这里不是我们这次的重点 */

    if (acpi_driver_match_device(dev, drv))

        return 1;

  

    /* Then try to match against the id table */

    /* 有驱动中有id_table,则dev中的名字和任何一个id_table里面的值匹配就认为匹配 */

    if (pdrv->id_table)

        return platform_match_id(pdrv->id_table, pdev) != NULL;

  

    /* fall-back to driver name match */

    /* 驱动和设备的名字匹配 */

    return (strcmp(pdev->name, drv->name) == 0);

}

  这里可以看到匹配的优先级如下:

  1. 设备里的driver_override被设置,优先级最高。
  2. 驱动里的of_match_table,和平台设备的compatible比较。
  3. 高级配置和电源管理之类的匹配。
  4. platform_driver里的id_table里的所有名字和设备名字匹配。
  5. 最后再是设备名字和驱动名字比较。

  当然除了第一个之外,其它的只要没匹配到,后面的几个匹配还会继续执行的。

设备树匹配方式

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

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

/**

 * of_driver_match_device - Tell if a driver's of_match_table matches a device.

 * @drv: the device_driver structure to test

 * @dev: the device structure to match against

 */

static inline int of_driver_match_device(struct device *dev,

                     const struct device_driver *drv)

{

    return of_match_device(drv->of_match_table, dev) != NULL;

}

  

  

/**

 * of_match_device - Tell if a struct device matches an of_device_id list

 * @ids: array of of device match structures to search in

 * @dev: the of device structure to match against

 *

 * Used by a driver to check whether an platform_device present in the

 * system is in its list of supported devices.

 */

const struct of_device_id *of_match_device(const struct of_device_id *matches,

                       const struct device *dev)

{

    if ((!matches) || (!dev->of_node))

        return NULL;

    return of_match_node(matches, dev->of_node);

}

  

  

  

/**

 * of_match_node - Tell if a device_node has a matching of_match structure

 *  @matches:   array of of device match structures to search in

 *  @node:      the of device structure to match against

 *

 *  Low level utility function used by device matching.

 */

const struct of_device_id *of_match_node(const struct of_device_id *matches,

                     const struct device_node *node)

{

    const struct of_device_id *match;

    unsigned long flags;

  

    raw_spin_lock_irqsave(&devtree_lock, flags);

    match = __of_match_node(matches, node);

    raw_spin_unlock_irqrestore(&devtree_lock, flags);

    return match;

}

  

static

const struct of_device_id *__of_match_node(const struct of_device_id *matches,

                       const struct device_node *node)

{

    const struct of_device_id *best_match = NULL;

    int score, best_score = 0;

  

    if (!matches)

        return NULL;

  

    //根据匹配的分数,选择最高分的是最佳匹配

    for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {

        score = __of_device_is_compatible(node, matches->compatible,

                          matches->type, matches->name);

        if (score > best_score) {

            best_match = matches;

            best_score = score;

        }

    }

  

    return best_match;

}

  

  

  

/**

 * __of_device_is_compatible() - Check if the node matches given constraints

 * @device: pointer to node

 * @compat: required compatible string, NULL or "" for any match

 * @type: required device_type value, NULL or "" for any match

 * @name: required node name, NULL or "" for any match

 *

 * Checks if the given @compat, @type and @name strings match the

 * properties of the given @device. A constraints can be skipped by

 * passing NULL or an empty string as the constraint.

 *

 * Returns 0 for no match, and a positive integer on match. The return

 * value is a relative score with larger values indicating better

 * matches. The score is weighted for the most specific compatible value

 * to get the highest score. Matching type is next, followed by matching

 * name. Practically speaking, this results in the following priority

 * order for matches:

 *

 * 1. specific compatible && type && name

 * 2. specific compatible && type

 * 3. specific compatible && name

 * 4. specific compatible

 * 5. general compatible && type && name

 * 6. general compatible && type

 * 7. general compatible && name

 * 8. general compatible

 * 9. type && name

 * 10. type

 * 11. name

 */

static int __of_device_is_compatible(const struct device_node *device,

                     const char *compat, const char *type, const char *name)

{

    struct property *prop;

    const char *cp;

    int index = 0, score = 0;

  

    /* Compatible match has highest priority */

    /* compatible 匹配有限即最高,匹配到了,则给的分数相对较高 */

    if (compat && compat[0]) {

        prop = __of_find_property(device, "compatible", NULL);

        for (cp = of_prop_next_string(prop, NULL); cp;

             cp = of_prop_next_string(prop, cp), index++) {

            if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {

                score = INT_MAX/2 - (index << 2);

                break;

            }

        }

        if (!score)

            return 0;

    }

  

    /* Matching type is better than matching name,类型匹配会加2分 */

    if (type && type[0]) {

        if (!device->type || of_node_cmp(type, device->type))

            return 0;

        score += 2;

    }

  

    /* Matching name is a bit better than not,最后在确认名字匹配加1分 */

    if (name && name[0]) {

        if (!device->name || of_node_cmp(name, device->name))

            return 0;

        score++;

    }

  

    return score;

}

  看这句 prop = __of_find_property(device, "compatible", NULL);
  可以发先追溯到底,是利用"compatible"来匹配的,即设备树加载之后,内核会自动把设备树节点转换成 platform_device这种格式,同时把名字放到of_node这个地方。

  id_tabel是根据id_table表中的每一个和设备名字进行匹配,这样一个驱动可以支持多个名称的设备。

1

2

3

4

5

6

7

8

9

10

11

12

13

static const struct platform_device_id *platform_match_id(

            const struct platform_device_id *id,

            struct platform_device *pdev)

{

    while (id->name[0]) {

        if (strcmp(pdev->name, id->name) == 0) {

            pdev->id_entry = id;

            return id;

        }

        id++;

    }

    return NULL;

}

  

举例:

  1.ti的omap8250驱动可以支持好多个型号的芯片,其它芯片只要这个的驱动基础上做很小的改动就可通用。

  其中的改动点,使用of_device_id 的date表示的。

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

/*

 * Struct used for matching a device

 */

struct of_device_id {

    char    name[32];

    char    type[32];

    char    compatible[128];

    const void *data;

};

  

  

  

static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE;

static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE;

static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE;

  

  

static const struct of_device_id omap8250_dt_ids[] = {

    { .compatible = "ti,am654-uart" },

    { .compatible = "ti,omap2-uart" },

    { .compatible = "ti,omap3-uart" },

    { .compatible = "ti,omap4-uart", .data = &omap4_habit, },

    { .compatible = "ti,am3352-uart", .data = &am3352_habit, },

    { .compatible = "ti,am4372-uart", .data = &am3352_habit, },

    { .compatible = "ti,dra742-uart", .data = &dra742_habit, },

    {},

};

  

  

static struct platform_driver omap8250_platform_driver = {

    .driver = {

        .name       = "omap8250",

        .pm     = &omap8250_dev_pm_ops,

        .of_match_table = omap8250_dt_ids,

    },

    .probe          = omap8250_probe,

    .remove         = omap8250_remove,

};

  

2.ad5380有好多中类型,芯片使用完全兼容。可能就是版本差异。驱动可以完全兼容。

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

static const struct spi_device_id ad5380_spi_ids[] = {

    "ad5380-3", ID_AD5380_3 },

    "ad5380-5", ID_AD5380_5 },

    "ad5381-3", ID_AD5381_3 },

    "ad5381-5", ID_AD5381_5 },

    "ad5382-3", ID_AD5382_3 },

    "ad5382-5", ID_AD5382_5 },

    "ad5383-3", ID_AD5383_3 },

    "ad5383-5", ID_AD5383_5 },

    "ad5384-3", ID_AD5380_3 },

    "ad5384-5", ID_AD5380_5 },

    "ad5390-3", ID_AD5390_3 },

    "ad5390-5", ID_AD5390_5 },

    "ad5391-3", ID_AD5391_3 },

    "ad5391-5", ID_AD5391_5 },

    "ad5392-3", ID_AD5392_3 },

    "ad5392-5", ID_AD5392_5 },

    { }

};

MODULE_DEVICE_TABLE(spi, ad5380_spi_ids);

  

static struct spi_driver ad5380_spi_driver = {

    .driver = {

           .name = "ad5380",

    },

    .probe = ad5380_spi_probe,

    .remove = ad5380_spi_remove,

    .id_table = ad5380_spi_ids,

};

  最后总结一下有了设备树前后,设备驱动怎么写

  有了设备树这样在dts中编写

1

2

3

4

samsung-beep{

         compatible = "samsung,beep";

         reg = <0x114000a0 0x4 0x139D0000 0x14>;

};

  a -- samsung-beep 为节点名,符合咱们前面提到的节点命名规范;

      我们通过名字可以知道,该节点描述的设备是beep, 设备名是samsung-beep;

  b -- compatible = "samsung,beep"; compatible 属性, 即一个字符串;

      前面提到,所有新的compatible值都应使用制造商的前缀,这里是samsung

  c -- reg = <0x114000a0 0x4 0x139D0000 0x14>;

       reg属性来将地址信息编码进设备树,表示该设备的地址范围;这里是我们用到的寄存器及偏移量;
 

之前在mach-xxx.c中编写

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

static struct  resource beep_resource[] =

{

    [0] = {

        .start = 0x114000a0,

        .end = 0x114000a0+0x4,

        .flags = IORESOURCE_MEM,

    },

    [1] = {

        .start = 0x139D0000,

        .end = 0x139D0000+0x14,

        .flags = IORESOURCE_MEM,

    },

};

static struct platform_device hello_device=

{

    .name = "beep",

    .id = -1,

    .dev.release = hello_release,

    .num_resources = ARRAY_SIZE(beep_resource ),

    .resource = beep_resource,

};

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值