18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/plat-pxa/gpio.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Generic PXA GPIO handling 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Nicolas Pitre 88c2ecf20Sopenharmony_ci * Created: Jun 15, 2001 98c2ecf20Sopenharmony_ci * Copyright: MontaVista Software Inc. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 158c2ecf20Sopenharmony_ci#include <linux/gpio-pxa.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/irq.h> 198c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 208c2ecf20Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/of_device.h> 248c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 258c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 268c2ecf20Sopenharmony_ci#include <linux/syscore_ops.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with 318c2ecf20Sopenharmony_ci * one set of registers. The register offsets are organized below: 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * GPLR GPDR GPSR GPCR GRER GFER GEDR 348c2ecf20Sopenharmony_ci * BANK 0 - 0x0000 0x000C 0x0018 0x0024 0x0030 0x003C 0x0048 358c2ecf20Sopenharmony_ci * BANK 1 - 0x0004 0x0010 0x001C 0x0028 0x0034 0x0040 0x004C 368c2ecf20Sopenharmony_ci * BANK 2 - 0x0008 0x0014 0x0020 0x002C 0x0038 0x0044 0x0050 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * BANK 3 - 0x0100 0x010C 0x0118 0x0124 0x0130 0x013C 0x0148 398c2ecf20Sopenharmony_ci * BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C 408c2ecf20Sopenharmony_ci * BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * BANK 6 - 0x0200 0x020C 0x0218 0x0224 0x0230 0x023C 0x0248 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * NOTE: 458c2ecf20Sopenharmony_ci * BANK 3 is only available on PXA27x and later processors. 468c2ecf20Sopenharmony_ci * BANK 4 and 5 are only available on PXA935, PXA1928 478c2ecf20Sopenharmony_ci * BANK 6 is only available on PXA1928 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define GPLR_OFFSET 0x00 518c2ecf20Sopenharmony_ci#define GPDR_OFFSET 0x0C 528c2ecf20Sopenharmony_ci#define GPSR_OFFSET 0x18 538c2ecf20Sopenharmony_ci#define GPCR_OFFSET 0x24 548c2ecf20Sopenharmony_ci#define GRER_OFFSET 0x30 558c2ecf20Sopenharmony_ci#define GFER_OFFSET 0x3C 568c2ecf20Sopenharmony_ci#define GEDR_OFFSET 0x48 578c2ecf20Sopenharmony_ci#define GAFR_OFFSET 0x54 588c2ecf20Sopenharmony_ci#define ED_MASK_OFFSET 0x9C /* GPIO edge detection for AP side */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define BANK_OFF(n) (((n) / 3) << 8) + (((n) % 3) << 2) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciint pxa_last_gpio; 638c2ecf20Sopenharmony_cistatic int irq_base; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct pxa_gpio_bank { 668c2ecf20Sopenharmony_ci void __iomem *regbase; 678c2ecf20Sopenharmony_ci unsigned long irq_mask; 688c2ecf20Sopenharmony_ci unsigned long irq_edge_rise; 698c2ecf20Sopenharmony_ci unsigned long irq_edge_fall; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 728c2ecf20Sopenharmony_ci unsigned long saved_gplr; 738c2ecf20Sopenharmony_ci unsigned long saved_gpdr; 748c2ecf20Sopenharmony_ci unsigned long saved_grer; 758c2ecf20Sopenharmony_ci unsigned long saved_gfer; 768c2ecf20Sopenharmony_ci#endif 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct pxa_gpio_chip { 808c2ecf20Sopenharmony_ci struct device *dev; 818c2ecf20Sopenharmony_ci struct gpio_chip chip; 828c2ecf20Sopenharmony_ci struct pxa_gpio_bank *banks; 838c2ecf20Sopenharmony_ci struct irq_domain *irqdomain; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci int irq0; 868c2ecf20Sopenharmony_ci int irq1; 878c2ecf20Sopenharmony_ci int (*set_wake)(unsigned int gpio, unsigned int on); 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cienum pxa_gpio_type { 918c2ecf20Sopenharmony_ci PXA25X_GPIO = 0, 928c2ecf20Sopenharmony_ci PXA26X_GPIO, 938c2ecf20Sopenharmony_ci PXA27X_GPIO, 948c2ecf20Sopenharmony_ci PXA3XX_GPIO, 958c2ecf20Sopenharmony_ci PXA93X_GPIO, 968c2ecf20Sopenharmony_ci MMP_GPIO = 0x10, 978c2ecf20Sopenharmony_ci MMP2_GPIO, 988c2ecf20Sopenharmony_ci PXA1928_GPIO, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct pxa_gpio_id { 1028c2ecf20Sopenharmony_ci enum pxa_gpio_type type; 1038c2ecf20Sopenharmony_ci int gpio_nums; 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(gpio_lock); 1078c2ecf20Sopenharmony_cistatic struct pxa_gpio_chip *pxa_gpio_chip; 1088c2ecf20Sopenharmony_cistatic enum pxa_gpio_type gpio_type; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic struct pxa_gpio_id pxa25x_id = { 1118c2ecf20Sopenharmony_ci .type = PXA25X_GPIO, 1128c2ecf20Sopenharmony_ci .gpio_nums = 85, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic struct pxa_gpio_id pxa26x_id = { 1168c2ecf20Sopenharmony_ci .type = PXA26X_GPIO, 1178c2ecf20Sopenharmony_ci .gpio_nums = 90, 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic struct pxa_gpio_id pxa27x_id = { 1218c2ecf20Sopenharmony_ci .type = PXA27X_GPIO, 1228c2ecf20Sopenharmony_ci .gpio_nums = 121, 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic struct pxa_gpio_id pxa3xx_id = { 1268c2ecf20Sopenharmony_ci .type = PXA3XX_GPIO, 1278c2ecf20Sopenharmony_ci .gpio_nums = 128, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic struct pxa_gpio_id pxa93x_id = { 1318c2ecf20Sopenharmony_ci .type = PXA93X_GPIO, 1328c2ecf20Sopenharmony_ci .gpio_nums = 192, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct pxa_gpio_id mmp_id = { 1368c2ecf20Sopenharmony_ci .type = MMP_GPIO, 1378c2ecf20Sopenharmony_ci .gpio_nums = 128, 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic struct pxa_gpio_id mmp2_id = { 1418c2ecf20Sopenharmony_ci .type = MMP2_GPIO, 1428c2ecf20Sopenharmony_ci .gpio_nums = 192, 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic struct pxa_gpio_id pxa1928_id = { 1468c2ecf20Sopenharmony_ci .type = PXA1928_GPIO, 1478c2ecf20Sopenharmony_ci .gpio_nums = 224, 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define for_each_gpio_bank(i, b, pc) \ 1518c2ecf20Sopenharmony_ci for (i = 0, b = pc->banks; i <= pxa_last_gpio; i += 32, b++) 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic inline struct pxa_gpio_chip *chip_to_pxachip(struct gpio_chip *c) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pxa_chip = gpiochip_get_data(c); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return pxa_chip; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic inline void __iomem *gpio_bank_base(struct gpio_chip *c, int gpio) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct pxa_gpio_chip *p = gpiochip_get_data(c); 1638c2ecf20Sopenharmony_ci struct pxa_gpio_bank *bank = p->banks + (gpio / 32); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return bank->regbase; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c, 1698c2ecf20Sopenharmony_ci unsigned gpio) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci return chip_to_pxachip(c)->banks + gpio / 32; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic inline int gpio_is_pxa_type(int type) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci return (type & MMP_GPIO) == 0; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic inline int gpio_is_mmp_type(int type) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci return (type & MMP_GPIO) != 0; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* GPIO86/87/88/89 on PXA26x have their direction bits in PXA_GPDR(2 inverted, 1858c2ecf20Sopenharmony_ci * as well as their Alternate Function value being '1' for GPIO in GAFRx. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_cistatic inline int __gpio_is_inverted(int gpio) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci if ((gpio_type == PXA26X_GPIO) && (gpio > 85)) 1908c2ecf20Sopenharmony_ci return 1; 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* 1958c2ecf20Sopenharmony_ci * On PXA25x and PXA27x, GAFRx and GPDRx together decide the alternate 1968c2ecf20Sopenharmony_ci * function of a GPIO, and GPDRx cannot be altered once configured. It 1978c2ecf20Sopenharmony_ci * is attributed as "occupied" here (I know this terminology isn't 1988c2ecf20Sopenharmony_ci * accurate, you are welcome to propose a better one :-) 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistatic inline int __gpio_is_occupied(struct pxa_gpio_chip *pchip, unsigned gpio) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci void __iomem *base; 2038c2ecf20Sopenharmony_ci unsigned long gafr = 0, gpdr = 0; 2048c2ecf20Sopenharmony_ci int ret, af = 0, dir = 0; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci base = gpio_bank_base(&pchip->chip, gpio); 2078c2ecf20Sopenharmony_ci gpdr = readl_relaxed(base + GPDR_OFFSET); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci switch (gpio_type) { 2108c2ecf20Sopenharmony_ci case PXA25X_GPIO: 2118c2ecf20Sopenharmony_ci case PXA26X_GPIO: 2128c2ecf20Sopenharmony_ci case PXA27X_GPIO: 2138c2ecf20Sopenharmony_ci gafr = readl_relaxed(base + GAFR_OFFSET); 2148c2ecf20Sopenharmony_ci af = (gafr >> ((gpio & 0xf) * 2)) & 0x3; 2158c2ecf20Sopenharmony_ci dir = gpdr & GPIO_bit(gpio); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (__gpio_is_inverted(gpio)) 2188c2ecf20Sopenharmony_ci ret = (af != 1) || (dir == 0); 2198c2ecf20Sopenharmony_ci else 2208c2ecf20Sopenharmony_ci ret = (af != 0) || (dir != 0); 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci default: 2238c2ecf20Sopenharmony_ci ret = gpdr & GPIO_bit(gpio); 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciint pxa_irq_to_gpio(int irq) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = pxa_gpio_chip; 2328c2ecf20Sopenharmony_ci int irq_gpio0; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci irq_gpio0 = irq_find_mapping(pchip->irqdomain, 0); 2358c2ecf20Sopenharmony_ci if (irq_gpio0 > 0) 2368c2ecf20Sopenharmony_ci return irq - irq_gpio0; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return irq_gpio0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic bool pxa_gpio_has_pinctrl(void) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci switch (gpio_type) { 2448c2ecf20Sopenharmony_ci case PXA3XX_GPIO: 2458c2ecf20Sopenharmony_ci case MMP2_GPIO: 2468c2ecf20Sopenharmony_ci case MMP_GPIO: 2478c2ecf20Sopenharmony_ci return false; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci default: 2508c2ecf20Sopenharmony_ci return true; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = chip_to_pxachip(chip); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return irq_find_mapping(pchip->irqdomain, offset); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci void __iomem *base = gpio_bank_base(chip, offset); 2648c2ecf20Sopenharmony_ci uint32_t value, mask = GPIO_bit(offset); 2658c2ecf20Sopenharmony_ci unsigned long flags; 2668c2ecf20Sopenharmony_ci int ret; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (pxa_gpio_has_pinctrl()) { 2698c2ecf20Sopenharmony_ci ret = pinctrl_gpio_direction_input(chip->base + offset); 2708c2ecf20Sopenharmony_ci if (ret) 2718c2ecf20Sopenharmony_ci return ret; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci spin_lock_irqsave(&gpio_lock, flags); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci value = readl_relaxed(base + GPDR_OFFSET); 2778c2ecf20Sopenharmony_ci if (__gpio_is_inverted(chip->base + offset)) 2788c2ecf20Sopenharmony_ci value |= mask; 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci value &= ~mask; 2818c2ecf20Sopenharmony_ci writel_relaxed(value, base + GPDR_OFFSET); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gpio_lock, flags); 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int pxa_gpio_direction_output(struct gpio_chip *chip, 2888c2ecf20Sopenharmony_ci unsigned offset, int value) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci void __iomem *base = gpio_bank_base(chip, offset); 2918c2ecf20Sopenharmony_ci uint32_t tmp, mask = GPIO_bit(offset); 2928c2ecf20Sopenharmony_ci unsigned long flags; 2938c2ecf20Sopenharmony_ci int ret; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (pxa_gpio_has_pinctrl()) { 2988c2ecf20Sopenharmony_ci ret = pinctrl_gpio_direction_output(chip->base + offset); 2998c2ecf20Sopenharmony_ci if (ret) 3008c2ecf20Sopenharmony_ci return ret; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci spin_lock_irqsave(&gpio_lock, flags); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci tmp = readl_relaxed(base + GPDR_OFFSET); 3068c2ecf20Sopenharmony_ci if (__gpio_is_inverted(chip->base + offset)) 3078c2ecf20Sopenharmony_ci tmp &= ~mask; 3088c2ecf20Sopenharmony_ci else 3098c2ecf20Sopenharmony_ci tmp |= mask; 3108c2ecf20Sopenharmony_ci writel_relaxed(tmp, base + GPDR_OFFSET); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gpio_lock, flags); 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci void __iomem *base = gpio_bank_base(chip, offset); 3198c2ecf20Sopenharmony_ci u32 gplr = readl_relaxed(base + GPLR_OFFSET); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return !!(gplr & GPIO_bit(offset)); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci void __iomem *base = gpio_bank_base(chip, offset); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci writel_relaxed(GPIO_bit(offset), 3298c2ecf20Sopenharmony_ci base + (value ? GPSR_OFFSET : GPCR_OFFSET)); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_GPIO 3338c2ecf20Sopenharmony_cistatic int pxa_gpio_of_xlate(struct gpio_chip *gc, 3348c2ecf20Sopenharmony_ci const struct of_phandle_args *gpiospec, 3358c2ecf20Sopenharmony_ci u32 *flags) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci if (gpiospec->args[0] > pxa_last_gpio) 3388c2ecf20Sopenharmony_ci return -EINVAL; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (flags) 3418c2ecf20Sopenharmony_ci *flags = gpiospec->args[1]; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return gpiospec->args[0]; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci#endif 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, 3488c2ecf20Sopenharmony_ci struct device_node *np, void __iomem *regbase) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci int i, gpio, nbanks = DIV_ROUND_UP(ngpio, 32); 3518c2ecf20Sopenharmony_ci struct pxa_gpio_bank *bank; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci pchip->banks = devm_kcalloc(pchip->dev, nbanks, sizeof(*pchip->banks), 3548c2ecf20Sopenharmony_ci GFP_KERNEL); 3558c2ecf20Sopenharmony_ci if (!pchip->banks) 3568c2ecf20Sopenharmony_ci return -ENOMEM; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci pchip->chip.label = "gpio-pxa"; 3598c2ecf20Sopenharmony_ci pchip->chip.direction_input = pxa_gpio_direction_input; 3608c2ecf20Sopenharmony_ci pchip->chip.direction_output = pxa_gpio_direction_output; 3618c2ecf20Sopenharmony_ci pchip->chip.get = pxa_gpio_get; 3628c2ecf20Sopenharmony_ci pchip->chip.set = pxa_gpio_set; 3638c2ecf20Sopenharmony_ci pchip->chip.to_irq = pxa_gpio_to_irq; 3648c2ecf20Sopenharmony_ci pchip->chip.ngpio = ngpio; 3658c2ecf20Sopenharmony_ci pchip->chip.request = gpiochip_generic_request; 3668c2ecf20Sopenharmony_ci pchip->chip.free = gpiochip_generic_free; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_GPIO 3698c2ecf20Sopenharmony_ci pchip->chip.of_node = np; 3708c2ecf20Sopenharmony_ci pchip->chip.of_xlate = pxa_gpio_of_xlate; 3718c2ecf20Sopenharmony_ci pchip->chip.of_gpio_n_cells = 2; 3728c2ecf20Sopenharmony_ci#endif 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) { 3758c2ecf20Sopenharmony_ci bank = pchip->banks + i; 3768c2ecf20Sopenharmony_ci bank->regbase = regbase + BANK_OFF(i); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return gpiochip_add_data(&pchip->chip, pchip); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci/* Update only those GRERx and GFERx edge detection register bits if those 3838c2ecf20Sopenharmony_ci * bits are set in c->irq_mask 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_cistatic inline void update_edge_detect(struct pxa_gpio_bank *c) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci uint32_t grer, gfer; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci grer = readl_relaxed(c->regbase + GRER_OFFSET) & ~c->irq_mask; 3908c2ecf20Sopenharmony_ci gfer = readl_relaxed(c->regbase + GFER_OFFSET) & ~c->irq_mask; 3918c2ecf20Sopenharmony_ci grer |= c->irq_edge_rise & c->irq_mask; 3928c2ecf20Sopenharmony_ci gfer |= c->irq_edge_fall & c->irq_mask; 3938c2ecf20Sopenharmony_ci writel_relaxed(grer, c->regbase + GRER_OFFSET); 3948c2ecf20Sopenharmony_ci writel_relaxed(gfer, c->regbase + GFER_OFFSET); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 4008c2ecf20Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 4018c2ecf20Sopenharmony_ci struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio); 4028c2ecf20Sopenharmony_ci unsigned long gpdr, mask = GPIO_bit(gpio); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (type == IRQ_TYPE_PROBE) { 4058c2ecf20Sopenharmony_ci /* Don't mess with enabled GPIOs using preconfigured edges or 4068c2ecf20Sopenharmony_ci * GPIOs set to alternate function or to output during probe 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio)) 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (__gpio_is_occupied(pchip, gpio)) 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (__gpio_is_inverted(gpio)) 4208c2ecf20Sopenharmony_ci writel_relaxed(gpdr | mask, c->regbase + GPDR_OFFSET); 4218c2ecf20Sopenharmony_ci else 4228c2ecf20Sopenharmony_ci writel_relaxed(gpdr & ~mask, c->regbase + GPDR_OFFSET); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 4258c2ecf20Sopenharmony_ci c->irq_edge_rise |= mask; 4268c2ecf20Sopenharmony_ci else 4278c2ecf20Sopenharmony_ci c->irq_edge_rise &= ~mask; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) 4308c2ecf20Sopenharmony_ci c->irq_edge_fall |= mask; 4318c2ecf20Sopenharmony_ci else 4328c2ecf20Sopenharmony_ci c->irq_edge_fall &= ~mask; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci update_edge_detect(c); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio, 4378c2ecf20Sopenharmony_ci ((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""), 4388c2ecf20Sopenharmony_ci ((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : "")); 4398c2ecf20Sopenharmony_ci return 0; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic irqreturn_t pxa_gpio_demux_handler(int in_irq, void *d) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci int loop, gpio, n, handled = 0; 4458c2ecf20Sopenharmony_ci unsigned long gedr; 4468c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = d; 4478c2ecf20Sopenharmony_ci struct pxa_gpio_bank *c; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci do { 4508c2ecf20Sopenharmony_ci loop = 0; 4518c2ecf20Sopenharmony_ci for_each_gpio_bank(gpio, c, pchip) { 4528c2ecf20Sopenharmony_ci gedr = readl_relaxed(c->regbase + GEDR_OFFSET); 4538c2ecf20Sopenharmony_ci gedr = gedr & c->irq_mask; 4548c2ecf20Sopenharmony_ci writel_relaxed(gedr, c->regbase + GEDR_OFFSET); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci for_each_set_bit(n, &gedr, BITS_PER_LONG) { 4578c2ecf20Sopenharmony_ci loop = 1; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci generic_handle_irq( 4608c2ecf20Sopenharmony_ci irq_find_mapping(pchip->irqdomain, 4618c2ecf20Sopenharmony_ci gpio + n)); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci handled += loop; 4658c2ecf20Sopenharmony_ci } while (loop); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return handled ? IRQ_HANDLED : IRQ_NONE; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic irqreturn_t pxa_gpio_direct_handler(int in_irq, void *d) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = d; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (in_irq == pchip->irq0) { 4758c2ecf20Sopenharmony_ci generic_handle_irq(irq_find_mapping(pchip->irqdomain, 0)); 4768c2ecf20Sopenharmony_ci } else if (in_irq == pchip->irq1) { 4778c2ecf20Sopenharmony_ci generic_handle_irq(irq_find_mapping(pchip->irqdomain, 1)); 4788c2ecf20Sopenharmony_ci } else { 4798c2ecf20Sopenharmony_ci pr_err("%s() unknown irq %d\n", __func__, in_irq); 4808c2ecf20Sopenharmony_ci return IRQ_NONE; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic void pxa_ack_muxed_gpio(struct irq_data *d) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 4888c2ecf20Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 4898c2ecf20Sopenharmony_ci void __iomem *base = gpio_bank_base(&pchip->chip, gpio); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci writel_relaxed(GPIO_bit(gpio), base + GEDR_OFFSET); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic void pxa_mask_muxed_gpio(struct irq_data *d) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 4978c2ecf20Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 4988c2ecf20Sopenharmony_ci struct pxa_gpio_bank *b = gpio_to_pxabank(&pchip->chip, gpio); 4998c2ecf20Sopenharmony_ci void __iomem *base = gpio_bank_base(&pchip->chip, gpio); 5008c2ecf20Sopenharmony_ci uint32_t grer, gfer; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci b->irq_mask &= ~GPIO_bit(gpio); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci grer = readl_relaxed(base + GRER_OFFSET) & ~GPIO_bit(gpio); 5058c2ecf20Sopenharmony_ci gfer = readl_relaxed(base + GFER_OFFSET) & ~GPIO_bit(gpio); 5068c2ecf20Sopenharmony_ci writel_relaxed(grer, base + GRER_OFFSET); 5078c2ecf20Sopenharmony_ci writel_relaxed(gfer, base + GFER_OFFSET); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int pxa_gpio_set_wake(struct irq_data *d, unsigned int on) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 5138c2ecf20Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (pchip->set_wake) 5168c2ecf20Sopenharmony_ci return pchip->set_wake(gpio, on); 5178c2ecf20Sopenharmony_ci else 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic void pxa_unmask_muxed_gpio(struct irq_data *d) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 5248c2ecf20Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 5258c2ecf20Sopenharmony_ci struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci c->irq_mask |= GPIO_bit(gpio); 5288c2ecf20Sopenharmony_ci update_edge_detect(c); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic struct irq_chip pxa_muxed_gpio_chip = { 5328c2ecf20Sopenharmony_ci .name = "GPIO", 5338c2ecf20Sopenharmony_ci .irq_ack = pxa_ack_muxed_gpio, 5348c2ecf20Sopenharmony_ci .irq_mask = pxa_mask_muxed_gpio, 5358c2ecf20Sopenharmony_ci .irq_unmask = pxa_unmask_muxed_gpio, 5368c2ecf20Sopenharmony_ci .irq_set_type = pxa_gpio_irq_type, 5378c2ecf20Sopenharmony_ci .irq_set_wake = pxa_gpio_set_wake, 5388c2ecf20Sopenharmony_ci}; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int pxa_gpio_nums(struct platform_device *pdev) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci const struct platform_device_id *id = platform_get_device_id(pdev); 5438c2ecf20Sopenharmony_ci struct pxa_gpio_id *pxa_id = (struct pxa_gpio_id *)id->driver_data; 5448c2ecf20Sopenharmony_ci int count = 0; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci switch (pxa_id->type) { 5478c2ecf20Sopenharmony_ci case PXA25X_GPIO: 5488c2ecf20Sopenharmony_ci case PXA26X_GPIO: 5498c2ecf20Sopenharmony_ci case PXA27X_GPIO: 5508c2ecf20Sopenharmony_ci case PXA3XX_GPIO: 5518c2ecf20Sopenharmony_ci case PXA93X_GPIO: 5528c2ecf20Sopenharmony_ci case MMP_GPIO: 5538c2ecf20Sopenharmony_ci case MMP2_GPIO: 5548c2ecf20Sopenharmony_ci case PXA1928_GPIO: 5558c2ecf20Sopenharmony_ci gpio_type = pxa_id->type; 5568c2ecf20Sopenharmony_ci count = pxa_id->gpio_nums - 1; 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci default: 5598c2ecf20Sopenharmony_ci count = -EINVAL; 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci return count; 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq, 5668c2ecf20Sopenharmony_ci irq_hw_number_t hw) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, 5698c2ecf20Sopenharmony_ci handle_edge_irq); 5708c2ecf20Sopenharmony_ci irq_set_chip_data(irq, d->host_data); 5718c2ecf20Sopenharmony_ci irq_set_noprobe(irq); 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic const struct irq_domain_ops pxa_irq_domain_ops = { 5768c2ecf20Sopenharmony_ci .map = pxa_irq_domain_map, 5778c2ecf20Sopenharmony_ci .xlate = irq_domain_xlate_twocell, 5788c2ecf20Sopenharmony_ci}; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 5818c2ecf20Sopenharmony_cistatic const struct of_device_id pxa_gpio_dt_ids[] = { 5828c2ecf20Sopenharmony_ci { .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, }, 5838c2ecf20Sopenharmony_ci { .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, }, 5848c2ecf20Sopenharmony_ci { .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, }, 5858c2ecf20Sopenharmony_ci { .compatible = "intel,pxa3xx-gpio", .data = &pxa3xx_id, }, 5868c2ecf20Sopenharmony_ci { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, }, 5878c2ecf20Sopenharmony_ci { .compatible = "marvell,mmp-gpio", .data = &mmp_id, }, 5888c2ecf20Sopenharmony_ci { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, }, 5898c2ecf20Sopenharmony_ci { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, }, 5908c2ecf20Sopenharmony_ci {} 5918c2ecf20Sopenharmony_ci}; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int pxa_gpio_probe_dt(struct platform_device *pdev, 5948c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci int nr_gpios; 5978c2ecf20Sopenharmony_ci const struct pxa_gpio_id *gpio_id; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci gpio_id = of_device_get_match_data(&pdev->dev); 6008c2ecf20Sopenharmony_ci gpio_type = gpio_id->type; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci nr_gpios = gpio_id->gpio_nums; 6038c2ecf20Sopenharmony_ci pxa_last_gpio = nr_gpios - 1; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, nr_gpios, 0); 6068c2ecf20Sopenharmony_ci if (irq_base < 0) { 6078c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); 6088c2ecf20Sopenharmony_ci return irq_base; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci return irq_base; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci#else 6138c2ecf20Sopenharmony_ci#define pxa_gpio_probe_dt(pdev, pchip) (-1) 6148c2ecf20Sopenharmony_ci#endif 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic int pxa_gpio_probe(struct platform_device *pdev) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip; 6198c2ecf20Sopenharmony_ci struct pxa_gpio_bank *c; 6208c2ecf20Sopenharmony_ci struct clk *clk; 6218c2ecf20Sopenharmony_ci struct pxa_gpio_platform_data *info; 6228c2ecf20Sopenharmony_ci void __iomem *gpio_reg_base; 6238c2ecf20Sopenharmony_ci int gpio, ret; 6248c2ecf20Sopenharmony_ci int irq0 = 0, irq1 = 0, irq_mux; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL); 6278c2ecf20Sopenharmony_ci if (!pchip) 6288c2ecf20Sopenharmony_ci return -ENOMEM; 6298c2ecf20Sopenharmony_ci pchip->dev = &pdev->dev; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci info = dev_get_platdata(&pdev->dev); 6328c2ecf20Sopenharmony_ci if (info) { 6338c2ecf20Sopenharmony_ci irq_base = info->irq_base; 6348c2ecf20Sopenharmony_ci if (irq_base <= 0) 6358c2ecf20Sopenharmony_ci return -EINVAL; 6368c2ecf20Sopenharmony_ci pxa_last_gpio = pxa_gpio_nums(pdev); 6378c2ecf20Sopenharmony_ci pchip->set_wake = info->gpio_set_wake; 6388c2ecf20Sopenharmony_ci } else { 6398c2ecf20Sopenharmony_ci irq_base = pxa_gpio_probe_dt(pdev, pchip); 6408c2ecf20Sopenharmony_ci if (irq_base < 0) 6418c2ecf20Sopenharmony_ci return -EINVAL; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (!pxa_last_gpio) 6458c2ecf20Sopenharmony_ci return -EINVAL; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci pchip->irqdomain = irq_domain_add_legacy(pdev->dev.of_node, 6488c2ecf20Sopenharmony_ci pxa_last_gpio + 1, irq_base, 6498c2ecf20Sopenharmony_ci 0, &pxa_irq_domain_ops, pchip); 6508c2ecf20Sopenharmony_ci if (!pchip->irqdomain) 6518c2ecf20Sopenharmony_ci return -ENOMEM; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci irq0 = platform_get_irq_byname_optional(pdev, "gpio0"); 6548c2ecf20Sopenharmony_ci irq1 = platform_get_irq_byname_optional(pdev, "gpio1"); 6558c2ecf20Sopenharmony_ci irq_mux = platform_get_irq_byname(pdev, "gpio_mux"); 6568c2ecf20Sopenharmony_ci if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0) 6578c2ecf20Sopenharmony_ci || (irq_mux <= 0)) 6588c2ecf20Sopenharmony_ci return -EINVAL; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci pchip->irq0 = irq0; 6618c2ecf20Sopenharmony_ci pchip->irq1 = irq1; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci gpio_reg_base = devm_platform_ioremap_resource(pdev, 0); 6648c2ecf20Sopenharmony_ci if (IS_ERR(gpio_reg_base)) 6658c2ecf20Sopenharmony_ci return PTR_ERR(gpio_reg_base); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci clk = clk_get(&pdev->dev, NULL); 6688c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 6698c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error %ld to get gpio clock\n", 6708c2ecf20Sopenharmony_ci PTR_ERR(clk)); 6718c2ecf20Sopenharmony_ci return PTR_ERR(clk); 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci ret = clk_prepare_enable(clk); 6748c2ecf20Sopenharmony_ci if (ret) { 6758c2ecf20Sopenharmony_ci clk_put(clk); 6768c2ecf20Sopenharmony_ci return ret; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* Initialize GPIO chips */ 6808c2ecf20Sopenharmony_ci ret = pxa_init_gpio_chip(pchip, pxa_last_gpio + 1, pdev->dev.of_node, 6818c2ecf20Sopenharmony_ci gpio_reg_base); 6828c2ecf20Sopenharmony_ci if (ret) { 6838c2ecf20Sopenharmony_ci clk_put(clk); 6848c2ecf20Sopenharmony_ci return ret; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* clear all GPIO edge detects */ 6888c2ecf20Sopenharmony_ci for_each_gpio_bank(gpio, c, pchip) { 6898c2ecf20Sopenharmony_ci writel_relaxed(0, c->regbase + GFER_OFFSET); 6908c2ecf20Sopenharmony_ci writel_relaxed(0, c->regbase + GRER_OFFSET); 6918c2ecf20Sopenharmony_ci writel_relaxed(~0, c->regbase + GEDR_OFFSET); 6928c2ecf20Sopenharmony_ci /* unmask GPIO edge detect for AP side */ 6938c2ecf20Sopenharmony_ci if (gpio_is_mmp_type(gpio_type)) 6948c2ecf20Sopenharmony_ci writel_relaxed(~0, c->regbase + ED_MASK_OFFSET); 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (irq0 > 0) { 6988c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, 6998c2ecf20Sopenharmony_ci irq0, pxa_gpio_direct_handler, 0, 7008c2ecf20Sopenharmony_ci "gpio-0", pchip); 7018c2ecf20Sopenharmony_ci if (ret) 7028c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "request of gpio0 irq failed: %d\n", 7038c2ecf20Sopenharmony_ci ret); 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci if (irq1 > 0) { 7068c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, 7078c2ecf20Sopenharmony_ci irq1, pxa_gpio_direct_handler, 0, 7088c2ecf20Sopenharmony_ci "gpio-1", pchip); 7098c2ecf20Sopenharmony_ci if (ret) 7108c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "request of gpio1 irq failed: %d\n", 7118c2ecf20Sopenharmony_ci ret); 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, 7148c2ecf20Sopenharmony_ci irq_mux, pxa_gpio_demux_handler, 0, 7158c2ecf20Sopenharmony_ci "gpio-mux", pchip); 7168c2ecf20Sopenharmony_ci if (ret) 7178c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "request of gpio-mux irq failed: %d\n", 7188c2ecf20Sopenharmony_ci ret); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci pxa_gpio_chip = pchip; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci return 0; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic const struct platform_device_id gpio_id_table[] = { 7268c2ecf20Sopenharmony_ci { "pxa25x-gpio", (unsigned long)&pxa25x_id }, 7278c2ecf20Sopenharmony_ci { "pxa26x-gpio", (unsigned long)&pxa26x_id }, 7288c2ecf20Sopenharmony_ci { "pxa27x-gpio", (unsigned long)&pxa27x_id }, 7298c2ecf20Sopenharmony_ci { "pxa3xx-gpio", (unsigned long)&pxa3xx_id }, 7308c2ecf20Sopenharmony_ci { "pxa93x-gpio", (unsigned long)&pxa93x_id }, 7318c2ecf20Sopenharmony_ci { "mmp-gpio", (unsigned long)&mmp_id }, 7328c2ecf20Sopenharmony_ci { "mmp2-gpio", (unsigned long)&mmp2_id }, 7338c2ecf20Sopenharmony_ci { "pxa1928-gpio", (unsigned long)&pxa1928_id }, 7348c2ecf20Sopenharmony_ci { }, 7358c2ecf20Sopenharmony_ci}; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic struct platform_driver pxa_gpio_driver = { 7388c2ecf20Sopenharmony_ci .probe = pxa_gpio_probe, 7398c2ecf20Sopenharmony_ci .driver = { 7408c2ecf20Sopenharmony_ci .name = "pxa-gpio", 7418c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(pxa_gpio_dt_ids), 7428c2ecf20Sopenharmony_ci }, 7438c2ecf20Sopenharmony_ci .id_table = gpio_id_table, 7448c2ecf20Sopenharmony_ci}; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic int __init pxa_gpio_legacy_init(void) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci if (of_have_populated_dt()) 7498c2ecf20Sopenharmony_ci return 0; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return platform_driver_register(&pxa_gpio_driver); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_cipostcore_initcall(pxa_gpio_legacy_init); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic int __init pxa_gpio_dt_init(void) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci if (of_have_populated_dt()) 7588c2ecf20Sopenharmony_ci return platform_driver_register(&pxa_gpio_driver); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_cidevice_initcall(pxa_gpio_dt_init); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 7658c2ecf20Sopenharmony_cistatic int pxa_gpio_suspend(void) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = pxa_gpio_chip; 7688c2ecf20Sopenharmony_ci struct pxa_gpio_bank *c; 7698c2ecf20Sopenharmony_ci int gpio; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (!pchip) 7728c2ecf20Sopenharmony_ci return 0; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci for_each_gpio_bank(gpio, c, pchip) { 7758c2ecf20Sopenharmony_ci c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET); 7768c2ecf20Sopenharmony_ci c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); 7778c2ecf20Sopenharmony_ci c->saved_grer = readl_relaxed(c->regbase + GRER_OFFSET); 7788c2ecf20Sopenharmony_ci c->saved_gfer = readl_relaxed(c->regbase + GFER_OFFSET); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* Clear GPIO transition detect bits */ 7818c2ecf20Sopenharmony_ci writel_relaxed(0xffffffff, c->regbase + GEDR_OFFSET); 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci return 0; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic void pxa_gpio_resume(void) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct pxa_gpio_chip *pchip = pxa_gpio_chip; 7898c2ecf20Sopenharmony_ci struct pxa_gpio_bank *c; 7908c2ecf20Sopenharmony_ci int gpio; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (!pchip) 7938c2ecf20Sopenharmony_ci return; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci for_each_gpio_bank(gpio, c, pchip) { 7968c2ecf20Sopenharmony_ci /* restore level with set/clear */ 7978c2ecf20Sopenharmony_ci writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET); 7988c2ecf20Sopenharmony_ci writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci writel_relaxed(c->saved_grer, c->regbase + GRER_OFFSET); 8018c2ecf20Sopenharmony_ci writel_relaxed(c->saved_gfer, c->regbase + GFER_OFFSET); 8028c2ecf20Sopenharmony_ci writel_relaxed(c->saved_gpdr, c->regbase + GPDR_OFFSET); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci#else 8068c2ecf20Sopenharmony_ci#define pxa_gpio_suspend NULL 8078c2ecf20Sopenharmony_ci#define pxa_gpio_resume NULL 8088c2ecf20Sopenharmony_ci#endif 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic struct syscore_ops pxa_gpio_syscore_ops = { 8118c2ecf20Sopenharmony_ci .suspend = pxa_gpio_suspend, 8128c2ecf20Sopenharmony_ci .resume = pxa_gpio_resume, 8138c2ecf20Sopenharmony_ci}; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int __init pxa_gpio_sysinit(void) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci register_syscore_ops(&pxa_gpio_syscore_ops); 8188c2ecf20Sopenharmony_ci return 0; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_cipostcore_initcall(pxa_gpio_sysinit); 821