Lines Matching +full:keypad +full:- +full:wakeup
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Samsung keypad driver
24 #include <linux/input/samsung-keypad.h>
78 static void samsung_keypad_scan(struct samsung_keypad *keypad, in samsung_keypad_scan() argument
84 for (col = 0; col < keypad->cols; col++) { in samsung_keypad_scan()
86 val <<= keypad->chip->column_shift; in samsung_keypad_scan()
88 writel(val, keypad->base + SAMSUNG_KEYIFCOL); in samsung_keypad_scan()
91 val = readl(keypad->base + SAMSUNG_KEYIFROW); in samsung_keypad_scan()
92 row_state[col] = ~val & GENMASK(keypad->rows - 1, 0); in samsung_keypad_scan()
96 writel(0, keypad->base + SAMSUNG_KEYIFCOL); in samsung_keypad_scan()
99 static bool samsung_keypad_report(struct samsung_keypad *keypad, in samsung_keypad_report() argument
102 struct input_dev *input_dev = keypad->input_dev; in samsung_keypad_report()
109 for (col = 0; col < keypad->cols; col++) { in samsung_keypad_report()
110 changed = row_state[col] ^ keypad->row_state[col]; in samsung_keypad_report()
115 for (row = 0; row < keypad->rows; row++) { in samsung_keypad_report()
121 dev_dbg(&keypad->input_dev->dev, in samsung_keypad_report()
125 val = MATRIX_SCAN_CODE(row, col, keypad->row_shift); in samsung_keypad_report()
129 keypad->keycodes[val], pressed); in samsung_keypad_report()
131 input_sync(keypad->input_dev); in samsung_keypad_report()
134 memcpy(keypad->row_state, row_state, sizeof(keypad->row_state)); in samsung_keypad_report()
141 struct samsung_keypad *keypad = dev_id; in samsung_keypad_irq() local
145 pm_runtime_get_sync(&keypad->pdev->dev); in samsung_keypad_irq()
148 readl(keypad->base + SAMSUNG_KEYIFSTSCLR); in samsung_keypad_irq()
150 writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); in samsung_keypad_irq()
152 samsung_keypad_scan(keypad, row_state); in samsung_keypad_irq()
154 key_down = samsung_keypad_report(keypad, row_state); in samsung_keypad_irq()
156 wait_event_timeout(keypad->wait, keypad->stopped, in samsung_keypad_irq()
159 } while (key_down && !keypad->stopped); in samsung_keypad_irq()
161 pm_runtime_put(&keypad->pdev->dev); in samsung_keypad_irq()
166 static void samsung_keypad_start(struct samsung_keypad *keypad) in samsung_keypad_start() argument
170 pm_runtime_get_sync(&keypad->pdev->dev); in samsung_keypad_start()
173 keypad->stopped = false; in samsung_keypad_start()
175 clk_enable(keypad->clk); in samsung_keypad_start()
178 val = readl(keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_start()
180 writel(val, keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_start()
183 writel(0, keypad->base + SAMSUNG_KEYIFCOL); in samsung_keypad_start()
185 pm_runtime_put(&keypad->pdev->dev); in samsung_keypad_start()
188 static void samsung_keypad_stop(struct samsung_keypad *keypad) in samsung_keypad_stop() argument
192 pm_runtime_get_sync(&keypad->pdev->dev); in samsung_keypad_stop()
195 keypad->stopped = true; in samsung_keypad_stop()
196 wake_up(&keypad->wait); in samsung_keypad_stop()
197 disable_irq(keypad->irq); in samsung_keypad_stop()
200 writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); in samsung_keypad_stop()
203 val = readl(keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_stop()
205 writel(val, keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_stop()
207 clk_disable(keypad->clk); in samsung_keypad_stop()
211 * re-enable the handler. in samsung_keypad_stop()
213 enable_irq(keypad->irq); in samsung_keypad_stop()
215 pm_runtime_put(&keypad->pdev->dev); in samsung_keypad_stop()
220 struct samsung_keypad *keypad = input_get_drvdata(input_dev); in samsung_keypad_open() local
222 samsung_keypad_start(keypad); in samsung_keypad_open()
229 struct samsung_keypad *keypad = input_get_drvdata(input_dev); in samsung_keypad_close() local
231 samsung_keypad_stop(keypad); in samsung_keypad_close()
241 struct device_node *np = dev->of_node, *key_np; in samsung_keypad_parse_dt()
246 return ERR_PTR(-EINVAL); in samsung_keypad_parse_dt()
252 return ERR_PTR(-ENOMEM); in samsung_keypad_parse_dt()
255 of_property_read_u32(np, "samsung,keypad-num-rows", &num_rows); in samsung_keypad_parse_dt()
256 of_property_read_u32(np, "samsung,keypad-num-columns", &num_cols); in samsung_keypad_parse_dt()
258 dev_err(dev, "number of keypad rows/columns not specified\n"); in samsung_keypad_parse_dt()
259 return ERR_PTR(-EINVAL); in samsung_keypad_parse_dt()
261 pdata->rows = num_rows; in samsung_keypad_parse_dt()
262 pdata->cols = num_cols; in samsung_keypad_parse_dt()
267 return ERR_PTR(-ENOMEM); in samsung_keypad_parse_dt()
269 pdata->keymap_data = keymap_data; in samsung_keypad_parse_dt()
272 keymap_data->keymap_size = key_count; in samsung_keypad_parse_dt()
276 return ERR_PTR(-ENOMEM); in samsung_keypad_parse_dt()
278 keymap_data->keymap = keymap; in samsung_keypad_parse_dt()
282 of_property_read_u32(key_np, "keypad,row", &row); in samsung_keypad_parse_dt()
283 of_property_read_u32(key_np, "keypad,column", &col); in samsung_keypad_parse_dt()
288 pdata->no_autorepeat = of_property_read_bool(np, "linux,input-no-autorepeat"); in samsung_keypad_parse_dt()
290 pdata->wakeup = of_property_read_bool(np, "wakeup-source") || in samsung_keypad_parse_dt()
292 of_property_read_bool(np, "linux,input-wakeup"); in samsung_keypad_parse_dt()
303 return ERR_PTR(-EINVAL); in samsung_keypad_parse_dt()
312 struct samsung_keypad *keypad; in samsung_keypad_probe() local
318 pdata = dev_get_platdata(&pdev->dev); in samsung_keypad_probe()
320 pdata = samsung_keypad_parse_dt(&pdev->dev); in samsung_keypad_probe()
325 keymap_data = pdata->keymap_data; in samsung_keypad_probe()
327 dev_err(&pdev->dev, "no keymap data defined\n"); in samsung_keypad_probe()
328 return -EINVAL; in samsung_keypad_probe()
331 if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS) in samsung_keypad_probe()
332 return -EINVAL; in samsung_keypad_probe()
334 if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS) in samsung_keypad_probe()
335 return -EINVAL; in samsung_keypad_probe()
338 if (pdata->cfg_gpio) in samsung_keypad_probe()
339 pdata->cfg_gpio(pdata->rows, pdata->cols); in samsung_keypad_probe()
341 row_shift = get_count_order(pdata->cols); in samsung_keypad_probe()
343 keypad = devm_kzalloc(&pdev->dev, in samsung_keypad_probe()
344 struct_size(keypad, keycodes, in samsung_keypad_probe()
345 pdata->rows << row_shift), in samsung_keypad_probe()
347 if (!keypad) in samsung_keypad_probe()
348 return -ENOMEM; in samsung_keypad_probe()
350 input_dev = devm_input_allocate_device(&pdev->dev); in samsung_keypad_probe()
352 return -ENOMEM; in samsung_keypad_probe()
356 return -ENODEV; in samsung_keypad_probe()
358 keypad->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); in samsung_keypad_probe()
359 if (!keypad->base) in samsung_keypad_probe()
360 return -EBUSY; in samsung_keypad_probe()
362 keypad->clk = devm_clk_get_prepared(&pdev->dev, "keypad"); in samsung_keypad_probe()
363 if (IS_ERR(keypad->clk)) { in samsung_keypad_probe()
364 dev_err(&pdev->dev, "failed to get keypad clk\n"); in samsung_keypad_probe()
365 return PTR_ERR(keypad->clk); in samsung_keypad_probe()
368 keypad->input_dev = input_dev; in samsung_keypad_probe()
369 keypad->pdev = pdev; in samsung_keypad_probe()
370 keypad->row_shift = row_shift; in samsung_keypad_probe()
371 keypad->rows = pdata->rows; in samsung_keypad_probe()
372 keypad->cols = pdata->cols; in samsung_keypad_probe()
373 keypad->stopped = true; in samsung_keypad_probe()
374 init_waitqueue_head(&keypad->wait); in samsung_keypad_probe()
376 keypad->chip = device_get_match_data(&pdev->dev); in samsung_keypad_probe()
377 if (!keypad->chip) { in samsung_keypad_probe()
380 keypad->chip = (const void *)id->driver_data; in samsung_keypad_probe()
383 if (!keypad->chip) { in samsung_keypad_probe()
384 dev_err(&pdev->dev, "Unable to determine chip type"); in samsung_keypad_probe()
385 return -EINVAL; in samsung_keypad_probe()
388 input_dev->name = pdev->name; in samsung_keypad_probe()
389 input_dev->id.bustype = BUS_HOST; in samsung_keypad_probe()
391 input_dev->open = samsung_keypad_open; in samsung_keypad_probe()
392 input_dev->close = samsung_keypad_close; in samsung_keypad_probe()
395 pdata->rows, pdata->cols, in samsung_keypad_probe()
396 keypad->keycodes, input_dev); in samsung_keypad_probe()
398 dev_err(&pdev->dev, "failed to build keymap\n"); in samsung_keypad_probe()
403 if (!pdata->no_autorepeat) in samsung_keypad_probe()
404 __set_bit(EV_REP, input_dev->evbit); in samsung_keypad_probe()
406 input_set_drvdata(input_dev, keypad); in samsung_keypad_probe()
408 keypad->irq = platform_get_irq(pdev, 0); in samsung_keypad_probe()
409 if (keypad->irq < 0) { in samsung_keypad_probe()
410 error = keypad->irq; in samsung_keypad_probe()
414 error = devm_request_threaded_irq(&pdev->dev, keypad->irq, NULL, in samsung_keypad_probe()
416 dev_name(&pdev->dev), keypad); in samsung_keypad_probe()
418 dev_err(&pdev->dev, "failed to register keypad interrupt\n"); in samsung_keypad_probe()
422 device_init_wakeup(&pdev->dev, pdata->wakeup); in samsung_keypad_probe()
423 platform_set_drvdata(pdev, keypad); in samsung_keypad_probe()
425 error = devm_pm_runtime_enable(&pdev->dev); in samsung_keypad_probe()
429 error = input_register_device(keypad->input_dev); in samsung_keypad_probe()
433 if (pdev->dev.of_node) { in samsung_keypad_probe()
434 devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap); in samsung_keypad_probe()
435 devm_kfree(&pdev->dev, (void *)pdata->keymap_data); in samsung_keypad_probe()
436 devm_kfree(&pdev->dev, (void *)pdata); in samsung_keypad_probe()
444 struct samsung_keypad *keypad = platform_get_drvdata(pdev); in samsung_keypad_runtime_suspend() local
448 if (keypad->stopped) in samsung_keypad_runtime_suspend()
452 error = enable_irq_wake(keypad->irq); in samsung_keypad_runtime_suspend()
454 keypad->wake_enabled = true; in samsung_keypad_runtime_suspend()
456 val = readl(keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_runtime_suspend()
458 writel(val, keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_runtime_suspend()
460 clk_disable(keypad->clk); in samsung_keypad_runtime_suspend()
468 struct samsung_keypad *keypad = platform_get_drvdata(pdev); in samsung_keypad_runtime_resume() local
471 if (keypad->stopped) in samsung_keypad_runtime_resume()
474 clk_enable(keypad->clk); in samsung_keypad_runtime_resume()
476 val = readl(keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_runtime_resume()
478 writel(val, keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_runtime_resume()
480 if (keypad->wake_enabled) in samsung_keypad_runtime_resume()
481 disable_irq_wake(keypad->irq); in samsung_keypad_runtime_resume()
486 static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad, in samsung_keypad_toggle_wakeup() argument
491 clk_enable(keypad->clk); in samsung_keypad_toggle_wakeup()
493 val = readl(keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_toggle_wakeup()
496 if (device_may_wakeup(&keypad->pdev->dev)) in samsung_keypad_toggle_wakeup()
497 enable_irq_wake(keypad->irq); in samsung_keypad_toggle_wakeup()
500 if (device_may_wakeup(&keypad->pdev->dev)) in samsung_keypad_toggle_wakeup()
501 disable_irq_wake(keypad->irq); in samsung_keypad_toggle_wakeup()
503 writel(val, keypad->base + SAMSUNG_KEYIFCON); in samsung_keypad_toggle_wakeup()
505 clk_disable(keypad->clk); in samsung_keypad_toggle_wakeup()
511 struct samsung_keypad *keypad = platform_get_drvdata(pdev); in samsung_keypad_suspend() local
512 struct input_dev *input_dev = keypad->input_dev; in samsung_keypad_suspend()
514 guard(mutex)(&input_dev->mutex); in samsung_keypad_suspend()
517 samsung_keypad_stop(keypad); in samsung_keypad_suspend()
519 samsung_keypad_toggle_wakeup(keypad, true); in samsung_keypad_suspend()
527 struct samsung_keypad *keypad = platform_get_drvdata(pdev); in samsung_keypad_resume() local
528 struct input_dev *input_dev = keypad->input_dev; in samsung_keypad_resume()
530 guard(mutex)(&input_dev->mutex); in samsung_keypad_resume()
532 samsung_keypad_toggle_wakeup(keypad, false); in samsung_keypad_resume()
535 samsung_keypad_start(keypad); in samsung_keypad_resume()
557 .compatible = "samsung,s3c6410-keypad",
560 .compatible = "samsung,s5pv210-keypad",
570 .name = "samsung-keypad",
573 .name = "s5pv210-keypad",
583 .name = "samsung-keypad",
591 MODULE_DESCRIPTION("Samsung keypad driver");