root/drivers/input/keyboard/samsung-keypad.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. samsung_keypad_scan
  2. samsung_keypad_report
  3. samsung_keypad_irq
  4. samsung_keypad_start
  5. samsung_keypad_stop
  6. samsung_keypad_open
  7. samsung_keypad_close
  8. samsung_keypad_parse_dt
  9. samsung_keypad_parse_dt
  10. samsung_keypad_probe
  11. samsung_keypad_remove
  12. samsung_keypad_runtime_suspend
  13. samsung_keypad_runtime_resume
  14. samsung_keypad_toggle_wakeup
  15. samsung_keypad_suspend
  16. samsung_keypad_resume

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

/* [<][>][^][v][top][bottom][index][help] */