以炬芯的方案来分析一下pinctrl子系统的代码
kernel/drivers/pinctrl/owl/pinctrl-s700.c中
pinctrl驱动是注册为平台驱动的。
platform_driver_register(&s700_pinctrl_driver); //注册平台设备驱动
//直接去看probe函数
static int s700_pinctrl_probe(struct platform_device *pdev)
{
pr_info("[OWL] pinctrl s700 probe\n");
return owl_pinctrl_probe(pdev, &s700_pinctrl_info); //重点是s700_pinctrl_info结构
}
//s700_pinctrl_info结构中封装了炬芯IC关于pin的所有基本信息,包括function了,group了等等。
static struct owl_pinctrl_soc_info s700_pinctrl_info = {
.gpio_ranges = s700_gpio_ranges,
.gpio_num_ranges = ARRAY_SIZE(s700_gpio_ranges),
.padinfo = s700_pad_tab,
.pins = (const struct pinctrl_pin_desc *)s700_pads,
.npins = ARRAY_SIZE(s700_pads),
.functions = s700_functions,
.nfunctions = ARRAY_SIZE(s700_functions),
.groups = s700_groups,
.ngroups = ARRAY_SIZE(s700_groups),
/*.owl_gpio_pad_data = &s700_gpio_pad_data,*/
};
接着到真正的probe函数,先看一下owl_pinctrl_desc结构,这个是贯穿pinctrl功能的一个结构,里面主要封装了此芯片pinctrl相关的操作函数,这些函数都是芯片厂商来实现的。
static struct pinctrl_desc owl_pinctrl_desc = {
.name = NULL,
.pins = NULL,
.npins = 0,
.pctlops = &owl_pctlops_ops, //全局相关的控制函数
.pmxops = &owl_pmxops_ops, //复用引脚相关的操作函数
.confops = &owl_confops_ops, //用来配置引脚的特性如:上拉下拉
.owner = THIS_MODULE,
};int owl_pinctrl_probe(struct platform_device *pdev,
struct owl_pinctrl_soc_info *info)
{
struct resource *res;
struct owl_pinctrl *apctl;
int i;
pr_info("[OWL] pinctrl initialization\n");
if (!info || !info->pins || !info->npins) {
dev_err(&pdev->dev, "wrong pinctrl info\n");
return -EINVAL;
}
owl_pinctrl_desc.name = dev_name(&pdev->dev); //对owl_pinctrl_desc继续做一些初始化工作
owl_pinctrl_desc.pins = info->pins;
owl_pinctrl_desc.npins = info->npins;
/* Create state holders etc for this driver */
apctl = devm_kzalloc(&pdev->dev, sizeof(*apctl), GFP_KERNEL);
if (!apctl)
return -ENOMEM;
apctl->info = info;
apctl->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
apctl->membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(apctl->membase))
return PTR_ERR(apctl->membase);
/* enable GPIO/MFP clock */
apctl->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(apctl->clk)) {
dev_err(&pdev->dev, "no clock defined\n");
return -ENODEV;
}
clk_prepare_enable(apctl->clk);
dev_info(&pdev->dev, "nfunctions %d, ngroups %d\n",
info->nfunctions, info->ngroups);
apctl->pctl = pinctrl_register(&owl_pinctrl_desc, &pdev->dev, apctl); //将owl_pinctrl_desc注册进内核中。
if (!apctl->pctl) {
dev_err(&pdev->dev, "could not register Actions SOC pinmux driver\n");
return -EINVAL;
}
/* We will handle a range of GPIO pins */
for (i = 0; i < info->gpio_num_ranges; i++)
pinctrl_add_gpio_range(apctl->pctl, &info->gpio_ranges[i]);
platform_set_drvdata(pdev, apctl);
dev_dbg(&pdev->dev, "initialized Actions SOC pin control driver\n");
return 0;
}接着去看pinctrl_register函数
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data)
{
struct pinctrl_dev *pctldev;
int ret;
pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
/* Initialize pin control device struct */
pctldev->owner = pctldesc->owner;
pctldev->desc = pctldesc;
pctldev->driver_data = driver_data;
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
INIT_LIST_HEAD(&pctldev->gpio_ranges);
pctldev->dev = dev;
mutex_init(&pctldev->mutex);
/* Register all the pins */
dev_dbg(dev, "try to register %d pins ...\n", pctldesc->npins);
ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);//把每一个pin都注册到系统中
mutex_lock(&pinctrldev_list_mutex);
list_add_tail(&pctldev->node, &pinctrldev_list);
mutex_unlock(&pinctrldev_list_mutex);
pctldev->p = pinctrl_get(pctldev->dev); //pinctrl_get调用create_pinctrl来获取pinctrl句柄
if (!IS_ERR(pctldev->p)) {
pctldev->hog_default =
pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);//查找pin的default状态
if (IS_ERR(pctldev->hog_default)) {
dev_dbg(dev, "failed to lookup the default state\n");
} else {
if (pinctrl_select_state(pctldev->p,
pctldev->hog_default)) //将pin设置为default状态
dev_err(dev,
"failed to select default state\n");
}
pctldev->hog_sleep =
pinctrl_lookup_state(pctldev->p,
PINCTRL_STATE_SLEEP); //查找sleep状态。
}
pinctrl_init_device_debugfs(pctldev);
return pctldev;
}pinctrl_get获取pin mapping databae的过程大致如下:
(1)pinctrl_get函数调用create_pinctrl来创建pinctrl句柄
(2)create_pinctrl函数调用pinctrl_dt_to_map来解析dts当前设备节点中的命名为pinctrl-N的属性信息。
(3)pinctrl_dt_to_map搜索当前设备驱动节点所有的pinctrl-%d,并通过其指向的phandle找到定义在pin controller device node中的pinctrl state节点,然后调用dt_to_map_one_config进行解析。
(4)dt_to_map_one_config函数向上搜索pinctrl state节点的父亲节点,并与所有哦注册的pinctrl驱动比对,找到匹配的pinctrl驱动的句柄后,调用pinctrl驱动注册的dt_node_to_map函数来解析pinctrl state节点数据。
(5)主控pinctrl驱动的owl_pinctrl_dt_node_to_map收到pin state节点句柄后,搜索以下属性:“actions,function”、“actions,pull”、“actions,paddrv”,“actions,pins”,“actions,groups”并将解析的数据打包成struct pinctrl_map结构,并回传给调用者。
至此,pinctrl_get就完成了收集并组装pin mapping database工作,并返回了pinctrl的控制句柄。设备驱动可以通过这个句柄来完成对pinctrl的各项操作。
pin controller device 包含一系列pin configuration node作为子节点。这些子节点描述了pinctrl_map中可能用到的所有pin state。
pinctrl模块对这些pin configuration node定义如下:
1.actions,groups的属性用于表示Mux Group的名字数组。
2.actions,pins的属性用于表示该组pin的名字数组。
3.actions,function的属性表示该组Mux Group使用功能的名字。
4.actions,paddrv的属性表示该组Dirve Group所代表的pin的驱动能力。
5.actions,pull的属性表述该组的pin需要配置的上下拉状态。
6.pin configuration node的名字任意。
pin controller的device node 定义为pinctrl@e01b0040,示例如下:
pinctrl@e01b0000 { //pinctrl@e01b0000其实就是一个设备节点,这个设备节点的解析是由pinctrl主控驱动完成的,主控驱动在初始化时会调用pinctrl_register函数将自己注册到pinctrl子系统中。
compatible = "actions,s700-pinctrl";
reg = <0 0xe01b0000 0 0x1000>;
pinctrl-names = "default";
pinctrl-0 = <&state_default>;//pinctrl_register会调用pinctrl_get来获取属于主控驱动的pin mapping database。pinctrl-names为default的节点会首先被初始化。
clocks = <&clock CLK_GPIO>; //pinctrl_register在获得pinctrl句柄后,会申请default的pin配置,所以如果有不属于任何其他设备的pinctrl配置,但也想使能,就可以统一放到这里进行初始化。
clock-names = "mfp";
state_default: pinctrl_default {
};
spi0_state_default: spi0_default {//其他子节点,由各个驱动在加载时由统一设备驱动模型在device和driver绑定时调用pinctrl_get时被解析,并将解析完成的pinctrl句柄存放在驱动设备的device中。
spi0_mfp {
actions,groups = "mfp1_2_0","mfp1_4_3";
actions,function = "spi0";
};
spi0_paddrv {
actions,groups = "paddrv1_11_10";
actions,paddrv = <2>;/*level 2*/
};
//spi0_pull {
//actions,pins = "P_I2C0_SCLK", "P_I2C0_SDATA";
//actions,schmitt = "P_I2C0_SCLK", "P_I2C0_SDATA";
//actions,pull = <0>;
//};
};
serial0_state_default: serial0_default{
serial_0{
actions,groups = "mfp2_2_0","mfp3_21_19";
actions,function = "uart0";
};
};
serial1_state_default: serial1_default{ //这些其他的
serial_1{
actions,groups = "mfp2_13_11";
actions,function = "uart1";
};
};
serial2_state_default: serial2_default{
serial_2{
actions,groups = "mfp2_23","mfp2_22","uart2_dummy";
actions,function = "uart2";
};
};
serial3_state_default: serial3_default{
serial_3{
actions,groups = "mfp2_21","mfp2_20","uart3_dummy";
actions,function = "uart3";
};
};
统一设备模型在匹配到驱动后,会调用devm_pinctrl_get来建立pinctrl database map。
在具体的驱动设备节点中,通过关键字“pinctrl-N”来引用在pin controller device设备节点中定义的pinctrl state节点。其中“N”表示序号,是pinctrl-names顶一顶 字符串数组下标。
mmc0: mmc@e0218000 {
compatible = "actions,s700-mmc";
reg = <0 0xe0218000 0 0x40>, <0 0xe01b0000 0 0x410>,
<0 0xe0168000 0 0x100>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clock CLK_SD2>;
clock-names = "mmc";
resets = <&reset RESET_SD2>;
reset-names = "mmc";
dmas = <&dma DMA_DRQ_SD2>;
dma-names = "mmc";
pinctrl-names = "pinctrl_mmc2";
pinctrl-0 = <&mm2_pinctrl_state>;
status = "disabled";
};mmc@e0218000是定义在root节点下的一级子节点。
在驱动调用platform_driver_register()时由统一设备模型对"compatible"属性进行配置,在匹配到后就调用pinctrl_bind_pins进行绑定,并调用pinctrl_get进行绑定,并调用pinctrl_get接卸“pinctrl-N”引用的pinctrl子节点,并将pinctrl句柄放到platform_device结构的dev结构中。
驱动通过pinctrl驱动提供的pinctrl_get接口从dev结构中获得pinctrl句柄的引用,并调用其他的pinctrl驱动提供的接口对pinctrl进行操作。
驱动使用pinctrl接口代码示例


550

被折叠的 条评论
为什么被折叠?



