Commit | Line | Data |
---|---|---|
75a6faf6 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
02c5ba1e LD |
2 | /* |
3 | * MAXIM MAX77620 GPIO driver | |
4 | * | |
5 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | |
02c5ba1e LD |
6 | */ |
7 | ||
8 | #include <linux/gpio/driver.h> | |
9 | #include <linux/interrupt.h> | |
10 | #include <linux/mfd/max77620.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/platform_device.h> | |
13 | #include <linux/regmap.h> | |
14 | ||
15 | #define GPIO_REG_ADDR(offset) (MAX77620_REG_GPIO0 + offset) | |
16 | ||
17 | struct max77620_gpio { | |
18 | struct gpio_chip gpio_chip; | |
19 | struct regmap *rmap; | |
20 | struct device *dev; | |
ab3dd9cc | 21 | struct mutex buslock; /* irq_bus_lock */ |
4ee82256 DO |
22 | unsigned int irq_type[MAX77620_GPIO_NR]; |
23 | bool irq_enabled[MAX77620_GPIO_NR]; | |
02c5ba1e LD |
24 | }; |
25 | ||
ab3dd9cc TA |
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; | |
32 | ||
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 | ||
4ee82256 | 41 | for_each_set_bit(offset, &pending, MAX77620_GPIO_NR) { |
ab3dd9cc TA |
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 | } | |
02c5ba1e | 58 | |
ab3dd9cc TA |
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, | |
02c5ba1e LD |
130 | }; |
131 | ||
132 | static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset) | |
133 | { | |
134 | struct max77620_gpio *mgpio = gpiochip_get_data(gc); | |
135 | int ret; | |
136 | ||
137 | ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), | |
138 | MAX77620_CNFG_GPIO_DIR_MASK, | |
139 | MAX77620_CNFG_GPIO_DIR_INPUT); | |
140 | if (ret < 0) | |
141 | dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret); | |
142 | ||
143 | return ret; | |
144 | } | |
145 | ||
146 | static int max77620_gpio_get(struct gpio_chip *gc, unsigned int offset) | |
147 | { | |
148 | struct max77620_gpio *mgpio = gpiochip_get_data(gc); | |
149 | unsigned int val; | |
150 | int ret; | |
151 | ||
152 | ret = regmap_read(mgpio->rmap, GPIO_REG_ADDR(offset), &val); | |
153 | if (ret < 0) { | |
154 | dev_err(mgpio->dev, "CNFG_GPIOx read failed: %d\n", ret); | |
155 | return ret; | |
156 | } | |
157 | ||
1941b441 VRT |
158 | if (val & MAX77620_CNFG_GPIO_DIR_MASK) |
159 | return !!(val & MAX77620_CNFG_GPIO_INPUT_VAL_MASK); | |
160 | else | |
161 | return !!(val & MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK); | |
02c5ba1e LD |
162 | } |
163 | ||
164 | static int max77620_gpio_dir_output(struct gpio_chip *gc, unsigned int offset, | |
165 | int value) | |
166 | { | |
167 | struct max77620_gpio *mgpio = gpiochip_get_data(gc); | |
168 | u8 val; | |
169 | int ret; | |
170 | ||
171 | val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH : | |
172 | MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW; | |
173 | ||
174 | ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), | |
175 | MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val); | |
176 | if (ret < 0) { | |
177 | dev_err(mgpio->dev, "CNFG_GPIOx val update failed: %d\n", ret); | |
178 | return ret; | |
179 | } | |
180 | ||
181 | ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), | |
182 | MAX77620_CNFG_GPIO_DIR_MASK, | |
183 | MAX77620_CNFG_GPIO_DIR_OUTPUT); | |
184 | if (ret < 0) | |
185 | dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret); | |
186 | ||
187 | return ret; | |
188 | } | |
189 | ||
2956b5d9 | 190 | static int max77620_gpio_set_debounce(struct max77620_gpio *mgpio, |
02c5ba1e LD |
191 | unsigned int offset, |
192 | unsigned int debounce) | |
193 | { | |
02c5ba1e LD |
194 | u8 val; |
195 | int ret; | |
196 | ||
197 | switch (debounce) { | |
198 | case 0: | |
199 | val = MAX77620_CNFG_GPIO_DBNC_None; | |
200 | break; | |
b0391479 | 201 | case 1 ... 8000: |
02c5ba1e LD |
202 | val = MAX77620_CNFG_GPIO_DBNC_8ms; |
203 | break; | |
b0391479 | 204 | case 8001 ... 16000: |
02c5ba1e LD |
205 | val = MAX77620_CNFG_GPIO_DBNC_16ms; |
206 | break; | |
b0391479 | 207 | case 16001 ... 32000: |
02c5ba1e LD |
208 | val = MAX77620_CNFG_GPIO_DBNC_32ms; |
209 | break; | |
210 | default: | |
211 | dev_err(mgpio->dev, "Illegal value %u\n", debounce); | |
212 | return -EINVAL; | |
213 | } | |
214 | ||
215 | ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), | |
216 | MAX77620_CNFG_GPIO_DBNC_MASK, val); | |
217 | if (ret < 0) | |
218 | dev_err(mgpio->dev, "CNFG_GPIOx_DBNC update failed: %d\n", ret); | |
219 | ||
220 | return ret; | |
221 | } | |
222 | ||
223 | static void max77620_gpio_set(struct gpio_chip *gc, unsigned int offset, | |
224 | int value) | |
225 | { | |
226 | struct max77620_gpio *mgpio = gpiochip_get_data(gc); | |
227 | u8 val; | |
228 | int ret; | |
229 | ||
230 | val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH : | |
231 | MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW; | |
232 | ||
233 | ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), | |
234 | MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val); | |
235 | if (ret < 0) | |
236 | dev_err(mgpio->dev, "CNFG_GPIO_OUT update failed: %d\n", ret); | |
237 | } | |
238 | ||
2956b5d9 MW |
239 | static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset, |
240 | unsigned long config) | |
23087a05 LD |
241 | { |
242 | struct max77620_gpio *mgpio = gpiochip_get_data(gc); | |
243 | ||
2956b5d9 MW |
244 | switch (pinconf_to_config_param(config)) { |
245 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: | |
23087a05 LD |
246 | return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), |
247 | MAX77620_CNFG_GPIO_DRV_MASK, | |
248 | MAX77620_CNFG_GPIO_DRV_OPENDRAIN); | |
2956b5d9 | 249 | case PIN_CONFIG_DRIVE_PUSH_PULL: |
23087a05 LD |
250 | return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), |
251 | MAX77620_CNFG_GPIO_DRV_MASK, | |
252 | MAX77620_CNFG_GPIO_DRV_PUSHPULL); | |
2956b5d9 MW |
253 | case PIN_CONFIG_INPUT_DEBOUNCE: |
254 | return max77620_gpio_set_debounce(mgpio, offset, | |
255 | pinconf_to_config_argument(config)); | |
23087a05 LD |
256 | default: |
257 | break; | |
258 | } | |
259 | ||
260 | return -ENOTSUPP; | |
261 | } | |
262 | ||
e6827bc3 DO |
263 | static int max77620_gpio_irq_init_hw(struct gpio_chip *gc) |
264 | { | |
265 | struct max77620_gpio *gpio = gpiochip_get_data(gc); | |
266 | unsigned int i; | |
267 | int err; | |
268 | ||
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; | |
285 | } | |
286 | ||
02c5ba1e LD |
287 | static int max77620_gpio_probe(struct platform_device *pdev) |
288 | { | |
289 | struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent); | |
290 | struct max77620_gpio *mgpio; | |
80606cb2 | 291 | struct gpio_irq_chip *girq; |
c607e5e2 | 292 | unsigned int gpio_irq; |
02c5ba1e LD |
293 | int ret; |
294 | ||
c607e5e2 DO |
295 | ret = platform_get_irq(pdev, 0); |
296 | if (ret < 0) | |
297 | return ret; | |
298 | ||
299 | gpio_irq = ret; | |
02c5ba1e LD |
300 | |
301 | mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL); | |
302 | if (!mgpio) | |
303 | return -ENOMEM; | |
304 | ||
15d9e7e8 | 305 | mutex_init(&mgpio->buslock); |
02c5ba1e LD |
306 | mgpio->rmap = chip->rmap; |
307 | mgpio->dev = &pdev->dev; | |
02c5ba1e LD |
308 | |
309 | mgpio->gpio_chip.label = pdev->name; | |
78934d88 | 310 | mgpio->gpio_chip.parent = pdev->dev.parent; |
02c5ba1e LD |
311 | mgpio->gpio_chip.direction_input = max77620_gpio_dir_input; |
312 | mgpio->gpio_chip.get = max77620_gpio_get; | |
313 | mgpio->gpio_chip.direction_output = max77620_gpio_dir_output; | |
02c5ba1e | 314 | mgpio->gpio_chip.set = max77620_gpio_set; |
2956b5d9 | 315 | mgpio->gpio_chip.set_config = max77620_gpio_set_config; |
02c5ba1e LD |
316 | mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR; |
317 | mgpio->gpio_chip.can_sleep = 1; | |
318 | mgpio->gpio_chip.base = -1; | |
02c5ba1e | 319 | |
80606cb2 LW |
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; | |
15d9e7e8 | 330 | |
02c5ba1e LD |
331 | platform_set_drvdata(pdev, mgpio); |
332 | ||
333 | ret = devm_gpiochip_add_data(&pdev->dev, &mgpio->gpio_chip, mgpio); | |
334 | if (ret < 0) { | |
335 | dev_err(&pdev->dev, "gpio_init: Failed to add max77620_gpio\n"); | |
336 | return ret; | |
337 | } | |
338 | ||
2a5e6f7e DO |
339 | ret = devm_request_threaded_irq(&pdev->dev, gpio_irq, NULL, |
340 | max77620_gpio_irqhandler, IRQF_ONESHOT, | |
341 | "max77620-gpio", mgpio); | |
02c5ba1e | 342 | if (ret < 0) { |
ab3dd9cc | 343 | dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret); |
02c5ba1e LD |
344 | return ret; |
345 | } | |
346 | ||
347 | return 0; | |
348 | } | |
349 | ||
350 | static const struct platform_device_id max77620_gpio_devtype[] = { | |
351 | { .name = "max77620-gpio", }, | |
3107d572 | 352 | { .name = "max20024-gpio", }, |
02c5ba1e LD |
353 | {}, |
354 | }; | |
355 | MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype); | |
356 | ||
357 | static struct platform_driver max77620_gpio_driver = { | |
358 | .driver.name = "max77620-gpio", | |
359 | .probe = max77620_gpio_probe, | |
360 | .id_table = max77620_gpio_devtype, | |
361 | }; | |
362 | ||
363 | module_platform_driver(max77620_gpio_driver); | |
364 | ||
365 | MODULE_DESCRIPTION("GPIO interface for MAX77620 and MAX20024 PMIC"); | |
366 | MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); | |
367 | MODULE_AUTHOR("Chaitanya Bandi <bandik@nvidia.com>"); | |
368 | MODULE_ALIAS("platform:max77620-gpio"); | |
369 | MODULE_LICENSE("GPL v2"); |