diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2021-07-04 23:05:31 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2021-07-04 23:05:31 -0700 |
commit | 818b26588994d9d95743fca0a427f08ec6c1c41d (patch) | |
tree | 870d9abed0e43b82257350a93e6517816815cd6c /drivers/input/touchscreen | |
parent | 45a4b68354ffccbc9ca71027bd34754ca24f5183 (diff) | |
parent | f8f84af5da9ee04ef1d271528656dac42a090d00 (diff) |
Merge branch 'next' into for-linus
Prepare input updates for 5.14 merge window.
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/cy8ctmg110_ts.c | 167 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp_core.c | 47 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp_core.h | 3 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp_i2c.c | 10 | ||||
-rw-r--r-- | drivers/input/touchscreen/cyttsp_spi.c | 10 | ||||
-rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 38 | ||||
-rw-r--r-- | drivers/input/touchscreen/hideep.c | 13 | ||||
-rw-r--r-- | drivers/input/touchscreen/resistive-adc-touch.c | 136 | ||||
-rw-r--r-- | drivers/input/touchscreen/tsc200x-core.c | 2 |
9 files changed, 284 insertions, 142 deletions
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index f465bae618fe..495ef156cf43 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -7,15 +7,14 @@ * Some cleanups by Alan Cox <alan@linux.intel.com> */ -#include <linux/module.h> -#include <linux/kernel.h> +#include <linux/i2c.h> #include <linux/input.h> -#include <linux/slab.h> #include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/i2c.h> -#include <linux/gpio.h> -#include <linux/input/cy8ctmg110_pdata.h> +#include <linux/gpio/consumer.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <asm/byteorder.h> #define CY8CTMG110_DRIVER_NAME "cy8ctmg110" @@ -45,18 +44,18 @@ struct cy8ctmg110 { struct input_dev *input; char phys[32]; struct i2c_client *client; - int reset_pin; - int irq_pin; + struct gpio_desc *reset_gpio; }; /* * cy8ctmg110_power is the routine that is called when touch hardware - * will powered off or on. + * is being powered off or on. When powering on this routine de-asserts + * the RESET line, when powering off reset line is asserted. */ static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron) { - if (ts->reset_pin) - gpio_direction_output(ts->reset_pin, 1 - poweron); + if (ts->reset_gpio) + gpiod_set_value_cansleep(ts->reset_gpio, !poweron); } static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg, @@ -112,7 +111,6 @@ static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc) { struct input_dev *input = tsc->input; unsigned char reg_p[CY8CTMG110_REG_MAX]; - int x, y; memset(reg_p, 0, CY8CTMG110_REG_MAX); @@ -120,16 +118,15 @@ static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc) if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0) return -EIO; - y = reg_p[2] << 8 | reg_p[3]; - x = reg_p[0] << 8 | reg_p[1]; - /* Number of touch */ if (reg_p[8] == 0) { input_report_key(input, BTN_TOUCH, 0); } else { input_report_key(input, BTN_TOUCH, 1); - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_X, + be16_to_cpup((__be16 *)(reg_p + 0))); + input_report_abs(input, ABS_Y, + be16_to_cpup((__be16 *)(reg_p + 2))); } input_sync(input); @@ -163,35 +160,35 @@ static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id) return IRQ_HANDLED; } +static void cy8ctmg110_shut_off(void *_ts) +{ + struct cy8ctmg110 *ts = _ts; + + cy8ctmg110_set_sleepmode(ts, true); + cy8ctmg110_power(ts, false); +} + static int cy8ctmg110_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct cy8ctmg110_pdata *pdata = dev_get_platdata(&client->dev); struct cy8ctmg110 *ts; struct input_dev *input_dev; int err; - /* No pdata no way forward */ - if (pdata == NULL) { - dev_err(&client->dev, "no pdata\n"); - return -ENODEV; - } - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) return -EIO; - ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ts || !input_dev) { - err = -ENOMEM; - goto err_free_mem; - } + ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&client->dev); + if (!input_dev) + return -ENOMEM; ts->client = client; ts->input = input_dev; - ts->reset_pin = pdata->reset_pin; - ts->irq_pin = pdata->irq_pin; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); @@ -199,84 +196,46 @@ static int cy8ctmg110_probe(struct i2c_client *client, input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen"; input_dev->phys = ts->phys; input_dev->id.bustype = BUS_I2C; - input_dev->dev.parent = &client->dev; - - 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_capability(input_dev, EV_KEY, BTN_TOUCH); input_set_abs_params(input_dev, ABS_X, CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0); input_set_abs_params(input_dev, ABS_Y, CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0); - if (ts->reset_pin) { - err = gpio_request(ts->reset_pin, NULL); - if (err) { - dev_err(&client->dev, - "Unable to request GPIO pin %d.\n", - ts->reset_pin); - goto err_free_mem; - } + /* Request and assert reset line */ + ts->reset_gpio = devm_gpiod_get_optional(&client->dev, NULL, + GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) { + err = PTR_ERR(ts->reset_gpio); + dev_err(&client->dev, + "Unable to request reset GPIO: %d\n", err); + return err; } cy8ctmg110_power(ts, true); cy8ctmg110_set_sleepmode(ts, false); - err = gpio_request(ts->irq_pin, "touch_irq_key"); - if (err < 0) { - dev_err(&client->dev, - "Failed to request GPIO %d, error %d\n", - ts->irq_pin, err); - goto err_shutoff_device; - } - - err = gpio_direction_input(ts->irq_pin); - if (err < 0) { - dev_err(&client->dev, - "Failed to configure input direction for GPIO %d, error %d\n", - ts->irq_pin, err); - goto err_free_irq_gpio; - } - - client->irq = gpio_to_irq(ts->irq_pin); - if (client->irq < 0) { - err = client->irq; - dev_err(&client->dev, - "Unable to get irq number for GPIO %d, error %d\n", - ts->irq_pin, err); - goto err_free_irq_gpio; - } + err = devm_add_action_or_reset(&client->dev, cy8ctmg110_shut_off, ts); + if (err) + return err; - err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "touch_reset_key", ts); - if (err < 0) { + err = devm_request_threaded_irq(&client->dev, client->irq, + NULL, cy8ctmg110_irq_thread, + IRQF_ONESHOT, "touch_reset_key", ts); + if (err) { dev_err(&client->dev, "irq %d busy? error %d\n", client->irq, err); - goto err_free_irq_gpio; + return err; } err = input_register_device(input_dev); if (err) - goto err_free_irq; + return err; i2c_set_clientdata(client, ts); - device_init_wakeup(&client->dev, 1); - return 0; -err_free_irq: - free_irq(client->irq, ts); -err_free_irq_gpio: - gpio_free(ts->irq_pin); -err_shutoff_device: - cy8ctmg110_set_sleepmode(ts, true); - cy8ctmg110_power(ts, false); - if (ts->reset_pin) - gpio_free(ts->reset_pin); -err_free_mem: - input_free_device(input_dev); - kfree(ts); - return err; + return 0; } static int __maybe_unused cy8ctmg110_suspend(struct device *dev) @@ -284,12 +243,11 @@ static int __maybe_unused cy8ctmg110_suspend(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct cy8ctmg110 *ts = i2c_get_clientdata(client); - if (device_may_wakeup(&client->dev)) - enable_irq_wake(client->irq); - else { + if (!device_may_wakeup(&client->dev)) { cy8ctmg110_set_sleepmode(ts, true); cy8ctmg110_power(ts, false); } + return 0; } @@ -298,34 +256,16 @@ static int __maybe_unused cy8ctmg110_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct cy8ctmg110 *ts = i2c_get_clientdata(client); - if (device_may_wakeup(&client->dev)) - disable_irq_wake(client->irq); - else { + if (!device_may_wakeup(&client->dev)) { cy8ctmg110_power(ts, true); cy8ctmg110_set_sleepmode(ts, false); } + return 0; } static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume); -static int cy8ctmg110_remove(struct i2c_client *client) -{ - struct cy8ctmg110 *ts = i2c_get_clientdata(client); - - cy8ctmg110_set_sleepmode(ts, true); - cy8ctmg110_power(ts, false); - - free_irq(client->irq, ts); - input_unregister_device(ts->input); - gpio_free(ts->irq_pin); - if (ts->reset_pin) - gpio_free(ts->reset_pin); - kfree(ts); - - return 0; -} - static const struct i2c_device_id cy8ctmg110_idtable[] = { { CY8CTMG110_DRIVER_NAME, 1 }, { } @@ -340,7 +280,6 @@ static struct i2c_driver cy8ctmg110_driver = { }, .id_table = cy8ctmg110_idtable, .probe = cy8ctmg110_probe, - .remove = cy8ctmg110_remove, }; module_i2c_driver(cy8ctmg110_driver); diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index 106dd4962785..1dbd849c9613 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/property.h> #include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> #include "cyttsp_core.h" @@ -45,8 +46,15 @@ #define CY_MAXZ 255 #define CY_DELAY_DFLT 20 /* ms */ #define CY_DELAY_MAX 500 -#define CY_ACT_DIST_DFLT 0xF8 +/* Active distance in pixels for a gesture to be reported */ +#define CY_ACT_DIST_DFLT 0xF8 /* pixels */ #define CY_ACT_DIST_MASK 0x0F +/* Active Power state scanning/processing refresh interval */ +#define CY_ACT_INTRVL_DFLT 0x00 /* ms */ +/* Low Power state scanning/processing refresh interval */ +#define CY_LP_INTRVL_DFLT 0x0A /* ms */ +/* touch timeout for the Active power */ +#define CY_TCH_TMOUT_DFLT 0xFF /* ms */ #define CY_HNDSHK_BIT 0x80 /* device mode bits */ #define CY_OPERATE_MODE 0x00 @@ -608,6 +616,14 @@ static int cyttsp_parse_properties(struct cyttsp *ts) return 0; } +static void cyttsp_disable_regulators(void *_ts) +{ + struct cyttsp *ts = _ts; + + regulator_bulk_disable(ARRAY_SIZE(ts->regulators), + ts->regulators); +} + struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, struct device *dev, int irq, size_t xfer_buf_size) { @@ -628,6 +644,32 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, ts->bus_ops = bus_ops; ts->irq = irq; + /* + * VCPIN is the analog voltage supply + * VDD is the digital voltage supply + */ + ts->regulators[0].supply = "vcpin"; + ts->regulators[1].supply = "vdd"; + error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators), + ts->regulators); + if (error) { + dev_err(dev, "Failed to get regulators: %d\n", error); + return ERR_PTR(error); + } + + error = regulator_bulk_enable(ARRAY_SIZE(ts->regulators), + ts->regulators); + if (error) { + dev_err(dev, "Cannot enable regulators: %d\n", error); + return ERR_PTR(error); + } + + error = devm_add_action_or_reset(dev, cyttsp_disable_regulators, ts); + if (error) { + dev_err(dev, "failed to install chip disable handler\n"); + return ERR_PTR(error); + } + ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ts->reset_gpio)) { error = PTR_ERR(ts->reset_gpio); @@ -664,8 +706,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, } error = devm_request_threaded_irq(dev, ts->irq, NULL, cyttsp_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT | - IRQF_NO_AUTOEN, + IRQF_ONESHOT | IRQF_NO_AUTOEN, "cyttsp", ts); if (error) { dev_err(ts->dev, "failed to request IRQ %d, err: %d\n", diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h index 9bc4fe7e6ac5..075509e695a2 100644 --- a/drivers/input/touchscreen/cyttsp_core.h +++ b/drivers/input/touchscreen/cyttsp_core.h @@ -22,7 +22,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/device.h> -#include <linux/input/cyttsp.h> +#include <linux/regulator/consumer.h> #define CY_NUM_RETRY 16 /* max number of retries for read ops */ @@ -122,6 +122,7 @@ struct cyttsp { enum cyttsp_state state; bool suspended; + struct regulator_bulk_data regulators[2]; struct gpio_desc *reset_gpio; bool use_hndshk; u8 act_dist; diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 061debf64a2b..4c8473d327ab 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -18,6 +18,8 @@ #include <linux/i2c.h> #include <linux/input.h> +#define CY_I2C_NAME "cyttsp-i2c" + #define CY_I2C_DATA_SIZE 128 static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = { @@ -52,10 +54,18 @@ static const struct i2c_device_id cyttsp_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id); +static const struct of_device_id cyttsp_of_i2c_match[] = { + { .compatible = "cypress,cy8ctma340", }, + { .compatible = "cypress,cy8ctst341", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, cyttsp_of_i2c_match); + static struct i2c_driver cyttsp_i2c_driver = { .driver = { .name = CY_I2C_NAME, .pm = &cyttsp_pm_ops, + .of_match_table = cyttsp_of_i2c_match, }, .probe = cyttsp_i2c_probe, .id_table = cyttsp_i2c_id, diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c index 54e410921d53..30c6fbf86a86 100644 --- a/drivers/input/touchscreen/cyttsp_spi.c +++ b/drivers/input/touchscreen/cyttsp_spi.c @@ -20,6 +20,8 @@ #include <linux/input.h> #include <linux/spi/spi.h> +#define CY_SPI_NAME "cyttsp-spi" + #define CY_SPI_WR_OP 0x00 /* r/~w */ #define CY_SPI_RD_OP 0x01 #define CY_SPI_CMD_BYTES 4 @@ -160,10 +162,18 @@ static int cyttsp_spi_probe(struct spi_device *spi) return 0; } +static const struct of_device_id cyttsp_of_spi_match[] = { + { .compatible = "cypress,cy8ctma340", }, + { .compatible = "cypress,cy8ctst341", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, cyttsp_of_spi_match); + static struct spi_driver cyttsp_spi_driver = { .driver = { .name = CY_SPI_NAME, .pm = &cyttsp_pm_ops, + .of_match_table = cyttsp_of_spi_match, }, .probe = cyttsp_spi_probe, }; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 2eefbc2485bc..263de3bfb6cd 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -104,6 +104,7 @@ struct edt_ft5x06_ts_data { u16 num_x; u16 num_y; struct regulator *vcc; + struct regulator *iovcc; struct gpio_desc *reset_gpio; struct gpio_desc *wake_gpio; @@ -1062,11 +1063,12 @@ static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) } } -static void edt_ft5x06_disable_regulator(void *arg) +static void edt_ft5x06_disable_regulators(void *arg) { struct edt_ft5x06_ts_data *data = arg; regulator_disable(data->vcc); + regulator_disable(data->iovcc); } static int edt_ft5x06_ts_probe(struct i2c_client *client, @@ -1107,14 +1109,33 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, return error; } + tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc"); + if (IS_ERR(tsdata->iovcc)) { + error = PTR_ERR(tsdata->iovcc); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "failed to request iovcc regulator: %d\n", error); + return error; + } + + error = regulator_enable(tsdata->iovcc); + if (error < 0) { + dev_err(&client->dev, "failed to enable iovcc: %d\n", error); + return error; + } + + /* Delay enabling VCC for > 10us (T_ivd) after IOVCC */ + usleep_range(10, 100); + error = regulator_enable(tsdata->vcc); if (error < 0) { dev_err(&client->dev, "failed to enable vcc: %d\n", error); + regulator_disable(tsdata->iovcc); return error; } error = devm_add_action_or_reset(&client->dev, - edt_ft5x06_disable_regulator, + edt_ft5x06_disable_regulators, tsdata); if (error) return error; @@ -1289,6 +1310,9 @@ static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev) ret = regulator_disable(tsdata->vcc); if (ret) dev_warn(dev, "Failed to disable vcc\n"); + ret = regulator_disable(tsdata->iovcc); + if (ret) + dev_warn(dev, "Failed to disable iovcc\n"); return 0; } @@ -1319,9 +1343,19 @@ static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev) gpiod_set_value_cansleep(reset_gpio, 1); usleep_range(5000, 6000); + ret = regulator_enable(tsdata->iovcc); + if (ret) { + dev_err(dev, "Failed to enable iovcc\n"); + return ret; + } + + /* Delay enabling VCC for > 10us (T_ivd) after IOVCC */ + usleep_range(10, 100); + ret = regulator_enable(tsdata->vcc); if (ret) { dev_err(dev, "Failed to enable vcc\n"); + regulator_disable(tsdata->iovcc); return ret; } diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index ddad4a82a5e5..e9547ee29756 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -361,13 +361,16 @@ static int hideep_enter_pgm(struct hideep_ts *ts) return -EIO; } -static void hideep_nvm_unlock(struct hideep_ts *ts) +static int hideep_nvm_unlock(struct hideep_ts *ts) { u32 unmask_code; + int error; hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_SFR_RPAGE); - hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code); + error = hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE); + if (error) + return error; /* make it unprotected code */ unmask_code &= ~HIDEEP_PROT_MODE; @@ -384,6 +387,8 @@ static void hideep_nvm_unlock(struct hideep_ts *ts) NVM_W_SFR(HIDEEP_NVM_MASK_OFS, ts->nvm_mask); SET_FLASH_HWCONTROL(); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE); + + return 0; } static int hideep_check_status(struct hideep_ts *ts) @@ -462,7 +467,9 @@ static int hideep_program_nvm(struct hideep_ts *ts, u32 addr = 0; int error; - hideep_nvm_unlock(ts); + error = hideep_nvm_unlock(ts); + if (error) + return error; while (ucode_len > 0) { xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE); diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c index e50af30183f4..744544a723b7 100644 --- a/drivers/input/touchscreen/resistive-adc-touch.c +++ b/drivers/input/touchscreen/resistive-adc-touch.c @@ -13,44 +13,78 @@ #include <linux/input/touchscreen.h> #include <linux/iio/consumer.h> #include <linux/iio/iio.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/property.h> #define DRIVER_NAME "resistive-adc-touch" #define GRTS_DEFAULT_PRESSURE_MIN 50000 +#define GRTS_DEFAULT_PRESSURE_MAX 65535 #define GRTS_MAX_POS_MASK GENMASK(11, 0) +#define GRTS_MAX_CHANNELS 4 + +enum grts_ch_type { + GRTS_CH_X, + GRTS_CH_Y, + GRTS_CH_PRESSURE, + GRTS_CH_Z1, + GRTS_CH_Z2, + GRTS_CH_MAX = GRTS_CH_Z2 + 1 +}; /** * struct grts_state - generic resistive touch screen information struct + * @x_plate_ohms: resistance of the X plate * @pressure_min: number representing the minimum for the pressure * @pressure: are we getting pressure info or not * @iio_chans: list of channels acquired * @iio_cb: iio_callback buffer for the data * @input: the input device structure that we register * @prop: touchscreen properties struct + * @ch_map: map of channels that are defined for the touchscreen */ struct grts_state { + u32 x_plate_ohms; u32 pressure_min; bool pressure; struct iio_channel *iio_chans; struct iio_cb_buffer *iio_cb; struct input_dev *input; struct touchscreen_properties prop; + u8 ch_map[GRTS_CH_MAX]; }; static int grts_cb(const void *data, void *private) { const u16 *touch_info = data; struct grts_state *st = private; - unsigned int x, y, press = 0x0; - - /* channel data coming in buffer in the order below */ - x = touch_info[0]; - y = touch_info[1]; - if (st->pressure) - press = touch_info[2]; + unsigned int x, y, press = 0; + + x = touch_info[st->ch_map[GRTS_CH_X]]; + y = touch_info[st->ch_map[GRTS_CH_Y]]; + + if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) { + press = touch_info[st->ch_map[GRTS_CH_PRESSURE]]; + } else if (st->ch_map[GRTS_CH_Z1] < GRTS_MAX_CHANNELS) { + unsigned int z1 = touch_info[st->ch_map[GRTS_CH_Z1]]; + unsigned int z2 = touch_info[st->ch_map[GRTS_CH_Z2]]; + unsigned int Rt; + + Rt = z2; + Rt -= z1; + Rt *= st->x_plate_ohms; + Rt = DIV_ROUND_CLOSEST(Rt, 16); + Rt *= x; + Rt /= z1; + Rt = DIV_ROUND_CLOSEST(Rt, 256); + /* + * On increased pressure the resistance (Rt) is decreasing + * so, convert values to make it looks as real pressure. + */ + if (Rt < GRTS_DEFAULT_PRESSURE_MAX) + press = GRTS_DEFAULT_PRESSURE_MAX - Rt; + } if ((!x && !y) || (st->pressure && (press < st->pressure_min))) { /* report end of touch */ @@ -94,12 +128,77 @@ static void grts_disable(void *data) iio_channel_release_all_cb(data); } +static int grts_map_channel(struct grts_state *st, struct device *dev, + enum grts_ch_type type, const char *name, + bool optional) +{ + int idx; + + idx = device_property_match_string(dev, "io-channel-names", name); + if (idx < 0) { + if (!optional) + return idx; + idx = GRTS_MAX_CHANNELS; + } else if (idx >= GRTS_MAX_CHANNELS) { + return -EOVERFLOW; + } + + st->ch_map[type] = idx; + return 0; +} + +static int grts_get_properties(struct grts_state *st, struct device *dev) +{ + int error; + + error = grts_map_channel(st, dev, GRTS_CH_X, "x", false); + if (error) + return error; + + error = grts_map_channel(st, dev, GRTS_CH_Y, "y", false); + if (error) + return error; + + /* pressure is optional */ + error = grts_map_channel(st, dev, GRTS_CH_PRESSURE, "pressure", true); + if (error) + return error; + + if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) { + st->pressure = true; + return 0; + } + + /* if no pressure is defined, try optional z1 + z2 */ + error = grts_map_channel(st, dev, GRTS_CH_Z1, "z1", true); + if (error) + return error; + + if (st->ch_map[GRTS_CH_Z1] >= GRTS_MAX_CHANNELS) + return 0; + + /* if z1 is provided z2 is not optional */ + error = grts_map_channel(st, dev, GRTS_CH_Z2, "z2", true); + if (error) + return error; + + error = device_property_read_u32(dev, + "touchscreen-x-plate-ohms", + &st->x_plate_ohms); + if (error) { + dev_err(dev, "can't get touchscreen-x-plate-ohms property\n"); + return error; + } + + st->pressure = true; + return 0; +} + static int grts_probe(struct platform_device *pdev) { struct grts_state *st; struct input_dev *input; struct device *dev = &pdev->dev; - struct iio_channel *chan; int error; st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL); @@ -115,12 +214,13 @@ static int grts_probe(struct platform_device *pdev) return error; } - chan = &st->iio_chans[0]; - st->pressure = false; - while (chan && chan->indio_dev) { - if (!strcmp(chan->channel->datasheet_name, "pressure")) - st->pressure = true; - chan++; + if (!device_property_present(dev, "io-channel-names")) + return -ENODEV; + + error = grts_get_properties(st, dev); + if (error) { + dev_err(dev, "Failed to parse properties\n"); + return error; } if (st->pressure) { @@ -148,7 +248,7 @@ static int grts_probe(struct platform_device *pdev) input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0); if (st->pressure) input_set_abs_params(input, ABS_PRESSURE, st->pressure_min, - 0xffff, 0, 0); + GRTS_DEFAULT_PRESSURE_MAX, 0, 0); input_set_capability(input, EV_KEY, BTN_TOUCH); @@ -193,7 +293,7 @@ static struct platform_driver grts_driver = { .probe = grts_probe, .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(grts_of_match), + .of_match_table = grts_of_match, }, }; diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index ce2fe30d6b8a..b8d720d52013 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -338,7 +338,7 @@ static struct attribute *tsc200x_attrs[] = { static umode_t tsc200x_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct tsc200x *ts = dev_get_drvdata(dev); umode_t mode = attr->mode; |