xref: /rk3399_rockchip-uboot/drivers/irq/irq-gpio.c (revision b8dc613cbc483a8abfcf4203e4fa0e18f60b1d27)
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