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