diff options
Diffstat (limited to 'drivers/pinctrl/freescale/pinctrl-imx.c')
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-imx.c | 300 |
1 files changed, 147 insertions, 153 deletions
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 5ef7e875b50e..a7ace9e1ad81 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -27,6 +27,7 @@ #include <linux/regmap.h> #include "../core.h" +#include "../pinmux.h" #include "pinctrl-imx.h" /* The bits in CONFIG cell defined in binding doc*/ @@ -42,59 +43,25 @@ struct imx_pinctrl { struct pinctrl_dev *pctl; void __iomem *base; void __iomem *input_sel_base; - const struct imx_pinctrl_soc_info *info; + struct imx_pinctrl_soc_info *info; }; -static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name( - const struct imx_pinctrl_soc_info *info, +static inline const struct group_desc *imx_pinctrl_find_group_by_name( + struct pinctrl_dev *pctldev, const char *name) { - const struct imx_pin_group *grp = NULL; + const struct group_desc *grp = NULL; int i; - for (i = 0; i < info->ngroups; i++) { - if (!strcmp(info->groups[i].name, name)) { - grp = &info->groups[i]; + for (i = 0; i < pctldev->num_groups; i++) { + grp = pinctrl_generic_get_group(pctldev, i); + if (grp && !strcmp(grp->name, name)) break; - } } return grp; } -static int imx_get_groups_count(struct pinctrl_dev *pctldev) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; - - return info->ngroups; -} - -static const char *imx_get_group_name(struct pinctrl_dev *pctldev, - unsigned selector) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; - - return info->groups[selector].name; -} - -static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, - const unsigned **pins, - unsigned *npins) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; - - if (selector >= info->ngroups) - return -EINVAL; - - *pins = info->groups[selector].pin_ids; - *npins = info->groups[selector].npins; - - return 0; -} - static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset) { @@ -106,8 +73,8 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map **map, unsigned *num_maps) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; - const struct imx_pin_group *grp; + struct imx_pinctrl_soc_info *info = ipctl->info; + const struct group_desc *grp; struct pinctrl_map *new_map; struct device_node *parent; int map_num = 1; @@ -117,15 +84,17 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, * first find the group of this node and check if we need create * config maps for pins */ - grp = imx_pinctrl_find_group_by_name(info, np->name); + grp = imx_pinctrl_find_group_by_name(pctldev, np->name); if (!grp) { dev_err(info->dev, "unable to find group for node %s\n", np->name); return -EINVAL; } - for (i = 0; i < grp->npins; i++) { - if (!(grp->pins[i].config & IMX_NO_PAD_CTL)) + for (i = 0; i < grp->num_pins; i++) { + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; + + if (!(pin->config & IMX_NO_PAD_CTL)) map_num++; } @@ -149,12 +118,14 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, /* create config map */ new_map++; - for (i = j = 0; i < grp->npins; i++) { - if (!(grp->pins[i].config & IMX_NO_PAD_CTL)) { + for (i = j = 0; i < grp->num_pins; i++) { + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; + + if (!(pin->config & IMX_NO_PAD_CTL)) { new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; new_map[j].data.configs.group_or_pin = - pin_get_name(pctldev, grp->pins[i].pin); - new_map[j].data.configs.configs = &grp->pins[i].config; + pin_get_name(pctldev, pin->pin); + new_map[j].data.configs.configs = &pin->config; new_map[j].data.configs.num_configs = 1; j++; } @@ -173,9 +144,9 @@ static void imx_dt_free_map(struct pinctrl_dev *pctldev, } 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, + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_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, @@ -186,24 +157,33 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; unsigned int npins, pin_id; int i; - struct imx_pin_group *grp; + struct group_desc *grp = NULL; + struct function_desc *func = NULL; /* * Configure the mux mode for each pin in the group for a specific * function. */ - grp = &info->groups[group]; - npins = grp->npins; + grp = pinctrl_generic_get_group(pctldev, group); + if (!grp) + return -EINVAL; + + func = pinmux_generic_get_function(pctldev, selector); + if (!func) + return -EINVAL; + + npins = grp->num_pins; dev_dbg(ipctl->dev, "enable function %s group %s\n", - info->functions[selector].name, grp->name); + func->name, grp->name); for (i = 0; i < npins; i++) { - struct imx_pin *pin = &grp->pins[i]; + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; + pin_id = pin->pin; pin_reg = &info->pin_regs[pin_id]; @@ -272,43 +252,13 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, return 0; } -static int imx_pmx_get_funcs_count(struct pinctrl_dev *pctldev) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; - - return info->nfunctions; -} - -static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev, - unsigned selector) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; - - return info->functions[selector].name; -} - -static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, - const char * const **groups, - unsigned * const num_groups) -{ - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; - - *groups = info->functions[selector].groups; - *num_groups = info->functions[selector].num_groups; - - return 0; -} - static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; - struct imx_pin_group *grp; + struct group_desc *grp; struct imx_pin *imx_pin; unsigned int pin, group; u32 reg; @@ -322,10 +272,12 @@ static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, return -EINVAL; /* Find the pinctrl config with GPIO mux mode for the requested pin */ - for (group = 0; group < info->ngroups; group++) { - grp = &info->groups[group]; - for (pin = 0; pin < grp->npins; pin++) { - imx_pin = &grp->pins[pin]; + for (group = 0; group < pctldev->num_groups; group++) { + grp = pinctrl_generic_get_group(pctldev, group); + if (!grp) + continue; + for (pin = 0; pin < grp->num_pins; pin++) { + imx_pin = &((struct imx_pin *)(grp->data))[pin]; if (imx_pin->pin == offset && !imx_pin->mux_mode) goto mux_pin; } @@ -346,7 +298,7 @@ static void imx_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; u32 reg; @@ -371,7 +323,7 @@ static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg; u32 reg; @@ -398,9 +350,9 @@ static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, } 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, + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, .set_mux = imx_pmx_set, .gpio_request_enable = imx_pmx_gpio_request_enable, .gpio_disable_free = imx_pmx_gpio_disable_free, @@ -411,7 +363,7 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin_id, unsigned long *config) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; if (pin_reg->conf_reg == -1) { @@ -433,7 +385,7 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev, unsigned num_configs) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; int i; @@ -467,7 +419,7 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin_id) { struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; unsigned long config; @@ -483,20 +435,22 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned group) { - struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct imx_pinctrl_soc_info *info = ipctl->info; - struct imx_pin_group *grp; + struct group_desc *grp; unsigned long config; const char *name; int i, ret; - if (group > info->ngroups) + if (group > pctldev->num_groups) return; seq_printf(s, "\n"); - grp = &info->groups[group]; - for (i = 0; i < grp->npins; i++) { - struct imx_pin *pin = &grp->pins[i]; + grp = pinctrl_generic_get_group(pctldev, group); + if (!grp) + return; + + for (i = 0; i < grp->num_pins; i++) { + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; + name = pin_get_name(pctldev, pin->pin); ret = imx_pinconf_get(pctldev, pin->pin, &config); if (ret) @@ -520,7 +474,7 @@ static const struct pinconf_ops imx_pinconf_ops = { #define SHARE_FSL_PIN_SIZE 20 static int imx_pinctrl_parse_groups(struct device_node *np, - struct imx_pin_group *grp, + struct group_desc *grp, struct imx_pinctrl_soc_info *info, u32 index) { @@ -554,20 +508,20 @@ static int imx_pinctrl_parse_groups(struct device_node *np, return -EINVAL; } - grp->npins = size / pin_size; - grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(struct imx_pin), - GFP_KERNEL); - grp->pin_ids = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), - GFP_KERNEL); - if (!grp->pins || ! grp->pin_ids) + grp->num_pins = size / pin_size; + grp->data = devm_kzalloc(info->dev, grp->num_pins * + sizeof(struct imx_pin), GFP_KERNEL); + grp->pins = devm_kzalloc(info->dev, grp->num_pins * + sizeof(unsigned int), GFP_KERNEL); + if (!grp->pins || !grp->data) return -ENOMEM; - for (i = 0; i < grp->npins; i++) { + for (i = 0; i < grp->num_pins; i++) { u32 mux_reg = be32_to_cpu(*list++); u32 conf_reg; unsigned int pin_id; struct imx_pin_reg *pin_reg; - struct imx_pin *pin = &grp->pins[i]; + struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i]; if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg) mux_reg = -1; @@ -583,7 +537,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np, 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; + grp->pins[i] = pin_id; pin_reg->mux_reg = mux_reg; pin_reg->conf_reg = conf_reg; pin->input_reg = be32_to_cpu(*list++); @@ -604,31 +558,46 @@ static int imx_pinctrl_parse_groups(struct device_node *np, } static int imx_pinctrl_parse_functions(struct device_node *np, - struct imx_pinctrl_soc_info *info, + struct imx_pinctrl *ipctl, u32 index) { + struct pinctrl_dev *pctl = ipctl->pctl; + struct imx_pinctrl_soc_info *info = ipctl->info; struct device_node *child; - struct imx_pmx_func *func; - struct imx_pin_group *grp; + struct function_desc *func; + struct group_desc *grp; u32 i = 0; dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); - func = &info->functions[index]; + func = pinmux_generic_get_function(pctl, index); + if (!func) + return -EINVAL; /* Initialise function */ func->name = np->name; - func->num_groups = of_get_child_count(np); - if (func->num_groups == 0) { + func->num_group_names = of_get_child_count(np); + if (func->num_group_names == 0) { dev_err(info->dev, "no groups defined in %s\n", np->full_name); return -EINVAL; } - func->groups = devm_kzalloc(info->dev, - func->num_groups * sizeof(char *), GFP_KERNEL); + func->group_names = devm_kzalloc(info->dev, + func->num_group_names * + sizeof(char *), GFP_KERNEL); for_each_child_of_node(np, child) { - func->groups[i] = child->name; - grp = &info->groups[info->group_index++]; + func->group_names[i] = child->name; + + grp = devm_kzalloc(info->dev, sizeof(struct group_desc), + GFP_KERNEL); + if (!grp) + return -ENOMEM; + + mutex_lock(&info->mutex); + radix_tree_insert(&pctl->pin_group_tree, + info->group_index++, grp); + mutex_unlock(&info->mutex); + imx_pinctrl_parse_groups(child, grp, info, i++); } @@ -659,10 +628,12 @@ static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np) } static int imx_pinctrl_probe_dt(struct platform_device *pdev, - struct imx_pinctrl_soc_info *info) + struct imx_pinctrl *ipctl) { struct device_node *np = pdev->dev.of_node; struct device_node *child; + struct pinctrl_dev *pctl = ipctl->pctl; + struct imx_pinctrl_soc_info *info = ipctl->info; u32 nfuncs = 0; u32 i = 0; bool flat_funcs; @@ -681,35 +652,50 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev, } } - info->nfunctions = nfuncs; - info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func), + for (i = 0; i < nfuncs; i++) { + struct function_desc *function; + + function = devm_kzalloc(&pdev->dev, sizeof(*function), GFP_KERNEL); - if (!info->functions) - return -ENOMEM; + if (!function) + return -ENOMEM; + + mutex_lock(&info->mutex); + radix_tree_insert(&pctl->pin_function_tree, i, function); + mutex_unlock(&info->mutex); + } + pctl->num_functions = nfuncs; info->group_index = 0; if (flat_funcs) { - info->ngroups = of_get_child_count(np); + pctl->num_groups = of_get_child_count(np); } else { - info->ngroups = 0; + pctl->num_groups = 0; for_each_child_of_node(np, child) - info->ngroups += of_get_child_count(child); + pctl->num_groups += of_get_child_count(child); } - info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group), - GFP_KERNEL); - if (!info->groups) - return -ENOMEM; if (flat_funcs) { - imx_pinctrl_parse_functions(np, info, 0); + imx_pinctrl_parse_functions(np, ipctl, 0); } else { + i = 0; for_each_child_of_node(np, child) - imx_pinctrl_parse_functions(child, info, i++); + imx_pinctrl_parse_functions(child, ipctl, i++); } return 0; } +/* + * imx_free_resources() - free memory used by this driver + * @info: info driver instance + */ +static void imx_free_resources(struct imx_pinctrl *ipctl) +{ + if (ipctl->pctl) + pinctrl_unregister(ipctl->pctl); +} + int imx_pinctrl_probe(struct platform_device *pdev, struct imx_pinctrl_soc_info *info) { @@ -783,23 +769,31 @@ int imx_pinctrl_probe(struct platform_device *pdev, imx_pinctrl_desc->confops = &imx_pinconf_ops; imx_pinctrl_desc->owner = THIS_MODULE; - ret = imx_pinctrl_probe_dt(pdev, info); - if (ret) { - dev_err(&pdev->dev, "fail to probe dt properties\n"); - return ret; - } + mutex_init(&info->mutex); ipctl->info = info; ipctl->dev = info->dev; platform_set_drvdata(pdev, ipctl); - ipctl->pctl = devm_pinctrl_register(&pdev->dev, - imx_pinctrl_desc, ipctl); - if (IS_ERR(ipctl->pctl)) { + ret = devm_pinctrl_register_and_init(&pdev->dev, + imx_pinctrl_desc, ipctl, + &ipctl->pctl); + if (ret) { dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); - return PTR_ERR(ipctl->pctl); + goto free; + } + + ret = imx_pinctrl_probe_dt(pdev, ipctl); + if (ret) { + dev_err(&pdev->dev, "fail to probe dt properties\n"); + goto free; } dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); return 0; + +free: + imx_free_resources(ipctl); + + return ret; } |