xref: /openbmc/linux/drivers/gpio/gpio-xgs-iproc.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
16a41b6c5SChris Packham // SPDX-License-Identifier: GPL-2.0
26a41b6c5SChris Packham /*
36a41b6c5SChris Packham  * Copyright (C) 2017 Broadcom
46a41b6c5SChris Packham  */
56a41b6c5SChris Packham 
66a41b6c5SChris Packham #include <linux/gpio/driver.h>
76a41b6c5SChris Packham #include <linux/init.h>
86a41b6c5SChris Packham #include <linux/interrupt.h>
96a41b6c5SChris Packham #include <linux/io.h>
106a41b6c5SChris Packham #include <linux/irq.h>
116a41b6c5SChris Packham #include <linux/kernel.h>
126a41b6c5SChris Packham #include <linux/module.h>
136a41b6c5SChris Packham #include <linux/platform_device.h>
14*9c1282b7SLinus Walleij #include <linux/seq_file.h>
156a41b6c5SChris Packham #include <linux/spinlock.h>
166a41b6c5SChris Packham 
176a41b6c5SChris Packham #define IPROC_CCA_INT_F_GPIOINT		BIT(0)
186a41b6c5SChris Packham #define IPROC_CCA_INT_STS		0x20
196a41b6c5SChris Packham #define IPROC_CCA_INT_MASK		0x24
206a41b6c5SChris Packham 
216a41b6c5SChris Packham #define IPROC_GPIO_CCA_DIN		0x0
226a41b6c5SChris Packham #define IPROC_GPIO_CCA_DOUT		0x4
236a41b6c5SChris Packham #define IPROC_GPIO_CCA_OUT_EN		0x8
246a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_LEVEL	0x10
256a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_LEVEL_MASK	0x14
266a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_EVENT	0x18
276a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_EVENT_MASK	0x1C
286a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_EDGE		0x24
296a41b6c5SChris Packham 
306a41b6c5SChris Packham struct iproc_gpio_chip {
316a41b6c5SChris Packham 	struct gpio_chip gc;
326a41b6c5SChris Packham 	spinlock_t lock;
336a41b6c5SChris Packham 	struct device *dev;
346a41b6c5SChris Packham 	void __iomem *base;
356a41b6c5SChris Packham 	void __iomem *intr;
366a41b6c5SChris Packham };
376a41b6c5SChris Packham 
386a41b6c5SChris Packham static inline struct iproc_gpio_chip *
to_iproc_gpio(struct gpio_chip * gc)396a41b6c5SChris Packham to_iproc_gpio(struct gpio_chip *gc)
406a41b6c5SChris Packham {
416a41b6c5SChris Packham 	return container_of(gc, struct iproc_gpio_chip, gc);
426a41b6c5SChris Packham }
436a41b6c5SChris Packham 
iproc_gpio_irq_ack(struct irq_data * d)446a41b6c5SChris Packham static void iproc_gpio_irq_ack(struct irq_data *d)
456a41b6c5SChris Packham {
466a41b6c5SChris Packham 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
476a41b6c5SChris Packham 	struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
486a41b6c5SChris Packham 	int pin = d->hwirq;
496a41b6c5SChris Packham 	unsigned long flags;
506a41b6c5SChris Packham 	u32 irq = d->irq;
516a41b6c5SChris Packham 	u32 irq_type, event_status = 0;
526a41b6c5SChris Packham 
536a41b6c5SChris Packham 	spin_lock_irqsave(&chip->lock, flags);
546a41b6c5SChris Packham 	irq_type = irq_get_trigger_type(irq);
556a41b6c5SChris Packham 	if (irq_type & IRQ_TYPE_EDGE_BOTH) {
566a41b6c5SChris Packham 		event_status |= BIT(pin);
576a41b6c5SChris Packham 		writel_relaxed(event_status,
586a41b6c5SChris Packham 			       chip->base + IPROC_GPIO_CCA_INT_EVENT);
596a41b6c5SChris Packham 	}
606a41b6c5SChris Packham 	spin_unlock_irqrestore(&chip->lock, flags);
616a41b6c5SChris Packham }
626a41b6c5SChris Packham 
iproc_gpio_irq_unmask(struct irq_data * d)636a41b6c5SChris Packham static void iproc_gpio_irq_unmask(struct irq_data *d)
646a41b6c5SChris Packham {
656a41b6c5SChris Packham 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
666a41b6c5SChris Packham 	struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
676a41b6c5SChris Packham 	int pin = d->hwirq;
686a41b6c5SChris Packham 	unsigned long flags;
696a41b6c5SChris Packham 	u32 irq = d->irq;
706a41b6c5SChris Packham 	u32 int_mask, irq_type, event_mask;
716a41b6c5SChris Packham 
72*9c1282b7SLinus Walleij 	gpiochip_enable_irq(gc, pin);
736a41b6c5SChris Packham 	spin_lock_irqsave(&chip->lock, flags);
746a41b6c5SChris Packham 	irq_type = irq_get_trigger_type(irq);
756a41b6c5SChris Packham 	event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
766a41b6c5SChris Packham 	int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
776a41b6c5SChris Packham 
786a41b6c5SChris Packham 	if (irq_type & IRQ_TYPE_EDGE_BOTH) {
796a41b6c5SChris Packham 		event_mask |= 1 << pin;
806a41b6c5SChris Packham 		writel_relaxed(event_mask,
816a41b6c5SChris Packham 			       chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
826a41b6c5SChris Packham 	} else {
836a41b6c5SChris Packham 		int_mask |= 1 << pin;
846a41b6c5SChris Packham 		writel_relaxed(int_mask,
856a41b6c5SChris Packham 			       chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
866a41b6c5SChris Packham 	}
876a41b6c5SChris Packham 	spin_unlock_irqrestore(&chip->lock, flags);
886a41b6c5SChris Packham }
896a41b6c5SChris Packham 
iproc_gpio_irq_mask(struct irq_data * d)906a41b6c5SChris Packham static void iproc_gpio_irq_mask(struct irq_data *d)
916a41b6c5SChris Packham {
926a41b6c5SChris Packham 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
936a41b6c5SChris Packham 	struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
946a41b6c5SChris Packham 	int pin = d->hwirq;
956a41b6c5SChris Packham 	unsigned long flags;
966a41b6c5SChris Packham 	u32 irq = d->irq;
976a41b6c5SChris Packham 	u32 irq_type, int_mask, event_mask;
986a41b6c5SChris Packham 
996a41b6c5SChris Packham 	spin_lock_irqsave(&chip->lock, flags);
1006a41b6c5SChris Packham 	irq_type = irq_get_trigger_type(irq);
1016a41b6c5SChris Packham 	event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
1026a41b6c5SChris Packham 	int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
1036a41b6c5SChris Packham 
1046a41b6c5SChris Packham 	if (irq_type & IRQ_TYPE_EDGE_BOTH) {
1056a41b6c5SChris Packham 		event_mask &= ~BIT(pin);
1066a41b6c5SChris Packham 		writel_relaxed(event_mask,
1076a41b6c5SChris Packham 			       chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
1086a41b6c5SChris Packham 	} else {
1096a41b6c5SChris Packham 		int_mask &= ~BIT(pin);
1106a41b6c5SChris Packham 		writel_relaxed(int_mask,
1116a41b6c5SChris Packham 			       chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
1126a41b6c5SChris Packham 	}
1136a41b6c5SChris Packham 	spin_unlock_irqrestore(&chip->lock, flags);
114*9c1282b7SLinus Walleij 	gpiochip_disable_irq(gc, pin);
1156a41b6c5SChris Packham }
1166a41b6c5SChris Packham 
iproc_gpio_irq_set_type(struct irq_data * d,u32 type)1176a41b6c5SChris Packham static int iproc_gpio_irq_set_type(struct irq_data *d, u32 type)
1186a41b6c5SChris Packham {
1196a41b6c5SChris Packham 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
1206a41b6c5SChris Packham 	struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
1216a41b6c5SChris Packham 	int pin = d->hwirq;
1226a41b6c5SChris Packham 	unsigned long flags;
1236a41b6c5SChris Packham 	u32 irq = d->irq;
1246a41b6c5SChris Packham 	u32 event_pol, int_pol;
1256a41b6c5SChris Packham 	int ret = 0;
1266a41b6c5SChris Packham 
1276a41b6c5SChris Packham 	spin_lock_irqsave(&chip->lock, flags);
1286a41b6c5SChris Packham 	switch (type & IRQ_TYPE_SENSE_MASK) {
1296a41b6c5SChris Packham 	case IRQ_TYPE_EDGE_RISING:
1306a41b6c5SChris Packham 		event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE);
1316a41b6c5SChris Packham 		event_pol &= ~BIT(pin);
1326a41b6c5SChris Packham 		writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE);
1336a41b6c5SChris Packham 		break;
1346a41b6c5SChris Packham 	case IRQ_TYPE_EDGE_FALLING:
1356a41b6c5SChris Packham 		event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE);
1366a41b6c5SChris Packham 		event_pol |= BIT(pin);
1376a41b6c5SChris Packham 		writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE);
1386a41b6c5SChris Packham 		break;
1396a41b6c5SChris Packham 	case IRQ_TYPE_LEVEL_HIGH:
1406a41b6c5SChris Packham 		int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1416a41b6c5SChris Packham 		int_pol &= ~BIT(pin);
1426a41b6c5SChris Packham 		writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1436a41b6c5SChris Packham 		break;
1446a41b6c5SChris Packham 	case IRQ_TYPE_LEVEL_LOW:
1456a41b6c5SChris Packham 		int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1466a41b6c5SChris Packham 		int_pol |= BIT(pin);
1476a41b6c5SChris Packham 		writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1486a41b6c5SChris Packham 		break;
1496a41b6c5SChris Packham 	default:
1506a41b6c5SChris Packham 		/* should not come here */
1516a41b6c5SChris Packham 		ret = -EINVAL;
1526a41b6c5SChris Packham 		goto out_unlock;
1536a41b6c5SChris Packham 	}
1546a41b6c5SChris Packham 
1556a41b6c5SChris Packham 	if (type & IRQ_TYPE_LEVEL_MASK)
1566a41b6c5SChris Packham 		irq_set_handler_locked(irq_get_irq_data(irq), handle_level_irq);
1576a41b6c5SChris Packham 	else if (type & IRQ_TYPE_EDGE_BOTH)
1586a41b6c5SChris Packham 		irq_set_handler_locked(irq_get_irq_data(irq), handle_edge_irq);
1596a41b6c5SChris Packham 
1606a41b6c5SChris Packham out_unlock:
1616a41b6c5SChris Packham 	spin_unlock_irqrestore(&chip->lock, flags);
1626a41b6c5SChris Packham 
1636a41b6c5SChris Packham 	return ret;
1646a41b6c5SChris Packham }
1656a41b6c5SChris Packham 
iproc_gpio_irq_handler(int irq,void * data)1666a41b6c5SChris Packham static irqreturn_t iproc_gpio_irq_handler(int irq, void *data)
1676a41b6c5SChris Packham {
1686a41b6c5SChris Packham 	struct gpio_chip *gc = (struct gpio_chip *)data;
1696a41b6c5SChris Packham 	struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
1706a41b6c5SChris Packham 	int bit;
1716a41b6c5SChris Packham 	unsigned long int_bits = 0;
1726a41b6c5SChris Packham 	u32 int_status;
1736a41b6c5SChris Packham 
1746a41b6c5SChris Packham 	/* go through the entire GPIOs and handle all interrupts */
1756a41b6c5SChris Packham 	int_status = readl_relaxed(chip->intr + IPROC_CCA_INT_STS);
1766a41b6c5SChris Packham 	if (int_status & IPROC_CCA_INT_F_GPIOINT) {
1776a41b6c5SChris Packham 		u32 event, level;
1786a41b6c5SChris Packham 
1796a41b6c5SChris Packham 		/* Get level and edge interrupts */
1806a41b6c5SChris Packham 		event =
1816a41b6c5SChris Packham 		    readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
1826a41b6c5SChris Packham 		event &= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT);
1836a41b6c5SChris Packham 		level = readl_relaxed(chip->base + IPROC_GPIO_CCA_DIN);
1846a41b6c5SChris Packham 		level ^= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1856a41b6c5SChris Packham 		level &=
1866a41b6c5SChris Packham 		    readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
1876a41b6c5SChris Packham 		int_bits = level | event;
1886a41b6c5SChris Packham 
1896a41b6c5SChris Packham 		for_each_set_bit(bit, &int_bits, gc->ngpio)
190dbd1c54fSMarc Zyngier 			generic_handle_domain_irq(gc->irq.domain, bit);
1916a41b6c5SChris Packham 	}
1926a41b6c5SChris Packham 
1936a41b6c5SChris Packham 	return int_bits ? IRQ_HANDLED : IRQ_NONE;
1946a41b6c5SChris Packham }
1956a41b6c5SChris Packham 
iproc_gpio_irq_print_chip(struct irq_data * d,struct seq_file * p)196*9c1282b7SLinus Walleij static void iproc_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
197*9c1282b7SLinus Walleij {
198*9c1282b7SLinus Walleij 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
199*9c1282b7SLinus Walleij 	struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
200*9c1282b7SLinus Walleij 
201*9c1282b7SLinus Walleij 	seq_printf(p, dev_name(chip->dev));
202*9c1282b7SLinus Walleij }
203*9c1282b7SLinus Walleij 
204*9c1282b7SLinus Walleij static const struct irq_chip iproc_gpio_irq_chip = {
205*9c1282b7SLinus Walleij 	.irq_ack = iproc_gpio_irq_ack,
206*9c1282b7SLinus Walleij 	.irq_mask = iproc_gpio_irq_mask,
207*9c1282b7SLinus Walleij 	.irq_unmask = iproc_gpio_irq_unmask,
208*9c1282b7SLinus Walleij 	.irq_set_type = iproc_gpio_irq_set_type,
209*9c1282b7SLinus Walleij 	.irq_print_chip = iproc_gpio_irq_print_chip,
210*9c1282b7SLinus Walleij 	.flags = IRQCHIP_IMMUTABLE,
211*9c1282b7SLinus Walleij 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
212*9c1282b7SLinus Walleij };
213*9c1282b7SLinus Walleij 
iproc_gpio_probe(struct platform_device * pdev)2146a41b6c5SChris Packham static int iproc_gpio_probe(struct platform_device *pdev)
2156a41b6c5SChris Packham {
2166a41b6c5SChris Packham 	struct device *dev = &pdev->dev;
2176a41b6c5SChris Packham 	struct device_node *dn = pdev->dev.of_node;
2186a41b6c5SChris Packham 	struct iproc_gpio_chip *chip;
2196a41b6c5SChris Packham 	u32 num_gpios;
2206a41b6c5SChris Packham 	int irq, ret;
2216a41b6c5SChris Packham 
2226a41b6c5SChris Packham 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
2236a41b6c5SChris Packham 	if (!chip)
2246a41b6c5SChris Packham 		return -ENOMEM;
2256a41b6c5SChris Packham 
2266a41b6c5SChris Packham 	chip->dev = dev;
2276a41b6c5SChris Packham 	platform_set_drvdata(pdev, chip);
2286a41b6c5SChris Packham 	spin_lock_init(&chip->lock);
2296a41b6c5SChris Packham 
2306a41b6c5SChris Packham 	chip->base = devm_platform_ioremap_resource(pdev, 0);
2316a41b6c5SChris Packham 	if (IS_ERR(chip->base))
2326a41b6c5SChris Packham 		return PTR_ERR(chip->base);
2336a41b6c5SChris Packham 
2346a41b6c5SChris Packham 	ret = bgpio_init(&chip->gc, dev, 4,
2356a41b6c5SChris Packham 			 chip->base + IPROC_GPIO_CCA_DIN,
2366a41b6c5SChris Packham 			 chip->base + IPROC_GPIO_CCA_DOUT,
2376a41b6c5SChris Packham 			 NULL,
2386a41b6c5SChris Packham 			 chip->base + IPROC_GPIO_CCA_OUT_EN,
2396a41b6c5SChris Packham 			 NULL,
2406a41b6c5SChris Packham 			 0);
2416a41b6c5SChris Packham 	if (ret) {
2426a41b6c5SChris Packham 		dev_err(dev, "unable to init GPIO chip\n");
2436a41b6c5SChris Packham 		return ret;
2446a41b6c5SChris Packham 	}
2456a41b6c5SChris Packham 
2466a41b6c5SChris Packham 	chip->gc.label = dev_name(dev);
24785fe6415SJonas Gorski 	if (!of_property_read_u32(dn, "ngpios", &num_gpios))
2486a41b6c5SChris Packham 		chip->gc.ngpio = num_gpios;
2496a41b6c5SChris Packham 
2506a41b6c5SChris Packham 	irq = platform_get_irq(pdev, 0);
2516a41b6c5SChris Packham 	if (irq > 0) {
2526a41b6c5SChris Packham 		struct gpio_irq_chip *girq;
2536a41b6c5SChris Packham 		u32 val;
2546a41b6c5SChris Packham 
2556a41b6c5SChris Packham 		chip->intr = devm_platform_ioremap_resource(pdev, 1);
2566a41b6c5SChris Packham 		if (IS_ERR(chip->intr))
2576a41b6c5SChris Packham 			return PTR_ERR(chip->intr);
2586a41b6c5SChris Packham 
2596a41b6c5SChris Packham 		/* Enable GPIO interrupts for CCA GPIO */
2606a41b6c5SChris Packham 		val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK);
2616a41b6c5SChris Packham 		val |= IPROC_CCA_INT_F_GPIOINT;
2626a41b6c5SChris Packham 		writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK);
2636a41b6c5SChris Packham 
2646a41b6c5SChris Packham 		/*
2656a41b6c5SChris Packham 		 * Directly request the irq here instead of passing
26672780ce5SLinus Walleij 		 * a flow-handler because the irq is shared.
2676a41b6c5SChris Packham 		 */
2686a41b6c5SChris Packham 		ret = devm_request_irq(dev, irq, iproc_gpio_irq_handler,
2696a41b6c5SChris Packham 				       IRQF_SHARED, chip->gc.label, &chip->gc);
2706a41b6c5SChris Packham 		if (ret) {
2716a41b6c5SChris Packham 			dev_err(dev, "Fail to request IRQ%d: %d\n", irq, ret);
2726a41b6c5SChris Packham 			return ret;
2736a41b6c5SChris Packham 		}
2746a41b6c5SChris Packham 
2756a41b6c5SChris Packham 		girq = &chip->gc.irq;
276*9c1282b7SLinus Walleij 		gpio_irq_chip_set_chip(girq, &iproc_gpio_irq_chip);
2776a41b6c5SChris Packham 		/* This will let us handle the parent IRQ in the driver */
2786a41b6c5SChris Packham 		girq->parent_handler = NULL;
2796a41b6c5SChris Packham 		girq->num_parents = 0;
2806a41b6c5SChris Packham 		girq->parents = NULL;
2816a41b6c5SChris Packham 		girq->default_type = IRQ_TYPE_NONE;
2826a41b6c5SChris Packham 		girq->handler = handle_simple_irq;
2836a41b6c5SChris Packham 	}
2846a41b6c5SChris Packham 
2856a41b6c5SChris Packham 	ret = devm_gpiochip_add_data(dev, &chip->gc, chip);
2866a41b6c5SChris Packham 	if (ret) {
2876a41b6c5SChris Packham 		dev_err(dev, "unable to add GPIO chip\n");
2886a41b6c5SChris Packham 		return ret;
2896a41b6c5SChris Packham 	}
2906a41b6c5SChris Packham 
2916a41b6c5SChris Packham 	return 0;
2926a41b6c5SChris Packham }
2936a41b6c5SChris Packham 
iproc_gpio_remove(struct platform_device * pdev)2949cc7a18bSArnd Bergmann static int iproc_gpio_remove(struct platform_device *pdev)
2956a41b6c5SChris Packham {
2963d57fa2aSUwe Kleine-König 	struct iproc_gpio_chip *chip = platform_get_drvdata(pdev);
2976a41b6c5SChris Packham 
2986a41b6c5SChris Packham 	if (chip->intr) {
2996a41b6c5SChris Packham 		u32 val;
3006a41b6c5SChris Packham 
3016a41b6c5SChris Packham 		val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK);
3026a41b6c5SChris Packham 		val &= ~IPROC_CCA_INT_F_GPIOINT;
3036a41b6c5SChris Packham 		writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK);
3046a41b6c5SChris Packham 	}
3056a41b6c5SChris Packham 
3066a41b6c5SChris Packham 	return 0;
3076a41b6c5SChris Packham }
3086a41b6c5SChris Packham 
3095d682fa3SMark Brown static const struct of_device_id bcm_iproc_gpio_of_match[] = {
3106a41b6c5SChris Packham 	{ .compatible = "brcm,iproc-gpio-cca" },
3116a41b6c5SChris Packham 	{}
3126a41b6c5SChris Packham };
3136a41b6c5SChris Packham MODULE_DEVICE_TABLE(of, bcm_iproc_gpio_of_match);
3146a41b6c5SChris Packham 
3156a41b6c5SChris Packham static struct platform_driver bcm_iproc_gpio_driver = {
3166a41b6c5SChris Packham 	.driver = {
3176a41b6c5SChris Packham 		.name = "iproc-xgs-gpio",
3186a41b6c5SChris Packham 		.of_match_table = bcm_iproc_gpio_of_match,
3196a41b6c5SChris Packham 	},
3206a41b6c5SChris Packham 	.probe = iproc_gpio_probe,
3216a41b6c5SChris Packham 	.remove = iproc_gpio_remove,
3226a41b6c5SChris Packham };
3236a41b6c5SChris Packham 
3246a41b6c5SChris Packham module_platform_driver(bcm_iproc_gpio_driver);
3256a41b6c5SChris Packham 
3266a41b6c5SChris Packham MODULE_DESCRIPTION("XGS IPROC GPIO driver");
3276a41b6c5SChris Packham MODULE_LICENSE("GPL v2");
328