Merge "msm7627a: Add support for evaluation board platform"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 9f796c0..6cf6264 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -842,19 +842,20 @@
 void cmd_erase_mmc(const char *arg, void *data, unsigned sz)
 {
 	unsigned long long ptn = 0;
+	unsigned int out[512] = {0};
 	int index = INVALID_PTN;
-	unsigned long long size;
 
 	index = partition_get_index(arg);
 	ptn = partition_get_offset(index);
-	size = partition_get_size(index);
 
 	if(ptn == 0) {
 		fastboot_fail("Partition table doesn't exist\n");
 		return;
 	}
-	if (mmc_erase_card(ptn, size)) {
-		fastboot_fail("Failed to erase partition\n");
+	/* Simple inefficient version of erase. Just writing
+       0 in first block */
+	if (mmc_write(ptn , 512, (unsigned int *)out)) {
+		fastboot_fail("failed to erase partition");
 		return;
 	}
 	fastboot_okay("");
@@ -1275,6 +1276,7 @@
 	fastboot_register("oem device-info", cmd_oem_devinfo);
 	fastboot_publish("product", TARGET(BOARD));
 	fastboot_publish("kernel", "lk");
+	fastboot_publish("serialno", sn_buf);
 	partition_dump();
 	sz = target_get_max_flash_size();
 	fastboot_init(target_get_scratch_address(), sz);
diff --git a/app/aboot/fastboot.c b/app/aboot/fastboot.c
index 0b3d166..2b699b3 100644
--- a/app/aboot/fastboot.c
+++ b/app/aboot/fastboot.c
@@ -376,6 +376,10 @@
 	fastboot_publish("version", "0.5");
 
 	thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
+	if (!thr)
+	{
+		goto fail_alloc_in;
+	}
 	thread_resume(thr);
 	return 0;
 
diff --git a/app/app.c b/app/app.c
index 2aad5f4..547659a 100644
--- a/app/app.c
+++ b/app/app.c
@@ -59,8 +59,14 @@
 
 static void start_app(const struct app_descriptor *app)
 {
+	thread_t *thr;
 	printf("starting app %s\n", app->name);
 
-	thread_resume(thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));	
+	thr = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+	if(!thr)
+	{
+		return;
+	}
+	thread_resume(thr);
 }
 
diff --git a/app/tests/led_tests.c b/app/tests/led_tests.c
new file mode 100644
index 0000000..97c6039
--- /dev/null
+++ b/app/tests/led_tests.c
@@ -0,0 +1,43 @@
+#include<dev/pm8921_leds.h>
+#include<dev/pm8921.h>
+
+void led_tests()
+{
+uint32_t duty_us, period_us;
+
+    /* 50% Duty cycle */
+    duty_us = 500000;
+    period_us = 1000000;
+
+    /* Configure PM8921_ID_LED_0 from PWM2*/
+    pm8921_config_led_current(PM8921_ID_LED_0, 2, PWM2, 1);
+
+    /* PWM2 for PM8921_ID_LED_0 is LPG 5
+     * Configure and enable lpg5
+     */
+    pm_set_pwm_config(5, duty_us, period_us, &pmic);
+    pm_pwm_channel_enable(5, &pmic);
+
+    /* Configure and enable lpg0 for  panel backlight*/
+    pm_set_pwm_config(0, duty_us, period_us, &pmic);
+    pm_pwm_channel_enable(0, &pmic);
+
+    mdelay(10000);
+
+    /* Configure PM8921_ID_LED_1 also from PWM2*/
+    pm8921_config_led_current(PM8921_ID_LED_1, 2, PWM2, 1);
+    mdelay(10000);
+
+    /* Disable PM8921_ID_LED_0 */
+    pm8921_config_led_current(PM8921_ID_LED_0, 2, 2, 0);
+
+    /* Turn on GPIO 24 through LPG 0
+     * Will be reconfigured during display_init
+     */
+    panel_backlight_on_pwm();
+
+    mdelay(10000);
+
+    /* Disable PM8921_ID_LED_1 */
+    pm8921_config_led_current(PM8921_ID_LED_1, 2, 2, 0);
+}
diff --git a/arch/arm/include/arch/arm/mmu.h b/arch/arm/include/arch/arm/mmu.h
index 1b777a3..d5067eb 100644
--- a/arch/arm/include/arch/arm/mmu.h
+++ b/arch/arm/include/arch/arm/mmu.h
@@ -47,6 +47,8 @@
 #define MMU_MEMORY_AP_READ_ONLY     (0x7 << 10)
 #define MMU_MEMORY_AP_READ_WRITE    (0x3 << 10)
 
+#define MMU_MEMORY_XN               (0x1 << 4)
+
 #else
 
 #error "MMU implementation needs to be updated for this ARM architecture"
diff --git a/dev/pmic/pm8921/include/dev/pm8921.h b/dev/pmic/pm8921/include/dev/pm8921.h
index 7c2b271..e2c185b 100644
--- a/dev/pmic/pm8921/include/dev/pm8921.h
+++ b/dev/pmic/pm8921/include/dev/pm8921.h
@@ -30,7 +30,7 @@
 #define __DEV_PM8921_H
 
 #include <sys/types.h>
-
+#include <dev/pm8921_leds.h>
 
 #define PM_GPIO_DIR_OUT         0x01
 #define PM_GPIO_DIR_IN          0x02
@@ -109,5 +109,12 @@
 int  pm8921_ldo_set_voltage(uint32_t ldo_id, uint32_t voltage);
 int  pm8921_config_reset_pwr_off(unsigned reset);
 int  pm8921_gpio_get(uint8_t gpio, uint8_t *status);
+int pm8921_config_led_current(enum pm8921_leds led_num,
+	uint8_t current,
+	enum led_mode sink,
+	int enable);
+int pm8921_config_drv_keypad(unsigned int drv_flash_sel,
+	unsigned int flash_logic,
+	unsigned int flash_ensel);
 
 #endif
diff --git a/dev/pmic/pm8921/include/dev/pm8921_leds.h b/dev/pmic/pm8921/include/dev/pm8921_leds.h
new file mode 100644
index 0000000..faad2f5
--- /dev/null
+++ b/dev/pmic/pm8921/include/dev/pm8921_leds.h
@@ -0,0 +1,99 @@
+/*
+ * * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PMIC_LED_H
+#define __PMIC_LED_H
+
+/* LED CNTL register */
+#define LED_CNTL_BASE                    0x131
+#define PM8921_LED_CNTL_REG(n)           (LED_CNTL_BASE + n)
+
+#define LED_DRV0_CNTL                    PM8921_LED_CNTL_REG(0)
+#define LED_DRV1_CNTL                    PM8921_LED_CNTL_REG(1)
+#define LED_DRV2_CNTL                    PM8921_LED_CNTL_REG(2)
+
+/* LED CNTL setting */
+
+/* Current settings:
+ * [00000, 10100]: Iout = x * 2 mA
+ * [10101, 11111]: invalid settings
+ */
+
+#define LED_CURRENT_SET(x)              ((x) << 3)
+#define LED_SIGNAL_SELECT(x)            ((x) << 0)
+
+#define PM8921_DRV_KEYPAD_CNTL_REG      0x48
+
+/* Keypad DRV CNTL Settings */
+
+#define DRV_FLASH_SEL(x)                ((x) << 4)
+#define FLASH_LOGIC_SEL(x)              ((x) << 2)
+#define FLASH_ENSEL(x)                  ((x) << 0)
+
+#define MAX_LC_LED_BRIGHTNESS           20
+#define MAX_FLASH_BRIGHTNESS            15
+#define MAX_KB_LED_BRIGHTNESS           15
+
+/*
+ * led ids
+ * @PM8921_ID_LED_0 - First low current led
+ * @PM8921_ID_LED_1 - Second low current led
+ * @PM8921_ID_LED_2 - Third low current led
+ */
+
+enum pm8921_leds {
+	PM8921_ID_LED_0,
+	PM8921_ID_LED_1,
+	PM8921_ID_LED_2,
+};
+
+enum led_mode{
+	MANUAL,
+	PWM1,
+	PWM2,
+	PWM3,
+	DBUS1,
+	DBUS2,
+	DBUS3,
+	DBUS4,
+};
+
+enum kp_backlight_mode{
+	MANUAL_MODE,
+	DBUS1_MODE,
+	DBUS2_MODE,
+	LPG_MODE,
+};
+
+enum kp_backlight_flash_logic{
+	FLASH_ON_WITH_DTEST_HIGH,
+	FLASH_ON_WITH_DTEST_LOW,
+};
+
+#endif
diff --git a/dev/pmic/pm8921/include/dev/pm8921_pwm.h b/dev/pmic/pm8921/include/dev/pm8921_pwm.h
new file mode 100644
index 0000000..23b0930
--- /dev/null
+++ b/dev/pmic/pm8921/include/dev/pm8921_pwm.h
@@ -0,0 +1,166 @@
+/*
+ * * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PMIC_PWM_H
+#define __PMIC_PWM_H
+
+/* PMIC 8921 LPG defines */
+
+#define PM8921_LPG_CTL_BASE         (0x13C)
+
+#define PM8921_LPG_CTL(n)           (PM8921_LPG_CTL_BASE + (n))
+#define PM8921_LPG_BANK_SEL         (0x143)
+#define PM8921_LPG_BANK_ENABLE      (0x144)
+
+#define USEC_PER_SEC                1000000L
+#define NSEC_PER_SEC                1000000000L
+#define NSEC_PER_USEC               1000
+
+#define PWM_FREQ_HZ                 300
+#define PWM_LEVEL                   15
+
+#define NUM_CLOCKS                  3
+#define NUM_PRE_DIVIDE              4
+
+#define NUM_LPG_CTL_REGS            7
+
+#define PRE_DIVIDE_0                2
+#define PRE_DIVIDE_1                3
+#define PRE_DIVIDE_2                5
+#define PRE_DIVIDE_3                6
+
+#define PRE_DIVIDE_MIN              PRE_DIVIDE_0
+#define PRE_DIVIDE_MAX              PRE_DIVIDE_3
+
+#define PM_PWM_M_MIN                0
+#define PM_PWM_M_MAX                7
+
+#define NSEC_1000HZ                (NSEC_PER_SEC / 1000)
+#define NSEC_32768HZ               (NSEC_PER_SEC / 32768)
+#define NSEC_19P2MHZ               (NSEC_PER_SEC / 19200000)
+
+#define CLK_PERIOD_MIN             NSEC_19P2MHZ
+#define CLK_PERIOD_MAX             NSEC_1000HZ
+
+#define MIN_MPT                    ((PRE_DIVIDE_MIN * CLK_PERIOD_MIN) << PM_PWM_M_MIN)
+#define MAX_MPT                    ((PRE_DIVIDE_MAX * CLK_PERIOD_MAX) << PM_PWM_M_MAX)
+
+/* The MAX value is computation limit. Hardware limit is 393 seconds. */
+#define PM_PWM_PERIOD_MAX          (274 * USEC_PER_SEC)
+/* The MIN value is hardware limit. */
+#define PM_PWM_PERIOD_MIN          7 /* micro seconds */
+
+#define PWM_PERIOD_USEC           (USEC_PER_SEC / PWM_FREQ_HZ)
+#define PWM_DUTY_LEVEL            (PWM_PERIOD_USEC / PWM_LEVEL)
+
+/* Control 0 */
+#define PM_PWM_1KHZ_COUNT_MASK    0xF0
+#define PM_PWM_1KHZ_COUNT_SHIFT   4
+
+#define PM_PWM_1KHZ_COUNT_MAX     15
+
+#define PM_PWM_OUTPUT_EN          0x08
+#define PM_PWM_PWM_EN             0x04
+#define PM_PWM_RAMP_GEN_EN        0x02
+#define PM_PWM_RAMP_START         0x01
+
+#define PM_PWM_PWM_START          (PM_PWM_OUTPUT_EN | PM_PWM_PWM_EN)
+#define PM_PWM_RAMP_GEN_START     (PM_PWM_RAMP_GEN_EN | PM_PWM_RAMP_START)
+
+/* Control 1 */
+#define PM_PWM_REVERSE_EN         0x80
+#define PM_PWM_BYPASS_LUT         0x40
+#define PM_PWM_HIGH_INDEX_MASK    0x3F
+
+/* Control 2 */
+#define PM_PWM_LOOP_EN            0x80
+#define PM_PWM_RAMP_UP            0x40
+#define PM_PWM_LOW_INDEX_MASK     0x3F
+
+/* Control 3 */
+#define PM_PWM_VALUE_BIT7_0       0xFF
+#define PM_PWM_VALUE_BIT5_0       0x3F
+
+/* Control 4 */
+#define PM_PWM_VALUE_BIT8         0x80
+
+#define PM_PWM_CLK_SEL_MASK       0x60
+#define PM_PWM_CLK_SEL_SHIFT      5
+
+#define PM_PWM_CLK_SEL_NO         0
+#define PM_PWM_CLK_SEL_1KHZ       1
+#define PM_PWM_CLK_SEL_32KHZ      2
+#define PM_PWM_CLK_SEL_19P2MHZ    3
+
+#define PM_PWM_PREDIVIDE_MASK     0x18
+#define PM_PWM_PREDIVIDE_SHIFT    3
+
+#define PM_PWM_PREDIVIDE_2        0
+#define PM_PWM_PREDIVIDE_3        1
+#define PM_PWM_PREDIVIDE_5        2
+#define PM_PWM_PREDIVIDE_6        3
+
+#define PM_PWM_M_MASK             0x07
+#define PM_PWM_M_MIN              0
+#define PM_PWM_M_MAX              7
+
+/* Control 5 */
+#define PM_PWM_PAUSE_COUNT_HI_MASK    0xFC
+#define PM_PWM_PAUSE_COUNT_HI_SHIFT   2
+
+#define PM_PWM_PAUSE_ENABLE_HIGH      0x02
+#define PM_PWM_SIZE_9_BIT             0x01
+
+/* Control 6 */
+#define PM_PWM_PAUSE_COUNT_LO_MASK    0xFC
+#define PM_PWM_PAUSE_COUNT_LO_SHIFT   2
+
+#define PM_PWM_PAUSE_ENABLE_LOW       0x02
+#define PM_PWM_RESERVED               0x01
+
+#define PM_PWM_PAUSE_COUNT_MAX        56 /* < 2^6 = 64*/
+
+struct pm8921_pwm_config {
+    uint8_t pwm_size;      /* round up to 6 or 9 for 6/9-bit PWM SIZE */
+    uint8_t clk;
+    uint8_t pre_div;
+    uint8_t pre_div_exp;
+    uint8_t pwm_value;
+    uint8_t bypass_lut;
+    uint8_t pwm_ctl[NUM_LPG_CTL_REGS];
+};
+
+/* External PWM functions */
+int pm8921_pwm_enable(uint8_t pwm_id, pm8921_dev_t *dev);
+int pm8921_pwm_config(uint8_t pwm_id,
+    uint32_t duty_us,
+    uint32_t period_us,
+    pm8921_dev_t *dev);
+
+#endif
diff --git a/dev/pmic/pm8921/pm8921.c b/dev/pmic/pm8921/pm8921.c
index 4ff05fa..c6ee438 100644
--- a/dev/pmic/pm8921/pm8921.c
+++ b/dev/pmic/pm8921/pm8921.c
@@ -31,7 +31,6 @@
 #include <dev/pm8921.h>
 #include "pm8921_hw.h"
 
-
 static pm8921_dev_t *dev;
 
 static uint8_t ldo_n_voltage_mult[LDO_VOLTAGE_ENTRIES] = {
@@ -292,3 +291,149 @@
 	return rc;
 }
 
+/* A wrapper function to configure PMIC PWM
+ * pwm_id : Channel number to configure
+ * duty_us : duty cycle for output waveform in micro seconds
+ * period_us : period for output waveform in micro seconds
+ */
+int pm8921_set_pwm_config(uint8_t pwm_id, uint32_t duty_us, uint32_t period_us)
+{
+	int rc;
+
+	rc = pm8921_pwm_config(pwm_id, duty_us, period_us, dev);
+
+	return rc;
+}
+
+/* A wrapper function to enable PMIC PWM
+ * pwm_id : Channel number to enable
+ */
+int pm8921_pwm_channel_enable(uint8_t pwm_id)
+{
+	int rc;
+
+	rc = pm8921_pwm_enable(pwm_id, dev);
+
+	return rc;
+}
+
+/* Configure LED's for current sinks
+ * enable = 1: Configure external signal detection
+ *             for the sink with the current level
+ * enable = 0: Turn off external signal detection
+ *
+ * Values for sink are defined as follows:
+ * 0 = MANUAL, turn on LED when curent [00000, 10100]
+ * 1 = PWM1
+ * 2 = PWM2
+ * 3 = PWM3
+ * 4 = DBUS1
+ * 5 = DBUS2
+ * 6 = DBUS3
+ * 7 = DBUS4
+ *
+ * Current settings are calculated as per the equation:
+ * [00000, 10100]: Iout = current * 2 mA
+ * [10101, 11111]: invalid settings
+ */
+
+int pm8921_config_led_current(enum pm8921_leds led_num,
+	uint8_t current,
+	enum led_mode sink,
+	int enable)
+{
+	uint8_t val;
+	int ret;
+
+	/* Program the CTRL reg */
+	val = 0x0;
+
+	if (enable != 0)
+	{
+
+		if (current > 0x15)
+		{
+			dprintf(CRITICAL, "Invalid current settings for PM8921 LED Ctrl Reg \
+				current=%d.\n", current);
+			return -1;
+		}
+
+		if (sink > 0x7)
+		{
+			dprintf(CRITICAL, "Invalid signal selection for PM8921 LED Ctrl Reg \
+				sink=%d.\n", sink);
+			return -1;
+		}
+
+		val |= LED_CURRENT_SET(current);
+		val |= LED_SIGNAL_SELECT(sink);
+	}
+
+	ret = dev->write(&val, 1, PM8921_LED_CNTL_REG(led_num));
+
+	if (ret)
+		dprintf(CRITICAL, "Failed to write to PM8921 LED Ctrl Reg ret=%d.\n", ret);
+
+	return ret;
+
+}
+
+/* Configure DRV_KEYPAD
+ *drv_flash_sel:
+ * 0000 = off
+ * Iout = drv_flash_sel * 20 mA (300 mA driver)
+ * Iout = drv_flash_sel * 40 mA (600 mA driver)
+ *
+ * flash_logic = 0 : flash is on when DTEST is high
+ * flash_logic = 0 : flash is off when DTEST is high
+ *
+ * flash_ensel = 0 : manual mode, turn on flash when drv_flash_sel > 0
+ * flash_ensel = 1 : DBUS1
+ * flash_ensel = 2 : DBUS2
+ * flash_ensel = 3 : enable flash from LPG
+ */
+
+int pm8921_config_drv_keypad(unsigned int drv_flash_sel, unsigned int flash_logic, unsigned int flash_ensel)
+{
+	uint8_t val;
+	int ret;
+
+	/* Program the CTRL reg */
+	val = 0x0;
+
+	if (drv_flash_sel != 0)
+	{
+		if (drv_flash_sel > 0x0F)
+		{
+			dprintf(CRITICAL, "Invalid current settings for PM8921 \
+				KEYPAD_DRV Ctrl Reg drv_flash_sel=%d.\n", drv_flash_sel);
+			return -1;
+		}
+
+		if (flash_logic > 1)
+		{
+			dprintf(CRITICAL, "Invalid signal selection for PM8921 \
+				KEYPAD_DRV Ctrl Reg flash_logic=%d.\n", flash_logic);
+			return -1;
+		}
+
+		if (flash_ensel > 3)
+		{
+			dprintf(CRITICAL, "Invalid signal selection for PM8921 \
+				KEYPAD_DRV Ctrl Reg flash_ensel=%d.\n", flash_ensel);
+			return -1;
+		}
+
+		val |= DRV_FLASH_SEL(drv_flash_sel);
+		val |= FLASH_LOGIC_SEL(flash_logic);
+		val |= FLASH_ENSEL(flash_ensel);
+	}
+
+	ret = dev->write(&val, 1, PM8921_DRV_KEYPAD_CNTL_REG);
+
+	if (ret)
+		dprintf(CRITICAL, "Failed to write to PM8921 KEYPAD_DRV Ctrl Reg ret=%d.\n", ret);
+
+	return ret;
+
+}
diff --git a/dev/pmic/pm8921/pm8921_pwm.c b/dev/pmic/pm8921/pm8921_pwm.c
new file mode 100644
index 0000000..de89778
--- /dev/null
+++ b/dev/pmic/pm8921/pm8921_pwm.c
@@ -0,0 +1,327 @@
+/*
+ * * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <dev/pm8921.h>
+#include <dev/pm8921_pwm.h>
+
+
+static char *clks[NUM_CLOCKS] = {
+	"1K", "32768", "19.2M"
+};
+
+static unsigned pre_div[NUM_PRE_DIVIDE] = {
+	PRE_DIVIDE_0, PRE_DIVIDE_1, PRE_DIVIDE_2, PRE_DIVIDE_3
+};
+
+static unsigned int pt_t[NUM_PRE_DIVIDE][NUM_CLOCKS] = {
+    {	PRE_DIVIDE_0 * NSEC_1000HZ,
+		PRE_DIVIDE_0 * NSEC_32768HZ,
+		PRE_DIVIDE_0 * NSEC_19P2MHZ,
+	},
+	{	PRE_DIVIDE_1 * NSEC_1000HZ,
+		PRE_DIVIDE_1 * NSEC_32768HZ,
+		PRE_DIVIDE_1 * NSEC_19P2MHZ,
+	},
+	{	PRE_DIVIDE_2 * NSEC_1000HZ,
+		PRE_DIVIDE_2 * NSEC_32768HZ,
+		PRE_DIVIDE_2 * NSEC_19P2MHZ,
+	},
+
+	{	PRE_DIVIDE_2 * NSEC_1000HZ,
+		PRE_DIVIDE_2 * NSEC_32768HZ,
+		PRE_DIVIDE_2 * NSEC_19P2MHZ,
+	},
+};
+
+static uint16_t duty_msec[PM_PWM_1KHZ_COUNT_MAX + 1] = {
+	0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
+};
+
+static uint16_t pause_count[PM_PWM_PAUSE_COUNT_MAX + 1] = {
+	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+	23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
+	375, 500, 667, 750, 800, 900, 1000, 1100,
+	1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
+	3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
+	7000
+};
+
+/* Function to get the PWM size, divider, clock for the given period */
+
+static void pm8921_pwm_calc_period(uint32_t period_us,
+	struct pm8921_pwm_config *pwm_conf)
+{
+	int n, m, clk, div;
+	int best_m, best_div, best_clk;
+	int last_err, cur_err, better_err, better_m;
+	uint32_t tmp_p, last_p, min_err, period_n;
+
+	/* PWM Period / N : handle underflow or overflow */
+	if (period_us < (PM_PWM_PERIOD_MAX / NSEC_PER_USEC))
+		period_n = (period_us * NSEC_PER_USEC) >> 6;
+	else
+		period_n = (period_us >> 6) * NSEC_PER_USEC;
+
+	if (period_n >= MAX_MPT)
+	{
+		n = 9;
+		period_n >>= 3;
+	}
+	else
+		n = 6;
+
+	min_err = MAX_MPT;
+	best_m = 0;
+	best_clk = 0;
+	best_div = 0;
+
+	for (clk = 0; clk < NUM_CLOCKS; clk++)
+	{
+		for (div = 0; div < NUM_PRE_DIVIDE; div++)
+		{
+			tmp_p = period_n;
+			last_p = tmp_p;
+			for (m = 0; m <= PM_PWM_M_MAX; m++)
+			{
+				if (tmp_p <= pt_t[div][clk])
+				{
+					/* Found local best */
+					if (!m)
+					{
+						better_err = pt_t[div][clk] - tmp_p;
+						better_m = m;
+					}
+					else
+					{
+						last_err = last_p - pt_t[div][clk];
+						cur_err = pt_t[div][clk] - tmp_p;
+
+						if (cur_err < last_err)
+						{
+							better_err = cur_err;
+							better_m = m;
+						}
+						else
+						{
+							better_err = last_err;
+							better_m = m - 1;
+						}
+					}
+
+					if (better_err < min_err)
+					{
+						min_err = better_err;
+						best_m = better_m;
+						best_clk = clk;
+						best_div = div;
+					}
+					break;
+				}
+				else
+				{
+					last_p = tmp_p;
+					tmp_p >>= 1;
+				}
+			}
+		}
+	}
+
+	pwm_conf->pwm_size = n;
+	pwm_conf->clk = best_clk;
+	pwm_conf->pre_div = best_div;
+	pwm_conf->pre_div_exp = best_m;
+}
+
+/* Function to configure PWM control registers with clock, divider values */
+
+static int pm8921_pwm_configure(uint8_t pwm_id,
+	struct pm8921_pwm_config *pwm_conf,
+	pm8921_dev_t *dev)
+{
+	int i, len, rc = -1;
+	uint8_t reg;
+
+	reg = (pwm_conf->pwm_size > 6) ? PM_PWM_SIZE_9_BIT : 0;
+	pwm_conf->pwm_ctl[5] = reg;
+
+	reg = ((pwm_conf->clk + 1) << PM_PWM_CLK_SEL_SHIFT)
+		& PM_PWM_CLK_SEL_MASK;
+	reg |= (pwm_conf->pre_div << PM_PWM_PREDIVIDE_SHIFT)
+		& PM_PWM_PREDIVIDE_MASK;
+	reg |= pwm_conf->pre_div_exp & PM_PWM_M_MASK;
+	pwm_conf->pwm_ctl[4] = reg;
+
+	/* Just to let know we bypass LUT */
+	if (pwm_conf->bypass_lut)
+	{
+		/* CTL0 is set in pwm_enable() */
+		pwm_conf->pwm_ctl[0] &= PM_PWM_PWM_START;
+		pwm_conf->pwm_ctl[1] = PM_PWM_BYPASS_LUT;
+		pwm_conf->pwm_ctl[2] = 0;
+
+		if (pwm_conf->pwm_size > 6)
+		{
+			pwm_conf->pwm_ctl[3] = pwm_conf->pwm_value
+						& PM_PWM_VALUE_BIT7_0;
+			pwm_conf->pwm_ctl[4] |= (pwm_conf->pwm_value >> 1)
+						& PM_PWM_VALUE_BIT8;
+		}
+		else
+		{
+			pwm_conf->pwm_ctl[3] = pwm_conf->pwm_value
+						& PM_PWM_VALUE_BIT5_0;
+		}
+
+		len = 6;
+	}
+	else
+	{
+		/* Right now, we are not using LUT */
+		goto bail_out;
+	}
+
+	/* Selecting the bank */
+	rc = dev->write(&pwm_id, 1, PM8921_LPG_BANK_SEL);
+	if (rc)
+		goto bail_out;
+
+	for (i = 0; i < len; i++)
+	{
+		rc = dev->write(&pwm_conf->pwm_ctl[i], 1, PM8921_LPG_CTL(i));
+		if (rc)
+		{
+			dprintf(CRITICAL, "pm8921_write() failed in \
+				pwm_configure %d\n", rc);
+			break;
+		}
+	}
+
+bail_out:
+	if (rc)
+		dprintf(CRITICAL, "Error in pm8921_pwm_configure()\n");
+	return rc;
+}
+
+/* Top level function for configuring PWM
+ * Always called from the main pm8921.c file
+ */
+
+int pm8921_pwm_config(uint8_t pwm_id,
+	uint32_t duty_us,
+	uint32_t period_us,
+	pm8921_dev_t *dev)
+{
+	struct pm8921_pwm_config pwm_conf;
+	uint32_t max_pwm_value, tmp;
+	int rc = -1;
+
+	if ((duty_us > period_us) || (period_us > PM_PWM_PERIOD_MAX) ||
+		(period_us < PM_PWM_PERIOD_MIN))
+	{
+		dprintf(CRITICAL, "Error in duty cycle and period\n");
+		return -1;
+	}
+
+	pm8921_pwm_calc_period(period_us, &pwm_conf);
+
+	/* Figure out pwm_value with overflow handling */
+	if (period_us > (1 << pwm_conf.pwm_size))
+	{
+		tmp = period_us;
+		tmp >>= pwm_conf.pwm_size;
+		pwm_conf.pwm_value = duty_us / tmp;
+	}
+	else
+	{
+		tmp = duty_us;
+		tmp <<= pwm_conf.pwm_size;
+		pwm_conf.pwm_value = tmp / period_us;
+	}
+
+	max_pwm_value = (1 << pwm_conf.pwm_size) - 1;
+
+	if (pwm_conf.pwm_value > max_pwm_value)
+		pwm_conf.pwm_value = max_pwm_value;
+
+	/* Bypassing LUT */
+	pwm_conf.bypass_lut = 1;
+
+	dprintf(SPEW, "duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
+		 duty_us, period_us, pwm_conf.pwm_value,
+		 1 << pwm_conf.pwm_size);
+
+	rc = pm8921_pwm_configure(pwm_id, &pwm_conf, dev);
+
+	if (rc)
+		dprintf(CRITICAL, "Error in pwm_config()\n");
+
+	return rc;
+}
+
+/* Top level function to enable PWM with specified id
+ * Always called from the main pm8921.c file
+ */
+
+
+int pm8921_pwm_enable(uint8_t pwm_id, pm8921_dev_t *dev)
+{
+	int rc = -1;
+	uint8_t reg;
+
+	/* Read it before enabling other bank */
+	rc = dev->read(&reg, 1, PM8921_LPG_BANK_ENABLE);
+	if (rc)
+		goto bail_out;
+
+	reg |= (1 << pwm_id);
+
+	rc = dev->write(&reg, 1, PM8921_LPG_BANK_ENABLE);
+	if (rc)
+		goto bail_out;
+
+	/* Selecting the bank */
+	rc = dev->write(&pwm_id, 1, PM8921_LPG_BANK_SEL);
+	if (rc)
+		goto bail_out;
+
+	/* Read it before setting PWM start */
+	rc = dev->read(&reg, 1, PM8921_LPG_CTL(0));
+	if (rc)
+		goto bail_out;
+
+	reg |= PM_PWM_PWM_START;
+	reg &= ~PM_PWM_RAMP_GEN_START;
+	rc = dev->write(&reg, 1, PM8921_LPG_CTL(0));
+
+bail_out:
+	if (rc)
+		dprintf(CRITICAL, "Error in pwm_enable()\n");
+	return rc;
+}
diff --git a/dev/pmic/pm8921/rules.mk b/dev/pmic/pm8921/rules.mk
index e377786..1ab80b1 100644
--- a/dev/pmic/pm8921/rules.mk
+++ b/dev/pmic/pm8921/rules.mk
@@ -3,5 +3,6 @@
 INCLUDES += -I$(LOCAL_DIR)/include
 
 OBJS += \
-	$(LOCAL_DIR)/pm8921.o
+	$(LOCAL_DIR)/pm8921.o \
+	$(LOCAL_DIR)/pm8921_pwm.o \
 
diff --git a/platform/msm8960/include/platform/iomap.h b/platform/msm8960/include/platform/iomap.h
index 7494995..f653437 100644
--- a/platform/msm8960/include/platform/iomap.h
+++ b/platform/msm8960/include/platform/iomap.h
@@ -36,9 +36,10 @@
 #define MSM_IOMAP_BASE      0x00100000
 #define MSM_IOMAP_END       0x28000000
 
+#define MSM_IMEM_BASE       0x2A000000
+
 #define MSM_SHARED_IMEM_BASE 0x2A03F000
 #define RESTART_REASON_ADDR  (MSM_SHARED_IMEM_BASE + 0x65C)
-#define MSM_SHARED_BASE     0x80000000
 
 #define MSM_SHARED_BASE     0x80000000
 
diff --git a/platform/msm8960/platform.c b/platform/msm8960/platform.c
old mode 100755
new mode 100644
index 8589d78..1233ce7
--- a/platform/msm8960/platform.c
+++ b/platform/msm8960/platform.c
@@ -36,6 +36,7 @@
 #include <dev/fbcon.h>
 #include <mmu.h>
 #include <arch/arm/mmu.h>
+#include <partition_parser.h>
 
 extern void platform_init_timer(void);
 extern void platform_panel_backlight_on(void);
@@ -59,15 +60,19 @@
 
 /* Kernel region - cacheable, write through */
 #define KERNEL_MEMORY     (MMU_MEMORY_TYPE_NORMAL_WRITE_THROUGH   | \
-                           MMU_MEMORY_AP_READ_WRITE)
+                           MMU_MEMORY_AP_READ_WRITE | MMU_MEMORY_XN)
 
 /* Scratch region - cacheable, write through */
 #define SCRATCH_MEMORY    (MMU_MEMORY_TYPE_NORMAL_WRITE_THROUGH   | \
-                           MMU_MEMORY_AP_READ_WRITE)
+                           MMU_MEMORY_AP_READ_WRITE | MMU_MEMORY_XN)
 
 /* Peripherals - non-shared device */
 #define IOMAP_MEMORY      (MMU_MEMORY_TYPE_DEVICE_NON_SHARED | \
-                           MMU_MEMORY_AP_READ_WRITE)
+                           MMU_MEMORY_AP_READ_WRITE | MMU_MEMORY_XN)
+
+/* IMEM: Must set execute never bit to avoid instruction prefetch from TZ */
+#define IMEM_MEMORY       (MMU_MEMORY_TYPE_STRONGLY_ORDERED | \
+                           MMU_MEMORY_AP_READ_WRITE | MMU_MEMORY_XN)
 
 mmu_section_t mmu_section_table[] = {
 /*  Physical addr,    Virtual addr,    Size (in MB),    Flags */
@@ -75,6 +80,7 @@
 	{BASE_ADDR, BASE_ADDR, 44, KERNEL_MEMORY},
 	{SCRATCH_ADDR, SCRATCH_ADDR, 128, SCRATCH_MEMORY},
 	{MSM_IOMAP_BASE, MSM_IOMAP_BASE, MSM_IOMAP_SIZE, IOMAP_MEMORY},
+	{MSM_IMEM_BASE, MSM_IMEM_BASE, 1, IMEM_MEMORY},
 };
 
 void platform_early_init(void)
@@ -109,12 +115,31 @@
 	mipi_dsi_shutdown();
 }
 
+/*
+ * Write-protect partition list.
+ *
+ * Partition added in this list should have (size + padding) in multiple of
+ * mmc write protect group size. Otherwise this can end up write protecting
+ * some blocks from next partition.
+ */
+char *wp_list[] = {"fsg", NULL};
+
+void platform_wp_paritition(void)
+{
+	int count = 0;
+	while(wp_list[count] != NULL)
+	{
+		paritition_wp_by_name(wp_list[count]);
+		count++;
+	}
+}
+
 void platform_uninit(void)
 {
 #if DISPLAY_SPLASH_SCREEN
 	display_shutdown();
 #endif
-
+	platform_wp_paritition();
 	platform_uninit_timer();
 }
 
@@ -157,3 +182,4 @@
 {
 	return ticks_per_sec;
 }
+
diff --git a/platform/msm_shared/include/mmc.h b/platform/msm_shared/include/mmc.h
index a07d169..6c754ff 100644
--- a/platform/msm_shared/include/mmc.h
+++ b/platform/msm_shared/include/mmc.h
@@ -374,6 +374,7 @@
 #define MMC_BOOT_E_DATA_ADM_ERR           21
 
 /* EXT_CSD */
+#define MMC_BOOT_ACCESS_BIT_SET           0x1
 #define MMC_BOOT_ACCESS_WRITE             0x3
 
 #define MMC_BOOT_EXT_USER_WP              171
@@ -593,6 +594,10 @@
 unsigned int mmc_erase_card(unsigned long long data_addr,
 			    unsigned long long data_len);
 
+unsigned int mmc_wp(unsigned int sector, unsigned int size,
+				unsigned char set_clear_wp);
+
 struct mmc_boot_host *get_mmc_host(void);
 struct mmc_boot_card *get_mmc_card(void);
+
 #endif
diff --git a/platform/msm_shared/include/partition_parser.h b/platform/msm_shared/include/partition_parser.h
index 8e0f2ee..48fd982 100644
--- a/platform/msm_shared/include/partition_parser.h
+++ b/platform/msm_shared/include/partition_parser.h
@@ -176,6 +176,7 @@
 		       struct mmc_boot_host *mmc_host,
 		       struct mmc_boot_card *mmc_card);
 unsigned int write_partition(unsigned size, unsigned char *partition);
+unsigned int paritition_wp_by_name(const char *name);
 
 /* For Debugging */
 void partition_dump(void);
diff --git a/platform/msm_shared/mmc.c b/platform/msm_shared/mmc.c
index b1fc977..2d86ba1 100644
--- a/platform/msm_shared/mmc.c
+++ b/platform/msm_shared/mmc.c
@@ -85,8 +85,6 @@
 struct mmc_boot_host mmc_host;
 struct mmc_boot_card mmc_card;
 
-static unsigned int mmc_wp(unsigned int addr, unsigned int size,
-			   unsigned char set_clear_wp);
 static unsigned int mmc_boot_send_ext_cmd(struct mmc_boot_card *card,
 					  unsigned char *buf);
 static unsigned int mmc_boot_read_reg(struct mmc_boot_card *card,
@@ -2284,7 +2282,7 @@
 	       sizeof(struct mmc_boot_command));
 
 	/* Disabling PERM_WP for USER AREA (CMD6) */
-	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
+	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_BIT_SET,
 				      MMC_BOOT_EXT_USER_WP,
 				      MMC_BOOT_US_PERM_WP_DIS);
 
@@ -2338,14 +2336,14 @@
 		    (card->csd.erase_grp_mult + 1) * (card->csd.wp_grp_size +
 						      1);
 	}
-
+	dprintf(SPEW, "Write protect size: %d bytes\n", (wp_group_size * MMC_BOOT_WR_BLOCK_LEN));
 	if (wp_group_size == 0) {
 		return MMC_BOOT_E_FAILURE;
 	}
 
 	/* Setting POWER_ON_WP for USER AREA (CMD6) */
 
-	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
+	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_BIT_SET,
 				      MMC_BOOT_EXT_USER_WP,
 				      MMC_BOOT_US_PWR_WP_EN);
 
@@ -2373,6 +2371,9 @@
 
 	if (size % wp_group_size) {
 		loop_count = (size / wp_group_size) + 1;
+		dprintf(CRITICAL, "WARNING: Size passed to write protect is not multiple of wp_group_size!\n");
+		dprintf(CRITICAL, "WARNING: Write protecting %d extra bytes.\n",
+						((loop_count * wp_group_size) - size) * MMC_BOOT_WR_BLOCK_LEN);
 	} else {
 		loop_count = (size / wp_group_size);
 	}
@@ -2433,9 +2434,9 @@
 }
 
 /*
- * Test Function for setting Write protect for given sector
+ * Function for setting Write protect for given sector
  */
-static unsigned int
+unsigned int
 mmc_wp(unsigned int sector, unsigned int size, unsigned char set_clear_wp)
 {
 	unsigned int rc = MMC_BOOT_E_SUCCESS;
diff --git a/platform/msm_shared/partition_parser.c b/platform/msm_shared/partition_parser.c
index 68e54f1..2becaed 100644
--- a/platform/msm_shared/partition_parser.c
+++ b/platform/msm_shared/partition_parser.c
@@ -251,6 +251,7 @@
 
 	/* Read GPT Entries */
 	for (i = 0; i < (max_partition_count / 4); i++) {
+		ASSERT(partition_count < NUM_PARTITIONS);
 		ret = mmc_boot_read_from_card(mmc_host, mmc_card,
 					      (partition_0 * BLOCK_SIZE) +
 					      (i * BLOCK_SIZE),
@@ -800,6 +801,10 @@
 	unsigned int input_string_length = strlen(name);
 	unsigned n;
 
+	if( partition_count >= NUM_PARTITIONS)
+	{
+		return INVALID_PTN;
+	}
 	for (n = 0; n < partition_count; n++) {
 		if (!memcmp
 		    (name, &partition_entries[n].name, input_string_length)
@@ -941,3 +946,42 @@
 
 	return 0;
 }
+
+/*
+ * Power on write protect partition by name.
+ *
+ * Partition passed to this function should have (size + padding) in multiple
+ * of mmc write protect group size. Otherwise this can end up write protecting
+ * some blocks from next partition.
+ */
+
+unsigned int paritition_wp_by_name(const char *name)
+{
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+	int index = INVALID_PTN;
+	unsigned int ret = MMC_BOOT_E_SUCCESS;
+
+	index = partition_get_index(name);
+	ptn = partition_get_offset(index);
+	if(ptn == 0) {
+		dprintf(CRITICAL, "%s partition not found.\n", name);
+		return 1;
+	}
+
+	size = partition_get_size(index);
+
+	/* Offset in sectors */
+	ptn = ptn / MMC_BOOT_RD_BLOCK_LEN;
+
+	/* Size in sectors */
+	size = size / MMC_BOOT_RD_BLOCK_LEN;
+
+	ret = mmc_wp((unsigned)ptn, (unsigned)size, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "Failed to write protect: %s\n", name);
+		return 1;
+	}
+	return 0;
+}
diff --git a/target/msm8960/keypad.c b/target/msm8960/keypad.c
index 4015170..806f07f 100644
--- a/target/msm8960/keypad.c
+++ b/target/msm8960/keypad.c
@@ -28,9 +28,12 @@
  */
 
 #include <string.h>
+#include <debug.h>
 #include <dev/keys.h>
 #include <dev/ssbi.h>
 #include <dev/gpio_keypad.h>
+#include <dev/pm8921.h>
+
 
 #define NUM_OF_ROWS 1
 #define NUM_OF_COLS 5
@@ -67,3 +70,37 @@
 
 	ssbi_keypad_init(&qwerty_keypad);
 }
+
+/* Configure keypad_drv through pwm or DBUS inputs or manually */
+int led_kp_set( int current,
+	enum kp_backlight_mode mode,
+	enum kp_backlight_flash_logic flash_logic)
+{
+	int rc = pm8921_config_drv_keypad(current, flash_logic, mode);
+
+	if (rc)
+	{
+		dprintf(CRITICAL, "FAIL pm8921_config_drv_keypad(): rc=%d.\n", rc);
+	}
+}
+
+/* Configure gpio 26 through lpg2 */
+void keypad_led_drv_on_pwm(void)
+{
+	struct pm8921_gpio keypad_pwm = {
+		.direction = PM_GPIO_DIR_OUT,
+		.output_buffer = 0,
+		.output_value = 0,
+		.pull = PM_GPIO_PULL_NO,
+		.vin_sel = 2,
+		.out_strength = PM_GPIO_STRENGTH_HIGH,
+		.function = PM_GPIO_FUNC_2,
+		.inv_int_pol = 0,
+	};
+
+	int rc = pm8921_gpio_config(PM_GPIO(26), &keypad_pwm);
+	if (rc)
+	{
+	dprintf(CRITICAL, "FAIL pm8921_gpio_config(): rc=%d.\n", rc);
+	}
+}
diff --git a/target/msm8960/panel.c b/target/msm8960/panel.c
index 924b310..caeda14 100644
--- a/target/msm8960/panel.c
+++ b/target/msm8960/panel.c
@@ -54,6 +54,49 @@
 	}
 }
 
+/* Configure gpio 24 through lpg0 */
+void panel_backlight_on_pwm(void)
+{
+	struct pm8921_gpio backlight_pwm = {
+		.direction = PM_GPIO_DIR_OUT,
+		.output_buffer = 0,
+		.output_value = 0,
+		.pull = PM_GPIO_PULL_NO,
+		.vin_sel = 2,
+		.out_strength = PM_GPIO_STRENGTH_HIGH,
+		.function = PM_GPIO_FUNC_2,
+		.inv_int_pol = 0,
+    };
+
+	int rc = pm8921_gpio_config(PM_GPIO(24), &backlight_pwm);
+	if (rc)
+	{
+		dprintf(CRITICAL, "FAIL pm8921_gpio_config(): rc=%d.\n", rc);
+	}
+}
+
+/* Configure gpio 25 through lpg1 */
+void panel_sec_backlight_on_pwm(void)
+{
+	struct pm8921_gpio backlight_pwm = {
+		.direction = PM_GPIO_DIR_OUT,
+		.output_buffer = 0,
+		.output_value = 0,
+		.pull = PM_GPIO_PULL_NO,
+		.vin_sel = 2,
+		.out_strength = PM_GPIO_STRENGTH_HIGH,
+		.function = PM_GPIO_FUNC_2,
+		.inv_int_pol = 0,
+	};
+
+	int rc = pm8921_gpio_config(PM_GPIO(25), &backlight_pwm);
+	if (rc)
+	{
+		dprintf(CRITICAL, "FAIL pm8921_gpio_config(): rc=%d.\n", rc);
+	}
+}
+
+
 /* Pull DISP_RST_N high to get panel out of reset */
 void mipi_panel_reset(void)
 {