in bcm/pinctrl-iproc-gpio.c [780:909]
static int iproc_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct iproc_gpio *chip;
struct gpio_chip *gc;
u32 ngpios, pinconf_disable_mask = 0;
int irq, ret;
bool no_pinconf = false;
enum iproc_pinconf_ctrl_type io_ctrl_type = IOCTRL_TYPE_INVALID;
/* NSP does not support drive strength config */
if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio"))
pinconf_disable_mask = BIT(IPROC_PINCONF_DRIVE_STRENGTH);
/* Stingray does not support pinconf in this controller */
else if (of_device_is_compatible(dev->of_node,
"brcm,iproc-stingray-gpio"))
no_pinconf = true;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->dev = dev;
platform_set_drvdata(pdev, chip);
chip->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(chip->base)) {
dev_err(dev, "unable to map I/O memory\n");
return PTR_ERR(chip->base);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res) {
chip->io_ctrl = devm_ioremap_resource(dev, res);
if (IS_ERR(chip->io_ctrl))
return PTR_ERR(chip->io_ctrl);
if (of_device_is_compatible(dev->of_node,
"brcm,cygnus-ccm-gpio"))
io_ctrl_type = IOCTRL_TYPE_CDRU;
else
io_ctrl_type = IOCTRL_TYPE_AON;
}
chip->io_ctrl_type = io_ctrl_type;
if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
dev_err(&pdev->dev, "missing ngpios DT property\n");
return -ENODEV;
}
raw_spin_lock_init(&chip->lock);
gc = &chip->gc;
gc->base = -1;
gc->ngpio = ngpios;
chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK;
gc->label = dev_name(dev);
gc->parent = dev;
gc->request = iproc_gpio_request;
gc->free = iproc_gpio_free;
gc->direction_input = iproc_gpio_direction_input;
gc->direction_output = iproc_gpio_direction_output;
gc->get_direction = iproc_gpio_get_direction;
gc->set = iproc_gpio_set;
gc->get = iproc_gpio_get;
chip->pinmux_is_supported = of_property_read_bool(dev->of_node,
"gpio-ranges");
/* optional GPIO interrupt support */
irq = platform_get_irq_optional(pdev, 0);
if (irq > 0) {
struct irq_chip *irqc;
struct gpio_irq_chip *girq;
irqc = &chip->irqchip;
irqc->name = dev_name(dev);
irqc->irq_ack = iproc_gpio_irq_ack;
irqc->irq_mask = iproc_gpio_irq_mask;
irqc->irq_unmask = iproc_gpio_irq_unmask;
irqc->irq_set_type = iproc_gpio_irq_set_type;
irqc->irq_enable = iproc_gpio_irq_unmask;
irqc->irq_disable = iproc_gpio_irq_mask;
girq = &gc->irq;
girq->chip = irqc;
girq->parent_handler = iproc_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1,
sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
girq->parents[0] = irq;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
}
ret = gpiochip_add_data(gc, chip);
if (ret < 0) {
dev_err(dev, "unable to add GPIO chip\n");
return ret;
}
if (!no_pinconf) {
ret = iproc_gpio_register_pinconf(chip);
if (ret) {
dev_err(dev, "unable to register pinconf\n");
goto err_rm_gpiochip;
}
if (pinconf_disable_mask) {
ret = iproc_pinconf_disable_map_create(chip,
pinconf_disable_mask);
if (ret) {
dev_err(dev,
"unable to create pinconf disable map\n");
goto err_rm_gpiochip;
}
}
}
return 0;
err_rm_gpiochip:
gpiochip_remove(gc);
return ret;
}