static int vf610_gpio_probe()

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);
}