in qcom/pinctrl-spmi-mpp.c [824:952]
static int pmic_mpp_probe(struct platform_device *pdev)
{
struct irq_domain *parent_domain;
struct device_node *parent_node;
struct device *dev = &pdev->dev;
struct pinctrl_pin_desc *pindesc;
struct pinctrl_desc *pctrldesc;
struct pmic_mpp_pad *pad, *pads;
struct pmic_mpp_state *state;
struct gpio_irq_chip *girq;
int ret, npins, i;
u32 reg;
ret = of_property_read_u32(dev->of_node, "reg", ®);
if (ret < 0) {
dev_err(dev, "missing base address");
return ret;
}
npins = (uintptr_t) device_get_match_data(&pdev->dev);
BUG_ON(npins > ARRAY_SIZE(pmic_mpp_groups));
state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
platform_set_drvdata(pdev, state);
state->dev = &pdev->dev;
state->map = dev_get_regmap(dev->parent, NULL);
pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
if (!pindesc)
return -ENOMEM;
pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
if (!pads)
return -ENOMEM;
pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
if (!pctrldesc)
return -ENOMEM;
pctrldesc->pctlops = &pmic_mpp_pinctrl_ops;
pctrldesc->pmxops = &pmic_mpp_pinmux_ops;
pctrldesc->confops = &pmic_mpp_pinconf_ops;
pctrldesc->owner = THIS_MODULE;
pctrldesc->name = dev_name(dev);
pctrldesc->pins = pindesc;
pctrldesc->npins = npins;
pctrldesc->num_custom_params = ARRAY_SIZE(pmic_mpp_bindings);
pctrldesc->custom_params = pmic_mpp_bindings;
#ifdef CONFIG_DEBUG_FS
pctrldesc->custom_conf_items = pmic_conf_items;
#endif
for (i = 0; i < npins; i++, pindesc++) {
pad = &pads[i];
pindesc->drv_data = pad;
pindesc->number = i;
pindesc->name = pmic_mpp_groups[i];
pad->base = reg + i * PMIC_MPP_ADDRESS_RANGE;
ret = pmic_mpp_populate(state, pad);
if (ret < 0)
return ret;
}
state->chip = pmic_mpp_gpio_template;
state->chip.parent = dev;
state->chip.base = -1;
state->chip.ngpio = npins;
state->chip.label = dev_name(dev);
state->chip.of_gpio_n_cells = 2;
state->chip.can_sleep = false;
state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
if (IS_ERR(state->ctrl))
return PTR_ERR(state->ctrl);
parent_node = of_irq_find_parent(state->dev->of_node);
if (!parent_node)
return -ENXIO;
parent_domain = irq_find_host(parent_node);
of_node_put(parent_node);
if (!parent_domain)
return -ENXIO;
state->irq.name = "spmi-mpp",
state->irq.irq_ack = irq_chip_ack_parent,
state->irq.irq_mask = irq_chip_mask_parent,
state->irq.irq_unmask = irq_chip_unmask_parent,
state->irq.irq_set_type = irq_chip_set_type_parent,
state->irq.irq_set_wake = irq_chip_set_wake_parent,
state->irq.flags = IRQCHIP_MASK_ON_SUSPEND,
girq = &state->chip.irq;
girq->chip = &state->irq;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
girq->fwnode = of_node_to_fwnode(state->dev->of_node);
girq->parent_domain = parent_domain;
girq->child_to_parent_hwirq = pmic_mpp_child_to_parent_hwirq;
girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_fourcell;
girq->child_offset_to_irq = pmic_mpp_child_offset_to_irq;
girq->child_irq_domain_ops.translate = pmic_mpp_domain_translate;
ret = gpiochip_add_data(&state->chip, state);
if (ret) {
dev_err(state->dev, "can't add gpio chip\n");
return ret;
}
ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
if (ret) {
dev_err(dev, "failed to add pin range\n");
goto err_range;
}
return 0;
err_range:
gpiochip_remove(&state->chip);
return ret;
}