xref: /openbmc/linux/drivers/ssb/driver_gpio.c (revision f285de79)
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 
11b8b6069cSMichael Büsch #include "ssb_private.h"
12b8b6069cSMichael Büsch 
132d4443beSLinus Walleij #include <linux/gpio/driver.h>
147c1bc0daSRafał Miłecki #include <linux/irq.h>
157c1bc0daSRafał Miłecki #include <linux/interrupt.h>
167c1bc0daSRafał Miłecki #include <linux/irqdomain.h>
17ec43b08bSHauke Mehrtens #include <linux/export.h>
18ec43b08bSHauke Mehrtens #include <linux/ssb/ssb.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)
ssb_gpio_to_irq(struct gpio_chip * chip,unsigned int gpio)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 
ssb_gpio_chipco_get_value(struct gpio_chip * chip,unsigned int gpio)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 
ssb_gpio_chipco_set_value(struct gpio_chip * chip,unsigned int gpio,int value)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 
ssb_gpio_chipco_direction_input(struct gpio_chip * chip,unsigned int gpio)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 
ssb_gpio_chipco_direction_output(struct gpio_chip * chip,unsigned int gpio,int value)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 
ssb_gpio_chipco_request(struct gpio_chip * chip,unsigned int gpio)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 
ssb_gpio_chipco_free(struct gpio_chip * chip,unsigned int gpio)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)
ssb_gpio_irq_chipco_mask(struct irq_data * d)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 
ssb_gpio_irq_chipco_unmask(struct irq_data * d)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 
ssb_gpio_irq_chipco_handler(int irq,void * dev_id)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)
135*f285de79SSebastian Andrzej Siewior 		generic_handle_domain_irq_safe(bus->irq_domain, gpio);
136*f285de79SSebastian Andrzej Siewior 
1377c1bc0daSRafał Miłecki 	ssb_chipco_gpio_polarity(chipco, irqs, val & irqs);
1387c1bc0daSRafał Miłecki 
1397c1bc0daSRafał Miłecki 	return IRQ_HANDLED;
1407c1bc0daSRafał Miłecki }
1417c1bc0daSRafał Miłecki 
ssb_gpio_irq_chipco_domain_init(struct ssb_bus * bus)1427c1bc0daSRafał Miłecki static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus)
1437c1bc0daSRafał Miłecki {
1447c1bc0daSRafał Miłecki 	struct ssb_chipcommon *chipco = &bus->chipco;
1457c1bc0daSRafał Miłecki 	struct gpio_chip *chip = &bus->gpio;
1467c1bc0daSRafał Miłecki 	int gpio, hwirq, err;
1477c1bc0daSRafał Miłecki 
1487c1bc0daSRafał Miłecki 	if (bus->bustype != SSB_BUSTYPE_SSB)
1497c1bc0daSRafał Miłecki 		return 0;
1507c1bc0daSRafał Miłecki 
1517c1bc0daSRafał Miłecki 	bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio,
1527c1bc0daSRafał Miłecki 						&irq_domain_simple_ops, chipco);
1537c1bc0daSRafał Miłecki 	if (!bus->irq_domain) {
1547c1bc0daSRafał Miłecki 		err = -ENODEV;
1557c1bc0daSRafał Miłecki 		goto err_irq_domain;
1567c1bc0daSRafał Miłecki 	}
1577c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
1587c1bc0daSRafał Miłecki 		int irq = irq_create_mapping(bus->irq_domain, gpio);
1597c1bc0daSRafał Miłecki 
1607c1bc0daSRafał Miłecki 		irq_set_chip_data(irq, bus);
1617c1bc0daSRafał Miłecki 		irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip,
1627c1bc0daSRafał Miłecki 					 handle_simple_irq);
1637c1bc0daSRafał Miłecki 	}
1647c1bc0daSRafał Miłecki 
1657c1bc0daSRafał Miłecki 	hwirq = ssb_mips_irq(bus->chipco.dev) + 2;
1667c1bc0daSRafał Miłecki 	err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED,
1677c1bc0daSRafał Miłecki 			  "gpio", bus);
1687c1bc0daSRafał Miłecki 	if (err)
1697c1bc0daSRafał Miłecki 		goto err_req_irq;
1707c1bc0daSRafał Miłecki 
1717c1bc0daSRafał Miłecki 	ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0);
1727c1bc0daSRafał Miłecki 	chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO);
1737c1bc0daSRafał Miłecki 
1747c1bc0daSRafał Miłecki 	return 0;
1757c1bc0daSRafał Miłecki 
1767c1bc0daSRafał Miłecki err_req_irq:
1777c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
1787c1bc0daSRafał Miłecki 		int irq = irq_find_mapping(bus->irq_domain, gpio);
1797c1bc0daSRafał Miłecki 
1807c1bc0daSRafał Miłecki 		irq_dispose_mapping(irq);
1817c1bc0daSRafał Miłecki 	}
1827c1bc0daSRafał Miłecki 	irq_domain_remove(bus->irq_domain);
1837c1bc0daSRafał Miłecki err_irq_domain:
1847c1bc0daSRafał Miłecki 	return err;
1857c1bc0daSRafał Miłecki }
1867c1bc0daSRafał Miłecki 
ssb_gpio_irq_chipco_domain_exit(struct ssb_bus * bus)1877c1bc0daSRafał Miłecki static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus)
1887c1bc0daSRafał Miłecki {
1897c1bc0daSRafał Miłecki 	struct ssb_chipcommon *chipco = &bus->chipco;
1907c1bc0daSRafał Miłecki 	struct gpio_chip *chip = &bus->gpio;
1917c1bc0daSRafał Miłecki 	int gpio;
1927c1bc0daSRafał Miłecki 
1937c1bc0daSRafał Miłecki 	if (bus->bustype != SSB_BUSTYPE_SSB)
1947c1bc0daSRafał Miłecki 		return;
1957c1bc0daSRafał Miłecki 
1967c1bc0daSRafał Miłecki 	chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO);
1977c1bc0daSRafał Miłecki 	free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco);
1987c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
1997c1bc0daSRafał Miłecki 		int irq = irq_find_mapping(bus->irq_domain, gpio);
2007c1bc0daSRafał Miłecki 
2017c1bc0daSRafał Miłecki 		irq_dispose_mapping(irq);
2027c1bc0daSRafał Miłecki 	}
2037c1bc0daSRafał Miłecki 	irq_domain_remove(bus->irq_domain);
2047c1bc0daSRafał Miłecki }
2057c1bc0daSRafał Miłecki #else
ssb_gpio_irq_chipco_domain_init(struct ssb_bus * bus)2067c1bc0daSRafał Miłecki static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus)
2077c1bc0daSRafał Miłecki {
2087c1bc0daSRafał Miłecki 	return 0;
2097c1bc0daSRafał Miłecki }
2107c1bc0daSRafał Miłecki 
ssb_gpio_irq_chipco_domain_exit(struct ssb_bus * bus)2117c1bc0daSRafał Miłecki static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus)
2127c1bc0daSRafał Miłecki {
2137c1bc0daSRafał Miłecki }
2147c1bc0daSRafał Miłecki #endif
2157c1bc0daSRafał Miłecki 
ssb_gpio_chipco_init(struct ssb_bus * bus)216ec43b08bSHauke Mehrtens static int ssb_gpio_chipco_init(struct ssb_bus *bus)
217ec43b08bSHauke Mehrtens {
218ec43b08bSHauke Mehrtens 	struct gpio_chip *chip = &bus->gpio;
2197c1bc0daSRafał Miłecki 	int err;
220ec43b08bSHauke Mehrtens 
221ec43b08bSHauke Mehrtens 	chip->label		= "ssb_chipco_gpio";
222ec43b08bSHauke Mehrtens 	chip->owner		= THIS_MODULE;
223ec43b08bSHauke Mehrtens 	chip->request		= ssb_gpio_chipco_request;
224ec43b08bSHauke Mehrtens 	chip->free		= ssb_gpio_chipco_free;
225ec43b08bSHauke Mehrtens 	chip->get		= ssb_gpio_chipco_get_value;
226ec43b08bSHauke Mehrtens 	chip->set		= ssb_gpio_chipco_set_value;
227ec43b08bSHauke Mehrtens 	chip->direction_input	= ssb_gpio_chipco_direction_input;
228ec43b08bSHauke Mehrtens 	chip->direction_output	= ssb_gpio_chipco_direction_output;
2297c1bc0daSRafał Miłecki #if IS_ENABLED(CONFIG_SSB_EMBEDDED)
2307c1bc0daSRafał Miłecki 	chip->to_irq		= ssb_gpio_to_irq;
2317c1bc0daSRafał Miłecki #endif
232ec43b08bSHauke Mehrtens 	chip->ngpio		= 16;
233ec43b08bSHauke Mehrtens 	/* There is just one SoC in one device and its GPIO addresses should be
234ec43b08bSHauke Mehrtens 	 * deterministic to address them more easily. The other buses could get
2355615eb58SShubhankar Kuranagatti 	 * a random base number.
2365615eb58SShubhankar Kuranagatti 	 */
237ec43b08bSHauke Mehrtens 	if (bus->bustype == SSB_BUSTYPE_SSB)
238ec43b08bSHauke Mehrtens 		chip->base		= 0;
239ec43b08bSHauke Mehrtens 	else
240ec43b08bSHauke Mehrtens 		chip->base		= -1;
241ec43b08bSHauke Mehrtens 
2427c1bc0daSRafał Miłecki 	err = ssb_gpio_irq_chipco_domain_init(bus);
2437c1bc0daSRafał Miłecki 	if (err)
2447c1bc0daSRafał Miłecki 		return err;
2457c1bc0daSRafał Miłecki 
2462d4443beSLinus Walleij 	err = gpiochip_add_data(chip, bus);
2477c1bc0daSRafał Miłecki 	if (err) {
2487c1bc0daSRafał Miłecki 		ssb_gpio_irq_chipco_domain_exit(bus);
2497c1bc0daSRafał Miłecki 		return err;
250ec43b08bSHauke Mehrtens 	}
251ec43b08bSHauke Mehrtens 
2527c1bc0daSRafał Miłecki 	return 0;
2537c1bc0daSRafał Miłecki }
2547c1bc0daSRafał Miłecki 
2557c1bc0daSRafał Miłecki /**************************************************
2567c1bc0daSRafał Miłecki  * EXTIF
2577c1bc0daSRafał Miłecki  **************************************************/
2587c1bc0daSRafał Miłecki 
259ec43b08bSHauke Mehrtens #ifdef CONFIG_SSB_DRIVER_EXTIF
260ec43b08bSHauke Mehrtens 
ssb_gpio_extif_get_value(struct gpio_chip * chip,unsigned int gpio)261c683ffe2SHugh Sipière static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned int gpio)
262ec43b08bSHauke Mehrtens {
2632d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
264ec43b08bSHauke Mehrtens 
265ec43b08bSHauke Mehrtens 	return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio);
266ec43b08bSHauke Mehrtens }
267ec43b08bSHauke Mehrtens 
ssb_gpio_extif_set_value(struct gpio_chip * chip,unsigned int gpio,int value)268c683ffe2SHugh Sipière static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned int gpio,
269ec43b08bSHauke Mehrtens 				     int value)
270ec43b08bSHauke Mehrtens {
2712d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
272ec43b08bSHauke Mehrtens 
273ec43b08bSHauke Mehrtens 	ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
274ec43b08bSHauke Mehrtens }
275ec43b08bSHauke Mehrtens 
ssb_gpio_extif_direction_input(struct gpio_chip * chip,unsigned int gpio)276ec43b08bSHauke Mehrtens static int ssb_gpio_extif_direction_input(struct gpio_chip *chip,
277c683ffe2SHugh Sipière 					  unsigned int gpio)
278ec43b08bSHauke Mehrtens {
2792d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
280ec43b08bSHauke Mehrtens 
281ec43b08bSHauke Mehrtens 	ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 0);
282ec43b08bSHauke Mehrtens 	return 0;
283ec43b08bSHauke Mehrtens }
284ec43b08bSHauke Mehrtens 
ssb_gpio_extif_direction_output(struct gpio_chip * chip,unsigned int gpio,int value)285ec43b08bSHauke Mehrtens static int ssb_gpio_extif_direction_output(struct gpio_chip *chip,
286c683ffe2SHugh Sipière 					   unsigned int gpio, int value)
287ec43b08bSHauke Mehrtens {
2882d4443beSLinus Walleij 	struct ssb_bus *bus = gpiochip_get_data(chip);
289ec43b08bSHauke Mehrtens 
290ec43b08bSHauke Mehrtens 	ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 1 << gpio);
291ec43b08bSHauke Mehrtens 	ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
292ec43b08bSHauke Mehrtens 	return 0;
293ec43b08bSHauke Mehrtens }
294ec43b08bSHauke Mehrtens 
2957c1bc0daSRafał Miłecki #if IS_ENABLED(CONFIG_SSB_EMBEDDED)
ssb_gpio_irq_extif_mask(struct irq_data * d)2967c1bc0daSRafał Miłecki static void ssb_gpio_irq_extif_mask(struct irq_data *d)
297a6ca2e10SHauke Mehrtens {
2987c1bc0daSRafał Miłecki 	struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
2997c1bc0daSRafał Miłecki 	int gpio = irqd_to_hwirq(d);
300a6ca2e10SHauke Mehrtens 
3017c1bc0daSRafał Miłecki 	ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0);
302a6ca2e10SHauke Mehrtens }
303a6ca2e10SHauke Mehrtens 
ssb_gpio_irq_extif_unmask(struct irq_data * d)3047c1bc0daSRafał Miłecki static void ssb_gpio_irq_extif_unmask(struct irq_data *d)
3057c1bc0daSRafał Miłecki {
3067c1bc0daSRafał Miłecki 	struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
3077c1bc0daSRafał Miłecki 	int gpio = irqd_to_hwirq(d);
3087c1bc0daSRafał Miłecki 	u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio));
3097c1bc0daSRafał Miłecki 
3107c1bc0daSRafał Miłecki 	ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val);
3117c1bc0daSRafał Miłecki 	ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio));
3127c1bc0daSRafał Miłecki }
3137c1bc0daSRafał Miłecki 
3147c1bc0daSRafał Miłecki static struct irq_chip ssb_gpio_irq_extif_chip = {
3157c1bc0daSRafał Miłecki 	.name		= "SSB-GPIO-EXTIF",
3167c1bc0daSRafał Miłecki 	.irq_mask	= ssb_gpio_irq_extif_mask,
3177c1bc0daSRafał Miłecki 	.irq_unmask	= ssb_gpio_irq_extif_unmask,
3187c1bc0daSRafał Miłecki };
3197c1bc0daSRafał Miłecki 
ssb_gpio_irq_extif_handler(int irq,void * dev_id)3207c1bc0daSRafał Miłecki static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id)
3217c1bc0daSRafał Miłecki {
3227c1bc0daSRafał Miłecki 	struct ssb_bus *bus = dev_id;
3237c1bc0daSRafał Miłecki 	struct ssb_extif *extif = &bus->extif;
3247c1bc0daSRafał Miłecki 	u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN);
3257c1bc0daSRafał Miłecki 	u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK);
3267c1bc0daSRafał Miłecki 	u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL);
3277c1bc0daSRafał Miłecki 	unsigned long irqs = (val ^ pol) & mask;
3287c1bc0daSRafał Miłecki 	int gpio;
3297c1bc0daSRafał Miłecki 
3307c1bc0daSRafał Miłecki 	if (!irqs)
3317c1bc0daSRafał Miłecki 		return IRQ_NONE;
3327c1bc0daSRafał Miłecki 
3337c1bc0daSRafał Miłecki 	for_each_set_bit(gpio, &irqs, bus->gpio.ngpio)
334*f285de79SSebastian Andrzej Siewior 		generic_handle_domain_irq_safe(bus->irq_domain, gpio);
335*f285de79SSebastian Andrzej Siewior 
3367c1bc0daSRafał Miłecki 	ssb_extif_gpio_polarity(extif, irqs, val & irqs);
3377c1bc0daSRafał Miłecki 
3387c1bc0daSRafał Miłecki 	return IRQ_HANDLED;
3397c1bc0daSRafał Miłecki }
3407c1bc0daSRafał Miłecki 
ssb_gpio_irq_extif_domain_init(struct ssb_bus * bus)3417c1bc0daSRafał Miłecki static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus)
3427c1bc0daSRafał Miłecki {
3437c1bc0daSRafał Miłecki 	struct ssb_extif *extif = &bus->extif;
3447c1bc0daSRafał Miłecki 	struct gpio_chip *chip = &bus->gpio;
3457c1bc0daSRafał Miłecki 	int gpio, hwirq, err;
3467c1bc0daSRafał Miłecki 
3477c1bc0daSRafał Miłecki 	if (bus->bustype != SSB_BUSTYPE_SSB)
3487c1bc0daSRafał Miłecki 		return 0;
3497c1bc0daSRafał Miłecki 
3507c1bc0daSRafał Miłecki 	bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio,
3517c1bc0daSRafał Miłecki 						&irq_domain_simple_ops, extif);
3527c1bc0daSRafał Miłecki 	if (!bus->irq_domain) {
3537c1bc0daSRafał Miłecki 		err = -ENODEV;
3547c1bc0daSRafał Miłecki 		goto err_irq_domain;
3557c1bc0daSRafał Miłecki 	}
3567c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
3577c1bc0daSRafał Miłecki 		int irq = irq_create_mapping(bus->irq_domain, gpio);
3587c1bc0daSRafał Miłecki 
3597c1bc0daSRafał Miłecki 		irq_set_chip_data(irq, bus);
3607c1bc0daSRafał Miłecki 		irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip,
3617c1bc0daSRafał Miłecki 					 handle_simple_irq);
3627c1bc0daSRafał Miłecki 	}
3637c1bc0daSRafał Miłecki 
3647c1bc0daSRafał Miłecki 	hwirq = ssb_mips_irq(bus->extif.dev) + 2;
3657c1bc0daSRafał Miłecki 	err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED,
3667c1bc0daSRafał Miłecki 			  "gpio", bus);
3677c1bc0daSRafał Miłecki 	if (err)
3687c1bc0daSRafał Miłecki 		goto err_req_irq;
3697c1bc0daSRafał Miłecki 
3707c1bc0daSRafał Miłecki 	ssb_extif_gpio_intmask(&bus->extif, ~0, 0);
3717c1bc0daSRafał Miłecki 
3727c1bc0daSRafał Miłecki 	return 0;
3737c1bc0daSRafał Miłecki 
3747c1bc0daSRafał Miłecki err_req_irq:
3757c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
3767c1bc0daSRafał Miłecki 		int irq = irq_find_mapping(bus->irq_domain, gpio);
3777c1bc0daSRafał Miłecki 
3787c1bc0daSRafał Miłecki 		irq_dispose_mapping(irq);
3797c1bc0daSRafał Miłecki 	}
3807c1bc0daSRafał Miłecki 	irq_domain_remove(bus->irq_domain);
3817c1bc0daSRafał Miłecki err_irq_domain:
3827c1bc0daSRafał Miłecki 	return err;
3837c1bc0daSRafał Miłecki }
3847c1bc0daSRafał Miłecki 
ssb_gpio_irq_extif_domain_exit(struct ssb_bus * bus)3857c1bc0daSRafał Miłecki static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus)
3867c1bc0daSRafał Miłecki {
3877c1bc0daSRafał Miłecki 	struct ssb_extif *extif = &bus->extif;
3887c1bc0daSRafał Miłecki 	struct gpio_chip *chip = &bus->gpio;
3897c1bc0daSRafał Miłecki 	int gpio;
3907c1bc0daSRafał Miłecki 
3917c1bc0daSRafał Miłecki 	if (bus->bustype != SSB_BUSTYPE_SSB)
3927c1bc0daSRafał Miłecki 		return;
3937c1bc0daSRafał Miłecki 
3947c1bc0daSRafał Miłecki 	free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif);
3957c1bc0daSRafał Miłecki 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
3967c1bc0daSRafał Miłecki 		int irq = irq_find_mapping(bus->irq_domain, gpio);
3977c1bc0daSRafał Miłecki 
3987c1bc0daSRafał Miłecki 		irq_dispose_mapping(irq);
3997c1bc0daSRafał Miłecki 	}
4007c1bc0daSRafał Miłecki 	irq_domain_remove(bus->irq_domain);
4017c1bc0daSRafał Miłecki }
4027c1bc0daSRafał Miłecki #else
ssb_gpio_irq_extif_domain_init(struct ssb_bus * bus)4037c1bc0daSRafał Miłecki static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus)
4047c1bc0daSRafał Miłecki {
4057c1bc0daSRafał Miłecki 	return 0;
4067c1bc0daSRafał Miłecki }
4077c1bc0daSRafał Miłecki 
ssb_gpio_irq_extif_domain_exit(struct ssb_bus * bus)4087c1bc0daSRafał Miłecki static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus)
4097c1bc0daSRafał Miłecki {
4107c1bc0daSRafał Miłecki }
4117c1bc0daSRafał Miłecki #endif
4127c1bc0daSRafał Miłecki 
ssb_gpio_extif_init(struct ssb_bus * bus)413ec43b08bSHauke Mehrtens static int ssb_gpio_extif_init(struct ssb_bus *bus)
414ec43b08bSHauke Mehrtens {
415ec43b08bSHauke Mehrtens 	struct gpio_chip *chip = &bus->gpio;
4167c1bc0daSRafał Miłecki 	int err;
417ec43b08bSHauke Mehrtens 
418ec43b08bSHauke Mehrtens 	chip->label		= "ssb_extif_gpio";
419ec43b08bSHauke Mehrtens 	chip->owner		= THIS_MODULE;
420ec43b08bSHauke Mehrtens 	chip->get		= ssb_gpio_extif_get_value;
421ec43b08bSHauke Mehrtens 	chip->set		= ssb_gpio_extif_set_value;
422ec43b08bSHauke Mehrtens 	chip->direction_input	= ssb_gpio_extif_direction_input;
423ec43b08bSHauke Mehrtens 	chip->direction_output	= ssb_gpio_extif_direction_output;
4247c1bc0daSRafał Miłecki #if IS_ENABLED(CONFIG_SSB_EMBEDDED)
4257c1bc0daSRafał Miłecki 	chip->to_irq		= ssb_gpio_to_irq;
4267c1bc0daSRafał Miłecki #endif
427ec43b08bSHauke Mehrtens 	chip->ngpio		= 5;
428ec43b08bSHauke Mehrtens 	/* There is just one SoC in one device and its GPIO addresses should be
429ec43b08bSHauke Mehrtens 	 * deterministic to address them more easily. The other buses could get
4305615eb58SShubhankar Kuranagatti 	 * a random base number.
4315615eb58SShubhankar Kuranagatti 	 */
432ec43b08bSHauke Mehrtens 	if (bus->bustype == SSB_BUSTYPE_SSB)
433ec43b08bSHauke Mehrtens 		chip->base		= 0;
434ec43b08bSHauke Mehrtens 	else
435ec43b08bSHauke Mehrtens 		chip->base		= -1;
436ec43b08bSHauke Mehrtens 
4377c1bc0daSRafał Miłecki 	err = ssb_gpio_irq_extif_domain_init(bus);
4387c1bc0daSRafał Miłecki 	if (err)
4397c1bc0daSRafał Miłecki 		return err;
4407c1bc0daSRafał Miłecki 
4412d4443beSLinus Walleij 	err = gpiochip_add_data(chip, bus);
4427c1bc0daSRafał Miłecki 	if (err) {
4437c1bc0daSRafał Miłecki 		ssb_gpio_irq_extif_domain_exit(bus);
4447c1bc0daSRafał Miłecki 		return err;
4457c1bc0daSRafał Miłecki 	}
4467c1bc0daSRafał Miłecki 
4477c1bc0daSRafał Miłecki 	return 0;
448ec43b08bSHauke Mehrtens }
449ec43b08bSHauke Mehrtens 
450ec43b08bSHauke Mehrtens #else
ssb_gpio_extif_init(struct ssb_bus * bus)451ec43b08bSHauke Mehrtens static int ssb_gpio_extif_init(struct ssb_bus *bus)
452ec43b08bSHauke Mehrtens {
453ec43b08bSHauke Mehrtens 	return -ENOTSUPP;
454ec43b08bSHauke Mehrtens }
455ec43b08bSHauke Mehrtens #endif
456ec43b08bSHauke Mehrtens 
4577c1bc0daSRafał Miłecki /**************************************************
4587c1bc0daSRafał Miłecki  * Init
4597c1bc0daSRafał Miłecki  **************************************************/
4607c1bc0daSRafał Miłecki 
ssb_gpio_init(struct ssb_bus * bus)461ec43b08bSHauke Mehrtens int ssb_gpio_init(struct ssb_bus *bus)
462ec43b08bSHauke Mehrtens {
463ec43b08bSHauke Mehrtens 	if (ssb_chipco_available(&bus->chipco))
464ec43b08bSHauke Mehrtens 		return ssb_gpio_chipco_init(bus);
465ec43b08bSHauke Mehrtens 	else if (ssb_extif_available(&bus->extif))
466ec43b08bSHauke Mehrtens 		return ssb_gpio_extif_init(bus);
467ec43b08bSHauke Mehrtens 	return -1;
468ec43b08bSHauke Mehrtens }
469600485edSHauke Mehrtens 
ssb_gpio_unregister(struct ssb_bus * bus)470600485edSHauke Mehrtens int ssb_gpio_unregister(struct ssb_bus *bus)
471600485edSHauke Mehrtens {
472600485edSHauke Mehrtens 	if (ssb_chipco_available(&bus->chipco) ||
473600485edSHauke Mehrtens 	    ssb_extif_available(&bus->extif)) {
47488d5e520Sabdoulaye berthe 		gpiochip_remove(&bus->gpio);
47588d5e520Sabdoulaye berthe 		return 0;
476600485edSHauke Mehrtens 	}
477600485edSHauke Mehrtens 	return -1;
478600485edSHauke Mehrtens }
479