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