static int iproc_gpio_probe()

in bcm/pinctrl-iproc-gpio.c [780:909]


static int iproc_gpio_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct resource *res;
	struct iproc_gpio *chip;
	struct gpio_chip *gc;
	u32 ngpios, pinconf_disable_mask = 0;
	int irq, ret;
	bool no_pinconf = false;
	enum iproc_pinconf_ctrl_type io_ctrl_type = IOCTRL_TYPE_INVALID;

	/* NSP does not support drive strength config */
	if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio"))
		pinconf_disable_mask = BIT(IPROC_PINCONF_DRIVE_STRENGTH);
	/* Stingray does not support pinconf in this controller */
	else if (of_device_is_compatible(dev->of_node,
					 "brcm,iproc-stingray-gpio"))
		no_pinconf = true;

	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
	if (!chip)
		return -ENOMEM;

	chip->dev = dev;
	platform_set_drvdata(pdev, chip);

	chip->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(chip->base)) {
		dev_err(dev, "unable to map I/O memory\n");
		return PTR_ERR(chip->base);
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	if (res) {
		chip->io_ctrl = devm_ioremap_resource(dev, res);
		if (IS_ERR(chip->io_ctrl))
			return PTR_ERR(chip->io_ctrl);
		if (of_device_is_compatible(dev->of_node,
					    "brcm,cygnus-ccm-gpio"))
			io_ctrl_type = IOCTRL_TYPE_CDRU;
		else
			io_ctrl_type = IOCTRL_TYPE_AON;
	}

	chip->io_ctrl_type = io_ctrl_type;

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

	raw_spin_lock_init(&chip->lock);

	gc = &chip->gc;
	gc->base = -1;
	gc->ngpio = ngpios;
	chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK;
	gc->label = dev_name(dev);
	gc->parent = dev;
	gc->request = iproc_gpio_request;
	gc->free = iproc_gpio_free;
	gc->direction_input = iproc_gpio_direction_input;
	gc->direction_output = iproc_gpio_direction_output;
	gc->get_direction = iproc_gpio_get_direction;
	gc->set = iproc_gpio_set;
	gc->get = iproc_gpio_get;

	chip->pinmux_is_supported = of_property_read_bool(dev->of_node,
							"gpio-ranges");

	/* optional GPIO interrupt support */
	irq = platform_get_irq_optional(pdev, 0);
	if (irq > 0) {
		struct irq_chip *irqc;
		struct gpio_irq_chip *girq;

		irqc = &chip->irqchip;
		irqc->name = dev_name(dev);
		irqc->irq_ack = iproc_gpio_irq_ack;
		irqc->irq_mask = iproc_gpio_irq_mask;
		irqc->irq_unmask = iproc_gpio_irq_unmask;
		irqc->irq_set_type = iproc_gpio_irq_set_type;
		irqc->irq_enable = iproc_gpio_irq_unmask;
		irqc->irq_disable = iproc_gpio_irq_mask;

		girq = &gc->irq;
		girq->chip = irqc;
		girq->parent_handler = iproc_gpio_irq_handler;
		girq->num_parents = 1;
		girq->parents = devm_kcalloc(dev, 1,
					     sizeof(*girq->parents),
					     GFP_KERNEL);
		if (!girq->parents)
			return -ENOMEM;
		girq->parents[0] = irq;
		girq->default_type = IRQ_TYPE_NONE;
		girq->handler = handle_bad_irq;
	}

	ret = gpiochip_add_data(gc, chip);
	if (ret < 0) {
		dev_err(dev, "unable to add GPIO chip\n");
		return ret;
	}

	if (!no_pinconf) {
		ret = iproc_gpio_register_pinconf(chip);
		if (ret) {
			dev_err(dev, "unable to register pinconf\n");
			goto err_rm_gpiochip;
		}

		if (pinconf_disable_mask) {
			ret = iproc_pinconf_disable_map_create(chip,
							 pinconf_disable_mask);
			if (ret) {
				dev_err(dev,
					"unable to create pinconf disable map\n");
				goto err_rm_gpiochip;
			}
		}
	}

	return 0;

err_rm_gpiochip:
	gpiochip_remove(gc);

	return ret;
}