14e6670feSJoseph Chen /*
24e6670feSJoseph Chen * (C) Copyright 2017 Rockchip Electronics Co., Ltd
34e6670feSJoseph Chen *
44e6670feSJoseph Chen * SPDX-License-Identifier: GPL-2.0+
54e6670feSJoseph Chen */
64e6670feSJoseph Chen
7ae63f119SJoseph Chen #include <dm.h>
8ae63f119SJoseph Chen #include <malloc.h>
9cf344252SJoseph Chen #include "irq-internal.h"
104e6670feSJoseph Chen
114e6670feSJoseph Chen typedef enum GPIOIntType {
124e6670feSJoseph Chen GPIOLevelLow = 0,
134e6670feSJoseph Chen GPIOLevelHigh,
144e6670feSJoseph Chen GPIOEdgelFalling,
154e6670feSJoseph Chen GPIOEdgelRising
164e6670feSJoseph Chen } eGPIOIntType_t;
174e6670feSJoseph Chen
184e6670feSJoseph Chen typedef enum eGPIOPinLevel {
194e6670feSJoseph Chen GPIO_LOW = 0,
204e6670feSJoseph Chen GPIO_HIGH
214e6670feSJoseph Chen } eGPIOPinLevel_t;
224e6670feSJoseph Chen
234e6670feSJoseph Chen typedef enum eGPIOPinDirection {
244e6670feSJoseph Chen GPIO_IN = 0,
254e6670feSJoseph Chen GPIO_OUT
264e6670feSJoseph Chen } eGPIOPinDirection_t;
274e6670feSJoseph Chen
284e6670feSJoseph Chen #define GPIO_SWPORT_DR 0x00
294e6670feSJoseph Chen #define GPIO_SWPORT_DDR 0x04
304e6670feSJoseph Chen #define GPIO_INTEN 0x30
314e6670feSJoseph Chen #define GPIO_INTMASK 0x34
324e6670feSJoseph Chen #define GPIO_INTTYPE_LEVEL 0x38
334e6670feSJoseph Chen #define GPIO_INT_POLARITY 0x3c
344e6670feSJoseph Chen #define GPIO_INT_STATUS 0x40
354e6670feSJoseph Chen #define GPIO_INT_RAWSTATUS 0x44
364e6670feSJoseph Chen #define GPIO_DEBOUNCE 0x48
374e6670feSJoseph Chen #define GPIO_PORTS_EOI 0x4c
384e6670feSJoseph Chen #define GPIO_EXT_PORT 0x50
394e6670feSJoseph Chen #define GPIO_LS_SYNC 0x60
404e6670feSJoseph Chen
pin_to_bit(unsigned pin)414e6670feSJoseph Chen static inline unsigned pin_to_bit(unsigned pin)
424e6670feSJoseph Chen {
434e6670feSJoseph Chen return (1 << pin);
444e6670feSJoseph Chen }
454e6670feSJoseph Chen
offset_to_bit(unsigned offset)464e6670feSJoseph Chen static inline unsigned offset_to_bit(unsigned offset)
474e6670feSJoseph Chen {
484e6670feSJoseph Chen return (1 << offset);
494e6670feSJoseph Chen }
504e6670feSJoseph Chen
gpio_bit_op(void __iomem * regbase,unsigned int offset,u32 bit,unsigned char flag)514e6670feSJoseph Chen static void gpio_bit_op(void __iomem *regbase, unsigned int offset,
524e6670feSJoseph Chen u32 bit, unsigned char flag)
534e6670feSJoseph Chen {
544e6670feSJoseph Chen u32 val = readl(regbase + offset);
554e6670feSJoseph Chen
564e6670feSJoseph Chen if (flag)
574e6670feSJoseph Chen val |= bit;
584e6670feSJoseph Chen else
594e6670feSJoseph Chen val &= ~bit;
604e6670feSJoseph Chen
614e6670feSJoseph Chen writel(val, regbase + offset);
624e6670feSJoseph Chen }
634e6670feSJoseph Chen
gpio_bit_rd(void __iomem * regbase,unsigned int offset,u32 bit)64c234b81eSJoseph Chen static int gpio_bit_rd(void __iomem *regbase, unsigned int offset, u32 bit)
65c234b81eSJoseph Chen {
66c234b81eSJoseph Chen return readl(regbase + offset) & bit ? 1 : 0;
67c234b81eSJoseph Chen }
68c234b81eSJoseph Chen
gpio_irq_unmask(void __iomem * regbase,unsigned int bit)694e6670feSJoseph Chen static void gpio_irq_unmask(void __iomem *regbase, unsigned int bit)
704e6670feSJoseph Chen {
714e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INTEN, bit, 1);
724e6670feSJoseph Chen }
734e6670feSJoseph Chen
gpio_irq_mask(void __iomem * regbase,unsigned int bit)744e6670feSJoseph Chen static void gpio_irq_mask(void __iomem *regbase, unsigned int bit)
754e6670feSJoseph Chen {
764e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INTEN, bit, 0);
774e6670feSJoseph Chen }
784e6670feSJoseph Chen
gpio_irq_ack(void __iomem * regbase,unsigned int bit)794e6670feSJoseph Chen static void gpio_irq_ack(void __iomem *regbase, unsigned int bit)
804e6670feSJoseph Chen {
814e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_PORTS_EOI, bit, 1);
824e6670feSJoseph Chen }
834e6670feSJoseph Chen
generic_gpio_handle_irq(int irq,void * data __always_unused)8442865eb5SJoseph Chen static void generic_gpio_handle_irq(int irq, void *data __always_unused)
854e6670feSJoseph Chen {
864e6670feSJoseph Chen struct gpio_bank *bank = gpio_id_to_bank(irq - IRQ_GPIO0);
874e6670feSJoseph Chen unsigned gpio_irq, pin, unmasked = 0;
884e6670feSJoseph Chen u32 isr, ilr;
894e6670feSJoseph Chen
904e6670feSJoseph Chen isr = readl(bank->regbase + GPIO_INT_STATUS);
914e6670feSJoseph Chen ilr = readl(bank->regbase + GPIO_INTTYPE_LEVEL);
924e6670feSJoseph Chen
934e6670feSJoseph Chen gpio_irq = bank->irq_base;
944e6670feSJoseph Chen
954e6670feSJoseph Chen while (isr) {
964e6670feSJoseph Chen pin = fls(isr) - 1;
974e6670feSJoseph Chen
984e6670feSJoseph Chen /* first mask and ack irq */
994e6670feSJoseph Chen gpio_irq_mask(bank->regbase, offset_to_bit(pin));
1004e6670feSJoseph Chen gpio_irq_ack(bank->regbase, offset_to_bit(pin));
1014e6670feSJoseph Chen
1024e6670feSJoseph Chen /*
103269512fdSJoseph Chen * If gpio is edge triggered, clear condition before executing
104269512fdSJoseph Chen * the handler, so that we don't miss next edges trigger.
1054e6670feSJoseph Chen */
1064e6670feSJoseph Chen if (ilr & (1 << pin)) {
1074e6670feSJoseph Chen unmasked = 1;
1084e6670feSJoseph Chen gpio_irq_unmask(bank->regbase, offset_to_bit(pin));
1094e6670feSJoseph Chen }
1104e6670feSJoseph Chen
111269512fdSJoseph Chen __generic_gpio_handle_irq(gpio_irq + pin);
1124e6670feSJoseph Chen
1134e6670feSJoseph Chen isr &= ~(1 << pin);
1144e6670feSJoseph Chen
1154e6670feSJoseph Chen if (!unmasked)
1164e6670feSJoseph Chen gpio_irq_unmask(bank->regbase, offset_to_bit(pin));
1174e6670feSJoseph Chen }
1184e6670feSJoseph Chen }
1194e6670feSJoseph Chen
gpio_set_intr_type(void __iomem * regbase,unsigned int bit,eGPIOIntType_t type)1204e6670feSJoseph Chen static void gpio_set_intr_type(void __iomem *regbase,
1214e6670feSJoseph Chen unsigned int bit,
1224e6670feSJoseph Chen eGPIOIntType_t type)
1234e6670feSJoseph Chen {
1244e6670feSJoseph Chen switch (type) {
1254e6670feSJoseph Chen case GPIOLevelLow:
1264e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 0);
1274e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 0);
1284e6670feSJoseph Chen break;
1294e6670feSJoseph Chen case GPIOLevelHigh:
1304e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 0);
1314e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 1);
1324e6670feSJoseph Chen break;
1334e6670feSJoseph Chen case GPIOEdgelFalling:
1344e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 1);
1354e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 0);
1364e6670feSJoseph Chen break;
1374e6670feSJoseph Chen case GPIOEdgelRising:
1384e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INTTYPE_LEVEL, bit, 1);
1394e6670feSJoseph Chen gpio_bit_op(regbase, GPIO_INT_POLARITY, bit, 1);
1404e6670feSJoseph Chen break;
1414e6670feSJoseph Chen }
1424e6670feSJoseph Chen }
1434e6670feSJoseph Chen
gpio_get_intr_type(void __iomem * regbase,unsigned int bit)144c234b81eSJoseph Chen static int gpio_get_intr_type(void __iomem *regbase,
145c234b81eSJoseph Chen unsigned int bit)
146c234b81eSJoseph Chen {
147c234b81eSJoseph Chen u32 polarity, level, magic = 0;
148c234b81eSJoseph Chen int type;
149c234b81eSJoseph Chen
150c234b81eSJoseph Chen polarity = gpio_bit_rd(regbase, GPIO_INT_POLARITY, bit);
151c234b81eSJoseph Chen level = gpio_bit_rd(regbase, GPIO_INTTYPE_LEVEL, bit);
152c234b81eSJoseph Chen magic = (polarity << 1) | (level << 0);
153c234b81eSJoseph Chen
154c234b81eSJoseph Chen switch (magic) {
155c234b81eSJoseph Chen case 0x00:
156c234b81eSJoseph Chen type = GPIOLevelLow;
157c234b81eSJoseph Chen break;
158c234b81eSJoseph Chen case 0x02:
159c234b81eSJoseph Chen type = GPIOLevelHigh;
160c234b81eSJoseph Chen break;
161c234b81eSJoseph Chen case 0x01:
162c234b81eSJoseph Chen type = GPIOEdgelFalling;
163c234b81eSJoseph Chen break;
164c234b81eSJoseph Chen case 0x03:
165c234b81eSJoseph Chen type = GPIOEdgelRising;
166c234b81eSJoseph Chen break;
16786457e16SJason Zhu default:
16886457e16SJason Zhu type = -EINVAL;
169c234b81eSJoseph Chen }
170c234b81eSJoseph Chen
171c234b81eSJoseph Chen return type;
172c234b81eSJoseph Chen }
173c234b81eSJoseph Chen
gpio_irq_set_type(int gpio_irq,unsigned int type)1744e6670feSJoseph Chen static int gpio_irq_set_type(int gpio_irq, unsigned int type)
1754e6670feSJoseph Chen {
1764e6670feSJoseph Chen int gpio = irq_to_gpio(gpio_irq);
1774e6670feSJoseph Chen struct gpio_bank *bank = gpio_to_bank(gpio);
1784e6670feSJoseph Chen eGPIOIntType_t int_type = 0;
1794e6670feSJoseph Chen
1804e6670feSJoseph Chen if (!bank)
1814e6670feSJoseph Chen return -EINVAL;
1824e6670feSJoseph Chen
1834e6670feSJoseph Chen gpio &= GPIO_PIN_MASK;
1844e6670feSJoseph Chen if (gpio >= bank->ngpio)
1854e6670feSJoseph Chen return -EINVAL;
1864e6670feSJoseph Chen
1874e6670feSJoseph Chen switch (type) {
1884e6670feSJoseph Chen case IRQ_TYPE_EDGE_RISING:
1894e6670feSJoseph Chen int_type = GPIOEdgelRising;
1904e6670feSJoseph Chen break;
1914e6670feSJoseph Chen case IRQ_TYPE_EDGE_FALLING:
1924e6670feSJoseph Chen int_type = GPIOEdgelFalling;
1934e6670feSJoseph Chen break;
1944e6670feSJoseph Chen case IRQ_TYPE_LEVEL_HIGH:
1954e6670feSJoseph Chen int_type = GPIOLevelHigh;
1964e6670feSJoseph Chen break;
1974e6670feSJoseph Chen case IRQ_TYPE_LEVEL_LOW:
1984e6670feSJoseph Chen int_type = GPIOLevelLow;
1994e6670feSJoseph Chen break;
2004e6670feSJoseph Chen default:
2014e6670feSJoseph Chen return -EINVAL;
2024e6670feSJoseph Chen }
2034e6670feSJoseph Chen
2044e6670feSJoseph Chen /* Before set interrupt type, gpio must set input */
2054e6670feSJoseph Chen gpio_bit_op(bank->regbase, GPIO_SWPORT_DDR,
2064e6670feSJoseph Chen offset_to_bit(gpio), GPIO_IN);
2074e6670feSJoseph Chen gpio_set_intr_type(bank->regbase, offset_to_bit(gpio), int_type);
2084e6670feSJoseph Chen
2094e6670feSJoseph Chen return 0;
2104e6670feSJoseph Chen }
2114e6670feSJoseph Chen
gpio_irq_revert_type(int gpio_irq)212c234b81eSJoseph Chen static int gpio_irq_revert_type(int gpio_irq)
213c234b81eSJoseph Chen {
214c234b81eSJoseph Chen int gpio = irq_to_gpio(gpio_irq);
215c234b81eSJoseph Chen struct gpio_bank *bank = gpio_to_bank(gpio);
216c234b81eSJoseph Chen eGPIOIntType_t int_type = 0;
217c234b81eSJoseph Chen int type;
218c234b81eSJoseph Chen
219c234b81eSJoseph Chen if (!bank)
220c234b81eSJoseph Chen return -EINVAL;
221c234b81eSJoseph Chen
222c234b81eSJoseph Chen gpio &= GPIO_PIN_MASK;
223c234b81eSJoseph Chen if (gpio >= bank->ngpio)
224c234b81eSJoseph Chen return -EINVAL;
225c234b81eSJoseph Chen
226c234b81eSJoseph Chen type = gpio_get_intr_type(bank->regbase, offset_to_bit(gpio));
227c234b81eSJoseph Chen switch (type) {
228c234b81eSJoseph Chen case GPIOEdgelFalling:
229c234b81eSJoseph Chen int_type = GPIOEdgelRising;
230c234b81eSJoseph Chen break;
231c234b81eSJoseph Chen case GPIOEdgelRising:
232c234b81eSJoseph Chen int_type = GPIOEdgelFalling;
233c234b81eSJoseph Chen break;
234c234b81eSJoseph Chen case GPIOLevelHigh:
235c234b81eSJoseph Chen int_type = GPIOLevelLow;
236c234b81eSJoseph Chen break;
237c234b81eSJoseph Chen case GPIOLevelLow:
238c234b81eSJoseph Chen int_type = GPIOLevelHigh;
239c234b81eSJoseph Chen break;
240c234b81eSJoseph Chen default:
241c234b81eSJoseph Chen return -EINVAL;
242c234b81eSJoseph Chen }
243c234b81eSJoseph Chen
244c234b81eSJoseph Chen gpio_set_intr_type(bank->regbase, offset_to_bit(gpio), int_type);
245c234b81eSJoseph Chen
246c234b81eSJoseph Chen return 0;
247c234b81eSJoseph Chen }
248c234b81eSJoseph Chen
gpio_irq_get_gpio_level(int gpio_irq)249c234b81eSJoseph Chen static int gpio_irq_get_gpio_level(int gpio_irq)
250c234b81eSJoseph Chen {
251c234b81eSJoseph Chen int gpio = irq_to_gpio(gpio_irq);
252c234b81eSJoseph Chen struct gpio_bank *bank = gpio_to_bank(gpio);
253c234b81eSJoseph Chen
254c234b81eSJoseph Chen if (!bank)
255c234b81eSJoseph Chen return -EINVAL;
256c234b81eSJoseph Chen
257c234b81eSJoseph Chen gpio &= GPIO_PIN_MASK;
258c234b81eSJoseph Chen if (gpio >= bank->ngpio)
259c234b81eSJoseph Chen return -EINVAL;
260c234b81eSJoseph Chen
261c234b81eSJoseph Chen return gpio_bit_rd(bank->regbase, GPIO_EXT_PORT, offset_to_bit(gpio));
262c234b81eSJoseph Chen }
263c234b81eSJoseph Chen
gpio_irq_enable(int gpio_irq)2644e6670feSJoseph Chen static int gpio_irq_enable(int gpio_irq)
2654e6670feSJoseph Chen {
2664e6670feSJoseph Chen int gpio = irq_to_gpio(gpio_irq);
2674e6670feSJoseph Chen struct gpio_bank *bank = gpio_to_bank(gpio);
2684e6670feSJoseph Chen
2694e6670feSJoseph Chen if (!bank)
2704e6670feSJoseph Chen return -EINVAL;
2714e6670feSJoseph Chen
2724e6670feSJoseph Chen gpio &= GPIO_PIN_MASK;
2734e6670feSJoseph Chen if (gpio >= bank->ngpio)
2744e6670feSJoseph Chen return -EINVAL;
2754e6670feSJoseph Chen
2764e6670feSJoseph Chen gpio_irq_unmask(bank->regbase, offset_to_bit(gpio));
2774e6670feSJoseph Chen
278a5e3baaaSJoseph Chen if (bank->use_count == 0)
279a5e3baaaSJoseph Chen irq_handler_enable(IRQ_GPIO0 + bank->id);
280a5e3baaaSJoseph Chen bank->use_count++;
281a5e3baaaSJoseph Chen
2824e6670feSJoseph Chen return 0;
2834e6670feSJoseph Chen }
2844e6670feSJoseph Chen
gpio_irq_disable(int irq)2854e6670feSJoseph Chen static int gpio_irq_disable(int irq)
2864e6670feSJoseph Chen {
2874e6670feSJoseph Chen int gpio = irq_to_gpio(irq);
2884e6670feSJoseph Chen struct gpio_bank *bank = gpio_to_bank(gpio);
2894e6670feSJoseph Chen
2904e6670feSJoseph Chen if (!bank)
2914e6670feSJoseph Chen return -EINVAL;
2924e6670feSJoseph Chen
293*25c13168SJoseph Chen if (bank->use_count <= 0)
294*25c13168SJoseph Chen return 0;
295*25c13168SJoseph Chen
2964e6670feSJoseph Chen gpio &= GPIO_PIN_MASK;
2974e6670feSJoseph Chen if (gpio >= bank->ngpio)
2984e6670feSJoseph Chen return -EINVAL;
2994e6670feSJoseph Chen
3004e6670feSJoseph Chen gpio_irq_mask(bank->regbase, offset_to_bit(gpio));
3014e6670feSJoseph Chen
302a5e3baaaSJoseph Chen if (bank->use_count == 1)
303a5e3baaaSJoseph Chen irq_handler_disable(IRQ_GPIO0 + bank->id);
304a5e3baaaSJoseph Chen bank->use_count--;
305a5e3baaaSJoseph Chen
3064e6670feSJoseph Chen return 0;
3074e6670feSJoseph Chen }
3084e6670feSJoseph Chen
gpio_irq_init(void)3094e6670feSJoseph Chen static int gpio_irq_init(void)
3104e6670feSJoseph Chen {
3114e6670feSJoseph Chen struct gpio_bank *bank = NULL;
3124e6670feSJoseph Chen int i = 0;
3134e6670feSJoseph Chen
3144e6670feSJoseph Chen for (i = 0; i < GPIO_BANK_NUM; i++) {
315ae63f119SJoseph Chen struct udevice *dev;
316ae63f119SJoseph Chen
317ae63f119SJoseph Chen dev = malloc(sizeof(*dev));
318ae63f119SJoseph Chen if (!dev)
319ae63f119SJoseph Chen return -ENOMEM;
320ae63f119SJoseph Chen
3214e6670feSJoseph Chen bank = gpio_id_to_bank(i);
3224e6670feSJoseph Chen if (bank) {
323ae63f119SJoseph Chen dev->name = bank->name;
324ae63f119SJoseph Chen
3254e6670feSJoseph Chen /* disable gpio pin interrupt */
3264e6670feSJoseph Chen writel(0, bank->regbase + GPIO_INTEN);
3274e6670feSJoseph Chen
3284e6670feSJoseph Chen /* register gpio group irq handler */
3294e6670feSJoseph Chen irq_install_handler(IRQ_GPIO0 + bank->id,
330ae63f119SJoseph Chen (interrupt_handler_t *)generic_gpio_handle_irq, dev);
3314e6670feSJoseph Chen
332a5e3baaaSJoseph Chen /* default disable all gpio group interrupt */
333a5e3baaaSJoseph Chen irq_handler_disable(IRQ_GPIO0 + bank->id);
3344e6670feSJoseph Chen }
3354e6670feSJoseph Chen }
3364e6670feSJoseph Chen
3374e6670feSJoseph Chen return 0;
3384e6670feSJoseph Chen }
3394e6670feSJoseph Chen
3404e6670feSJoseph Chen static struct irq_chip gpio_irq_chip = {
3414e6670feSJoseph Chen .name = "gpio-irq-chip",
3424e6670feSJoseph Chen .irq_init = gpio_irq_init,
3434e6670feSJoseph Chen .irq_enable = gpio_irq_enable,
3444e6670feSJoseph Chen .irq_disable = gpio_irq_disable,
3454e6670feSJoseph Chen .irq_set_type = gpio_irq_set_type,
346c234b81eSJoseph Chen .irq_revert_type = gpio_irq_revert_type,
347c234b81eSJoseph Chen .irq_get_gpio_level = gpio_irq_get_gpio_level,
3484e6670feSJoseph Chen };
3494e6670feSJoseph Chen
arch_gpio_get_irqchip(void)350cf344252SJoseph Chen struct irq_chip *arch_gpio_get_irqchip(void)
3514e6670feSJoseph Chen {
3524e6670feSJoseph Chen return &gpio_irq_chip;
3534e6670feSJoseph Chen }
354