diff options
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/joystick/sensehat-joystick.c | 2 | ||||
| -rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 124 | ||||
| -rw-r--r-- | drivers/input/touchscreen/goodix.c | 10 | ||||
| -rw-r--r-- | drivers/input/touchscreen/goodix.h | 5 | ||||
| -rw-r--r-- | drivers/input/touchscreen/ili210x.c | 63 |
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); |
