1*0e5f11aaSEric Miao /* 2*0e5f11aaSEric Miao * linux/drivers/input/keyboard/pxa27x_keypad.c 3*0e5f11aaSEric Miao * 4*0e5f11aaSEric Miao * Driver for the pxa27x matrix keyboard controller. 5*0e5f11aaSEric Miao * 6*0e5f11aaSEric Miao * Created: Feb 22, 2007 7*0e5f11aaSEric Miao * Author: Rodolfo Giometti <giometti@linux.it> 8*0e5f11aaSEric Miao * 9*0e5f11aaSEric Miao * Based on a previous implementations by Kevin O'Connor 10*0e5f11aaSEric Miao * <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and 11*0e5f11aaSEric Miao * on some suggestions by Nicolas Pitre <nico@cam.org>. 12*0e5f11aaSEric Miao * 13*0e5f11aaSEric Miao * This program is free software; you can redistribute it and/or modify 14*0e5f11aaSEric Miao * it under the terms of the GNU General Public License version 2 as 15*0e5f11aaSEric Miao * published by the Free Software Foundation. 16*0e5f11aaSEric Miao */ 17*0e5f11aaSEric Miao 18*0e5f11aaSEric Miao 19*0e5f11aaSEric Miao #include <linux/kernel.h> 20*0e5f11aaSEric Miao #include <linux/module.h> 21*0e5f11aaSEric Miao #include <linux/init.h> 22*0e5f11aaSEric Miao #include <linux/interrupt.h> 23*0e5f11aaSEric Miao #include <linux/input.h> 24*0e5f11aaSEric Miao #include <linux/device.h> 25*0e5f11aaSEric Miao #include <linux/platform_device.h> 26*0e5f11aaSEric Miao #include <linux/clk.h> 27*0e5f11aaSEric Miao #include <linux/err.h> 28*0e5f11aaSEric Miao 29*0e5f11aaSEric Miao #include <asm/mach-types.h> 30*0e5f11aaSEric Miao #include <asm/mach/arch.h> 31*0e5f11aaSEric Miao #include <asm/mach/map.h> 32*0e5f11aaSEric Miao 33*0e5f11aaSEric Miao #include <asm/arch/hardware.h> 34*0e5f11aaSEric Miao #include <asm/arch/pxa-regs.h> 35*0e5f11aaSEric Miao #include <asm/arch/irqs.h> 36*0e5f11aaSEric Miao #include <asm/arch/pxa27x_keypad.h> 37*0e5f11aaSEric Miao 38*0e5f11aaSEric Miao #define DRIVER_NAME "pxa27x-keypad" 39*0e5f11aaSEric Miao 40*0e5f11aaSEric Miao #define KPASMKP(col) (col/2 == 0 ? KPASMKP0 : \ 41*0e5f11aaSEric Miao col/2 == 1 ? KPASMKP1 : \ 42*0e5f11aaSEric Miao col/2 == 2 ? KPASMKP2 : KPASMKP3) 43*0e5f11aaSEric Miao #define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2))) 44*0e5f11aaSEric Miao 45*0e5f11aaSEric Miao static struct clk *pxa27x_keypad_clk; 46*0e5f11aaSEric Miao 47*0e5f11aaSEric Miao static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) 48*0e5f11aaSEric Miao { 49*0e5f11aaSEric Miao struct platform_device *pdev = dev_id; 50*0e5f11aaSEric Miao struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; 51*0e5f11aaSEric Miao struct input_dev *input_dev = platform_get_drvdata(pdev); 52*0e5f11aaSEric Miao unsigned long kpc = KPC; 53*0e5f11aaSEric Miao int p, row, col, rel; 54*0e5f11aaSEric Miao 55*0e5f11aaSEric Miao if (kpc & KPC_DI) { 56*0e5f11aaSEric Miao unsigned long kpdk = KPDK; 57*0e5f11aaSEric Miao 58*0e5f11aaSEric Miao if (!(kpdk & KPDK_DKP)) { 59*0e5f11aaSEric Miao /* better luck next time */ 60*0e5f11aaSEric Miao } else if (kpc & KPC_REE0) { 61*0e5f11aaSEric Miao unsigned long kprec = KPREC; 62*0e5f11aaSEric Miao KPREC = 0x7f; 63*0e5f11aaSEric Miao 64*0e5f11aaSEric Miao if (kprec & KPREC_OF0) 65*0e5f11aaSEric Miao rel = (kprec & 0xff) + 0x7f; 66*0e5f11aaSEric Miao else if (kprec & KPREC_UF0) 67*0e5f11aaSEric Miao rel = (kprec & 0xff) - 0x7f - 0xff; 68*0e5f11aaSEric Miao else 69*0e5f11aaSEric Miao rel = (kprec & 0xff) - 0x7f; 70*0e5f11aaSEric Miao 71*0e5f11aaSEric Miao if (rel) { 72*0e5f11aaSEric Miao input_report_rel(input_dev, REL_WHEEL, rel); 73*0e5f11aaSEric Miao input_sync(input_dev); 74*0e5f11aaSEric Miao } 75*0e5f11aaSEric Miao } 76*0e5f11aaSEric Miao } 77*0e5f11aaSEric Miao 78*0e5f11aaSEric Miao if (kpc & KPC_MI) { 79*0e5f11aaSEric Miao /* report the status of every button */ 80*0e5f11aaSEric Miao for (row = 0; row < pdata->nr_rows; row++) { 81*0e5f11aaSEric Miao for (col = 0; col < pdata->nr_cols; col++) { 82*0e5f11aaSEric Miao p = KPASMKP(col) & KPASMKPx_MKC(row, col) ? 83*0e5f11aaSEric Miao 1 : 0; 84*0e5f11aaSEric Miao pr_debug("keycode %x - pressed %x\n", 85*0e5f11aaSEric Miao pdata->keycodes[row][col], p); 86*0e5f11aaSEric Miao input_report_key(input_dev, 87*0e5f11aaSEric Miao pdata->keycodes[row][col], p); 88*0e5f11aaSEric Miao } 89*0e5f11aaSEric Miao } 90*0e5f11aaSEric Miao input_sync(input_dev); 91*0e5f11aaSEric Miao } 92*0e5f11aaSEric Miao 93*0e5f11aaSEric Miao return IRQ_HANDLED; 94*0e5f11aaSEric Miao } 95*0e5f11aaSEric Miao 96*0e5f11aaSEric Miao static int pxa27x_keypad_open(struct input_dev *dev) 97*0e5f11aaSEric Miao { 98*0e5f11aaSEric Miao /* Set keypad control register */ 99*0e5f11aaSEric Miao KPC |= (KPC_ASACT | 100*0e5f11aaSEric Miao KPC_MS_ALL | 101*0e5f11aaSEric Miao (2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL | 102*0e5f11aaSEric Miao KPC_ME | KPC_MIE | KPC_DE | KPC_DIE); 103*0e5f11aaSEric Miao 104*0e5f11aaSEric Miao KPC &= ~KPC_AS; /* disable automatic scan */ 105*0e5f11aaSEric Miao KPC &= ~KPC_IMKP; /* do not ignore multiple keypresses */ 106*0e5f11aaSEric Miao 107*0e5f11aaSEric Miao /* Set rotary count to mid-point value */ 108*0e5f11aaSEric Miao KPREC = 0x7F; 109*0e5f11aaSEric Miao 110*0e5f11aaSEric Miao /* Enable unit clock */ 111*0e5f11aaSEric Miao clk_enable(pxa27x_keypad_clk); 112*0e5f11aaSEric Miao 113*0e5f11aaSEric Miao return 0; 114*0e5f11aaSEric Miao } 115*0e5f11aaSEric Miao 116*0e5f11aaSEric Miao static void pxa27x_keypad_close(struct input_dev *dev) 117*0e5f11aaSEric Miao { 118*0e5f11aaSEric Miao /* Disable clock unit */ 119*0e5f11aaSEric Miao clk_disable(pxa27x_keypad_clk); 120*0e5f11aaSEric Miao } 121*0e5f11aaSEric Miao 122*0e5f11aaSEric Miao #ifdef CONFIG_PM 123*0e5f11aaSEric Miao static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state) 124*0e5f11aaSEric Miao { 125*0e5f11aaSEric Miao struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; 126*0e5f11aaSEric Miao 127*0e5f11aaSEric Miao /* Save controller status */ 128*0e5f11aaSEric Miao pdata->reg_kpc = KPC; 129*0e5f11aaSEric Miao pdata->reg_kprec = KPREC; 130*0e5f11aaSEric Miao 131*0e5f11aaSEric Miao return 0; 132*0e5f11aaSEric Miao } 133*0e5f11aaSEric Miao 134*0e5f11aaSEric Miao static int pxa27x_keypad_resume(struct platform_device *pdev) 135*0e5f11aaSEric Miao { 136*0e5f11aaSEric Miao struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; 137*0e5f11aaSEric Miao struct input_dev *input_dev = platform_get_drvdata(pdev); 138*0e5f11aaSEric Miao 139*0e5f11aaSEric Miao mutex_lock(&input_dev->mutex); 140*0e5f11aaSEric Miao 141*0e5f11aaSEric Miao if (input_dev->users) { 142*0e5f11aaSEric Miao /* Restore controller status */ 143*0e5f11aaSEric Miao KPC = pdata->reg_kpc; 144*0e5f11aaSEric Miao KPREC = pdata->reg_kprec; 145*0e5f11aaSEric Miao 146*0e5f11aaSEric Miao /* Enable unit clock */ 147*0e5f11aaSEric Miao clk_disable(pxa27x_keypad_clk); 148*0e5f11aaSEric Miao clk_enable(pxa27x_keypad_clk); 149*0e5f11aaSEric Miao } 150*0e5f11aaSEric Miao 151*0e5f11aaSEric Miao mutex_unlock(&input_dev->mutex); 152*0e5f11aaSEric Miao 153*0e5f11aaSEric Miao return 0; 154*0e5f11aaSEric Miao } 155*0e5f11aaSEric Miao #else 156*0e5f11aaSEric Miao #define pxa27x_keypad_suspend NULL 157*0e5f11aaSEric Miao #define pxa27x_keypad_resume NULL 158*0e5f11aaSEric Miao #endif 159*0e5f11aaSEric Miao 160*0e5f11aaSEric Miao static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) 161*0e5f11aaSEric Miao { 162*0e5f11aaSEric Miao struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; 163*0e5f11aaSEric Miao struct input_dev *input_dev; 164*0e5f11aaSEric Miao int i, row, col, error; 165*0e5f11aaSEric Miao 166*0e5f11aaSEric Miao pxa27x_keypad_clk = clk_get(&pdev->dev, "KBDCLK"); 167*0e5f11aaSEric Miao if (IS_ERR(pxa27x_keypad_clk)) { 168*0e5f11aaSEric Miao error = PTR_ERR(pxa27x_keypad_clk); 169*0e5f11aaSEric Miao goto err_clk; 170*0e5f11aaSEric Miao } 171*0e5f11aaSEric Miao 172*0e5f11aaSEric Miao /* Create and register the input driver. */ 173*0e5f11aaSEric Miao input_dev = input_allocate_device(); 174*0e5f11aaSEric Miao if (!input_dev) { 175*0e5f11aaSEric Miao printk(KERN_ERR "Cannot request keypad device\n"); 176*0e5f11aaSEric Miao error = -ENOMEM; 177*0e5f11aaSEric Miao goto err_alloc; 178*0e5f11aaSEric Miao } 179*0e5f11aaSEric Miao 180*0e5f11aaSEric Miao input_dev->name = DRIVER_NAME; 181*0e5f11aaSEric Miao input_dev->id.bustype = BUS_HOST; 182*0e5f11aaSEric Miao input_dev->open = pxa27x_keypad_open; 183*0e5f11aaSEric Miao input_dev->close = pxa27x_keypad_close; 184*0e5f11aaSEric Miao input_dev->dev.parent = &pdev->dev; 185*0e5f11aaSEric Miao 186*0e5f11aaSEric Miao input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | 187*0e5f11aaSEric Miao BIT_MASK(EV_REL); 188*0e5f11aaSEric Miao input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL); 189*0e5f11aaSEric Miao for (row = 0; row < pdata->nr_rows; row++) { 190*0e5f11aaSEric Miao for (col = 0; col < pdata->nr_cols; col++) { 191*0e5f11aaSEric Miao int code = pdata->keycodes[row][col]; 192*0e5f11aaSEric Miao if (code > 0) 193*0e5f11aaSEric Miao set_bit(code, input_dev->keybit); 194*0e5f11aaSEric Miao } 195*0e5f11aaSEric Miao } 196*0e5f11aaSEric Miao 197*0e5f11aaSEric Miao error = request_irq(IRQ_KEYPAD, pxa27x_keypad_irq_handler, IRQF_DISABLED, 198*0e5f11aaSEric Miao DRIVER_NAME, pdev); 199*0e5f11aaSEric Miao if (error) { 200*0e5f11aaSEric Miao printk(KERN_ERR "Cannot request keypad IRQ\n"); 201*0e5f11aaSEric Miao goto err_free_dev; 202*0e5f11aaSEric Miao } 203*0e5f11aaSEric Miao 204*0e5f11aaSEric Miao platform_set_drvdata(pdev, input_dev); 205*0e5f11aaSEric Miao 206*0e5f11aaSEric Miao /* Register the input device */ 207*0e5f11aaSEric Miao error = input_register_device(input_dev); 208*0e5f11aaSEric Miao if (error) 209*0e5f11aaSEric Miao goto err_free_irq; 210*0e5f11aaSEric Miao 211*0e5f11aaSEric Miao /* Setup GPIOs. */ 212*0e5f11aaSEric Miao for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++) 213*0e5f11aaSEric Miao pxa_gpio_mode(pdata->gpio_modes[i]); 214*0e5f11aaSEric Miao 215*0e5f11aaSEric Miao /* 216*0e5f11aaSEric Miao * Store rows/cols info into keyboard registers. 217*0e5f11aaSEric Miao */ 218*0e5f11aaSEric Miao 219*0e5f11aaSEric Miao KPC |= (pdata->nr_rows - 1) << 26; 220*0e5f11aaSEric Miao KPC |= (pdata->nr_cols - 1) << 23; 221*0e5f11aaSEric Miao 222*0e5f11aaSEric Miao for (col = 0; col < pdata->nr_cols; col++) 223*0e5f11aaSEric Miao KPC |= KPC_MS0 << col; 224*0e5f11aaSEric Miao 225*0e5f11aaSEric Miao return 0; 226*0e5f11aaSEric Miao 227*0e5f11aaSEric Miao err_free_irq: 228*0e5f11aaSEric Miao platform_set_drvdata(pdev, NULL); 229*0e5f11aaSEric Miao free_irq(IRQ_KEYPAD, pdev); 230*0e5f11aaSEric Miao err_free_dev: 231*0e5f11aaSEric Miao input_free_device(input_dev); 232*0e5f11aaSEric Miao err_alloc: 233*0e5f11aaSEric Miao clk_put(pxa27x_keypad_clk); 234*0e5f11aaSEric Miao err_clk: 235*0e5f11aaSEric Miao return error; 236*0e5f11aaSEric Miao } 237*0e5f11aaSEric Miao 238*0e5f11aaSEric Miao static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) 239*0e5f11aaSEric Miao { 240*0e5f11aaSEric Miao struct input_dev *input_dev = platform_get_drvdata(pdev); 241*0e5f11aaSEric Miao 242*0e5f11aaSEric Miao input_unregister_device(input_dev); 243*0e5f11aaSEric Miao free_irq(IRQ_KEYPAD, pdev); 244*0e5f11aaSEric Miao clk_put(pxa27x_keypad_clk); 245*0e5f11aaSEric Miao platform_set_drvdata(pdev, NULL); 246*0e5f11aaSEric Miao 247*0e5f11aaSEric Miao return 0; 248*0e5f11aaSEric Miao } 249*0e5f11aaSEric Miao 250*0e5f11aaSEric Miao static struct platform_driver pxa27x_keypad_driver = { 251*0e5f11aaSEric Miao .probe = pxa27x_keypad_probe, 252*0e5f11aaSEric Miao .remove = __devexit_p(pxa27x_keypad_remove), 253*0e5f11aaSEric Miao .suspend = pxa27x_keypad_suspend, 254*0e5f11aaSEric Miao .resume = pxa27x_keypad_resume, 255*0e5f11aaSEric Miao .driver = { 256*0e5f11aaSEric Miao .name = DRIVER_NAME, 257*0e5f11aaSEric Miao }, 258*0e5f11aaSEric Miao }; 259*0e5f11aaSEric Miao 260*0e5f11aaSEric Miao static int __init pxa27x_keypad_init(void) 261*0e5f11aaSEric Miao { 262*0e5f11aaSEric Miao return platform_driver_register(&pxa27x_keypad_driver); 263*0e5f11aaSEric Miao } 264*0e5f11aaSEric Miao 265*0e5f11aaSEric Miao static void __exit pxa27x_keypad_exit(void) 266*0e5f11aaSEric Miao { 267*0e5f11aaSEric Miao platform_driver_unregister(&pxa27x_keypad_driver); 268*0e5f11aaSEric Miao } 269*0e5f11aaSEric Miao 270*0e5f11aaSEric Miao module_init(pxa27x_keypad_init); 271*0e5f11aaSEric Miao module_exit(pxa27x_keypad_exit); 272*0e5f11aaSEric Miao 273*0e5f11aaSEric Miao MODULE_DESCRIPTION("PXA27x Keypad Controller Driver"); 274*0e5f11aaSEric Miao MODULE_LICENSE("GPL"); 275