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