static int grgpio_probe()

in gpio-grgpio.c [328:432]


static int grgpio_probe(struct platform_device *ofdev)
{
	struct device_node *np = ofdev->dev.of_node;
	void  __iomem *regs;
	struct gpio_chip *gc;
	struct grgpio_priv *priv;
	int err;
	u32 prop;
	s32 *irqmap;
	int size;
	int i;

	priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	regs = devm_platform_ioremap_resource(ofdev, 0);
	if (IS_ERR(regs))
		return PTR_ERR(regs);

	gc = &priv->gc;
	err = bgpio_init(gc, &ofdev->dev, 4, regs + GRGPIO_DATA,
			 regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL,
			 BGPIOF_BIG_ENDIAN_BYTE_ORDER);
	if (err) {
		dev_err(&ofdev->dev, "bgpio_init() failed\n");
		return err;
	}

	priv->regs = regs;
	priv->imask = gc->read_reg(regs + GRGPIO_IMASK);
	priv->dev = &ofdev->dev;

	gc->owner = THIS_MODULE;
	gc->to_irq = grgpio_to_irq;
	gc->label = devm_kasprintf(&ofdev->dev, GFP_KERNEL, "%pOF", np);
	gc->base = -1;

	err = of_property_read_u32(np, "nbits", &prop);
	if (err || prop <= 0 || prop > GRGPIO_MAX_NGPIO) {
		gc->ngpio = GRGPIO_MAX_NGPIO;
		dev_dbg(&ofdev->dev,
			"No or invalid nbits property: assume %d\n", gc->ngpio);
	} else {
		gc->ngpio = prop;
	}

	/*
	 * The irqmap contains the index values indicating which underlying irq,
	 * if anyone, is connected to that line
	 */
	irqmap = (s32 *)of_get_property(np, "irqmap", &size);
	if (irqmap) {
		if (size < gc->ngpio) {
			dev_err(&ofdev->dev,
				"irqmap shorter than ngpio (%d < %d)\n",
				size, gc->ngpio);
			return -EINVAL;
		}

		priv->domain = irq_domain_add_linear(np, gc->ngpio,
						     &grgpio_irq_domain_ops,
						     priv);
		if (!priv->domain) {
			dev_err(&ofdev->dev, "Could not add irq domain\n");
			return -EINVAL;
		}

		for (i = 0; i < gc->ngpio; i++) {
			struct grgpio_lirq *lirq;
			int ret;

			lirq = &priv->lirqs[i];
			lirq->index = irqmap[i];

			if (lirq->index < 0)
				continue;

			ret = platform_get_irq(ofdev, lirq->index);
			if (ret <= 0) {
				/*
				 * Continue without irq functionality for that
				 * gpio line
				 */
				continue;
			}
			priv->uirqs[lirq->index].uirq = ret;
		}
	}

	platform_set_drvdata(ofdev, priv);

	err = gpiochip_add_data(gc, priv);
	if (err) {
		dev_err(&ofdev->dev, "Could not add gpiochip\n");
		if (priv->domain)
			irq_domain_remove(priv->domain);
		return err;
	}

	dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n",
		 priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off");

	return 0;
}