static int mvebu_gpio_probe()

in gpio-mvebu.c [1122:1310]


static int mvebu_gpio_probe(struct platform_device *pdev)
{
	struct mvebu_gpio_chip *mvchip;
	const struct of_device_id *match;
	struct device_node *np = pdev->dev.of_node;
	struct irq_chip_generic *gc;
	struct irq_chip_type *ct;
	unsigned int ngpios;
	bool have_irqs;
	int soc_variant;
	int i, cpu, id;
	int err;

	match = of_match_device(mvebu_gpio_of_match, &pdev->dev);
	if (match)
		soc_variant = (unsigned long) match->data;
	else
		soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;

	/* Some gpio controllers do not provide irq support */
	err = platform_irq_count(pdev);
	if (err < 0)
		return err;

	have_irqs = err != 0;

	mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip),
			      GFP_KERNEL);
	if (!mvchip)
		return -ENOMEM;

	platform_set_drvdata(pdev, mvchip);

	if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
		dev_err(&pdev->dev, "Missing ngpios OF property\n");
		return -ENODEV;
	}

	id = of_alias_get_id(pdev->dev.of_node, "gpio");
	if (id < 0) {
		dev_err(&pdev->dev, "Couldn't get OF id\n");
		return id;
	}

	mvchip->clk = devm_clk_get(&pdev->dev, NULL);
	/* Not all SoCs require a clock.*/
	if (!IS_ERR(mvchip->clk))
		clk_prepare_enable(mvchip->clk);

	mvchip->soc_variant = soc_variant;
	mvchip->chip.label = dev_name(&pdev->dev);
	mvchip->chip.parent = &pdev->dev;
	mvchip->chip.request = gpiochip_generic_request;
	mvchip->chip.free = gpiochip_generic_free;
	mvchip->chip.get_direction = mvebu_gpio_get_direction;
	mvchip->chip.direction_input = mvebu_gpio_direction_input;
	mvchip->chip.get = mvebu_gpio_get;
	mvchip->chip.direction_output = mvebu_gpio_direction_output;
	mvchip->chip.set = mvebu_gpio_set;
	if (have_irqs)
		mvchip->chip.to_irq = mvebu_gpio_to_irq;
	mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK;
	mvchip->chip.ngpio = ngpios;
	mvchip->chip.can_sleep = false;
	mvchip->chip.dbg_show = mvebu_gpio_dbg_show;

	if (soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K)
		err = mvebu_gpio_probe_syscon(pdev, mvchip);
	else
		err = mvebu_gpio_probe_raw(pdev, mvchip);

	if (err)
		return err;

	/*
	 * Mask and clear GPIO interrupts.
	 */
	switch (soc_variant) {
	case MVEBU_GPIO_SOC_VARIANT_ORION:
	case MVEBU_GPIO_SOC_VARIANT_A8K:
		regmap_write(mvchip->regs,
			     GPIO_EDGE_CAUSE_OFF + mvchip->offset, 0);
		regmap_write(mvchip->regs,
			     GPIO_EDGE_MASK_OFF + mvchip->offset, 0);
		regmap_write(mvchip->regs,
			     GPIO_LEVEL_MASK_OFF + mvchip->offset, 0);
		break;
	case MVEBU_GPIO_SOC_VARIANT_MV78200:
		regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0);
		for (cpu = 0; cpu < 2; cpu++) {
			regmap_write(mvchip->regs,
				     GPIO_EDGE_MASK_MV78200_OFF(cpu), 0);
			regmap_write(mvchip->regs,
				     GPIO_LEVEL_MASK_MV78200_OFF(cpu), 0);
		}
		break;
	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
		regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0);
		regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF, 0);
		regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF, 0);
		for (cpu = 0; cpu < 4; cpu++) {
			regmap_write(mvchip->percpu_regs,
				     GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu), 0);
			regmap_write(mvchip->percpu_regs,
				     GPIO_EDGE_MASK_ARMADAXP_OFF(cpu), 0);
			regmap_write(mvchip->percpu_regs,
				     GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu), 0);
		}
		break;
	default:
		BUG();
	}

	devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip);

	/* Some MVEBU SoCs have simple PWM support for GPIO lines */
	if (IS_ENABLED(CONFIG_PWM)) {
		err = mvebu_pwm_probe(pdev, mvchip, id);
		if (err)
			return err;
	}

	/* Some gpio controllers do not provide irq support */
	if (!have_irqs)
		return 0;

	mvchip->domain =
	    irq_domain_add_linear(np, ngpios, &irq_generic_chip_ops, NULL);
	if (!mvchip->domain) {
		dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
			mvchip->chip.label);
		err = -ENODEV;
		goto err_pwm;
	}

	err = irq_alloc_domain_generic_chips(
	    mvchip->domain, ngpios, 2, np->name, handle_level_irq,
	    IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
	if (err) {
		dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
			mvchip->chip.label);
		goto err_domain;
	}

	/*
	 * NOTE: The common accessors cannot be used because of the percpu
	 * access to the mask registers
	 */
	gc = irq_get_domain_generic_chip(mvchip->domain, 0);
	gc->private = mvchip;
	ct = &gc->chip_types[0];
	ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
	ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
	ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
	ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
	ct->chip.name = mvchip->chip.label;

	ct = &gc->chip_types[1];
	ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
	ct->chip.irq_ack = mvebu_gpio_irq_ack;
	ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
	ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
	ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
	ct->handler = handle_edge_irq;
	ct->chip.name = mvchip->chip.label;

	/*
	 * Setup the interrupt handlers. Each chip can have up to 4
	 * interrupt handlers, with each handler dealing with 8 GPIO
	 * pins.
	 */
	for (i = 0; i < 4; i++) {
		int irq = platform_get_irq_optional(pdev, i);

		if (irq < 0)
			continue;
		irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler,
						 mvchip);
	}

	return 0;

err_domain:
	irq_domain_remove(mvchip->domain);
err_pwm:
	pwmchip_remove(&mvchip->mvpwm->chip);

	return err;
}