Merge "msm: qpnp-power-on: Add API to reset and shutdown the system"
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 46b39ec..21d376a 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -13,7 +13,7 @@
- interrupts: Specifies the interrupt associated with PON.
Optional properties:
-- qcom,pon-dbc-delay: The debouce delay for the power-key interrupt
+- qcom,pon-dbc-delay The debouce delay for the power-key interrupt
specifed in us. The value ranges from 2 seconds
to 1/64 of a second. Possible values are -
- 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
@@ -24,11 +24,15 @@
reset source. All the child nodes are optional,
if none of them are specified the driver fails
to register.
+- qcom,system-reset Specifies that this PON peripheral can be used
+ to reset the system. This property can only be
+ used by one device on the system. It is an error
+ to include it more than once.
All the below properties are in the sub-node section (properties of the child
node).
-- qcom,pull-up: The initial state of the reset pin under
+- qcom,pull-up The initial state of the reset pin under
consideration.
0 = No pull-up
1 = pull-up enabled
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 996456f..33b12ae 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,7 @@
#define QPNP_PON_RESIN_S1_TIMER(base) (base + 0x44)
#define QPNP_PON_RESIN_S2_TIMER(base) (base + 0x45)
#define QPNP_PON_RESIN_S2_CNTL(base) (base + 0x46)
+#define QPNP_PON_PS_HOLD_RST_CTL(base) (base + 0x5A)
#define QPNP_PON_RESIN_PULL_UP BIT(0)
#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
@@ -50,6 +51,10 @@
#define QPNP_PON_RESIN_N_SET BIT(1)
#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
+#define QPNP_PON_RESET_EN BIT(7)
+#define QPNP_PON_WARM_RESET BIT(0)
+#define QPNP_PON_SHUTDOWN BIT(2)
+
/* Ranges */
#define QPNP_PON_S1_TIMER_MAX 10256
#define QPNP_PON_S2_TIMER_MAX 2000
@@ -84,6 +89,8 @@
struct delayed_work bark_work;
};
+static struct qpnp_pon *sys_reset_dev;
+
static u32 s1_delay[PON_S1_COUNT_MAX + 1] = {
0 , 32, 56, 80, 138, 184, 272, 408, 608, 904, 1352, 2048,
3072, 4480, 6720, 10256
@@ -113,6 +120,57 @@
return rc;
}
+/**
+ * qpnp_pon_system_pwr_off - Configure system-reset PMIC for shutdown or reset
+ * @reset: Configures for shutdown if 0, or reset if 1.
+ *
+ * This function will only configure a single PMIC. The other PMICs in the
+ * system are slaved off of it and require no explicit configuration. Once
+ * the system-reset PMIC is configured properly, the MSM can drop PS_HOLD to
+ * activate the specified configuration.
+ */
+int qpnp_pon_system_pwr_off(bool reset)
+{
+ int rc;
+ struct qpnp_pon *pon = sys_reset_dev;
+
+ if (!pon)
+ return -ENODEV;
+
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
+ QPNP_PON_RESET_EN, 0);
+ if (rc)
+ dev_err(&pon->spmi->dev,
+ "Unable to write to addr=%x, rc(%d)\n",
+ QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+
+ /*
+ * We need 10 sleep clock cycles here. But since the clock is
+ * internally generated, we need to add 50% tolerance to be
+ * conservative.
+ */
+ udelay(500);
+
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
+ QPNP_PON_WARM_RESET | QPNP_PON_SHUTDOWN,
+ reset ? QPNP_PON_WARM_RESET : QPNP_PON_SHUTDOWN);
+ if (rc)
+ dev_err(&pon->spmi->dev,
+ "Unable to write to addr=%x, rc(%d)\n",
+ QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
+ QPNP_PON_RESET_EN,
+ QPNP_PON_RESET_EN);
+ if (rc)
+ dev_err(&pon->spmi->dev,
+ "Unable to write to addr=%x, rc(%d)\n",
+ QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_pon_system_pwr_off);
+
static struct qpnp_pon_config *
qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
{
@@ -662,7 +720,7 @@
struct resource *pon_resource;
struct device_node *itr = NULL;
u32 delay = 0;
- int rc = 0;
+ int rc, sys_reset;
pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
GFP_KERNEL);
@@ -671,6 +729,15 @@
return -ENOMEM;
}
+ sys_reset = of_property_read_bool(spmi->dev.of_node,
+ "qcom,system-reset");
+ if (sys_reset && sys_reset_dev) {
+ dev_err(&spmi->dev, "qcom,system-reset property can only be specified for one device on the system\n");
+ return -EINVAL;
+ } else if (sys_reset) {
+ sys_reset_dev = pon;
+ }
+
pon->spmi = spmi;
/* get the total number of pon configurations */
diff --git a/include/linux/qpnp/power-on.h b/include/linux/qpnp/power-on.h
new file mode 100644
index 0000000..85dbce9
--- /dev/null
+++ b/include/linux/qpnp/power-on.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef QPNP_PON_H
+#define QPNP_PON_H
+
+#include <linux/errno.h>
+
+#ifdef CONFIG_QPNP_POWER_ON
+int qpnp_pon_system_pwr_off(bool reset);
+#else
+static int qpnp_pon_system_pwr_off(bool reset) { return -ENODEV; }
+#endif
+
+#endif