[msm8660]: Add fastboot key detection for QT8660
Due to a hardware design bug, keypad controller in PM8058 could not be
used for key detection. Hence detecting it by configuring PM8058 GPIOs
as normal function and accessing it over SSBI
Change-Id: I92db69fe504598a6d1dfc0736642b1cb7a02be4c
diff --git a/dev/keys/gpio_keypad.c b/dev/keys/gpio_keypad.c
index d021a78..2ec7c5d 100644
--- a/dev/keys/gpio_keypad.c
+++ b/dev/keys/gpio_keypad.c
@@ -2,7 +2,7 @@
* Copyright (c) 2009, Google Inc.
* All rights reserved.
*
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -43,6 +43,8 @@
#include <reg.h>
#include <platform/iomap.h>
+#define LINUX_MACHTYPE_8660_QT 3298
+
struct gpio_kp {
struct gpio_keypad_info *keypad_info;
struct timer timer;
@@ -455,7 +457,7 @@
return 0;
}
-int pm8058_gpio_config_kypd_drv(int gpio_start, int num_gpios)
+int pm8058_gpio_config_kypd_drv(int gpio_start, int num_gpios, unsigned mach_id)
{
int rc;
struct pm8058_gpio kypd_drv = {
@@ -467,6 +469,9 @@
.inv_int_pol = 1,
};
+ if(mach_id == LINUX_MACHTYPE_8660_QT)
+ kypd_drv.function = PM_GPIO_FUNC_NORMAL;
+
while (num_gpios--) {
rc = pm8058_gpio_config(gpio_start++, &kypd_drv);
if (rc) {
@@ -501,7 +506,7 @@
return 0;
}
-void ssbi_gpio_init(void)
+static void ssbi_gpio_init(unsigned int mach_id)
{
unsigned char kypd_cntl_init;
unsigned char kypd_scan_init = 0x20;
@@ -520,8 +525,16 @@
if ((*wr_function)(&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, columns);
- pm8058_gpio_config_kypd_drv(SSBI_OFFSET_ADDR_GPIO_KYPD_DRV, rows);
+ if(mach_id == LINUX_MACHTYPE_8660_QT)
+ {
+ pm8058_gpio_config_kypd_sns(QT_PMIC_GPIO_KYPD_SNS, rows);
+ pm8058_gpio_config_kypd_drv(QT_PMIC_GPIO_KYPD_DRV, columns, mach_id);
+ }
+ else
+ {
+ pm8058_gpio_config_kypd_sns(SSBI_OFFSET_ADDR_GPIO_KYPD_SNS, columns);
+ pm8058_gpio_config_kypd_drv(SSBI_OFFSET_ADDR_GPIO_KYPD_DRV, rows, mach_id);
+ }
}
static enum handler_return
@@ -584,8 +597,54 @@
}
+static enum handler_return
+scan_qt_keypad(struct timer *timer, time_t now, void *arg)
+{
+ unsigned int gpio;
+ unsigned int last_state=0;
+ unsigned int new_state=0;
+ unsigned int bits_changed;
+ static unsigned int key_detected=0;
+
+ /* Row GPIOs 8,9,10 are used for sensing here */
+ for(gpio=8;gpio<=10;gpio++)
+ {
+ bool status;
+ status = pm8058_gpio_get(gpio);
+ if(status == 0)
+ new_state |= (1<<(gpio-8));
+ }
+
+ bits_changed = last_state ^ new_state;
+
+ if(bits_changed)
+ {
+ unsigned int shift;
+ for(int rows=0;rows<(qwerty_keypad->keypad_info)->rows;rows++)
+ {
+ if((bits_changed & (1<<rows)) == 0)
+ continue;
+ shift = rows*8 + 3;
+ }
+ if ((qwerty_keypad->keypad_info)->keymap[shift])
+ {
+ if (shift != key_detected)
+ {
+ key_detected = shift;
+ keys_post_event((qwerty_keypad->keypad_info)->keymap[shift], 1);
+ timer_set_oneshot(timer,(qwerty_keypad->keypad_info)->poll_time,
+ scan_qt_keypad, NULL);
+ return INT_RESCHEDULE;
+ }
+ }
+ }
+ event_signal(&qwerty_keypad->full_scan, false);
+ return INT_RESCHEDULE;
+}
+
void ssbi_keypad_init(struct qwerty_keypad_info *qwerty_kp)
{
+ unsigned int mach_id;
int len;
len = sizeof(struct gpio_qwerty_kp);
@@ -594,13 +653,25 @@
memset(qwerty_keypad, 0, len);
qwerty_keypad->keypad_info = qwerty_kp;
- ssbi_gpio_init();
-
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);
+
+#ifdef QT_8660_KEYPAD_HW_BUG
+ mach_id = board_machtype();
+#endif
+ ssbi_gpio_init(mach_id);
+
+ if(mach_id == LINUX_MACHTYPE_8660_QT)
+ {
+ mdelay((qwerty_keypad->keypad_info)->settle_time);
+#ifdef QT_8660_KEYPAD_HW_BUG
+ timer_set_oneshot(&qwerty_keypad->timer, 0, scan_qt_keypad, NULL);
+#endif
+ }
+ else
+ 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);