aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorBaolin Wang <baolin.wang@linaro.org>2018-02-26 10:23:14 +0800
committerSebastian Reichel <sebastian.reichel@collabora.co.uk>2018-03-09 17:11:31 +0100
commit3f5faf3a0667ea39faf7152c5bdd4befb9e483a8 (patch)
treec875fc8ffac9561a75b680f6f6d27bc388f99d14 /drivers/power
parentpower: supply: axp20x_battery: add support for AXP813 (diff)
downloadlinux-dev-3f5faf3a0667ea39faf7152c5bdd4befb9e483a8.tar.xz
linux-dev-3f5faf3a0667ea39faf7152c5bdd4befb9e483a8.zip
power: reset: Add Spreadtrum SC27xx PMIC power off support
On Spreadtrum platform, we need power off system through external SC27xx series PMICs including the SC2720, SC2721, SC2723, SC2730 and SC2731 chips. Thus this patch adds SC27xx series PMICs power-off support. Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/reset/Kconfig9
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/sc27xx-poweroff.c66
3 files changed, 76 insertions, 0 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 176bd6df1238..df58fc878b3e 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -225,5 +225,14 @@ config SYSCON_REBOOT_MODE
register, then the bootloader can read it to take different
action according to the mode.
+config POWER_RESET_SC27XX
+ bool "Spreadtrum SC27xx PMIC power-off driver"
+ depends on MFD_SC27XX_PMIC || COMPILE_TEST
+ help
+ This driver supports powering off a system through
+ Spreadtrum SC27xx series PMICs. The SC27xx series
+ PMICs includes the SC2720, SC2721, SC2723, SC2730
+ and SC2731 chips.
+
endif
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 6b9eb1393179..7778c7485cf1 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o
obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o
obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
+obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
diff --git a/drivers/power/reset/sc27xx-poweroff.c b/drivers/power/reset/sc27xx-poweroff.c
new file mode 100644
index 000000000000..65c477eee559
--- /dev/null
+++ b/drivers/power/reset/sc27xx-poweroff.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Spreadtrum Communications Inc.
+ * Copyright (C) 2018 Linaro Ltd.
+ */
+
+#include <linux/cpu.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/syscore_ops.h>
+
+#define SC27XX_PWR_PD_HW 0xc2c
+#define SC27XX_PWR_OFF_EN BIT(0)
+
+static struct regmap *regmap;
+
+/*
+ * On Spreadtrum platform, we need power off system through external SC27xx
+ * series PMICs, and it is one similar SPI bus mapped by regmap to access PMIC,
+ * which is not fast io access.
+ *
+ * So before stopping other cores, we need release other cores' resource by
+ * taking cpus down to avoid racing regmap or spi mutex lock when poweroff
+ * system through PMIC.
+ */
+void sc27xx_poweroff_shutdown(void)
+{
+#ifdef CONFIG_PM_SLEEP_SMP
+ int cpu = smp_processor_id();
+
+ freeze_secondary_cpus(cpu);
+#endif
+}
+
+static struct syscore_ops poweroff_syscore_ops = {
+ .shutdown = sc27xx_poweroff_shutdown,
+};
+
+static void sc27xx_poweroff_do_poweroff(void)
+{
+ regmap_write(regmap, SC27XX_PWR_PD_HW, SC27XX_PWR_OFF_EN);
+}
+
+static int sc27xx_poweroff_probe(struct platform_device *pdev)
+{
+ if (regmap)
+ return -EINVAL;
+
+ regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!regmap)
+ return -ENODEV;
+
+ pm_power_off = sc27xx_poweroff_do_poweroff;
+ register_syscore_ops(&poweroff_syscore_ops);
+ return 0;
+}
+
+static struct platform_driver sc27xx_poweroff_driver = {
+ .probe = sc27xx_poweroff_probe,
+ .driver = {
+ .name = "sc27xx-poweroff",
+ },
+};
+builtin_platform_driver(sc27xx_poweroff_driver);