设备驱动中的pinctrl(kernel-4.7)

来源:互联网 发布:光猫 连接端口23失败 编辑:程序博客网 时间:2024/06/02 12:22

在查看kernel源码时,很容易忽略大量的英文注释,其实,英文注解很好的提示代码的功用,所以,网上没有好的参考资料,可以参考英文注释来分析。
下面是driver/pinctrl/core.h中关于pinctrl的重要结构体定义:

/** * struct pinctrl_dev - pin control class device * @node: node to include this pin controller in the global pin controller list * @desc: the pin controller descriptor supplied when initializing this pin *  controller * @pin_desc_tree: each pin descriptor for this pin controller is stored in *  this radix tree * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller, *  ranges are added to this list at runtime * @dev: the device entry for this pin controller * @owner: module providing the pin controller, used for refcounting * @driver_data: driver data for drivers registering to the pin controller *  subsystem * @p: result of pinctrl_get() for this device * @hog_default: default state for pins hogged by this device * @hog_sleep: sleep state for pins hogged by this device * @mutex: mutex taken on each pin controller specific action * @device_root: debugfs root for this device */struct pinctrl_dev {    struct list_head node;    struct pinctrl_desc *desc;    struct radix_tree_root pin_desc_tree;    struct list_head gpio_ranges;    struct device *dev;    struct module *owner;    void *driver_data;    struct pinctrl *p;    struct pinctrl_state *hog_default;    struct pinctrl_state *hog_sleep;    struct mutex mutex;#ifdef CONFIG_DEBUG_FS    struct dentry *device_root;#endif}; /** * struct pinctrl - per-device pin control state holder * @node: global list node * @dev: the device using this pin control handle * @states: a list of states for this device * @state: the current state * @dt_maps: the mapping table chunks dynamically parsed from device tree for *  this device, if any * @users: reference count */struct pinctrl {    struct list_head node;    struct device *dev;    struct list_head states;    struct pinctrl_state *state;    struct list_head dt_maps;    struct kref users;}; /** * struct pinctrl_state - a pinctrl state for a device * @node: list node for struct pinctrl's @states field * @name: the name of this state * @settings: a list of settings for this state */struct pinctrl_state {    struct list_head node;    const char *name;    struct list_head settings;};

下面include/linux/pinctrl.h中pinctrl操作重要的结构体,阅读英文注释了解功用:

/** * struct pinctrl_pin_desc - boards/machines provide information on their * pins, pads or other muxable units in this struct * @number: unique pin number from the global pin number space * @name: a name for this pin * @drv_data: driver-defined per-pin data. pinctrl core does not touch this */struct pinctrl_pin_desc {    unsigned number;    const char *name;    void *drv_data;};/** * struct pinctrl_gpio_range - each pin controller can provide subranges of * the GPIO number space to be handled by the controller * @node: list node for internal use * @name: a name for the chip in this range * @id: an ID number for the chip in this range * @base: base offset of the GPIO range * @pin_base: base pin number of the GPIO range if pins == NULL * @pins: enumeration of pins in GPIO range or NULL * @npins: number of pins in the GPIO range, including the base number * @gc: an optional pointer to a gpio_chip */struct pinctrl_gpio_range {    struct list_head node;    const char *name;    unsigned int id;    unsigned int base;    unsigned int pin_base;    unsigned const *pins;    unsigned int npins;    struct gpio_chip *gc;};/** * struct pinctrl_ops - global pin control operations, to be implemented by * pin controller drivers. * @get_groups_count: Returns the count of total number of groups registered. * @get_group_name: return the group name of the pin group * @get_group_pins: return an array of pins corresponding to a certain *  group selector @pins, and the size of the array in @num_pins * @pin_dbg_show: optional debugfs display hook that will provide per-device *  info for a certain pin in debugfs * @dt_node_to_map: parse a device tree "pin configuration node", and create *  mapping table entries for it. These are returned through the @map and *  @num_maps output parameters. This function is optional, and may be *  omitted for pinctrl drivers that do not support device tree. * @dt_free_map: free mapping table entries created via @dt_node_to_map. The *  top-level @map pointer must be freed, along with any dynamically *  allocated members of the mapping table entries themselves. This *  function is optional, and may be omitted for pinctrl drivers that do *  not support device tree. */struct pinctrl_ops {    int (*get_groups_count) (struct pinctrl_dev *pctldev);    const char *(*get_group_name) (struct pinctrl_dev *pctldev,                       unsigned selector);    int (*get_group_pins) (struct pinctrl_dev *pctldev,                   unsigned selector,                   const unsigned **pins,                   unsigned *num_pins);    void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,              unsigned offset);    int (*dt_node_to_map) (struct pinctrl_dev *pctldev,                   struct device_node *np_config,                   struct pinctrl_map **map, unsigned *num_maps);    void (*dt_free_map) (struct pinctrl_dev *pctldev,                 struct pinctrl_map *map, unsigned num_maps);};/** * struct pinctrl_desc - pin controller descriptor, register this to pin * control subsystem * @name: name for the pin controller * @pins: an array of pin descriptors describing all the pins handled by *  this pin controller * @npins: number of descriptors in the array, usually just ARRAY_SIZE() *  of the pins field above * @pctlops: pin control operation vtable, to support global concepts like *  grouping of pins, this is optional. * @pmxops: pinmux operations vtable, if you support pinmuxing in your driver * @confops: pin config operations vtable, if you support pin configuration in *  your driver * @owner: module providing the pin controller, used for refcounting * @num_custom_params: Number of driver-specific custom parameters to be parsed *  from the hardware description * @custom_params: List of driver_specific custom parameters to be parsed from *  the hardware description * @custom_conf_items: Information how to print @params in debugfs, must be *  the same size as the @custom_params, i.e. @num_custom_params */struct pinctrl_desc {    const char *name;    const struct pinctrl_pin_desc *pins;    unsigned int npins;    const struct pinctrl_ops *pctlops;    const struct pinmux_ops *pmxops;    const struct pinconf_ops *confops;    struct module *owner;#ifdef CONFIG_GENERIC_PINCONF    unsigned int num_custom_params;    const struct pinconf_generic_params *custom_params;    const struct pin_config_item *custom_conf_items;#endif};

当内核使用pinctrl,pinctrl模块被初始化,将cpu的pin在pinctrl框架中注册一个pin的描述符,这个描述符包含了每个pin描述符组成的数列,用来对特定的pin进行操作。kernel中给出pinctrl的使用示例,如下:

一个PGA的 chip底层 :

      A   B   C   D   E   F   G   H   8    o   o   o   o   o   o   o   o   7    o   o   o   o   o   o   o   o   6    o   o   o   o   o   o   o   o   5    o   o   o   o   o   o   o   o   4    o   o   o   o   o   o   o   o   3    o   o   o   o   o   o   o   o   2    o   o   o   o   o   o   o   o   1    o   o   o   o   o   o   o   o

将以上每个pin的控制器和名字都加入到驱动中,一边对pin进行操作:

#include <linux/pinctrl/pinctrl.h>const struct pinctrl_pin_desc foo_pins[] = {      PINCTRL_PIN(0, "A8"),      PINCTRL_PIN(1, "B8"),      PINCTRL_PIN(2, "C8"),      ...      PINCTRL_PIN(61, "F1"),      PINCTRL_PIN(62, "G1"),      PINCTRL_PIN(63, "H1"),};static struct pinctrl_desc foo_desc = {    .name = "foo",    .pins = foo_pins,    .npins = ARRAY_SIZE(foo_pins),    .owner = THIS_MODULE,};int __init foo_probe(void){    struct pinctrl_dev *pctl;    pctl = pinctrl_register(&foo_desc, <PARENT>, NULL);    if (!pctl)        pr_err("could not register foo pin driver\n");}

每个具体的pin的名字和功用需要查看芯片手册来进行注册使用。
driver/pinctrl.h中定义了PINCTR_PIN()创建对pin的注册。

/* Convenience macro to define a single named or anonymous pin descriptor */#define PINCTRL_PIN(a, b) { .number = a, .name = b }#define PINCTRL_PIN_ANON(a) { .number = a } 

如果需要对一组pin 进行控制操作,则使用pinctrl子系统提供的group管理进行。例如,如果有一组SPI接口使用的pins:on { 0, 8, 16, 24 },
一组I2C使用的pins:on { 24, 25 } ,这两组pinctrl的注册使用可以用pinctlr_ops来实现:

#include <linux/pinctrl/pinctrl.h>struct foo_group {    const char *name;    const unsigned int *pins;    const unsigned num_pins;};static const unsigned int spi0_pins[] = { 0, 8, 16, 24 };static const unsigned int i2c0_pins[] = { 24, 25 };static const struct foo_group foo_groups[] = {    {        .name = "spi0_grp",        .pins = spi0_pins,        .num_pins = ARRAY_SIZE(spi0_pins),    },    {        .name = "i2c0_grp",        .pins = i2c0_pins,        .num_pins = ARRAY_SIZE(i2c0_pins),    },};static int foo_get_groups_count(struct pinctrl_dev *pctldev){    return ARRAY_SIZE(foo_groups);}static const char *foo_get_group_name(struct pinctrl_dev *pctldev,                       unsigned selector){    return foo_groups[selector].name;}static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,                   const unsigned **pins,                   unsigned *num_pins){    *pins = (unsigned *) foo_groups[selector].pins;    *num_pins = foo_groups[selector].num_pins;    return 0;}static struct pinctrl_ops foo_pctrl_ops = {    .get_groups_count = foo_get_groups_count,    .get_group_name = foo_get_group_name,    .get_group_pins = foo_get_group_pins,};static struct pinctrl_desc foo_desc = {       ...       .pctlops = &foo_pctrl_ops,};

pinctrl子系统将会调用get_groups_count() 来获取定义好的一组pins,然后调用其他函数来获取组中pin名。上面是简单示例,具体的驱动中会需要定义更复杂的group来实现特定的pin操作。

pin的配置在驱动中可以将配置条件到mapping table中,

#include <linux/pinctrl/pinctrl.h>#include <linux/pinctrl/pinconf.h>#include "platform_x_pindefs.h"static int foo_pin_config_get(struct pinctrl_dev *pctldev,            unsigned offset,            unsigned long *config){    struct my_conftype conf;    ... Find setting for pin @ offset ...    *config = (unsigned long) conf;}static int foo_pin_config_set(struct pinctrl_dev *pctldev,            unsigned offset,            unsigned long config){    struct my_conftype *conf = (struct my_conftype *) config;    switch (conf) {        case PLATFORM_X_PULL_UP:        ...        }    }}static int foo_pin_config_group_get (struct pinctrl_dev *pctldev,            unsigned selector,            unsigned long *config){    ...}static int foo_pin_config_group_set (struct pinctrl_dev *pctldev,            unsigned selector,            unsigned long config){    ...}static struct pinconf_ops foo_pconf_ops = {    .pin_config_get = foo_pin_config_get,    .pin_config_set = foo_pin_config_set,    .pin_config_group_get = foo_pin_config_group_get,    .pin_config_group_set = foo_pin_config_group_set,};/* Pin config operations are handled by some pin controller */static struct pinctrl_desc foo_desc = {    ...    .confops = &foo_pconf_ops,};

未完待续。。。。

0 0
原创粉丝点击