162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Intel Tangier GPIO driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2016, 2021, 2023 Intel Corporation. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 862306a36Sopenharmony_ci * Pandith N <pandith.n@intel.com> 962306a36Sopenharmony_ci * Raag Jadav <raag.jadav@intel.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/bitops.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/export.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/irq.h> 1962306a36Sopenharmony_ci#include <linux/math.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 2262306a36Sopenharmony_ci#include <linux/spinlock.h> 2362306a36Sopenharmony_ci#include <linux/string_helpers.h> 2462306a36Sopenharmony_ci#include <linux/types.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/gpio/driver.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "gpio-tangier.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define GCCR 0x000 /* Controller configuration */ 3162306a36Sopenharmony_ci#define GPLR 0x004 /* Pin level r/o */ 3262306a36Sopenharmony_ci#define GPDR 0x01c /* Pin direction */ 3362306a36Sopenharmony_ci#define GPSR 0x034 /* Pin set w/o */ 3462306a36Sopenharmony_ci#define GPCR 0x04c /* Pin clear w/o */ 3562306a36Sopenharmony_ci#define GRER 0x064 /* Rising edge detect */ 3662306a36Sopenharmony_ci#define GFER 0x07c /* Falling edge detect */ 3762306a36Sopenharmony_ci#define GFBR 0x094 /* Glitch filter bypass */ 3862306a36Sopenharmony_ci#define GIMR 0x0ac /* Interrupt mask */ 3962306a36Sopenharmony_ci#define GISR 0x0c4 /* Interrupt source */ 4062306a36Sopenharmony_ci#define GITR 0x300 /* Input type */ 4162306a36Sopenharmony_ci#define GLPR 0x318 /* Level input polarity */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * struct tng_gpio_context - Context to be saved during suspend-resume 4562306a36Sopenharmony_ci * @level: Pin level 4662306a36Sopenharmony_ci * @gpdr: Pin direction 4762306a36Sopenharmony_ci * @grer: Rising edge detect enable 4862306a36Sopenharmony_ci * @gfer: Falling edge detect enable 4962306a36Sopenharmony_ci * @gimr: Interrupt mask 5062306a36Sopenharmony_ci * @gwmr: Wake mask 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_cistruct tng_gpio_context { 5362306a36Sopenharmony_ci u32 level; 5462306a36Sopenharmony_ci u32 gpdr; 5562306a36Sopenharmony_ci u32 grer; 5662306a36Sopenharmony_ci u32 gfer; 5762306a36Sopenharmony_ci u32 gimr; 5862306a36Sopenharmony_ci u32 gwmr; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset, 6262306a36Sopenharmony_ci unsigned int reg) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(chip); 6562306a36Sopenharmony_ci u8 reg_offset = offset / 32; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return priv->reg_base + reg + reg_offset * 4; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void __iomem *gpio_reg_and_bit(struct gpio_chip *chip, unsigned int offset, 7162306a36Sopenharmony_ci unsigned int reg, u8 *bit) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(chip); 7462306a36Sopenharmony_ci u8 reg_offset = offset / 32; 7562306a36Sopenharmony_ci u8 shift = offset % 32; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci *bit = shift; 7862306a36Sopenharmony_ci return priv->reg_base + reg + reg_offset * 4; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int tng_gpio_get(struct gpio_chip *chip, unsigned int offset) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci void __iomem *gplr; 8462306a36Sopenharmony_ci u8 shift; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci gplr = gpio_reg_and_bit(chip, offset, GPLR, &shift); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return !!(readl(gplr) & BIT(shift)); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void tng_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(chip); 9462306a36Sopenharmony_ci unsigned long flags; 9562306a36Sopenharmony_ci void __iomem *reg; 9662306a36Sopenharmony_ci u8 shift; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci reg = gpio_reg_and_bit(chip, offset, value ? GPSR : GPCR, &shift); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci writel(BIT(shift), reg); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int tng_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(chip); 11062306a36Sopenharmony_ci unsigned long flags; 11162306a36Sopenharmony_ci void __iomem *gpdr; 11262306a36Sopenharmony_ci u32 value; 11362306a36Sopenharmony_ci u8 shift; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci value = readl(gpdr); 12062306a36Sopenharmony_ci value &= ~BIT(shift); 12162306a36Sopenharmony_ci writel(value, gpdr); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int tng_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, 12962306a36Sopenharmony_ci int value) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(chip); 13262306a36Sopenharmony_ci unsigned long flags; 13362306a36Sopenharmony_ci void __iomem *gpdr; 13462306a36Sopenharmony_ci u8 shift; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift); 13762306a36Sopenharmony_ci tng_gpio_set(chip, offset, value); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci value = readl(gpdr); 14262306a36Sopenharmony_ci value |= BIT(shift); 14362306a36Sopenharmony_ci writel(value, gpdr); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int tng_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci void __iomem *gpdr; 15362306a36Sopenharmony_ci u8 shift; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (readl(gpdr) & BIT(shift)) 15862306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int tng_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, 16462306a36Sopenharmony_ci unsigned int debounce) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(chip); 16762306a36Sopenharmony_ci unsigned long flags; 16862306a36Sopenharmony_ci void __iomem *gfbr; 16962306a36Sopenharmony_ci u32 value; 17062306a36Sopenharmony_ci u8 shift; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci gfbr = gpio_reg_and_bit(chip, offset, GFBR, &shift); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci value = readl(gfbr); 17762306a36Sopenharmony_ci if (debounce) 17862306a36Sopenharmony_ci value &= ~BIT(shift); 17962306a36Sopenharmony_ci else 18062306a36Sopenharmony_ci value |= BIT(shift); 18162306a36Sopenharmony_ci writel(value, gfbr); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int tng_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 18962306a36Sopenharmony_ci unsigned long config) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci u32 debounce; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci switch (pinconf_to_config_param(config)) { 19462306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 19562306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 19662306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 19762306a36Sopenharmony_ci return gpiochip_generic_config(chip, offset, config); 19862306a36Sopenharmony_ci case PIN_CONFIG_INPUT_DEBOUNCE: 19962306a36Sopenharmony_ci debounce = pinconf_to_config_argument(config); 20062306a36Sopenharmony_ci return tng_gpio_set_debounce(chip, offset, debounce); 20162306a36Sopenharmony_ci default: 20262306a36Sopenharmony_ci return -ENOTSUPP; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void tng_irq_ack(struct irq_data *d) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct tng_gpio *priv = irq_data_get_irq_chip_data(d); 20962306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 21062306a36Sopenharmony_ci unsigned long flags; 21162306a36Sopenharmony_ci void __iomem *gisr; 21262306a36Sopenharmony_ci u8 shift; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci gisr = gpio_reg_and_bit(&priv->chip, gpio, GISR, &shift); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 21762306a36Sopenharmony_ci writel(BIT(shift), gisr); 21862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void tng_irq_unmask_mask(struct tng_gpio *priv, u32 gpio, bool unmask) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci unsigned long flags; 22462306a36Sopenharmony_ci void __iomem *gimr; 22562306a36Sopenharmony_ci u32 value; 22662306a36Sopenharmony_ci u8 shift; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci gimr = gpio_reg_and_bit(&priv->chip, gpio, GIMR, &shift); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci value = readl(gimr); 23362306a36Sopenharmony_ci if (unmask) 23462306a36Sopenharmony_ci value |= BIT(shift); 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci value &= ~BIT(shift); 23762306a36Sopenharmony_ci writel(value, gimr); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void tng_irq_mask(struct irq_data *d) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct tng_gpio *priv = irq_data_get_irq_chip_data(d); 24562306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci tng_irq_unmask_mask(priv, gpio, false); 24862306a36Sopenharmony_ci gpiochip_disable_irq(&priv->chip, gpio); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void tng_irq_unmask(struct irq_data *d) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct tng_gpio *priv = irq_data_get_irq_chip_data(d); 25462306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci gpiochip_enable_irq(&priv->chip, gpio); 25762306a36Sopenharmony_ci tng_irq_unmask_mask(priv, gpio, true); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int tng_irq_set_type(struct irq_data *d, unsigned int type) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 26362306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(gc); 26462306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 26562306a36Sopenharmony_ci void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); 26662306a36Sopenharmony_ci void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); 26762306a36Sopenharmony_ci void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR); 26862306a36Sopenharmony_ci void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR); 26962306a36Sopenharmony_ci u8 shift = gpio % 32; 27062306a36Sopenharmony_ci unsigned long flags; 27162306a36Sopenharmony_ci u32 value; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci value = readl(grer); 27662306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 27762306a36Sopenharmony_ci value |= BIT(shift); 27862306a36Sopenharmony_ci else 27962306a36Sopenharmony_ci value &= ~BIT(shift); 28062306a36Sopenharmony_ci writel(value, grer); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci value = readl(gfer); 28362306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) 28462306a36Sopenharmony_ci value |= BIT(shift); 28562306a36Sopenharmony_ci else 28662306a36Sopenharmony_ci value &= ~BIT(shift); 28762306a36Sopenharmony_ci writel(value, gfer); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* 29062306a36Sopenharmony_ci * To prevent glitches from triggering an unintended level interrupt, 29162306a36Sopenharmony_ci * configure GLPR register first and then configure GITR. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci value = readl(glpr); 29462306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_LOW) 29562306a36Sopenharmony_ci value |= BIT(shift); 29662306a36Sopenharmony_ci else 29762306a36Sopenharmony_ci value &= ~BIT(shift); 29862306a36Sopenharmony_ci writel(value, glpr); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_MASK) { 30162306a36Sopenharmony_ci value = readl(gitr); 30262306a36Sopenharmony_ci value |= BIT(shift); 30362306a36Sopenharmony_ci writel(value, gitr); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci irq_set_handler_locked(d, handle_level_irq); 30662306a36Sopenharmony_ci } else if (type & IRQ_TYPE_EDGE_BOTH) { 30762306a36Sopenharmony_ci value = readl(gitr); 30862306a36Sopenharmony_ci value &= ~BIT(shift); 30962306a36Sopenharmony_ci writel(value, gitr); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci irq_set_handler_locked(d, handle_edge_irq); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int tng_irq_set_wake(struct irq_data *d, unsigned int on) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 32262306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(gc); 32362306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 32462306a36Sopenharmony_ci void __iomem *gwmr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwmr); 32562306a36Sopenharmony_ci void __iomem *gwsr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwsr); 32662306a36Sopenharmony_ci u8 shift = gpio % 32; 32762306a36Sopenharmony_ci unsigned long flags; 32862306a36Sopenharmony_ci u32 value; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Clear the existing wake status */ 33362306a36Sopenharmony_ci writel(BIT(shift), gwsr); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci value = readl(gwmr); 33662306a36Sopenharmony_ci if (on) 33762306a36Sopenharmony_ci value |= BIT(shift); 33862306a36Sopenharmony_ci else 33962306a36Sopenharmony_ci value &= ~BIT(shift); 34062306a36Sopenharmony_ci writel(value, gwmr); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci dev_dbg(priv->dev, "%s wake for gpio %lu\n", str_enable_disable(on), gpio); 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic const struct irq_chip tng_irqchip = { 34962306a36Sopenharmony_ci .name = "gpio-tangier", 35062306a36Sopenharmony_ci .irq_ack = tng_irq_ack, 35162306a36Sopenharmony_ci .irq_mask = tng_irq_mask, 35262306a36Sopenharmony_ci .irq_unmask = tng_irq_unmask, 35362306a36Sopenharmony_ci .irq_set_type = tng_irq_set_type, 35462306a36Sopenharmony_ci .irq_set_wake = tng_irq_set_wake, 35562306a36Sopenharmony_ci .flags = IRQCHIP_IMMUTABLE, 35662306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 35762306a36Sopenharmony_ci}; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic void tng_irq_handler(struct irq_desc *desc) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct gpio_chip *gc = irq_desc_get_handler_data(desc); 36262306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(gc); 36362306a36Sopenharmony_ci struct irq_chip *irqchip = irq_desc_get_chip(desc); 36462306a36Sopenharmony_ci unsigned long base, gpio; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci chained_irq_enter(irqchip, desc); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* Check GPIO controller to check which pin triggered the interrupt */ 36962306a36Sopenharmony_ci for (base = 0; base < priv->chip.ngpio; base += 32) { 37062306a36Sopenharmony_ci void __iomem *gisr = gpio_reg(&priv->chip, base, GISR); 37162306a36Sopenharmony_ci void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR); 37262306a36Sopenharmony_ci unsigned long pending, enabled; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci pending = readl(gisr); 37562306a36Sopenharmony_ci enabled = readl(gimr); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* Only interrupts that are enabled */ 37862306a36Sopenharmony_ci pending &= enabled; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci for_each_set_bit(gpio, &pending, 32) 38162306a36Sopenharmony_ci generic_handle_domain_irq(gc->irq.domain, base + gpio); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci chained_irq_exit(irqchip, desc); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int tng_irq_init_hw(struct gpio_chip *chip) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(chip); 39062306a36Sopenharmony_ci void __iomem *reg; 39162306a36Sopenharmony_ci unsigned int base; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci for (base = 0; base < priv->chip.ngpio; base += 32) { 39462306a36Sopenharmony_ci /* Clear the rising-edge detect register */ 39562306a36Sopenharmony_ci reg = gpio_reg(&priv->chip, base, GRER); 39662306a36Sopenharmony_ci writel(0, reg); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* Clear the falling-edge detect register */ 39962306a36Sopenharmony_ci reg = gpio_reg(&priv->chip, base, GFER); 40062306a36Sopenharmony_ci writel(0, reg); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int tng_gpio_add_pin_ranges(struct gpio_chip *chip) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct tng_gpio *priv = gpiochip_get_data(chip); 40962306a36Sopenharmony_ci const struct tng_gpio_pinrange *range; 41062306a36Sopenharmony_ci unsigned int i; 41162306a36Sopenharmony_ci int ret; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci for (i = 0; i < priv->pin_info.nranges; i++) { 41462306a36Sopenharmony_ci range = &priv->pin_info.pin_ranges[i]; 41562306a36Sopenharmony_ci ret = gpiochip_add_pin_range(&priv->chip, 41662306a36Sopenharmony_ci priv->pin_info.name, 41762306a36Sopenharmony_ci range->gpio_base, 41862306a36Sopenharmony_ci range->pin_base, 41962306a36Sopenharmony_ci range->npins); 42062306a36Sopenharmony_ci if (ret) { 42162306a36Sopenharmony_ci dev_err(priv->dev, "failed to add GPIO pin range\n"); 42262306a36Sopenharmony_ci return ret; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciint devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci const struct tng_gpio_info *info = &gpio->info; 43262306a36Sopenharmony_ci size_t nctx = DIV_ROUND_UP(info->ngpio, 32); 43362306a36Sopenharmony_ci struct gpio_irq_chip *girq; 43462306a36Sopenharmony_ci int ret; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci gpio->ctx = devm_kcalloc(dev, nctx, sizeof(*gpio->ctx), GFP_KERNEL); 43762306a36Sopenharmony_ci if (!gpio->ctx) 43862306a36Sopenharmony_ci return -ENOMEM; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci gpio->chip.label = dev_name(dev); 44162306a36Sopenharmony_ci gpio->chip.parent = dev; 44262306a36Sopenharmony_ci gpio->chip.request = gpiochip_generic_request; 44362306a36Sopenharmony_ci gpio->chip.free = gpiochip_generic_free; 44462306a36Sopenharmony_ci gpio->chip.direction_input = tng_gpio_direction_input; 44562306a36Sopenharmony_ci gpio->chip.direction_output = tng_gpio_direction_output; 44662306a36Sopenharmony_ci gpio->chip.get = tng_gpio_get; 44762306a36Sopenharmony_ci gpio->chip.set = tng_gpio_set; 44862306a36Sopenharmony_ci gpio->chip.get_direction = tng_gpio_get_direction; 44962306a36Sopenharmony_ci gpio->chip.set_config = tng_gpio_set_config; 45062306a36Sopenharmony_ci gpio->chip.base = info->base; 45162306a36Sopenharmony_ci gpio->chip.ngpio = info->ngpio; 45262306a36Sopenharmony_ci gpio->chip.can_sleep = false; 45362306a36Sopenharmony_ci gpio->chip.add_pin_ranges = tng_gpio_add_pin_ranges; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci raw_spin_lock_init(&gpio->lock); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci girq = &gpio->chip.irq; 45862306a36Sopenharmony_ci gpio_irq_chip_set_chip(girq, &tng_irqchip); 45962306a36Sopenharmony_ci girq->init_hw = tng_irq_init_hw; 46062306a36Sopenharmony_ci girq->parent_handler = tng_irq_handler; 46162306a36Sopenharmony_ci girq->num_parents = 1; 46262306a36Sopenharmony_ci girq->parents = devm_kcalloc(dev, girq->num_parents, 46362306a36Sopenharmony_ci sizeof(*girq->parents), GFP_KERNEL); 46462306a36Sopenharmony_ci if (!girq->parents) 46562306a36Sopenharmony_ci return -ENOMEM; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci girq->parents[0] = gpio->irq; 46862306a36Sopenharmony_ci girq->first = info->first; 46962306a36Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 47062306a36Sopenharmony_ci girq->handler = handle_bad_irq; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci ret = devm_gpiochip_add_data(dev, &gpio->chip, gpio); 47362306a36Sopenharmony_ci if (ret) 47462306a36Sopenharmony_ci return dev_err_probe(dev, ret, "gpiochip_add error\n"); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return 0; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(devm_tng_gpio_probe, GPIO_TANGIER); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ciint tng_gpio_suspend(struct device *dev) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct tng_gpio *priv = dev_get_drvdata(dev); 48362306a36Sopenharmony_ci struct tng_gpio_context *ctx = priv->ctx; 48462306a36Sopenharmony_ci unsigned long flags; 48562306a36Sopenharmony_ci unsigned int base; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) { 49062306a36Sopenharmony_ci /* GPLR is RO, values read will be restored using GPSR */ 49162306a36Sopenharmony_ci ctx->level = readl(gpio_reg(&priv->chip, base, GPLR)); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci ctx->gpdr = readl(gpio_reg(&priv->chip, base, GPDR)); 49462306a36Sopenharmony_ci ctx->grer = readl(gpio_reg(&priv->chip, base, GRER)); 49562306a36Sopenharmony_ci ctx->gfer = readl(gpio_reg(&priv->chip, base, GFER)); 49662306a36Sopenharmony_ci ctx->gimr = readl(gpio_reg(&priv->chip, base, GIMR)); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ctx->gwmr = readl(gpio_reg(&priv->chip, base, priv->wake_regs.gwmr)); 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(tng_gpio_suspend, GPIO_TANGIER); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ciint tng_gpio_resume(struct device *dev) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct tng_gpio *priv = dev_get_drvdata(dev); 51062306a36Sopenharmony_ci struct tng_gpio_context *ctx = priv->ctx; 51162306a36Sopenharmony_ci unsigned long flags; 51262306a36Sopenharmony_ci unsigned int base; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci raw_spin_lock_irqsave(&priv->lock, flags); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) { 51762306a36Sopenharmony_ci /* GPLR is RO, values read will be restored using GPSR */ 51862306a36Sopenharmony_ci writel(ctx->level, gpio_reg(&priv->chip, base, GPSR)); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci writel(ctx->gpdr, gpio_reg(&priv->chip, base, GPDR)); 52162306a36Sopenharmony_ci writel(ctx->grer, gpio_reg(&priv->chip, base, GRER)); 52262306a36Sopenharmony_ci writel(ctx->gfer, gpio_reg(&priv->chip, base, GFER)); 52362306a36Sopenharmony_ci writel(ctx->gimr, gpio_reg(&priv->chip, base, GIMR)); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci writel(ctx->gwmr, gpio_reg(&priv->chip, base, priv->wake_regs.gwmr)); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&priv->lock, flags); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return 0; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(tng_gpio_resume, GPIO_TANGIER); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ciMODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); 53562306a36Sopenharmony_ciMODULE_AUTHOR("Pandith N <pandith.n@intel.com>"); 53662306a36Sopenharmony_ciMODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>"); 53762306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel Tangier GPIO driver"); 53862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 539