xref: /openbmc/linux/drivers/gpio/gpio-pxa.c (revision 22823378add28f439ff43170a00f3cc92e000356)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2354bf801SLinus Walleij /*
3354bf801SLinus Walleij  *  linux/arch/arm/plat-pxa/gpio.c
4354bf801SLinus Walleij  *
5354bf801SLinus Walleij  *  Generic PXA GPIO handling
6354bf801SLinus Walleij  *
7354bf801SLinus Walleij  *  Author:	Nicolas Pitre
8354bf801SLinus Walleij  *  Created:	Jun 15, 2001
9354bf801SLinus Walleij  *  Copyright:	MontaVista Software Inc.
10354bf801SLinus Walleij  */
117a4d5079SHaojian Zhuang #include <linux/module.h>
12389eda15SHaojian Zhuang #include <linux/clk.h>
13389eda15SHaojian Zhuang #include <linux/err.h>
1484bf021eSLinus Walleij #include <linux/gpio/driver.h>
15157d2644SHaojian Zhuang #include <linux/gpio-pxa.h>
16354bf801SLinus Walleij #include <linux/init.h>
17ae4f4cfdSRob Herring #include <linux/interrupt.h>
18354bf801SLinus Walleij #include <linux/irq.h>
197a4d5079SHaojian Zhuang #include <linux/irqdomain.h>
20de88cbb7SCatalin Marinas #include <linux/irqchip/chained_irq.h>
21354bf801SLinus Walleij #include <linux/io.h>
227a4d5079SHaojian Zhuang #include <linux/of.h>
23a770d946SRobert Jarzmik #include <linux/pinctrl/consumer.h>
24157d2644SHaojian Zhuang #include <linux/platform_device.h>
25354bf801SLinus Walleij #include <linux/syscore_ops.h>
26354bf801SLinus Walleij #include <linux/slab.h>
27354bf801SLinus Walleij 
28157d2644SHaojian Zhuang /*
29157d2644SHaojian Zhuang  * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with
30157d2644SHaojian Zhuang  * one set of registers. The register offsets are organized below:
31157d2644SHaojian Zhuang  *
32157d2644SHaojian Zhuang  *           GPLR    GPDR    GPSR    GPCR    GRER    GFER    GEDR
33157d2644SHaojian Zhuang  * BANK 0 - 0x0000  0x000C  0x0018  0x0024  0x0030  0x003C  0x0048
34157d2644SHaojian Zhuang  * BANK 1 - 0x0004  0x0010  0x001C  0x0028  0x0034  0x0040  0x004C
35157d2644SHaojian Zhuang  * BANK 2 - 0x0008  0x0014  0x0020  0x002C  0x0038  0x0044  0x0050
36157d2644SHaojian Zhuang  *
37157d2644SHaojian Zhuang  * BANK 3 - 0x0100  0x010C  0x0118  0x0124  0x0130  0x013C  0x0148
38157d2644SHaojian Zhuang  * BANK 4 - 0x0104  0x0110  0x011C  0x0128  0x0134  0x0140  0x014C
39157d2644SHaojian Zhuang  * BANK 5 - 0x0108  0x0114  0x0120  0x012C  0x0138  0x0144  0x0150
40157d2644SHaojian Zhuang  *
41684bba2fSRob Herring  * BANK 6 - 0x0200  0x020C  0x0218  0x0224  0x0230  0x023C  0x0248
42684bba2fSRob Herring  *
43157d2644SHaojian Zhuang  * NOTE:
44157d2644SHaojian Zhuang  *   BANK 3 is only available on PXA27x and later processors.
45684bba2fSRob Herring  *   BANK 4 and 5 are only available on PXA935, PXA1928
46684bba2fSRob Herring  *   BANK 6 is only available on PXA1928
47157d2644SHaojian Zhuang  */
48157d2644SHaojian Zhuang 
49157d2644SHaojian Zhuang #define GPLR_OFFSET	0x00
50157d2644SHaojian Zhuang #define GPDR_OFFSET	0x0C
51157d2644SHaojian Zhuang #define GPSR_OFFSET	0x18
52157d2644SHaojian Zhuang #define GPCR_OFFSET	0x24
53157d2644SHaojian Zhuang #define GRER_OFFSET	0x30
54157d2644SHaojian Zhuang #define GFER_OFFSET	0x3C
55157d2644SHaojian Zhuang #define GEDR_OFFSET	0x48
56157d2644SHaojian Zhuang #define GAFR_OFFSET	0x54
57be24168fSHaojian Zhuang #define ED_MASK_OFFSET	0x9C	/* GPIO edge detection for AP side */
58157d2644SHaojian Zhuang 
591e970b7dSRob Herring #define BANK_OFF(n)	(((n) / 3) << 8) + (((n) % 3) << 2)
60f55be1bfSLinus Walleij 
61354bf801SLinus Walleij int pxa_last_gpio;
629450be76SDaniel Mack static int irq_base;
63354bf801SLinus Walleij 
64fc0589caSRobert Jarzmik struct pxa_gpio_bank {
65354bf801SLinus Walleij 	void __iomem	*regbase;
66354bf801SLinus Walleij 	unsigned long	irq_mask;
67354bf801SLinus Walleij 	unsigned long	irq_edge_rise;
68354bf801SLinus Walleij 	unsigned long	irq_edge_fall;
69354bf801SLinus Walleij 
70354bf801SLinus Walleij #ifdef CONFIG_PM
71354bf801SLinus Walleij 	unsigned long	saved_gplr;
72354bf801SLinus Walleij 	unsigned long	saved_gpdr;
73354bf801SLinus Walleij 	unsigned long	saved_grer;
74354bf801SLinus Walleij 	unsigned long	saved_gfer;
75354bf801SLinus Walleij #endif
76354bf801SLinus Walleij };
77354bf801SLinus Walleij 
78fc0589caSRobert Jarzmik struct pxa_gpio_chip {
79fc0589caSRobert Jarzmik 	struct device *dev;
80fc0589caSRobert Jarzmik 	struct gpio_chip chip;
81fc0589caSRobert Jarzmik 	struct pxa_gpio_bank *banks;
82384ca3c6SRobert Jarzmik 	struct irq_domain *irqdomain;
83fc0589caSRobert Jarzmik 
84fc0589caSRobert Jarzmik 	int irq0;
85fc0589caSRobert Jarzmik 	int irq1;
86fc0589caSRobert Jarzmik 	int (*set_wake)(unsigned int gpio, unsigned int on);
87fc0589caSRobert Jarzmik };
88fc0589caSRobert Jarzmik 
892cab0292SHaojian Zhuang enum pxa_gpio_type {
904929f5a8SHaojian Zhuang 	PXA25X_GPIO = 0,
914929f5a8SHaojian Zhuang 	PXA26X_GPIO,
924929f5a8SHaojian Zhuang 	PXA27X_GPIO,
934929f5a8SHaojian Zhuang 	PXA3XX_GPIO,
944929f5a8SHaojian Zhuang 	PXA93X_GPIO,
954929f5a8SHaojian Zhuang 	MMP_GPIO = 0x10,
962cab0292SHaojian Zhuang 	MMP2_GPIO,
97684bba2fSRob Herring 	PXA1928_GPIO,
982cab0292SHaojian Zhuang };
992cab0292SHaojian Zhuang 
1002cab0292SHaojian Zhuang struct pxa_gpio_id {
1012cab0292SHaojian Zhuang 	enum pxa_gpio_type	type;
1022cab0292SHaojian Zhuang 	int			gpio_nums;
1034929f5a8SHaojian Zhuang };
1044929f5a8SHaojian Zhuang 
105354bf801SLinus Walleij static DEFINE_SPINLOCK(gpio_lock);
106fc0589caSRobert Jarzmik static struct pxa_gpio_chip *pxa_gpio_chip;
1072cab0292SHaojian Zhuang static enum pxa_gpio_type gpio_type;
108354bf801SLinus Walleij 
1092cab0292SHaojian Zhuang static struct pxa_gpio_id pxa25x_id = {
1102cab0292SHaojian Zhuang 	.type		= PXA25X_GPIO,
1112cab0292SHaojian Zhuang 	.gpio_nums	= 85,
1122cab0292SHaojian Zhuang };
1132cab0292SHaojian Zhuang 
1142cab0292SHaojian Zhuang static struct pxa_gpio_id pxa26x_id = {
1152cab0292SHaojian Zhuang 	.type		= PXA26X_GPIO,
1162cab0292SHaojian Zhuang 	.gpio_nums	= 90,
1172cab0292SHaojian Zhuang };
1182cab0292SHaojian Zhuang 
1192cab0292SHaojian Zhuang static struct pxa_gpio_id pxa27x_id = {
1202cab0292SHaojian Zhuang 	.type		= PXA27X_GPIO,
1212cab0292SHaojian Zhuang 	.gpio_nums	= 121,
1222cab0292SHaojian Zhuang };
1232cab0292SHaojian Zhuang 
1242cab0292SHaojian Zhuang static struct pxa_gpio_id pxa3xx_id = {
1252cab0292SHaojian Zhuang 	.type		= PXA3XX_GPIO,
1262cab0292SHaojian Zhuang 	.gpio_nums	= 128,
1272cab0292SHaojian Zhuang };
1282cab0292SHaojian Zhuang 
1292cab0292SHaojian Zhuang static struct pxa_gpio_id pxa93x_id = {
1302cab0292SHaojian Zhuang 	.type		= PXA93X_GPIO,
1312cab0292SHaojian Zhuang 	.gpio_nums	= 192,
1322cab0292SHaojian Zhuang };
1332cab0292SHaojian Zhuang 
1342cab0292SHaojian Zhuang static struct pxa_gpio_id mmp_id = {
1352cab0292SHaojian Zhuang 	.type		= MMP_GPIO,
1362cab0292SHaojian Zhuang 	.gpio_nums	= 128,
1372cab0292SHaojian Zhuang };
1382cab0292SHaojian Zhuang 
1392cab0292SHaojian Zhuang static struct pxa_gpio_id mmp2_id = {
1402cab0292SHaojian Zhuang 	.type		= MMP2_GPIO,
1412cab0292SHaojian Zhuang 	.gpio_nums	= 192,
1422cab0292SHaojian Zhuang };
1432cab0292SHaojian Zhuang 
144684bba2fSRob Herring static struct pxa_gpio_id pxa1928_id = {
145684bba2fSRob Herring 	.type		= PXA1928_GPIO,
146684bba2fSRob Herring 	.gpio_nums	= 224,
147684bba2fSRob Herring };
148684bba2fSRob Herring 
149fc0589caSRobert Jarzmik #define for_each_gpio_bank(i, b, pc)					\
150fc0589caSRobert Jarzmik 	for (i = 0, b = pc->banks; i <= pxa_last_gpio; i += 32, b++)
151354bf801SLinus Walleij 
chip_to_pxachip(struct gpio_chip * c)152fc0589caSRobert Jarzmik static inline struct pxa_gpio_chip *chip_to_pxachip(struct gpio_chip *c)
153354bf801SLinus Walleij {
15481d0c31dSLinus Walleij 	struct pxa_gpio_chip *pxa_chip = gpiochip_get_data(c);
155fc0589caSRobert Jarzmik 
156fc0589caSRobert Jarzmik 	return pxa_chip;
157fc0589caSRobert Jarzmik }
15881d0c31dSLinus Walleij 
gpio_bank_base(struct gpio_chip * c,int gpio)159fc0589caSRobert Jarzmik static inline void __iomem *gpio_bank_base(struct gpio_chip *c, int gpio)
160fc0589caSRobert Jarzmik {
16181d0c31dSLinus Walleij 	struct pxa_gpio_chip *p = gpiochip_get_data(c);
16281d0c31dSLinus Walleij 	struct pxa_gpio_bank *bank = p->banks + (gpio / 32);
163fc0589caSRobert Jarzmik 
164fc0589caSRobert Jarzmik 	return bank->regbase;
165354bf801SLinus Walleij }
166354bf801SLinus Walleij 
gpio_to_pxabank(struct gpio_chip * c,unsigned gpio)167fc0589caSRobert Jarzmik static inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c,
168fc0589caSRobert Jarzmik 						    unsigned gpio)
169354bf801SLinus Walleij {
170fc0589caSRobert Jarzmik 	return chip_to_pxachip(c)->banks + gpio / 32;
171354bf801SLinus Walleij }
172354bf801SLinus Walleij 
gpio_is_mmp_type(int type)1734929f5a8SHaojian Zhuang static inline int gpio_is_mmp_type(int type)
1744929f5a8SHaojian Zhuang {
1754929f5a8SHaojian Zhuang 	return (type & MMP_GPIO) != 0;
1764929f5a8SHaojian Zhuang }
1774929f5a8SHaojian Zhuang 
178157d2644SHaojian Zhuang /* GPIO86/87/88/89 on PXA26x have their direction bits in PXA_GPDR(2 inverted,
179157d2644SHaojian Zhuang  * as well as their Alternate Function value being '1' for GPIO in GAFRx.
180157d2644SHaojian Zhuang  */
__gpio_is_inverted(int gpio)181157d2644SHaojian Zhuang static inline int __gpio_is_inverted(int gpio)
182157d2644SHaojian Zhuang {
183157d2644SHaojian Zhuang 	if ((gpio_type == PXA26X_GPIO) && (gpio > 85))
184157d2644SHaojian Zhuang 		return 1;
185157d2644SHaojian Zhuang 	return 0;
186157d2644SHaojian Zhuang }
187157d2644SHaojian Zhuang 
188157d2644SHaojian Zhuang /*
189157d2644SHaojian Zhuang  * On PXA25x and PXA27x, GAFRx and GPDRx together decide the alternate
190157d2644SHaojian Zhuang  * function of a GPIO, and GPDRx cannot be altered once configured. It
191157d2644SHaojian Zhuang  * is attributed as "occupied" here (I know this terminology isn't
192157d2644SHaojian Zhuang  * accurate, you are welcome to propose a better one :-)
193157d2644SHaojian Zhuang  */
__gpio_is_occupied(struct pxa_gpio_chip * pchip,unsigned gpio)194fc0589caSRobert Jarzmik static inline int __gpio_is_occupied(struct pxa_gpio_chip *pchip, unsigned gpio)
195157d2644SHaojian Zhuang {
196157d2644SHaojian Zhuang 	void __iomem *base;
197157d2644SHaojian Zhuang 	unsigned long gafr = 0, gpdr = 0;
198157d2644SHaojian Zhuang 	int ret, af = 0, dir = 0;
199157d2644SHaojian Zhuang 
200fc0589caSRobert Jarzmik 	base = gpio_bank_base(&pchip->chip, gpio);
201157d2644SHaojian Zhuang 	gpdr = readl_relaxed(base + GPDR_OFFSET);
202157d2644SHaojian Zhuang 
203157d2644SHaojian Zhuang 	switch (gpio_type) {
204157d2644SHaojian Zhuang 	case PXA25X_GPIO:
205157d2644SHaojian Zhuang 	case PXA26X_GPIO:
206157d2644SHaojian Zhuang 	case PXA27X_GPIO:
207157d2644SHaojian Zhuang 		gafr = readl_relaxed(base + GAFR_OFFSET);
208157d2644SHaojian Zhuang 		af = (gafr >> ((gpio & 0xf) * 2)) & 0x3;
209157d2644SHaojian Zhuang 		dir = gpdr & GPIO_bit(gpio);
210157d2644SHaojian Zhuang 
211157d2644SHaojian Zhuang 		if (__gpio_is_inverted(gpio))
212157d2644SHaojian Zhuang 			ret = (af != 1) || (dir == 0);
213157d2644SHaojian Zhuang 		else
214157d2644SHaojian Zhuang 			ret = (af != 0) || (dir != 0);
215157d2644SHaojian Zhuang 		break;
216157d2644SHaojian Zhuang 	default:
217157d2644SHaojian Zhuang 		ret = gpdr & GPIO_bit(gpio);
218157d2644SHaojian Zhuang 		break;
219157d2644SHaojian Zhuang 	}
220157d2644SHaojian Zhuang 	return ret;
221157d2644SHaojian Zhuang }
222157d2644SHaojian Zhuang 
pxa_irq_to_gpio(int irq)2234929f5a8SHaojian Zhuang int pxa_irq_to_gpio(int irq)
2244929f5a8SHaojian Zhuang {
225384ca3c6SRobert Jarzmik 	struct pxa_gpio_chip *pchip = pxa_gpio_chip;
226384ca3c6SRobert Jarzmik 	int irq_gpio0;
227384ca3c6SRobert Jarzmik 
228384ca3c6SRobert Jarzmik 	irq_gpio0 = irq_find_mapping(pchip->irqdomain, 0);
229384ca3c6SRobert Jarzmik 	if (irq_gpio0 > 0)
230384ca3c6SRobert Jarzmik 		return irq - irq_gpio0;
231384ca3c6SRobert Jarzmik 
232384ca3c6SRobert Jarzmik 	return irq_gpio0;
233384ca3c6SRobert Jarzmik }
234384ca3c6SRobert Jarzmik 
pxa_gpio_has_pinctrl(void)2359dabfdd8SDaniel Mack static bool pxa_gpio_has_pinctrl(void)
2369dabfdd8SDaniel Mack {
2379dabfdd8SDaniel Mack 	switch (gpio_type) {
2389dabfdd8SDaniel Mack 	case PXA3XX_GPIO:
239af14b2c9SLubomir Rintel 	case MMP2_GPIO:
240*f0575116SDuje Mihanović 	case MMP_GPIO:
2419dabfdd8SDaniel Mack 		return false;
2429dabfdd8SDaniel Mack 
2439dabfdd8SDaniel Mack 	default:
2449dabfdd8SDaniel Mack 		return true;
2459dabfdd8SDaniel Mack 	}
2469dabfdd8SDaniel Mack }
2479dabfdd8SDaniel Mack 
pxa_gpio_to_irq(struct gpio_chip * chip,unsigned offset)248384ca3c6SRobert Jarzmik static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
249384ca3c6SRobert Jarzmik {
250384ca3c6SRobert Jarzmik 	struct pxa_gpio_chip *pchip = chip_to_pxachip(chip);
251384ca3c6SRobert Jarzmik 
252384ca3c6SRobert Jarzmik 	return irq_find_mapping(pchip->irqdomain, offset);
2534929f5a8SHaojian Zhuang }
2544929f5a8SHaojian Zhuang 
pxa_gpio_direction_input(struct gpio_chip * chip,unsigned offset)255354bf801SLinus Walleij static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
256354bf801SLinus Walleij {
257fc0589caSRobert Jarzmik 	void __iomem *base = gpio_bank_base(chip, offset);
258fc0589caSRobert Jarzmik 	uint32_t value, mask = GPIO_bit(offset);
259354bf801SLinus Walleij 	unsigned long flags;
260a770d946SRobert Jarzmik 	int ret;
261a770d946SRobert Jarzmik 
2629dabfdd8SDaniel Mack 	if (pxa_gpio_has_pinctrl()) {
263a770d946SRobert Jarzmik 		ret = pinctrl_gpio_direction_input(chip->base + offset);
26470cdb6adSRobert Jarzmik 		if (ret)
26570cdb6adSRobert Jarzmik 			return ret;
2669dabfdd8SDaniel Mack 	}
267354bf801SLinus Walleij 
268354bf801SLinus Walleij 	spin_lock_irqsave(&gpio_lock, flags);
269354bf801SLinus Walleij 
270df664d20SHaojian Zhuang 	value = readl_relaxed(base + GPDR_OFFSET);
271354bf801SLinus Walleij 	if (__gpio_is_inverted(chip->base + offset))
272354bf801SLinus Walleij 		value |= mask;
273354bf801SLinus Walleij 	else
274354bf801SLinus Walleij 		value &= ~mask;
275df664d20SHaojian Zhuang 	writel_relaxed(value, base + GPDR_OFFSET);
276354bf801SLinus Walleij 
277354bf801SLinus Walleij 	spin_unlock_irqrestore(&gpio_lock, flags);
278354bf801SLinus Walleij 	return 0;
279354bf801SLinus Walleij }
280354bf801SLinus Walleij 
pxa_gpio_direction_output(struct gpio_chip * chip,unsigned offset,int value)281354bf801SLinus Walleij static int pxa_gpio_direction_output(struct gpio_chip *chip,
282354bf801SLinus Walleij 				     unsigned offset, int value)
283354bf801SLinus Walleij {
284fc0589caSRobert Jarzmik 	void __iomem *base = gpio_bank_base(chip, offset);
285fc0589caSRobert Jarzmik 	uint32_t tmp, mask = GPIO_bit(offset);
286354bf801SLinus Walleij 	unsigned long flags;
287a770d946SRobert Jarzmik 	int ret;
288354bf801SLinus Walleij 
289df664d20SHaojian Zhuang 	writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
290354bf801SLinus Walleij 
2919dabfdd8SDaniel Mack 	if (pxa_gpio_has_pinctrl()) {
292a770d946SRobert Jarzmik 		ret = pinctrl_gpio_direction_output(chip->base + offset);
293c4e5ffb6SRobert Jarzmik 		if (ret)
294c4e5ffb6SRobert Jarzmik 			return ret;
2959dabfdd8SDaniel Mack 	}
296a770d946SRobert Jarzmik 
297354bf801SLinus Walleij 	spin_lock_irqsave(&gpio_lock, flags);
298354bf801SLinus Walleij 
299df664d20SHaojian Zhuang 	tmp = readl_relaxed(base + GPDR_OFFSET);
300354bf801SLinus Walleij 	if (__gpio_is_inverted(chip->base + offset))
301354bf801SLinus Walleij 		tmp &= ~mask;
302354bf801SLinus Walleij 	else
303354bf801SLinus Walleij 		tmp |= mask;
304df664d20SHaojian Zhuang 	writel_relaxed(tmp, base + GPDR_OFFSET);
305354bf801SLinus Walleij 
306354bf801SLinus Walleij 	spin_unlock_irqrestore(&gpio_lock, flags);
307354bf801SLinus Walleij 	return 0;
308354bf801SLinus Walleij }
309354bf801SLinus Walleij 
pxa_gpio_get(struct gpio_chip * chip,unsigned offset)310354bf801SLinus Walleij static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
311354bf801SLinus Walleij {
312fc0589caSRobert Jarzmik 	void __iomem *base = gpio_bank_base(chip, offset);
313fc0589caSRobert Jarzmik 	u32 gplr = readl_relaxed(base + GPLR_OFFSET);
314fc0589caSRobert Jarzmik 
315fc0589caSRobert Jarzmik 	return !!(gplr & GPIO_bit(offset));
316354bf801SLinus Walleij }
317354bf801SLinus Walleij 
pxa_gpio_set(struct gpio_chip * chip,unsigned offset,int value)318354bf801SLinus Walleij static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
319354bf801SLinus Walleij {
320fc0589caSRobert Jarzmik 	void __iomem *base = gpio_bank_base(chip, offset);
321fc0589caSRobert Jarzmik 
322fc0589caSRobert Jarzmik 	writel_relaxed(GPIO_bit(offset),
323fc0589caSRobert Jarzmik 		       base + (value ? GPSR_OFFSET : GPCR_OFFSET));
324354bf801SLinus Walleij }
325354bf801SLinus Walleij 
32672121572SDaniel Mack #ifdef CONFIG_OF_GPIO
pxa_gpio_of_xlate(struct gpio_chip * gc,const struct of_phandle_args * gpiospec,u32 * flags)32772121572SDaniel Mack static int pxa_gpio_of_xlate(struct gpio_chip *gc,
32872121572SDaniel Mack 			     const struct of_phandle_args *gpiospec,
32972121572SDaniel Mack 			     u32 *flags)
33072121572SDaniel Mack {
33172121572SDaniel Mack 	if (gpiospec->args[0] > pxa_last_gpio)
33272121572SDaniel Mack 		return -EINVAL;
33372121572SDaniel Mack 
33472121572SDaniel Mack 	if (flags)
33572121572SDaniel Mack 		*flags = gpiospec->args[1];
33672121572SDaniel Mack 
337fc0589caSRobert Jarzmik 	return gpiospec->args[0];
33872121572SDaniel Mack }
33972121572SDaniel Mack #endif
34072121572SDaniel Mack 
pxa_init_gpio_chip(struct pxa_gpio_chip * pchip,int ngpio,void __iomem * regbase)34145a541a6SAndy Shevchenko static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, void __iomem *regbase)
342354bf801SLinus Walleij {
343fc0589caSRobert Jarzmik 	int i, gpio, nbanks = DIV_ROUND_UP(ngpio, 32);
344fc0589caSRobert Jarzmik 	struct pxa_gpio_bank *bank;
345354bf801SLinus Walleij 
346fc0589caSRobert Jarzmik 	pchip->banks = devm_kcalloc(pchip->dev, nbanks, sizeof(*pchip->banks),
347fc0589caSRobert Jarzmik 				    GFP_KERNEL);
348fc0589caSRobert Jarzmik 	if (!pchip->banks)
349354bf801SLinus Walleij 		return -ENOMEM;
350fc0589caSRobert Jarzmik 
35145a541a6SAndy Shevchenko 	pchip->chip.parent = pchip->dev;
352fc0589caSRobert Jarzmik 	pchip->chip.label = "gpio-pxa";
353fc0589caSRobert Jarzmik 	pchip->chip.direction_input  = pxa_gpio_direction_input;
354fc0589caSRobert Jarzmik 	pchip->chip.direction_output = pxa_gpio_direction_output;
355fc0589caSRobert Jarzmik 	pchip->chip.get = pxa_gpio_get;
356fc0589caSRobert Jarzmik 	pchip->chip.set = pxa_gpio_set;
357fc0589caSRobert Jarzmik 	pchip->chip.to_irq = pxa_gpio_to_irq;
358fc0589caSRobert Jarzmik 	pchip->chip.ngpio = ngpio;
359ad5c3221SLinus Walleij 	pchip->chip.request = gpiochip_generic_request;
360ad5c3221SLinus Walleij 	pchip->chip.free = gpiochip_generic_free;
3619dabfdd8SDaniel Mack 
362fc0589caSRobert Jarzmik #ifdef CONFIG_OF_GPIO
363fc0589caSRobert Jarzmik 	pchip->chip.of_xlate = pxa_gpio_of_xlate;
364fc0589caSRobert Jarzmik 	pchip->chip.of_gpio_n_cells = 2;
365fc0589caSRobert Jarzmik #endif
366354bf801SLinus Walleij 
367354bf801SLinus Walleij 	for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
368fc0589caSRobert Jarzmik 		bank = pchip->banks + i;
369fc0589caSRobert Jarzmik 		bank->regbase = regbase + BANK_OFF(i);
370354bf801SLinus Walleij 	}
371fc0589caSRobert Jarzmik 
37281d0c31dSLinus Walleij 	return gpiochip_add_data(&pchip->chip, pchip);
373354bf801SLinus Walleij }
374354bf801SLinus Walleij 
375354bf801SLinus Walleij /* Update only those GRERx and GFERx edge detection register bits if those
376354bf801SLinus Walleij  * bits are set in c->irq_mask
377354bf801SLinus Walleij  */
update_edge_detect(struct pxa_gpio_bank * c)378fc0589caSRobert Jarzmik static inline void update_edge_detect(struct pxa_gpio_bank *c)
379354bf801SLinus Walleij {
380354bf801SLinus Walleij 	uint32_t grer, gfer;
381354bf801SLinus Walleij 
382df664d20SHaojian Zhuang 	grer = readl_relaxed(c->regbase + GRER_OFFSET) & ~c->irq_mask;
383df664d20SHaojian Zhuang 	gfer = readl_relaxed(c->regbase + GFER_OFFSET) & ~c->irq_mask;
384354bf801SLinus Walleij 	grer |= c->irq_edge_rise & c->irq_mask;
385354bf801SLinus Walleij 	gfer |= c->irq_edge_fall & c->irq_mask;
386df664d20SHaojian Zhuang 	writel_relaxed(grer, c->regbase + GRER_OFFSET);
387df664d20SHaojian Zhuang 	writel_relaxed(gfer, c->regbase + GFER_OFFSET);
388354bf801SLinus Walleij }
389354bf801SLinus Walleij 
pxa_gpio_irq_type(struct irq_data * d,unsigned int type)390354bf801SLinus Walleij static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
391354bf801SLinus Walleij {
392384ca3c6SRobert Jarzmik 	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
393384ca3c6SRobert Jarzmik 	unsigned int gpio = irqd_to_hwirq(d);
394fc0589caSRobert Jarzmik 	struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio);
395354bf801SLinus Walleij 	unsigned long gpdr, mask = GPIO_bit(gpio);
396354bf801SLinus Walleij 
397354bf801SLinus Walleij 	if (type == IRQ_TYPE_PROBE) {
398354bf801SLinus Walleij 		/* Don't mess with enabled GPIOs using preconfigured edges or
399354bf801SLinus Walleij 		 * GPIOs set to alternate function or to output during probe
400354bf801SLinus Walleij 		 */
401354bf801SLinus Walleij 		if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio))
402354bf801SLinus Walleij 			return 0;
403354bf801SLinus Walleij 
404fc0589caSRobert Jarzmik 		if (__gpio_is_occupied(pchip, gpio))
405354bf801SLinus Walleij 			return 0;
406354bf801SLinus Walleij 
407354bf801SLinus Walleij 		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
408354bf801SLinus Walleij 	}
409354bf801SLinus Walleij 
410df664d20SHaojian Zhuang 	gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
411354bf801SLinus Walleij 
412354bf801SLinus Walleij 	if (__gpio_is_inverted(gpio))
413df664d20SHaojian Zhuang 		writel_relaxed(gpdr | mask,  c->regbase + GPDR_OFFSET);
414354bf801SLinus Walleij 	else
415df664d20SHaojian Zhuang 		writel_relaxed(gpdr & ~mask, c->regbase + GPDR_OFFSET);
416354bf801SLinus Walleij 
417354bf801SLinus Walleij 	if (type & IRQ_TYPE_EDGE_RISING)
418354bf801SLinus Walleij 		c->irq_edge_rise |= mask;
419354bf801SLinus Walleij 	else
420354bf801SLinus Walleij 		c->irq_edge_rise &= ~mask;
421354bf801SLinus Walleij 
422354bf801SLinus Walleij 	if (type & IRQ_TYPE_EDGE_FALLING)
423354bf801SLinus Walleij 		c->irq_edge_fall |= mask;
424354bf801SLinus Walleij 	else
425354bf801SLinus Walleij 		c->irq_edge_fall &= ~mask;
426354bf801SLinus Walleij 
427354bf801SLinus Walleij 	update_edge_detect(c);
428354bf801SLinus Walleij 
429354bf801SLinus Walleij 	pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio,
430354bf801SLinus Walleij 		((type & IRQ_TYPE_EDGE_RISING)  ? " rising"  : ""),
431354bf801SLinus Walleij 		((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : ""));
432354bf801SLinus Walleij 	return 0;
433354bf801SLinus Walleij }
434354bf801SLinus Walleij 
pxa_gpio_demux_handler(int in_irq,void * d)435384ca3c6SRobert Jarzmik static irqreturn_t pxa_gpio_demux_handler(int in_irq, void *d)
436354bf801SLinus Walleij {
437fc0589caSRobert Jarzmik 	int loop, gpio, n, handled = 0;
438354bf801SLinus Walleij 	unsigned long gedr;
439384ca3c6SRobert Jarzmik 	struct pxa_gpio_chip *pchip = d;
440fc0589caSRobert Jarzmik 	struct pxa_gpio_bank *c;
4410d2ee5d7SChao Xie 
442354bf801SLinus Walleij 	do {
443354bf801SLinus Walleij 		loop = 0;
444fc0589caSRobert Jarzmik 		for_each_gpio_bank(gpio, c, pchip) {
445df664d20SHaojian Zhuang 			gedr = readl_relaxed(c->regbase + GEDR_OFFSET);
446354bf801SLinus Walleij 			gedr = gedr & c->irq_mask;
447df664d20SHaojian Zhuang 			writel_relaxed(gedr, c->regbase + GEDR_OFFSET);
448354bf801SLinus Walleij 
449d724f1c9SWei Yongjun 			for_each_set_bit(n, &gedr, BITS_PER_LONG) {
450354bf801SLinus Walleij 				loop = 1;
451354bf801SLinus Walleij 
452dbd1c54fSMarc Zyngier 				generic_handle_domain_irq(pchip->irqdomain,
453dbd1c54fSMarc Zyngier 							  gpio + n);
454354bf801SLinus Walleij 			}
455354bf801SLinus Walleij 		}
456384ca3c6SRobert Jarzmik 		handled += loop;
457354bf801SLinus Walleij 	} while (loop);
4580d2ee5d7SChao Xie 
459384ca3c6SRobert Jarzmik 	return handled ? IRQ_HANDLED : IRQ_NONE;
460384ca3c6SRobert Jarzmik }
461384ca3c6SRobert Jarzmik 
pxa_gpio_direct_handler(int in_irq,void * d)462384ca3c6SRobert Jarzmik static irqreturn_t pxa_gpio_direct_handler(int in_irq, void *d)
463384ca3c6SRobert Jarzmik {
464384ca3c6SRobert Jarzmik 	struct pxa_gpio_chip *pchip = d;
465384ca3c6SRobert Jarzmik 
466384ca3c6SRobert Jarzmik 	if (in_irq == pchip->irq0) {
467dbd1c54fSMarc Zyngier 		generic_handle_domain_irq(pchip->irqdomain, 0);
468384ca3c6SRobert Jarzmik 	} else if (in_irq == pchip->irq1) {
469dbd1c54fSMarc Zyngier 		generic_handle_domain_irq(pchip->irqdomain, 1);
470384ca3c6SRobert Jarzmik 	} else {
471384ca3c6SRobert Jarzmik 		pr_err("%s() unknown irq %d\n", __func__, in_irq);
472384ca3c6SRobert Jarzmik 		return IRQ_NONE;
473384ca3c6SRobert Jarzmik 	}
474384ca3c6SRobert Jarzmik 	return IRQ_HANDLED;
475354bf801SLinus Walleij }
476354bf801SLinus Walleij 
pxa_ack_muxed_gpio(struct irq_data * d)477354bf801SLinus Walleij static void pxa_ack_muxed_gpio(struct irq_data *d)
478354bf801SLinus Walleij {
479384ca3c6SRobert Jarzmik 	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
480384ca3c6SRobert Jarzmik 	unsigned int gpio = irqd_to_hwirq(d);
481fc0589caSRobert Jarzmik 	void __iomem *base = gpio_bank_base(&pchip->chip, gpio);
482354bf801SLinus Walleij 
483fc0589caSRobert Jarzmik 	writel_relaxed(GPIO_bit(gpio), base + GEDR_OFFSET);
484354bf801SLinus Walleij }
485354bf801SLinus Walleij 
pxa_mask_muxed_gpio(struct irq_data * d)486354bf801SLinus Walleij static void pxa_mask_muxed_gpio(struct irq_data *d)
487354bf801SLinus Walleij {
488384ca3c6SRobert Jarzmik 	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
489384ca3c6SRobert Jarzmik 	unsigned int gpio = irqd_to_hwirq(d);
490fc0589caSRobert Jarzmik 	struct pxa_gpio_bank *b = gpio_to_pxabank(&pchip->chip, gpio);
491fc0589caSRobert Jarzmik 	void __iomem *base = gpio_bank_base(&pchip->chip, gpio);
492354bf801SLinus Walleij 	uint32_t grer, gfer;
493354bf801SLinus Walleij 
494fc0589caSRobert Jarzmik 	b->irq_mask &= ~GPIO_bit(gpio);
495354bf801SLinus Walleij 
496fc0589caSRobert Jarzmik 	grer = readl_relaxed(base + GRER_OFFSET) & ~GPIO_bit(gpio);
497fc0589caSRobert Jarzmik 	gfer = readl_relaxed(base + GFER_OFFSET) & ~GPIO_bit(gpio);
498fc0589caSRobert Jarzmik 	writel_relaxed(grer, base + GRER_OFFSET);
499fc0589caSRobert Jarzmik 	writel_relaxed(gfer, base + GFER_OFFSET);
500354bf801SLinus Walleij }
501354bf801SLinus Walleij 
pxa_gpio_set_wake(struct irq_data * d,unsigned int on)502b95ace54SRobert Jarzmik static int pxa_gpio_set_wake(struct irq_data *d, unsigned int on)
503b95ace54SRobert Jarzmik {
504384ca3c6SRobert Jarzmik 	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
505384ca3c6SRobert Jarzmik 	unsigned int gpio = irqd_to_hwirq(d);
506b95ace54SRobert Jarzmik 
507fc0589caSRobert Jarzmik 	if (pchip->set_wake)
508fc0589caSRobert Jarzmik 		return pchip->set_wake(gpio, on);
509b95ace54SRobert Jarzmik 	else
510b95ace54SRobert Jarzmik 		return 0;
511b95ace54SRobert Jarzmik }
512b95ace54SRobert Jarzmik 
pxa_unmask_muxed_gpio(struct irq_data * d)513354bf801SLinus Walleij static void pxa_unmask_muxed_gpio(struct irq_data *d)
514354bf801SLinus Walleij {
515384ca3c6SRobert Jarzmik 	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
516384ca3c6SRobert Jarzmik 	unsigned int gpio = irqd_to_hwirq(d);
517fc0589caSRobert Jarzmik 	struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio);
518354bf801SLinus Walleij 
519354bf801SLinus Walleij 	c->irq_mask |= GPIO_bit(gpio);
520354bf801SLinus Walleij 	update_edge_detect(c);
521354bf801SLinus Walleij }
522354bf801SLinus Walleij 
523354bf801SLinus Walleij static struct irq_chip pxa_muxed_gpio_chip = {
524354bf801SLinus Walleij 	.name		= "GPIO",
525354bf801SLinus Walleij 	.irq_ack	= pxa_ack_muxed_gpio,
526354bf801SLinus Walleij 	.irq_mask	= pxa_mask_muxed_gpio,
527354bf801SLinus Walleij 	.irq_unmask	= pxa_unmask_muxed_gpio,
528354bf801SLinus Walleij 	.irq_set_type	= pxa_gpio_irq_type,
529b95ace54SRobert Jarzmik 	.irq_set_wake	= pxa_gpio_set_wake,
530354bf801SLinus Walleij };
531354bf801SLinus Walleij 
pxa_gpio_nums(struct platform_device * pdev)5322cab0292SHaojian Zhuang static int pxa_gpio_nums(struct platform_device *pdev)
533478e223cSHaojian Zhuang {
5342cab0292SHaojian Zhuang 	const struct platform_device_id *id = platform_get_device_id(pdev);
5352cab0292SHaojian Zhuang 	struct pxa_gpio_id *pxa_id = (struct pxa_gpio_id *)id->driver_data;
536478e223cSHaojian Zhuang 	int count = 0;
537478e223cSHaojian Zhuang 
5382cab0292SHaojian Zhuang 	switch (pxa_id->type) {
5392cab0292SHaojian Zhuang 	case PXA25X_GPIO:
5402cab0292SHaojian Zhuang 	case PXA26X_GPIO:
5412cab0292SHaojian Zhuang 	case PXA27X_GPIO:
5422cab0292SHaojian Zhuang 	case PXA3XX_GPIO:
5432cab0292SHaojian Zhuang 	case PXA93X_GPIO:
5442cab0292SHaojian Zhuang 	case MMP_GPIO:
5452cab0292SHaojian Zhuang 	case MMP2_GPIO:
546684bba2fSRob Herring 	case PXA1928_GPIO:
5472cab0292SHaojian Zhuang 		gpio_type = pxa_id->type;
5482cab0292SHaojian Zhuang 		count = pxa_id->gpio_nums - 1;
5492cab0292SHaojian Zhuang 		break;
5502cab0292SHaojian Zhuang 	default:
5512cab0292SHaojian Zhuang 		count = -EINVAL;
5522cab0292SHaojian Zhuang 		break;
553478e223cSHaojian Zhuang 	}
554478e223cSHaojian Zhuang 	return count;
555478e223cSHaojian Zhuang }
556478e223cSHaojian Zhuang 
pxa_irq_domain_map(struct irq_domain * d,unsigned int irq,irq_hw_number_t hw)5577a4d5079SHaojian Zhuang static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
5587a4d5079SHaojian Zhuang 			      irq_hw_number_t hw)
5597a4d5079SHaojian Zhuang {
5607a4d5079SHaojian Zhuang 	irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
5617a4d5079SHaojian Zhuang 				 handle_edge_irq);
562384ca3c6SRobert Jarzmik 	irq_set_chip_data(irq, d->host_data);
56323393d49SRob Herring 	irq_set_noprobe(irq);
5647a4d5079SHaojian Zhuang 	return 0;
5657a4d5079SHaojian Zhuang }
5667a4d5079SHaojian Zhuang 
5671e9aa2a8SYueHaibing static const struct irq_domain_ops pxa_irq_domain_ops = {
5687a4d5079SHaojian Zhuang 	.map	= pxa_irq_domain_map,
56972121572SDaniel Mack 	.xlate	= irq_domain_xlate_twocell,
5707a4d5079SHaojian Zhuang };
5717a4d5079SHaojian Zhuang 
5720440091bSRobert Jarzmik #ifdef CONFIG_OF
5730440091bSRobert Jarzmik static const struct of_device_id pxa_gpio_dt_ids[] = {
5740440091bSRobert Jarzmik 	{ .compatible = "intel,pxa25x-gpio",	.data = &pxa25x_id, },
5750440091bSRobert Jarzmik 	{ .compatible = "intel,pxa26x-gpio",	.data = &pxa26x_id, },
5760440091bSRobert Jarzmik 	{ .compatible = "intel,pxa27x-gpio",	.data = &pxa27x_id, },
5770440091bSRobert Jarzmik 	{ .compatible = "intel,pxa3xx-gpio",	.data = &pxa3xx_id, },
5780440091bSRobert Jarzmik 	{ .compatible = "marvell,pxa93x-gpio",	.data = &pxa93x_id, },
5790440091bSRobert Jarzmik 	{ .compatible = "marvell,mmp-gpio",	.data = &mmp_id, },
5800440091bSRobert Jarzmik 	{ .compatible = "marvell,mmp2-gpio",	.data = &mmp2_id, },
5810440091bSRobert Jarzmik 	{ .compatible = "marvell,pxa1928-gpio",	.data = &pxa1928_id, },
5820440091bSRobert Jarzmik 	{}
5830440091bSRobert Jarzmik };
5840440091bSRobert Jarzmik 
pxa_gpio_probe_dt(struct platform_device * pdev,struct pxa_gpio_chip * pchip)585fc0589caSRobert Jarzmik static int pxa_gpio_probe_dt(struct platform_device *pdev,
586fc0589caSRobert Jarzmik 			     struct pxa_gpio_chip *pchip)
5877a4d5079SHaojian Zhuang {
588fc0589caSRobert Jarzmik 	int nr_gpios;
589f8731174SHaojian Zhuang 	const struct pxa_gpio_id *gpio_id;
5907a4d5079SHaojian Zhuang 
5918357759aSThierry Reding 	gpio_id = of_device_get_match_data(&pdev->dev);
592f8731174SHaojian Zhuang 	gpio_type = gpio_id->type;
5937a4d5079SHaojian Zhuang 
594f8731174SHaojian Zhuang 	nr_gpios = gpio_id->gpio_nums;
5957a4d5079SHaojian Zhuang 	pxa_last_gpio = nr_gpios - 1;
5967a4d5079SHaojian Zhuang 
597bda61a19SBartosz Golaszewski 	irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, nr_gpios, 0);
5987a4d5079SHaojian Zhuang 	if (irq_base < 0) {
5997a4d5079SHaojian Zhuang 		dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
600fc0589caSRobert Jarzmik 		return irq_base;
6017a4d5079SHaojian Zhuang 	}
602384ca3c6SRobert Jarzmik 	return irq_base;
6037a4d5079SHaojian Zhuang }
6047a4d5079SHaojian Zhuang #else
605fc0589caSRobert Jarzmik #define pxa_gpio_probe_dt(pdev, pchip)		(-1)
6067a4d5079SHaojian Zhuang #endif
6077a4d5079SHaojian Zhuang 
pxa_gpio_probe(struct platform_device * pdev)6083836309dSBill Pemberton static int pxa_gpio_probe(struct platform_device *pdev)
609354bf801SLinus Walleij {
610fc0589caSRobert Jarzmik 	struct pxa_gpio_chip *pchip;
611fc0589caSRobert Jarzmik 	struct pxa_gpio_bank *c;
612389eda15SHaojian Zhuang 	struct clk *clk;
613b95ace54SRobert Jarzmik 	struct pxa_gpio_platform_data *info;
614fc0589caSRobert Jarzmik 	void __iomem *gpio_reg_base;
615384ca3c6SRobert Jarzmik 	int gpio, ret;
616ae61bac9SWei Yongjun 	int irq0 = 0, irq1 = 0, irq_mux;
617354bf801SLinus Walleij 
618fc0589caSRobert Jarzmik 	pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL);
619fc0589caSRobert Jarzmik 	if (!pchip)
620fc0589caSRobert Jarzmik 		return -ENOMEM;
621fc0589caSRobert Jarzmik 	pchip->dev = &pdev->dev;
622fc0589caSRobert Jarzmik 
623b8f649f1SHaojian Zhuang 	info = dev_get_platdata(&pdev->dev);
624b8f649f1SHaojian Zhuang 	if (info) {
625b8f649f1SHaojian Zhuang 		irq_base = info->irq_base;
626b8f649f1SHaojian Zhuang 		if (irq_base <= 0)
627b8f649f1SHaojian Zhuang 			return -EINVAL;
6282cab0292SHaojian Zhuang 		pxa_last_gpio = pxa_gpio_nums(pdev);
629fc0589caSRobert Jarzmik 		pchip->set_wake = info->gpio_set_wake;
6309450be76SDaniel Mack 	} else {
631384ca3c6SRobert Jarzmik 		irq_base = pxa_gpio_probe_dt(pdev, pchip);
632384ca3c6SRobert Jarzmik 		if (irq_base < 0)
633b8f649f1SHaojian Zhuang 			return -EINVAL;
6349450be76SDaniel Mack 	}
6359450be76SDaniel Mack 
636478e223cSHaojian Zhuang 	if (!pxa_last_gpio)
637157d2644SHaojian Zhuang 		return -EINVAL;
638157d2644SHaojian Zhuang 
639384ca3c6SRobert Jarzmik 	pchip->irqdomain = irq_domain_add_legacy(pdev->dev.of_node,
640384ca3c6SRobert Jarzmik 						 pxa_last_gpio + 1, irq_base,
641384ca3c6SRobert Jarzmik 						 0, &pxa_irq_domain_ops, pchip);
64241d107adSDan Carpenter 	if (!pchip->irqdomain)
64341d107adSDan Carpenter 		return -ENOMEM;
644384ca3c6SRobert Jarzmik 
645a630fe34SLubomir Rintel 	irq0 = platform_get_irq_byname_optional(pdev, "gpio0");
646a630fe34SLubomir Rintel 	irq1 = platform_get_irq_byname_optional(pdev, "gpio1");
647157d2644SHaojian Zhuang 	irq_mux = platform_get_irq_byname(pdev, "gpio_mux");
648157d2644SHaojian Zhuang 	if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0)
649157d2644SHaojian Zhuang 		|| (irq_mux <= 0))
650157d2644SHaojian Zhuang 		return -EINVAL;
651384ca3c6SRobert Jarzmik 
652384ca3c6SRobert Jarzmik 	pchip->irq0 = irq0;
653384ca3c6SRobert Jarzmik 	pchip->irq1 = irq1;
654542c25b7SEnrico Weigelt, metux IT consult 
655542c25b7SEnrico Weigelt, metux IT consult 	gpio_reg_base = devm_platform_ioremap_resource(pdev, 0);
656558ab2e8STiezhu Yang 	if (IS_ERR(gpio_reg_base))
657558ab2e8STiezhu Yang 		return PTR_ERR(gpio_reg_base);
658157d2644SHaojian Zhuang 
6593f4e432fSBartosz Golaszewski 	clk = devm_clk_get_enabled(&pdev->dev, NULL);
660389eda15SHaojian Zhuang 	if (IS_ERR(clk)) {
661389eda15SHaojian Zhuang 		dev_err(&pdev->dev, "Error %ld to get gpio clock\n",
662389eda15SHaojian Zhuang 			PTR_ERR(clk));
663389eda15SHaojian Zhuang 		return PTR_ERR(clk);
664389eda15SHaojian Zhuang 	}
665389eda15SHaojian Zhuang 
666354bf801SLinus Walleij 	/* Initialize GPIO chips */
66745a541a6SAndy Shevchenko 	ret = pxa_init_gpio_chip(pchip, pxa_last_gpio + 1, gpio_reg_base);
6683f4e432fSBartosz Golaszewski 	if (ret)
669fc0589caSRobert Jarzmik 		return ret;
670354bf801SLinus Walleij 
671354bf801SLinus Walleij 	/* clear all GPIO edge detects */
672fc0589caSRobert Jarzmik 	for_each_gpio_bank(gpio, c, pchip) {
673df664d20SHaojian Zhuang 		writel_relaxed(0, c->regbase + GFER_OFFSET);
674df664d20SHaojian Zhuang 		writel_relaxed(0, c->regbase + GRER_OFFSET);
675df664d20SHaojian Zhuang 		writel_relaxed(~0, c->regbase + GEDR_OFFSET);
676be24168fSHaojian Zhuang 		/* unmask GPIO edge detect for AP side */
677be24168fSHaojian Zhuang 		if (gpio_is_mmp_type(gpio_type))
678be24168fSHaojian Zhuang 			writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
679354bf801SLinus Walleij 	}
680354bf801SLinus Walleij 
681ae4f4cfdSRob Herring 	if (irq0 > 0) {
682384ca3c6SRobert Jarzmik 		ret = devm_request_irq(&pdev->dev,
683384ca3c6SRobert Jarzmik 				       irq0, pxa_gpio_direct_handler, 0,
684384ca3c6SRobert Jarzmik 				       "gpio-0", pchip);
685384ca3c6SRobert Jarzmik 		if (ret)
686384ca3c6SRobert Jarzmik 			dev_err(&pdev->dev, "request of gpio0 irq failed: %d\n",
687384ca3c6SRobert Jarzmik 				ret);
688ae4f4cfdSRob Herring 	}
689ae4f4cfdSRob Herring 	if (irq1 > 0) {
690384ca3c6SRobert Jarzmik 		ret = devm_request_irq(&pdev->dev,
691384ca3c6SRobert Jarzmik 				       irq1, pxa_gpio_direct_handler, 0,
692384ca3c6SRobert Jarzmik 				       "gpio-1", pchip);
693384ca3c6SRobert Jarzmik 		if (ret)
694384ca3c6SRobert Jarzmik 			dev_err(&pdev->dev, "request of gpio1 irq failed: %d\n",
695384ca3c6SRobert Jarzmik 				ret);
696ae4f4cfdSRob Herring 	}
697384ca3c6SRobert Jarzmik 	ret = devm_request_irq(&pdev->dev,
698384ca3c6SRobert Jarzmik 			       irq_mux, pxa_gpio_demux_handler, 0,
699384ca3c6SRobert Jarzmik 				       "gpio-mux", pchip);
700384ca3c6SRobert Jarzmik 	if (ret)
701384ca3c6SRobert Jarzmik 		dev_err(&pdev->dev, "request of gpio-mux irq failed: %d\n",
702384ca3c6SRobert Jarzmik 				ret);
70387c49e20SHaojian Zhuang 
704fc0589caSRobert Jarzmik 	pxa_gpio_chip = pchip;
705354bf801SLinus Walleij 
706157d2644SHaojian Zhuang 	return 0;
707354bf801SLinus Walleij }
708354bf801SLinus Walleij 
7092cab0292SHaojian Zhuang static const struct platform_device_id gpio_id_table[] = {
7102cab0292SHaojian Zhuang 	{ "pxa25x-gpio",	(unsigned long)&pxa25x_id },
7112cab0292SHaojian Zhuang 	{ "pxa26x-gpio",	(unsigned long)&pxa26x_id },
7122cab0292SHaojian Zhuang 	{ "pxa27x-gpio",	(unsigned long)&pxa27x_id },
7132cab0292SHaojian Zhuang 	{ "pxa3xx-gpio",	(unsigned long)&pxa3xx_id },
7142cab0292SHaojian Zhuang 	{ "pxa93x-gpio",	(unsigned long)&pxa93x_id },
7152cab0292SHaojian Zhuang 	{ "mmp-gpio",		(unsigned long)&mmp_id },
7162cab0292SHaojian Zhuang 	{ "mmp2-gpio",		(unsigned long)&mmp2_id },
717684bba2fSRob Herring 	{ "pxa1928-gpio",	(unsigned long)&pxa1928_id },
7182cab0292SHaojian Zhuang 	{ },
7192cab0292SHaojian Zhuang };
7202cab0292SHaojian Zhuang 
721157d2644SHaojian Zhuang static struct platform_driver pxa_gpio_driver = {
722157d2644SHaojian Zhuang 	.probe		= pxa_gpio_probe,
723157d2644SHaojian Zhuang 	.driver		= {
724157d2644SHaojian Zhuang 		.name	= "pxa-gpio",
725f43e04ecSArnd Bergmann 		.of_match_table = of_match_ptr(pxa_gpio_dt_ids),
726157d2644SHaojian Zhuang 	},
7272cab0292SHaojian Zhuang 	.id_table	= gpio_id_table,
728157d2644SHaojian Zhuang };
729cf3fa17cSLinus Walleij 
pxa_gpio_legacy_init(void)730eae122b8SRobert Jarzmik static int __init pxa_gpio_legacy_init(void)
731cf3fa17cSLinus Walleij {
732eae122b8SRobert Jarzmik 	if (of_have_populated_dt())
733eae122b8SRobert Jarzmik 		return 0;
734eae122b8SRobert Jarzmik 
735cf3fa17cSLinus Walleij 	return platform_driver_register(&pxa_gpio_driver);
736cf3fa17cSLinus Walleij }
737eae122b8SRobert Jarzmik postcore_initcall(pxa_gpio_legacy_init);
738eae122b8SRobert Jarzmik 
pxa_gpio_dt_init(void)739eae122b8SRobert Jarzmik static int __init pxa_gpio_dt_init(void)
740eae122b8SRobert Jarzmik {
741eae122b8SRobert Jarzmik 	if (of_have_populated_dt())
742eae122b8SRobert Jarzmik 		return platform_driver_register(&pxa_gpio_driver);
743eae122b8SRobert Jarzmik 
744eae122b8SRobert Jarzmik 	return 0;
745eae122b8SRobert Jarzmik }
746eae122b8SRobert Jarzmik device_initcall(pxa_gpio_dt_init);
747157d2644SHaojian Zhuang 
748354bf801SLinus Walleij #ifdef CONFIG_PM
pxa_gpio_suspend(void)749354bf801SLinus Walleij static int pxa_gpio_suspend(void)
750354bf801SLinus Walleij {
751fc0589caSRobert Jarzmik 	struct pxa_gpio_chip *pchip = pxa_gpio_chip;
752fc0589caSRobert Jarzmik 	struct pxa_gpio_bank *c;
753354bf801SLinus Walleij 	int gpio;
754354bf801SLinus Walleij 
7559ce3ebe9SRobert Jarzmik 	if (!pchip)
7569ce3ebe9SRobert Jarzmik 		return 0;
7579ce3ebe9SRobert Jarzmik 
758fc0589caSRobert Jarzmik 	for_each_gpio_bank(gpio, c, pchip) {
759df664d20SHaojian Zhuang 		c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET);
760df664d20SHaojian Zhuang 		c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
761df664d20SHaojian Zhuang 		c->saved_grer = readl_relaxed(c->regbase + GRER_OFFSET);
762df664d20SHaojian Zhuang 		c->saved_gfer = readl_relaxed(c->regbase + GFER_OFFSET);
763354bf801SLinus Walleij 
764354bf801SLinus Walleij 		/* Clear GPIO transition detect bits */
765df664d20SHaojian Zhuang 		writel_relaxed(0xffffffff, c->regbase + GEDR_OFFSET);
766354bf801SLinus Walleij 	}
767354bf801SLinus Walleij 	return 0;
768354bf801SLinus Walleij }
769354bf801SLinus Walleij 
pxa_gpio_resume(void)770354bf801SLinus Walleij static void pxa_gpio_resume(void)
771354bf801SLinus Walleij {
772fc0589caSRobert Jarzmik 	struct pxa_gpio_chip *pchip = pxa_gpio_chip;
773fc0589caSRobert Jarzmik 	struct pxa_gpio_bank *c;
774354bf801SLinus Walleij 	int gpio;
775354bf801SLinus Walleij 
7769ce3ebe9SRobert Jarzmik 	if (!pchip)
7779ce3ebe9SRobert Jarzmik 		return;
7789ce3ebe9SRobert Jarzmik 
779fc0589caSRobert Jarzmik 	for_each_gpio_bank(gpio, c, pchip) {
780354bf801SLinus Walleij 		/* restore level with set/clear */
781df664d20SHaojian Zhuang 		writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET);
782df664d20SHaojian Zhuang 		writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET);
783354bf801SLinus Walleij 
784df664d20SHaojian Zhuang 		writel_relaxed(c->saved_grer, c->regbase + GRER_OFFSET);
785df664d20SHaojian Zhuang 		writel_relaxed(c->saved_gfer, c->regbase + GFER_OFFSET);
786df664d20SHaojian Zhuang 		writel_relaxed(c->saved_gpdr, c->regbase + GPDR_OFFSET);
787354bf801SLinus Walleij 	}
788354bf801SLinus Walleij }
789354bf801SLinus Walleij #else
790354bf801SLinus Walleij #define pxa_gpio_suspend	NULL
791354bf801SLinus Walleij #define pxa_gpio_resume		NULL
792354bf801SLinus Walleij #endif
793354bf801SLinus Walleij 
7941e9aa2a8SYueHaibing static struct syscore_ops pxa_gpio_syscore_ops = {
795354bf801SLinus Walleij 	.suspend	= pxa_gpio_suspend,
796354bf801SLinus Walleij 	.resume		= pxa_gpio_resume,
797354bf801SLinus Walleij };
798157d2644SHaojian Zhuang 
pxa_gpio_sysinit(void)799157d2644SHaojian Zhuang static int __init pxa_gpio_sysinit(void)
800157d2644SHaojian Zhuang {
801157d2644SHaojian Zhuang 	register_syscore_ops(&pxa_gpio_syscore_ops);
802157d2644SHaojian Zhuang 	return 0;
803157d2644SHaojian Zhuang }
804157d2644SHaojian Zhuang postcore_initcall(pxa_gpio_sysinit);
805