Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
5e969a40 TR |
2 | /* |
3 | * Copyright (C) 2011-2012 Avionic Design GmbH | |
5e969a40 TR |
4 | */ |
5 | ||
0752e169 | 6 | #include <linux/gpio/driver.h> |
5e969a40 TR |
7 | #include <linux/i2c.h> |
8 | #include <linux/interrupt.h> | |
5e969a40 TR |
9 | #include <linux/module.h> |
10 | #include <linux/of_irq.h> | |
11 | #include <linux/seq_file.h> | |
12 | #include <linux/slab.h> | |
13 | ||
14 | #define GPIO_DDR(gpio) (0x00 << (gpio)->reg_shift) | |
15 | #define GPIO_PLR(gpio) (0x01 << (gpio)->reg_shift) | |
16 | #define GPIO_IER(gpio) (0x02 << (gpio)->reg_shift) | |
17 | #define GPIO_ISR(gpio) (0x03 << (gpio)->reg_shift) | |
18 | #define GPIO_PTR(gpio) (0x04 << (gpio)->reg_shift) | |
19 | ||
20 | struct adnp { | |
21 | struct i2c_client *client; | |
22 | struct gpio_chip gpio; | |
23 | unsigned int reg_shift; | |
24 | ||
25 | struct mutex i2c_lock; | |
5e969a40 TR |
26 | struct mutex irq_lock; |
27 | ||
28 | u8 *irq_enable; | |
29 | u8 *irq_level; | |
30 | u8 *irq_rise; | |
31 | u8 *irq_fall; | |
32 | u8 *irq_high; | |
33 | u8 *irq_low; | |
34 | }; | |
35 | ||
5e969a40 TR |
36 | static int adnp_read(struct adnp *adnp, unsigned offset, uint8_t *value) |
37 | { | |
38 | int err; | |
39 | ||
40 | err = i2c_smbus_read_byte_data(adnp->client, offset); | |
41 | if (err < 0) { | |
58383c78 | 42 | dev_err(adnp->gpio.parent, "%s failed: %d\n", |
5e969a40 TR |
43 | "i2c_smbus_read_byte_data()", err); |
44 | return err; | |
45 | } | |
46 | ||
47 | *value = err; | |
48 | return 0; | |
49 | } | |
50 | ||
51 | static int adnp_write(struct adnp *adnp, unsigned offset, uint8_t value) | |
52 | { | |
53 | int err; | |
54 | ||
55 | err = i2c_smbus_write_byte_data(adnp->client, offset, value); | |
56 | if (err < 0) { | |
58383c78 | 57 | dev_err(adnp->gpio.parent, "%s failed: %d\n", |
5e969a40 TR |
58 | "i2c_smbus_write_byte_data()", err); |
59 | return err; | |
60 | } | |
61 | ||
62 | return 0; | |
63 | } | |
64 | ||
65 | static int adnp_gpio_get(struct gpio_chip *chip, unsigned offset) | |
66 | { | |
1e69c4fe | 67 | struct adnp *adnp = gpiochip_get_data(chip); |
5e969a40 TR |
68 | unsigned int reg = offset >> adnp->reg_shift; |
69 | unsigned int pos = offset & 7; | |
70 | u8 value; | |
71 | int err; | |
72 | ||
73 | err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &value); | |
74 | if (err < 0) | |
75 | return err; | |
76 | ||
77 | return (value & BIT(pos)) ? 1 : 0; | |
78 | } | |
79 | ||
80 | static void __adnp_gpio_set(struct adnp *adnp, unsigned offset, int value) | |
81 | { | |
82 | unsigned int reg = offset >> adnp->reg_shift; | |
83 | unsigned int pos = offset & 7; | |
84 | int err; | |
85 | u8 val; | |
86 | ||
87 | err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &val); | |
88 | if (err < 0) | |
89 | return; | |
90 | ||
91 | if (value) | |
92 | val |= BIT(pos); | |
93 | else | |
94 | val &= ~BIT(pos); | |
95 | ||
96 | adnp_write(adnp, GPIO_PLR(adnp) + reg, val); | |
97 | } | |
98 | ||
99 | static void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |
100 | { | |
1e69c4fe | 101 | struct adnp *adnp = gpiochip_get_data(chip); |
5e969a40 TR |
102 | |
103 | mutex_lock(&adnp->i2c_lock); | |
104 | __adnp_gpio_set(adnp, offset, value); | |
105 | mutex_unlock(&adnp->i2c_lock); | |
106 | } | |
107 | ||
108 | static int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | |
109 | { | |
1e69c4fe | 110 | struct adnp *adnp = gpiochip_get_data(chip); |
5e969a40 TR |
111 | unsigned int reg = offset >> adnp->reg_shift; |
112 | unsigned int pos = offset & 7; | |
113 | u8 value; | |
114 | int err; | |
115 | ||
116 | mutex_lock(&adnp->i2c_lock); | |
117 | ||
118 | err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); | |
119 | if (err < 0) | |
120 | goto out; | |
121 | ||
122 | value &= ~BIT(pos); | |
123 | ||
124 | err = adnp_write(adnp, GPIO_DDR(adnp) + reg, value); | |
125 | if (err < 0) | |
126 | goto out; | |
127 | ||
128 | err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); | |
129 | if (err < 0) | |
130 | goto out; | |
131 | ||
c5bc6e52 AL |
132 | if (value & BIT(pos)) { |
133 | err = -EPERM; | |
134 | goto out; | |
135 | } | |
5e969a40 TR |
136 | |
137 | err = 0; | |
138 | ||
139 | out: | |
140 | mutex_unlock(&adnp->i2c_lock); | |
141 | return err; | |
142 | } | |
143 | ||
144 | static int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | |
145 | int value) | |
146 | { | |
1e69c4fe | 147 | struct adnp *adnp = gpiochip_get_data(chip); |
5e969a40 TR |
148 | unsigned int reg = offset >> adnp->reg_shift; |
149 | unsigned int pos = offset & 7; | |
150 | int err; | |
151 | u8 val; | |
152 | ||
153 | mutex_lock(&adnp->i2c_lock); | |
154 | ||
155 | err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); | |
156 | if (err < 0) | |
157 | goto out; | |
158 | ||
159 | val |= BIT(pos); | |
160 | ||
161 | err = adnp_write(adnp, GPIO_DDR(adnp) + reg, val); | |
162 | if (err < 0) | |
163 | goto out; | |
164 | ||
165 | err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); | |
166 | if (err < 0) | |
167 | goto out; | |
168 | ||
169 | if (!(val & BIT(pos))) { | |
170 | err = -EPERM; | |
171 | goto out; | |
172 | } | |
173 | ||
174 | __adnp_gpio_set(adnp, offset, value); | |
175 | err = 0; | |
176 | ||
177 | out: | |
178 | mutex_unlock(&adnp->i2c_lock); | |
179 | return err; | |
180 | } | |
181 | ||
182 | static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | |
183 | { | |
1e69c4fe | 184 | struct adnp *adnp = gpiochip_get_data(chip); |
5e969a40 TR |
185 | unsigned int num_regs = 1 << adnp->reg_shift, i, j; |
186 | int err; | |
187 | ||
188 | for (i = 0; i < num_regs; i++) { | |
189 | u8 ddr, plr, ier, isr; | |
190 | ||
191 | mutex_lock(&adnp->i2c_lock); | |
192 | ||
193 | err = adnp_read(adnp, GPIO_DDR(adnp) + i, &ddr); | |
5ac9d2df ME |
194 | if (err < 0) |
195 | goto unlock; | |
5e969a40 TR |
196 | |
197 | err = adnp_read(adnp, GPIO_PLR(adnp) + i, &plr); | |
5ac9d2df ME |
198 | if (err < 0) |
199 | goto unlock; | |
5e969a40 TR |
200 | |
201 | err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); | |
5ac9d2df ME |
202 | if (err < 0) |
203 | goto unlock; | |
5e969a40 TR |
204 | |
205 | err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); | |
5ac9d2df ME |
206 | if (err < 0) |
207 | goto unlock; | |
5e969a40 TR |
208 | |
209 | mutex_unlock(&adnp->i2c_lock); | |
210 | ||
211 | for (j = 0; j < 8; j++) { | |
212 | unsigned int bit = (i << adnp->reg_shift) + j; | |
213 | const char *direction = "input "; | |
214 | const char *level = "low "; | |
215 | const char *interrupt = "disabled"; | |
216 | const char *pending = ""; | |
217 | ||
218 | if (ddr & BIT(j)) | |
219 | direction = "output"; | |
220 | ||
221 | if (plr & BIT(j)) | |
222 | level = "high"; | |
223 | ||
224 | if (ier & BIT(j)) | |
225 | interrupt = "enabled "; | |
226 | ||
227 | if (isr & BIT(j)) | |
228 | pending = "pending"; | |
229 | ||
230 | seq_printf(s, "%2u: %s %s IRQ %s %s\n", bit, | |
231 | direction, level, interrupt, pending); | |
232 | } | |
233 | } | |
5ac9d2df ME |
234 | |
235 | return; | |
236 | ||
237 | unlock: | |
238 | mutex_unlock(&adnp->i2c_lock); | |
5e969a40 TR |
239 | } |
240 | ||
5e969a40 TR |
241 | static irqreturn_t adnp_irq(int irq, void *data) |
242 | { | |
243 | struct adnp *adnp = data; | |
244 | unsigned int num_regs, i; | |
245 | ||
246 | num_regs = 1 << adnp->reg_shift; | |
247 | ||
248 | for (i = 0; i < num_regs; i++) { | |
249 | unsigned int base = i << adnp->reg_shift, bit; | |
250 | u8 changed, level, isr, ier; | |
251 | unsigned long pending; | |
252 | int err; | |
253 | ||
254 | mutex_lock(&adnp->i2c_lock); | |
255 | ||
256 | err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level); | |
257 | if (err < 0) { | |
258 | mutex_unlock(&adnp->i2c_lock); | |
259 | continue; | |
260 | } | |
261 | ||
262 | err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); | |
263 | if (err < 0) { | |
264 | mutex_unlock(&adnp->i2c_lock); | |
265 | continue; | |
266 | } | |
267 | ||
268 | err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); | |
269 | if (err < 0) { | |
270 | mutex_unlock(&adnp->i2c_lock); | |
271 | continue; | |
272 | } | |
273 | ||
274 | mutex_unlock(&adnp->i2c_lock); | |
275 | ||
276 | /* determine pins that changed levels */ | |
277 | changed = level ^ adnp->irq_level[i]; | |
278 | ||
279 | /* compute edge-triggered interrupts */ | |
280 | pending = changed & ((adnp->irq_fall[i] & ~level) | | |
281 | (adnp->irq_rise[i] & level)); | |
282 | ||
283 | /* add in level-triggered interrupts */ | |
284 | pending |= (adnp->irq_high[i] & level) | | |
285 | (adnp->irq_low[i] & ~level); | |
286 | ||
287 | /* mask out non-pending and disabled interrupts */ | |
288 | pending &= isr & ier; | |
289 | ||
290 | for_each_set_bit(bit, &pending, 8) { | |
472f95b9 | 291 | unsigned int child_irq; |
f0fbe7bc | 292 | child_irq = irq_find_mapping(adnp->gpio.irq.domain, |
0752e169 | 293 | base + bit); |
472f95b9 | 294 | handle_nested_irq(child_irq); |
5e969a40 TR |
295 | } |
296 | } | |
297 | ||
298 | return IRQ_HANDLED; | |
299 | } | |
300 | ||
0752e169 | 301 | static void adnp_irq_mask(struct irq_data *d) |
5e969a40 | 302 | { |
0752e169 | 303 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 304 | struct adnp *adnp = gpiochip_get_data(gc); |
0752e169 LW |
305 | unsigned int reg = d->hwirq >> adnp->reg_shift; |
306 | unsigned int pos = d->hwirq & 7; | |
5e969a40 TR |
307 | |
308 | adnp->irq_enable[reg] &= ~BIT(pos); | |
309 | } | |
310 | ||
0752e169 | 311 | static void adnp_irq_unmask(struct irq_data *d) |
5e969a40 | 312 | { |
0752e169 | 313 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 314 | struct adnp *adnp = gpiochip_get_data(gc); |
0752e169 LW |
315 | unsigned int reg = d->hwirq >> adnp->reg_shift; |
316 | unsigned int pos = d->hwirq & 7; | |
5e969a40 TR |
317 | |
318 | adnp->irq_enable[reg] |= BIT(pos); | |
319 | } | |
320 | ||
0752e169 | 321 | static int adnp_irq_set_type(struct irq_data *d, unsigned int type) |
5e969a40 | 322 | { |
0752e169 | 323 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 324 | struct adnp *adnp = gpiochip_get_data(gc); |
0752e169 LW |
325 | unsigned int reg = d->hwirq >> adnp->reg_shift; |
326 | unsigned int pos = d->hwirq & 7; | |
5e969a40 TR |
327 | |
328 | if (type & IRQ_TYPE_EDGE_RISING) | |
329 | adnp->irq_rise[reg] |= BIT(pos); | |
330 | else | |
331 | adnp->irq_rise[reg] &= ~BIT(pos); | |
332 | ||
333 | if (type & IRQ_TYPE_EDGE_FALLING) | |
334 | adnp->irq_fall[reg] |= BIT(pos); | |
335 | else | |
336 | adnp->irq_fall[reg] &= ~BIT(pos); | |
337 | ||
338 | if (type & IRQ_TYPE_LEVEL_HIGH) | |
339 | adnp->irq_high[reg] |= BIT(pos); | |
340 | else | |
341 | adnp->irq_high[reg] &= ~BIT(pos); | |
342 | ||
343 | if (type & IRQ_TYPE_LEVEL_LOW) | |
344 | adnp->irq_low[reg] |= BIT(pos); | |
345 | else | |
346 | adnp->irq_low[reg] &= ~BIT(pos); | |
347 | ||
348 | return 0; | |
349 | } | |
350 | ||
0752e169 | 351 | static void adnp_irq_bus_lock(struct irq_data *d) |
5e969a40 | 352 | { |
0752e169 | 353 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 354 | struct adnp *adnp = gpiochip_get_data(gc); |
5e969a40 TR |
355 | |
356 | mutex_lock(&adnp->irq_lock); | |
357 | } | |
358 | ||
0752e169 | 359 | static void adnp_irq_bus_unlock(struct irq_data *d) |
5e969a40 | 360 | { |
0752e169 | 361 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 362 | struct adnp *adnp = gpiochip_get_data(gc); |
5e969a40 TR |
363 | unsigned int num_regs = 1 << adnp->reg_shift, i; |
364 | ||
365 | mutex_lock(&adnp->i2c_lock); | |
366 | ||
367 | for (i = 0; i < num_regs; i++) | |
368 | adnp_write(adnp, GPIO_IER(adnp) + i, adnp->irq_enable[i]); | |
369 | ||
370 | mutex_unlock(&adnp->i2c_lock); | |
371 | mutex_unlock(&adnp->irq_lock); | |
372 | } | |
373 | ||
374 | static struct irq_chip adnp_irq_chip = { | |
375 | .name = "gpio-adnp", | |
376 | .irq_mask = adnp_irq_mask, | |
377 | .irq_unmask = adnp_irq_unmask, | |
378 | .irq_set_type = adnp_irq_set_type, | |
379 | .irq_bus_lock = adnp_irq_bus_lock, | |
380 | .irq_bus_sync_unlock = adnp_irq_bus_unlock, | |
5e969a40 TR |
381 | }; |
382 | ||
383 | static int adnp_irq_setup(struct adnp *adnp) | |
384 | { | |
385 | unsigned int num_regs = 1 << adnp->reg_shift, i; | |
386 | struct gpio_chip *chip = &adnp->gpio; | |
387 | int err; | |
388 | ||
389 | mutex_init(&adnp->irq_lock); | |
390 | ||
391 | /* | |
392 | * Allocate memory to keep track of the current level and trigger | |
393 | * modes of the interrupts. To avoid multiple allocations, a single | |
394 | * large buffer is allocated and pointers are setup to point at the | |
395 | * corresponding offsets. For consistency, the layout of the buffer | |
396 | * is chosen to match the register layout of the hardware in that | |
397 | * each segment contains the corresponding bits for all interrupts. | |
398 | */ | |
a86854d0 | 399 | adnp->irq_enable = devm_kcalloc(chip->parent, num_regs, 6, |
58383c78 | 400 | GFP_KERNEL); |
5e969a40 TR |
401 | if (!adnp->irq_enable) |
402 | return -ENOMEM; | |
403 | ||
404 | adnp->irq_level = adnp->irq_enable + (num_regs * 1); | |
405 | adnp->irq_rise = adnp->irq_enable + (num_regs * 2); | |
406 | adnp->irq_fall = adnp->irq_enable + (num_regs * 3); | |
407 | adnp->irq_high = adnp->irq_enable + (num_regs * 4); | |
408 | adnp->irq_low = adnp->irq_enable + (num_regs * 5); | |
409 | ||
410 | for (i = 0; i < num_regs; i++) { | |
411 | /* | |
412 | * Read the initial level of all pins to allow the emulation | |
413 | * of edge triggered interrupts. | |
414 | */ | |
415 | err = adnp_read(adnp, GPIO_PLR(adnp) + i, &adnp->irq_level[i]); | |
416 | if (err < 0) | |
417 | return err; | |
418 | ||
419 | /* disable all interrupts */ | |
420 | err = adnp_write(adnp, GPIO_IER(adnp) + i, 0); | |
421 | if (err < 0) | |
422 | return err; | |
423 | ||
424 | adnp->irq_enable[i] = 0x00; | |
425 | } | |
426 | ||
58383c78 | 427 | err = devm_request_threaded_irq(chip->parent, adnp->client->irq, |
0752e169 LW |
428 | NULL, adnp_irq, |
429 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | |
58383c78 | 430 | dev_name(chip->parent), adnp); |
5e969a40 | 431 | if (err != 0) { |
58383c78 | 432 | dev_err(chip->parent, "can't request IRQ#%d: %d\n", |
5e969a40 | 433 | adnp->client->irq, err); |
5b21533b | 434 | return err; |
5e969a40 TR |
435 | } |
436 | ||
565a0e9a LW |
437 | return 0; |
438 | } | |
439 | ||
440 | static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios, | |
441 | bool is_irq_controller) | |
442 | { | |
443 | struct gpio_chip *chip = &adnp->gpio; | |
444 | int err; | |
445 | ||
446 | adnp->reg_shift = get_count_order(num_gpios) - 3; | |
447 | ||
448 | chip->direction_input = adnp_gpio_direction_input; | |
449 | chip->direction_output = adnp_gpio_direction_output; | |
450 | chip->get = adnp_gpio_get; | |
451 | chip->set = adnp_gpio_set; | |
452 | chip->can_sleep = true; | |
453 | ||
454 | if (IS_ENABLED(CONFIG_DEBUG_FS)) | |
455 | chip->dbg_show = adnp_gpio_dbg_show; | |
456 | ||
457 | chip->base = -1; | |
458 | chip->ngpio = num_gpios; | |
459 | chip->label = adnp->client->name; | |
460 | chip->parent = &adnp->client->dev; | |
461 | chip->of_node = chip->parent->of_node; | |
462 | chip->owner = THIS_MODULE; | |
463 | ||
464 | if (is_irq_controller) { | |
465 | struct gpio_irq_chip *girq; | |
466 | ||
467 | err = adnp_irq_setup(adnp); | |
468 | if (err) | |
469 | return err; | |
470 | ||
471 | girq = &chip->irq; | |
472 | girq->chip = &adnp_irq_chip; | |
473 | /* This will let us handle the parent IRQ in the driver */ | |
474 | girq->parent_handler = NULL; | |
475 | girq->num_parents = 0; | |
476 | girq->parents = NULL; | |
477 | girq->default_type = IRQ_TYPE_NONE; | |
478 | girq->handler = handle_simple_irq; | |
479 | girq->threaded = true; | |
5e969a40 TR |
480 | } |
481 | ||
565a0e9a LW |
482 | err = devm_gpiochip_add_data(&adnp->client->dev, chip, adnp); |
483 | if (err) | |
484 | return err; | |
35ca3f61 | 485 | |
0752e169 | 486 | return 0; |
5e969a40 TR |
487 | } |
488 | ||
3836309d | 489 | static int adnp_i2c_probe(struct i2c_client *client, |
5e969a40 TR |
490 | const struct i2c_device_id *id) |
491 | { | |
492 | struct device_node *np = client->dev.of_node; | |
493 | struct adnp *adnp; | |
494 | u32 num_gpios; | |
495 | int err; | |
496 | ||
497 | err = of_property_read_u32(np, "nr-gpios", &num_gpios); | |
498 | if (err < 0) | |
499 | return err; | |
500 | ||
501 | client->irq = irq_of_parse_and_map(np, 0); | |
502 | if (!client->irq) | |
503 | return -EPROBE_DEFER; | |
504 | ||
505 | adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL); | |
506 | if (!adnp) | |
507 | return -ENOMEM; | |
508 | ||
509 | mutex_init(&adnp->i2c_lock); | |
510 | adnp->client = client; | |
511 | ||
565a0e9a LW |
512 | err = adnp_gpio_setup(adnp, num_gpios, |
513 | of_property_read_bool(np, "interrupt-controller")); | |
0752e169 | 514 | if (err) |
5e969a40 TR |
515 | return err; |
516 | ||
5e969a40 | 517 | i2c_set_clientdata(client, adnp); |
5e969a40 | 518 | |
0752e169 | 519 | return 0; |
5e969a40 TR |
520 | } |
521 | ||
b5ba78de | 522 | static const struct i2c_device_id adnp_i2c_id[] = { |
5e969a40 TR |
523 | { "gpio-adnp" }, |
524 | { }, | |
525 | }; | |
526 | MODULE_DEVICE_TABLE(i2c, adnp_i2c_id); | |
527 | ||
b5ba78de | 528 | static const struct of_device_id adnp_of_match[] = { |
5e969a40 TR |
529 | { .compatible = "ad,gpio-adnp", }, |
530 | { }, | |
531 | }; | |
532 | MODULE_DEVICE_TABLE(of, adnp_of_match); | |
533 | ||
534 | static struct i2c_driver adnp_i2c_driver = { | |
535 | .driver = { | |
536 | .name = "gpio-adnp", | |
83924fb3 | 537 | .of_match_table = adnp_of_match, |
5e969a40 TR |
538 | }, |
539 | .probe = adnp_i2c_probe, | |
5e969a40 TR |
540 | .id_table = adnp_i2c_id, |
541 | }; | |
542 | module_i2c_driver(adnp_i2c_driver); | |
543 | ||
544 | MODULE_DESCRIPTION("Avionic Design N-bit GPIO expander"); | |
545 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | |
546 | MODULE_LICENSE("GPL"); |