summaryrefslogtreecommitdiffstats
path: root/drivers/power/reset
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/reset')
-rw-r--r--drivers/power/reset/Kconfig14
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/at91-reset.c6
-rw-r--r--drivers/power/reset/at91-sama5d2_shdwc.c80
-rw-r--r--drivers/power/reset/gpio-restart.c8
-rw-r--r--drivers/power/reset/mt6323-poweroff.c97
-rw-r--r--drivers/power/reset/reboot-mode.c2
7 files changed, 172 insertions, 36 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index a564237278ff..513efe8e7628 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -26,7 +26,7 @@ config POWER_RESET_AT91_POWEROFF
config POWER_RESET_AT91_RESET
tristate "Atmel AT91 reset driver"
depends on ARCH_AT91
- default SOC_AT91SAM9 || SOC_SAMA5
+ default SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAMA5
help
This driver supports restart for Atmel AT91SAM9 and SAMA5
SoCs
@@ -34,7 +34,7 @@ config POWER_RESET_AT91_RESET
config POWER_RESET_AT91_SAMA5D2_SHDWC
tristate "Atmel AT91 SAMA5D2-Compatible shutdown controller driver"
depends on ARCH_AT91
- default SOC_SAMA5
+ default SOC_SAM9X60 || SOC_SAMA5
help
This driver supports the alternate shutdown controller for some Atmel
SAMA5 SoCs. It is present for example on SAMA5D2 SoC.
@@ -140,6 +140,16 @@ config POWER_RESET_LTC2952
This driver supports an external powerdown trigger and board power
down via the LTC2952. Bindings are made in the device tree.
+config POWER_RESET_MT6323
+ bool "MediaTek MT6323 power-off driver"
+ depends on MFD_MT6397
+ help
+ The power-off driver is responsible for externally shutdown down
+ the power of a remote MediaTek SoC MT6323 is connected to through
+ controlling a tiny circuit BBPU inside MT6323 RTC.
+
+ Say Y if you have a board where MT6323 could be found.
+
config POWER_RESET_QNAP
bool "QNAP power-off driver"
depends on OF_GPIO && PLAT_ORION
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 85da3198e4e0..da37f8b851dc 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
+obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o
obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o
obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 44ca983a49a1..d94e3267c3b6 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -131,7 +131,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
- writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST),
+ writel(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
at91_rstc_base);
return NOTIFY_DONE;
@@ -140,9 +140,7 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
static int samx7_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
- writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST),
- at91_rstc_base);
-
+ writel(AT91_RSTC_KEY | AT91_RSTC_PROCRST, at91_rstc_base);
return NOTIFY_DONE;
}
diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c
index e341cc5c0ea6..2fe3a627cb53 100644
--- a/drivers/power/reset/at91-sama5d2_shdwc.c
+++ b/drivers/power/reset/at91-sama5d2_shdwc.c
@@ -66,7 +66,7 @@
#define SHDW_CFG_NOT_USED (32)
-struct shdwc_config {
+struct shdwc_reg_config {
u8 wkup_pin_input;
u8 mr_rtcwk_shift;
u8 mr_rttwk_shift;
@@ -74,8 +74,17 @@ struct shdwc_config {
u8 sr_rttwk_shift;
};
+struct pmc_reg_config {
+ u8 mckr;
+};
+
+struct reg_config {
+ struct shdwc_reg_config shdwc;
+ struct pmc_reg_config pmc;
+};
+
struct shdwc {
- const struct shdwc_config *cfg;
+ const struct reg_config *rcfg;
struct clk *sclk;
void __iomem *shdwc_base;
void __iomem *mpddrc_base;
@@ -95,6 +104,7 @@ static const unsigned long long sdwc_dbc_period[] = {
static void __init at91_wakeup_status(struct platform_device *pdev)
{
struct shdwc *shdw = platform_get_drvdata(pdev);
+ const struct reg_config *rcfg = shdw->rcfg;
u32 reg;
char *reason = "unknown";
@@ -106,11 +116,11 @@ static void __init at91_wakeup_status(struct platform_device *pdev)
if (!reg)
return;
- if (SHDW_WK_PIN(reg, shdw->cfg))
+ if (SHDW_WK_PIN(reg, &rcfg->shdwc))
reason = "WKUP pin";
- else if (SHDW_RTCWK(reg, shdw->cfg))
+ else if (SHDW_RTCWK(reg, &rcfg->shdwc))
reason = "RTC";
- else if (SHDW_RTTWK(reg, shdw->cfg))
+ else if (SHDW_RTTWK(reg, &rcfg->shdwc))
reason = "RTT";
pr_info("AT91: Wake-Up source: %s\n", reason);
@@ -131,9 +141,9 @@ static void at91_poweroff(void)
" str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
/* Switch the master clock source to slow clock. */
- "1: ldr r6, [%4, #" __stringify(AT91_PMC_MCKR) "]\n\t"
+ "1: ldr r6, [%4, %5]\n\t"
" bic r6, r6, #" __stringify(AT91_PMC_CSS) "\n\t"
- " str r6, [%4, #" __stringify(AT91_PMC_MCKR) "]\n\t"
+ " str r6, [%4, %5]\n\t"
/* Wait for clock switch. */
"2: ldr r6, [%4, #" __stringify(AT91_PMC_SR) "]\n\t"
" tst r6, #" __stringify(AT91_PMC_MCKRDY) "\n\t"
@@ -148,7 +158,8 @@ static void at91_poweroff(void)
"r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
"r" (at91_shdwc->shdwc_base),
"r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW),
- "r" (at91_shdwc->pmc_base)
+ "r" (at91_shdwc->pmc_base),
+ "r" (at91_shdwc->rcfg->pmc.mckr)
: "r6");
}
@@ -215,6 +226,7 @@ static u32 at91_shdwc_get_wakeup_input(struct platform_device *pdev,
static void at91_shdwc_dt_configure(struct platform_device *pdev)
{
struct shdwc *shdw = platform_get_drvdata(pdev);
+ const struct reg_config *rcfg = shdw->rcfg;
struct device_node *np = pdev->dev.of_node;
u32 mode = 0, tmp, input;
@@ -227,10 +239,10 @@ static void at91_shdwc_dt_configure(struct platform_device *pdev)
mode |= AT91_SHDW_WKUPDBC(at91_shdwc_debouncer_value(pdev, tmp));
if (of_property_read_bool(np, "atmel,wakeup-rtc-timer"))
- mode |= SHDW_RTCWKEN(shdw->cfg);
+ mode |= SHDW_RTCWKEN(&rcfg->shdwc);
if (of_property_read_bool(np, "atmel,wakeup-rtt-timer"))
- mode |= SHDW_RTTWKEN(shdw->cfg);
+ mode |= SHDW_RTTWKEN(&rcfg->shdwc);
dev_dbg(&pdev->dev, "%s: mode = %#x\n", __func__, mode);
writel(mode, shdw->shdwc_base + AT91_SHDW_MR);
@@ -239,36 +251,52 @@ static void at91_shdwc_dt_configure(struct platform_device *pdev)
writel(input, shdw->shdwc_base + AT91_SHDW_WUIR);
}
-static const struct shdwc_config sama5d2_shdwc_config = {
- .wkup_pin_input = 0,
- .mr_rtcwk_shift = 17,
- .mr_rttwk_shift = SHDW_CFG_NOT_USED,
- .sr_rtcwk_shift = 5,
- .sr_rttwk_shift = SHDW_CFG_NOT_USED,
+static const struct reg_config sama5d2_reg_config = {
+ .shdwc = {
+ .wkup_pin_input = 0,
+ .mr_rtcwk_shift = 17,
+ .mr_rttwk_shift = SHDW_CFG_NOT_USED,
+ .sr_rtcwk_shift = 5,
+ .sr_rttwk_shift = SHDW_CFG_NOT_USED,
+ },
+ .pmc = {
+ .mckr = 0x30,
+ },
};
-static const struct shdwc_config sam9x60_shdwc_config = {
- .wkup_pin_input = 0,
- .mr_rtcwk_shift = 17,
- .mr_rttwk_shift = 16,
- .sr_rtcwk_shift = 5,
- .sr_rttwk_shift = 4,
+static const struct reg_config sam9x60_reg_config = {
+ .shdwc = {
+ .wkup_pin_input = 0,
+ .mr_rtcwk_shift = 17,
+ .mr_rttwk_shift = 16,
+ .sr_rtcwk_shift = 5,
+ .sr_rttwk_shift = 4,
+ },
+ .pmc = {
+ .mckr = 0x28,
+ },
};
static const struct of_device_id at91_shdwc_of_match[] = {
{
.compatible = "atmel,sama5d2-shdwc",
- .data = &sama5d2_shdwc_config,
+ .data = &sama5d2_reg_config,
},
{
.compatible = "microchip,sam9x60-shdwc",
- .data = &sam9x60_shdwc_config,
+ .data = &sam9x60_reg_config,
}, {
/*sentinel*/
}
};
MODULE_DEVICE_TABLE(of, at91_shdwc_of_match);
+static const struct of_device_id at91_pmc_ids[] = {
+ { .compatible = "atmel,sama5d2-pmc" },
+ { .compatible = "microchip,sam9x60-pmc" },
+ { /* Sentinel. */ }
+};
+
static int __init at91_shdwc_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -297,7 +325,7 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
}
match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node);
- at91_shdwc->cfg = match->data;
+ at91_shdwc->rcfg = match->data;
at91_shdwc->sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(at91_shdwc->sclk))
@@ -313,7 +341,7 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
at91_shdwc_dt_configure(pdev);
- np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-pmc");
+ np = of_find_matching_node(NULL, at91_pmc_ids);
if (!np) {
ret = -ENODEV;
goto clk_disable;
diff --git a/drivers/power/reset/gpio-restart.c b/drivers/power/reset/gpio-restart.c
index 2880cd5ae0d2..5466eeea261c 100644
--- a/drivers/power/reset/gpio-restart.c
+++ b/drivers/power/reset/gpio-restart.c
@@ -64,9 +64,11 @@ static int gpio_restart_probe(struct platform_device *pdev)
gpio_restart->reset_gpio = devm_gpiod_get(&pdev->dev, NULL,
open_source ? GPIOD_IN : GPIOD_OUT_LOW);
- if (IS_ERR(gpio_restart->reset_gpio)) {
- dev_err(&pdev->dev, "Could net get reset GPIO\n");
- return PTR_ERR(gpio_restart->reset_gpio);
+ ret = PTR_ERR_OR_ZERO(gpio_restart->reset_gpio);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Could not get reset GPIO\n");
+ return ret;
}
gpio_restart->restart_handler.notifier_call = gpio_restart_notify;
diff --git a/drivers/power/reset/mt6323-poweroff.c b/drivers/power/reset/mt6323-poweroff.c
new file mode 100644
index 000000000000..1caf43d9e46d
--- /dev/null
+++ b/drivers/power/reset/mt6323-poweroff.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Power off through MediaTek PMIC
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6397/rtc.h>
+
+struct mt6323_pwrc {
+ struct device *dev;
+ struct regmap *regmap;
+ u32 base;
+};
+
+static struct mt6323_pwrc *mt_pwrc;
+
+static void mt6323_do_pwroff(void)
+{
+ struct mt6323_pwrc *pwrc = mt_pwrc;
+ unsigned int val;
+ int ret;
+
+ regmap_write(pwrc->regmap, pwrc->base + RTC_BBPU, RTC_BBPU_KEY);
+ regmap_write(pwrc->regmap, pwrc->base + RTC_WRTGR, 1);
+
+ ret = regmap_read_poll_timeout(pwrc->regmap,
+ pwrc->base + RTC_BBPU, val,
+ !(val & RTC_BBPU_CBUSY),
+ MTK_RTC_POLL_DELAY_US,
+ MTK_RTC_POLL_TIMEOUT);
+ if (ret)
+ dev_err(pwrc->dev, "failed to write BBPU: %d\n", ret);
+
+ /* Wait some time until system down, otherwise, notice with a warn */
+ mdelay(1000);
+
+ WARN_ONCE(1, "Unable to power off system\n");
+}
+
+static int mt6323_pwrc_probe(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent);
+ struct mt6323_pwrc *pwrc;
+ struct resource *res;
+
+ pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
+ if (!pwrc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pwrc->base = res->start;
+ pwrc->regmap = mt6397_chip->regmap;
+ pwrc->dev = &pdev->dev;
+ mt_pwrc = pwrc;
+
+ pm_power_off = &mt6323_do_pwroff;
+
+ return 0;
+}
+
+static int mt6323_pwrc_remove(struct platform_device *pdev)
+{
+ if (pm_power_off == &mt6323_do_pwroff)
+ pm_power_off = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id mt6323_pwrc_dt_match[] = {
+ { .compatible = "mediatek,mt6323-pwrc" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt6323_pwrc_dt_match);
+
+static struct platform_driver mt6323_pwrc_driver = {
+ .probe = mt6323_pwrc_probe,
+ .remove = mt6323_pwrc_remove,
+ .driver = {
+ .name = "mt6323-pwrc",
+ .of_match_table = mt6323_pwrc_dt_match,
+ },
+};
+
+module_platform_driver(mt6323_pwrc_driver);
+
+MODULE_DESCRIPTION("Poweroff driver for MT6323 PMIC");
+MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index 06ff035b57f5..b4076b10b893 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -190,6 +190,6 @@ void devm_reboot_mode_unregister(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_reboot_mode_unregister);
-MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com");
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
MODULE_DESCRIPTION("System reboot mode core library");
MODULE_LICENSE("GPL v2");
OpenPOWER on IntegriCloud