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