Lines Matching +full:exynos4210 +full:- +full:wakeup +full:- +full:eint
1 // SPDX-License-Identifier: GPL-2.0+
3 // Exynos specific support for Samsung pinctrl/gpiolib driver with eint support.
14 // external gpio and wakeup interrupt support.
27 #include <linux/soc/samsung/exynos-pmu.h>
28 #include <linux/soc/samsung/exynos-regs-pmu.h>
30 #include "pinctrl-samsung.h"
31 #include "pinctrl-exynos.h"
55 unsigned long reg_mask = our_chip->eint_mask + bank->eint_offset; in exynos_irq_mask()
59 raw_spin_lock_irqsave(&bank->slock, flags); in exynos_irq_mask()
61 mask = readl(bank->eint_base + reg_mask); in exynos_irq_mask()
62 mask |= 1 << irqd->hwirq; in exynos_irq_mask()
63 writel(mask, bank->eint_base + reg_mask); in exynos_irq_mask()
65 raw_spin_unlock_irqrestore(&bank->slock, flags); in exynos_irq_mask()
73 unsigned long reg_pend = our_chip->eint_pend + bank->eint_offset; in exynos_irq_ack()
75 writel(1 << irqd->hwirq, bank->eint_base + reg_pend); in exynos_irq_ack()
83 unsigned long reg_mask = our_chip->eint_mask + bank->eint_offset; in exynos_irq_unmask()
90 * If we don't do this we'll get a double-interrupt. Level triggered in exynos_irq_unmask()
98 raw_spin_lock_irqsave(&bank->slock, flags); in exynos_irq_unmask()
100 mask = readl(bank->eint_base + reg_mask); in exynos_irq_unmask()
101 mask &= ~(1 << irqd->hwirq); in exynos_irq_unmask()
102 writel(mask, bank->eint_base + reg_mask); in exynos_irq_unmask()
104 raw_spin_unlock_irqrestore(&bank->slock, flags); in exynos_irq_unmask()
112 unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq; in exynos_irq_set_type()
114 unsigned long reg_con = our_chip->eint_con + bank->eint_offset; in exynos_irq_set_type()
134 return -EINVAL; in exynos_irq_set_type()
142 con = readl(bank->eint_base + reg_con); in exynos_irq_set_type()
145 writel(con, bank->eint_base + reg_con); in exynos_irq_set_type()
153 const struct samsung_pin_bank_type *bank_type = bank->type; in exynos_irq_request_resources()
158 ret = gpiochip_lock_as_irq(&bank->gpio_chip, irqd->hwirq); in exynos_irq_request_resources()
160 dev_err(bank->gpio_chip.parent, in exynos_irq_request_resources()
161 "unable to lock pin %s-%lu IRQ\n", in exynos_irq_request_resources()
162 bank->name, irqd->hwirq); in exynos_irq_request_resources()
166 reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC]; in exynos_irq_request_resources()
167 shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC]; in exynos_irq_request_resources()
168 mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1; in exynos_irq_request_resources()
170 raw_spin_lock_irqsave(&bank->slock, flags); in exynos_irq_request_resources()
172 con = readl(bank->pctl_base + reg_con); in exynos_irq_request_resources()
175 writel(con, bank->pctl_base + reg_con); in exynos_irq_request_resources()
177 raw_spin_unlock_irqrestore(&bank->slock, flags); in exynos_irq_request_resources()
185 const struct samsung_pin_bank_type *bank_type = bank->type; in exynos_irq_release_resources()
189 reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC]; in exynos_irq_release_resources()
190 shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC]; in exynos_irq_release_resources()
191 mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1; in exynos_irq_release_resources()
193 raw_spin_lock_irqsave(&bank->slock, flags); in exynos_irq_release_resources()
195 con = readl(bank->pctl_base + reg_con); in exynos_irq_release_resources()
198 writel(con, bank->pctl_base + reg_con); in exynos_irq_release_resources()
200 raw_spin_unlock_irqrestore(&bank->slock, flags); in exynos_irq_release_resources()
202 gpiochip_unlock_as_irq(&bank->gpio_chip, irqd->hwirq); in exynos_irq_release_resources()
227 struct samsung_pin_bank *b = h->host_data; in exynos_eint_irq_map()
230 irq_set_chip_and_handler(virq, &b->irq_chip->chip, in exynos_eint_irq_map()
236 * irq domain callbacks for external gpio and wakeup interrupt controllers.
246 struct samsung_pin_bank *bank = d->pin_banks; in exynos_eint_gpio_irq()
250 svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET); in exynos_eint_gpio_irq()
256 bank += (group - 1); in exynos_eint_gpio_irq()
258 ret = generic_handle_domain_irq(bank->irq_domain, pin); in exynos_eint_gpio_irq()
273 * exynos_eint_gpio_init() - setup handling of external gpio interrupts.
279 struct device *dev = d->dev; in exynos_eint_gpio_init()
283 if (!d->irq) { in exynos_eint_gpio_init()
285 return -EINVAL; in exynos_eint_gpio_init()
288 ret = devm_request_irq(dev, d->irq, exynos_eint_gpio_irq, in exynos_eint_gpio_init()
292 return -ENXIO; in exynos_eint_gpio_init()
295 bank = d->pin_banks; in exynos_eint_gpio_init()
296 for (i = 0; i < d->nr_banks; ++i, ++bank) { in exynos_eint_gpio_init()
297 if (bank->eint_type != EINT_TYPE_GPIO) in exynos_eint_gpio_init()
300 bank->irq_chip = devm_kmemdup(dev, &exynos_gpio_irq_chip, in exynos_eint_gpio_init()
301 sizeof(*bank->irq_chip), GFP_KERNEL); in exynos_eint_gpio_init()
302 if (!bank->irq_chip) { in exynos_eint_gpio_init()
303 ret = -ENOMEM; in exynos_eint_gpio_init()
306 bank->irq_chip->chip.name = bank->name; in exynos_eint_gpio_init()
308 bank->irq_domain = irq_domain_create_linear(bank->fwnode, in exynos_eint_gpio_init()
309 bank->nr_pins, &exynos_eint_irqd_ops, bank); in exynos_eint_gpio_init()
310 if (!bank->irq_domain) { in exynos_eint_gpio_init()
312 ret = -ENXIO; in exynos_eint_gpio_init()
316 bank->soc_priv = devm_kzalloc(d->dev, in exynos_eint_gpio_init()
318 if (!bank->soc_priv) { in exynos_eint_gpio_init()
319 irq_domain_remove(bank->irq_domain); in exynos_eint_gpio_init()
320 ret = -ENOMEM; in exynos_eint_gpio_init()
329 for (--i, --bank; i >= 0; --i, --bank) { in exynos_eint_gpio_init()
330 if (bank->eint_type != EINT_TYPE_GPIO) in exynos_eint_gpio_init()
332 irq_domain_remove(bank->irq_domain); in exynos_eint_gpio_init()
343 unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq); in exynos_wkup_irq_set_wake()
345 pr_info("wake %s for irq %u (%s-%lu)\n", on ? "enabled" : "disabled", in exynos_wkup_irq_set_wake()
346 irqd->irq, bank->name, irqd->hwirq); in exynos_wkup_irq_set_wake()
349 *our_chip->eint_wake_mask_value |= bit; in exynos_wkup_irq_set_wake()
351 *our_chip->eint_wake_mask_value &= ~bit; in exynos_wkup_irq_set_wake()
362 if (!drvdata->retention_ctrl || !drvdata->retention_ctrl->priv) { in exynos_pinctrl_set_eint_wakeup_mask()
363 dev_warn(drvdata->dev, in exynos_pinctrl_set_eint_wakeup_mask()
364 …"No retention data configured bank with external wakeup interrupt. Wake-up mask will not be set.\n… in exynos_pinctrl_set_eint_wakeup_mask()
368 pmu_regs = drvdata->retention_ctrl->priv; in exynos_pinctrl_set_eint_wakeup_mask()
369 dev_info(drvdata->dev, in exynos_pinctrl_set_eint_wakeup_mask()
370 "Setting external wakeup interrupt mask: 0x%x\n", in exynos_pinctrl_set_eint_wakeup_mask()
371 *irq_chip->eint_wake_mask_value); in exynos_pinctrl_set_eint_wakeup_mask()
373 regmap_write(pmu_regs, irq_chip->eint_wake_mask_reg, in exynos_pinctrl_set_eint_wakeup_mask()
374 *irq_chip->eint_wake_mask_value); in exynos_pinctrl_set_eint_wakeup_mask()
384 if (!drvdata->retention_ctrl || !drvdata->retention_ctrl->priv) { in s5pv210_pinctrl_set_eint_wakeup_mask()
385 dev_warn(drvdata->dev, in s5pv210_pinctrl_set_eint_wakeup_mask()
386 …"No retention data configured bank with external wakeup interrupt. Wake-up mask will not be set.\n… in s5pv210_pinctrl_set_eint_wakeup_mask()
391 clk_base = (void __iomem *) drvdata->retention_ctrl->priv; in s5pv210_pinctrl_set_eint_wakeup_mask()
393 __raw_writel(*irq_chip->eint_wake_mask_value, in s5pv210_pinctrl_set_eint_wakeup_mask()
394 clk_base + irq_chip->eint_wake_mask_reg); in s5pv210_pinctrl_set_eint_wakeup_mask()
399 * irq_chip for wakeup interrupts
459 /* list of external wakeup controllers supported */
461 { .compatible = "samsung,s5pv210-wakeup-eint",
463 { .compatible = "samsung,exynos4210-wakeup-eint",
465 { .compatible = "samsung,exynos7-wakeup-eint",
467 { .compatible = "samsung,exynos850-wakeup-eint",
469 { .compatible = "samsung,exynosautov9-wakeup-eint",
474 /* interrupt handler for wakeup interrupts 0..15 */
478 struct samsung_pin_bank *bank = eintd->bank; in exynos_irq_eint0_15()
483 generic_handle_domain_irq(bank->irq_domain, eintd->irq); in exynos_irq_eint0_15()
494 irq = fls(pend) - 1; in exynos_irq_demux_eint()
500 /* interrupt handler for wakeup interrupt 16 */
511 for (i = 0; i < eintd->nr_banks; ++i) { in exynos_irq_demux_eint16_31()
512 struct samsung_pin_bank *b = eintd->banks[i]; in exynos_irq_demux_eint16_31()
513 pend = readl(b->eint_base + b->irq_chip->eint_pend in exynos_irq_demux_eint16_31()
514 + b->eint_offset); in exynos_irq_demux_eint16_31()
515 mask = readl(b->eint_base + b->irq_chip->eint_mask in exynos_irq_demux_eint16_31()
516 + b->eint_offset); in exynos_irq_demux_eint16_31()
517 exynos_irq_demux_eint(pend & ~mask, b->irq_domain); in exynos_irq_demux_eint16_31()
524 * exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
529 struct device *dev = d->dev; in exynos_eint_wkup_init()
540 for_each_child_of_node(dev->of_node, np) { in exynos_eint_wkup_init()
545 irq_chip = match->data; in exynos_eint_wkup_init()
551 return -ENODEV; in exynos_eint_wkup_init()
553 bank = d->pin_banks; in exynos_eint_wkup_init()
554 for (i = 0; i < d->nr_banks; ++i, ++bank) { in exynos_eint_wkup_init()
555 if (bank->eint_type != EINT_TYPE_WKUP) in exynos_eint_wkup_init()
558 bank->irq_chip = devm_kmemdup(dev, irq_chip, sizeof(*irq_chip), in exynos_eint_wkup_init()
560 if (!bank->irq_chip) { in exynos_eint_wkup_init()
562 return -ENOMEM; in exynos_eint_wkup_init()
564 bank->irq_chip->chip.name = bank->name; in exynos_eint_wkup_init()
566 bank->irq_domain = irq_domain_create_linear(bank->fwnode, in exynos_eint_wkup_init()
567 bank->nr_pins, &exynos_eint_irqd_ops, bank); in exynos_eint_wkup_init()
568 if (!bank->irq_domain) { in exynos_eint_wkup_init()
571 return -ENXIO; in exynos_eint_wkup_init()
574 if (!fwnode_property_present(bank->fwnode, "interrupts")) { in exynos_eint_wkup_init()
575 bank->eint_type = EINT_TYPE_WKUP_MUX; in exynos_eint_wkup_init()
581 bank->nr_pins, sizeof(*weint_data), in exynos_eint_wkup_init()
585 return -ENOMEM; in exynos_eint_wkup_init()
588 for (idx = 0; idx < bank->nr_pins; ++idx) { in exynos_eint_wkup_init()
589 irq = irq_of_parse_and_map(to_of_node(bank->fwnode), idx); in exynos_eint_wkup_init()
591 dev_err(dev, "irq number for eint-%s-%d not found\n", in exynos_eint_wkup_init()
592 bank->name, idx); in exynos_eint_wkup_init()
618 return -ENOMEM; in exynos_eint_wkup_init()
623 bank = d->pin_banks; in exynos_eint_wkup_init()
625 for (i = 0; i < d->nr_banks; ++i, ++bank) { in exynos_eint_wkup_init()
626 if (bank->eint_type != EINT_TYPE_WKUP_MUX) in exynos_eint_wkup_init()
629 muxed_data->banks[idx++] = bank; in exynos_eint_wkup_init()
631 muxed_data->nr_banks = muxed_banks; in exynos_eint_wkup_init()
640 struct exynos_eint_gpio_save *save = bank->soc_priv; in exynos_pinctrl_suspend_bank()
641 void __iomem *regs = bank->eint_base; in exynos_pinctrl_suspend_bank()
643 save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET in exynos_pinctrl_suspend_bank()
644 + bank->eint_offset); in exynos_pinctrl_suspend_bank()
645 save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET in exynos_pinctrl_suspend_bank()
646 + 2 * bank->eint_offset); in exynos_pinctrl_suspend_bank()
647 save->eint_fltcon1 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET in exynos_pinctrl_suspend_bank()
648 + 2 * bank->eint_offset + 4); in exynos_pinctrl_suspend_bank()
649 save->eint_mask = readl(regs + bank->irq_chip->eint_mask in exynos_pinctrl_suspend_bank()
650 + bank->eint_offset); in exynos_pinctrl_suspend_bank()
652 pr_debug("%s: save con %#010x\n", bank->name, save->eint_con); in exynos_pinctrl_suspend_bank()
653 pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0); in exynos_pinctrl_suspend_bank()
654 pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1); in exynos_pinctrl_suspend_bank()
655 pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask); in exynos_pinctrl_suspend_bank()
660 struct samsung_pin_bank *bank = drvdata->pin_banks; in exynos_pinctrl_suspend()
664 for (i = 0; i < drvdata->nr_banks; ++i, ++bank) { in exynos_pinctrl_suspend()
665 if (bank->eint_type == EINT_TYPE_GPIO) in exynos_pinctrl_suspend()
667 else if (bank->eint_type == EINT_TYPE_WKUP) { in exynos_pinctrl_suspend()
669 irq_chip = bank->irq_chip; in exynos_pinctrl_suspend()
670 irq_chip->set_eint_wakeup_mask(drvdata, in exynos_pinctrl_suspend()
681 struct exynos_eint_gpio_save *save = bank->soc_priv; in exynos_pinctrl_resume_bank()
682 void __iomem *regs = bank->eint_base; in exynos_pinctrl_resume_bank()
684 pr_debug("%s: con %#010x => %#010x\n", bank->name, in exynos_pinctrl_resume_bank()
686 + bank->eint_offset), save->eint_con); in exynos_pinctrl_resume_bank()
687 pr_debug("%s: fltcon0 %#010x => %#010x\n", bank->name, in exynos_pinctrl_resume_bank()
689 + 2 * bank->eint_offset), save->eint_fltcon0); in exynos_pinctrl_resume_bank()
690 pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name, in exynos_pinctrl_resume_bank()
692 + 2 * bank->eint_offset + 4), save->eint_fltcon1); in exynos_pinctrl_resume_bank()
693 pr_debug("%s: mask %#010x => %#010x\n", bank->name, in exynos_pinctrl_resume_bank()
694 readl(regs + bank->irq_chip->eint_mask in exynos_pinctrl_resume_bank()
695 + bank->eint_offset), save->eint_mask); in exynos_pinctrl_resume_bank()
697 writel(save->eint_con, regs + EXYNOS_GPIO_ECON_OFFSET in exynos_pinctrl_resume_bank()
698 + bank->eint_offset); in exynos_pinctrl_resume_bank()
699 writel(save->eint_fltcon0, regs + EXYNOS_GPIO_EFLTCON_OFFSET in exynos_pinctrl_resume_bank()
700 + 2 * bank->eint_offset); in exynos_pinctrl_resume_bank()
701 writel(save->eint_fltcon1, regs + EXYNOS_GPIO_EFLTCON_OFFSET in exynos_pinctrl_resume_bank()
702 + 2 * bank->eint_offset + 4); in exynos_pinctrl_resume_bank()
703 writel(save->eint_mask, regs + bank->irq_chip->eint_mask in exynos_pinctrl_resume_bank()
704 + bank->eint_offset); in exynos_pinctrl_resume_bank()
709 struct samsung_pin_bank *bank = drvdata->pin_banks; in exynos_pinctrl_resume()
712 for (i = 0; i < drvdata->nr_banks; ++i, ++bank) in exynos_pinctrl_resume()
713 if (bank->eint_type == EINT_TYPE_GPIO) in exynos_pinctrl_resume()
719 if (drvdata->retention_ctrl->refcnt) in exynos_retention_enable()
720 atomic_inc(drvdata->retention_ctrl->refcnt); in exynos_retention_enable()
725 struct samsung_retention_ctrl *ctrl = drvdata->retention_ctrl; in exynos_retention_disable()
726 struct regmap *pmu_regs = ctrl->priv; in exynos_retention_disable()
729 if (ctrl->refcnt && !atomic_dec_and_test(ctrl->refcnt)) in exynos_retention_disable()
732 for (i = 0; i < ctrl->nr_regs; i++) in exynos_retention_disable()
733 regmap_write(pmu_regs, ctrl->regs[i], ctrl->value); in exynos_retention_disable()
744 ctrl = devm_kzalloc(drvdata->dev, sizeof(*ctrl), GFP_KERNEL); in exynos_retention_init()
746 return ERR_PTR(-ENOMEM); in exynos_retention_init()
752 ctrl->priv = pmu_regs; in exynos_retention_init()
753 ctrl->regs = data->regs; in exynos_retention_init()
754 ctrl->nr_regs = data->nr_regs; in exynos_retention_init()
755 ctrl->value = data->value; in exynos_retention_init()
756 ctrl->refcnt = data->refcnt; in exynos_retention_init()
757 ctrl->enable = exynos_retention_enable; in exynos_retention_init()
758 ctrl->disable = exynos_retention_disable; in exynos_retention_init()
761 for (i = 0; i < ctrl->nr_regs; i++) in exynos_retention_init()
762 regmap_write(pmu_regs, ctrl->regs[i], ctrl->value); in exynos_retention_init()