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*d7416f9eSEric Miao #define KPC_MKRN(n) ((((n) & 0x7) - 1) << 26) /* matrix key row number */ 41*d7416f9eSEric Miao #define KPC_MKCN(n) ((((n) & 0x7) - 1) << 23) /* matrix key column number */ 42*d7416f9eSEric Miao #define KPC_DKN(n) ((((n) & 0x7) - 1) << 6) /* direct key number */ 43*d7416f9eSEric Miao 441814db69SEric Miao #define KPAS_MUKP(n) (((n) >> 26) & 0x1f) 451814db69SEric Miao #define KPAS_RP(n) (((n) >> 4) & 0xf) 461814db69SEric Miao #define KPAS_CP(n) ((n) & 0xf) 470e5f11aaSEric Miao 481814db69SEric Miao #define KPASMKP_MKC_MASK (0xff) 491814db69SEric Miao 501814db69SEric Miao #define MAX_MATRIX_KEY_NUM (8 * 8) 511814db69SEric Miao 521814db69SEric Miao struct pxa27x_keypad { 531814db69SEric Miao struct pxa27x_keypad_platform_data *pdata; 541814db69SEric Miao 551814db69SEric Miao struct clk *clk; 561814db69SEric Miao struct input_dev *input_dev; 571814db69SEric Miao 581814db69SEric Miao /* matrix key code map */ 591814db69SEric Miao unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; 601814db69SEric Miao 611814db69SEric Miao /* state row bits of each column scan */ 621814db69SEric Miao uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS]; 631814db69SEric Miao }; 641814db69SEric Miao 651814db69SEric Miao static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) 661814db69SEric Miao { 671814db69SEric Miao struct pxa27x_keypad_platform_data *pdata = keypad->pdata; 681814db69SEric Miao struct input_dev *input_dev = keypad->input_dev; 691814db69SEric Miao unsigned int *key; 701814db69SEric Miao int i; 711814db69SEric Miao 721814db69SEric Miao key = &pdata->matrix_key_map[0]; 731814db69SEric Miao for (i = 0; i < pdata->matrix_key_map_size; i++, key++) { 741814db69SEric Miao int row = ((*key) >> 28) & 0xf; 751814db69SEric Miao int col = ((*key) >> 24) & 0xf; 761814db69SEric Miao int code = (*key) & 0xffffff; 771814db69SEric Miao 781814db69SEric Miao keypad->matrix_keycodes[(row << 3) + col] = code; 791814db69SEric Miao set_bit(code, input_dev->keybit); 801814db69SEric Miao } 811814db69SEric Miao } 821814db69SEric Miao 831814db69SEric Miao static inline unsigned int lookup_matrix_keycode( 841814db69SEric Miao struct pxa27x_keypad *keypad, int row, int col) 851814db69SEric Miao { 861814db69SEric Miao return keypad->matrix_keycodes[(row << 3) + col]; 871814db69SEric Miao } 881814db69SEric Miao 891814db69SEric Miao static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) 901814db69SEric Miao { 911814db69SEric Miao struct pxa27x_keypad_platform_data *pdata = keypad->pdata; 921814db69SEric Miao int row, col, num_keys_pressed = 0; 931814db69SEric Miao uint32_t new_state[MAX_MATRIX_KEY_COLS]; 941814db69SEric Miao uint32_t kpas = KPAS; 951814db69SEric Miao 961814db69SEric Miao num_keys_pressed = KPAS_MUKP(kpas); 971814db69SEric Miao 981814db69SEric Miao memset(new_state, 0, sizeof(new_state)); 991814db69SEric Miao 1001814db69SEric Miao if (num_keys_pressed == 0) 1011814db69SEric Miao goto scan; 1021814db69SEric Miao 1031814db69SEric Miao if (num_keys_pressed == 1) { 1041814db69SEric Miao col = KPAS_CP(kpas); 1051814db69SEric Miao row = KPAS_RP(kpas); 1061814db69SEric Miao 1071814db69SEric Miao /* if invalid row/col, treat as no key pressed */ 1081814db69SEric Miao if (col >= pdata->matrix_key_cols || 1091814db69SEric Miao row >= pdata->matrix_key_rows) 1101814db69SEric Miao goto scan; 1111814db69SEric Miao 1121814db69SEric Miao new_state[col] = (1 << row); 1131814db69SEric Miao goto scan; 1141814db69SEric Miao } 1151814db69SEric Miao 1161814db69SEric Miao if (num_keys_pressed > 1) { 1171814db69SEric Miao uint32_t kpasmkp0 = KPASMKP0; 1181814db69SEric Miao uint32_t kpasmkp1 = KPASMKP1; 1191814db69SEric Miao uint32_t kpasmkp2 = KPASMKP2; 1201814db69SEric Miao uint32_t kpasmkp3 = KPASMKP3; 1211814db69SEric Miao 1221814db69SEric Miao new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK; 1231814db69SEric Miao new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK; 1241814db69SEric Miao new_state[2] = kpasmkp1 & KPASMKP_MKC_MASK; 1251814db69SEric Miao new_state[3] = (kpasmkp1 >> 16) & KPASMKP_MKC_MASK; 1261814db69SEric Miao new_state[4] = kpasmkp2 & KPASMKP_MKC_MASK; 1271814db69SEric Miao new_state[5] = (kpasmkp2 >> 16) & KPASMKP_MKC_MASK; 1281814db69SEric Miao new_state[6] = kpasmkp3 & KPASMKP_MKC_MASK; 1291814db69SEric Miao new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK; 1301814db69SEric Miao } 1311814db69SEric Miao scan: 1321814db69SEric Miao for (col = 0; col < pdata->matrix_key_cols; col++) { 1331814db69SEric Miao uint32_t bits_changed; 1341814db69SEric Miao 1351814db69SEric Miao bits_changed = keypad->matrix_key_state[col] ^ new_state[col]; 1361814db69SEric Miao if (bits_changed == 0) 1371814db69SEric Miao continue; 1381814db69SEric Miao 1391814db69SEric Miao for (row = 0; row < pdata->matrix_key_rows; row++) { 1401814db69SEric Miao if ((bits_changed & (1 << row)) == 0) 1411814db69SEric Miao continue; 1421814db69SEric Miao 1431814db69SEric Miao input_report_key(keypad->input_dev, 1441814db69SEric Miao lookup_matrix_keycode(keypad, row, col), 1451814db69SEric Miao new_state[col] & (1 << row)); 1461814db69SEric Miao } 1471814db69SEric Miao } 1481814db69SEric Miao input_sync(keypad->input_dev); 1491814db69SEric Miao memcpy(keypad->matrix_key_state, new_state, sizeof(new_state)); 1501814db69SEric Miao } 1510e5f11aaSEric Miao 152*d7416f9eSEric Miao #define DEFAULT_KPREC (0x007f007f) 153*d7416f9eSEric Miao 1540e5f11aaSEric Miao static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) 1550e5f11aaSEric Miao { 1561814db69SEric Miao struct pxa27x_keypad *keypad = dev_id; 1571814db69SEric Miao struct input_dev *input_dev = keypad->input_dev; 1580e5f11aaSEric Miao unsigned long kpc = KPC; 1591814db69SEric Miao int rel; 1600e5f11aaSEric Miao 1610e5f11aaSEric Miao if (kpc & KPC_DI) { 1620e5f11aaSEric Miao unsigned long kpdk = KPDK; 1630e5f11aaSEric Miao 1640e5f11aaSEric Miao if (!(kpdk & KPDK_DKP)) { 1650e5f11aaSEric Miao /* better luck next time */ 1660e5f11aaSEric Miao } else if (kpc & KPC_REE0) { 1670e5f11aaSEric Miao unsigned long kprec = KPREC; 1680e5f11aaSEric Miao KPREC = 0x7f; 1690e5f11aaSEric Miao 1700e5f11aaSEric Miao if (kprec & KPREC_OF0) 1710e5f11aaSEric Miao rel = (kprec & 0xff) + 0x7f; 1720e5f11aaSEric Miao else if (kprec & KPREC_UF0) 1730e5f11aaSEric Miao rel = (kprec & 0xff) - 0x7f - 0xff; 1740e5f11aaSEric Miao else 1750e5f11aaSEric Miao rel = (kprec & 0xff) - 0x7f; 1760e5f11aaSEric Miao 1770e5f11aaSEric Miao if (rel) { 1780e5f11aaSEric Miao input_report_rel(input_dev, REL_WHEEL, rel); 1790e5f11aaSEric Miao input_sync(input_dev); 1800e5f11aaSEric Miao } 1810e5f11aaSEric Miao } 1820e5f11aaSEric Miao } 1830e5f11aaSEric Miao 1841814db69SEric Miao if (kpc & KPC_MI) 1851814db69SEric Miao pxa27x_keypad_scan_matrix(keypad); 1860e5f11aaSEric Miao 1870e5f11aaSEric Miao return IRQ_HANDLED; 1880e5f11aaSEric Miao } 1890e5f11aaSEric Miao 190*d7416f9eSEric Miao static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) 191*d7416f9eSEric Miao { 192*d7416f9eSEric Miao struct pxa27x_keypad_platform_data *pdata = keypad->pdata; 193*d7416f9eSEric Miao unsigned long kpc = 0; 194*d7416f9eSEric Miao 195*d7416f9eSEric Miao /* enable matrix keys with automatic scan */ 196*d7416f9eSEric Miao if (pdata->matrix_key_rows && pdata->matrix_key_cols) { 197*d7416f9eSEric Miao kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL; 198*d7416f9eSEric Miao kpc |= KPC_MKRN(pdata->matrix_key_rows) | 199*d7416f9eSEric Miao KPC_MKCN(pdata->matrix_key_cols); 200*d7416f9eSEric Miao } 201*d7416f9eSEric Miao 202*d7416f9eSEric Miao /* FIXME: hardcoded to enable rotary 0 _only_ */ 203*d7416f9eSEric Miao kpc |= KPC_DKN(2) | KPC_REE0 | KPC_DI | KPC_DIE; 204*d7416f9eSEric Miao 205*d7416f9eSEric Miao KPC = kpc; 206*d7416f9eSEric Miao KPREC = DEFAULT_KPREC; 207*d7416f9eSEric Miao } 208*d7416f9eSEric Miao 2090e5f11aaSEric Miao static int pxa27x_keypad_open(struct input_dev *dev) 2100e5f11aaSEric Miao { 2111814db69SEric Miao struct pxa27x_keypad *keypad = input_get_drvdata(dev); 2121814db69SEric Miao 2130e5f11aaSEric Miao /* Enable unit clock */ 2141814db69SEric Miao clk_enable(keypad->clk); 215*d7416f9eSEric Miao pxa27x_keypad_config(keypad); 2160e5f11aaSEric Miao 2170e5f11aaSEric Miao return 0; 2180e5f11aaSEric Miao } 2190e5f11aaSEric Miao 2200e5f11aaSEric Miao static void pxa27x_keypad_close(struct input_dev *dev) 2210e5f11aaSEric Miao { 2221814db69SEric Miao struct pxa27x_keypad *keypad = input_get_drvdata(dev); 2231814db69SEric Miao 2240e5f11aaSEric Miao /* Disable clock unit */ 2251814db69SEric Miao clk_disable(keypad->clk); 2260e5f11aaSEric Miao } 2270e5f11aaSEric Miao 2280e5f11aaSEric Miao #ifdef CONFIG_PM 2290e5f11aaSEric Miao static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state) 2300e5f11aaSEric Miao { 2311814db69SEric Miao struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); 2320e5f11aaSEric Miao 233*d7416f9eSEric Miao clk_disable(keypad->clk); 2340e5f11aaSEric Miao return 0; 2350e5f11aaSEric Miao } 2360e5f11aaSEric Miao 2370e5f11aaSEric Miao static int pxa27x_keypad_resume(struct platform_device *pdev) 2380e5f11aaSEric Miao { 2391814db69SEric Miao struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); 2401814db69SEric Miao struct input_dev *input_dev = keypad->input_dev; 2410e5f11aaSEric Miao 2420e5f11aaSEric Miao mutex_lock(&input_dev->mutex); 2430e5f11aaSEric Miao 2440e5f11aaSEric Miao if (input_dev->users) { 2450e5f11aaSEric Miao /* Enable unit clock */ 2461814db69SEric Miao clk_enable(keypad->clk); 247*d7416f9eSEric Miao pxa27x_keypad_config(keypad); 2480e5f11aaSEric Miao } 2490e5f11aaSEric Miao 2500e5f11aaSEric Miao mutex_unlock(&input_dev->mutex); 2510e5f11aaSEric Miao 2520e5f11aaSEric Miao return 0; 2530e5f11aaSEric Miao } 2540e5f11aaSEric Miao #else 2550e5f11aaSEric Miao #define pxa27x_keypad_suspend NULL 2560e5f11aaSEric Miao #define pxa27x_keypad_resume NULL 2570e5f11aaSEric Miao #endif 2580e5f11aaSEric Miao 2590e5f11aaSEric Miao static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) 2600e5f11aaSEric Miao { 2611814db69SEric Miao struct pxa27x_keypad *keypad; 2620e5f11aaSEric Miao struct input_dev *input_dev; 263*d7416f9eSEric Miao int error; 2640e5f11aaSEric Miao 2651814db69SEric Miao keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL); 2661814db69SEric Miao if (keypad == NULL) { 2671814db69SEric Miao dev_err(&pdev->dev, "failed to allocate driver data\n"); 2681814db69SEric Miao return -ENOMEM; 2691814db69SEric Miao } 2701814db69SEric Miao 2711814db69SEric Miao keypad->pdata = pdev->dev.platform_data; 2721814db69SEric Miao if (keypad->pdata == NULL) { 2731814db69SEric Miao dev_err(&pdev->dev, "no platform data defined\n"); 2741814db69SEric Miao error = -EINVAL; 2751814db69SEric Miao goto failed_free; 2761814db69SEric Miao } 2771814db69SEric Miao 2781814db69SEric Miao keypad->clk = clk_get(&pdev->dev, "KBDCLK"); 2791814db69SEric Miao if (IS_ERR(keypad->clk)) { 2801814db69SEric Miao dev_err(&pdev->dev, "failed to get keypad clock\n"); 2811814db69SEric Miao error = PTR_ERR(keypad->clk); 2821814db69SEric Miao goto failed_free; 2830e5f11aaSEric Miao } 2840e5f11aaSEric Miao 2850e5f11aaSEric Miao /* Create and register the input driver. */ 2860e5f11aaSEric Miao input_dev = input_allocate_device(); 2870e5f11aaSEric Miao if (!input_dev) { 2881814db69SEric Miao dev_err(&pdev->dev, "failed to allocate input device\n"); 2890e5f11aaSEric Miao error = -ENOMEM; 2901814db69SEric Miao goto failed_put_clk; 2910e5f11aaSEric Miao } 2920e5f11aaSEric Miao 2930e5f11aaSEric Miao input_dev->name = DRIVER_NAME; 2940e5f11aaSEric Miao input_dev->id.bustype = BUS_HOST; 2950e5f11aaSEric Miao input_dev->open = pxa27x_keypad_open; 2960e5f11aaSEric Miao input_dev->close = pxa27x_keypad_close; 2970e5f11aaSEric Miao input_dev->dev.parent = &pdev->dev; 2980e5f11aaSEric Miao 2991814db69SEric Miao keypad->input_dev = input_dev; 3001814db69SEric Miao input_set_drvdata(input_dev, keypad); 3011814db69SEric Miao 3020e5f11aaSEric Miao input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | 3030e5f11aaSEric Miao BIT_MASK(EV_REL); 3040e5f11aaSEric Miao input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL); 3051814db69SEric Miao 3061814db69SEric Miao pxa27x_keypad_build_keycode(keypad); 3070e5f11aaSEric Miao 3080e5f11aaSEric Miao error = request_irq(IRQ_KEYPAD, pxa27x_keypad_irq_handler, IRQF_DISABLED, 3091814db69SEric Miao DRIVER_NAME, keypad); 3100e5f11aaSEric Miao if (error) { 3110e5f11aaSEric Miao printk(KERN_ERR "Cannot request keypad IRQ\n"); 3120e5f11aaSEric Miao goto err_free_dev; 3130e5f11aaSEric Miao } 3140e5f11aaSEric Miao 3151814db69SEric Miao platform_set_drvdata(pdev, keypad); 3160e5f11aaSEric Miao 3170e5f11aaSEric Miao /* Register the input device */ 3180e5f11aaSEric Miao error = input_register_device(input_dev); 3190e5f11aaSEric Miao if (error) 3200e5f11aaSEric Miao goto err_free_irq; 3210e5f11aaSEric Miao 3220e5f11aaSEric Miao return 0; 3230e5f11aaSEric Miao 3240e5f11aaSEric Miao err_free_irq: 3250e5f11aaSEric Miao platform_set_drvdata(pdev, NULL); 3260e5f11aaSEric Miao free_irq(IRQ_KEYPAD, pdev); 3270e5f11aaSEric Miao err_free_dev: 3280e5f11aaSEric Miao input_free_device(input_dev); 3291814db69SEric Miao failed_put_clk: 3301814db69SEric Miao clk_put(keypad->clk); 3311814db69SEric Miao failed_free: 3321814db69SEric Miao kfree(keypad); 3330e5f11aaSEric Miao return error; 3340e5f11aaSEric Miao } 3350e5f11aaSEric Miao 3360e5f11aaSEric Miao static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) 3370e5f11aaSEric Miao { 3381814db69SEric Miao struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); 3390e5f11aaSEric Miao 3400e5f11aaSEric Miao free_irq(IRQ_KEYPAD, pdev); 3410e5f11aaSEric Miao 3421814db69SEric Miao clk_disable(keypad->clk); 3431814db69SEric Miao clk_put(keypad->clk); 3441814db69SEric Miao 3451814db69SEric Miao input_unregister_device(keypad->input_dev); 3461814db69SEric Miao 3471814db69SEric Miao platform_set_drvdata(pdev, NULL); 3481814db69SEric Miao kfree(keypad); 3490e5f11aaSEric Miao return 0; 3500e5f11aaSEric Miao } 3510e5f11aaSEric Miao 3520e5f11aaSEric Miao static struct platform_driver pxa27x_keypad_driver = { 3530e5f11aaSEric Miao .probe = pxa27x_keypad_probe, 3540e5f11aaSEric Miao .remove = __devexit_p(pxa27x_keypad_remove), 3550e5f11aaSEric Miao .suspend = pxa27x_keypad_suspend, 3560e5f11aaSEric Miao .resume = pxa27x_keypad_resume, 3570e5f11aaSEric Miao .driver = { 3580e5f11aaSEric Miao .name = DRIVER_NAME, 3590e5f11aaSEric Miao }, 3600e5f11aaSEric Miao }; 3610e5f11aaSEric Miao 3620e5f11aaSEric Miao static int __init pxa27x_keypad_init(void) 3630e5f11aaSEric Miao { 3640e5f11aaSEric Miao return platform_driver_register(&pxa27x_keypad_driver); 3650e5f11aaSEric Miao } 3660e5f11aaSEric Miao 3670e5f11aaSEric Miao static void __exit pxa27x_keypad_exit(void) 3680e5f11aaSEric Miao { 3690e5f11aaSEric Miao platform_driver_unregister(&pxa27x_keypad_driver); 3700e5f11aaSEric Miao } 3710e5f11aaSEric Miao 3720e5f11aaSEric Miao module_init(pxa27x_keypad_init); 3730e5f11aaSEric Miao module_exit(pxa27x_keypad_exit); 3740e5f11aaSEric Miao 3750e5f11aaSEric Miao MODULE_DESCRIPTION("PXA27x Keypad Controller Driver"); 3760e5f11aaSEric Miao MODULE_LICENSE("GPL"); 377