1 /* 2 * Samsung keypad driver 3 * 4 * Copyright (C) 2010 Samsung Electronics Co.Ltd 5 * Author: Joonyoung Shim <jy0922.shim@samsung.com> 6 * Author: Donghwa Lee <dh09.lee@samsung.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 */ 13 14 #include <linux/clk.h> 15 #include <linux/delay.h> 16 #include <linux/err.h> 17 #include <linux/init.h> 18 #include <linux/input.h> 19 #include <linux/interrupt.h> 20 #include <linux/io.h> 21 #include <linux/module.h> 22 #include <linux/platform_device.h> 23 #include <linux/pm.h> 24 #include <linux/pm_runtime.h> 25 #include <linux/slab.h> 26 #include <linux/of.h> 27 #include <linux/of_gpio.h> 28 #include <linux/sched.h> 29 #include <linux/input/samsung-keypad.h> 30 31 #define SAMSUNG_KEYIFCON 0x00 32 #define SAMSUNG_KEYIFSTSCLR 0x04 33 #define SAMSUNG_KEYIFCOL 0x08 34 #define SAMSUNG_KEYIFROW 0x0c 35 #define SAMSUNG_KEYIFFC 0x10 36 37 /* SAMSUNG_KEYIFCON */ 38 #define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0) 39 #define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1) 40 #define SAMSUNG_KEYIFCON_DF_EN (1 << 2) 41 #define SAMSUNG_KEYIFCON_FC_EN (1 << 3) 42 #define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4) 43 44 /* SAMSUNG_KEYIFSTSCLR */ 45 #define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0) 46 #define SAMSUNG_KEYIFSTSCLR_R_INT_MASK (0xff << 8) 47 #define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET 8 48 #define S5PV210_KEYIFSTSCLR_P_INT_MASK (0x3fff << 0) 49 #define S5PV210_KEYIFSTSCLR_R_INT_MASK (0x3fff << 16) 50 #define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16 51 52 /* SAMSUNG_KEYIFCOL */ 53 #define SAMSUNG_KEYIFCOL_MASK (0xff << 0) 54 #define S5PV210_KEYIFCOLEN_MASK (0xff << 8) 55 56 /* SAMSUNG_KEYIFROW */ 57 #define SAMSUNG_KEYIFROW_MASK (0xff << 0) 58 #define S5PV210_KEYIFROW_MASK (0x3fff << 0) 59 60 /* SAMSUNG_KEYIFFC */ 61 #define SAMSUNG_KEYIFFC_MASK (0x3ff << 0) 62 63 enum samsung_keypad_type { 64 KEYPAD_TYPE_SAMSUNG, 65 KEYPAD_TYPE_S5PV210, 66 }; 67 68 struct samsung_keypad { 69 struct input_dev *input_dev; 70 struct platform_device *pdev; 71 struct clk *clk; 72 void __iomem *base; 73 wait_queue_head_t wait; 74 bool stopped; 75 bool wake_enabled; 76 int irq; 77 enum samsung_keypad_type type; 78 unsigned int row_shift; 79 unsigned int rows; 80 unsigned int cols; 81 unsigned int row_state[SAMSUNG_MAX_COLS]; 82 #ifdef CONFIG_OF 83 int row_gpios[SAMSUNG_MAX_ROWS]; 84 int col_gpios[SAMSUNG_MAX_COLS]; 85 #endif 86 unsigned short keycodes[]; 87 }; 88 89 static void samsung_keypad_scan(struct samsung_keypad *keypad, 90 unsigned int *row_state) 91 { 92 unsigned int col; 93 unsigned int val; 94 95 for (col = 0; col < keypad->cols; col++) { 96 if (keypad->type == KEYPAD_TYPE_S5PV210) { 97 val = S5PV210_KEYIFCOLEN_MASK; 98 val &= ~(1 << col) << 8; 99 } else { 100 val = SAMSUNG_KEYIFCOL_MASK; 101 val &= ~(1 << col); 102 } 103 104 writel(val, keypad->base + SAMSUNG_KEYIFCOL); 105 mdelay(1); 106 107 val = readl(keypad->base + SAMSUNG_KEYIFROW); 108 row_state[col] = ~val & ((1 << keypad->rows) - 1); 109 } 110 111 /* KEYIFCOL reg clear */ 112 writel(0, keypad->base + SAMSUNG_KEYIFCOL); 113 } 114 115 static bool samsung_keypad_report(struct samsung_keypad *keypad, 116 unsigned int *row_state) 117 { 118 struct input_dev *input_dev = keypad->input_dev; 119 unsigned int changed; 120 unsigned int pressed; 121 unsigned int key_down = 0; 122 unsigned int val; 123 unsigned int col, row; 124 125 for (col = 0; col < keypad->cols; col++) { 126 changed = row_state[col] ^ keypad->row_state[col]; 127 key_down |= row_state[col]; 128 if (!changed) 129 continue; 130 131 for (row = 0; row < keypad->rows; row++) { 132 if (!(changed & (1 << row))) 133 continue; 134 135 pressed = row_state[col] & (1 << row); 136 137 dev_dbg(&keypad->input_dev->dev, 138 "key %s, row: %d, col: %d\n", 139 pressed ? "pressed" : "released", row, col); 140 141 val = MATRIX_SCAN_CODE(row, col, keypad->row_shift); 142 143 input_event(input_dev, EV_MSC, MSC_SCAN, val); 144 input_report_key(input_dev, 145 keypad->keycodes[val], pressed); 146 } 147 input_sync(keypad->input_dev); 148 } 149 150 memcpy(keypad->row_state, row_state, sizeof(keypad->row_state)); 151 152 return key_down; 153 } 154 155 static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) 156 { 157 struct samsung_keypad *keypad = dev_id; 158 unsigned int row_state[SAMSUNG_MAX_COLS]; 159 unsigned int val; 160 bool key_down; 161 162 pm_runtime_get_sync(&keypad->pdev->dev); 163 164 do { 165 val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR); 166 /* Clear interrupt. */ 167 writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); 168 169 samsung_keypad_scan(keypad, row_state); 170 171 key_down = samsung_keypad_report(keypad, row_state); 172 if (key_down) 173 wait_event_timeout(keypad->wait, keypad->stopped, 174 msecs_to_jiffies(50)); 175 176 } while (key_down && !keypad->stopped); 177 178 pm_runtime_put(&keypad->pdev->dev); 179 180 return IRQ_HANDLED; 181 } 182 183 static void samsung_keypad_start(struct samsung_keypad *keypad) 184 { 185 unsigned int val; 186 187 pm_runtime_get_sync(&keypad->pdev->dev); 188 189 /* Tell IRQ thread that it may poll the device. */ 190 keypad->stopped = false; 191 192 clk_enable(keypad->clk); 193 194 /* Enable interrupt bits. */ 195 val = readl(keypad->base + SAMSUNG_KEYIFCON); 196 val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN; 197 writel(val, keypad->base + SAMSUNG_KEYIFCON); 198 199 /* KEYIFCOL reg clear. */ 200 writel(0, keypad->base + SAMSUNG_KEYIFCOL); 201 202 pm_runtime_put(&keypad->pdev->dev); 203 } 204 205 static void samsung_keypad_stop(struct samsung_keypad *keypad) 206 { 207 unsigned int val; 208 209 pm_runtime_get_sync(&keypad->pdev->dev); 210 211 /* Signal IRQ thread to stop polling and disable the handler. */ 212 keypad->stopped = true; 213 wake_up(&keypad->wait); 214 disable_irq(keypad->irq); 215 216 /* Clear interrupt. */ 217 writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); 218 219 /* Disable interrupt bits. */ 220 val = readl(keypad->base + SAMSUNG_KEYIFCON); 221 val &= ~(SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN); 222 writel(val, keypad->base + SAMSUNG_KEYIFCON); 223 224 clk_disable(keypad->clk); 225 226 /* 227 * Now that chip should not generate interrupts we can safely 228 * re-enable the handler. 229 */ 230 enable_irq(keypad->irq); 231 232 pm_runtime_put(&keypad->pdev->dev); 233 } 234 235 static int samsung_keypad_open(struct input_dev *input_dev) 236 { 237 struct samsung_keypad *keypad = input_get_drvdata(input_dev); 238 239 samsung_keypad_start(keypad); 240 241 return 0; 242 } 243 244 static void samsung_keypad_close(struct input_dev *input_dev) 245 { 246 struct samsung_keypad *keypad = input_get_drvdata(input_dev); 247 248 samsung_keypad_stop(keypad); 249 } 250 251 #ifdef CONFIG_OF 252 static struct samsung_keypad_platdata *samsung_keypad_parse_dt( 253 struct device *dev) 254 { 255 struct samsung_keypad_platdata *pdata; 256 struct matrix_keymap_data *keymap_data; 257 uint32_t *keymap, num_rows = 0, num_cols = 0; 258 struct device_node *np = dev->of_node, *key_np; 259 unsigned int key_count = 0; 260 261 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 262 if (!pdata) { 263 dev_err(dev, "could not allocate memory for platform data\n"); 264 return NULL; 265 } 266 267 of_property_read_u32(np, "samsung,keypad-num-rows", &num_rows); 268 of_property_read_u32(np, "samsung,keypad-num-columns", &num_cols); 269 if (!num_rows || !num_cols) { 270 dev_err(dev, "number of keypad rows/columns not specified\n"); 271 return NULL; 272 } 273 pdata->rows = num_rows; 274 pdata->cols = num_cols; 275 276 keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL); 277 if (!keymap_data) { 278 dev_err(dev, "could not allocate memory for keymap data\n"); 279 return NULL; 280 } 281 pdata->keymap_data = keymap_data; 282 283 for_each_child_of_node(np, key_np) 284 key_count++; 285 286 keymap_data->keymap_size = key_count; 287 keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL); 288 if (!keymap) { 289 dev_err(dev, "could not allocate memory for keymap\n"); 290 return NULL; 291 } 292 keymap_data->keymap = keymap; 293 294 for_each_child_of_node(np, key_np) { 295 u32 row, col, key_code; 296 of_property_read_u32(key_np, "keypad,row", &row); 297 of_property_read_u32(key_np, "keypad,column", &col); 298 of_property_read_u32(key_np, "linux,code", &key_code); 299 *keymap++ = KEY(row, col, key_code); 300 } 301 302 if (of_get_property(np, "linux,input-no-autorepeat", NULL)) 303 pdata->no_autorepeat = true; 304 if (of_get_property(np, "linux,input-wakeup", NULL)) 305 pdata->wakeup = true; 306 307 return pdata; 308 } 309 310 static void samsung_keypad_parse_dt_gpio(struct device *dev, 311 struct samsung_keypad *keypad) 312 { 313 struct device_node *np = dev->of_node; 314 int gpio, ret, row, col; 315 316 for (row = 0; row < keypad->rows; row++) { 317 gpio = of_get_named_gpio(np, "row-gpios", row); 318 keypad->row_gpios[row] = gpio; 319 if (!gpio_is_valid(gpio)) { 320 dev_err(dev, "keypad row[%d]: invalid gpio %d\n", 321 row, gpio); 322 continue; 323 } 324 325 ret = gpio_request(gpio, "keypad-row"); 326 if (ret) 327 dev_err(dev, "keypad row[%d] gpio request failed\n", 328 row); 329 } 330 331 for (col = 0; col < keypad->cols; col++) { 332 gpio = of_get_named_gpio(np, "col-gpios", col); 333 keypad->col_gpios[col] = gpio; 334 if (!gpio_is_valid(gpio)) { 335 dev_err(dev, "keypad column[%d]: invalid gpio %d\n", 336 col, gpio); 337 continue; 338 } 339 340 ret = gpio_request(gpio, "keypad-col"); 341 if (ret) 342 dev_err(dev, "keypad column[%d] gpio request failed\n", 343 col); 344 } 345 } 346 347 static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) 348 { 349 int cnt; 350 351 for (cnt = 0; cnt < keypad->rows; cnt++) 352 if (gpio_is_valid(keypad->row_gpios[cnt])) 353 gpio_free(keypad->row_gpios[cnt]); 354 355 for (cnt = 0; cnt < keypad->cols; cnt++) 356 if (gpio_is_valid(keypad->col_gpios[cnt])) 357 gpio_free(keypad->col_gpios[cnt]); 358 } 359 #else 360 static 361 struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev) 362 { 363 return NULL; 364 } 365 366 static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) 367 { 368 } 369 #endif 370 371 static int __devinit samsung_keypad_probe(struct platform_device *pdev) 372 { 373 const struct samsung_keypad_platdata *pdata; 374 const struct matrix_keymap_data *keymap_data; 375 struct samsung_keypad *keypad; 376 struct resource *res; 377 struct input_dev *input_dev; 378 unsigned int row_shift; 379 unsigned int keymap_size; 380 int error; 381 382 if (pdev->dev.of_node) 383 pdata = samsung_keypad_parse_dt(&pdev->dev); 384 else 385 pdata = pdev->dev.platform_data; 386 if (!pdata) { 387 dev_err(&pdev->dev, "no platform data defined\n"); 388 return -EINVAL; 389 } 390 391 keymap_data = pdata->keymap_data; 392 if (!keymap_data) { 393 dev_err(&pdev->dev, "no keymap data defined\n"); 394 return -EINVAL; 395 } 396 397 if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS) 398 return -EINVAL; 399 400 if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS) 401 return -EINVAL; 402 403 /* initialize the gpio */ 404 if (pdata->cfg_gpio) 405 pdata->cfg_gpio(pdata->rows, pdata->cols); 406 407 row_shift = get_count_order(pdata->cols); 408 keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]); 409 410 keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL); 411 input_dev = input_allocate_device(); 412 if (!keypad || !input_dev) { 413 error = -ENOMEM; 414 goto err_free_mem; 415 } 416 417 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 418 if (!res) { 419 error = -ENODEV; 420 goto err_free_mem; 421 } 422 423 keypad->base = ioremap(res->start, resource_size(res)); 424 if (!keypad->base) { 425 error = -EBUSY; 426 goto err_free_mem; 427 } 428 429 keypad->clk = clk_get(&pdev->dev, "keypad"); 430 if (IS_ERR(keypad->clk)) { 431 dev_err(&pdev->dev, "failed to get keypad clk\n"); 432 error = PTR_ERR(keypad->clk); 433 goto err_unmap_base; 434 } 435 436 keypad->input_dev = input_dev; 437 keypad->pdev = pdev; 438 keypad->row_shift = row_shift; 439 keypad->rows = pdata->rows; 440 keypad->cols = pdata->cols; 441 keypad->stopped = true; 442 init_waitqueue_head(&keypad->wait); 443 444 if (pdev->dev.of_node) { 445 #ifdef CONFIG_OF 446 samsung_keypad_parse_dt_gpio(&pdev->dev, keypad); 447 keypad->type = of_device_is_compatible(pdev->dev.of_node, 448 "samsung,s5pv210-keypad"); 449 #endif 450 } else { 451 keypad->type = platform_get_device_id(pdev)->driver_data; 452 } 453 454 input_dev->name = pdev->name; 455 input_dev->id.bustype = BUS_HOST; 456 input_dev->dev.parent = &pdev->dev; 457 input_set_drvdata(input_dev, keypad); 458 459 input_dev->open = samsung_keypad_open; 460 input_dev->close = samsung_keypad_close; 461 462 input_dev->evbit[0] = BIT_MASK(EV_KEY); 463 if (!pdata->no_autorepeat) 464 input_dev->evbit[0] |= BIT_MASK(EV_REP); 465 466 input_set_capability(input_dev, EV_MSC, MSC_SCAN); 467 468 input_dev->keycode = keypad->keycodes; 469 input_dev->keycodesize = sizeof(keypad->keycodes[0]); 470 input_dev->keycodemax = pdata->rows << row_shift; 471 472 matrix_keypad_build_keymap(keymap_data, row_shift, 473 input_dev->keycode, input_dev->keybit); 474 475 keypad->irq = platform_get_irq(pdev, 0); 476 if (keypad->irq < 0) { 477 error = keypad->irq; 478 goto err_put_clk; 479 } 480 481 error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq, 482 IRQF_ONESHOT, dev_name(&pdev->dev), keypad); 483 if (error) { 484 dev_err(&pdev->dev, "failed to register keypad interrupt\n"); 485 goto err_put_clk; 486 } 487 488 device_init_wakeup(&pdev->dev, pdata->wakeup); 489 platform_set_drvdata(pdev, keypad); 490 pm_runtime_enable(&pdev->dev); 491 492 error = input_register_device(keypad->input_dev); 493 if (error) 494 goto err_free_irq; 495 496 if (pdev->dev.of_node) { 497 devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap); 498 devm_kfree(&pdev->dev, (void *)pdata->keymap_data); 499 devm_kfree(&pdev->dev, (void *)pdata); 500 } 501 return 0; 502 503 err_free_irq: 504 free_irq(keypad->irq, keypad); 505 pm_runtime_disable(&pdev->dev); 506 device_init_wakeup(&pdev->dev, 0); 507 platform_set_drvdata(pdev, NULL); 508 err_put_clk: 509 clk_put(keypad->clk); 510 samsung_keypad_dt_gpio_free(keypad); 511 err_unmap_base: 512 iounmap(keypad->base); 513 err_free_mem: 514 input_free_device(input_dev); 515 kfree(keypad); 516 517 return error; 518 } 519 520 static int __devexit samsung_keypad_remove(struct platform_device *pdev) 521 { 522 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 523 524 pm_runtime_disable(&pdev->dev); 525 device_init_wakeup(&pdev->dev, 0); 526 platform_set_drvdata(pdev, NULL); 527 528 input_unregister_device(keypad->input_dev); 529 530 /* 531 * It is safe to free IRQ after unregistering device because 532 * samsung_keypad_close will shut off interrupts. 533 */ 534 free_irq(keypad->irq, keypad); 535 536 clk_put(keypad->clk); 537 samsung_keypad_dt_gpio_free(keypad); 538 539 iounmap(keypad->base); 540 kfree(keypad); 541 542 return 0; 543 } 544 545 #ifdef CONFIG_PM_RUNTIME 546 static int samsung_keypad_runtime_suspend(struct device *dev) 547 { 548 struct platform_device *pdev = to_platform_device(dev); 549 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 550 unsigned int val; 551 int error; 552 553 if (keypad->stopped) 554 return 0; 555 556 /* This may fail on some SoCs due to lack of controller support */ 557 error = enable_irq_wake(keypad->irq); 558 if (!error) 559 keypad->wake_enabled = true; 560 561 val = readl(keypad->base + SAMSUNG_KEYIFCON); 562 val |= SAMSUNG_KEYIFCON_WAKEUPEN; 563 writel(val, keypad->base + SAMSUNG_KEYIFCON); 564 565 clk_disable(keypad->clk); 566 567 return 0; 568 } 569 570 static int samsung_keypad_runtime_resume(struct device *dev) 571 { 572 struct platform_device *pdev = to_platform_device(dev); 573 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 574 unsigned int val; 575 576 if (keypad->stopped) 577 return 0; 578 579 clk_enable(keypad->clk); 580 581 val = readl(keypad->base + SAMSUNG_KEYIFCON); 582 val &= ~SAMSUNG_KEYIFCON_WAKEUPEN; 583 writel(val, keypad->base + SAMSUNG_KEYIFCON); 584 585 if (keypad->wake_enabled) 586 disable_irq_wake(keypad->irq); 587 588 return 0; 589 } 590 #endif 591 592 #ifdef CONFIG_PM_SLEEP 593 static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad, 594 bool enable) 595 { 596 unsigned int val; 597 598 clk_enable(keypad->clk); 599 600 val = readl(keypad->base + SAMSUNG_KEYIFCON); 601 if (enable) { 602 val |= SAMSUNG_KEYIFCON_WAKEUPEN; 603 if (device_may_wakeup(&keypad->pdev->dev)) 604 enable_irq_wake(keypad->irq); 605 } else { 606 val &= ~SAMSUNG_KEYIFCON_WAKEUPEN; 607 if (device_may_wakeup(&keypad->pdev->dev)) 608 disable_irq_wake(keypad->irq); 609 } 610 writel(val, keypad->base + SAMSUNG_KEYIFCON); 611 612 clk_disable(keypad->clk); 613 } 614 615 static int samsung_keypad_suspend(struct device *dev) 616 { 617 struct platform_device *pdev = to_platform_device(dev); 618 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 619 struct input_dev *input_dev = keypad->input_dev; 620 621 mutex_lock(&input_dev->mutex); 622 623 if (input_dev->users) 624 samsung_keypad_stop(keypad); 625 626 samsung_keypad_toggle_wakeup(keypad, true); 627 628 mutex_unlock(&input_dev->mutex); 629 630 return 0; 631 } 632 633 static int samsung_keypad_resume(struct device *dev) 634 { 635 struct platform_device *pdev = to_platform_device(dev); 636 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 637 struct input_dev *input_dev = keypad->input_dev; 638 639 mutex_lock(&input_dev->mutex); 640 641 samsung_keypad_toggle_wakeup(keypad, false); 642 643 if (input_dev->users) 644 samsung_keypad_start(keypad); 645 646 mutex_unlock(&input_dev->mutex); 647 648 return 0; 649 } 650 #endif 651 652 static const struct dev_pm_ops samsung_keypad_pm_ops = { 653 SET_SYSTEM_SLEEP_PM_OPS(samsung_keypad_suspend, samsung_keypad_resume) 654 SET_RUNTIME_PM_OPS(samsung_keypad_runtime_suspend, 655 samsung_keypad_runtime_resume, NULL) 656 }; 657 658 #ifdef CONFIG_OF 659 static const struct of_device_id samsung_keypad_dt_match[] = { 660 { .compatible = "samsung,s3c6410-keypad" }, 661 { .compatible = "samsung,s5pv210-keypad" }, 662 {}, 663 }; 664 MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match); 665 #else 666 #define samsung_keypad_dt_match NULL 667 #endif 668 669 static struct platform_device_id samsung_keypad_driver_ids[] = { 670 { 671 .name = "samsung-keypad", 672 .driver_data = KEYPAD_TYPE_SAMSUNG, 673 }, { 674 .name = "s5pv210-keypad", 675 .driver_data = KEYPAD_TYPE_S5PV210, 676 }, 677 { }, 678 }; 679 MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids); 680 681 static struct platform_driver samsung_keypad_driver = { 682 .probe = samsung_keypad_probe, 683 .remove = __devexit_p(samsung_keypad_remove), 684 .driver = { 685 .name = "samsung-keypad", 686 .owner = THIS_MODULE, 687 .of_match_table = samsung_keypad_dt_match, 688 .pm = &samsung_keypad_pm_ops, 689 }, 690 .id_table = samsung_keypad_driver_ids, 691 }; 692 module_platform_driver(samsung_keypad_driver); 693 694 MODULE_DESCRIPTION("Samsung keypad driver"); 695 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 696 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>"); 697 MODULE_LICENSE("GPL"); 698