aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/joystick/sensehat-joystick.c2
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c124
-rw-r--r--drivers/input/touchscreen/goodix.c10
-rw-r--r--drivers/input/touchscreen/goodix.h5
-rw-r--r--drivers/input/touchscreen/ili210x.c63
5 files changed, 176 insertions, 28 deletions
diff --git a/drivers/input/joystick/sensehat-joystick.c b/drivers/input/joystick/sensehat-joystick.c
index a84df39d3b2f..f24beb98e444 100644
--- a/drivers/input/joystick/sensehat-joystick.c
+++ b/drivers/input/joystick/sensehat-joystick.c
@@ -28,7 +28,7 @@ struct sensehat_joystick {
};
static const unsigned int keymap[] = {
- BTN_DPAD_DOWN, BTN_DPAD_RIGHT, BTN_DPAD_UP, BTN_SELECT, BTN_DPAD_LEFT,
+ KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT
};
static irqreturn_t sensehat_joystick_report(int irq, void *cookie)
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index bf498bd4dea9..da8d3eb802fc 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -69,6 +69,7 @@
#define TOUCH_EVENT_RESERVED 0x03
#define EDT_NAME_LEN 23
+#define EDT_NAME_PREFIX_LEN 8
#define EDT_SWITCH_MODE_RETRIES 10
#define EDT_SWITCH_MODE_DELAY 5 /* msec */
#define EDT_RAW_DATA_RETRIES 100
@@ -80,6 +81,10 @@
#define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc)
#define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f)
+#define RESET_DELAY_MS 300 /* reset deassert to I2C */
+#define FIRST_POLL_DELAY_MS 300 /* in addition to the above */
+#define POLL_INTERVAL_MS 17 /* 17ms = 60fps */
+
enum edt_pmode {
EDT_PMODE_NOT_SUPPORTED,
EDT_PMODE_HIBERNATE,
@@ -138,14 +143,19 @@ struct edt_ft5x06_ts_data {
u8 tdata_cmd;
int tdata_len;
int tdata_offset;
+ unsigned int known_ids;
- char name[EDT_NAME_LEN];
+ char name[EDT_NAME_PREFIX_LEN + EDT_NAME_LEN];
char fw_version[EDT_NAME_LEN];
+ int init_td_status;
struct edt_reg_addr reg_addr;
enum edt_ver version;
unsigned int crc_errors;
unsigned int header_errors;
+
+ struct timer_list timer;
+ struct work_struct work_i2c_poll;
};
struct edt_i2c_chip_data {
@@ -302,17 +312,49 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
u8 rdbuf[63];
int i, type, x, y, id;
int error;
+ int num_points;
+ unsigned int active_ids = 0, known_ids = tsdata->known_ids;
+ long released_ids;
+ int b = 0;
memset(rdbuf, 0, sizeof(rdbuf));
error = regmap_bulk_read(tsdata->regmap, tsdata->tdata_cmd, rdbuf,
tsdata->tdata_len);
+ if (tsdata->version == EDT_M06) {
+ num_points = tsdata->max_support_points;
+ } else {
+ /* Register 2 is TD_STATUS, containing the number of touch
+ * points.
+ */
+ num_points = min(rdbuf[2] & 0xf, tsdata->max_support_points);
+
+ /* When polling FT5x06 without IRQ: initial register contents
+ * could be stale or undefined; discard all readings until
+ * TD_STATUS changes for the first time (or num_points is 0).
+ */
+ if (tsdata->init_td_status) {
+ if (tsdata->init_td_status < 0)
+ tsdata->init_td_status = rdbuf[2];
+
+ if (num_points && rdbuf[2] == tsdata->init_td_status)
+ goto out;
+
+ tsdata->init_td_status = 0;
+ }
+
+ if (!error && num_points)
+ error = regmap_bulk_read(tsdata->regmap,
+ tsdata->tdata_offset,
+ &rdbuf[tsdata->tdata_offset],
+ tsdata->point_len * num_points);
+ }
if (error) {
dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
error);
goto out;
}
- for (i = 0; i < tsdata->max_support_points; i++) {
+ for (i = 0; i < num_points; i++) {
u8 *buf = &rdbuf[i * tsdata->point_len + tsdata->tdata_offset];
type = buf[0] >> 6;
@@ -334,11 +376,26 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
input_mt_slot(tsdata->input, id);
if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER,
- type != TOUCH_EVENT_UP))
+ type != TOUCH_EVENT_UP)) {
touchscreen_report_pos(tsdata->input, &tsdata->prop,
x, y, true);
+ active_ids |= BIT(id);
+ } else {
+ known_ids &= ~BIT(id);
+ }
}
+ /* One issue with the device is the TOUCH_UP message is not always
+ * returned. Instead track which ids we know about and report when they
+ * are no longer updated
+ */
+ released_ids = known_ids & ~active_ids;
+ for_each_set_bit_from(b, &released_ids, tsdata->max_support_points) {
+ input_mt_slot(tsdata->input, b);
+ input_mt_report_slot_inactive(tsdata->input);
+ }
+ tsdata->known_ids = active_ids;
+
input_mt_report_pointer_emulation(tsdata->input, true);
input_sync(tsdata->input);
@@ -346,6 +403,22 @@ out:
return IRQ_HANDLED;
}
+static void edt_ft5x06_ts_irq_poll_timer(struct timer_list *t)
+{
+ struct edt_ft5x06_ts_data *tsdata = from_timer(tsdata, t, timer);
+
+ schedule_work(&tsdata->work_i2c_poll);
+ mod_timer(&tsdata->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS));
+}
+
+static void edt_ft5x06_ts_work_i2c_poll(struct work_struct *work)
+{
+ struct edt_ft5x06_ts_data *tsdata = container_of(work,
+ struct edt_ft5x06_ts_data, work_i2c_poll);
+
+ edt_ft5x06_ts_isr(0, tsdata);
+}
+
struct edt_ft5x06_attribute {
struct device_attribute dattr;
size_t field_offset;
@@ -858,6 +931,9 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
char *model_name = tsdata->name;
char *fw_version = tsdata->fw_version;
+ snprintf(model_name, EDT_NAME_PREFIX_LEN + 1, "%s ", dev_name(&client->dev));
+ model_name += strlen(model_name);
+
/* see what we find if we assume it is a M06 *
* if we get less than EDT_NAME_LEN, we don't want
* to have garbage in there
@@ -1046,20 +1122,23 @@ static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
static void edt_ft5x06_ts_set_tdata_parameters(struct edt_ft5x06_ts_data *tsdata)
{
int crclen;
+ int points;
if (tsdata->version == EDT_M06) {
tsdata->tdata_cmd = 0xf9;
tsdata->tdata_offset = 5;
tsdata->point_len = 4;
crclen = 1;
+ points = tsdata->max_support_points;
} else {
tsdata->tdata_cmd = 0x0;
tsdata->tdata_offset = 3;
tsdata->point_len = 6;
crclen = 0;
+ points = 0;
}
- tsdata->tdata_len = tsdata->point_len * tsdata->max_support_points +
+ tsdata->tdata_len = tsdata->point_len * points +
tsdata->tdata_offset + crclen;
}
@@ -1254,7 +1333,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
if (tsdata->reset_gpio) {
usleep_range(5000, 6000);
gpiod_set_value_cansleep(tsdata->reset_gpio, 0);
- msleep(300);
+ msleep(RESET_DELAY_MS);
}
input = devm_input_allocate_device(&client->dev);
@@ -1328,17 +1407,28 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
return error;
}
- irq_flags = irq_get_trigger_type(client->irq);
- if (irq_flags == IRQF_TRIGGER_NONE)
- irq_flags = IRQF_TRIGGER_FALLING;
- irq_flags |= IRQF_ONESHOT;
+ if (client->irq) {
+ irq_flags = irq_get_trigger_type(client->irq);
+ if (irq_flags == IRQF_TRIGGER_NONE)
+ irq_flags = IRQF_TRIGGER_FALLING;
+ irq_flags |= IRQF_ONESHOT;
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, edt_ft5x06_ts_isr, irq_flags,
- client->name, tsdata);
- if (error) {
- dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
- return error;
+ error = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, edt_ft5x06_ts_isr,
+ irq_flags, client->name,
+ tsdata);
+ if (error) {
+ dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+ return error;
+ }
+ } else {
+ tsdata->init_td_status = -1; /* filter bogus initial data */
+ INIT_WORK(&tsdata->work_i2c_poll,
+ edt_ft5x06_ts_work_i2c_poll);
+ timer_setup(&tsdata->timer, edt_ft5x06_ts_irq_poll_timer, 0);
+ tsdata->timer.expires =
+ jiffies + msecs_to_jiffies(FIRST_POLL_DELAY_MS);
+ add_timer(&tsdata->timer);
}
error = input_register_device(input);
@@ -1360,6 +1450,10 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client)
{
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+ if (!client->irq) {
+ timer_delete(&tsdata->timer);
+ cancel_work_sync(&tsdata->work_i2c_poll);
+ }
edt_ft5x06_ts_teardown_debugfs(tsdata);
}
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index f8798d11ec03..eb8140a2ba25 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1142,7 +1142,10 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
return -ENOMEM;
}
- ts->input_dev->name = "Goodix Capacitive TouchScreen";
+ snprintf(ts->name, GOODIX_NAME_MAX_LEN, "%s Goodix Capacitive TouchScreen",
+ dev_name(&ts->client->dev));
+
+ ts->input_dev->name = ts->name;
ts->input_dev->phys = "input/ts";
ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0x0416;
@@ -1420,6 +1423,11 @@ static void goodix_ts_remove(struct i2c_client *client)
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
+ if (!client->irq) {
+ timer_delete(&ts->timer);
+ cancel_work_sync(&ts->work_i2c_poll);
+ }
+
if (ts->load_cfg_from_disk)
wait_for_completion(&ts->firmware_loading_complete);
}
diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
index 0d1e8a8d2cba..7338a3c246bb 100644
--- a/drivers/input/touchscreen/goodix.h
+++ b/drivers/input/touchscreen/goodix.h
@@ -57,6 +57,8 @@
#define GOODIX_CONFIG_MAX_LENGTH 240
#define GOODIX_MAX_KEYS 7
+#define GOODIX_NAME_MAX_LEN 38
+
enum goodix_irq_pin_access_method {
IRQ_PIN_ACCESS_NONE,
IRQ_PIN_ACCESS_GPIO,
@@ -90,6 +92,7 @@ struct goodix_ts_data {
int gpio_int_idx;
char id[GOODIX_ID_MAX_LEN + 1];
char cfg_name[64];
+ char name[GOODIX_NAME_MAX_LEN];
u16 version;
bool reset_controller_at_probe;
bool load_cfg_from_disk;
@@ -103,6 +106,8 @@ struct goodix_ts_data {
u8 main_clk[GOODIX_MAIN_CLK_LEN];
int bak_ref_len;
u8 *bak_ref;
+ struct timer_list timer;
+ struct work_struct work_i2c_poll;
};
int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
index fa38d70aded7..dd7191607dfd 100644
--- a/drivers/input/touchscreen/ili210x.c
+++ b/drivers/input/touchscreen/ili210x.c
@@ -67,6 +67,8 @@ struct ili210x {
u8 version_proto[2];
u8 ic_mode[2];
bool stop;
+ struct timer_list poll_timer;
+ struct work_struct poll_work;
};
static int ili210x_read_reg(struct i2c_client *client,
@@ -360,6 +362,34 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data)
return IRQ_HANDLED;
}
+static void ili210x_poll_work(struct work_struct *work)
+{
+ struct ili210x *priv = container_of(work, struct ili210x, poll_work);
+ struct i2c_client *client = priv->client;
+ const struct ili2xxx_chip *chip = priv->chip;
+ u8 touchdata[ILI210X_DATA_SIZE] = { 0 };
+ bool touch;
+ int error;
+
+ error = chip->get_touch_data(client, touchdata);
+ if (error) {
+ dev_err(&client->dev, "Unable to get touch data: %d\n", error);
+ return;
+ }
+
+ touch = ili210x_report_events(priv, touchdata);
+}
+
+static void ili210x_poll_timer_callback(struct timer_list *t)
+{
+ struct ili210x *priv = from_timer(priv, t, poll_timer);
+
+ schedule_work(&priv->poll_work);
+
+ if (!priv->stop)
+ mod_timer(&priv->poll_timer, jiffies + msecs_to_jiffies(ILI2XXX_POLL_PERIOD));
+}
+
static int ili251x_firmware_update_resolution(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -947,11 +977,6 @@ static int ili210x_i2c_probe(struct i2c_client *client)
return -ENODEV;
}
- if (client->irq <= 0) {
- dev_err(dev, "No IRQ!\n");
- return -EINVAL;
- }
-
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
@@ -1003,12 +1028,17 @@ static int ili210x_i2c_probe(struct i2c_client *client)
return error;
}
- error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq,
- IRQF_ONESHOT, client->name, priv);
- if (error) {
- dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
- error);
- return error;
+ if (client->irq) {
+ error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq,
+ IRQF_ONESHOT, client->name, priv);
+ if (error) {
+ dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", error);
+ return error;
+ }
+ } else {
+ timer_setup(&priv->poll_timer, ili210x_poll_timer_callback, 0);
+ mod_timer(&priv->poll_timer, jiffies + msecs_to_jiffies(ILI2XXX_POLL_PERIOD));
+ INIT_WORK(&priv->poll_work, ili210x_poll_work);
}
error = devm_add_action_or_reset(dev, ili210x_stop, priv);
@@ -1024,6 +1054,16 @@ static int ili210x_i2c_probe(struct i2c_client *client)
return 0;
}
+static void ili210x_i2c_remove(struct i2c_client *client)
+{
+ struct ili210x *tsdata = i2c_get_clientdata(client);
+
+ if (!client->irq) {
+ timer_delete(&tsdata->poll_timer);
+ cancel_work_sync(&tsdata->poll_work);
+ }
+}
+
static const struct i2c_device_id ili210x_i2c_id[] = {
{ "ili210x", (long)&ili210x_chip },
{ "ili2117", (long)&ili211x_chip },
@@ -1050,6 +1090,7 @@ static struct i2c_driver ili210x_ts_driver = {
},
.id_table = ili210x_i2c_id,
.probe = ili210x_i2c_probe,
+ .remove = ili210x_i2c_remove,
};
module_i2c_driver(ili210x_ts_driver);