[msm7630]: Add code to support qwerty keypad in lk bootloader
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 665c566..dbfc0ac 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -2,31 +2,32 @@
  * Copyright (c) 2009, Google Inc.
  * 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 Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE 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.
+ * 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 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <app.h>
@@ -328,10 +329,8 @@
 {
 	page_size = flash_page_size();
 	page_mask = page_size - 1;
-#ifndef PLATFORM_MSM7X30
 	if (keys_get_state(KEY_BACK) != 0)
 		goto fastboot;
-#endif
 
 	boot_linux_from_flash();
 	dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
diff --git a/dev/keys/gpio_keypad.c b/dev/keys/gpio_keypad.c
index 5d15076..bb95f77 100644
--- a/dev/keys/gpio_keypad.c
+++ b/dev/keys/gpio_keypad.c
@@ -2,6 +2,8 @@
  * Copyright (c) 2009, Google Inc.
  * All rights reserved.
  *
+ * Copyright (c) 2009, 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:
@@ -38,6 +40,7 @@
 #include <dev/gpio_keypad.h>
 #include <kernel/event.h>
 #include <kernel/timer.h>
+#include <reg.h>
 
 struct gpio_kp {
 	struct gpio_keypad_info *keypad_info;
@@ -48,6 +51,16 @@
 	unsigned long keys_pressed[0];
 };
 
+struct gpio_qwerty_kp {
+	struct qwerty_keypad_info *keypad_info;
+	struct timer timer;
+	event_t full_scan;
+	int num_of_scans;
+	unsigned int some_keys_pressed:2;
+	unsigned long keys_pressed[0];
+};
+
+static struct gpio_qwerty_kp *qwerty_keypad;
 /* TODO: Support multiple keypads? */
 static struct gpio_kp *keypad;
 
@@ -176,3 +189,293 @@
 	/* wait for the keypad to complete one full scan */
 	event_wait(&keypad->full_scan);
 }
+
+int i2c_ssbi_poll_for_device_ready(void)
+{
+	unsigned long timeout = SSBI_TIMEOUT_US;
+
+	while (!(readl(MSM_SSBI_BASE + SSBI2_STATUS) & SSBI_STATUS_READY)) {
+		if (--timeout == 0) {
+		        dprintf(INFO, "In Device ready function:Timeout, status %x\n", readl(MSM_SSBI_BASE + SSBI2_STATUS));
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int i2c_ssbi_poll_for_read_completed(void)
+{
+	unsigned long timeout = SSBI_TIMEOUT_US;
+
+	while (!(readl(MSM_SSBI_BASE + SSBI2_STATUS) & SSBI_STATUS_RD_READY)) {
+		if (--timeout == 0) {
+		        dprintf(INFO, "In read completed function:Timeout, status %x\n", readl(MSM_SSBI_BASE + SSBI2_STATUS));
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int i2c_ssbi_read_bytes(unsigned char  *buffer, unsigned short length,
+                                                unsigned short slave_addr)
+{
+	int ret = 0;
+	unsigned char *buf = buffer;
+	unsigned short len = length;
+	unsigned short addr = slave_addr;
+	unsigned long read_cmd = SSBI_CMD_READ(addr);
+	unsigned long mode2 = readl(MSM_SSBI_BASE + SSBI2_MODE2);
+
+	//buf = alloc(len * sizeof(8));
+	if (mode2 & SSBI_MODE2_SSBI2_MODE)
+		writel(SSBI_MODE2_REG_ADDR_15_8(mode2, addr),
+				MSM_SSBI_BASE + SSBI2_MODE2);
+
+	while (len) {
+		ret = i2c_ssbi_poll_for_device_ready();
+		if (ret) {
+		        dprintf (CRITICAL, "Error: device not ready\n");
+			return ret;
+		}
+
+		writel(read_cmd, MSM_SSBI_BASE + SSBI2_CMD);
+
+		ret = i2c_ssbi_poll_for_read_completed();
+		if (ret) {
+		        dprintf (CRITICAL, "Error: read not completed\n");
+			return ret;
+		}
+
+		*buf++ = readl(MSM_SSBI_BASE + SSBI2_RD) & SSBI_RD_REG_DATA_MASK;
+		len--;
+	}
+	return 0;
+}
+
+int i2c_ssbi_write_bytes(unsigned char  *buffer, unsigned short length,
+                                                unsigned short slave_addr)
+{
+	int ret = 0;
+	unsigned long timeout = SSBI_TIMEOUT_US;
+	unsigned char *buf = buffer;
+	unsigned short len = length;
+	unsigned short addr = slave_addr;
+	unsigned long mode2 = readl(MSM_SSBI_BASE + SSBI2_MODE2);
+
+	if (mode2 & SSBI_MODE2_SSBI2_MODE)
+		writel(SSBI_MODE2_REG_ADDR_15_8(mode2, addr),
+				MSM_SSBI_BASE + SSBI2_MODE2);
+
+	while (len) {
+		ret = i2c_ssbi_poll_for_device_ready();
+		if (ret) {
+		        dprintf (CRITICAL, "Error: device not ready\n");
+			return ret;
+		}
+
+		writel(SSBI_CMD_WRITE(addr, *buf++), MSM_SSBI_BASE + SSBI2_CMD);
+
+		while (readl(MSM_SSBI_BASE + SSBI2_STATUS) & SSBI_STATUS_MCHN_BUSY) {
+		  if (--timeout == 0) {
+		    dprintf(INFO, "In Device ready function:Timeout, status %x\n", readl(MSM_SSBI_BASE + SSBI2_STATUS));
+		    return 1;
+		  }
+		}
+		len--;
+	}
+	return 0;
+}
+
+int pm8058_gpio_config(int gpio, struct pm8058_gpio *param)
+{
+	int	rc;
+	unsigned char bank[8];
+	static int dir_map[] = {
+		PM8058_GPIO_MODE_OFF,
+		PM8058_GPIO_MODE_OUTPUT,
+		PM8058_GPIO_MODE_INPUT,
+		PM8058_GPIO_MODE_BOTH,
+	};
+
+	if (param == 0) {
+	  dprintf (INFO, "pm8058_gpio struct not defined\n");
+          return -1;
+	}
+
+	/* Select banks and configure the gpio */
+	bank[0] = PM8058_GPIO_WRITE |
+		((param->vin_sel << PM8058_GPIO_VIN_SHIFT) &
+			PM8058_GPIO_VIN_MASK) |
+		PM8058_GPIO_MODE_ENABLE;
+	bank[1] = PM8058_GPIO_WRITE |
+		((1 << PM8058_GPIO_BANK_SHIFT) & PM8058_GPIO_BANK_MASK) |
+		((dir_map[param->direction] << PM8058_GPIO_MODE_SHIFT) &
+			PM8058_GPIO_MODE_MASK) |
+		((param->direction & PM_GPIO_DIR_OUT) ?
+			PM8058_GPIO_OUT_BUFFER : 0);
+	bank[2] = PM8058_GPIO_WRITE |
+		((2 << PM8058_GPIO_BANK_SHIFT) & PM8058_GPIO_BANK_MASK) |
+		((param->pull << PM8058_GPIO_PULL_SHIFT) &
+			PM8058_GPIO_PULL_MASK);
+	bank[3] = PM8058_GPIO_WRITE |
+		((3 << PM8058_GPIO_BANK_SHIFT) & PM8058_GPIO_BANK_MASK) |
+		((param->out_strength << PM8058_GPIO_OUT_STRENGTH_SHIFT) &
+			PM8058_GPIO_OUT_STRENGTH_MASK);
+	bank[4] = PM8058_GPIO_WRITE |
+		((4 << PM8058_GPIO_BANK_SHIFT) & PM8058_GPIO_BANK_MASK) |
+		((param->function << PM8058_GPIO_FUNC_SHIFT) &
+			PM8058_GPIO_FUNC_MASK);
+
+	rc = i2c_ssbi_write_bytes(bank, 5, SSBI_REG_ADDR_GPIO(gpio));
+	if (rc) {
+	        dprintf(INFO, "Failed on 1st ssbi_write(): rc=%d.\n", rc);
+		return 1;
+	}
+	return 0;
+}
+
+int pm8058_gpio_config_kypd_drv(int gpio_start, int num_gpios)
+{
+	int	rc;
+	struct pm8058_gpio kypd_drv = {
+		.direction	= PM_GPIO_DIR_OUT,
+		.pull		= PM_GPIO_PULL_NO,
+		.vin_sel	= 2,
+		.out_strength	= PM_GPIO_STRENGTH_LOW,
+		.function	= PM_GPIO_FUNC_1,
+		.inv_int_pol	= 1,
+	};
+
+	while (num_gpios--) {
+		rc = pm8058_gpio_config(gpio_start++, &kypd_drv);
+		if (rc) {
+		        dprintf(INFO, "FAIL pm8058_gpio_config(): rc=%d.\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+int pm8058_gpio_config_kypd_sns(int gpio_start, int num_gpios)
+{
+	int	rc;
+	struct pm8058_gpio kypd_sns = {
+		.direction	= PM_GPIO_DIR_IN,
+		.pull		= PM_GPIO_PULL_UP1,
+		.vin_sel	= 2,
+		.out_strength	= PM_GPIO_STRENGTH_NO,
+		.function	= PM_GPIO_FUNC_NORMAL,
+		.inv_int_pol	= 1,
+	};
+
+	while (num_gpios--) {
+		rc = pm8058_gpio_config(gpio_start++, &kypd_sns);
+		if (rc) {
+		        dprintf(INFO, "FAIL pm8058_gpio_config(): rc=%d.\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static enum handler_return
+scan_qwerty_keypad(struct timer *timer, time_t now, void *arg)
+{
+    int rows = (qwerty_keypad->keypad_info)->rows;
+    int columns = (qwerty_keypad->keypad_info)->columns;
+    unsigned char column_keys = 0x00;
+    int shift = 0;
+    static int key_detected = 0;
+
+    if (i2c_ssbi_read_bytes((qwerty_keypad->keypad_info)->rec_keys, NUM_OF_SSBI_READS,
+                                                 SSBI_REG_KYPD_REC_DATA_ADDR))
+      dprintf (CRITICAL, "Error in initializing SSBI_REG_KYPD_CNTL register\n");
+
+    if (i2c_ssbi_read_bytes((qwerty_keypad->keypad_info)->old_keys, NUM_OF_SSBI_READS,
+                                                 SSBI_REG_KYPD_OLD_DATA_ADDR))
+      dprintf (CRITICAL, "Error in initializing SSBI_REG_KYPD_CNTL register\n");
+
+    while (rows--) {
+        if ((qwerty_keypad->keypad_info)->rec_keys[rows] 
+                  != (qwerty_keypad->keypad_info)->old_keys[rows]) {
+	    while (columns--) {
+	        column_keys = ((qwerty_keypad->keypad_info)->rec_keys[rows]);
+	        if ((0x01 << columns) & (~column_keys)) {
+	            shift = (rows * (qwerty_keypad->keypad_info)->columns) + columns;
+	            if ((qwerty_keypad->keypad_info)->keymap[shift]) {
+		        if (shift != key_detected) {
+			  // key_changed((qwerty_keypad->keypad_info)->keymap[shift], 1);
+			    key_detected = shift;
+			    keys_post_event((qwerty_keypad->keypad_info)->keymap[shift], 1);
+		            event_signal(&qwerty_keypad->full_scan, false);
+			    timer_set_oneshot(timer, (qwerty_keypad->keypad_info)->poll_time,
+				 scan_qwerty_keypad, NULL);
+			    return INT_RESCHEDULE;
+
+		        }
+		        break;
+	            }
+		}
+	    }
+	}
+    }
+    if (qwerty_keypad->num_of_scans < 10)
+    {
+      (qwerty_keypad->num_of_scans)++;
+      timer_set_oneshot(timer, (qwerty_keypad->keypad_info)->settle_time,
+	   scan_qwerty_keypad, NULL);
+      return INT_RESCHEDULE;
+    }
+
+    event_signal(&qwerty_keypad->full_scan, false);
+    return INT_RESCHEDULE;
+
+}
+
+void ssbi_gpio_init(void)
+{
+    unsigned char kypd_cntl_init = 0xF8;
+    unsigned char kypd_scan_init = 0x20;
+
+    if (i2c_ssbi_write_bytes(&kypd_cntl_init, 1, SSBI_REG_KYPD_CNTL_ADDR))
+      dprintf (CRITICAL, "Error in initializing SSBI_REG_KYPD_CNTL register\n");
+
+    if (i2c_ssbi_write_bytes(&kypd_scan_init, 1, SSBI_REG_KYPD_SCAN_ADDR))
+      dprintf (CRITICAL, "Error in initializing SSBI_REG_KYPD_SCAN register\n");
+
+    pm8058_gpio_config_kypd_sns(SSBI_OFFSET_ADDR_GPIO_KYPD_SNS, NUM_OF_KYPD_SNS_GPIOS);
+    pm8058_gpio_config_kypd_drv(SSBI_OFFSET_ADDR_GPIO_KYPD_DRV,  NUM_OF_KYPD_DRV_GPIOS);
+
+
+}
+
+void ssbi_keypad_init(struct qwerty_keypad_info  *qwerty_kp)
+{
+    int *modem_stat_check = (SMEM_BASE + 0x14);
+    int len;
+
+    /* Wait for modem to be ready before keypad init */
+    while (readl(modem_stat_check) != 1);
+
+    ssbi_gpio_init();
+
+    len = sizeof(struct gpio_qwerty_kp);
+    qwerty_keypad = malloc(len);
+    ASSERT(qwerty_keypad);
+
+    memset(qwerty_keypad, 0, len);
+    qwerty_keypad->keypad_info = qwerty_kp;
+    qwerty_keypad->num_of_scans = 0;
+
+    event_init(&qwerty_keypad->full_scan, false, EVENT_FLAG_AUTOUNSIGNAL);
+    timer_initialize(&qwerty_keypad->timer);
+    timer_set_oneshot(&qwerty_keypad->timer, 0, scan_qwerty_keypad, NULL);
+
+    /* wait for the keypad to complete one full scan */
+    event_wait(&qwerty_keypad->full_scan);
+}
+
diff --git a/include/dev/gpio_keypad.h b/include/dev/gpio_keypad.h
index 3e05128..8c006d3 100644
--- a/include/dev/gpio_keypad.h
+++ b/include/dev/gpio_keypad.h
@@ -2,6 +2,8 @@
  * Copyright (c) 2008, Google Inc.
  * All rights reserved.
  *
+ * Copyright (c) 2009, 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:
@@ -53,4 +55,156 @@
 
 void gpio_keypad_init(struct gpio_keypad_info *kpinfo);
 
+//Macros for SSBI Qwerty keypad for 7x30
+
+/* SSBI 2.0 controller registers */
+#define MSM_SSBI_BASE                   0xAD900000
+#define SMEM_BASE                       0x100000
+
+#define SSBI_TIMEOUT_US			100
+
+#define SSBI2_CTL			0x0000
+#define SSBI2_RESET			0x0004
+#define SSBI2_CMD			0x0008
+#define SSBI2_RD			0x0010
+#define SSBI2_STATUS			0x0014
+#define SSBI2_PRIORITIES		0x0018
+#define SSBI2_MODE2			0x001C
+
+/* SSBI_CMD fields */
+#define SSBI_CMD_SEND_TERM_SYM		(0x01 << 27)
+#define SSBI_CMD_WAKEUP_SLAVE		(0x01 << 26)
+#define SSBI_CMD_USE_ENABLE		(0x01 << 25)
+#define SSBI_CMD_RDWRN			(0x01 << 24)
+#define SSBI_CMD_REG_ADDR_SHFT		(0x10)
+#define SSBI_CMD_REG_ADDR_MASK		(0xFF << SSBI_CMD_REG_ADDR_SHFT)
+#define SSBI_CMD_REG_DATA_SHFT		(0x00)
+#define SSBI_CMD_REG_DATA_MASK		(0xFF << SSBI_CMD_REG_DATA_SHFT)
+
+/* SSBI_STATUS fields */
+#define SSBI_STATUS_DATA_IN		0x10
+#define SSBI_STATUS_RD_CLOBBERED	0x08
+#define SSBI_STATUS_RD_READY		0x04
+#define SSBI_STATUS_READY		0x02
+#define SSBI_STATUS_MCHN_BUSY		0x01
+
+/* SSBI_RD fields */
+#define SSBI_RD_USE_ENABLE		0x02000000
+#define SSBI_RD_RDWRN			0x01000000
+#define SSBI_RD_REG_ADDR_SHFT		0x10
+#define SSBI_RD_REG_ADDR_MASK		(0xFF << SSBI_RD_REG_ADDR_SHFT)
+#define SSBI_RD_REG_DATA_SHFT		(0x00)
+#define SSBI_RD_REG_DATA_MASK		(0xFF << SSBI_RD_REG_DATA_SHFT)
+
+/* SSBI_MODE2 fields */
+#define SSBI_MODE2_REG_ADDR_15_8_SHFT	0x04
+#define SSBI_MODE2_REG_ADDR_15_8_MASK	(0x7F << SSBI_MODE2_REG_ADDR_15_8_SHFT)
+#define SSBI_MODE2_ADDR_WIDTH_SHFT	0x01
+#define SSBI_MODE2_ADDR_WIDTH_MASK	(0x07 << SSBI_MODE2_ADDR_WIDTH_SHFT)
+#define SSBI_MODE2_SSBI2_MODE		0x00000001
+
+//Keypad controller configurations
+#define SSBI_REG_KYPD_CNTL_ADDR         0x148
+#define SSBI_REG_KYPD_SCAN_ADDR         0x149
+#define SSBI_REG_KYPD_TEST_ADDR         0x14A
+#define SSBI_REG_KYPD_REC_DATA_ADDR     0x14B
+#define SSBI_REG_KYPD_OLD_DATA_ADDR     0x14C
+
+// GPIO configurations
+
+#define	SSBI_REG_ADDR_GPIO_BASE		0x150
+#define SSBI_OFFSET_ADDR_GPIO_KYPD_SNS  0x000
+#define SSBI_OFFSET_ADDR_GPIO_KYPD_DRV  0x008
+#define	SSBI_REG_ADDR_GPIO(n)		(SSBI_REG_ADDR_GPIO_BASE + n)
+
+#define	PM_GPIO_DIR_OUT			0x01
+#define	PM_GPIO_DIR_IN			0x02
+#define	PM_GPIO_DIR_BOTH		(PM_GPIO_DIR_OUT | PM_GPIO_DIR_IN)
+
+#define	PM_GPIO_PULL_UP1		2
+#define	PM_GPIO_PULL_UP2		3
+#define	PM_GPIO_PULL_DN			4
+#define	PM_GPIO_PULL_NO			5
+
+#define	PM_GPIO_STRENGTH_NO		0
+#define	PM_GPIO_STRENGTH_HIGH		1
+#define	PM_GPIO_STRENGTH_MED		2
+#define	PM_GPIO_STRENGTH_LOW		3
+
+#define	PM_GPIO_FUNC_NORMAL		0
+#define	PM_GPIO_FUNC_PAIRED		1
+#define	PM_GPIO_FUNC_1			2
+#define	PM_GPIO_FUNC_2			3
+
+#define	PM8058_GPIO_BANK_MASK		0x70
+#define	PM8058_GPIO_BANK_SHIFT		4
+#define	PM8058_GPIO_WRITE		0x80
+
+/* Bank 0 */
+#define	PM8058_GPIO_VIN_MASK		0x0E
+#define	PM8058_GPIO_VIN_SHIFT		1
+#define	PM8058_GPIO_MODE_ENABLE		0x01
+
+/* Bank 1 */
+#define	PM8058_GPIO_MODE_MASK		0x0C
+#define	PM8058_GPIO_MODE_SHIFT		2
+#define	PM8058_GPIO_OUT_BUFFER		0x02
+#define	PM8058_GPIO_OUT_INVERT		0x01
+
+#define	PM8058_GPIO_MODE_OFF		3
+#define	PM8058_GPIO_MODE_OUTPUT		2
+#define	PM8058_GPIO_MODE_INPUT		0
+#define	PM8058_GPIO_MODE_BOTH		1
+
+/* Bank 2 */
+#define	PM8058_GPIO_PULL_MASK		0x0E
+#define	PM8058_GPIO_PULL_SHIFT		1
+
+/* Bank 3 */
+#define	PM8058_GPIO_OUT_STRENGTH_MASK   0x0C
+#define	PM8058_GPIO_OUT_STRENGTH_SHIFT  2
+
+/* Bank 4 */
+#define	PM8058_GPIO_FUNC_MASK		0x0E
+#define	PM8058_GPIO_FUNC_SHIFT		1
+
+#define NUM_OF_SSBI_READS               15
+#define NUM_OF_KYPD_DRV_GPIOS           12
+#define NUM_OF_KYPD_SNS_GPIOS            8
+
+struct pm8058_gpio {
+	int		direction;
+	int		pull;
+	int		vin_sel;	/* 0..7 */
+	int		out_strength;
+	int		function;
+	int		inv_int_pol;	/* invert interrupt polarity */
+};
+
+struct qwerty_keypad_info {
+	/* size must be ninputs * noutputs */
+	unsigned int   *keymap;
+        unsigned char  *old_keys;
+        unsigned char  *rec_keys;
+        unsigned int   rows;
+        unsigned int   columns;
+	/* time to wait before reading inputs after driving each output */
+	time_t         settle_time;
+	time_t         poll_time;
+	unsigned       flags;
+};
+
+#define SSBI_CMD_READ(AD) \
+	(SSBI_CMD_RDWRN | (((AD) & 0xFF) << SSBI_CMD_REG_ADDR_SHFT))
+
+#define SSBI_CMD_WRITE(AD, DT) \
+  ((((AD) & 0xFF) << SSBI_CMD_REG_ADDR_SHFT) | \
+   (((DT) & 0xFF) << SSBI_CMD_REG_DATA_SHFT))
+
+#define SSBI_MODE2_REG_ADDR_15_8(MD, AD) \
+	(((MD) & 0x0F) | ((((AD) >> 8) << SSBI_MODE2_REG_ADDR_15_8_SHFT) & \
+	SSBI_MODE2_REG_ADDR_15_8_MASK))
+
+void ssbi_keypad_init (struct qwerty_keypad_info *);
+
 #endif /* __DEV_GPIO_KEYPAD_H */
diff --git a/target/msm7630_surf/init.c b/target/msm7630_surf/init.c
index 0f2d816..63dff0b 100644
--- a/target/msm7630_surf/init.c
+++ b/target/msm7630_surf/init.c
@@ -83,8 +83,8 @@
 
 	dprintf(INFO, "target_init()\n");
 
-	//keys_init();
-	//keypad_init();
+	keys_init();
+	keypad_init();
 
 	ptable_init(&flash_ptable);
 	smem_ptable_init();
diff --git a/target/msm7630_surf/keypad.c b/target/msm7630_surf/keypad.c
index c44b06d..4fa6913 100644
--- a/target/msm7630_surf/keypad.c
+++ b/target/msm7630_surf/keypad.c
@@ -34,79 +34,30 @@
 #include <dev/gpio_keypad.h>
 
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#define BITS_IN_ELEMENT(x) (sizeof(x)[0] * 8)
 
-/* don't turn this on without updating the ffa support */
-#define SCAN_FUNCTION_KEYS 0
+static unsigned char qwerty_keys_old[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x00, 0x00, 0x00, 0x00};
+static unsigned char qwerty_keys_new[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					   0x00, 0x00, 0x00, 0x00, 0x00};
 
-static unsigned int halibut_row_gpios[] = {
-	31, 32, 33, 34, 35, 41
-#if SCAN_FUNCTION_KEYS
-	, 42
-#endif
+#define KEYMAP_INDEX(row, col) (row)* BITS_IN_ELEMENT(qwerty_keys_new) + (col)
+
+static unsigned int qwerty_keymap[] = {
+    [KEYMAP_INDEX(4, 2)] = KEY_BACK,          /* -L on SURF & FFA */
 };
 
-static unsigned int halibut_col_gpios[] = { 36, 37, 38, 39, 40 };
-
-#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(halibut_col_gpios) + (col))
-
-static const unsigned short halibut_keymap[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = {
-	[KEYMAP_INDEX(0, 0)] = KEY_5,
-	[KEYMAP_INDEX(0, 1)] = KEY_9,
-	[KEYMAP_INDEX(0, 2)] = KEY_SOFT1,
-	[KEYMAP_INDEX(0, 3)] = KEY_6,
-	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
-
-	[KEYMAP_INDEX(1, 0)] = KEY_0,
-	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
-	[KEYMAP_INDEX(1, 2)] = KEY_1,
-	[KEYMAP_INDEX(1, 3)] = KEY_SHARP,
-	[KEYMAP_INDEX(1, 4)] = KEY_SEND,
-
-	[KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP,
-	[KEYMAP_INDEX(2, 1)] = KEY_HOME,      /* FA   */
-	[KEYMAP_INDEX(2, 2)] = KEY_F8,        /* QCHT */
-	[KEYMAP_INDEX(2, 3)] = KEY_F6,        /* R+   */
-	[KEYMAP_INDEX(2, 4)] = KEY_F7,        /* R-   */
-
-	[KEYMAP_INDEX(3, 0)] = KEY_UP,
-	[KEYMAP_INDEX(3, 1)] = KEY_CLEAR,
-	[KEYMAP_INDEX(3, 2)] = KEY_4,
-	[KEYMAP_INDEX(3, 3)] = KEY_MUTE,      /* SPKR */
-	[KEYMAP_INDEX(3, 4)] = KEY_2,
-
-	[KEYMAP_INDEX(4, 0)] = KEY_SOFT2,           /* SOFT2 */
-	[KEYMAP_INDEX(4, 1)] = KEY_CENTER,    /* KEY_CENTER */
-	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
-	[KEYMAP_INDEX(4, 3)] = KEY_BACK,      /* FB */
-	[KEYMAP_INDEX(4, 4)] = KEY_8,
-
-	[KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN,
-	[KEYMAP_INDEX(5, 1)] = KEY_STAR,      /* KEY_STAR */
-	[KEYMAP_INDEX(5, 2)] = KEY_MAIL,      /* MESG */
-	[KEYMAP_INDEX(5, 3)] = KEY_3,
-	[KEYMAP_INDEX(5, 4)] = KEY_7,
-
-#if SCAN_FUNCTION_KEYS
-	[KEYMAP_INDEX(6, 0)] = KEY_F5,
-	[KEYMAP_INDEX(6, 1)] = KEY_F4,
-	[KEYMAP_INDEX(6, 2)] = KEY_F3,
-	[KEYMAP_INDEX(6, 3)] = KEY_F2,
-	[KEYMAP_INDEX(6, 4)] = KEY_F1
-#endif
-};
-
-static struct gpio_keypad_info halibut_keypad_info = {
-	.keymap		= halibut_keymap,
-	.output_gpios	= halibut_row_gpios,
-	.input_gpios	= halibut_col_gpios,
-	.noutputs	= ARRAY_SIZE(halibut_row_gpios),
-	.ninputs	= ARRAY_SIZE(halibut_col_gpios),
-	.settle_time	= 5 /* msec */,
-	.poll_time	= 20 /* msec */,
-	.flags		= GPIOKPF_DRIVE_INACTIVE,
+static struct qwerty_keypad_info qwerty_keypad = {
+    .keymap         = qwerty_keymap,
+    .old_keys       = qwerty_keys_old,
+    .rec_keys       = qwerty_keys_new,
+    .rows           = ARRAY_SIZE(qwerty_keys_new),
+    .columns        = sizeof(unsigned char) * 8,
+    .settle_time    = 5 /* msec */,
+    .poll_time	    = 20 /* msec */,
 };
 
 void keypad_init(void)
 {
-	gpio_keypad_init(&halibut_keypad_info);
+    ssbi_keypad_init(&qwerty_keypad);
 }