18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Intel Merrifield SoC GPIO driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Intel Corporation.
68c2ecf20Sopenharmony_ci * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/acpi.h>
108c2ecf20Sopenharmony_ci#include <linux/bitops.h>
118c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/pci.h>
168c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define GCCR		0x000	/* controller configuration */
198c2ecf20Sopenharmony_ci#define GPLR		0x004	/* pin level r/o */
208c2ecf20Sopenharmony_ci#define GPDR		0x01c	/* pin direction */
218c2ecf20Sopenharmony_ci#define GPSR		0x034	/* pin set w/o */
228c2ecf20Sopenharmony_ci#define GPCR		0x04c	/* pin clear w/o */
238c2ecf20Sopenharmony_ci#define GRER		0x064	/* rising edge detect */
248c2ecf20Sopenharmony_ci#define GFER		0x07c	/* falling edge detect */
258c2ecf20Sopenharmony_ci#define GFBR		0x094	/* glitch filter bypass */
268c2ecf20Sopenharmony_ci#define GIMR		0x0ac	/* interrupt mask */
278c2ecf20Sopenharmony_ci#define GISR		0x0c4	/* interrupt source */
288c2ecf20Sopenharmony_ci#define GITR		0x300	/* input type */
298c2ecf20Sopenharmony_ci#define GLPR		0x318	/* level input polarity */
308c2ecf20Sopenharmony_ci#define GWMR		0x400	/* wake mask */
318c2ecf20Sopenharmony_ci#define GWSR		0x418	/* wake source */
328c2ecf20Sopenharmony_ci#define GSIR		0xc00	/* secure input */
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Intel Merrifield has 192 GPIO pins */
358c2ecf20Sopenharmony_ci#define MRFLD_NGPIO	192
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct mrfld_gpio_pinrange {
388c2ecf20Sopenharmony_ci	unsigned int gpio_base;
398c2ecf20Sopenharmony_ci	unsigned int pin_base;
408c2ecf20Sopenharmony_ci	unsigned int npins;
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define GPIO_PINRANGE(gstart, gend, pstart)		\
448c2ecf20Sopenharmony_ci	{						\
458c2ecf20Sopenharmony_ci		.gpio_base = (gstart),			\
468c2ecf20Sopenharmony_ci		.pin_base = (pstart),			\
478c2ecf20Sopenharmony_ci		.npins = (gend) - (gstart) + 1,		\
488c2ecf20Sopenharmony_ci	}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistruct mrfld_gpio {
518c2ecf20Sopenharmony_ci	struct gpio_chip	chip;
528c2ecf20Sopenharmony_ci	void __iomem		*reg_base;
538c2ecf20Sopenharmony_ci	raw_spinlock_t		lock;
548c2ecf20Sopenharmony_ci	struct device		*dev;
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic const struct mrfld_gpio_pinrange mrfld_gpio_ranges[] = {
588c2ecf20Sopenharmony_ci	GPIO_PINRANGE(0, 11, 146),
598c2ecf20Sopenharmony_ci	GPIO_PINRANGE(12, 13, 144),
608c2ecf20Sopenharmony_ci	GPIO_PINRANGE(14, 15, 35),
618c2ecf20Sopenharmony_ci	GPIO_PINRANGE(16, 16, 164),
628c2ecf20Sopenharmony_ci	GPIO_PINRANGE(17, 18, 105),
638c2ecf20Sopenharmony_ci	GPIO_PINRANGE(19, 22, 101),
648c2ecf20Sopenharmony_ci	GPIO_PINRANGE(23, 30, 107),
658c2ecf20Sopenharmony_ci	GPIO_PINRANGE(32, 43, 67),
668c2ecf20Sopenharmony_ci	GPIO_PINRANGE(44, 63, 195),
678c2ecf20Sopenharmony_ci	GPIO_PINRANGE(64, 67, 140),
688c2ecf20Sopenharmony_ci	GPIO_PINRANGE(68, 69, 165),
698c2ecf20Sopenharmony_ci	GPIO_PINRANGE(70, 71, 65),
708c2ecf20Sopenharmony_ci	GPIO_PINRANGE(72, 76, 228),
718c2ecf20Sopenharmony_ci	GPIO_PINRANGE(77, 86, 37),
728c2ecf20Sopenharmony_ci	GPIO_PINRANGE(87, 87, 48),
738c2ecf20Sopenharmony_ci	GPIO_PINRANGE(88, 88, 47),
748c2ecf20Sopenharmony_ci	GPIO_PINRANGE(89, 96, 49),
758c2ecf20Sopenharmony_ci	GPIO_PINRANGE(97, 97, 34),
768c2ecf20Sopenharmony_ci	GPIO_PINRANGE(102, 119, 83),
778c2ecf20Sopenharmony_ci	GPIO_PINRANGE(120, 123, 79),
788c2ecf20Sopenharmony_ci	GPIO_PINRANGE(124, 135, 115),
798c2ecf20Sopenharmony_ci	GPIO_PINRANGE(137, 142, 158),
808c2ecf20Sopenharmony_ci	GPIO_PINRANGE(154, 163, 24),
818c2ecf20Sopenharmony_ci	GPIO_PINRANGE(164, 176, 215),
828c2ecf20Sopenharmony_ci	GPIO_PINRANGE(177, 189, 127),
838c2ecf20Sopenharmony_ci	GPIO_PINRANGE(190, 191, 178),
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset,
878c2ecf20Sopenharmony_ci			      unsigned int reg_type_offset)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(chip);
908c2ecf20Sopenharmony_ci	u8 reg = offset / 32;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	return priv->reg_base + reg_type_offset + reg * 4;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic int mrfld_gpio_get(struct gpio_chip *chip, unsigned int offset)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	void __iomem *gplr = gpio_reg(chip, offset, GPLR);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return !!(readl(gplr) & BIT(offset % 32));
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic void mrfld_gpio_set(struct gpio_chip *chip, unsigned int offset,
1038c2ecf20Sopenharmony_ci			   int value)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(chip);
1068c2ecf20Sopenharmony_ci	void __iomem *gpsr, *gpcr;
1078c2ecf20Sopenharmony_ci	unsigned long flags;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&priv->lock, flags);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (value) {
1128c2ecf20Sopenharmony_ci		gpsr = gpio_reg(chip, offset, GPSR);
1138c2ecf20Sopenharmony_ci		writel(BIT(offset % 32), gpsr);
1148c2ecf20Sopenharmony_ci	} else {
1158c2ecf20Sopenharmony_ci		gpcr = gpio_reg(chip, offset, GPCR);
1168c2ecf20Sopenharmony_ci		writel(BIT(offset % 32), gpcr);
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&priv->lock, flags);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int mrfld_gpio_direction_input(struct gpio_chip *chip,
1238c2ecf20Sopenharmony_ci				      unsigned int offset)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(chip);
1268c2ecf20Sopenharmony_ci	void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
1278c2ecf20Sopenharmony_ci	unsigned long flags;
1288c2ecf20Sopenharmony_ci	u32 value;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&priv->lock, flags);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	value = readl(gpdr);
1338c2ecf20Sopenharmony_ci	value &= ~BIT(offset % 32);
1348c2ecf20Sopenharmony_ci	writel(value, gpdr);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&priv->lock, flags);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return 0;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic int mrfld_gpio_direction_output(struct gpio_chip *chip,
1428c2ecf20Sopenharmony_ci				       unsigned int offset, int value)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(chip);
1458c2ecf20Sopenharmony_ci	void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
1468c2ecf20Sopenharmony_ci	unsigned long flags;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	mrfld_gpio_set(chip, offset, value);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&priv->lock, flags);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	value = readl(gpdr);
1538c2ecf20Sopenharmony_ci	value |= BIT(offset % 32);
1548c2ecf20Sopenharmony_ci	writel(value, gpdr);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&priv->lock, flags);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return 0;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (readl(gpdr) & BIT(offset % 32))
1668c2ecf20Sopenharmony_ci		return GPIO_LINE_DIRECTION_OUT;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	return GPIO_LINE_DIRECTION_IN;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
1728c2ecf20Sopenharmony_ci				   unsigned int debounce)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(chip);
1758c2ecf20Sopenharmony_ci	void __iomem *gfbr = gpio_reg(chip, offset, GFBR);
1768c2ecf20Sopenharmony_ci	unsigned long flags;
1778c2ecf20Sopenharmony_ci	u32 value;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&priv->lock, flags);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (debounce)
1828c2ecf20Sopenharmony_ci		value = readl(gfbr) & ~BIT(offset % 32);
1838c2ecf20Sopenharmony_ci	else
1848c2ecf20Sopenharmony_ci		value = readl(gfbr) | BIT(offset % 32);
1858c2ecf20Sopenharmony_ci	writel(value, gfbr);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&priv->lock, flags);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return 0;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic int mrfld_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
1938c2ecf20Sopenharmony_ci				 unsigned long config)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	u32 debounce;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
1988c2ecf20Sopenharmony_ci		return -ENOTSUPP;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	debounce = pinconf_to_config_argument(config);
2018c2ecf20Sopenharmony_ci	return mrfld_gpio_set_debounce(chip, offset, debounce);
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic void mrfld_irq_ack(struct irq_data *d)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
2078c2ecf20Sopenharmony_ci	u32 gpio = irqd_to_hwirq(d);
2088c2ecf20Sopenharmony_ci	void __iomem *gisr = gpio_reg(&priv->chip, gpio, GISR);
2098c2ecf20Sopenharmony_ci	unsigned long flags;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&priv->lock, flags);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	writel(BIT(gpio % 32), gisr);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&priv->lock, flags);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic void mrfld_irq_unmask_mask(struct irq_data *d, bool unmask)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
2218c2ecf20Sopenharmony_ci	u32 gpio = irqd_to_hwirq(d);
2228c2ecf20Sopenharmony_ci	void __iomem *gimr = gpio_reg(&priv->chip, gpio, GIMR);
2238c2ecf20Sopenharmony_ci	unsigned long flags;
2248c2ecf20Sopenharmony_ci	u32 value;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&priv->lock, flags);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (unmask)
2298c2ecf20Sopenharmony_ci		value = readl(gimr) | BIT(gpio % 32);
2308c2ecf20Sopenharmony_ci	else
2318c2ecf20Sopenharmony_ci		value = readl(gimr) & ~BIT(gpio % 32);
2328c2ecf20Sopenharmony_ci	writel(value, gimr);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&priv->lock, flags);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic void mrfld_irq_mask(struct irq_data *d)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	mrfld_irq_unmask_mask(d, false);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic void mrfld_irq_unmask(struct irq_data *d)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	mrfld_irq_unmask_mask(d, true);
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic int mrfld_irq_set_type(struct irq_data *d, unsigned int type)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
2508c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(gc);
2518c2ecf20Sopenharmony_ci	u32 gpio = irqd_to_hwirq(d);
2528c2ecf20Sopenharmony_ci	void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER);
2538c2ecf20Sopenharmony_ci	void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER);
2548c2ecf20Sopenharmony_ci	void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR);
2558c2ecf20Sopenharmony_ci	void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR);
2568c2ecf20Sopenharmony_ci	unsigned long flags;
2578c2ecf20Sopenharmony_ci	u32 value;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&priv->lock, flags);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_EDGE_RISING)
2628c2ecf20Sopenharmony_ci		value = readl(grer) | BIT(gpio % 32);
2638c2ecf20Sopenharmony_ci	else
2648c2ecf20Sopenharmony_ci		value = readl(grer) & ~BIT(gpio % 32);
2658c2ecf20Sopenharmony_ci	writel(value, grer);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_EDGE_FALLING)
2688c2ecf20Sopenharmony_ci		value = readl(gfer) | BIT(gpio % 32);
2698c2ecf20Sopenharmony_ci	else
2708c2ecf20Sopenharmony_ci		value = readl(gfer) & ~BIT(gpio % 32);
2718c2ecf20Sopenharmony_ci	writel(value, gfer);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/*
2748c2ecf20Sopenharmony_ci	 * To prevent glitches from triggering an unintended level interrupt,
2758c2ecf20Sopenharmony_ci	 * configure GLPR register first and then configure GITR.
2768c2ecf20Sopenharmony_ci	 */
2778c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_LEVEL_LOW)
2788c2ecf20Sopenharmony_ci		value = readl(glpr) | BIT(gpio % 32);
2798c2ecf20Sopenharmony_ci	else
2808c2ecf20Sopenharmony_ci		value = readl(glpr) & ~BIT(gpio % 32);
2818c2ecf20Sopenharmony_ci	writel(value, glpr);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (type & IRQ_TYPE_LEVEL_MASK) {
2848c2ecf20Sopenharmony_ci		value = readl(gitr) | BIT(gpio % 32);
2858c2ecf20Sopenharmony_ci		writel(value, gitr);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci		irq_set_handler_locked(d, handle_level_irq);
2888c2ecf20Sopenharmony_ci	} else if (type & IRQ_TYPE_EDGE_BOTH) {
2898c2ecf20Sopenharmony_ci		value = readl(gitr) & ~BIT(gpio % 32);
2908c2ecf20Sopenharmony_ci		writel(value, gitr);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		irq_set_handler_locked(d, handle_edge_irq);
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&priv->lock, flags);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return 0;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic int mrfld_irq_set_wake(struct irq_data *d, unsigned int on)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3038c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(gc);
3048c2ecf20Sopenharmony_ci	u32 gpio = irqd_to_hwirq(d);
3058c2ecf20Sopenharmony_ci	void __iomem *gwmr = gpio_reg(&priv->chip, gpio, GWMR);
3068c2ecf20Sopenharmony_ci	void __iomem *gwsr = gpio_reg(&priv->chip, gpio, GWSR);
3078c2ecf20Sopenharmony_ci	unsigned long flags;
3088c2ecf20Sopenharmony_ci	u32 value;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&priv->lock, flags);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/* Clear the existing wake status */
3138c2ecf20Sopenharmony_ci	writel(BIT(gpio % 32), gwsr);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	if (on)
3168c2ecf20Sopenharmony_ci		value = readl(gwmr) | BIT(gpio % 32);
3178c2ecf20Sopenharmony_ci	else
3188c2ecf20Sopenharmony_ci		value = readl(gwmr) & ~BIT(gpio % 32);
3198c2ecf20Sopenharmony_ci	writel(value, gwmr);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&priv->lock, flags);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	dev_dbg(priv->dev, "%sable wake for gpio %u\n", on ? "en" : "dis", gpio);
3248c2ecf20Sopenharmony_ci	return 0;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic struct irq_chip mrfld_irqchip = {
3288c2ecf20Sopenharmony_ci	.name		= "gpio-merrifield",
3298c2ecf20Sopenharmony_ci	.irq_ack	= mrfld_irq_ack,
3308c2ecf20Sopenharmony_ci	.irq_mask	= mrfld_irq_mask,
3318c2ecf20Sopenharmony_ci	.irq_unmask	= mrfld_irq_unmask,
3328c2ecf20Sopenharmony_ci	.irq_set_type	= mrfld_irq_set_type,
3338c2ecf20Sopenharmony_ci	.irq_set_wake	= mrfld_irq_set_wake,
3348c2ecf20Sopenharmony_ci};
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic void mrfld_irq_handler(struct irq_desc *desc)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
3398c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(gc);
3408c2ecf20Sopenharmony_ci	struct irq_chip *irqchip = irq_desc_get_chip(desc);
3418c2ecf20Sopenharmony_ci	unsigned long base, gpio;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	chained_irq_enter(irqchip, desc);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	/* Check GPIO controller to check which pin triggered the interrupt */
3468c2ecf20Sopenharmony_ci	for (base = 0; base < priv->chip.ngpio; base += 32) {
3478c2ecf20Sopenharmony_ci		void __iomem *gisr = gpio_reg(&priv->chip, base, GISR);
3488c2ecf20Sopenharmony_ci		void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR);
3498c2ecf20Sopenharmony_ci		unsigned long pending, enabled;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci		pending = readl(gisr);
3528c2ecf20Sopenharmony_ci		enabled = readl(gimr);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		/* Only interrupts that are enabled */
3558c2ecf20Sopenharmony_ci		pending &= enabled;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		for_each_set_bit(gpio, &pending, 32) {
3588c2ecf20Sopenharmony_ci			unsigned int irq;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci			irq = irq_find_mapping(gc->irq.domain, base + gpio);
3618c2ecf20Sopenharmony_ci			generic_handle_irq(irq);
3628c2ecf20Sopenharmony_ci		}
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	chained_irq_exit(irqchip, desc);
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic int mrfld_irq_init_hw(struct gpio_chip *chip)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(chip);
3718c2ecf20Sopenharmony_ci	void __iomem *reg;
3728c2ecf20Sopenharmony_ci	unsigned int base;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	for (base = 0; base < priv->chip.ngpio; base += 32) {
3758c2ecf20Sopenharmony_ci		/* Clear the rising-edge detect register */
3768c2ecf20Sopenharmony_ci		reg = gpio_reg(&priv->chip, base, GRER);
3778c2ecf20Sopenharmony_ci		writel(0, reg);
3788c2ecf20Sopenharmony_ci		/* Clear the falling-edge detect register */
3798c2ecf20Sopenharmony_ci		reg = gpio_reg(&priv->chip, base, GFER);
3808c2ecf20Sopenharmony_ci		writel(0, reg);
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	return 0;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	struct acpi_device *adev;
3898c2ecf20Sopenharmony_ci	const char *name;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	adev = acpi_dev_get_first_match_dev("INTC1002", NULL, -1);
3928c2ecf20Sopenharmony_ci	if (adev) {
3938c2ecf20Sopenharmony_ci		name = devm_kstrdup(priv->dev, acpi_dev_name(adev), GFP_KERNEL);
3948c2ecf20Sopenharmony_ci		acpi_dev_put(adev);
3958c2ecf20Sopenharmony_ci	} else {
3968c2ecf20Sopenharmony_ci		name = "pinctrl-merrifield";
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return name;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv = gpiochip_get_data(chip);
4058c2ecf20Sopenharmony_ci	const struct mrfld_gpio_pinrange *range;
4068c2ecf20Sopenharmony_ci	const char *pinctrl_dev_name;
4078c2ecf20Sopenharmony_ci	unsigned int i;
4088c2ecf20Sopenharmony_ci	int retval;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv);
4118c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) {
4128c2ecf20Sopenharmony_ci		range = &mrfld_gpio_ranges[i];
4138c2ecf20Sopenharmony_ci		retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name,
4148c2ecf20Sopenharmony_ci						range->gpio_base,
4158c2ecf20Sopenharmony_ci						range->pin_base,
4168c2ecf20Sopenharmony_ci						range->npins);
4178c2ecf20Sopenharmony_ci		if (retval) {
4188c2ecf20Sopenharmony_ci			dev_err(priv->dev, "failed to add GPIO pin range\n");
4198c2ecf20Sopenharmony_ci			return retval;
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	return 0;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	struct gpio_irq_chip *girq;
4298c2ecf20Sopenharmony_ci	struct mrfld_gpio *priv;
4308c2ecf20Sopenharmony_ci	u32 gpio_base, irq_base;
4318c2ecf20Sopenharmony_ci	void __iomem *base;
4328c2ecf20Sopenharmony_ci	int retval;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	retval = pcim_enable_device(pdev);
4358c2ecf20Sopenharmony_ci	if (retval)
4368c2ecf20Sopenharmony_ci		return retval;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	retval = pcim_iomap_regions(pdev, BIT(1) | BIT(0), pci_name(pdev));
4398c2ecf20Sopenharmony_ci	if (retval) {
4408c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "I/O memory mapping error\n");
4418c2ecf20Sopenharmony_ci		return retval;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	base = pcim_iomap_table(pdev)[1];
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	irq_base = readl(base + 0 * sizeof(u32));
4478c2ecf20Sopenharmony_ci	gpio_base = readl(base + 1 * sizeof(u32));
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* Release the IO mapping, since we already get the info from BAR1 */
4508c2ecf20Sopenharmony_ci	pcim_iounmap_regions(pdev, BIT(1));
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
4538c2ecf20Sopenharmony_ci	if (!priv)
4548c2ecf20Sopenharmony_ci		return -ENOMEM;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	priv->dev = &pdev->dev;
4578c2ecf20Sopenharmony_ci	priv->reg_base = pcim_iomap_table(pdev)[0];
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	priv->chip.label = dev_name(&pdev->dev);
4608c2ecf20Sopenharmony_ci	priv->chip.parent = &pdev->dev;
4618c2ecf20Sopenharmony_ci	priv->chip.request = gpiochip_generic_request;
4628c2ecf20Sopenharmony_ci	priv->chip.free = gpiochip_generic_free;
4638c2ecf20Sopenharmony_ci	priv->chip.direction_input = mrfld_gpio_direction_input;
4648c2ecf20Sopenharmony_ci	priv->chip.direction_output = mrfld_gpio_direction_output;
4658c2ecf20Sopenharmony_ci	priv->chip.get = mrfld_gpio_get;
4668c2ecf20Sopenharmony_ci	priv->chip.set = mrfld_gpio_set;
4678c2ecf20Sopenharmony_ci	priv->chip.get_direction = mrfld_gpio_get_direction;
4688c2ecf20Sopenharmony_ci	priv->chip.set_config = mrfld_gpio_set_config;
4698c2ecf20Sopenharmony_ci	priv->chip.base = gpio_base;
4708c2ecf20Sopenharmony_ci	priv->chip.ngpio = MRFLD_NGPIO;
4718c2ecf20Sopenharmony_ci	priv->chip.can_sleep = false;
4728c2ecf20Sopenharmony_ci	priv->chip.add_pin_ranges = mrfld_gpio_add_pin_ranges;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	raw_spin_lock_init(&priv->lock);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
4778c2ecf20Sopenharmony_ci	if (retval < 0)
4788c2ecf20Sopenharmony_ci		return retval;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	girq = &priv->chip.irq;
4818c2ecf20Sopenharmony_ci	girq->chip = &mrfld_irqchip;
4828c2ecf20Sopenharmony_ci	girq->init_hw = mrfld_irq_init_hw;
4838c2ecf20Sopenharmony_ci	girq->parent_handler = mrfld_irq_handler;
4848c2ecf20Sopenharmony_ci	girq->num_parents = 1;
4858c2ecf20Sopenharmony_ci	girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
4868c2ecf20Sopenharmony_ci				     sizeof(*girq->parents), GFP_KERNEL);
4878c2ecf20Sopenharmony_ci	if (!girq->parents)
4888c2ecf20Sopenharmony_ci		return -ENOMEM;
4898c2ecf20Sopenharmony_ci	girq->parents[0] = pci_irq_vector(pdev, 0);
4908c2ecf20Sopenharmony_ci	girq->first = irq_base;
4918c2ecf20Sopenharmony_ci	girq->default_type = IRQ_TYPE_NONE;
4928c2ecf20Sopenharmony_ci	girq->handler = handle_bad_irq;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
4958c2ecf20Sopenharmony_ci	if (retval) {
4968c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
4978c2ecf20Sopenharmony_ci		return retval;
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, priv);
5018c2ecf20Sopenharmony_ci	return 0;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic const struct pci_device_id mrfld_gpio_ids[] = {
5058c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, 0x1199) },
5068c2ecf20Sopenharmony_ci	{ }
5078c2ecf20Sopenharmony_ci};
5088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mrfld_gpio_ids);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic struct pci_driver mrfld_gpio_driver = {
5118c2ecf20Sopenharmony_ci	.name		= "gpio-merrifield",
5128c2ecf20Sopenharmony_ci	.id_table	= mrfld_gpio_ids,
5138c2ecf20Sopenharmony_ci	.probe		= mrfld_gpio_probe,
5148c2ecf20Sopenharmony_ci};
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cimodule_pci_driver(mrfld_gpio_driver);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
5198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel Merrifield SoC GPIO driver");
5208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
521