上一篇文章简单了解了 pinctrl子系统驱动框架,文章地址如下:
本文继上一篇文章pinctrl子系统驱动代码的学习,具体来了解 pinctrl子系统驱动所做的最关键的工作。
上一篇文章的学习中可以知道,设备树中的 compatible 属性值会和 of_device_id 中的所有兼容性字符串比较,查看是否可以使用此驱动。
imx6ul_pinctrl_of_match 结构体数组一共有两个兼容性字符串,分别为“fsl,imx6ul-iomuxc”和“fsl,imx6ull-iomuxc-snvs”,因此 iomuxc 节点与此驱动匹配,所以 pinctrl-imx6ul.c 会完成 I.MX6ULL 的 PIN 配置工作。
当设备和驱动匹配成功以后, platform_driver 的 probe 成员变量所代表的函数就会执行,在代码中设置 probe 成员变量为 imx6ul_pinctrl_probe 函数,因此, imx6ul_pinctrl_probe 这个函数就会执行,可 以认为 imx6ul_pinctrl_probe 函数,就是 I.MX6ULL 这个 SOC 的 PIN 配置入口函数。以此为入口,如下图的函数调用路径:
static int imx_pinctrl_parse_groups(struct device_node *np, struct imx_pin_group *grp,
struct imx_pinctrl_soc_info *info, u32 index)
{
int size, pin_size;
const __be32 *list;
int i;
...........
pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
pin_reg = &info->pin_regs[pin_id];
pin->pin = pin_id;
grp->pin_ids[i] = pin_id;
pin_reg->mux_reg = mux_reg;
pin_reg->conf_reg = conf_reg;
pin->input_reg = be32_to_cpu(*list++);
pin->mux_mode = be32_to_cpu(*list++);
pin->input_val = be32_to_cpu(*list++);
/* SION bit is in mux register */
config = be32_to_cpu(*list++);
if (config & IMX_PAD_SION)
pin->mux_mode |= IOMUXC_CONFIG_SION;
pin->config = config & ~IMX_PAD_SION;
............
}
return 0;
}
下来看一下函数 pinctrl_register,此函数用于向 Linux 内核注册一个 PIN 控制器,此函数原型如下:
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, struct device *dev,
void *driver_data)
参数 pctldesc 非常重要,因为此参数就是要注册的 PIN 控制器,PIN 控制器用于配置 SOC 的 PIN 复用功能和电气特性。参数 pctldesc 是 pinctrl_desc 结构体类型指针,pinctrl_desc 结构体如下所示:
struct pinctrl_desc {
const char *name;
struct pinctrl_pin_desc const *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
};
int imx_pinctrl_probe(struct platform_device *pdev, struct imx_pinctrl_soc_info *info)
{
struct device_node *dev_np = pdev->dev.of_node;
struct device_node *np;
struct imx_pinctrl *ipctl;
struct resource *res;
struct pinctrl_desc *imx_pinctrl_desc;
......
imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc), GFP_KERNEL);
if (!imx_pinctrl_desc)
return -ENOMEM;
......
imx_pinctrl_desc->name = dev_name(&pdev->dev);
imx_pinctrl_desc->pins = info->pins;
imx_pinctrl_desc->npins = info->npins;
imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
imx_pinctrl_desc->pmxops = &imx_pmx_ops;
imx_pinctrl_desc->confops = &imx_pinconf_ops;
imx_pinctrl_desc->owner = THIS_MODULE;
......
ipctl->pctl = pinctrl_register(imx_pinctrl_desc, &pdev->dev, ipctl);
......
}
static const struct pinctrl_ops imx_pctrl_ops = {
.get_groups_count = imx_get_groups_count,
.get_group_name = imx_get_group_name,
.get_group_pins = imx_get_group_pins,
.pin_dbg_show = imx_pin_dbg_show,
.dt_node_to_map = imx_dt_node_to_map,
.dt_free_map = imx_dt_free_map,
};
static const struct pinmux_ops imx_pmx_ops = {
.get_functions_count = imx_pmx_get_funcs_count,
.get_function_name = imx_pmx_get_func_name,
.get_function_groups = imx_pmx_get_groups,
.set_mux = imx_pmx_set,
.gpio_request_enable = imx_pmx_gpio_request_enable,
.gpio_set_direction = imx_pmx_gpio_set_direction,
};
static const struct pinconf_ops imx_pinconf_ops = {
.pin_config_get = imx_pinconf_get,
.pin_config_set = imx_pinconf_set,
.pin_config_dbg_show = imx_pinconf_dbg_show,
.pin_config_group_dbg_show = imx_pinconf_group_dbg_show,
};