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
74e6670feSJoseph Chen #include <dm.h>
8cf344252SJoseph Chen #include "irq-internal.h"
94e6670feSJoseph Chen
105db1153eSJoseph Chen DECLARE_GLOBAL_DATA_PTR;
115db1153eSJoseph Chen
124e6670feSJoseph Chen static struct gpio_bank gpio_banks[GPIO_BANK_NUM] = {
134e6670feSJoseph Chen #if GPIO_BANK_NUM >= 1
144e6670feSJoseph Chen GPIO_BANK_REGISTER(0, GPIO_BANK_PINS),
154e6670feSJoseph Chen #endif
164e6670feSJoseph Chen #if GPIO_BANK_NUM >= 2
174e6670feSJoseph Chen GPIO_BANK_REGISTER(1, GPIO_BANK_PINS),
184e6670feSJoseph Chen #endif
194e6670feSJoseph Chen #if GPIO_BANK_NUM >= 3
204e6670feSJoseph Chen GPIO_BANK_REGISTER(2, GPIO_BANK_PINS),
214e6670feSJoseph Chen #endif
224e6670feSJoseph Chen #if GPIO_BANK_NUM >= 4
234e6670feSJoseph Chen GPIO_BANK_REGISTER(3, GPIO_BANK_PINS),
244e6670feSJoseph Chen #endif
254e6670feSJoseph Chen #if GPIO_BANK_NUM >= 5
264e6670feSJoseph Chen GPIO_BANK_REGISTER(4, GPIO_BANK_PINS),
274e6670feSJoseph Chen #endif
284e6670feSJoseph Chen #if GPIO_BANK_NUM >= 6
294e6670feSJoseph Chen GPIO_BANK_REGISTER(5, GPIO_BANK_PINS),
304e6670feSJoseph Chen #endif
314e6670feSJoseph Chen #if GPIO_BANK_NUM >= 7
324e6670feSJoseph Chen GPIO_BANK_REGISTER(6, GPIO_BANK_PINS),
334e6670feSJoseph Chen #endif
344e6670feSJoseph Chen #if GPIO_BANK_NUM >= 8
354e6670feSJoseph Chen GPIO_BANK_REGISTER(7, GPIO_BANK_PINS),
364e6670feSJoseph Chen #endif
374e6670feSJoseph Chen #if GPIO_BANK_NUM >= 9
384e6670feSJoseph Chen GPIO_BANK_REGISTER(8, GPIO_BANK_PINS),
394e6670feSJoseph Chen #endif
404e6670feSJoseph Chen #if GPIO_BANK_NUM >= 10
414e6670feSJoseph Chen GPIO_BANK_REGISTER(9, GPIO_BANK_PINS),
424e6670feSJoseph Chen #endif
434e6670feSJoseph Chen };
444e6670feSJoseph Chen
45*b476d716SJoseph Chen static const char *aliases_gpios[GPIO_BANK_NUM];
46*b476d716SJoseph Chen static const char *order_gpios[GPIO_BANK_NUM];
478db67737SJoseph Chen
gpio_is_valid(u32 gpio)484e6670feSJoseph Chen static int gpio_is_valid(u32 gpio)
494e6670feSJoseph Chen {
50269512fdSJoseph Chen if ((gpio == EINVAL_GPIO) ||
51269512fdSJoseph Chen !GPIO_BANK_VALID(gpio) ||
524e6670feSJoseph Chen !GPIO_PIN_VALID(gpio)) {
53269512fdSJoseph Chen IRQ_E("gpio-%d(bank-%d, pin-%d) is invalid!\n",
54269512fdSJoseph Chen gpio, GPIO_BANK(gpio), GPIO_PIN(gpio));
554e6670feSJoseph Chen return 0;
564e6670feSJoseph Chen }
574e6670feSJoseph Chen
584e6670feSJoseph Chen return 1;
594e6670feSJoseph Chen }
604e6670feSJoseph Chen
__hard_gpio_to_irq(u32 gpio)61269512fdSJoseph Chen static int __hard_gpio_to_irq(u32 gpio)
624e6670feSJoseph Chen {
634e6670feSJoseph Chen int idx, bank = 0, pin = 0;
648696cc38SJoseph Chen int irq;
654e6670feSJoseph Chen
664e6670feSJoseph Chen if (!gpio_is_valid(gpio))
674e6670feSJoseph Chen return -EINVAL;
684e6670feSJoseph Chen
694e6670feSJoseph Chen bank = (gpio & GPIO_BANK_MASK) >> GPIO_BANK_OFFSET;
704e6670feSJoseph Chen pin = (gpio & GPIO_PIN_MASK) >> GPIO_PIN_OFFSET;
714e6670feSJoseph Chen
724e6670feSJoseph Chen for (idx = 0; idx < ARRAY_SIZE(gpio_banks); idx++) {
738696cc38SJoseph Chen if (gpio_banks[idx].id == bank) {
748696cc38SJoseph Chen irq = (gpio_banks[idx].irq_base + pin);
758696cc38SJoseph Chen if (irq_is_busy(irq))
768696cc38SJoseph Chen return -EBUSY;
778696cc38SJoseph Chen return irq;
788696cc38SJoseph Chen }
794e6670feSJoseph Chen }
804e6670feSJoseph Chen
814e6670feSJoseph Chen return -EINVAL;
824e6670feSJoseph Chen }
834e6670feSJoseph Chen
init_order_gpios(void)84*b476d716SJoseph Chen static int init_order_gpios(void)
85*b476d716SJoseph Chen {
86*b476d716SJoseph Chen const void *fdt = gd->fdt_blob;
87*b476d716SJoseph Chen static int initialized;
88*b476d716SJoseph Chen int node, offset;
89*b476d716SJoseph Chen int i = 0;
90*b476d716SJoseph Chen
91*b476d716SJoseph Chen if (initialized)
92*b476d716SJoseph Chen return 0;
93*b476d716SJoseph Chen
94*b476d716SJoseph Chen node = fdt_path_offset(fdt, "/pinctrl");
95*b476d716SJoseph Chen if (node < 0)
96*b476d716SJoseph Chen return -EINVAL;
97*b476d716SJoseph Chen
98*b476d716SJoseph Chen for (offset = fdt_first_subnode(fdt, node);
99*b476d716SJoseph Chen offset >= 0 && i < GPIO_BANK_NUM;
100*b476d716SJoseph Chen offset = fdt_next_subnode(fdt, offset)) {
101*b476d716SJoseph Chen if (i >= GPIO_BANK_NUM)
102*b476d716SJoseph Chen break;
103*b476d716SJoseph Chen
104*b476d716SJoseph Chen order_gpios[i++] = fdt_get_name(fdt, offset, NULL);
105*b476d716SJoseph Chen IRQ_D("order gpio: %s\n", order_gpios[i - 1]);
106*b476d716SJoseph Chen }
107*b476d716SJoseph Chen
108*b476d716SJoseph Chen initialized = 1;
109*b476d716SJoseph Chen
110*b476d716SJoseph Chen return 0;
111*b476d716SJoseph Chen }
112*b476d716SJoseph Chen
init_aliases_gpios(void)113*b476d716SJoseph Chen static int init_aliases_gpios(void)
114*b476d716SJoseph Chen {
115*b476d716SJoseph Chen static int initialized;
116*b476d716SJoseph Chen char alias_name[6];
117*b476d716SJoseph Chen int i;
118*b476d716SJoseph Chen
119*b476d716SJoseph Chen if (initialized)
120*b476d716SJoseph Chen return 0;
121*b476d716SJoseph Chen
122*b476d716SJoseph Chen for (i = 0; i < GPIO_BANK_NUM; i++) {
123*b476d716SJoseph Chen snprintf(alias_name, 6, "gpio%d", i);
124*b476d716SJoseph Chen aliases_gpios[i] = fdt_get_alias(gd->fdt_blob, alias_name);
125*b476d716SJoseph Chen if (!aliases_gpios[i])
126*b476d716SJoseph Chen return -EINVAL;
127*b476d716SJoseph Chen
128*b476d716SJoseph Chen IRQ_D("aliases gpio: %s\n", aliases_gpios[i]);
129*b476d716SJoseph Chen }
130*b476d716SJoseph Chen
131*b476d716SJoseph Chen initialized = 1;
132*b476d716SJoseph Chen
133*b476d716SJoseph Chen return 0;
134*b476d716SJoseph Chen }
135*b476d716SJoseph Chen
lookup_gpio_bank(const char * name)136*b476d716SJoseph Chen static int lookup_gpio_bank(const char *name)
137*b476d716SJoseph Chen {
138*b476d716SJoseph Chen int bank, ret;
139*b476d716SJoseph Chen
140*b476d716SJoseph Chen for (bank = 0; bank < GPIO_BANK_NUM; bank++) {
141*b476d716SJoseph Chen if (strstr(name, gpio_banks[bank].name))
142*b476d716SJoseph Chen return bank;
143*b476d716SJoseph Chen }
144*b476d716SJoseph Chen
145*b476d716SJoseph Chen ret = init_aliases_gpios();
146*b476d716SJoseph Chen for (bank = 0; !ret && bank < GPIO_BANK_NUM; bank++) {
147*b476d716SJoseph Chen /*
148*b476d716SJoseph Chen * @name pattern can be:
149*b476d716SJoseph Chen * /pinctrl/gpio@fd8a0000 or gpio@fd8a0000
150*b476d716SJoseph Chen */
151*b476d716SJoseph Chen if (strstr(aliases_gpios[bank], name))
152*b476d716SJoseph Chen return bank;
153*b476d716SJoseph Chen }
154*b476d716SJoseph Chen
155*b476d716SJoseph Chen ret = init_order_gpios();
156*b476d716SJoseph Chen for (bank = 0; !ret && bank < GPIO_BANK_NUM; bank++) {
157*b476d716SJoseph Chen if (!strcmp(name, order_gpios[bank]))
158*b476d716SJoseph Chen return bank;
159*b476d716SJoseph Chen }
160*b476d716SJoseph Chen
161*b476d716SJoseph Chen return -ENOENT;
162*b476d716SJoseph Chen }
163*b476d716SJoseph Chen
__phandle_gpio_to_irq(u32 gpio_phandle,u32 offset)164269512fdSJoseph Chen static int __phandle_gpio_to_irq(u32 gpio_phandle, u32 offset)
1655db1153eSJoseph Chen {
1668db67737SJoseph Chen const void *blob = gd->fdt_blob;
1678db67737SJoseph Chen const char *gpio_name;
1688db67737SJoseph Chen int irq, node;
169*b476d716SJoseph Chen int bank;
1705db1153eSJoseph Chen
1718db67737SJoseph Chen node = fdt_node_offset_by_phandle(blob, gpio_phandle);
1725db1153eSJoseph Chen if (node < 0) {
1738db67737SJoseph Chen IRQ_E("No gpio node by phandle(0x%x), ret=%d\n", gpio_phandle, node);
1745db1153eSJoseph Chen return EINVAL_GPIO;
1755db1153eSJoseph Chen }
1765db1153eSJoseph Chen
1778db67737SJoseph Chen gpio_name = fdt_get_name(blob, node, NULL);
1788db67737SJoseph Chen if (!gpio_name)
1795db1153eSJoseph Chen return EINVAL_GPIO;
1805db1153eSJoseph Chen
181*b476d716SJoseph Chen bank = lookup_gpio_bank(gpio_name);
182*b476d716SJoseph Chen if (bank < 0) {
1838db67737SJoseph Chen IRQ_E("IRQ Framework can't find: %s\n", gpio_name);
1848db67737SJoseph Chen return EINVAL_GPIO;
1855db1153eSJoseph Chen }
1865db1153eSJoseph Chen
187269512fdSJoseph Chen IRQ_D("%s: gpio%d-%d\n", __func__, bank, offset);
1885db1153eSJoseph Chen
1898db67737SJoseph Chen irq = RK_IRQ_GPIO(bank, offset);
1908db67737SJoseph Chen if (!gpio_is_valid(irq))
1918db67737SJoseph Chen return EINVAL_GPIO;
1925db1153eSJoseph Chen
1938db67737SJoseph Chen return __hard_gpio_to_irq(irq);
1945db1153eSJoseph Chen }
1955db1153eSJoseph Chen
__irq_to_gpio(int irq)196269512fdSJoseph Chen static int __irq_to_gpio(int irq)
1974e6670feSJoseph Chen {
1984e6670feSJoseph Chen int bank, pin, idx;
1994e6670feSJoseph Chen
2004e6670feSJoseph Chen bank = (irq - PIN_BASE) / GPIO_BANK_PINS;
2014e6670feSJoseph Chen pin = (irq - PIN_BASE) % GPIO_BANK_PINS;
2024e6670feSJoseph Chen
2034e6670feSJoseph Chen for (idx = 0; idx < ARRAY_SIZE(gpio_banks); idx++) {
2044e6670feSJoseph Chen if (gpio_banks[idx].id == bank) {
2054e6670feSJoseph Chen return (bank << GPIO_BANK_OFFSET) |
2064e6670feSJoseph Chen (pin << GPIO_PIN_OFFSET);
2074e6670feSJoseph Chen }
2084e6670feSJoseph Chen }
2094e6670feSJoseph Chen
2104e6670feSJoseph Chen return -EINVAL;
2114e6670feSJoseph Chen }
2124e6670feSJoseph Chen
gpio_to_irq(struct gpio_desc * gpio)2134e6670feSJoseph Chen int gpio_to_irq(struct gpio_desc *gpio)
2144e6670feSJoseph Chen {
215dbcd1484SJoseph Chen int irq_gpio, bank, ret = EINVAL_GPIO;
216dbcd1484SJoseph Chen char *name, *name_tok;
217269512fdSJoseph Chen bool found;
2184e6670feSJoseph Chen
2194e6670feSJoseph Chen if (!gpio->dev->name) {
220269512fdSJoseph Chen IRQ_E("Can't find dev name for gpio bank\n");
2214e6670feSJoseph Chen return EINVAL_GPIO;
2224e6670feSJoseph Chen }
2234e6670feSJoseph Chen
224dbcd1484SJoseph Chen name_tok = strdup(gpio->dev->name);
225dbcd1484SJoseph Chen if (!name_tok) {
226269512fdSJoseph Chen IRQ_E("Strdup '%s' failed!\n", gpio->dev->name);
227dbcd1484SJoseph Chen return -ENOMEM;
228dbcd1484SJoseph Chen }
229dbcd1484SJoseph Chen
230dbcd1484SJoseph Chen name = strtok(name_tok, "@");
2314e6670feSJoseph Chen if (!name) {
232269512fdSJoseph Chen IRQ_E("Can't strtok '@' for '%s'\n", name_tok);
233dbcd1484SJoseph Chen goto out;
2344e6670feSJoseph Chen }
2354e6670feSJoseph Chen
2364e6670feSJoseph Chen for (bank = 0; bank < ARRAY_SIZE(gpio_banks); bank++) {
2374e6670feSJoseph Chen if (!strcmp(gpio_banks[bank].name, name)) {
2384e6670feSJoseph Chen found = true;
2394e6670feSJoseph Chen break;
2404e6670feSJoseph Chen }
2414e6670feSJoseph Chen }
2424e6670feSJoseph Chen
2434e6670feSJoseph Chen if (!found) {
244269512fdSJoseph Chen IRQ_E("GPIO irq framework can't find '%s'\n", name);
245dbcd1484SJoseph Chen goto out;
2464e6670feSJoseph Chen }
2474e6670feSJoseph Chen
2484e6670feSJoseph Chen irq_gpio = RK_IRQ_GPIO(bank, gpio->offset);
2494e6670feSJoseph Chen if (!gpio_is_valid(irq_gpio))
250dbcd1484SJoseph Chen goto out;
2514e6670feSJoseph Chen
252dbcd1484SJoseph Chen free(name_tok);
253269512fdSJoseph Chen return __hard_gpio_to_irq(irq_gpio);
254dbcd1484SJoseph Chen
255dbcd1484SJoseph Chen out:
256dbcd1484SJoseph Chen free(name_tok);
257dbcd1484SJoseph Chen return ret;
2584e6670feSJoseph Chen }
2594e6670feSJoseph Chen
hard_gpio_to_irq(u32 gpio)2604e6670feSJoseph Chen int hard_gpio_to_irq(u32 gpio)
2614e6670feSJoseph Chen {
2624e6670feSJoseph Chen if (!gpio_is_valid(gpio))
2634e6670feSJoseph Chen return EINVAL_GPIO;
2644e6670feSJoseph Chen
265269512fdSJoseph Chen return __hard_gpio_to_irq(gpio);
2664e6670feSJoseph Chen }
2674e6670feSJoseph Chen
phandle_gpio_to_irq(u32 gpio_phandle,u32 pin)2685db1153eSJoseph Chen int phandle_gpio_to_irq(u32 gpio_phandle, u32 pin)
2695db1153eSJoseph Chen {
2705db1153eSJoseph Chen if (gpio_phandle < 0)
2715db1153eSJoseph Chen return EINVAL_GPIO;
2725db1153eSJoseph Chen
273269512fdSJoseph Chen return __phandle_gpio_to_irq(gpio_phandle, pin);
2745db1153eSJoseph Chen }
2755db1153eSJoseph Chen
irq_to_gpio(int irq)2764e6670feSJoseph Chen int irq_to_gpio(int irq)
2774e6670feSJoseph Chen {
278269512fdSJoseph Chen return __irq_to_gpio(irq);
2794e6670feSJoseph Chen }
2804e6670feSJoseph Chen
gpio_id_to_bank(u32 id)2814e6670feSJoseph Chen struct gpio_bank *gpio_id_to_bank(u32 id)
2824e6670feSJoseph Chen {
2834e6670feSJoseph Chen int idx;
2844e6670feSJoseph Chen
2854e6670feSJoseph Chen for (idx = 0; idx < ARRAY_SIZE(gpio_banks); idx++) {
2864e6670feSJoseph Chen if (gpio_banks[idx].id == id)
2874e6670feSJoseph Chen return &gpio_banks[idx];
2884e6670feSJoseph Chen }
2894e6670feSJoseph Chen
2904e6670feSJoseph Chen return NULL;
2914e6670feSJoseph Chen }
2924e6670feSJoseph Chen
gpio_to_bank(u32 gpio)2934e6670feSJoseph Chen struct gpio_bank *gpio_to_bank(u32 gpio)
2944e6670feSJoseph Chen {
2954e6670feSJoseph Chen int id;
2964e6670feSJoseph Chen
2974e6670feSJoseph Chen if (!gpio_is_valid(gpio))
2984e6670feSJoseph Chen return NULL;
2994e6670feSJoseph Chen
3004e6670feSJoseph Chen id = (gpio & GPIO_BANK_MASK) >> GPIO_BANK_OFFSET;
3014e6670feSJoseph Chen
3024e6670feSJoseph Chen return gpio_id_to_bank(id);
3034e6670feSJoseph Chen }
304