Commit | Line | Data |
---|---|---|
8b37eb74 | 1 | // SPDX-License-Identifier: GPL-2.0 |
119f5e44 MD |
2 | /* |
3 | * Renesas R-Car GPIO Support | |
4 | * | |
1fd2b49d | 5 | * Copyright (C) 2014 Renesas Electronics Corporation |
119f5e44 | 6 | * Copyright (C) 2013 Magnus Damm |
119f5e44 MD |
7 | */ |
8 | ||
9 | #include <linux/err.h> | |
4b1d8007 | 10 | #include <linux/gpio/driver.h> |
119f5e44 MD |
11 | #include <linux/init.h> |
12 | #include <linux/interrupt.h> | |
13 | #include <linux/io.h> | |
14 | #include <linux/ioport.h> | |
15 | #include <linux/irq.h> | |
119f5e44 | 16 | #include <linux/module.h> |
bd0bf468 | 17 | #include <linux/of.h> |
f9f2a6fe | 18 | #include <linux/of_device.h> |
dc3465a9 | 19 | #include <linux/pinctrl/consumer.h> |
119f5e44 | 20 | #include <linux/platform_device.h> |
df0c6c80 | 21 | #include <linux/pm_runtime.h> |
119f5e44 MD |
22 | #include <linux/spinlock.h> |
23 | #include <linux/slab.h> | |
24 | ||
51750fb1 HD |
25 | struct gpio_rcar_bank_info { |
26 | u32 iointsel; | |
27 | u32 inoutsel; | |
28 | u32 outdt; | |
29 | u32 posneg; | |
30 | u32 edglevel; | |
31 | u32 bothedge; | |
32 | u32 intmsk; | |
33 | }; | |
34 | ||
208c80f1 GU |
35 | struct gpio_rcar_info { |
36 | bool has_outdtsel; | |
37 | bool has_both_edge_trigger; | |
ecba1eaa | 38 | bool has_always_in; |
93ac0b0c | 39 | bool has_inen; |
208c80f1 GU |
40 | }; |
41 | ||
119f5e44 MD |
42 | struct gpio_rcar_priv { |
43 | void __iomem *base; | |
44 | spinlock_t lock; | |
a53f7953 | 45 | struct device *dev; |
119f5e44 MD |
46 | struct gpio_chip gpio_chip; |
47 | struct irq_chip irq_chip; | |
8b092be9 | 48 | unsigned int irq_parent; |
9ac79ba9 | 49 | atomic_t wakeup_path; |
208c80f1 | 50 | struct gpio_rcar_info info; |
51750fb1 | 51 | struct gpio_rcar_bank_info bank_info; |
119f5e44 MD |
52 | }; |
53 | ||
677d7d61 GU |
54 | #define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ |
55 | #define INOUTSEL 0x04 /* General Input/Output Switching Register */ | |
56 | #define OUTDT 0x08 /* General Output Register */ | |
57 | #define INDT 0x0c /* General Input Register */ | |
58 | #define INTDT 0x10 /* Interrupt Display Register */ | |
59 | #define INTCLR 0x14 /* Interrupt Clear Register */ | |
60 | #define INTMSK 0x18 /* Interrupt Mask Register */ | |
61 | #define MSKCLR 0x1c /* Interrupt Mask Clear Register */ | |
62 | #define POSNEG 0x20 /* Positive/Negative Logic Select Register */ | |
63 | #define EDGLEVEL 0x24 /* Edge/level Select Register */ | |
64 | #define FILONOFF 0x28 /* Chattering Prevention On/Off Register */ | |
65 | #define OUTDTSEL 0x40 /* Output Data Select Register */ | |
66 | #define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */ | |
93ac0b0c | 67 | #define INEN 0x50 /* General Input Enable Register */ |
119f5e44 | 68 | |
159f8a02 LP |
69 | #define RCAR_MAX_GPIO_PER_BANK 32 |
70 | ||
119f5e44 MD |
71 | static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs) |
72 | { | |
73 | return ioread32(p->base + offs); | |
74 | } | |
75 | ||
76 | static inline void gpio_rcar_write(struct gpio_rcar_priv *p, int offs, | |
77 | u32 value) | |
78 | { | |
79 | iowrite32(value, p->base + offs); | |
80 | } | |
81 | ||
82 | static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs, | |
83 | int bit, bool value) | |
84 | { | |
85 | u32 tmp = gpio_rcar_read(p, offs); | |
86 | ||
87 | if (value) | |
88 | tmp |= BIT(bit); | |
89 | else | |
90 | tmp &= ~BIT(bit); | |
91 | ||
92 | gpio_rcar_write(p, offs, tmp); | |
93 | } | |
94 | ||
95 | static void gpio_rcar_irq_disable(struct irq_data *d) | |
96 | { | |
c7f3c5d3 | 97 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
c7b6f457 | 98 | struct gpio_rcar_priv *p = gpiochip_get_data(gc); |
119f5e44 MD |
99 | |
100 | gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d))); | |
101 | } | |
102 | ||
103 | static void gpio_rcar_irq_enable(struct irq_data *d) | |
104 | { | |
c7f3c5d3 | 105 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
c7b6f457 | 106 | struct gpio_rcar_priv *p = gpiochip_get_data(gc); |
119f5e44 MD |
107 | |
108 | gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d))); | |
109 | } | |
110 | ||
111 | static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, | |
112 | unsigned int hwirq, | |
113 | bool active_high_rising_edge, | |
7e1092b5 SH |
114 | bool level_trigger, |
115 | bool both) | |
119f5e44 MD |
116 | { |
117 | unsigned long flags; | |
118 | ||
119 | /* follow steps in the GPIO documentation for | |
120 | * "Setting Edge-Sensitive Interrupt Input Mode" and | |
121 | * "Setting Level-Sensitive Interrupt Input Mode" | |
122 | */ | |
123 | ||
124 | spin_lock_irqsave(&p->lock, flags); | |
125 | ||
b36368f6 | 126 | /* Configure positive or negative logic in POSNEG */ |
119f5e44 MD |
127 | gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge); |
128 | ||
129 | /* Configure edge or level trigger in EDGLEVEL */ | |
130 | gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger); | |
131 | ||
7e1092b5 | 132 | /* Select one edge or both edges in BOTHEDGE */ |
208c80f1 | 133 | if (p->info.has_both_edge_trigger) |
7e1092b5 SH |
134 | gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both); |
135 | ||
119f5e44 MD |
136 | /* Select "Interrupt Input Mode" in IOINTSEL */ |
137 | gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true); | |
138 | ||
139 | /* Write INTCLR in case of edge trigger */ | |
140 | if (!level_trigger) | |
141 | gpio_rcar_write(p, INTCLR, BIT(hwirq)); | |
142 | ||
143 | spin_unlock_irqrestore(&p->lock, flags); | |
144 | } | |
145 | ||
146 | static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type) | |
147 | { | |
c7f3c5d3 | 148 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
c7b6f457 | 149 | struct gpio_rcar_priv *p = gpiochip_get_data(gc); |
119f5e44 MD |
150 | unsigned int hwirq = irqd_to_hwirq(d); |
151 | ||
a53f7953 | 152 | dev_dbg(p->dev, "sense irq = %d, type = %d\n", hwirq, type); |
119f5e44 MD |
153 | |
154 | switch (type & IRQ_TYPE_SENSE_MASK) { | |
155 | case IRQ_TYPE_LEVEL_HIGH: | |
7e1092b5 SH |
156 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true, |
157 | false); | |
119f5e44 MD |
158 | break; |
159 | case IRQ_TYPE_LEVEL_LOW: | |
7e1092b5 SH |
160 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true, |
161 | false); | |
119f5e44 MD |
162 | break; |
163 | case IRQ_TYPE_EDGE_RISING: | |
7e1092b5 SH |
164 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false, |
165 | false); | |
119f5e44 MD |
166 | break; |
167 | case IRQ_TYPE_EDGE_FALLING: | |
7e1092b5 SH |
168 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false, |
169 | false); | |
170 | break; | |
171 | case IRQ_TYPE_EDGE_BOTH: | |
208c80f1 | 172 | if (!p->info.has_both_edge_trigger) |
7e1092b5 SH |
173 | return -EINVAL; |
174 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false, | |
175 | true); | |
119f5e44 MD |
176 | break; |
177 | default: | |
178 | return -EINVAL; | |
179 | } | |
180 | return 0; | |
181 | } | |
182 | ||
ab82fa7d GU |
183 | static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on) |
184 | { | |
185 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
c7b6f457 | 186 | struct gpio_rcar_priv *p = gpiochip_get_data(gc); |
501ef0f9 GU |
187 | int error; |
188 | ||
189 | if (p->irq_parent) { | |
190 | error = irq_set_irq_wake(p->irq_parent, on); | |
191 | if (error) { | |
a53f7953 | 192 | dev_dbg(p->dev, "irq %u doesn't support irq_set_wake\n", |
501ef0f9 GU |
193 | p->irq_parent); |
194 | p->irq_parent = 0; | |
195 | } | |
196 | } | |
ab82fa7d | 197 | |
ab82fa7d | 198 | if (on) |
9ac79ba9 | 199 | atomic_inc(&p->wakeup_path); |
ab82fa7d | 200 | else |
9ac79ba9 | 201 | atomic_dec(&p->wakeup_path); |
ab82fa7d GU |
202 | |
203 | return 0; | |
204 | } | |
205 | ||
119f5e44 MD |
206 | static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id) |
207 | { | |
208 | struct gpio_rcar_priv *p = dev_id; | |
209 | u32 pending; | |
210 | unsigned int offset, irqs_handled = 0; | |
211 | ||
8808b64d VB |
212 | while ((pending = gpio_rcar_read(p, INTDT) & |
213 | gpio_rcar_read(p, INTMSK))) { | |
119f5e44 MD |
214 | offset = __ffs(pending); |
215 | gpio_rcar_write(p, INTCLR, BIT(offset)); | |
f0fbe7bc | 216 | generic_handle_irq(irq_find_mapping(p->gpio_chip.irq.domain, |
c7f3c5d3 | 217 | offset)); |
119f5e44 MD |
218 | irqs_handled++; |
219 | } | |
220 | ||
221 | return irqs_handled ? IRQ_HANDLED : IRQ_NONE; | |
222 | } | |
223 | ||
119f5e44 MD |
224 | static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip, |
225 | unsigned int gpio, | |
226 | bool output) | |
227 | { | |
c7b6f457 | 228 | struct gpio_rcar_priv *p = gpiochip_get_data(chip); |
119f5e44 MD |
229 | unsigned long flags; |
230 | ||
231 | /* follow steps in the GPIO documentation for | |
232 | * "Setting General Output Mode" and | |
233 | * "Setting General Input Mode" | |
234 | */ | |
235 | ||
236 | spin_lock_irqsave(&p->lock, flags); | |
237 | ||
b36368f6 | 238 | /* Configure positive logic in POSNEG */ |
119f5e44 MD |
239 | gpio_rcar_modify_bit(p, POSNEG, gpio, false); |
240 | ||
241 | /* Select "General Input/Output Mode" in IOINTSEL */ | |
242 | gpio_rcar_modify_bit(p, IOINTSEL, gpio, false); | |
243 | ||
244 | /* Select Input Mode or Output Mode in INOUTSEL */ | |
245 | gpio_rcar_modify_bit(p, INOUTSEL, gpio, output); | |
246 | ||
3ae4f3aa | 247 | /* Select General Output Register to output data in OUTDTSEL */ |
208c80f1 | 248 | if (p->info.has_outdtsel && output) |
3ae4f3aa VZ |
249 | gpio_rcar_modify_bit(p, OUTDTSEL, gpio, false); |
250 | ||
119f5e44 MD |
251 | spin_unlock_irqrestore(&p->lock, flags); |
252 | } | |
253 | ||
dc3465a9 LP |
254 | static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset) |
255 | { | |
2d65472b GU |
256 | struct gpio_rcar_priv *p = gpiochip_get_data(chip); |
257 | int error; | |
258 | ||
a53f7953 | 259 | error = pm_runtime_get_sync(p->dev); |
6f8cd246 DL |
260 | if (error < 0) { |
261 | pm_runtime_put(p->dev); | |
2d65472b | 262 | return error; |
6f8cd246 | 263 | } |
2d65472b | 264 | |
a9a1d2a7 | 265 | error = pinctrl_gpio_request(chip->base + offset); |
2d65472b | 266 | if (error) |
a53f7953 | 267 | pm_runtime_put(p->dev); |
2d65472b GU |
268 | |
269 | return error; | |
dc3465a9 LP |
270 | } |
271 | ||
272 | static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset) | |
273 | { | |
2d65472b GU |
274 | struct gpio_rcar_priv *p = gpiochip_get_data(chip); |
275 | ||
a9a1d2a7 | 276 | pinctrl_gpio_free(chip->base + offset); |
dc3465a9 | 277 | |
ce0e2c60 LW |
278 | /* |
279 | * Set the GPIO as an input to ensure that the next GPIO request won't | |
dc3465a9 LP |
280 | * drive the GPIO pin as an output. |
281 | */ | |
282 | gpio_rcar_config_general_input_output_mode(chip, offset, false); | |
2d65472b | 283 | |
a53f7953 | 284 | pm_runtime_put(p->dev); |
dc3465a9 LP |
285 | } |
286 | ||
ad817297 GU |
287 | static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset) |
288 | { | |
289 | struct gpio_rcar_priv *p = gpiochip_get_data(chip); | |
290 | ||
e42615ec MV |
291 | if (gpio_rcar_read(p, INOUTSEL) & BIT(offset)) |
292 | return GPIO_LINE_DIRECTION_OUT; | |
293 | ||
294 | return GPIO_LINE_DIRECTION_IN; | |
ad817297 GU |
295 | } |
296 | ||
119f5e44 MD |
297 | static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) |
298 | { | |
299 | gpio_rcar_config_general_input_output_mode(chip, offset, false); | |
300 | return 0; | |
301 | } | |
302 | ||
303 | static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset) | |
304 | { | |
714d3a29 | 305 | struct gpio_rcar_priv *p = gpiochip_get_data(chip); |
ae9550f6 MD |
306 | u32 bit = BIT(offset); |
307 | ||
ecba1eaa GU |
308 | /* |
309 | * Before R-Car Gen3, INDT does not show correct pin state when | |
310 | * configured as output, so use OUTDT in case of output pins | |
311 | */ | |
312 | if (!p->info.has_always_in && (gpio_rcar_read(p, INOUTSEL) & bit)) | |
714d3a29 | 313 | return !!(gpio_rcar_read(p, OUTDT) & bit); |
ae9550f6 | 314 | else |
714d3a29 | 315 | return !!(gpio_rcar_read(p, INDT) & bit); |
119f5e44 MD |
316 | } |
317 | ||
183245c4 GU |
318 | static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask, |
319 | unsigned long *bits) | |
320 | { | |
321 | struct gpio_rcar_priv *p = gpiochip_get_data(chip); | |
322 | u32 bankmask, outputs, m, val = 0; | |
323 | unsigned long flags; | |
324 | ||
325 | bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0); | |
326 | if (chip->valid_mask) | |
327 | bankmask &= chip->valid_mask[0]; | |
328 | ||
329 | if (!bankmask) | |
330 | return 0; | |
331 | ||
ecba1eaa GU |
332 | if (p->info.has_always_in) { |
333 | bits[0] = gpio_rcar_read(p, INDT) & bankmask; | |
334 | return 0; | |
335 | } | |
336 | ||
183245c4 GU |
337 | spin_lock_irqsave(&p->lock, flags); |
338 | outputs = gpio_rcar_read(p, INOUTSEL); | |
339 | m = outputs & bankmask; | |
340 | if (m) | |
341 | val |= gpio_rcar_read(p, OUTDT) & m; | |
342 | ||
343 | m = ~outputs & bankmask; | |
344 | if (m) | |
345 | val |= gpio_rcar_read(p, INDT) & m; | |
346 | spin_unlock_irqrestore(&p->lock, flags); | |
347 | ||
348 | bits[0] = val; | |
349 | return 0; | |
350 | } | |
351 | ||
119f5e44 MD |
352 | static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value) |
353 | { | |
c7b6f457 | 354 | struct gpio_rcar_priv *p = gpiochip_get_data(chip); |
119f5e44 MD |
355 | unsigned long flags; |
356 | ||
357 | spin_lock_irqsave(&p->lock, flags); | |
358 | gpio_rcar_modify_bit(p, OUTDT, offset, value); | |
359 | spin_unlock_irqrestore(&p->lock, flags); | |
360 | } | |
361 | ||
dbb763b8 GU |
362 | static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask, |
363 | unsigned long *bits) | |
364 | { | |
365 | struct gpio_rcar_priv *p = gpiochip_get_data(chip); | |
366 | unsigned long flags; | |
367 | u32 val, bankmask; | |
368 | ||
369 | bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0); | |
496069b8 BD |
370 | if (chip->valid_mask) |
371 | bankmask &= chip->valid_mask[0]; | |
372 | ||
dbb763b8 GU |
373 | if (!bankmask) |
374 | return; | |
375 | ||
376 | spin_lock_irqsave(&p->lock, flags); | |
377 | val = gpio_rcar_read(p, OUTDT); | |
378 | val &= ~bankmask; | |
379 | val |= (bankmask & bits[0]); | |
380 | gpio_rcar_write(p, OUTDT, val); | |
381 | spin_unlock_irqrestore(&p->lock, flags); | |
382 | } | |
383 | ||
119f5e44 MD |
384 | static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, |
385 | int value) | |
386 | { | |
387 | /* write GPIO value to output before selecting output mode of pin */ | |
388 | gpio_rcar_set(chip, offset, value); | |
389 | gpio_rcar_config_general_input_output_mode(chip, offset, true); | |
390 | return 0; | |
391 | } | |
392 | ||
1fd2b49d | 393 | static const struct gpio_rcar_info gpio_rcar_info_gen1 = { |
3ae4f3aa | 394 | .has_outdtsel = false, |
1fd2b49d | 395 | .has_both_edge_trigger = false, |
ecba1eaa | 396 | .has_always_in = false, |
93ac0b0c | 397 | .has_inen = false, |
1fd2b49d HN |
398 | }; |
399 | ||
400 | static const struct gpio_rcar_info gpio_rcar_info_gen2 = { | |
3ae4f3aa | 401 | .has_outdtsel = true, |
1fd2b49d | 402 | .has_both_edge_trigger = true, |
ecba1eaa | 403 | .has_always_in = false, |
93ac0b0c | 404 | .has_inen = false, |
ecba1eaa GU |
405 | }; |
406 | ||
407 | static const struct gpio_rcar_info gpio_rcar_info_gen3 = { | |
408 | .has_outdtsel = true, | |
409 | .has_both_edge_trigger = true, | |
410 | .has_always_in = true, | |
93ac0b0c GU |
411 | .has_inen = false, |
412 | }; | |
413 | ||
414 | static const struct gpio_rcar_info gpio_rcar_info_v3u = { | |
415 | .has_outdtsel = true, | |
416 | .has_both_edge_trigger = true, | |
417 | .has_always_in = true, | |
418 | .has_inen = true, | |
1fd2b49d HN |
419 | }; |
420 | ||
850dfe17 LP |
421 | static const struct of_device_id gpio_rcar_of_table[] = { |
422 | { | |
93ac0b0c GU |
423 | .compatible = "renesas,gpio-r8a779a0", |
424 | .data = &gpio_rcar_info_v3u, | |
425 | }, { | |
dbd1dad2 SH |
426 | .compatible = "renesas,rcar-gen1-gpio", |
427 | .data = &gpio_rcar_info_gen1, | |
428 | }, { | |
429 | .compatible = "renesas,rcar-gen2-gpio", | |
430 | .data = &gpio_rcar_info_gen2, | |
431 | }, { | |
432 | .compatible = "renesas,rcar-gen3-gpio", | |
ecba1eaa | 433 | .data = &gpio_rcar_info_gen3, |
850dfe17 LP |
434 | }, { |
435 | .compatible = "renesas,gpio-rcar", | |
1fd2b49d | 436 | .data = &gpio_rcar_info_gen1, |
850dfe17 LP |
437 | }, { |
438 | /* Terminator */ | |
439 | }, | |
440 | }; | |
441 | ||
442 | MODULE_DEVICE_TABLE(of, gpio_rcar_of_table); | |
443 | ||
8b092be9 | 444 | static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins) |
159f8a02 | 445 | { |
a53f7953 | 446 | struct device_node *np = p->dev->of_node; |
8b092be9 | 447 | const struct gpio_rcar_info *info; |
159f8a02 LP |
448 | struct of_phandle_args args; |
449 | int ret; | |
159f8a02 | 450 | |
a53f7953 | 451 | info = of_device_get_match_data(p->dev); |
208c80f1 | 452 | p->info = *info; |
850dfe17 | 453 | |
8b092be9 GU |
454 | ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args); |
455 | *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; | |
850dfe17 | 456 | |
8b092be9 | 457 | if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) { |
a53f7953 VZ |
458 | dev_warn(p->dev, "Invalid number of gpio lines %u, using %u\n", |
459 | *npins, RCAR_MAX_GPIO_PER_BANK); | |
8b092be9 | 460 | *npins = RCAR_MAX_GPIO_PER_BANK; |
159f8a02 | 461 | } |
850dfe17 LP |
462 | |
463 | return 0; | |
159f8a02 LP |
464 | } |
465 | ||
93ac0b0c GU |
466 | static void gpio_rcar_enable_inputs(struct gpio_rcar_priv *p) |
467 | { | |
468 | u32 mask = GENMASK(p->gpio_chip.ngpio - 1, 0); | |
469 | ||
470 | /* Select "Input Enable" in INEN */ | |
471 | if (p->gpio_chip.valid_mask) | |
472 | mask &= p->gpio_chip.valid_mask[0]; | |
473 | if (mask) | |
474 | gpio_rcar_write(p, INEN, gpio_rcar_read(p, INEN) | mask); | |
475 | } | |
476 | ||
119f5e44 MD |
477 | static int gpio_rcar_probe(struct platform_device *pdev) |
478 | { | |
119f5e44 | 479 | struct gpio_rcar_priv *p; |
ecbf7c2e | 480 | struct resource *irq; |
119f5e44 MD |
481 | struct gpio_chip *gpio_chip; |
482 | struct irq_chip *irq_chip; | |
b470cef1 | 483 | struct gpio_irq_chip *girq; |
b22978fc GU |
484 | struct device *dev = &pdev->dev; |
485 | const char *name = dev_name(dev); | |
8b092be9 | 486 | unsigned int npins; |
119f5e44 MD |
487 | int ret; |
488 | ||
b22978fc | 489 | p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); |
7d82bf34 GU |
490 | if (!p) |
491 | return -ENOMEM; | |
119f5e44 | 492 | |
a53f7953 | 493 | p->dev = dev; |
119f5e44 MD |
494 | spin_lock_init(&p->lock); |
495 | ||
8b092be9 GU |
496 | /* Get device configuration from DT node */ |
497 | ret = gpio_rcar_parse_dt(p, &npins); | |
850dfe17 LP |
498 | if (ret < 0) |
499 | return ret; | |
159f8a02 LP |
500 | |
501 | platform_set_drvdata(pdev, p); | |
502 | ||
df0c6c80 | 503 | pm_runtime_enable(dev); |
df0c6c80 | 504 | |
119f5e44 | 505 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
5a24d4b6 SS |
506 | if (!irq) { |
507 | dev_err(dev, "missing IRQ\n"); | |
119f5e44 MD |
508 | ret = -EINVAL; |
509 | goto err0; | |
510 | } | |
511 | ||
ecbf7c2e | 512 | p->base = devm_platform_ioremap_resource(pdev, 0); |
5a24d4b6 SS |
513 | if (IS_ERR(p->base)) { |
514 | ret = PTR_ERR(p->base); | |
119f5e44 MD |
515 | goto err0; |
516 | } | |
517 | ||
518 | gpio_chip = &p->gpio_chip; | |
dc3465a9 LP |
519 | gpio_chip->request = gpio_rcar_request; |
520 | gpio_chip->free = gpio_rcar_free; | |
ad817297 | 521 | gpio_chip->get_direction = gpio_rcar_get_direction; |
119f5e44 MD |
522 | gpio_chip->direction_input = gpio_rcar_direction_input; |
523 | gpio_chip->get = gpio_rcar_get; | |
183245c4 | 524 | gpio_chip->get_multiple = gpio_rcar_get_multiple; |
119f5e44 MD |
525 | gpio_chip->direction_output = gpio_rcar_direction_output; |
526 | gpio_chip->set = gpio_rcar_set; | |
dbb763b8 | 527 | gpio_chip->set_multiple = gpio_rcar_set_multiple; |
119f5e44 | 528 | gpio_chip->label = name; |
58383c78 | 529 | gpio_chip->parent = dev; |
119f5e44 | 530 | gpio_chip->owner = THIS_MODULE; |
8b092be9 GU |
531 | gpio_chip->base = -1; |
532 | gpio_chip->ngpio = npins; | |
119f5e44 MD |
533 | |
534 | irq_chip = &p->irq_chip; | |
f932a686 | 535 | irq_chip->name = "gpio-rcar"; |
47bd38a3 | 536 | irq_chip->parent_device = dev; |
119f5e44 MD |
537 | irq_chip->irq_mask = gpio_rcar_irq_disable; |
538 | irq_chip->irq_unmask = gpio_rcar_irq_enable; | |
119f5e44 | 539 | irq_chip->irq_set_type = gpio_rcar_irq_set_type; |
ab82fa7d | 540 | irq_chip->irq_set_wake = gpio_rcar_irq_set_wake; |
b183cab7 | 541 | irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; |
119f5e44 | 542 | |
b470cef1 LW |
543 | girq = &gpio_chip->irq; |
544 | girq->chip = irq_chip; | |
545 | /* This will let us handle the parent IRQ in the driver */ | |
546 | girq->parent_handler = NULL; | |
547 | girq->num_parents = 0; | |
548 | girq->parents = NULL; | |
549 | girq->default_type = IRQ_TYPE_NONE; | |
550 | girq->handler = handle_level_irq; | |
551 | ||
c7b6f457 | 552 | ret = gpiochip_add_data(gpio_chip, p); |
c7f3c5d3 GU |
553 | if (ret) { |
554 | dev_err(dev, "failed to add GPIO controller\n"); | |
0c8aab8e | 555 | goto err0; |
119f5e44 MD |
556 | } |
557 | ||
ab82fa7d | 558 | p->irq_parent = irq->start; |
b22978fc GU |
559 | if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, |
560 | IRQF_SHARED, name, p)) { | |
561 | dev_err(dev, "failed to request IRQ\n"); | |
119f5e44 MD |
562 | ret = -ENOENT; |
563 | goto err1; | |
564 | } | |
565 | ||
93ac0b0c GU |
566 | if (p->info.has_inen) { |
567 | pm_runtime_get_sync(p->dev); | |
568 | gpio_rcar_enable_inputs(p); | |
569 | pm_runtime_put(p->dev); | |
570 | } | |
571 | ||
8b092be9 | 572 | dev_info(dev, "driving %d GPIOs\n", npins); |
dc3465a9 | 573 | |
119f5e44 MD |
574 | return 0; |
575 | ||
576 | err1: | |
4d84b9e4 | 577 | gpiochip_remove(gpio_chip); |
119f5e44 | 578 | err0: |
df0c6c80 | 579 | pm_runtime_disable(dev); |
119f5e44 MD |
580 | return ret; |
581 | } | |
582 | ||
583 | static int gpio_rcar_remove(struct platform_device *pdev) | |
584 | { | |
585 | struct gpio_rcar_priv *p = platform_get_drvdata(pdev); | |
119f5e44 | 586 | |
9f5132ae | 587 | gpiochip_remove(&p->gpio_chip); |
119f5e44 | 588 | |
df0c6c80 | 589 | pm_runtime_disable(&pdev->dev); |
119f5e44 MD |
590 | return 0; |
591 | } | |
592 | ||
51750fb1 HD |
593 | #ifdef CONFIG_PM_SLEEP |
594 | static int gpio_rcar_suspend(struct device *dev) | |
595 | { | |
596 | struct gpio_rcar_priv *p = dev_get_drvdata(dev); | |
597 | ||
598 | p->bank_info.iointsel = gpio_rcar_read(p, IOINTSEL); | |
599 | p->bank_info.inoutsel = gpio_rcar_read(p, INOUTSEL); | |
600 | p->bank_info.outdt = gpio_rcar_read(p, OUTDT); | |
601 | p->bank_info.intmsk = gpio_rcar_read(p, INTMSK); | |
602 | p->bank_info.posneg = gpio_rcar_read(p, POSNEG); | |
603 | p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL); | |
208c80f1 | 604 | if (p->info.has_both_edge_trigger) |
51750fb1 HD |
605 | p->bank_info.bothedge = gpio_rcar_read(p, BOTHEDGE); |
606 | ||
9ac79ba9 GU |
607 | if (atomic_read(&p->wakeup_path)) |
608 | device_set_wakeup_path(dev); | |
609 | ||
51750fb1 HD |
610 | return 0; |
611 | } | |
612 | ||
613 | static int gpio_rcar_resume(struct device *dev) | |
614 | { | |
615 | struct gpio_rcar_priv *p = dev_get_drvdata(dev); | |
616 | unsigned int offset; | |
617 | u32 mask; | |
618 | ||
619 | for (offset = 0; offset < p->gpio_chip.ngpio; offset++) { | |
496069b8 BD |
620 | if (!gpiochip_line_is_valid(&p->gpio_chip, offset)) |
621 | continue; | |
622 | ||
51750fb1 HD |
623 | mask = BIT(offset); |
624 | /* I/O pin */ | |
625 | if (!(p->bank_info.iointsel & mask)) { | |
626 | if (p->bank_info.inoutsel & mask) | |
627 | gpio_rcar_direction_output( | |
628 | &p->gpio_chip, offset, | |
629 | !!(p->bank_info.outdt & mask)); | |
630 | else | |
631 | gpio_rcar_direction_input(&p->gpio_chip, | |
632 | offset); | |
633 | } else { | |
634 | /* Interrupt pin */ | |
635 | gpio_rcar_config_interrupt_input_mode( | |
636 | p, | |
637 | offset, | |
638 | !(p->bank_info.posneg & mask), | |
639 | !(p->bank_info.edglevel & mask), | |
640 | !!(p->bank_info.bothedge & mask)); | |
641 | ||
642 | if (p->bank_info.intmsk & mask) | |
643 | gpio_rcar_write(p, MSKCLR, mask); | |
644 | } | |
645 | } | |
646 | ||
93ac0b0c GU |
647 | if (p->info.has_inen) |
648 | gpio_rcar_enable_inputs(p); | |
649 | ||
51750fb1 HD |
650 | return 0; |
651 | } | |
652 | #endif /* CONFIG_PM_SLEEP*/ | |
653 | ||
654 | static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, gpio_rcar_resume); | |
655 | ||
119f5e44 MD |
656 | static struct platform_driver gpio_rcar_device_driver = { |
657 | .probe = gpio_rcar_probe, | |
658 | .remove = gpio_rcar_remove, | |
659 | .driver = { | |
660 | .name = "gpio_rcar", | |
51750fb1 | 661 | .pm = &gpio_rcar_pm_ops, |
159f8a02 | 662 | .of_match_table = of_match_ptr(gpio_rcar_of_table), |
119f5e44 MD |
663 | } |
664 | }; | |
665 | ||
666 | module_platform_driver(gpio_rcar_device_driver); | |
667 | ||
668 | MODULE_AUTHOR("Magnus Damm"); | |
669 | MODULE_DESCRIPTION("Renesas R-Car GPIO Driver"); | |
670 | MODULE_LICENSE("GPL v2"); |