forked from luck/tmp_suning_uos_patched
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>
This commit is contained in:
parent
970fc7f4af
commit
97ea1906b3
@ -18,6 +18,18 @@ Optional properties:
|
|||||||
through pmic_power_en
|
through pmic_power_en
|
||||||
- clocks: Any internal or external clocks feeding in to rtc
|
- clocks: Any internal or external clocks feeding in to rtc
|
||||||
- clock-names: Corresponding names of the clocks
|
- clock-names: Corresponding names of the clocks
|
||||||
|
- pinctrl-0: a phandle pointing to the pin settings for the device
|
||||||
|
- pinctrl-names: should be "default"
|
||||||
|
|
||||||
|
Optional subnodes:
|
||||||
|
- generic pinctrl node
|
||||||
|
|
||||||
|
Required pinctrl subnodes properties:
|
||||||
|
- pins - Names of ext_wakeup pins to configure
|
||||||
|
|
||||||
|
Optional pinctrl subnodes properties:
|
||||||
|
- input-enable - Enables ext_wakeup
|
||||||
|
- ti,active-high - Set input active high (by default active low)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -30,4 +42,13 @@ rtc@1c23000 {
|
|||||||
system-power-controller;
|
system-power-controller;
|
||||||
clocks = <&clk_32k_rtc>, <&clk_32768_ck>;
|
clocks = <&clk_32k_rtc>, <&clk_32768_ck>;
|
||||||
clock-names = "ext-clk", "int-clk";
|
clock-names = "ext-clk", "int-clk";
|
||||||
|
|
||||||
|
pinctrl-0 = <&ext_wakeup>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
|
||||||
|
ext_wakeup: ext-wakeup {
|
||||||
|
pins = "ext_wakeup0";
|
||||||
|
input-enable;
|
||||||
|
ti,active-high;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -1245,6 +1245,9 @@ config RTC_DRV_IMXDI
|
|||||||
config RTC_DRV_OMAP
|
config RTC_DRV_OMAP
|
||||||
tristate "TI OMAP Real Time Clock"
|
tristate "TI OMAP Real Time Clock"
|
||||||
depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST
|
depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST
|
||||||
|
depends on OF
|
||||||
|
depends on PINCTRL
|
||||||
|
select GENERIC_PINCONF
|
||||||
help
|
help
|
||||||
Say "yes" here to support the on chip real time clock
|
Say "yes" here to support the on chip real time clock
|
||||||
present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx.
|
present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx.
|
||||||
|
@ -13,19 +13,23 @@
|
|||||||
* 2 of the License, or (at your option) any later version.
|
* 2 of the License, or (at your option) any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/ioport.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/rtc.h>
|
|
||||||
#include <linux/bcd.h>
|
#include <linux/bcd.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/pinctrl/pinctrl.h>
|
||||||
|
#include <linux/pinctrl/pinconf.h>
|
||||||
|
#include <linux/pinctrl/pinconf-generic.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/io.h>
|
#include <linux/rtc.h>
|
||||||
#include <linux/clk.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock
|
* The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock
|
||||||
@ -115,6 +119,8 @@
|
|||||||
|
|
||||||
/* OMAP_RTC_PMIC bit fields: */
|
/* OMAP_RTC_PMIC bit fields: */
|
||||||
#define OMAP_RTC_PMIC_POWER_EN_EN BIT(16)
|
#define OMAP_RTC_PMIC_POWER_EN_EN BIT(16)
|
||||||
|
#define OMAP_RTC_PMIC_EXT_WKUP_EN(x) BIT(x)
|
||||||
|
#define OMAP_RTC_PMIC_EXT_WKUP_POL(x) BIT(4 + x)
|
||||||
|
|
||||||
/* OMAP_RTC_KICKER values */
|
/* OMAP_RTC_KICKER values */
|
||||||
#define KICK0_VALUE 0x83e70b13
|
#define KICK0_VALUE 0x83e70b13
|
||||||
@ -141,6 +147,7 @@ struct omap_rtc {
|
|||||||
bool is_pmic_controller;
|
bool is_pmic_controller;
|
||||||
bool has_ext_clk;
|
bool has_ext_clk;
|
||||||
const struct omap_rtc_device_type *type;
|
const struct omap_rtc_device_type *type;
|
||||||
|
struct pinctrl_dev *pctldev;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg)
|
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[] = {
|
|||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, omap_rtc_of_match);
|
MODULE_DEVICE_TABLE(of, omap_rtc_of_match);
|
||||||
|
|
||||||
|
static const struct pinctrl_pin_desc rtc_pins_desc[] = {
|
||||||
|
PINCTRL_PIN(0, "ext_wakeup0"),
|
||||||
|
PINCTRL_PIN(1, "ext_wakeup1"),
|
||||||
|
PINCTRL_PIN(2, "ext_wakeup2"),
|
||||||
|
PINCTRL_PIN(3, "ext_wakeup3"),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rtc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *rtc_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int group)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pinctrl_ops rtc_pinctrl_ops = {
|
||||||
|
.get_groups_count = rtc_pinctrl_get_groups_count,
|
||||||
|
.get_group_name = rtc_pinctrl_get_group_name,
|
||||||
|
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
|
||||||
|
.dt_free_map = pinconf_generic_dt_free_map,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rtc_pin_config_param {
|
||||||
|
PIN_CONFIG_ACTIVE_HIGH = PIN_CONFIG_END + 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pinconf_generic_params rtc_params[] = {
|
||||||
|
{"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
static const struct pin_config_item rtc_conf_items[ARRAY_SIZE(rtc_params)] = {
|
||||||
|
PCONFDUMP(PIN_CONFIG_ACTIVE_HIGH, "input active high", NULL, false),
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int rtc_pinconf_get(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int pin, unsigned long *config)
|
||||||
|
{
|
||||||
|
struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
unsigned int param = pinconf_to_config_param(*config);
|
||||||
|
u32 val;
|
||||||
|
u16 arg = 0;
|
||||||
|
|
||||||
|
rtc->type->unlock(rtc);
|
||||||
|
val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
|
||||||
|
rtc->type->lock(rtc);
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case PIN_CONFIG_INPUT_ENABLE:
|
||||||
|
if (!(val & OMAP_RTC_PMIC_EXT_WKUP_EN(pin)))
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_ACTIVE_HIGH:
|
||||||
|
if (val & OMAP_RTC_PMIC_EXT_WKUP_POL(pin))
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUPP;
|
||||||
|
};
|
||||||
|
|
||||||
|
*config = pinconf_to_config_packed(param, arg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rtc_pinconf_set(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int pin, unsigned long *configs,
|
||||||
|
unsigned int num_configs)
|
||||||
|
{
|
||||||
|
struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
u32 val;
|
||||||
|
unsigned int param;
|
||||||
|
u16 param_val;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
rtc->type->unlock(rtc);
|
||||||
|
val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
|
||||||
|
rtc->type->lock(rtc);
|
||||||
|
|
||||||
|
/* active low by default */
|
||||||
|
val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin);
|
||||||
|
|
||||||
|
for (i = 0; i < num_configs; i++) {
|
||||||
|
param = pinconf_to_config_param(configs[i]);
|
||||||
|
param_val = pinconf_to_config_argument(configs[i]);
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case PIN_CONFIG_INPUT_ENABLE:
|
||||||
|
if (param_val)
|
||||||
|
val |= OMAP_RTC_PMIC_EXT_WKUP_EN(pin);
|
||||||
|
else
|
||||||
|
val &= ~OMAP_RTC_PMIC_EXT_WKUP_EN(pin);
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_ACTIVE_HIGH:
|
||||||
|
val &= ~OMAP_RTC_PMIC_EXT_WKUP_POL(pin);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(&rtc->rtc->dev, "Property %u not supported\n",
|
||||||
|
param);
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc->type->unlock(rtc);
|
||||||
|
rtc_writel(rtc, OMAP_RTC_PMIC_REG, val);
|
||||||
|
rtc->type->lock(rtc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pinconf_ops rtc_pinconf_ops = {
|
||||||
|
.is_generic = true,
|
||||||
|
.pin_config_get = rtc_pinconf_get,
|
||||||
|
.pin_config_set = rtc_pinconf_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pinctrl_desc rtc_pinctrl_desc = {
|
||||||
|
.pins = rtc_pins_desc,
|
||||||
|
.npins = ARRAY_SIZE(rtc_pins_desc),
|
||||||
|
.pctlops = &rtc_pinctrl_ops,
|
||||||
|
.confops = &rtc_pinconf_ops,
|
||||||
|
.custom_params = rtc_params,
|
||||||
|
.num_custom_params = ARRAY_SIZE(rtc_params),
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
.custom_conf_items = rtc_conf_items,
|
||||||
|
#endif
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
static int omap_rtc_probe(struct platform_device *pdev)
|
static int omap_rtc_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct omap_rtc *rtc;
|
struct omap_rtc *rtc;
|
||||||
@ -681,6 +821,15 @@ static int omap_rtc_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Support ext_wakeup pinconf */
|
||||||
|
rtc_pinctrl_desc.name = dev_name(&pdev->dev);
|
||||||
|
|
||||||
|
rtc->pctldev = pinctrl_register(&rtc_pinctrl_desc, &pdev->dev, rtc);
|
||||||
|
if (IS_ERR(rtc->pctldev)) {
|
||||||
|
dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
|
||||||
|
return PTR_ERR(rtc->pctldev);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@ -724,6 +873,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
|
|||||||
pm_runtime_put_sync(&pdev->dev);
|
pm_runtime_put_sync(&pdev->dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
|
/* Remove ext_wakeup pinconf */
|
||||||
|
pinctrl_unregister(rtc->pctldev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user