aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Stuebner <heiko@sntech.de>2013-05-20 11:56:13 -0400
committerKukjin Kim <kgene.kim@samsung.com>2013-05-20 11:56:13 -0400
commitaf99a7507469d4fa6dd4d8d633e093b1ff7aff6e (patch)
tree667e75e419dc30de7d4a34b9492b799c3c140bd9
parentf722406faae2d073cc1d01063d1123c35425939e (diff)
pinctrl: Add pinctrl-s3c24xx driver
The s3c24xx pins follow a similar pattern as the other Samsung SoCs and can therefore reuse the already introduced infrastructure. The s3c24xx SoCs have one design oddity in that the first 4 external interrupts do not reside in the eint pending register but in the main interrupt controller instead. We solve this by forwarding the external interrupt from the main controller into the irq domain of the pin bank. The masking/acking of these interrupts is handled in the same way. Furthermore the S3C2412/2413 SoCs contain another oddity in that they keep the same 4 eints in the main interrupt controller and eintpend register and requiring ack operations to happen in both. This is solved by using different compatible properties for the wakeup eint node which set a property accordingly. Signed-off-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Tomasz Figa <t.figa@samsung.com> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt8
-rw-r--r--drivers/gpio/gpio-samsung.c4
-rw-r--r--drivers/pinctrl/Kconfig5
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/pinctrl-s3c24xx.c652
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c10
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h4
7 files changed, 684 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
index c70fca146e91..b2bc219e2003 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -7,6 +7,10 @@ on-chip controllers onto these pads.
7 7
8Required Properties: 8Required Properties:
9- compatible: should be one of the following. 9- compatible: should be one of the following.
10 - "samsung,s3c2412-pinctrl": for S3C2412-compatible pin-controller,
11 - "samsung,s3c2416-pinctrl": for S3C2416-compatible pin-controller,
12 - "samsung,s3c2440-pinctrl": for S3C2440-compatible pin-controller,
13 - "samsung,s3c2450-pinctrl": for S3C2450-compatible pin-controller,
10 - "samsung,s3c64xx-pinctrl": for S3C64xx-compatible pin-controller, 14 - "samsung,s3c64xx-pinctrl": for S3C64xx-compatible pin-controller,
11 - "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller. 15 - "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller.
12 - "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller. 16 - "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
@@ -106,6 +110,10 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
106 110
107 - compatible: identifies the type of the external wakeup interrupt controller 111 - compatible: identifies the type of the external wakeup interrupt controller
108 The possible values are: 112 The possible values are:
113 - samsung,s3c2410-wakeup-eint: represents wakeup interrupt controller
114 found on Samsung S3C24xx SoCs except S3C2412 and S3C2413,
115 - samsung,s3c2412-wakeup-eint: represents wakeup interrupt controller
116 found on Samsung S3C2412 and S3C2413 SoCs,
109 - samsung,s3c64xx-wakeup-eint: represents wakeup interrupt controller 117 - samsung,s3c64xx-wakeup-eint: represents wakeup interrupt controller
110 found on Samsung S3C64xx SoCs, 118 found on Samsung S3C64xx SoCs,
111 - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller 119 - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index b22ca7933745..83a0d711b154 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -3026,6 +3026,10 @@ static __init int samsung_gpiolib_init(void)
3026 */ 3026 */
3027 struct device_node *pctrl_np; 3027 struct device_node *pctrl_np;
3028 static const struct of_device_id exynos_pinctrl_ids[] = { 3028 static const struct of_device_id exynos_pinctrl_ids[] = {
3029 { .compatible = "samsung,s3c2412-pinctrl", },
3030 { .compatible = "samsung,s3c2416-pinctrl", },
3031 { .compatible = "samsung,s3c2440-pinctrl", },
3032 { .compatible = "samsung,s3c2450-pinctrl", },
3029 { .compatible = "samsung,exynos4210-pinctrl", }, 3033 { .compatible = "samsung,exynos4210-pinctrl", },
3030 { .compatible = "samsung,exynos4x12-pinctrl", }, 3034 { .compatible = "samsung,exynos4x12-pinctrl", },
3031 { .compatible = "samsung,exynos5250-pinctrl", }, 3035 { .compatible = "samsung,exynos5250-pinctrl", },
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f6692438149..526a5d04c216 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -216,6 +216,11 @@ config PINCTRL_EXYNOS5440
216 select PINMUX 216 select PINMUX
217 select PINCONF 217 select PINCONF
218 218
219config PINCTRL_S3C24XX
220 bool "Samsung S3C24XX SoC pinctrl driver"
221 depends on ARCH_S3C24XX
222 select PINCTRL_SAMSUNG
223
219config PINCTRL_S3C64XX 224config PINCTRL_S3C64XX
220 bool "Samsung S3C64XX SoC pinctrl driver" 225 bool "Samsung S3C64XX SoC pinctrl driver"
221 depends on ARCH_S3C64XX 226 depends on ARCH_S3C64XX
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 9bdaeb8785ce..f90b645fb601 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
42obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o 42obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o
43obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o 43obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o
44obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o 44obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o
45obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o
45obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o 46obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o
46obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o 47obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
47obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o 48obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
diff --git a/drivers/pinctrl/pinctrl-s3c24xx.c b/drivers/pinctrl/pinctrl-s3c24xx.c
new file mode 100644
index 000000000000..c8b03996cdcb
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-s3c24xx.c
@@ -0,0 +1,652 @@
1/*
2 * S3C24XX specific support for Samsung pinctrl/gpiolib driver.
3 *
4 * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This file contains the SamsungS3C24XX specific information required by the
12 * Samsung pinctrl/gpiolib driver. It also includes the implementation of
13 * external gpio and wakeup interrupt support.
14 */
15
16#include <linux/module.h>
17#include <linux/device.h>
18#include <linux/interrupt.h>
19#include <linux/irqdomain.h>
20#include <linux/irq.h>
21#include <linux/of_irq.h>
22#include <linux/io.h>
23#include <linux/slab.h>
24#include <linux/err.h>
25
26#include <asm/mach/irq.h>
27
28#include "pinctrl-samsung.h"
29
30#define NUM_EINT 24
31#define NUM_EINT_IRQ 6
32#define EINT_MAX_PER_GROUP 8
33
34#define EINTPEND_REG 0xa8
35#define EINTMASK_REG 0xa4
36
37#define EINT_GROUP(i) ((int)((i) / EINT_MAX_PER_GROUP))
38#define EINT_REG(i) ((EINT_GROUP(i) * 4) + 0x88)
39#define EINT_OFFS(i) ((i) % EINT_MAX_PER_GROUP * 4)
40
41#define EINT_LEVEL_LOW 0
42#define EINT_LEVEL_HIGH 1
43#define EINT_EDGE_FALLING 2
44#define EINT_EDGE_RISING 4
45#define EINT_EDGE_BOTH 6
46#define EINT_MASK 0xf
47
48static struct samsung_pin_bank_type bank_type_1bit = {
49 .fld_width = { 1, 1, },
50 .reg_offset = { 0x00, 0x04, },
51};
52
53static struct samsung_pin_bank_type bank_type_2bit = {
54 .fld_width = { 2, 1, 2, },
55 .reg_offset = { 0x00, 0x04, 0x08, },
56};
57
58#define PIN_BANK_A(pins, reg, id) \
59 { \
60 .type = &bank_type_1bit, \
61 .pctl_offset = reg, \
62 .nr_pins = pins, \
63 .eint_type = EINT_TYPE_NONE, \
64 .name = id \
65 }
66
67#define PIN_BANK_2BIT(pins, reg, id) \
68 { \
69 .type = &bank_type_2bit, \
70 .pctl_offset = reg, \
71 .nr_pins = pins, \
72 .eint_type = EINT_TYPE_NONE, \
73 .name = id \
74 }
75
76#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs, emask)\
77 { \
78 .type = &bank_type_2bit, \
79 .pctl_offset = reg, \
80 .nr_pins = pins, \
81 .eint_type = EINT_TYPE_WKUP, \
82 .eint_func = 2, \
83 .eint_mask = emask, \
84 .eint_offset = eoffs, \
85 .name = id \
86 }
87
88/**
89 * struct s3c24xx_eint_data: EINT common data
90 * @drvdata: pin controller driver data
91 * @domains: IRQ domains of particular EINT interrupts
92 * @parents: mapped parent irqs in the main interrupt controller
93 */
94struct s3c24xx_eint_data {
95 struct samsung_pinctrl_drv_data *drvdata;
96 struct irq_domain *domains[NUM_EINT];
97 int parents[NUM_EINT_IRQ];
98};
99
100/**
101 * struct s3c24xx_eint_domain_data: per irq-domain data
102 * @bank: pin bank related to the domain
103 * @eint_data: common data
104 * eint0_3_parent_only: live eints 0-3 only in the main intc
105 */
106struct s3c24xx_eint_domain_data {
107 struct samsung_pin_bank *bank;
108 struct s3c24xx_eint_data *eint_data;
109 bool eint0_3_parent_only;
110};
111
112static int s3c24xx_eint_get_trigger(unsigned int type)
113{
114 switch (type) {
115 case IRQ_TYPE_EDGE_RISING:
116 return EINT_EDGE_RISING;
117 break;
118 case IRQ_TYPE_EDGE_FALLING:
119 return EINT_EDGE_FALLING;
120 break;
121 case IRQ_TYPE_EDGE_BOTH:
122 return EINT_EDGE_BOTH;
123 break;
124 case IRQ_TYPE_LEVEL_HIGH:
125 return EINT_LEVEL_HIGH;
126 break;
127 case IRQ_TYPE_LEVEL_LOW:
128 return EINT_LEVEL_LOW;
129 break;
130 default:
131 return -EINVAL;
132 }
133}
134
135static void s3c24xx_eint_set_handler(unsigned int irq, unsigned int type)
136{
137 /* Edge- and level-triggered interrupts need different handlers */
138 if (type & IRQ_TYPE_EDGE_BOTH)
139 __irq_set_handler_locked(irq, handle_edge_irq);
140 else
141 __irq_set_handler_locked(irq, handle_level_irq);
142}
143
144static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d,
145 struct samsung_pin_bank *bank, int pin)
146{
147 struct samsung_pin_bank_type *bank_type = bank->type;
148 unsigned long flags;
149 void __iomem *reg;
150 u8 shift;
151 u32 mask;
152 u32 val;
153
154 /* Make sure that pin is configured as interrupt */
155 reg = d->virt_base + bank->pctl_offset;
156 shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
157 mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
158
159 spin_lock_irqsave(&bank->slock, flags);
160
161 val = readl(reg);
162 val &= ~(mask << shift);
163 val |= bank->eint_func << shift;
164 writel(val, reg);
165
166 spin_unlock_irqrestore(&bank->slock, flags);
167}
168
169static int s3c24xx_eint_type(struct irq_data *data, unsigned int type)
170{
171 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
172 struct samsung_pinctrl_drv_data *d = bank->drvdata;
173 int index = bank->eint_offset + data->hwirq;
174 void __iomem *reg;
175 int trigger;
176 u8 shift;
177 u32 val;
178
179 trigger = s3c24xx_eint_get_trigger(type);
180 if (trigger < 0) {
181 dev_err(d->dev, "unsupported external interrupt type\n");
182 return -EINVAL;
183 }
184
185 s3c24xx_eint_set_handler(data->irq, type);
186
187 /* Set up interrupt trigger */
188 reg = d->virt_base + EINT_REG(index);
189 shift = EINT_OFFS(index);
190
191 val = readl(reg);
192 val &= ~(EINT_MASK << shift);
193 val |= trigger << shift;
194 writel(val, reg);
195
196 s3c24xx_eint_set_function(d, bank, data->hwirq);
197
198 return 0;
199}
200
201/* Handling of EINTs 0-3 on all except S3C2412 and S3C2413 */
202
203static void s3c2410_eint0_3_ack(struct irq_data *data)
204{
205 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
206 struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data;
207 struct s3c24xx_eint_data *eint_data = ddata->eint_data;
208 int parent_irq = eint_data->parents[data->hwirq];
209 struct irq_chip *parent_chip = irq_get_chip(parent_irq);
210
211 parent_chip->irq_ack(irq_get_irq_data(parent_irq));
212}
213
214static void s3c2410_eint0_3_mask(struct irq_data *data)
215{
216 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
217 struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data;
218 struct s3c24xx_eint_data *eint_data = ddata->eint_data;
219 int parent_irq = eint_data->parents[data->hwirq];
220 struct irq_chip *parent_chip = irq_get_chip(parent_irq);
221
222 parent_chip->irq_mask(irq_get_irq_data(parent_irq));
223}
224
225static void s3c2410_eint0_3_unmask(struct irq_data *data)
226{
227 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
228 struct s3c24xx_eint_domain_data *ddata = bank->irq_domain->host_data;
229 struct s3c24xx_eint_data *eint_data = ddata->eint_data;
230 int parent_irq = eint_data->parents[data->hwirq];
231 struct irq_chip *parent_chip = irq_get_chip(parent_irq);
232
233 parent_chip->irq_unmask(irq_get_irq_data(parent_irq));
234}
235
236static struct irq_chip s3c2410_eint0_3_chip = {
237 .name = "s3c2410-eint0_3",
238 .irq_ack = s3c2410_eint0_3_ack,
239 .irq_mask = s3c2410_eint0_3_mask,
240 .irq_unmask = s3c2410_eint0_3_unmask,
241 .irq_set_type = s3c24xx_eint_type,
242};
243
244static void s3c2410_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
245{
246 struct irq_data *data = irq_desc_get_irq_data(desc);
247 struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq);
248 unsigned int virq;
249
250 /* the first 4 eints have a simple 1 to 1 mapping */
251 virq = irq_linear_revmap(eint_data->domains[data->hwirq], data->hwirq);
252 /* Something must be really wrong if an unmapped EINT is unmasked */
253 BUG_ON(!virq);
254
255 generic_handle_irq(virq);
256}
257
258/* Handling of EINTs 0-3 on S3C2412 and S3C2413 */
259
260static void s3c2412_eint0_3_ack(struct irq_data *data)
261{
262 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
263 struct samsung_pinctrl_drv_data *d = bank->drvdata;
264
265 unsigned long bitval = 1UL << data->hwirq;
266 writel(bitval, d->virt_base + EINTPEND_REG);
267}
268
269static void s3c2412_eint0_3_mask(struct irq_data *data)
270{
271 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
272 struct samsung_pinctrl_drv_data *d = bank->drvdata;
273 unsigned long mask;
274
275 mask = readl(d->virt_base + EINTMASK_REG);
276 mask |= (1UL << data->hwirq);
277 writel(mask, d->virt_base + EINTMASK_REG);
278}
279
280static void s3c2412_eint0_3_unmask(struct irq_data *data)
281{
282 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
283 struct samsung_pinctrl_drv_data *d = bank->drvdata;
284 unsigned long mask;
285
286 mask = readl(d->virt_base + EINTMASK_REG);
287 mask &= ~(1UL << data->hwirq);
288 writel(mask, d->virt_base + EINTMASK_REG);
289}
290
291static struct irq_chip s3c2412_eint0_3_chip = {
292 .name = "s3c2412-eint0_3",
293 .irq_ack = s3c2412_eint0_3_ack,
294 .irq_mask = s3c2412_eint0_3_mask,
295 .irq_unmask = s3c2412_eint0_3_unmask,
296 .irq_set_type = s3c24xx_eint_type,
297};
298
299static void s3c2412_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
300{
301 struct irq_chip *chip = irq_get_chip(irq);
302 struct irq_data *data = irq_desc_get_irq_data(desc);
303 struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq);
304 unsigned int virq;
305
306 chained_irq_enter(chip, desc);
307
308 /* the first 4 eints have a simple 1 to 1 mapping */
309 virq = irq_linear_revmap(eint_data->domains[data->hwirq], data->hwirq);
310 /* Something must be really wrong if an unmapped EINT is unmasked */
311 BUG_ON(!virq);
312
313 generic_handle_irq(virq);
314
315 chained_irq_exit(chip, desc);
316}
317
318/* Handling of all other eints */
319
320static void s3c24xx_eint_ack(struct irq_data *data)
321{
322 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
323 struct samsung_pinctrl_drv_data *d = bank->drvdata;
324 unsigned char index = bank->eint_offset + data->hwirq;
325
326 writel(1UL << index, d->virt_base + EINTPEND_REG);
327}
328
329static void s3c24xx_eint_mask(struct irq_data *data)
330{
331 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
332 struct samsung_pinctrl_drv_data *d = bank->drvdata;
333 unsigned char index = bank->eint_offset + data->hwirq;
334 unsigned long mask;
335
336 mask = readl(d->virt_base + EINTMASK_REG);
337 mask |= (1UL << index);
338 writel(mask, d->virt_base + EINTMASK_REG);
339}
340
341static void s3c24xx_eint_unmask(struct irq_data *data)
342{
343 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(data);
344 struct samsung_pinctrl_drv_data *d = bank->drvdata;
345 unsigned char index = bank->eint_offset + data->hwirq;
346 unsigned long mask;
347
348 mask = readl(d->virt_base + EINTMASK_REG);
349 mask &= ~(1UL << index);
350 writel(mask, d->virt_base + EINTMASK_REG);
351}
352
353static struct irq_chip s3c24xx_eint_chip = {
354 .name = "s3c-eint",
355 .irq_ack = s3c24xx_eint_ack,
356 .irq_mask = s3c24xx_eint_mask,
357 .irq_unmask = s3c24xx_eint_unmask,
358 .irq_set_type = s3c24xx_eint_type,
359};
360
361static inline void s3c24xx_demux_eint(unsigned int irq, struct irq_desc *desc,
362 u32 offset, u32 range)
363{
364 struct irq_chip *chip = irq_get_chip(irq);
365 struct s3c24xx_eint_data *data = irq_get_handler_data(irq);
366 struct samsung_pinctrl_drv_data *d = data->drvdata;
367 unsigned int pend, mask;
368
369 chained_irq_enter(chip, desc);
370
371 pend = readl(d->virt_base + EINTPEND_REG);
372 mask = readl(d->virt_base + EINTMASK_REG);
373
374 pend &= ~mask;
375 pend &= range;
376
377 while (pend) {
378 unsigned int virq;
379
380 irq = __ffs(pend);
381 pend &= ~(1 << irq);
382 virq = irq_linear_revmap(data->domains[irq], irq - offset);
383 /* Something is really wrong if an unmapped EINT is unmasked */
384 BUG_ON(!virq);
385
386 generic_handle_irq(virq);
387 }
388
389 chained_irq_exit(chip, desc);
390}
391
392static void s3c24xx_demux_eint4_7(unsigned int irq, struct irq_desc *desc)
393{
394 s3c24xx_demux_eint(irq, desc, 0, 0xf0);
395}
396
397static void s3c24xx_demux_eint8_23(unsigned int irq, struct irq_desc *desc)
398{
399 s3c24xx_demux_eint(irq, desc, 8, 0xffff00);
400}
401
402static irq_flow_handler_t s3c2410_eint_handlers[NUM_EINT_IRQ] = {
403 s3c2410_demux_eint0_3,
404 s3c2410_demux_eint0_3,
405 s3c2410_demux_eint0_3,
406 s3c2410_demux_eint0_3,
407 s3c24xx_demux_eint4_7,
408 s3c24xx_demux_eint8_23,
409};
410
411static irq_flow_handler_t s3c2412_eint_handlers[NUM_EINT_IRQ] = {
412 s3c2412_demux_eint0_3,
413 s3c2412_demux_eint0_3,
414 s3c2412_demux_eint0_3,
415 s3c2412_demux_eint0_3,
416 s3c24xx_demux_eint4_7,
417 s3c24xx_demux_eint8_23,
418};
419
420static int s3c24xx_gpf_irq_map(struct irq_domain *h, unsigned int virq,
421 irq_hw_number_t hw)
422{
423 struct s3c24xx_eint_domain_data *ddata = h->host_data;
424 struct samsung_pin_bank *bank = ddata->bank;
425
426 if (!(bank->eint_mask & (1 << (bank->eint_offset + hw))))
427 return -EINVAL;
428
429 if (hw <= 3) {
430 if (ddata->eint0_3_parent_only)
431 irq_set_chip_and_handler(virq, &s3c2410_eint0_3_chip,
432 handle_edge_irq);
433 else
434 irq_set_chip_and_handler(virq, &s3c2412_eint0_3_chip,
435 handle_edge_irq);
436 } else {
437 irq_set_chip_and_handler(virq, &s3c24xx_eint_chip,
438 handle_edge_irq);
439 }
440 irq_set_chip_data(virq, bank);
441 set_irq_flags(virq, IRQF_VALID);
442 return 0;
443}
444
445static const struct irq_domain_ops s3c24xx_gpf_irq_ops = {
446 .map = s3c24xx_gpf_irq_map,
447 .xlate = irq_domain_xlate_twocell,
448};
449
450static int s3c24xx_gpg_irq_map(struct irq_domain *h, unsigned int virq,
451 irq_hw_number_t hw)
452{
453 struct s3c24xx_eint_domain_data *ddata = h->host_data;
454 struct samsung_pin_bank *bank = ddata->bank;
455
456 if (!(bank->eint_mask & (1 << (bank->eint_offset + hw))))
457 return -EINVAL;
458
459 irq_set_chip_and_handler(virq, &s3c24xx_eint_chip, handle_edge_irq);
460 irq_set_chip_data(virq, bank);
461 set_irq_flags(virq, IRQF_VALID);
462 return 0;
463}
464
465static const struct irq_domain_ops s3c24xx_gpg_irq_ops = {
466 .map = s3c24xx_gpg_irq_map,
467 .xlate = irq_domain_xlate_twocell,
468};
469
470static const struct of_device_id s3c24xx_eint_irq_ids[] = {
471 { .compatible = "samsung,s3c2410-wakeup-eint", .data = (void *)1 },
472 { .compatible = "samsung,s3c2412-wakeup-eint", .data = (void *)0 },
473 { }
474};
475
476static int s3c24xx_eint_init(struct samsung_pinctrl_drv_data *d)
477{
478 struct device *dev = d->dev;
479 const struct of_device_id *match;
480 struct device_node *eint_np = NULL;
481 struct device_node *np;
482 struct samsung_pin_bank *bank;
483 struct s3c24xx_eint_data *eint_data;
484 const struct irq_domain_ops *ops;
485 unsigned int i;
486 bool eint0_3_parent_only;
487 irq_flow_handler_t *handlers;
488
489 for_each_child_of_node(dev->of_node, np) {
490 match = of_match_node(s3c24xx_eint_irq_ids, np);
491 if (match) {
492 eint_np = np;
493 eint0_3_parent_only = (bool)match->data;
494 break;
495 }
496 }
497 if (!eint_np)
498 return -ENODEV;
499
500 eint_data = devm_kzalloc(dev, sizeof(*eint_data), GFP_KERNEL);
501 if (!eint_data)
502 return -ENOMEM;
503
504 eint_data->drvdata = d;
505
506 handlers = eint0_3_parent_only ? s3c2410_eint_handlers
507 : s3c2412_eint_handlers;
508 for (i = 0; i < NUM_EINT_IRQ; ++i) {
509 unsigned int irq;
510
511 irq = irq_of_parse_and_map(eint_np, i);
512 if (!irq) {
513 dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
514 return -ENXIO;
515 }
516
517 eint_data->parents[i] = irq;
518 irq_set_chained_handler(irq, handlers[i]);
519 irq_set_handler_data(irq, eint_data);
520 }
521
522 bank = d->ctrl->pin_banks;
523 for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
524 struct s3c24xx_eint_domain_data *ddata;
525 unsigned int mask;
526 unsigned int irq;
527 unsigned int pin;
528
529 if (bank->eint_type != EINT_TYPE_WKUP)
530 continue;
531
532 ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
533 if (!ddata)
534 return -ENOMEM;
535
536 ddata->bank = bank;
537 ddata->eint_data = eint_data;
538 ddata->eint0_3_parent_only = eint0_3_parent_only;
539
540 ops = (bank->eint_offset == 0) ? &s3c24xx_gpf_irq_ops
541 : &s3c24xx_gpg_irq_ops;
542
543 bank->irq_domain = irq_domain_add_linear(bank->of_node,
544 bank->nr_pins, ops, ddata);
545 if (!bank->irq_domain) {
546 dev_err(dev, "wkup irq domain add failed\n");
547 return -ENXIO;
548 }
549
550 irq = bank->eint_offset;
551 mask = bank->eint_mask;
552 for (pin = 0; mask; ++pin, mask >>= 1) {
553 if (irq > NUM_EINT)
554 break;
555 if (!(mask & 1))
556 continue;
557 eint_data->domains[irq] = bank->irq_domain;
558 ++irq;
559 }
560 }
561
562 return 0;
563}
564
565static struct samsung_pin_bank s3c2412_pin_banks[] = {
566 PIN_BANK_A(23, 0x000, "gpa"),
567 PIN_BANK_2BIT(11, 0x010, "gpb"),
568 PIN_BANK_2BIT(16, 0x020, "gpc"),
569 PIN_BANK_2BIT(16, 0x030, "gpd"),
570 PIN_BANK_2BIT(16, 0x040, "gpe"),
571 PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
572 PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00),
573 PIN_BANK_2BIT(11, 0x070, "gph"),
574 PIN_BANK_2BIT(13, 0x080, "gpj"),
575};
576
577struct samsung_pin_ctrl s3c2412_pin_ctrl[] = {
578 {
579 .pin_banks = s3c2412_pin_banks,
580 .nr_banks = ARRAY_SIZE(s3c2412_pin_banks),
581 .eint_wkup_init = s3c24xx_eint_init,
582 .label = "S3C2412-GPIO",
583 },
584};
585
586static struct samsung_pin_bank s3c2416_pin_banks[] = {
587 PIN_BANK_A(27, 0x000, "gpa"),
588 PIN_BANK_2BIT(11, 0x010, "gpb"),
589 PIN_BANK_2BIT(16, 0x020, "gpc"),
590 PIN_BANK_2BIT(16, 0x030, "gpd"),
591 PIN_BANK_2BIT(16, 0x040, "gpe"),
592 PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
593 PIN_BANK_2BIT_EINTW(8, 0x060, "gpg", 8, 0xff00),
594 PIN_BANK_2BIT(15, 0x070, "gph"),
595 PIN_BANK_2BIT(16, 0x0e0, "gpk"),
596 PIN_BANK_2BIT(14, 0x0f0, "gpl"),
597 PIN_BANK_2BIT(2, 0x100, "gpm"),
598};
599
600struct samsung_pin_ctrl s3c2416_pin_ctrl[] = {
601 {
602 .pin_banks = s3c2416_pin_banks,
603 .nr_banks = ARRAY_SIZE(s3c2416_pin_banks),
604 .eint_wkup_init = s3c24xx_eint_init,
605 .label = "S3C2416-GPIO",
606 },
607};
608
609static struct samsung_pin_bank s3c2440_pin_banks[] = {
610 PIN_BANK_A(25, 0x000, "gpa"),
611 PIN_BANK_2BIT(11, 0x010, "gpb"),
612 PIN_BANK_2BIT(16, 0x020, "gpc"),
613 PIN_BANK_2BIT(16, 0x030, "gpd"),
614 PIN_BANK_2BIT(16, 0x040, "gpe"),
615 PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
616 PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00),
617 PIN_BANK_2BIT(11, 0x070, "gph"),
618 PIN_BANK_2BIT(13, 0x0d0, "gpj"),
619};
620
621struct samsung_pin_ctrl s3c2440_pin_ctrl[] = {
622 {
623 .pin_banks = s3c2440_pin_banks,
624 .nr_banks = ARRAY_SIZE(s3c2440_pin_banks),
625 .eint_wkup_init = s3c24xx_eint_init,
626 .label = "S3C2440-GPIO",
627 },
628};
629
630static struct samsung_pin_bank s3c2450_pin_banks[] = {
631 PIN_BANK_A(28, 0x000, "gpa"),
632 PIN_BANK_2BIT(11, 0x010, "gpb"),
633 PIN_BANK_2BIT(16, 0x020, "gpc"),
634 PIN_BANK_2BIT(16, 0x030, "gpd"),
635 PIN_BANK_2BIT(16, 0x040, "gpe"),
636 PIN_BANK_2BIT_EINTW(8, 0x050, "gpf", 0, 0xff),
637 PIN_BANK_2BIT_EINTW(16, 0x060, "gpg", 8, 0xffff00),
638 PIN_BANK_2BIT(15, 0x070, "gph"),
639 PIN_BANK_2BIT(16, 0x0d0, "gpj"),
640 PIN_BANK_2BIT(16, 0x0e0, "gpk"),
641 PIN_BANK_2BIT(15, 0x0f0, "gpl"),
642 PIN_BANK_2BIT(2, 0x100, "gpm"),
643};
644
645struct samsung_pin_ctrl s3c2450_pin_ctrl[] = {
646 {
647 .pin_banks = s3c2450_pin_banks,
648 .nr_banks = ARRAY_SIZE(s3c2450_pin_banks),
649 .eint_wkup_init = s3c24xx_eint_init,
650 .label = "S3C2450-GPIO",
651 },
652};
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 976366899f68..e2102062f40f 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -977,6 +977,16 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
977 { .compatible = "samsung,s3c64xx-pinctrl", 977 { .compatible = "samsung,s3c64xx-pinctrl",
978 .data = s3c64xx_pin_ctrl }, 978 .data = s3c64xx_pin_ctrl },
979#endif 979#endif
980#ifdef CONFIG_PINCTRL_S3C24XX
981 { .compatible = "samsung,s3c2412-pinctrl",
982 .data = s3c2412_pin_ctrl },
983 { .compatible = "samsung,s3c2416-pinctrl",
984 .data = s3c2416_pin_ctrl },
985 { .compatible = "samsung,s3c2440-pinctrl",
986 .data = s3c2440_pin_ctrl },
987 { .compatible = "samsung,s3c2450-pinctrl",
988 .data = s3c2450_pin_ctrl },
989#endif
980 {}, 990 {},
981}; 991};
982MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); 992MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 7c7f9ebcd05b..b2e850e91372 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -246,5 +246,9 @@ extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
246extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; 246extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
247extern struct samsung_pin_ctrl exynos5250_pin_ctrl[]; 247extern struct samsung_pin_ctrl exynos5250_pin_ctrl[];
248extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[]; 248extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
249extern struct samsung_pin_ctrl s3c2412_pin_ctrl[];
250extern struct samsung_pin_ctrl s3c2416_pin_ctrl[];
251extern struct samsung_pin_ctrl s3c2440_pin_ctrl[];
252extern struct samsung_pin_ctrl s3c2450_pin_ctrl[];
249 253
250#endif /* __PINCTRL_SAMSUNG_H */ 254#endif /* __PINCTRL_SAMSUNG_H */