625 unsigned *const num_pins) 626{
627 *pins = (unsigned *) foo_groups[selector].pins; 628 *num_pins =foo_groups[selector].num_pins; 629 return 0; 630} 631
632static struct pinctrl_ops foo_pctrl_ops = { 633 .get_groups_count =foo_get_groups_count, 634 .get_group_name = foo_get_group_name, 635 .get_group_pins = foo_get_group_pins, 636}; 637
638struct foo_pmx_func { 639 const char *name;
640 const char * const *groups; 641 const unsigned num_groups; 642}; 643
644static const char * const spi0_groups[] = { \645static const char * const i2c0_groups[] = { \
646static const char * const mmc0_groups[] = { \647 \648
649static const struct foo_pmx_func foo_functions[] = { 650 {
651 .name = \652 .groups = spi0_groups,
653 .num_groups =ARRAY_SIZE(spi0_groups), 654 }, 655 {
656 .name = \657 .groups = i2c0_groups,
658 .num_groups =ARRAY_SIZE(i2c0_groups), 659 }, 660 {
661 .name = \
662 .groups = mmc0_groups,
663 .num_groups =ARRAY_SIZE(mmc0_groups), 664 }, 665}; 666
667int foo_get_functions_count(struct pinctrl_dev *pctldev) 668{
669 return ARRAY_SIZE(foo_functions); 670} 671
672const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector) 673{
674 return foo_functions[selector].name; 675} 676
677static int foo_get_groups(struct pinctrl_dev *pctldev, unsigned selector, 678 const char * const**groups, 679 unsigned * constnum_groups) 680{
681 *groups = foo_functions[selector].groups;
682 *num_groups =foo_functions[selector].num_groups; 683 return 0; 684} 685
686int foo_enable(struct pinctrl_dev *pctldev, unsigned selector, 687 unsigned group) 688{
689 u8 regbit = (1 < selector groupp> 690
691 writeb((readb(MUX)|regbit), MUX) 692 return 0; 693} 694
695void foo_disable(struct pinctrl_dev *pctldev, unsigned selector, 696 unsigned group) 697{
698 u8 regbit = (1 < selector groupp>
699
700 writeb((readb(MUX) & ~(regbit)),MUX) 701 return 0; 702} 703
704 structpinmux_ops foo_pmxops = {
705 .get_functions_count =foo_get_functions_count, 706 .get_function_name = foo_get_fname, 707 .get_function_groups = foo_get_groups, 708 .enable = foo_enable, 709 .disable = foo_disable, 710}; 711
712/* Pinmux operations are handled by some pin controller */ 713static struct pinctrl_desc foo_desc = { 714 ...
715 .pctlops = &foo_pctrl_ops, 716 .pmxops = &foo_pmxops, 717}; 718
具体的pinctrl、使用引脚的设备、功能、引脚组的映射关系,可以在板文件中透过定义pinctrl_map结构体的实例来展开,如:
828static struct pinctrl_map __initdata mapping[] = {
829 PIN_MAP_MUX_GROUP(\830};
PIN_MAP_MUX_GROUP是一个快捷的宏,用于赋值pinctrl_map的各个成员: 88#define PIN_MAP_MUX_GROUP(dev, state, pinctrl, grp, func) \\ 89 { \\
90 .dev_name = dev, \\ 91 .name = state, \\
92 .type =PIN_MAP_TYPE_MUX_GROUP, \\ 93 .ctrl_dev_name = pinctrl, \\ 94 .data.mux = { \\ 95 .group = grp, \\ 96 .function = func, \\ 97 }, \\ 98 }
99
当然,这种映射关系最好是在DeviceTree中透过结点的属性进行,具体的结点属性的定义方法依赖于具体的pinctrl驱动,最终在pinctrl驱动中透过pinctrl_ops结构体的.dt_node_to_map()成员函数读出属性并建立映射表。 又由于1个功能可能可由2个不同的引脚组实现,可能形成如下对于同1个功能有2个可选引脚组的pinctrl_map: staticstruct pinctrl_map __initdata mapping[] = {
PIN_MAP_MUX_GROUP(\PIN_MAP_MUX_GROUP(\};
在运行时,我们可以透过类似的API去查找并设置位置A的引脚组行驶SPI接口的功能: 954 p = devm_pinctrl_get(dev);
955 s = pinctrl_lookup_state(p, \ 956 ret = pinctrl_select_state(p, s); 或者可以更加简单地使用:
p =devm_pinctrl_get_select(dev, \
若想运行时切换位置A和B的引脚组行使SPI的接口功能,代码结构类似: 1163foo_probe() 1164{
1165 /* Setup */
1166 p = devm_pinctrl_get(&device); 1167 if (IS_ERR(p)) 1168 ... 1169
1170 s1 = pinctrl_lookup_state(foo-
1174 s2 = pinctrl_lookup_state(foo-
1179foo_switch() 1180{
1181 /* Enable on position A */ 1182 ret = pinctrl_select_state(s1); 1183 if (ret < 0 p> 1184 ...
1185 1186 ... 1187
1188 /* Enable on position B */ 1189 ret = pinctrl_select_state(s2); 1190 if (ret < 0 p> 1191 ... 1192 1193 ... 1194}
pinctrl子系统中定义了pinctrl_get_select_default()以及有devm_前缀的devm_ pinctrl_get_select() API,许多驱动如drivers/i2c/busses/i2c-imx.c、drivers/leds/leds-gpio.c、drivers/spi/spi-imx.c、
drivers/tty/serial/omap-serial.c、sound/soc/mxs/mxs-saif.c都是透过这一API来获取自己的引脚组的。xxx_get_select_default()最终会调用
pinctrl_get_select(dev,PINCTRL_STATE_DEFAULT);
其中PINCTRL_STATE_DEFAULT定义为\,它描述了缺省状态下某设备的pinmux功能和引脚组映射情况。
8. clock驱动
在一个SoC中,晶振、PLL、divider和gate等会形成一个clock树形结构,在Linux 2.6中,也存有clk_get_rate()、clk_set_rate()、clk_get_parent()、clk_set_parent()等通用API,但是这些API由每个SoC单独实现,而且各个SoC供应商在实现方面的差异很大,于是内核增加了一个新的common clk框架以解决这个碎片化问题。之所以称为common clk,这个common主要体现在:
§ 统一的clk结构体,统一的定义于clk.h中的clk API,这些API会调用到统一的clk_ops中的callback函数; 这个统一的 clk结构体的定义如下: struct clk {
const char *name; const struct clk_ops *ops; struct clk_hw *hw; char **parent_names; struct clk **parents; struct clk *parent; struct hlist_head children; struct hlist_node child_node; ... };
其中的clk_ops定义为: struct clk_ops {