static int ep93xx_gpio_add_bank()

in gpio-ep93xx.c [332:418]


static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc,
				struct platform_device *pdev,
				struct ep93xx_gpio *epg,
				struct ep93xx_gpio_bank *bank)
{
	void __iomem *data = epg->base + bank->data;
	void __iomem *dir = epg->base + bank->dir;
	struct gpio_chip *gc = &egc->gc;
	struct device *dev = &pdev->dev;
	struct gpio_irq_chip *girq;
	int err;

	err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
	if (err)
		return err;

	gc->label = bank->label;
	gc->base = bank->base;

	girq = &gc->irq;
	if (bank->has_irq || bank->has_hierarchical_irq) {
		struct irq_chip *ic;

		gc->set_config = ep93xx_gpio_set_config;
		egc->eic = devm_kcalloc(dev, 1,
					sizeof(*egc->eic),
					GFP_KERNEL);
		if (!egc->eic)
			return -ENOMEM;
		egc->eic->irq_offset = bank->irq;
		ic = &egc->eic->ic;
		ic->name = devm_kasprintf(dev, GFP_KERNEL, "gpio-irq-%s", bank->label);
		if (!ic->name)
			return -ENOMEM;
		ep93xx_init_irq_chip(dev, ic);
		girq->chip = ic;
	}

	if (bank->has_irq) {
		int ab_parent_irq = platform_get_irq(pdev, 0);

		girq->parent_handler = ep93xx_gpio_ab_irq_handler;
		girq->num_parents = 1;
		girq->parents = devm_kcalloc(dev, girq->num_parents,
					     sizeof(*girq->parents),
					     GFP_KERNEL);
		if (!girq->parents)
			return -ENOMEM;
		girq->default_type = IRQ_TYPE_NONE;
		girq->handler = handle_level_irq;
		girq->parents[0] = ab_parent_irq;
		girq->first = bank->irq_base;
	}

	/* Only bank F has especially funky IRQ handling */
	if (bank->has_hierarchical_irq) {
		int gpio_irq;
		int i;

		/*
		 * FIXME: convert this to use hierarchical IRQ support!
		 * this requires fixing the root irqchip to be hierarchical.
		 */
		girq->parent_handler = ep93xx_gpio_f_irq_handler;
		girq->num_parents = 8;
		girq->parents = devm_kcalloc(dev, girq->num_parents,
					     sizeof(*girq->parents),
					     GFP_KERNEL);
		if (!girq->parents)
			return -ENOMEM;
		/* Pick resources 1..8 for these IRQs */
		for (i = 0; i < girq->num_parents; i++) {
			girq->parents[i] = platform_get_irq(pdev, i + 1);
			gpio_irq = bank->irq_base + i;
			irq_set_chip_data(gpio_irq, &epg->gc[5]);
			irq_set_chip_and_handler(gpio_irq,
						 girq->chip,
						 handle_level_irq);
			irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
		}
		girq->default_type = IRQ_TYPE_NONE;
		girq->handler = handle_level_irq;
		girq->first = bank->irq_base;
	}

	return devm_gpiochip_add_data(dev, gc, epg);
}