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