1 /* 2 * linux/drivers/input/keyboard/omap-keypad.c 3 * 4 * OMAP Keypad Driver 5 * 6 * Copyright (C) 2003 Nokia Corporation 7 * Written by Timo Teräs <ext-timo.teras@nokia.com> 8 * 9 * Added support for H2 & H3 Keypad 10 * Copyright (C) 2004 Texas Instruments 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 */ 26 27 #include <linux/module.h> 28 #include <linux/init.h> 29 #include <linux/interrupt.h> 30 #include <linux/types.h> 31 #include <linux/input.h> 32 #include <linux/kernel.h> 33 #include <linux/delay.h> 34 #include <linux/platform_device.h> 35 #include <linux/mutex.h> 36 #include <linux/errno.h> 37 #include <asm/arch/gpio.h> 38 #include <asm/arch/keypad.h> 39 #include <asm/arch/menelaus.h> 40 #include <asm/irq.h> 41 #include <asm/hardware.h> 42 #include <asm/io.h> 43 #include <asm/mach-types.h> 44 #include <asm/arch/mux.h> 45 46 #undef NEW_BOARD_LEARNING_MODE 47 48 static void omap_kp_tasklet(unsigned long); 49 static void omap_kp_timer(unsigned long); 50 51 static unsigned char keypad_state[8]; 52 static DEFINE_MUTEX(kp_enable_mutex); 53 static int kp_enable = 1; 54 static int kp_cur_group = -1; 55 56 struct omap_kp { 57 struct input_dev *input; 58 struct timer_list timer; 59 int irq; 60 unsigned int rows; 61 unsigned int cols; 62 unsigned long delay; 63 unsigned int debounce; 64 }; 65 66 DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0); 67 68 static int *keymap; 69 static unsigned int *row_gpios; 70 static unsigned int *col_gpios; 71 72 #ifdef CONFIG_ARCH_OMAP2 73 static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value) 74 { 75 int col; 76 for (col = 0; col < omap_kp->cols; col++) { 77 if (value & (1 << col)) 78 omap_set_gpio_dataout(col_gpios[col], 1); 79 else 80 omap_set_gpio_dataout(col_gpios[col], 0); 81 } 82 } 83 84 static u8 get_row_gpio_val(struct omap_kp *omap_kp) 85 { 86 int row; 87 u8 value = 0; 88 89 for (row = 0; row < omap_kp->rows; row++) { 90 if (omap_get_gpio_datain(row_gpios[row])) 91 value |= (1 << row); 92 } 93 return value; 94 } 95 #else 96 #define set_col_gpio_val(x, y) do {} while (0) 97 #define get_row_gpio_val(x) 0 98 #endif 99 100 static irqreturn_t omap_kp_interrupt(int irq, void *dev_id) 101 { 102 struct omap_kp *omap_kp = dev_id; 103 104 /* disable keyboard interrupt and schedule for handling */ 105 if (cpu_is_omap24xx()) { 106 int i; 107 for (i = 0; i < omap_kp->rows; i++) 108 disable_irq(OMAP_GPIO_IRQ(row_gpios[i])); 109 } else 110 /* disable keyboard interrupt and schedule for handling */ 111 omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 112 113 tasklet_schedule(&kp_tasklet); 114 115 return IRQ_HANDLED; 116 } 117 118 static void omap_kp_timer(unsigned long data) 119 { 120 tasklet_schedule(&kp_tasklet); 121 } 122 123 static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state) 124 { 125 int col = 0; 126 127 /* read the keypad status */ 128 if (cpu_is_omap24xx()) { 129 int i; 130 for (i = 0; i < omap_kp->rows; i++) 131 disable_irq(OMAP_GPIO_IRQ(row_gpios[i])); 132 133 /* read the keypad status */ 134 for (col = 0; col < omap_kp->cols; col++) { 135 set_col_gpio_val(omap_kp, ~(1 << col)); 136 state[col] = ~(get_row_gpio_val(omap_kp)) & 0x3f; 137 } 138 set_col_gpio_val(omap_kp, 0); 139 140 } else { 141 /* disable keyboard interrupt and schedule for handling */ 142 omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 143 144 /* read the keypad status */ 145 omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); 146 for (col = 0; col < omap_kp->cols; col++) { 147 omap_writew(~(1 << col) & 0xff, 148 OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); 149 150 udelay(omap_kp->delay); 151 152 state[col] = ~omap_readw(OMAP_MPUIO_BASE + 153 OMAP_MPUIO_KBR_LATCH) & 0xff; 154 } 155 omap_writew(0x00, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); 156 udelay(2); 157 } 158 } 159 160 static inline int omap_kp_find_key(int col, int row) 161 { 162 int i, key; 163 164 key = KEY(col, row, 0); 165 for (i = 0; keymap[i] != 0; i++) 166 if ((keymap[i] & 0xff000000) == key) 167 return keymap[i] & 0x00ffffff; 168 return -1; 169 } 170 171 static void omap_kp_tasklet(unsigned long data) 172 { 173 struct omap_kp *omap_kp_data = (struct omap_kp *) data; 174 unsigned char new_state[8], changed, key_down = 0; 175 int col, row; 176 int spurious = 0; 177 178 /* check for any changes */ 179 omap_kp_scan_keypad(omap_kp_data, new_state); 180 181 /* check for changes and print those */ 182 for (col = 0; col < omap_kp_data->cols; col++) { 183 changed = new_state[col] ^ keypad_state[col]; 184 key_down |= new_state[col]; 185 if (changed == 0) 186 continue; 187 188 for (row = 0; row < omap_kp_data->rows; row++) { 189 int key; 190 if (!(changed & (1 << row))) 191 continue; 192 #ifdef NEW_BOARD_LEARNING_MODE 193 printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col, 194 row, (new_state[col] & (1 << row)) ? 195 "pressed" : "released"); 196 #else 197 key = omap_kp_find_key(col, row); 198 if (key < 0) { 199 printk(KERN_WARNING 200 "omap-keypad: Spurious key event %d-%d\n", 201 col, row); 202 /* We scan again after a couple of seconds */ 203 spurious = 1; 204 continue; 205 } 206 207 if (!(kp_cur_group == (key & GROUP_MASK) || 208 kp_cur_group == -1)) 209 continue; 210 211 kp_cur_group = key & GROUP_MASK; 212 input_report_key(omap_kp_data->input, key & ~GROUP_MASK, 213 new_state[col] & (1 << row)); 214 #endif 215 } 216 } 217 memcpy(keypad_state, new_state, sizeof(keypad_state)); 218 219 if (key_down) { 220 int delay = HZ / 20; 221 /* some key is pressed - keep irq disabled and use timer 222 * to poll the keypad */ 223 if (spurious) 224 delay = 2 * HZ; 225 mod_timer(&omap_kp_data->timer, jiffies + delay); 226 } else { 227 /* enable interrupts */ 228 if (cpu_is_omap24xx()) { 229 int i; 230 for (i = 0; i < omap_kp_data->rows; i++) 231 enable_irq(OMAP_GPIO_IRQ(row_gpios[i])); 232 } else { 233 omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 234 kp_cur_group = -1; 235 } 236 } 237 } 238 239 static ssize_t omap_kp_enable_show(struct device *dev, 240 struct device_attribute *attr, char *buf) 241 { 242 return sprintf(buf, "%u\n", kp_enable); 243 } 244 245 static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr, 246 const char *buf, size_t count) 247 { 248 int state; 249 250 if (sscanf(buf, "%u", &state) != 1) 251 return -EINVAL; 252 253 if ((state != 1) && (state != 0)) 254 return -EINVAL; 255 256 mutex_lock(&kp_enable_mutex); 257 if (state != kp_enable) { 258 if (state) 259 enable_irq(INT_KEYBOARD); 260 else 261 disable_irq(INT_KEYBOARD); 262 kp_enable = state; 263 } 264 mutex_unlock(&kp_enable_mutex); 265 266 return strnlen(buf, count); 267 } 268 269 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store); 270 271 #ifdef CONFIG_PM 272 static int omap_kp_suspend(struct platform_device *dev, pm_message_t state) 273 { 274 /* Nothing yet */ 275 276 return 0; 277 } 278 279 static int omap_kp_resume(struct platform_device *dev) 280 { 281 /* Nothing yet */ 282 283 return 0; 284 } 285 #else 286 #define omap_kp_suspend NULL 287 #define omap_kp_resume NULL 288 #endif 289 290 static int __init omap_kp_probe(struct platform_device *pdev) 291 { 292 struct omap_kp *omap_kp; 293 struct input_dev *input_dev; 294 struct omap_kp_platform_data *pdata = pdev->dev.platform_data; 295 int i, col_idx, row_idx, irq_idx, ret; 296 297 if (!pdata->rows || !pdata->cols || !pdata->keymap) { 298 printk(KERN_ERR "No rows, cols or keymap from pdata\n"); 299 return -EINVAL; 300 } 301 302 omap_kp = kzalloc(sizeof(struct omap_kp), GFP_KERNEL); 303 input_dev = input_allocate_device(); 304 if (!omap_kp || !input_dev) { 305 kfree(omap_kp); 306 input_free_device(input_dev); 307 return -ENOMEM; 308 } 309 310 platform_set_drvdata(pdev, omap_kp); 311 312 omap_kp->input = input_dev; 313 314 /* Disable the interrupt for the MPUIO keyboard */ 315 if (!cpu_is_omap24xx()) 316 omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 317 318 keymap = pdata->keymap; 319 320 if (pdata->rep) 321 __set_bit(EV_REP, input_dev->evbit); 322 323 if (pdata->delay) 324 omap_kp->delay = pdata->delay; 325 326 if (pdata->row_gpios && pdata->col_gpios) { 327 row_gpios = pdata->row_gpios; 328 col_gpios = pdata->col_gpios; 329 } 330 331 omap_kp->rows = pdata->rows; 332 omap_kp->cols = pdata->cols; 333 334 if (cpu_is_omap24xx()) { 335 /* Cols: outputs */ 336 for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) { 337 if (omap_request_gpio(col_gpios[col_idx]) < 0) { 338 printk(KERN_ERR "Failed to request" 339 "GPIO%d for keypad\n", 340 col_gpios[col_idx]); 341 goto err1; 342 } 343 omap_set_gpio_direction(col_gpios[col_idx], 0); 344 } 345 /* Rows: inputs */ 346 for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) { 347 if (omap_request_gpio(row_gpios[row_idx]) < 0) { 348 printk(KERN_ERR "Failed to request" 349 "GPIO%d for keypad\n", 350 row_gpios[row_idx]); 351 goto err2; 352 } 353 omap_set_gpio_direction(row_gpios[row_idx], 1); 354 } 355 } 356 357 setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp); 358 359 /* get the irq and init timer*/ 360 tasklet_enable(&kp_tasklet); 361 kp_tasklet.data = (unsigned long) omap_kp; 362 363 ret = device_create_file(&pdev->dev, &dev_attr_enable); 364 if (ret < 0) 365 goto err2; 366 367 /* setup input device */ 368 __set_bit(EV_KEY, input_dev->evbit); 369 for (i = 0; keymap[i] != 0; i++) 370 __set_bit(keymap[i] & KEY_MAX, input_dev->keybit); 371 input_dev->name = "omap-keypad"; 372 input_dev->phys = "omap-keypad/input0"; 373 input_dev->dev.parent = &pdev->dev; 374 375 input_dev->id.bustype = BUS_HOST; 376 input_dev->id.vendor = 0x0001; 377 input_dev->id.product = 0x0001; 378 input_dev->id.version = 0x0100; 379 380 ret = input_register_device(omap_kp->input); 381 if (ret < 0) { 382 printk(KERN_ERR "Unable to register omap-keypad input device\n"); 383 goto err3; 384 } 385 386 if (pdata->dbounce) 387 omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING); 388 389 /* scan current status and enable interrupt */ 390 omap_kp_scan_keypad(omap_kp, keypad_state); 391 if (!cpu_is_omap24xx()) { 392 omap_kp->irq = platform_get_irq(pdev, 0); 393 if (omap_kp->irq >= 0) { 394 if (request_irq(omap_kp->irq, omap_kp_interrupt, 0, 395 "omap-keypad", omap_kp) < 0) 396 goto err4; 397 } 398 omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 399 } else { 400 for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) { 401 if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]), 402 omap_kp_interrupt, 403 IRQF_TRIGGER_FALLING, 404 "omap-keypad", omap_kp) < 0) 405 goto err5; 406 } 407 } 408 return 0; 409 err5: 410 for (i = irq_idx - 1; i >=0; i--) 411 free_irq(row_gpios[i], 0); 412 err4: 413 input_unregister_device(omap_kp->input); 414 input_dev = NULL; 415 err3: 416 device_remove_file(&pdev->dev, &dev_attr_enable); 417 err2: 418 for (i = row_idx-1; i >=0; i--) 419 omap_free_gpio(row_gpios[i]); 420 err1: 421 for (i = col_idx-1; i >=0; i--) 422 omap_free_gpio(col_gpios[i]); 423 424 kfree(omap_kp); 425 input_free_device(input_dev); 426 427 return -EINVAL; 428 } 429 430 static int omap_kp_remove(struct platform_device *pdev) 431 { 432 struct omap_kp *omap_kp = platform_get_drvdata(pdev); 433 434 /* disable keypad interrupt handling */ 435 tasklet_disable(&kp_tasklet); 436 if (cpu_is_omap24xx()) { 437 int i; 438 for (i = 0; i < omap_kp->cols; i++) 439 omap_free_gpio(col_gpios[i]); 440 for (i = 0; i < omap_kp->rows; i++) { 441 omap_free_gpio(row_gpios[i]); 442 free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0); 443 } 444 } else { 445 omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); 446 free_irq(omap_kp->irq, 0); 447 } 448 449 del_timer_sync(&omap_kp->timer); 450 tasklet_kill(&kp_tasklet); 451 452 /* unregister everything */ 453 input_unregister_device(omap_kp->input); 454 455 kfree(omap_kp); 456 457 return 0; 458 } 459 460 static struct platform_driver omap_kp_driver = { 461 .probe = omap_kp_probe, 462 .remove = omap_kp_remove, 463 .suspend = omap_kp_suspend, 464 .resume = omap_kp_resume, 465 .driver = { 466 .name = "omap-keypad", 467 }, 468 }; 469 470 static int __devinit omap_kp_init(void) 471 { 472 printk(KERN_INFO "OMAP Keypad Driver\n"); 473 return platform_driver_register(&omap_kp_driver); 474 } 475 476 static void __exit omap_kp_exit(void) 477 { 478 platform_driver_unregister(&omap_kp_driver); 479 } 480 481 module_init(omap_kp_init); 482 module_exit(omap_kp_exit); 483 484 MODULE_AUTHOR("Timo Teräs"); 485 MODULE_DESCRIPTION("OMAP Keypad Driver"); 486 MODULE_LICENSE("GPL"); 487