Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

input: samsung-keypad: Add device tree support

Add device tree based discovery support for Samsung's keypad controller.

Cc: Joonyoung Shim <jy0922.shim@samsung.com>
Cc: Donghwa Lee <dh09.lee@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>

authored by

Thomas Abraham and committed by
Kukjin Kim
b3d6ac3e 8742e044

+250 -12
+88
Documentation/devicetree/bindings/input/samsung-keypad.txt
··· 1 + * Samsung's Keypad Controller device tree bindings 2 + 3 + Samsung's Keypad controller is used to interface a SoC with a matrix-type 4 + keypad device. The keypad controller supports multiple row and column lines. 5 + A key can be placed at each intersection of a unique row and a unique column. 6 + The keypad controller can sense a key-press and key-release and report the 7 + event using a interrupt to the cpu. 8 + 9 + Required SoC Specific Properties: 10 + - compatible: should be one of the following 11 + - "samsung,s3c6410-keypad": For controllers compatible with s3c6410 keypad 12 + controller. 13 + - "samsung,s5pv210-keypad": For controllers compatible with s5pv210 keypad 14 + controller. 15 + 16 + - reg: physical base address of the controller and length of memory mapped 17 + region. 18 + 19 + - interrupts: The interrupt number to the cpu. 20 + 21 + Required Board Specific Properties: 22 + - samsung,keypad-num-rows: Number of row lines connected to the keypad 23 + controller. 24 + 25 + - samsung,keypad-num-columns: Number of column lines connected to the 26 + keypad controller. 27 + 28 + - row-gpios: List of gpios used as row lines. The gpio specifier for 29 + this property depends on the gpio controller to which these row lines 30 + are connected. 31 + 32 + - col-gpios: List of gpios used as column lines. The gpio specifier for 33 + this property depends on the gpio controller to which these column 34 + lines are connected. 35 + 36 + - Keys represented as child nodes: Each key connected to the keypad 37 + controller is represented as a child node to the keypad controller 38 + device node and should include the following properties. 39 + - keypad,row: the row number to which the key is connected. 40 + - keypad,column: the column number to which the key is connected. 41 + - linux,code: the key-code to be reported when the key is pressed 42 + and released. 43 + 44 + Optional Properties specific to linux: 45 + - linux,keypad-no-autorepeat: do no enable autorepeat feature. 46 + - linux,keypad-wakeup: use any event on keypad as wakeup event. 47 + 48 + 49 + Example: 50 + keypad@100A0000 { 51 + compatible = "samsung,s5pv210-keypad"; 52 + reg = <0x100A0000 0x100>; 53 + interrupts = <173>; 54 + samsung,keypad-num-rows = <2>; 55 + samsung,keypad-num-columns = <8>; 56 + linux,input-no-autorepeat; 57 + linux,input-wakeup; 58 + 59 + row-gpios = <&gpx2 0 3 3 0 60 + &gpx2 1 3 3 0>; 61 + 62 + col-gpios = <&gpx1 0 3 0 0 63 + &gpx1 1 3 0 0 64 + &gpx1 2 3 0 0 65 + &gpx1 3 3 0 0 66 + &gpx1 4 3 0 0 67 + &gpx1 5 3 0 0 68 + &gpx1 6 3 0 0 69 + &gpx1 7 3 0 0>; 70 + 71 + key_1 { 72 + keypad,row = <0>; 73 + keypad,column = <3>; 74 + linux,code = <2>; 75 + }; 76 + 77 + key_2 { 78 + keypad,row = <0>; 79 + keypad,column = <4>; 80 + linux,code = <3>; 81 + }; 82 + 83 + key_3 { 84 + keypad,row = <0>; 85 + keypad,column = <5>; 86 + linux,code = <4>; 87 + }; 88 + };
+162 -12
drivers/input/keyboard/samsung-keypad.c
··· 21 21 #include <linux/module.h> 22 22 #include <linux/platform_device.h> 23 23 #include <linux/slab.h> 24 + #include <linux/of.h> 25 + #include <linux/of_gpio.h> 24 26 #include <linux/sched.h> 25 27 #include <plat/keypad.h> 26 28 ··· 70 68 wait_queue_head_t wait; 71 69 bool stopped; 72 70 int irq; 71 + enum samsung_keypad_type type; 73 72 unsigned int row_shift; 74 73 unsigned int rows; 75 74 unsigned int cols; 76 75 unsigned int row_state[SAMSUNG_MAX_COLS]; 76 + #ifdef CONFIG_OF 77 + int row_gpios[SAMSUNG_MAX_ROWS]; 78 + int col_gpios[SAMSUNG_MAX_COLS]; 79 + #endif 77 80 unsigned short keycodes[]; 78 81 }; 79 - 80 - static int samsung_keypad_is_s5pv210(struct device *dev) 81 - { 82 - struct platform_device *pdev = to_platform_device(dev); 83 - enum samsung_keypad_type type = 84 - platform_get_device_id(pdev)->driver_data; 85 - 86 - return type == KEYPAD_TYPE_S5PV210; 87 - } 88 82 89 83 static void samsung_keypad_scan(struct samsung_keypad *keypad, 90 84 unsigned int *row_state) 91 85 { 92 - struct device *dev = keypad->input_dev->dev.parent; 93 86 unsigned int col; 94 87 unsigned int val; 95 88 96 89 for (col = 0; col < keypad->cols; col++) { 97 - if (samsung_keypad_is_s5pv210(dev)) { 90 + if (keypad->type == KEYPAD_TYPE_S5PV210) { 98 91 val = S5PV210_KEYIFCOLEN_MASK; 99 92 val &= ~(1 << col) << 8; 100 93 } else { ··· 232 235 samsung_keypad_stop(keypad); 233 236 } 234 237 238 + #ifdef CONFIG_OF 239 + static struct samsung_keypad_platdata *samsung_keypad_parse_dt( 240 + struct device *dev) 241 + { 242 + struct samsung_keypad_platdata *pdata; 243 + struct matrix_keymap_data *keymap_data; 244 + uint32_t *keymap, num_rows = 0, num_cols = 0; 245 + struct device_node *np = dev->of_node, *key_np; 246 + unsigned int key_count = 0; 247 + 248 + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 249 + if (!pdata) { 250 + dev_err(dev, "could not allocate memory for platform data\n"); 251 + return NULL; 252 + } 253 + 254 + of_property_read_u32(np, "samsung,keypad-num-rows", &num_rows); 255 + of_property_read_u32(np, "samsung,keypad-num-columns", &num_cols); 256 + if (!num_rows || !num_cols) { 257 + dev_err(dev, "number of keypad rows/columns not specified\n"); 258 + return NULL; 259 + } 260 + pdata->rows = num_rows; 261 + pdata->cols = num_cols; 262 + 263 + keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL); 264 + if (!keymap_data) { 265 + dev_err(dev, "could not allocate memory for keymap data\n"); 266 + return NULL; 267 + } 268 + pdata->keymap_data = keymap_data; 269 + 270 + for_each_child_of_node(np, key_np) 271 + key_count++; 272 + 273 + keymap_data->keymap_size = key_count; 274 + keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL); 275 + if (!keymap) { 276 + dev_err(dev, "could not allocate memory for keymap\n"); 277 + return NULL; 278 + } 279 + keymap_data->keymap = keymap; 280 + 281 + for_each_child_of_node(np, key_np) { 282 + u32 row, col, key_code; 283 + of_property_read_u32(key_np, "keypad,row", &row); 284 + of_property_read_u32(key_np, "keypad,column", &col); 285 + of_property_read_u32(key_np, "linux,code", &key_code); 286 + *keymap++ = KEY(row, col, key_code); 287 + } 288 + 289 + if (of_get_property(np, "linux,input-no-autorepeat", NULL)) 290 + pdata->no_autorepeat = true; 291 + if (of_get_property(np, "linux,input-wakeup", NULL)) 292 + pdata->wakeup = true; 293 + 294 + return pdata; 295 + } 296 + 297 + static void samsung_keypad_parse_dt_gpio(struct device *dev, 298 + struct samsung_keypad *keypad) 299 + { 300 + struct device_node *np = dev->of_node; 301 + int gpio, ret, row, col; 302 + 303 + for (row = 0; row < keypad->rows; row++) { 304 + gpio = of_get_named_gpio(np, "row-gpios", row); 305 + keypad->row_gpios[row] = gpio; 306 + if (!gpio_is_valid(gpio)) { 307 + dev_err(dev, "keypad row[%d]: invalid gpio %d\n", 308 + row, gpio); 309 + continue; 310 + } 311 + 312 + ret = gpio_request(gpio, "keypad-row"); 313 + if (ret) 314 + dev_err(dev, "keypad row[%d] gpio request failed\n", 315 + row); 316 + } 317 + 318 + for (col = 0; col < keypad->cols; col++) { 319 + gpio = of_get_named_gpio(np, "col-gpios", col); 320 + keypad->col_gpios[col] = gpio; 321 + if (!gpio_is_valid(gpio)) { 322 + dev_err(dev, "keypad column[%d]: invalid gpio %d\n", 323 + col, gpio); 324 + continue; 325 + } 326 + 327 + ret = gpio_request(gpio, "keypad-col"); 328 + if (ret) 329 + dev_err(dev, "keypad column[%d] gpio request failed\n", 330 + col); 331 + } 332 + } 333 + 334 + static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) 335 + { 336 + int cnt; 337 + 338 + for (cnt = 0; cnt < keypad->rows; cnt++) 339 + if (gpio_is_valid(keypad->row_gpios[cnt])) 340 + gpio_free(keypad->row_gpios[cnt]); 341 + 342 + for (cnt = 0; cnt < keypad->cols; cnt++) 343 + if (gpio_is_valid(keypad->col_gpios[cnt])) 344 + gpio_free(keypad->col_gpios[cnt]); 345 + } 346 + #else 347 + static 348 + struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev) 349 + { 350 + return NULL; 351 + } 352 + 353 + static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) 354 + { 355 + } 356 + #endif 357 + 235 358 static int __devinit samsung_keypad_probe(struct platform_device *pdev) 236 359 { 237 360 const struct samsung_keypad_platdata *pdata; ··· 363 246 unsigned int keymap_size; 364 247 int error; 365 248 366 - pdata = pdev->dev.platform_data; 249 + if (pdev->dev.of_node) 250 + pdata = samsung_keypad_parse_dt(&pdev->dev); 251 + else 252 + pdata = pdev->dev.platform_data; 367 253 if (!pdata) { 368 254 dev_err(&pdev->dev, "no platform data defined\n"); 369 255 return -EINVAL; ··· 423 303 keypad->cols = pdata->cols; 424 304 init_waitqueue_head(&keypad->wait); 425 305 306 + if (pdev->dev.of_node) { 307 + #ifdef CONFIG_OF 308 + samsung_keypad_parse_dt_gpio(&pdev->dev, keypad); 309 + keypad->type = of_device_is_compatible(pdev->dev.of_node, 310 + "samsung,s5pv210-keypad"); 311 + #endif 312 + } else { 313 + keypad->type = platform_get_device_id(pdev)->driver_data; 314 + } 315 + 426 316 input_dev->name = pdev->name; 427 317 input_dev->id.bustype = BUS_HOST; 428 318 input_dev->dev.parent = &pdev->dev; ··· 473 343 474 344 device_init_wakeup(&pdev->dev, pdata->wakeup); 475 345 platform_set_drvdata(pdev, keypad); 346 + 347 + if (pdev->dev.of_node) { 348 + devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap); 349 + devm_kfree(&pdev->dev, (void *)pdata->keymap_data); 350 + devm_kfree(&pdev->dev, (void *)pdata); 351 + } 476 352 return 0; 477 353 478 354 err_free_irq: 479 355 free_irq(keypad->irq, keypad); 480 356 err_put_clk: 481 357 clk_put(keypad->clk); 358 + samsung_keypad_dt_gpio_free(keypad); 482 359 err_unmap_base: 483 360 iounmap(keypad->base); 484 361 err_free_mem: ··· 511 374 free_irq(keypad->irq, keypad); 512 375 513 376 clk_put(keypad->clk); 377 + samsung_keypad_dt_gpio_free(keypad); 514 378 515 379 iounmap(keypad->base); 516 380 kfree(keypad); ··· 585 447 }; 586 448 #endif 587 449 450 + #ifdef CONFIG_OF 451 + static const struct of_device_id samsung_keypad_dt_match[] = { 452 + { .compatible = "samsung,s3c6410-keypad" }, 453 + { .compatible = "samsung,s5pv210-keypad" }, 454 + {}, 455 + }; 456 + MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match); 457 + #else 458 + #define samsung_keypad_dt_match NULL 459 + #endif 460 + 588 461 static struct platform_device_id samsung_keypad_driver_ids[] = { 589 462 { 590 463 .name = "samsung-keypad", ··· 614 465 .driver = { 615 466 .name = "samsung-keypad", 616 467 .owner = THIS_MODULE, 468 + .of_match_table = samsung_keypad_dt_match, 617 469 #ifdef CONFIG_PM 618 470 .pm = &samsung_keypad_pm_ops, 619 471 #endif