xref: /openbmc/linux/drivers/gpio/gpio-xgs-iproc.c (revision 72780ce5f1a4189f3c8dcfb1c596c65146452668)
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>
146a41b6c5SChris Packham #include <linux/spinlock.h>
156a41b6c5SChris Packham 
166a41b6c5SChris Packham #define IPROC_CCA_INT_F_GPIOINT		BIT(0)
176a41b6c5SChris Packham #define IPROC_CCA_INT_STS		0x20
186a41b6c5SChris Packham #define IPROC_CCA_INT_MASK		0x24
196a41b6c5SChris Packham 
206a41b6c5SChris Packham #define IPROC_GPIO_CCA_DIN		0x0
216a41b6c5SChris Packham #define IPROC_GPIO_CCA_DOUT		0x4
226a41b6c5SChris Packham #define IPROC_GPIO_CCA_OUT_EN		0x8
236a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_LEVEL	0x10
246a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_LEVEL_MASK	0x14
256a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_EVENT	0x18
266a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_EVENT_MASK	0x1C
276a41b6c5SChris Packham #define IPROC_GPIO_CCA_INT_EDGE		0x24
286a41b6c5SChris Packham 
296a41b6c5SChris Packham struct iproc_gpio_chip {
306a41b6c5SChris Packham 	struct irq_chip irqchip;
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 *
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 
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 
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 
726a41b6c5SChris Packham 	spin_lock_irqsave(&chip->lock, flags);
736a41b6c5SChris Packham 	irq_type = irq_get_trigger_type(irq);
746a41b6c5SChris Packham 	event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
756a41b6c5SChris Packham 	int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
766a41b6c5SChris Packham 
776a41b6c5SChris Packham 	if (irq_type & IRQ_TYPE_EDGE_BOTH) {
786a41b6c5SChris Packham 		event_mask |= 1 << pin;
796a41b6c5SChris Packham 		writel_relaxed(event_mask,
806a41b6c5SChris Packham 			       chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
816a41b6c5SChris Packham 	} else {
826a41b6c5SChris Packham 		int_mask |= 1 << pin;
836a41b6c5SChris Packham 		writel_relaxed(int_mask,
846a41b6c5SChris Packham 			       chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
856a41b6c5SChris Packham 	}
866a41b6c5SChris Packham 	spin_unlock_irqrestore(&chip->lock, flags);
876a41b6c5SChris Packham }
886a41b6c5SChris Packham 
896a41b6c5SChris Packham static void iproc_gpio_irq_mask(struct irq_data *d)
906a41b6c5SChris Packham {
916a41b6c5SChris Packham 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
926a41b6c5SChris Packham 	struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
936a41b6c5SChris Packham 	int pin = d->hwirq;
946a41b6c5SChris Packham 	unsigned long flags;
956a41b6c5SChris Packham 	u32 irq = d->irq;
966a41b6c5SChris Packham 	u32 irq_type, int_mask, event_mask;
976a41b6c5SChris Packham 
986a41b6c5SChris Packham 	spin_lock_irqsave(&chip->lock, flags);
996a41b6c5SChris Packham 	irq_type = irq_get_trigger_type(irq);
1006a41b6c5SChris Packham 	event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
1016a41b6c5SChris Packham 	int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
1026a41b6c5SChris Packham 
1036a41b6c5SChris Packham 	if (irq_type & IRQ_TYPE_EDGE_BOTH) {
1046a41b6c5SChris Packham 		event_mask &= ~BIT(pin);
1056a41b6c5SChris Packham 		writel_relaxed(event_mask,
1066a41b6c5SChris Packham 			       chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
1076a41b6c5SChris Packham 	} else {
1086a41b6c5SChris Packham 		int_mask &= ~BIT(pin);
1096a41b6c5SChris Packham 		writel_relaxed(int_mask,
1106a41b6c5SChris Packham 			       chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
1116a41b6c5SChris Packham 	}
1126a41b6c5SChris Packham 	spin_unlock_irqrestore(&chip->lock, flags);
1136a41b6c5SChris Packham }
1146a41b6c5SChris Packham 
1156a41b6c5SChris Packham static int iproc_gpio_irq_set_type(struct irq_data *d, u32 type)
1166a41b6c5SChris Packham {
1176a41b6c5SChris Packham 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
1186a41b6c5SChris Packham 	struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
1196a41b6c5SChris Packham 	int pin = d->hwirq;
1206a41b6c5SChris Packham 	unsigned long flags;
1216a41b6c5SChris Packham 	u32 irq = d->irq;
1226a41b6c5SChris Packham 	u32 event_pol, int_pol;
1236a41b6c5SChris Packham 	int ret = 0;
1246a41b6c5SChris Packham 
1256a41b6c5SChris Packham 	spin_lock_irqsave(&chip->lock, flags);
1266a41b6c5SChris Packham 	switch (type & IRQ_TYPE_SENSE_MASK) {
1276a41b6c5SChris Packham 	case IRQ_TYPE_EDGE_RISING:
1286a41b6c5SChris Packham 		event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE);
1296a41b6c5SChris Packham 		event_pol &= ~BIT(pin);
1306a41b6c5SChris Packham 		writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE);
1316a41b6c5SChris Packham 		break;
1326a41b6c5SChris Packham 	case IRQ_TYPE_EDGE_FALLING:
1336a41b6c5SChris Packham 		event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE);
1346a41b6c5SChris Packham 		event_pol |= BIT(pin);
1356a41b6c5SChris Packham 		writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE);
1366a41b6c5SChris Packham 		break;
1376a41b6c5SChris Packham 	case IRQ_TYPE_LEVEL_HIGH:
1386a41b6c5SChris Packham 		int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1396a41b6c5SChris Packham 		int_pol &= ~BIT(pin);
1406a41b6c5SChris Packham 		writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1416a41b6c5SChris Packham 		break;
1426a41b6c5SChris Packham 	case IRQ_TYPE_LEVEL_LOW:
1436a41b6c5SChris Packham 		int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1446a41b6c5SChris Packham 		int_pol |= BIT(pin);
1456a41b6c5SChris Packham 		writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1466a41b6c5SChris Packham 		break;
1476a41b6c5SChris Packham 	default:
1486a41b6c5SChris Packham 		/* should not come here */
1496a41b6c5SChris Packham 		ret = -EINVAL;
1506a41b6c5SChris Packham 		goto out_unlock;
1516a41b6c5SChris Packham 	}
1526a41b6c5SChris Packham 
1536a41b6c5SChris Packham 	if (type & IRQ_TYPE_LEVEL_MASK)
1546a41b6c5SChris Packham 		irq_set_handler_locked(irq_get_irq_data(irq), handle_level_irq);
1556a41b6c5SChris Packham 	else if (type & IRQ_TYPE_EDGE_BOTH)
1566a41b6c5SChris Packham 		irq_set_handler_locked(irq_get_irq_data(irq), handle_edge_irq);
1576a41b6c5SChris Packham 
1586a41b6c5SChris Packham out_unlock:
1596a41b6c5SChris Packham 	spin_unlock_irqrestore(&chip->lock, flags);
1606a41b6c5SChris Packham 
1616a41b6c5SChris Packham 	return ret;
1626a41b6c5SChris Packham }
1636a41b6c5SChris Packham 
1646a41b6c5SChris Packham static irqreturn_t iproc_gpio_irq_handler(int irq, void *data)
1656a41b6c5SChris Packham {
1666a41b6c5SChris Packham 	struct gpio_chip *gc = (struct gpio_chip *)data;
1676a41b6c5SChris Packham 	struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
1686a41b6c5SChris Packham 	int bit;
1696a41b6c5SChris Packham 	unsigned long int_bits = 0;
1706a41b6c5SChris Packham 	u32 int_status;
1716a41b6c5SChris Packham 
1726a41b6c5SChris Packham 	/* go through the entire GPIOs and handle all interrupts */
1736a41b6c5SChris Packham 	int_status = readl_relaxed(chip->intr + IPROC_CCA_INT_STS);
1746a41b6c5SChris Packham 	if (int_status & IPROC_CCA_INT_F_GPIOINT) {
1756a41b6c5SChris Packham 		u32 event, level;
1766a41b6c5SChris Packham 
1776a41b6c5SChris Packham 		/* Get level and edge interrupts */
1786a41b6c5SChris Packham 		event =
1796a41b6c5SChris Packham 		    readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
1806a41b6c5SChris Packham 		event &= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT);
1816a41b6c5SChris Packham 		level = readl_relaxed(chip->base + IPROC_GPIO_CCA_DIN);
1826a41b6c5SChris Packham 		level ^= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL);
1836a41b6c5SChris Packham 		level &=
1846a41b6c5SChris Packham 		    readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
1856a41b6c5SChris Packham 		int_bits = level | event;
1866a41b6c5SChris Packham 
1876a41b6c5SChris Packham 		for_each_set_bit(bit, &int_bits, gc->ngpio)
1886a41b6c5SChris Packham 			generic_handle_irq(irq_linear_revmap(gc->irq.domain, bit));
1896a41b6c5SChris Packham 	}
1906a41b6c5SChris Packham 
1916a41b6c5SChris Packham 	return int_bits ? IRQ_HANDLED : IRQ_NONE;
1926a41b6c5SChris Packham }
1936a41b6c5SChris Packham 
1946a41b6c5SChris Packham static int iproc_gpio_probe(struct platform_device *pdev)
1956a41b6c5SChris Packham {
1966a41b6c5SChris Packham 	struct device *dev = &pdev->dev;
1976a41b6c5SChris Packham 	struct device_node *dn = pdev->dev.of_node;
1986a41b6c5SChris Packham 	struct iproc_gpio_chip *chip;
1996a41b6c5SChris Packham 	u32 num_gpios;
2006a41b6c5SChris Packham 	int irq, ret;
2016a41b6c5SChris Packham 
2026a41b6c5SChris Packham 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
2036a41b6c5SChris Packham 	if (!chip)
2046a41b6c5SChris Packham 		return -ENOMEM;
2056a41b6c5SChris Packham 
2066a41b6c5SChris Packham 	chip->dev = dev;
2076a41b6c5SChris Packham 	platform_set_drvdata(pdev, chip);
2086a41b6c5SChris Packham 	spin_lock_init(&chip->lock);
2096a41b6c5SChris Packham 
2106a41b6c5SChris Packham 	chip->base = devm_platform_ioremap_resource(pdev, 0);
2116a41b6c5SChris Packham 	if (IS_ERR(chip->base))
2126a41b6c5SChris Packham 		return PTR_ERR(chip->base);
2136a41b6c5SChris Packham 
2146a41b6c5SChris Packham 	ret = bgpio_init(&chip->gc, dev, 4,
2156a41b6c5SChris Packham 			 chip->base + IPROC_GPIO_CCA_DIN,
2166a41b6c5SChris Packham 			 chip->base + IPROC_GPIO_CCA_DOUT,
2176a41b6c5SChris Packham 			 NULL,
2186a41b6c5SChris Packham 			 chip->base + IPROC_GPIO_CCA_OUT_EN,
2196a41b6c5SChris Packham 			 NULL,
2206a41b6c5SChris Packham 			 0);
2216a41b6c5SChris Packham 	if (ret) {
2226a41b6c5SChris Packham 		dev_err(dev, "unable to init GPIO chip\n");
2236a41b6c5SChris Packham 		return ret;
2246a41b6c5SChris Packham 	}
2256a41b6c5SChris Packham 
2266a41b6c5SChris Packham 	chip->gc.label = dev_name(dev);
2276a41b6c5SChris Packham 	if (of_property_read_u32(dn, "ngpios", &num_gpios))
2286a41b6c5SChris Packham 		chip->gc.ngpio = num_gpios;
2296a41b6c5SChris Packham 
2306a41b6c5SChris Packham 	irq = platform_get_irq(pdev, 0);
2316a41b6c5SChris Packham 	if (irq > 0) {
2326a41b6c5SChris Packham 		struct gpio_irq_chip *girq;
2336a41b6c5SChris Packham 		struct irq_chip *irqc;
2346a41b6c5SChris Packham 		u32 val;
2356a41b6c5SChris Packham 
2366a41b6c5SChris Packham 		irqc = &chip->irqchip;
2376a41b6c5SChris Packham 		irqc->name = dev_name(dev);
2386a41b6c5SChris Packham 		irqc->irq_ack = iproc_gpio_irq_ack;
2396a41b6c5SChris Packham 		irqc->irq_mask = iproc_gpio_irq_mask;
2406a41b6c5SChris Packham 		irqc->irq_unmask = iproc_gpio_irq_unmask;
2416a41b6c5SChris Packham 		irqc->irq_set_type = iproc_gpio_irq_set_type;
2426a41b6c5SChris Packham 
2436a41b6c5SChris Packham 		chip->intr = devm_platform_ioremap_resource(pdev, 1);
2446a41b6c5SChris Packham 		if (IS_ERR(chip->intr))
2456a41b6c5SChris Packham 			return PTR_ERR(chip->intr);
2466a41b6c5SChris Packham 
2476a41b6c5SChris Packham 		/* Enable GPIO interrupts for CCA GPIO */
2486a41b6c5SChris Packham 		val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK);
2496a41b6c5SChris Packham 		val |= IPROC_CCA_INT_F_GPIOINT;
2506a41b6c5SChris Packham 		writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK);
2516a41b6c5SChris Packham 
2526a41b6c5SChris Packham 		/*
2536a41b6c5SChris Packham 		 * Directly request the irq here instead of passing
254*72780ce5SLinus Walleij 		 * a flow-handler because the irq is shared.
2556a41b6c5SChris Packham 		 */
2566a41b6c5SChris Packham 		ret = devm_request_irq(dev, irq, iproc_gpio_irq_handler,
2576a41b6c5SChris Packham 				       IRQF_SHARED, chip->gc.label, &chip->gc);
2586a41b6c5SChris Packham 		if (ret) {
2596a41b6c5SChris Packham 			dev_err(dev, "Fail to request IRQ%d: %d\n", irq, ret);
2606a41b6c5SChris Packham 			return ret;
2616a41b6c5SChris Packham 		}
2626a41b6c5SChris Packham 
2636a41b6c5SChris Packham 		girq = &chip->gc.irq;
2646a41b6c5SChris Packham 		girq->chip = irqc;
2656a41b6c5SChris Packham 		/* This will let us handle the parent IRQ in the driver */
2666a41b6c5SChris Packham 		girq->parent_handler = NULL;
2676a41b6c5SChris Packham 		girq->num_parents = 0;
2686a41b6c5SChris Packham 		girq->parents = NULL;
2696a41b6c5SChris Packham 		girq->default_type = IRQ_TYPE_NONE;
2706a41b6c5SChris Packham 		girq->handler = handle_simple_irq;
2716a41b6c5SChris Packham 	}
2726a41b6c5SChris Packham 
2736a41b6c5SChris Packham 	ret = devm_gpiochip_add_data(dev, &chip->gc, chip);
2746a41b6c5SChris Packham 	if (ret) {
2756a41b6c5SChris Packham 		dev_err(dev, "unable to add GPIO chip\n");
2766a41b6c5SChris Packham 		return ret;
2776a41b6c5SChris Packham 	}
2786a41b6c5SChris Packham 
2796a41b6c5SChris Packham 	return 0;
2806a41b6c5SChris Packham }
2816a41b6c5SChris Packham 
2826a41b6c5SChris Packham static int __exit iproc_gpio_remove(struct platform_device *pdev)
2836a41b6c5SChris Packham {
2846a41b6c5SChris Packham 	struct iproc_gpio_chip *chip;
2856a41b6c5SChris Packham 
2866a41b6c5SChris Packham 	chip = platform_get_drvdata(pdev);
2876a41b6c5SChris Packham 	if (!chip)
2886a41b6c5SChris Packham 		return -ENODEV;
2896a41b6c5SChris Packham 
2906a41b6c5SChris Packham 	if (chip->intr) {
2916a41b6c5SChris Packham 		u32 val;
2926a41b6c5SChris Packham 
2936a41b6c5SChris Packham 		val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK);
2946a41b6c5SChris Packham 		val &= ~IPROC_CCA_INT_F_GPIOINT;
2956a41b6c5SChris Packham 		writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK);
2966a41b6c5SChris Packham 	}
2976a41b6c5SChris Packham 
2986a41b6c5SChris Packham 	return 0;
2996a41b6c5SChris Packham }
3006a41b6c5SChris Packham 
3015d682fa3SMark Brown static const struct of_device_id bcm_iproc_gpio_of_match[] = {
3026a41b6c5SChris Packham 	{ .compatible = "brcm,iproc-gpio-cca" },
3036a41b6c5SChris Packham 	{}
3046a41b6c5SChris Packham };
3056a41b6c5SChris Packham MODULE_DEVICE_TABLE(of, bcm_iproc_gpio_of_match);
3066a41b6c5SChris Packham 
3076a41b6c5SChris Packham static struct platform_driver bcm_iproc_gpio_driver = {
3086a41b6c5SChris Packham 	.driver = {
3096a41b6c5SChris Packham 		.name = "iproc-xgs-gpio",
3106a41b6c5SChris Packham 		.of_match_table = bcm_iproc_gpio_of_match,
3116a41b6c5SChris Packham 	},
3126a41b6c5SChris Packham 	.probe = iproc_gpio_probe,
3136a41b6c5SChris Packham 	.remove = iproc_gpio_remove,
3146a41b6c5SChris Packham };
3156a41b6c5SChris Packham 
3166a41b6c5SChris Packham module_platform_driver(bcm_iproc_gpio_driver);
3176a41b6c5SChris Packham 
3186a41b6c5SChris Packham MODULE_DESCRIPTION("XGS IPROC GPIO driver");
3196a41b6c5SChris Packham MODULE_LICENSE("GPL v2");
320