aboutsummaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
authorBengt Jonsson <bengt.g.jonsson@stericsson.com>2010-11-25 09:48:12 +0100
committerJonas ABERG <jonas.aberg@stericsson.com>2010-12-16 17:09:44 +0100
commit1e0930e0e4c4888e88131371160b4859c7a1d9ca (patch)
tree91eec1b677772d8015c9d6d0ced5fb9858697320 /drivers/regulator
parentd9007d6905c26253c7d95027024809c3b437b2a2 (diff)
regulator: possibility to force extsupplies down in suspend
This patch adds the possibility to force extsupply1 (controls extsmps1) off and extsupply3 (controls extsmps3 and extsmps4) to hw control during suspend. The purpose is to save power. The original regulator setting is read during suspend and restored in resume. This functionality is default off but can be enabled through debugfs. ST-Ericsson Id: ER281086 Signed-off-by: Bengt Jonsson <bengt.g.jonsson@stericsson.com> Change-Id: Id7b88d5afbe9387ce26c87e0df70198634008644 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/11153 Tested-by: Bengt JONSSON <bengt.g.jonsson@stericsson.com> Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig8
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/ab8500-debug.c237
3 files changed, 246 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 33a702b4bba..2d7644501ad 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -72,6 +72,14 @@ config REGULATOR_AB8500
This driver supports the regulators found on the ST-Ericsson mixed
signal AB8500 PMIC
+config REGULATOR_AB8500_DEBUG
+ bool "AB8500 regulator debug"
+ depends on REGULATOR_AB8500
+ help
+ Say Y here to add debug functionality for ST-Ericsson
+ ab8500 regulators. This is a module that exposes a
+ number of settings and debug output in debugfs.
+
config REGULATOR_BQ24022
tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
help
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 0b18070d376..f6916e1384c 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
+obj-$(CONFIG_REGULATOR_AB8500_DEBUG) += ab8500-debug.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
diff --git a/drivers/regulator/ab8500-debug.c b/drivers/regulator/ab8500-debug.c
new file mode 100644
index 00000000000..d67de004921
--- /dev/null
+++ b/drivers/regulator/ab8500-debug.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson.
+ *
+ * License Terms: GNU General Public License v2
+ */
+
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+#include <linux/mfd/abx500.h>
+
+/* for error prints */
+struct device *dev;
+
+/* setting for suspend force (disabled by default) */
+static bool setting_suspend_force;
+
+static int ab8500_regulator_suspend_force_show(struct seq_file *s, void *p)
+{
+ /* print suspend standby status */
+ if (setting_suspend_force)
+ return seq_printf(s, "suspend force enabled\n");
+ else
+ return seq_printf(s, "no suspend force\n");
+}
+
+static int ab8500_regulator_suspend_force_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+
+ /* copy user data */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ /* convert */
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+
+ /* set suspend force setting */
+ if (user_val > 1) {
+ dev_err(dev, "debugfs error input > 1\n");
+ return -EINVAL;
+ }
+
+ if (user_val)
+ setting_suspend_force = true;
+ else
+ setting_suspend_force = false;
+
+ return buf_size;
+}
+
+static int ab8500_regulator_suspend_force_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_regulator_suspend_force_show,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_regulator_suspend_force_fops = {
+ .open = ab8500_regulator_suspend_force_open,
+ .write = ab8500_regulator_suspend_force_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static struct dentry *ab8500_regulator_dir;
+static struct dentry *ab8500_regulator_suspend_force_file;
+
+static int __devinit ab8500_regulator_debug_probe(struct platform_device *plf)
+{
+ dev = &plf->dev;
+
+ /* create directory */
+ ab8500_regulator_dir = debugfs_create_dir("ab8500-regulator", NULL);
+ if (!ab8500_regulator_dir)
+ goto exit_no_debugfs;
+
+ /* create "dump" file */
+ ab8500_regulator_suspend_force_file = debugfs_create_file(
+ "suspend-force",
+ S_IRUGO, ab8500_regulator_dir, &plf->dev,
+ &ab8500_regulator_suspend_force_fops);
+ if (!ab8500_regulator_suspend_force_file)
+ goto exit_destroy_dir;
+
+ return 0;
+
+exit_destroy_dir:
+ debugfs_remove(ab8500_regulator_dir);
+
+exit_no_debugfs:
+ dev_err(&plf->dev, "failed to create debugfs entries.\n");
+ return -ENOMEM;
+}
+
+static int __devexit ab8500_regulator_debug_remove(struct platform_device *plf)
+{
+ debugfs_remove(ab8500_regulator_suspend_force_file);
+ debugfs_remove(ab8500_regulator_dir);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* "ExtSupplyRegu" register */
+#define EXTSUPPLY_REGU_BANK 0x04
+#define EXTSUPPLY_REGU_ADDR 0x08
+
+/*
+ * extsupply1 mode (controlling extsmps1)
+ * - force to off in suspend
+ */
+#define EXTSUPPLY_REGU_EXT1_MASK 0x03
+#define EXTSUPPLY_REGU_EXT1_VAL_OFF 0x00
+
+/*
+ * extsupply3 mode (controlling extsmps3 and extsmps4)
+ * - force to hw control in suspend
+ */
+#define EXTSUPPLY_REGU_EXT3_MASK 0x30
+#define EXTSUPPLY_REGU_EXT3_VAL_HW 0x20
+
+/* restore val */
+static u8 extsupply_restore_val;
+static bool extsupply_restore;
+
+static int ab8500_regulator_debug_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ int ret;
+
+ if (setting_suspend_force) {
+ extsupply_restore = true;
+
+ /* get restore value */
+ ret = abx500_get_register_interruptible(&pdev->dev,
+ EXTSUPPLY_REGU_BANK, EXTSUPPLY_REGU_ADDR,
+ &extsupply_restore_val);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to read 0x%02x:0x%02x\n",
+ EXTSUPPLY_REGU_BANK, EXTSUPPLY_REGU_ADDR);
+ extsupply_restore = false;
+ }
+
+ /* force setting in suspend */
+ ret = abx500_mask_and_set_register_interruptible(&pdev->dev,
+ EXTSUPPLY_REGU_BANK, EXTSUPPLY_REGU_ADDR,
+ EXTSUPPLY_REGU_EXT1_MASK | EXTSUPPLY_REGU_EXT3_MASK,
+ EXTSUPPLY_REGU_EXT1_VAL_OFF
+ | EXTSUPPLY_REGU_EXT3_VAL_HW);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to force 0x%02x:0x%02x\n",
+ EXTSUPPLY_REGU_BANK, EXTSUPPLY_REGU_ADDR);
+ extsupply_restore = false;
+ }
+ }
+
+ return 0;
+}
+
+static int ab8500_regulator_debug_resume(struct platform_device *pdev)
+{
+ int ret;
+
+ if (extsupply_restore) {
+ /* restore value */
+ ret = abx500_mask_and_set_register_interruptible(&pdev->dev,
+ EXTSUPPLY_REGU_BANK, EXTSUPPLY_REGU_ADDR,
+ EXTSUPPLY_REGU_EXT1_MASK | EXTSUPPLY_REGU_EXT3_MASK,
+ extsupply_restore_val);
+ if (ret < 0)
+ dev_err(&pdev->dev,
+ "failed to restore 0x%02x:0x%02x\n",
+ EXTSUPPLY_REGU_BANK, EXTSUPPLY_REGU_ADDR);
+
+ extsupply_restore = false;
+ }
+
+ return 0;
+}
+
+#else
+#define ab8500_regulator_debug_suspend NULL
+#define ab8500_regulator_debug_resume NULL
+#endif
+
+static struct platform_driver ab8500_regulator_debug_driver = {
+ .driver = {
+ .name = "ab8500-regulator-debug",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_regulator_debug_probe,
+ .remove = __devexit_p(ab8500_regulator_debug_remove),
+ .suspend = ab8500_regulator_debug_suspend,
+ .resume = ab8500_regulator_debug_resume,
+};
+
+static int __init ab8500_regulator_debug_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&ab8500_regulator_debug_driver);
+ if (ret)
+ pr_err("Failed to register ab8500 regulator: %d\n", ret);
+
+ return ret;
+}
+subsys_initcall(ab8500_regulator_debug_init);
+
+static void __exit ab8500_regulator_debug_exit(void)
+{
+ platform_driver_unregister(&ab8500_regulator_debug_driver);
+}
+module_exit(ab8500_regulator_debug_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com");
+MODULE_DESCRIPTION("AB8500 Regulator Debug");
+MODULE_ALIAS("platform:ab8500-regulator-debug");