From: Maximilian Weigand <mweigand@mweigand.net>
To: Linus Walleij <linus.walleij@linaro.org>,
Dmitry Torokhov <dmitry.torokhov@gmail.com>,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org
Cc: Maximilian Weigand <mweigand@mweigand.net>,
Alistair Francis <alistair@alistair23.me>
Subject: [PATCH 6/6] Input: cyttsp5: implement proper sleep and wakeup procedures
Date: Thu, 23 Mar 2023 14:52:05 +0100 [thread overview]
Message-ID: <20230323135205.1160879-7-mweigand@mweigand.net> (raw)
In-Reply-To: <20230323135205.1160879-1-mweigand@mweigand.net>
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 because it pulled the interrupt line low during sleep in
response to a touch event, thereby effectively disabling the interrupt
handling (which triggers on the falling edge).
Signed-off-by: Maximilian Weigand <mweigand@mweigand.net>
Reviewed-by: Alistair Francis <alistair@alistair23.me>
---
drivers/input/touchscreen/cyttsp5.c | 129 +++++++++++++++++++++++++++-
1 file changed, 128 insertions(+), 1 deletion(-)
diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c
index 01dd10a596ab..3e8387f6347c 100644
--- a/drivers/input/touchscreen/cyttsp5.c
+++ b/drivers/input/touchscreen/cyttsp5.c
@@ -43,6 +43,7 @@
#define HID_DESC_REG 0x1
#define HID_INPUT_REG 0x3
#define HID_OUTPUT_REG 0x4
+#define HID_COMMAND_REG 0x5
#define REPORT_ID_TOUCH 0x1
#define REPORT_ID_BTN 0x3
@@ -68,6 +69,7 @@
#define HID_APP_OUTPUT_REPORT_ID 0x2F
#define HID_BL_RESPONSE_REPORT_ID 0x30
#define HID_BL_OUTPUT_REPORT_ID 0x40
+#define HID_RESPONSE_REPORT_ID 0xF0
#define HID_OUTPUT_RESPONSE_REPORT_OFFSET 2
#define HID_OUTPUT_RESPONSE_CMD_OFFSET 4
@@ -78,9 +80,15 @@
#define HID_SYSINFO_BTN_MASK GENMASK(7, 0)
#define HID_SYSINFO_MAX_BTN 8
+#define HID_CMD_SET_POWER 0x8
+
+#define HID_POWER_ON 0x0
+#define HID_POWER_SLEEP 0x1
+
#define CY_HID_OUTPUT_TIMEOUT_MS 200
#define CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT_MS 3000
#define CY_HID_GET_HID_DESCRIPTOR_TIMEOUT_MS 4000
+#define CY_HID_SET_POWER_TIMEOUT 500
/* maximum number of concurrent tracks */
#define TOUCH_REPORT_SIZE 10
@@ -100,6 +108,14 @@
#define TOUCH_REPORT_USAGE_PG_MIN 0xFF010063
#define TOUCH_COL_USAGE_PG 0x000D0022
+#define SET_CMD_LOW(byte, bits) \
+ ((byte) = (((byte) & 0xF0) | ((bits) & 0x0F)))
+#define SET_CMD_HIGH(byte, bits)\
+ ((byte) = (((byte) & 0x0F) | ((bits) & 0xF0)))
+#define SET_CMD_OPCODE(byte, opcode) SET_CMD_LOW(byte, opcode)
+#define SET_CMD_REPORT_TYPE(byte, type) SET_CMD_HIGH(byte, ((type) << 4))
+#define SET_CMD_REPORT_ID(byte, id) SET_CMD_LOW(byte, id)
+
/* System Information interface definitions */
struct cyttsp5_sensing_conf_data_dev {
u8 electrodes_x;
@@ -179,6 +195,7 @@ struct cyttsp5_hid_desc {
struct cyttsp5 {
struct device *dev;
struct completion cmd_done;
+ struct completion cmd_command_done;
struct cyttsp5_sysinfo sysinfo;
struct cyttsp5_hid_desc hid_desc;
u8 cmd_buf[CYTTSP5_PREALLOCATED_CMD_BUFFER];
@@ -191,6 +208,7 @@ struct cyttsp5 {
struct regmap *regmap;
struct touchscreen_properties prop;
struct regulator *vdd;
+ bool is_wakeup_source;
};
/*
@@ -556,6 +574,84 @@ static int cyttsp5_hid_output_get_sysinfo(struct cyttsp5 *ts)
return cyttsp5_get_sysinfo_regs(ts);
}
+static int cyttsp5_enter_sleep(struct cyttsp5 *ts)
+{
+ int rc;
+ u8 cmd[2];
+ u16 crc;
+
+ memset(cmd, 0, sizeof(cmd));
+
+ SET_CMD_REPORT_TYPE(cmd[0], 0);
+ SET_CMD_REPORT_ID(cmd[0], HID_POWER_SLEEP);
+ SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER);
+
+ rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, 2);
+ if (rc) {
+ dev_err(ts->dev, "Failed to write command %d", rc);
+ return rc;
+ }
+
+ rc = wait_for_completion_interruptible_timeout(&ts->cmd_command_done,
+ msecs_to_jiffies(CY_HID_SET_POWER_TIMEOUT));
+ if (rc <= 0) {
+ dev_err(ts->dev, "HID output cmd execution timed out\n");
+ rc = -ETIMEDOUT;
+ return rc;
+ }
+
+ /* validate */
+ if ((ts->response_buf[2] != HID_RESPONSE_REPORT_ID)
+ || ((ts->response_buf[3] & 0x3) != HID_POWER_SLEEP)
+ || ((ts->response_buf[4] & 0xF) != HID_CMD_SET_POWER)) {
+ rc = -EINVAL;
+ dev_err(ts->dev, "Validation of the sleep response failed\n");
+ return rc;
+ }
+
+ return 0;
+
+}
+
+static int cyttsp5_wakeup(struct cyttsp5 *ts)
+{
+ int rc;
+ u8 cmd[2];
+ u16 crc;
+
+ memset(cmd, 0, sizeof(cmd));
+
+ SET_CMD_REPORT_TYPE(cmd[0], 0);
+ SET_CMD_REPORT_ID(cmd[0], HID_POWER_ON);
+ SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER);
+
+ rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, 2);
+ if (rc) {
+ dev_err(ts->dev, "Failed to write command %d", rc);
+ return rc;
+ }
+
+ rc = wait_for_completion_interruptible_timeout(&ts->cmd_command_done,
+ msecs_to_jiffies(CY_HID_SET_POWER_TIMEOUT));
+ if (rc <= 0) {
+ dev_err(ts->dev, "HID output cmd execution timed out\n");
+ rc = -ETIMEDOUT;
+ return rc;
+ }
+
+ /* validate */
+ if ((ts->response_buf[2] != HID_RESPONSE_REPORT_ID)
+ || ((ts->response_buf[3] & 0x3) != HID_POWER_ON)
+ || ((ts->response_buf[4] & 0xF) != HID_CMD_SET_POWER)) {
+ rc = -EINVAL;
+ dev_err(ts->dev, "Validation of the sleep response failed\n");
+ return rc;
+ }
+
+ return 0;
+
+}
+
static int cyttsp5_hid_output_bl_launch_app(struct cyttsp5 *ts)
{
int rc;
@@ -670,6 +766,10 @@ static irqreturn_t cyttsp5_handle_irq(int irq, void *handle)
case HID_BTN_REPORT_ID:
cyttsp5_btn_attention(ts->dev);
break;
+ case HID_RESPONSE_REPORT_ID:
+ memcpy(ts->response_buf, ts->input_buf, size);
+ complete(&ts->cmd_command_done);
+ break;
default:
/* It is not an input but a command response */
memcpy(ts->response_buf, ts->input_buf, size);
@@ -784,6 +884,7 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq,
dev_set_drvdata(dev, ts);
init_completion(&ts->cmd_done);
+ init_completion(&ts->cmd_command_done);
/* Power up the device */
ts->vdd = devm_regulator_get(dev, "vdd");
@@ -830,8 +931,11 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq,
return error;
}
- if (device_property_read_bool(dev, "wakeup-source"))
+ if (device_property_read_bool(dev, "wakeup-source")) {
device_init_wakeup(dev, true);
+ ts->is_wakeup_source = true;
+ } else
+ ts->is_wakeup_source = false;
error = cyttsp5_startup(ts);
if (error) {
@@ -884,6 +988,29 @@ static const struct i2c_device_id cyttsp5_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id);
+static int __maybe_unused cyttsp5_suspend(struct device *dev)
+{
+ struct cyttsp5 *ts = dev_get_drvdata(dev);
+
+ if (!ts->is_wakeup_source)
+ cyttsp5_enter_sleep(ts);
+ return 0;
+}
+
+static int __maybe_unused cyttsp5_resume(struct device *dev)
+{
+ struct cyttsp5 *ts = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(dev);
+ int error;
+
+ if (!ts->is_wakeup_source)
+ cyttsp5_wakeup(ts);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cyttsp5_pm, cyttsp5_suspend, cyttsp5_resume);
+
static struct i2c_driver cyttsp5_i2c_driver = {
.driver = {
.name = CYTTSP5_NAME,
--
2.39.2
next prev parent reply other threads:[~2023-03-23 13:52 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-23 13:51 [PATCH 0/6] Small fixes to the cyttsp5 touchscreen driver Maximilian Weigand
2023-03-23 13:52 ` [PATCH 1/6] Input: cyttsp5: fix array length Maximilian Weigand
2023-03-23 13:52 ` [PATCH 2/6] Input: cyttsp5: remove unused code Maximilian Weigand
2023-03-23 15:18 ` kernel test robot
2023-03-27 15:17 ` kernel test robot
2023-03-23 13:52 ` [PATCH 3/6] devicetree: input: cypress,tt21000: fix interrupt type in dts example Maximilian Weigand
2023-03-24 9:41 ` Krzysztof Kozlowski
2023-03-29 8:43 ` Linus Walleij
2023-03-23 13:52 ` [PATCH 4/6] Input: cyttsp5: properly initialize the device as a pm wakeup device Maximilian Weigand
2023-03-23 13:52 ` [PATCH 5/6] devicetree: input: cypress,tt21000: add wakeup-source entry to documentation Maximilian Weigand
2023-03-24 9:42 ` Krzysztof Kozlowski
2023-03-29 8:43 ` Linus Walleij
2023-03-23 13:52 ` Maximilian Weigand [this message]
2023-03-27 18:11 ` [PATCH 6/6] Input: cyttsp5: implement proper sleep and wakeup procedures kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230323135205.1160879-7-mweigand@mweigand.net \
--to=mweigand@mweigand.net \
--cc=alistair@alistair23.me \
--cc=devicetree@vger.kernel.org \
--cc=dmitry.torokhov@gmail.com \
--cc=linus.walleij@linaro.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).