linux pinctrl驱动分析 altas200模块
准备
使用的源码包为华为官方的ascend200AI加速模块的SDK,其下载地址位于:点击跳转
使用的固件与驱动版本为:1.0.9.alpha
压缩包名称为:A200-3000-sdk_20.2.0.zip
将A200-3000-sdk_20.2.0.zip解压后可以看到Ascend310-source-minirc.tar.gz压缩包,这个压缩包里有ascend200AI加速模块的linux内核源码包、设备树及驱动文件等。
设备树节点
pinctrl的设备树节点位于source/dtb/hi1910-asic-000-pinctrl.dtsi
这里以pmx_ctrl1节点和pmx_cfg1两个节点为例:
pmx_ctrl1: pinmux@110080000 {
compatible = "pinctrl-single", "pinctrl-single1";
reg = <0x1 0x10080000 0x0 0x38>;
#gpio-range-cells = <3>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <7>;
gpio2_pmx_func: gpio2_pmx_func {
pinctrl-single,pins = <0x2c 0x0>;
};
gpio2_pmx_idle: gpio2_pmx_idle {
pinctrl-single,pins = <0x2c 0x0>;
};
gpio3_pmx_func: gpio3_pmx_func {
pinctrl-single,pins = <0x30 0x0>;
};
gpio3_pmx_idle: gpio3_pmx_idle {
pinctrl-single,pins = <0x30 0x0>;
};
};
pmx_cfg1: pinmux@110080800 {
compatible = "pinconf-single", "pinctrl-single1";
reg = <0x1 0x10080800 0x0 0x05c>;
pinctrl-single,register-width = <32>;
gpio6_cfg_func: gpio6_cfg_func {
pinctrl-single,pins = <0x28 0>;
pinctrl-single,bias-pulldown = <0 2 0 2>;
pinctrl-single,bias-pullup = <1 1 0 1>;
pinctrl-single,drive-strength = <0x30 0x70>;
};
gpio6_cfg_idle: gpio6_cfg_idle {
pinctrl-single,pins = <0x28 0>;
pinctrl-single,bias-pulldown = <0 2 0 2>;
pinctrl-single,bias-pullup = <1 1 0 1>;
pinctrl-single,drive-strength = <0x30 0x70>;
};
gpio2_cfg_func: gpio2_cfg_func {
pinctrl-single,pins = <0x50 0>;
pinctrl-single,bias-pulldown = <2 2 0 2>;
pinctrl-single,bias-pullup = <0 1 0 1>;
pinctrl-single,drive-strength = <0x30 0x70>;
pinctrl-single,input-schmitt-enable = <8 8 0 8>;
};
gpio2_cfg_idle: gpio2_cfg_idle {
pinctrl-single,pins = <0x50 0>;
pinctrl-single,bias-pulldown = <2 2 0 2>;
pinctrl-single,bias-pullup = <0 1 0 1>;
pinctrl-single,drive-strength = <0x30 0x70>;
pinctrl-single,input-schmitt-enable = <8 8 0 8>;
};
gpio3_cfg_func: gpio3_cfg_func {
pinctrl-single,pins = <0x54 0>;
pinctrl-single,bias-pulldown = <0 2 0 2>;
pinctrl-single,bias-pullup = <1 1 0 1>;
pinctrl-single,drive-strength = <0x30 0x70>;
pinctrl-single,input-schmitt-enable = <8 8 0 8>;
};
gpio3_cfg_idle: gpio3_cfg_idle {
pinctrl-single,pins = <0x54 0>;
pinctrl-single,bias-pulldown = <0 2 0 2>;
pinctrl-single,bias-pullup = <1 1 0 1>;
pinctrl-single,drive-strength = <0x30 0x70>;
pinctrl-single,input-schmitt-enable = <8 8 0 8>;
};
};
pinctrl驱动分析
设备树节点无论是pinconf-single还是pinctrl-single匹配到的都是source\kernel\linux-4.19\drivers\pinctrl\pinctrl-single.c
pcs_probe函数
static int pcs_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct pcs_pdata *pdata;
struct resource *res;
struct pcs_device *pcs;
const struct pcs_soc_data *soc;
int ret;
//of_device_get_match_data 判断dts中的compatible属性是否包含driver中指定的compatible,
// 实际上返回的是dev->driver->of_match_table->data。
// data是void *类型,自己如果想取到data里的值,就可以自己定义类型,里面可以放一些自己需要的参数。
//of_device_get_match_data对于pmx_ctrl1节点,它的data为空,可以不管
//而pmx_cfg1节点此时soc->flag=PCS_FEAT_PINCONF。让后给pcs分配内存
//PCS_FEAT_PINCONF (1 << 0)
soc = of_device_get_match_data(&pdev->dev);
if (WARN_ON(!soc))
return -EINVAL;
//申请pcs结构体内存,这个pdev->dev这个参数是为了绑定这片内存
//devm_kzalloc分配的内存当指定的dev驱动被注销时会自动释放
pcs = devm_kzalloc(&pdev->dev, sizeof(*pcs), GFP_KERNEL);
if (!pcs)
return -ENOMEM;
//这个np是dtb转化的device_node
pcs->dev = &pdev->dev;
pcs->np = np;
raw_spin_lock_init(&pcs->lock);
mutex_init(&pcs->mutex);
//初始化链表
INIT_LIST_HEAD(&pcs->gpiofuncs);
//pcs->flags = PCS_FEAT_PINCONF = 1
pcs->flags = soc->flags;
//之后pcs->socdata指向soc结构体
memcpy(&pcs->socdata, soc, sizeof(*soc));
//获取"pinctrl-single,register-width"属性,好像是寄存器的位宽,都是32位的
ret = of_property_read_u32(np, "pinctrl-single,register-width",
&pcs->width);
if (ret) {
dev_err(pcs->dev, "register width not specified\n");
return ret;
}
//pcs->fmask是7
ret = of_property_read_u32(np, "pinctrl-single,function-mask",
&pcs->fmask);
if (!ret) {
//存在属性,所以指向下面的代码
//__ffs 用于找到一个int或者long行最高哪位是1,例如0x8000,就会返回15.
//pcs->fshift 为2 pcs->fmax为1
pcs->fshift = __ffs(pcs->fmask);
pcs->fmax = pcs->fmask >> pcs->fshift;
} else {
/* If mask property doesn't exist, function mux is invalid. */
pcs->fmask = 0;
pcs->fshift = 0;
pcs->fmax = 0;
}
//这个属性没有
ret = of_property_read_u32(np, "pinctrl-single,function-off",
&pcs->foff);
if (ret)
pcs->foff = PCS_OFF_DISABLED;
//这个没有读到 也是0
pcs->bits_per_mux = of_property_read_bool(np,
"pinctrl-single,bit-per-mux");
//pcs->bits_per_mux ? 2 : 1 为1
//这个函数是老版的函数要找"#pinctrl-cells"属性,没有 直接返回0
ret = pcs_quirk_missing_pinctrl_cells(pcs, np,
pcs->bits_per_mux ? 2 : 1);
if (ret) {
dev_err(&pdev->dev, "unable to patch #pinctrl-cells\n");
return ret;
}
//获取IORESOURCE_MEM资源,即reg属性
//pmx_ctrl1节点reg = <0x1 0x10080000 0x0 0x38>;
//pmx_cfg1节点为reg = <0x1 0x10080800 0x0 0x05c>;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(pcs->dev, "could not get resource\n");
return -ENODEV;
}
//节点pmx_ctrl1
//res->start:268959744 ----- res->end:268959799
//resource_size:56
//节点pmx_cfg1
//res->start:268961792 ----- res->end:268961883
//resource_size:92
//devm_request_mem_region将res的物理空间iormmap映射出来,返回给pcs->res,能通过用户空间操作
pcs->res = devm_request_mem_region(pcs->dev, res->start,
resource_size(res), DRIVER_NAME);
if (!pcs->res) {
dev_err(pcs->dev, "could not get mem_region\n");
return -EBUSY;
}
//这里的pcs的size和base就是映射出来的大小和基址
pcs->size = resource_size(pcs->res);
pcs->base = devm_ioremap(pcs->dev, pcs->res->start, pcs->size);
if (!pcs->base) {
dev_err(pcs->dev, "could not ioremap\n");
return -ENODEV;
}
//pdev->device->device_data指针指向pcs,保存变量,pcs是malloc出来的内存
platform_set_drvdata(pdev, pcs);
//(pcs->width为32
switch (pcs->width) {
case 8:
pcs->read = pcs_readb;
pcs->write = pcs_writeb;
break;
case 16:
pcs->read = pcs_readw;
pcs->write = pcs_writew;
break;
case 32:
pcs->read = pcs_readl;
pcs->write = pcs_writel;
break;
default:
break;
}
//DRIVER_NAME "pinctrl-single"
//构造pinctrl_desc结构体,desc.pctlops是引脚的操作功能,desc.pmxops是引脚复用功能
//这两个函数是具体的硬件功能操作函数
pcs->desc.name = DRIVER_NAME;
pcs->desc.pctlops = &pcs_pinctrl_ops;
pcs->desc.pmxops = &pcs_pinmux_ops;
//pmx_cfg1:
//PCS_HAS_PINCONF = (pcs->flags & PCS_FEAT_PINCONF)
//PCS_FEAT_PINCONF (1 << 0)
//pcs->flag = PCS_FEAT_PINCONF (1 << 0)
//PCS_HAS_PINCONF = 1
//注意:pmx_ctrl1节点没有flag属性,所以这个为0
//pcs_pinconf_ops是配置功能,所以只有pmx_cfg1节点的desc有这个功能
if (PCS_HAS_PINCONF)
pcs->desc.confops = &pcs_pinconf_ops;
pcs->desc.owner = THIS_MODULE;
//这个函数啥也没干,只是设置pindesc等一些属性,主要是引脚树木等
ret = pcs_allocate_pin_table(pcs);
if (ret < 0)
goto free;
//pinctrl_register函数,构造pinctrl_dev结构体
//1.传入pinctrl_desc,pctldev->desc指向传入的pinctrl_desc
//2.申请pinctrl_dev结构体内存
//3.初始化了pin_desc_tree、pin_group_tree、pin_function_tree三个树
//4.检查pctldev->desc->pctlops是否有get_group_count和get_group_name函数
//5.检查pctldev->desc->pmxops是否有必要的函数
//6.检查pctldev->desc->confops是否有必要的函数
//7.指向pinctrl_register_one_pin挨个注册管脚
//8.将每个pin的pin_desc都加入到 &pcs->pctl(pinctrl_dev)管理起来
ret = pinctrl_register_and_init(&pcs->desc, pcs->dev, pcs, &pcs->pctl);
if (ret) {
dev_err(pcs->dev, "could not register single pinctrl driver\n");
goto free;
}
//去device_node找pinctrl-single,gpio-range和#pinctrl-single,gpio-range-cells,没有就直接返回了
ret = pcs_add_gpio_func(np, pcs);
if (ret < 0)
goto free;
//中断也没有,不用管
pcs->socdata.irq = irq_of_parse_and_map(np, 0);
if (pcs->socdata.irq)
pcs->flags |= PCS_FEAT_IRQ;
/* We still need auxdata for some omaps for PRM interrupts */
pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
if (pdata->rearm)
pcs->socdata.rearm = pdata->rearm;
if (pdata->irq) {
pcs->socdata.irq = pdata->irq;
pcs->flags |= PCS_FEAT_IRQ;
}
}
//为0也不用管
if (PCS_HAS_IRQ) {
ret = pcs_irq_init_chained_handler(pcs, np);
if (ret < 0)
dev_warn(pcs->dev, "initialized with no interrupts\n");
}
dev_info(pcs->dev, "%i pins, size %u\n", pcs->desc.npins, pcs->size);
return pinctrl_enable(pcs->pctl);
free:
pcs_free_resources(pcs);
return ret;
}
pcs_allocate_pin_table函数
static int pcs_allocate_pin_table(struct pcs_device *pcs)
{
int mux_bytes, nr_pins, i;
int num_pins_in_register = 0;
//mux_bytes = 4
mux_bytes = pcs->width / BITS_PER_BYTE;
//pinctrl-single,bit-per-mux属性未定义
//所以bits_per_mux =0
if (pcs->bits_per_mux) {
pcs->bits_per_pin = fls(pcs->fmask);
nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin;
num_pins_in_register = pcs->width / pcs->bits_per_pin;
} else {
nr_pins = pcs->size / mux_bytes;
}
//pmx_ctrl1节点:
//nr_pins = 0x38/4 = 14
//pmx_cfg1节点:
//nr_pins = 0x5C/4 = 23
dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins);
//这个pcs->dev就是device_node
//分配nr_pins个struct pinctrl_pin_desc *pa;的内存大小给pcs->pins.pa
pcs->pins.pa = devm_kcalloc(pcs->dev,
nr_pins, sizeof(*pcs->pins.pa),
GFP_KERNEL);
if (!pcs->pins.pa)
return -ENOMEM;
//npins表示每个控制器pin的数目
pcs->desc.pins = pcs->pins.pa;
pcs->desc.npins = nr_pins;
for (i = 0; i < pcs->desc.npins; i++) {
unsigned offset;
int res;
int byte_num;
int pin_pos = 0;
//pcs->bits_per_mux为0执行的是下面的那一句
if (pcs->bits_per_mux) {
byte_num = (pcs->bits_per_pin * i) / BITS_PER_BYTE;
offset = (byte_num / mux_bytes) * mux_bytes;
pin_pos = i % num_pins_in_register;
} else {
//每次循环offset偏移加4
offset = i * mux_bytes;
}
//传进来的pin_pos为0,这个函数貌似啥也没干,执行结束后只是pcs->pins.cur变成了14
res = pcs_add_pin(pcs, offset, pin_pos);
if (res < 0) {
dev_err(pcs->dev, "error adding pins: %i\n", res);
return res;
}
}
printk("pcs_allocate_pin_table end\n");
return 0;
}
pcs_add_pin函数
static int pcs_add_pin(struct pcs_device *pcs, unsigned offset,
unsigned pin_pos)
{
struct pcs_soc_data *pcs_soc = &pcs->socdata;
struct pinctrl_pin_desc *pin;
int i;
i = pcs->pins.cur;
if (i >= pcs->desc.npins) {
dev_err(pcs->dev, "too many pins, max %i\n",
pcs->desc.npins);
return -ENOMEM;
}
if (pcs_soc->irq_enable_mask) {
unsigned val;
val = pcs->read(pcs->base + offset);
if (val & pcs_soc->irq_enable_mask) {
dev_dbg(pcs->dev, "irq enabled at boot for pin at %lx (%x), clearing\n",
(unsigned long)pcs->res->start + offset, val);
val &= ~pcs_soc->irq_enable_mask;
pcs->write(val, pcs->base + offset);
}
}
pin = &pcs->pins.pa[i];
pin->number = i;
pcs->pins.cur++;
return i;
}
pinctrl_register_one_pin函数
static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pin)
{
struct pin_desc *pindesc;
//查看是否已经注册这个pin
pindesc = pin_desc_get(pctldev, pin->number);
if (pindesc) {
dev_err(pctldev->dev, "pin %d already registered\n",
pin->number);
return -EINVAL;
}
//分配内存
pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
if (!pindesc)
return -ENOMEM;
/* Set owner */
pindesc->pctldev = pctldev;
/* Copy basic pin info */
if (pin->name) {
//如果指定了名字,则设定为默认
pindesc->name = pin->name;
} else {
//设置默认名字
pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", pin->number);
if (!pindesc->name) {
kfree(pindesc);
return -ENOMEM;
}
pindesc->dynamic_name = true;
}
pindesc->drv_data = pin->drv_data;
//将该pin添加到pctldev中
radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);
pr_debug("registered pin %d (%s) on %s\n",
pin->number, pindesc->name, pctldev->desc->name);
return 0;
}
pinctrl_enable函数
int pinctrl_enable(struct pinctrl_dev *pctldev)
{
int error;
error = pinctrl_claim_hogs(pctldev);
if (error) {
dev_err(pctldev->dev, "could not claim hogs: %i\n",
error);
mutex_destroy(&pctldev->mutex);
kfree(pctldev);
return error;
}
mutex_lock(&pinctrldev_list_mutex);
list_add_tail(&pctldev->node, &pinctrldev_list);
mutex_unlock(&pinctrldev_list_mutex);
pinctrl_init_device_debugfs(pctldev);
return 0;
}
pinctrl_claim_hogs函数
pinctrl_claim_hogs()
//构建pinctrl结构体
pctldev->p = create_pinctrl(pctldev->dev, pctldev);
{
//分配pin ctrl占用的内存并初始化;
p = kzalloc(sizeof(*p), GFP_KERNEL);
//解析设备树节点信息
ret = pinctrl_dt_to_map(p, pctldev);
{
for (state = 0; ; state++) {
propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
//寻找这个节点下的pinctrl-%d属性
prop = of_find_property(np, propname, &size);
//根据state找到pinctrl-names中的第几个字符串,返回给statename
ret = of_property_read_string_index(np, "pinctrl-names",
state, &statename);
for (config = 0; config < size; config++) {
phandle = be32_to_cpup(list++);
//查找整个设备树。从根节点开始,找到属性带pinctrl-%d的device_node
np_config = of_find_node_by_phandle(phandle);
//这个函数会找到pinctrl-%d属性的父节点
//调用父节点的pctldev->desc->pctlop->dt_node_to_map函数
//本驱动中dt_node_to_map会根据pinctrl-single,pins属性来设置复用寄存器的值
ret = dt_to_map_one_config(p, pctldev, statename,
np_config);
}
}
}
}
}
总结
主要结构体
pcs_device
* struct pcs_device - pinctrl device instance
* @res: resources
* @base: virtual address of the controller
* @saved_vals: saved values for the controller
* @size: size of the ioremapped area
* @dev: device entry
* @np: device tree node
* @pctl: pin controller device
* @flags: mask of PCS_FEAT_xxx values
* @missing_nr_pinctrl_cells: for legacy binding, may go away
* @socdata: soc specific data
* @lock: spinlock for register access
* @mutex: mutex protecting the lists
* @width: bits per mux register
* @fmask: function register mask
* @fshift: function register shift
* @foff: value to turn mux off
* @fmax: max number of functions in fmask
* @bits_per_mux: number of bits per mux
* @bits_per_pin: number of bits per pin
* @pins: physical pins on the SoC
* @gpiofuncs: list of gpio functions
* @irqs: list of interrupt registers
* @chip: chip container for this instance
* @domain: IRQ domain for this instance
* @desc: pin controller descriptor
* @read: register read function to use
* @write: register write function to use
struct pcs_device {
struct resource *res;
void __iomem *base;
void *saved_vals;
unsigned size;
struct device *dev;
struct device_node *np;
struct pinctrl_dev *pctl;
unsigned flags;
#define PCS_CONTEXT_LOSS_OFF (1 << 3)
#define PCS_QUIRK_SHARED_IRQ (1 << 2)
#define PCS_FEAT_IRQ (1 << 1)
#define PCS_FEAT_PINCONF (1 << 0)
struct property *missing_nr_pinctrl_cells;
struct pcs_soc_data socdata;
raw_spinlock_t lock;
struct mutex mutex;
unsigned width;
unsigned fmask;
unsigned fshift;
unsigned foff;
unsigned fmax;
bool bits_per_mux;
unsigned bits_per_pin;
struct pcs_data pins;
struct list_head gpiofuncs;
struct list_head irqs;
struct irq_chip chip;
struct irq_domain *domain;
struct pinctrl_desc desc;
unsigned (*read)(void __iomem *reg);
void (*write)(unsigned val, void __iomem *reg);
};
厂家自定义的结构体,probe函数主要是填充这个结构体,每个pinctrl控制器的节点会构造一个结构体
pinctrl_desc
/**
* 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_desc描述了该pinctrl设备的相关信息,引脚数量,引脚配置操作函数,硬件功能操作函数,引脚复用操作函数
struct pinctrl_ops {
//获取系统中pin groups的个数,后续的操作,将以相应的索引为单位(类似数组的下标,个数为数组的大小)
int (*get_groups_count) (struct pinctrl_dev *pctldev);
//获取指定group(由索引selector指定)的名称
const char *(*get_group_name) (struct pinctrl_dev *pctldev, unsigned selector);
//获取指定group的所有pins(由索引selector指定),结果保存在pins(指针数组)和num_pins(指针)中
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);
//用于将device tree中的pin state信息转换为pin map
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 pinmux_ops {
//检查某个pin是否已作它用,用于管脚复用时的互斥
int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
//request的反操作
int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
//获取系统中function的个数
int (*get_functions_count) (struct pinctrl_dev *pctldev);
//获取指定function的名称
const char *(*get_function_name) (struct pinctrl_dev *pctldev, unsigned selector);
//获取指定function所占用的pin group
int (*get_function_groups) (struct pinctrl_dev *pctldev, unsigned selector, const char * const **groups, unsigned *num_groups);
//将指定的pin group(group_selector)设置为指定的function(func_selector)
int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector, unsigned group_selector);
//以下是gpio相关的操作
int (*gpio_request_enable) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
void (*gpio_disable_free) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
int (*gpio_set_direction) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input);
//为true时,说明该pin controller不允许某个pin作为gpio和其它功能同时使用
bool strict;
};
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
bool is_generic;
#endif
//获取指定 pin 的当前配置,保存在 config 指针中
int (*pin_config_get) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config);
//设置指定pin的配置
int (*pin_config_set) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs);
//获取指定pin group的配置项
int (*pin_config_group_get) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *config);
//设置指定pin group的配置项
int (*pin_config_group_set) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *configs, unsigned num_configs);
......
pinctrl_dev
/**
* 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
* @pin_group_tree: optionally each pin group can be stored in this radix tree
* @num_groups: optionally number of groups can be kept here
* @pin_function_tree: optionally each function can be stored in this radix tree
* @num_functions: optionally number of functions can be kept here
* @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;
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
struct radix_tree_root pin_group_tree;
unsigned int num_groups;
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
struct radix_tree_root pin_function_tree;
unsigned int num_functions;
#endif
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
};
总结
probe函数填充pcs_device结构体信息,pcs_allocate_pin_table遍历出所有pin的树木和信息,设置pcs->desc.pins和pcs->desc.npins。指向pinctrl_register_and_init,主要是为了构造pinctrl_dev结构体,初始化了pin_desc_tree、pin_group_tree、pin_function_tree三个树,检查pctldev->desc->pctlops、pmxops、pmxops是否有必要的函数,让后将每个pin的pin_desc加入到pinctrl_dev的pin_desc_tree串起来。pcs_add_gpio_func去device_node找pinctrl-single,gpio-range和#pinctrl-single,gpio-range-cells,没有就直接返回了。pinctrl_enable还会解析设备树节点查找是否有设置过pinctrl-%d和pinctrl-names的信息,pinctrl-%d属性的值是要使用pinctrl的节点,调用dt_node_to_map会根据pinctrl-single,pins属性来设置复用寄存器的值。gpio的子系统底层也会调用pinctrl,以后在研究