in gpio-mxc.c [355:473]
static int mxc_gpio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct mxc_gpio_port *port;
int irq_count;
int irq_base;
int err;
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
if (!port)
return -ENOMEM;
port->dev = &pdev->dev;
port->hwdata = device_get_match_data(&pdev->dev);
port->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(port->base))
return PTR_ERR(port->base);
irq_count = platform_irq_count(pdev);
if (irq_count < 0)
return irq_count;
if (irq_count > 1) {
port->irq_high = platform_get_irq(pdev, 1);
if (port->irq_high < 0)
port->irq_high = 0;
}
port->irq = platform_get_irq(pdev, 0);
if (port->irq < 0)
return port->irq;
/* the controller clock is optional */
port->clk = devm_clk_get_optional(&pdev->dev, NULL);
if (IS_ERR(port->clk))
return PTR_ERR(port->clk);
err = clk_prepare_enable(port->clk);
if (err) {
dev_err(&pdev->dev, "Unable to enable clock.\n");
return err;
}
if (of_device_is_compatible(np, "fsl,imx7d-gpio"))
port->power_off = true;
/* disable the interrupt and clear the status */
writel(0, port->base + GPIO_IMR);
writel(~0, port->base + GPIO_ISR);
if (of_device_is_compatible(np, "fsl,imx21-gpio")) {
/*
* Setup one handler for all GPIO interrupts. Actually setting
* the handler is needed only once, but doing it for every port
* is more robust and easier.
*/
irq_set_chained_handler(port->irq, mx2_gpio_irq_handler);
} else {
/* setup one handler for each entry */
irq_set_chained_handler_and_data(port->irq,
mx3_gpio_irq_handler, port);
if (port->irq_high > 0)
/* setup handler for GPIO 16 to 31 */
irq_set_chained_handler_and_data(port->irq_high,
mx3_gpio_irq_handler,
port);
}
err = bgpio_init(&port->gc, &pdev->dev, 4,
port->base + GPIO_PSR,
port->base + GPIO_DR, NULL,
port->base + GPIO_GDIR, NULL,
BGPIOF_READ_OUTPUT_REG_SET);
if (err)
goto out_bgio;
port->gc.request = gpiochip_generic_request;
port->gc.free = gpiochip_generic_free;
port->gc.to_irq = mxc_gpio_to_irq;
port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
pdev->id * 32;
err = devm_gpiochip_add_data(&pdev->dev, &port->gc, port);
if (err)
goto out_bgio;
irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id());
if (irq_base < 0) {
err = irq_base;
goto out_bgio;
}
port->domain = irq_domain_add_legacy(np, 32, irq_base, 0,
&irq_domain_simple_ops, NULL);
if (!port->domain) {
err = -ENODEV;
goto out_bgio;
}
/* gpio-mxc can be a generic irq chip */
err = mxc_gpio_init_gc(port, irq_base);
if (err < 0)
goto out_irqdomain_remove;
list_add_tail(&port->node, &mxc_gpio_ports);
platform_set_drvdata(pdev, port);
return 0;
out_irqdomain_remove:
irq_domain_remove(port->domain);
out_bgio:
clk_disable_unprepare(port->clk);
dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
return err;
}