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 | ||
241 | static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) | |
242 | { | |
243 | struct gpio_chip *chip = &adnp->gpio; | |
0752e169 | 244 | int err; |
5e969a40 TR |
245 | |
246 | adnp->reg_shift = get_count_order(num_gpios) - 3; | |
247 | ||
248 | chip->direction_input = adnp_gpio_direction_input; | |
249 | chip->direction_output = adnp_gpio_direction_output; | |
250 | chip->get = adnp_gpio_get; | |
251 | chip->set = adnp_gpio_set; | |
9fb1f39e | 252 | chip->can_sleep = true; |
5e969a40 TR |
253 | |
254 | if (IS_ENABLED(CONFIG_DEBUG_FS)) | |
255 | chip->dbg_show = adnp_gpio_dbg_show; | |
256 | ||
257 | chip->base = -1; | |
258 | chip->ngpio = num_gpios; | |
259 | chip->label = adnp->client->name; | |
58383c78 LW |
260 | chip->parent = &adnp->client->dev; |
261 | chip->of_node = chip->parent->of_node; | |
5e969a40 TR |
262 | chip->owner = THIS_MODULE; |
263 | ||
daa994bf | 264 | err = devm_gpiochip_add_data(&adnp->client->dev, chip, adnp); |
0752e169 LW |
265 | if (err) |
266 | return err; | |
267 | ||
5e969a40 TR |
268 | return 0; |
269 | } | |
270 | ||
271 | static irqreturn_t adnp_irq(int irq, void *data) | |
272 | { | |
273 | struct adnp *adnp = data; | |
274 | unsigned int num_regs, i; | |
275 | ||
276 | num_regs = 1 << adnp->reg_shift; | |
277 | ||
278 | for (i = 0; i < num_regs; i++) { | |
279 | unsigned int base = i << adnp->reg_shift, bit; | |
280 | u8 changed, level, isr, ier; | |
281 | unsigned long pending; | |
282 | int err; | |
283 | ||
284 | mutex_lock(&adnp->i2c_lock); | |
285 | ||
286 | err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level); | |
287 | if (err < 0) { | |
288 | mutex_unlock(&adnp->i2c_lock); | |
289 | continue; | |
290 | } | |
291 | ||
292 | err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); | |
293 | if (err < 0) { | |
294 | mutex_unlock(&adnp->i2c_lock); | |
295 | continue; | |
296 | } | |
297 | ||
298 | err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); | |
299 | if (err < 0) { | |
300 | mutex_unlock(&adnp->i2c_lock); | |
301 | continue; | |
302 | } | |
303 | ||
304 | mutex_unlock(&adnp->i2c_lock); | |
305 | ||
306 | /* determine pins that changed levels */ | |
307 | changed = level ^ adnp->irq_level[i]; | |
308 | ||
309 | /* compute edge-triggered interrupts */ | |
310 | pending = changed & ((adnp->irq_fall[i] & ~level) | | |
311 | (adnp->irq_rise[i] & level)); | |
312 | ||
313 | /* add in level-triggered interrupts */ | |
314 | pending |= (adnp->irq_high[i] & level) | | |
315 | (adnp->irq_low[i] & ~level); | |
316 | ||
317 | /* mask out non-pending and disabled interrupts */ | |
318 | pending &= isr & ier; | |
319 | ||
320 | for_each_set_bit(bit, &pending, 8) { | |
472f95b9 | 321 | unsigned int child_irq; |
f0fbe7bc | 322 | child_irq = irq_find_mapping(adnp->gpio.irq.domain, |
0752e169 | 323 | base + bit); |
472f95b9 | 324 | handle_nested_irq(child_irq); |
5e969a40 TR |
325 | } |
326 | } | |
327 | ||
328 | return IRQ_HANDLED; | |
329 | } | |
330 | ||
0752e169 | 331 | static void adnp_irq_mask(struct irq_data *d) |
5e969a40 | 332 | { |
0752e169 | 333 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 334 | struct adnp *adnp = gpiochip_get_data(gc); |
0752e169 LW |
335 | unsigned int reg = d->hwirq >> adnp->reg_shift; |
336 | unsigned int pos = d->hwirq & 7; | |
5e969a40 TR |
337 | |
338 | adnp->irq_enable[reg] &= ~BIT(pos); | |
339 | } | |
340 | ||
0752e169 | 341 | static void adnp_irq_unmask(struct irq_data *d) |
5e969a40 | 342 | { |
0752e169 | 343 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 344 | struct adnp *adnp = gpiochip_get_data(gc); |
0752e169 LW |
345 | unsigned int reg = d->hwirq >> adnp->reg_shift; |
346 | unsigned int pos = d->hwirq & 7; | |
5e969a40 TR |
347 | |
348 | adnp->irq_enable[reg] |= BIT(pos); | |
349 | } | |
350 | ||
0752e169 | 351 | static int adnp_irq_set_type(struct irq_data *d, unsigned int type) |
5e969a40 | 352 | { |
0752e169 | 353 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 354 | struct adnp *adnp = gpiochip_get_data(gc); |
0752e169 LW |
355 | unsigned int reg = d->hwirq >> adnp->reg_shift; |
356 | unsigned int pos = d->hwirq & 7; | |
5e969a40 TR |
357 | |
358 | if (type & IRQ_TYPE_EDGE_RISING) | |
359 | adnp->irq_rise[reg] |= BIT(pos); | |
360 | else | |
361 | adnp->irq_rise[reg] &= ~BIT(pos); | |
362 | ||
363 | if (type & IRQ_TYPE_EDGE_FALLING) | |
364 | adnp->irq_fall[reg] |= BIT(pos); | |
365 | else | |
366 | adnp->irq_fall[reg] &= ~BIT(pos); | |
367 | ||
368 | if (type & IRQ_TYPE_LEVEL_HIGH) | |
369 | adnp->irq_high[reg] |= BIT(pos); | |
370 | else | |
371 | adnp->irq_high[reg] &= ~BIT(pos); | |
372 | ||
373 | if (type & IRQ_TYPE_LEVEL_LOW) | |
374 | adnp->irq_low[reg] |= BIT(pos); | |
375 | else | |
376 | adnp->irq_low[reg] &= ~BIT(pos); | |
377 | ||
378 | return 0; | |
379 | } | |
380 | ||
0752e169 | 381 | static void adnp_irq_bus_lock(struct irq_data *d) |
5e969a40 | 382 | { |
0752e169 | 383 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 384 | struct adnp *adnp = gpiochip_get_data(gc); |
5e969a40 TR |
385 | |
386 | mutex_lock(&adnp->irq_lock); | |
387 | } | |
388 | ||
0752e169 | 389 | static void adnp_irq_bus_unlock(struct irq_data *d) |
5e969a40 | 390 | { |
0752e169 | 391 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
1e69c4fe | 392 | struct adnp *adnp = gpiochip_get_data(gc); |
5e969a40 TR |
393 | unsigned int num_regs = 1 << adnp->reg_shift, i; |
394 | ||
395 | mutex_lock(&adnp->i2c_lock); | |
396 | ||
397 | for (i = 0; i < num_regs; i++) | |
398 | adnp_write(adnp, GPIO_IER(adnp) + i, adnp->irq_enable[i]); | |
399 | ||
400 | mutex_unlock(&adnp->i2c_lock); | |
401 | mutex_unlock(&adnp->irq_lock); | |
402 | } | |
403 | ||
404 | static struct irq_chip adnp_irq_chip = { | |
405 | .name = "gpio-adnp", | |
406 | .irq_mask = adnp_irq_mask, | |
407 | .irq_unmask = adnp_irq_unmask, | |
408 | .irq_set_type = adnp_irq_set_type, | |
409 | .irq_bus_lock = adnp_irq_bus_lock, | |
410 | .irq_bus_sync_unlock = adnp_irq_bus_unlock, | |
5e969a40 TR |
411 | }; |
412 | ||
413 | static int adnp_irq_setup(struct adnp *adnp) | |
414 | { | |
415 | unsigned int num_regs = 1 << adnp->reg_shift, i; | |
416 | struct gpio_chip *chip = &adnp->gpio; | |
417 | int err; | |
418 | ||
419 | mutex_init(&adnp->irq_lock); | |
420 | ||
421 | /* | |
422 | * Allocate memory to keep track of the current level and trigger | |
423 | * modes of the interrupts. To avoid multiple allocations, a single | |
424 | * large buffer is allocated and pointers are setup to point at the | |
425 | * corresponding offsets. For consistency, the layout of the buffer | |
426 | * is chosen to match the register layout of the hardware in that | |
427 | * each segment contains the corresponding bits for all interrupts. | |
428 | */ | |
a86854d0 | 429 | adnp->irq_enable = devm_kcalloc(chip->parent, num_regs, 6, |
58383c78 | 430 | GFP_KERNEL); |
5e969a40 TR |
431 | if (!adnp->irq_enable) |
432 | return -ENOMEM; | |
433 | ||
434 | adnp->irq_level = adnp->irq_enable + (num_regs * 1); | |
435 | adnp->irq_rise = adnp->irq_enable + (num_regs * 2); | |
436 | adnp->irq_fall = adnp->irq_enable + (num_regs * 3); | |
437 | adnp->irq_high = adnp->irq_enable + (num_regs * 4); | |
438 | adnp->irq_low = adnp->irq_enable + (num_regs * 5); | |
439 | ||
440 | for (i = 0; i < num_regs; i++) { | |
441 | /* | |
442 | * Read the initial level of all pins to allow the emulation | |
443 | * of edge triggered interrupts. | |
444 | */ | |
445 | err = adnp_read(adnp, GPIO_PLR(adnp) + i, &adnp->irq_level[i]); | |
446 | if (err < 0) | |
447 | return err; | |
448 | ||
449 | /* disable all interrupts */ | |
450 | err = adnp_write(adnp, GPIO_IER(adnp) + i, 0); | |
451 | if (err < 0) | |
452 | return err; | |
453 | ||
454 | adnp->irq_enable[i] = 0x00; | |
455 | } | |
456 | ||
58383c78 | 457 | err = devm_request_threaded_irq(chip->parent, adnp->client->irq, |
0752e169 LW |
458 | NULL, adnp_irq, |
459 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | |
58383c78 | 460 | dev_name(chip->parent), adnp); |
5e969a40 | 461 | if (err != 0) { |
58383c78 | 462 | dev_err(chip->parent, "can't request IRQ#%d: %d\n", |
5e969a40 | 463 | adnp->client->irq, err); |
5b21533b | 464 | return err; |
5e969a40 TR |
465 | } |
466 | ||
d245b3f9 LW |
467 | err = gpiochip_irqchip_add_nested(chip, |
468 | &adnp_irq_chip, | |
469 | 0, | |
470 | handle_simple_irq, | |
471 | IRQ_TYPE_NONE); | |
0752e169 | 472 | if (err) { |
58383c78 | 473 | dev_err(chip->parent, |
0752e169 LW |
474 | "could not connect irqchip to gpiochip\n"); |
475 | return err; | |
5e969a40 TR |
476 | } |
477 | ||
35ca3f61 LW |
478 | gpiochip_set_nested_irqchip(chip, &adnp_irq_chip, adnp->client->irq); |
479 | ||
0752e169 | 480 | return 0; |
5e969a40 TR |
481 | } |
482 | ||
3836309d | 483 | static int adnp_i2c_probe(struct i2c_client *client, |
5e969a40 TR |
484 | const struct i2c_device_id *id) |
485 | { | |
486 | struct device_node *np = client->dev.of_node; | |
487 | struct adnp *adnp; | |
488 | u32 num_gpios; | |
489 | int err; | |
490 | ||
491 | err = of_property_read_u32(np, "nr-gpios", &num_gpios); | |
492 | if (err < 0) | |
493 | return err; | |
494 | ||
495 | client->irq = irq_of_parse_and_map(np, 0); | |
496 | if (!client->irq) | |
497 | return -EPROBE_DEFER; | |
498 | ||
499 | adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL); | |
500 | if (!adnp) | |
501 | return -ENOMEM; | |
502 | ||
503 | mutex_init(&adnp->i2c_lock); | |
504 | adnp->client = client; | |
505 | ||
506 | err = adnp_gpio_setup(adnp, num_gpios); | |
0752e169 | 507 | if (err) |
5e969a40 TR |
508 | return err; |
509 | ||
510 | if (of_find_property(np, "interrupt-controller", NULL)) { | |
511 | err = adnp_irq_setup(adnp); | |
0752e169 LW |
512 | if (err) |
513 | return err; | |
5e969a40 TR |
514 | } |
515 | ||
5e969a40 | 516 | i2c_set_clientdata(client, adnp); |
5e969a40 | 517 | |
0752e169 | 518 | return 0; |
5e969a40 TR |
519 | } |
520 | ||
b5ba78de | 521 | static const struct i2c_device_id adnp_i2c_id[] = { |
5e969a40 TR |
522 | { "gpio-adnp" }, |
523 | { }, | |
524 | }; | |
525 | MODULE_DEVICE_TABLE(i2c, adnp_i2c_id); | |
526 | ||
b5ba78de | 527 | static const struct of_device_id adnp_of_match[] = { |
5e969a40 TR |
528 | { .compatible = "ad,gpio-adnp", }, |
529 | { }, | |
530 | }; | |
531 | MODULE_DEVICE_TABLE(of, adnp_of_match); | |
532 | ||
533 | static struct i2c_driver adnp_i2c_driver = { | |
534 | .driver = { | |
535 | .name = "gpio-adnp", | |
83924fb3 | 536 | .of_match_table = adnp_of_match, |
5e969a40 TR |
537 | }, |
538 | .probe = adnp_i2c_probe, | |
5e969a40 TR |
539 | .id_table = adnp_i2c_id, |
540 | }; | |
541 | module_i2c_driver(adnp_i2c_driver); | |
542 | ||
543 | MODULE_DESCRIPTION("Avionic Design N-bit GPIO expander"); | |
544 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | |
545 | MODULE_LICENSE("GPL"); |