summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2010-05-04 19:59:08 +0530
committerGary King <gking@nvidia.com>2010-05-04 17:43:25 -0700
commit7871116830fe633b55d8104deddac603f003306a (patch)
tree05915eb688a98cbcfa6ad1417cda55026c320544
parentfc5f671424da0d58aad8378294dfdc0432ec5997 (diff)
tegra kbc: Fixing android boot if key is kept press during boot.
Following changes are done: - Created the new workqueue for the kbc scan process. On default workqueue, the msleep() was not causing the schedule() to booting process. - If there is no entry in fifo then wait for the next scan to complete before re-reading the number of entries in the fifo. if there is no entry then rep key released. - Fixed timing calculation and size of the event entry array. - Fixed the debaunce count calculation from debaunce time from odm. Tested on whistler, with normal boot as well as with continous key pressed d the entire boot time. Change-Id: I53b321ae6f5e1f425b51edcd63f7de4ae404e505 Reviewed-on: http://git-master/r/1238 Reviewed-by: Hu He <hhe@nvidia.com> Tested-by: Hu He <hhe@nvidia.com> Reviewed-by: Gary King <gking@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/board_nvodm.c2
-rw-r--r--arch/arm/mach-tegra/odm_to_plat.c6
-rw-r--r--drivers/input/keyboard/tegra-kbc.c59
3 files changed, 45 insertions, 22 deletions
diff --git a/arch/arm/mach-tegra/board_nvodm.c b/arch/arm/mach-tegra/board_nvodm.c
index d9eefc00db3f..f13f503a3683 100644
--- a/arch/arm/mach-tegra/board_nvodm.c
+++ b/arch/arm/mach-tegra/board_nvodm.c
@@ -430,7 +430,7 @@ static void kbc_init(void)
struct tegra_kbc_plat *pdata = NULL;
static struct resource res[2];
- dev = platform_device_alloc("tegra_kbc", -1);
+ dev = platform_device_alloc("tegra-kbc", -1);
if (!dev)
goto fail;
diff --git a/arch/arm/mach-tegra/odm_to_plat.c b/arch/arm/mach-tegra/odm_to_plat.c
index 7ccc982d1f25..209268572276 100644
--- a/arch/arm/mach-tegra/odm_to_plat.c
+++ b/arch/arm/mach-tegra/odm_to_plat.c
@@ -71,12 +71,14 @@ struct tegra_kbc_plat *tegra_kbc_odm_to_plat(void)
NvOdmKbcGetParameter(NvOdmKbcParameter_DebounceTime, 1, &temp);
- pdata->debounce_cnt = temp;
+ /* debounce time is reported from ODM in milliseconds,
+ * but needs to be specified in 32KHz ticks */
+ pdata->debounce_cnt = temp *32;
/* repeat cycle is reported from ODM in milliseconds,
* but needs to be specified in 32KHz ticks */
NvOdmKbcGetParameter(NvOdmKbcParameter_RepeatCycleTime, 1, &temp);
- pdata->repeat_cnt = temp * 4096 / 125;
+ pdata->repeat_cnt = temp * 32;
temp = NvOdmPeripheralEnumerate(&srch_attr, &srch_val, 1, &guid, 1);
if (!temp) {
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index 1a5768fb602f..efd584dcd125 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -59,6 +59,7 @@ struct tegra_kbc {
unsigned int repoll_time;
struct tegra_kbc_plat *pdata;
struct work_struct key_repeat;
+ struct workqueue_struct *kbc_work_queue;
#ifdef RM_SUPPORT
NvU32 client_id;
#else
@@ -208,7 +209,7 @@ static int tegra_kbc_resume(struct platform_device *pdev)
static void tegra_kbc_report_keys(struct tegra_kbc *kbc, int *fifo)
{
int curr_fifo[KBC_MAX_KPENT];
- u32 kp_ent_val[(KBC_MAX_KPENT*8 + 3) / 4];
+ u32 kp_ent_val[(KBC_MAX_KPENT + 3) / 4];
u32 *kp_ents = kp_ent_val;
u32 kp_ent;
unsigned long flags;
@@ -273,13 +274,13 @@ static void tegra_kbc_key_repeat(struct work_struct *work)
if (!val) {
/* release any pressed keys and exit the loop */
for (i=0; i<ARRAY_SIZE(fifo); i++) {
- if (fifo[i]==-1) continue;
+ if (fifo[i] == -1)
+ continue;
input_report_key(kbc->idev, fifo[i], 0);
}
break;
}
tegra_kbc_report_keys(kbc, fifo);
- /* FIXME: why is this here? */
msleep((val==1) ? kbc->repoll_time : 1);
}
@@ -296,6 +297,7 @@ static void tegra_kbc_close(struct input_dev *dev)
unsigned long flags;
u32 val;
+ spin_lock_irqsave(&kbc->lock, flags);
val = readl(kbc->mmio + KBC_CONTROL_0);
val &= ~1;
writel(val, kbc->mmio + KBC_CONTROL_0);
@@ -373,18 +375,6 @@ static int tegra_kbc_open(struct input_dev *dev)
tegra_kbc_config_pins(kbc);
tegra_kbc_setup_wakekeys(kbc, false);
- /* atomically clear out any remaining entries in the key FIFO
- * and enable keyboard interrupts */
- spin_lock_irqsave(&kbc->lock, flags);
- val = readl(kbc->mmio + KBC_INT_0);
- val >>= 4;
- if (val) {
- val = readl(kbc->mmio + KBC_KP_ENT0_0);
- val = readl(kbc->mmio + KBC_KP_ENT1_0);
- }
- writel(0x7, kbc->mmio + KBC_INT_0);
- spin_unlock_irqrestore(&kbc->lock, flags);
-
writel(kbc->pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
val = kbc->pdata->debounce_cnt << 4;
@@ -393,6 +383,22 @@ static int tegra_kbc_open(struct input_dev *dev)
val |= 1; /* enable */
writel(val, kbc->mmio + KBC_CONTROL_0);
+ /* atomically clear out any remaining entries in the key FIFO
+ * and enable keyboard interrupts */
+ spin_lock_irqsave(&kbc->lock, flags);
+ while(1) {
+ val = readl(kbc->mmio + KBC_INT_0);
+ val >>= 4;
+ if (val) {
+ val = readl(kbc->mmio + KBC_KP_ENT0_0);
+ val = readl(kbc->mmio + KBC_KP_ENT1_0);
+ } else {
+ break;
+ }
+ }
+ writel(0x7, kbc->mmio + KBC_INT_0);
+ spin_unlock_irqrestore(&kbc->lock, flags);
+
return 0;
}
@@ -410,6 +416,7 @@ static int __devexit tegra_kbc_remove(struct platform_device *pdev)
input_unregister_device(kbc->idev);
input_free_device(kbc->idev);
iounmap(kbc->mmio);
+ destroy_workqueue(kbc->kbc_work_queue);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res_size(res));
@@ -438,8 +445,7 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
writel(ctl, kbc->mmio + KBC_CONTROL_0);
return IRQ_HANDLED;
}
-
- schedule_work(&kbc->key_repeat);
+ queue_work(kbc->kbc_work_queue, &kbc->key_repeat);
return IRQ_HANDLED;
}
@@ -454,6 +460,7 @@ static int __init tegra_kbc_probe(struct platform_device *pdev)
int cols[KBC_MAX_COL];
int i, j;
int nr = 0;
+ char name[64];
if (!pdata) return -EINVAL;
@@ -534,8 +541,10 @@ static int __init tegra_kbc_probe(struct platform_device *pdev)
}
}
+ /* The debaunce count is maximum 0x3FF clocks i.e. 10 bit configuration */
+ pdata->debounce_cnt = (pdata->debounce_cnt > 0x3FF)?0x3FF:pdata->debounce_cnt;
kbc->repoll_time = 5 + (16+pdata->debounce_cnt)*nr + pdata->repeat_cnt;
- kbc->repoll_time = (kbc->repoll_time*1000 + 16384) / 32768;
+ kbc->repoll_time = (kbc->repoll_time + 31) / 32;
kbc->idev->evbit[0] = BIT_MASK(EV_KEY);
@@ -550,9 +559,20 @@ static int __init tegra_kbc_probe(struct platform_device *pdev)
}
}
+
+ /* create the workqueue for the kbc path */
+ snprintf(name, sizeof(name), "tegra-kbc");
+ kbc->kbc_work_queue = create_singlethread_workqueue(name);
+ if (kbc->kbc_work_queue == NULL) {
+ dev_err(&pdev->dev, "Failed to create work queue\n");
+ err = -ENODEV;
+ goto fail;
+ }
+
/* keycode FIFO needs to be read atomically; leave local
* interrupts disabled when handling KBC interrupt */
INIT_WORK(&kbc->key_repeat, tegra_kbc_key_repeat);
+
err = request_irq(irq, tegra_kbc_isr, IRQF_DISABLED, pdev->name, kbc);
if (err) {
dev_err(&pdev->dev, "failed to request keypad IRQ\n");
@@ -574,6 +594,7 @@ fail:
if (kbc->idev) input_free_device(kbc->idev);
free_resource(kbc);
if (kbc->mmio) iounmap(kbc->mmio);
+ if (kbc->kbc_work_queue) destroy_workqueue(kbc->kbc_work_queue);
kfree(kbc);
return err;
}
@@ -586,7 +607,7 @@ static struct platform_driver tegra_kbc_driver = {
.resume = tegra_kbc_resume,
#endif
.driver = {
- .name = "tegra_kbc"
+ .name = "tegra-kbc"
}
};