162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/plat-pxa/gpio.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Generic PXA GPIO handling 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Nicolas Pitre 862306a36Sopenharmony_ci * Created: Jun 15, 2001 962306a36Sopenharmony_ci * Copyright: MontaVista Software Inc. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/clk.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1562306a36Sopenharmony_ci#include <linux/gpio-pxa.h> 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/irq.h> 1962306a36Sopenharmony_ci#include <linux/irqdomain.h> 2062306a36Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 2162306a36Sopenharmony_ci#include <linux/io.h> 2262306a36Sopenharmony_ci#include <linux/of.h> 2362306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include <linux/syscore_ops.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with 3062306a36Sopenharmony_ci * one set of registers. The register offsets are organized below: 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * GPLR GPDR GPSR GPCR GRER GFER GEDR 3362306a36Sopenharmony_ci * BANK 0 - 0x0000 0x000C 0x0018 0x0024 0x0030 0x003C 0x0048 3462306a36Sopenharmony_ci * BANK 1 - 0x0004 0x0010 0x001C 0x0028 0x0034 0x0040 0x004C 3562306a36Sopenharmony_ci * BANK 2 - 0x0008 0x0014 0x0020 0x002C 0x0038 0x0044 0x0050 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * BANK 3 - 0x0100 0x010C 0x0118 0x0124 0x0130 0x013C 0x0148 3862306a36Sopenharmony_ci * BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C 3962306a36Sopenharmony_ci * BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * BANK 6 - 0x0200 0x020C 0x0218 0x0224 0x0230 0x023C 0x0248 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * NOTE: 4462306a36Sopenharmony_ci * BANK 3 is only available on PXA27x and later processors. 4562306a36Sopenharmony_ci * BANK 4 and 5 are only available on PXA935, PXA1928 4662306a36Sopenharmony_ci * BANK 6 is only available on PXA1928 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define GPLR_OFFSET 0x00 5062306a36Sopenharmony_ci#define GPDR_OFFSET 0x0C 5162306a36Sopenharmony_ci#define GPSR_OFFSET 0x18 5262306a36Sopenharmony_ci#define GPCR_OFFSET 0x24 5362306a36Sopenharmony_ci#define GRER_OFFSET 0x30 5462306a36Sopenharmony_ci#define GFER_OFFSET 0x3C 5562306a36Sopenharmony_ci#define GEDR_OFFSET 0x48 5662306a36Sopenharmony_ci#define GAFR_OFFSET 0x54 5762306a36Sopenharmony_ci#define ED_MASK_OFFSET 0x9C /* GPIO edge detection for AP side */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define BANK_OFF(n) (((n) / 3) << 8) + (((n) % 3) << 2) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciint pxa_last_gpio; 6262306a36Sopenharmony_cistatic int irq_base; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct pxa_gpio_bank { 6562306a36Sopenharmony_ci void __iomem *regbase; 6662306a36Sopenharmony_ci unsigned long irq_mask; 6762306a36Sopenharmony_ci unsigned long irq_edge_rise; 6862306a36Sopenharmony_ci unsigned long irq_edge_fall; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#ifdef CONFIG_PM 7162306a36Sopenharmony_ci unsigned long saved_gplr; 7262306a36Sopenharmony_ci unsigned long saved_gpdr; 7362306a36Sopenharmony_ci unsigned long saved_grer; 7462306a36Sopenharmony_ci unsigned long saved_gfer; 7562306a36Sopenharmony_ci#endif 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistruct pxa_gpio_chip { 7962306a36Sopenharmony_ci struct device *dev; 8062306a36Sopenharmony_ci struct gpio_chip chip; 8162306a36Sopenharmony_ci struct pxa_gpio_bank *banks; 8262306a36Sopenharmony_ci struct irq_domain *irqdomain; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci int irq0; 8562306a36Sopenharmony_ci int irq1; 8662306a36Sopenharmony_ci int (*set_wake)(unsigned int gpio, unsigned int on); 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cienum pxa_gpio_type { 9062306a36Sopenharmony_ci PXA25X_GPIO = 0, 9162306a36Sopenharmony_ci PXA26X_GPIO, 9262306a36Sopenharmony_ci PXA27X_GPIO, 9362306a36Sopenharmony_ci PXA3XX_GPIO, 9462306a36Sopenharmony_ci PXA93X_GPIO, 9562306a36Sopenharmony_ci MMP_GPIO = 0x10, 9662306a36Sopenharmony_ci MMP2_GPIO, 9762306a36Sopenharmony_ci PXA1928_GPIO, 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistruct pxa_gpio_id { 10162306a36Sopenharmony_ci enum pxa_gpio_type type; 10262306a36Sopenharmony_ci int gpio_nums; 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(gpio_lock); 10662306a36Sopenharmony_cistatic struct pxa_gpio_chip *pxa_gpio_chip; 10762306a36Sopenharmony_cistatic enum pxa_gpio_type gpio_type; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic struct pxa_gpio_id pxa25x_id = { 11062306a36Sopenharmony_ci .type = PXA25X_GPIO, 11162306a36Sopenharmony_ci .gpio_nums = 85, 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic struct pxa_gpio_id pxa26x_id = { 11562306a36Sopenharmony_ci .type = PXA26X_GPIO, 11662306a36Sopenharmony_ci .gpio_nums = 90, 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic struct pxa_gpio_id pxa27x_id = { 12062306a36Sopenharmony_ci .type = PXA27X_GPIO, 12162306a36Sopenharmony_ci .gpio_nums = 121, 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic struct pxa_gpio_id pxa3xx_id = { 12562306a36Sopenharmony_ci .type = PXA3XX_GPIO, 12662306a36Sopenharmony_ci .gpio_nums = 128, 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic struct pxa_gpio_id pxa93x_id = { 13062306a36Sopenharmony_ci .type = PXA93X_GPIO, 13162306a36Sopenharmony_ci .gpio_nums = 192, 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic struct pxa_gpio_id mmp_id = { 13562306a36Sopenharmony_ci .type = MMP_GPIO, 13662306a36Sopenharmony_ci .gpio_nums = 128, 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic struct pxa_gpio_id mmp2_id = { 14062306a36Sopenharmony_ci .type = MMP2_GPIO, 14162306a36Sopenharmony_ci .gpio_nums = 192, 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic struct pxa_gpio_id pxa1928_id = { 14562306a36Sopenharmony_ci .type = PXA1928_GPIO, 14662306a36Sopenharmony_ci .gpio_nums = 224, 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define for_each_gpio_bank(i, b, pc) \ 15062306a36Sopenharmony_ci for (i = 0, b = pc->banks; i <= pxa_last_gpio; i += 32, b++) 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic inline struct pxa_gpio_chip *chip_to_pxachip(struct gpio_chip *c) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct pxa_gpio_chip *pxa_chip = gpiochip_get_data(c); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return pxa_chip; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic inline void __iomem *gpio_bank_base(struct gpio_chip *c, int gpio) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct pxa_gpio_chip *p = gpiochip_get_data(c); 16262306a36Sopenharmony_ci struct pxa_gpio_bank *bank = p->banks + (gpio / 32); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return bank->regbase; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c, 16862306a36Sopenharmony_ci unsigned gpio) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci return chip_to_pxachip(c)->banks + gpio / 32; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic inline int gpio_is_mmp_type(int type) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci return (type & MMP_GPIO) != 0; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* GPIO86/87/88/89 on PXA26x have their direction bits in PXA_GPDR(2 inverted, 17962306a36Sopenharmony_ci * as well as their Alternate Function value being '1' for GPIO in GAFRx. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cistatic inline int __gpio_is_inverted(int gpio) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci if ((gpio_type == PXA26X_GPIO) && (gpio > 85)) 18462306a36Sopenharmony_ci return 1; 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* 18962306a36Sopenharmony_ci * On PXA25x and PXA27x, GAFRx and GPDRx together decide the alternate 19062306a36Sopenharmony_ci * function of a GPIO, and GPDRx cannot be altered once configured. It 19162306a36Sopenharmony_ci * is attributed as "occupied" here (I know this terminology isn't 19262306a36Sopenharmony_ci * accurate, you are welcome to propose a better one :-) 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_cistatic inline int __gpio_is_occupied(struct pxa_gpio_chip *pchip, unsigned gpio) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci void __iomem *base; 19762306a36Sopenharmony_ci unsigned long gafr = 0, gpdr = 0; 19862306a36Sopenharmony_ci int ret, af = 0, dir = 0; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci base = gpio_bank_base(&pchip->chip, gpio); 20162306a36Sopenharmony_ci gpdr = readl_relaxed(base + GPDR_OFFSET); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci switch (gpio_type) { 20462306a36Sopenharmony_ci case PXA25X_GPIO: 20562306a36Sopenharmony_ci case PXA26X_GPIO: 20662306a36Sopenharmony_ci case PXA27X_GPIO: 20762306a36Sopenharmony_ci gafr = readl_relaxed(base + GAFR_OFFSET); 20862306a36Sopenharmony_ci af = (gafr >> ((gpio & 0xf) * 2)) & 0x3; 20962306a36Sopenharmony_ci dir = gpdr & GPIO_bit(gpio); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (__gpio_is_inverted(gpio)) 21262306a36Sopenharmony_ci ret = (af != 1) || (dir == 0); 21362306a36Sopenharmony_ci else 21462306a36Sopenharmony_ci ret = (af != 0) || (dir != 0); 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci default: 21762306a36Sopenharmony_ci ret = gpdr & GPIO_bit(gpio); 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci return ret; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciint pxa_irq_to_gpio(int irq) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = pxa_gpio_chip; 22662306a36Sopenharmony_ci int irq_gpio0; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci irq_gpio0 = irq_find_mapping(pchip->irqdomain, 0); 22962306a36Sopenharmony_ci if (irq_gpio0 > 0) 23062306a36Sopenharmony_ci return irq - irq_gpio0; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return irq_gpio0; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic bool pxa_gpio_has_pinctrl(void) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci switch (gpio_type) { 23862306a36Sopenharmony_ci case PXA3XX_GPIO: 23962306a36Sopenharmony_ci case MMP2_GPIO: 24062306a36Sopenharmony_ci case MMP_GPIO: 24162306a36Sopenharmony_ci return false; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci default: 24462306a36Sopenharmony_ci return true; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = chip_to_pxachip(chip); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return irq_find_mapping(pchip->irqdomain, offset); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci void __iomem *base = gpio_bank_base(chip, offset); 25862306a36Sopenharmony_ci uint32_t value, mask = GPIO_bit(offset); 25962306a36Sopenharmony_ci unsigned long flags; 26062306a36Sopenharmony_ci int ret; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (pxa_gpio_has_pinctrl()) { 26362306a36Sopenharmony_ci ret = pinctrl_gpio_direction_input(chip->base + offset); 26462306a36Sopenharmony_ci if (ret) 26562306a36Sopenharmony_ci return ret; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci spin_lock_irqsave(&gpio_lock, flags); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci value = readl_relaxed(base + GPDR_OFFSET); 27162306a36Sopenharmony_ci if (__gpio_is_inverted(chip->base + offset)) 27262306a36Sopenharmony_ci value |= mask; 27362306a36Sopenharmony_ci else 27462306a36Sopenharmony_ci value &= ~mask; 27562306a36Sopenharmony_ci writel_relaxed(value, base + GPDR_OFFSET); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci spin_unlock_irqrestore(&gpio_lock, flags); 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic int pxa_gpio_direction_output(struct gpio_chip *chip, 28262306a36Sopenharmony_ci unsigned offset, int value) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci void __iomem *base = gpio_bank_base(chip, offset); 28562306a36Sopenharmony_ci uint32_t tmp, mask = GPIO_bit(offset); 28662306a36Sopenharmony_ci unsigned long flags; 28762306a36Sopenharmony_ci int ret; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (pxa_gpio_has_pinctrl()) { 29262306a36Sopenharmony_ci ret = pinctrl_gpio_direction_output(chip->base + offset); 29362306a36Sopenharmony_ci if (ret) 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci spin_lock_irqsave(&gpio_lock, flags); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci tmp = readl_relaxed(base + GPDR_OFFSET); 30062306a36Sopenharmony_ci if (__gpio_is_inverted(chip->base + offset)) 30162306a36Sopenharmony_ci tmp &= ~mask; 30262306a36Sopenharmony_ci else 30362306a36Sopenharmony_ci tmp |= mask; 30462306a36Sopenharmony_ci writel_relaxed(tmp, base + GPDR_OFFSET); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci spin_unlock_irqrestore(&gpio_lock, flags); 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci void __iomem *base = gpio_bank_base(chip, offset); 31362306a36Sopenharmony_ci u32 gplr = readl_relaxed(base + GPLR_OFFSET); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return !!(gplr & GPIO_bit(offset)); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci void __iomem *base = gpio_bank_base(chip, offset); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci writel_relaxed(GPIO_bit(offset), 32362306a36Sopenharmony_ci base + (value ? GPSR_OFFSET : GPCR_OFFSET)); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci#ifdef CONFIG_OF_GPIO 32762306a36Sopenharmony_cistatic int pxa_gpio_of_xlate(struct gpio_chip *gc, 32862306a36Sopenharmony_ci const struct of_phandle_args *gpiospec, 32962306a36Sopenharmony_ci u32 *flags) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci if (gpiospec->args[0] > pxa_last_gpio) 33262306a36Sopenharmony_ci return -EINVAL; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (flags) 33562306a36Sopenharmony_ci *flags = gpiospec->args[1]; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return gpiospec->args[0]; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci#endif 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, void __iomem *regbase) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci int i, gpio, nbanks = DIV_ROUND_UP(ngpio, 32); 34462306a36Sopenharmony_ci struct pxa_gpio_bank *bank; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci pchip->banks = devm_kcalloc(pchip->dev, nbanks, sizeof(*pchip->banks), 34762306a36Sopenharmony_ci GFP_KERNEL); 34862306a36Sopenharmony_ci if (!pchip->banks) 34962306a36Sopenharmony_ci return -ENOMEM; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci pchip->chip.parent = pchip->dev; 35262306a36Sopenharmony_ci pchip->chip.label = "gpio-pxa"; 35362306a36Sopenharmony_ci pchip->chip.direction_input = pxa_gpio_direction_input; 35462306a36Sopenharmony_ci pchip->chip.direction_output = pxa_gpio_direction_output; 35562306a36Sopenharmony_ci pchip->chip.get = pxa_gpio_get; 35662306a36Sopenharmony_ci pchip->chip.set = pxa_gpio_set; 35762306a36Sopenharmony_ci pchip->chip.to_irq = pxa_gpio_to_irq; 35862306a36Sopenharmony_ci pchip->chip.ngpio = ngpio; 35962306a36Sopenharmony_ci pchip->chip.request = gpiochip_generic_request; 36062306a36Sopenharmony_ci pchip->chip.free = gpiochip_generic_free; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci#ifdef CONFIG_OF_GPIO 36362306a36Sopenharmony_ci pchip->chip.of_xlate = pxa_gpio_of_xlate; 36462306a36Sopenharmony_ci pchip->chip.of_gpio_n_cells = 2; 36562306a36Sopenharmony_ci#endif 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) { 36862306a36Sopenharmony_ci bank = pchip->banks + i; 36962306a36Sopenharmony_ci bank->regbase = regbase + BANK_OFF(i); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return gpiochip_add_data(&pchip->chip, pchip); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci/* Update only those GRERx and GFERx edge detection register bits if those 37662306a36Sopenharmony_ci * bits are set in c->irq_mask 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_cistatic inline void update_edge_detect(struct pxa_gpio_bank *c) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci uint32_t grer, gfer; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci grer = readl_relaxed(c->regbase + GRER_OFFSET) & ~c->irq_mask; 38362306a36Sopenharmony_ci gfer = readl_relaxed(c->regbase + GFER_OFFSET) & ~c->irq_mask; 38462306a36Sopenharmony_ci grer |= c->irq_edge_rise & c->irq_mask; 38562306a36Sopenharmony_ci gfer |= c->irq_edge_fall & c->irq_mask; 38662306a36Sopenharmony_ci writel_relaxed(grer, c->regbase + GRER_OFFSET); 38762306a36Sopenharmony_ci writel_relaxed(gfer, c->regbase + GFER_OFFSET); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 39362306a36Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 39462306a36Sopenharmony_ci struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio); 39562306a36Sopenharmony_ci unsigned long gpdr, mask = GPIO_bit(gpio); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (type == IRQ_TYPE_PROBE) { 39862306a36Sopenharmony_ci /* Don't mess with enabled GPIOs using preconfigured edges or 39962306a36Sopenharmony_ci * GPIOs set to alternate function or to output during probe 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ci if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio)) 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (__gpio_is_occupied(pchip, gpio)) 40562306a36Sopenharmony_ci return 0; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (__gpio_is_inverted(gpio)) 41362306a36Sopenharmony_ci writel_relaxed(gpdr | mask, c->regbase + GPDR_OFFSET); 41462306a36Sopenharmony_ci else 41562306a36Sopenharmony_ci writel_relaxed(gpdr & ~mask, c->regbase + GPDR_OFFSET); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 41862306a36Sopenharmony_ci c->irq_edge_rise |= mask; 41962306a36Sopenharmony_ci else 42062306a36Sopenharmony_ci c->irq_edge_rise &= ~mask; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) 42362306a36Sopenharmony_ci c->irq_edge_fall |= mask; 42462306a36Sopenharmony_ci else 42562306a36Sopenharmony_ci c->irq_edge_fall &= ~mask; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci update_edge_detect(c); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio, 43062306a36Sopenharmony_ci ((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""), 43162306a36Sopenharmony_ci ((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : "")); 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic irqreturn_t pxa_gpio_demux_handler(int in_irq, void *d) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci int loop, gpio, n, handled = 0; 43862306a36Sopenharmony_ci unsigned long gedr; 43962306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = d; 44062306a36Sopenharmony_ci struct pxa_gpio_bank *c; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci do { 44362306a36Sopenharmony_ci loop = 0; 44462306a36Sopenharmony_ci for_each_gpio_bank(gpio, c, pchip) { 44562306a36Sopenharmony_ci gedr = readl_relaxed(c->regbase + GEDR_OFFSET); 44662306a36Sopenharmony_ci gedr = gedr & c->irq_mask; 44762306a36Sopenharmony_ci writel_relaxed(gedr, c->regbase + GEDR_OFFSET); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci for_each_set_bit(n, &gedr, BITS_PER_LONG) { 45062306a36Sopenharmony_ci loop = 1; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci generic_handle_domain_irq(pchip->irqdomain, 45362306a36Sopenharmony_ci gpio + n); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci handled += loop; 45762306a36Sopenharmony_ci } while (loop); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return handled ? IRQ_HANDLED : IRQ_NONE; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic irqreturn_t pxa_gpio_direct_handler(int in_irq, void *d) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = d; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (in_irq == pchip->irq0) { 46762306a36Sopenharmony_ci generic_handle_domain_irq(pchip->irqdomain, 0); 46862306a36Sopenharmony_ci } else if (in_irq == pchip->irq1) { 46962306a36Sopenharmony_ci generic_handle_domain_irq(pchip->irqdomain, 1); 47062306a36Sopenharmony_ci } else { 47162306a36Sopenharmony_ci pr_err("%s() unknown irq %d\n", __func__, in_irq); 47262306a36Sopenharmony_ci return IRQ_NONE; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci return IRQ_HANDLED; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic void pxa_ack_muxed_gpio(struct irq_data *d) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 48062306a36Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 48162306a36Sopenharmony_ci void __iomem *base = gpio_bank_base(&pchip->chip, gpio); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci writel_relaxed(GPIO_bit(gpio), base + GEDR_OFFSET); 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void pxa_mask_muxed_gpio(struct irq_data *d) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 48962306a36Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 49062306a36Sopenharmony_ci struct pxa_gpio_bank *b = gpio_to_pxabank(&pchip->chip, gpio); 49162306a36Sopenharmony_ci void __iomem *base = gpio_bank_base(&pchip->chip, gpio); 49262306a36Sopenharmony_ci uint32_t grer, gfer; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci b->irq_mask &= ~GPIO_bit(gpio); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci grer = readl_relaxed(base + GRER_OFFSET) & ~GPIO_bit(gpio); 49762306a36Sopenharmony_ci gfer = readl_relaxed(base + GFER_OFFSET) & ~GPIO_bit(gpio); 49862306a36Sopenharmony_ci writel_relaxed(grer, base + GRER_OFFSET); 49962306a36Sopenharmony_ci writel_relaxed(gfer, base + GFER_OFFSET); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic int pxa_gpio_set_wake(struct irq_data *d, unsigned int on) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 50562306a36Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (pchip->set_wake) 50862306a36Sopenharmony_ci return pchip->set_wake(gpio, on); 50962306a36Sopenharmony_ci else 51062306a36Sopenharmony_ci return 0; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic void pxa_unmask_muxed_gpio(struct irq_data *d) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d); 51662306a36Sopenharmony_ci unsigned int gpio = irqd_to_hwirq(d); 51762306a36Sopenharmony_ci struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci c->irq_mask |= GPIO_bit(gpio); 52062306a36Sopenharmony_ci update_edge_detect(c); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic struct irq_chip pxa_muxed_gpio_chip = { 52462306a36Sopenharmony_ci .name = "GPIO", 52562306a36Sopenharmony_ci .irq_ack = pxa_ack_muxed_gpio, 52662306a36Sopenharmony_ci .irq_mask = pxa_mask_muxed_gpio, 52762306a36Sopenharmony_ci .irq_unmask = pxa_unmask_muxed_gpio, 52862306a36Sopenharmony_ci .irq_set_type = pxa_gpio_irq_type, 52962306a36Sopenharmony_ci .irq_set_wake = pxa_gpio_set_wake, 53062306a36Sopenharmony_ci}; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int pxa_gpio_nums(struct platform_device *pdev) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci const struct platform_device_id *id = platform_get_device_id(pdev); 53562306a36Sopenharmony_ci struct pxa_gpio_id *pxa_id = (struct pxa_gpio_id *)id->driver_data; 53662306a36Sopenharmony_ci int count = 0; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci switch (pxa_id->type) { 53962306a36Sopenharmony_ci case PXA25X_GPIO: 54062306a36Sopenharmony_ci case PXA26X_GPIO: 54162306a36Sopenharmony_ci case PXA27X_GPIO: 54262306a36Sopenharmony_ci case PXA3XX_GPIO: 54362306a36Sopenharmony_ci case PXA93X_GPIO: 54462306a36Sopenharmony_ci case MMP_GPIO: 54562306a36Sopenharmony_ci case MMP2_GPIO: 54662306a36Sopenharmony_ci case PXA1928_GPIO: 54762306a36Sopenharmony_ci gpio_type = pxa_id->type; 54862306a36Sopenharmony_ci count = pxa_id->gpio_nums - 1; 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci default: 55162306a36Sopenharmony_ci count = -EINVAL; 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci return count; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq, 55862306a36Sopenharmony_ci irq_hw_number_t hw) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, 56162306a36Sopenharmony_ci handle_edge_irq); 56262306a36Sopenharmony_ci irq_set_chip_data(irq, d->host_data); 56362306a36Sopenharmony_ci irq_set_noprobe(irq); 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic const struct irq_domain_ops pxa_irq_domain_ops = { 56862306a36Sopenharmony_ci .map = pxa_irq_domain_map, 56962306a36Sopenharmony_ci .xlate = irq_domain_xlate_twocell, 57062306a36Sopenharmony_ci}; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci#ifdef CONFIG_OF 57362306a36Sopenharmony_cistatic const struct of_device_id pxa_gpio_dt_ids[] = { 57462306a36Sopenharmony_ci { .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, }, 57562306a36Sopenharmony_ci { .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, }, 57662306a36Sopenharmony_ci { .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, }, 57762306a36Sopenharmony_ci { .compatible = "intel,pxa3xx-gpio", .data = &pxa3xx_id, }, 57862306a36Sopenharmony_ci { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, }, 57962306a36Sopenharmony_ci { .compatible = "marvell,mmp-gpio", .data = &mmp_id, }, 58062306a36Sopenharmony_ci { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, }, 58162306a36Sopenharmony_ci { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, }, 58262306a36Sopenharmony_ci {} 58362306a36Sopenharmony_ci}; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int pxa_gpio_probe_dt(struct platform_device *pdev, 58662306a36Sopenharmony_ci struct pxa_gpio_chip *pchip) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci int nr_gpios; 58962306a36Sopenharmony_ci const struct pxa_gpio_id *gpio_id; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci gpio_id = of_device_get_match_data(&pdev->dev); 59262306a36Sopenharmony_ci gpio_type = gpio_id->type; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci nr_gpios = gpio_id->gpio_nums; 59562306a36Sopenharmony_ci pxa_last_gpio = nr_gpios - 1; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, nr_gpios, 0); 59862306a36Sopenharmony_ci if (irq_base < 0) { 59962306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); 60062306a36Sopenharmony_ci return irq_base; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci return irq_base; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci#else 60562306a36Sopenharmony_ci#define pxa_gpio_probe_dt(pdev, pchip) (-1) 60662306a36Sopenharmony_ci#endif 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic int pxa_gpio_probe(struct platform_device *pdev) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct pxa_gpio_chip *pchip; 61162306a36Sopenharmony_ci struct pxa_gpio_bank *c; 61262306a36Sopenharmony_ci struct clk *clk; 61362306a36Sopenharmony_ci struct pxa_gpio_platform_data *info; 61462306a36Sopenharmony_ci void __iomem *gpio_reg_base; 61562306a36Sopenharmony_ci int gpio, ret; 61662306a36Sopenharmony_ci int irq0 = 0, irq1 = 0, irq_mux; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL); 61962306a36Sopenharmony_ci if (!pchip) 62062306a36Sopenharmony_ci return -ENOMEM; 62162306a36Sopenharmony_ci pchip->dev = &pdev->dev; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci info = dev_get_platdata(&pdev->dev); 62462306a36Sopenharmony_ci if (info) { 62562306a36Sopenharmony_ci irq_base = info->irq_base; 62662306a36Sopenharmony_ci if (irq_base <= 0) 62762306a36Sopenharmony_ci return -EINVAL; 62862306a36Sopenharmony_ci pxa_last_gpio = pxa_gpio_nums(pdev); 62962306a36Sopenharmony_ci pchip->set_wake = info->gpio_set_wake; 63062306a36Sopenharmony_ci } else { 63162306a36Sopenharmony_ci irq_base = pxa_gpio_probe_dt(pdev, pchip); 63262306a36Sopenharmony_ci if (irq_base < 0) 63362306a36Sopenharmony_ci return -EINVAL; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (!pxa_last_gpio) 63762306a36Sopenharmony_ci return -EINVAL; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci pchip->irqdomain = irq_domain_add_legacy(pdev->dev.of_node, 64062306a36Sopenharmony_ci pxa_last_gpio + 1, irq_base, 64162306a36Sopenharmony_ci 0, &pxa_irq_domain_ops, pchip); 64262306a36Sopenharmony_ci if (!pchip->irqdomain) 64362306a36Sopenharmony_ci return -ENOMEM; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci irq0 = platform_get_irq_byname_optional(pdev, "gpio0"); 64662306a36Sopenharmony_ci irq1 = platform_get_irq_byname_optional(pdev, "gpio1"); 64762306a36Sopenharmony_ci irq_mux = platform_get_irq_byname(pdev, "gpio_mux"); 64862306a36Sopenharmony_ci if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0) 64962306a36Sopenharmony_ci || (irq_mux <= 0)) 65062306a36Sopenharmony_ci return -EINVAL; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci pchip->irq0 = irq0; 65362306a36Sopenharmony_ci pchip->irq1 = irq1; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci gpio_reg_base = devm_platform_ioremap_resource(pdev, 0); 65662306a36Sopenharmony_ci if (IS_ERR(gpio_reg_base)) 65762306a36Sopenharmony_ci return PTR_ERR(gpio_reg_base); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci clk = devm_clk_get_enabled(&pdev->dev, NULL); 66062306a36Sopenharmony_ci if (IS_ERR(clk)) { 66162306a36Sopenharmony_ci dev_err(&pdev->dev, "Error %ld to get gpio clock\n", 66262306a36Sopenharmony_ci PTR_ERR(clk)); 66362306a36Sopenharmony_ci return PTR_ERR(clk); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* Initialize GPIO chips */ 66762306a36Sopenharmony_ci ret = pxa_init_gpio_chip(pchip, pxa_last_gpio + 1, gpio_reg_base); 66862306a36Sopenharmony_ci if (ret) 66962306a36Sopenharmony_ci return ret; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* clear all GPIO edge detects */ 67262306a36Sopenharmony_ci for_each_gpio_bank(gpio, c, pchip) { 67362306a36Sopenharmony_ci writel_relaxed(0, c->regbase + GFER_OFFSET); 67462306a36Sopenharmony_ci writel_relaxed(0, c->regbase + GRER_OFFSET); 67562306a36Sopenharmony_ci writel_relaxed(~0, c->regbase + GEDR_OFFSET); 67662306a36Sopenharmony_ci /* unmask GPIO edge detect for AP side */ 67762306a36Sopenharmony_ci if (gpio_is_mmp_type(gpio_type)) 67862306a36Sopenharmony_ci writel_relaxed(~0, c->regbase + ED_MASK_OFFSET); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (irq0 > 0) { 68262306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, 68362306a36Sopenharmony_ci irq0, pxa_gpio_direct_handler, 0, 68462306a36Sopenharmony_ci "gpio-0", pchip); 68562306a36Sopenharmony_ci if (ret) 68662306a36Sopenharmony_ci dev_err(&pdev->dev, "request of gpio0 irq failed: %d\n", 68762306a36Sopenharmony_ci ret); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci if (irq1 > 0) { 69062306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, 69162306a36Sopenharmony_ci irq1, pxa_gpio_direct_handler, 0, 69262306a36Sopenharmony_ci "gpio-1", pchip); 69362306a36Sopenharmony_ci if (ret) 69462306a36Sopenharmony_ci dev_err(&pdev->dev, "request of gpio1 irq failed: %d\n", 69562306a36Sopenharmony_ci ret); 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, 69862306a36Sopenharmony_ci irq_mux, pxa_gpio_demux_handler, 0, 69962306a36Sopenharmony_ci "gpio-mux", pchip); 70062306a36Sopenharmony_ci if (ret) 70162306a36Sopenharmony_ci dev_err(&pdev->dev, "request of gpio-mux irq failed: %d\n", 70262306a36Sopenharmony_ci ret); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci pxa_gpio_chip = pchip; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return 0; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic const struct platform_device_id gpio_id_table[] = { 71062306a36Sopenharmony_ci { "pxa25x-gpio", (unsigned long)&pxa25x_id }, 71162306a36Sopenharmony_ci { "pxa26x-gpio", (unsigned long)&pxa26x_id }, 71262306a36Sopenharmony_ci { "pxa27x-gpio", (unsigned long)&pxa27x_id }, 71362306a36Sopenharmony_ci { "pxa3xx-gpio", (unsigned long)&pxa3xx_id }, 71462306a36Sopenharmony_ci { "pxa93x-gpio", (unsigned long)&pxa93x_id }, 71562306a36Sopenharmony_ci { "mmp-gpio", (unsigned long)&mmp_id }, 71662306a36Sopenharmony_ci { "mmp2-gpio", (unsigned long)&mmp2_id }, 71762306a36Sopenharmony_ci { "pxa1928-gpio", (unsigned long)&pxa1928_id }, 71862306a36Sopenharmony_ci { }, 71962306a36Sopenharmony_ci}; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic struct platform_driver pxa_gpio_driver = { 72262306a36Sopenharmony_ci .probe = pxa_gpio_probe, 72362306a36Sopenharmony_ci .driver = { 72462306a36Sopenharmony_ci .name = "pxa-gpio", 72562306a36Sopenharmony_ci .of_match_table = of_match_ptr(pxa_gpio_dt_ids), 72662306a36Sopenharmony_ci }, 72762306a36Sopenharmony_ci .id_table = gpio_id_table, 72862306a36Sopenharmony_ci}; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic int __init pxa_gpio_legacy_init(void) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci if (of_have_populated_dt()) 73362306a36Sopenharmony_ci return 0; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return platform_driver_register(&pxa_gpio_driver); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_cipostcore_initcall(pxa_gpio_legacy_init); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic int __init pxa_gpio_dt_init(void) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci if (of_have_populated_dt()) 74262306a36Sopenharmony_ci return platform_driver_register(&pxa_gpio_driver); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return 0; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_cidevice_initcall(pxa_gpio_dt_init); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci#ifdef CONFIG_PM 74962306a36Sopenharmony_cistatic int pxa_gpio_suspend(void) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = pxa_gpio_chip; 75262306a36Sopenharmony_ci struct pxa_gpio_bank *c; 75362306a36Sopenharmony_ci int gpio; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (!pchip) 75662306a36Sopenharmony_ci return 0; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci for_each_gpio_bank(gpio, c, pchip) { 75962306a36Sopenharmony_ci c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET); 76062306a36Sopenharmony_ci c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); 76162306a36Sopenharmony_ci c->saved_grer = readl_relaxed(c->regbase + GRER_OFFSET); 76262306a36Sopenharmony_ci c->saved_gfer = readl_relaxed(c->regbase + GFER_OFFSET); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci /* Clear GPIO transition detect bits */ 76562306a36Sopenharmony_ci writel_relaxed(0xffffffff, c->regbase + GEDR_OFFSET); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic void pxa_gpio_resume(void) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct pxa_gpio_chip *pchip = pxa_gpio_chip; 77362306a36Sopenharmony_ci struct pxa_gpio_bank *c; 77462306a36Sopenharmony_ci int gpio; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (!pchip) 77762306a36Sopenharmony_ci return; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci for_each_gpio_bank(gpio, c, pchip) { 78062306a36Sopenharmony_ci /* restore level with set/clear */ 78162306a36Sopenharmony_ci writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET); 78262306a36Sopenharmony_ci writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci writel_relaxed(c->saved_grer, c->regbase + GRER_OFFSET); 78562306a36Sopenharmony_ci writel_relaxed(c->saved_gfer, c->regbase + GFER_OFFSET); 78662306a36Sopenharmony_ci writel_relaxed(c->saved_gpdr, c->regbase + GPDR_OFFSET); 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci#else 79062306a36Sopenharmony_ci#define pxa_gpio_suspend NULL 79162306a36Sopenharmony_ci#define pxa_gpio_resume NULL 79262306a36Sopenharmony_ci#endif 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic struct syscore_ops pxa_gpio_syscore_ops = { 79562306a36Sopenharmony_ci .suspend = pxa_gpio_suspend, 79662306a36Sopenharmony_ci .resume = pxa_gpio_resume, 79762306a36Sopenharmony_ci}; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic int __init pxa_gpio_sysinit(void) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci register_syscore_ops(&pxa_gpio_syscore_ops); 80262306a36Sopenharmony_ci return 0; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_cipostcore_initcall(pxa_gpio_sysinit); 805