in gpio-vf610.c [240:342]
static int vf610_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct vf610_gpio_port *port;
struct gpio_chip *gc;
struct gpio_irq_chip *girq;
struct irq_chip *ic;
int i;
int ret;
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
if (!port)
return -ENOMEM;
port->sdata = of_device_get_match_data(dev);
port->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(port->base))
return PTR_ERR(port->base);
port->gpio_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(port->gpio_base))
return PTR_ERR(port->gpio_base);
port->irq = platform_get_irq(pdev, 0);
if (port->irq < 0)
return port->irq;
port->clk_port = devm_clk_get(dev, "port");
ret = PTR_ERR_OR_ZERO(port->clk_port);
if (!ret) {
ret = clk_prepare_enable(port->clk_port);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk,
port->clk_port);
if (ret)
return ret;
} else if (ret == -EPROBE_DEFER) {
/*
* Percolate deferrals, for anything else,
* just live without the clocking.
*/
return ret;
}
port->clk_gpio = devm_clk_get(dev, "gpio");
ret = PTR_ERR_OR_ZERO(port->clk_gpio);
if (!ret) {
ret = clk_prepare_enable(port->clk_gpio);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, vf610_gpio_disable_clk,
port->clk_gpio);
if (ret)
return ret;
} else if (ret == -EPROBE_DEFER) {
return ret;
}
gc = &port->gc;
gc->parent = dev;
gc->label = "vf610-gpio";
gc->ngpio = VF610_GPIO_PER_PORT;
gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
gc->request = gpiochip_generic_request;
gc->free = gpiochip_generic_free;
gc->direction_input = vf610_gpio_direction_input;
gc->get = vf610_gpio_get;
gc->direction_output = vf610_gpio_direction_output;
gc->set = vf610_gpio_set;
ic = &port->ic;
ic->name = "gpio-vf610";
ic->irq_ack = vf610_gpio_irq_ack;
ic->irq_mask = vf610_gpio_irq_mask;
ic->irq_unmask = vf610_gpio_irq_unmask;
ic->irq_set_type = vf610_gpio_irq_set_type;
ic->irq_set_wake = vf610_gpio_irq_set_wake;
/* Mask all GPIO interrupts */
for (i = 0; i < gc->ngpio; i++)
vf610_gpio_writel(0, port->base + PORT_PCR(i));
/* Clear the interrupt status register for all GPIO's */
vf610_gpio_writel(~0, port->base + PORT_ISFR);
girq = &gc->irq;
girq->chip = ic;
girq->parent_handler = vf610_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(&pdev->dev, 1,
sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
girq->parents[0] = port->irq;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_edge_irq;
return devm_gpiochip_add_data(dev, gc, port);
}