18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TI DaVinci GPIO Support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2006-2007 David Brownell 68c2ecf20Sopenharmony_ci * Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/irq.h> 168c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/of.h> 198c2ecf20Sopenharmony_ci#include <linux/of_device.h> 208c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_data/gpio-davinci.h> 238c2ecf20Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 248c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <asm-generic/gpio.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define MAX_REGS_BANKS 5 298c2ecf20Sopenharmony_ci#define MAX_INT_PER_BANK 32 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct davinci_gpio_regs { 328c2ecf20Sopenharmony_ci u32 dir; 338c2ecf20Sopenharmony_ci u32 out_data; 348c2ecf20Sopenharmony_ci u32 set_data; 358c2ecf20Sopenharmony_ci u32 clr_data; 368c2ecf20Sopenharmony_ci u32 in_data; 378c2ecf20Sopenharmony_ci u32 set_rising; 388c2ecf20Sopenharmony_ci u32 clr_rising; 398c2ecf20Sopenharmony_ci u32 set_falling; 408c2ecf20Sopenharmony_ci u32 clr_falling; 418c2ecf20Sopenharmony_ci u32 intstat; 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_citypedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void __iomem *gpio_base; 498c2ecf20Sopenharmony_cistatic unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct davinci_gpio_irq_data { 528c2ecf20Sopenharmony_ci void __iomem *regs; 538c2ecf20Sopenharmony_ci struct davinci_gpio_controller *chip; 548c2ecf20Sopenharmony_ci int bank_num; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct davinci_gpio_controller { 588c2ecf20Sopenharmony_ci struct gpio_chip chip; 598c2ecf20Sopenharmony_ci struct irq_domain *irq_domain; 608c2ecf20Sopenharmony_ci /* Serialize access to GPIO registers */ 618c2ecf20Sopenharmony_ci spinlock_t lock; 628c2ecf20Sopenharmony_ci void __iomem *regs[MAX_REGS_BANKS]; 638c2ecf20Sopenharmony_ci int gpio_unbanked; 648c2ecf20Sopenharmony_ci int irqs[MAX_INT_PER_BANK]; 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic inline u32 __gpio_mask(unsigned gpio) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci return 1 << (gpio % 32); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci g = (__force struct davinci_gpio_regs __iomem *)irq_data_get_irq_chip_data(d); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return g; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int davinci_gpio_irq_setup(struct platform_device *pdev); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------*/ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* board setup code *MUST* setup pinmux and enable the GPIO clock. */ 868c2ecf20Sopenharmony_cistatic inline int __davinci_direction(struct gpio_chip *chip, 878c2ecf20Sopenharmony_ci unsigned offset, bool out, int value) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct davinci_gpio_controller *d = gpiochip_get_data(chip); 908c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g; 918c2ecf20Sopenharmony_ci unsigned long flags; 928c2ecf20Sopenharmony_ci u32 temp; 938c2ecf20Sopenharmony_ci int bank = offset / 32; 948c2ecf20Sopenharmony_ci u32 mask = __gpio_mask(offset); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci g = d->regs[bank]; 978c2ecf20Sopenharmony_ci spin_lock_irqsave(&d->lock, flags); 988c2ecf20Sopenharmony_ci temp = readl_relaxed(&g->dir); 998c2ecf20Sopenharmony_ci if (out) { 1008c2ecf20Sopenharmony_ci temp &= ~mask; 1018c2ecf20Sopenharmony_ci writel_relaxed(mask, value ? &g->set_data : &g->clr_data); 1028c2ecf20Sopenharmony_ci } else { 1038c2ecf20Sopenharmony_ci temp |= mask; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci writel_relaxed(temp, &g->dir); 1068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&d->lock, flags); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int davinci_direction_in(struct gpio_chip *chip, unsigned offset) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return __davinci_direction(chip, offset, false, 0); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int 1178c2ecf20Sopenharmony_cidavinci_direction_out(struct gpio_chip *chip, unsigned offset, int value) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return __davinci_direction(chip, offset, true, value); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* 1238c2ecf20Sopenharmony_ci * Read the pin's value (works even if it's set up as output); 1248c2ecf20Sopenharmony_ci * returns zero/nonzero. 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * Note that changes are synched to the GPIO clock, so reading values back 1278c2ecf20Sopenharmony_ci * right after you've set them may give old values. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_cistatic int davinci_gpio_get(struct gpio_chip *chip, unsigned offset) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct davinci_gpio_controller *d = gpiochip_get_data(chip); 1328c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g; 1338c2ecf20Sopenharmony_ci int bank = offset / 32; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci g = d->regs[bank]; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return !!(__gpio_mask(offset) & readl_relaxed(&g->in_data)); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* 1418c2ecf20Sopenharmony_ci * Assuming the pin is muxed as a gpio output, set its output value. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic void 1448c2ecf20Sopenharmony_cidavinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct davinci_gpio_controller *d = gpiochip_get_data(chip); 1478c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g; 1488c2ecf20Sopenharmony_ci int bank = offset / 32; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci g = d->regs[bank]; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci writel_relaxed(__gpio_mask(offset), 1538c2ecf20Sopenharmony_ci value ? &g->set_data : &g->clr_data); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic struct davinci_gpio_platform_data * 1578c2ecf20Sopenharmony_cidavinci_gpio_get_pdata(struct platform_device *pdev) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct device_node *dn = pdev->dev.of_node; 1608c2ecf20Sopenharmony_ci struct davinci_gpio_platform_data *pdata; 1618c2ecf20Sopenharmony_ci int ret; 1628c2ecf20Sopenharmony_ci u32 val; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) 1658c2ecf20Sopenharmony_ci return dev_get_platdata(&pdev->dev); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 1688c2ecf20Sopenharmony_ci if (!pdata) 1698c2ecf20Sopenharmony_ci return NULL; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci ret = of_property_read_u32(dn, "ti,ngpio", &val); 1728c2ecf20Sopenharmony_ci if (ret) 1738c2ecf20Sopenharmony_ci goto of_err; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci pdata->ngpio = val; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ret = of_property_read_u32(dn, "ti,davinci-gpio-unbanked", &val); 1788c2ecf20Sopenharmony_ci if (ret) 1798c2ecf20Sopenharmony_ci goto of_err; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci pdata->gpio_unbanked = val; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return pdata; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ciof_err: 1868c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Populating pdata from DT failed: err %d\n", ret); 1878c2ecf20Sopenharmony_ci return NULL; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int davinci_gpio_probe(struct platform_device *pdev) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci int bank, i, ret = 0; 1938c2ecf20Sopenharmony_ci unsigned int ngpio, nbank, nirq; 1948c2ecf20Sopenharmony_ci struct davinci_gpio_controller *chips; 1958c2ecf20Sopenharmony_ci struct davinci_gpio_platform_data *pdata; 1968c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci pdata = davinci_gpio_get_pdata(pdev); 1998c2ecf20Sopenharmony_ci if (!pdata) { 2008c2ecf20Sopenharmony_ci dev_err(dev, "No platform data found\n"); 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci dev->platform_data = pdata; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * The gpio banks conceptually expose a segmented bitmap, 2088c2ecf20Sopenharmony_ci * and "ngpio" is one more than the largest zero-based 2098c2ecf20Sopenharmony_ci * bit index that's valid. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci ngpio = pdata->ngpio; 2128c2ecf20Sopenharmony_ci if (ngpio == 0) { 2138c2ecf20Sopenharmony_ci dev_err(dev, "How many GPIOs?\n"); 2148c2ecf20Sopenharmony_ci return -EINVAL; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (WARN_ON(ARCH_NR_GPIOS < ngpio)) 2188c2ecf20Sopenharmony_ci ngpio = ARCH_NR_GPIOS; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * If there are unbanked interrupts then the number of 2228c2ecf20Sopenharmony_ci * interrupts is equal to number of gpios else all are banked so 2238c2ecf20Sopenharmony_ci * number of interrupts is equal to number of banks(each with 16 gpios) 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci if (pdata->gpio_unbanked) 2268c2ecf20Sopenharmony_ci nirq = pdata->gpio_unbanked; 2278c2ecf20Sopenharmony_ci else 2288c2ecf20Sopenharmony_ci nirq = DIV_ROUND_UP(ngpio, 16); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci chips = devm_kzalloc(dev, sizeof(*chips), GFP_KERNEL); 2318c2ecf20Sopenharmony_ci if (!chips) 2328c2ecf20Sopenharmony_ci return -ENOMEM; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci gpio_base = devm_platform_ioremap_resource(pdev, 0); 2358c2ecf20Sopenharmony_ci if (IS_ERR(gpio_base)) 2368c2ecf20Sopenharmony_ci return PTR_ERR(gpio_base); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci for (i = 0; i < nirq; i++) { 2398c2ecf20Sopenharmony_ci chips->irqs[i] = platform_get_irq(pdev, i); 2408c2ecf20Sopenharmony_ci if (chips->irqs[i] < 0) 2418c2ecf20Sopenharmony_ci return dev_err_probe(dev, chips->irqs[i], "IRQ not populated\n"); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci chips->chip.label = dev_name(dev); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci chips->chip.direction_input = davinci_direction_in; 2478c2ecf20Sopenharmony_ci chips->chip.get = davinci_gpio_get; 2488c2ecf20Sopenharmony_ci chips->chip.direction_output = davinci_direction_out; 2498c2ecf20Sopenharmony_ci chips->chip.set = davinci_gpio_set; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci chips->chip.ngpio = ngpio; 2528c2ecf20Sopenharmony_ci chips->chip.base = pdata->no_auto_base ? pdata->base : -1; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_GPIO 2558c2ecf20Sopenharmony_ci chips->chip.of_gpio_n_cells = 2; 2568c2ecf20Sopenharmony_ci chips->chip.parent = dev; 2578c2ecf20Sopenharmony_ci chips->chip.of_node = dev->of_node; 2588c2ecf20Sopenharmony_ci chips->chip.request = gpiochip_generic_request; 2598c2ecf20Sopenharmony_ci chips->chip.free = gpiochip_generic_free; 2608c2ecf20Sopenharmony_ci#endif 2618c2ecf20Sopenharmony_ci spin_lock_init(&chips->lock); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci nbank = DIV_ROUND_UP(ngpio, 32); 2648c2ecf20Sopenharmony_ci for (bank = 0; bank < nbank; bank++) 2658c2ecf20Sopenharmony_ci chips->regs[bank] = gpio_base + offset_array[bank]; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci ret = devm_gpiochip_add_data(dev, &chips->chip, chips); 2688c2ecf20Sopenharmony_ci if (ret) 2698c2ecf20Sopenharmony_ci return ret; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, chips); 2728c2ecf20Sopenharmony_ci ret = davinci_gpio_irq_setup(pdev); 2738c2ecf20Sopenharmony_ci if (ret) 2748c2ecf20Sopenharmony_ci return ret; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------*/ 2808c2ecf20Sopenharmony_ci/* 2818c2ecf20Sopenharmony_ci * We expect irqs will normally be set up as input pins, but they can also be 2828c2ecf20Sopenharmony_ci * used as output pins ... which is convenient for testing. 2838c2ecf20Sopenharmony_ci * 2848c2ecf20Sopenharmony_ci * NOTE: The first few GPIOs also have direct INTC hookups in addition 2858c2ecf20Sopenharmony_ci * to their GPIOBNK0 irq, with a bit less overhead. 2868c2ecf20Sopenharmony_ci * 2878c2ecf20Sopenharmony_ci * All those INTC hookups (direct, plus several IRQ banks) can also 2888c2ecf20Sopenharmony_ci * serve as EDMA event triggers. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void gpio_irq_disable(struct irq_data *d) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g = irq2regs(d); 2948c2ecf20Sopenharmony_ci uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci writel_relaxed(mask, &g->clr_falling); 2978c2ecf20Sopenharmony_ci writel_relaxed(mask, &g->clr_rising); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic void gpio_irq_enable(struct irq_data *d) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g = irq2regs(d); 3038c2ecf20Sopenharmony_ci uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d); 3048c2ecf20Sopenharmony_ci unsigned status = irqd_get_trigger_type(d); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; 3078c2ecf20Sopenharmony_ci if (!status) 3088c2ecf20Sopenharmony_ci status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (status & IRQ_TYPE_EDGE_FALLING) 3118c2ecf20Sopenharmony_ci writel_relaxed(mask, &g->set_falling); 3128c2ecf20Sopenharmony_ci if (status & IRQ_TYPE_EDGE_RISING) 3138c2ecf20Sopenharmony_ci writel_relaxed(mask, &g->set_rising); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int gpio_irq_type(struct irq_data *d, unsigned trigger) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) 3198c2ecf20Sopenharmony_ci return -EINVAL; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic struct irq_chip gpio_irqchip = { 3258c2ecf20Sopenharmony_ci .name = "GPIO", 3268c2ecf20Sopenharmony_ci .irq_enable = gpio_irq_enable, 3278c2ecf20Sopenharmony_ci .irq_disable = gpio_irq_disable, 3288c2ecf20Sopenharmony_ci .irq_set_type = gpio_irq_type, 3298c2ecf20Sopenharmony_ci .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE, 3308c2ecf20Sopenharmony_ci}; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic void gpio_irq_handler(struct irq_desc *desc) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g; 3358c2ecf20Sopenharmony_ci u32 mask = 0xffff; 3368c2ecf20Sopenharmony_ci int bank_num; 3378c2ecf20Sopenharmony_ci struct davinci_gpio_controller *d; 3388c2ecf20Sopenharmony_ci struct davinci_gpio_irq_data *irqdata; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci irqdata = (struct davinci_gpio_irq_data *)irq_desc_get_handler_data(desc); 3418c2ecf20Sopenharmony_ci bank_num = irqdata->bank_num; 3428c2ecf20Sopenharmony_ci g = irqdata->regs; 3438c2ecf20Sopenharmony_ci d = irqdata->chip; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* we only care about one bank */ 3468c2ecf20Sopenharmony_ci if ((bank_num % 2) == 1) 3478c2ecf20Sopenharmony_ci mask <<= 16; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* temporarily mask (level sensitive) parent IRQ */ 3508c2ecf20Sopenharmony_ci chained_irq_enter(irq_desc_get_chip(desc), desc); 3518c2ecf20Sopenharmony_ci while (1) { 3528c2ecf20Sopenharmony_ci u32 status; 3538c2ecf20Sopenharmony_ci int bit; 3548c2ecf20Sopenharmony_ci irq_hw_number_t hw_irq; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* ack any irqs */ 3578c2ecf20Sopenharmony_ci status = readl_relaxed(&g->intstat) & mask; 3588c2ecf20Sopenharmony_ci if (!status) 3598c2ecf20Sopenharmony_ci break; 3608c2ecf20Sopenharmony_ci writel_relaxed(status, &g->intstat); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* now demux them to the right lowlevel handler */ 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci while (status) { 3658c2ecf20Sopenharmony_ci bit = __ffs(status); 3668c2ecf20Sopenharmony_ci status &= ~BIT(bit); 3678c2ecf20Sopenharmony_ci /* Max number of gpios per controller is 144 so 3688c2ecf20Sopenharmony_ci * hw_irq will be in [0..143] 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_ci hw_irq = (bank_num / 2) * 32 + bit; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci generic_handle_irq( 3738c2ecf20Sopenharmony_ci irq_find_mapping(d->irq_domain, hw_irq)); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci chained_irq_exit(irq_desc_get_chip(desc), desc); 3778c2ecf20Sopenharmony_ci /* now it may re-trigger */ 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct davinci_gpio_controller *d = gpiochip_get_data(chip); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (d->irq_domain) 3858c2ecf20Sopenharmony_ci return irq_create_mapping(d->irq_domain, offset); 3868c2ecf20Sopenharmony_ci else 3878c2ecf20Sopenharmony_ci return -ENXIO; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct davinci_gpio_controller *d = gpiochip_get_data(chip); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* 3958c2ecf20Sopenharmony_ci * NOTE: we assume for now that only irqs in the first gpio_chip 3968c2ecf20Sopenharmony_ci * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs). 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci if (offset < d->gpio_unbanked) 3998c2ecf20Sopenharmony_ci return d->irqs[offset]; 4008c2ecf20Sopenharmony_ci else 4018c2ecf20Sopenharmony_ci return -ENODEV; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct davinci_gpio_controller *d; 4078c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g; 4088c2ecf20Sopenharmony_ci u32 mask, i; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data); 4118c2ecf20Sopenharmony_ci g = (struct davinci_gpio_regs __iomem *)d->regs[0]; 4128c2ecf20Sopenharmony_ci for (i = 0; i < MAX_INT_PER_BANK; i++) 4138c2ecf20Sopenharmony_ci if (data->irq == d->irqs[i]) 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (i == MAX_INT_PER_BANK) 4178c2ecf20Sopenharmony_ci return -EINVAL; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci mask = __gpio_mask(i); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) 4228c2ecf20Sopenharmony_ci return -EINVAL; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_FALLING) 4258c2ecf20Sopenharmony_ci ? &g->set_falling : &g->clr_falling); 4268c2ecf20Sopenharmony_ci writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_RISING) 4278c2ecf20Sopenharmony_ci ? &g->set_rising : &g->clr_rising); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic int 4338c2ecf20Sopenharmony_cidavinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, 4348c2ecf20Sopenharmony_ci irq_hw_number_t hw) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct davinci_gpio_controller *chips = 4378c2ecf20Sopenharmony_ci (struct davinci_gpio_controller *)d->host_data; 4388c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g = chips->regs[hw / 32]; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq, 4418c2ecf20Sopenharmony_ci "davinci_gpio"); 4428c2ecf20Sopenharmony_ci irq_set_irq_type(irq, IRQ_TYPE_NONE); 4438c2ecf20Sopenharmony_ci irq_set_chip_data(irq, (__force void *)g); 4448c2ecf20Sopenharmony_ci irq_set_handler_data(irq, (void *)(uintptr_t)__gpio_mask(hw)); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic const struct irq_domain_ops davinci_gpio_irq_ops = { 4508c2ecf20Sopenharmony_ci .map = davinci_gpio_irq_map, 4518c2ecf20Sopenharmony_ci .xlate = irq_domain_xlate_onetwocell, 4528c2ecf20Sopenharmony_ci}; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci static struct irq_chip_type gpio_unbanked; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci gpio_unbanked = *irq_data_get_chip_type(irq_get_irq_data(irq)); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return &gpio_unbanked.chip; 4618c2ecf20Sopenharmony_ci}; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic struct irq_chip *keystone_gpio_get_irq_chip(unsigned int irq) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci static struct irq_chip gpio_unbanked; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci gpio_unbanked = *irq_get_chip(irq); 4688c2ecf20Sopenharmony_ci return &gpio_unbanked; 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic const struct of_device_id davinci_gpio_ids[]; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/* 4748c2ecf20Sopenharmony_ci * NOTE: for suspend/resume, probably best to make a platform_device with 4758c2ecf20Sopenharmony_ci * suspend_late/resume_resume calls hooking into results of the set_wake() 4768c2ecf20Sopenharmony_ci * calls ... so if no gpios are wakeup events the clock can be disabled, 4778c2ecf20Sopenharmony_ci * with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0 4788c2ecf20Sopenharmony_ci * (dm6446) can be set appropriately for GPIOV33 pins. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int davinci_gpio_irq_setup(struct platform_device *pdev) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci unsigned gpio, bank; 4848c2ecf20Sopenharmony_ci int irq; 4858c2ecf20Sopenharmony_ci int ret; 4868c2ecf20Sopenharmony_ci struct clk *clk; 4878c2ecf20Sopenharmony_ci u32 binten = 0; 4888c2ecf20Sopenharmony_ci unsigned ngpio; 4898c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4908c2ecf20Sopenharmony_ci struct davinci_gpio_controller *chips = platform_get_drvdata(pdev); 4918c2ecf20Sopenharmony_ci struct davinci_gpio_platform_data *pdata = dev->platform_data; 4928c2ecf20Sopenharmony_ci struct davinci_gpio_regs __iomem *g; 4938c2ecf20Sopenharmony_ci struct irq_domain *irq_domain = NULL; 4948c2ecf20Sopenharmony_ci const struct of_device_id *match; 4958c2ecf20Sopenharmony_ci struct irq_chip *irq_chip; 4968c2ecf20Sopenharmony_ci struct davinci_gpio_irq_data *irqdata; 4978c2ecf20Sopenharmony_ci gpio_get_irq_chip_cb_t gpio_get_irq_chip; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* 5008c2ecf20Sopenharmony_ci * Use davinci_gpio_get_irq_chip by default to handle non DT cases 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci gpio_get_irq_chip = davinci_gpio_get_irq_chip; 5038c2ecf20Sopenharmony_ci match = of_match_device(of_match_ptr(davinci_gpio_ids), 5048c2ecf20Sopenharmony_ci dev); 5058c2ecf20Sopenharmony_ci if (match) 5068c2ecf20Sopenharmony_ci gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci ngpio = pdata->ngpio; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci clk = devm_clk_get(dev, "gpio"); 5118c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 5128c2ecf20Sopenharmony_ci dev_err(dev, "Error %ld getting gpio clock\n", PTR_ERR(clk)); 5138c2ecf20Sopenharmony_ci return PTR_ERR(clk); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci ret = clk_prepare_enable(clk); 5178c2ecf20Sopenharmony_ci if (ret) 5188c2ecf20Sopenharmony_ci return ret; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (!pdata->gpio_unbanked) { 5218c2ecf20Sopenharmony_ci irq = devm_irq_alloc_descs(dev, -1, 0, ngpio, 0); 5228c2ecf20Sopenharmony_ci if (irq < 0) { 5238c2ecf20Sopenharmony_ci dev_err(dev, "Couldn't allocate IRQ numbers\n"); 5248c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 5258c2ecf20Sopenharmony_ci return irq; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci irq_domain = irq_domain_add_legacy(dev->of_node, ngpio, irq, 0, 5298c2ecf20Sopenharmony_ci &davinci_gpio_irq_ops, 5308c2ecf20Sopenharmony_ci chips); 5318c2ecf20Sopenharmony_ci if (!irq_domain) { 5328c2ecf20Sopenharmony_ci dev_err(dev, "Couldn't register an IRQ domain\n"); 5338c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 5348c2ecf20Sopenharmony_ci return -ENODEV; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* 5398c2ecf20Sopenharmony_ci * Arrange gpio_to_irq() support, handling either direct IRQs or 5408c2ecf20Sopenharmony_ci * banked IRQs. Having GPIOs in the first GPIO bank use direct 5418c2ecf20Sopenharmony_ci * IRQs, while the others use banked IRQs, would need some setup 5428c2ecf20Sopenharmony_ci * tweaks to recognize hardware which can do that. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_ci chips->chip.to_irq = gpio_to_irq_banked; 5458c2ecf20Sopenharmony_ci chips->irq_domain = irq_domain; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* 5488c2ecf20Sopenharmony_ci * AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO 5498c2ecf20Sopenharmony_ci * controller only handling trigger modes. We currently assume no 5508c2ecf20Sopenharmony_ci * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_ci if (pdata->gpio_unbanked) { 5538c2ecf20Sopenharmony_ci /* pass "bank 0" GPIO IRQs to AINTC */ 5548c2ecf20Sopenharmony_ci chips->chip.to_irq = gpio_to_irq_unbanked; 5558c2ecf20Sopenharmony_ci chips->gpio_unbanked = pdata->gpio_unbanked; 5568c2ecf20Sopenharmony_ci binten = GENMASK(pdata->gpio_unbanked / 16, 0); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* AINTC handles mask/unmask; GPIO handles triggering */ 5598c2ecf20Sopenharmony_ci irq = chips->irqs[0]; 5608c2ecf20Sopenharmony_ci irq_chip = gpio_get_irq_chip(irq); 5618c2ecf20Sopenharmony_ci irq_chip->name = "GPIO-AINTC"; 5628c2ecf20Sopenharmony_ci irq_chip->irq_set_type = gpio_irq_type_unbanked; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* default trigger: both edges */ 5658c2ecf20Sopenharmony_ci g = chips->regs[0]; 5668c2ecf20Sopenharmony_ci writel_relaxed(~0, &g->set_falling); 5678c2ecf20Sopenharmony_ci writel_relaxed(~0, &g->set_rising); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* set the direct IRQs up to use that irqchip */ 5708c2ecf20Sopenharmony_ci for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++) { 5718c2ecf20Sopenharmony_ci irq_set_chip(chips->irqs[gpio], irq_chip); 5728c2ecf20Sopenharmony_ci irq_set_handler_data(chips->irqs[gpio], chips); 5738c2ecf20Sopenharmony_ci irq_set_status_flags(chips->irqs[gpio], 5748c2ecf20Sopenharmony_ci IRQ_TYPE_EDGE_BOTH); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci goto done; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* 5818c2ecf20Sopenharmony_ci * Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we 5828c2ecf20Sopenharmony_ci * then chain through our own handler. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ci for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 16) { 5858c2ecf20Sopenharmony_ci /* disabled by default, enabled only as needed 5868c2ecf20Sopenharmony_ci * There are register sets for 32 GPIOs. 2 banks of 16 5878c2ecf20Sopenharmony_ci * GPIOs are covered by each set of registers hence divide by 2 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci g = chips->regs[bank / 2]; 5908c2ecf20Sopenharmony_ci writel_relaxed(~0, &g->clr_falling); 5918c2ecf20Sopenharmony_ci writel_relaxed(~0, &g->clr_rising); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* 5948c2ecf20Sopenharmony_ci * Each chip handles 32 gpios, and each irq bank consists of 16 5958c2ecf20Sopenharmony_ci * gpio irqs. Pass the irq bank's corresponding controller to 5968c2ecf20Sopenharmony_ci * the chained irq handler. 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_ci irqdata = devm_kzalloc(&pdev->dev, 5998c2ecf20Sopenharmony_ci sizeof(struct 6008c2ecf20Sopenharmony_ci davinci_gpio_irq_data), 6018c2ecf20Sopenharmony_ci GFP_KERNEL); 6028c2ecf20Sopenharmony_ci if (!irqdata) { 6038c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 6048c2ecf20Sopenharmony_ci return -ENOMEM; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci irqdata->regs = g; 6088c2ecf20Sopenharmony_ci irqdata->bank_num = bank; 6098c2ecf20Sopenharmony_ci irqdata->chip = chips; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(chips->irqs[bank], 6128c2ecf20Sopenharmony_ci gpio_irq_handler, irqdata); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci binten |= BIT(bank); 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cidone: 6188c2ecf20Sopenharmony_ci /* 6198c2ecf20Sopenharmony_ci * BINTEN -- per-bank interrupt enable. genirq would also let these 6208c2ecf20Sopenharmony_ci * bits be set/cleared dynamically. 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_ci writel_relaxed(binten, gpio_base + BINTEN); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic const struct of_device_id davinci_gpio_ids[] = { 6288c2ecf20Sopenharmony_ci { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip}, 6298c2ecf20Sopenharmony_ci { .compatible = "ti,am654-gpio", keystone_gpio_get_irq_chip}, 6308c2ecf20Sopenharmony_ci { .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip}, 6318c2ecf20Sopenharmony_ci { /* sentinel */ }, 6328c2ecf20Sopenharmony_ci}; 6338c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, davinci_gpio_ids); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic struct platform_driver davinci_gpio_driver = { 6368c2ecf20Sopenharmony_ci .probe = davinci_gpio_probe, 6378c2ecf20Sopenharmony_ci .driver = { 6388c2ecf20Sopenharmony_ci .name = "davinci_gpio", 6398c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(davinci_gpio_ids), 6408c2ecf20Sopenharmony_ci }, 6418c2ecf20Sopenharmony_ci}; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/** 6448c2ecf20Sopenharmony_ci * GPIO driver registration needs to be done before machine_init functions 6458c2ecf20Sopenharmony_ci * access GPIO. Hence davinci_gpio_drv_reg() is a postcore_initcall. 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_cistatic int __init davinci_gpio_drv_reg(void) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci return platform_driver_register(&davinci_gpio_driver); 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_cipostcore_initcall(davinci_gpio_drv_reg); 652