in mvebu/pinctrl-mvebu.c [568:749]
int mvebu_pinctrl_probe(struct platform_device *pdev)
{
struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev);
struct mvebu_pinctrl *pctl;
struct pinctrl_pin_desc *pdesc;
unsigned gid, n, k;
unsigned size, noname = 0;
char *noname_buf;
void *p;
int ret;
if (!soc || !soc->controls || !soc->modes) {
dev_err(&pdev->dev, "wrong pinctrl soc info\n");
return -EINVAL;
}
pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl),
GFP_KERNEL);
if (!pctl)
return -ENOMEM;
pctl->desc.name = dev_name(&pdev->dev);
pctl->desc.owner = THIS_MODULE;
pctl->desc.pctlops = &mvebu_pinctrl_ops;
pctl->desc.pmxops = &mvebu_pinmux_ops;
pctl->desc.confops = &mvebu_pinconf_ops;
pctl->variant = soc->variant;
pctl->dev = &pdev->dev;
platform_set_drvdata(pdev, pctl);
/* count controls and create names for mvebu generic
register controls; also does sanity checks */
pctl->num_groups = 0;
pctl->desc.npins = 0;
for (n = 0; n < soc->ncontrols; n++) {
const struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
pctl->desc.npins += ctrl->npins;
/* initialize control's pins[] array */
for (k = 0; k < ctrl->npins; k++)
ctrl->pins[k] = ctrl->pid + k;
/*
* We allow to pass controls with NULL name that we treat
* as a range of one-pin groups with generic mvebu register
* controls.
*/
if (!ctrl->name) {
pctl->num_groups += ctrl->npins;
noname += ctrl->npins;
} else {
pctl->num_groups += 1;
}
}
pdesc = devm_kcalloc(&pdev->dev,
pctl->desc.npins,
sizeof(struct pinctrl_pin_desc),
GFP_KERNEL);
if (!pdesc)
return -ENOMEM;
for (n = 0; n < pctl->desc.npins; n++)
pdesc[n].number = n;
pctl->desc.pins = pdesc;
/*
* allocate groups and name buffers for unnamed groups.
*/
size = pctl->num_groups * sizeof(*pctl->groups) + noname * 8;
p = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (!p)
return -ENOMEM;
pctl->groups = p;
noname_buf = p + pctl->num_groups * sizeof(*pctl->groups);
/* assign mpp controls to groups */
gid = 0;
for (n = 0; n < soc->ncontrols; n++) {
const struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
struct mvebu_mpp_ctrl_data *data = soc->control_data ?
&soc->control_data[n] : NULL;
pctl->groups[gid].gid = gid;
pctl->groups[gid].ctrl = ctrl;
pctl->groups[gid].data = data;
pctl->groups[gid].name = ctrl->name;
pctl->groups[gid].pins = ctrl->pins;
pctl->groups[gid].npins = ctrl->npins;
/*
* We treat unnamed controls as a range of one-pin groups
* with generic mvebu register controls. Use one group for
* each in this range and assign a default group name.
*/
if (!ctrl->name) {
pctl->groups[gid].name = noname_buf;
pctl->groups[gid].npins = 1;
sprintf(noname_buf, "mpp%d", ctrl->pid+0);
noname_buf += 8;
for (k = 1; k < ctrl->npins; k++) {
gid++;
pctl->groups[gid].gid = gid;
pctl->groups[gid].ctrl = ctrl;
pctl->groups[gid].data = data;
pctl->groups[gid].name = noname_buf;
pctl->groups[gid].pins = &ctrl->pins[k];
pctl->groups[gid].npins = 1;
sprintf(noname_buf, "mpp%d", ctrl->pid+k);
noname_buf += 8;
}
}
gid++;
}
/* assign mpp modes to groups */
for (n = 0; n < soc->nmodes; n++) {
struct mvebu_mpp_mode *mode = &soc->modes[n];
struct mvebu_mpp_ctrl_setting *set = &mode->settings[0];
struct mvebu_pinctrl_group *grp;
unsigned num_settings;
unsigned supp_settings;
for (num_settings = 0, supp_settings = 0; ; set++) {
if (!set->name)
break;
num_settings++;
/* skip unsupported settings for this variant */
if (pctl->variant && !(pctl->variant & set->variant))
continue;
supp_settings++;
/* find gpio/gpo/gpi settings */
if (strcmp(set->name, "gpio") == 0)
set->flags = MVEBU_SETTING_GPI |
MVEBU_SETTING_GPO;
else if (strcmp(set->name, "gpo") == 0)
set->flags = MVEBU_SETTING_GPO;
else if (strcmp(set->name, "gpi") == 0)
set->flags = MVEBU_SETTING_GPI;
}
/* skip modes with no settings for this variant */
if (!supp_settings)
continue;
grp = mvebu_pinctrl_find_group_by_pid(pctl, mode->pid);
if (!grp) {
dev_warn(&pdev->dev, "unknown pinctrl group %d\n",
mode->pid);
continue;
}
grp->settings = mode->settings;
grp->num_settings = num_settings;
}
ret = mvebu_pinctrl_build_functions(pdev, pctl);
if (ret) {
dev_err(&pdev->dev, "unable to build functions\n");
return ret;
}
pctl->pctldev = devm_pinctrl_register(&pdev->dev, &pctl->desc, pctl);
if (IS_ERR(pctl->pctldev)) {
dev_err(&pdev->dev, "unable to register pinctrl driver\n");
return PTR_ERR(pctl->pctldev);
}
dev_info(&pdev->dev, "registered pinctrl driver\n");
/* register gpio ranges */
for (n = 0; n < soc->ngpioranges; n++)
pinctrl_add_gpio_range(pctl->pctldev, &soc->gpioranges[n]);
return 0;
}