power: reset: as3722: system power off and reset through system-pmic
Laxman Dewangan [Fri, 8 Nov 2013 08:44:28 +0000 (13:44 +0530)]
Implement the system pmic power off and reset driver for ams AS3722 PMIC
device.

Change-Id: I04a4b48e016342fafdf6aba8b84daddd87176a83
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/328148

drivers/power/reset/as3722-poweroff.c
include/linux/mfd/as3722-plat.h
include/linux/mfd/as3722-reg.h
include/linux/mfd/as3722.h [new file with mode: 0644]

index 0e489ff..0b7d067 100644 (file)
  */
 
 #include <linux/mfd/as3722.h>
+#include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+ #include <linux/power/reset/system-pmic.h>
 #include <linux/slab.h>
 
 struct as3722_poweroff {
        struct device *dev;
        struct as3722 *as3722;
+       struct system_pmic_dev *system_pmic_dev;
+       bool use_power_off;
+       bool use_power_reset;
 };
 
-static struct as3722_poweroff *as3722_pm_poweroff;
-
-static void as3722_pm_power_off(void)
+static void as3722_pm_power_off(void *drv_data)
 {
+       struct as3722_poweroff *as3722_poweroff = drv_data;
        int ret;
 
-       if (!as3722_pm_poweroff) {
-               pr_err("AS3722 poweroff is not initialised\n");
-               return;
-       }
-
-       ret = as3722_update_bits(as3722_pm_poweroff->as3722,
+       dev_info(as3722_poweroff->dev, " Powering off system\n");
+       ret = as3722_update_bits(as3722_poweroff->as3722,
                AS3722_RESET_CONTROL_REG, AS3722_POWER_OFF, AS3722_POWER_OFF);
        if (ret < 0)
-               dev_err(as3722_pm_poweroff->dev,
+               dev_err(as3722_poweroff->dev,
+                       "RESET_CONTROL_REG update failed, %d\n", ret);
+}
+
+static void as3722_pm_power_reset(void *drv_data)
+{
+       struct as3722_poweroff *as3722_poweroff = drv_data;
+       int ret;
+
+       dev_info(as3722_poweroff->dev, " Power resetting of system\n");
+       ret = as3722_update_bits(as3722_poweroff->as3722,
+               AS3722_RESET_CONTROL_REG, AS3722_FORCE_RESET,
+               AS3722_FORCE_RESET);
+       if (ret < 0)
+               dev_err(as3722_poweroff->dev,
                        "RESET_CONTROL_REG update failed, %d\n", ret);
 }
 
+static struct system_pmic_ops as3722_pm_ops = {
+       .power_off = as3722_pm_power_off,
+       .power_reset = as3722_pm_power_reset,
+};
+
 static int as3722_poweroff_probe(struct platform_device *pdev)
 {
        struct as3722_poweroff *as3722_poweroff;
        struct device_node *np = pdev->dev.parent->of_node;
+       struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent);
+       struct as3722_platform_data *pdata = as3722->dev->platform_data;
+       struct system_pmic_config config;
+       bool use_power_off = false;
+       bool use_power_reset = false;
+
+       if (pdata) {
+               use_power_off = pdata->use_power_off;
+               use_power_reset = pdata->use_power_reset;
+       } else {
+               if (np) {
+                       use_power_off = of_property_read_bool(np,
+                                       "ams,system-power-controller");
+                       if (!use_power_off)
+                               use_power_off = of_property_read_bool(np,
+                                       "system-pmic-power-off");
+                       use_power_reset = of_property_read_bool(np,
+                                       "ams,system-power-controller");
+                       if (!use_power_reset)
+                               use_power_reset = of_property_read_bool(np,
+                                       "system-pmic-power-reset");
+               }
+       }
 
-       if (!np)
-               return -EINVAL;
-
-       if (!of_property_read_bool(np, "ams,system-power-controller"))
+       if (!use_power_off && !use_power_reset) {
+               dev_warn(&pdev->dev,
+                       "power off and reset functionality not selected\n");
                return 0;
+       }
 
        as3722_poweroff = devm_kzalloc(&pdev->dev, sizeof(*as3722_poweroff),
                                GFP_KERNEL);
        if (!as3722_poweroff)
                return -ENOMEM;
 
-       as3722_poweroff->as3722 = dev_get_drvdata(pdev->dev.parent);
+       as3722_poweroff->as3722 = as3722;
        as3722_poweroff->dev = &pdev->dev;
-       as3722_pm_poweroff = as3722_poweroff;
-       if (!pm_power_off)
-               pm_power_off = as3722_pm_power_off;
+       as3722_poweroff->use_power_off = use_power_off;
+       as3722_poweroff->use_power_reset = use_power_reset;
+
+       config.allow_power_off = use_power_off;
+       config.allow_power_reset = use_power_reset;
 
+       as3722_poweroff->system_pmic_dev = system_pmic_register(&pdev->dev,
+                               &as3722_pm_ops, &config, as3722_poweroff);
+       if (IS_ERR(as3722_poweroff->system_pmic_dev)) {
+               int ret = PTR_ERR(as3722_poweroff->system_pmic_dev);
+
+               dev_err(&pdev->dev, "System PMIC registartion failed: %d\n",
+                       ret);
+               return ret;
+       }
        return 0;
 }
 
 static int as3722_poweroff_remove(struct platform_device *pdev)
 {
-       if (pm_power_off == as3722_pm_power_off)
-               pm_power_off = NULL;
-       as3722_pm_poweroff = NULL;
+       struct as3722_poweroff *as3722_poweroff = platform_get_drvdata(pdev);
 
+       system_pmic_unregister(as3722_poweroff->system_pmic_dev);
        return 0;
 }
 
index 59cac4a..7b16da1 100644 (file)
@@ -132,6 +132,7 @@ struct as3722_platform_data {
        int use_internal_i2c_pullup;
        int num_gpio_cfgs;
        bool use_power_off;
+       bool use_power_reset;
        struct as3722_gpio_config *gpio_cfgs;
        struct as3722_rtc_platform_data *rtc_pdata;
        struct as3722_pinctrl_init_data *pinctrl_pdata;
index 0725f46..8ad77aa 100644 (file)
@@ -475,4 +475,6 @@ AS3722_LDO11,
 #define AS3722_WATCHDOG_SW_SIG_MASK            (1<<0)
 #define AS3722_WATCHDOG_SW_SIG                 (1<<0)
 
+#define AS3722_FORCE_RESET                     BIT(0)
+#define AS3722_POWER_OFF                       BIT(1)
 #endif
diff --git a/include/linux/mfd/as3722.h b/include/linux/mfd/as3722.h
new file mode 100644 (file)
index 0000000..52edf1a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * as3722.h definitions
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_MFD_AS3722_H__
+#define __LINUX_MFD_AS3722_H__
+
+#include <linux/mfd/as3722-reg.h>
+#include <linux/mfd/as3722-plat.h>
+
+static inline int as3722_update_bits(struct as3722 *as3722, u32 reg,
+                u32 mask, u8 val)
+{
+        return regmap_update_bits(as3722->regmap, reg, mask, val);
+}
+
+#endif