diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2010-05-04 19:59:08 +0530 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-05-04 17:43:25 -0700 |
commit | 7871116830fe633b55d8104deddac603f003306a (patch) | |
tree | 05915eb688a98cbcfa6ad1417cda55026c320544 | |
parent | fc5f671424da0d58aad8378294dfdc0432ec5997 (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.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/odm_to_plat.c | 6 | ||||
-rw-r--r-- | drivers/input/keyboard/tegra-kbc.c | 59 |
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" } }; |