xref: /openbmc/linux/drivers/pinctrl/samsung/pinctrl-s3c64xx.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1221173a3SKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0+
2221173a3SKrzysztof Kozlowski //
3221173a3SKrzysztof Kozlowski // S3C64xx specific support for pinctrl-samsung driver.
4221173a3SKrzysztof Kozlowski //
5221173a3SKrzysztof Kozlowski // Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
6221173a3SKrzysztof Kozlowski //
7221173a3SKrzysztof Kozlowski // Based on pinctrl-exynos.c, please see the file for original copyrights.
8221173a3SKrzysztof Kozlowski //
9221173a3SKrzysztof Kozlowski // This file contains the Samsung S3C64xx specific information required by the
10221173a3SKrzysztof Kozlowski // the Samsung pinctrl/gpiolib driver. It also includes the implementation of
11221173a3SKrzysztof Kozlowski // external gpio and wakeup interrupt support.
12ebe629a3SSachin Kamat 
138208b28aSPaul Gortmaker #include <linux/init.h>
14ebe629a3SSachin Kamat #include <linux/device.h>
15ebe629a3SSachin Kamat #include <linux/interrupt.h>
16ebe629a3SSachin Kamat #include <linux/irqdomain.h>
17ebe629a3SSachin Kamat #include <linux/irq.h>
18ebe629a3SSachin Kamat #include <linux/of_irq.h>
19ebe629a3SSachin Kamat #include <linux/io.h>
20ebe629a3SSachin Kamat #include <linux/irqchip/chained_irq.h>
21ebe629a3SSachin Kamat #include <linux/slab.h>
22ebe629a3SSachin Kamat #include <linux/err.h>
23ebe629a3SSachin Kamat 
24ebe629a3SSachin Kamat #include "pinctrl-samsung.h"
25ebe629a3SSachin Kamat 
26ebe629a3SSachin Kamat #define NUM_EINT0		28
27ebe629a3SSachin Kamat #define NUM_EINT0_IRQ		4
28ebe629a3SSachin Kamat #define EINT_MAX_PER_REG	16
29ebe629a3SSachin Kamat #define EINT_MAX_PER_GROUP	16
30ebe629a3SSachin Kamat 
31ebe629a3SSachin Kamat /* External GPIO and wakeup interrupt related definitions */
32ebe629a3SSachin Kamat #define SVC_GROUP_SHIFT		4
33ebe629a3SSachin Kamat #define SVC_GROUP_MASK		0xf
34ebe629a3SSachin Kamat #define SVC_NUM_MASK		0xf
35ebe629a3SSachin Kamat #define SVC_GROUP(x)		((x >> SVC_GROUP_SHIFT) & \
36ebe629a3SSachin Kamat 						SVC_GROUP_MASK)
37ebe629a3SSachin Kamat 
38ebe629a3SSachin Kamat #define EINT12CON_REG		0x200
39ebe629a3SSachin Kamat #define EINT12MASK_REG		0x240
40ebe629a3SSachin Kamat #define EINT12PEND_REG		0x260
41ebe629a3SSachin Kamat 
42ebe629a3SSachin Kamat #define EINT_OFFS(i)		((i) % (2 * EINT_MAX_PER_GROUP))
43ebe629a3SSachin Kamat #define EINT_GROUP(i)		((i) / EINT_MAX_PER_GROUP)
44ebe629a3SSachin Kamat #define EINT_REG(g)		(4 * ((g) / 2))
45ebe629a3SSachin Kamat 
46ebe629a3SSachin Kamat #define EINTCON_REG(i)		(EINT12CON_REG + EINT_REG(EINT_GROUP(i)))
47ebe629a3SSachin Kamat #define EINTMASK_REG(i)		(EINT12MASK_REG + EINT_REG(EINT_GROUP(i)))
48ebe629a3SSachin Kamat #define EINTPEND_REG(i)		(EINT12PEND_REG + EINT_REG(EINT_GROUP(i)))
49ebe629a3SSachin Kamat 
50ebe629a3SSachin Kamat #define SERVICE_REG		0x284
51ebe629a3SSachin Kamat #define SERVICEPEND_REG		0x288
52ebe629a3SSachin Kamat 
53ebe629a3SSachin Kamat #define EINT0CON0_REG		0x900
54ebe629a3SSachin Kamat #define EINT0MASK_REG		0x920
55ebe629a3SSachin Kamat #define EINT0PEND_REG		0x924
56ebe629a3SSachin Kamat 
57ebe629a3SSachin Kamat /* S3C64xx specific external interrupt trigger types */
58ebe629a3SSachin Kamat #define EINT_LEVEL_LOW		0
59ebe629a3SSachin Kamat #define EINT_LEVEL_HIGH		1
60ebe629a3SSachin Kamat #define EINT_EDGE_FALLING	2
61ebe629a3SSachin Kamat #define EINT_EDGE_RISING	4
62ebe629a3SSachin Kamat #define EINT_EDGE_BOTH		6
63ebe629a3SSachin Kamat #define EINT_CON_MASK		0xF
64ebe629a3SSachin Kamat #define EINT_CON_LEN		4
65ebe629a3SSachin Kamat 
6694ce944bSTomasz Figa static const struct samsung_pin_bank_type bank_type_4bit_off = {
67ebe629a3SSachin Kamat 	.fld_width = { 4, 1, 2, 0, 2, 2, },
68ebe629a3SSachin Kamat 	.reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
69ebe629a3SSachin Kamat };
70ebe629a3SSachin Kamat 
7194ce944bSTomasz Figa static const struct samsung_pin_bank_type bank_type_4bit_alive = {
72ebe629a3SSachin Kamat 	.fld_width = { 4, 1, 2, },
73ebe629a3SSachin Kamat 	.reg_offset = { 0x00, 0x04, 0x08, },
74ebe629a3SSachin Kamat };
75ebe629a3SSachin Kamat 
7694ce944bSTomasz Figa static const struct samsung_pin_bank_type bank_type_4bit2_off = {
77ebe629a3SSachin Kamat 	.fld_width = { 4, 1, 2, 0, 2, 2, },
78ebe629a3SSachin Kamat 	.reg_offset = { 0x00, 0x08, 0x0c, 0, 0x10, 0x14, },
79ebe629a3SSachin Kamat };
80ebe629a3SSachin Kamat 
8194ce944bSTomasz Figa static const struct samsung_pin_bank_type bank_type_4bit2_alive = {
82ebe629a3SSachin Kamat 	.fld_width = { 4, 1, 2, },
83ebe629a3SSachin Kamat 	.reg_offset = { 0x00, 0x08, 0x0c, },
84ebe629a3SSachin Kamat };
85ebe629a3SSachin Kamat 
8694ce944bSTomasz Figa static const struct samsung_pin_bank_type bank_type_2bit_off = {
87ebe629a3SSachin Kamat 	.fld_width = { 2, 1, 2, 0, 2, 2, },
88ebe629a3SSachin Kamat 	.reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
89ebe629a3SSachin Kamat };
90ebe629a3SSachin Kamat 
9194ce944bSTomasz Figa static const struct samsung_pin_bank_type bank_type_2bit_alive = {
92ebe629a3SSachin Kamat 	.fld_width = { 2, 1, 2, },
93ebe629a3SSachin Kamat 	.reg_offset = { 0x00, 0x04, 0x08, },
94ebe629a3SSachin Kamat };
95ebe629a3SSachin Kamat 
96ebe629a3SSachin Kamat #define PIN_BANK_4BIT(pins, reg, id)			\
97ebe629a3SSachin Kamat 	{						\
98ebe629a3SSachin Kamat 		.type		= &bank_type_4bit_off,	\
99ebe629a3SSachin Kamat 		.pctl_offset	= reg,			\
100ebe629a3SSachin Kamat 		.nr_pins	= pins,			\
101ebe629a3SSachin Kamat 		.eint_type	= EINT_TYPE_NONE,	\
102ebe629a3SSachin Kamat 		.name		= id			\
103ebe629a3SSachin Kamat 	}
104ebe629a3SSachin Kamat 
105ebe629a3SSachin Kamat #define PIN_BANK_4BIT_EINTG(pins, reg, id, eoffs)	\
106ebe629a3SSachin Kamat 	{						\
107ebe629a3SSachin Kamat 		.type		= &bank_type_4bit_off,	\
108ebe629a3SSachin Kamat 		.pctl_offset	= reg,			\
109ebe629a3SSachin Kamat 		.nr_pins	= pins,			\
110ebe629a3SSachin Kamat 		.eint_type	= EINT_TYPE_GPIO,	\
111ebe629a3SSachin Kamat 		.eint_func	= 7,			\
112ebe629a3SSachin Kamat 		.eint_mask	= (1 << (pins)) - 1,	\
113ebe629a3SSachin Kamat 		.eint_offset	= eoffs,		\
114ebe629a3SSachin Kamat 		.name		= id			\
115ebe629a3SSachin Kamat 	}
116ebe629a3SSachin Kamat 
117ebe629a3SSachin Kamat #define PIN_BANK_4BIT_EINTW(pins, reg, id, eoffs, emask) \
118ebe629a3SSachin Kamat 	{						\
119ebe629a3SSachin Kamat 		.type		= &bank_type_4bit_alive,\
120ebe629a3SSachin Kamat 		.pctl_offset	= reg,			\
121ebe629a3SSachin Kamat 		.nr_pins	= pins,			\
122ebe629a3SSachin Kamat 		.eint_type	= EINT_TYPE_WKUP,	\
123ebe629a3SSachin Kamat 		.eint_func	= 3,			\
124ebe629a3SSachin Kamat 		.eint_mask	= emask,		\
125ebe629a3SSachin Kamat 		.eint_offset	= eoffs,		\
126ebe629a3SSachin Kamat 		.name		= id			\
127ebe629a3SSachin Kamat 	}
128ebe629a3SSachin Kamat 
129ebe629a3SSachin Kamat #define PIN_BANK_4BIT2_EINTG(pins, reg, id, eoffs)	\
130ebe629a3SSachin Kamat 	{						\
131ebe629a3SSachin Kamat 		.type		= &bank_type_4bit2_off,	\
132ebe629a3SSachin Kamat 		.pctl_offset	= reg,			\
133ebe629a3SSachin Kamat 		.nr_pins	= pins,			\
134ebe629a3SSachin Kamat 		.eint_type	= EINT_TYPE_GPIO,	\
135ebe629a3SSachin Kamat 		.eint_func	= 7,			\
136ebe629a3SSachin Kamat 		.eint_mask	= (1 << (pins)) - 1,	\
137ebe629a3SSachin Kamat 		.eint_offset	= eoffs,		\
138ebe629a3SSachin Kamat 		.name		= id			\
139ebe629a3SSachin Kamat 	}
140ebe629a3SSachin Kamat 
141ebe629a3SSachin Kamat #define PIN_BANK_4BIT2_EINTW(pins, reg, id, eoffs, emask) \
142ebe629a3SSachin Kamat 	{						\
143ebe629a3SSachin Kamat 		.type		= &bank_type_4bit2_alive,\
144ebe629a3SSachin Kamat 		.pctl_offset	= reg,			\
145ebe629a3SSachin Kamat 		.nr_pins	= pins,			\
146ebe629a3SSachin Kamat 		.eint_type	= EINT_TYPE_WKUP,	\
147ebe629a3SSachin Kamat 		.eint_func	= 3,			\
148ebe629a3SSachin Kamat 		.eint_mask	= emask,		\
149ebe629a3SSachin Kamat 		.eint_offset	= eoffs,		\
150ebe629a3SSachin Kamat 		.name		= id			\
151ebe629a3SSachin Kamat 	}
152ebe629a3SSachin Kamat 
153ebe629a3SSachin Kamat #define PIN_BANK_4BIT2_ALIVE(pins, reg, id)		\
154ebe629a3SSachin Kamat 	{						\
155ebe629a3SSachin Kamat 		.type		= &bank_type_4bit2_alive,\
156ebe629a3SSachin Kamat 		.pctl_offset	= reg,			\
157ebe629a3SSachin Kamat 		.nr_pins	= pins,			\
158ebe629a3SSachin Kamat 		.eint_type	= EINT_TYPE_NONE,	\
159ebe629a3SSachin Kamat 		.name		= id			\
160ebe629a3SSachin Kamat 	}
161ebe629a3SSachin Kamat 
162ebe629a3SSachin Kamat #define PIN_BANK_2BIT(pins, reg, id)			\
163ebe629a3SSachin Kamat 	{						\
164ebe629a3SSachin Kamat 		.type		= &bank_type_2bit_off,	\
165ebe629a3SSachin Kamat 		.pctl_offset	= reg,			\
166ebe629a3SSachin Kamat 		.nr_pins	= pins,			\
167ebe629a3SSachin Kamat 		.eint_type	= EINT_TYPE_NONE,	\
168ebe629a3SSachin Kamat 		.name		= id			\
169ebe629a3SSachin Kamat 	}
170ebe629a3SSachin Kamat 
171ebe629a3SSachin Kamat #define PIN_BANK_2BIT_EINTG(pins, reg, id, eoffs, emask) \
172ebe629a3SSachin Kamat 	{						\
173ebe629a3SSachin Kamat 		.type		= &bank_type_2bit_off,	\
174ebe629a3SSachin Kamat 		.pctl_offset	= reg,			\
175ebe629a3SSachin Kamat 		.nr_pins	= pins,			\
176ebe629a3SSachin Kamat 		.eint_type	= EINT_TYPE_GPIO,	\
177ebe629a3SSachin Kamat 		.eint_func	= 3,			\
178ebe629a3SSachin Kamat 		.eint_mask	= emask,		\
179ebe629a3SSachin Kamat 		.eint_offset	= eoffs,		\
180ebe629a3SSachin Kamat 		.name		= id			\
181ebe629a3SSachin Kamat 	}
182ebe629a3SSachin Kamat 
183ebe629a3SSachin Kamat #define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs)	\
184ebe629a3SSachin Kamat 	{						\
185ebe629a3SSachin Kamat 		.type		= &bank_type_2bit_alive,\
186ebe629a3SSachin Kamat 		.pctl_offset	= reg,			\
187ebe629a3SSachin Kamat 		.nr_pins	= pins,			\
188ebe629a3SSachin Kamat 		.eint_type	= EINT_TYPE_WKUP,	\
189ebe629a3SSachin Kamat 		.eint_func	= 2,			\
190ebe629a3SSachin Kamat 		.eint_mask	= (1 << (pins)) - 1,	\
191ebe629a3SSachin Kamat 		.eint_offset	= eoffs,		\
192ebe629a3SSachin Kamat 		.name		= id			\
193ebe629a3SSachin Kamat 	}
194ebe629a3SSachin Kamat 
195ebe629a3SSachin Kamat /**
1960dc0bdf0SLee Jones  * struct s3c64xx_eint0_data - EINT0 common data
197ebe629a3SSachin Kamat  * @drvdata: pin controller driver data
198ebe629a3SSachin Kamat  * @domains: IRQ domains of particular EINT0 interrupts
199ebe629a3SSachin Kamat  * @pins: pin offsets inside of banks of particular EINT0 interrupts
200ebe629a3SSachin Kamat  */
201ebe629a3SSachin Kamat struct s3c64xx_eint0_data {
202ebe629a3SSachin Kamat 	struct samsung_pinctrl_drv_data *drvdata;
203ebe629a3SSachin Kamat 	struct irq_domain *domains[NUM_EINT0];
204ebe629a3SSachin Kamat 	u8 pins[NUM_EINT0];
205ebe629a3SSachin Kamat };
206ebe629a3SSachin Kamat 
207ebe629a3SSachin Kamat /**
2080dc0bdf0SLee Jones  * struct s3c64xx_eint0_domain_data - EINT0 per-domain data
209ebe629a3SSachin Kamat  * @bank: pin bank related to the domain
210ebe629a3SSachin Kamat  * @eints: EINT0 interrupts related to the domain
211ebe629a3SSachin Kamat  */
212ebe629a3SSachin Kamat struct s3c64xx_eint0_domain_data {
213ebe629a3SSachin Kamat 	struct samsung_pin_bank *bank;
214ebe629a3SSachin Kamat 	u8 eints[];
215ebe629a3SSachin Kamat };
216ebe629a3SSachin Kamat 
217ebe629a3SSachin Kamat /**
2180dc0bdf0SLee Jones  * struct s3c64xx_eint_gpio_data - GPIO EINT data
219ebe629a3SSachin Kamat  * @drvdata: pin controller driver data
220ebe629a3SSachin Kamat  * @domains: array of domains related to EINT interrupt groups
221ebe629a3SSachin Kamat  */
222ebe629a3SSachin Kamat struct s3c64xx_eint_gpio_data {
223ebe629a3SSachin Kamat 	struct samsung_pinctrl_drv_data *drvdata;
224ebe629a3SSachin Kamat 	struct irq_domain *domains[];
225ebe629a3SSachin Kamat };
226ebe629a3SSachin Kamat 
227ebe629a3SSachin Kamat /*
228ebe629a3SSachin Kamat  * Common functions for S3C64xx EINT configuration
229ebe629a3SSachin Kamat  */
230ebe629a3SSachin Kamat 
s3c64xx_irq_get_trigger(unsigned int type)231ebe629a3SSachin Kamat static int s3c64xx_irq_get_trigger(unsigned int type)
232ebe629a3SSachin Kamat {
233ebe629a3SSachin Kamat 	int trigger;
234ebe629a3SSachin Kamat 
235ebe629a3SSachin Kamat 	switch (type) {
236ebe629a3SSachin Kamat 	case IRQ_TYPE_EDGE_RISING:
237ebe629a3SSachin Kamat 		trigger = EINT_EDGE_RISING;
238ebe629a3SSachin Kamat 		break;
239ebe629a3SSachin Kamat 	case IRQ_TYPE_EDGE_FALLING:
240ebe629a3SSachin Kamat 		trigger = EINT_EDGE_FALLING;
241ebe629a3SSachin Kamat 		break;
242ebe629a3SSachin Kamat 	case IRQ_TYPE_EDGE_BOTH:
243ebe629a3SSachin Kamat 		trigger = EINT_EDGE_BOTH;
244ebe629a3SSachin Kamat 		break;
245ebe629a3SSachin Kamat 	case IRQ_TYPE_LEVEL_HIGH:
246ebe629a3SSachin Kamat 		trigger = EINT_LEVEL_HIGH;
247ebe629a3SSachin Kamat 		break;
248ebe629a3SSachin Kamat 	case IRQ_TYPE_LEVEL_LOW:
249ebe629a3SSachin Kamat 		trigger = EINT_LEVEL_LOW;
250ebe629a3SSachin Kamat 		break;
251ebe629a3SSachin Kamat 	default:
252ebe629a3SSachin Kamat 		return -EINVAL;
253ebe629a3SSachin Kamat 	}
254ebe629a3SSachin Kamat 
255ebe629a3SSachin Kamat 	return trigger;
256ebe629a3SSachin Kamat }
257ebe629a3SSachin Kamat 
s3c64xx_irq_set_handler(struct irq_data * d,unsigned int type)258f66eb498SThomas Gleixner static void s3c64xx_irq_set_handler(struct irq_data *d, unsigned int type)
259ebe629a3SSachin Kamat {
260ebe629a3SSachin Kamat 	/* Edge- and level-triggered interrupts need different handlers */
261ebe629a3SSachin Kamat 	if (type & IRQ_TYPE_EDGE_BOTH)
262f66eb498SThomas Gleixner 		irq_set_handler_locked(d, handle_edge_irq);
263ebe629a3SSachin Kamat 	else
264f66eb498SThomas Gleixner 		irq_set_handler_locked(d, handle_level_irq);
265ebe629a3SSachin Kamat }
266ebe629a3SSachin Kamat 
s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data * d,struct samsung_pin_bank * bank,int pin)267ebe629a3SSachin Kamat static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d,
268ebe629a3SSachin Kamat 					struct samsung_pin_bank *bank, int pin)
269ebe629a3SSachin Kamat {
27094ce944bSTomasz Figa 	const struct samsung_pin_bank_type *bank_type = bank->type;
271ebe629a3SSachin Kamat 	unsigned long flags;
272ebe629a3SSachin Kamat 	void __iomem *reg;
273ebe629a3SSachin Kamat 	u8 shift;
274ebe629a3SSachin Kamat 	u32 mask;
275ebe629a3SSachin Kamat 	u32 val;
276ebe629a3SSachin Kamat 
277ebe629a3SSachin Kamat 	/* Make sure that pin is configured as interrupt */
278cee7413dSKrzysztof Kozlowski 	reg = d->virt_base + bank->pctl_offset;
279ebe629a3SSachin Kamat 	shift = pin;
280ebe629a3SSachin Kamat 	if (bank_type->fld_width[PINCFG_TYPE_FUNC] * shift >= 32) {
281ebe629a3SSachin Kamat 		/* 4-bit bank type with 2 con regs */
282ebe629a3SSachin Kamat 		reg += 4;
283ebe629a3SSachin Kamat 		shift -= 8;
284ebe629a3SSachin Kamat 	}
285ebe629a3SSachin Kamat 
286ebe629a3SSachin Kamat 	shift = shift * bank_type->fld_width[PINCFG_TYPE_FUNC];
287ebe629a3SSachin Kamat 	mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
288ebe629a3SSachin Kamat 
289ef1e2150SChanho Park 	raw_spin_lock_irqsave(&bank->slock, flags);
290ebe629a3SSachin Kamat 
291ebe629a3SSachin Kamat 	val = readl(reg);
292ebe629a3SSachin Kamat 	val &= ~(mask << shift);
293ebe629a3SSachin Kamat 	val |= bank->eint_func << shift;
294ebe629a3SSachin Kamat 	writel(val, reg);
295ebe629a3SSachin Kamat 
296ef1e2150SChanho Park 	raw_spin_unlock_irqrestore(&bank->slock, flags);
297ebe629a3SSachin Kamat }
298ebe629a3SSachin Kamat 
299ebe629a3SSachin Kamat /*
300ebe629a3SSachin Kamat  * Functions for EINT GPIO configuration (EINT groups 1-9)
301ebe629a3SSachin Kamat  */
302ebe629a3SSachin Kamat 
s3c64xx_gpio_irq_set_mask(struct irq_data * irqd,bool mask)303ebe629a3SSachin Kamat static inline void s3c64xx_gpio_irq_set_mask(struct irq_data *irqd, bool mask)
304ebe629a3SSachin Kamat {
305ebe629a3SSachin Kamat 	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
306cee7413dSKrzysztof Kozlowski 	struct samsung_pinctrl_drv_data *d = bank->drvdata;
307ebe629a3SSachin Kamat 	unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
308cee7413dSKrzysztof Kozlowski 	void __iomem *reg = d->virt_base + EINTMASK_REG(bank->eint_offset);
309ebe629a3SSachin Kamat 	u32 val;
310ebe629a3SSachin Kamat 
311ebe629a3SSachin Kamat 	val = readl(reg);
312ebe629a3SSachin Kamat 	if (mask)
313ebe629a3SSachin Kamat 		val |= 1 << index;
314ebe629a3SSachin Kamat 	else
315ebe629a3SSachin Kamat 		val &= ~(1 << index);
316ebe629a3SSachin Kamat 	writel(val, reg);
317ebe629a3SSachin Kamat }
318ebe629a3SSachin Kamat 
s3c64xx_gpio_irq_unmask(struct irq_data * irqd)319ebe629a3SSachin Kamat static void s3c64xx_gpio_irq_unmask(struct irq_data *irqd)
320ebe629a3SSachin Kamat {
321ebe629a3SSachin Kamat 	s3c64xx_gpio_irq_set_mask(irqd, false);
322ebe629a3SSachin Kamat }
323ebe629a3SSachin Kamat 
s3c64xx_gpio_irq_mask(struct irq_data * irqd)324ebe629a3SSachin Kamat static void s3c64xx_gpio_irq_mask(struct irq_data *irqd)
325ebe629a3SSachin Kamat {
326ebe629a3SSachin Kamat 	s3c64xx_gpio_irq_set_mask(irqd, true);
327ebe629a3SSachin Kamat }
328ebe629a3SSachin Kamat 
s3c64xx_gpio_irq_ack(struct irq_data * irqd)329ebe629a3SSachin Kamat static void s3c64xx_gpio_irq_ack(struct irq_data *irqd)
330ebe629a3SSachin Kamat {
331ebe629a3SSachin Kamat 	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
332cee7413dSKrzysztof Kozlowski 	struct samsung_pinctrl_drv_data *d = bank->drvdata;
333ebe629a3SSachin Kamat 	unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
334cee7413dSKrzysztof Kozlowski 	void __iomem *reg = d->virt_base + EINTPEND_REG(bank->eint_offset);
335ebe629a3SSachin Kamat 
336ebe629a3SSachin Kamat 	writel(1 << index, reg);
337ebe629a3SSachin Kamat }
338ebe629a3SSachin Kamat 
s3c64xx_gpio_irq_set_type(struct irq_data * irqd,unsigned int type)339ebe629a3SSachin Kamat static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
340ebe629a3SSachin Kamat {
341ebe629a3SSachin Kamat 	struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
342ebe629a3SSachin Kamat 	struct samsung_pinctrl_drv_data *d = bank->drvdata;
343ebe629a3SSachin Kamat 	void __iomem *reg;
344ebe629a3SSachin Kamat 	int trigger;
345ebe629a3SSachin Kamat 	u8 shift;
346ebe629a3SSachin Kamat 	u32 val;
347ebe629a3SSachin Kamat 
348ebe629a3SSachin Kamat 	trigger = s3c64xx_irq_get_trigger(type);
349ebe629a3SSachin Kamat 	if (trigger < 0) {
350ebe629a3SSachin Kamat 		pr_err("unsupported external interrupt type\n");
351ebe629a3SSachin Kamat 		return -EINVAL;
352ebe629a3SSachin Kamat 	}
353ebe629a3SSachin Kamat 
354f66eb498SThomas Gleixner 	s3c64xx_irq_set_handler(irqd, type);
355ebe629a3SSachin Kamat 
356ebe629a3SSachin Kamat 	/* Set up interrupt trigger */
357cee7413dSKrzysztof Kozlowski 	reg = d->virt_base + EINTCON_REG(bank->eint_offset);
358ebe629a3SSachin Kamat 	shift = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
359ebe629a3SSachin Kamat 	shift = 4 * (shift / 4); /* 4 EINTs per trigger selector */
360ebe629a3SSachin Kamat 
361ebe629a3SSachin Kamat 	val = readl(reg);
362ebe629a3SSachin Kamat 	val &= ~(EINT_CON_MASK << shift);
363ebe629a3SSachin Kamat 	val |= trigger << shift;
364ebe629a3SSachin Kamat 	writel(val, reg);
365ebe629a3SSachin Kamat 
366ebe629a3SSachin Kamat 	s3c64xx_irq_set_function(d, bank, irqd->hwirq);
367ebe629a3SSachin Kamat 
368ebe629a3SSachin Kamat 	return 0;
369ebe629a3SSachin Kamat }
370ebe629a3SSachin Kamat 
371ebe629a3SSachin Kamat /*
372ebe629a3SSachin Kamat  * irq_chip for gpio interrupts.
373ebe629a3SSachin Kamat  */
374ebe629a3SSachin Kamat static struct irq_chip s3c64xx_gpio_irq_chip = {
375ebe629a3SSachin Kamat 	.name		= "GPIO",
376ebe629a3SSachin Kamat 	.irq_unmask	= s3c64xx_gpio_irq_unmask,
377ebe629a3SSachin Kamat 	.irq_mask	= s3c64xx_gpio_irq_mask,
378ebe629a3SSachin Kamat 	.irq_ack	= s3c64xx_gpio_irq_ack,
379ebe629a3SSachin Kamat 	.irq_set_type	= s3c64xx_gpio_irq_set_type,
380ebe629a3SSachin Kamat };
381ebe629a3SSachin Kamat 
s3c64xx_gpio_irq_map(struct irq_domain * h,unsigned int virq,irq_hw_number_t hw)382ebe629a3SSachin Kamat static int s3c64xx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
383ebe629a3SSachin Kamat 					irq_hw_number_t hw)
384ebe629a3SSachin Kamat {
385ebe629a3SSachin Kamat 	struct samsung_pin_bank *bank = h->host_data;
386ebe629a3SSachin Kamat 
387ebe629a3SSachin Kamat 	if (!(bank->eint_mask & (1 << hw)))
388ebe629a3SSachin Kamat 		return -EINVAL;
389ebe629a3SSachin Kamat 
390ebe629a3SSachin Kamat 	irq_set_chip_and_handler(virq,
391ebe629a3SSachin Kamat 				&s3c64xx_gpio_irq_chip, handle_level_irq);
392ebe629a3SSachin Kamat 	irq_set_chip_data(virq, bank);
393ebe629a3SSachin Kamat 
394ebe629a3SSachin Kamat 	return 0;
395ebe629a3SSachin Kamat }
396ebe629a3SSachin Kamat 
397ebe629a3SSachin Kamat /*
398ebe629a3SSachin Kamat  * irq domain callbacks for external gpio interrupt controller.
399ebe629a3SSachin Kamat  */
400ebe629a3SSachin Kamat static const struct irq_domain_ops s3c64xx_gpio_irqd_ops = {
401ebe629a3SSachin Kamat 	.map	= s3c64xx_gpio_irq_map,
402ebe629a3SSachin Kamat 	.xlate	= irq_domain_xlate_twocell,
403ebe629a3SSachin Kamat };
404ebe629a3SSachin Kamat 
s3c64xx_eint_gpio_irq(struct irq_desc * desc)405bd0b9ac4SThomas Gleixner static void s3c64xx_eint_gpio_irq(struct irq_desc *desc)
406ebe629a3SSachin Kamat {
4075663bb27SJiang Liu 	struct irq_chip *chip = irq_desc_get_chip(desc);
4085663bb27SJiang Liu 	struct s3c64xx_eint_gpio_data *data = irq_desc_get_handler_data(desc);
409cee7413dSKrzysztof Kozlowski 	struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
410ebe629a3SSachin Kamat 
411ebe629a3SSachin Kamat 	chained_irq_enter(chip, desc);
412ebe629a3SSachin Kamat 
413ebe629a3SSachin Kamat 	do {
414ebe629a3SSachin Kamat 		unsigned int svc;
415ebe629a3SSachin Kamat 		unsigned int group;
416ebe629a3SSachin Kamat 		unsigned int pin;
417a9cb09b7SMarc Zyngier 		int ret;
418ebe629a3SSachin Kamat 
419cee7413dSKrzysztof Kozlowski 		svc = readl(drvdata->virt_base + SERVICE_REG);
420ebe629a3SSachin Kamat 		group = SVC_GROUP(svc);
421ebe629a3SSachin Kamat 		pin = svc & SVC_NUM_MASK;
422ebe629a3SSachin Kamat 
423ebe629a3SSachin Kamat 		if (!group)
424ebe629a3SSachin Kamat 			break;
425ebe629a3SSachin Kamat 
426ebe629a3SSachin Kamat 		/* Group 1 is used for two pin banks */
427ebe629a3SSachin Kamat 		if (group == 1) {
428ebe629a3SSachin Kamat 			if (pin < 8)
429ebe629a3SSachin Kamat 				group = 0;
430ebe629a3SSachin Kamat 			else
431ebe629a3SSachin Kamat 				pin -= 8;
432ebe629a3SSachin Kamat 		}
433ebe629a3SSachin Kamat 
434a9cb09b7SMarc Zyngier 		ret = generic_handle_domain_irq(data->domains[group], pin);
435ebe629a3SSachin Kamat 		/*
436ebe629a3SSachin Kamat 		 * Something must be really wrong if an unmapped EINT
437ebe629a3SSachin Kamat 		 * was unmasked...
438ebe629a3SSachin Kamat 		 */
439a9cb09b7SMarc Zyngier 		BUG_ON(ret);
440ebe629a3SSachin Kamat 	} while (1);
441ebe629a3SSachin Kamat 
442ebe629a3SSachin Kamat 	chained_irq_exit(chip, desc);
443ebe629a3SSachin Kamat }
444ebe629a3SSachin Kamat 
445ebe629a3SSachin Kamat /**
446ebe629a3SSachin Kamat  * s3c64xx_eint_gpio_init() - setup handling of external gpio interrupts.
447ebe629a3SSachin Kamat  * @d: driver data of samsung pinctrl driver.
448ebe629a3SSachin Kamat  */
s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data * d)449ebe629a3SSachin Kamat static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
450ebe629a3SSachin Kamat {
451ebe629a3SSachin Kamat 	struct s3c64xx_eint_gpio_data *data;
452ebe629a3SSachin Kamat 	struct samsung_pin_bank *bank;
453ebe629a3SSachin Kamat 	struct device *dev = d->dev;
454ebe629a3SSachin Kamat 	unsigned int nr_domains;
455ebe629a3SSachin Kamat 	unsigned int i;
456ebe629a3SSachin Kamat 
457ebe629a3SSachin Kamat 	if (!d->irq) {
458ebe629a3SSachin Kamat 		dev_err(dev, "irq number not available\n");
459ebe629a3SSachin Kamat 		return -EINVAL;
460ebe629a3SSachin Kamat 	}
461ebe629a3SSachin Kamat 
462ebe629a3SSachin Kamat 	nr_domains = 0;
4631bf00d7aSTomasz Figa 	bank = d->pin_banks;
4641bf00d7aSTomasz Figa 	for (i = 0; i < d->nr_banks; ++i, ++bank) {
465ebe629a3SSachin Kamat 		unsigned int nr_eints;
466ebe629a3SSachin Kamat 		unsigned int mask;
467ebe629a3SSachin Kamat 
468ebe629a3SSachin Kamat 		if (bank->eint_type != EINT_TYPE_GPIO)
469ebe629a3SSachin Kamat 			continue;
470ebe629a3SSachin Kamat 
471ebe629a3SSachin Kamat 		mask = bank->eint_mask;
472ebe629a3SSachin Kamat 		nr_eints = fls(mask);
473ebe629a3SSachin Kamat 
474*492fca28SAndy Shevchenko 		bank->irq_domain = irq_domain_create_linear(bank->fwnode,
475ebe629a3SSachin Kamat 					nr_eints, &s3c64xx_gpio_irqd_ops, bank);
476ebe629a3SSachin Kamat 		if (!bank->irq_domain) {
477ebe629a3SSachin Kamat 			dev_err(dev, "gpio irq domain add failed\n");
478ebe629a3SSachin Kamat 			return -ENXIO;
479ebe629a3SSachin Kamat 		}
480ebe629a3SSachin Kamat 
481ebe629a3SSachin Kamat 		++nr_domains;
482ebe629a3SSachin Kamat 	}
483ebe629a3SSachin Kamat 
4840ed2dd03SKees Cook 	data = devm_kzalloc(dev, struct_size(data, domains, nr_domains),
4850ed2dd03SKees Cook 			    GFP_KERNEL);
486fa5c0f46SMarek Szyprowski 	if (!data)
487ebe629a3SSachin Kamat 		return -ENOMEM;
488ebe629a3SSachin Kamat 	data->drvdata = d;
489ebe629a3SSachin Kamat 
4901bf00d7aSTomasz Figa 	bank = d->pin_banks;
491ebe629a3SSachin Kamat 	nr_domains = 0;
4921bf00d7aSTomasz Figa 	for (i = 0; i < d->nr_banks; ++i, ++bank) {
493ebe629a3SSachin Kamat 		if (bank->eint_type != EINT_TYPE_GPIO)
494ebe629a3SSachin Kamat 			continue;
495ebe629a3SSachin Kamat 
496ebe629a3SSachin Kamat 		data->domains[nr_domains++] = bank->irq_domain;
497ebe629a3SSachin Kamat 	}
498ebe629a3SSachin Kamat 
499623a650eSThomas Gleixner 	irq_set_chained_handler_and_data(d->irq, s3c64xx_eint_gpio_irq, data);
500ebe629a3SSachin Kamat 
501ebe629a3SSachin Kamat 	return 0;
502ebe629a3SSachin Kamat }
503ebe629a3SSachin Kamat 
504ebe629a3SSachin Kamat /*
505ebe629a3SSachin Kamat  * Functions for configuration of EINT0 wake-up interrupts
506ebe629a3SSachin Kamat  */
507ebe629a3SSachin Kamat 
s3c64xx_eint0_irq_set_mask(struct irq_data * irqd,bool mask)508ebe629a3SSachin Kamat static inline void s3c64xx_eint0_irq_set_mask(struct irq_data *irqd, bool mask)
509ebe629a3SSachin Kamat {
510ebe629a3SSachin Kamat 	struct s3c64xx_eint0_domain_data *ddata =
511ebe629a3SSachin Kamat 					irq_data_get_irq_chip_data(irqd);
512cee7413dSKrzysztof Kozlowski 	struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata;
513ebe629a3SSachin Kamat 	u32 val;
514ebe629a3SSachin Kamat 
515cee7413dSKrzysztof Kozlowski 	val = readl(d->virt_base + EINT0MASK_REG);
516ebe629a3SSachin Kamat 	if (mask)
517ebe629a3SSachin Kamat 		val |= 1 << ddata->eints[irqd->hwirq];
518ebe629a3SSachin Kamat 	else
519ebe629a3SSachin Kamat 		val &= ~(1 << ddata->eints[irqd->hwirq]);
520cee7413dSKrzysztof Kozlowski 	writel(val, d->virt_base + EINT0MASK_REG);
521ebe629a3SSachin Kamat }
522ebe629a3SSachin Kamat 
s3c64xx_eint0_irq_unmask(struct irq_data * irqd)523ebe629a3SSachin Kamat static void s3c64xx_eint0_irq_unmask(struct irq_data *irqd)
524ebe629a3SSachin Kamat {
525ebe629a3SSachin Kamat 	s3c64xx_eint0_irq_set_mask(irqd, false);
526ebe629a3SSachin Kamat }
527ebe629a3SSachin Kamat 
s3c64xx_eint0_irq_mask(struct irq_data * irqd)528ebe629a3SSachin Kamat static void s3c64xx_eint0_irq_mask(struct irq_data *irqd)
529ebe629a3SSachin Kamat {
530ebe629a3SSachin Kamat 	s3c64xx_eint0_irq_set_mask(irqd, true);
531ebe629a3SSachin Kamat }
532ebe629a3SSachin Kamat 
s3c64xx_eint0_irq_ack(struct irq_data * irqd)533ebe629a3SSachin Kamat static void s3c64xx_eint0_irq_ack(struct irq_data *irqd)
534ebe629a3SSachin Kamat {
535ebe629a3SSachin Kamat 	struct s3c64xx_eint0_domain_data *ddata =
536ebe629a3SSachin Kamat 					irq_data_get_irq_chip_data(irqd);
537cee7413dSKrzysztof Kozlowski 	struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata;
538ebe629a3SSachin Kamat 
539ebe629a3SSachin Kamat 	writel(1 << ddata->eints[irqd->hwirq],
540cee7413dSKrzysztof Kozlowski 					d->virt_base + EINT0PEND_REG);
541ebe629a3SSachin Kamat }
542ebe629a3SSachin Kamat 
s3c64xx_eint0_irq_set_type(struct irq_data * irqd,unsigned int type)543ebe629a3SSachin Kamat static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type)
544ebe629a3SSachin Kamat {
545ebe629a3SSachin Kamat 	struct s3c64xx_eint0_domain_data *ddata =
546ebe629a3SSachin Kamat 					irq_data_get_irq_chip_data(irqd);
547ebe629a3SSachin Kamat 	struct samsung_pin_bank *bank = ddata->bank;
548cee7413dSKrzysztof Kozlowski 	struct samsung_pinctrl_drv_data *d = bank->drvdata;
549ebe629a3SSachin Kamat 	void __iomem *reg;
550ebe629a3SSachin Kamat 	int trigger;
551ebe629a3SSachin Kamat 	u8 shift;
552ebe629a3SSachin Kamat 	u32 val;
553ebe629a3SSachin Kamat 
554ebe629a3SSachin Kamat 	trigger = s3c64xx_irq_get_trigger(type);
555ebe629a3SSachin Kamat 	if (trigger < 0) {
556ebe629a3SSachin Kamat 		pr_err("unsupported external interrupt type\n");
557ebe629a3SSachin Kamat 		return -EINVAL;
558ebe629a3SSachin Kamat 	}
559ebe629a3SSachin Kamat 
560f66eb498SThomas Gleixner 	s3c64xx_irq_set_handler(irqd, type);
561ebe629a3SSachin Kamat 
562ebe629a3SSachin Kamat 	/* Set up interrupt trigger */
563cee7413dSKrzysztof Kozlowski 	reg = d->virt_base + EINT0CON0_REG;
564ebe629a3SSachin Kamat 	shift = ddata->eints[irqd->hwirq];
565ebe629a3SSachin Kamat 	if (shift >= EINT_MAX_PER_REG) {
566ebe629a3SSachin Kamat 		reg += 4;
567ebe629a3SSachin Kamat 		shift -= EINT_MAX_PER_REG;
568ebe629a3SSachin Kamat 	}
569ebe629a3SSachin Kamat 	shift = EINT_CON_LEN * (shift / 2);
570ebe629a3SSachin Kamat 
571ebe629a3SSachin Kamat 	val = readl(reg);
572ebe629a3SSachin Kamat 	val &= ~(EINT_CON_MASK << shift);
573ebe629a3SSachin Kamat 	val |= trigger << shift;
574ebe629a3SSachin Kamat 	writel(val, reg);
575ebe629a3SSachin Kamat 
576ebe629a3SSachin Kamat 	s3c64xx_irq_set_function(d, bank, irqd->hwirq);
577ebe629a3SSachin Kamat 
578ebe629a3SSachin Kamat 	return 0;
579ebe629a3SSachin Kamat }
580ebe629a3SSachin Kamat 
581ebe629a3SSachin Kamat /*
582ebe629a3SSachin Kamat  * irq_chip for wakeup interrupts
583ebe629a3SSachin Kamat  */
584ebe629a3SSachin Kamat static struct irq_chip s3c64xx_eint0_irq_chip = {
585ebe629a3SSachin Kamat 	.name		= "EINT0",
586ebe629a3SSachin Kamat 	.irq_unmask	= s3c64xx_eint0_irq_unmask,
587ebe629a3SSachin Kamat 	.irq_mask	= s3c64xx_eint0_irq_mask,
588ebe629a3SSachin Kamat 	.irq_ack	= s3c64xx_eint0_irq_ack,
589ebe629a3SSachin Kamat 	.irq_set_type	= s3c64xx_eint0_irq_set_type,
590ebe629a3SSachin Kamat };
591ebe629a3SSachin Kamat 
s3c64xx_irq_demux_eint(struct irq_desc * desc,u32 range)5925663bb27SJiang Liu static inline void s3c64xx_irq_demux_eint(struct irq_desc *desc, u32 range)
593ebe629a3SSachin Kamat {
5945663bb27SJiang Liu 	struct irq_chip *chip = irq_desc_get_chip(desc);
5955663bb27SJiang Liu 	struct s3c64xx_eint0_data *data = irq_desc_get_handler_data(desc);
596cee7413dSKrzysztof Kozlowski 	struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
597ebe629a3SSachin Kamat 	unsigned int pend, mask;
598ebe629a3SSachin Kamat 
599ebe629a3SSachin Kamat 	chained_irq_enter(chip, desc);
600ebe629a3SSachin Kamat 
601cee7413dSKrzysztof Kozlowski 	pend = readl(drvdata->virt_base + EINT0PEND_REG);
602cee7413dSKrzysztof Kozlowski 	mask = readl(drvdata->virt_base + EINT0MASK_REG);
603ebe629a3SSachin Kamat 
604ebe629a3SSachin Kamat 	pend = pend & range & ~mask;
605ebe629a3SSachin Kamat 	pend &= range;
606ebe629a3SSachin Kamat 
607ebe629a3SSachin Kamat 	while (pend) {
608a9cb09b7SMarc Zyngier 		unsigned int irq;
609a9cb09b7SMarc Zyngier 		int ret;
610ebe629a3SSachin Kamat 
611ebe629a3SSachin Kamat 		irq = fls(pend) - 1;
612ebe629a3SSachin Kamat 		pend &= ~(1 << irq);
613a9cb09b7SMarc Zyngier 		ret = generic_handle_domain_irq(data->domains[irq], data->pins[irq]);
614ebe629a3SSachin Kamat 		/*
615ebe629a3SSachin Kamat 		 * Something must be really wrong if an unmapped EINT
616ebe629a3SSachin Kamat 		 * was unmasked...
617ebe629a3SSachin Kamat 		 */
618a9cb09b7SMarc Zyngier 		BUG_ON(ret);
619ebe629a3SSachin Kamat 	}
620ebe629a3SSachin Kamat 
621ebe629a3SSachin Kamat 	chained_irq_exit(chip, desc);
622ebe629a3SSachin Kamat }
623ebe629a3SSachin Kamat 
s3c64xx_demux_eint0_3(struct irq_desc * desc)624bd0b9ac4SThomas Gleixner static void s3c64xx_demux_eint0_3(struct irq_desc *desc)
625ebe629a3SSachin Kamat {
6265663bb27SJiang Liu 	s3c64xx_irq_demux_eint(desc, 0xf);
627ebe629a3SSachin Kamat }
628ebe629a3SSachin Kamat 
s3c64xx_demux_eint4_11(struct irq_desc * desc)629bd0b9ac4SThomas Gleixner static void s3c64xx_demux_eint4_11(struct irq_desc *desc)
630ebe629a3SSachin Kamat {
6315663bb27SJiang Liu 	s3c64xx_irq_demux_eint(desc, 0xff0);
632ebe629a3SSachin Kamat }
633ebe629a3SSachin Kamat 
s3c64xx_demux_eint12_19(struct irq_desc * desc)634bd0b9ac4SThomas Gleixner static void s3c64xx_demux_eint12_19(struct irq_desc *desc)
635ebe629a3SSachin Kamat {
6365663bb27SJiang Liu 	s3c64xx_irq_demux_eint(desc, 0xff000);
637ebe629a3SSachin Kamat }
638ebe629a3SSachin Kamat 
s3c64xx_demux_eint20_27(struct irq_desc * desc)639bd0b9ac4SThomas Gleixner static void s3c64xx_demux_eint20_27(struct irq_desc *desc)
640ebe629a3SSachin Kamat {
6415663bb27SJiang Liu 	s3c64xx_irq_demux_eint(desc, 0xff00000);
642ebe629a3SSachin Kamat }
643ebe629a3SSachin Kamat 
644ebe629a3SSachin Kamat static irq_flow_handler_t s3c64xx_eint0_handlers[NUM_EINT0_IRQ] = {
645ebe629a3SSachin Kamat 	s3c64xx_demux_eint0_3,
646ebe629a3SSachin Kamat 	s3c64xx_demux_eint4_11,
647ebe629a3SSachin Kamat 	s3c64xx_demux_eint12_19,
648ebe629a3SSachin Kamat 	s3c64xx_demux_eint20_27,
649ebe629a3SSachin Kamat };
650ebe629a3SSachin Kamat 
s3c64xx_eint0_irq_map(struct irq_domain * h,unsigned int virq,irq_hw_number_t hw)651ebe629a3SSachin Kamat static int s3c64xx_eint0_irq_map(struct irq_domain *h, unsigned int virq,
652ebe629a3SSachin Kamat 					irq_hw_number_t hw)
653ebe629a3SSachin Kamat {
654ebe629a3SSachin Kamat 	struct s3c64xx_eint0_domain_data *ddata = h->host_data;
655ebe629a3SSachin Kamat 	struct samsung_pin_bank *bank = ddata->bank;
656ebe629a3SSachin Kamat 
657ebe629a3SSachin Kamat 	if (!(bank->eint_mask & (1 << hw)))
658ebe629a3SSachin Kamat 		return -EINVAL;
659ebe629a3SSachin Kamat 
660ebe629a3SSachin Kamat 	irq_set_chip_and_handler(virq,
661ebe629a3SSachin Kamat 				&s3c64xx_eint0_irq_chip, handle_level_irq);
662ebe629a3SSachin Kamat 	irq_set_chip_data(virq, ddata);
663ebe629a3SSachin Kamat 
664ebe629a3SSachin Kamat 	return 0;
665ebe629a3SSachin Kamat }
666ebe629a3SSachin Kamat 
667ebe629a3SSachin Kamat /*
668ebe629a3SSachin Kamat  * irq domain callbacks for external wakeup interrupt controller.
669ebe629a3SSachin Kamat  */
670ebe629a3SSachin Kamat static const struct irq_domain_ops s3c64xx_eint0_irqd_ops = {
671ebe629a3SSachin Kamat 	.map	= s3c64xx_eint0_irq_map,
672ebe629a3SSachin Kamat 	.xlate	= irq_domain_xlate_twocell,
673ebe629a3SSachin Kamat };
674ebe629a3SSachin Kamat 
675ebe629a3SSachin Kamat /* list of external wakeup controllers supported */
676ebe629a3SSachin Kamat static const struct of_device_id s3c64xx_eint0_irq_ids[] = {
677ebe629a3SSachin Kamat 	{ .compatible = "samsung,s3c64xx-wakeup-eint", },
678ebe629a3SSachin Kamat 	{ }
679ebe629a3SSachin Kamat };
680ebe629a3SSachin Kamat 
681ebe629a3SSachin Kamat /**
682ebe629a3SSachin Kamat  * s3c64xx_eint_eint0_init() - setup handling of external wakeup interrupts.
683ebe629a3SSachin Kamat  * @d: driver data of samsung pinctrl driver.
684ebe629a3SSachin Kamat  */
s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data * d)685ebe629a3SSachin Kamat static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d)
686ebe629a3SSachin Kamat {
687ebe629a3SSachin Kamat 	struct device *dev = d->dev;
688ebe629a3SSachin Kamat 	struct device_node *eint0_np = NULL;
689ebe629a3SSachin Kamat 	struct device_node *np;
690ebe629a3SSachin Kamat 	struct samsung_pin_bank *bank;
691ebe629a3SSachin Kamat 	struct s3c64xx_eint0_data *data;
692ebe629a3SSachin Kamat 	unsigned int i;
693ebe629a3SSachin Kamat 
694ebe629a3SSachin Kamat 	for_each_child_of_node(dev->of_node, np) {
695ebe629a3SSachin Kamat 		if (of_match_node(s3c64xx_eint0_irq_ids, np)) {
696ebe629a3SSachin Kamat 			eint0_np = np;
697ebe629a3SSachin Kamat 			break;
698ebe629a3SSachin Kamat 		}
699ebe629a3SSachin Kamat 	}
700ebe629a3SSachin Kamat 	if (!eint0_np)
701ebe629a3SSachin Kamat 		return -ENODEV;
702ebe629a3SSachin Kamat 
703ebe629a3SSachin Kamat 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
7047f028caaSKrzysztof Kozlowski 	if (!data) {
7057f028caaSKrzysztof Kozlowski 		of_node_put(eint0_np);
706ebe629a3SSachin Kamat 		return -ENOMEM;
7077f028caaSKrzysztof Kozlowski 	}
708ebe629a3SSachin Kamat 	data->drvdata = d;
709ebe629a3SSachin Kamat 
710ebe629a3SSachin Kamat 	for (i = 0; i < NUM_EINT0_IRQ; ++i) {
711ebe629a3SSachin Kamat 		unsigned int irq;
712ebe629a3SSachin Kamat 
713ebe629a3SSachin Kamat 		irq = irq_of_parse_and_map(eint0_np, i);
714ebe629a3SSachin Kamat 		if (!irq) {
715ebe629a3SSachin Kamat 			dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
7167f028caaSKrzysztof Kozlowski 			of_node_put(eint0_np);
717ebe629a3SSachin Kamat 			return -ENXIO;
718ebe629a3SSachin Kamat 		}
719ebe629a3SSachin Kamat 
720623a650eSThomas Gleixner 		irq_set_chained_handler_and_data(irq,
721623a650eSThomas Gleixner 						 s3c64xx_eint0_handlers[i],
722623a650eSThomas Gleixner 						 data);
723ebe629a3SSachin Kamat 	}
7247f028caaSKrzysztof Kozlowski 	of_node_put(eint0_np);
725ebe629a3SSachin Kamat 
7261bf00d7aSTomasz Figa 	bank = d->pin_banks;
7271bf00d7aSTomasz Figa 	for (i = 0; i < d->nr_banks; ++i, ++bank) {
728ebe629a3SSachin Kamat 		struct s3c64xx_eint0_domain_data *ddata;
729ebe629a3SSachin Kamat 		unsigned int nr_eints;
730ebe629a3SSachin Kamat 		unsigned int mask;
731ebe629a3SSachin Kamat 		unsigned int irq;
732ebe629a3SSachin Kamat 		unsigned int pin;
733ebe629a3SSachin Kamat 
734ebe629a3SSachin Kamat 		if (bank->eint_type != EINT_TYPE_WKUP)
735ebe629a3SSachin Kamat 			continue;
736ebe629a3SSachin Kamat 
737ebe629a3SSachin Kamat 		mask = bank->eint_mask;
738ebe629a3SSachin Kamat 		nr_eints = fls(mask);
739ebe629a3SSachin Kamat 
740ebe629a3SSachin Kamat 		ddata = devm_kzalloc(dev,
741ebe629a3SSachin Kamat 				sizeof(*ddata) + nr_eints, GFP_KERNEL);
742fa5c0f46SMarek Szyprowski 		if (!ddata)
743ebe629a3SSachin Kamat 			return -ENOMEM;
744ebe629a3SSachin Kamat 		ddata->bank = bank;
745ebe629a3SSachin Kamat 
746*492fca28SAndy Shevchenko 		bank->irq_domain = irq_domain_create_linear(bank->fwnode,
747ebe629a3SSachin Kamat 				nr_eints, &s3c64xx_eint0_irqd_ops, ddata);
748ebe629a3SSachin Kamat 		if (!bank->irq_domain) {
749ebe629a3SSachin Kamat 			dev_err(dev, "wkup irq domain add failed\n");
750ebe629a3SSachin Kamat 			return -ENXIO;
751ebe629a3SSachin Kamat 		}
752ebe629a3SSachin Kamat 
753ebe629a3SSachin Kamat 		irq = bank->eint_offset;
754ebe629a3SSachin Kamat 		mask = bank->eint_mask;
755ebe629a3SSachin Kamat 		for (pin = 0; mask; ++pin, mask >>= 1) {
756ebe629a3SSachin Kamat 			if (!(mask & 1))
757ebe629a3SSachin Kamat 				continue;
758ebe629a3SSachin Kamat 			data->domains[irq] = bank->irq_domain;
759ebe629a3SSachin Kamat 			data->pins[irq] = pin;
760ebe629a3SSachin Kamat 			ddata->eints[pin] = irq;
761ebe629a3SSachin Kamat 			++irq;
762ebe629a3SSachin Kamat 		}
763ebe629a3SSachin Kamat 	}
764ebe629a3SSachin Kamat 
765ebe629a3SSachin Kamat 	return 0;
766ebe629a3SSachin Kamat }
767ebe629a3SSachin Kamat 
768ebe629a3SSachin Kamat /* pin banks of s3c64xx pin-controller 0 */
7698100cf47STomasz Figa static const struct samsung_pin_bank_data s3c64xx_pin_banks0[] __initconst = {
770ebe629a3SSachin Kamat 	PIN_BANK_4BIT_EINTG(8, 0x000, "gpa", 0),
771ebe629a3SSachin Kamat 	PIN_BANK_4BIT_EINTG(7, 0x020, "gpb", 8),
772ebe629a3SSachin Kamat 	PIN_BANK_4BIT_EINTG(8, 0x040, "gpc", 16),
773ebe629a3SSachin Kamat 	PIN_BANK_4BIT_EINTG(5, 0x060, "gpd", 32),
774ebe629a3SSachin Kamat 	PIN_BANK_4BIT(5, 0x080, "gpe"),
775ebe629a3SSachin Kamat 	PIN_BANK_2BIT_EINTG(16, 0x0a0, "gpf", 48, 0x3fff),
776ebe629a3SSachin Kamat 	PIN_BANK_4BIT_EINTG(7, 0x0c0, "gpg", 64),
777ebe629a3SSachin Kamat 	PIN_BANK_4BIT2_EINTG(10, 0x0e0, "gph", 80),
778ebe629a3SSachin Kamat 	PIN_BANK_2BIT(16, 0x100, "gpi"),
779ebe629a3SSachin Kamat 	PIN_BANK_2BIT(12, 0x120, "gpj"),
780ebe629a3SSachin Kamat 	PIN_BANK_4BIT2_ALIVE(16, 0x800, "gpk"),
781ebe629a3SSachin Kamat 	PIN_BANK_4BIT2_EINTW(15, 0x810, "gpl", 16, 0x7f00),
782ebe629a3SSachin Kamat 	PIN_BANK_4BIT_EINTW(6, 0x820, "gpm", 23, 0x1f),
783ebe629a3SSachin Kamat 	PIN_BANK_2BIT_EINTW(16, 0x830, "gpn", 0),
784ebe629a3SSachin Kamat 	PIN_BANK_2BIT_EINTG(16, 0x140, "gpo", 96, 0xffff),
785ebe629a3SSachin Kamat 	PIN_BANK_2BIT_EINTG(15, 0x160, "gpp", 112, 0x7fff),
786ebe629a3SSachin Kamat 	PIN_BANK_2BIT_EINTG(9, 0x180, "gpq", 128, 0x1ff),
787ebe629a3SSachin Kamat };
788ebe629a3SSachin Kamat 
789ebe629a3SSachin Kamat /*
790ebe629a3SSachin Kamat  * Samsung pinctrl driver data for S3C64xx SoC. S3C64xx SoC includes
791ebe629a3SSachin Kamat  * one gpio/pin-mux/pinconfig controller.
792ebe629a3SSachin Kamat  */
79393b0beaeSKrzysztof Kozlowski static const struct samsung_pin_ctrl s3c64xx_pin_ctrl[] __initconst = {
794ebe629a3SSachin Kamat 	{
795ebe629a3SSachin Kamat 		/* pin-controller instance 1 data */
796ebe629a3SSachin Kamat 		.pin_banks	= s3c64xx_pin_banks0,
797ebe629a3SSachin Kamat 		.nr_banks	= ARRAY_SIZE(s3c64xx_pin_banks0),
798ebe629a3SSachin Kamat 		.eint_gpio_init = s3c64xx_eint_gpio_init,
799ebe629a3SSachin Kamat 		.eint_wkup_init = s3c64xx_eint_eint0_init,
800ebe629a3SSachin Kamat 	},
801ebe629a3SSachin Kamat };
80293b0beaeSKrzysztof Kozlowski 
80393b0beaeSKrzysztof Kozlowski const struct samsung_pinctrl_of_match_data s3c64xx_of_data __initconst = {
80493b0beaeSKrzysztof Kozlowski 	.ctrl		= s3c64xx_pin_ctrl,
80593b0beaeSKrzysztof Kozlowski 	.num_ctrl	= ARRAY_SIZE(s3c64xx_pin_ctrl),
80693b0beaeSKrzysztof Kozlowski };
807