xref: /openbmc/linux/drivers/ssb/driver_gpio.c (revision c683ffe2)
1ec43b08bSHauke Mehrtens /*
2ec43b08bSHauke Mehrtens  * Sonics Silicon Backplane
3ec43b08bSHauke Mehrtens  * GPIO driver
4ec43b08bSHauke Mehrtens  *
5ec43b08bSHauke Mehrtens  * Copyright 2011, Broadcom Corporation
6ec43b08bSHauke Mehrtens  * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
7ec43b08bSHauke Mehrtens  *
8ec43b08bSHauke Mehrtens  * Licensed under the GNU/GPL. See COPYING for details.
9ec43b08bSHauke Mehrtens  */
10ec43b08bSHauke Mehrtens 
112d4443beSLinus Walleij #include <linux/gpio/driver.h>
127c1bc0daSRafał Miłecki #include <linux/irq.h>
137c1bc0daSRafał Miłecki #include <linux/interrupt.h>
147c1bc0daSRafał Miłecki #include <linux/irqdomain.h>
15ec43b08bSHauke Mehrtens #include <linux/export.h>
16ec43b08bSHauke Mehrtens #include <linux/ssb/ssb.h>
17ec43b08bSHauke Mehrtens 
18ec43b08bSHauke Mehrtens #include "ssb_private.h"
19ec43b08bSHauke Mehrtens 
207c1bc0daSRafał Miłecki 
217c1bc0daSRafał Miłecki /**************************************************
227c1bc0daSRafał Miłecki  * Shared
237c1bc0daSRafał Miłecki  **************************************************/
247c1bc0daSRafał Miłecki 
257c1bc0daSRafał Miłecki #if IS_ENABLED(CONFIG_SSB_EMBEDDED)
26c683ffe2SHugh Sipière static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned int gpio)
277c1bc0daSRafał Miłecki {
282d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
297c1bc0daSRafał Miłecki 
307c1bc0daSRafał Miłecki 	if (bus->bustype == SSB_BUSTYPE_SSB)
317c1bc0daSRafał Miłecki 		return irq_find_mapping(bus->irq_domain, gpio);
327c1bc0daSRafał Miłecki 	else
337c1bc0daSRafał Miłecki 		return -EINVAL;
347c1bc0daSRafał Miłecki }
357c1bc0daSRafał Miłecki #endif
367c1bc0daSRafał Miłecki 
377c1bc0daSRafał Miłecki /**************************************************
387c1bc0daSRafał Miłecki  * ChipCommon
397c1bc0daSRafał Miłecki  **************************************************/
407c1bc0daSRafał Miłecki 
41c683ffe2SHugh Sipière static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned int gpio)
42ec43b08bSHauke Mehrtens {
432d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
44ec43b08bSHauke Mehrtens 
45ec43b08bSHauke Mehrtens 	return !!ssb_chipco_gpio_in(&bus->chipco, 1 << gpio);
46ec43b08bSHauke Mehrtens }
47ec43b08bSHauke Mehrtens 
48c683ffe2SHugh Sipière static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned int gpio,
49ec43b08bSHauke Mehrtens 				      int value)
50ec43b08bSHauke Mehrtens {
512d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
52ec43b08bSHauke Mehrtens 
53ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
54ec43b08bSHauke Mehrtens }
55ec43b08bSHauke Mehrtens 
56ec43b08bSHauke Mehrtens static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip,
57c683ffe2SHugh Sipière 					   unsigned int gpio)
58ec43b08bSHauke Mehrtens {
592d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
60ec43b08bSHauke Mehrtens 
61ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 0);
62ec43b08bSHauke Mehrtens 	return 0;
63ec43b08bSHauke Mehrtens }
64ec43b08bSHauke Mehrtens 
65ec43b08bSHauke Mehrtens static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip,
66c683ffe2SHugh Sipière 					    unsigned int gpio, int value)
67ec43b08bSHauke Mehrtens {
682d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
69ec43b08bSHauke Mehrtens 
70ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 1 << gpio);
71ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
72ec43b08bSHauke Mehrtens 	return 0;
73ec43b08bSHauke Mehrtens }
74ec43b08bSHauke Mehrtens 
75c683ffe2SHugh Sipière static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned int gpio)
76ec43b08bSHauke Mehrtens {
772d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
78ec43b08bSHauke Mehrtens 
79ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_control(&bus->chipco, 1 << gpio, 0);
80ec43b08bSHauke Mehrtens 	/* clear pulldown */
81ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_pulldown(&bus->chipco, 1 << gpio, 0);
82ec43b08bSHauke Mehrtens 	/* Set pullup */
83ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 1 << gpio);
84ec43b08bSHauke Mehrtens 
85ec43b08bSHauke Mehrtens 	return 0;
86ec43b08bSHauke Mehrtens }
87ec43b08bSHauke Mehrtens 
88c683ffe2SHugh Sipière static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned int gpio)
89ec43b08bSHauke Mehrtens {
902d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
91ec43b08bSHauke Mehrtens 
92ec43b08bSHauke Mehrtens 	/* clear pullup */
93ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0);
94ec43b08bSHauke Mehrtens }
95ec43b08bSHauke Mehrtens 
967c1bc0daSRafał Miłecki #if IS_ENABLED(CONFIG_SSB_EMBEDDED)
977c1bc0daSRafał Miłecki static void ssb_gpio_irq_chipco_mask(struct irq_data *d)
98a6ca2e10SHauke Mehrtens {
997c1bc0daSRafał Miłecki 	struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
1007c1bc0daSRafał Miłecki 	int gpio = irqd_to_hwirq(d);
101a6ca2e10SHauke Mehrtens 
1027c1bc0daSRafał Miłecki 	ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0);
103a6ca2e10SHauke Mehrtens }
104a6ca2e10SHauke Mehrtens 
1057c1bc0daSRafał Miłecki static void ssb_gpio_irq_chipco_unmask(struct irq_data *d)
1067c1bc0daSRafał Miłecki {
1077c1bc0daSRafał Miłecki 	struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
1087c1bc0daSRafał Miłecki 	int gpio = irqd_to_hwirq(d);
1097c1bc0daSRafał Miłecki 	u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio));
1107c1bc0daSRafał Miłecki 
1117c1bc0daSRafał Miłecki 	ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val);
1127c1bc0daSRafał Miłecki 	ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio));
1137c1bc0daSRafał Miłecki }
1147c1bc0daSRafał Miłecki 
1157c1bc0daSRafał Miłecki static struct irq_chip ssb_gpio_irq_chipco_chip = {
1167c1bc0daSRafał Miłecki 	.name		= "SSB-GPIO-CC",
1177c1bc0daSRafał Miłecki 	.irq_mask	= ssb_gpio_irq_chipco_mask,
1187c1bc0daSRafał Miłecki 	.irq_unmask	= ssb_gpio_irq_chipco_unmask,
1197c1bc0daSRafał Miłecki };
1207c1bc0daSRafał Miłecki 
1217c1bc0daSRafał Miłecki static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id)
1227c1bc0daSRafał Miłecki {
1237c1bc0daSRafał Miłecki 	struct ssb_bus *bus = dev_id;
1247c1bc0daSRafał Miłecki 	struct ssb_chipcommon *chipco = &bus->chipco;
1257c1bc0daSRafał Miłecki 	u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN);
1267c1bc0daSRafał Miłecki 	u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ);
1277c1bc0daSRafał Miłecki 	u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL);
1287c1bc0daSRafał Miłecki 	unsigned long irqs = (val ^ pol) & mask;
1297c1bc0daSRafał Miłecki 	int gpio;
1307c1bc0daSRafał Miłecki 
1317c1bc0daSRafał Miłecki 	if (!irqs)
1327c1bc0daSRafał Miłecki 		return IRQ_NONE;
1337c1bc0daSRafał Miłecki 
1347c1bc0daSRafał Miłecki 	for_each_set_bit(gpio, &irqs, bus->gpio.ngpio)
1357c1bc0daSRafał Miłecki 		generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio));
1367c1bc0daSRafał Miłecki 	ssb_chipco_gpio_polarity(chipco, irqs, val & irqs);
1377c1bc0daSRafał Miłecki 
1387c1bc0daSRafał Miłecki 	return IRQ_HANDLED;
1397c1bc0daSRafał Miłecki }
1407c1bc0daSRafał Miłecki 
1417c1bc0daSRafał Miłecki static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus)
1427c1bc0daSRafał Miłecki {
1437c1bc0daSRafał Miłecki 	struct ssb_chipcommon *chipco = &bus->chipco;
1447c1bc0daSRafał Miłecki 	struct gpio_chip *chip = &bus->gpio;
1457c1bc0daSRafał Miłecki 	int gpio, hwirq, err;
1467c1bc0daSRafał Miłecki 
1477c1bc0daSRafał Miłecki 	if (bus->bustype != SSB_BUSTYPE_SSB)
1487c1bc0daSRafał Miłecki 		return 0;
1497c1bc0daSRafał Miłecki 
1507c1bc0daSRafał Miłecki 	bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio,
1517c1bc0daSRafał Miłecki 						&irq_domain_simple_ops, chipco);
1527c1bc0daSRafał Miłecki 	if (!bus->irq_domain) {
1537c1bc0daSRafał Miłecki 		err = -ENODEV;
1547c1bc0daSRafał Miłecki 		goto err_irq_domain;
1557c1bc0daSRafał Miłecki 	}
1567c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
1577c1bc0daSRafał Miłecki 		int irq = irq_create_mapping(bus->irq_domain, gpio);
1587c1bc0daSRafał Miłecki 
1597c1bc0daSRafał Miłecki 		irq_set_chip_data(irq, bus);
1607c1bc0daSRafał Miłecki 		irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip,
1617c1bc0daSRafał Miłecki 					 handle_simple_irq);
1627c1bc0daSRafał Miłecki 	}
1637c1bc0daSRafał Miłecki 
1647c1bc0daSRafał Miłecki 	hwirq = ssb_mips_irq(bus->chipco.dev) + 2;
1657c1bc0daSRafał Miłecki 	err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED,
1667c1bc0daSRafał Miłecki 			  "gpio", bus);
1677c1bc0daSRafał Miłecki 	if (err)
1687c1bc0daSRafał Miłecki 		goto err_req_irq;
1697c1bc0daSRafał Miłecki 
1707c1bc0daSRafał Miłecki 	ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0);
1717c1bc0daSRafał Miłecki 	chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO);
1727c1bc0daSRafał Miłecki 
1737c1bc0daSRafał Miłecki 	return 0;
1747c1bc0daSRafał Miłecki 
1757c1bc0daSRafał Miłecki err_req_irq:
1767c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
1777c1bc0daSRafał Miłecki 		int irq = irq_find_mapping(bus->irq_domain, gpio);
1787c1bc0daSRafał Miłecki 
1797c1bc0daSRafał Miłecki 		irq_dispose_mapping(irq);
1807c1bc0daSRafał Miłecki 	}
1817c1bc0daSRafał Miłecki 	irq_domain_remove(bus->irq_domain);
1827c1bc0daSRafał Miłecki err_irq_domain:
1837c1bc0daSRafał Miłecki 	return err;
1847c1bc0daSRafał Miłecki }
1857c1bc0daSRafał Miłecki 
1867c1bc0daSRafał Miłecki static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus)
1877c1bc0daSRafał Miłecki {
1887c1bc0daSRafał Miłecki 	struct ssb_chipcommon *chipco = &bus->chipco;
1897c1bc0daSRafał Miłecki 	struct gpio_chip *chip = &bus->gpio;
1907c1bc0daSRafał Miłecki 	int gpio;
1917c1bc0daSRafał Miłecki 
1927c1bc0daSRafał Miłecki 	if (bus->bustype != SSB_BUSTYPE_SSB)
1937c1bc0daSRafał Miłecki 		return;
1947c1bc0daSRafał Miłecki 
1957c1bc0daSRafał Miłecki 	chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO);
1967c1bc0daSRafał Miłecki 	free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco);
1977c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
1987c1bc0daSRafał Miłecki 		int irq = irq_find_mapping(bus->irq_domain, gpio);
1997c1bc0daSRafał Miłecki 
2007c1bc0daSRafał Miłecki 		irq_dispose_mapping(irq);
2017c1bc0daSRafał Miłecki 	}
2027c1bc0daSRafał Miłecki 	irq_domain_remove(bus->irq_domain);
2037c1bc0daSRafał Miłecki }
2047c1bc0daSRafał Miłecki #else
2057c1bc0daSRafał Miłecki static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus)
2067c1bc0daSRafał Miłecki {
2077c1bc0daSRafał Miłecki 	return 0;
2087c1bc0daSRafał Miłecki }
2097c1bc0daSRafał Miłecki 
2107c1bc0daSRafał Miłecki static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus)
2117c1bc0daSRafał Miłecki {
2127c1bc0daSRafał Miłecki }
2137c1bc0daSRafał Miłecki #endif
2147c1bc0daSRafał Miłecki 
215ec43b08bSHauke Mehrtens static int ssb_gpio_chipco_init(struct ssb_bus *bus)
216ec43b08bSHauke Mehrtens {
217ec43b08bSHauke Mehrtens 	struct gpio_chip *chip = &bus->gpio;
2187c1bc0daSRafał Miłecki 	int err;
219ec43b08bSHauke Mehrtens 
220ec43b08bSHauke Mehrtens 	chip->label		= "ssb_chipco_gpio";
221ec43b08bSHauke Mehrtens 	chip->owner		= THIS_MODULE;
222ec43b08bSHauke Mehrtens 	chip->request		= ssb_gpio_chipco_request;
223ec43b08bSHauke Mehrtens 	chip->free		= ssb_gpio_chipco_free;
224ec43b08bSHauke Mehrtens 	chip->get		= ssb_gpio_chipco_get_value;
225ec43b08bSHauke Mehrtens 	chip->set		= ssb_gpio_chipco_set_value;
226ec43b08bSHauke Mehrtens 	chip->direction_input	= ssb_gpio_chipco_direction_input;
227ec43b08bSHauke Mehrtens 	chip->direction_output	= ssb_gpio_chipco_direction_output;
2287c1bc0daSRafał Miłecki #if IS_ENABLED(CONFIG_SSB_EMBEDDED)
2297c1bc0daSRafał Miłecki 	chip->to_irq		= ssb_gpio_to_irq;
2307c1bc0daSRafał Miłecki #endif
231ec43b08bSHauke Mehrtens 	chip->ngpio		= 16;
232ec43b08bSHauke Mehrtens 	/* There is just one SoC in one device and its GPIO addresses should be
233ec43b08bSHauke Mehrtens 	 * deterministic to address them more easily. The other buses could get
234ec43b08bSHauke Mehrtens 	 * a random base number. */
235ec43b08bSHauke Mehrtens 	if (bus->bustype == SSB_BUSTYPE_SSB)
236ec43b08bSHauke Mehrtens 		chip->base		= 0;
237ec43b08bSHauke Mehrtens 	else
238ec43b08bSHauke Mehrtens 		chip->base		= -1;
239ec43b08bSHauke Mehrtens 
2407c1bc0daSRafał Miłecki 	err = ssb_gpio_irq_chipco_domain_init(bus);
2417c1bc0daSRafał Miłecki 	if (err)
2427c1bc0daSRafał Miłecki 		return err;
2437c1bc0daSRafał Miłecki 
2442d4443beSLinus Walleij 	err = gpiochip_add_data(chip, bus);
2457c1bc0daSRafał Miłecki 	if (err) {
2467c1bc0daSRafał Miłecki 		ssb_gpio_irq_chipco_domain_exit(bus);
2477c1bc0daSRafał Miłecki 		return err;
248ec43b08bSHauke Mehrtens 	}
249ec43b08bSHauke Mehrtens 
2507c1bc0daSRafał Miłecki 	return 0;
2517c1bc0daSRafał Miłecki }
2527c1bc0daSRafał Miłecki 
2537c1bc0daSRafał Miłecki /**************************************************
2547c1bc0daSRafał Miłecki  * EXTIF
2557c1bc0daSRafał Miłecki  **************************************************/
2567c1bc0daSRafał Miłecki 
257ec43b08bSHauke Mehrtens #ifdef CONFIG_SSB_DRIVER_EXTIF
258ec43b08bSHauke Mehrtens 
259c683ffe2SHugh Sipière static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned int gpio)
260ec43b08bSHauke Mehrtens {
2612d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
262ec43b08bSHauke Mehrtens 
263ec43b08bSHauke Mehrtens 	return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio);
264ec43b08bSHauke Mehrtens }
265ec43b08bSHauke Mehrtens 
266c683ffe2SHugh Sipière static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned int gpio,
267ec43b08bSHauke Mehrtens 				     int value)
268ec43b08bSHauke Mehrtens {
2692d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
270ec43b08bSHauke Mehrtens 
271ec43b08bSHauke Mehrtens 	ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
272ec43b08bSHauke Mehrtens }
273ec43b08bSHauke Mehrtens 
274ec43b08bSHauke Mehrtens static int ssb_gpio_extif_direction_input(struct gpio_chip *chip,
275c683ffe2SHugh Sipière 					  unsigned int gpio)
276ec43b08bSHauke Mehrtens {
2772d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
278ec43b08bSHauke Mehrtens 
279ec43b08bSHauke Mehrtens 	ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 0);
280ec43b08bSHauke Mehrtens 	return 0;
281ec43b08bSHauke Mehrtens }
282ec43b08bSHauke Mehrtens 
283ec43b08bSHauke Mehrtens static int ssb_gpio_extif_direction_output(struct gpio_chip *chip,
284c683ffe2SHugh Sipière 					   unsigned int gpio, int value)
285ec43b08bSHauke Mehrtens {
2862d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
287ec43b08bSHauke Mehrtens 
288ec43b08bSHauke Mehrtens 	ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 1 << gpio);
289ec43b08bSHauke Mehrtens 	ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
290ec43b08bSHauke Mehrtens 	return 0;
291ec43b08bSHauke Mehrtens }
292ec43b08bSHauke Mehrtens 
2937c1bc0daSRafał Miłecki #if IS_ENABLED(CONFIG_SSB_EMBEDDED)
2947c1bc0daSRafał Miłecki static void ssb_gpio_irq_extif_mask(struct irq_data *d)
295a6ca2e10SHauke Mehrtens {
2967c1bc0daSRafał Miłecki 	struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
2977c1bc0daSRafał Miłecki 	int gpio = irqd_to_hwirq(d);
298a6ca2e10SHauke Mehrtens 
2997c1bc0daSRafał Miłecki 	ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0);
300a6ca2e10SHauke Mehrtens }
301a6ca2e10SHauke Mehrtens 
3027c1bc0daSRafał Miłecki static void ssb_gpio_irq_extif_unmask(struct irq_data *d)
3037c1bc0daSRafał Miłecki {
3047c1bc0daSRafał Miłecki 	struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
3057c1bc0daSRafał Miłecki 	int gpio = irqd_to_hwirq(d);
3067c1bc0daSRafał Miłecki 	u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio));
3077c1bc0daSRafał Miłecki 
3087c1bc0daSRafał Miłecki 	ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val);
3097c1bc0daSRafał Miłecki 	ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio));
3107c1bc0daSRafał Miłecki }
3117c1bc0daSRafał Miłecki 
3127c1bc0daSRafał Miłecki static struct irq_chip ssb_gpio_irq_extif_chip = {
3137c1bc0daSRafał Miłecki 	.name		= "SSB-GPIO-EXTIF",
3147c1bc0daSRafał Miłecki 	.irq_mask	= ssb_gpio_irq_extif_mask,
3157c1bc0daSRafał Miłecki 	.irq_unmask	= ssb_gpio_irq_extif_unmask,
3167c1bc0daSRafał Miłecki };
3177c1bc0daSRafał Miłecki 
3187c1bc0daSRafał Miłecki static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id)
3197c1bc0daSRafał Miłecki {
3207c1bc0daSRafał Miłecki 	struct ssb_bus *bus = dev_id;
3217c1bc0daSRafał Miłecki 	struct ssb_extif *extif = &bus->extif;
3227c1bc0daSRafał Miłecki 	u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN);
3237c1bc0daSRafał Miłecki 	u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK);
3247c1bc0daSRafał Miłecki 	u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL);
3257c1bc0daSRafał Miłecki 	unsigned long irqs = (val ^ pol) & mask;
3267c1bc0daSRafał Miłecki 	int gpio;
3277c1bc0daSRafał Miłecki 
3287c1bc0daSRafał Miłecki 	if (!irqs)
3297c1bc0daSRafał Miłecki 		return IRQ_NONE;
3307c1bc0daSRafał Miłecki 
3317c1bc0daSRafał Miłecki 	for_each_set_bit(gpio, &irqs, bus->gpio.ngpio)
3327c1bc0daSRafał Miłecki 		generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio));
3337c1bc0daSRafał Miłecki 	ssb_extif_gpio_polarity(extif, irqs, val & irqs);
3347c1bc0daSRafał Miłecki 
3357c1bc0daSRafał Miłecki 	return IRQ_HANDLED;
3367c1bc0daSRafał Miłecki }
3377c1bc0daSRafał Miłecki 
3387c1bc0daSRafał Miłecki static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus)
3397c1bc0daSRafał Miłecki {
3407c1bc0daSRafał Miłecki 	struct ssb_extif *extif = &bus->extif;
3417c1bc0daSRafał Miłecki 	struct gpio_chip *chip = &bus->gpio;
3427c1bc0daSRafał Miłecki 	int gpio, hwirq, err;
3437c1bc0daSRafał Miłecki 
3447c1bc0daSRafał Miłecki 	if (bus->bustype != SSB_BUSTYPE_SSB)
3457c1bc0daSRafał Miłecki 		return 0;
3467c1bc0daSRafał Miłecki 
3477c1bc0daSRafał Miłecki 	bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio,
3487c1bc0daSRafał Miłecki 						&irq_domain_simple_ops, extif);
3497c1bc0daSRafał Miłecki 	if (!bus->irq_domain) {
3507c1bc0daSRafał Miłecki 		err = -ENODEV;
3517c1bc0daSRafał Miłecki 		goto err_irq_domain;
3527c1bc0daSRafał Miłecki 	}
3537c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
3547c1bc0daSRafał Miłecki 		int irq = irq_create_mapping(bus->irq_domain, gpio);
3557c1bc0daSRafał Miłecki 
3567c1bc0daSRafał Miłecki 		irq_set_chip_data(irq, bus);
3577c1bc0daSRafał Miłecki 		irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip,
3587c1bc0daSRafał Miłecki 					 handle_simple_irq);
3597c1bc0daSRafał Miłecki 	}
3607c1bc0daSRafał Miłecki 
3617c1bc0daSRafał Miłecki 	hwirq = ssb_mips_irq(bus->extif.dev) + 2;
3627c1bc0daSRafał Miłecki 	err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED,
3637c1bc0daSRafał Miłecki 			  "gpio", bus);
3647c1bc0daSRafał Miłecki 	if (err)
3657c1bc0daSRafał Miłecki 		goto err_req_irq;
3667c1bc0daSRafał Miłecki 
3677c1bc0daSRafał Miłecki 	ssb_extif_gpio_intmask(&bus->extif, ~0, 0);
3687c1bc0daSRafał Miłecki 
3697c1bc0daSRafał Miłecki 	return 0;
3707c1bc0daSRafał Miłecki 
3717c1bc0daSRafał Miłecki err_req_irq:
3727c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
3737c1bc0daSRafał Miłecki 		int irq = irq_find_mapping(bus->irq_domain, gpio);
3747c1bc0daSRafał Miłecki 
3757c1bc0daSRafał Miłecki 		irq_dispose_mapping(irq);
3767c1bc0daSRafał Miłecki 	}
3777c1bc0daSRafał Miłecki 	irq_domain_remove(bus->irq_domain);
3787c1bc0daSRafał Miłecki err_irq_domain:
3797c1bc0daSRafał Miłecki 	return err;
3807c1bc0daSRafał Miłecki }
3817c1bc0daSRafał Miłecki 
3827c1bc0daSRafał Miłecki static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus)
3837c1bc0daSRafał Miłecki {
3847c1bc0daSRafał Miłecki 	struct ssb_extif *extif = &bus->extif;
3857c1bc0daSRafał Miłecki 	struct gpio_chip *chip = &bus->gpio;
3867c1bc0daSRafał Miłecki 	int gpio;
3877c1bc0daSRafał Miłecki 
3887c1bc0daSRafał Miłecki 	if (bus->bustype != SSB_BUSTYPE_SSB)
3897c1bc0daSRafał Miłecki 		return;
3907c1bc0daSRafał Miłecki 
3917c1bc0daSRafał Miłecki 	free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif);
3927c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
3937c1bc0daSRafał Miłecki 		int irq = irq_find_mapping(bus->irq_domain, gpio);
3947c1bc0daSRafał Miłecki 
3957c1bc0daSRafał Miłecki 		irq_dispose_mapping(irq);
3967c1bc0daSRafał Miłecki 	}
3977c1bc0daSRafał Miłecki 	irq_domain_remove(bus->irq_domain);
3987c1bc0daSRafał Miłecki }
3997c1bc0daSRafał Miłecki #else
4007c1bc0daSRafał Miłecki static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus)
4017c1bc0daSRafał Miłecki {
4027c1bc0daSRafał Miłecki 	return 0;
4037c1bc0daSRafał Miłecki }
4047c1bc0daSRafał Miłecki 
4057c1bc0daSRafał Miłecki static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus)
4067c1bc0daSRafał Miłecki {
4077c1bc0daSRafał Miłecki }
4087c1bc0daSRafał Miłecki #endif
4097c1bc0daSRafał Miłecki 
410ec43b08bSHauke Mehrtens static int ssb_gpio_extif_init(struct ssb_bus *bus)
411ec43b08bSHauke Mehrtens {
412ec43b08bSHauke Mehrtens 	struct gpio_chip *chip = &bus->gpio;
4137c1bc0daSRafał Miłecki 	int err;
414ec43b08bSHauke Mehrtens 
415ec43b08bSHauke Mehrtens 	chip->label		= "ssb_extif_gpio";
416ec43b08bSHauke Mehrtens 	chip->owner		= THIS_MODULE;
417ec43b08bSHauke Mehrtens 	chip->get		= ssb_gpio_extif_get_value;
418ec43b08bSHauke Mehrtens 	chip->set		= ssb_gpio_extif_set_value;
419ec43b08bSHauke Mehrtens 	chip->direction_input	= ssb_gpio_extif_direction_input;
420ec43b08bSHauke Mehrtens 	chip->direction_output	= ssb_gpio_extif_direction_output;
4217c1bc0daSRafał Miłecki #if IS_ENABLED(CONFIG_SSB_EMBEDDED)
4227c1bc0daSRafał Miłecki 	chip->to_irq		= ssb_gpio_to_irq;
4237c1bc0daSRafał Miłecki #endif
424ec43b08bSHauke Mehrtens 	chip->ngpio		= 5;
425ec43b08bSHauke Mehrtens 	/* There is just one SoC in one device and its GPIO addresses should be
426ec43b08bSHauke Mehrtens 	 * deterministic to address them more easily. The other buses could get
427ec43b08bSHauke Mehrtens 	 * a random base number. */
428ec43b08bSHauke Mehrtens 	if (bus->bustype == SSB_BUSTYPE_SSB)
429ec43b08bSHauke Mehrtens 		chip->base		= 0;
430ec43b08bSHauke Mehrtens 	else
431ec43b08bSHauke Mehrtens 		chip->base		= -1;
432ec43b08bSHauke Mehrtens 
4337c1bc0daSRafał Miłecki 	err = ssb_gpio_irq_extif_domain_init(bus);
4347c1bc0daSRafał Miłecki 	if (err)
4357c1bc0daSRafał Miłecki 		return err;
4367c1bc0daSRafał Miłecki 
4372d4443beSLinus Walleij 	err = gpiochip_add_data(chip, bus);
4387c1bc0daSRafał Miłecki 	if (err) {
4397c1bc0daSRafał Miłecki 		ssb_gpio_irq_extif_domain_exit(bus);
4407c1bc0daSRafał Miłecki 		return err;
4417c1bc0daSRafał Miłecki 	}
4427c1bc0daSRafał Miłecki 
4437c1bc0daSRafał Miłecki 	return 0;
444ec43b08bSHauke Mehrtens }
445ec43b08bSHauke Mehrtens 
446ec43b08bSHauke Mehrtens #else
447ec43b08bSHauke Mehrtens static int ssb_gpio_extif_init(struct ssb_bus *bus)
448ec43b08bSHauke Mehrtens {
449ec43b08bSHauke Mehrtens 	return -ENOTSUPP;
450ec43b08bSHauke Mehrtens }
451ec43b08bSHauke Mehrtens #endif
452ec43b08bSHauke Mehrtens 
4537c1bc0daSRafał Miłecki /**************************************************
4547c1bc0daSRafał Miłecki  * Init
4557c1bc0daSRafał Miłecki  **************************************************/
4567c1bc0daSRafał Miłecki 
457ec43b08bSHauke Mehrtens int ssb_gpio_init(struct ssb_bus *bus)
458ec43b08bSHauke Mehrtens {
459ec43b08bSHauke Mehrtens 	if (ssb_chipco_available(&bus->chipco))
460ec43b08bSHauke Mehrtens 		return ssb_gpio_chipco_init(bus);
461ec43b08bSHauke Mehrtens 	else if (ssb_extif_available(&bus->extif))
462ec43b08bSHauke Mehrtens 		return ssb_gpio_extif_init(bus);
463ec43b08bSHauke Mehrtens 	else
464ec43b08bSHauke Mehrtens 		SSB_WARN_ON(1);
465ec43b08bSHauke Mehrtens 
466ec43b08bSHauke Mehrtens 	return -1;
467ec43b08bSHauke Mehrtens }
468600485edSHauke Mehrtens 
469600485edSHauke Mehrtens int ssb_gpio_unregister(struct ssb_bus *bus)
470600485edSHauke Mehrtens {
471600485edSHauke Mehrtens 	if (ssb_chipco_available(&bus->chipco) ||
472600485edSHauke Mehrtens 	    ssb_extif_available(&bus->extif)) {
47388d5e520Sabdoulaye berthe 		gpiochip_remove(&bus->gpio);
47488d5e520Sabdoulaye berthe 		return 0;
475600485edSHauke Mehrtens 	} else {
476600485edSHauke Mehrtens 		SSB_WARN_ON(1);
477600485edSHauke Mehrtens 	}
478600485edSHauke Mehrtens 
479600485edSHauke Mehrtens 	return -1;
480600485edSHauke Mehrtens }
481