xref: /openbmc/linux/arch/arm/plat-orion/gpio.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
19569dae7SLennert Buytenhek /*
29569dae7SLennert Buytenhek  * arch/arm/plat-orion/gpio.c
39569dae7SLennert Buytenhek  *
49569dae7SLennert Buytenhek  * Marvell Orion SoC GPIO handling.
59569dae7SLennert Buytenhek  *
69569dae7SLennert Buytenhek  * This file is licensed under the terms of the GNU General Public
79569dae7SLennert Buytenhek  * License version 2.  This program is licensed "as is" without any
89569dae7SLennert Buytenhek  * warranty of any kind, whether express or implied.
99569dae7SLennert Buytenhek  */
109569dae7SLennert Buytenhek 
11278b45b0SAndrew Lunn #define DEBUG
12278b45b0SAndrew Lunn 
139569dae7SLennert Buytenhek #include <linux/kernel.h>
149569dae7SLennert Buytenhek #include <linux/init.h>
1507332318SLennert Buytenhek #include <linux/irq.h>
16278b45b0SAndrew Lunn #include <linux/irqdomain.h>
179569dae7SLennert Buytenhek #include <linux/module.h>
189569dae7SLennert Buytenhek #include <linux/spinlock.h>
199569dae7SLennert Buytenhek #include <linux/bitops.h>
209569dae7SLennert Buytenhek #include <linux/io.h>
21*d1143d50SLinus Walleij #include <linux/gpio/driver.h>
22*d1143d50SLinus Walleij #include <linux/gpio/consumer.h>
23ff3e660bSArnaud Patard (Rtp) #include <linux/leds.h>
24278b45b0SAndrew Lunn #include <linux/of.h>
25278b45b0SAndrew Lunn #include <linux/of_irq.h>
26278b45b0SAndrew Lunn #include <linux/of_address.h>
27ce91574cSRob Herring #include <plat/orion-gpio.h>
289569dae7SLennert Buytenhek 
299eac6d0aSLennert Buytenhek /*
309eac6d0aSLennert Buytenhek  * GPIO unit register offsets.
319eac6d0aSLennert Buytenhek  */
329eac6d0aSLennert Buytenhek #define GPIO_OUT_OFF		0x0000
339eac6d0aSLennert Buytenhek #define GPIO_IO_CONF_OFF	0x0004
349eac6d0aSLennert Buytenhek #define GPIO_BLINK_EN_OFF	0x0008
359eac6d0aSLennert Buytenhek #define GPIO_IN_POL_OFF		0x000c
369eac6d0aSLennert Buytenhek #define GPIO_DATA_IN_OFF	0x0010
379eac6d0aSLennert Buytenhek #define GPIO_EDGE_CAUSE_OFF	0x0014
389eac6d0aSLennert Buytenhek #define GPIO_EDGE_MASK_OFF	0x0018
399eac6d0aSLennert Buytenhek #define GPIO_LEVEL_MASK_OFF	0x001c
409569dae7SLennert Buytenhek 
419eac6d0aSLennert Buytenhek struct orion_gpio_chip {
429eac6d0aSLennert Buytenhek 	struct gpio_chip	chip;
439eac6d0aSLennert Buytenhek 	spinlock_t		lock;
449eac6d0aSLennert Buytenhek 	void __iomem		*base;
459eac6d0aSLennert Buytenhek 	unsigned long		valid_input;
469eac6d0aSLennert Buytenhek 	unsigned long		valid_output;
479eac6d0aSLennert Buytenhek 	int			mask_offset;
489eac6d0aSLennert Buytenhek 	int			secondary_irq_base;
49278b45b0SAndrew Lunn 	struct irq_domain       *domain;
509eac6d0aSLennert Buytenhek };
519eac6d0aSLennert Buytenhek 
GPIO_OUT(struct orion_gpio_chip * ochip)529eac6d0aSLennert Buytenhek static void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip)
539eac6d0aSLennert Buytenhek {
549eac6d0aSLennert Buytenhek 	return ochip->base + GPIO_OUT_OFF;
559eac6d0aSLennert Buytenhek }
569eac6d0aSLennert Buytenhek 
GPIO_IO_CONF(struct orion_gpio_chip * ochip)579eac6d0aSLennert Buytenhek static void __iomem *GPIO_IO_CONF(struct orion_gpio_chip *ochip)
589eac6d0aSLennert Buytenhek {
599eac6d0aSLennert Buytenhek 	return ochip->base + GPIO_IO_CONF_OFF;
609eac6d0aSLennert Buytenhek }
619eac6d0aSLennert Buytenhek 
GPIO_BLINK_EN(struct orion_gpio_chip * ochip)629eac6d0aSLennert Buytenhek static void __iomem *GPIO_BLINK_EN(struct orion_gpio_chip *ochip)
639eac6d0aSLennert Buytenhek {
649eac6d0aSLennert Buytenhek 	return ochip->base + GPIO_BLINK_EN_OFF;
659eac6d0aSLennert Buytenhek }
669eac6d0aSLennert Buytenhek 
GPIO_IN_POL(struct orion_gpio_chip * ochip)679eac6d0aSLennert Buytenhek static void __iomem *GPIO_IN_POL(struct orion_gpio_chip *ochip)
689eac6d0aSLennert Buytenhek {
699eac6d0aSLennert Buytenhek 	return ochip->base + GPIO_IN_POL_OFF;
709eac6d0aSLennert Buytenhek }
719eac6d0aSLennert Buytenhek 
GPIO_DATA_IN(struct orion_gpio_chip * ochip)729eac6d0aSLennert Buytenhek static void __iomem *GPIO_DATA_IN(struct orion_gpio_chip *ochip)
739eac6d0aSLennert Buytenhek {
749eac6d0aSLennert Buytenhek 	return ochip->base + GPIO_DATA_IN_OFF;
759eac6d0aSLennert Buytenhek }
769eac6d0aSLennert Buytenhek 
GPIO_EDGE_CAUSE(struct orion_gpio_chip * ochip)779eac6d0aSLennert Buytenhek static void __iomem *GPIO_EDGE_CAUSE(struct orion_gpio_chip *ochip)
789eac6d0aSLennert Buytenhek {
799eac6d0aSLennert Buytenhek 	return ochip->base + GPIO_EDGE_CAUSE_OFF;
809eac6d0aSLennert Buytenhek }
819eac6d0aSLennert Buytenhek 
GPIO_EDGE_MASK(struct orion_gpio_chip * ochip)829eac6d0aSLennert Buytenhek static void __iomem *GPIO_EDGE_MASK(struct orion_gpio_chip *ochip)
839eac6d0aSLennert Buytenhek {
849eac6d0aSLennert Buytenhek 	return ochip->base + ochip->mask_offset + GPIO_EDGE_MASK_OFF;
859eac6d0aSLennert Buytenhek }
869eac6d0aSLennert Buytenhek 
GPIO_LEVEL_MASK(struct orion_gpio_chip * ochip)879eac6d0aSLennert Buytenhek static void __iomem *GPIO_LEVEL_MASK(struct orion_gpio_chip *ochip)
889eac6d0aSLennert Buytenhek {
899eac6d0aSLennert Buytenhek 	return ochip->base + ochip->mask_offset + GPIO_LEVEL_MASK_OFF;
909eac6d0aSLennert Buytenhek }
919eac6d0aSLennert Buytenhek 
929eac6d0aSLennert Buytenhek 
939eac6d0aSLennert Buytenhek static struct orion_gpio_chip orion_gpio_chips[2];
949eac6d0aSLennert Buytenhek static int orion_gpio_chip_count;
959eac6d0aSLennert Buytenhek 
969eac6d0aSLennert Buytenhek static inline void
__set_direction(struct orion_gpio_chip * ochip,unsigned pin,int input)979eac6d0aSLennert Buytenhek __set_direction(struct orion_gpio_chip *ochip, unsigned pin, int input)
989569dae7SLennert Buytenhek {
999569dae7SLennert Buytenhek 	u32 u;
1009569dae7SLennert Buytenhek 
1019eac6d0aSLennert Buytenhek 	u = readl(GPIO_IO_CONF(ochip));
1029569dae7SLennert Buytenhek 	if (input)
1039eac6d0aSLennert Buytenhek 		u |= 1 << pin;
1049569dae7SLennert Buytenhek 	else
1059eac6d0aSLennert Buytenhek 		u &= ~(1 << pin);
1069eac6d0aSLennert Buytenhek 	writel(u, GPIO_IO_CONF(ochip));
1079569dae7SLennert Buytenhek }
1089569dae7SLennert Buytenhek 
__set_level(struct orion_gpio_chip * ochip,unsigned pin,int high)1099eac6d0aSLennert Buytenhek static void __set_level(struct orion_gpio_chip *ochip, unsigned pin, int high)
1109569dae7SLennert Buytenhek {
1119569dae7SLennert Buytenhek 	u32 u;
1129569dae7SLennert Buytenhek 
1139eac6d0aSLennert Buytenhek 	u = readl(GPIO_OUT(ochip));
1149569dae7SLennert Buytenhek 	if (high)
1159eac6d0aSLennert Buytenhek 		u |= 1 << pin;
1169569dae7SLennert Buytenhek 	else
1179eac6d0aSLennert Buytenhek 		u &= ~(1 << pin);
1189eac6d0aSLennert Buytenhek 	writel(u, GPIO_OUT(ochip));
1199569dae7SLennert Buytenhek }
1209569dae7SLennert Buytenhek 
1219eac6d0aSLennert Buytenhek static inline void
__set_blinking(struct orion_gpio_chip * ochip,unsigned pin,int blink)1229eac6d0aSLennert Buytenhek __set_blinking(struct orion_gpio_chip *ochip, unsigned pin, int blink)
123a8865655SErik Benada {
124a8865655SErik Benada 	u32 u;
125a8865655SErik Benada 
1269eac6d0aSLennert Buytenhek 	u = readl(GPIO_BLINK_EN(ochip));
127a8865655SErik Benada 	if (blink)
1289eac6d0aSLennert Buytenhek 		u |= 1 << pin;
129a8865655SErik Benada 	else
1309eac6d0aSLennert Buytenhek 		u &= ~(1 << pin);
1319eac6d0aSLennert Buytenhek 	writel(u, GPIO_BLINK_EN(ochip));
132a8865655SErik Benada }
133a8865655SErik Benada 
1349eac6d0aSLennert Buytenhek static inline int
orion_gpio_is_valid(struct orion_gpio_chip * ochip,unsigned pin,int mode)1359eac6d0aSLennert Buytenhek orion_gpio_is_valid(struct orion_gpio_chip *ochip, unsigned pin, int mode)
136a8865655SErik Benada {
1379eac6d0aSLennert Buytenhek 	if (pin >= ochip->chip.ngpio)
138a8865655SErik Benada 		goto err_out;
1399eac6d0aSLennert Buytenhek 
1409eac6d0aSLennert Buytenhek 	if ((mode & GPIO_INPUT_OK) && !test_bit(pin, &ochip->valid_input))
141a8865655SErik Benada 		goto err_out;
1429eac6d0aSLennert Buytenhek 
1439eac6d0aSLennert Buytenhek 	if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, &ochip->valid_output))
1449eac6d0aSLennert Buytenhek 		goto err_out;
1459eac6d0aSLennert Buytenhek 
1469eac6d0aSLennert Buytenhek 	return 1;
147a8865655SErik Benada 
148a8865655SErik Benada err_out:
149a8865655SErik Benada 	pr_debug("%s: invalid GPIO %d\n", __func__, pin);
150a8865655SErik Benada 	return false;
151a8865655SErik Benada }
1529569dae7SLennert Buytenhek 
1539569dae7SLennert Buytenhek /*
1547fd2bf3dSAlexandre Courbot  * GPIO primitives.
1559569dae7SLennert Buytenhek  */
orion_gpio_request(struct gpio_chip * chip,unsigned pin)156a8865655SErik Benada static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
1579569dae7SLennert Buytenhek {
15866d718ddSLinus Walleij 	struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
1599eac6d0aSLennert Buytenhek 
1609eac6d0aSLennert Buytenhek 	if (orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK) ||
1619eac6d0aSLennert Buytenhek 	    orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
162a8865655SErik Benada 		return 0;
1639eac6d0aSLennert Buytenhek 
1649569dae7SLennert Buytenhek 	return -EINVAL;
1659569dae7SLennert Buytenhek }
1669569dae7SLennert Buytenhek 
orion_gpio_direction_input(struct gpio_chip * chip,unsigned pin)1679eac6d0aSLennert Buytenhek static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
1689569dae7SLennert Buytenhek {
16966d718ddSLinus Walleij 	struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
1709eac6d0aSLennert Buytenhek 	unsigned long flags;
1719eac6d0aSLennert Buytenhek 
1729eac6d0aSLennert Buytenhek 	if (!orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK))
1739eac6d0aSLennert Buytenhek 		return -EINVAL;
1749eac6d0aSLennert Buytenhek 
1759eac6d0aSLennert Buytenhek 	spin_lock_irqsave(&ochip->lock, flags);
1769eac6d0aSLennert Buytenhek 	__set_direction(ochip, pin, 1);
1779eac6d0aSLennert Buytenhek 	spin_unlock_irqrestore(&ochip->lock, flags);
1789eac6d0aSLennert Buytenhek 
1799eac6d0aSLennert Buytenhek 	return 0;
1809569dae7SLennert Buytenhek }
1819569dae7SLennert Buytenhek 
orion_gpio_get(struct gpio_chip * chip,unsigned pin)1829eac6d0aSLennert Buytenhek static int orion_gpio_get(struct gpio_chip *chip, unsigned pin)
1839eac6d0aSLennert Buytenhek {
18466d718ddSLinus Walleij 	struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
1859eac6d0aSLennert Buytenhek 	int val;
1869eac6d0aSLennert Buytenhek 
1879eac6d0aSLennert Buytenhek 	if (readl(GPIO_IO_CONF(ochip)) & (1 << pin)) {
1889eac6d0aSLennert Buytenhek 		val = readl(GPIO_DATA_IN(ochip)) ^ readl(GPIO_IN_POL(ochip));
1899eac6d0aSLennert Buytenhek 	} else {
1909eac6d0aSLennert Buytenhek 		val = readl(GPIO_OUT(ochip));
1919eac6d0aSLennert Buytenhek 	}
1929eac6d0aSLennert Buytenhek 
1939eac6d0aSLennert Buytenhek 	return (val >> pin) & 1;
1949eac6d0aSLennert Buytenhek }
1959eac6d0aSLennert Buytenhek 
1969eac6d0aSLennert Buytenhek static int
orion_gpio_direction_output(struct gpio_chip * chip,unsigned pin,int value)1979eac6d0aSLennert Buytenhek orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value)
1989eac6d0aSLennert Buytenhek {
19966d718ddSLinus Walleij 	struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
2009eac6d0aSLennert Buytenhek 	unsigned long flags;
2019eac6d0aSLennert Buytenhek 
2029eac6d0aSLennert Buytenhek 	if (!orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
2039eac6d0aSLennert Buytenhek 		return -EINVAL;
2049eac6d0aSLennert Buytenhek 
2059eac6d0aSLennert Buytenhek 	spin_lock_irqsave(&ochip->lock, flags);
2069eac6d0aSLennert Buytenhek 	__set_blinking(ochip, pin, 0);
2079eac6d0aSLennert Buytenhek 	__set_level(ochip, pin, value);
2089eac6d0aSLennert Buytenhek 	__set_direction(ochip, pin, 0);
2099eac6d0aSLennert Buytenhek 	spin_unlock_irqrestore(&ochip->lock, flags);
2109eac6d0aSLennert Buytenhek 
2119eac6d0aSLennert Buytenhek 	return 0;
2129eac6d0aSLennert Buytenhek }
2139eac6d0aSLennert Buytenhek 
orion_gpio_set(struct gpio_chip * chip,unsigned pin,int value)2149eac6d0aSLennert Buytenhek static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
2159eac6d0aSLennert Buytenhek {
21666d718ddSLinus Walleij 	struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
2179eac6d0aSLennert Buytenhek 	unsigned long flags;
2189eac6d0aSLennert Buytenhek 
2199eac6d0aSLennert Buytenhek 	spin_lock_irqsave(&ochip->lock, flags);
2209eac6d0aSLennert Buytenhek 	__set_level(ochip, pin, value);
2219eac6d0aSLennert Buytenhek 	spin_unlock_irqrestore(&ochip->lock, flags);
2229eac6d0aSLennert Buytenhek }
2239eac6d0aSLennert Buytenhek 
orion_gpio_to_irq(struct gpio_chip * chip,unsigned pin)2249eac6d0aSLennert Buytenhek static int orion_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
2259eac6d0aSLennert Buytenhek {
22666d718ddSLinus Walleij 	struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
2279eac6d0aSLennert Buytenhek 
228278b45b0SAndrew Lunn 	return irq_create_mapping(ochip->domain,
229278b45b0SAndrew Lunn 				  ochip->secondary_irq_base + pin);
2309eac6d0aSLennert Buytenhek }
2319eac6d0aSLennert Buytenhek 
2329569dae7SLennert Buytenhek /*
2339569dae7SLennert Buytenhek  * Orion-specific GPIO API extensions.
2349569dae7SLennert Buytenhek  */
orion_gpio_chip_find(int pin)2359eac6d0aSLennert Buytenhek static struct orion_gpio_chip *orion_gpio_chip_find(int pin)
2369eac6d0aSLennert Buytenhek {
2379eac6d0aSLennert Buytenhek 	int i;
2389eac6d0aSLennert Buytenhek 
2399eac6d0aSLennert Buytenhek 	for (i = 0; i < orion_gpio_chip_count; i++) {
2409eac6d0aSLennert Buytenhek 		struct orion_gpio_chip *ochip = orion_gpio_chips + i;
2419eac6d0aSLennert Buytenhek 		struct gpio_chip *chip = &ochip->chip;
2429eac6d0aSLennert Buytenhek 
2439eac6d0aSLennert Buytenhek 		if (pin >= chip->base && pin < chip->base + chip->ngpio)
2449eac6d0aSLennert Buytenhek 			return ochip;
2459eac6d0aSLennert Buytenhek 	}
2469eac6d0aSLennert Buytenhek 
2479eac6d0aSLennert Buytenhek 	return NULL;
2489eac6d0aSLennert Buytenhek }
2499eac6d0aSLennert Buytenhek 
orion_gpio_set_unused(unsigned pin)2509569dae7SLennert Buytenhek void __init orion_gpio_set_unused(unsigned pin)
2519569dae7SLennert Buytenhek {
2529eac6d0aSLennert Buytenhek 	struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin);
2539eac6d0aSLennert Buytenhek 
2549eac6d0aSLennert Buytenhek 	if (ochip == NULL)
2559eac6d0aSLennert Buytenhek 		return;
2569eac6d0aSLennert Buytenhek 
2579eac6d0aSLennert Buytenhek 	pin -= ochip->chip.base;
2589eac6d0aSLennert Buytenhek 
259a8865655SErik Benada 	/* Configure as output, drive low. */
2609eac6d0aSLennert Buytenhek 	__set_level(ochip, pin, 0);
2619eac6d0aSLennert Buytenhek 	__set_direction(ochip, pin, 0);
2629569dae7SLennert Buytenhek }
2639569dae7SLennert Buytenhek 
orion_gpio_set_valid(unsigned pin,int mode)26428d27cf4SNicolas Pitre void __init orion_gpio_set_valid(unsigned pin, int mode)
2659569dae7SLennert Buytenhek {
2669eac6d0aSLennert Buytenhek 	struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin);
2679eac6d0aSLennert Buytenhek 
2689eac6d0aSLennert Buytenhek 	if (ochip == NULL)
2699eac6d0aSLennert Buytenhek 		return;
2709eac6d0aSLennert Buytenhek 
2719eac6d0aSLennert Buytenhek 	pin -= ochip->chip.base;
2729eac6d0aSLennert Buytenhek 
27328d27cf4SNicolas Pitre 	if (mode == 1)
27428d27cf4SNicolas Pitre 		mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK;
2759eac6d0aSLennert Buytenhek 
27628d27cf4SNicolas Pitre 	if (mode & GPIO_INPUT_OK)
2779eac6d0aSLennert Buytenhek 		__set_bit(pin, &ochip->valid_input);
2789569dae7SLennert Buytenhek 	else
2799eac6d0aSLennert Buytenhek 		__clear_bit(pin, &ochip->valid_input);
2809eac6d0aSLennert Buytenhek 
28128d27cf4SNicolas Pitre 	if (mode & GPIO_OUTPUT_OK)
2829eac6d0aSLennert Buytenhek 		__set_bit(pin, &ochip->valid_output);
28328d27cf4SNicolas Pitre 	else
2849eac6d0aSLennert Buytenhek 		__clear_bit(pin, &ochip->valid_output);
2859569dae7SLennert Buytenhek }
2869569dae7SLennert Buytenhek 
orion_gpio_set_blink(unsigned pin,int blink)2879569dae7SLennert Buytenhek void orion_gpio_set_blink(unsigned pin, int blink)
2889569dae7SLennert Buytenhek {
2899eac6d0aSLennert Buytenhek 	struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin);
2909569dae7SLennert Buytenhek 	unsigned long flags;
2919569dae7SLennert Buytenhek 
2929eac6d0aSLennert Buytenhek 	if (ochip == NULL)
2939eac6d0aSLennert Buytenhek 		return;
2949569dae7SLennert Buytenhek 
2959eac6d0aSLennert Buytenhek 	spin_lock_irqsave(&ochip->lock, flags);
29692a486eaSArnaud Patard (Rtp) 	__set_level(ochip, pin & 31, 0);
29792a486eaSArnaud Patard (Rtp) 	__set_blinking(ochip, pin & 31, blink);
2989eac6d0aSLennert Buytenhek 	spin_unlock_irqrestore(&ochip->lock, flags);
2999569dae7SLennert Buytenhek }
3009569dae7SLennert Buytenhek EXPORT_SYMBOL(orion_gpio_set_blink);
30107332318SLennert Buytenhek 
302ff3e660bSArnaud Patard (Rtp) #define ORION_BLINK_HALF_PERIOD 100 /* ms */
303ff3e660bSArnaud Patard (Rtp) 
orion_gpio_led_blink_set(struct gpio_desc * desc,int state,unsigned long * delay_on,unsigned long * delay_off)304c673a2b4SMika Westerberg int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
305ff3e660bSArnaud Patard (Rtp) 	unsigned long *delay_on, unsigned long *delay_off)
306ff3e660bSArnaud Patard (Rtp) {
307c673a2b4SMika Westerberg 	unsigned gpio = desc_to_gpio(desc);
308ff3e660bSArnaud Patard (Rtp) 
309ff3e660bSArnaud Patard (Rtp) 	if (delay_on && delay_off && !*delay_on && !*delay_off)
310ff3e660bSArnaud Patard (Rtp) 		*delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
311ff3e660bSArnaud Patard (Rtp) 
312ff3e660bSArnaud Patard (Rtp) 	switch (state) {
313ff3e660bSArnaud Patard (Rtp) 	case GPIO_LED_NO_BLINK_LOW:
314ff3e660bSArnaud Patard (Rtp) 	case GPIO_LED_NO_BLINK_HIGH:
315ff3e660bSArnaud Patard (Rtp) 		orion_gpio_set_blink(gpio, 0);
316*d1143d50SLinus Walleij 		gpiod_set_raw_value(desc, state);
317ff3e660bSArnaud Patard (Rtp) 		break;
318ff3e660bSArnaud Patard (Rtp) 	case GPIO_LED_BLINK:
319ff3e660bSArnaud Patard (Rtp) 		orion_gpio_set_blink(gpio, 1);
320ff3e660bSArnaud Patard (Rtp) 	}
321ff3e660bSArnaud Patard (Rtp) 	return 0;
322ff3e660bSArnaud Patard (Rtp) }
323ff3e660bSArnaud Patard (Rtp) EXPORT_SYMBOL_GPL(orion_gpio_led_blink_set);
324ff3e660bSArnaud Patard (Rtp) 
32507332318SLennert Buytenhek 
32607332318SLennert Buytenhek /*****************************************************************************
32707332318SLennert Buytenhek  * Orion GPIO IRQ
32807332318SLennert Buytenhek  *
32907332318SLennert Buytenhek  * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same
33007332318SLennert Buytenhek  * value of the line or the opposite value.
33107332318SLennert Buytenhek  *
33207332318SLennert Buytenhek  * Level IRQ handlers: DATA_IN is used directly as cause register.
33307332318SLennert Buytenhek  *                     Interrupt are masked by LEVEL_MASK registers.
33407332318SLennert Buytenhek  * Edge IRQ handlers:  Change in DATA_IN are latched in EDGE_CAUSE.
33507332318SLennert Buytenhek  *                     Interrupt are masked by EDGE_MASK registers.
33607332318SLennert Buytenhek  * Both-edge handlers: Similar to regular Edge handlers, but also swaps
33707332318SLennert Buytenhek  *                     the polarity to catch the next line transaction.
33807332318SLennert Buytenhek  *                     This is a race condition that might not perfectly
33907332318SLennert Buytenhek  *                     work on some use cases.
34007332318SLennert Buytenhek  *
34107332318SLennert Buytenhek  * Every eight GPIO lines are grouped (OR'ed) before going up to main
34207332318SLennert Buytenhek  * cause register.
34307332318SLennert Buytenhek  *
34407332318SLennert Buytenhek  *                    EDGE  cause    mask
34507332318SLennert Buytenhek  *        data-in   /--------| |-----| |----\
34607332318SLennert Buytenhek  *     -----| |-----                         ---- to main cause reg
34707332318SLennert Buytenhek  *           X      \----------------| |----/
34807332318SLennert Buytenhek  *        polarity    LEVEL          mask
34907332318SLennert Buytenhek  *
35007332318SLennert Buytenhek  ****************************************************************************/
35107332318SLennert Buytenhek 
gpio_irq_set_type(struct irq_data * d,u32 type)3523b0c8d40SLennert Buytenhek static int gpio_irq_set_type(struct irq_data *d, u32 type)
35307332318SLennert Buytenhek {
354e59347a1SThomas Gleixner 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
355e59347a1SThomas Gleixner 	struct irq_chip_type *ct = irq_data_get_chip_type(d);
356e59347a1SThomas Gleixner 	struct orion_gpio_chip *ochip = gc->private;
3579eac6d0aSLennert Buytenhek 	int pin;
35807332318SLennert Buytenhek 	u32 u;
35907332318SLennert Buytenhek 
360278b45b0SAndrew Lunn 	pin = d->hwirq - ochip->secondary_irq_base;
3619eac6d0aSLennert Buytenhek 
3629eac6d0aSLennert Buytenhek 	u = readl(GPIO_IO_CONF(ochip)) & (1 << pin);
36307332318SLennert Buytenhek 	if (!u) {
36407332318SLennert Buytenhek 		return -EINVAL;
36507332318SLennert Buytenhek 	}
36607332318SLennert Buytenhek 
367e59347a1SThomas Gleixner 	type &= IRQ_TYPE_SENSE_MASK;
368e59347a1SThomas Gleixner 	if (type == IRQ_TYPE_NONE)
36907332318SLennert Buytenhek 		return -EINVAL;
370e59347a1SThomas Gleixner 
371e59347a1SThomas Gleixner 	/* Check if we need to change chip and handler */
372e59347a1SThomas Gleixner 	if (!(ct->type & type))
373e59347a1SThomas Gleixner 		if (irq_setup_alt_chip(d, type))
374e59347a1SThomas Gleixner 			return -EINVAL;
37507332318SLennert Buytenhek 
37607332318SLennert Buytenhek 	/*
37707332318SLennert Buytenhek 	 * Configure interrupt polarity.
37807332318SLennert Buytenhek 	 */
37907332318SLennert Buytenhek 	if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) {
3809eac6d0aSLennert Buytenhek 		u = readl(GPIO_IN_POL(ochip));
3819eac6d0aSLennert Buytenhek 		u &= ~(1 << pin);
3829eac6d0aSLennert Buytenhek 		writel(u, GPIO_IN_POL(ochip));
38307332318SLennert Buytenhek 	} else if (type == IRQ_TYPE_EDGE_FALLING || type == IRQ_TYPE_LEVEL_LOW) {
3849eac6d0aSLennert Buytenhek 		u = readl(GPIO_IN_POL(ochip));
3859eac6d0aSLennert Buytenhek 		u |= 1 << pin;
3869eac6d0aSLennert Buytenhek 		writel(u, GPIO_IN_POL(ochip));
38707332318SLennert Buytenhek 	} else if (type == IRQ_TYPE_EDGE_BOTH) {
38807332318SLennert Buytenhek 		u32 v;
38907332318SLennert Buytenhek 
3909eac6d0aSLennert Buytenhek 		v = readl(GPIO_IN_POL(ochip)) ^ readl(GPIO_DATA_IN(ochip));
39107332318SLennert Buytenhek 
39207332318SLennert Buytenhek 		/*
39307332318SLennert Buytenhek 		 * set initial polarity based on current input level
39407332318SLennert Buytenhek 		 */
3959eac6d0aSLennert Buytenhek 		u = readl(GPIO_IN_POL(ochip));
3969eac6d0aSLennert Buytenhek 		if (v & (1 << pin))
3979eac6d0aSLennert Buytenhek 			u |= 1 << pin;		/* falling */
39807332318SLennert Buytenhek 		else
3999eac6d0aSLennert Buytenhek 			u &= ~(1 << pin);	/* rising */
4009eac6d0aSLennert Buytenhek 		writel(u, GPIO_IN_POL(ochip));
40107332318SLennert Buytenhek 	}
40207332318SLennert Buytenhek 	return 0;
40307332318SLennert Buytenhek }
40407332318SLennert Buytenhek 
gpio_irq_handler(struct irq_desc * desc)405bd0b9ac4SThomas Gleixner static void gpio_irq_handler(struct irq_desc *desc)
4069eac6d0aSLennert Buytenhek {
407f575398bSJiang Liu 	struct orion_gpio_chip *ochip = irq_desc_get_handler_data(desc);
408e83bbb11SThomas Gleixner 	u32 cause, type;
4099eac6d0aSLennert Buytenhek 	int i;
41007332318SLennert Buytenhek 
4119eac6d0aSLennert Buytenhek 	if (ochip == NULL)
4129eac6d0aSLennert Buytenhek 		return;
41307332318SLennert Buytenhek 
4149eac6d0aSLennert Buytenhek 	cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip));
4159eac6d0aSLennert Buytenhek 	cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip));
41607332318SLennert Buytenhek 
4179eac6d0aSLennert Buytenhek 	for (i = 0; i < ochip->chip.ngpio; i++) {
4189eac6d0aSLennert Buytenhek 		int irq;
4199eac6d0aSLennert Buytenhek 
4209eac6d0aSLennert Buytenhek 		irq = ochip->secondary_irq_base + i;
4219eac6d0aSLennert Buytenhek 
4229eac6d0aSLennert Buytenhek 		if (!(cause & (1 << i)))
42307332318SLennert Buytenhek 			continue;
42407332318SLennert Buytenhek 
425f88704c9SJavier Martinez Canillas 		type = irq_get_trigger_type(irq);
426e83bbb11SThomas Gleixner 		if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
42707332318SLennert Buytenhek 			/* Swap polarity (race with GPIO line) */
42807332318SLennert Buytenhek 			u32 polarity;
42907332318SLennert Buytenhek 
4309eac6d0aSLennert Buytenhek 			polarity = readl(GPIO_IN_POL(ochip));
4319eac6d0aSLennert Buytenhek 			polarity ^= 1 << i;
4329eac6d0aSLennert Buytenhek 			writel(polarity, GPIO_IN_POL(ochip));
43307332318SLennert Buytenhek 		}
434e83bbb11SThomas Gleixner 		generic_handle_irq(irq);
43507332318SLennert Buytenhek 	}
43607332318SLennert Buytenhek }
437278b45b0SAndrew Lunn 
4388d007488SSimon Guinot #ifdef CONFIG_DEBUG_FS
4398d007488SSimon Guinot #include <linux/seq_file.h>
4408d007488SSimon Guinot 
orion_gpio_dbg_show(struct seq_file * s,struct gpio_chip * chip)4418d007488SSimon Guinot static void orion_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
4428d007488SSimon Guinot {
44366d718ddSLinus Walleij 
44466d718ddSLinus Walleij 	struct orion_gpio_chip *ochip = gpiochip_get_data(chip);
4458d007488SSimon Guinot 	u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
44601b5e345SAndy Shevchenko 	const char *label;
4478d007488SSimon Guinot 	int i;
4488d007488SSimon Guinot 
4498d007488SSimon Guinot 	out	= readl_relaxed(GPIO_OUT(ochip));
4508d007488SSimon Guinot 	io_conf	= readl_relaxed(GPIO_IO_CONF(ochip));
4518d007488SSimon Guinot 	blink	= readl_relaxed(GPIO_BLINK_EN(ochip));
4528d007488SSimon Guinot 	in_pol	= readl_relaxed(GPIO_IN_POL(ochip));
4538d007488SSimon Guinot 	data_in	= readl_relaxed(GPIO_DATA_IN(ochip));
4548d007488SSimon Guinot 	cause	= readl_relaxed(GPIO_EDGE_CAUSE(ochip));
4558d007488SSimon Guinot 	edg_msk	= readl_relaxed(GPIO_EDGE_MASK(ochip));
4568d007488SSimon Guinot 	lvl_msk	= readl_relaxed(GPIO_LEVEL_MASK(ochip));
4578d007488SSimon Guinot 
45801b5e345SAndy Shevchenko 	for_each_requested_gpio(chip, i, label) {
4598d007488SSimon Guinot 		u32 msk;
4608d007488SSimon Guinot 		bool is_out;
4618d007488SSimon Guinot 
4628d007488SSimon Guinot 		msk = 1 << i;
4638d007488SSimon Guinot 		is_out = !(io_conf & msk);
4648d007488SSimon Guinot 
4658d007488SSimon Guinot 		seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label);
4668d007488SSimon Guinot 
4678d007488SSimon Guinot 		if (is_out) {
4688d007488SSimon Guinot 			seq_printf(s, " out %s %s\n",
4698d007488SSimon Guinot 				   out & msk ? "hi" : "lo",
4708d007488SSimon Guinot 				   blink & msk ? "(blink )" : "");
4718d007488SSimon Guinot 			continue;
4728d007488SSimon Guinot 		}
4738d007488SSimon Guinot 
4748d007488SSimon Guinot 		seq_printf(s, " in  %s (act %s) - IRQ",
4758d007488SSimon Guinot 			   (data_in ^ in_pol) & msk  ? "hi" : "lo",
4768d007488SSimon Guinot 			   in_pol & msk ? "lo" : "hi");
4778d007488SSimon Guinot 		if (!((edg_msk | lvl_msk) & msk)) {
478d6ea6893SMarkus Elfring 			seq_puts(s, " disabled\n");
4798d007488SSimon Guinot 			continue;
4808d007488SSimon Guinot 		}
4818d007488SSimon Guinot 		if (edg_msk & msk)
482d6ea6893SMarkus Elfring 			seq_puts(s, " edge ");
4838d007488SSimon Guinot 		if (lvl_msk & msk)
484d6ea6893SMarkus Elfring 			seq_puts(s, " level");
4858d007488SSimon Guinot 		seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear  ");
4868d007488SSimon Guinot 	}
4878d007488SSimon Guinot }
4888d007488SSimon Guinot #else
4898d007488SSimon Guinot #define orion_gpio_dbg_show NULL
4908d007488SSimon Guinot #endif
4918d007488SSimon Guinot 
orion_gpio_unmask_irq(struct irq_data * d)4929ece8839SEvgeniy Dushistov static void orion_gpio_unmask_irq(struct irq_data *d)
4939ece8839SEvgeniy Dushistov {
4949ece8839SEvgeniy Dushistov 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
4959ece8839SEvgeniy Dushistov 	struct irq_chip_type *ct = irq_data_get_chip_type(d);
4969ece8839SEvgeniy Dushistov 	u32 reg_val;
4979ece8839SEvgeniy Dushistov 	u32 mask = d->mask;
4989ece8839SEvgeniy Dushistov 
4999ece8839SEvgeniy Dushistov 	irq_gc_lock(gc);
5002f90bce7SGregory CLEMENT 	reg_val = irq_reg_readl(gc, ct->regs.mask);
5019ece8839SEvgeniy Dushistov 	reg_val |= mask;
5022f90bce7SGregory CLEMENT 	irq_reg_writel(gc, reg_val, ct->regs.mask);
5039ece8839SEvgeniy Dushistov 	irq_gc_unlock(gc);
5049ece8839SEvgeniy Dushistov }
5059ece8839SEvgeniy Dushistov 
orion_gpio_mask_irq(struct irq_data * d)5069ece8839SEvgeniy Dushistov static void orion_gpio_mask_irq(struct irq_data *d)
5079ece8839SEvgeniy Dushistov {
5089ece8839SEvgeniy Dushistov 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
5099ece8839SEvgeniy Dushistov 	struct irq_chip_type *ct = irq_data_get_chip_type(d);
5109ece8839SEvgeniy Dushistov 	u32 mask = d->mask;
5119ece8839SEvgeniy Dushistov 	u32 reg_val;
5129ece8839SEvgeniy Dushistov 
5139ece8839SEvgeniy Dushistov 	irq_gc_lock(gc);
5142f90bce7SGregory CLEMENT 	reg_val = irq_reg_readl(gc, ct->regs.mask);
5159ece8839SEvgeniy Dushistov 	reg_val &= ~mask;
5162f90bce7SGregory CLEMENT 	irq_reg_writel(gc, reg_val, ct->regs.mask);
5179ece8839SEvgeniy Dushistov 	irq_gc_unlock(gc);
5189ece8839SEvgeniy Dushistov }
5199ece8839SEvgeniy Dushistov 
orion_gpio_init(int gpio_base,int ngpio,void __iomem * base,int mask_offset,int secondary_irq_base,int irqs[4])520bba14b32SAndy Shevchenko void __init orion_gpio_init(int gpio_base, int ngpio,
521278b45b0SAndrew Lunn 			    void __iomem *base, int mask_offset,
522278b45b0SAndrew Lunn 			    int secondary_irq_base,
523278b45b0SAndrew Lunn 			    int irqs[4])
524278b45b0SAndrew Lunn {
525278b45b0SAndrew Lunn 	struct orion_gpio_chip *ochip;
526278b45b0SAndrew Lunn 	struct irq_chip_generic *gc;
527278b45b0SAndrew Lunn 	struct irq_chip_type *ct;
528278b45b0SAndrew Lunn 	char gc_label[16];
529278b45b0SAndrew Lunn 	int i;
530278b45b0SAndrew Lunn 
531278b45b0SAndrew Lunn 	if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips))
532278b45b0SAndrew Lunn 		return;
533278b45b0SAndrew Lunn 
534278b45b0SAndrew Lunn 	snprintf(gc_label, sizeof(gc_label), "orion_gpio%d",
535278b45b0SAndrew Lunn 		orion_gpio_chip_count);
536278b45b0SAndrew Lunn 
537278b45b0SAndrew Lunn 	ochip = orion_gpio_chips + orion_gpio_chip_count;
538278b45b0SAndrew Lunn 	ochip->chip.label = kstrdup(gc_label, GFP_KERNEL);
539278b45b0SAndrew Lunn 	ochip->chip.request = orion_gpio_request;
540278b45b0SAndrew Lunn 	ochip->chip.direction_input = orion_gpio_direction_input;
541278b45b0SAndrew Lunn 	ochip->chip.get = orion_gpio_get;
542278b45b0SAndrew Lunn 	ochip->chip.direction_output = orion_gpio_direction_output;
543278b45b0SAndrew Lunn 	ochip->chip.set = orion_gpio_set;
544278b45b0SAndrew Lunn 	ochip->chip.to_irq = orion_gpio_to_irq;
545278b45b0SAndrew Lunn 	ochip->chip.base = gpio_base;
546278b45b0SAndrew Lunn 	ochip->chip.ngpio = ngpio;
547278b45b0SAndrew Lunn 	ochip->chip.can_sleep = 0;
5488d007488SSimon Guinot 	ochip->chip.dbg_show = orion_gpio_dbg_show;
549278b45b0SAndrew Lunn 
550278b45b0SAndrew Lunn 	spin_lock_init(&ochip->lock);
551278b45b0SAndrew Lunn 	ochip->base = (void __iomem *)base;
552278b45b0SAndrew Lunn 	ochip->valid_input = 0;
553278b45b0SAndrew Lunn 	ochip->valid_output = 0;
554278b45b0SAndrew Lunn 	ochip->mask_offset = mask_offset;
555278b45b0SAndrew Lunn 	ochip->secondary_irq_base = secondary_irq_base;
556278b45b0SAndrew Lunn 
55766d718ddSLinus Walleij 	gpiochip_add_data(&ochip->chip, ochip);
558278b45b0SAndrew Lunn 
559278b45b0SAndrew Lunn 	/*
560278b45b0SAndrew Lunn 	 * Mask and clear GPIO interrupts.
561278b45b0SAndrew Lunn 	 */
562278b45b0SAndrew Lunn 	writel(0, GPIO_EDGE_CAUSE(ochip));
563278b45b0SAndrew Lunn 	writel(0, GPIO_EDGE_MASK(ochip));
564278b45b0SAndrew Lunn 	writel(0, GPIO_LEVEL_MASK(ochip));
565278b45b0SAndrew Lunn 
566278b45b0SAndrew Lunn 	/* Setup the interrupt handlers. Each chip can have up to 4
567278b45b0SAndrew Lunn 	 * interrupt handlers, with each handler dealing with 8 GPIO
568278b45b0SAndrew Lunn 	 * pins. */
569278b45b0SAndrew Lunn 
570278b45b0SAndrew Lunn 	for (i = 0; i < 4; i++) {
571278b45b0SAndrew Lunn 		if (irqs[i]) {
572206287c2SThomas Gleixner 			irq_set_chained_handler_and_data(irqs[i],
573206287c2SThomas Gleixner 							 gpio_irq_handler,
574206287c2SThomas Gleixner 							 ochip);
575278b45b0SAndrew Lunn 		}
576278b45b0SAndrew Lunn 	}
577278b45b0SAndrew Lunn 
578278b45b0SAndrew Lunn 	gc = irq_alloc_generic_chip("orion_gpio_irq", 2,
579278b45b0SAndrew Lunn 				    secondary_irq_base,
580278b45b0SAndrew Lunn 				    ochip->base, handle_level_irq);
581278b45b0SAndrew Lunn 	gc->private = ochip;
582278b45b0SAndrew Lunn 	ct = gc->chip_types;
583278b45b0SAndrew Lunn 	ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF;
584278b45b0SAndrew Lunn 	ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
5859ece8839SEvgeniy Dushistov 	ct->chip.irq_mask = orion_gpio_mask_irq;
5869ece8839SEvgeniy Dushistov 	ct->chip.irq_unmask = orion_gpio_unmask_irq;
587278b45b0SAndrew Lunn 	ct->chip.irq_set_type = gpio_irq_set_type;
588278b45b0SAndrew Lunn 	ct->chip.name = ochip->chip.label;
589278b45b0SAndrew Lunn 
590278b45b0SAndrew Lunn 	ct++;
591278b45b0SAndrew Lunn 	ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF;
592278b45b0SAndrew Lunn 	ct->regs.ack = GPIO_EDGE_CAUSE_OFF;
593278b45b0SAndrew Lunn 	ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
594278b45b0SAndrew Lunn 	ct->chip.irq_ack = irq_gc_ack_clr_bit;
5959ece8839SEvgeniy Dushistov 	ct->chip.irq_mask = orion_gpio_mask_irq;
5969ece8839SEvgeniy Dushistov 	ct->chip.irq_unmask = orion_gpio_unmask_irq;
597278b45b0SAndrew Lunn 	ct->chip.irq_set_type = gpio_irq_set_type;
598278b45b0SAndrew Lunn 	ct->handler = handle_edge_irq;
599278b45b0SAndrew Lunn 	ct->chip.name = ochip->chip.label;
600278b45b0SAndrew Lunn 
601278b45b0SAndrew Lunn 	irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE,
602278b45b0SAndrew Lunn 			       IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
603278b45b0SAndrew Lunn 
604278b45b0SAndrew Lunn 	/* Setup irq domain on top of the generic chip. */
605bba14b32SAndy Shevchenko 	ochip->domain = irq_domain_add_legacy(NULL,
606278b45b0SAndrew Lunn 					      ochip->chip.ngpio,
607278b45b0SAndrew Lunn 					      ochip->secondary_irq_base,
608278b45b0SAndrew Lunn 					      ochip->secondary_irq_base,
609278b45b0SAndrew Lunn 					      &irq_domain_simple_ops,
610278b45b0SAndrew Lunn 					      ochip);
611278b45b0SAndrew Lunn 	if (!ochip->domain)
612278b45b0SAndrew Lunn 		panic("%s: couldn't allocate irq domain (DT).\n",
613278b45b0SAndrew Lunn 		      ochip->chip.label);
614278b45b0SAndrew Lunn 
615278b45b0SAndrew Lunn 	orion_gpio_chip_count++;
616278b45b0SAndrew Lunn }
617