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