Merge "ASoC: wcd9xxx: don't release mbhc firmware while it's still in use"
diff --git a/Documentation/devicetree/bindings/input/misc/cm36283.txt b/Documentation/devicetree/bindings/input/misc/cm36283.txt
new file mode 100644
index 0000000..b5ee7d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/cm36283.txt
@@ -0,0 +1,40 @@
+Capella cm36283 L/P sensor
+
+Required properties:
+
+ - compatible		: Should be "capella,cm36283".
+ - reg				: i2c slave address of the device.
+ - interrupt-parent	: Parent of interrupt.
+ - interrupts		: L/P sample interrupt to indicate new data ready.
+ - vdd-supply		: Power supply needed to power up the device.
+ - vio-supply		: IO power supply needed for IO and I2C.
+ - capella,interrupt-gpio	: The gpio pin for the interrupt.
+ - capella,levels	: The adc value for light sensor to trigger different light level.
+ - capella,ps_close_thd_set	: The threshold adc value for proximity sensor to trigger close  interrupt.
+ - capella,ps_away_thd_set: The threshold adc value for proximity sensor to trigger away interrupt.
+ - capella,ls_cmd	: The initial value to configure cm36283 ALS_CONF register.
+ - capella,ps_conf1_val	: The initial value to configure cm36283 PS_CONF1 register.
+ - capella,ps_conf3_val	: The initial value to configure cm36283 PS_CONF3 register.
+
+Optional properties:
+
+ - capella,use-polling	: Property to specify if using polling instead of interrupt for adc value report.
+
+Example:
+
+		capella@60 {
+				compatible = "capella,cm36283";
+				reg = <0x60>;
+				interrupt-parent = <&msmgpio>;
+				interrupts = <80 0x2>;
+				vdd-supply = <&pm8110_l19>;
+				vio-supply = <&pm8110_l14>;
+				capella,use-polling;
+				capella,interrupt-gpio = <80>;
+				capella,levels = <0x0A 0xA0 0xE1 0x140 0x280 0x500 0xA28 0x16A8 0x1F40 0x2800>;
+				capella,ps_close_thd_set = <0xa>;
+				capella,ps_away_thd_set = <0x5>;
+				capella,ls_cmd = <0x44>;  /* PS_IT=160ms, INT_PERS=2*/
+				capella,ps_conf1_val = <0x0006>;  /*CM36283_PS_ITB_1_2 | CM36283_PS_DR_1_40| CM36283_PS_IT_1T | CM36283_PS_PERS_2 | CM36283_PS_RES_1*/
+				capella,ps_conf3_val = <0x3010>;  /* CM36283_PS_MS_NORMAL | CM36283_PS_PROL_255 | CM36283_PS_SMART_PERS_ENABLE, */
+		};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 8827983..9fd3afe 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -9,6 +9,7 @@
 arm	ARM Ltd.
 atmel	Atmel Corporation
 bosch	Bosch Sensortec GmbH
+capella	Capella Microsystems, Inc.
 cavium	Cavium, Inc.
 chrp	Common Hardware Reference Platform
 cortina	Cortina Systems, Inc.
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 7e80d19..8ed6ae2 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -114,6 +114,23 @@
 			fsl,irq-gpio = <&msmgpio 81 0x00>;
 			fsl,sensors-position = <5>;
 		};
+		capella@60 {
+			compatible = "capella,cm36283";
+			reg = <0x60>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <80 0x2>;
+			vdd-supply = <&pm8110_l19>;
+			vio-supply = <&pm8110_l14>;
+			capella,use-polling;
+			capella,interrupt-gpio = <&msmgpio 80 0x2>;
+			capella,levels = <0x0A 0xA0 0xE1 0x140 0x280 0x500 0xA28 0x16A8 0x1F40
+				0x2800>;
+			capella,ps_close_thd_set = <0xa>;
+			capella,ps_away_thd_set = <0x5>;
+			capella,ls_cmd = <0x44>; /* PS_IT=160ms, INT_PERS=2*/
+			capella,ps_conf1_val = <0x0006>;
+			capella,ps_conf3_val = <0x3010>;
+		};
 	};
 
 	gen-vkeys {
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 68841bc..dba3da4 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -24,7 +24,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -41,7 +41,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 		};
 
@@ -58,7 +58,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 06 26 30 0f];
 	};
 
@@ -75,7 +75,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 7bf8edbe..7d96cb1 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -98,14 +98,17 @@
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
 CONFIG_INET=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
@@ -142,6 +145,7 @@
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -417,8 +421,10 @@
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_NFC_QNCI=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index a9f18fd..1d5c492 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -99,14 +99,17 @@
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
 CONFIG_INET=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
@@ -143,6 +146,7 @@
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -468,8 +472,10 @@
 CONFIG_EARLY_PRINTK=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_NFC_QNCI=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 2b76ba8..03ddb3a 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -391,3 +391,4 @@
 CONFIG_SENSORS_STK3X1X=y
 CONFIG_SENSORS_MMA8X5X=y
 CONFIG_LOGCAT_SIZE=64
+CONFIG_SENSORS_CAPELLA_CM36283=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 0f4e4c6..9788e7c 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -438,3 +438,4 @@
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_SENSORS_STK3X1X=y
 CONFIG_SENSORS_MMA8X5X=y
+CONFIG_SENSORS_CAPELLA_CM36283=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 6ad1b12..3bc159a 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -159,6 +159,7 @@
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 2976ee8..118fdd4 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -165,6 +165,7 @@
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
diff --git a/arch/arm/mach-msm/include/mach/qpnp-int.h b/arch/arm/mach-msm/include/mach/qpnp-int.h
index 2b86216..1f31ea5 100644
--- a/arch/arm/mach-msm/include/mach/qpnp-int.h
+++ b/arch/arm/mach-msm/include/mach/qpnp-int.h
@@ -71,6 +71,28 @@
  */
 int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
 		       struct qpnp_irq_spec *spec);
+
+/**
+ * qpnpint_show_irq - Prints the Linux interrupt number
+ *
+ * Pass a PMIC Arbiter interrupt to Linux.
+ */
+int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec);
+
+#ifdef CONFIG_MSM_SHOW_RESUME_IRQ
+extern int msm_show_resume_irq_mask;
+static inline bool qpnpint_show_resume_irq(void)
+{
+	return msm_show_resume_irq_mask;
+}
+#else
+static inline bool qpnpint_show_resume_irq(void)
+{
+	return false;
+}
+#endif
+
 #else
 static inline int __init qpnpint_of_init(struct device_node *node,
 				  struct device_node *parent)
@@ -97,5 +119,15 @@
 {
 	return -ENXIO;
 }
+int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return -ENXIO;
+}
+
+static inline bool qpnpint_show_resume_irq(void)
+{
+	return false;
+}
 #endif /* CONFIG_MSM_QPNP_INT */
 #endif /* QPNPINT_H */
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index aaa2fc8..716ea0d 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -704,4 +704,14 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called stk3x1x.
 
+config SENSORS_CAPELLA_CM36283
+	tristate "CM36283 proximity and light sensor"
+	depends on I2C
+	default n
+	help
+	  Say Y here to enable the CM36283 Proximity
+	  Sensor with Ambient Light Sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called CM36283.
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 445fba0..c927e0e 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -65,3 +65,4 @@
 obj-$(CONFIG_BMP18X_I2C)		+= bmp18x-i2c.o
 obj-$(CONFIG_SENSORS_MMA8X5X)	  	+= mma8x5x.o
 obj-$(CONFIG_SENSORS_STK3X1X)		+= stk3x1x.o
+obj-$(CONFIG_SENSORS_CAPELLA_CM36283)	+= cm36283.o
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index a9f8140..d850a0e 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -2,7 +2,9 @@
  *
  * Copyright (C) 2012 Capella Microsystems Inc.
  * Author: Frank Hsieh <pengyueh@gmail.com>
- *                                    
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  * may be copied, distributed, and modified under those terms.
@@ -32,6 +34,7 @@
 #include <linux/wakelock.h>
 #include <linux/jiffies.h>
 #include <linux/cm36283.h>
+#include <linux/of_gpio.h>
 
 #include <asm/uaccess.h>
 #include <asm/mach-types.h>
@@ -53,7 +56,31 @@
 #define CM36283_VI2C_MIN_UV	1750000
 #define CM36283_VI2C_MAX_UV	1950000
 
+/* cm36283 polling rate in ms */
+#define CM36283_LS_MIN_POLL_DELAY	1
+#define CM36283_LS_MAX_POLL_DELAY	1000
+#define CM36283_LS_DEFAULT_POLL_DELAY	100
+
+#define CM36283_PS_MIN_POLL_DELAY	1
+#define CM36283_PS_MAX_POLL_DELAY	1000
+#define CM36283_PS_DEFAULT_POLL_DELAY	100
+
 static int record_init_fail = 0;
+
+static const int als_range[] = {
+	[CM36283_ALS_IT0] = 6554,
+	[CM36283_ALS_IT1] = 3277,
+	[CM36283_ALS_IT2] = 1638,
+	[CM36283_ALS_IT3] = 819,
+};
+
+static const int als_sense[] = {
+	[CM36283_ALS_IT0] = 10,
+	[CM36283_ALS_IT1] = 20,
+	[CM36283_ALS_IT2] = 40,
+	[CM36283_ALS_IT3] = 80,
+};
+
 static void sensor_irq_do_work(struct work_struct *work);
 static DECLARE_WORK(sensor_irq_work, sensor_irq_do_work);
 
@@ -101,23 +128,30 @@
 
 	uint16_t ls_cmd;
 	uint8_t record_clear_int_fail;
-
+	bool polling;
+	atomic_t ls_poll_delay;
+	atomic_t ps_poll_delay;
 	struct regulator *vdd;
 	struct regulator *vio;
+	struct delayed_work ldwork;
+	struct delayed_work pdwork;
 };
 struct cm36283_info *lp_info;
 int fLevel=-1;
 static struct mutex als_enable_mutex, als_disable_mutex, als_get_adc_mutex;
 static struct mutex ps_enable_mutex, ps_disable_mutex, ps_get_adc_mutex;
 static struct mutex CM36283_control_mutex;
+static struct mutex wq_lock;
 static int lightsensor_enable(struct cm36283_info *lpi);
 static int lightsensor_disable(struct cm36283_info *lpi);
 static int initial_cm36283(struct cm36283_info *lpi);
 static void psensor_initial_cmd(struct cm36283_info *lpi);
+static int cm36283_power_set(struct cm36283_info *info, bool on);
 
 int32_t als_kadc;
 
-static int control_and_report(struct cm36283_info *lpi, uint8_t mode, uint16_t param);
+static int control_and_report(struct cm36283_info *lpi, uint8_t mode,
+		uint16_t param, int report);
 
 static int I2C_RxData(uint16_t slaveAddr, uint8_t cmd, uint8_t *rxData, int length)
 {
@@ -382,12 +416,91 @@
 {
 	struct cm36283_info *lpi = lp_info;
 	uint16_t intFlag;
-  _cm36283_I2C_Read_Word(lpi->slave_addr, INT_FLAG, &intFlag);
-	control_and_report(lpi, CONTROL_INT_ISR_REPORT, intFlag);  
-	  
+	_cm36283_I2C_Read_Word(lpi->slave_addr, INT_FLAG, &intFlag);
+	control_and_report(lpi, CONTROL_INT_ISR_REPORT, intFlag, 1);
+
 	enable_irq(lpi->irq);
 }
 
+static int get_als_range(void)
+{
+	uint16_t ls_conf;
+	int ret = 0;
+	int index = 0;
+	struct cm36283_info *lpi = lp_info;
+
+	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ALS_CONF, &ls_conf);
+	if (ret) {
+		dev_err(&lpi->i2c_client->dev, "read ALS_CONF from i2c error. %d\n",
+				ret);
+		return -EIO;
+	}
+
+	index = (ls_conf & 0xC0) >> 0x06;
+	return  als_range[index];
+}
+
+static int get_als_sense(void)
+{
+	uint16_t ls_conf;
+	int ret = 0;
+	int index = 0;
+	struct cm36283_info *lpi = lp_info;
+
+	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ALS_CONF, &ls_conf);
+	if (ret) {
+		dev_err(&lpi->i2c_client->dev, "read ALS_CONF from i2c error. %d\n",
+				ret);
+		return -EIO;
+	}
+
+	index = (ls_conf & 0xC0) >> 0x06;
+	return  als_sense[index];
+}
+
+static void psensor_delay_work_handler(struct work_struct *work)
+{
+	struct cm36283_info *lpi = lp_info;
+	uint16_t adc_value = 0;
+	int ret;
+
+	mutex_lock(&wq_lock);
+
+	ret = get_ps_adc_value(&adc_value);
+
+	mutex_unlock(&wq_lock);
+
+	if (ret >= 0) {
+		input_report_abs(lpi->ps_input_dev, ABS_DISTANCE,
+				adc_value > lpi->ps_close_thd_set ? 0 : 1);
+		input_sync(lpi->ps_input_dev);
+	}
+	schedule_delayed_work(&lpi->pdwork,
+			msecs_to_jiffies(atomic_read(&lpi->ps_poll_delay)));
+}
+
+static void lsensor_delay_work_handler(struct work_struct *work)
+{
+	struct cm36283_info *lpi = lp_info;
+	uint16_t adc_value = 0;
+	int sense;
+
+	mutex_lock(&wq_lock);
+
+	get_ls_adc_value(&adc_value, 0);
+	sense = get_als_sense();
+
+	mutex_unlock(&wq_lock);
+
+	if (sense > 0) {
+		lpi->current_adc = adc_value;
+		input_report_abs(lpi->ls_input_dev, ABS_MISC, adc_value/sense);
+		input_sync(lpi->ls_input_dev);
+	}
+	schedule_delayed_work(&lpi->ldwork,
+			msecs_to_jiffies(atomic_read(&lpi->ls_poll_delay)));
+}
+
 static irqreturn_t cm36283_irq_handler(int irq, void *data)
 {
 	struct cm36283_info *lpi = data;
@@ -431,33 +544,44 @@
 static int psensor_enable(struct cm36283_info *lpi)
 {
 	int ret = -EIO;
+	unsigned int delay;
 	
 	mutex_lock(&ps_enable_mutex);
 	D("[PS][CM36283] %s\n", __func__);
 
-	if ( lpi->ps_enable ) {
+	if (lpi->ps_enable) {
 		D("[PS][CM36283] %s: already enabled\n", __func__);
 		ret = 0;
-	} else
-  	ret = control_and_report(lpi, CONTROL_PS, 1);
-	
+	} else {
+		ret = control_and_report(lpi, CONTROL_PS, 1, 0);
+	}
+
 	mutex_unlock(&ps_enable_mutex);
+
+	delay = atomic_read(&lpi->ps_poll_delay);
+	if (lpi->polling)
+		schedule_delayed_work(&lpi->pdwork, msecs_to_jiffies(delay));
+
 	return ret;
 }
 
 static int psensor_disable(struct cm36283_info *lpi)
 {
 	int ret = -EIO;
-	
+
+	if (lpi->polling)
+		cancel_delayed_work_sync(&lpi->pdwork);
+
 	mutex_lock(&ps_disable_mutex);
 	D("[PS][CM36283] %s\n", __func__);
 
-	if ( lpi->ps_enable == 0 ) {
+	if (lpi->ps_enable == 0) {
 		D("[PS][CM36283] %s: already disabled\n", __func__);
 		ret = 0;
-	} else
-  	ret = control_and_report(lpi, CONTROL_PS,0);
-	
+	} else {
+		ret = control_and_report(lpi, CONTROL_PS, 0, 0);
+	}
+
 	mutex_unlock(&ps_disable_mutex);
 	return ret;
 }
@@ -581,6 +705,7 @@
 static int lightsensor_enable(struct cm36283_info *lpi)
 {
 	int ret = -EIO;
+	unsigned int delay;
 	
 	mutex_lock(&als_enable_mutex);
 	D("[LS][CM36283] %s\n", __func__);
@@ -588,10 +713,17 @@
 	if (lpi->als_enable) {
 		D("[LS][CM36283] %s: already enabled\n", __func__);
 		ret = 0;
-	} else
-  	ret = control_and_report(lpi, CONTROL_ALS, 1);
+	} else {
+		ret = control_and_report(lpi, CONTROL_ALS, 1, 0);
+	}
 	
 	mutex_unlock(&als_enable_mutex);
+
+	delay = atomic_read(&lpi->ls_poll_delay);
+	if (lpi->polling)
+		schedule_delayed_work(&lpi->ldwork,
+				msecs_to_jiffies(delay));
+
 	return ret;
 }
 
@@ -601,11 +733,15 @@
 	mutex_lock(&als_disable_mutex);
 	D("[LS][CM36283] %s\n", __func__);
 
+	if (lpi->polling)
+		cancel_delayed_work_sync(&lpi->ldwork);
+
 	if ( lpi->als_enable == 0 ) {
 		D("[LS][CM36283] %s: already disabled\n", __func__);
 		ret = 0;
-	} else
-    ret = control_and_report(lpi, CONTROL_ALS, 0);
+	} else {
+		ret = control_and_report(lpi, CONTROL_ALS, 0, 0);
+	}
 	
 	mutex_unlock(&als_disable_mutex);
 	return ret;
@@ -688,13 +824,14 @@
 	uint16_t value;
 	int ret;
 	struct cm36283_info *lpi = lp_info;
-	int intr_val;
-
-	intr_val = gpio_get_value(lpi->intr_pin);
+	int intr_val = -1;
 
 	get_ps_adc_value(&value);
+	if (gpio_is_valid(lpi->intr_pin))
+		intr_val = gpio_get_value(lpi->intr_pin);
 
-	ret = sprintf(buf, "ADC[0x%04X], ENABLE = %d, intr_pin = %d\n", value, lpi->ps_enable, intr_val);
+	ret = snprintf(buf, PAGE_SIZE, "ADC[0x%04X], ENABLE=%d intr_pin=%d\n",
+			value, lpi->ps_enable, intr_val);
 
 	return ret;
 }
@@ -1076,6 +1213,62 @@
 }
 static DEVICE_ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store);
 
+static ssize_t ls_poll_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cm36283_info *lpi = lp_info;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			atomic_read(&lpi->ls_poll_delay));
+}
+
+static ssize_t ls_poll_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct cm36283_info *lpi = lp_info;
+	unsigned long interval_ms;
+
+	if (kstrtoul(buf, 10, &interval_ms))
+		return -EINVAL;
+
+	if ((interval_ms < CM36283_LS_MIN_POLL_DELAY) ||
+			(interval_ms > CM36283_LS_MAX_POLL_DELAY))
+		return -EINVAL;
+
+	atomic_set(&lpi->ls_poll_delay, (unsigned int) interval_ms);
+	return count;
+}
+
+static DEVICE_ATTR(ls_poll_delay, 0664, ls_poll_delay_show,
+		ls_poll_delay_store);
+
+static ssize_t ps_poll_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cm36283_info *lpi = lp_info;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			atomic_read(&lpi->ps_poll_delay));
+}
+
+static ssize_t ps_poll_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct cm36283_info *lpi = lp_info;
+	unsigned long interval_ms;
+
+	if (kstrtoul(buf, 10, &interval_ms))
+		return -EINVAL;
+
+	if ((interval_ms < CM36283_PS_MIN_POLL_DELAY) ||
+			(interval_ms > CM36283_PS_MAX_POLL_DELAY))
+		return -EINVAL;
+
+	atomic_set(&lpi->ps_poll_delay, (unsigned int) interval_ms);
+	return count;
+}
+
+static DEVICE_ATTR(ps_poll_delay, 0664, ps_poll_delay_show,
+		ps_poll_delay_store);
+
 static ssize_t ls_fLevel_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
@@ -1103,6 +1296,7 @@
 static int lightsensor_setup(struct cm36283_info *lpi)
 {
 	int ret;
+	int range;
 
 	lpi->ls_input_dev = input_allocate_device();
 	if (!lpi->ls_input_dev) {
@@ -1113,7 +1307,9 @@
 	}
 	lpi->ls_input_dev->name = "cm36283-ls";
 	set_bit(EV_ABS, lpi->ls_input_dev->evbit);
-	input_set_abs_params(lpi->ls_input_dev, ABS_MISC, 0, 9, 0, 0);
+
+	range = get_als_range();
+	input_set_abs_params(lpi->ls_input_dev, ABS_MISC, 0, range, 0, 0);
 
 	ret = input_register_device(lpi->ls_input_dev);
 	if (ret < 0) {
@@ -1188,13 +1384,8 @@
 	D("[PS][CM36283] %s, INTERRUPT GPIO val = %d\n", __func__, val);
 
 	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ID_REG, &idReg);
-	if ((ret < 0) || (idReg != 0xC082)) {
-  		if (record_init_fail == 0)
-  			record_init_fail = 1;
-  		return -ENOMEM;/*If devices without cm36283 chip and did not probe driver*/	
-  }
-  
-	return 0;
+
+	return ret;
 }
 
 static int cm36283_setup(struct cm36283_info *lpi)
@@ -1228,14 +1419,15 @@
 	}
 	
 	/*Default disable P sensor and L sensor*/
-  ls_initial_cmd(lpi);
+	ls_initial_cmd(lpi);
 	psensor_initial_cmd(lpi);
 
-	ret = request_any_context_irq(lpi->irq,
-			cm36283_irq_handler,
-			IRQF_TRIGGER_LOW,
-			"cm36283",
-			lpi);
+	if (!lpi->polling)
+		ret = request_any_context_irq(lpi->irq,
+				cm36283_irq_handler,
+				IRQF_TRIGGER_LOW,
+				"cm36283",
+				lpi);
 	if (ret < 0) {
 		pr_err(
 			"[PS][CM36283 error]%s: req_irq(%d) fail for gpio %d (%d)\n",
@@ -1274,6 +1466,78 @@
 }
 #endif
 
+static int cm36283_parse_dt(struct device *dev,
+				struct cm36283_platform_data *pdata)
+{
+	struct device_node *np = dev->of_node;
+	u32	levels[CM36283_LEVELS_SIZE], i;
+	u32 temp_val;
+	int rc;
+
+	rc = of_get_named_gpio_flags(np, "capella,interrupt-gpio",
+			0, NULL);
+	if (rc < 0) {
+		dev_err(dev, "Unable to read interrupt pin number\n");
+		return rc;
+	} else {
+		pdata->intr = rc;
+	}
+
+	rc = of_property_read_u32_array(np, "capella,levels", levels,
+			CM36283_LEVELS_SIZE);
+	if (rc) {
+		dev_err(dev, "Unable to read levels data\n");
+		return rc;
+	} else {
+		for (i = 0; i < CM36283_LEVELS_SIZE; i++)
+			pdata->levels[i] = levels[i];
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_close_thd_set", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_close_thd_set\n");
+		return rc;
+	} else {
+		pdata->ps_close_thd_set = (u8)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_away_thd_set", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_away_thd_set\n");
+		return rc;
+	} else {
+		pdata->ps_away_thd_set = (u8)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ls_cmd", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ls_cmd\n");
+		return rc;
+	} else {
+		pdata->ls_cmd = (u16)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_conf1_val", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_conf1_val\n");
+		return rc;
+	} else {
+		pdata->ps_conf1_val = (u16)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_conf3_val", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_conf3_val\n");
+		return rc;
+	} else {
+		pdata->ps_conf3_val = (u16)temp_val;
+	}
+
+	pdata->polling = of_property_read_bool(np, "capella,use-polling");
+
+	return 0;
+}
+
 static int cm36283_probe(struct i2c_client *client,
 	const struct i2c_device_id *id)
 {
@@ -1291,12 +1555,29 @@
 	/*D("[CM36283] %s: client->irq = %d\n", __func__, client->irq);*/
 
 	lpi->i2c_client = client;
-	pdata = client->dev.platform_data;
-	if (!pdata) {
-		pr_err("[PS][CM36283 error]%s: Assign platform_data error!!\n",
-			__func__);
-		ret = -EBUSY;
-		goto err_platform_data_null;
+
+	if (client->dev.of_node) {
+		pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev, "Failed to allocate memory for pdata\n");
+			ret = -ENOMEM;
+			goto err_platform_data_null;
+		}
+
+		ret = cm36283_parse_dt(&client->dev, pdata);
+		pdata->slave_addr = client->addr;
+		if (ret) {
+			dev_err(&client->dev, "Failed to get pdata from device tree\n");
+			goto err_parse_dt;
+		}
+	} else {
+		pdata = client->dev.platform_data;
+		if (!pdata) {
+			dev_err(&client->dev, "%s: Assign platform_data error!!\n",
+					__func__);
+			ret = -EBUSY;
+			goto err_platform_data_null;
+		}
 	}
 
 	lpi->irq = client->irq;
@@ -1313,6 +1594,12 @@
 	lpi->ps_close_thd_set = pdata->ps_close_thd_set;	
 	lpi->ps_conf1_val = pdata->ps_conf1_val;
 	lpi->ps_conf3_val = pdata->ps_conf3_val;
+	lpi->polling = pdata->polling;
+	atomic_set(&lpi->ls_poll_delay,
+			(unsigned int) CM36283_LS_DEFAULT_POLL_DELAY);
+	atomic_set(&lpi->ps_poll_delay,
+			(unsigned int) CM36283_PS_DEFAULT_POLL_DELAY);
+
 	
 	lpi->ls_cmd  = pdata->ls_cmd;
 	
@@ -1333,23 +1620,11 @@
 	mutex_init(&als_disable_mutex);
 	mutex_init(&als_get_adc_mutex);
 
-	ret = lightsensor_setup(lpi);
-	if (ret < 0) {
-		pr_err("[LS][CM36283 error]%s: lightsensor_setup error!!\n",
-			__func__);
-		goto err_lightsensor_setup;
-	}
 
 	mutex_init(&ps_enable_mutex);
 	mutex_init(&ps_disable_mutex);
 	mutex_init(&ps_get_adc_mutex);
 
-	ret = psensor_setup(lpi);
-	if (ret < 0) {
-		pr_err("[PS][CM36283 error]%s: psensor_setup error!!\n",
-			__func__);
-		goto err_psensor_setup;
-	}
 
   //SET LUX STEP FACTOR HERE
   // if adc raw value one step = 5/100 = 1/20 = 0.05 lux
@@ -1379,11 +1654,32 @@
 	}
 	wake_lock_init(&(lpi->ps_wake_lock), WAKE_LOCK_SUSPEND, "proximity");
 
+	ret = cm36283_power_set(lpi, true);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s:cm36283 power on error!\n", __func__);
+		goto err_cm36283_power_on;
+	}
+
 	ret = cm36283_setup(lpi);
 	if (ret < 0) {
 		pr_err("[PS_ERR][CM36283 error]%s: cm36283_setup error!\n", __func__);
 		goto err_cm36283_setup;
 	}
+
+	ret = lightsensor_setup(lpi);
+	if (ret < 0) {
+		pr_err("[LS][CM36283 error]%s: lightsensor_setup error!!\n",
+			__func__);
+		goto err_lightsensor_setup;
+	}
+
+	ret = psensor_setup(lpi);
+	if (ret < 0) {
+		pr_err("[PS][CM36283 error]%s: psensor_setup error!!\n",
+			__func__);
+		goto err_psensor_setup;
+	}
+
 	lpi->cm36283_class = class_create(THIS_MODULE, "optical_sensors");
 	if (IS_ERR(lpi->cm36283_class)) {
 		ret = PTR_ERR(lpi->cm36283_class);
@@ -1430,37 +1726,45 @@
 	if (ret)
 		goto err_create_ls_device_file;
 
+	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_poll_delay);
+	if (ret)
+		goto err_create_ls_device_file;
+
 	lpi->ps_dev = device_create(lpi->cm36283_class,
 				NULL, 0, "%s", "proximity");
 	if (unlikely(IS_ERR(lpi->ps_dev))) {
 		ret = PTR_ERR(lpi->ps_dev);
 		lpi->ps_dev = NULL;
-		goto err_create_ls_device_file;
+		goto err_create_ps_device;
 	}
 
 	/* register the attributes */
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_adc);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	ret = device_create_file(lpi->ps_dev,
 		&dev_attr_ps_parameters);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	/* register the attributes */
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_conf);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	/* register the attributes */
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_thd);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_hw);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
+
+	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_poll_delay);
+	if (ret)
+		goto err_create_ps_device_file;
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 	lpi->early_suspend.level =
@@ -1470,47 +1774,59 @@
 	register_early_suspend(&lpi->early_suspend);
 #endif
 
+	mutex_init(&wq_lock);
+	INIT_DELAYED_WORK(&lpi->ldwork, lsensor_delay_work_handler);
+	INIT_DELAYED_WORK(&lpi->pdwork, psensor_delay_work_handler);
 	D("[PS][CM36283] %s: Probe success!\n", __func__);
 
 	return ret;
 
-err_create_ps_device:
+err_create_ps_device_file:
 	device_unregister(lpi->ps_dev);
+err_create_ps_device:
 err_create_ls_device_file:
 	device_unregister(lpi->ls_dev);
 err_create_ls_device:
 	class_destroy(lpi->cm36283_class);
 err_create_class:
-err_cm36283_setup:
-	destroy_workqueue(lpi->lp_wq);
-	wake_lock_destroy(&(lpi->ps_wake_lock));
-
-	input_unregister_device(lpi->ls_input_dev);
-	input_free_device(lpi->ls_input_dev);
+	misc_deregister(&psensor_misc);
 	input_unregister_device(lpi->ps_input_dev);
 	input_free_device(lpi->ps_input_dev);
+err_psensor_setup:
+	misc_deregister(&lightsensor_misc);
+	input_unregister_device(lpi->ls_input_dev);
+	input_free_device(lpi->ls_input_dev);
+err_lightsensor_setup:
+err_cm36283_setup:
+	cm36283_power_set(lpi, false);
+err_cm36283_power_on:
+	wake_lock_destroy(&(lpi->ps_wake_lock));
+	destroy_workqueue(lpi->lp_wq);
 err_create_singlethread_workqueue:
 err_lightsensor_update_table:
-	misc_deregister(&psensor_misc);
-err_psensor_setup:
 	mutex_destroy(&CM36283_control_mutex);
-	mutex_destroy(&ps_enable_mutex);
-	mutex_destroy(&ps_disable_mutex);
-	mutex_destroy(&ps_get_adc_mutex);
-	misc_deregister(&lightsensor_misc);
-err_lightsensor_setup:
 	mutex_destroy(&als_enable_mutex);
 	mutex_destroy(&als_disable_mutex);
 	mutex_destroy(&als_get_adc_mutex);
+	mutex_destroy(&ps_enable_mutex);
+	mutex_destroy(&ps_disable_mutex);
+	mutex_destroy(&ps_get_adc_mutex);
+err_parse_dt:
+	if (client->dev.of_node && (pdata != NULL))
+		devm_kfree(&client->dev, pdata);
 err_platform_data_null:
 	kfree(lpi);
+	dev_err(&client->dev, "%s:error exit! ret = %d\n", __func__, ret);
+
 	return ret;
 }
-   
-static int control_and_report( struct cm36283_info *lpi, uint8_t mode, uint16_t param ) {
-  int ret=0;
+
+static int control_and_report(struct cm36283_info *lpi, uint8_t mode,
+	uint16_t param, int report)
+{
+	int ret = 0;
 	uint16_t adc_value = 0;
-	uint16_t ps_data = 0;	
+	uint16_t ps_data = 0;
 	int level = 0, i, val;
 	
   mutex_lock(&CM36283_control_mutex);
@@ -1575,63 +1891,62 @@
       		  }
       	  }
     	  }
-    
-    	  ret = set_lsensor_range(((i == 0) || (adc_value == 0)) ? 0 :
-    		   	*(lpi->cali_table + (i - 1)) + 1,
-    		    *(lpi->cali_table + i));
-    	  
-        lpi->ls_cmd |= CM36283_ALS_INT_EN;
-    	  
-        ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);  
-    	  
-    		if ((i == 0) || (adc_value == 0))
-    			D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd equal 0, h_thd = 0x%x \n",
-    				__func__, adc_value, level, *(lpi->cali_table + i));
-    		else
-    			D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd = 0x%x, h_thd = 0x%x \n",
-    				__func__, adc_value, level, *(lpi->cali_table + (i - 1)) + 1, *(lpi->cali_table + i));
-    		lpi->current_level = level;
-    		lpi->current_adc = adc_value;    
-        input_report_abs(lpi->ls_input_dev, ABS_MISC, level);
-        input_sync(lpi->ls_input_dev);
+	if (!lpi->polling) {
+		ret = set_lsensor_range(((i == 0) ||
+					(adc_value == 0)) ? 0 :
+				*(lpi->cali_table + (i - 1)) + 1,
+				*(lpi->cali_table + i));
+
+		lpi->ls_cmd |= CM36283_ALS_INT_EN;
+	}
+
+	ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF,
+			lpi->ls_cmd);
+
+	if (report) {
+		lpi->current_level = level;
+		lpi->current_adc = adc_value;
+		input_report_abs(lpi->ls_input_dev, ABS_MISC, level);
+		input_sync(lpi->ls_input_dev);
+	}
     }
   }
 
 #define PS_CLOSE 1
 #define PS_AWAY  (1<<1)
 #define PS_CLOSE_AND_AWAY PS_CLOSE+PS_AWAY
+	if (report && (lpi->ps_enable)) {
+		int ps_status = 0;
+		if (mode == CONTROL_PS)
+			ps_status = PS_CLOSE_AND_AWAY;
+		else if (mode == CONTROL_INT_ISR_REPORT) {
+			if (param & INT_FLAG_PS_IF_CLOSE)
+				ps_status |= PS_CLOSE;
+			if (param & INT_FLAG_PS_IF_AWAY)
+				ps_status |= PS_AWAY;
+		}
 
-  if(lpi->ps_enable){
-    int ps_status = 0;
-    if( mode == CONTROL_PS )
-      ps_status = PS_CLOSE_AND_AWAY;   
-    else if(mode == CONTROL_INT_ISR_REPORT ){  
-      if ( param & INT_FLAG_PS_IF_CLOSE )
-        ps_status |= PS_CLOSE;      
-      if ( param & INT_FLAG_PS_IF_AWAY )
-        ps_status |= PS_AWAY;
-    }
-      
-    if (ps_status!=0){
-      switch(ps_status){
-        case PS_CLOSE_AND_AWAY:
-          get_stable_ps_adc_value(&ps_data);
-          val = (ps_data >= lpi->ps_close_thd_set) ? 0 : 1;
-          break;
-        case PS_AWAY:
-          val = 1;
-          break;
-        case PS_CLOSE:
-          val = 0;
-          break;
-        };
-      input_report_abs(lpi->ps_input_dev, ABS_DISTANCE, val);      
-      input_sync(lpi->ps_input_dev);        
-    }
-  }
+		if (ps_status != 0) {
+			switch (ps_status) {
+			case PS_CLOSE_AND_AWAY:
+				get_stable_ps_adc_value(&ps_data);
+				val = (ps_data >= lpi->ps_close_thd_set)
+					? 0 : 1;
+				break;
+			case PS_AWAY:
+				val = 1;
+				break;
+			case PS_CLOSE:
+				val = 0;
+				break;
+			};
+			input_report_abs(lpi->ps_input_dev, ABS_DISTANCE, val);
+			input_sync(lpi->ps_input_dev);
+		}
+	}
 
-  mutex_unlock(&CM36283_control_mutex);
-  return ret;
+	mutex_unlock(&CM36283_control_mutex);
+	return ret;
 }
 
 static int cm36283_power_set(struct cm36283_info *info, bool on)
@@ -1769,6 +2084,11 @@
 	{}
 };
 
+static struct of_device_id cm36283_match_table[] = {
+	{ .compatible = "capella,cm36283",},
+	{ },
+};
+
 static struct i2c_driver cm36283_driver = {
 	.id_table = cm36283_i2c_id,
 	.probe = cm36283_probe,
@@ -1776,6 +2096,7 @@
 		.name = CM36283_I2C_NAME,
 		.owner = THIS_MODULE,
 		.pm = &cm36283_pm,
+		.of_match_table = cm36283_match_table,
 	},
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 32cf0d3..9384a5b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -124,7 +124,6 @@
 		j++;
 		lane_mask >>= 1;
 	}
-	msleep(20);
 	return rc;
 }
 
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index 03e9021..3e14333 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -591,8 +591,9 @@
 }
 EXPORT_SYMBOL(qpnpint_unregister_controller);
 
-int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
-		       struct qpnp_irq_spec *spec)
+static int __qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec,
+		       bool show)
 {
 	struct irq_domain *domain;
 	unsigned long hwirq, busno;
@@ -617,12 +618,40 @@
 	domain = chip_lookup[busno]->domain;
 	irq = irq_radix_revmap_lookup(domain, hwirq);
 
-	generic_handle_irq(irq);
+	if (show) {
+		struct irq_desc *desc;
+		const char *name = "null";
+
+		desc = irq_to_desc(irq);
+		if (desc == NULL)
+			name = "stray irq";
+		else if (desc->action && desc->action->name)
+			name = desc->action->name;
+
+		pr_warn("%d triggered [0x%01x, 0x%02x,0x%01x] %s\n",
+				irq, spec->slave, spec->per, spec->irq, name);
+	} else {
+		generic_handle_irq(irq);
+	}
 
 	return 0;
 }
+
+int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return  __qpnpint_handle_irq(spmi_ctrl, spec, false);
+}
+
 EXPORT_SYMBOL(qpnpint_handle_irq);
 
+int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return  __qpnpint_handle_irq(spmi_ctrl, spec, true);
+}
+EXPORT_SYMBOL(qpnpint_show_irq);
+
 int __init qpnpint_of_init(struct device_node *node, struct device_node *parent)
 {
 	struct q_chip_data *chip_d;
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index f85a576..bc328e0 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -24,6 +24,7 @@
 #include <linux/of_spmi.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
+#include <linux/syscore_ops.h>
 #include <mach/qpnp-int.h>
 #include "spmi-dbgfs.h"
 
@@ -126,9 +127,12 @@
 	u32			mapping_table[SPMI_MAPPING_TABLE_LEN];
 };
 
+static struct spmi_pmic_arb_dev *the_pmic_arb;
+
 static u32 pmic_arb_read(struct spmi_pmic_arb_dev *dev, u32 offset)
 {
 	u32 val = readl_relaxed(dev->base + offset);
+
 	pr_debug("address 0x%p, val 0x%x\n", dev->base + offset, val);
 	return val;
 }
@@ -485,7 +489,7 @@
 }
 
 static irqreturn_t
-periph_interrupt(struct spmi_pmic_arb_dev *pmic_arb, u8 apid)
+periph_interrupt(struct spmi_pmic_arb_dev *pmic_arb, u8 apid, bool show)
 {
 	u16 ppid = get_peripheral_id(pmic_arb, apid);
 	void __iomem *intr = pmic_arb->intr;
@@ -511,10 +515,12 @@
 	/* Read the peripheral specific interrupt bits */
 	status = readl_relaxed(intr + SPMI_PIC_IRQ_STATUS(apid));
 
-	/* Clear the peripheral interrupts */
-	writel_relaxed(status, intr + SPMI_PIC_IRQ_CLEAR(apid));
-	/* Interrupt needs to be cleared/acknowledged before exiting ISR */
-	mb();
+	if (!show) {
+		/* Clear the peripheral interrupts */
+		writel_relaxed(status, intr + SPMI_PIC_IRQ_CLEAR(apid));
+		/* Irq needs to be cleared/acknowledged before exiting ISR */
+		mb();
+	}
 
 	dev_dbg(pmic_arb->dev,
 		"interrupt, apid:0x%x, sid:0x%x, pid:0x%x, intr:0x%x\n",
@@ -528,14 +534,20 @@
 				.per = pid,
 				.irq = i,
 			};
-			qpnpint_handle_irq(&pmic_arb->controller, &irq_spec);
+			if (show)
+				qpnpint_show_irq(&pmic_arb->controller,
+								&irq_spec);
+			else
+				qpnpint_handle_irq(&pmic_arb->controller,
+								&irq_spec);
 		}
 	}
 	return IRQ_HANDLED;
 }
 
 /* Peripheral interrupt handler */
-static irqreturn_t pmic_arb_periph_irq(int irq, void *dev_id)
+static irqreturn_t
+__pmic_arb_periph_irq(int irq, void *dev_id, bool show)
 {
 	struct spmi_pmic_arb_dev *pmic_arb = dev_id;
 	void __iomem *intr = pmic_arb->intr;
@@ -556,7 +568,8 @@
 		for (j = 0; status && j < 32; ++j, status >>= 1) {
 			if (status & 0x1) {
 				u8 id = (i * 32) + j;
-				ret |= periph_interrupt(pmic_arb, id);
+
+				ret |= periph_interrupt(pmic_arb, id, show);
 			}
 		}
 	}
@@ -564,6 +577,22 @@
 	return ret;
 }
 
+static irqreturn_t pmic_arb_periph_irq(int irq, void *dev_id)
+{
+	return __pmic_arb_periph_irq(irq, dev_id, false);
+}
+
+static void spmi_pmic_arb_resume(void)
+{
+	if (qpnpint_show_resume_irq())
+		__pmic_arb_periph_irq(the_pmic_arb->pic_irq,
+						the_pmic_arb, true);
+}
+
+static struct syscore_ops spmi_pmic_arb_syscore_ops = {
+	.resume = spmi_pmic_arb_resume,
+};
+
 /* Callback to register an APID for specific slave/peripheral */
 static int pmic_arb_intr_priv_data(struct spmi_controller *ctrl,
 				struct qpnp_irq_spec *spec, uint32_t *data)
@@ -766,6 +795,9 @@
 	pr_debug("PMIC Arb Version 0x%x\n",
 			pmic_arb_read(pmic_arb, PMIC_ARB_VERSION));
 
+	the_pmic_arb = pmic_arb;
+	register_syscore_ops(&spmi_pmic_arb_syscore_ops);
+
 	return 0;
 
 err_reg_controller:
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index fcc5a8d..613af4e 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -164,7 +164,7 @@
 #define TSENS10_POINT2_BACKUP_MASK	0x3f000000
 
 #define TSENS_8X26_BASE0_MASK		0x1fe000
-#define TSENS0_8X26_POINT1_MASK		0x7f00000
+#define TSENS0_8X26_POINT1_MASK		0x7e00000
 #define TSENS1_8X26_POINT1_MASK		0x3f
 #define TSENS2_8X26_POINT1_MASK		0xfc0
 #define TSENS3_8X26_POINT1_MASK		0x3f000
@@ -174,11 +174,11 @@
 #define TSENS_8X26_TSENS_CAL_SEL	0xe0000000
 #define TSENS_8X26_BASE1_MASK		0xff
 #define TSENS0_8X26_POINT2_MASK		0x3f00
-#define TSENS1_8X26_POINT2_MASK		0xfc00
+#define TSENS1_8X26_POINT2_MASK		0xfc000
 #define TSENS2_8X26_POINT2_MASK		0x3f00000
 #define TSENS3_8X26_POINT2_MASK		0xfc000000
-#define TSENS4_8X26_POINT2_MASK		0xfc000000
-#define TSENS5_8X26_POINT2_MASK		0x3f00000
+#define TSENS4_8X26_POINT2_MASK		0x3f00000
+#define TSENS5_8X26_POINT2_MASK		0xfc000000
 #define TSENS6_8X26_POINT2_MASK		0x7e0000
 
 #define TSENS_8X26_CAL_SEL_SHIFT	29
diff --git a/include/linux/cm36283.h b/include/linux/cm36283.h
index 362b709..2872d04 100644
--- a/include/linux/cm36283.h
+++ b/include/linux/cm36283.h
@@ -120,6 +120,15 @@
 extern unsigned int ps_kparam1;
 extern unsigned int ps_kparam2;
 
+#define CM36283_LEVELS_SIZE		10
+
+enum {
+	CM36283_ALS_IT0 = 0,
+	CM36283_ALS_IT1,
+	CM36283_ALS_IT2,
+	CM36283_ALS_IT3,
+};
+
 struct cm36283_platform_data {
 	int intr;
 	uint16_t levels[10];
@@ -131,6 +140,7 @@
 	uint16_t ls_cmd;
 	uint16_t ps_conf1_val;
 	uint16_t ps_conf3_val;	
+	bool polling;
 };
 
 #endif
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 88fcf61..fb58d12 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -82,14 +82,15 @@
 */
 #define ADM_CMD_DEVICE_OPEN_V5                          0x00010326
 
-#define ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG                           13
+/* Definition for a low latency stream session. */
+#define ADM_LOW_LATENCY_DEVICE_SESSION			0x2000
+
+/* Definition for a ultra low latency stream session. */
+#define ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION		0x4000
 
 /* Definition for a legacy device session. */
 #define ADM_LEGACY_DEVICE_SESSION                                      0
 
-/* Definition for a low latency stream session. */
-#define ADM_LOW_LATENCY_DEVICE_SESSION                                 1
-
 /* Indicates that endpoint_id_2 is to be ignored.*/
 #define ADM_CMD_COPP_OPEN_END_POINT_ID_2_IGNORE				0xFFFF
 
@@ -3816,11 +3817,12 @@
 #define ASM_STREAM_CMD_OPEN_WRITE_V2       0x00010D8F
 #define ASM_STREAM_CMD_OPEN_WRITE_V3       0x00010DB3
 
-#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE                     28
+#define ASM_LOW_LATENCY_STREAM_SESSION				0x10000000
+
+#define ASM_ULTRA_LOW_LATENCY_STREAM_SESSION			0x20000000
 
 #define ASM_LEGACY_STREAM_SESSION                                      0
 
-#define ASM_LOW_LATENCY_STREAM_SESSION                                  1
 
 struct asm_stream_cmd_open_write_v3 {
 	struct apr_hdr			hdr;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index de60430..62fe6d2 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -371,8 +371,12 @@
 		msm_send_eq_values(fedai_id);
 	topology = get_topology(path_type);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions) && perf_mode)
-			set_bit(fedai_id, &msm_bedais[i].perf_mode);
+		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions)) {
+			if (perf_mode)
+				set_bit(fedai_id, &msm_bedais[i].perf_mode);
+			else
+				clear_bit(fedai_id, &msm_bedais[i].perf_mode);
+		}
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index b1f968d..d99812f 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -522,7 +522,6 @@
 				/* Should only come here if there is an APR */
 				/* error or malformed APR packet. Otherwise */
 				/* response will be returned as */
-				/* ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
 				if (payload[1] != 0) {
 					pr_err("%s: ADM map error, resuming\n",
 						__func__);
@@ -967,11 +966,9 @@
 		open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
 		open.flags = 0x00;
 		if (perf_mode) {
-			open.flags |= ADM_LOW_LATENCY_DEVICE_SESSION <<
-				ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+			open.flags |= ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
 		} else {
-			open.flags |= ADM_LEGACY_DEVICE_SESSION <<
-				ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+			open.flags |= ADM_LEGACY_DEVICE_SESSION;
 		}
 
 		open.mode_of_operation = path;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 6a34470..1abc47d 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1504,11 +1504,9 @@
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open.mode_flags = 0x00;
 	if (ac->perf_mode)
-		open.mode_flags |= (ASM_LOW_LATENCY_STREAM_SESSION <<
-				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+		open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
 	else
-		open.mode_flags |= (ASM_LEGACY_STREAM_SESSION <<
-				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+		open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
 
 	/* source endpoint : matrix */
 	open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;