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