Commit | Line | Data |
---|---|---|
fefe7b09 TP |
1 | /* |
2 | * GPIO driver for Marvell SoCs | |
3 | * | |
4 | * Copyright (C) 2012 Marvell | |
5 | * | |
6 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | |
7 | * Andrew Lunn <andrew@lunn.ch> | |
8 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | |
9 | * | |
10 | * This file is licensed under the terms of the GNU General Public | |
11 | * License version 2. This program is licensed "as is" without any | |
12 | * warranty of any kind, whether express or implied. | |
13 | * | |
14 | * This driver is a fairly straightforward GPIO driver for the | |
15 | * complete family of Marvell EBU SoC platforms (Orion, Dove, | |
16 | * Kirkwood, Discovery, Armada 370/XP). The only complexity of this | |
17 | * driver is the different register layout that exists between the | |
18 | * non-SMP platforms (Orion, Dove, Kirkwood, Armada 370) and the SMP | |
19 | * platforms (MV78200 from the Discovery family and the Armada | |
20 | * XP). Therefore, this driver handles three variants of the GPIO | |
21 | * block: | |
22 | * - the basic variant, called "orion-gpio", with the simplest | |
23 | * register set. Used on Orion, Dove, Kirkwoord, Armada 370 and | |
24 | * non-SMP Discovery systems | |
25 | * - the mv78200 variant for MV78200 Discovery systems. This variant | |
26 | * turns the edge mask and level mask registers into CPU0 edge | |
27 | * mask/level mask registers, and adds CPU1 edge mask/level mask | |
28 | * registers. | |
29 | * - the armadaxp variant for Armada XP systems. This variant keeps | |
30 | * the normal cause/edge mask/level mask registers when the global | |
31 | * interrupts are used, but adds per-CPU cause/edge mask/level mask | |
32 | * registers n a separate memory area for the per-CPU GPIO | |
33 | * interrupts. | |
34 | */ | |
35 | ||
6ec015d6 GC |
36 | #include <linux/bitops.h> |
37 | #include <linux/clk.h> | |
641d0342 | 38 | #include <linux/err.h> |
fefe7b09 | 39 | #include <linux/gpio.h> |
6ec015d6 GC |
40 | #include <linux/init.h> |
41 | #include <linux/io.h> | |
fefe7b09 | 42 | #include <linux/irq.h> |
6ec015d6 | 43 | #include <linux/irqchip/chained_irq.h> |
fefe7b09 | 44 | #include <linux/irqdomain.h> |
b6730b20 | 45 | #include <linux/mfd/syscon.h> |
fefe7b09 | 46 | #include <linux/of_device.h> |
6ec015d6 | 47 | #include <linux/of_irq.h> |
fefe7b09 | 48 | #include <linux/pinctrl/consumer.h> |
757642f9 | 49 | #include <linux/platform_device.h> |
6ec015d6 | 50 | #include <linux/pwm.h> |
2233bf7a | 51 | #include <linux/regmap.h> |
6ec015d6 | 52 | #include <linux/slab.h> |
fefe7b09 | 53 | |
757642f9 AL |
54 | #include "gpiolib.h" |
55 | ||
fefe7b09 TP |
56 | /* |
57 | * GPIO unit register offsets. | |
58 | */ | |
757642f9 AL |
59 | #define GPIO_OUT_OFF 0x0000 |
60 | #define GPIO_IO_CONF_OFF 0x0004 | |
61 | #define GPIO_BLINK_EN_OFF 0x0008 | |
62 | #define GPIO_IN_POL_OFF 0x000c | |
63 | #define GPIO_DATA_IN_OFF 0x0010 | |
64 | #define GPIO_EDGE_CAUSE_OFF 0x0014 | |
65 | #define GPIO_EDGE_MASK_OFF 0x0018 | |
66 | #define GPIO_LEVEL_MASK_OFF 0x001c | |
67 | #define GPIO_BLINK_CNT_SELECT_OFF 0x0020 | |
68 | ||
69 | /* | |
70 | * PWM register offsets. | |
71 | */ | |
72 | #define PWM_BLINK_ON_DURATION_OFF 0x0 | |
73 | #define PWM_BLINK_OFF_DURATION_OFF 0x4 | |
74 | ||
fefe7b09 TP |
75 | |
76 | /* The MV78200 has per-CPU registers for edge mask and level mask */ | |
a4319a61 | 77 | #define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) |
fefe7b09 TP |
78 | #define GPIO_LEVEL_MASK_MV78200_OFF(cpu) ((cpu) ? 0x34 : 0x1C) |
79 | ||
7077f4cc RS |
80 | /* |
81 | * The Armada XP has per-CPU registers for interrupt cause, interrupt | |
fefe7b09 | 82 | * mask and interrupt level mask. Those are relative to the |
7077f4cc RS |
83 | * percpu_membase. |
84 | */ | |
fefe7b09 TP |
85 | #define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4) |
86 | #define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4) | |
87 | #define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4) | |
88 | ||
a4319a61 AL |
89 | #define MVEBU_GPIO_SOC_VARIANT_ORION 0x1 |
90 | #define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2 | |
fefe7b09 | 91 | #define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3 |
b6730b20 | 92 | #define MVEBU_GPIO_SOC_VARIANT_A8K 0x4 |
fefe7b09 | 93 | |
a4319a61 | 94 | #define MVEBU_MAX_GPIO_PER_BANK 32 |
fefe7b09 | 95 | |
757642f9 AL |
96 | struct mvebu_pwm { |
97 | void __iomem *membase; | |
98 | unsigned long clk_rate; | |
99 | struct gpio_desc *gpiod; | |
100 | struct pwm_chip chip; | |
101 | spinlock_t lock; | |
102 | struct mvebu_gpio_chip *mvchip; | |
103 | ||
104 | /* Used to preserve GPIO/PWM registers across suspend/resume */ | |
105 | u32 blink_select; | |
106 | u32 blink_on_duration; | |
107 | u32 blink_off_duration; | |
108 | }; | |
109 | ||
fefe7b09 TP |
110 | struct mvebu_gpio_chip { |
111 | struct gpio_chip chip; | |
2233bf7a | 112 | struct regmap *regs; |
b6730b20 | 113 | u32 offset; |
2233bf7a | 114 | struct regmap *percpu_regs; |
d5359226 | 115 | int irqbase; |
fefe7b09 | 116 | struct irq_domain *domain; |
a4319a61 | 117 | int soc_variant; |
b5b7b487 | 118 | |
757642f9 AL |
119 | /* Used for PWM support */ |
120 | struct clk *clk; | |
121 | struct mvebu_pwm *mvpwm; | |
122 | ||
a4319a61 | 123 | /* Used to preserve GPIO registers across suspend/resume */ |
f4c240ca RS |
124 | u32 out_reg; |
125 | u32 io_conf_reg; | |
126 | u32 blink_en_reg; | |
127 | u32 in_pol_reg; | |
128 | u32 edge_mask_regs[4]; | |
129 | u32 level_mask_regs[4]; | |
fefe7b09 TP |
130 | }; |
131 | ||
132 | /* | |
133 | * Functions returning addresses of individual registers for a given | |
134 | * GPIO controller. | |
135 | */ | |
fefe7b09 | 136 | |
2233bf7a TP |
137 | static void mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip, |
138 | struct regmap **map, unsigned int *offset) | |
e9133760 | 139 | { |
2233bf7a | 140 | int cpu; |
e9133760 | 141 | |
2233bf7a TP |
142 | switch (mvchip->soc_variant) { |
143 | case MVEBU_GPIO_SOC_VARIANT_ORION: | |
144 | case MVEBU_GPIO_SOC_VARIANT_MV78200: | |
b6730b20 | 145 | case MVEBU_GPIO_SOC_VARIANT_A8K: |
2233bf7a | 146 | *map = mvchip->regs; |
b6730b20 | 147 | *offset = GPIO_EDGE_CAUSE_OFF + mvchip->offset; |
2233bf7a TP |
148 | break; |
149 | case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: | |
150 | cpu = smp_processor_id(); | |
151 | *map = mvchip->percpu_regs; | |
152 | *offset = GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); | |
153 | break; | |
154 | default: | |
155 | BUG(); | |
156 | } | |
757642f9 AL |
157 | } |
158 | ||
2233bf7a TP |
159 | static u32 |
160 | mvebu_gpio_read_edge_cause(struct mvebu_gpio_chip *mvchip) | |
fefe7b09 | 161 | { |
2233bf7a TP |
162 | struct regmap *map; |
163 | unsigned int offset; | |
164 | u32 val; | |
fefe7b09 | 165 | |
2233bf7a TP |
166 | mvebu_gpioreg_edge_cause(mvchip, &map, &offset); |
167 | regmap_read(map, offset, &val); | |
168 | ||
169 | return val; | |
fefe7b09 TP |
170 | } |
171 | ||
2233bf7a TP |
172 | static void |
173 | mvebu_gpio_write_edge_cause(struct mvebu_gpio_chip *mvchip, u32 val) | |
fefe7b09 | 174 | { |
2233bf7a TP |
175 | struct regmap *map; |
176 | unsigned int offset; | |
177 | ||
178 | mvebu_gpioreg_edge_cause(mvchip, &map, &offset); | |
179 | regmap_write(map, offset, val); | |
fefe7b09 TP |
180 | } |
181 | ||
2233bf7a TP |
182 | static inline void |
183 | mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip, | |
184 | struct regmap **map, unsigned int *offset) | |
fefe7b09 TP |
185 | { |
186 | int cpu; | |
187 | ||
f4dcd2d9 | 188 | switch (mvchip->soc_variant) { |
fefe7b09 | 189 | case MVEBU_GPIO_SOC_VARIANT_ORION: |
b6730b20 | 190 | case MVEBU_GPIO_SOC_VARIANT_A8K: |
2233bf7a | 191 | *map = mvchip->regs; |
b6730b20 | 192 | *offset = GPIO_EDGE_MASK_OFF + mvchip->offset; |
2233bf7a | 193 | break; |
fefe7b09 | 194 | case MVEBU_GPIO_SOC_VARIANT_MV78200: |
2233bf7a TP |
195 | cpu = smp_processor_id(); |
196 | *map = mvchip->regs; | |
197 | *offset = GPIO_EDGE_MASK_MV78200_OFF(cpu); | |
198 | break; | |
fefe7b09 TP |
199 | case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: |
200 | cpu = smp_processor_id(); | |
2233bf7a TP |
201 | *map = mvchip->percpu_regs; |
202 | *offset = GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); | |
203 | break; | |
fefe7b09 TP |
204 | default: |
205 | BUG(); | |
206 | } | |
207 | } | |
208 | ||
2233bf7a TP |
209 | static u32 |
210 | mvebu_gpio_read_edge_mask(struct mvebu_gpio_chip *mvchip) | |
fefe7b09 | 211 | { |
2233bf7a TP |
212 | struct regmap *map; |
213 | unsigned int offset; | |
214 | u32 val; | |
fefe7b09 | 215 | |
2233bf7a TP |
216 | mvebu_gpioreg_edge_mask(mvchip, &map, &offset); |
217 | regmap_read(map, offset, &val); | |
218 | ||
219 | return val; | |
fefe7b09 TP |
220 | } |
221 | ||
2233bf7a TP |
222 | static void |
223 | mvebu_gpio_write_edge_mask(struct mvebu_gpio_chip *mvchip, u32 val) | |
224 | { | |
225 | struct regmap *map; | |
226 | unsigned int offset; | |
227 | ||
228 | mvebu_gpioreg_edge_mask(mvchip, &map, &offset); | |
229 | regmap_write(map, offset, val); | |
230 | } | |
231 | ||
232 | static void | |
233 | mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip, | |
234 | struct regmap **map, unsigned int *offset) | |
fefe7b09 TP |
235 | { |
236 | int cpu; | |
237 | ||
f4dcd2d9 | 238 | switch (mvchip->soc_variant) { |
fefe7b09 | 239 | case MVEBU_GPIO_SOC_VARIANT_ORION: |
b6730b20 | 240 | case MVEBU_GPIO_SOC_VARIANT_A8K: |
2233bf7a | 241 | *map = mvchip->regs; |
b6730b20 | 242 | *offset = GPIO_LEVEL_MASK_OFF + mvchip->offset; |
2233bf7a | 243 | break; |
fefe7b09 TP |
244 | case MVEBU_GPIO_SOC_VARIANT_MV78200: |
245 | cpu = smp_processor_id(); | |
2233bf7a TP |
246 | *map = mvchip->regs; |
247 | *offset = GPIO_LEVEL_MASK_MV78200_OFF(cpu); | |
248 | break; | |
fefe7b09 TP |
249 | case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: |
250 | cpu = smp_processor_id(); | |
2233bf7a TP |
251 | *map = mvchip->percpu_regs; |
252 | *offset = GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); | |
253 | break; | |
fefe7b09 TP |
254 | default: |
255 | BUG(); | |
256 | } | |
257 | } | |
258 | ||
2233bf7a TP |
259 | static u32 |
260 | mvebu_gpio_read_level_mask(struct mvebu_gpio_chip *mvchip) | |
261 | { | |
262 | struct regmap *map; | |
263 | unsigned int offset; | |
264 | u32 val; | |
265 | ||
266 | mvebu_gpioreg_level_mask(mvchip, &map, &offset); | |
267 | regmap_read(map, offset, &val); | |
268 | ||
269 | return val; | |
270 | } | |
271 | ||
272 | static void | |
273 | mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val) | |
274 | { | |
275 | struct regmap *map; | |
276 | unsigned int offset; | |
277 | ||
278 | mvebu_gpioreg_level_mask(mvchip, &map, &offset); | |
279 | regmap_write(map, offset, val); | |
280 | } | |
281 | ||
757642f9 AL |
282 | /* |
283 | * Functions returning addresses of individual registers for a given | |
284 | * PWM controller. | |
285 | */ | |
286 | static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm) | |
287 | { | |
288 | return mvpwm->membase + PWM_BLINK_ON_DURATION_OFF; | |
289 | } | |
290 | ||
291 | static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm) | |
292 | { | |
293 | return mvpwm->membase + PWM_BLINK_OFF_DURATION_OFF; | |
294 | } | |
295 | ||
fefe7b09 TP |
296 | /* |
297 | * Functions implementing the gpio_chip methods | |
298 | */ | |
d276de70 | 299 | static void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) |
fefe7b09 | 300 | { |
bbe76004 | 301 | struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); |
fefe7b09 | 302 | |
b6730b20 | 303 | regmap_update_bits(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, |
2233bf7a | 304 | BIT(pin), value ? BIT(pin) : 0); |
fefe7b09 TP |
305 | } |
306 | ||
d276de70 | 307 | static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin) |
fefe7b09 | 308 | { |
bbe76004 | 309 | struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); |
fefe7b09 TP |
310 | u32 u; |
311 | ||
b6730b20 | 312 | regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u); |
2233bf7a TP |
313 | |
314 | if (u & BIT(pin)) { | |
315 | u32 data_in, in_pol; | |
316 | ||
b6730b20 GC |
317 | regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, |
318 | &data_in); | |
319 | regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, | |
320 | &in_pol); | |
2233bf7a | 321 | u = data_in ^ in_pol; |
fefe7b09 | 322 | } else { |
b6730b20 | 323 | regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &u); |
fefe7b09 TP |
324 | } |
325 | ||
326 | return (u >> pin) & 1; | |
327 | } | |
328 | ||
d276de70 RS |
329 | static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned int pin, |
330 | int value) | |
e9133760 | 331 | { |
bbe76004 | 332 | struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); |
e9133760 | 333 | |
b6730b20 | 334 | regmap_update_bits(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, |
2233bf7a | 335 | BIT(pin), value ? BIT(pin) : 0); |
e9133760 JL |
336 | } |
337 | ||
d276de70 | 338 | static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) |
fefe7b09 | 339 | { |
bbe76004 | 340 | struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); |
fefe7b09 | 341 | int ret; |
fefe7b09 | 342 | |
7077f4cc RS |
343 | /* |
344 | * Check with the pinctrl driver whether this pin is usable as | |
345 | * an input GPIO | |
346 | */ | |
fefe7b09 TP |
347 | ret = pinctrl_gpio_direction_input(chip->base + pin); |
348 | if (ret) | |
349 | return ret; | |
350 | ||
b6730b20 | 351 | regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, |
43a2dcec | 352 | BIT(pin), BIT(pin)); |
fefe7b09 TP |
353 | |
354 | return 0; | |
355 | } | |
356 | ||
d276de70 | 357 | static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, |
fefe7b09 TP |
358 | int value) |
359 | { | |
bbe76004 | 360 | struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); |
fefe7b09 | 361 | int ret; |
fefe7b09 | 362 | |
7077f4cc RS |
363 | /* |
364 | * Check with the pinctrl driver whether this pin is usable as | |
365 | * an output GPIO | |
366 | */ | |
fefe7b09 TP |
367 | ret = pinctrl_gpio_direction_output(chip->base + pin); |
368 | if (ret) | |
369 | return ret; | |
370 | ||
e9133760 | 371 | mvebu_gpio_blink(chip, pin, 0); |
c57d75c0 TP |
372 | mvebu_gpio_set(chip, pin, value); |
373 | ||
b6730b20 | 374 | regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, |
2233bf7a | 375 | BIT(pin), 0); |
fefe7b09 TP |
376 | |
377 | return 0; | |
378 | } | |
379 | ||
d276de70 | 380 | static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin) |
fefe7b09 | 381 | { |
bbe76004 | 382 | struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); |
163ad364 | 383 | |
fefe7b09 TP |
384 | return irq_create_mapping(mvchip->domain, pin); |
385 | } | |
386 | ||
387 | /* | |
388 | * Functions implementing the irq_chip methods | |
389 | */ | |
390 | static void mvebu_gpio_irq_ack(struct irq_data *d) | |
391 | { | |
392 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
393 | struct mvebu_gpio_chip *mvchip = gc->private; | |
812d4788 | 394 | u32 mask = d->mask; |
fefe7b09 TP |
395 | |
396 | irq_gc_lock(gc); | |
2233bf7a | 397 | mvebu_gpio_write_edge_cause(mvchip, ~mask); |
fefe7b09 TP |
398 | irq_gc_unlock(gc); |
399 | } | |
400 | ||
401 | static void mvebu_gpio_edge_irq_mask(struct irq_data *d) | |
402 | { | |
403 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
404 | struct mvebu_gpio_chip *mvchip = gc->private; | |
61819549 | 405 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
812d4788 | 406 | u32 mask = d->mask; |
fefe7b09 TP |
407 | |
408 | irq_gc_lock(gc); | |
61819549 | 409 | ct->mask_cache_priv &= ~mask; |
2233bf7a | 410 | mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv); |
fefe7b09 TP |
411 | irq_gc_unlock(gc); |
412 | } | |
413 | ||
414 | static void mvebu_gpio_edge_irq_unmask(struct irq_data *d) | |
415 | { | |
416 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
417 | struct mvebu_gpio_chip *mvchip = gc->private; | |
61819549 | 418 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
812d4788 | 419 | u32 mask = d->mask; |
fefe7b09 TP |
420 | |
421 | irq_gc_lock(gc); | |
61819549 | 422 | ct->mask_cache_priv |= mask; |
2233bf7a | 423 | mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv); |
fefe7b09 TP |
424 | irq_gc_unlock(gc); |
425 | } | |
426 | ||
427 | static void mvebu_gpio_level_irq_mask(struct irq_data *d) | |
428 | { | |
429 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
430 | struct mvebu_gpio_chip *mvchip = gc->private; | |
61819549 | 431 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
812d4788 | 432 | u32 mask = d->mask; |
fefe7b09 TP |
433 | |
434 | irq_gc_lock(gc); | |
61819549 | 435 | ct->mask_cache_priv &= ~mask; |
2233bf7a | 436 | mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv); |
fefe7b09 TP |
437 | irq_gc_unlock(gc); |
438 | } | |
439 | ||
440 | static void mvebu_gpio_level_irq_unmask(struct irq_data *d) | |
441 | { | |
442 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
443 | struct mvebu_gpio_chip *mvchip = gc->private; | |
61819549 | 444 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
812d4788 | 445 | u32 mask = d->mask; |
fefe7b09 TP |
446 | |
447 | irq_gc_lock(gc); | |
61819549 | 448 | ct->mask_cache_priv |= mask; |
2233bf7a | 449 | mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv); |
fefe7b09 TP |
450 | irq_gc_unlock(gc); |
451 | } | |
452 | ||
453 | /***************************************************************************** | |
454 | * MVEBU GPIO IRQ | |
455 | * | |
456 | * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same | |
457 | * value of the line or the opposite value. | |
458 | * | |
459 | * Level IRQ handlers: DATA_IN is used directly as cause register. | |
a4319a61 | 460 | * Interrupt are masked by LEVEL_MASK registers. |
fefe7b09 | 461 | * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. |
a4319a61 | 462 | * Interrupt are masked by EDGE_MASK registers. |
fefe7b09 | 463 | * Both-edge handlers: Similar to regular Edge handlers, but also swaps |
a4319a61 AL |
464 | * the polarity to catch the next line transaction. |
465 | * This is a race condition that might not perfectly | |
466 | * work on some use cases. | |
fefe7b09 TP |
467 | * |
468 | * Every eight GPIO lines are grouped (OR'ed) before going up to main | |
469 | * cause register. | |
470 | * | |
a4319a61 AL |
471 | * EDGE cause mask |
472 | * data-in /--------| |-----| |----\ | |
473 | * -----| |----- ---- to main cause reg | |
474 | * X \----------------| |----/ | |
475 | * polarity LEVEL mask | |
fefe7b09 TP |
476 | * |
477 | ****************************************************************************/ | |
478 | ||
479 | static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) | |
480 | { | |
481 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
482 | struct irq_chip_type *ct = irq_data_get_chip_type(d); | |
483 | struct mvebu_gpio_chip *mvchip = gc->private; | |
484 | int pin; | |
485 | u32 u; | |
486 | ||
487 | pin = d->hwirq; | |
488 | ||
b6730b20 | 489 | regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u); |
2233bf7a | 490 | if ((u & BIT(pin)) == 0) |
fefe7b09 | 491 | return -EINVAL; |
fefe7b09 TP |
492 | |
493 | type &= IRQ_TYPE_SENSE_MASK; | |
494 | if (type == IRQ_TYPE_NONE) | |
495 | return -EINVAL; | |
496 | ||
497 | /* Check if we need to change chip and handler */ | |
498 | if (!(ct->type & type)) | |
499 | if (irq_setup_alt_chip(d, type)) | |
500 | return -EINVAL; | |
501 | ||
502 | /* | |
503 | * Configure interrupt polarity. | |
504 | */ | |
f4dcd2d9 | 505 | switch (type) { |
fefe7b09 TP |
506 | case IRQ_TYPE_EDGE_RISING: |
507 | case IRQ_TYPE_LEVEL_HIGH: | |
b6730b20 GC |
508 | regmap_update_bits(mvchip->regs, |
509 | GPIO_IN_POL_OFF + mvchip->offset, | |
2233bf7a | 510 | BIT(pin), 0); |
7cf8c9f7 | 511 | break; |
fefe7b09 TP |
512 | case IRQ_TYPE_EDGE_FALLING: |
513 | case IRQ_TYPE_LEVEL_LOW: | |
b6730b20 GC |
514 | regmap_update_bits(mvchip->regs, |
515 | GPIO_IN_POL_OFF + mvchip->offset, | |
43a2dcec | 516 | BIT(pin), BIT(pin)); |
7cf8c9f7 | 517 | break; |
fefe7b09 | 518 | case IRQ_TYPE_EDGE_BOTH: { |
2233bf7a | 519 | u32 data_in, in_pol, val; |
fefe7b09 | 520 | |
b6730b20 GC |
521 | regmap_read(mvchip->regs, |
522 | GPIO_IN_POL_OFF + mvchip->offset, &in_pol); | |
523 | regmap_read(mvchip->regs, | |
524 | GPIO_DATA_IN_OFF + mvchip->offset, &data_in); | |
fefe7b09 TP |
525 | |
526 | /* | |
527 | * set initial polarity based on current input level | |
528 | */ | |
2233bf7a TP |
529 | if ((data_in ^ in_pol) & BIT(pin)) |
530 | val = BIT(pin); /* falling */ | |
fefe7b09 | 531 | else |
2233bf7a TP |
532 | val = 0; /* raising */ |
533 | ||
b6730b20 GC |
534 | regmap_update_bits(mvchip->regs, |
535 | GPIO_IN_POL_OFF + mvchip->offset, | |
2233bf7a | 536 | BIT(pin), val); |
7cf8c9f7 | 537 | break; |
fefe7b09 TP |
538 | } |
539 | } | |
540 | return 0; | |
541 | } | |
542 | ||
bd0b9ac4 | 543 | static void mvebu_gpio_irq_handler(struct irq_desc *desc) |
fefe7b09 | 544 | { |
476f8b4c | 545 | struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc); |
01ca59f1 | 546 | struct irq_chip *chip = irq_desc_get_chip(desc); |
2233bf7a | 547 | u32 cause, type, data_in, level_mask, edge_cause, edge_mask; |
fefe7b09 TP |
548 | int i; |
549 | ||
550 | if (mvchip == NULL) | |
551 | return; | |
552 | ||
01ca59f1 TP |
553 | chained_irq_enter(chip, desc); |
554 | ||
b6730b20 | 555 | regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, &data_in); |
2233bf7a TP |
556 | level_mask = mvebu_gpio_read_level_mask(mvchip); |
557 | edge_cause = mvebu_gpio_read_edge_cause(mvchip); | |
558 | edge_mask = mvebu_gpio_read_edge_mask(mvchip); | |
559 | ||
3f13b6a2 | 560 | cause = (data_in & level_mask) | (edge_cause & edge_mask); |
fefe7b09 TP |
561 | |
562 | for (i = 0; i < mvchip->chip.ngpio; i++) { | |
563 | int irq; | |
564 | ||
812d4788 | 565 | irq = irq_find_mapping(mvchip->domain, i); |
fefe7b09 | 566 | |
d2cabc4a | 567 | if (!(cause & BIT(i))) |
fefe7b09 TP |
568 | continue; |
569 | ||
fb90c22a | 570 | type = irq_get_trigger_type(irq); |
fefe7b09 TP |
571 | if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { |
572 | /* Swap polarity (race with GPIO line) */ | |
573 | u32 polarity; | |
574 | ||
b6730b20 GC |
575 | regmap_read(mvchip->regs, |
576 | GPIO_IN_POL_OFF + mvchip->offset, | |
577 | &polarity); | |
d2cabc4a | 578 | polarity ^= BIT(i); |
b6730b20 GC |
579 | regmap_write(mvchip->regs, |
580 | GPIO_IN_POL_OFF + mvchip->offset, | |
581 | polarity); | |
fefe7b09 | 582 | } |
01ca59f1 | 583 | |
fefe7b09 TP |
584 | generic_handle_irq(irq); |
585 | } | |
01ca59f1 TP |
586 | |
587 | chained_irq_exit(chip, desc); | |
fefe7b09 TP |
588 | } |
589 | ||
757642f9 AL |
590 | /* |
591 | * Functions implementing the pwm_chip methods | |
592 | */ | |
593 | static struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip) | |
594 | { | |
595 | return container_of(chip, struct mvebu_pwm, chip); | |
596 | } | |
597 | ||
598 | static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) | |
599 | { | |
600 | struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); | |
601 | struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; | |
602 | struct gpio_desc *desc; | |
603 | unsigned long flags; | |
604 | int ret = 0; | |
605 | ||
606 | spin_lock_irqsave(&mvpwm->lock, flags); | |
607 | ||
608 | if (mvpwm->gpiod) { | |
609 | ret = -EBUSY; | |
610 | } else { | |
611 | desc = gpio_to_desc(mvchip->chip.base + pwm->hwpwm); | |
612 | if (!desc) { | |
613 | ret = -ENODEV; | |
614 | goto out; | |
615 | } | |
616 | ||
617 | ret = gpiod_request(desc, "mvebu-pwm"); | |
618 | if (ret) | |
619 | goto out; | |
620 | ||
621 | ret = gpiod_direction_output(desc, 0); | |
622 | if (ret) { | |
623 | gpiod_free(desc); | |
624 | goto out; | |
625 | } | |
626 | ||
627 | mvpwm->gpiod = desc; | |
628 | } | |
629 | out: | |
630 | spin_unlock_irqrestore(&mvpwm->lock, flags); | |
631 | return ret; | |
632 | } | |
633 | ||
634 | static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | |
635 | { | |
636 | struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); | |
637 | unsigned long flags; | |
638 | ||
639 | spin_lock_irqsave(&mvpwm->lock, flags); | |
640 | gpiod_free(mvpwm->gpiod); | |
641 | mvpwm->gpiod = NULL; | |
642 | spin_unlock_irqrestore(&mvpwm->lock, flags); | |
643 | } | |
644 | ||
645 | static void mvebu_pwm_get_state(struct pwm_chip *chip, | |
646 | struct pwm_device *pwm, | |
647 | struct pwm_state *state) { | |
648 | ||
649 | struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); | |
650 | struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; | |
651 | unsigned long long val; | |
652 | unsigned long flags; | |
653 | u32 u; | |
654 | ||
655 | spin_lock_irqsave(&mvpwm->lock, flags); | |
656 | ||
657 | val = (unsigned long long) | |
658 | readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm)); | |
659 | val *= NSEC_PER_SEC; | |
660 | do_div(val, mvpwm->clk_rate); | |
661 | if (val > UINT_MAX) | |
662 | state->duty_cycle = UINT_MAX; | |
663 | else if (val) | |
664 | state->duty_cycle = val; | |
665 | else | |
666 | state->duty_cycle = 1; | |
667 | ||
668 | val = (unsigned long long) | |
669 | readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm)); | |
670 | val *= NSEC_PER_SEC; | |
671 | do_div(val, mvpwm->clk_rate); | |
672 | if (val < state->duty_cycle) { | |
673 | state->period = 1; | |
674 | } else { | |
675 | val -= state->duty_cycle; | |
676 | if (val > UINT_MAX) | |
677 | state->period = UINT_MAX; | |
678 | else if (val) | |
679 | state->period = val; | |
680 | else | |
681 | state->period = 1; | |
682 | } | |
683 | ||
b6730b20 | 684 | regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u); |
757642f9 AL |
685 | if (u) |
686 | state->enabled = true; | |
687 | else | |
688 | state->enabled = false; | |
689 | ||
690 | spin_unlock_irqrestore(&mvpwm->lock, flags); | |
691 | } | |
692 | ||
693 | static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | |
694 | struct pwm_state *state) | |
695 | { | |
696 | struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); | |
697 | struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; | |
698 | unsigned long long val; | |
699 | unsigned long flags; | |
700 | unsigned int on, off; | |
701 | ||
702 | val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle; | |
703 | do_div(val, NSEC_PER_SEC); | |
704 | if (val > UINT_MAX) | |
705 | return -EINVAL; | |
706 | if (val) | |
707 | on = val; | |
708 | else | |
709 | on = 1; | |
710 | ||
711 | val = (unsigned long long) mvpwm->clk_rate * | |
712 | (state->period - state->duty_cycle); | |
713 | do_div(val, NSEC_PER_SEC); | |
714 | if (val > UINT_MAX) | |
715 | return -EINVAL; | |
716 | if (val) | |
717 | off = val; | |
718 | else | |
719 | off = 1; | |
720 | ||
721 | spin_lock_irqsave(&mvpwm->lock, flags); | |
722 | ||
723 | writel_relaxed(on, mvebu_pwmreg_blink_on_duration(mvpwm)); | |
724 | writel_relaxed(off, mvebu_pwmreg_blink_off_duration(mvpwm)); | |
725 | if (state->enabled) | |
726 | mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1); | |
727 | else | |
728 | mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 0); | |
729 | ||
730 | spin_unlock_irqrestore(&mvpwm->lock, flags); | |
731 | ||
732 | return 0; | |
733 | } | |
734 | ||
735 | static const struct pwm_ops mvebu_pwm_ops = { | |
736 | .request = mvebu_pwm_request, | |
737 | .free = mvebu_pwm_free, | |
738 | .get_state = mvebu_pwm_get_state, | |
739 | .apply = mvebu_pwm_apply, | |
740 | .owner = THIS_MODULE, | |
741 | }; | |
742 | ||
743 | static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip) | |
744 | { | |
745 | struct mvebu_pwm *mvpwm = mvchip->mvpwm; | |
746 | ||
b6730b20 | 747 | regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, |
2233bf7a | 748 | &mvpwm->blink_select); |
757642f9 AL |
749 | mvpwm->blink_on_duration = |
750 | readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm)); | |
751 | mvpwm->blink_off_duration = | |
752 | readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm)); | |
753 | } | |
754 | ||
755 | static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip) | |
756 | { | |
757 | struct mvebu_pwm *mvpwm = mvchip->mvpwm; | |
758 | ||
b6730b20 | 759 | regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, |
2233bf7a | 760 | mvpwm->blink_select); |
757642f9 AL |
761 | writel_relaxed(mvpwm->blink_on_duration, |
762 | mvebu_pwmreg_blink_on_duration(mvpwm)); | |
763 | writel_relaxed(mvpwm->blink_off_duration, | |
764 | mvebu_pwmreg_blink_off_duration(mvpwm)); | |
765 | } | |
766 | ||
767 | static int mvebu_pwm_probe(struct platform_device *pdev, | |
768 | struct mvebu_gpio_chip *mvchip, | |
769 | int id) | |
770 | { | |
771 | struct device *dev = &pdev->dev; | |
772 | struct mvebu_pwm *mvpwm; | |
773 | struct resource *res; | |
774 | u32 set; | |
775 | ||
776 | if (!of_device_is_compatible(mvchip->chip.of_node, | |
6c7515c6 | 777 | "marvell,armada-370-gpio")) |
757642f9 AL |
778 | return 0; |
779 | ||
757642f9 AL |
780 | /* |
781 | * There are only two sets of PWM configuration registers for | |
782 | * all the GPIO lines on those SoCs which this driver reserves | |
783 | * for the first two GPIO chips. So if the resource is missing | |
784 | * we can't treat it as an error. | |
785 | */ | |
786 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"); | |
787 | if (!res) | |
788 | return 0; | |
789 | ||
7bee9f9a UKK |
790 | if (IS_ERR(mvchip->clk)) |
791 | return PTR_ERR(mvchip->clk); | |
792 | ||
757642f9 AL |
793 | /* |
794 | * Use set A for lines of GPIO chip with id 0, B for GPIO chip | |
795 | * with id 1. Don't allow further GPIO chips to be used for PWM. | |
796 | */ | |
797 | if (id == 0) | |
798 | set = 0; | |
799 | else if (id == 1) | |
800 | set = U32_MAX; | |
801 | else | |
802 | return -EINVAL; | |
b6730b20 | 803 | regmap_write(mvchip->regs, |
c7d28eca | 804 | GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set); |
757642f9 AL |
805 | |
806 | mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL); | |
807 | if (!mvpwm) | |
808 | return -ENOMEM; | |
809 | mvchip->mvpwm = mvpwm; | |
810 | mvpwm->mvchip = mvchip; | |
811 | ||
812 | mvpwm->membase = devm_ioremap_resource(dev, res); | |
813 | if (IS_ERR(mvpwm->membase)) | |
814 | return PTR_ERR(mvpwm->membase); | |
815 | ||
816 | mvpwm->clk_rate = clk_get_rate(mvchip->clk); | |
817 | if (!mvpwm->clk_rate) { | |
818 | dev_err(dev, "failed to get clock rate\n"); | |
819 | return -EINVAL; | |
820 | } | |
821 | ||
822 | mvpwm->chip.dev = dev; | |
823 | mvpwm->chip.ops = &mvebu_pwm_ops; | |
824 | mvpwm->chip.npwm = mvchip->chip.ngpio; | |
fc7a9068 RG |
825 | /* |
826 | * There may already be some PWM allocated, so we can't force | |
827 | * mvpwm->chip.base to a fixed point like mvchip->chip.base. | |
828 | * So, we let pwmchip_add() do the numbering and take the next free | |
829 | * region. | |
830 | */ | |
831 | mvpwm->chip.base = -1; | |
757642f9 AL |
832 | |
833 | spin_lock_init(&mvpwm->lock); | |
834 | ||
835 | return pwmchip_add(&mvpwm->chip); | |
836 | } | |
837 | ||
a4ba5e1b SG |
838 | #ifdef CONFIG_DEBUG_FS |
839 | #include <linux/seq_file.h> | |
840 | ||
841 | static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | |
842 | { | |
bbe76004 | 843 | struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); |
a4ba5e1b SG |
844 | u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk; |
845 | int i; | |
846 | ||
b6730b20 GC |
847 | regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &out); |
848 | regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &io_conf); | |
849 | regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &blink); | |
850 | regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, &in_pol); | |
851 | regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, &data_in); | |
2233bf7a TP |
852 | cause = mvebu_gpio_read_edge_cause(mvchip); |
853 | edg_msk = mvebu_gpio_read_edge_mask(mvchip); | |
854 | lvl_msk = mvebu_gpio_read_level_mask(mvchip); | |
a4ba5e1b SG |
855 | |
856 | for (i = 0; i < chip->ngpio; i++) { | |
857 | const char *label; | |
858 | u32 msk; | |
859 | bool is_out; | |
860 | ||
861 | label = gpiochip_is_requested(chip, i); | |
862 | if (!label) | |
863 | continue; | |
864 | ||
d2cabc4a | 865 | msk = BIT(i); |
a4ba5e1b SG |
866 | is_out = !(io_conf & msk); |
867 | ||
868 | seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label); | |
869 | ||
870 | if (is_out) { | |
871 | seq_printf(s, " out %s %s\n", | |
872 | out & msk ? "hi" : "lo", | |
873 | blink & msk ? "(blink )" : ""); | |
874 | continue; | |
875 | } | |
876 | ||
877 | seq_printf(s, " in %s (act %s) - IRQ", | |
878 | (data_in ^ in_pol) & msk ? "hi" : "lo", | |
879 | in_pol & msk ? "lo" : "hi"); | |
880 | if (!((edg_msk | lvl_msk) & msk)) { | |
a4319a61 | 881 | seq_puts(s, " disabled\n"); |
a4ba5e1b SG |
882 | continue; |
883 | } | |
884 | if (edg_msk & msk) | |
a4319a61 | 885 | seq_puts(s, " edge "); |
a4ba5e1b | 886 | if (lvl_msk & msk) |
a4319a61 | 887 | seq_puts(s, " level"); |
a4ba5e1b SG |
888 | seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear "); |
889 | } | |
890 | } | |
891 | #else | |
892 | #define mvebu_gpio_dbg_show NULL | |
893 | #endif | |
894 | ||
271b17b6 | 895 | static const struct of_device_id mvebu_gpio_of_match[] = { |
fefe7b09 TP |
896 | { |
897 | .compatible = "marvell,orion-gpio", | |
a4319a61 | 898 | .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, |
fefe7b09 TP |
899 | }, |
900 | { | |
901 | .compatible = "marvell,mv78200-gpio", | |
a4319a61 | 902 | .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, |
fefe7b09 TP |
903 | }, |
904 | { | |
905 | .compatible = "marvell,armadaxp-gpio", | |
a4319a61 | 906 | .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, |
fefe7b09 | 907 | }, |
757642f9 | 908 | { |
6c7515c6 | 909 | .compatible = "marvell,armada-370-gpio", |
757642f9 AL |
910 | .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, |
911 | }, | |
b6730b20 GC |
912 | { |
913 | .compatible = "marvell,armada-8k-gpio", | |
914 | .data = (void *) MVEBU_GPIO_SOC_VARIANT_A8K, | |
915 | }, | |
fefe7b09 TP |
916 | { |
917 | /* sentinel */ | |
918 | }, | |
919 | }; | |
fefe7b09 | 920 | |
b5b7b487 TP |
921 | static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) |
922 | { | |
923 | struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev); | |
924 | int i; | |
925 | ||
b6730b20 GC |
926 | regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, |
927 | &mvchip->out_reg); | |
928 | regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, | |
929 | &mvchip->io_conf_reg); | |
930 | regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, | |
931 | &mvchip->blink_en_reg); | |
932 | regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, | |
933 | &mvchip->in_pol_reg); | |
b5b7b487 TP |
934 | |
935 | switch (mvchip->soc_variant) { | |
936 | case MVEBU_GPIO_SOC_VARIANT_ORION: | |
b6730b20 GC |
937 | case MVEBU_GPIO_SOC_VARIANT_A8K: |
938 | regmap_read(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset, | |
2233bf7a | 939 | &mvchip->edge_mask_regs[0]); |
b6730b20 | 940 | regmap_read(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset, |
2233bf7a | 941 | &mvchip->level_mask_regs[0]); |
b5b7b487 TP |
942 | break; |
943 | case MVEBU_GPIO_SOC_VARIANT_MV78200: | |
944 | for (i = 0; i < 2; i++) { | |
2233bf7a TP |
945 | regmap_read(mvchip->regs, |
946 | GPIO_EDGE_MASK_MV78200_OFF(i), | |
947 | &mvchip->edge_mask_regs[i]); | |
948 | regmap_read(mvchip->regs, | |
949 | GPIO_LEVEL_MASK_MV78200_OFF(i), | |
950 | &mvchip->level_mask_regs[i]); | |
b5b7b487 TP |
951 | } |
952 | break; | |
953 | case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: | |
954 | for (i = 0; i < 4; i++) { | |
2233bf7a TP |
955 | regmap_read(mvchip->regs, |
956 | GPIO_EDGE_MASK_ARMADAXP_OFF(i), | |
957 | &mvchip->edge_mask_regs[i]); | |
958 | regmap_read(mvchip->regs, | |
959 | GPIO_LEVEL_MASK_ARMADAXP_OFF(i), | |
960 | &mvchip->level_mask_regs[i]); | |
b5b7b487 TP |
961 | } |
962 | break; | |
963 | default: | |
964 | BUG(); | |
965 | } | |
966 | ||
757642f9 AL |
967 | if (IS_ENABLED(CONFIG_PWM)) |
968 | mvebu_pwm_suspend(mvchip); | |
969 | ||
b5b7b487 TP |
970 | return 0; |
971 | } | |
972 | ||
973 | static int mvebu_gpio_resume(struct platform_device *pdev) | |
974 | { | |
975 | struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev); | |
976 | int i; | |
977 | ||
b6730b20 GC |
978 | regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, |
979 | mvchip->out_reg); | |
980 | regmap_write(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, | |
981 | mvchip->io_conf_reg); | |
982 | regmap_write(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, | |
983 | mvchip->blink_en_reg); | |
984 | regmap_write(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, | |
985 | mvchip->in_pol_reg); | |
b5b7b487 TP |
986 | |
987 | switch (mvchip->soc_variant) { | |
988 | case MVEBU_GPIO_SOC_VARIANT_ORION: | |
b6730b20 GC |
989 | case MVEBU_GPIO_SOC_VARIANT_A8K: |
990 | regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset, | |
2233bf7a | 991 | mvchip->edge_mask_regs[0]); |
b6730b20 | 992 | regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset, |
2233bf7a | 993 | mvchip->level_mask_regs[0]); |
b5b7b487 TP |
994 | break; |
995 | case MVEBU_GPIO_SOC_VARIANT_MV78200: | |
996 | for (i = 0; i < 2; i++) { | |
2233bf7a TP |
997 | regmap_write(mvchip->regs, |
998 | GPIO_EDGE_MASK_MV78200_OFF(i), | |
999 | mvchip->edge_mask_regs[i]); | |
1000 | regmap_write(mvchip->regs, | |
1001 | GPIO_LEVEL_MASK_MV78200_OFF(i), | |
1002 | mvchip->level_mask_regs[i]); | |
b5b7b487 TP |
1003 | } |
1004 | break; | |
1005 | case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: | |
1006 | for (i = 0; i < 4; i++) { | |
2233bf7a TP |
1007 | regmap_write(mvchip->regs, |
1008 | GPIO_EDGE_MASK_ARMADAXP_OFF(i), | |
1009 | mvchip->edge_mask_regs[i]); | |
1010 | regmap_write(mvchip->regs, | |
1011 | GPIO_LEVEL_MASK_ARMADAXP_OFF(i), | |
1012 | mvchip->level_mask_regs[i]); | |
b5b7b487 TP |
1013 | } |
1014 | break; | |
1015 | default: | |
1016 | BUG(); | |
1017 | } | |
1018 | ||
757642f9 AL |
1019 | if (IS_ENABLED(CONFIG_PWM)) |
1020 | mvebu_pwm_resume(mvchip); | |
1021 | ||
b5b7b487 TP |
1022 | return 0; |
1023 | } | |
1024 | ||
2233bf7a TP |
1025 | static const struct regmap_config mvebu_gpio_regmap_config = { |
1026 | .reg_bits = 32, | |
1027 | .reg_stride = 4, | |
1028 | .val_bits = 32, | |
1029 | .fast_io = true, | |
1030 | }; | |
1031 | ||
b6730b20 GC |
1032 | static int mvebu_gpio_probe_raw(struct platform_device *pdev, |
1033 | struct mvebu_gpio_chip *mvchip) | |
1034 | { | |
1035 | struct resource *res; | |
1036 | void __iomem *base; | |
1037 | ||
1038 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
1039 | base = devm_ioremap_resource(&pdev->dev, res); | |
1040 | if (IS_ERR(base)) | |
1041 | return PTR_ERR(base); | |
1042 | ||
1043 | mvchip->regs = devm_regmap_init_mmio(&pdev->dev, base, | |
1044 | &mvebu_gpio_regmap_config); | |
1045 | if (IS_ERR(mvchip->regs)) | |
1046 | return PTR_ERR(mvchip->regs); | |
1047 | ||
1048 | /* | |
1049 | * For the legacy SoCs, the regmap directly maps to the GPIO | |
1050 | * registers, so no offset is needed. | |
1051 | */ | |
1052 | mvchip->offset = 0; | |
1053 | ||
1054 | /* | |
1055 | * The Armada XP has a second range of registers for the | |
1056 | * per-CPU registers | |
1057 | */ | |
1058 | if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) { | |
1059 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | |
1060 | base = devm_ioremap_resource(&pdev->dev, res); | |
1061 | if (IS_ERR(base)) | |
1062 | return PTR_ERR(base); | |
1063 | ||
1064 | mvchip->percpu_regs = | |
1065 | devm_regmap_init_mmio(&pdev->dev, base, | |
1066 | &mvebu_gpio_regmap_config); | |
1067 | if (IS_ERR(mvchip->percpu_regs)) | |
1068 | return PTR_ERR(mvchip->percpu_regs); | |
1069 | } | |
1070 | ||
1071 | return 0; | |
1072 | } | |
1073 | ||
1074 | static int mvebu_gpio_probe_syscon(struct platform_device *pdev, | |
1075 | struct mvebu_gpio_chip *mvchip) | |
1076 | { | |
1077 | mvchip->regs = syscon_node_to_regmap(pdev->dev.parent->of_node); | |
1078 | if (IS_ERR(mvchip->regs)) | |
1079 | return PTR_ERR(mvchip->regs); | |
1080 | ||
1081 | if (of_property_read_u32(pdev->dev.of_node, "offset", &mvchip->offset)) | |
1082 | return -EINVAL; | |
1083 | ||
1084 | return 0; | |
1085 | } | |
1086 | ||
3836309d | 1087 | static int mvebu_gpio_probe(struct platform_device *pdev) |
fefe7b09 TP |
1088 | { |
1089 | struct mvebu_gpio_chip *mvchip; | |
1090 | const struct of_device_id *match; | |
1091 | struct device_node *np = pdev->dev.of_node; | |
fefe7b09 TP |
1092 | struct irq_chip_generic *gc; |
1093 | struct irq_chip_type *ct; | |
1094 | unsigned int ngpios; | |
812d4788 | 1095 | bool have_irqs; |
fefe7b09 TP |
1096 | int soc_variant; |
1097 | int i, cpu, id; | |
f1d2d081 | 1098 | int err; |
fefe7b09 TP |
1099 | |
1100 | match = of_match_device(mvebu_gpio_of_match, &pdev->dev); | |
1101 | if (match) | |
f0d50460 | 1102 | soc_variant = (unsigned long) match->data; |
fefe7b09 TP |
1103 | else |
1104 | soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; | |
1105 | ||
812d4788 JG |
1106 | /* Some gpio controllers do not provide irq support */ |
1107 | have_irqs = of_irq_count(np) != 0; | |
1108 | ||
a4319a61 AL |
1109 | mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), |
1110 | GFP_KERNEL); | |
6c8365f6 | 1111 | if (!mvchip) |
fefe7b09 | 1112 | return -ENOMEM; |
fefe7b09 | 1113 | |
b5b7b487 TP |
1114 | platform_set_drvdata(pdev, mvchip); |
1115 | ||
fefe7b09 TP |
1116 | if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { |
1117 | dev_err(&pdev->dev, "Missing ngpios OF property\n"); | |
1118 | return -ENODEV; | |
1119 | } | |
1120 | ||
1121 | id = of_alias_get_id(pdev->dev.of_node, "gpio"); | |
1122 | if (id < 0) { | |
1123 | dev_err(&pdev->dev, "Couldn't get OF id\n"); | |
1124 | return id; | |
1125 | } | |
1126 | ||
757642f9 | 1127 | mvchip->clk = devm_clk_get(&pdev->dev, NULL); |
de88747f | 1128 | /* Not all SoCs require a clock.*/ |
757642f9 AL |
1129 | if (!IS_ERR(mvchip->clk)) |
1130 | clk_prepare_enable(mvchip->clk); | |
de88747f | 1131 | |
fefe7b09 TP |
1132 | mvchip->soc_variant = soc_variant; |
1133 | mvchip->chip.label = dev_name(&pdev->dev); | |
58383c78 | 1134 | mvchip->chip.parent = &pdev->dev; |
203f0daa JG |
1135 | mvchip->chip.request = gpiochip_generic_request; |
1136 | mvchip->chip.free = gpiochip_generic_free; | |
fefe7b09 TP |
1137 | mvchip->chip.direction_input = mvebu_gpio_direction_input; |
1138 | mvchip->chip.get = mvebu_gpio_get; | |
1139 | mvchip->chip.direction_output = mvebu_gpio_direction_output; | |
1140 | mvchip->chip.set = mvebu_gpio_set; | |
812d4788 JG |
1141 | if (have_irqs) |
1142 | mvchip->chip.to_irq = mvebu_gpio_to_irq; | |
fefe7b09 TP |
1143 | mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK; |
1144 | mvchip->chip.ngpio = ngpios; | |
9fb1f39e | 1145 | mvchip->chip.can_sleep = false; |
fefe7b09 | 1146 | mvchip->chip.of_node = np; |
a4ba5e1b | 1147 | mvchip->chip.dbg_show = mvebu_gpio_dbg_show; |
fefe7b09 | 1148 | |
b6730b20 GC |
1149 | if (soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) |
1150 | err = mvebu_gpio_probe_syscon(pdev, mvchip); | |
1151 | else | |
1152 | err = mvebu_gpio_probe_raw(pdev, mvchip); | |
fefe7b09 | 1153 | |
b6730b20 GC |
1154 | if (err) |
1155 | return err; | |
fefe7b09 TP |
1156 | |
1157 | /* | |
1158 | * Mask and clear GPIO interrupts. | |
1159 | */ | |
f4dcd2d9 | 1160 | switch (soc_variant) { |
fefe7b09 | 1161 | case MVEBU_GPIO_SOC_VARIANT_ORION: |
b6730b20 GC |
1162 | case MVEBU_GPIO_SOC_VARIANT_A8K: |
1163 | regmap_write(mvchip->regs, | |
1164 | GPIO_EDGE_CAUSE_OFF + mvchip->offset, 0); | |
1165 | regmap_write(mvchip->regs, | |
1166 | GPIO_EDGE_MASK_OFF + mvchip->offset, 0); | |
1167 | regmap_write(mvchip->regs, | |
1168 | GPIO_LEVEL_MASK_OFF + mvchip->offset, 0); | |
fefe7b09 TP |
1169 | break; |
1170 | case MVEBU_GPIO_SOC_VARIANT_MV78200: | |
2233bf7a | 1171 | regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0); |
fefe7b09 | 1172 | for (cpu = 0; cpu < 2; cpu++) { |
2233bf7a TP |
1173 | regmap_write(mvchip->regs, |
1174 | GPIO_EDGE_MASK_MV78200_OFF(cpu), 0); | |
1175 | regmap_write(mvchip->regs, | |
1176 | GPIO_LEVEL_MASK_MV78200_OFF(cpu), 0); | |
fefe7b09 TP |
1177 | } |
1178 | break; | |
1179 | case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: | |
2233bf7a TP |
1180 | regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0); |
1181 | regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF, 0); | |
1182 | regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF, 0); | |
fefe7b09 | 1183 | for (cpu = 0; cpu < 4; cpu++) { |
2233bf7a TP |
1184 | regmap_write(mvchip->percpu_regs, |
1185 | GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu), 0); | |
1186 | regmap_write(mvchip->percpu_regs, | |
1187 | GPIO_EDGE_MASK_ARMADAXP_OFF(cpu), 0); | |
1188 | regmap_write(mvchip->percpu_regs, | |
1189 | GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu), 0); | |
fefe7b09 TP |
1190 | } |
1191 | break; | |
1192 | default: | |
1193 | BUG(); | |
1194 | } | |
1195 | ||
00b9ab4a | 1196 | devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip); |
fefe7b09 TP |
1197 | |
1198 | /* Some gpio controllers do not provide irq support */ | |
812d4788 | 1199 | if (!have_irqs) |
fefe7b09 TP |
1200 | return 0; |
1201 | ||
812d4788 JG |
1202 | mvchip->domain = |
1203 | irq_domain_add_linear(np, ngpios, &irq_generic_chip_ops, NULL); | |
1204 | if (!mvchip->domain) { | |
1205 | dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n", | |
1206 | mvchip->chip.label); | |
1207 | return -ENODEV; | |
fefe7b09 TP |
1208 | } |
1209 | ||
812d4788 JG |
1210 | err = irq_alloc_domain_generic_chips( |
1211 | mvchip->domain, ngpios, 2, np->name, handle_level_irq, | |
1212 | IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0); | |
1213 | if (err) { | |
1214 | dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n", | |
1215 | mvchip->chip.label); | |
1216 | goto err_domain; | |
fefe7b09 TP |
1217 | } |
1218 | ||
899c37ed RS |
1219 | /* |
1220 | * NOTE: The common accessors cannot be used because of the percpu | |
812d4788 JG |
1221 | * access to the mask registers |
1222 | */ | |
1223 | gc = irq_get_domain_generic_chip(mvchip->domain, 0); | |
fefe7b09 TP |
1224 | gc->private = mvchip; |
1225 | ct = &gc->chip_types[0]; | |
1226 | ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; | |
1227 | ct->chip.irq_mask = mvebu_gpio_level_irq_mask; | |
1228 | ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask; | |
1229 | ct->chip.irq_set_type = mvebu_gpio_irq_set_type; | |
1230 | ct->chip.name = mvchip->chip.label; | |
1231 | ||
1232 | ct = &gc->chip_types[1]; | |
1233 | ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | |
1234 | ct->chip.irq_ack = mvebu_gpio_irq_ack; | |
1235 | ct->chip.irq_mask = mvebu_gpio_edge_irq_mask; | |
1236 | ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask; | |
1237 | ct->chip.irq_set_type = mvebu_gpio_irq_set_type; | |
1238 | ct->handler = handle_edge_irq; | |
1239 | ct->chip.name = mvchip->chip.label; | |
1240 | ||
899c37ed RS |
1241 | /* |
1242 | * Setup the interrupt handlers. Each chip can have up to 4 | |
812d4788 JG |
1243 | * interrupt handlers, with each handler dealing with 8 GPIO |
1244 | * pins. | |
1245 | */ | |
1246 | for (i = 0; i < 4; i++) { | |
1247 | int irq = platform_get_irq(pdev, i); | |
fefe7b09 | 1248 | |
812d4788 JG |
1249 | if (irq < 0) |
1250 | continue; | |
1251 | irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler, | |
1252 | mvchip); | |
fefe7b09 TP |
1253 | } |
1254 | ||
6c7515c6 | 1255 | /* Some MVEBU SoCs have simple PWM support for GPIO lines */ |
757642f9 AL |
1256 | if (IS_ENABLED(CONFIG_PWM)) |
1257 | return mvebu_pwm_probe(pdev, mvchip, id); | |
1258 | ||
fefe7b09 | 1259 | return 0; |
f1d2d081 | 1260 | |
812d4788 JG |
1261 | err_domain: |
1262 | irq_domain_remove(mvchip->domain); | |
f1d2d081 | 1263 | |
f1d2d081 | 1264 | return err; |
fefe7b09 TP |
1265 | } |
1266 | ||
1267 | static struct platform_driver mvebu_gpio_driver = { | |
1268 | .driver = { | |
a4319a61 | 1269 | .name = "mvebu-gpio", |
fefe7b09 TP |
1270 | .of_match_table = mvebu_gpio_of_match, |
1271 | }, | |
1272 | .probe = mvebu_gpio_probe, | |
b5b7b487 TP |
1273 | .suspend = mvebu_gpio_suspend, |
1274 | .resume = mvebu_gpio_resume, | |
fefe7b09 | 1275 | }; |
ed329f3a | 1276 | builtin_platform_driver(mvebu_gpio_driver); |