Merge changes I1b449119,If7d42ce3 into msm-3.4

* changes:
  arm/dt: msmcopper: Add PON device for PM8941
  msm: qpnp-power-on: Add QPNP PMIC power-on(PON) driver
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
new file mode 100644
index 0000000..2e7f9c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -0,0 +1,39 @@
+Qualcomm QPNP power-on
+
+The qpnp-power-on is a driver which supports the power-on(PON)
+peripheral on Qualcomm PMICs. The supported functionality includes
+power on/off reason, power-key press/release detection and other PON
+features. This peripheral is connected to the host processor via the SPMI
+interface.
+
+Required properties:
+- compatible:	Must be "qcom,qpnp-power-on"
+- reg:		Specifies the SPMI address and size for this PON (power-on) peripheral
+- interrupts:	Specifies the interrupt associated with the power-key.
+
+Optional properties:
+- qcom,pon-key-enable:		Enable power-key detection. It enables monitoring
+				of the KPDPWR_N line (connected to the power-key).
+- qcom,pon-key-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
+				- Intermediate value is rounded down to the
+				nearest valid value.
+- qcom,pon-key-pull-up:		The intial state of the KPDPWR_N pin
+				(connected to the power-key)
+				0 = No pull-up
+				1 = pull-up enabled
+
+If any of the above optional property is not defined, the driver will continue
+with the default hardware state.
+
+Example:
+	qcom,power-on@800 {
+		compatible = "qcom,qpnp-power-on";
+		reg = <0x800 0x100>;
+		interrupts = <0x0 0x8 0x1>;
+		qcom,pon-key-enable= <true>;
+		qcom,pon-key-pull-up = <true>;
+		qcom,pon-key-dbc-delay = <15625>;
+	}
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 87864fd..f462a1e 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -22,6 +22,16 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		qcom,power-on@800 {
+			compatible = "qcom,qpnp-power-on";
+			reg = <0x800 0x100>;
+			interrupts = <0x0 0x8 0x0>;
+			interrupt-names = "power-key";
+			qcom,pon-key-enable = <1>;
+			qcom,pon-key-dbc-delay = <15625>;
+			qcom,pon-key-pull-up = <1>;
+		};
+
 		pm8941_gpios {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 0c3d4ad..d75cac4 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -60,4 +60,11 @@
           devices support Pulse Width Modulation output with user generated
           patterns. They share a lookup table with size of 64 entries.
 
+config QPNP_POWER_ON
+	tristate "QPNP PMIC POWER-ON Driver"
+	depends on OF_SPMI && SPMI && MSM_QPNP_INT
+	help
+	  This driver supports the power-on functionality on Qualcomm
+	  PNP PMIC. It currently supports reporting the change in status of
+	  the KPDPWR_N line (connected to the power-key).
 endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 6deb6ee..2b6b806 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -5,3 +5,4 @@
 obj-$(CONFIG_USB_BAM) += usb_bam.o
 obj-$(CONFIG_SPS) += sps/
 obj-$(CONFIG_QPNP_PWM) += qpnp-pwm.o
+obj-$(CONFIG_QPNP_POWER_ON) += qpnp-power-on.o
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
new file mode 100644
index 0000000..d8bb884
--- /dev/null
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -0,0 +1,241 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+
+#define QPNP_PON_RT_STS(base)		(base + 0x10)
+#define QPNP_PON_PULL_CTL(base)		(base + 0x70)
+#define QPNP_PON_DBC_CTL(base)		(base + 0x71)
+
+#define QPNP_PON_CNTL_PULL_UP		BIT(1)
+#define QPNP_PON_CNTL_TRIG_DELAY_MASK	(0x7)
+#define QPNP_PON_KPDPWR_N_SET		BIT(0)
+
+struct qpnp_pon {
+	struct spmi_device *spmi;
+	struct input_dev *pon_input;
+	u32 key_status_irq;
+	u16 base;
+};
+
+static irqreturn_t qpnp_pon_key_irq(int irq, void *_pon)
+{
+	u8 pon_rt_sts;
+	int rc;
+	struct qpnp_pon *pon = _pon;
+
+	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+				QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
+		return IRQ_HANDLED;
+	}
+
+	input_report_key(pon->pon_input, KEY_POWER,
+				!(pon_rt_sts & QPNP_PON_KPDPWR_N_SET));
+	input_sync(pon->pon_input);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit qpnp_pon_key_init(struct qpnp_pon *pon)
+{
+	int rc = 0;
+	u32 pullup, delay;
+	u8 pon_cntl;
+
+	pon->key_status_irq = spmi_get_irq_byname(pon->spmi,
+						NULL, "power-key");
+	if (pon->key_status_irq < 0) {
+		dev_err(&pon->spmi->dev, "Unable to get pon key irq\n");
+		return -ENXIO;
+	}
+
+	rc = of_property_read_u32(pon->spmi->dev.of_node,
+					"qcom,pon-key-dbc-delay", &delay);
+	if (rc) {
+		delay = (delay << 6) / USEC_PER_SEC;
+		delay = ilog2(delay);
+
+		rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+				QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
+						QPNP_PON_DBC_CTL(pon->base));
+			return rc;
+		}
+		pon_cntl &= ~QPNP_PON_CNTL_TRIG_DELAY_MASK;
+		pon_cntl |= (delay & QPNP_PON_CNTL_TRIG_DELAY_MASK);
+		rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
+				QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "spmi write addre=%x failed\n",
+						QPNP_PON_DBC_CTL(pon->base));
+			return rc;
+		}
+	}
+
+	rc = of_property_read_u32(pon->spmi->dev.of_node,
+				"qcom,pon-key-pull-up", &pullup);
+	if (!rc) {
+		rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+				QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
+						QPNP_PON_PULL_CTL(pon->base));
+			return rc;
+		}
+		if (pullup)
+			pon_cntl |= QPNP_PON_CNTL_PULL_UP;
+		else
+			pon_cntl &= ~QPNP_PON_CNTL_PULL_UP;
+
+		rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
+				QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "spmi write addr=%x failed\n",
+						QPNP_PON_PULL_CTL(pon->base));
+			return rc;
+		}
+	}
+
+	pon->pon_input = input_allocate_device();
+	if (!pon->pon_input) {
+		dev_err(&pon->spmi->dev, "Can't allocate pon button\n");
+		return -ENOMEM;
+	}
+
+	input_set_capability(pon->pon_input, EV_KEY, KEY_POWER);
+	pon->pon_input->name = "qpnp_pon_key";
+	pon->pon_input->phys = "qpnp_pon_key/input0";
+
+	rc = input_register_device(pon->pon_input);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Can't register pon key: %d\n", rc);
+		goto free_input_dev;
+	}
+
+	rc = request_any_context_irq(pon->key_status_irq, qpnp_pon_key_irq,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+						"qpnp_pon_key_status", pon);
+	if (rc < 0) {
+		dev_err(&pon->spmi->dev, "Can't request %d IRQ for pon: %d\n",
+						pon->key_status_irq, rc);
+		goto unreg_input_dev;
+	}
+
+	device_init_wakeup(&pon->spmi->dev, 1);
+	enable_irq_wake(pon->key_status_irq);
+
+	return rc;
+
+unreg_input_dev:
+	input_unregister_device(pon->pon_input);
+free_input_dev:
+	input_free_device(pon->pon_input);
+	return rc;
+}
+
+static int __devinit qpnp_pon_probe(struct spmi_device *spmi)
+{
+	struct qpnp_pon *pon;
+	struct resource *pon_resource;
+	u32 pon_key_enable = 0;
+	int rc = 0;
+
+	pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
+							GFP_KERNEL);
+	if (!pon) {
+		dev_err(&spmi->dev, "Can't allocate qpnp_pon\n");
+		return -ENOMEM;
+	}
+
+	pon->spmi = spmi;
+
+	pon_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+	if (!pon_resource) {
+		dev_err(&spmi->dev, "Unable to get PON base address\n");
+		return -ENXIO;
+	}
+	pon->base = pon_resource->start;
+
+	dev_set_drvdata(&spmi->dev, pon);
+
+	/* pon-key-enable property must be set to register pon key */
+	rc = of_property_read_u32(spmi->dev.of_node, "qcom,pon-key-enable",
+							&pon_key_enable);
+	if (rc && rc != -EINVAL) {
+		dev_err(&spmi->dev,
+			"Error reading 'pon-key-enable' property (%d)", rc);
+		return rc;
+	}
+
+	if (pon_key_enable) {
+		rc = qpnp_pon_key_init(pon);
+		if (rc < 0) {
+			dev_err(&spmi->dev, "Failed to register pon-key\n");
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int qpnp_pon_remove(struct spmi_device *spmi)
+{
+	struct qpnp_pon *pon = dev_get_drvdata(&spmi->dev);
+
+	if (pon->pon_input) {
+		free_irq(pon->key_status_irq, pon);
+		input_unregister_device(pon->pon_input);
+	}
+
+	return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+	{	.compatible = "qcom,qpnp-power-on",
+	}
+};
+
+static struct spmi_driver qpnp_pon_driver = {
+	.driver		= {
+		.name	= "qcom,qpnp-power-on",
+		.of_match_table = spmi_match_table,
+	},
+	.probe		= qpnp_pon_probe,
+	.remove		= __devexit_p(qpnp_pon_remove),
+};
+
+static int __init qpnp_pon_init(void)
+{
+	return spmi_driver_register(&qpnp_pon_driver);
+}
+module_init(qpnp_pon_init);
+
+static void __exit qpnp_pon_exit(void)
+{
+	return spmi_driver_unregister(&qpnp_pon_driver);
+}
+module_exit(qpnp_pon_exit);
+
+MODULE_DESCRIPTION("QPNP PMIC POWER-ON driver");
+MODULE_LICENSE("GPL v2");