.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * MAXIM MAX77620 GPIO driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms and conditions of the GNU General Public License, |
---|
8 | | - * version 2, as published by the Free Software Foundation. |
---|
9 | 6 | */ |
---|
10 | 7 | |
---|
11 | 8 | #include <linux/gpio/driver.h> |
---|
.. | .. |
---|
21 | 18 | struct gpio_chip gpio_chip; |
---|
22 | 19 | struct regmap *rmap; |
---|
23 | 20 | struct device *dev; |
---|
| 21 | + struct mutex buslock; /* irq_bus_lock */ |
---|
| 22 | + unsigned int irq_type[MAX77620_GPIO_NR]; |
---|
| 23 | + bool irq_enabled[MAX77620_GPIO_NR]; |
---|
24 | 24 | }; |
---|
25 | 25 | |
---|
26 | | -static const struct regmap_irq max77620_gpio_irqs[] = { |
---|
27 | | - [0] = { |
---|
28 | | - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE0, |
---|
29 | | - .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, |
---|
30 | | - .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, |
---|
31 | | - .reg_offset = 0, |
---|
32 | | - .type_reg_offset = 0, |
---|
33 | | - }, |
---|
34 | | - [1] = { |
---|
35 | | - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE1, |
---|
36 | | - .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, |
---|
37 | | - .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, |
---|
38 | | - .reg_offset = 0, |
---|
39 | | - .type_reg_offset = 1, |
---|
40 | | - }, |
---|
41 | | - [2] = { |
---|
42 | | - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE2, |
---|
43 | | - .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, |
---|
44 | | - .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, |
---|
45 | | - .reg_offset = 0, |
---|
46 | | - .type_reg_offset = 2, |
---|
47 | | - }, |
---|
48 | | - [3] = { |
---|
49 | | - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE3, |
---|
50 | | - .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, |
---|
51 | | - .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, |
---|
52 | | - .reg_offset = 0, |
---|
53 | | - .type_reg_offset = 3, |
---|
54 | | - }, |
---|
55 | | - [4] = { |
---|
56 | | - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE4, |
---|
57 | | - .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, |
---|
58 | | - .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, |
---|
59 | | - .reg_offset = 0, |
---|
60 | | - .type_reg_offset = 4, |
---|
61 | | - }, |
---|
62 | | - [5] = { |
---|
63 | | - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE5, |
---|
64 | | - .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, |
---|
65 | | - .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, |
---|
66 | | - .reg_offset = 0, |
---|
67 | | - .type_reg_offset = 5, |
---|
68 | | - }, |
---|
69 | | - [6] = { |
---|
70 | | - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE6, |
---|
71 | | - .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, |
---|
72 | | - .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, |
---|
73 | | - .reg_offset = 0, |
---|
74 | | - .type_reg_offset = 6, |
---|
75 | | - }, |
---|
76 | | - [7] = { |
---|
77 | | - .mask = MAX77620_IRQ_LVL2_GPIO_EDGE7, |
---|
78 | | - .type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, |
---|
79 | | - .type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, |
---|
80 | | - .reg_offset = 0, |
---|
81 | | - .type_reg_offset = 7, |
---|
82 | | - }, |
---|
83 | | -}; |
---|
| 26 | +static irqreturn_t max77620_gpio_irqhandler(int irq, void *data) |
---|
| 27 | +{ |
---|
| 28 | + struct max77620_gpio *gpio = data; |
---|
| 29 | + unsigned int value, offset; |
---|
| 30 | + unsigned long pending; |
---|
| 31 | + int err; |
---|
84 | 32 | |
---|
85 | | -static const struct regmap_irq_chip max77620_gpio_irq_chip = { |
---|
86 | | - .name = "max77620-gpio", |
---|
87 | | - .irqs = max77620_gpio_irqs, |
---|
88 | | - .num_irqs = ARRAY_SIZE(max77620_gpio_irqs), |
---|
89 | | - .num_regs = 1, |
---|
90 | | - .num_type_reg = 8, |
---|
91 | | - .irq_reg_stride = 1, |
---|
92 | | - .type_reg_stride = 1, |
---|
93 | | - .status_base = MAX77620_REG_IRQ_LVL2_GPIO, |
---|
94 | | - .type_base = MAX77620_REG_GPIO0, |
---|
| 33 | + err = regmap_read(gpio->rmap, MAX77620_REG_IRQ_LVL2_GPIO, &value); |
---|
| 34 | + if (err < 0) { |
---|
| 35 | + dev_err(gpio->dev, "REG_IRQ_LVL2_GPIO read failed: %d\n", err); |
---|
| 36 | + return IRQ_NONE; |
---|
| 37 | + } |
---|
| 38 | + |
---|
| 39 | + pending = value; |
---|
| 40 | + |
---|
| 41 | + for_each_set_bit(offset, &pending, MAX77620_GPIO_NR) { |
---|
| 42 | + unsigned int virq; |
---|
| 43 | + |
---|
| 44 | + virq = irq_find_mapping(gpio->gpio_chip.irq.domain, offset); |
---|
| 45 | + handle_nested_irq(virq); |
---|
| 46 | + } |
---|
| 47 | + |
---|
| 48 | + return IRQ_HANDLED; |
---|
| 49 | +} |
---|
| 50 | + |
---|
| 51 | +static void max77620_gpio_irq_mask(struct irq_data *data) |
---|
| 52 | +{ |
---|
| 53 | + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); |
---|
| 54 | + struct max77620_gpio *gpio = gpiochip_get_data(chip); |
---|
| 55 | + |
---|
| 56 | + gpio->irq_enabled[data->hwirq] = false; |
---|
| 57 | +} |
---|
| 58 | + |
---|
| 59 | +static void max77620_gpio_irq_unmask(struct irq_data *data) |
---|
| 60 | +{ |
---|
| 61 | + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); |
---|
| 62 | + struct max77620_gpio *gpio = gpiochip_get_data(chip); |
---|
| 63 | + |
---|
| 64 | + gpio->irq_enabled[data->hwirq] = true; |
---|
| 65 | +} |
---|
| 66 | + |
---|
| 67 | +static int max77620_gpio_set_irq_type(struct irq_data *data, unsigned int type) |
---|
| 68 | +{ |
---|
| 69 | + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); |
---|
| 70 | + struct max77620_gpio *gpio = gpiochip_get_data(chip); |
---|
| 71 | + unsigned int irq_type; |
---|
| 72 | + |
---|
| 73 | + switch (type) { |
---|
| 74 | + case IRQ_TYPE_EDGE_RISING: |
---|
| 75 | + irq_type = MAX77620_CNFG_GPIO_INT_RISING; |
---|
| 76 | + break; |
---|
| 77 | + |
---|
| 78 | + case IRQ_TYPE_EDGE_FALLING: |
---|
| 79 | + irq_type = MAX77620_CNFG_GPIO_INT_FALLING; |
---|
| 80 | + break; |
---|
| 81 | + |
---|
| 82 | + case IRQ_TYPE_EDGE_BOTH: |
---|
| 83 | + irq_type = MAX77620_CNFG_GPIO_INT_RISING | |
---|
| 84 | + MAX77620_CNFG_GPIO_INT_FALLING; |
---|
| 85 | + break; |
---|
| 86 | + |
---|
| 87 | + default: |
---|
| 88 | + return -EINVAL; |
---|
| 89 | + } |
---|
| 90 | + |
---|
| 91 | + gpio->irq_type[data->hwirq] = irq_type; |
---|
| 92 | + |
---|
| 93 | + return 0; |
---|
| 94 | +} |
---|
| 95 | + |
---|
| 96 | +static void max77620_gpio_bus_lock(struct irq_data *data) |
---|
| 97 | +{ |
---|
| 98 | + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); |
---|
| 99 | + struct max77620_gpio *gpio = gpiochip_get_data(chip); |
---|
| 100 | + |
---|
| 101 | + mutex_lock(&gpio->buslock); |
---|
| 102 | +} |
---|
| 103 | + |
---|
| 104 | +static void max77620_gpio_bus_sync_unlock(struct irq_data *data) |
---|
| 105 | +{ |
---|
| 106 | + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); |
---|
| 107 | + struct max77620_gpio *gpio = gpiochip_get_data(chip); |
---|
| 108 | + unsigned int value, offset = data->hwirq; |
---|
| 109 | + int err; |
---|
| 110 | + |
---|
| 111 | + value = gpio->irq_enabled[offset] ? gpio->irq_type[offset] : 0; |
---|
| 112 | + |
---|
| 113 | + err = regmap_update_bits(gpio->rmap, GPIO_REG_ADDR(offset), |
---|
| 114 | + MAX77620_CNFG_GPIO_INT_MASK, value); |
---|
| 115 | + if (err < 0) |
---|
| 116 | + dev_err(chip->parent, "failed to update interrupt mask: %d\n", |
---|
| 117 | + err); |
---|
| 118 | + |
---|
| 119 | + mutex_unlock(&gpio->buslock); |
---|
| 120 | +} |
---|
| 121 | + |
---|
| 122 | +static struct irq_chip max77620_gpio_irqchip = { |
---|
| 123 | + .name = "max77620-gpio", |
---|
| 124 | + .irq_mask = max77620_gpio_irq_mask, |
---|
| 125 | + .irq_unmask = max77620_gpio_irq_unmask, |
---|
| 126 | + .irq_set_type = max77620_gpio_set_irq_type, |
---|
| 127 | + .irq_bus_lock = max77620_gpio_bus_lock, |
---|
| 128 | + .irq_bus_sync_unlock = max77620_gpio_bus_sync_unlock, |
---|
| 129 | + .flags = IRQCHIP_MASK_ON_SUSPEND, |
---|
95 | 130 | }; |
---|
96 | 131 | |
---|
97 | 132 | static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset) |
---|
.. | .. |
---|
225 | 260 | return -ENOTSUPP; |
---|
226 | 261 | } |
---|
227 | 262 | |
---|
228 | | -static int max77620_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) |
---|
| 263 | +static int max77620_gpio_irq_init_hw(struct gpio_chip *gc) |
---|
229 | 264 | { |
---|
230 | | - struct max77620_gpio *mgpio = gpiochip_get_data(gc); |
---|
231 | | - struct max77620_chip *chip = dev_get_drvdata(mgpio->dev->parent); |
---|
| 265 | + struct max77620_gpio *gpio = gpiochip_get_data(gc); |
---|
| 266 | + unsigned int i; |
---|
| 267 | + int err; |
---|
232 | 268 | |
---|
233 | | - return regmap_irq_get_virq(chip->gpio_irq_data, offset); |
---|
| 269 | + /* |
---|
| 270 | + * GPIO interrupts may be left ON after bootloader, hence let's |
---|
| 271 | + * pre-initialize hardware to the expected state by disabling all |
---|
| 272 | + * the interrupts. |
---|
| 273 | + */ |
---|
| 274 | + for (i = 0; i < MAX77620_GPIO_NR; i++) { |
---|
| 275 | + err = regmap_update_bits(gpio->rmap, GPIO_REG_ADDR(i), |
---|
| 276 | + MAX77620_CNFG_GPIO_INT_MASK, 0); |
---|
| 277 | + if (err < 0) { |
---|
| 278 | + dev_err(gpio->dev, |
---|
| 279 | + "failed to disable interrupt: %d\n", err); |
---|
| 280 | + return err; |
---|
| 281 | + } |
---|
| 282 | + } |
---|
| 283 | + |
---|
| 284 | + return 0; |
---|
234 | 285 | } |
---|
235 | 286 | |
---|
236 | 287 | static int max77620_gpio_probe(struct platform_device *pdev) |
---|
237 | 288 | { |
---|
238 | 289 | struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent); |
---|
239 | 290 | struct max77620_gpio *mgpio; |
---|
240 | | - int gpio_irq; |
---|
| 291 | + struct gpio_irq_chip *girq; |
---|
| 292 | + unsigned int gpio_irq; |
---|
241 | 293 | int ret; |
---|
242 | 294 | |
---|
243 | | - gpio_irq = platform_get_irq(pdev, 0); |
---|
244 | | - if (gpio_irq <= 0) { |
---|
245 | | - dev_err(&pdev->dev, "GPIO irq not available %d\n", gpio_irq); |
---|
246 | | - return -ENODEV; |
---|
247 | | - } |
---|
| 295 | + ret = platform_get_irq(pdev, 0); |
---|
| 296 | + if (ret < 0) |
---|
| 297 | + return ret; |
---|
| 298 | + |
---|
| 299 | + gpio_irq = ret; |
---|
248 | 300 | |
---|
249 | 301 | mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL); |
---|
250 | 302 | if (!mgpio) |
---|
251 | 303 | return -ENOMEM; |
---|
252 | 304 | |
---|
| 305 | + mutex_init(&mgpio->buslock); |
---|
253 | 306 | mgpio->rmap = chip->rmap; |
---|
254 | 307 | mgpio->dev = &pdev->dev; |
---|
255 | 308 | |
---|
256 | 309 | mgpio->gpio_chip.label = pdev->name; |
---|
257 | | - mgpio->gpio_chip.parent = &pdev->dev; |
---|
| 310 | + mgpio->gpio_chip.parent = pdev->dev.parent; |
---|
258 | 311 | mgpio->gpio_chip.direction_input = max77620_gpio_dir_input; |
---|
259 | 312 | mgpio->gpio_chip.get = max77620_gpio_get; |
---|
260 | 313 | mgpio->gpio_chip.direction_output = max77620_gpio_dir_output; |
---|
261 | 314 | mgpio->gpio_chip.set = max77620_gpio_set; |
---|
262 | 315 | mgpio->gpio_chip.set_config = max77620_gpio_set_config; |
---|
263 | | - mgpio->gpio_chip.to_irq = max77620_gpio_to_irq; |
---|
264 | 316 | mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR; |
---|
265 | 317 | mgpio->gpio_chip.can_sleep = 1; |
---|
266 | 318 | mgpio->gpio_chip.base = -1; |
---|
267 | | -#ifdef CONFIG_OF_GPIO |
---|
268 | | - mgpio->gpio_chip.of_node = pdev->dev.parent->of_node; |
---|
269 | | -#endif |
---|
| 319 | + |
---|
| 320 | + girq = &mgpio->gpio_chip.irq; |
---|
| 321 | + girq->chip = &max77620_gpio_irqchip; |
---|
| 322 | + /* This will let us handle the parent IRQ in the driver */ |
---|
| 323 | + girq->parent_handler = NULL; |
---|
| 324 | + girq->num_parents = 0; |
---|
| 325 | + girq->parents = NULL; |
---|
| 326 | + girq->default_type = IRQ_TYPE_NONE; |
---|
| 327 | + girq->handler = handle_edge_irq; |
---|
| 328 | + girq->init_hw = max77620_gpio_irq_init_hw, |
---|
| 329 | + girq->threaded = true; |
---|
270 | 330 | |
---|
271 | 331 | platform_set_drvdata(pdev, mgpio); |
---|
272 | 332 | |
---|
.. | .. |
---|
276 | 336 | return ret; |
---|
277 | 337 | } |
---|
278 | 338 | |
---|
279 | | - ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq, |
---|
280 | | - IRQF_ONESHOT, -1, |
---|
281 | | - &max77620_gpio_irq_chip, |
---|
282 | | - &chip->gpio_irq_data); |
---|
| 339 | + ret = devm_request_threaded_irq(&pdev->dev, gpio_irq, NULL, |
---|
| 340 | + max77620_gpio_irqhandler, IRQF_ONESHOT, |
---|
| 341 | + "max77620-gpio", mgpio); |
---|
283 | 342 | if (ret < 0) { |
---|
284 | | - dev_err(&pdev->dev, "Failed to add gpio irq_chip %d\n", ret); |
---|
| 343 | + dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret); |
---|
285 | 344 | return ret; |
---|
286 | 345 | } |
---|
287 | 346 | |
---|