blob: bd2e16d6e21c40cf244b62003f02ca7b29b86984 [file] [log] [blame]
Kuninori Morimoto8b37eb72018-11-08 06:35:16 +00001// SPDX-License-Identifier: GPL-2.0
Magnus Damm119f5e42013-03-13 20:32:13 +09002/*
3 * Renesas R-Car GPIO Support
4 *
Hisashi Nakamura1fd2b492014-11-07 20:54:08 +09005 * Copyright (C) 2014 Renesas Electronics Corporation
Magnus Damm119f5e42013-03-13 20:32:13 +09006 * Copyright (C) 2013 Magnus Damm
Magnus Damm119f5e42013-03-13 20:32:13 +09007 */
8
9#include <linux/err.h>
Linus Walleij4b1d8002018-05-31 08:08:13 +020010#include <linux/gpio/driver.h>
Magnus Damm119f5e42013-03-13 20:32:13 +090011#include <linux/init.h>
12#include <linux/interrupt.h>
13#include <linux/io.h>
14#include <linux/ioport.h>
15#include <linux/irq.h>
Magnus Damm119f5e42013-03-13 20:32:13 +090016#include <linux/module.h>
Sachin Kamatbd0bf462013-10-16 15:35:02 +053017#include <linux/of.h>
Geert Uytterhoevenf9f2a6f2017-10-04 14:16:16 +020018#include <linux/of_device.h>
Laurent Pinchartdc3465a2013-03-10 03:27:00 +010019#include <linux/pinctrl/consumer.h>
Magnus Damm119f5e42013-03-13 20:32:13 +090020#include <linux/platform_device.h>
Geert Uytterhoevendf0c6c82014-04-14 20:33:13 +020021#include <linux/pm_runtime.h>
Magnus Damm119f5e42013-03-13 20:32:13 +090022#include <linux/spinlock.h>
23#include <linux/slab.h>
24
Hien Dang51750fb2018-02-05 04:15:02 +090025struct 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
Geert Uytterhoeven208c80f2020-10-28 15:15:03 +010035struct gpio_rcar_info {
36 bool has_outdtsel;
37 bool has_both_edge_trigger;
Geert Uytterhoevenecba1ea2021-01-08 11:20:25 +010038 bool has_always_in;
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +010039 bool has_inen;
Geert Uytterhoeven208c80f2020-10-28 15:15:03 +010040};
41
Magnus Damm119f5e42013-03-13 20:32:13 +090042struct gpio_rcar_priv {
43 void __iomem *base;
44 spinlock_t lock;
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +020045 struct device *dev;
Magnus Damm119f5e42013-03-13 20:32:13 +090046 struct gpio_chip gpio_chip;
47 struct irq_chip irq_chip;
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +010048 unsigned int irq_parent;
Geert Uytterhoeven9ac79ba2018-02-12 14:55:13 +010049 atomic_t wakeup_path;
Geert Uytterhoeven208c80f2020-10-28 15:15:03 +010050 struct gpio_rcar_info info;
Hien Dang51750fb2018-02-05 04:15:02 +090051 struct gpio_rcar_bank_info bank_info;
Magnus Damm119f5e42013-03-13 20:32:13 +090052};
53
Geert Uytterhoeven677d7d62020-10-28 15:15:02 +010054#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 */
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +010067#define INEN 0x50 /* General Input Enable Register */
Magnus Damm119f5e42013-03-13 20:32:13 +090068
Laurent Pinchart159f8a02013-05-21 13:40:06 +020069#define RCAR_MAX_GPIO_PER_BANK 32
70
Magnus Damm119f5e42013-03-13 20:32:13 +090071static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs)
72{
73 return ioread32(p->base + offs);
74}
75
76static inline void gpio_rcar_write(struct gpio_rcar_priv *p, int offs,
77 u32 value)
78{
79 iowrite32(value, p->base + offs);
80}
81
82static 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
95static void gpio_rcar_irq_disable(struct irq_data *d)
96{
Geert Uytterhoevenc7f3c5d2015-01-12 11:07:59 +010097 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleijc7b6f452015-12-07 14:12:45 +010098 struct gpio_rcar_priv *p = gpiochip_get_data(gc);
Magnus Damm119f5e42013-03-13 20:32:13 +090099
100 gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d)));
101}
102
103static void gpio_rcar_irq_enable(struct irq_data *d)
104{
Geert Uytterhoevenc7f3c5d2015-01-12 11:07:59 +0100105 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleijc7b6f452015-12-07 14:12:45 +0100106 struct gpio_rcar_priv *p = gpiochip_get_data(gc);
Magnus Damm119f5e42013-03-13 20:32:13 +0900107
108 gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d)));
109}
110
111static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
112 unsigned int hwirq,
113 bool active_high_rising_edge,
Simon Horman7e1092b2013-05-24 18:47:24 +0900114 bool level_trigger,
115 bool both)
Magnus Damm119f5e42013-03-13 20:32:13 +0900116{
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
Ashish Chavanb36368f2020-02-09 15:26:00 +0530126 /* Configure positive or negative logic in POSNEG */
Magnus Damm119f5e42013-03-13 20:32:13 +0900127 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
Simon Horman7e1092b2013-05-24 18:47:24 +0900132 /* Select one edge or both edges in BOTHEDGE */
Geert Uytterhoeven208c80f2020-10-28 15:15:03 +0100133 if (p->info.has_both_edge_trigger)
Simon Horman7e1092b2013-05-24 18:47:24 +0900134 gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
135
Magnus Damm119f5e42013-03-13 20:32:13 +0900136 /* 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
146static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
147{
Geert Uytterhoevenc7f3c5d2015-01-12 11:07:59 +0100148 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleijc7b6f452015-12-07 14:12:45 +0100149 struct gpio_rcar_priv *p = gpiochip_get_data(gc);
Magnus Damm119f5e42013-03-13 20:32:13 +0900150 unsigned int hwirq = irqd_to_hwirq(d);
151
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +0200152 dev_dbg(p->dev, "sense irq = %d, type = %d\n", hwirq, type);
Magnus Damm119f5e42013-03-13 20:32:13 +0900153
154 switch (type & IRQ_TYPE_SENSE_MASK) {
155 case IRQ_TYPE_LEVEL_HIGH:
Simon Horman7e1092b2013-05-24 18:47:24 +0900156 gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true,
157 false);
Magnus Damm119f5e42013-03-13 20:32:13 +0900158 break;
159 case IRQ_TYPE_LEVEL_LOW:
Simon Horman7e1092b2013-05-24 18:47:24 +0900160 gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true,
161 false);
Magnus Damm119f5e42013-03-13 20:32:13 +0900162 break;
163 case IRQ_TYPE_EDGE_RISING:
Simon Horman7e1092b2013-05-24 18:47:24 +0900164 gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
165 false);
Magnus Damm119f5e42013-03-13 20:32:13 +0900166 break;
167 case IRQ_TYPE_EDGE_FALLING:
Simon Horman7e1092b2013-05-24 18:47:24 +0900168 gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false,
169 false);
170 break;
171 case IRQ_TYPE_EDGE_BOTH:
Geert Uytterhoeven208c80f2020-10-28 15:15:03 +0100172 if (!p->info.has_both_edge_trigger)
Simon Horman7e1092b2013-05-24 18:47:24 +0900173 return -EINVAL;
174 gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
175 true);
Magnus Damm119f5e42013-03-13 20:32:13 +0900176 break;
177 default:
178 return -EINVAL;
179 }
180 return 0;
181}
182
Geert Uytterhoevenab82fa72015-03-18 19:41:09 +0100183static 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);
Linus Walleijc7b6f452015-12-07 14:12:45 +0100186 struct gpio_rcar_priv *p = gpiochip_get_data(gc);
Geert Uytterhoeven501ef0f2015-05-21 13:21:37 +0200187 int error;
Geert Uytterhoevenab82fa72015-03-18 19:41:09 +0100188
Geert Uytterhoeven501ef0f2015-05-21 13:21:37 +0200189 if (p->irq_parent) {
190 error = irq_set_irq_wake(p->irq_parent, on);
191 if (error) {
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +0200192 dev_dbg(p->dev, "irq %u doesn't support irq_set_wake\n",
Geert Uytterhoeven501ef0f2015-05-21 13:21:37 +0200193 p->irq_parent);
194 p->irq_parent = 0;
195 }
196 }
Geert Uytterhoevenab82fa72015-03-18 19:41:09 +0100197
Geert Uytterhoevenab82fa72015-03-18 19:41:09 +0100198 if (on)
Geert Uytterhoeven9ac79ba2018-02-12 14:55:13 +0100199 atomic_inc(&p->wakeup_path);
Geert Uytterhoevenab82fa72015-03-18 19:41:09 +0100200 else
Geert Uytterhoeven9ac79ba2018-02-12 14:55:13 +0100201 atomic_dec(&p->wakeup_path);
Geert Uytterhoevenab82fa72015-03-18 19:41:09 +0100202
203 return 0;
204}
205
Magnus Damm119f5e42013-03-13 20:32:13 +0900206static 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
Valentine Barshak8808b642013-11-29 22:04:09 +0400212 while ((pending = gpio_rcar_read(p, INTDT) &
213 gpio_rcar_read(p, INTMSK))) {
Magnus Damm119f5e42013-03-13 20:32:13 +0900214 offset = __ffs(pending);
215 gpio_rcar_write(p, INTCLR, BIT(offset));
Marc Zyngierdbd1c542021-05-04 17:42:18 +0100216 generic_handle_domain_irq(p->gpio_chip.irq.domain,
217 offset);
Magnus Damm119f5e42013-03-13 20:32:13 +0900218 irqs_handled++;
219 }
220
221 return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
222}
223
Magnus Damm119f5e42013-03-13 20:32:13 +0900224static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
225 unsigned int gpio,
226 bool output)
227{
Linus Walleijc7b6f452015-12-07 14:12:45 +0100228 struct gpio_rcar_priv *p = gpiochip_get_data(chip);
Magnus Damm119f5e42013-03-13 20:32:13 +0900229 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
Ashish Chavanb36368f2020-02-09 15:26:00 +0530238 /* Configure positive logic in POSNEG */
Magnus Damm119f5e42013-03-13 20:32:13 +0900239 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
Vladimir Zapolskiy3ae4f3a2019-01-18 10:53:43 +0200247 /* Select General Output Register to output data in OUTDTSEL */
Geert Uytterhoeven208c80f2020-10-28 15:15:03 +0100248 if (p->info.has_outdtsel && output)
Vladimir Zapolskiy3ae4f3a2019-01-18 10:53:43 +0200249 gpio_rcar_modify_bit(p, OUTDTSEL, gpio, false);
250
Magnus Damm119f5e42013-03-13 20:32:13 +0900251 spin_unlock_irqrestore(&p->lock, flags);
252}
253
Laurent Pinchartdc3465a2013-03-10 03:27:00 +0100254static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
255{
Geert Uytterhoeven2d654722016-12-08 18:32:28 +0100256 struct gpio_rcar_priv *p = gpiochip_get_data(chip);
257 int error;
258
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +0200259 error = pm_runtime_get_sync(p->dev);
Dinghao Liu6f8cd242020-05-22 16:08:38 +0800260 if (error < 0) {
261 pm_runtime_put(p->dev);
Geert Uytterhoeven2d654722016-12-08 18:32:28 +0100262 return error;
Dinghao Liu6f8cd242020-05-22 16:08:38 +0800263 }
Geert Uytterhoeven2d654722016-12-08 18:32:28 +0100264
Linus Walleija9a1d2a2017-09-22 11:02:10 +0200265 error = pinctrl_gpio_request(chip->base + offset);
Geert Uytterhoeven2d654722016-12-08 18:32:28 +0100266 if (error)
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +0200267 pm_runtime_put(p->dev);
Geert Uytterhoeven2d654722016-12-08 18:32:28 +0100268
269 return error;
Laurent Pinchartdc3465a2013-03-10 03:27:00 +0100270}
271
272static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
273{
Geert Uytterhoeven2d654722016-12-08 18:32:28 +0100274 struct gpio_rcar_priv *p = gpiochip_get_data(chip);
275
Linus Walleija9a1d2a2017-09-22 11:02:10 +0200276 pinctrl_gpio_free(chip->base + offset);
Laurent Pinchartdc3465a2013-03-10 03:27:00 +0100277
Linus Walleijce0e2c62016-04-12 10:05:22 +0200278 /*
279 * Set the GPIO as an input to ensure that the next GPIO request won't
Laurent Pinchartdc3465a2013-03-10 03:27:00 +0100280 * drive the GPIO pin as an output.
281 */
282 gpio_rcar_config_general_input_output_mode(chip, offset, false);
Geert Uytterhoeven2d654722016-12-08 18:32:28 +0100283
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +0200284 pm_runtime_put(p->dev);
Laurent Pinchartdc3465a2013-03-10 03:27:00 +0100285}
286
Geert Uytterhoevenad817292018-07-12 11:15:01 +0200287static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset)
288{
289 struct gpio_rcar_priv *p = gpiochip_get_data(chip);
290
Matti Vaittinene42615e2019-11-06 10:54:12 +0200291 if (gpio_rcar_read(p, INOUTSEL) & BIT(offset))
292 return GPIO_LINE_DIRECTION_OUT;
293
294 return GPIO_LINE_DIRECTION_IN;
Geert Uytterhoevenad817292018-07-12 11:15:01 +0200295}
296
Magnus Damm119f5e42013-03-13 20:32:13 +0900297static 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
303static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
304{
Geert Uytterhoeven714d3a22020-10-28 15:15:01 +0100305 struct gpio_rcar_priv *p = gpiochip_get_data(chip);
Magnus Dammae9550f2013-06-17 08:41:52 +0900306 u32 bit = BIT(offset);
307
Geert Uytterhoevenecba1ea2021-01-08 11:20:25 +0100308 /*
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))
Geert Uytterhoeven714d3a22020-10-28 15:15:01 +0100313 return !!(gpio_rcar_read(p, OUTDT) & bit);
Magnus Dammae9550f2013-06-17 08:41:52 +0900314 else
Geert Uytterhoeven714d3a22020-10-28 15:15:01 +0100315 return !!(gpio_rcar_read(p, INDT) & bit);
Magnus Damm119f5e42013-03-13 20:32:13 +0900316}
317
Geert Uytterhoeven183245c2020-10-28 15:15:04 +0100318static 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
Geert Uytterhoevenecba1ea2021-01-08 11:20:25 +0100332 if (p->info.has_always_in) {
333 bits[0] = gpio_rcar_read(p, INDT) & bankmask;
334 return 0;
335 }
336
Geert Uytterhoeven183245c2020-10-28 15:15:04 +0100337 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
Magnus Damm119f5e42013-03-13 20:32:13 +0900352static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
353{
Linus Walleijc7b6f452015-12-07 14:12:45 +0100354 struct gpio_rcar_priv *p = gpiochip_get_data(chip);
Magnus Damm119f5e42013-03-13 20:32:13 +0900355 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
Geert Uytterhoevendbb763b82016-03-14 16:21:44 +0100362static 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);
Biju Das496069b2018-08-07 08:57:02 +0100370 if (chip->valid_mask)
371 bankmask &= chip->valid_mask[0];
372
Geert Uytterhoevendbb763b82016-03-14 16:21:44 +0100373 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
Magnus Damm119f5e42013-03-13 20:32:13 +0900384static 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
Hisashi Nakamura1fd2b492014-11-07 20:54:08 +0900393static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
Vladimir Zapolskiy3ae4f3a2019-01-18 10:53:43 +0200394 .has_outdtsel = false,
Hisashi Nakamura1fd2b492014-11-07 20:54:08 +0900395 .has_both_edge_trigger = false,
Geert Uytterhoevenecba1ea2021-01-08 11:20:25 +0100396 .has_always_in = false,
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +0100397 .has_inen = false,
Hisashi Nakamura1fd2b492014-11-07 20:54:08 +0900398};
399
400static const struct gpio_rcar_info gpio_rcar_info_gen2 = {
Vladimir Zapolskiy3ae4f3a2019-01-18 10:53:43 +0200401 .has_outdtsel = true,
Hisashi Nakamura1fd2b492014-11-07 20:54:08 +0900402 .has_both_edge_trigger = true,
Geert Uytterhoevenecba1ea2021-01-08 11:20:25 +0100403 .has_always_in = false,
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +0100404 .has_inen = false,
Geert Uytterhoevenecba1ea2021-01-08 11:20:25 +0100405};
406
407static const struct gpio_rcar_info gpio_rcar_info_gen3 = {
408 .has_outdtsel = true,
409 .has_both_edge_trigger = true,
410 .has_always_in = true,
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +0100411 .has_inen = false,
412};
413
414static 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,
Hisashi Nakamura1fd2b492014-11-07 20:54:08 +0900419};
420
Laurent Pinchart850dfe12013-11-29 14:48:00 +0100421static const struct of_device_id gpio_rcar_of_table[] = {
422 {
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +0100423 .compatible = "renesas,gpio-r8a779a0",
424 .data = &gpio_rcar_info_v3u,
425 }, {
Simon Hormandbd1dad2017-07-11 14:38:30 +0200426 .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",
Geert Uytterhoevenecba1ea2021-01-08 11:20:25 +0100433 .data = &gpio_rcar_info_gen3,
Simon Hormandbd1dad2017-07-11 14:38:30 +0200434 }, {
Laurent Pinchart850dfe12013-11-29 14:48:00 +0100435 .compatible = "renesas,gpio-rcar",
Hisashi Nakamura1fd2b492014-11-07 20:54:08 +0900436 .data = &gpio_rcar_info_gen1,
Laurent Pinchart850dfe12013-11-29 14:48:00 +0100437 }, {
438 /* Terminator */
439 },
440};
441
442MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);
443
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +0100444static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
Laurent Pinchart159f8a02013-05-21 13:40:06 +0200445{
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +0200446 struct device_node *np = p->dev->of_node;
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +0100447 const struct gpio_rcar_info *info;
Laurent Pinchart159f8a02013-05-21 13:40:06 +0200448 struct of_phandle_args args;
449 int ret;
Laurent Pinchart159f8a02013-05-21 13:40:06 +0200450
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +0200451 info = of_device_get_match_data(p->dev);
Geert Uytterhoeven208c80f2020-10-28 15:15:03 +0100452 p->info = *info;
Laurent Pinchart850dfe12013-11-29 14:48:00 +0100453
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +0100454 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;
Laurent Pinchart850dfe12013-11-29 14:48:00 +0100456
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +0100457 if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +0200458 dev_warn(p->dev, "Invalid number of gpio lines %u, using %u\n",
459 *npins, RCAR_MAX_GPIO_PER_BANK);
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +0100460 *npins = RCAR_MAX_GPIO_PER_BANK;
Laurent Pinchart159f8a02013-05-21 13:40:06 +0200461 }
Laurent Pinchart850dfe12013-11-29 14:48:00 +0100462
463 return 0;
Laurent Pinchart159f8a02013-05-21 13:40:06 +0200464}
465
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +0100466static 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
Magnus Damm119f5e42013-03-13 20:32:13 +0900477static int gpio_rcar_probe(struct platform_device *pdev)
478{
Magnus Damm119f5e42013-03-13 20:32:13 +0900479 struct gpio_rcar_priv *p;
Magnus Damm119f5e42013-03-13 20:32:13 +0900480 struct gpio_chip *gpio_chip;
481 struct irq_chip *irq_chip;
Linus Walleijb470cef2020-07-22 13:31:41 +0200482 struct gpio_irq_chip *girq;
Geert Uytterhoevenb22978f2014-03-27 21:47:36 +0100483 struct device *dev = &pdev->dev;
484 const char *name = dev_name(dev);
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +0100485 unsigned int npins;
Magnus Damm119f5e42013-03-13 20:32:13 +0900486 int ret;
487
Geert Uytterhoevenb22978f2014-03-27 21:47:36 +0100488 p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
Geert Uytterhoeven7d82bf32015-01-12 11:07:58 +0100489 if (!p)
490 return -ENOMEM;
Magnus Damm119f5e42013-03-13 20:32:13 +0900491
Vladimir Zapolskiya53f7952018-11-22 22:19:41 +0200492 p->dev = dev;
Magnus Damm119f5e42013-03-13 20:32:13 +0900493 spin_lock_init(&p->lock);
494
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +0100495 /* Get device configuration from DT node */
496 ret = gpio_rcar_parse_dt(p, &npins);
Laurent Pinchart850dfe12013-11-29 14:48:00 +0100497 if (ret < 0)
498 return ret;
Laurent Pinchart159f8a02013-05-21 13:40:06 +0200499
500 platform_set_drvdata(pdev, p);
501
Geert Uytterhoevendf0c6c82014-04-14 20:33:13 +0200502 pm_runtime_enable(dev);
Geert Uytterhoevendf0c6c82014-04-14 20:33:13 +0200503
Lad Prabhakarf1ff2722021-12-22 17:19:15 +0000504 ret = platform_get_irq(pdev, 0);
505 if (ret < 0)
Magnus Damm119f5e42013-03-13 20:32:13 +0900506 goto err0;
Lad Prabhakarf1ff2722021-12-22 17:19:15 +0000507 p->irq_parent = ret;
Magnus Damm119f5e42013-03-13 20:32:13 +0900508
Enrico Weigelt, metux IT consultecbf7c22019-03-11 19:55:06 +0100509 p->base = devm_platform_ioremap_resource(pdev, 0);
Sergei Shtylyov5a24d4b2017-10-13 00:08:14 +0300510 if (IS_ERR(p->base)) {
511 ret = PTR_ERR(p->base);
Magnus Damm119f5e42013-03-13 20:32:13 +0900512 goto err0;
513 }
514
515 gpio_chip = &p->gpio_chip;
Laurent Pinchartdc3465a2013-03-10 03:27:00 +0100516 gpio_chip->request = gpio_rcar_request;
517 gpio_chip->free = gpio_rcar_free;
Geert Uytterhoevenad817292018-07-12 11:15:01 +0200518 gpio_chip->get_direction = gpio_rcar_get_direction;
Magnus Damm119f5e42013-03-13 20:32:13 +0900519 gpio_chip->direction_input = gpio_rcar_direction_input;
520 gpio_chip->get = gpio_rcar_get;
Geert Uytterhoeven183245c2020-10-28 15:15:04 +0100521 gpio_chip->get_multiple = gpio_rcar_get_multiple;
Magnus Damm119f5e42013-03-13 20:32:13 +0900522 gpio_chip->direction_output = gpio_rcar_direction_output;
523 gpio_chip->set = gpio_rcar_set;
Geert Uytterhoevendbb763b82016-03-14 16:21:44 +0100524 gpio_chip->set_multiple = gpio_rcar_set_multiple;
Magnus Damm119f5e42013-03-13 20:32:13 +0900525 gpio_chip->label = name;
Linus Walleij58383c782015-11-04 09:56:26 +0100526 gpio_chip->parent = dev;
Magnus Damm119f5e42013-03-13 20:32:13 +0900527 gpio_chip->owner = THIS_MODULE;
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +0100528 gpio_chip->base = -1;
529 gpio_chip->ngpio = npins;
Magnus Damm119f5e42013-03-13 20:32:13 +0900530
531 irq_chip = &p->irq_chip;
Geert Uytterhoevenf932a682019-10-24 14:22:24 +0200532 irq_chip->name = "gpio-rcar";
Niklas Söderlund47bd38a2016-12-08 18:32:27 +0100533 irq_chip->parent_device = dev;
Magnus Damm119f5e42013-03-13 20:32:13 +0900534 irq_chip->irq_mask = gpio_rcar_irq_disable;
535 irq_chip->irq_unmask = gpio_rcar_irq_enable;
Magnus Damm119f5e42013-03-13 20:32:13 +0900536 irq_chip->irq_set_type = gpio_rcar_irq_set_type;
Geert Uytterhoevenab82fa72015-03-18 19:41:09 +0100537 irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
Enrico Weigelt, metux IT consultb183cab2019-06-17 18:49:14 +0200538 irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
Magnus Damm119f5e42013-03-13 20:32:13 +0900539
Linus Walleijb470cef2020-07-22 13:31:41 +0200540 girq = &gpio_chip->irq;
541 girq->chip = irq_chip;
542 /* This will let us handle the parent IRQ in the driver */
543 girq->parent_handler = NULL;
544 girq->num_parents = 0;
545 girq->parents = NULL;
546 girq->default_type = IRQ_TYPE_NONE;
547 girq->handler = handle_level_irq;
548
Linus Walleijc7b6f452015-12-07 14:12:45 +0100549 ret = gpiochip_add_data(gpio_chip, p);
Geert Uytterhoevenc7f3c5d2015-01-12 11:07:59 +0100550 if (ret) {
551 dev_err(dev, "failed to add GPIO controller\n");
Dan Carpenter0c8aab82013-11-07 10:56:51 +0300552 goto err0;
Magnus Damm119f5e42013-03-13 20:32:13 +0900553 }
554
Lad Prabhakarffe31c92022-01-04 15:36:15 +0000555 ret = devm_request_irq(dev, p->irq_parent, gpio_rcar_irq_handler,
556 IRQF_SHARED, name, p);
557 if (ret) {
Geert Uytterhoevenb22978f2014-03-27 21:47:36 +0100558 dev_err(dev, "failed to request IRQ\n");
Magnus Damm119f5e42013-03-13 20:32:13 +0900559 goto err1;
560 }
561
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +0100562 if (p->info.has_inen) {
Geert Uytterhoeven3d134e72021-07-14 14:51:13 +0200563 pm_runtime_get_sync(dev);
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +0100564 gpio_rcar_enable_inputs(p);
Geert Uytterhoeven3d134e72021-07-14 14:51:13 +0200565 pm_runtime_put(dev);
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +0100566 }
567
Geert Uytterhoeven8b092be2015-12-04 16:33:52 +0100568 dev_info(dev, "driving %d GPIOs\n", npins);
Laurent Pinchartdc3465a2013-03-10 03:27:00 +0100569
Magnus Damm119f5e42013-03-13 20:32:13 +0900570 return 0;
571
572err1:
Geert Uytterhoeven4d84b9e2015-03-18 19:41:07 +0100573 gpiochip_remove(gpio_chip);
Magnus Damm119f5e42013-03-13 20:32:13 +0900574err0:
Geert Uytterhoevendf0c6c82014-04-14 20:33:13 +0200575 pm_runtime_disable(dev);
Magnus Damm119f5e42013-03-13 20:32:13 +0900576 return ret;
577}
578
579static int gpio_rcar_remove(struct platform_device *pdev)
580{
581 struct gpio_rcar_priv *p = platform_get_drvdata(pdev);
Magnus Damm119f5e42013-03-13 20:32:13 +0900582
abdoulaye berthe9f5132a2014-07-12 22:30:12 +0200583 gpiochip_remove(&p->gpio_chip);
Magnus Damm119f5e42013-03-13 20:32:13 +0900584
Geert Uytterhoevendf0c6c82014-04-14 20:33:13 +0200585 pm_runtime_disable(&pdev->dev);
Magnus Damm119f5e42013-03-13 20:32:13 +0900586 return 0;
587}
588
Hien Dang51750fb2018-02-05 04:15:02 +0900589#ifdef CONFIG_PM_SLEEP
590static int gpio_rcar_suspend(struct device *dev)
591{
592 struct gpio_rcar_priv *p = dev_get_drvdata(dev);
593
594 p->bank_info.iointsel = gpio_rcar_read(p, IOINTSEL);
595 p->bank_info.inoutsel = gpio_rcar_read(p, INOUTSEL);
596 p->bank_info.outdt = gpio_rcar_read(p, OUTDT);
597 p->bank_info.intmsk = gpio_rcar_read(p, INTMSK);
598 p->bank_info.posneg = gpio_rcar_read(p, POSNEG);
599 p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL);
Geert Uytterhoeven208c80f2020-10-28 15:15:03 +0100600 if (p->info.has_both_edge_trigger)
Hien Dang51750fb2018-02-05 04:15:02 +0900601 p->bank_info.bothedge = gpio_rcar_read(p, BOTHEDGE);
602
Geert Uytterhoeven9ac79ba2018-02-12 14:55:13 +0100603 if (atomic_read(&p->wakeup_path))
604 device_set_wakeup_path(dev);
605
Hien Dang51750fb2018-02-05 04:15:02 +0900606 return 0;
607}
608
609static int gpio_rcar_resume(struct device *dev)
610{
611 struct gpio_rcar_priv *p = dev_get_drvdata(dev);
612 unsigned int offset;
613 u32 mask;
614
615 for (offset = 0; offset < p->gpio_chip.ngpio; offset++) {
Biju Das496069b2018-08-07 08:57:02 +0100616 if (!gpiochip_line_is_valid(&p->gpio_chip, offset))
617 continue;
618
Hien Dang51750fb2018-02-05 04:15:02 +0900619 mask = BIT(offset);
620 /* I/O pin */
621 if (!(p->bank_info.iointsel & mask)) {
622 if (p->bank_info.inoutsel & mask)
623 gpio_rcar_direction_output(
624 &p->gpio_chip, offset,
625 !!(p->bank_info.outdt & mask));
626 else
627 gpio_rcar_direction_input(&p->gpio_chip,
628 offset);
629 } else {
630 /* Interrupt pin */
631 gpio_rcar_config_interrupt_input_mode(
632 p,
633 offset,
634 !(p->bank_info.posneg & mask),
635 !(p->bank_info.edglevel & mask),
636 !!(p->bank_info.bothedge & mask));
637
638 if (p->bank_info.intmsk & mask)
639 gpio_rcar_write(p, MSKCLR, mask);
640 }
641 }
642
Geert Uytterhoeven93ac0b02021-01-08 11:20:26 +0100643 if (p->info.has_inen)
644 gpio_rcar_enable_inputs(p);
645
Hien Dang51750fb2018-02-05 04:15:02 +0900646 return 0;
647}
648#endif /* CONFIG_PM_SLEEP*/
649
650static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, gpio_rcar_resume);
651
Magnus Damm119f5e42013-03-13 20:32:13 +0900652static struct platform_driver gpio_rcar_device_driver = {
653 .probe = gpio_rcar_probe,
654 .remove = gpio_rcar_remove,
655 .driver = {
656 .name = "gpio_rcar",
Hien Dang51750fb2018-02-05 04:15:02 +0900657 .pm = &gpio_rcar_pm_ops,
Laurent Pinchart159f8a02013-05-21 13:40:06 +0200658 .of_match_table = of_match_ptr(gpio_rcar_of_table),
Magnus Damm119f5e42013-03-13 20:32:13 +0900659 }
660};
661
662module_platform_driver(gpio_rcar_device_driver);
663
664MODULE_AUTHOR("Magnus Damm");
665MODULE_DESCRIPTION("Renesas R-Car GPIO Driver");
666MODULE_LICENSE("GPL v2");