概述
在查看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 drivern");
}
每个具体的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,
};
未完待续。。。。
最后
以上就是大力春天为你收集整理的设备驱动中的pinctrl(kernel-4.7)的全部内容,希望文章能够帮你解决设备驱动中的pinctrl(kernel-4.7)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复