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

Configure Feed

Select the types of activity you want to include in your feed.

Input: cyttsp5 - implement proper sleep and wakeup procedures

The touchscreen can be put into a deep sleep state that prevents it from
emitting touch irqs. Put the touchscreen into deep sleep during suspend
if it is not marked as a wakeup source.

This also fixes a problem with the touchscreen getting unresponsive after
system resume when a falling edge trigger is used for the interrupt.
When left on during suspend, the touchscreen would pull the interrupt
line down in response to touch events, leaving the interrupt effectively
disabled after resume.

Signed-off-by: Maximilian Weigand <mweigand@mweigand.net>
Reviewed-by: Alistair Francis <alistair@alistair23.me>
Link: https://lore.kernel.org/r/20230504120316.408687-2-mweigand2017@gmail.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Maximilian Weigand and committed by
Dmitry Torokhov
3c98b8db c73b4db0

+77
+77
drivers/input/touchscreen/cyttsp5.c
··· 43 43 #define HID_DESC_REG 0x1 44 44 #define HID_INPUT_REG 0x3 45 45 #define HID_OUTPUT_REG 0x4 46 + #define HID_COMMAND_REG 0x5 46 47 47 48 #define REPORT_ID_TOUCH 0x1 48 49 #define REPORT_ID_BTN 0x3 ··· 69 68 #define HID_APP_OUTPUT_REPORT_ID 0x2F 70 69 #define HID_BL_RESPONSE_REPORT_ID 0x30 71 70 #define HID_BL_OUTPUT_REPORT_ID 0x40 71 + #define HID_RESPONSE_REPORT_ID 0xF0 72 72 73 73 #define HID_OUTPUT_RESPONSE_REPORT_OFFSET 2 74 74 #define HID_OUTPUT_RESPONSE_CMD_OFFSET 4 ··· 80 78 #define HID_SYSINFO_BTN_MASK GENMASK(7, 0) 81 79 #define HID_SYSINFO_MAX_BTN 8 82 80 81 + #define HID_CMD_SET_POWER 0x8 82 + 83 + #define HID_POWER_ON 0x0 84 + #define HID_POWER_SLEEP 0x1 85 + 83 86 #define CY_HID_OUTPUT_TIMEOUT_MS 200 84 87 #define CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT_MS 3000 85 88 #define CY_HID_GET_HID_DESCRIPTOR_TIMEOUT_MS 4000 89 + #define CY_HID_SET_POWER_TIMEOUT 500 86 90 87 91 /* maximum number of concurrent tracks */ 88 92 #define TOUCH_REPORT_SIZE 10 ··· 107 99 #define TOUCH_REPORT_USAGE_PG_MAJ 0xFF010062 108 100 #define TOUCH_REPORT_USAGE_PG_MIN 0xFF010063 109 101 #define TOUCH_COL_USAGE_PG 0x000D0022 102 + 103 + #define SET_CMD_LOW(byte, bits) \ 104 + ((byte) = (((byte) & 0xF0) | ((bits) & 0x0F))) 105 + #define SET_CMD_HIGH(byte, bits)\ 106 + ((byte) = (((byte) & 0x0F) | ((bits) & 0xF0))) 107 + #define SET_CMD_OPCODE(byte, opcode) SET_CMD_LOW(byte, opcode) 108 + #define SET_CMD_REPORT_TYPE(byte, type) SET_CMD_HIGH(byte, ((type) << 4)) 109 + #define SET_CMD_REPORT_ID(byte, id) SET_CMD_LOW(byte, id) 110 110 111 111 /* System Information interface definitions */ 112 112 struct cyttsp5_sensing_conf_data_dev { ··· 572 556 return cyttsp5_get_sysinfo_regs(ts); 573 557 } 574 558 559 + static int cyttsp5_power_control(struct cyttsp5 *ts, bool on) 560 + { 561 + u8 state = on ? HID_POWER_ON : HID_POWER_SLEEP; 562 + u8 cmd[2] = { 0 }; 563 + int rc; 564 + 565 + SET_CMD_REPORT_TYPE(cmd[0], 0); 566 + SET_CMD_REPORT_ID(cmd[0], HID_POWER_SLEEP); 567 + SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER); 568 + 569 + rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, sizeof(cmd)); 570 + if (rc) { 571 + dev_err(ts->dev, "Failed to write power command %d", rc); 572 + return rc; 573 + } 574 + 575 + rc = wait_for_completion_interruptible_timeout(&ts->cmd_done, 576 + msecs_to_jiffies(CY_HID_SET_POWER_TIMEOUT)); 577 + if (rc <= 0) { 578 + dev_err(ts->dev, "HID power cmd execution timed out\n"); 579 + return -ETIMEDOUT; 580 + } 581 + 582 + if (ts->response_buf[2] != HID_RESPONSE_REPORT_ID || 583 + (ts->response_buf[3] & 0x03) != state || 584 + (ts->response_buf[4] & 0x0f) != HID_CMD_SET_POWER) { 585 + dev_err(ts->dev, "Validation of the %s response failed\n", 586 + on ? "wakeup" : "sleep"); 587 + return -EINVAL; 588 + } 589 + 590 + return 0; 591 + } 592 + 575 593 static int cyttsp5_hid_output_bl_launch_app(struct cyttsp5 *ts) 576 594 { 577 595 int rc; ··· 718 668 break; 719 669 case HID_BTN_REPORT_ID: 720 670 cyttsp5_btn_attention(ts->dev); 671 + break; 672 + case HID_RESPONSE_REPORT_ID: 673 + memcpy(ts->response_buf, ts->input_buf, size); 674 + complete(&ts->cmd_done); 721 675 break; 722 676 default: 723 677 /* It is not an input but a command response */ ··· 934 880 }; 935 881 MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id); 936 882 883 + static int __maybe_unused cyttsp5_suspend(struct device *dev) 884 + { 885 + struct cyttsp5 *ts = dev_get_drvdata(dev); 886 + 887 + if (!device_may_wakeup(dev)) 888 + cyttsp5_power_control(ts, false); 889 + 890 + return 0; 891 + } 892 + 893 + static int __maybe_unused cyttsp5_resume(struct device *dev) 894 + { 895 + struct cyttsp5 *ts = dev_get_drvdata(dev); 896 + 897 + if (!device_may_wakeup(dev)) 898 + cyttsp5_power_control(ts, true); 899 + 900 + return 0; 901 + } 902 + 903 + static SIMPLE_DEV_PM_OPS(cyttsp5_pm, cyttsp5_suspend, cyttsp5_resume); 904 + 937 905 static struct i2c_driver cyttsp5_i2c_driver = { 938 906 .driver = { 939 907 .name = CYTTSP5_NAME, 940 908 .of_match_table = cyttsp5_of_match, 909 + .pm = &cyttsp5_pm, 941 910 }, 942 911 .probe_new = cyttsp5_i2c_probe, 943 912 .id_table = cyttsp5_i2c_id,