From dc3ec8dee0a8a3ced5ea99aad092f1f927acd601 Mon Sep 17 00:00:00 2001
From: SwtcR <[email protected]>
Date: Sun, 11 Feb 2018 09:10:38 +0900
Subject: [PATCH 059/124] stmfts: support polled mode when there is no IRQ
---
drivers/input/touchscreen/stmfts.c | 59 +++++++++++++++++++++++-------
1 file changed, 46 insertions(+), 13 deletions(-)
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 704e99046916..4cba504f046e 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/kthread.h>
/* I2C commands */
#define STMFTS_READ_INFO 0x80
@@ -104,6 +105,8 @@ struct stmfts_data {
bool led_status;
bool hover_enabled;
bool running;
+
+ struct task_struct *poll_thread;
};
static void stmfts_brightness_set(struct led_classdev *led_cdev,
@@ -313,6 +316,18 @@ static irqreturn_t stmfts_irq_handler(int irq, void *dev)
return IRQ_HANDLED;
}
+static int stmfts_poll_thread(void *data)
+{
+ printk("poll_thread starting\n");
+ while (!kthread_should_stop()) {
+ stmfts_irq_handler(0, data);
+ msleep(2);
+ }
+ printk("poll_thread exiting\n");
+ return 0;
+}
+
+
static int stmfts_command(struct stmfts_data *sdata, const u8 cmd)
{
int err;
@@ -546,18 +561,26 @@ static int stmfts_power_on(struct stmfts_data *sdata)
sdata->fw_ver = be16_to_cpup((__be16 *)®[2]);
sdata->config_id = reg[4];
sdata->config_ver = reg[5];
-
- enable_irq(sdata->client->irq);
+
+ if (sdata->client->irq)
+ enable_irq(sdata->client->irq);
msleep(50);
+ if (!sdata->client->irq) {
+ sdata->poll_thread = kthread_run(stmfts_poll_thread, sdata, "stmfts_poll");
+ if (IS_ERR(sdata->poll_thread))
+ return -EIO;
+ }
+
err = stmfts_command(sdata, STMFTS_SYSTEM_RESET);
if (err)
- return err;
+ goto stop_thread;
err = stmfts_command(sdata, STMFTS_SLEEP_OUT);
if (err)
- return err;
+ dev_warn(&sdata->client->dev,
+ "failed to perform sleep_out: %d\n", err);
/* optional tuning */
err = stmfts_command(sdata, STMFTS_MS_CX_TUNING);
@@ -573,7 +596,7 @@ static int stmfts_power_on(struct stmfts_data *sdata)
err = stmfts_command(sdata, STMFTS_FULL_FORCE_CALIBRATION);
if (err)
- return err;
+ goto stop_thread;
/*
* At this point no one is using the touchscreen
@@ -582,13 +605,21 @@ static int stmfts_power_on(struct stmfts_data *sdata)
(void) i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
return 0;
+
+stop_thread:
+ if (!sdata->client->irq)
+ kthread_stop(sdata->poll_thread);
+ return err;
}
static void stmfts_power_off(void *data)
{
struct stmfts_data *sdata = data;
- disable_irq(sdata->client->irq);
+ if (!sdata->client->irq)
+ kthread_stop(sdata->poll_thread);
+ else
+ disable_irq(sdata->client->irq);
regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
sdata->regulators);
}
@@ -689,13 +720,15 @@ static int stmfts_probe(struct i2c_client *client,
* interrupts. To be on the safe side it's better to not enable
* the interrupts during their request.
*/
- irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
- err = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, stmfts_irq_handler,
- IRQF_ONESHOT,
- "stmfts_irq", sdata);
- if (err)
- return err;
+ if (client->irq) {
+ irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
+ err = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, stmfts_irq_handler,
+ IRQF_ONESHOT,
+ "stmfts_irq", sdata);
+ if (err)
+ return err;
+ }
dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n");
--
2.20.1
From 7690882eba261d8bceb176b5a2109db2bc43c278 Mon Sep 17 00:00:00 2001
From: SwtcR <[email protected]>
Date: Mon, 12 Feb 2018 19:11:58 +0900
Subject: [PATCH 060/124] stmfts: hack to support Switch data format
---
drivers/input/touchscreen/stmfts.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 4cba504f046e..003aa7befe62 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -172,6 +172,7 @@ static int stmfts_read_events(struct stmfts_data *sdata)
static void stmfts_report_contact_event(struct stmfts_data *sdata,
const u8 event[])
{
+#if 0
u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
u16 x = event[1] | ((event[2] & STMFTS_MASK_X_MSB) << 8);
u16 y = (event[2] >> 4) | (event[3] << 4);
@@ -179,7 +180,17 @@ static void stmfts_report_contact_event(struct stmfts_data *sdata,
u8 min = event[5];
u8 orientation = event[6];
u8 area = event[7];
+#else
+ u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
+ u16 x = (event[1] << 4) | ((event[3] & 0xf0) >> 4);
+ u16 y = (event[2] << 4) | (event[3] & 0x0f);
+ u8 maj = event[4] | (event[5] << 8);
+ u8 min = maj;
+ // these two are not quite right but meh
+ u8 orientation = event[6];
+ u8 area = event[7];
+#endif
input_mt_slot(sdata->input, slot_id);
input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, true);
--
2.20.1
From 107b486493d8da5ea4c2aeb182bf80cc6fc38fea Mon Sep 17 00:00:00 2001
From: SwtcR <[email protected]>
Date: Thu, 22 Feb 2018 01:40:29 +0900
Subject: [PATCH 061/124] stmfts: support configurable IRQ enable register
---
drivers/input/touchscreen/stmfts.c | 66 ++++++++++++++++++++++++++----
1 file changed, 59 insertions(+), 7 deletions(-)
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 003aa7befe62..797c2048a293 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -35,6 +35,7 @@
#define STMFTS_FULL_FORCE_CALIBRATION 0xa2
#define STMFTS_MS_CX_TUNING 0xa3
#define STMFTS_SS_CX_TUNING 0xa4
+#define STMFTS_WRITE_REGISTER 0xb6
/* events */
#define STMFTS_EV_NO_EVENT 0x00
@@ -105,6 +106,8 @@ struct stmfts_data {
bool led_status;
bool hover_enabled;
bool running;
+ int irq_enable_reg;
+ u8 irq_enable_data;
struct task_struct *poll_thread;
};
@@ -329,12 +332,10 @@ static irqreturn_t stmfts_irq_handler(int irq, void *dev)
static int stmfts_poll_thread(void *data)
{
- printk("poll_thread starting\n");
while (!kthread_should_stop()) {
stmfts_irq_handler(0, data);
msleep(2);
}
- printk("poll_thread exiting\n");
return 0;
}
@@ -356,6 +357,18 @@ static int stmfts_command(struct stmfts_data *sdata, const u8 cmd)
return 0;
}
+static int stmfts_write_register(struct stmfts_data *sdata, const u16 reg, const u8 value)
+{
+ u8 buf[3];
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+ buf[2] = value;
+
+ return i2c_smbus_write_i2c_block_data(sdata->client,
+ STMFTS_WRITE_REGISTER, 3, buf);
+}
+
static int stmfts_input_open(struct input_dev *dev)
{
struct stmfts_data *sdata = input_get_drvdata(dev);
@@ -584,9 +597,33 @@ static int stmfts_power_on(struct stmfts_data *sdata)
return -EIO;
}
- err = stmfts_command(sdata, STMFTS_SYSTEM_RESET);
+ /*
+ * IRQs may be disabled on startup, so we need to reset the chip, then
+ * immediately issue the command to enable IRQs. This will trigger
+ * the completion for the reset command's queued status message.
+ */
+ reinit_completion(&sdata->cmd_done);
+
+ err = i2c_smbus_write_byte(sdata->client, STMFTS_SYSTEM_RESET);
if (err)
- goto stop_thread;
+ goto cleanup_irq;
+
+ msleep(10);
+
+ if (sdata->client->irq && sdata->irq_enable_reg != -1) {
+ err = stmfts_write_register(sdata, sdata->irq_enable_reg,
+ sdata->irq_enable_data);
+ if (err)
+ goto cleanup_irq;
+ }
+
+ if (!wait_for_completion_timeout(&sdata->cmd_done,
+ msecs_to_jiffies(1000))) {
+ err = -ETIMEDOUT;
+ dev_err(&sdata->client->dev,
+ "reset did not complete: %d\n", err);
+ goto cleanup_irq;
+ }
err = stmfts_command(sdata, STMFTS_SLEEP_OUT);
if (err)
@@ -606,8 +643,11 @@ static int stmfts_power_on(struct stmfts_data *sdata)
"failed to perform self auto tune: %d\n", err);
err = stmfts_command(sdata, STMFTS_FULL_FORCE_CALIBRATION);
- if (err)
- goto stop_thread;
+ if (err) {
+ dev_err(&sdata->client->dev,
+ "failed to perform calibration: %d\n", err);
+ goto cleanup_irq;
+ }
/*
* At this point no one is using the touchscreen
@@ -617,9 +657,11 @@ static int stmfts_power_on(struct stmfts_data *sdata)
return 0;
-stop_thread:
+cleanup_irq:
if (!sdata->client->irq)
kthread_stop(sdata->poll_thread);
+ else
+ disable_irq(sdata->client->irq);
return err;
}
@@ -667,6 +709,7 @@ static int stmfts_probe(struct i2c_client *client,
{
int err;
struct stmfts_data *sdata;
+ u32 prop[2];
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_BYTE_DATA |
@@ -712,6 +755,15 @@ static int stmfts_probe(struct i2c_client *client,
sdata->use_key = device_property_read_bool(&client->dev,
"touch-key-connected");
+
+ if (!device_property_read_u32_array(&client->dev,
+ "interrupt-enable-reg", prop, 2)) {
+ sdata->irq_enable_reg = prop[0] & 0xffff;
+ sdata->irq_enable_data = prop[1] & 0xff;
+ } else {
+ sdata->irq_enable_reg = -1;
+ }
+
if (sdata->use_key) {
input_set_capability(sdata->input, EV_KEY, KEY_MENU);
input_set_capability(sdata->input, EV_KEY, KEY_BACK);
--
2.20.1