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; 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 key_count = of_get_child_count(np); 284 keymap_data->keymap_size = key_count; 285 keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL); 286 if (!keymap) { 287 dev_err(dev, "could not allocate memory for keymap\n"); 288 return NULL; 289 } 290 keymap_data->keymap = keymap; 291 292 for_each_child_of_node(np, key_np) { 293 u32 row, col, key_code; 294 of_property_read_u32(key_np, "keypad,row", &row); 295 of_property_read_u32(key_np, "keypad,column", &col); 296 of_property_read_u32(key_np, "linux,code", &key_code); 297 *keymap++ = KEY(row, col, key_code); 298 } 299 300 if (of_get_property(np, "linux,input-no-autorepeat", NULL)) 301 pdata->no_autorepeat = true; 302 if (of_get_property(np, "linux,input-wakeup", NULL)) 303 pdata->wakeup = true; 304 305 return pdata; 306 } 307 308 static void samsung_keypad_parse_dt_gpio(struct device *dev, 309 struct samsung_keypad *keypad) 310 { 311 struct device_node *np = dev->of_node; 312 int gpio, ret, row, col; 313 314 for (row = 0; row < keypad->rows; row++) { 315 gpio = of_get_named_gpio(np, "row-gpios", row); 316 keypad->row_gpios[row] = gpio; 317 if (!gpio_is_valid(gpio)) { 318 dev_err(dev, "keypad row[%d]: invalid gpio %d\n", 319 row, gpio); 320 continue; 321 } 322 323 ret = gpio_request(gpio, "keypad-row"); 324 if (ret) 325 dev_err(dev, "keypad row[%d] gpio request failed\n", 326 row); 327 } 328 329 for (col = 0; col < keypad->cols; col++) { 330 gpio = of_get_named_gpio(np, "col-gpios", col); 331 keypad->col_gpios[col] = gpio; 332 if (!gpio_is_valid(gpio)) { 333 dev_err(dev, "keypad column[%d]: invalid gpio %d\n", 334 col, gpio); 335 continue; 336 } 337 338 ret = gpio_request(gpio, "keypad-col"); 339 if (ret) 340 dev_err(dev, "keypad column[%d] gpio request failed\n", 341 col); 342 } 343 } 344 345 static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) 346 { 347 int cnt; 348 349 for (cnt = 0; cnt < keypad->rows; cnt++) 350 if (gpio_is_valid(keypad->row_gpios[cnt])) 351 gpio_free(keypad->row_gpios[cnt]); 352 353 for (cnt = 0; cnt < keypad->cols; cnt++) 354 if (gpio_is_valid(keypad->col_gpios[cnt])) 355 gpio_free(keypad->col_gpios[cnt]); 356 } 357 #else 358 static 359 struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev) 360 { 361 return NULL; 362 } 363 364 static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) 365 { 366 } 367 #endif 368 369 static int __devinit samsung_keypad_probe(struct platform_device *pdev) 370 { 371 const struct samsung_keypad_platdata *pdata; 372 const struct matrix_keymap_data *keymap_data; 373 struct samsung_keypad *keypad; 374 struct resource *res; 375 struct input_dev *input_dev; 376 unsigned int row_shift; 377 unsigned int keymap_size; 378 int error; 379 380 if (pdev->dev.of_node) 381 pdata = samsung_keypad_parse_dt(&pdev->dev); 382 else 383 pdata = pdev->dev.platform_data; 384 if (!pdata) { 385 dev_err(&pdev->dev, "no platform data defined\n"); 386 return -EINVAL; 387 } 388 389 keymap_data = pdata->keymap_data; 390 if (!keymap_data) { 391 dev_err(&pdev->dev, "no keymap data defined\n"); 392 return -EINVAL; 393 } 394 395 if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS) 396 return -EINVAL; 397 398 if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS) 399 return -EINVAL; 400 401 /* initialize the gpio */ 402 if (pdata->cfg_gpio) 403 pdata->cfg_gpio(pdata->rows, pdata->cols); 404 405 row_shift = get_count_order(pdata->cols); 406 keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]); 407 408 keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL); 409 input_dev = input_allocate_device(); 410 if (!keypad || !input_dev) { 411 error = -ENOMEM; 412 goto err_free_mem; 413 } 414 415 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 416 if (!res) { 417 error = -ENODEV; 418 goto err_free_mem; 419 } 420 421 keypad->base = ioremap(res->start, resource_size(res)); 422 if (!keypad->base) { 423 error = -EBUSY; 424 goto err_free_mem; 425 } 426 427 keypad->clk = clk_get(&pdev->dev, "keypad"); 428 if (IS_ERR(keypad->clk)) { 429 dev_err(&pdev->dev, "failed to get keypad clk\n"); 430 error = PTR_ERR(keypad->clk); 431 goto err_unmap_base; 432 } 433 434 error = clk_prepare(keypad->clk); 435 if (error) { 436 dev_err(&pdev->dev, "keypad clock prepare failed\n"); 437 goto err_put_clk; 438 } 439 440 keypad->input_dev = input_dev; 441 keypad->pdev = pdev; 442 keypad->row_shift = row_shift; 443 keypad->rows = pdata->rows; 444 keypad->cols = pdata->cols; 445 keypad->stopped = true; 446 init_waitqueue_head(&keypad->wait); 447 448 if (pdev->dev.of_node) { 449 #ifdef CONFIG_OF 450 samsung_keypad_parse_dt_gpio(&pdev->dev, keypad); 451 keypad->type = of_device_is_compatible(pdev->dev.of_node, 452 "samsung,s5pv210-keypad"); 453 #endif 454 } else { 455 keypad->type = platform_get_device_id(pdev)->driver_data; 456 } 457 458 input_dev->name = pdev->name; 459 input_dev->id.bustype = BUS_HOST; 460 input_dev->dev.parent = &pdev->dev; 461 462 input_dev->open = samsung_keypad_open; 463 input_dev->close = samsung_keypad_close; 464 465 error = matrix_keypad_build_keymap(keymap_data, NULL, 466 pdata->rows, pdata->cols, 467 keypad->keycodes, input_dev); 468 if (error) { 469 dev_err(&pdev->dev, "failed to build keymap\n"); 470 goto err_unprepare_clk; 471 } 472 473 input_set_capability(input_dev, EV_MSC, MSC_SCAN); 474 if (!pdata->no_autorepeat) 475 __set_bit(EV_REP, input_dev->evbit); 476 477 input_set_drvdata(input_dev, keypad); 478 479 keypad->irq = platform_get_irq(pdev, 0); 480 if (keypad->irq < 0) { 481 error = keypad->irq; 482 goto err_put_clk; 483 } 484 485 error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq, 486 IRQF_ONESHOT, dev_name(&pdev->dev), keypad); 487 if (error) { 488 dev_err(&pdev->dev, "failed to register keypad interrupt\n"); 489 goto err_put_clk; 490 } 491 492 device_init_wakeup(&pdev->dev, pdata->wakeup); 493 platform_set_drvdata(pdev, keypad); 494 pm_runtime_enable(&pdev->dev); 495 496 error = input_register_device(keypad->input_dev); 497 if (error) 498 goto err_free_irq; 499 500 if (pdev->dev.of_node) { 501 devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap); 502 devm_kfree(&pdev->dev, (void *)pdata->keymap_data); 503 devm_kfree(&pdev->dev, (void *)pdata); 504 } 505 return 0; 506 507 err_free_irq: 508 free_irq(keypad->irq, keypad); 509 pm_runtime_disable(&pdev->dev); 510 device_init_wakeup(&pdev->dev, 0); 511 platform_set_drvdata(pdev, NULL); 512 err_unprepare_clk: 513 clk_unprepare(keypad->clk); 514 err_put_clk: 515 clk_put(keypad->clk); 516 samsung_keypad_dt_gpio_free(keypad); 517 err_unmap_base: 518 iounmap(keypad->base); 519 err_free_mem: 520 input_free_device(input_dev); 521 kfree(keypad); 522 523 return error; 524 } 525 526 static int __devexit samsung_keypad_remove(struct platform_device *pdev) 527 { 528 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 529 530 pm_runtime_disable(&pdev->dev); 531 device_init_wakeup(&pdev->dev, 0); 532 platform_set_drvdata(pdev, NULL); 533 534 input_unregister_device(keypad->input_dev); 535 536 /* 537 * It is safe to free IRQ after unregistering device because 538 * samsung_keypad_close will shut off interrupts. 539 */ 540 free_irq(keypad->irq, keypad); 541 542 clk_unprepare(keypad->clk); 543 clk_put(keypad->clk); 544 samsung_keypad_dt_gpio_free(keypad); 545 546 iounmap(keypad->base); 547 kfree(keypad); 548 549 return 0; 550 } 551 552 #ifdef CONFIG_PM_RUNTIME 553 static int samsung_keypad_runtime_suspend(struct device *dev) 554 { 555 struct platform_device *pdev = to_platform_device(dev); 556 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 557 unsigned int val; 558 int error; 559 560 if (keypad->stopped) 561 return 0; 562 563 /* This may fail on some SoCs due to lack of controller support */ 564 error = enable_irq_wake(keypad->irq); 565 if (!error) 566 keypad->wake_enabled = true; 567 568 val = readl(keypad->base + SAMSUNG_KEYIFCON); 569 val |= SAMSUNG_KEYIFCON_WAKEUPEN; 570 writel(val, keypad->base + SAMSUNG_KEYIFCON); 571 572 clk_disable(keypad->clk); 573 574 return 0; 575 } 576 577 static int samsung_keypad_runtime_resume(struct device *dev) 578 { 579 struct platform_device *pdev = to_platform_device(dev); 580 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 581 unsigned int val; 582 583 if (keypad->stopped) 584 return 0; 585 586 clk_enable(keypad->clk); 587 588 val = readl(keypad->base + SAMSUNG_KEYIFCON); 589 val &= ~SAMSUNG_KEYIFCON_WAKEUPEN; 590 writel(val, keypad->base + SAMSUNG_KEYIFCON); 591 592 if (keypad->wake_enabled) 593 disable_irq_wake(keypad->irq); 594 595 return 0; 596 } 597 #endif 598 599 #ifdef CONFIG_PM_SLEEP 600 static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad, 601 bool enable) 602 { 603 unsigned int val; 604 605 clk_enable(keypad->clk); 606 607 val = readl(keypad->base + SAMSUNG_KEYIFCON); 608 if (enable) { 609 val |= SAMSUNG_KEYIFCON_WAKEUPEN; 610 if (device_may_wakeup(&keypad->pdev->dev)) 611 enable_irq_wake(keypad->irq); 612 } else { 613 val &= ~SAMSUNG_KEYIFCON_WAKEUPEN; 614 if (device_may_wakeup(&keypad->pdev->dev)) 615 disable_irq_wake(keypad->irq); 616 } 617 writel(val, keypad->base + SAMSUNG_KEYIFCON); 618 619 clk_disable(keypad->clk); 620 } 621 622 static int samsung_keypad_suspend(struct device *dev) 623 { 624 struct platform_device *pdev = to_platform_device(dev); 625 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 626 struct input_dev *input_dev = keypad->input_dev; 627 628 mutex_lock(&input_dev->mutex); 629 630 if (input_dev->users) 631 samsung_keypad_stop(keypad); 632 633 samsung_keypad_toggle_wakeup(keypad, true); 634 635 mutex_unlock(&input_dev->mutex); 636 637 return 0; 638 } 639 640 static int samsung_keypad_resume(struct device *dev) 641 { 642 struct platform_device *pdev = to_platform_device(dev); 643 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 644 struct input_dev *input_dev = keypad->input_dev; 645 646 mutex_lock(&input_dev->mutex); 647 648 samsung_keypad_toggle_wakeup(keypad, false); 649 650 if (input_dev->users) 651 samsung_keypad_start(keypad); 652 653 mutex_unlock(&input_dev->mutex); 654 655 return 0; 656 } 657 #endif 658 659 static const struct dev_pm_ops samsung_keypad_pm_ops = { 660 SET_SYSTEM_SLEEP_PM_OPS(samsung_keypad_suspend, samsung_keypad_resume) 661 SET_RUNTIME_PM_OPS(samsung_keypad_runtime_suspend, 662 samsung_keypad_runtime_resume, NULL) 663 }; 664 665 #ifdef CONFIG_OF 666 static const struct of_device_id samsung_keypad_dt_match[] = { 667 { .compatible = "samsung,s3c6410-keypad" }, 668 { .compatible = "samsung,s5pv210-keypad" }, 669 {}, 670 }; 671 MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match); 672 #endif 673 674 static struct platform_device_id samsung_keypad_driver_ids[] = { 675 { 676 .name = "samsung-keypad", 677 .driver_data = KEYPAD_TYPE_SAMSUNG, 678 }, { 679 .name = "s5pv210-keypad", 680 .driver_data = KEYPAD_TYPE_S5PV210, 681 }, 682 { }, 683 }; 684 MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids); 685 686 static struct platform_driver samsung_keypad_driver = { 687 .probe = samsung_keypad_probe, 688 .remove = __devexit_p(samsung_keypad_remove), 689 .driver = { 690 .name = "samsung-keypad", 691 .owner = THIS_MODULE, 692 .of_match_table = of_match_ptr(samsung_keypad_dt_match), 693 .pm = &samsung_keypad_pm_ops, 694 }, 695 .id_table = samsung_keypad_driver_ids, 696 }; 697 module_platform_driver(samsung_keypad_driver); 698 699 MODULE_DESCRIPTION("Samsung keypad driver"); 700 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 701 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>"); 702 MODULE_LICENSE("GPL"); 703