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