1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de> |
4 | // Copyright 2008 Juergen Beisert, kernel@pengutronix.de |
5 | // |
6 | // Based on code from Freescale Semiconductor, |
7 | // Authors: Daniel Mack, Juergen Beisert. |
8 | // Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. |
9 | |
10 | #include <linux/clk.h> |
11 | #include <linux/err.h> |
12 | #include <linux/init.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/io.h> |
15 | #include <linux/irq.h> |
16 | #include <linux/irqdomain.h> |
17 | #include <linux/irqchip/chained_irq.h> |
18 | #include <linux/module.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/pm_runtime.h> |
21 | #include <linux/slab.h> |
22 | #include <linux/spinlock.h> |
23 | #include <linux/syscore_ops.h> |
24 | #include <linux/gpio/driver.h> |
25 | #include <linux/of.h> |
26 | #include <linux/bug.h> |
27 | |
28 | #define IMX_SCU_WAKEUP_OFF 0 |
29 | #define IMX_SCU_WAKEUP_LOW_LVL 4 |
30 | #define IMX_SCU_WAKEUP_FALL_EDGE 5 |
31 | #define IMX_SCU_WAKEUP_RISE_EDGE 6 |
32 | #define IMX_SCU_WAKEUP_HIGH_LVL 7 |
33 | |
34 | /* device type dependent stuff */ |
35 | struct mxc_gpio_hwdata { |
36 | unsigned dr_reg; |
37 | unsigned gdir_reg; |
38 | unsigned psr_reg; |
39 | unsigned icr1_reg; |
40 | unsigned icr2_reg; |
41 | unsigned imr_reg; |
42 | unsigned isr_reg; |
43 | int edge_sel_reg; |
44 | unsigned low_level; |
45 | unsigned high_level; |
46 | unsigned rise_edge; |
47 | unsigned fall_edge; |
48 | }; |
49 | |
50 | struct mxc_gpio_reg_saved { |
51 | u32 icr1; |
52 | u32 icr2; |
53 | u32 imr; |
54 | u32 gdir; |
55 | u32 edge_sel; |
56 | u32 dr; |
57 | }; |
58 | |
59 | struct mxc_gpio_port { |
60 | struct list_head node; |
61 | void __iomem *base; |
62 | struct clk *clk; |
63 | int irq; |
64 | int irq_high; |
65 | void (*mx_irq_handler)(struct irq_desc *desc); |
66 | struct irq_domain *domain; |
67 | struct gpio_chip gc; |
68 | struct device *dev; |
69 | u32 both_edges; |
70 | struct mxc_gpio_reg_saved gpio_saved_reg; |
71 | bool power_off; |
72 | u32 wakeup_pads; |
73 | bool is_pad_wakeup; |
74 | u32 pad_type[32]; |
75 | const struct mxc_gpio_hwdata *hwdata; |
76 | }; |
77 | |
78 | static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = { |
79 | .dr_reg = 0x1c, |
80 | .gdir_reg = 0x00, |
81 | .psr_reg = 0x24, |
82 | .icr1_reg = 0x28, |
83 | .icr2_reg = 0x2c, |
84 | .imr_reg = 0x30, |
85 | .isr_reg = 0x34, |
86 | .edge_sel_reg = -EINVAL, |
87 | .low_level = 0x03, |
88 | .high_level = 0x02, |
89 | .rise_edge = 0x00, |
90 | .fall_edge = 0x01, |
91 | }; |
92 | |
93 | static struct mxc_gpio_hwdata imx31_gpio_hwdata = { |
94 | .dr_reg = 0x00, |
95 | .gdir_reg = 0x04, |
96 | .psr_reg = 0x08, |
97 | .icr1_reg = 0x0c, |
98 | .icr2_reg = 0x10, |
99 | .imr_reg = 0x14, |
100 | .isr_reg = 0x18, |
101 | .edge_sel_reg = -EINVAL, |
102 | .low_level = 0x00, |
103 | .high_level = 0x01, |
104 | .rise_edge = 0x02, |
105 | .fall_edge = 0x03, |
106 | }; |
107 | |
108 | static struct mxc_gpio_hwdata imx35_gpio_hwdata = { |
109 | .dr_reg = 0x00, |
110 | .gdir_reg = 0x04, |
111 | .psr_reg = 0x08, |
112 | .icr1_reg = 0x0c, |
113 | .icr2_reg = 0x10, |
114 | .imr_reg = 0x14, |
115 | .isr_reg = 0x18, |
116 | .edge_sel_reg = 0x1c, |
117 | .low_level = 0x00, |
118 | .high_level = 0x01, |
119 | .rise_edge = 0x02, |
120 | .fall_edge = 0x03, |
121 | }; |
122 | |
123 | #define GPIO_DR (port->hwdata->dr_reg) |
124 | #define GPIO_GDIR (port->hwdata->gdir_reg) |
125 | #define GPIO_PSR (port->hwdata->psr_reg) |
126 | #define GPIO_ICR1 (port->hwdata->icr1_reg) |
127 | #define GPIO_ICR2 (port->hwdata->icr2_reg) |
128 | #define GPIO_IMR (port->hwdata->imr_reg) |
129 | #define GPIO_ISR (port->hwdata->isr_reg) |
130 | #define GPIO_EDGE_SEL (port->hwdata->edge_sel_reg) |
131 | |
132 | #define GPIO_INT_LOW_LEV (port->hwdata->low_level) |
133 | #define GPIO_INT_HIGH_LEV (port->hwdata->high_level) |
134 | #define GPIO_INT_RISE_EDGE (port->hwdata->rise_edge) |
135 | #define GPIO_INT_FALL_EDGE (port->hwdata->fall_edge) |
136 | #define GPIO_INT_BOTH_EDGES 0x4 |
137 | |
138 | static const struct of_device_id mxc_gpio_dt_ids[] = { |
139 | { .compatible = "fsl,imx1-gpio" , .data = &imx1_imx21_gpio_hwdata }, |
140 | { .compatible = "fsl,imx21-gpio" , .data = &imx1_imx21_gpio_hwdata }, |
141 | { .compatible = "fsl,imx31-gpio" , .data = &imx31_gpio_hwdata }, |
142 | { .compatible = "fsl,imx35-gpio" , .data = &imx35_gpio_hwdata }, |
143 | { .compatible = "fsl,imx7d-gpio" , .data = &imx35_gpio_hwdata }, |
144 | { .compatible = "fsl,imx8dxl-gpio" , .data = &imx35_gpio_hwdata }, |
145 | { .compatible = "fsl,imx8qm-gpio" , .data = &imx35_gpio_hwdata }, |
146 | { .compatible = "fsl,imx8qxp-gpio" , .data = &imx35_gpio_hwdata }, |
147 | { /* sentinel */ } |
148 | }; |
149 | MODULE_DEVICE_TABLE(of, mxc_gpio_dt_ids); |
150 | |
151 | /* |
152 | * MX2 has one interrupt *for all* gpio ports. The list is used |
153 | * to save the references to all ports, so that mx2_gpio_irq_handler |
154 | * can walk through all interrupt status registers. |
155 | */ |
156 | static LIST_HEAD(mxc_gpio_ports); |
157 | |
158 | /* Note: This driver assumes 32 GPIOs are handled in one register */ |
159 | |
160 | static int gpio_set_irq_type(struct irq_data *d, u32 type) |
161 | { |
162 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
163 | struct mxc_gpio_port *port = gc->private; |
164 | unsigned long flags; |
165 | u32 bit, val; |
166 | u32 gpio_idx = d->hwirq; |
167 | int edge; |
168 | void __iomem *reg = port->base; |
169 | |
170 | port->both_edges &= ~(1 << gpio_idx); |
171 | switch (type) { |
172 | case IRQ_TYPE_EDGE_RISING: |
173 | edge = GPIO_INT_RISE_EDGE; |
174 | break; |
175 | case IRQ_TYPE_EDGE_FALLING: |
176 | edge = GPIO_INT_FALL_EDGE; |
177 | break; |
178 | case IRQ_TYPE_EDGE_BOTH: |
179 | if (GPIO_EDGE_SEL >= 0) { |
180 | edge = GPIO_INT_BOTH_EDGES; |
181 | } else { |
182 | val = port->gc.get(&port->gc, gpio_idx); |
183 | if (val) { |
184 | edge = GPIO_INT_LOW_LEV; |
185 | pr_debug("mxc: set GPIO %d to low trigger\n" , gpio_idx); |
186 | } else { |
187 | edge = GPIO_INT_HIGH_LEV; |
188 | pr_debug("mxc: set GPIO %d to high trigger\n" , gpio_idx); |
189 | } |
190 | port->both_edges |= 1 << gpio_idx; |
191 | } |
192 | break; |
193 | case IRQ_TYPE_LEVEL_LOW: |
194 | edge = GPIO_INT_LOW_LEV; |
195 | break; |
196 | case IRQ_TYPE_LEVEL_HIGH: |
197 | edge = GPIO_INT_HIGH_LEV; |
198 | break; |
199 | default: |
200 | return -EINVAL; |
201 | } |
202 | |
203 | raw_spin_lock_irqsave(&port->gc.bgpio_lock, flags); |
204 | |
205 | if (GPIO_EDGE_SEL >= 0) { |
206 | val = readl(addr: port->base + GPIO_EDGE_SEL); |
207 | if (edge == GPIO_INT_BOTH_EDGES) |
208 | writel(val: val | (1 << gpio_idx), |
209 | addr: port->base + GPIO_EDGE_SEL); |
210 | else |
211 | writel(val: val & ~(1 << gpio_idx), |
212 | addr: port->base + GPIO_EDGE_SEL); |
213 | } |
214 | |
215 | if (edge != GPIO_INT_BOTH_EDGES) { |
216 | reg += GPIO_ICR1 + ((gpio_idx & 0x10) >> 2); /* lower or upper register */ |
217 | bit = gpio_idx & 0xf; |
218 | val = readl(addr: reg) & ~(0x3 << (bit << 1)); |
219 | writel(val: val | (edge << (bit << 1)), addr: reg); |
220 | } |
221 | |
222 | writel(val: 1 << gpio_idx, addr: port->base + GPIO_ISR); |
223 | port->pad_type[gpio_idx] = type; |
224 | |
225 | raw_spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); |
226 | |
227 | return port->gc.direction_input(&port->gc, gpio_idx); |
228 | } |
229 | |
230 | static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) |
231 | { |
232 | void __iomem *reg = port->base; |
233 | unsigned long flags; |
234 | u32 bit, val; |
235 | int edge; |
236 | |
237 | raw_spin_lock_irqsave(&port->gc.bgpio_lock, flags); |
238 | |
239 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ |
240 | bit = gpio & 0xf; |
241 | val = readl(addr: reg); |
242 | edge = (val >> (bit << 1)) & 3; |
243 | val &= ~(0x3 << (bit << 1)); |
244 | if (edge == GPIO_INT_HIGH_LEV) { |
245 | edge = GPIO_INT_LOW_LEV; |
246 | pr_debug("mxc: switch GPIO %d to low trigger\n" , gpio); |
247 | } else if (edge == GPIO_INT_LOW_LEV) { |
248 | edge = GPIO_INT_HIGH_LEV; |
249 | pr_debug("mxc: switch GPIO %d to high trigger\n" , gpio); |
250 | } else { |
251 | pr_err("mxc: invalid configuration for GPIO %d: %x\n" , |
252 | gpio, edge); |
253 | goto unlock; |
254 | } |
255 | writel(val: val | (edge << (bit << 1)), addr: reg); |
256 | |
257 | unlock: |
258 | raw_spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); |
259 | } |
260 | |
261 | /* handle 32 interrupts in one status register */ |
262 | static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) |
263 | { |
264 | while (irq_stat != 0) { |
265 | int irqoffset = fls(x: irq_stat) - 1; |
266 | |
267 | if (port->both_edges & (1 << irqoffset)) |
268 | mxc_flip_edge(port, gpio: irqoffset); |
269 | |
270 | generic_handle_domain_irq(domain: port->domain, hwirq: irqoffset); |
271 | |
272 | irq_stat &= ~(1 << irqoffset); |
273 | } |
274 | } |
275 | |
276 | /* MX1 and MX3 has one interrupt *per* gpio port */ |
277 | static void mx3_gpio_irq_handler(struct irq_desc *desc) |
278 | { |
279 | u32 irq_stat; |
280 | struct mxc_gpio_port *port = irq_desc_get_handler_data(desc); |
281 | struct irq_chip *chip = irq_desc_get_chip(desc); |
282 | |
283 | if (port->is_pad_wakeup) |
284 | return; |
285 | |
286 | chained_irq_enter(chip, desc); |
287 | |
288 | irq_stat = readl(addr: port->base + GPIO_ISR) & readl(addr: port->base + GPIO_IMR); |
289 | |
290 | mxc_gpio_irq_handler(port, irq_stat); |
291 | |
292 | chained_irq_exit(chip, desc); |
293 | } |
294 | |
295 | /* MX2 has one interrupt *for all* gpio ports */ |
296 | static void mx2_gpio_irq_handler(struct irq_desc *desc) |
297 | { |
298 | u32 irq_msk, irq_stat; |
299 | struct mxc_gpio_port *port; |
300 | struct irq_chip *chip = irq_desc_get_chip(desc); |
301 | |
302 | chained_irq_enter(chip, desc); |
303 | |
304 | /* walk through all interrupt status registers */ |
305 | list_for_each_entry(port, &mxc_gpio_ports, node) { |
306 | irq_msk = readl(addr: port->base + GPIO_IMR); |
307 | if (!irq_msk) |
308 | continue; |
309 | |
310 | irq_stat = readl(addr: port->base + GPIO_ISR) & irq_msk; |
311 | if (irq_stat) |
312 | mxc_gpio_irq_handler(port, irq_stat); |
313 | } |
314 | chained_irq_exit(chip, desc); |
315 | } |
316 | |
317 | /* |
318 | * Set interrupt number "irq" in the GPIO as a wake-up source. |
319 | * While system is running, all registered GPIO interrupts need to have |
320 | * wake-up enabled. When system is suspended, only selected GPIO interrupts |
321 | * need to have wake-up enabled. |
322 | * @param irq interrupt source number |
323 | * @param enable enable as wake-up if equal to non-zero |
324 | * @return This function returns 0 on success. |
325 | */ |
326 | static int gpio_set_wake_irq(struct irq_data *d, u32 enable) |
327 | { |
328 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
329 | struct mxc_gpio_port *port = gc->private; |
330 | u32 gpio_idx = d->hwirq; |
331 | int ret; |
332 | |
333 | if (enable) { |
334 | if (port->irq_high && (gpio_idx >= 16)) |
335 | ret = enable_irq_wake(irq: port->irq_high); |
336 | else |
337 | ret = enable_irq_wake(irq: port->irq); |
338 | port->wakeup_pads |= (1 << gpio_idx); |
339 | } else { |
340 | if (port->irq_high && (gpio_idx >= 16)) |
341 | ret = disable_irq_wake(irq: port->irq_high); |
342 | else |
343 | ret = disable_irq_wake(irq: port->irq); |
344 | port->wakeup_pads &= ~(1 << gpio_idx); |
345 | } |
346 | |
347 | return ret; |
348 | } |
349 | |
350 | static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) |
351 | { |
352 | struct irq_chip_generic *gc; |
353 | struct irq_chip_type *ct; |
354 | int rv; |
355 | |
356 | gc = devm_irq_alloc_generic_chip(dev: port->dev, name: "gpio-mxc" , num_ct: 1, irq_base, |
357 | reg_base: port->base, handler: handle_level_irq); |
358 | if (!gc) |
359 | return -ENOMEM; |
360 | gc->private = port; |
361 | |
362 | ct = gc->chip_types; |
363 | ct->chip.irq_ack = irq_gc_ack_set_bit; |
364 | ct->chip.irq_mask = irq_gc_mask_clr_bit; |
365 | ct->chip.irq_unmask = irq_gc_mask_set_bit; |
366 | ct->chip.irq_set_type = gpio_set_irq_type; |
367 | ct->chip.irq_set_wake = gpio_set_wake_irq; |
368 | ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND; |
369 | ct->regs.ack = GPIO_ISR; |
370 | ct->regs.mask = GPIO_IMR; |
371 | |
372 | rv = devm_irq_setup_generic_chip(dev: port->dev, gc, IRQ_MSK(32), |
373 | flags: IRQ_GC_INIT_NESTED_LOCK, |
374 | clr: IRQ_NOREQUEST, set: 0); |
375 | |
376 | return rv; |
377 | } |
378 | |
379 | static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset) |
380 | { |
381 | struct mxc_gpio_port *port = gpiochip_get_data(gc); |
382 | |
383 | return irq_find_mapping(domain: port->domain, hwirq: offset); |
384 | } |
385 | |
386 | static int mxc_gpio_request(struct gpio_chip *chip, unsigned int offset) |
387 | { |
388 | int ret; |
389 | |
390 | ret = gpiochip_generic_request(gc: chip, offset); |
391 | if (ret) |
392 | return ret; |
393 | |
394 | return pm_runtime_resume_and_get(dev: chip->parent); |
395 | } |
396 | |
397 | static void mxc_gpio_free(struct gpio_chip *chip, unsigned int offset) |
398 | { |
399 | gpiochip_generic_free(gc: chip, offset); |
400 | pm_runtime_put(dev: chip->parent); |
401 | } |
402 | |
403 | static void mxc_update_irq_chained_handler(struct mxc_gpio_port *port, bool enable) |
404 | { |
405 | if (enable) |
406 | irq_set_chained_handler_and_data(irq: port->irq, handle: port->mx_irq_handler, data: port); |
407 | else |
408 | irq_set_chained_handler_and_data(irq: port->irq, NULL, NULL); |
409 | |
410 | /* setup handler for GPIO 16 to 31 */ |
411 | if (port->irq_high > 0) { |
412 | if (enable) |
413 | irq_set_chained_handler_and_data(irq: port->irq_high, |
414 | handle: port->mx_irq_handler, |
415 | data: port); |
416 | else |
417 | irq_set_chained_handler_and_data(irq: port->irq_high, NULL, NULL); |
418 | } |
419 | } |
420 | |
421 | static int mxc_gpio_probe(struct platform_device *pdev) |
422 | { |
423 | struct device_node *np = pdev->dev.of_node; |
424 | struct mxc_gpio_port *port; |
425 | int irq_count; |
426 | int irq_base; |
427 | int err; |
428 | |
429 | port = devm_kzalloc(dev: &pdev->dev, size: sizeof(*port), GFP_KERNEL); |
430 | if (!port) |
431 | return -ENOMEM; |
432 | |
433 | port->dev = &pdev->dev; |
434 | port->hwdata = device_get_match_data(dev: &pdev->dev); |
435 | |
436 | port->base = devm_platform_ioremap_resource(pdev, index: 0); |
437 | if (IS_ERR(ptr: port->base)) |
438 | return PTR_ERR(ptr: port->base); |
439 | |
440 | irq_count = platform_irq_count(pdev); |
441 | if (irq_count < 0) |
442 | return irq_count; |
443 | |
444 | if (irq_count > 1) { |
445 | port->irq_high = platform_get_irq(pdev, 1); |
446 | if (port->irq_high < 0) |
447 | port->irq_high = 0; |
448 | } |
449 | |
450 | port->irq = platform_get_irq(pdev, 0); |
451 | if (port->irq < 0) |
452 | return port->irq; |
453 | |
454 | /* the controller clock is optional */ |
455 | port->clk = devm_clk_get_optional_enabled(dev: &pdev->dev, NULL); |
456 | if (IS_ERR(ptr: port->clk)) |
457 | return PTR_ERR(ptr: port->clk); |
458 | |
459 | if (of_device_is_compatible(device: np, "fsl,imx7d-gpio" )) |
460 | port->power_off = true; |
461 | |
462 | pm_runtime_get_noresume(dev: &pdev->dev); |
463 | pm_runtime_set_active(dev: &pdev->dev); |
464 | pm_runtime_enable(dev: &pdev->dev); |
465 | |
466 | /* disable the interrupt and clear the status */ |
467 | writel(val: 0, addr: port->base + GPIO_IMR); |
468 | writel(val: ~0, addr: port->base + GPIO_ISR); |
469 | |
470 | if (of_device_is_compatible(device: np, "fsl,imx21-gpio" )) { |
471 | /* |
472 | * Setup one handler for all GPIO interrupts. Actually setting |
473 | * the handler is needed only once, but doing it for every port |
474 | * is more robust and easier. |
475 | */ |
476 | port->irq_high = -1; |
477 | port->mx_irq_handler = mx2_gpio_irq_handler; |
478 | } else |
479 | port->mx_irq_handler = mx3_gpio_irq_handler; |
480 | |
481 | mxc_update_irq_chained_handler(port, enable: true); |
482 | err = bgpio_init(gc: &port->gc, dev: &pdev->dev, sz: 4, |
483 | dat: port->base + GPIO_PSR, |
484 | set: port->base + GPIO_DR, NULL, |
485 | dirout: port->base + GPIO_GDIR, NULL, |
486 | BGPIOF_READ_OUTPUT_REG_SET); |
487 | if (err) |
488 | goto out_bgio; |
489 | |
490 | port->gc.request = mxc_gpio_request; |
491 | port->gc.free = mxc_gpio_free; |
492 | port->gc.to_irq = mxc_gpio_to_irq; |
493 | port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, stem: "gpio" ) * 32 : |
494 | pdev->id * 32; |
495 | |
496 | err = devm_gpiochip_add_data(&pdev->dev, &port->gc, port); |
497 | if (err) |
498 | goto out_bgio; |
499 | |
500 | irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id()); |
501 | if (irq_base < 0) { |
502 | err = irq_base; |
503 | goto out_bgio; |
504 | } |
505 | |
506 | port->domain = irq_domain_add_legacy(of_node: np, size: 32, first_irq: irq_base, first_hwirq: 0, |
507 | ops: &irq_domain_simple_ops, NULL); |
508 | if (!port->domain) { |
509 | err = -ENODEV; |
510 | goto out_bgio; |
511 | } |
512 | |
513 | irq_domain_set_pm_device(d: port->domain, dev: &pdev->dev); |
514 | |
515 | /* gpio-mxc can be a generic irq chip */ |
516 | err = mxc_gpio_init_gc(port, irq_base); |
517 | if (err < 0) |
518 | goto out_irqdomain_remove; |
519 | |
520 | list_add_tail(new: &port->node, head: &mxc_gpio_ports); |
521 | |
522 | platform_set_drvdata(pdev, data: port); |
523 | pm_runtime_put_autosuspend(dev: &pdev->dev); |
524 | |
525 | return 0; |
526 | |
527 | out_irqdomain_remove: |
528 | irq_domain_remove(host: port->domain); |
529 | out_bgio: |
530 | pm_runtime_disable(dev: &pdev->dev); |
531 | pm_runtime_put_noidle(dev: &pdev->dev); |
532 | dev_info(&pdev->dev, "%s failed with errno %d\n" , __func__, err); |
533 | return err; |
534 | } |
535 | |
536 | static void mxc_gpio_save_regs(struct mxc_gpio_port *port) |
537 | { |
538 | if (!port->power_off) |
539 | return; |
540 | |
541 | port->gpio_saved_reg.icr1 = readl(addr: port->base + GPIO_ICR1); |
542 | port->gpio_saved_reg.icr2 = readl(addr: port->base + GPIO_ICR2); |
543 | port->gpio_saved_reg.imr = readl(addr: port->base + GPIO_IMR); |
544 | port->gpio_saved_reg.gdir = readl(addr: port->base + GPIO_GDIR); |
545 | port->gpio_saved_reg.edge_sel = readl(addr: port->base + GPIO_EDGE_SEL); |
546 | port->gpio_saved_reg.dr = readl(addr: port->base + GPIO_DR); |
547 | } |
548 | |
549 | static void mxc_gpio_restore_regs(struct mxc_gpio_port *port) |
550 | { |
551 | if (!port->power_off) |
552 | return; |
553 | |
554 | writel(val: port->gpio_saved_reg.icr1, addr: port->base + GPIO_ICR1); |
555 | writel(val: port->gpio_saved_reg.icr2, addr: port->base + GPIO_ICR2); |
556 | writel(val: port->gpio_saved_reg.imr, addr: port->base + GPIO_IMR); |
557 | writel(val: port->gpio_saved_reg.gdir, addr: port->base + GPIO_GDIR); |
558 | writel(val: port->gpio_saved_reg.edge_sel, addr: port->base + GPIO_EDGE_SEL); |
559 | writel(val: port->gpio_saved_reg.dr, addr: port->base + GPIO_DR); |
560 | } |
561 | |
562 | static bool mxc_gpio_generic_config(struct mxc_gpio_port *port, |
563 | unsigned int offset, unsigned long conf) |
564 | { |
565 | struct device_node *np = port->dev->of_node; |
566 | |
567 | if (of_device_is_compatible(device: np, "fsl,imx8dxl-gpio" ) || |
568 | of_device_is_compatible(device: np, "fsl,imx8qxp-gpio" ) || |
569 | of_device_is_compatible(device: np, "fsl,imx8qm-gpio" )) |
570 | return (gpiochip_generic_config(gc: &port->gc, offset, config: conf) == 0); |
571 | |
572 | return false; |
573 | } |
574 | |
575 | static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable) |
576 | { |
577 | unsigned long config; |
578 | bool ret = false; |
579 | int i, type; |
580 | |
581 | static const u32 pad_type_map[] = { |
582 | IMX_SCU_WAKEUP_OFF, /* 0 */ |
583 | IMX_SCU_WAKEUP_RISE_EDGE, /* IRQ_TYPE_EDGE_RISING */ |
584 | IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_FALLING */ |
585 | IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_BOTH */ |
586 | IMX_SCU_WAKEUP_HIGH_LVL, /* IRQ_TYPE_LEVEL_HIGH */ |
587 | IMX_SCU_WAKEUP_OFF, /* 5 */ |
588 | IMX_SCU_WAKEUP_OFF, /* 6 */ |
589 | IMX_SCU_WAKEUP_OFF, /* 7 */ |
590 | IMX_SCU_WAKEUP_LOW_LVL, /* IRQ_TYPE_LEVEL_LOW */ |
591 | }; |
592 | |
593 | for (i = 0; i < 32; i++) { |
594 | if ((port->wakeup_pads & (1 << i))) { |
595 | type = port->pad_type[i]; |
596 | if (enable) |
597 | config = pad_type_map[type]; |
598 | else |
599 | config = IMX_SCU_WAKEUP_OFF; |
600 | ret |= mxc_gpio_generic_config(port, offset: i, conf: config); |
601 | } |
602 | } |
603 | |
604 | return ret; |
605 | } |
606 | |
607 | static int mxc_gpio_runtime_suspend(struct device *dev) |
608 | { |
609 | struct mxc_gpio_port *port = dev_get_drvdata(dev); |
610 | |
611 | mxc_gpio_save_regs(port); |
612 | clk_disable_unprepare(clk: port->clk); |
613 | mxc_update_irq_chained_handler(port, enable: false); |
614 | |
615 | return 0; |
616 | } |
617 | |
618 | static int mxc_gpio_runtime_resume(struct device *dev) |
619 | { |
620 | struct mxc_gpio_port *port = dev_get_drvdata(dev); |
621 | int ret; |
622 | |
623 | mxc_update_irq_chained_handler(port, enable: true); |
624 | ret = clk_prepare_enable(clk: port->clk); |
625 | if (ret) { |
626 | mxc_update_irq_chained_handler(port, enable: false); |
627 | return ret; |
628 | } |
629 | |
630 | mxc_gpio_restore_regs(port); |
631 | |
632 | return 0; |
633 | } |
634 | |
635 | static int mxc_gpio_noirq_suspend(struct device *dev) |
636 | { |
637 | struct platform_device *pdev = to_platform_device(dev); |
638 | struct mxc_gpio_port *port = platform_get_drvdata(pdev); |
639 | |
640 | if (port->wakeup_pads > 0) |
641 | port->is_pad_wakeup = mxc_gpio_set_pad_wakeup(port, enable: true); |
642 | |
643 | return 0; |
644 | } |
645 | |
646 | static int mxc_gpio_noirq_resume(struct device *dev) |
647 | { |
648 | struct platform_device *pdev = to_platform_device(dev); |
649 | struct mxc_gpio_port *port = platform_get_drvdata(pdev); |
650 | |
651 | if (port->wakeup_pads > 0) |
652 | mxc_gpio_set_pad_wakeup(port, enable: false); |
653 | port->is_pad_wakeup = false; |
654 | |
655 | return 0; |
656 | } |
657 | |
658 | static const struct dev_pm_ops mxc_gpio_dev_pm_ops = { |
659 | NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume) |
660 | RUNTIME_PM_OPS(mxc_gpio_runtime_suspend, mxc_gpio_runtime_resume, NULL) |
661 | }; |
662 | |
663 | static int mxc_gpio_syscore_suspend(void) |
664 | { |
665 | struct mxc_gpio_port *port; |
666 | int ret; |
667 | |
668 | /* walk through all ports */ |
669 | list_for_each_entry(port, &mxc_gpio_ports, node) { |
670 | ret = clk_prepare_enable(clk: port->clk); |
671 | if (ret) |
672 | return ret; |
673 | mxc_gpio_save_regs(port); |
674 | clk_disable_unprepare(clk: port->clk); |
675 | } |
676 | |
677 | return 0; |
678 | } |
679 | |
680 | static void mxc_gpio_syscore_resume(void) |
681 | { |
682 | struct mxc_gpio_port *port; |
683 | int ret; |
684 | |
685 | /* walk through all ports */ |
686 | list_for_each_entry(port, &mxc_gpio_ports, node) { |
687 | ret = clk_prepare_enable(clk: port->clk); |
688 | if (ret) { |
689 | pr_err("mxc: failed to enable gpio clock %d\n" , ret); |
690 | return; |
691 | } |
692 | mxc_gpio_restore_regs(port); |
693 | clk_disable_unprepare(clk: port->clk); |
694 | } |
695 | } |
696 | |
697 | static struct syscore_ops mxc_gpio_syscore_ops = { |
698 | .suspend = mxc_gpio_syscore_suspend, |
699 | .resume = mxc_gpio_syscore_resume, |
700 | }; |
701 | |
702 | static struct platform_driver mxc_gpio_driver = { |
703 | .driver = { |
704 | .name = "gpio-mxc" , |
705 | .of_match_table = mxc_gpio_dt_ids, |
706 | .suppress_bind_attrs = true, |
707 | .pm = pm_ptr(&mxc_gpio_dev_pm_ops), |
708 | }, |
709 | .probe = mxc_gpio_probe, |
710 | }; |
711 | |
712 | static int __init gpio_mxc_init(void) |
713 | { |
714 | register_syscore_ops(ops: &mxc_gpio_syscore_ops); |
715 | |
716 | return platform_driver_register(&mxc_gpio_driver); |
717 | } |
718 | subsys_initcall(gpio_mxc_init); |
719 | |
720 | MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>" ); |
721 | MODULE_DESCRIPTION("i.MX GPIO Driver" ); |
722 | MODULE_LICENSE("GPL" ); |
723 | |