1// SPDX-License-Identifier: GPL-2.0+
2//
3// Exynos specific support for Samsung pinctrl/gpiolib driver with eint support.
4//
5// Copyright (c) 2012 Samsung Electronics Co., Ltd.
6// http://www.samsung.com
7// Copyright (c) 2012 Linaro Ltd
8// http://www.linaro.org
9//
10// Author: Thomas Abraham <thomas.ab@samsung.com>
11//
12// This file contains the Samsung Exynos specific information required by the
13// the Samsung pinctrl/gpiolib driver. It also includes the implementation of
14// external gpio and wakeup interrupt support.
15
16#include <linux/device.h>
17#include <linux/interrupt.h>
18#include <linux/irqdomain.h>
19#include <linux/irq.h>
20#include <linux/irqchip/chained_irq.h>
21#include <linux/of.h>
22#include <linux/of_irq.h>
23#include <linux/slab.h>
24#include <linux/spinlock.h>
25#include <linux/regmap.h>
26#include <linux/err.h>
27#include <linux/soc/samsung/exynos-pmu.h>
28#include <linux/soc/samsung/exynos-regs-pmu.h>
29
30#include "pinctrl-samsung.h"
31#include "pinctrl-exynos.h"
32
33struct exynos_irq_chip {
34 struct irq_chip chip;
35
36 u32 eint_con;
37 u32 eint_mask;
38 u32 eint_pend;
39 u32 *eint_wake_mask_value;
40 u32 eint_wake_mask_reg;
41 void (*set_eint_wakeup_mask)(struct samsung_pinctrl_drv_data *drvdata,
42 struct exynos_irq_chip *irq_chip);
43};
44
45static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip)
46{
47 return container_of(chip, struct exynos_irq_chip, chip);
48}
49
50static void exynos_irq_mask(struct irq_data *irqd)
51{
52 struct irq_chip *chip = irq_data_get_irq_chip(d: irqd);
53 struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
54 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(d: irqd);
55 unsigned long reg_mask;
56 unsigned int mask;
57 unsigned long flags;
58
59 if (bank->eint_mask_offset)
60 reg_mask = bank->pctl_offset + bank->eint_mask_offset;
61 else
62 reg_mask = our_chip->eint_mask + bank->eint_offset;
63
64 raw_spin_lock_irqsave(&bank->slock, flags);
65
66 mask = readl(addr: bank->eint_base + reg_mask);
67 mask |= 1 << irqd->hwirq;
68 writel(val: mask, addr: bank->eint_base + reg_mask);
69
70 raw_spin_unlock_irqrestore(&bank->slock, flags);
71}
72
73static void exynos_irq_ack(struct irq_data *irqd)
74{
75 struct irq_chip *chip = irq_data_get_irq_chip(d: irqd);
76 struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
77 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(d: irqd);
78 unsigned long reg_pend;
79
80 if (bank->eint_pend_offset)
81 reg_pend = bank->pctl_offset + bank->eint_pend_offset;
82 else
83 reg_pend = our_chip->eint_pend + bank->eint_offset;
84
85 writel(val: 1 << irqd->hwirq, addr: bank->eint_base + reg_pend);
86}
87
88static void exynos_irq_unmask(struct irq_data *irqd)
89{
90 struct irq_chip *chip = irq_data_get_irq_chip(d: irqd);
91 struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
92 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(d: irqd);
93 unsigned long reg_mask;
94 unsigned int mask;
95 unsigned long flags;
96
97 /*
98 * Ack level interrupts right before unmask
99 *
100 * If we don't do this we'll get a double-interrupt. Level triggered
101 * interrupts must not fire an interrupt if the level is not
102 * _currently_ active, even if it was active while the interrupt was
103 * masked.
104 */
105 if (irqd_get_trigger_type(d: irqd) & IRQ_TYPE_LEVEL_MASK)
106 exynos_irq_ack(irqd);
107
108 if (bank->eint_mask_offset)
109 reg_mask = bank->pctl_offset + bank->eint_mask_offset;
110 else
111 reg_mask = our_chip->eint_mask + bank->eint_offset;
112
113 raw_spin_lock_irqsave(&bank->slock, flags);
114
115 mask = readl(addr: bank->eint_base + reg_mask);
116 mask &= ~(1 << irqd->hwirq);
117 writel(val: mask, addr: bank->eint_base + reg_mask);
118
119 raw_spin_unlock_irqrestore(&bank->slock, flags);
120}
121
122static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
123{
124 struct irq_chip *chip = irq_data_get_irq_chip(d: irqd);
125 struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
126 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(d: irqd);
127 unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
128 unsigned int con, trig_type;
129 unsigned long reg_con;
130
131 switch (type) {
132 case IRQ_TYPE_EDGE_RISING:
133 trig_type = EXYNOS_EINT_EDGE_RISING;
134 break;
135 case IRQ_TYPE_EDGE_FALLING:
136 trig_type = EXYNOS_EINT_EDGE_FALLING;
137 break;
138 case IRQ_TYPE_EDGE_BOTH:
139 trig_type = EXYNOS_EINT_EDGE_BOTH;
140 break;
141 case IRQ_TYPE_LEVEL_HIGH:
142 trig_type = EXYNOS_EINT_LEVEL_HIGH;
143 break;
144 case IRQ_TYPE_LEVEL_LOW:
145 trig_type = EXYNOS_EINT_LEVEL_LOW;
146 break;
147 default:
148 pr_err("unsupported external interrupt type\n");
149 return -EINVAL;
150 }
151
152 if (type & IRQ_TYPE_EDGE_BOTH)
153 irq_set_handler_locked(data: irqd, handler: handle_edge_irq);
154 else
155 irq_set_handler_locked(data: irqd, handler: handle_level_irq);
156
157 if (bank->eint_con_offset)
158 reg_con = bank->pctl_offset + bank->eint_con_offset;
159 else
160 reg_con = our_chip->eint_con + bank->eint_offset;
161
162 con = readl(addr: bank->eint_base + reg_con);
163 con &= ~(EXYNOS_EINT_CON_MASK << shift);
164 con |= trig_type << shift;
165 writel(val: con, addr: bank->eint_base + reg_con);
166
167 return 0;
168}
169
170static int exynos_irq_set_affinity(struct irq_data *irqd,
171 const struct cpumask *dest, bool force)
172{
173 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(d: irqd);
174 struct samsung_pinctrl_drv_data *d = bank->drvdata;
175 struct irq_data *parent = irq_get_irq_data(irq: d->irq);
176
177 if (parent)
178 return parent->chip->irq_set_affinity(parent, dest, force);
179
180 return -EINVAL;
181}
182
183static int exynos_irq_request_resources(struct irq_data *irqd)
184{
185 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(d: irqd);
186 const struct samsung_pin_bank_type *bank_type = bank->type;
187 unsigned long reg_con, flags;
188 unsigned int shift, mask, con;
189 int ret;
190
191 ret = gpiochip_lock_as_irq(gc: &bank->gpio_chip, offset: irqd->hwirq);
192 if (ret) {
193 dev_err(bank->gpio_chip.parent,
194 "unable to lock pin %s-%lu IRQ\n",
195 bank->name, irqd->hwirq);
196 return ret;
197 }
198
199 reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
200 shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
201 mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
202
203 raw_spin_lock_irqsave(&bank->slock, flags);
204
205 con = readl(addr: bank->pctl_base + reg_con);
206 con &= ~(mask << shift);
207 con |= EXYNOS_PIN_CON_FUNC_EINT << shift;
208 writel(val: con, addr: bank->pctl_base + reg_con);
209
210 raw_spin_unlock_irqrestore(&bank->slock, flags);
211
212 return 0;
213}
214
215static void exynos_irq_release_resources(struct irq_data *irqd)
216{
217 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(d: irqd);
218 const struct samsung_pin_bank_type *bank_type = bank->type;
219 unsigned long reg_con, flags;
220 unsigned int shift, mask, con;
221
222 reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
223 shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
224 mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
225
226 raw_spin_lock_irqsave(&bank->slock, flags);
227
228 con = readl(addr: bank->pctl_base + reg_con);
229 con &= ~(mask << shift);
230 con |= PIN_CON_FUNC_INPUT << shift;
231 writel(val: con, addr: bank->pctl_base + reg_con);
232
233 raw_spin_unlock_irqrestore(&bank->slock, flags);
234
235 gpiochip_unlock_as_irq(gc: &bank->gpio_chip, offset: irqd->hwirq);
236}
237
238/*
239 * irq_chip for gpio interrupts.
240 */
241static const struct exynos_irq_chip exynos_gpio_irq_chip __initconst = {
242 .chip = {
243 .name = "exynos_gpio_irq_chip",
244 .irq_unmask = exynos_irq_unmask,
245 .irq_mask = exynos_irq_mask,
246 .irq_ack = exynos_irq_ack,
247 .irq_set_type = exynos_irq_set_type,
248 .irq_set_affinity = exynos_irq_set_affinity,
249 .irq_request_resources = exynos_irq_request_resources,
250 .irq_release_resources = exynos_irq_release_resources,
251 },
252 .eint_con = EXYNOS_GPIO_ECON_OFFSET,
253 .eint_mask = EXYNOS_GPIO_EMASK_OFFSET,
254 .eint_pend = EXYNOS_GPIO_EPEND_OFFSET,
255 /* eint_wake_mask_value not used */
256};
257
258static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
259 irq_hw_number_t hw)
260{
261 struct samsung_pin_bank *b = h->host_data;
262
263 irq_set_chip_data(irq: virq, data: b);
264 irq_set_chip_and_handler(irq: virq, chip: &b->irq_chip->chip,
265 handle: handle_level_irq);
266 return 0;
267}
268
269/*
270 * irq domain callbacks for external gpio and wakeup interrupt controllers.
271 */
272static const struct irq_domain_ops exynos_eint_irqd_ops = {
273 .map = exynos_eint_irq_map,
274 .xlate = irq_domain_xlate_twocell,
275};
276
277static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
278{
279 struct samsung_pinctrl_drv_data *d = data;
280 struct samsung_pin_bank *bank = d->pin_banks;
281 unsigned int svc, group, pin;
282 int ret;
283
284 if (bank->eint_con_offset)
285 svc = readl(addr: bank->eint_base + EXYNOSAUTO_SVC_OFFSET);
286 else
287 svc = readl(addr: bank->eint_base + EXYNOS_SVC_OFFSET);
288 group = EXYNOS_SVC_GROUP(svc);
289 pin = svc & EXYNOS_SVC_NUM_MASK;
290
291 if (!group)
292 return IRQ_HANDLED;
293 bank += (group - 1);
294
295 ret = generic_handle_domain_irq(domain: bank->irq_domain, hwirq: pin);
296 if (ret)
297 return IRQ_NONE;
298
299 return IRQ_HANDLED;
300}
301
302struct exynos_eint_gpio_save {
303 u32 eint_con;
304 u32 eint_fltcon0;
305 u32 eint_fltcon1;
306 u32 eint_mask;
307};
308
309/*
310 * exynos_eint_gpio_init() - setup handling of external gpio interrupts.
311 * @d: driver data of samsung pinctrl driver.
312 */
313__init int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
314{
315 struct samsung_pin_bank *bank;
316 struct device *dev = d->dev;
317 int ret;
318 int i;
319
320 if (!d->irq) {
321 dev_err(dev, "irq number not available\n");
322 return -EINVAL;
323 }
324
325 ret = devm_request_irq(dev, irq: d->irq, handler: exynos_eint_gpio_irq,
326 irqflags: 0, devname: dev_name(dev), dev_id: d);
327 if (ret) {
328 dev_err(dev, "irq request failed\n");
329 return -ENXIO;
330 }
331
332 bank = d->pin_banks;
333 for (i = 0; i < d->nr_banks; ++i, ++bank) {
334 if (bank->eint_type != EINT_TYPE_GPIO)
335 continue;
336
337 bank->irq_chip = devm_kmemdup(dev, src: &exynos_gpio_irq_chip,
338 len: sizeof(*bank->irq_chip), GFP_KERNEL);
339 if (!bank->irq_chip) {
340 ret = -ENOMEM;
341 goto err_domains;
342 }
343 bank->irq_chip->chip.name = bank->name;
344
345 bank->irq_domain = irq_domain_create_linear(fwnode: bank->fwnode,
346 size: bank->nr_pins, ops: &exynos_eint_irqd_ops, host_data: bank);
347 if (!bank->irq_domain) {
348 dev_err(dev, "gpio irq domain add failed\n");
349 ret = -ENXIO;
350 goto err_domains;
351 }
352
353 bank->soc_priv = devm_kzalloc(dev: d->dev,
354 size: sizeof(struct exynos_eint_gpio_save), GFP_KERNEL);
355 if (!bank->soc_priv) {
356 irq_domain_remove(host: bank->irq_domain);
357 ret = -ENOMEM;
358 goto err_domains;
359 }
360
361 }
362
363 return 0;
364
365err_domains:
366 for (--i, --bank; i >= 0; --i, --bank) {
367 if (bank->eint_type != EINT_TYPE_GPIO)
368 continue;
369 irq_domain_remove(host: bank->irq_domain);
370 }
371
372 return ret;
373}
374
375static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
376{
377 struct irq_chip *chip = irq_data_get_irq_chip(d: irqd);
378 struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
379 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(d: irqd);
380 unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq);
381
382 pr_info("wake %s for irq %u (%s-%lu)\n", on ? "enabled" : "disabled",
383 irqd->irq, bank->name, irqd->hwirq);
384
385 if (!on)
386 *our_chip->eint_wake_mask_value |= bit;
387 else
388 *our_chip->eint_wake_mask_value &= ~bit;
389
390 return 0;
391}
392
393static void
394exynos_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
395 struct exynos_irq_chip *irq_chip)
396{
397 struct regmap *pmu_regs;
398
399 if (!drvdata->retention_ctrl || !drvdata->retention_ctrl->priv) {
400 dev_warn(drvdata->dev,
401 "No retention data configured bank with external wakeup interrupt. Wake-up mask will not be set.\n");
402 return;
403 }
404
405 pmu_regs = drvdata->retention_ctrl->priv;
406 dev_info(drvdata->dev,
407 "Setting external wakeup interrupt mask: 0x%x\n",
408 *irq_chip->eint_wake_mask_value);
409
410 regmap_write(map: pmu_regs, reg: irq_chip->eint_wake_mask_reg,
411 val: *irq_chip->eint_wake_mask_value);
412}
413
414static void
415s5pv210_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
416 struct exynos_irq_chip *irq_chip)
417
418{
419 void __iomem *clk_base;
420
421 if (!drvdata->retention_ctrl || !drvdata->retention_ctrl->priv) {
422 dev_warn(drvdata->dev,
423 "No retention data configured bank with external wakeup interrupt. Wake-up mask will not be set.\n");
424 return;
425 }
426
427
428 clk_base = (void __iomem *) drvdata->retention_ctrl->priv;
429
430 __raw_writel(val: *irq_chip->eint_wake_mask_value,
431 addr: clk_base + irq_chip->eint_wake_mask_reg);
432}
433
434static u32 eint_wake_mask_value = EXYNOS_EINT_WAKEUP_MASK_DISABLED;
435/*
436 * irq_chip for wakeup interrupts
437 */
438static const struct exynos_irq_chip s5pv210_wkup_irq_chip __initconst = {
439 .chip = {
440 .name = "s5pv210_wkup_irq_chip",
441 .irq_unmask = exynos_irq_unmask,
442 .irq_mask = exynos_irq_mask,
443 .irq_ack = exynos_irq_ack,
444 .irq_set_type = exynos_irq_set_type,
445 .irq_set_wake = exynos_wkup_irq_set_wake,
446 .irq_request_resources = exynos_irq_request_resources,
447 .irq_release_resources = exynos_irq_release_resources,
448 },
449 .eint_con = EXYNOS_WKUP_ECON_OFFSET,
450 .eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
451 .eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
452 .eint_wake_mask_value = &eint_wake_mask_value,
453 /* Only differences with exynos4210_wkup_irq_chip: */
454 .eint_wake_mask_reg = S5PV210_EINT_WAKEUP_MASK,
455 .set_eint_wakeup_mask = s5pv210_pinctrl_set_eint_wakeup_mask,
456};
457
458static const struct exynos_irq_chip exynos4210_wkup_irq_chip __initconst = {
459 .chip = {
460 .name = "exynos4210_wkup_irq_chip",
461 .irq_unmask = exynos_irq_unmask,
462 .irq_mask = exynos_irq_mask,
463 .irq_ack = exynos_irq_ack,
464 .irq_set_type = exynos_irq_set_type,
465 .irq_set_wake = exynos_wkup_irq_set_wake,
466 .irq_request_resources = exynos_irq_request_resources,
467 .irq_release_resources = exynos_irq_release_resources,
468 },
469 .eint_con = EXYNOS_WKUP_ECON_OFFSET,
470 .eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
471 .eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
472 .eint_wake_mask_value = &eint_wake_mask_value,
473 .eint_wake_mask_reg = EXYNOS_EINT_WAKEUP_MASK,
474 .set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
475};
476
477static const struct exynos_irq_chip exynos7_wkup_irq_chip __initconst = {
478 .chip = {
479 .name = "exynos7_wkup_irq_chip",
480 .irq_unmask = exynos_irq_unmask,
481 .irq_mask = exynos_irq_mask,
482 .irq_ack = exynos_irq_ack,
483 .irq_set_type = exynos_irq_set_type,
484 .irq_set_wake = exynos_wkup_irq_set_wake,
485 .irq_request_resources = exynos_irq_request_resources,
486 .irq_release_resources = exynos_irq_release_resources,
487 },
488 .eint_con = EXYNOS7_WKUP_ECON_OFFSET,
489 .eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
490 .eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
491 .eint_wake_mask_value = &eint_wake_mask_value,
492 .eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
493 .set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
494};
495
496static const struct exynos_irq_chip exynosautov920_wkup_irq_chip __initconst = {
497 .chip = {
498 .name = "exynosautov920_wkup_irq_chip",
499 .irq_unmask = exynos_irq_unmask,
500 .irq_mask = exynos_irq_mask,
501 .irq_ack = exynos_irq_ack,
502 .irq_set_type = exynos_irq_set_type,
503 .irq_set_wake = exynos_wkup_irq_set_wake,
504 .irq_request_resources = exynos_irq_request_resources,
505 .irq_release_resources = exynos_irq_release_resources,
506 },
507 .eint_wake_mask_value = &eint_wake_mask_value,
508 .eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
509 .set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
510};
511
512/* list of external wakeup controllers supported */
513static const struct of_device_id exynos_wkup_irq_ids[] = {
514 { .compatible = "samsung,s5pv210-wakeup-eint",
515 .data = &s5pv210_wkup_irq_chip },
516 { .compatible = "samsung,exynos4210-wakeup-eint",
517 .data = &exynos4210_wkup_irq_chip },
518 { .compatible = "samsung,exynos7-wakeup-eint",
519 .data = &exynos7_wkup_irq_chip },
520 { .compatible = "samsung,exynos850-wakeup-eint",
521 .data = &exynos7_wkup_irq_chip },
522 { .compatible = "samsung,exynosautov9-wakeup-eint",
523 .data = &exynos7_wkup_irq_chip },
524 { .compatible = "samsung,exynosautov920-wakeup-eint",
525 .data = &exynosautov920_wkup_irq_chip },
526 { }
527};
528
529/* interrupt handler for wakeup interrupts 0..15 */
530static void exynos_irq_eint0_15(struct irq_desc *desc)
531{
532 struct exynos_weint_data *eintd = irq_desc_get_handler_data(desc);
533 struct samsung_pin_bank *bank = eintd->bank;
534 struct irq_chip *chip = irq_desc_get_chip(desc);
535
536 chained_irq_enter(chip, desc);
537
538 generic_handle_domain_irq(domain: bank->irq_domain, hwirq: eintd->irq);
539
540 chained_irq_exit(chip, desc);
541}
542
543static inline void exynos_irq_demux_eint(unsigned int pend,
544 struct irq_domain *domain)
545{
546 unsigned int irq;
547
548 while (pend) {
549 irq = fls(x: pend) - 1;
550 generic_handle_domain_irq(domain, hwirq: irq);
551 pend &= ~(1 << irq);
552 }
553}
554
555/* interrupt handler for wakeup interrupt 16 */
556static void exynos_irq_demux_eint16_31(struct irq_desc *desc)
557{
558 struct irq_chip *chip = irq_desc_get_chip(desc);
559 struct exynos_muxed_weint_data *eintd = irq_desc_get_handler_data(desc);
560 unsigned int pend;
561 unsigned int mask;
562 int i;
563
564 chained_irq_enter(chip, desc);
565
566 for (i = 0; i < eintd->nr_banks; ++i) {
567 struct samsung_pin_bank *b = eintd->banks[i];
568 pend = readl(addr: b->eint_base + b->irq_chip->eint_pend
569 + b->eint_offset);
570 mask = readl(addr: b->eint_base + b->irq_chip->eint_mask
571 + b->eint_offset);
572 exynos_irq_demux_eint(pend: pend & ~mask, domain: b->irq_domain);
573 }
574
575 chained_irq_exit(chip, desc);
576}
577
578/*
579 * exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
580 * @d: driver data of samsung pinctrl driver.
581 */
582__init int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
583{
584 struct device *dev = d->dev;
585 struct device_node *wkup_np = NULL;
586 struct device_node *np;
587 struct samsung_pin_bank *bank;
588 struct exynos_weint_data *weint_data;
589 struct exynos_muxed_weint_data *muxed_data;
590 const struct exynos_irq_chip *irq_chip;
591 unsigned int muxed_banks = 0;
592 unsigned int i;
593 int idx, irq;
594
595 for_each_child_of_node(dev->of_node, np) {
596 const struct of_device_id *match;
597
598 match = of_match_node(matches: exynos_wkup_irq_ids, node: np);
599 if (match) {
600 irq_chip = match->data;
601 wkup_np = np;
602 break;
603 }
604 }
605 if (!wkup_np)
606 return -ENODEV;
607
608 bank = d->pin_banks;
609 for (i = 0; i < d->nr_banks; ++i, ++bank) {
610 if (bank->eint_type != EINT_TYPE_WKUP)
611 continue;
612
613 bank->irq_chip = devm_kmemdup(dev, src: irq_chip, len: sizeof(*irq_chip),
614 GFP_KERNEL);
615 if (!bank->irq_chip) {
616 of_node_put(node: wkup_np);
617 return -ENOMEM;
618 }
619 bank->irq_chip->chip.name = bank->name;
620
621 bank->irq_domain = irq_domain_create_linear(fwnode: bank->fwnode,
622 size: bank->nr_pins, ops: &exynos_eint_irqd_ops, host_data: bank);
623 if (!bank->irq_domain) {
624 dev_err(dev, "wkup irq domain add failed\n");
625 of_node_put(node: wkup_np);
626 return -ENXIO;
627 }
628
629 if (!fwnode_property_present(fwnode: bank->fwnode, propname: "interrupts")) {
630 bank->eint_type = EINT_TYPE_WKUP_MUX;
631 ++muxed_banks;
632 continue;
633 }
634
635 weint_data = devm_kcalloc(dev,
636 n: bank->nr_pins, size: sizeof(*weint_data),
637 GFP_KERNEL);
638 if (!weint_data) {
639 of_node_put(node: wkup_np);
640 return -ENOMEM;
641 }
642
643 for (idx = 0; idx < bank->nr_pins; ++idx) {
644 irq = irq_of_parse_and_map(to_of_node(bank->fwnode), index: idx);
645 if (!irq) {
646 dev_err(dev, "irq number for eint-%s-%d not found\n",
647 bank->name, idx);
648 continue;
649 }
650 weint_data[idx].irq = idx;
651 weint_data[idx].bank = bank;
652 irq_set_chained_handler_and_data(irq,
653 handle: exynos_irq_eint0_15,
654 data: &weint_data[idx]);
655 }
656 }
657
658 if (!muxed_banks) {
659 of_node_put(node: wkup_np);
660 return 0;
661 }
662
663 irq = irq_of_parse_and_map(node: wkup_np, index: 0);
664 of_node_put(node: wkup_np);
665 if (!irq) {
666 dev_err(dev, "irq number for muxed EINTs not found\n");
667 return 0;
668 }
669
670 muxed_data = devm_kzalloc(dev, size: sizeof(*muxed_data)
671 + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL);
672 if (!muxed_data)
673 return -ENOMEM;
674 muxed_data->nr_banks = muxed_banks;
675
676 irq_set_chained_handler_and_data(irq, handle: exynos_irq_demux_eint16_31,
677 data: muxed_data);
678
679 bank = d->pin_banks;
680 idx = 0;
681 for (i = 0; i < d->nr_banks; ++i, ++bank) {
682 if (bank->eint_type != EINT_TYPE_WKUP_MUX)
683 continue;
684
685 muxed_data->banks[idx++] = bank;
686 }
687
688 return 0;
689}
690
691static void exynos_pinctrl_suspend_bank(
692 struct samsung_pinctrl_drv_data *drvdata,
693 struct samsung_pin_bank *bank)
694{
695 struct exynos_eint_gpio_save *save = bank->soc_priv;
696 const void __iomem *regs = bank->eint_base;
697
698 save->eint_con = readl(addr: regs + EXYNOS_GPIO_ECON_OFFSET
699 + bank->eint_offset);
700 save->eint_fltcon0 = readl(addr: regs + EXYNOS_GPIO_EFLTCON_OFFSET
701 + 2 * bank->eint_offset);
702 save->eint_fltcon1 = readl(addr: regs + EXYNOS_GPIO_EFLTCON_OFFSET
703 + 2 * bank->eint_offset + 4);
704 save->eint_mask = readl(addr: regs + bank->irq_chip->eint_mask
705 + bank->eint_offset);
706
707 pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
708 pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0);
709 pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1);
710 pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
711}
712
713static void exynosauto_pinctrl_suspend_bank(struct samsung_pinctrl_drv_data *drvdata,
714 struct samsung_pin_bank *bank)
715{
716 struct exynos_eint_gpio_save *save = bank->soc_priv;
717 const void __iomem *regs = bank->eint_base;
718
719 save->eint_con = readl(addr: regs + bank->pctl_offset + bank->eint_con_offset);
720 save->eint_mask = readl(addr: regs + bank->pctl_offset + bank->eint_mask_offset);
721
722 pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
723 pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
724}
725
726void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
727{
728 struct samsung_pin_bank *bank = drvdata->pin_banks;
729 struct exynos_irq_chip *irq_chip = NULL;
730 int i;
731
732 for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {
733 if (bank->eint_type == EINT_TYPE_GPIO) {
734 if (bank->eint_con_offset)
735 exynosauto_pinctrl_suspend_bank(drvdata, bank);
736 else
737 exynos_pinctrl_suspend_bank(drvdata, bank);
738 }
739 else if (bank->eint_type == EINT_TYPE_WKUP) {
740 if (!irq_chip) {
741 irq_chip = bank->irq_chip;
742 irq_chip->set_eint_wakeup_mask(drvdata,
743 irq_chip);
744 }
745 }
746 }
747}
748
749static void exynos_pinctrl_resume_bank(
750 struct samsung_pinctrl_drv_data *drvdata,
751 struct samsung_pin_bank *bank)
752{
753 struct exynos_eint_gpio_save *save = bank->soc_priv;
754 void __iomem *regs = bank->eint_base;
755
756 pr_debug("%s: con %#010x => %#010x\n", bank->name,
757 readl(regs + EXYNOS_GPIO_ECON_OFFSET
758 + bank->eint_offset), save->eint_con);
759 pr_debug("%s: fltcon0 %#010x => %#010x\n", bank->name,
760 readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
761 + 2 * bank->eint_offset), save->eint_fltcon0);
762 pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name,
763 readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
764 + 2 * bank->eint_offset + 4), save->eint_fltcon1);
765 pr_debug("%s: mask %#010x => %#010x\n", bank->name,
766 readl(regs + bank->irq_chip->eint_mask
767 + bank->eint_offset), save->eint_mask);
768
769 writel(val: save->eint_con, addr: regs + EXYNOS_GPIO_ECON_OFFSET
770 + bank->eint_offset);
771 writel(val: save->eint_fltcon0, addr: regs + EXYNOS_GPIO_EFLTCON_OFFSET
772 + 2 * bank->eint_offset);
773 writel(val: save->eint_fltcon1, addr: regs + EXYNOS_GPIO_EFLTCON_OFFSET
774 + 2 * bank->eint_offset + 4);
775 writel(val: save->eint_mask, addr: regs + bank->irq_chip->eint_mask
776 + bank->eint_offset);
777}
778
779static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvdata,
780 struct samsung_pin_bank *bank)
781{
782 struct exynos_eint_gpio_save *save = bank->soc_priv;
783 void __iomem *regs = bank->eint_base;
784
785 pr_debug("%s: con %#010x => %#010x\n", bank->name,
786 readl(regs + bank->pctl_offset + bank->eint_con_offset), save->eint_con);
787 pr_debug("%s: mask %#010x => %#010x\n", bank->name,
788 readl(regs + bank->pctl_offset + bank->eint_mask_offset), save->eint_mask);
789
790 writel(val: save->eint_con, addr: regs + bank->pctl_offset + bank->eint_con_offset);
791 writel(val: save->eint_mask, addr: regs + bank->pctl_offset + bank->eint_mask_offset);
792}
793
794void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
795{
796 struct samsung_pin_bank *bank = drvdata->pin_banks;
797 int i;
798
799 for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
800 if (bank->eint_type == EINT_TYPE_GPIO) {
801 if (bank->eint_con_offset)
802 exynosauto_pinctrl_resume_bank(drvdata, bank);
803 else
804 exynos_pinctrl_resume_bank(drvdata, bank);
805 }
806}
807
808static void exynos_retention_enable(struct samsung_pinctrl_drv_data *drvdata)
809{
810 if (drvdata->retention_ctrl->refcnt)
811 atomic_inc(v: drvdata->retention_ctrl->refcnt);
812}
813
814static void exynos_retention_disable(struct samsung_pinctrl_drv_data *drvdata)
815{
816 struct samsung_retention_ctrl *ctrl = drvdata->retention_ctrl;
817 struct regmap *pmu_regs = ctrl->priv;
818 int i;
819
820 if (ctrl->refcnt && !atomic_dec_and_test(v: ctrl->refcnt))
821 return;
822
823 for (i = 0; i < ctrl->nr_regs; i++)
824 regmap_write(map: pmu_regs, reg: ctrl->regs[i], val: ctrl->value);
825}
826
827struct samsung_retention_ctrl *
828exynos_retention_init(struct samsung_pinctrl_drv_data *drvdata,
829 const struct samsung_retention_data *data)
830{
831 struct samsung_retention_ctrl *ctrl;
832 struct regmap *pmu_regs;
833 int i;
834
835 ctrl = devm_kzalloc(dev: drvdata->dev, size: sizeof(*ctrl), GFP_KERNEL);
836 if (!ctrl)
837 return ERR_PTR(error: -ENOMEM);
838
839 pmu_regs = exynos_get_pmu_regmap();
840 if (IS_ERR(ptr: pmu_regs))
841 return ERR_CAST(ptr: pmu_regs);
842
843 ctrl->priv = pmu_regs;
844 ctrl->regs = data->regs;
845 ctrl->nr_regs = data->nr_regs;
846 ctrl->value = data->value;
847 ctrl->refcnt = data->refcnt;
848 ctrl->enable = exynos_retention_enable;
849 ctrl->disable = exynos_retention_disable;
850
851 /* Ensure that retention is disabled on driver init */
852 for (i = 0; i < ctrl->nr_regs; i++)
853 regmap_write(map: pmu_regs, reg: ctrl->regs[i], val: ctrl->value);
854
855 return ctrl;
856}
857

source code of linux/drivers/pinctrl/samsung/pinctrl-exynos.c