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