diff options
Diffstat (limited to 'drivers/input/touchscreen')
31 files changed, 1147 insertions, 1351 deletions
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 1d1bbc8da949..81a3ea4b9a3d 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -185,10 +185,8 @@ static int pm860x_touch_probe(struct platform_device *pdev) int irq, ret, res_x = 0, data = 0; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "No IRQ resource!\n"); + if (irq < 0) return -EINVAL; - } if (pm860x_touch_dt_init(pdev, chip, &res_x)) { if (pdata) { diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index fb91f2d4049e..c071f7c407b6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -633,7 +633,7 @@ config TOUCHSCREEN_HP600 depends on SH_HP6XX && SH_ADC help Say Y here if you have a HP Jornada 620/660/680/690 and want to - support the built-in touchscreen. + support the built-in touchscreen. To compile this driver as a module, choose M here: the module will be called hp680_ts_input. @@ -700,7 +700,6 @@ config TOUCHSCREEN_EDT_FT5X06 config TOUCHSCREEN_RASPBERRYPI_FW tristate "Raspberry Pi's firmware base touch screen support" depends on RASPBERRYPI_FIRMWARE || (RASPBERRYPI_FIRMWARE=n && COMPILE_TEST) - select INPUT_POLLDEV help Say Y here if you have the official Raspberry Pi 7 inch screen on your system. @@ -1038,7 +1037,6 @@ config TOUCHSCREEN_TS4800 depends on HAS_IOMEM && OF depends on SOC_IMX51 || COMPILE_TEST select MFD_SYSCON - select INPUT_POLLDEV help Say Y here if you have a touchscreen on a TS-4800 board. @@ -1112,15 +1110,6 @@ config TOUCHSCREEN_TSC2007_IIO or ambient light monitoring), temperature and raw input values. -config TOUCHSCREEN_W90X900 - tristate "W90P910 touchscreen driver" - depends on ARCH_W90X900 - help - Say Y here if you have a W90P910 based touchscreen. - - To compile this driver as a module, choose M here: the - module will be called w90p910_ts. - config TOUCHSCREEN_PCAP tristate "Motorola PCAP touchscreen" depends on EZX_PCAP @@ -1219,7 +1208,6 @@ config TOUCHSCREEN_SUR40 tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" depends on USB && MEDIA_USB_SUPPORT && HAS_DMA depends on VIDEO_V4L2 - select INPUT_POLLDEV select VIDEOBUF2_DMA_SG help Say Y here if you want support for the Samsung SUR40 touchscreen @@ -1255,7 +1243,6 @@ config TOUCHSCREEN_SX8654 config TOUCHSCREEN_TPS6507X tristate "TPS6507x based touchscreens" depends on I2C - select INPUT_POLLDEV help Say Y here if you have a TPS6507x based touchscreen controller. diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 084a596a0c8b..94c6162409b3 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -102,7 +102,6 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o -obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_ZET6223) += zet6223.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index accbbe8d2966..8fd7fc39c4fd 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -20,6 +20,7 @@ #include <linux/sched.h> #include <linux/delay.h> #include <linux/input.h> +#include <linux/input/touchscreen.h> #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/pm.h> @@ -129,6 +130,8 @@ struct ads7846 { u16 penirq_recheck_delay_usecs; + struct touchscreen_properties core_prop; + struct mutex lock; bool stopped; /* P: lock */ bool disabled; /* P: lock */ @@ -330,7 +333,8 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) req->xfer[1].len = 2; /* for 1uF, settle for 800 usec; no cap, 100 usec. */ - req->xfer[1].delay_usecs = ts->vref_delay_usecs; + req->xfer[1].delay.value = ts->vref_delay_usecs; + req->xfer[1].delay.unit = SPI_DELAY_UNIT_USECS; spi_message_add_tail(&req->xfer[1], &req->msg); /* Enable reference voltage */ @@ -823,17 +827,13 @@ static void ads7846_report_state(struct ads7846 *ts) if (Rt) { struct input_dev *input = ts->input; - if (ts->swap_xy) - swap(x, y); - if (!ts->pendown) { input_report_key(input, BTN_TOUCH, 1); ts->pendown = true; dev_vdbg(&ts->spi->dev, "DOWN\n"); } - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); + touchscreen_report_pos(input, &ts->core_prop, x, y, false); input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt); input_sync(input); @@ -1019,7 +1019,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, * have had enough time to stabilize. */ if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + x->delay.value = pdata->settle_delay_usecs; + x->delay.unit = SPI_DELAY_UNIT_USECS; x++; x->tx_buf = &packet->read_y; @@ -1062,7 +1063,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, /* ... maybe discard first sample ... */ if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + x->delay.value = pdata->settle_delay_usecs; + x->delay.unit = SPI_DELAY_UNIT_USECS; x++; x->tx_buf = &packet->read_x; @@ -1095,7 +1097,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, /* ... maybe discard first sample ... */ if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + x->delay.value = pdata->settle_delay_usecs; + x->delay.unit = SPI_DELAY_UNIT_USECS; x++; x->tx_buf = &packet->read_z1; @@ -1126,7 +1129,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, /* ... maybe discard first sample ... */ if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + x->delay.value = pdata->settle_delay_usecs; + x->delay.unit = SPI_DELAY_UNIT_USECS; x++; x->tx_buf = &packet->read_z2; @@ -1185,6 +1189,7 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) struct ads7846_platform_data *pdata; struct device_node *node = dev->of_node; const struct of_device_id *match; + u32 value; if (!node) { dev_err(dev, "Device does not have associated DT data\n"); @@ -1223,10 +1228,18 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) of_property_read_u16(node, "ti,x-max", &pdata->x_max); of_property_read_u16(node, "ti,y-max", &pdata->y_max); + /* + * touchscreen-max-pressure gets parsed during + * touchscreen_parse_properties() + */ of_property_read_u16(node, "ti,pressure-min", &pdata->pressure_min); + if (!of_property_read_u32(node, "touchscreen-min-pressure", &value)) + pdata->pressure_min = (u16) value; of_property_read_u16(node, "ti,pressure-max", &pdata->pressure_max); of_property_read_u16(node, "ti,debounce-max", &pdata->debounce_max); + if (!of_property_read_u32(node, "touchscreen-average-samples", &value)) + pdata->debounce_max = (u16) value; of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol); of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep); @@ -1309,10 +1322,7 @@ static int ads7846_probe(struct spi_device *spi) ts->model = pdata->model ? : 7846; ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; - ts->pressure_max = pdata->pressure_max ? : ~0; - ts->vref_mv = pdata->vref_mv; - ts->swap_xy = pdata->swap_xy; if (pdata->filter != NULL) { if (pdata->filter_init != NULL) { @@ -1364,6 +1374,23 @@ static int ads7846_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_PRESSURE, pdata->pressure_min, pdata->pressure_max, 0, 0); + /* + * Parse common framework properties. Must be done here to ensure the + * correct behaviour in case of using the legacy vendor bindings. The + * general binding value overrides the vendor specific one. + */ + touchscreen_parse_properties(ts->input, false, &ts->core_prop); + ts->pressure_max = input_abs_get_max(input_dev, ABS_PRESSURE) ? : ~0; + + /* + * Check if legacy ti,swap-xy binding is used instead of + * touchscreen-swapped-x-y + */ + if (!ts->core_prop.swap_x_y && pdata->swap_xy) { + swap(input_dev->absinfo[ABS_X], input_dev->absinfo[ABS_Y]); + ts->core_prop.swap_x_y = true; + } + ads7846_setup_spi_msg(ts, pdata); ts->reg = regulator_get(&spi->dev, "vcc"); diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 28644f372bd8..c0d5c2413356 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -13,7 +13,7 @@ #include <linux/irq.h> #include <linux/interrupt.h> -#define AR1021_TOCUH_PKG_SIZE 5 +#define AR1021_TOUCH_PKG_SIZE 5 #define AR1021_MAX_X 4095 #define AR1021_MAX_Y 4095 @@ -25,7 +25,7 @@ struct ar1021_i2c { struct i2c_client *client; struct input_dev *input; - u8 data[AR1021_TOCUH_PKG_SIZE]; + u8 data[AR1021_TOUCH_PKG_SIZE]; }; static irqreturn_t ar1021_i2c_irq(int irq, void *dev_id) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 4a5f482cf1af..ae60442efda0 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2990,8 +2990,7 @@ static int mxt_parse_device_properties(struct mxt_data *data) int error; if (device_property_present(dev, keymap_property)) { - n_keys = device_property_read_u32_array(dev, keymap_property, - NULL, 0); + n_keys = device_property_count_u32(dev, keymap_property); if (n_keys <= 0) { error = n_keys < 0 ? n_keys : -EINVAL; dev_err(dev, "invalid/malformed '%s' property: %d\n", @@ -3157,6 +3156,8 @@ static int __maybe_unused mxt_suspend(struct device *dev) mutex_unlock(&input_dev->mutex); + disable_irq(data->irq); + return 0; } @@ -3169,6 +3170,8 @@ static int __maybe_unused mxt_resume(struct device *dev) if (!input_dev) return 0; + enable_irq(data->irq); + mutex_lock(&input_dev->mutex); if (input_dev->users) diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c index 4d11b27c7c43..7de1fd24ce36 100644 --- a/drivers/input/touchscreen/bcm_iproc_tsc.c +++ b/drivers/input/touchscreen/bcm_iproc_tsc.c @@ -489,10 +489,8 @@ static int iproc_ts_probe(struct platform_device *pdev) /* get interrupt */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "platform_get_irq failed: %d\n", irq); + if (irq < 0) return irq; - } error = devm_request_irq(&pdev->dev, irq, iproc_touchscreen_interrupt, diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index 1d703e230ac3..2f1f0d7607f8 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -4,21 +4,21 @@ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson */ -#include <linux/kernel.h> +#include <linux/bitops.h> #include <linux/delay.h> -#include <linux/interrupt.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> -#include <linux/workqueue.h> #include <linux/input.h> -#include <linux/input/bu21013.h> -#include <linux/slab.h> -#include <linux/regulator/consumer.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> #include <linux/module.h> -#include <linux/gpio.h> -#include <linux/of.h> -#include <linux/of_gpio.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/types.h> -#define PEN_DOWN_INTR 0 #define MAX_FINGERS 2 #define RESET_DELAY 30 #define PENUP_TIMEOUT (10) @@ -137,69 +137,63 @@ #define DRIVER_TP "bu21013_tp" /** - * struct bu21013_ts_data - touch panel data structure + * struct bu21013_ts - touch panel data structure * @client: pointer to the i2c client - * @wait: variable to wait_queue_head_t structure - * @touch_stopped: touch stop flag - * @chip: pointer to the touch panel controller * @in_dev: pointer to the input device structure - * @intr_pin: interrupt pin value + * @props: the device coordinate transformation properties * @regulator: pointer to the Regulator used for touch screen + * @cs_gpiod: chip select GPIO line + * @int_gpiod: touch interrupt GPIO line + * @touch_x_max: maximum X coordinate reported by the device + * @touch_y_max: maximum Y coordinate reported by the device + * @x_flip: indicates that the driver should invert X coordinate before + * reporting + * @y_flip: indicates that the driver should invert Y coordinate before + * reporting + * @touch_stopped: touch stop flag * * Touch panel device data structure */ -struct bu21013_ts_data { +struct bu21013_ts { struct i2c_client *client; - wait_queue_head_t wait; - const struct bu21013_platform_device *chip; struct input_dev *in_dev; + struct touchscreen_properties props; struct regulator *regulator; - unsigned int irq; - unsigned int intr_pin; + struct gpio_desc *cs_gpiod; + struct gpio_desc *int_gpiod; + u32 touch_x_max; + u32 touch_y_max; + bool x_flip; + bool y_flip; bool touch_stopped; }; -/** - * bu21013_read_block_data(): read the touch co-ordinates - * @data: bu21013_ts_data structure pointer - * @buf: byte pointer - * - * Read the touch co-ordinates using i2c read block into buffer - * and returns integer. - */ -static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf) +static int bu21013_read_block_data(struct bu21013_ts *ts, u8 *buf) { int ret, i; for (i = 0; i < I2C_RETRY_COUNT; i++) { - ret = i2c_smbus_read_i2c_block_data - (data->client, BU21013_SENSORS_BTN_0_7_REG, - LENGTH_OF_BUFFER, buf); + ret = i2c_smbus_read_i2c_block_data(ts->client, + BU21013_SENSORS_BTN_0_7_REG, + LENGTH_OF_BUFFER, buf); if (ret == LENGTH_OF_BUFFER) return 0; } + return -EINVAL; } -/** - * bu21013_do_touch_report(): Get the touch co-ordinates - * @data: bu21013_ts_data structure pointer - * - * Get the touch co-ordinates from touch sensor registers and writes - * into device structure and returns integer. - */ -static int bu21013_do_touch_report(struct bu21013_ts_data *data) +static int bu21013_do_touch_report(struct bu21013_ts *ts) { - u8 buf[LENGTH_OF_BUFFER]; - unsigned int pos_x[2], pos_y[2]; - bool has_x_sensors, has_y_sensors; - int finger_down_count = 0; - int i; - - if (data == NULL) - return -EINVAL; - - if (bu21013_read_block_data(data, buf) < 0) + struct input_dev *input = ts->in_dev; + struct input_mt_pos pos[MAX_FINGERS]; + int slots[MAX_FINGERS]; + u8 buf[LENGTH_OF_BUFFER]; + bool has_x_sensors, has_y_sensors; + int finger_down_count = 0; + int i; + + if (bu21013_read_block_data(ts, buf) < 0) return -EINVAL; has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7); @@ -209,501 +203,411 @@ static int bu21013_do_touch_report(struct bu21013_ts_data *data) return 0; for (i = 0; i < MAX_FINGERS; i++) { - const u8 *p = &buf[4 * i + 3]; - unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS); - unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS); - if (x == 0 || y == 0) - continue; - pos_x[finger_down_count] = x; - pos_y[finger_down_count] = y; - finger_down_count++; - } - - if (finger_down_count) { - if (finger_down_count == 2 && - (abs(pos_x[0] - pos_x[1]) < DELTA_MIN || - abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) { - return 0; - } + const u8 *data = &buf[4 * i + 3]; + unsigned int x, y; + + x = data[0] << SHIFT_2 | (data[1] & MASK_BITS); + y = data[2] << SHIFT_2 | (data[3] & MASK_BITS); + if (x != 0 && y != 0) + touchscreen_set_mt_pos(&pos[finger_down_count++], + &ts->props, x, y); + } - for (i = 0; i < finger_down_count; i++) { - if (data->chip->x_flip) - pos_x[i] = data->chip->touch_x_max - pos_x[i]; - if (data->chip->y_flip) - pos_y[i] = data->chip->touch_y_max - pos_y[i]; - - input_report_abs(data->in_dev, - ABS_MT_POSITION_X, pos_x[i]); - input_report_abs(data->in_dev, - ABS_MT_POSITION_Y, pos_y[i]); - input_mt_sync(data->in_dev); - } - } else - input_mt_sync(data->in_dev); + if (finger_down_count == 2 && + (abs(pos[0].x - pos[1].x) < DELTA_MIN || + abs(pos[0].y - pos[1].y) < DELTA_MIN)) { + return 0; + } + + input_mt_assign_slots(input, slots, pos, finger_down_count, DELTA_MIN); + for (i = 0; i < finger_down_count; i++) { + input_mt_slot(input, slots[i]); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + input_report_abs(input, ABS_MT_POSITION_X, pos[i].x); + input_report_abs(input, ABS_MT_POSITION_Y, pos[i].y); + } - input_sync(data->in_dev); + input_mt_sync_frame(input); + input_sync(input); return 0; } -/** - * bu21013_gpio_irq() - gpio thread function for touch interrupt - * @irq: irq value - * @device_data: void pointer - * - * This gpio thread function for touch interrupt - * and returns irqreturn_t. - */ + static irqreturn_t bu21013_gpio_irq(int irq, void *device_data) { - struct bu21013_ts_data *data = device_data; - struct i2c_client *i2c = data->client; - int retval; + struct bu21013_ts *ts = device_data; + int keep_polling; + int error; do { - retval = bu21013_do_touch_report(data); - if (retval < 0) { - dev_err(&i2c->dev, "bu21013_do_touch_report failed\n"); - return IRQ_NONE; + error = bu21013_do_touch_report(ts); + if (error) { + dev_err(&ts->client->dev, "%s failed\n", __func__); + break; } - data->intr_pin = gpio_get_value(data->chip->touch_pin); - if (data->intr_pin == PEN_DOWN_INTR) - wait_event_timeout(data->wait, data->touch_stopped, - msecs_to_jiffies(2)); - } while (!data->intr_pin && !data->touch_stopped); + if (unlikely(ts->touch_stopped)) + break; + + keep_polling = ts->int_gpiod ? + gpiod_get_value(ts->int_gpiod) : false; + if (keep_polling) + usleep_range(2000, 2500); + } while (keep_polling); return IRQ_HANDLED; } -/** - * bu21013_init_chip() - power on sequence for the bu21013 controller - * @data: device structure pointer - * - * This function is used to power on - * the bu21013 controller and returns integer. - */ -static int bu21013_init_chip(struct bu21013_ts_data *data) +static int bu21013_init_chip(struct bu21013_ts *ts) { - int retval; - struct i2c_client *i2c = data->client; + struct i2c_client *client = ts->client; + int error; - retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG, - BU21013_RESET_ENABLE); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_RESET reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_RESET_REG, + BU21013_RESET_ENABLE); + if (error) { + dev_err(&client->dev, "BU21013_RESET reg write failed\n"); + return error; } msleep(RESET_DELAY); - retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG, - BU21013_SENSORS_EN_0_7); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_0_7_REG, + BU21013_SENSORS_EN_0_7); + if (error) { + dev_err(&client->dev, "BU21013_SENSOR_0_7 reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG, - BU21013_SENSORS_EN_8_15); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_8_15_REG, + BU21013_SENSORS_EN_8_15); + if (error) { + dev_err(&client->dev, "BU21013_SENSOR_8_15 reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG, - BU21013_SENSORS_EN_16_23); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_16_23_REG, + BU21013_SENSORS_EN_16_23); + if (error) { + dev_err(&client->dev, "BU21013_SENSOR_16_23 reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG, - (BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1)); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_POS_MODE1_REG, + BU21013_POS_MODE1_0 | + BU21013_POS_MODE1_1); + if (error) { + dev_err(&client->dev, "BU21013_POS_MODE1 reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG, - (BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 | - BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW | - BU21013_POS_MODE2_MULTI)); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_POS_MODE2_REG, + BU21013_POS_MODE2_ZERO | + BU21013_POS_MODE2_AVG1 | + BU21013_POS_MODE2_AVG2 | + BU21013_POS_MODE2_EN_RAW | + BU21013_POS_MODE2_MULTI); + if (error) { + dev_err(&client->dev, "BU21013_POS_MODE2 reg write failed\n"); + return error; } - if (data->chip->ext_clk) - retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG, - (BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB)); - else - retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG, - (BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB)); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_CLK_MODE_REG, + BU21013_CLK_MODE_DIV | + BU21013_CLK_MODE_CALIB); + if (error) { + dev_err(&client->dev, "BU21013_CLK_MODE reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG, - (BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN)); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_IDLE_REG, + BU21013_IDLET_0 | + BU21013_IDLE_INTERMIT_EN); + if (error) { + dev_err(&client->dev, "BU21013_IDLE reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG, - BU21013_INT_MODE_LEVEL); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_INT_MODE_REG, + BU21013_INT_MODE_LEVEL); + if (error) { + dev_err(&client->dev, "BU21013_INT_MODE reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG, - (BU21013_DELTA_0_6 | - BU21013_FILTER_EN)); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_FILTER_REG, + BU21013_DELTA_0_6 | + BU21013_FILTER_EN); + if (error) { + dev_err(&client->dev, "BU21013_FILTER reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG, - BU21013_TH_ON_5); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_TH_ON_REG, + BU21013_TH_ON_5); + if (error) { + dev_err(&client->dev, "BU21013_TH_ON reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG, - BU21013_TH_OFF_4 | BU21013_TH_OFF_3); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_TH_OFF_REG, + BU21013_TH_OFF_4 | BU21013_TH_OFF_3); + if (error) { + dev_err(&client->dev, "BU21013_TH_OFF reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG, - (BU21013_GAIN_0 | BU21013_GAIN_1)); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_GAIN_REG, + BU21013_GAIN_0 | BU21013_GAIN_1); + if (error) { + dev_err(&client->dev, "BU21013_GAIN reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG, - BU21013_OFFSET_MODE_DEFAULT); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_OFFSET_MODE_REG, + BU21013_OFFSET_MODE_DEFAULT); + if (error) { + dev_err(&client->dev, "BU21013_OFFSET_MODE reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG, - (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 | - BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3)); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_XY_EDGE_REG, + BU21013_X_EDGE_0 | + BU21013_X_EDGE_2 | + BU21013_Y_EDGE_1 | + BU21013_Y_EDGE_3); + if (error) { + dev_err(&client->dev, "BU21013_XY_EDGE reg write failed\n"); + return error; } - retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG, - BU21013_DONE); - if (retval < 0) { - dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n"); - return retval; + error = i2c_smbus_write_byte_data(client, BU21013_DONE_REG, + BU21013_DONE); + if (error) { + dev_err(&client->dev, "BU21013_REG_DONE reg write failed\n"); + return error; } return 0; } -/** - * bu21013_free_irq() - frees IRQ registered for touchscreen - * @bu21013_data: device structure pointer - * - * This function signals interrupt thread to stop processing and - * frees interrupt. - */ -static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data) -{ - bu21013_data->touch_stopped = true; - wake_up(&bu21013_data->wait); - free_irq(bu21013_data->irq, bu21013_data); -} - -/** - * bu21013_cs_disable() - deconfigures the touch panel controller - * @bu21013_data: device structure pointer - * - * This function is used to deconfigure the chip selection - * for touch panel controller. - */ -static void bu21013_cs_disable(struct bu21013_ts_data *bu21013_data) +static void bu21013_power_off(void *_ts) { - int error; + struct bu21013_ts *ts = _ts; - error = gpio_direction_output(bu21013_data->chip->cs_pin, 0); - if (error < 0) - dev_warn(&bu21013_data->client->dev, - "%s: gpio direction failed, error: %d\n", - __func__, error); - else - gpio_set_value(bu21013_data->chip->cs_pin, 0); - - gpio_free(bu21013_data->chip->cs_pin); + regulator_disable(ts->regulator); } -#ifdef CONFIG_OF -static const struct bu21013_platform_device * -bu21013_parse_dt(struct device *dev) +static void bu21013_disable_chip(void *_ts) { - struct device_node *np = dev->of_node; - struct bu21013_platform_device *pdata; + struct bu21013_ts *ts = _ts; - if (!np) { - dev_err(dev, "no device tree or platform data\n"); - return ERR_PTR(-EINVAL); - } - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return ERR_PTR(-ENOMEM); - - pdata->y_flip = pdata->x_flip = false; - - pdata->x_flip = of_property_read_bool(np, "rohm,flip-x"); - pdata->y_flip = of_property_read_bool(np, "rohm,flip-y"); - - of_property_read_u32(np, "rohm,touch-max-x", &pdata->touch_x_max); - of_property_read_u32(np, "rohm,touch-max-y", &pdata->touch_y_max); - - pdata->touch_pin = of_get_named_gpio(np, "touch-gpio", 0); - pdata->cs_pin = of_get_named_gpio(np, "reset-gpio", 0); - - pdata->ext_clk = false; - - return pdata; -} -#else -static inline const struct bu21013_platform_device * -bu21013_parse_dt(struct device *dev) -{ - dev_err(dev, "no platform data available\n"); - return ERR_PTR(-EINVAL); + gpiod_set_value(ts->cs_gpiod, 0); } -#endif -/** - * bu21013_probe() - initializes the i2c-client touchscreen driver - * @client: i2c client structure pointer - * @id: i2c device id pointer - * - * This function used to initializes the i2c-client touchscreen - * driver and returns integer. - */ static int bu21013_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct bu21013_platform_device *pdata = - dev_get_platdata(&client->dev); - struct bu21013_ts_data *bu21013_data; + struct bu21013_ts *ts; struct input_dev *in_dev; + struct input_absinfo *info; + u32 max_x = 0, max_y = 0; int error; if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { + I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&client->dev, "i2c smbus byte data not supported\n"); return -EIO; } - if (!pdata) { - pdata = bu21013_parse_dt(&client->dev); - if (IS_ERR(pdata)) - return PTR_ERR(pdata); - } - - if (!gpio_is_valid(pdata->touch_pin)) { - dev_err(&client->dev, "invalid touch_pin supplied\n"); + if (!client->irq) { + dev_err(&client->dev, "No IRQ set up\n"); return -EINVAL; } - bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL); - in_dev = input_allocate_device(); - if (!bu21013_data || !in_dev) { + ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + ts->client = client; + + ts->x_flip = device_property_read_bool(&client->dev, "rohm,flip-x"); + ts->y_flip = device_property_read_bool(&client->dev, "rohm,flip-y"); + + in_dev = devm_input_allocate_device(&client->dev); + if (!in_dev) { dev_err(&client->dev, "device memory alloc failed\n"); - error = -ENOMEM; - goto err_free_mem; + return -ENOMEM; } + ts->in_dev = in_dev; + input_set_drvdata(in_dev, ts); - bu21013_data->in_dev = in_dev; - bu21013_data->chip = pdata; - bu21013_data->client = client; - bu21013_data->irq = gpio_to_irq(pdata->touch_pin); + /* register the device to input subsystem */ + in_dev->name = DRIVER_TP; + in_dev->id.bustype = BUS_I2C; + + device_property_read_u32(&client->dev, "rohm,touch-max-x", &max_x); + device_property_read_u32(&client->dev, "rohm,touch-max-y", &max_y); + + input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0); + input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0); + + touchscreen_parse_properties(in_dev, true, &ts->props); + + /* Adjust for the legacy "flip" properties, if present */ + if (!ts->props.invert_x && + device_property_read_bool(&client->dev, "rohm,flip-x")) { + info = &in_dev->absinfo[ABS_MT_POSITION_X]; + info->maximum -= info->minimum; + info->minimum = 0; + } - bu21013_data->regulator = regulator_get(&client->dev, "avdd"); - if (IS_ERR(bu21013_data->regulator)) { + if (!ts->props.invert_y && + device_property_read_bool(&client->dev, "rohm,flip-y")) { + info = &in_dev->absinfo[ABS_MT_POSITION_Y]; + info->maximum -= info->minimum; + info->minimum = 0; + } + + error = input_mt_init_slots(in_dev, MAX_FINGERS, + INPUT_MT_DIRECT | INPUT_MT_TRACK | + INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(&client->dev, "failed to initialize MT slots"); + return error; + } + + ts->regulator = devm_regulator_get(&client->dev, "avdd"); + if (IS_ERR(ts->regulator)) { dev_err(&client->dev, "regulator_get failed\n"); - error = PTR_ERR(bu21013_data->regulator); - goto err_free_mem; + return PTR_ERR(ts->regulator); } - error = regulator_enable(bu21013_data->regulator); - if (error < 0) { + error = regulator_enable(ts->regulator); + if (error) { dev_err(&client->dev, "regulator enable failed\n"); - goto err_put_regulator; + return error; } - bu21013_data->touch_stopped = false; - init_waitqueue_head(&bu21013_data->wait); + error = devm_add_action_or_reset(&client->dev, bu21013_power_off, ts); + if (error) { + dev_err(&client->dev, "failed to install power off handler\n"); + return error; + } - /* configure the gpio pins */ - error = gpio_request_one(pdata->cs_pin, GPIOF_OUT_INIT_HIGH, - "touchp_reset"); - if (error < 0) { - dev_err(&client->dev, "Unable to request gpio reset_pin\n"); - goto err_disable_regulator; + /* Named "CS" on the chip, DT binding is "reset" */ + ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); + error = PTR_ERR_OR_ZERO(ts->cs_gpiod); + if (error) { + if (error != -EPROBE_DEFER) + dev_err(&client->dev, "failed to get CS GPIO\n"); + return error; + } + gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS"); + + error = devm_add_action_or_reset(&client->dev, + bu21013_disable_chip, ts); + if (error) { + dev_err(&client->dev, + "failed to install chip disable handler\n"); + return error; } + /* Named "INT" on the chip, DT binding is "touch" */ + ts->int_gpiod = devm_gpiod_get_optional(&client->dev, + "touch", GPIOD_IN); + error = PTR_ERR_OR_ZERO(ts->int_gpiod); + if (error) { + if (error != -EPROBE_DEFER) + dev_err(&client->dev, "failed to get INT GPIO\n"); + return error; + } + + if (ts->int_gpiod) + gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT"); + /* configure the touch panel controller */ - error = bu21013_init_chip(bu21013_data); + error = bu21013_init_chip(ts); if (error) { dev_err(&client->dev, "error in bu21013 config\n"); - goto err_cs_disable; + return error; } - /* register the device to input subsystem */ - in_dev->name = DRIVER_TP; - in_dev->id.bustype = BUS_I2C; - in_dev->dev.parent = &client->dev; - - __set_bit(EV_SYN, in_dev->evbit); - __set_bit(EV_KEY, in_dev->evbit); - __set_bit(EV_ABS, in_dev->evbit); - - input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, - pdata->touch_x_max, 0, 0); - input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, - pdata->touch_y_max, 0, 0); - input_set_drvdata(in_dev, bu21013_data); - - error = request_threaded_irq(bu21013_data->irq, NULL, bu21013_gpio_irq, - IRQF_TRIGGER_FALLING | IRQF_SHARED | - IRQF_ONESHOT, - DRIVER_TP, bu21013_data); + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, bu21013_gpio_irq, + IRQF_ONESHOT, DRIVER_TP, ts); if (error) { dev_err(&client->dev, "request irq %d failed\n", - bu21013_data->irq); - goto err_cs_disable; + client->irq); + return error; } error = input_register_device(in_dev); if (error) { dev_err(&client->dev, "failed to register input device\n"); - goto err_free_irq; + return error; } - device_init_wakeup(&client->dev, pdata->wakeup); - i2c_set_clientdata(client, bu21013_data); + i2c_set_clientdata(client, ts); return 0; - -err_free_irq: - bu21013_free_irq(bu21013_data); -err_cs_disable: - bu21013_cs_disable(bu21013_data); -err_disable_regulator: - regulator_disable(bu21013_data->regulator); -err_put_regulator: - regulator_put(bu21013_data->regulator); -err_free_mem: - input_free_device(in_dev); - kfree(bu21013_data); - - return error; } -/** - * bu21013_remove() - removes the i2c-client touchscreen driver - * @client: i2c client structure pointer - * - * This function uses to remove the i2c-client - * touchscreen driver and returns integer. - */ + static int bu21013_remove(struct i2c_client *client) { - struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client); + struct bu21013_ts *ts = i2c_get_clientdata(client); - bu21013_free_irq(bu21013_data); - - bu21013_cs_disable(bu21013_data); - - input_unregister_device(bu21013_data->in_dev); - - regulator_disable(bu21013_data->regulator); - regulator_put(bu21013_data->regulator); - - kfree(bu21013_data); + /* Make sure IRQ will exit quickly even if there is contact */ + ts->touch_stopped = true; + /* The resources will be freed by devm */ return 0; } -#ifdef CONFIG_PM -/** - * bu21013_suspend() - suspend the touch screen controller - * @dev: pointer to device structure - * - * This function is used to suspend the - * touch panel controller and returns integer - */ -static int bu21013_suspend(struct device *dev) +static int __maybe_unused bu21013_suspend(struct device *dev) { - struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev); - struct i2c_client *client = bu21013_data->client; + struct i2c_client *client = to_i2c_client(dev); + struct bu21013_ts *ts = i2c_get_clientdata(client); - bu21013_data->touch_stopped = true; - if (device_may_wakeup(&client->dev)) - enable_irq_wake(bu21013_data->irq); - else - disable_irq(bu21013_data->irq); + ts->touch_stopped = true; + mb(); + disable_irq(client->irq); - regulator_disable(bu21013_data->regulator); + if (!device_may_wakeup(&client->dev)) + regulator_disable(ts->regulator); return 0; } -/** - * bu21013_resume() - resume the touch screen controller - * @dev: pointer to device structure - * - * This function is used to resume the touch panel - * controller and returns integer. - */ -static int bu21013_resume(struct device *dev) +static int __maybe_unused bu21013_resume(struct device *dev) { - struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev); - struct i2c_client *client = bu21013_data->client; - int retval; + struct i2c_client *client = to_i2c_client(dev); + struct bu21013_ts *ts = i2c_get_clientdata(client); + int error; - retval = regulator_enable(bu21013_data->regulator); - if (retval < 0) { - dev_err(&client->dev, "bu21013 regulator enable failed\n"); - return retval; - } + if (!device_may_wakeup(&client->dev)) { + error = regulator_enable(ts->regulator); + if (error) { + dev_err(&client->dev, + "failed to re-enable regulator when resuming\n"); + return error; + } - retval = bu21013_init_chip(bu21013_data); - if (retval < 0) { - dev_err(&client->dev, "bu21013 controller config failed\n"); - return retval; + error = bu21013_init_chip(ts); + if (error) { + dev_err(&client->dev, + "failed to reinitialize chip when resuming\n"); + return error; + } } - bu21013_data->touch_stopped = false; - - if (device_may_wakeup(&client->dev)) - disable_irq_wake(bu21013_data->irq); - else - enable_irq(bu21013_data->irq); + ts->touch_stopped = false; + mb(); + enable_irq(client->irq); return 0; } -static const struct dev_pm_ops bu21013_dev_pm_ops = { - .suspend = bu21013_suspend, - .resume = bu21013_resume, -}; -#endif +static SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume); static const struct i2c_device_id bu21013_id[] = { { DRIVER_TP, 0 }, @@ -714,9 +618,7 @@ MODULE_DEVICE_TABLE(i2c, bu21013_id); static struct i2c_driver bu21013_driver = { .driver = { .name = DRIVER_TP, -#ifdef CONFIG_PM .pm = &bu21013_dev_pm_ops, -#endif }, .probe = bu21013_probe, .remove = bu21013_remove, diff --git a/drivers/input/touchscreen/colibri-vf50-ts.c b/drivers/input/touchscreen/colibri-vf50-ts.c index 0e40897949bb..aa829725ded7 100644 --- a/drivers/input/touchscreen/colibri-vf50-ts.c +++ b/drivers/input/touchscreen/colibri-vf50-ts.c @@ -9,7 +9,6 @@ #include <linux/delay.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/iio/consumer.h> #include <linux/iio/types.h> diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c index 4b22d49a0f49..6bcffc930384 100644 --- a/drivers/input/touchscreen/cyttsp4_core.c +++ b/drivers/input/touchscreen/cyttsp4_core.c @@ -1990,11 +1990,6 @@ static int cyttsp4_mt_probe(struct cyttsp4 *cd) /* get sysinfo */ md->si = &cd->sysinfo; - if (!md->si) { - dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n", - __func__, md->si); - goto error_get_sysinfo; - } rc = cyttsp4_setup_input_device(cd); if (rc) @@ -2004,8 +1999,6 @@ static int cyttsp4_mt_probe(struct cyttsp4 *cd) error_init_input: input_free_device(md->input); -error_get_sysinfo: - input_set_drvdata(md->input, NULL); error_alloc_failed: dev_err(dev, "%s failed.\n", __func__); return rc; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 3cc4341bbdff..d2587724c52a 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -13,20 +13,22 @@ * http://www.glyn.com/Products/Displays */ -#include <linux/module.h> -#include <linux/ratelimit.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <linux/i2c.h> -#include <linux/kernel.h> -#include <linux/uaccess.h> -#include <linux/delay.h> #include <linux/debugfs.h> -#include <linux/slab.h> +#include <linux/delay.h> #include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/input.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/ratelimit.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + #include <asm/unaligned.h> #define WORK_REGISTER_THRESHOLD 0x00 @@ -88,6 +90,7 @@ struct edt_ft5x06_ts_data { struct touchscreen_properties prop; u16 num_x; u16 num_y; + struct regulator *vcc; struct gpio_desc *reset_gpio; struct gpio_desc *wake_gpio; @@ -764,8 +767,6 @@ edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, const char *debugfs_name) { tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL); - if (!tsdata->debug_dir) - return; debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x); debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y); @@ -1038,11 +1039,19 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) } } +static void edt_ft5x06_disable_regulator(void *arg) +{ + struct edt_ft5x06_ts_data *data = arg; + + regulator_disable(data->vcc); +} + static int edt_ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct edt_i2c_chip_data *chip_data; struct edt_ft5x06_ts_data *tsdata; + u8 buf[2] = { 0xfc, 0x00 }; struct input_dev *input; unsigned long irq_flags; int error; @@ -1066,6 +1075,27 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, tsdata->max_support_points = chip_data->max_support_points; + tsdata->vcc = devm_regulator_get(&client->dev, "vcc"); + if (IS_ERR(tsdata->vcc)) { + error = PTR_ERR(tsdata->vcc); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "failed to request regulator: %d\n", error); + return error; + } + + error = regulator_enable(tsdata->vcc); + if (error < 0) { + dev_err(&client->dev, "failed to enable vcc: %d\n", error); + return error; + } + + error = devm_add_action_or_reset(&client->dev, + edt_ft5x06_disable_regulator, + tsdata); + if (error) + return error; + tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(tsdata->reset_gpio)) { @@ -1112,6 +1142,12 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, return error; } + /* + * Dummy read access. EP0700MLP1 returns bogus data on the first + * register read access and ignores writes. + */ + edt_ft5x06_ts_readwrite(tsdata->client, 2, buf, 2, buf); + edt_ft5x06_ts_set_regs(tsdata); edt_ft5x06_ts_get_defaults(&client->dev, tsdata); edt_ft5x06_ts_get_parameters(tsdata); @@ -1172,7 +1208,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, return error; edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); - device_init_wakeup(&client->dev, 1); dev_dbg(&client->dev, "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", @@ -1192,29 +1227,6 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client) return 0; } -static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - if (device_may_wakeup(dev)) - enable_irq_wake(client->irq); - - return 0; -} - -static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - if (device_may_wakeup(dev)) - disable_irq_wake(client->irq); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, - edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); - static const struct edt_i2c_chip_data edt_ft5x06_data = { .max_support_points = 5, }; @@ -1253,7 +1265,6 @@ static struct i2c_driver edt_ft5x06_ts_driver = { .driver = { .name = "edt_ft5x06", .of_match_table = edt_ft5x06_of_match, - .pm = &edt_ft5x06_ts_pm_ops, }, .id_table = edt_ft5x06_ts_id, .probe = edt_ft5x06_ts_probe, diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index d4ad24ea54c8..491179967b29 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -59,8 +59,10 @@ #define CMD_HEADER_WRITE 0x54 #define CMD_HEADER_READ 0x53 #define CMD_HEADER_6B_READ 0x5B +#define CMD_HEADER_ROM_READ 0x96 #define CMD_HEADER_RESP 0x52 #define CMD_HEADER_6B_RESP 0x9B +#define CMD_HEADER_ROM_RESP 0x95 #define CMD_HEADER_HELLO 0x55 #define CMD_HEADER_REK 0x66 @@ -200,6 +202,10 @@ static int elants_i2c_execute_command(struct i2c_client *client, expected_response = CMD_HEADER_6B_RESP; break; + case CMD_HEADER_ROM_READ: + expected_response = CMD_HEADER_ROM_RESP; + break; + default: dev_err(&client->dev, "%s: invalid command %*ph\n", __func__, (int)cmd_size, cmd); @@ -556,6 +562,8 @@ static int elants_i2c_initialize(struct elants_data *ts) /* hw version is available even if device in recovery state */ error2 = elants_i2c_query_hw_version(ts); + if (!error2) + error2 = elants_i2c_query_bc_version(ts); if (!error) error = error2; @@ -564,8 +572,6 @@ static int elants_i2c_initialize(struct elants_data *ts) if (!error) error = elants_i2c_query_test_version(ts); if (!error) - error = elants_i2c_query_bc_version(ts); - if (!error) error = elants_i2c_query_ts_info(ts); if (error) @@ -613,39 +619,94 @@ static int elants_i2c_fw_write_page(struct i2c_client *client, return error; } +static int elants_i2c_validate_remark_id(struct elants_data *ts, + const struct firmware *fw) +{ + struct i2c_client *client = ts->client; + int error; + const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21 }; + u8 resp[6] = { 0 }; + u16 ts_remark_id = 0; + u16 fw_remark_id = 0; + + /* Compare TS Remark ID and FW Remark ID */ + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "failed to query Remark ID: %d\n", error); + return error; + } + + ts_remark_id = get_unaligned_be16(&resp[3]); + + fw_remark_id = get_unaligned_le16(&fw->data[fw->size - 4]); + + if (fw_remark_id != ts_remark_id) { + dev_err(&client->dev, + "Remark ID Mismatched: ts_remark_id=0x%04x, fw_remark_id=0x%04x.\n", + ts_remark_id, fw_remark_id); + return -EINVAL; + } + + return 0; +} + static int elants_i2c_do_update_firmware(struct i2c_client *client, const struct firmware *fw, bool force) { + struct elants_data *ts = i2c_get_clientdata(client); const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; - const u8 close_idle[] = {0x54, 0x2c, 0x01, 0x01}; + const u8 close_idle[] = { 0x54, 0x2c, 0x01, 0x01 }; u8 buf[HEADER_SIZE]; u16 send_id; int page, n_fw_pages; int error; + bool check_remark_id = ts->iap_version >= 0x60; /* Recovery mode detection! */ if (force) { dev_dbg(&client->dev, "Recovery mode procedure\n"); + + if (check_remark_id) { + error = elants_i2c_validate_remark_id(ts, fw); + if (error) + return error; + } + error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2)); + if (error) { + dev_err(&client->dev, "failed to enter IAP mode: %d\n", + error); + return error; + } } else { /* Start IAP Procedure */ dev_dbg(&client->dev, "Normal IAP procedure\n"); + /* Close idle mode */ error = elants_i2c_send(client, close_idle, sizeof(close_idle)); if (error) dev_err(&client->dev, "Failed close idle: %d\n", error); msleep(60); + elants_i2c_sw_reset(client); msleep(20); - error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); - } - if (error) { - dev_err(&client->dev, "failed to enter IAP mode: %d\n", error); - return error; + if (check_remark_id) { + error = elants_i2c_validate_remark_id(ts, fw); + if (error) + return error; + } + + error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); + if (error) { + dev_err(&client->dev, "failed to enter IAP mode: %d\n", + error); + return error; + } } msleep(20); diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c index 1d6c8f490b40..60a7246c5157 100644 --- a/drivers/input/touchscreen/fsl-imx25-tcq.c +++ b/drivers/input/touchscreen/fsl-imx25-tcq.c @@ -503,7 +503,6 @@ static int mx25_tcq_probe(struct platform_device *pdev) struct input_dev *idev; struct mx25_tcq_priv *priv; struct mx25_tsadc *tsadc = dev_get_drvdata(dev->parent); - struct resource *res; void __iomem *mem; int error; @@ -512,8 +511,7 @@ static int mx25_tcq_probe(struct platform_device *pdev) return -ENOMEM; priv->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mem = devm_ioremap_resource(dev, res); + mem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mem)) return PTR_ERR(mem); @@ -528,10 +526,8 @@ static int mx25_tcq_probe(struct platform_device *pdev) } priv->irq = platform_get_irq(pdev, 0); - if (priv->irq <= 0) { - dev_err(dev, "Failed to get IRQ\n"); + if (priv->irq <= 0) return priv->irq; - } idev = devm_input_allocate_device(dev); if (!idev) { diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 5178ea8b5f30..0403102e807e 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -53,6 +53,7 @@ struct goodix_ts_data { const char *cfg_name; struct completion firmware_loading_complete; unsigned long irq_flags; + unsigned int contact_size; }; #define GOODIX_GPIO_INT_NAME "irq" @@ -62,6 +63,7 @@ struct goodix_ts_data { #define GOODIX_MAX_WIDTH 4096 #define GOODIX_INT_TRIGGER 1 #define GOODIX_CONTACT_SIZE 8 +#define GOODIX_MAX_CONTACT_SIZE 9 #define GOODIX_MAX_CONTACTS 10 #define GOODIX_CONFIG_MAX_LENGTH 240 @@ -127,6 +129,15 @@ static const unsigned long goodix_irq_flags[] = { static const struct dmi_system_id rotated_screen[] = { #if defined(CONFIG_DMI) && defined(CONFIG_X86) { + .ident = "Teclast X89", + .matches = { + /* tPAD is too generic, also match on bios date */ + DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), + DMI_MATCH(DMI_BOARD_NAME, "tPAD"), + DMI_MATCH(DMI_BIOS_DATE, "12/19/2014"), + }, + }, + { .ident = "WinBook TW100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "WinBook"), @@ -144,6 +155,19 @@ static const struct dmi_system_id rotated_screen[] = { {} }; +static const struct dmi_system_id nine_bytes_report[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) + { + .ident = "Lenovo YogaBook", + /* YB1-X91L/F and YB1-X90L/F */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9") + } + }, +#endif + {} +}; + /** * goodix_i2c_read - read data from a register of the i2c slave device. * @@ -249,7 +273,7 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT); do { error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR, - data, GOODIX_CONTACT_SIZE + 1); + data, ts->contact_size + 1); if (error) { dev_err(&ts->client->dev, "I2C transfer error: %d\n", error); @@ -262,12 +286,12 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) return -EPROTO; if (touch_num > 1) { - data += 1 + GOODIX_CONTACT_SIZE; + data += 1 + ts->contact_size; error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR + - 1 + GOODIX_CONTACT_SIZE, + 1 + ts->contact_size, data, - GOODIX_CONTACT_SIZE * + ts->contact_size * (touch_num - 1)); if (error) return error; @@ -286,7 +310,7 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) return 0; } -static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data) +static void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data) { int id = coor_data[0] & 0x0F; int input_x = get_unaligned_le16(&coor_data[1]); @@ -301,6 +325,21 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data) input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); } +static void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data) +{ + int id = coor_data[1] & 0x0F; + int input_x = get_unaligned_le16(&coor_data[3]); + int input_y = get_unaligned_le16(&coor_data[5]); + int input_w = get_unaligned_le16(&coor_data[7]); + + input_mt_slot(ts->input_dev, id); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); + touchscreen_report_pos(ts->input_dev, &ts->prop, + input_x, input_y, true); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); +} + /** * goodix_process_events - Process incoming events * @@ -311,7 +350,7 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data) */ static void goodix_process_events(struct goodix_ts_data *ts) { - u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS]; + u8 point_data[1 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS]; int touch_num; int i; @@ -326,8 +365,12 @@ static void goodix_process_events(struct goodix_ts_data *ts) input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4)); for (i = 0; i < touch_num; i++) - goodix_ts_report_touch(ts, - &point_data[1 + GOODIX_CONTACT_SIZE * i]); + if (ts->contact_size == 9) + goodix_ts_report_touch_9b(ts, + &point_data[1 + ts->contact_size * i]); + else + goodix_ts_report_touch_8b(ts, + &point_data[1 + ts->contact_size * i]); input_mt_sync_frame(ts->input_dev); input_sync(ts->input_dev); @@ -730,6 +773,13 @@ static int goodix_configure_dev(struct goodix_ts_data *ts) "Applying '180 degrees rotated screen' quirk\n"); } + if (dmi_check_system(nine_bytes_report)) { + ts->contact_size = 9; + + dev_dbg(&ts->client->dev, + "Non-standard 9-bytes report format quirk\n"); + } + error = input_mt_init_slots(ts->input_dev, ts->max_touch_num, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); if (error) { @@ -810,6 +860,7 @@ static int goodix_ts_probe(struct i2c_client *client, ts->client = client; i2c_set_clientdata(client, ts); init_completion(&ts->firmware_loading_complete); + ts->contact_size = GOODIX_CONTACT_SIZE; error = goodix_get_gpio_config(ts); if (error) diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index 84fbbf415c43..ddad4a82a5e5 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -811,8 +811,7 @@ static int hideep_init_input(struct hideep_ts *ts) if (error) return error; - ts->key_num = device_property_read_u32_array(dev, "linux,keycodes", - NULL, 0); + ts->key_num = device_property_count_u32(dev, "linux,keycodes"); if (ts->key_num > HIDEEP_KEY_MAX) { dev_err(dev, "too many keys defined: %d\n", ts->key_num); diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index e9006407c9bc..199cf3daec10 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -1,54 +1,54 @@ // SPDX-License-Identifier: GPL-2.0-only -#include <linux/module.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/slab.h> #include <linux/input.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> -#include <linux/delay.h> -#include <linux/workqueue.h> -#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/module.h> #include <linux/of_device.h> +#include <linux/sizes.h> +#include <linux/slab.h> #include <asm/unaligned.h> -#define ILI210X_TOUCHES 2 -#define ILI251X_TOUCHES 10 -#define DEFAULT_POLL_PERIOD 20 +#define ILI2XXX_POLL_PERIOD 20 + +#define ILI210X_DATA_SIZE 64 +#define ILI211X_DATA_SIZE 43 +#define ILI251X_DATA_SIZE1 31 +#define ILI251X_DATA_SIZE2 20 /* Touchscreen commands */ #define REG_TOUCHDATA 0x10 #define REG_PANEL_INFO 0x20 -#define REG_FIRMWARE_VERSION 0x40 #define REG_CALIBRATE 0xcc -struct firmware_version { - u8 id; - u8 major; - u8 minor; -} __packed; - -enum ili2xxx_model { - MODEL_ILI210X, - MODEL_ILI251X, +struct ili2xxx_chip { + int (*read_reg)(struct i2c_client *client, u8 reg, + void *buf, size_t len); + int (*get_touch_data)(struct i2c_client *client, u8 *data); + bool (*parse_touch_data)(const u8 *data, unsigned int finger, + unsigned int *x, unsigned int *y); + bool (*continue_polling)(const u8 *data, bool touch); + unsigned int max_touches; + unsigned int resolution; + bool has_calibrate_reg; }; struct ili210x { struct i2c_client *client; struct input_dev *input; - unsigned int poll_period; - struct delayed_work dwork; struct gpio_desc *reset_gpio; struct touchscreen_properties prop; - enum ili2xxx_model model; - unsigned int max_touches; + const struct ili2xxx_chip *chip; + bool stop; }; -static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, - size_t len) +static int ili210x_read_reg(struct i2c_client *client, + u8 reg, void *buf, size_t len) { - struct ili210x *priv = i2c_get_clientdata(client); - struct i2c_msg msg[2] = { + struct i2c_msg msg[] = { { .addr = client->addr, .flags = 0, @@ -62,151 +62,253 @@ static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, .buf = buf, } }; + int error, ret; - if (priv->model == MODEL_ILI251X) { - if (i2c_transfer(client->adapter, msg, 1) != 1) { - dev_err(&client->dev, "i2c transfer failed\n"); - return -EIO; - } - - usleep_range(5000, 5500); - - if (i2c_transfer(client->adapter, msg + 1, 1) != 1) { - dev_err(&client->dev, "i2c transfer failed\n"); - return -EIO; - } - } else { - if (i2c_transfer(client->adapter, msg, 2) != 2) { - dev_err(&client->dev, "i2c transfer failed\n"); - return -EIO; - } + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + error = ret < 0 ? ret : -EIO; + dev_err(&client->dev, "%s failed: %d\n", __func__, error); + return error; } return 0; } -static int ili210x_read(struct i2c_client *client, void *buf, size_t len) +static int ili210x_read_touch_data(struct i2c_client *client, u8 *data) { - struct i2c_msg msg = { - .addr = client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = buf, - }; + return ili210x_read_reg(client, REG_TOUCHDATA, + data, ILI210X_DATA_SIZE); +} + +static bool ili210x_touchdata_to_coords(const u8 *touchdata, + unsigned int finger, + unsigned int *x, unsigned int *y) +{ + if (touchdata[0] & BIT(finger)) + return false; + + *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0); + *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2); + + return true; +} - if (i2c_transfer(client->adapter, &msg, 1) != 1) { - dev_err(&client->dev, "i2c transfer failed\n"); +static bool ili210x_check_continue_polling(const u8 *data, bool touch) +{ + return data[0] & 0xf3; +} + +static const struct ili2xxx_chip ili210x_chip = { + .read_reg = ili210x_read_reg, + .get_touch_data = ili210x_read_touch_data, + .parse_touch_data = ili210x_touchdata_to_coords, + .continue_polling = ili210x_check_continue_polling, + .max_touches = 2, + .has_calibrate_reg = true, +}; + +static int ili211x_read_touch_data(struct i2c_client *client, u8 *data) +{ + s16 sum = 0; + int error; + int ret; + int i; + + ret = i2c_master_recv(client, data, ILI211X_DATA_SIZE); + if (ret != ILI211X_DATA_SIZE) { + error = ret < 0 ? ret : -EIO; + dev_err(&client->dev, "%s failed: %d\n", __func__, error); + return error; + } + + /* This chip uses custom checksum at the end of data */ + for (i = 0; i < ILI211X_DATA_SIZE - 1; i++) + sum = (sum + data[i]) & 0xff; + + if ((-sum & 0xff) != data[ILI211X_DATA_SIZE - 1]) { + dev_err(&client->dev, + "CRC error (crc=0x%02x expected=0x%02x)\n", + sum, data[ILI211X_DATA_SIZE - 1]); return -EIO; } return 0; } -static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, +static bool ili211x_touchdata_to_coords(const u8 *touchdata, unsigned int finger, unsigned int *x, unsigned int *y) { - if (finger >= ILI210X_TOUCHES) - return false; + u32 data; - if (touchdata[0] & BIT(finger)) + data = get_unaligned_be32(touchdata + 1 + (finger * 4) + 0); + if (data == 0xffffffff) /* Finger up */ return false; - *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0); - *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2); + *x = ((touchdata[1 + (finger * 4) + 0] & 0xf0) << 4) | + touchdata[1 + (finger * 4) + 1]; + *y = ((touchdata[1 + (finger * 4) + 0] & 0x0f) << 8) | + touchdata[1 + (finger * 4) + 2]; return true; } -static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, +static bool ili211x_decline_polling(const u8 *data, bool touch) +{ + return false; +} + +static const struct ili2xxx_chip ili211x_chip = { + .read_reg = ili210x_read_reg, + .get_touch_data = ili211x_read_touch_data, + .parse_touch_data = ili211x_touchdata_to_coords, + .continue_polling = ili211x_decline_polling, + .max_touches = 10, + .resolution = 2048, +}; + +static bool ili212x_touchdata_to_coords(const u8 *touchdata, unsigned int finger, unsigned int *x, unsigned int *y) { - if (finger >= ILI251X_TOUCHES) + u16 val; + + val = get_unaligned_be16(touchdata + 3 + (finger * 5) + 0); + if (!(val & BIT(15))) /* Touch indication */ return false; - *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0); - if (!(*x & BIT(15))) /* Touch indication */ + *x = val & 0x3fff; + *y = get_unaligned_be16(touchdata + 3 + (finger * 5) + 2); + + return true; +} + +static bool ili212x_check_continue_polling(const u8 *data, bool touch) +{ + return touch; +} + +static const struct ili2xxx_chip ili212x_chip = { + .read_reg = ili210x_read_reg, + .get_touch_data = ili210x_read_touch_data, + .parse_touch_data = ili212x_touchdata_to_coords, + .continue_polling = ili212x_check_continue_polling, + .max_touches = 10, + .has_calibrate_reg = true, +}; + +static int ili251x_read_reg(struct i2c_client *client, + u8 reg, void *buf, size_t len) +{ + int error; + int ret; + + ret = i2c_master_send(client, ®, 1); + if (ret == 1) { + usleep_range(5000, 5500); + + ret = i2c_master_recv(client, buf, len); + if (ret == len) + return 0; + } + + error = ret < 0 ? ret : -EIO; + dev_err(&client->dev, "%s failed: %d\n", __func__, error); + return ret; +} + +static int ili251x_read_touch_data(struct i2c_client *client, u8 *data) +{ + int error; + + error = ili251x_read_reg(client, REG_TOUCHDATA, + data, ILI251X_DATA_SIZE1); + if (!error && data[0] == 2) { + error = i2c_master_recv(client, data + ILI251X_DATA_SIZE1, + ILI251X_DATA_SIZE2); + if (error >= 0 && error != ILI251X_DATA_SIZE2) + error = -EIO; + } + + return error; +} + +static bool ili251x_touchdata_to_coords(const u8 *touchdata, + unsigned int finger, + unsigned int *x, unsigned int *y) +{ + u16 val; + + val = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0); + if (!(val & BIT(15))) /* Touch indication */ return false; - *x &= 0x3fff; + *x = val & 0x3fff; *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2); return true; } +static bool ili251x_check_continue_polling(const u8 *data, bool touch) +{ + return touch; +} + +static const struct ili2xxx_chip ili251x_chip = { + .read_reg = ili251x_read_reg, + .get_touch_data = ili251x_read_touch_data, + .parse_touch_data = ili251x_touchdata_to_coords, + .continue_polling = ili251x_check_continue_polling, + .max_touches = 10, + .has_calibrate_reg = true, +}; + static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) { struct input_dev *input = priv->input; int i; - bool contact = false, touch = false; + bool contact = false, touch; unsigned int x = 0, y = 0; - for (i = 0; i < priv->max_touches; i++) { - if (priv->model == MODEL_ILI210X) { - touch = ili210x_touchdata_to_coords(priv, touchdata, - i, &x, &y); - } else if (priv->model == MODEL_ILI251X) { - touch = ili251x_touchdata_to_coords(priv, touchdata, - i, &x, &y); - if (touch) - contact = true; - } + for (i = 0; i < priv->chip->max_touches; i++) { + touch = priv->chip->parse_touch_data(touchdata, i, &x, &y); input_mt_slot(input, i); - input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); - if (!touch) - continue; - touchscreen_report_pos(input, &priv->prop, x, y, - true); + if (input_mt_report_slot_state(input, MT_TOOL_FINGER, touch)) { + touchscreen_report_pos(input, &priv->prop, x, y, true); + contact = true; + } } input_mt_report_pointer_emulation(input, false); input_sync(input); - if (priv->model == MODEL_ILI210X) - contact = touchdata[0] & 0xf3; - return contact; } -static void ili210x_work(struct work_struct *work) +static irqreturn_t ili210x_irq(int irq, void *irq_data) { - struct ili210x *priv = container_of(work, struct ili210x, - dwork.work); + struct ili210x *priv = irq_data; struct i2c_client *client = priv->client; - u8 touchdata[64] = { 0 }; + const struct ili2xxx_chip *chip = priv->chip; + u8 touchdata[ILI210X_DATA_SIZE] = { 0 }; + bool keep_polling; bool touch; - int error = -EINVAL; - - if (priv->model == MODEL_ILI210X) { - error = ili210x_read_reg(client, REG_TOUCHDATA, - touchdata, sizeof(touchdata)); - } else if (priv->model == MODEL_ILI251X) { - error = ili210x_read_reg(client, REG_TOUCHDATA, - touchdata, 31); - if (!error && touchdata[0] == 2) - error = ili210x_read(client, &touchdata[31], 20); - } - - if (error) { - dev_err(&client->dev, - "Unable to get touchdata, err = %d\n", error); - return; - } - - touch = ili210x_report_events(priv, touchdata); - - if (touch) - schedule_delayed_work(&priv->dwork, - msecs_to_jiffies(priv->poll_period)); -} + int error; -static irqreturn_t ili210x_irq(int irq, void *irq_data) -{ - struct ili210x *priv = irq_data; + do { + error = chip->get_touch_data(client, touchdata); + if (error) { + dev_err(&client->dev, + "Unable to get touch data: %d\n", error); + break; + } - schedule_delayed_work(&priv->dwork, 0); + touch = ili210x_report_events(priv, touchdata); + keep_polling = chip->continue_polling(touchdata, touch); + if (keep_polling) + msleep(ILI2XXX_POLL_PERIOD); + } while (!priv->stop && keep_polling); return IRQ_HANDLED; } @@ -242,8 +344,19 @@ static struct attribute *ili210x_attributes[] = { NULL, }; +static umode_t ili210x_calibrate_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = kobj_to_dev(kobj); + struct i2c_client *client = to_i2c_client(dev); + struct ili210x *priv = i2c_get_clientdata(client); + + return priv->chip->has_calibrate_reg ? attr->mode : 0; +} + static const struct attribute_group ili210x_attr_group = { .attrs = ili210x_attributes, + .is_visible = ili210x_calibrate_visible, }; static void ili210x_power_down(void *data) @@ -253,28 +366,35 @@ static void ili210x_power_down(void *data) gpiod_set_value_cansleep(reset_gpio, 1); } -static void ili210x_cancel_work(void *data) +static void ili210x_stop(void *data) { struct ili210x *priv = data; - cancel_delayed_work_sync(&priv->dwork); + /* Tell ISR to quit even if there is a contact. */ + priv->stop = true; } static int ili210x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct device *dev = &client->dev; + const struct ili2xxx_chip *chip; struct ili210x *priv; struct gpio_desc *reset_gpio; struct input_dev *input; - struct firmware_version firmware; - enum ili2xxx_model model; int error; - - model = (enum ili2xxx_model)id->driver_data; + unsigned int max_xy; dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); + chip = device_get_match_data(dev); + if (!chip && id) + chip = (const struct ili2xxx_chip *)id->driver_data; + if (!chip) { + dev_err(&client->dev, "unknown device model\n"); + return -ENODEV; + } + if (client->irq <= 0) { dev_err(dev, "No IRQ!\n"); return -EINVAL; @@ -305,49 +425,39 @@ static int ili210x_i2c_probe(struct i2c_client *client, priv->client = client; priv->input = input; - priv->poll_period = DEFAULT_POLL_PERIOD; - INIT_DELAYED_WORK(&priv->dwork, ili210x_work); priv->reset_gpio = reset_gpio; - priv->model = model; - if (model == MODEL_ILI210X) - priv->max_touches = ILI210X_TOUCHES; - if (model == MODEL_ILI251X) - priv->max_touches = ILI251X_TOUCHES; - + priv->chip = chip; i2c_set_clientdata(client, priv); - /* Get firmware version */ - error = ili210x_read_reg(client, REG_FIRMWARE_VERSION, - &firmware, sizeof(firmware)); - if (error) { - dev_err(dev, "Failed to get firmware version, err: %d\n", - error); - return error; - } - /* Setup input device */ input->name = "ILI210x Touchscreen"; input->id.bustype = BUS_I2C; - input->dev.parent = dev; /* Multi touch */ - input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0); + max_xy = (chip->resolution ?: SZ_64K) - 1; + input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0); touchscreen_parse_properties(input, true, &priv->prop); - input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT); - error = devm_add_action(dev, ili210x_cancel_work, priv); - if (error) + error = input_mt_init_slots(input, priv->chip->max_touches, + INPUT_MT_DIRECT); + if (error) { + dev_err(dev, "Unable to set up slots, err: %d\n", error); return error; + } - error = devm_request_irq(dev, client->irq, ili210x_irq, 0, - client->name, priv); + 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; } + error = devm_add_action_or_reset(dev, ili210x_stop, priv); + if (error) + return error; + error = devm_device_add_group(dev, &ili210x_attr_group); if (error) { dev_err(dev, "Unable to create sysfs attributes, err: %d\n", @@ -361,56 +471,30 @@ static int ili210x_i2c_probe(struct i2c_client *client, return error; } - device_init_wakeup(dev, 1); - - dev_dbg(dev, - "ILI210x initialized (IRQ: %d), firmware version %d.%d.%d", - client->irq, firmware.id, firmware.major, firmware.minor); - - return 0; -} - -static int __maybe_unused ili210x_i2c_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - if (device_may_wakeup(&client->dev)) - enable_irq_wake(client->irq); - return 0; } -static int __maybe_unused ili210x_i2c_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - if (device_may_wakeup(&client->dev)) - disable_irq_wake(client->irq); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm, - ili210x_i2c_suspend, ili210x_i2c_resume); - static const struct i2c_device_id ili210x_i2c_id[] = { - { "ili210x", MODEL_ILI210X }, - { "ili251x", MODEL_ILI251X }, + { "ili210x", (long)&ili210x_chip }, + { "ili2117", (long)&ili211x_chip }, + { "ili2120", (long)&ili212x_chip }, + { "ili251x", (long)&ili251x_chip }, { } }; MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); static const struct of_device_id ili210x_dt_ids[] = { - { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X }, - { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X }, - { }, + { .compatible = "ilitek,ili210x", .data = &ili210x_chip }, + { .compatible = "ilitek,ili2117", .data = &ili211x_chip }, + { .compatible = "ilitek,ili2120", .data = &ili212x_chip }, + { .compatible = "ilitek,ili251x", .data = &ili251x_chip }, + { } }; MODULE_DEVICE_TABLE(of, ili210x_dt_ids); static struct i2c_driver ili210x_ts_driver = { .driver = { .name = "ili210x_i2c", - .pm = &ili210x_i2c_pm, .of_match_table = ili210x_dt_ids, }, .id_table = ili210x_i2c_id, diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index e04eecd65bbb..9ed258854349 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -430,16 +430,12 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) } tsc_irq = platform_get_irq(pdev, 0); - if (tsc_irq < 0) { - dev_err(&pdev->dev, "no tsc irq resource?\n"); + if (tsc_irq < 0) return tsc_irq; - } adc_irq = platform_get_irq(pdev, 1); - if (adc_irq < 0) { - dev_err(&pdev->dev, "no adc irq resource?\n"); + if (adc_irq < 0) return adc_irq; - } err = devm_request_threaded_irq(tsc->dev, tsc_irq, NULL, tsc_irq_fn, IRQF_ONESHOT, diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 567ed64b5392..b2cd9472e2d1 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -212,10 +212,8 @@ static int lpc32xx_ts_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Can't get interrupt resource\n"); + if (irq < 0) return irq; - } tsc = kzalloc(sizeof(*tsc), GFP_KERNEL); input = input_allocate_device(); diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index a5ab774da4cc..69c6d559eeb0 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -446,8 +446,7 @@ static int mms114_probe(struct i2c_client *client, data->client = client; data->input_dev = input_dev; - /* FIXME: switch to device_get_match_data() when available */ - match_data = of_device_get_match_data(&client->dev); + match_data = device_get_match_data(&client->dev); if (!match_data) return -EINVAL; diff --git a/drivers/input/touchscreen/mxs-lradc-ts.c b/drivers/input/touchscreen/mxs-lradc-ts.c index 593b8d3e90b5..9e36fee38d61 100644 --- a/drivers/input/touchscreen/mxs-lradc-ts.c +++ b/drivers/input/touchscreen/mxs-lradc-ts.c @@ -606,7 +606,6 @@ static int mxs_lradc_ts_probe(struct platform_device *pdev) struct device_node *node = dev->parent->of_node; struct mxs_lradc *lradc = dev_get_drvdata(dev->parent); struct mxs_lradc_ts *ts; - struct resource *iores; int ret, irq, virq, i; u32 ts_wires = 0, adapt; @@ -620,12 +619,9 @@ static int mxs_lradc_ts_probe(struct platform_device *pdev) ts->dev = dev; spin_lock_init(&ts->lock); - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) - return -EINVAL; - ts->base = devm_ioremap(dev, iores->start, resource_size(iores)); - if (!ts->base) - return -ENOMEM; + ts->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ts->base)) + return PTR_ERR(ts->base); ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires", &ts_wires); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index e146dfa257b1..9aa098577350 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -5,22 +5,73 @@ * Copyright (C) 2010-2011 Pixcir, Inc. */ +#include <asm/unaligned.h> #include <linux/delay.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/slab.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/input.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> -#include <linux/gpio.h> -#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> #include <linux/of_device.h> -#include <linux/platform_data/pixcir_i2c_ts.h> -#include <asm/unaligned.h> +#include <linux/module.h> +#include <linux/slab.h> #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ +/* + * Register map + */ +#define PIXCIR_REG_POWER_MODE 51 +#define PIXCIR_REG_INT_MODE 52 + +/* + * Power modes: + * active: max scan speed + * idle: lower scan speed with automatic transition to active on touch + * halt: datasheet says sleep but this is more like halt as the chip + * clocks are cut and it can only be brought out of this mode + * using the RESET pin. + */ +enum pixcir_power_mode { + PIXCIR_POWER_ACTIVE, + PIXCIR_POWER_IDLE, + PIXCIR_POWER_HALT, +}; + +#define PIXCIR_POWER_MODE_MASK 0x03 +#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2) + +/* + * Interrupt modes: + * periodical: interrupt is asserted periodicaly + * diff coordinates: interrupt is asserted when coordinates change + * level on touch: interrupt level asserted during touch + * pulse on touch: interrupt pulse asserted during touch + * + */ +enum pixcir_int_mode { + PIXCIR_INT_PERIODICAL, + PIXCIR_INT_DIFF_COORD, + PIXCIR_INT_LEVEL_TOUCH, + PIXCIR_INT_PULSE_TOUCH, +}; + +#define PIXCIR_INT_MODE_MASK 0x03 +#define PIXCIR_INT_ENABLE (1UL << 3) +#define PIXCIR_INT_POL_HIGH (1UL << 2) + +/** + * struct pixcir_i2c_chip_data - chip related data + * @max_fingers: Max number of fingers reported simultaneously by h/w + * @has_hw_ids: Hardware supports finger tracking IDs + * + */ +struct pixcir_i2c_chip_data { + u8 max_fingers; + bool has_hw_ids; +}; + struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; @@ -30,7 +81,6 @@ struct pixcir_i2c_ts_data { struct gpio_desc *gpio_wake; const struct pixcir_i2c_chip_data *chip; struct touchscreen_properties prop; - int max_fingers; /* Max fingers supported in this instance */ bool running; }; @@ -54,7 +104,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, memset(report, 0, sizeof(struct pixcir_report_data)); i = chip->has_hw_ids ? 1 : 0; - readsize = 2 + tsdata->max_fingers * (4 + i); + readsize = 2 + tsdata->chip->max_fingers * (4 + i); if (readsize > sizeof(rdbuf)) readsize = sizeof(rdbuf); @@ -75,8 +125,8 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, } touch = rdbuf[0] & 0x7; - if (touch > tsdata->max_fingers) - touch = tsdata->max_fingers; + if (touch > tsdata->chip->max_fingers) + touch = tsdata->chip->max_fingers; report->num_touches = touch; bufptr = &rdbuf[2]; @@ -192,7 +242,7 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE); if (ret < 0) { - dev_err(dev, "%s: can't read reg 0x%x : %d\n", + dev_err(dev, "%s: can't read reg %d : %d\n", __func__, PIXCIR_REG_POWER_MODE, ret); return ret; } @@ -205,7 +255,7 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret); if (ret < 0) { - dev_err(dev, "%s: can't write reg 0x%x : %d\n", + dev_err(dev, "%s: can't write reg %d : %d\n", __func__, PIXCIR_REG_POWER_MODE, ret); return ret; } @@ -231,7 +281,7 @@ static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts, ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); if (ret < 0) { - dev_err(dev, "%s: can't read reg 0x%x : %d\n", + dev_err(dev, "%s: can't read reg %d : %d\n", __func__, PIXCIR_REG_INT_MODE, ret); return ret; } @@ -246,7 +296,7 @@ static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts, ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); if (ret < 0) { - dev_err(dev, "%s: can't write reg 0x%x : %d\n", + dev_err(dev, "%s: can't write reg %d : %d\n", __func__, PIXCIR_REG_INT_MODE, ret); return ret; } @@ -264,7 +314,7 @@ static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable) ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); if (ret < 0) { - dev_err(dev, "%s: can't read reg 0x%x : %d\n", + dev_err(dev, "%s: can't read reg %d : %d\n", __func__, PIXCIR_REG_INT_MODE, ret); return ret; } @@ -276,7 +326,7 @@ static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable) ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); if (ret < 0) { - dev_err(dev, "%s: can't write reg 0x%x : %d\n", + dev_err(dev, "%s: can't write reg %d : %d\n", __func__, PIXCIR_REG_INT_MODE, ret); return ret; } @@ -412,31 +462,9 @@ unlock: static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume); -#ifdef CONFIG_OF -static const struct of_device_id pixcir_of_match[]; - -static int pixcir_parse_dt(struct device *dev, - struct pixcir_i2c_ts_data *tsdata) -{ - tsdata->chip = of_device_get_match_data(dev); - if (!tsdata->chip) - return -EINVAL; - - return 0; -} -#else -static int pixcir_parse_dt(struct device *dev, - struct pixcir_i2c_ts_data *tsdata) -{ - return -EINVAL; -} -#endif - static int pixcir_i2c_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct pixcir_ts_platform_data *pdata = - dev_get_platdata(&client->dev); struct device *dev = &client->dev; struct pixcir_i2c_ts_data *tsdata; struct input_dev *input; @@ -446,19 +474,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, if (!tsdata) return -ENOMEM; - if (pdata) { - tsdata->chip = &pdata->chip; - } else if (dev->of_node) { - error = pixcir_parse_dt(dev, tsdata); - if (error) - return error; - } else { - dev_err(dev, "platform data not defined\n"); - return -EINVAL; - } - - if (!tsdata->chip->max_fingers) { - dev_err(dev, "Invalid max_fingers in chip data\n"); + tsdata->chip = device_get_match_data(dev); + if (!tsdata->chip && id) + tsdata->chip = (const void *)id->driver_data; + if (!tsdata->chip) { + dev_err(dev, "can't locate chip data\n"); return -EINVAL; } @@ -475,30 +495,17 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->id.bustype = BUS_I2C; input->open = pixcir_input_open; input->close = pixcir_input_close; - input->dev.parent = dev; - - if (pdata) { - input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); - } else { - input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); - input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); - touchscreen_parse_properties(input, true, &tsdata->prop); - if (!input_abs_get_max(input, ABS_MT_POSITION_X) || - !input_abs_get_max(input, ABS_MT_POSITION_Y)) { - dev_err(dev, "Touchscreen size is not specified\n"); - return -EINVAL; - } - } - tsdata->max_fingers = tsdata->chip->max_fingers; - if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) { - tsdata->max_fingers = PIXCIR_MAX_SLOTS; - dev_info(dev, "Limiting maximum fingers to %d\n", - tsdata->max_fingers); + input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); + input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); + touchscreen_parse_properties(input, true, &tsdata->prop); + if (!input_abs_get_max(input, ABS_MT_POSITION_X) || + !input_abs_get_max(input, ABS_MT_POSITION_Y)) { + dev_err(dev, "Touchscreen size is not specified\n"); + return -EINVAL; } - error = input_mt_init_slots(input, tsdata->max_fingers, + error = input_mt_init_slots(input, tsdata->chip->max_fingers, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); if (error) { dev_err(dev, "Error initializing Multi-Touch slots\n"); @@ -510,7 +517,9 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, tsdata->gpio_attb = devm_gpiod_get(dev, "attb", GPIOD_IN); if (IS_ERR(tsdata->gpio_attb)) { error = PTR_ERR(tsdata->gpio_attb); - dev_err(dev, "Failed to request ATTB gpio: %d\n", error); + if (error != -EPROBE_DEFER) + dev_err(dev, "Failed to request ATTB gpio: %d\n", + error); return error; } @@ -518,7 +527,9 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, GPIOD_OUT_LOW); if (IS_ERR(tsdata->gpio_reset)) { error = PTR_ERR(tsdata->gpio_reset); - dev_err(dev, "Failed to request RESET gpio: %d\n", error); + if (error != -EPROBE_DEFER) + dev_err(dev, "Failed to request RESET gpio: %d\n", + error); return error; } @@ -574,14 +585,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return 0; } -static const struct i2c_device_id pixcir_i2c_ts_id[] = { - { "pixcir_ts", 0 }, - { "pixcir_tangoc", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id); - -#ifdef CONFIG_OF static const struct pixcir_i2c_chip_data pixcir_ts_data = { .max_fingers = 2, /* no hw id support */ @@ -592,6 +595,14 @@ static const struct pixcir_i2c_chip_data pixcir_tangoc_data = { .has_hw_ids = true, }; +static const struct i2c_device_id pixcir_i2c_ts_id[] = { + { "pixcir_ts", (unsigned long) &pixcir_ts_data }, + { "pixcir_tangoc", (unsigned long) &pixcir_tangoc_data }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id); + +#ifdef CONFIG_OF static const struct of_device_id pixcir_of_match[] = { { .compatible = "pixcir,pixcir_ts", .data = &pixcir_ts_data }, { .compatible = "pixcir,pixcir_tangoc", .data = &pixcir_tangoc_data }, diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index 69881265d121..0e2e08f3f433 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -16,7 +16,6 @@ #include <linux/platform_device.h> #include <linux/input.h> #include <linux/input/mt.h> -#include <linux/input-polldev.h> #include <linux/input/touchscreen.h> #include <soc/bcm2835/raspberrypi-firmware.h> @@ -34,7 +33,7 @@ struct rpi_ts { struct platform_device *pdev; - struct input_polled_dev *poll_dev; + struct input_dev *input; struct touchscreen_properties prop; void __iomem *fw_regs_va; @@ -57,10 +56,9 @@ struct rpi_ts_regs { } point[RPI_TS_MAX_SUPPORTED_POINTS]; }; -static void rpi_ts_poll(struct input_polled_dev *dev) +static void rpi_ts_poll(struct input_dev *input) { - struct input_dev *input = dev->input; - struct rpi_ts *ts = dev->private; + struct rpi_ts *ts = input_get_drvdata(input); struct rpi_ts_regs regs; int modified_ids = 0; long released_ids; @@ -123,10 +121,9 @@ static int rpi_ts_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct input_polled_dev *poll_dev; + struct input_dev *input; struct device_node *fw_node; struct rpi_firmware *fw; - struct input_dev *input; struct rpi_ts *ts; u32 touchbuf; int error; @@ -160,7 +157,6 @@ static int rpi_ts_probe(struct platform_device *pdev) return error; } - touchbuf = (u32)ts->fw_regs_phys; error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF, &touchbuf, sizeof(touchbuf)); @@ -170,19 +166,17 @@ static int rpi_ts_probe(struct platform_device *pdev) return error; } - poll_dev = devm_input_allocate_polled_device(dev); - if (!poll_dev) { + input = devm_input_allocate_device(dev); + if (!input) { dev_err(dev, "Failed to allocate input device\n"); return -ENOMEM; } - ts->poll_dev = poll_dev; - input = poll_dev->input; + + ts->input = input; + input_set_drvdata(input, ts); input->name = "raspberrypi-ts"; input->id.bustype = BUS_HOST; - poll_dev->poll_interval = RPI_TS_POLL_INTERVAL; - poll_dev->poll = rpi_ts_poll; - poll_dev->private = ts; input_set_abs_params(input, ABS_MT_POSITION_X, 0, RPI_TS_DEFAULT_WIDTH, 0, 0); @@ -197,7 +191,15 @@ static int rpi_ts_probe(struct platform_device *pdev) return error; } - error = input_register_polled_device(poll_dev); + error = input_setup_polling(input, rpi_ts_poll); + if (error) { + dev_err(dev, "could not set up polling mode, %d\n", error); + return error; + } + + input_set_poll_interval(input, RPI_TS_POLL_INTERVAL); + + error = input_register_device(input); if (error) { dev_err(dev, "could not register input device, %d\n", error); return error; @@ -214,10 +216,10 @@ MODULE_DEVICE_TABLE(of, rpi_ts_match); static struct platform_driver rpi_ts_driver = { .driver = { - .name = "raspberrypi-ts", + .name = "raspberrypi-ts", .of_match_table = rpi_ts_match, }, - .probe = rpi_ts_probe, + .probe = rpi_ts_probe, }; module_platform_driver(rpi_ts_driver); diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index b346e7cafd62..82920ff46f72 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -13,7 +13,6 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/gpio.h> #include <linux/input.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 34923399ece4..63b29c7279e2 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -14,23 +14,19 @@ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/of.h> #include <linux/pm_qos.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/input/touchscreen.h> #define ST1232_TS_NAME "st1232-ts" #define ST1633_TS_NAME "st1633-ts" -struct st1232_ts_finger { - u16 x; - u16 y; - u8 t; - bool is_valid; -}; +#define ST_TS_MAX_FINGERS 10 struct st_chip_info { bool have_z; @@ -50,79 +46,89 @@ struct st1232_ts_data { const struct st_chip_info *chip_info; int read_buf_len; u8 *read_buf; - struct st1232_ts_finger *finger; }; static int st1232_ts_read_data(struct st1232_ts_data *ts) { - struct st1232_ts_finger *finger = ts->finger; struct i2c_client *client = ts->client; - struct i2c_msg msg[2]; - int error; - int i, y; u8 start_reg = ts->chip_info->start_reg; - u8 *buf = ts->read_buf; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .len = sizeof(start_reg), + .buf = &start_reg, + }, + { + .addr = client->addr, + .flags = I2C_M_RD | I2C_M_DMA_SAFE, + .len = ts->read_buf_len, + .buf = ts->read_buf, + } + }; + int ret; - /* read touchscreen data */ - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = &start_reg; + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) + return ret < 0 ? ret : -EIO; - msg[1].addr = ts->client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = ts->read_buf_len; - msg[1].buf = buf; + return 0; +} - error = i2c_transfer(client->adapter, msg, 2); - if (error < 0) - return error; +static int st1232_ts_parse_and_report(struct st1232_ts_data *ts) +{ + struct input_dev *input = ts->input_dev; + struct input_mt_pos pos[ST_TS_MAX_FINGERS]; + u8 z[ST_TS_MAX_FINGERS]; + int slots[ST_TS_MAX_FINGERS]; + int n_contacts = 0; + int i; + + for (i = 0; i < ts->chip_info->max_fingers; i++) { + u8 *buf = &ts->read_buf[i * 4]; + + if (buf[0] & BIT(7)) { + unsigned int x = ((buf[0] & 0x70) << 4) | buf[1]; + unsigned int y = ((buf[0] & 0x07) << 8) | buf[2]; - for (i = 0, y = 0; i < ts->chip_info->max_fingers; i++, y += 3) { - finger[i].is_valid = buf[i + y] >> 7; - if (finger[i].is_valid) { - finger[i].x = ((buf[i + y] & 0x0070) << 4) | buf[i + 1]; - finger[i].y = ((buf[i + y] & 0x0007) << 8) | buf[i + 2]; + touchscreen_set_mt_pos(&pos[n_contacts], + &ts->prop, x, y); /* st1232 includes a z-axis / touch strength */ if (ts->chip_info->have_z) - finger[i].t = buf[i + 6]; + z[n_contacts] = ts->read_buf[i + 6]; + + n_contacts++; } } - return 0; + input_mt_assign_slots(input, slots, pos, n_contacts, 0); + for (i = 0; i < n_contacts; i++) { + input_mt_slot(input, slots[i]); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + input_report_abs(input, ABS_MT_POSITION_X, pos[i].x); + input_report_abs(input, ABS_MT_POSITION_Y, pos[i].y); + if (ts->chip_info->have_z) + input_report_abs(input, ABS_MT_TOUCH_MAJOR, z[i]); + } + + input_mt_sync_frame(input); + input_sync(input); + + return n_contacts; } static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id) { struct st1232_ts_data *ts = dev_id; - struct st1232_ts_finger *finger = ts->finger; - struct input_dev *input_dev = ts->input_dev; - int count = 0; - int i, ret; - - ret = st1232_ts_read_data(ts); - if (ret < 0) - goto end; - - /* multi touch protocol */ - for (i = 0; i < ts->chip_info->max_fingers; i++) { - if (!finger[i].is_valid) - continue; - - if (ts->chip_info->have_z) - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, - finger[i].t); + int count; + int error; - touchscreen_report_pos(input_dev, &ts->prop, - finger[i].x, finger[i].y, true); - input_mt_sync(input_dev); - count++; - } + error = st1232_ts_read_data(ts); + if (error) + goto out; - /* SYN_MT_REPORT only if no contact */ + count = st1232_ts_parse_and_report(ts); if (!count) { - input_mt_sync(input_dev); if (ts->low_latency_req.dev) { dev_pm_qos_remove_request(&ts->low_latency_req); ts->low_latency_req.dev = NULL; @@ -134,10 +140,7 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id) DEV_PM_QOS_RESUME_LATENCY, 100); } - /* SYN_REPORT */ - input_sync(input_dev); - -end: +out: return IRQ_HANDLED; } @@ -147,6 +150,11 @@ static void st1232_ts_power(struct st1232_ts_data *ts, bool poweron) gpiod_set_value_cansleep(ts->reset_gpio, !poweron); } +static void st1232_ts_power_off(void *data) +{ + st1232_ts_power(data, false); +} + static const struct st_chip_info st1232_chip_info = { .have_z = true, .max_x = 0x31f, /* 800 - 1 */ @@ -170,7 +178,6 @@ static int st1232_ts_probe(struct i2c_client *client, { const struct st_chip_info *match; struct st1232_ts_data *ts; - struct st1232_ts_finger *finger; struct input_dev *input_dev; int error; @@ -197,11 +204,6 @@ static int st1232_ts_probe(struct i2c_client *client, return -ENOMEM; ts->chip_info = match; - ts->finger = devm_kcalloc(&client->dev, - ts->chip_info->max_fingers, sizeof(*finger), - GFP_KERNEL); - if (!ts->finger) - return -ENOMEM; /* allocate a buffer according to the number of registers to read */ ts->read_buf_len = ts->chip_info->max_fingers * 4; @@ -227,14 +229,15 @@ static int st1232_ts_probe(struct i2c_client *client, st1232_ts_power(ts, true); + error = devm_add_action_or_reset(&client->dev, st1232_ts_power_off, ts); + if (error) { + dev_err(&client->dev, + "Failed to install power off action: %d\n", error); + return error; + } + input_dev->name = "st1232-touchscreen"; input_dev->id.bustype = BUS_I2C; - input_dev->dev.parent = &client->dev; - - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - __set_bit(EV_SYN, input_dev->evbit); - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(EV_ABS, input_dev->evbit); if (ts->chip_info->have_z) input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, @@ -247,6 +250,14 @@ static int st1232_ts_probe(struct i2c_client *client, touchscreen_parse_properties(input_dev, true, &ts->prop); + error = input_mt_init_slots(input_dev, ts->chip_info->max_fingers, + INPUT_MT_DIRECT | INPUT_MT_TRACK | + INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(&client->dev, "failed to initialize MT slots\n"); + return error; + } + error = devm_request_threaded_irq(&client->dev, client->irq, NULL, st1232_ts_irq_handler, IRQF_ONESHOT, @@ -264,16 +275,6 @@ static int st1232_ts_probe(struct i2c_client *client, } i2c_set_clientdata(client, ts); - device_init_wakeup(&client->dev, 1); - - return 0; -} - -static int st1232_ts_remove(struct i2c_client *client) -{ - struct st1232_ts_data *ts = i2c_get_clientdata(client); - - st1232_ts_power(ts, false); return 0; } @@ -283,12 +284,10 @@ static int __maybe_unused st1232_ts_suspend(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct st1232_ts_data *ts = i2c_get_clientdata(client); - if (device_may_wakeup(&client->dev)) { - enable_irq_wake(client->irq); - } else { - disable_irq(client->irq); + disable_irq(client->irq); + + if (!device_may_wakeup(&client->dev)) st1232_ts_power(ts, false); - } return 0; } @@ -298,12 +297,10 @@ static int __maybe_unused st1232_ts_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct st1232_ts_data *ts = i2c_get_clientdata(client); - if (device_may_wakeup(&client->dev)) { - disable_irq_wake(client->irq); - } else { + if (!device_may_wakeup(&client->dev)) st1232_ts_power(ts, true); - enable_irq(client->irq); - } + + enable_irq(client->irq); return 0; } @@ -327,7 +324,6 @@ MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids); static struct i2c_driver st1232_ts_driver = { .probe = st1232_ts_probe, - .remove = st1232_ts_remove, .id_table = st1232_ts_id, .driver = { .name = ST1232_TS_NAME, diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index f11ba7f2dca7..742a7e96c1b5 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -237,6 +237,7 @@ static int sun4i_ts_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct device *hwmon; + struct thermal_zone_device *thermal; int error; u32 reg; bool ts_attached; @@ -300,8 +301,7 @@ static int sun4i_ts_probe(struct platform_device *pdev) input_set_drvdata(ts->input, ts); } - ts->base = devm_ioremap_resource(dev, - platform_get_resource(pdev, IORESOURCE_MEM, 0)); + ts->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ts->base)) return PTR_ERR(ts->base); @@ -356,7 +356,10 @@ static int sun4i_ts_probe(struct platform_device *pdev) if (IS_ERR(hwmon)) return PTR_ERR(hwmon); - devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, &sun4i_ts_tz_ops); + thermal = devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, + &sun4i_ts_tz_ops); + if (IS_ERR(thermal)) + return PTR_ERR(thermal); writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 00cb1ba2d364..34d31c7ec8ba 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -27,7 +27,7 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/printk.h> -#include <linux/input-polldev.h> +#include <linux/input.h> #include <linux/input/mt.h> #include <linux/usb/input.h> #include <linux/videodev2.h> @@ -186,7 +186,7 @@ static const struct v4l2_pix_format sur40_pix_format[] = { .width = SENSOR_RES_X / 2, .height = SENSOR_RES_Y / 2, .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .bytesperline = SENSOR_RES_X / 2, .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2), }, @@ -195,7 +195,7 @@ static const struct v4l2_pix_format sur40_pix_format[] = { .width = SENSOR_RES_X / 2, .height = SENSOR_RES_Y / 2, .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .bytesperline = SENSOR_RES_X / 2, .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2), } @@ -206,7 +206,7 @@ struct sur40_state { struct usb_device *usbdev; struct device *dev; - struct input_polled_dev *input; + struct input_dev *input; struct v4l2_device v4l2; struct video_device vdev; @@ -370,6 +370,10 @@ static int sur40_init(struct sur40_state *dev) goto error; result = sur40_command(dev, SUR40_GET_VERSION, 0x03, buffer, 12); + if (result < 0) + goto error; + + result = 0; /* * Discard the result buffer - no known data inside except @@ -381,22 +385,22 @@ error: } /* - * Callback routines from input_polled_dev + * Callback routines from input_dev */ /* Enable the device, polling will now start. */ -static void sur40_open(struct input_polled_dev *polldev) +static int sur40_open(struct input_dev *input) { - struct sur40_state *sur40 = polldev->private; + struct sur40_state *sur40 = input_get_drvdata(input); dev_dbg(sur40->dev, "open\n"); - sur40_init(sur40); + return sur40_init(sur40); } /* Disable device, polling has stopped. */ -static void sur40_close(struct input_polled_dev *polldev) +static void sur40_close(struct input_dev *input) { - struct sur40_state *sur40 = polldev->private; + struct sur40_state *sur40 = input_get_drvdata(input); dev_dbg(sur40->dev, "close\n"); /* @@ -448,10 +452,9 @@ static void sur40_report_blob(struct sur40_blob *blob, struct input_dev *input) } /* core function: poll for new input data */ -static void sur40_poll(struct input_polled_dev *polldev) +static void sur40_poll(struct input_dev *input) { - struct sur40_state *sur40 = polldev->private; - struct input_dev *input = polldev->input; + struct sur40_state *sur40 = input_get_drvdata(input); int result, bulk_read, need_blobs, packet_blobs, i; u32 uninitialized_var(packet_id); @@ -613,10 +616,9 @@ err_poll: } /* Initialize input device parameters. */ -static void sur40_input_setup(struct input_dev *input_dev) +static int sur40_input_setup_events(struct input_dev *input_dev) { - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(EV_ABS, input_dev->evbit); + int error; input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, SENSOR_RES_X, 0, 0); @@ -637,8 +639,14 @@ static void sur40_input_setup(struct input_dev *input_dev) input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); - input_mt_init_slots(input_dev, MAX_CONTACTS, - INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + error = input_mt_init_slots(input_dev, MAX_CONTACTS, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(input_dev->dev.parent, "failed to set up slots\n"); + return error; + } + + return 0; } /* Check candidate USB interface. */ @@ -649,11 +657,11 @@ static int sur40_probe(struct usb_interface *interface, struct sur40_state *sur40; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; - struct input_polled_dev *poll_dev; + struct input_dev *input; int error; /* Check if we really have the right interface. */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; if (iface_desc->desc.bInterfaceClass != 0xFF) return -ENODEV; @@ -670,8 +678,8 @@ static int sur40_probe(struct usb_interface *interface, if (!sur40) return -ENOMEM; - poll_dev = input_allocate_polled_device(); - if (!poll_dev) { + input = input_allocate_device(); + if (!input) { error = -ENOMEM; goto err_free_dev; } @@ -681,26 +689,33 @@ static int sur40_probe(struct usb_interface *interface, spin_lock_init(&sur40->qlock); mutex_init(&sur40->lock); - /* Set up polled input device control structure */ - poll_dev->private = sur40; - poll_dev->poll_interval = POLL_INTERVAL; - poll_dev->open = sur40_open; - poll_dev->poll = sur40_poll; - poll_dev->close = sur40_close; - /* Set up regular input device structure */ - sur40_input_setup(poll_dev->input); - - poll_dev->input->name = DRIVER_LONG; - usb_to_input_id(usbdev, &poll_dev->input->id); + input->name = DRIVER_LONG; + usb_to_input_id(usbdev, &input->id); usb_make_path(usbdev, sur40->phys, sizeof(sur40->phys)); strlcat(sur40->phys, "/input0", sizeof(sur40->phys)); - poll_dev->input->phys = sur40->phys; - poll_dev->input->dev.parent = &interface->dev; + input->phys = sur40->phys; + input->dev.parent = &interface->dev; + + input->open = sur40_open; + input->close = sur40_close; + + error = sur40_input_setup_events(input); + if (error) + goto err_free_input; + + input_set_drvdata(input, sur40); + error = input_setup_polling(input, sur40_poll); + if (error) { + dev_err(&interface->dev, "failed to set up polling"); + goto err_free_input; + } + + input_set_poll_interval(input, POLL_INTERVAL); sur40->usbdev = usbdev; sur40->dev = &interface->dev; - sur40->input = poll_dev; + sur40->input = input; /* use the bulk-in endpoint tested above */ sur40->bulk_in_size = usb_endpoint_maxp(endpoint); @@ -709,11 +724,11 @@ static int sur40_probe(struct usb_interface *interface, if (!sur40->bulk_in_buffer) { dev_err(&interface->dev, "Unable to allocate input buffer."); error = -ENOMEM; - goto err_free_polldev; + goto err_free_input; } /* register the polled input device */ - error = input_register_polled_device(poll_dev); + error = input_register_device(input); if (error) { dev_err(&interface->dev, "Unable to register polled input device."); @@ -796,8 +811,8 @@ err_unreg_v4l2: v4l2_device_unregister(&sur40->v4l2); err_free_buffer: kfree(sur40->bulk_in_buffer); -err_free_polldev: - input_free_polled_device(sur40->input); +err_free_input: + input_free_device(input); err_free_dev: kfree(sur40); @@ -813,8 +828,7 @@ static void sur40_disconnect(struct usb_interface *interface) video_unregister_device(&sur40->vdev); v4l2_device_unregister(&sur40->v4l2); - input_unregister_polled_device(sur40->input); - input_free_polled_device(sur40->input); + input_unregister_device(sur40->input); kfree(sur40->bulk_in_buffer); kfree(sur40); diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index 75170a7439b1..357a3108f2e5 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c @@ -17,7 +17,6 @@ #include <linux/workqueue.h> #include <linux/slab.h> #include <linux/input.h> -#include <linux/input-polldev.h> #include <linux/platform_device.h> #include <linux/mfd/tps6507x.h> #include <linux/input/tps6507x-ts.h> @@ -40,7 +39,7 @@ struct ts_event { struct tps6507x_ts { struct device *dev; - struct input_polled_dev *poll_dev; + struct input_dev *input; struct tps6507x_dev *mfd; char phys[32]; struct ts_event tc; @@ -148,10 +147,9 @@ static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc) return ret; } -static void tps6507x_ts_poll(struct input_polled_dev *poll_dev) +static void tps6507x_ts_poll(struct input_dev *input_dev) { - struct tps6507x_ts *tsc = poll_dev->private; - struct input_dev *input_dev = poll_dev->input; + struct tps6507x_ts *tsc = input_get_drvdata(input_dev); bool pendown; s32 ret; @@ -205,7 +203,6 @@ static int tps6507x_ts_probe(struct platform_device *pdev) const struct tps6507x_board *tps_board; const struct touchscreen_init_data *init_data; struct tps6507x_ts *tsc; - struct input_polled_dev *poll_dev; struct input_dev *input_dev; int error; @@ -240,23 +237,16 @@ static int tps6507x_ts_probe(struct platform_device *pdev) snprintf(tsc->phys, sizeof(tsc->phys), "%s/input0", dev_name(tsc->dev)); - poll_dev = devm_input_allocate_polled_device(&pdev->dev); - if (!poll_dev) { + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) { dev_err(tsc->dev, "Failed to allocate polled input device.\n"); return -ENOMEM; } - tsc->poll_dev = poll_dev; - - poll_dev->private = tsc; - poll_dev->poll = tps6507x_ts_poll; - poll_dev->poll_interval = init_data ? - init_data->poll_period : TSC_DEFAULT_POLL_PERIOD; - - input_dev = poll_dev->input; - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + tsc->input = input_dev; + input_set_drvdata(input_dev, tsc); + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); input_set_abs_params(input_dev, ABS_X, 0, MAX_10BIT, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, MAX_10BIT, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0); @@ -275,7 +265,15 @@ static int tps6507x_ts_probe(struct platform_device *pdev) if (error) return error; - error = input_register_polled_device(poll_dev); + error = input_setup_polling(input_dev, tps6507x_ts_poll); + if (error) + return error; + + input_set_poll_interval(input_dev, + init_data ? init_data->poll_period : + TSC_DEFAULT_POLL_PERIOD); + + error = input_register_device(input_dev); if (error) return error; diff --git a/drivers/input/touchscreen/ts4800-ts.c b/drivers/input/touchscreen/ts4800-ts.c index fed73eeb47b3..6cf66aadc10e 100644 --- a/drivers/input/touchscreen/ts4800-ts.c +++ b/drivers/input/touchscreen/ts4800-ts.c @@ -10,7 +10,6 @@ #include <linux/bitops.h> #include <linux/input.h> -#include <linux/input-polldev.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/mfd/syscon.h> @@ -33,7 +32,7 @@ #define Y_OFFSET 0x2 struct ts4800_ts { - struct input_polled_dev *poll_dev; + struct input_dev *input; struct device *dev; char phys[32]; @@ -46,22 +45,26 @@ struct ts4800_ts { int debounce; }; -static void ts4800_ts_open(struct input_polled_dev *dev) +static int ts4800_ts_open(struct input_dev *input_dev) { - struct ts4800_ts *ts = dev->private; - int ret; + struct ts4800_ts *ts = input_get_drvdata(input_dev); + int error; ts->pendown = false; ts->debounce = DEBOUNCE_COUNT; - ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, ts->bit); - if (ret) - dev_warn(ts->dev, "Failed to enable touchscreen\n"); + error = regmap_update_bits(ts->regmap, ts->reg, ts->bit, ts->bit); + if (error) { + dev_warn(ts->dev, "Failed to enable touchscreen: %d\n", error); + return error; + } + + return 0; } -static void ts4800_ts_close(struct input_polled_dev *dev) +static void ts4800_ts_close(struct input_dev *input_dev) { - struct ts4800_ts *ts = dev->private; + struct ts4800_ts *ts = input_get_drvdata(input_dev); int ret; ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, 0); @@ -70,10 +73,9 @@ static void ts4800_ts_close(struct input_polled_dev *dev) } -static void ts4800_ts_poll(struct input_polled_dev *dev) +static void ts4800_ts_poll(struct input_dev *input_dev) { - struct input_dev *input_dev = dev->input; - struct ts4800_ts *ts = dev->private; + struct ts4800_ts *ts = input_get_drvdata(input_dev); u16 last_x = readw(ts->base + X_OFFSET); u16 last_y = readw(ts->base + Y_OFFSET); bool pendown = last_x & PENDOWN_MASK; @@ -146,9 +148,8 @@ static int ts4800_parse_dt(struct platform_device *pdev, static int ts4800_ts_probe(struct platform_device *pdev) { - struct input_polled_dev *poll_dev; + struct input_dev *input_dev; struct ts4800_ts *ts; - struct resource *res; int error; ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL); @@ -159,37 +160,42 @@ static int ts4800_ts_probe(struct platform_device *pdev) if (error) return error; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ts->base = devm_ioremap_resource(&pdev->dev, res); + ts->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ts->base)) return PTR_ERR(ts->base); - poll_dev = devm_input_allocate_polled_device(&pdev->dev); - if (!poll_dev) + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) return -ENOMEM; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&pdev->dev)); - ts->poll_dev = poll_dev; + ts->input = input_dev; ts->dev = &pdev->dev; - poll_dev->private = ts; - poll_dev->poll_interval = POLL_INTERVAL; - poll_dev->open = ts4800_ts_open; - poll_dev->close = ts4800_ts_close; - poll_dev->poll = ts4800_ts_poll; + input_set_drvdata(input_dev, ts); + + input_dev->name = "TS-4800 Touchscreen"; + input_dev->phys = ts->phys; + + input_dev->open = ts4800_ts_open; + input_dev->close = ts4800_ts_close; + + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); - poll_dev->input->name = "TS-4800 Touchscreen"; - poll_dev->input->phys = ts->phys; + error = input_setup_polling(input_dev, ts4800_ts_poll); + if (error) { + dev_err(&pdev->dev, "Unable to set up polling: %d\n", error); + return error; + } - input_set_capability(poll_dev->input, EV_KEY, BTN_TOUCH); - input_set_abs_params(poll_dev->input, ABS_X, 0, MAX_12BIT, 0, 0); - input_set_abs_params(poll_dev->input, ABS_Y, 0, MAX_12BIT, 0, 0); + input_set_poll_interval(input_dev, POLL_INTERVAL); - error = input_register_polled_device(poll_dev); + error = input_register_device(input_dev); if (error) { dev_err(&pdev->dev, - "Unabled to register polled input device (%d)\n", - error); + "Unable to register input device: %d\n", error); return error; } diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c deleted file mode 100644 index 7893d7fa398c..000000000000 --- a/drivers/input/touchscreen/w90p910_ts.c +++ /dev/null @@ -1,331 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2008 Nuvoton technology corporation. - * - * Wan ZongShun <mcuos.com@gmail.com> - */ - -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/input.h> -#include <linux/interrupt.h> -#include <linux/slab.h> - -/* ADC controller bit defines */ -#define ADC_DELAY 0xf00 -#define ADC_DOWN 0x01 -#define ADC_TSC_Y (0x01 << 8) -#define ADC_TSC_X (0x00 << 8) -#define TSC_FOURWIRE (~(0x03 << 1)) -#define ADC_CLK_EN (0x01 << 28) /* ADC clock enable */ -#define ADC_READ_CON (0x01 << 12) -#define ADC_CONV (0x01 << 13) -#define ADC_SEMIAUTO (0x01 << 14) -#define ADC_WAITTRIG (0x03 << 14) -#define ADC_RST1 (0x01 << 16) -#define ADC_RST0 (0x00 << 16) -#define ADC_EN (0x01 << 17) -#define ADC_INT (0x01 << 18) -#define WT_INT (0x01 << 20) -#define ADC_INT_EN (0x01 << 21) -#define LVD_INT_EN (0x01 << 22) -#define WT_INT_EN (0x01 << 23) -#define ADC_DIV (0x04 << 1) /* div = 6 */ - -enum ts_state { - TS_WAIT_NEW_PACKET, /* We are waiting next touch report */ - TS_WAIT_X_COORD, /* We are waiting for ADC to report X coord */ - TS_WAIT_Y_COORD, /* We are waiting for ADC to report Y coord */ - TS_IDLE, /* Input device is closed, don't do anything */ -}; - -struct w90p910_ts { - struct input_dev *input; - struct timer_list timer; - struct clk *clk; - int irq_num; - void __iomem *ts_reg; - spinlock_t lock; - enum ts_state state; -}; - -static void w90p910_report_event(struct w90p910_ts *w90p910_ts, bool down) -{ - struct input_dev *dev = w90p910_ts->input; - - if (down) { - input_report_abs(dev, ABS_X, - __raw_readl(w90p910_ts->ts_reg + 0x0c)); - input_report_abs(dev, ABS_Y, - __raw_readl(w90p910_ts->ts_reg + 0x10)); - } - - input_report_key(dev, BTN_TOUCH, down); - input_sync(dev); -} - -static void w90p910_prepare_x_reading(struct w90p910_ts *w90p910_ts) -{ - unsigned long ctlreg; - - __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg + 0x04); - ctlreg = __raw_readl(w90p910_ts->ts_reg); - ctlreg &= ~(ADC_WAITTRIG | WT_INT | WT_INT_EN); - ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; - __raw_writel(ctlreg, w90p910_ts->ts_reg); - - w90p910_ts->state = TS_WAIT_X_COORD; -} - -static void w90p910_prepare_y_reading(struct w90p910_ts *w90p910_ts) -{ - unsigned long ctlreg; - - __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg + 0x04); - ctlreg = __raw_readl(w90p910_ts->ts_reg); - ctlreg &= ~(ADC_WAITTRIG | ADC_INT | WT_INT_EN); - ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; - __raw_writel(ctlreg, w90p910_ts->ts_reg); - - w90p910_ts->state = TS_WAIT_Y_COORD; -} - -static void w90p910_prepare_next_packet(struct w90p910_ts *w90p910_ts) -{ - unsigned long ctlreg; - - ctlreg = __raw_readl(w90p910_ts->ts_reg); - ctlreg &= ~(ADC_INT | ADC_INT_EN | ADC_SEMIAUTO | ADC_CONV); - ctlreg |= ADC_WAITTRIG | WT_INT_EN; - __raw_writel(ctlreg, w90p910_ts->ts_reg); - - w90p910_ts->state = TS_WAIT_NEW_PACKET; -} - -static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id) -{ - struct w90p910_ts *w90p910_ts = dev_id; - unsigned long flags; - - spin_lock_irqsave(&w90p910_ts->lock, flags); - - switch (w90p910_ts->state) { - case TS_WAIT_NEW_PACKET: - /* - * The controller only generates interrupts when pen - * is down. - */ - del_timer(&w90p910_ts->timer); - w90p910_prepare_x_reading(w90p910_ts); - break; - - - case TS_WAIT_X_COORD: - w90p910_prepare_y_reading(w90p910_ts); - break; - - case TS_WAIT_Y_COORD: - w90p910_report_event(w90p910_ts, true); - w90p910_prepare_next_packet(w90p910_ts); - mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(100)); - break; - - case TS_IDLE: - break; - } - - spin_unlock_irqrestore(&w90p910_ts->lock, flags); - - return IRQ_HANDLED; -} - -static void w90p910_check_pen_up(struct timer_list *t) -{ - struct w90p910_ts *w90p910_ts = from_timer(w90p910_ts, t, timer); - unsigned long flags; - - spin_lock_irqsave(&w90p910_ts->lock, flags); - - if (w90p910_ts->state == TS_WAIT_NEW_PACKET && - !(__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN)) { - - w90p910_report_event(w90p910_ts, false); - } - - spin_unlock_irqrestore(&w90p910_ts->lock, flags); -} - -static int w90p910_open(struct input_dev *dev) -{ - struct w90p910_ts *w90p910_ts = input_get_drvdata(dev); - unsigned long val; - - /* enable the ADC clock */ - clk_enable(w90p910_ts->clk); - - __raw_writel(ADC_RST1, w90p910_ts->ts_reg); - msleep(1); - __raw_writel(ADC_RST0, w90p910_ts->ts_reg); - msleep(1); - - /* set delay and screen type */ - val = __raw_readl(w90p910_ts->ts_reg + 0x04); - __raw_writel(val & TSC_FOURWIRE, w90p910_ts->ts_reg + 0x04); - __raw_writel(ADC_DELAY, w90p910_ts->ts_reg + 0x08); - - w90p910_ts->state = TS_WAIT_NEW_PACKET; - wmb(); - - /* set trigger mode */ - val = __raw_readl(w90p910_ts->ts_reg); - val |= ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN; - __raw_writel(val, w90p910_ts->ts_reg); - - return 0; -} - -static void w90p910_close(struct input_dev *dev) -{ - struct w90p910_ts *w90p910_ts = input_get_drvdata(dev); - unsigned long val; - - /* disable trigger mode */ - - spin_lock_irq(&w90p910_ts->lock); - - w90p910_ts->state = TS_IDLE; - - val = __raw_readl(w90p910_ts->ts_reg); - val &= ~(ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN | ADC_INT_EN); - __raw_writel(val, w90p910_ts->ts_reg); - - spin_unlock_irq(&w90p910_ts->lock); - - /* Now that interrupts are shut off we can safely delete timer */ - del_timer_sync(&w90p910_ts->timer); - - /* stop the ADC clock */ - clk_disable(w90p910_ts->clk); -} - -static int w90x900ts_probe(struct platform_device *pdev) -{ - struct w90p910_ts *w90p910_ts; - struct input_dev *input_dev; - struct resource *res; - int err; - - w90p910_ts = kzalloc(sizeof(struct w90p910_ts), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!w90p910_ts || !input_dev) { - err = -ENOMEM; - goto fail1; - } - - w90p910_ts->input = input_dev; - w90p910_ts->state = TS_IDLE; - spin_lock_init(&w90p910_ts->lock); - timer_setup(&w90p910_ts->timer, w90p910_check_pen_up, 0); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - err = -ENXIO; - goto fail1; - } - - if (!request_mem_region(res->start, resource_size(res), - pdev->name)) { - err = -EBUSY; - goto fail1; - } - - w90p910_ts->ts_reg = ioremap(res->start, resource_size(res)); - if (!w90p910_ts->ts_reg) { - err = -ENOMEM; - goto fail2; - } - - w90p910_ts->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(w90p910_ts->clk)) { - err = PTR_ERR(w90p910_ts->clk); - goto fail3; - } - - input_dev->name = "W90P910 TouchScreen"; - input_dev->phys = "w90p910ts/event0"; - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0x0005; - input_dev->id.product = 0x0001; - input_dev->id.version = 0x0100; - input_dev->dev.parent = &pdev->dev; - input_dev->open = w90p910_open; - input_dev->close = w90p910_close; - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - - input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0); - input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0); - - input_set_drvdata(input_dev, w90p910_ts); - - w90p910_ts->irq_num = platform_get_irq(pdev, 0); - if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt, - 0, "w90p910ts", w90p910_ts)) { - err = -EBUSY; - goto fail4; - } - - err = input_register_device(w90p910_ts->input); - if (err) - goto fail5; - - platform_set_drvdata(pdev, w90p910_ts); - - return 0; - -fail5: free_irq(w90p910_ts->irq_num, w90p910_ts); -fail4: clk_put(w90p910_ts->clk); -fail3: iounmap(w90p910_ts->ts_reg); -fail2: release_mem_region(res->start, resource_size(res)); -fail1: input_free_device(input_dev); - kfree(w90p910_ts); - return err; -} - -static int w90x900ts_remove(struct platform_device *pdev) -{ - struct w90p910_ts *w90p910_ts = platform_get_drvdata(pdev); - struct resource *res; - - free_irq(w90p910_ts->irq_num, w90p910_ts); - del_timer_sync(&w90p910_ts->timer); - iounmap(w90p910_ts->ts_reg); - - clk_put(w90p910_ts->clk); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - input_unregister_device(w90p910_ts->input); - kfree(w90p910_ts); - - return 0; -} - -static struct platform_driver w90x900ts_driver = { - .probe = w90x900ts_probe, - .remove = w90x900ts_remove, - .driver = { - .name = "nuc900-ts", - }, -}; -module_platform_driver(w90x900ts_driver); - -MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); -MODULE_DESCRIPTION("w90p910 touch screen driver!"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:nuc900-ts"); diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index f017af8c2aa3..1afc6bde2891 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -12,7 +12,6 @@ #include <linux/slab.h> #include <linux/irq.h> #include <linux/interrupt.h> -#include <linux/gpio.h> #include <asm/unaligned.h> #define WACOM_CMD_QUERY0 0x04 diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 3715d1eace92..691285ace228 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -27,6 +27,8 @@ MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +#define W8001_MAX_PHYS 42 + #define W8001_MAX_LENGTH 13 #define W8001_LEAD_MASK 0x80 #define W8001_LEAD_BYTE 0x80 @@ -89,7 +91,7 @@ struct w8001 { unsigned char response_type; unsigned char response[W8001_MAX_LENGTH]; unsigned char data[W8001_MAX_LENGTH]; - char phys[32]; + char phys[W8001_MAX_PHYS]; int type; unsigned int pktlen; u16 max_touch_x; |