10e5f11aaSEric Miao /* 20e5f11aaSEric Miao * linux/drivers/input/keyboard/pxa27x_keypad.c 30e5f11aaSEric Miao * 40e5f11aaSEric Miao * Driver for the pxa27x matrix keyboard controller. 50e5f11aaSEric Miao * 60e5f11aaSEric Miao * Created: Feb 22, 2007 70e5f11aaSEric Miao * Author: Rodolfo Giometti <giometti@linux.it> 80e5f11aaSEric Miao * 90e5f11aaSEric Miao * Based on a previous implementations by Kevin O'Connor 100e5f11aaSEric Miao * <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and 110e5f11aaSEric Miao * on some suggestions by Nicolas Pitre <nico@cam.org>. 120e5f11aaSEric Miao * 130e5f11aaSEric Miao * This program is free software; you can redistribute it and/or modify 140e5f11aaSEric Miao * it under the terms of the GNU General Public License version 2 as 150e5f11aaSEric Miao * published by the Free Software Foundation. 160e5f11aaSEric Miao */ 170e5f11aaSEric Miao 180e5f11aaSEric Miao 190e5f11aaSEric Miao #include <linux/kernel.h> 200e5f11aaSEric Miao #include <linux/module.h> 210e5f11aaSEric Miao #include <linux/init.h> 220e5f11aaSEric Miao #include <linux/interrupt.h> 230e5f11aaSEric Miao #include <linux/input.h> 240e5f11aaSEric Miao #include <linux/device.h> 250e5f11aaSEric Miao #include <linux/platform_device.h> 260e5f11aaSEric Miao #include <linux/clk.h> 270e5f11aaSEric Miao #include <linux/err.h> 280e5f11aaSEric Miao 290e5f11aaSEric Miao #include <asm/mach-types.h> 300e5f11aaSEric Miao #include <asm/mach/arch.h> 310e5f11aaSEric Miao #include <asm/mach/map.h> 320e5f11aaSEric Miao 330e5f11aaSEric Miao #include <asm/arch/hardware.h> 340e5f11aaSEric Miao #include <asm/arch/pxa-regs.h> 350e5f11aaSEric Miao #include <asm/arch/irqs.h> 360e5f11aaSEric Miao #include <asm/arch/pxa27x_keypad.h> 370e5f11aaSEric Miao 380e5f11aaSEric Miao #define DRIVER_NAME "pxa27x-keypad" 390e5f11aaSEric Miao 40*1814db69SEric Miao #define KPAS_MUKP(n) (((n) >> 26) & 0x1f) 41*1814db69SEric Miao #define KPAS_RP(n) (((n) >> 4) & 0xf) 42*1814db69SEric Miao #define KPAS_CP(n) ((n) & 0xf) 430e5f11aaSEric Miao 44*1814db69SEric Miao #define KPASMKP_MKC_MASK (0xff) 45*1814db69SEric Miao 46*1814db69SEric Miao #define MAX_MATRIX_KEY_NUM (8 * 8) 47*1814db69SEric Miao 48*1814db69SEric Miao struct pxa27x_keypad { 49*1814db69SEric Miao struct pxa27x_keypad_platform_data *pdata; 50*1814db69SEric Miao 51*1814db69SEric Miao struct clk *clk; 52*1814db69SEric Miao struct input_dev *input_dev; 53*1814db69SEric Miao 54*1814db69SEric Miao /* matrix key code map */ 55*1814db69SEric Miao unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; 56*1814db69SEric Miao 57*1814db69SEric Miao /* state row bits of each column scan */ 58*1814db69SEric Miao uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS]; 59*1814db69SEric Miao }; 60*1814db69SEric Miao 61*1814db69SEric Miao static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) 62*1814db69SEric Miao { 63*1814db69SEric Miao struct pxa27x_keypad_platform_data *pdata = keypad->pdata; 64*1814db69SEric Miao struct input_dev *input_dev = keypad->input_dev; 65*1814db69SEric Miao unsigned int *key; 66*1814db69SEric Miao int i; 67*1814db69SEric Miao 68*1814db69SEric Miao key = &pdata->matrix_key_map[0]; 69*1814db69SEric Miao for (i = 0; i < pdata->matrix_key_map_size; i++, key++) { 70*1814db69SEric Miao int row = ((*key) >> 28) & 0xf; 71*1814db69SEric Miao int col = ((*key) >> 24) & 0xf; 72*1814db69SEric Miao int code = (*key) & 0xffffff; 73*1814db69SEric Miao 74*1814db69SEric Miao keypad->matrix_keycodes[(row << 3) + col] = code; 75*1814db69SEric Miao set_bit(code, input_dev->keybit); 76*1814db69SEric Miao } 77*1814db69SEric Miao } 78*1814db69SEric Miao 79*1814db69SEric Miao static inline unsigned int lookup_matrix_keycode( 80*1814db69SEric Miao struct pxa27x_keypad *keypad, int row, int col) 81*1814db69SEric Miao { 82*1814db69SEric Miao return keypad->matrix_keycodes[(row << 3) + col]; 83*1814db69SEric Miao } 84*1814db69SEric Miao 85*1814db69SEric Miao static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) 86*1814db69SEric Miao { 87*1814db69SEric Miao struct pxa27x_keypad_platform_data *pdata = keypad->pdata; 88*1814db69SEric Miao int row, col, num_keys_pressed = 0; 89*1814db69SEric Miao uint32_t new_state[MAX_MATRIX_KEY_COLS]; 90*1814db69SEric Miao uint32_t kpas = KPAS; 91*1814db69SEric Miao 92*1814db69SEric Miao num_keys_pressed = KPAS_MUKP(kpas); 93*1814db69SEric Miao 94*1814db69SEric Miao memset(new_state, 0, sizeof(new_state)); 95*1814db69SEric Miao 96*1814db69SEric Miao if (num_keys_pressed == 0) 97*1814db69SEric Miao goto scan; 98*1814db69SEric Miao 99*1814db69SEric Miao if (num_keys_pressed == 1) { 100*1814db69SEric Miao col = KPAS_CP(kpas); 101*1814db69SEric Miao row = KPAS_RP(kpas); 102*1814db69SEric Miao 103*1814db69SEric Miao /* if invalid row/col, treat as no key pressed */ 104*1814db69SEric Miao if (col >= pdata->matrix_key_cols || 105*1814db69SEric Miao row >= pdata->matrix_key_rows) 106*1814db69SEric Miao goto scan; 107*1814db69SEric Miao 108*1814db69SEric Miao new_state[col] = (1 << row); 109*1814db69SEric Miao goto scan; 110*1814db69SEric Miao } 111*1814db69SEric Miao 112*1814db69SEric Miao if (num_keys_pressed > 1) { 113*1814db69SEric Miao uint32_t kpasmkp0 = KPASMKP0; 114*1814db69SEric Miao uint32_t kpasmkp1 = KPASMKP1; 115*1814db69SEric Miao uint32_t kpasmkp2 = KPASMKP2; 116*1814db69SEric Miao uint32_t kpasmkp3 = KPASMKP3; 117*1814db69SEric Miao 118*1814db69SEric Miao new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK; 119*1814db69SEric Miao new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK; 120*1814db69SEric Miao new_state[2] = kpasmkp1 & KPASMKP_MKC_MASK; 121*1814db69SEric Miao new_state[3] = (kpasmkp1 >> 16) & KPASMKP_MKC_MASK; 122*1814db69SEric Miao new_state[4] = kpasmkp2 & KPASMKP_MKC_MASK; 123*1814db69SEric Miao new_state[5] = (kpasmkp2 >> 16) & KPASMKP_MKC_MASK; 124*1814db69SEric Miao new_state[6] = kpasmkp3 & KPASMKP_MKC_MASK; 125*1814db69SEric Miao new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK; 126*1814db69SEric Miao } 127*1814db69SEric Miao scan: 128*1814db69SEric Miao for (col = 0; col < pdata->matrix_key_cols; col++) { 129*1814db69SEric Miao uint32_t bits_changed; 130*1814db69SEric Miao 131*1814db69SEric Miao bits_changed = keypad->matrix_key_state[col] ^ new_state[col]; 132*1814db69SEric Miao if (bits_changed == 0) 133*1814db69SEric Miao continue; 134*1814db69SEric Miao 135*1814db69SEric Miao for (row = 0; row < pdata->matrix_key_rows; row++) { 136*1814db69SEric Miao if ((bits_changed & (1 << row)) == 0) 137*1814db69SEric Miao continue; 138*1814db69SEric Miao 139*1814db69SEric Miao input_report_key(keypad->input_dev, 140*1814db69SEric Miao lookup_matrix_keycode(keypad, row, col), 141*1814db69SEric Miao new_state[col] & (1 << row)); 142*1814db69SEric Miao } 143*1814db69SEric Miao } 144*1814db69SEric Miao input_sync(keypad->input_dev); 145*1814db69SEric Miao memcpy(keypad->matrix_key_state, new_state, sizeof(new_state)); 146*1814db69SEric Miao } 1470e5f11aaSEric Miao 1480e5f11aaSEric Miao static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) 1490e5f11aaSEric Miao { 150*1814db69SEric Miao struct pxa27x_keypad *keypad = dev_id; 151*1814db69SEric Miao struct input_dev *input_dev = keypad->input_dev; 1520e5f11aaSEric Miao unsigned long kpc = KPC; 153*1814db69SEric Miao int rel; 1540e5f11aaSEric Miao 1550e5f11aaSEric Miao if (kpc & KPC_DI) { 1560e5f11aaSEric Miao unsigned long kpdk = KPDK; 1570e5f11aaSEric Miao 1580e5f11aaSEric Miao if (!(kpdk & KPDK_DKP)) { 1590e5f11aaSEric Miao /* better luck next time */ 1600e5f11aaSEric Miao } else if (kpc & KPC_REE0) { 1610e5f11aaSEric Miao unsigned long kprec = KPREC; 1620e5f11aaSEric Miao KPREC = 0x7f; 1630e5f11aaSEric Miao 1640e5f11aaSEric Miao if (kprec & KPREC_OF0) 1650e5f11aaSEric Miao rel = (kprec & 0xff) + 0x7f; 1660e5f11aaSEric Miao else if (kprec & KPREC_UF0) 1670e5f11aaSEric Miao rel = (kprec & 0xff) - 0x7f - 0xff; 1680e5f11aaSEric Miao else 1690e5f11aaSEric Miao rel = (kprec & 0xff) - 0x7f; 1700e5f11aaSEric Miao 1710e5f11aaSEric Miao if (rel) { 1720e5f11aaSEric Miao input_report_rel(input_dev, REL_WHEEL, rel); 1730e5f11aaSEric Miao input_sync(input_dev); 1740e5f11aaSEric Miao } 1750e5f11aaSEric Miao } 1760e5f11aaSEric Miao } 1770e5f11aaSEric Miao 178*1814db69SEric Miao if (kpc & KPC_MI) 179*1814db69SEric Miao pxa27x_keypad_scan_matrix(keypad); 1800e5f11aaSEric Miao 1810e5f11aaSEric Miao return IRQ_HANDLED; 1820e5f11aaSEric Miao } 1830e5f11aaSEric Miao 1840e5f11aaSEric Miao static int pxa27x_keypad_open(struct input_dev *dev) 1850e5f11aaSEric Miao { 186*1814db69SEric Miao struct pxa27x_keypad *keypad = input_get_drvdata(dev); 187*1814db69SEric Miao 1880e5f11aaSEric Miao /* Set keypad control register */ 1890e5f11aaSEric Miao KPC |= (KPC_ASACT | 1900e5f11aaSEric Miao KPC_MS_ALL | 1910e5f11aaSEric Miao (2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL | 1920e5f11aaSEric Miao KPC_ME | KPC_MIE | KPC_DE | KPC_DIE); 1930e5f11aaSEric Miao 1940e5f11aaSEric Miao KPC &= ~KPC_AS; /* disable automatic scan */ 1950e5f11aaSEric Miao KPC &= ~KPC_IMKP; /* do not ignore multiple keypresses */ 1960e5f11aaSEric Miao 1970e5f11aaSEric Miao /* Set rotary count to mid-point value */ 1980e5f11aaSEric Miao KPREC = 0x7F; 1990e5f11aaSEric Miao 2000e5f11aaSEric Miao /* Enable unit clock */ 201*1814db69SEric Miao clk_enable(keypad->clk); 2020e5f11aaSEric Miao 2030e5f11aaSEric Miao return 0; 2040e5f11aaSEric Miao } 2050e5f11aaSEric Miao 2060e5f11aaSEric Miao static void pxa27x_keypad_close(struct input_dev *dev) 2070e5f11aaSEric Miao { 208*1814db69SEric Miao struct pxa27x_keypad *keypad = input_get_drvdata(dev); 209*1814db69SEric Miao 2100e5f11aaSEric Miao /* Disable clock unit */ 211*1814db69SEric Miao clk_disable(keypad->clk); 2120e5f11aaSEric Miao } 2130e5f11aaSEric Miao 2140e5f11aaSEric Miao #ifdef CONFIG_PM 2150e5f11aaSEric Miao static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state) 2160e5f11aaSEric Miao { 217*1814db69SEric Miao struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); 218*1814db69SEric Miao struct pxa27x_keypad_platform_data *pdata = keypad->pdata; 2190e5f11aaSEric Miao 2200e5f11aaSEric Miao /* Save controller status */ 2210e5f11aaSEric Miao pdata->reg_kpc = KPC; 2220e5f11aaSEric Miao pdata->reg_kprec = KPREC; 2230e5f11aaSEric Miao 2240e5f11aaSEric Miao return 0; 2250e5f11aaSEric Miao } 2260e5f11aaSEric Miao 2270e5f11aaSEric Miao static int pxa27x_keypad_resume(struct platform_device *pdev) 2280e5f11aaSEric Miao { 229*1814db69SEric Miao struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); 230*1814db69SEric Miao struct pxa27x_keypad_platform_data *pdata = keypad->pdata; 231*1814db69SEric Miao struct input_dev *input_dev = keypad->input_dev; 2320e5f11aaSEric Miao 2330e5f11aaSEric Miao mutex_lock(&input_dev->mutex); 2340e5f11aaSEric Miao 2350e5f11aaSEric Miao if (input_dev->users) { 2360e5f11aaSEric Miao /* Restore controller status */ 2370e5f11aaSEric Miao KPC = pdata->reg_kpc; 2380e5f11aaSEric Miao KPREC = pdata->reg_kprec; 2390e5f11aaSEric Miao 2400e5f11aaSEric Miao /* Enable unit clock */ 241*1814db69SEric Miao clk_enable(keypad->clk); 2420e5f11aaSEric Miao } 2430e5f11aaSEric Miao 2440e5f11aaSEric Miao mutex_unlock(&input_dev->mutex); 2450e5f11aaSEric Miao 2460e5f11aaSEric Miao return 0; 2470e5f11aaSEric Miao } 2480e5f11aaSEric Miao #else 2490e5f11aaSEric Miao #define pxa27x_keypad_suspend NULL 2500e5f11aaSEric Miao #define pxa27x_keypad_resume NULL 2510e5f11aaSEric Miao #endif 2520e5f11aaSEric Miao 2530e5f11aaSEric Miao static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) 2540e5f11aaSEric Miao { 255*1814db69SEric Miao struct pxa27x_keypad *keypad; 2560e5f11aaSEric Miao struct input_dev *input_dev; 257*1814db69SEric Miao int col, error; 2580e5f11aaSEric Miao 259*1814db69SEric Miao keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL); 260*1814db69SEric Miao if (keypad == NULL) { 261*1814db69SEric Miao dev_err(&pdev->dev, "failed to allocate driver data\n"); 262*1814db69SEric Miao return -ENOMEM; 263*1814db69SEric Miao } 264*1814db69SEric Miao 265*1814db69SEric Miao keypad->pdata = pdev->dev.platform_data; 266*1814db69SEric Miao if (keypad->pdata == NULL) { 267*1814db69SEric Miao dev_err(&pdev->dev, "no platform data defined\n"); 268*1814db69SEric Miao error = -EINVAL; 269*1814db69SEric Miao goto failed_free; 270*1814db69SEric Miao } 271*1814db69SEric Miao 272*1814db69SEric Miao keypad->clk = clk_get(&pdev->dev, "KBDCLK"); 273*1814db69SEric Miao if (IS_ERR(keypad->clk)) { 274*1814db69SEric Miao dev_err(&pdev->dev, "failed to get keypad clock\n"); 275*1814db69SEric Miao error = PTR_ERR(keypad->clk); 276*1814db69SEric Miao goto failed_free; 2770e5f11aaSEric Miao } 2780e5f11aaSEric Miao 2790e5f11aaSEric Miao /* Create and register the input driver. */ 2800e5f11aaSEric Miao input_dev = input_allocate_device(); 2810e5f11aaSEric Miao if (!input_dev) { 282*1814db69SEric Miao dev_err(&pdev->dev, "failed to allocate input device\n"); 2830e5f11aaSEric Miao error = -ENOMEM; 284*1814db69SEric Miao goto failed_put_clk; 2850e5f11aaSEric Miao } 2860e5f11aaSEric Miao 2870e5f11aaSEric Miao input_dev->name = DRIVER_NAME; 2880e5f11aaSEric Miao input_dev->id.bustype = BUS_HOST; 2890e5f11aaSEric Miao input_dev->open = pxa27x_keypad_open; 2900e5f11aaSEric Miao input_dev->close = pxa27x_keypad_close; 2910e5f11aaSEric Miao input_dev->dev.parent = &pdev->dev; 2920e5f11aaSEric Miao 293*1814db69SEric Miao keypad->input_dev = input_dev; 294*1814db69SEric Miao input_set_drvdata(input_dev, keypad); 295*1814db69SEric Miao 2960e5f11aaSEric Miao input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | 2970e5f11aaSEric Miao BIT_MASK(EV_REL); 2980e5f11aaSEric Miao input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL); 299*1814db69SEric Miao 300*1814db69SEric Miao pxa27x_keypad_build_keycode(keypad); 3010e5f11aaSEric Miao 3020e5f11aaSEric Miao error = request_irq(IRQ_KEYPAD, pxa27x_keypad_irq_handler, IRQF_DISABLED, 303*1814db69SEric Miao DRIVER_NAME, keypad); 3040e5f11aaSEric Miao if (error) { 3050e5f11aaSEric Miao printk(KERN_ERR "Cannot request keypad IRQ\n"); 3060e5f11aaSEric Miao goto err_free_dev; 3070e5f11aaSEric Miao } 3080e5f11aaSEric Miao 309*1814db69SEric Miao platform_set_drvdata(pdev, keypad); 3100e5f11aaSEric Miao 3110e5f11aaSEric Miao /* Register the input device */ 3120e5f11aaSEric Miao error = input_register_device(input_dev); 3130e5f11aaSEric Miao if (error) 3140e5f11aaSEric Miao goto err_free_irq; 3150e5f11aaSEric Miao 3160e5f11aaSEric Miao /* 3170e5f11aaSEric Miao * Store rows/cols info into keyboard registers. 3180e5f11aaSEric Miao */ 3190e5f11aaSEric Miao 320*1814db69SEric Miao KPC |= (keypad->pdata->matrix_key_rows - 1) << 26; 321*1814db69SEric Miao KPC |= (keypad->pdata->matrix_key_cols - 1) << 23; 3220e5f11aaSEric Miao 323*1814db69SEric Miao for (col = 0; col < keypad->pdata->matrix_key_cols; col++) 3240e5f11aaSEric Miao KPC |= KPC_MS0 << col; 3250e5f11aaSEric Miao 3260e5f11aaSEric Miao return 0; 3270e5f11aaSEric Miao 3280e5f11aaSEric Miao err_free_irq: 3290e5f11aaSEric Miao platform_set_drvdata(pdev, NULL); 3300e5f11aaSEric Miao free_irq(IRQ_KEYPAD, pdev); 3310e5f11aaSEric Miao err_free_dev: 3320e5f11aaSEric Miao input_free_device(input_dev); 333*1814db69SEric Miao failed_put_clk: 334*1814db69SEric Miao clk_put(keypad->clk); 335*1814db69SEric Miao failed_free: 336*1814db69SEric Miao kfree(keypad); 3370e5f11aaSEric Miao return error; 3380e5f11aaSEric Miao } 3390e5f11aaSEric Miao 3400e5f11aaSEric Miao static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) 3410e5f11aaSEric Miao { 342*1814db69SEric Miao struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); 3430e5f11aaSEric Miao 3440e5f11aaSEric Miao free_irq(IRQ_KEYPAD, pdev); 3450e5f11aaSEric Miao 346*1814db69SEric Miao clk_disable(keypad->clk); 347*1814db69SEric Miao clk_put(keypad->clk); 348*1814db69SEric Miao 349*1814db69SEric Miao input_unregister_device(keypad->input_dev); 350*1814db69SEric Miao 351*1814db69SEric Miao platform_set_drvdata(pdev, NULL); 352*1814db69SEric Miao kfree(keypad); 3530e5f11aaSEric Miao return 0; 3540e5f11aaSEric Miao } 3550e5f11aaSEric Miao 3560e5f11aaSEric Miao static struct platform_driver pxa27x_keypad_driver = { 3570e5f11aaSEric Miao .probe = pxa27x_keypad_probe, 3580e5f11aaSEric Miao .remove = __devexit_p(pxa27x_keypad_remove), 3590e5f11aaSEric Miao .suspend = pxa27x_keypad_suspend, 3600e5f11aaSEric Miao .resume = pxa27x_keypad_resume, 3610e5f11aaSEric Miao .driver = { 3620e5f11aaSEric Miao .name = DRIVER_NAME, 3630e5f11aaSEric Miao }, 3640e5f11aaSEric Miao }; 3650e5f11aaSEric Miao 3660e5f11aaSEric Miao static int __init pxa27x_keypad_init(void) 3670e5f11aaSEric Miao { 3680e5f11aaSEric Miao return platform_driver_register(&pxa27x_keypad_driver); 3690e5f11aaSEric Miao } 3700e5f11aaSEric Miao 3710e5f11aaSEric Miao static void __exit pxa27x_keypad_exit(void) 3720e5f11aaSEric Miao { 3730e5f11aaSEric Miao platform_driver_unregister(&pxa27x_keypad_driver); 3740e5f11aaSEric Miao } 3750e5f11aaSEric Miao 3760e5f11aaSEric Miao module_init(pxa27x_keypad_init); 3770e5f11aaSEric Miao module_exit(pxa27x_keypad_exit); 3780e5f11aaSEric Miao 3790e5f11aaSEric Miao MODULE_DESCRIPTION("PXA27x Keypad Controller Driver"); 3800e5f11aaSEric Miao MODULE_LICENSE("GPL"); 381