diff options
author | Marcin Niestroj <m.niestroj@grinn-global.com> | 2016-09-16 05:26:28 -0400 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2016-09-21 15:46:04 -0400 |
commit | 97ea1906b3c2201273ea6bb40c43c611c056ddb3 (patch) | |
tree | 71548d748629fe2f6b63e2ea9b92b007a6bbdeb9 /drivers/rtc/rtc-omap.c | |
parent | 970fc7f4afd52d638d88aeda985ea03ccd33acee (diff) |
rtc: omap: Support ext_wakeup configuration
Support configuration of ext_wakeup sources. This patch makes it
possible to enable ext_wakeup and set it's polarity, depending on board
configuration. AM335x's dedicated PMIC (tps65217) uses ext_wakeup to
notify about power-button presses. Handling power-button presses enables
to recover from RTC-only power states correctly.
Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc/rtc-omap.c')
-rw-r--r-- | drivers/rtc/rtc-omap.c | 168 |
1 files changed, 160 insertions, 8 deletions
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index cadac8e2aa6b..b04ea9b5ae67 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
@@ -13,19 +13,23 @@ | |||
13 | * 2 of the License, or (at your option) any later version. | 13 | * 2 of the License, or (at your option) any later version. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <dt-bindings/gpio/gpio.h> |
17 | #include <linux/bcd.h> | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/delay.h> | ||
17 | #include <linux/init.h> | 20 | #include <linux/init.h> |
18 | #include <linux/module.h> | 21 | #include <linux/io.h> |
19 | #include <linux/ioport.h> | 22 | #include <linux/ioport.h> |
20 | #include <linux/delay.h> | 23 | #include <linux/kernel.h> |
21 | #include <linux/rtc.h> | 24 | #include <linux/module.h> |
22 | #include <linux/bcd.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/of.h> | 25 | #include <linux/of.h> |
25 | #include <linux/of_device.h> | 26 | #include <linux/of_device.h> |
27 | #include <linux/pinctrl/pinctrl.h> | ||
28 | #include <linux/pinctrl/pinconf.h> | ||
29 | #include <linux/pinctrl/pinconf-generic.h> | ||
30 | #include <linux/platform_device.h> | ||
26 | #include <linux/pm_runtime.h> | 31 | #include <linux/pm_runtime.h> |
27 | #include <linux/io.h> | 32 | #include <linux/rtc.h> |
28 | #include <linux/clk.h> | ||
29 | 33 | ||
30 | /* | 34 | /* |
31 | * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock | 35 | * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock |
@@ -115,6 +119,8 @@ | |||
115 | 119 | ||
116 | /* OMAP_RTC_PMIC bit fields: */ | 120 | /* OMAP_RTC_PMIC bit fields: */ |
117 | #define OMAP_RTC_PMIC_POWER_EN_EN BIT(16) | 121 | #define OMAP_RTC_PMIC_POWER_EN_EN BIT(16) |
122 | #define OMAP_RTC_PMIC_EXT_WKUP_EN(x) BIT(x) | ||
123 | #define OMAP_RTC_PMIC_EXT_WKUP_POL(x) BIT(4 + x) | ||
118 | 124 | ||
119 | /* OMAP_RTC_KICKER values */ | 125 | /* OMAP_RTC_KICKER values */ |
120 | #define KICK0_VALUE 0x83e70b13 | 126 | #define KICK0_VALUE 0x83e70b13 |
@@ -141,6 +147,7 @@ struct omap_rtc { | |||
141 | bool is_pmic_controller; | 147 | bool is_pmic_controller; |
142 | bool has_ext_clk; | 148 | bool has_ext_clk; |
143 | const struct omap_rtc_device_type *type; | 149 | const struct omap_rtc_device_type *type; |
150 | struct pinctrl_dev *pctldev; | ||
144 | }; | 151 | }; |
145 | 152 | ||
146 | static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg) | 153 | static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg) |
@@ -525,6 +532,139 @@ static const struct of_device_id omap_rtc_of_match[] = { | |||
525 | }; | 532 | }; |
526 | MODULE_DEVICE_TABLE(of, omap_rtc_of_match); | 533 | MODULE_DEVICE_TABLE(of, omap_rtc_of_match); |
527 | 534 | ||
535 | static const struct pinctrl_pin_desc rtc_pins_desc[] = { | ||
536 | PINCTRL_PIN(0, "ext_wakeup0"), | ||
537 | PINCTRL_PIN(1, "ext_wakeup1"), | ||
538 | PINCTRL_PIN(2, "ext_wakeup2"), | ||
539 | PINCTRL_PIN(3, "ext_wakeup3"), | ||
540 | }; | ||
541 | |||
542 | static int rtc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) | ||
543 | { | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static const char *rtc_pinctrl_get_group_name(struct pinctrl_dev *pctldev, | ||
548 | unsigned int group) | ||
549 | { | ||
550 | return NULL; | ||
551 | } | ||
552 | |||
553 | static const struct pinctrl_ops rtc_pinctrl_ops = { | ||
554 | .get_groups_count = rtc_pinctrl_get_groups_count, | ||
555 | .get_group_name = rtc_pinctrl_get_group_name, | ||
556 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, | ||
557 | .dt_free_map = pinconf_generic_dt_free_map, | ||
558 | }; | ||
559 | |||
560 | enum rtc_pin_config_param { | ||
561 | PIN_CONFIG_ACTIVE_HIGH = PIN_CONFIG_END + 1, | ||
562 | }; | ||
563 | |||
564 | static const struct pinconf_generic_params rtc_params[] = { | ||
565 | {"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0}, | ||
566 | }; | ||
567 | |||
568 | #ifdef CONFIG_DEBUG_FS | ||
569 | static const struct pin_config_item rtc_conf_items[ARRAY_SIZE(rtc_params)] = { | ||
570 | PCONFDUMP(PIN_CONFIG_ACTIVE_HIGH, "input active high", NULL, false), | ||
571 | }; | ||
572 | #endif | ||
573 | |||
574 | static int rtc_pinconf_get(struct pinctrl_dev *pctldev, | ||
575 | unsigned int pin, unsigned long *config) | ||
576 | { | ||
577 | struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev); | ||
578 | unsigned int param = pinconf_to_config_param(*config); | ||
579 | u32 val; | ||
580 | u16 arg = 0; | ||
581 | |||
582 | rtc->type->unlock(rtc); | ||
583 | val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); | ||
584 | rtc->type->lock(rtc); | ||
585 | |||
586 | switch (param) { | ||
587 | case PIN_CONFIG_INPUT_ENABLE: | ||
588 | if (!(val & OMAP_RTC_PMIC_EXT_WKUP_EN(pin))) | ||
589 | return -EINVAL; | ||
590 | break; | ||
591 | case PIN_CONFIG_ACTIVE_HIGH: | ||
592 | if (val & OMAP_RTC_PMIC_EXT_WKUP_POL(pin)) | ||
593 | return -EINVAL; | ||
594 | break; | ||
595 | default: | ||
596 | return -ENOTSUPP; | ||
597 | }; | ||
598 | |||
599 | *config = pinconf_to_config_packed(param, arg); | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | static int rtc_pinconf_set(struct pinctrl_dev *pctldev, | ||
605 | unsigned int pin, unsigned long *configs, | ||
606 | unsigned int num_configs) | ||
607 | { | ||
608 | struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev); | ||
609 | u32 val; | ||
610 | unsigned int param; | ||
611 | u16 param_val; | ||
612 | int i; | ||
613 | |||
614 | rtc->type->unlock(rtc); | ||
615 | val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); | ||
616 | rtc->type->lock(rtc); | ||
617 | |||
618 | /* active low by default */ | ||
619 | val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin); | ||
620 | |||
621 | for (i = 0; i < num_configs; i++) { | ||
622 | param = pinconf_to_config_param(configs[i]); | ||
623 | param_val = pinconf_to_config_argument(configs[i]); | ||
624 | |||
625 | switch (param) { | ||
626 | case PIN_CONFIG_INPUT_ENABLE: | ||
627 | if (param_val) | ||
628 | val |= OMAP_RTC_PMIC_EXT_WKUP_EN(pin); | ||
629 | else | ||
630 | val &= ~OMAP_RTC_PMIC_EXT_WKUP_EN(pin); | ||
631 | break; | ||
632 | case PIN_CONFIG_ACTIVE_HIGH: | ||
633 | val &= ~OMAP_RTC_PMIC_EXT_WKUP_POL(pin); | ||
634 | break; | ||
635 | default: | ||
636 | dev_err(&rtc->rtc->dev, "Property %u not supported\n", | ||
637 | param); | ||
638 | return -ENOTSUPP; | ||
639 | } | ||
640 | } | ||
641 | |||
642 | rtc->type->unlock(rtc); | ||
643 | rtc_writel(rtc, OMAP_RTC_PMIC_REG, val); | ||
644 | rtc->type->lock(rtc); | ||
645 | |||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | static const struct pinconf_ops rtc_pinconf_ops = { | ||
650 | .is_generic = true, | ||
651 | .pin_config_get = rtc_pinconf_get, | ||
652 | .pin_config_set = rtc_pinconf_set, | ||
653 | }; | ||
654 | |||
655 | static struct pinctrl_desc rtc_pinctrl_desc = { | ||
656 | .pins = rtc_pins_desc, | ||
657 | .npins = ARRAY_SIZE(rtc_pins_desc), | ||
658 | .pctlops = &rtc_pinctrl_ops, | ||
659 | .confops = &rtc_pinconf_ops, | ||
660 | .custom_params = rtc_params, | ||
661 | .num_custom_params = ARRAY_SIZE(rtc_params), | ||
662 | #ifdef CONFIG_DEBUG_FS | ||
663 | .custom_conf_items = rtc_conf_items, | ||
664 | #endif | ||
665 | .owner = THIS_MODULE, | ||
666 | }; | ||
667 | |||
528 | static int omap_rtc_probe(struct platform_device *pdev) | 668 | static int omap_rtc_probe(struct platform_device *pdev) |
529 | { | 669 | { |
530 | struct omap_rtc *rtc; | 670 | struct omap_rtc *rtc; |
@@ -681,6 +821,15 @@ static int omap_rtc_probe(struct platform_device *pdev) | |||
681 | } | 821 | } |
682 | } | 822 | } |
683 | 823 | ||
824 | /* Support ext_wakeup pinconf */ | ||
825 | rtc_pinctrl_desc.name = dev_name(&pdev->dev); | ||
826 | |||
827 | rtc->pctldev = pinctrl_register(&rtc_pinctrl_desc, &pdev->dev, rtc); | ||
828 | if (IS_ERR(rtc->pctldev)) { | ||
829 | dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); | ||
830 | return PTR_ERR(rtc->pctldev); | ||
831 | } | ||
832 | |||
684 | return 0; | 833 | return 0; |
685 | 834 | ||
686 | err: | 835 | err: |
@@ -724,6 +873,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) | |||
724 | pm_runtime_put_sync(&pdev->dev); | 873 | pm_runtime_put_sync(&pdev->dev); |
725 | pm_runtime_disable(&pdev->dev); | 874 | pm_runtime_disable(&pdev->dev); |
726 | 875 | ||
876 | /* Remove ext_wakeup pinconf */ | ||
877 | pinctrl_unregister(rtc->pctldev); | ||
878 | |||
727 | return 0; | 879 | return 0; |
728 | } | 880 | } |
729 | 881 | ||