diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-09-03 20:01:44 +0300 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-09-03 20:01:44 +0300 |
commit | 01b944fe1cd4e21a2a9ed51adbdbafe2d5e905ba (patch) | |
tree | 85f506cf9fce3d8fd47cf624dd8698472bffc13f /drivers/input/touchscreen | |
parent | e51e38494a8ecc18650efb0c840600637891de2c (diff) | |
parent | 58f1eae48e5372200553de07b5ecc7574803ee91 (diff) | |
download | linux-01b944fe1cd4e21a2a9ed51adbdbafe2d5e905ba.tar.xz |
Merge branch 'next' into for-linus
Prepare first round of input updates for 4.3 merge window.
Diffstat (limited to 'drivers/input/touchscreen')
28 files changed, 1115 insertions, 469 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index aa2b5f21b89b..059edeb7f04a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -11,9 +11,9 @@ menuconfig INPUT_TOUCHSCREEN if INPUT_TOUCHSCREEN -config OF_TOUCHSCREEN +config TOUCHSCREEN_PROPERTIES def_tristate INPUT - depends on INPUT && OF + depends on INPUT config TOUCHSCREEN_88PM860X tristate "Marvell 88PM860x touchscreen" @@ -118,7 +118,7 @@ config TOUCHSCREEN_ATMEL_MXT config TOUCHSCREEN_AUO_PIXCIR tristate "AUO in-cell touchscreen using Pixcir ICs" depends on I2C - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here if you have a AUO display with in-cell touchscreen using Pixcir ICs. @@ -142,7 +142,7 @@ config TOUCHSCREEN_BU21013 config TOUCHSCREEN_CHIPONE_ICN8318 tristate "chipone icn8318 touchscreen controller" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST depends on I2C depends on OF help @@ -156,7 +156,7 @@ config TOUCHSCREEN_CHIPONE_ICN8318 config TOUCHSCREEN_CY8CTMG110 tristate "cy8ctmg110 touchscreen" depends on I2C - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here if you have a cy8ctmg110 capacitive touchscreen on an AAVA device. @@ -915,10 +915,11 @@ config TOUCHSCREEN_TSC_SERIO module will be called tsc40. config TOUCHSCREEN_TSC2005 - tristate "TSC2005 based touchscreens" - depends on SPI_MASTER - help - Say Y here if you have a TSC2005 based touchscreen. + tristate "TSC2005 based touchscreens" + depends on SPI_MASTER + select REGMAP_SPI + help + Say Y here if you have a TSC2005 based touchscreen. If unsure, say N. @@ -992,8 +993,9 @@ config TOUCHSCREEN_SUN4I config TOUCHSCREEN_SUR40 tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" - depends on USB + depends on USB && MEDIA_USB_SUPPORT && HAS_DMA select INPUT_POLLDEV + select VIDEOBUF2_DMA_SG help Say Y here if you want support for the Samsung SUR40 touchscreen (also known as Microsoft Surface 2.0 or Microsoft PixelSense). @@ -1028,7 +1030,7 @@ config TOUCHSCREEN_TPS6507X config TOUCHSCREEN_ZFORCE tristate "Neonode zForce infrared touchscreens" depends on I2C - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here if you have a touchscreen using the zforce infraread technology from Neonode. diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index fa3d33bac7fc..c85aae23e7f8 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -6,7 +6,7 @@ wm97xx-ts-y := wm97xx-core.o -obj-$(CONFIG_OF_TOUCHSCREEN) += of_touchscreen.o +obj-$(CONFIG_TOUCHSCREEN_PROPERTIES) += of_touchscreen.o obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index dcf390771549..d66962c5b1c2 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -94,7 +94,6 @@ MODULE_DEVICE_TABLE(i2c, ad7879_id); static struct i2c_driver ad7879_i2c_driver = { .driver = { .name = "ad7879", - .owner = THIS_MODULE, .pm = &ad7879_pm_ops, }, .probe = ad7879_i2c_probe, diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index e4eb8a6c658f..0f5f968592bd 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1234,7 +1234,8 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) of_property_read_u32(node, "ti,pendown-gpio-debounce", &pdata->gpio_pendown_debounce); - pdata->wakeup = of_property_read_bool(node, "linux,wakeup"); + pdata->wakeup = of_property_read_bool(node, "wakeup-source") || + of_property_read_bool(node, "linux,wakeup"); pdata->gpio_pendown = of_get_named_gpio(dev->of_node, "pendown-gpio", 0); diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index f0b954d46a25..71b5a634cf6d 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -166,7 +166,6 @@ MODULE_DEVICE_TABLE(of, ar1021_i2c_of_match); static struct i2c_driver ar1021_i2c_driver = { .driver = { .name = "ar1021_i2c", - .owner = THIS_MODULE, .pm = &ar1021_i2c_pm, .of_match_table = ar1021_i2c_of_match, }, diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index dfc7309e3d38..c5622058c22b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -22,34 +22,20 @@ #include <linux/delay.h> #include <linux/firmware.h> #include <linux/i2c.h> -#include <linux/i2c/atmel_mxt_ts.h> +#include <linux/platform_data/atmel_mxt_ts.h> #include <linux/input/mt.h> #include <linux/interrupt.h> #include <linux/of.h> #include <linux/slab.h> #include <asm/unaligned.h> -/* Version */ -#define MXT_VER_20 20 -#define MXT_VER_21 21 -#define MXT_VER_22 22 - /* Firmware files */ #define MXT_FW_NAME "maxtouch.fw" #define MXT_CFG_NAME "maxtouch.cfg" #define MXT_CFG_MAGIC "OBP_RAW V1" /* Registers */ -#define MXT_INFO 0x00 -#define MXT_FAMILY_ID 0x00 -#define MXT_VARIANT_ID 0x01 -#define MXT_VERSION 0x02 -#define MXT_BUILD 0x03 -#define MXT_MATRIX_X_SIZE 0x04 -#define MXT_MATRIX_Y_SIZE 0x05 -#define MXT_OBJECT_NUM 0x06 #define MXT_OBJECT_START 0x07 - #define MXT_OBJECT_SIZE 6 #define MXT_INFO_CHECKSUM_SIZE 3 #define MXT_MAX_BLOCK_WRITE 256 @@ -103,21 +89,16 @@ #define MXT_T6_STATUS_COMSERR (1 << 2) /* MXT_GEN_POWER_T7 field */ -#define MXT_POWER_IDLEACQINT 0 -#define MXT_POWER_ACTVACQINT 1 -#define MXT_POWER_ACTV2IDLETO 2 - -/* MXT_GEN_ACQUIRE_T8 field */ -#define MXT_ACQUIRE_CHRGTIME 0 -#define MXT_ACQUIRE_TCHDRIFT 2 -#define MXT_ACQUIRE_DRIFTST 3 -#define MXT_ACQUIRE_TCHAUTOCAL 4 -#define MXT_ACQUIRE_SYNC 5 -#define MXT_ACQUIRE_ATCHCALST 6 -#define MXT_ACQUIRE_ATCHCALSTHR 7 +struct t7_config { + u8 idle; + u8 active; +} __packed; + +#define MXT_POWER_CFG_RUN 0 +#define MXT_POWER_CFG_DEEPSLEEP 1 /* MXT_TOUCH_MULTI_T9 field */ -#define MXT_TOUCH_CTRL 0 +#define MXT_T9_CTRL 0 #define MXT_T9_ORIENT 9 #define MXT_T9_RANGE 18 @@ -139,51 +120,10 @@ struct t9_range { /* MXT_TOUCH_MULTI_T9 orient */ #define MXT_T9_ORIENT_SWITCH (1 << 0) -/* MXT_PROCI_GRIPFACE_T20 field */ -#define MXT_GRIPFACE_CTRL 0 -#define MXT_GRIPFACE_XLOGRIP 1 -#define MXT_GRIPFACE_XHIGRIP 2 -#define MXT_GRIPFACE_YLOGRIP 3 -#define MXT_GRIPFACE_YHIGRIP 4 -#define MXT_GRIPFACE_MAXTCHS 5 -#define MXT_GRIPFACE_SZTHR1 7 -#define MXT_GRIPFACE_SZTHR2 8 -#define MXT_GRIPFACE_SHPTHR1 9 -#define MXT_GRIPFACE_SHPTHR2 10 -#define MXT_GRIPFACE_SUPEXTTO 11 - -/* MXT_PROCI_NOISE field */ -#define MXT_NOISE_CTRL 0 -#define MXT_NOISE_OUTFLEN 1 -#define MXT_NOISE_GCAFUL_LSB 3 -#define MXT_NOISE_GCAFUL_MSB 4 -#define MXT_NOISE_GCAFLL_LSB 5 -#define MXT_NOISE_GCAFLL_MSB 6 -#define MXT_NOISE_ACTVGCAFVALID 7 -#define MXT_NOISE_NOISETHR 8 -#define MXT_NOISE_FREQHOPSCALE 10 -#define MXT_NOISE_FREQ0 11 -#define MXT_NOISE_FREQ1 12 -#define MXT_NOISE_FREQ2 13 -#define MXT_NOISE_FREQ3 14 -#define MXT_NOISE_FREQ4 15 -#define MXT_NOISE_IDLEGCAFVALID 16 - /* MXT_SPT_COMMSCONFIG_T18 */ #define MXT_COMMS_CTRL 0 #define MXT_COMMS_CMD 1 -/* MXT_SPT_CTECONFIG_T28 field */ -#define MXT_CTE_CTRL 0 -#define MXT_CTE_CMD 1 -#define MXT_CTE_MODE 2 -#define MXT_CTE_IDLEGCAFDEPTH 3 -#define MXT_CTE_ACTVGCAFDEPTH 4 -#define MXT_CTE_VOLTAGE 5 - -#define MXT_VOLTAGE_DEFAULT 2700000 -#define MXT_VOLTAGE_STEP 10000 - /* Define for MXT_GEN_COMMAND_T6 */ #define MXT_BOOT_VALUE 0xa5 #define MXT_RESET_VALUE 0x01 @@ -291,6 +231,7 @@ struct mxt_data { u8 last_message_count; u8 num_touchids; u8 multitouch; + struct t7_config t7_cfg; /* Cached parameters from object table */ u16 T5_address; @@ -997,16 +938,15 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data) count = data->msg_buf[0]; - if (count == 0) { - /* - * This condition is caused by the CHG line being configured - * in Mode 0. It results in unnecessary I2C operations but it - * is benign. - */ - dev_dbg(dev, "Interrupt triggered but zero messages\n"); + /* + * This condition may be caused by the CHG line being configured in + * Mode 0. It results in unnecessary I2C operations but it is benign. + */ + if (count == 0) return IRQ_NONE; - } else if (count > data->max_reportid) { - dev_err(dev, "T44 count %d exceeded max report id\n", count); + + if (count > data->max_reportid) { + dev_warn(dev, "T44 count %d exceeded max report id\n", count); count = data->max_reportid; } @@ -1157,7 +1097,9 @@ static int mxt_soft_reset(struct mxt_data *data) struct device *dev = &data->client->dev; int ret = 0; - dev_info(dev, "Resetting chip\n"); + dev_info(dev, "Resetting device\n"); + + disable_irq(data->irq); reinit_completion(&data->reset_completion); @@ -1165,6 +1107,11 @@ static int mxt_soft_reset(struct mxt_data *data) if (ret) return ret; + /* Ignore CHG line for 100ms after reset */ + msleep(100); + + enable_irq(data->irq); + ret = mxt_wait_for_completion(data, &data->reset_completion, MXT_RESET_TIMEOUT); if (ret) @@ -1361,6 +1308,8 @@ static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start, return 0; } +static int mxt_init_t7_power_cfg(struct mxt_data *data); + /* * mxt_update_cfg - download configuration to chip * @@ -1508,6 +1457,9 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) dev_info(dev, "Config successfully updated\n"); + /* T7 config may have changed */ + mxt_init_t7_power_cfg(data); + release_mem: kfree(config_mem); return ret; @@ -1533,7 +1485,7 @@ static int mxt_get_info(struct mxt_data *data) int error; /* Read 7-byte info block starting at address 0 */ - error = __mxt_read_reg(client, MXT_INFO, sizeof(*info), info); + error = __mxt_read_reg(client, 0, sizeof(*info), info); if (error) return error; @@ -1905,6 +1857,8 @@ static int mxt_initialize_input_device(struct mxt_data *data) if (pdata->t19_num_keys) { mxt_set_up_as_touchpad(input_dev, data); mt_flags |= INPUT_MT_POINTER; + } else { + mt_flags |= INPUT_MT_DIRECT; } /* For multi touch */ @@ -2051,6 +2005,60 @@ err_free_object_table: return error; } +static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep) +{ + struct device *dev = &data->client->dev; + int error; + struct t7_config *new_config; + struct t7_config deepsleep = { .active = 0, .idle = 0 }; + + if (sleep == MXT_POWER_CFG_DEEPSLEEP) + new_config = &deepsleep; + else + new_config = &data->t7_cfg; + + error = __mxt_write_reg(data->client, data->T7_address, + sizeof(data->t7_cfg), new_config); + if (error) + return error; + + dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n", + new_config->active, new_config->idle); + + return 0; +} + +static int mxt_init_t7_power_cfg(struct mxt_data *data) +{ + struct device *dev = &data->client->dev; + int error; + bool retry = false; + +recheck: + error = __mxt_read_reg(data->client, data->T7_address, + sizeof(data->t7_cfg), &data->t7_cfg); + if (error) + return error; + + if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) { + if (!retry) { + dev_dbg(dev, "T7 cfg zero, resetting\n"); + mxt_soft_reset(data); + retry = true; + goto recheck; + } else { + dev_dbg(dev, "T7 cfg zero after reset, overriding\n"); + data->t7_cfg.active = 20; + data->t7_cfg.idle = 100; + return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); + } + } + + dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n", + data->t7_cfg.active, data->t7_cfg.idle); + return 0; +} + static int mxt_configure_objects(struct mxt_data *data, const struct firmware *cfg) { @@ -2058,6 +2066,12 @@ static int mxt_configure_objects(struct mxt_data *data, struct mxt_info *info = &data->info; int error; + error = mxt_init_t7_power_cfg(data); + if (error) { + dev_err(dev, "Failed to initialize power cfg\n"); + return error; + } + if (cfg) { error = mxt_update_cfg(data, cfg); if (error) @@ -2346,14 +2360,41 @@ static const struct attribute_group mxt_attr_group = { static void mxt_start(struct mxt_data *data) { - /* Touch enable */ - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0x83); + switch (data->pdata->suspend_mode) { + case MXT_SUSPEND_T9_CTRL: + mxt_soft_reset(data); + + /* Touch enable */ + /* 0x83 = SCANEN | RPTEN | ENABLE */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83); + break; + + case MXT_SUSPEND_DEEP_SLEEP: + default: + mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); + + /* Recalibrate since chip has been in deep sleep */ + mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); + break; + } + } static void mxt_stop(struct mxt_data *data) { - /* Touch disable */ - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0); + switch (data->pdata->suspend_mode) { + case MXT_SUSPEND_T9_CTRL: + /* Touch disable */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0); + break; + + case MXT_SUSPEND_DEEP_SLEEP: + default: + mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP); + break; + } } static int mxt_input_open(struct input_dev *dev) @@ -2376,19 +2417,18 @@ static void mxt_input_close(struct input_dev *dev) static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) { struct mxt_platform_data *pdata; + struct device_node *np = client->dev.of_node; u32 *keymap; - u32 keycode; - int proplen, i, ret; + int proplen, ret; - if (!client->dev.of_node) + if (!np) return ERR_PTR(-ENOENT); pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - if (of_find_property(client->dev.of_node, "linux,gpio-keymap", - &proplen)) { + if (of_find_property(np, "linux,gpio-keymap", &proplen)) { pdata->t19_num_keys = proplen / sizeof(u32); keymap = devm_kzalloc(&client->dev, @@ -2397,18 +2437,17 @@ static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) if (!keymap) return ERR_PTR(-ENOMEM); - for (i = 0; i < pdata->t19_num_keys; i++) { - ret = of_property_read_u32_index(client->dev.of_node, - "linux,gpio-keymap", i, &keycode); - if (ret) - keycode = KEY_RESERVED; - - keymap[i] = keycode; - } + ret = of_property_read_u32_array(np, "linux,gpio-keymap", + keymap, pdata->t19_num_keys); + if (ret) + dev_warn(&client->dev, + "Couldn't read linux,gpio-keymap: %d\n", ret); pdata->t19_keymap = keymap; } + pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP; + return pdata; } #else @@ -2609,6 +2648,9 @@ static int __maybe_unused mxt_suspend(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; + if (!input_dev) + return 0; + mutex_lock(&input_dev->mutex); if (input_dev->users) @@ -2625,7 +2667,8 @@ static int __maybe_unused mxt_resume(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; - mxt_soft_reset(data); + if (!input_dev) + return 0; mutex_lock(&input_dev->mutex); @@ -2666,7 +2709,6 @@ MODULE_DEVICE_TABLE(i2c, mxt_id); static struct i2c_driver mxt_driver = { .driver = { .name = "atmel_mxt_ts", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mxt_of_match), .acpi_match_table = ACPI_PTR(mxt_acpi_id), .pm = &mxt_pm_ops, diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 40e02dd5b2f9..38c06f754acd 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -686,7 +686,6 @@ MODULE_DEVICE_TABLE(of, auo_pixcir_ts_dt_idtable); static struct i2c_driver auo_pixcir_driver = { .driver = { - .owner = THIS_MODULE, .name = "auo_pixcir_ts", .pm = &auo_pixcir_pm_ops, .of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable), diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index b9b5ddad6658..931417eb4f5a 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -716,7 +716,6 @@ MODULE_DEVICE_TABLE(i2c, bu21013_id); static struct i2c_driver bu21013_driver = { .driver = { .name = DRIVER_TP, - .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &bu21013_dev_pm_ops, #endif diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c index 32e9db0e04bf..22a6fead8cfb 100644 --- a/drivers/input/touchscreen/chipone_icn8318.c +++ b/drivers/input/touchscreen/chipone_icn8318.c @@ -300,7 +300,6 @@ MODULE_DEVICE_TABLE(i2c, icn8318_i2c_id); static struct i2c_driver icn8318_driver = { .driver = { - .owner = THIS_MODULE, .name = "chipone_icn8318", .pm = &icn8318_pm_ops, .of_match_table = icn8318_of_match, diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index f2119ee0e21b..cc1d1350074e 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -347,7 +347,6 @@ MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable); static struct i2c_driver cy8ctmg110_driver = { .driver = { - .owner = THIS_MODULE, .name = CY8CTMG110_DRIVER_NAME, .pm = &cy8ctmg110_pm, }, diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c index 8e2012c79058..9a323dd915de 100644 --- a/drivers/input/touchscreen/cyttsp4_i2c.c +++ b/drivers/input/touchscreen/cyttsp4_i2c.c @@ -74,7 +74,6 @@ MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id); static struct i2c_driver cyttsp4_i2c_driver = { .driver = { .name = CYTTSP4_I2C_NAME, - .owner = THIS_MODULE, .pm = &cyttsp4_pm_ops, }, .probe = cyttsp4_i2c_probe, diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 63104a86a9bd..519e2de2f8df 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -74,7 +74,6 @@ MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id); static struct i2c_driver cyttsp_i2c_driver = { .driver = { .name = CY_I2C_NAME, - .owner = THIS_MODULE, .pm = &cyttsp_pm_ops, }, .probe = cyttsp_i2c_probe, diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 394b1de9a2a3..48de1e8b3c93 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1041,7 +1041,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, 0, tsdata->num_y * 64 - 1, 0, 0); if (!pdata) - touchscreen_parse_of_params(input, true); + touchscreen_parse_properties(input, true); error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT); if (error) { @@ -1134,7 +1134,6 @@ MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); static struct i2c_driver edt_ft5x06_ts_driver = { .driver = { - .owner = THIS_MODULE, .name = "edt_ft5x06", .of_match_table = of_match_ptr(edt_ft5x06_of_match), .pm = &edt_ft5x06_ts_pm_ops, diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 4c56299284ef..1afc08b08155 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -264,11 +264,11 @@ static const struct of_device_id egalax_ts_dt_ids[] = { { .compatible = "eeti,egalax_ts" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, egalax_ts_dt_ids); static struct i2c_driver egalax_ts_driver = { .driver = { .name = "egalax_ts", - .owner = THIS_MODULE, .pm = &egalax_ts_pm_ops, .of_match_table = egalax_ts_dt_ids, }, diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 0efd766a545b..ddac134b25b1 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -38,6 +38,8 @@ #include <linux/input/mt.h> #include <linux/acpi.h> #include <linux/of.h> +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> #include <asm/unaligned.h> /* Device, Driver information */ @@ -102,6 +104,9 @@ /* calibration timeout definition */ #define ELAN_CALI_TIMEOUT_MSEC 10000 +#define ELAN_POWERON_DELAY_USEC 500 +#define ELAN_RESET_DELAY_MSEC 20 + enum elants_state { ELAN_STATE_NORMAL, ELAN_WAIT_QUEUE_HEADER, @@ -118,6 +123,10 @@ struct elants_data { struct i2c_client *client; struct input_dev *input; + struct regulator *vcc33; + struct regulator *vccio; + struct gpio_desc *reset_gpio; + u16 fw_version; u8 test_version; u8 solution_version; @@ -141,6 +150,7 @@ struct elants_data { u8 buf[MAX_PACKET_SIZE]; bool wake_irq_enabled; + bool keep_power_in_suspend; }; static int elants_i2c_send(struct i2c_client *client, @@ -605,6 +615,7 @@ static int elants_i2c_do_update_firmware(struct i2c_client *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}; u8 buf[HEADER_SIZE]; u16 send_id; int page, n_fw_pages; @@ -617,8 +628,13 @@ static int elants_i2c_do_update_firmware(struct i2c_client *client, } 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)); } @@ -1052,6 +1068,67 @@ static void elants_i2c_remove_sysfs_group(void *_data) sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group); } +static int elants_i2c_power_on(struct elants_data *ts) +{ + int error; + + /* + * If we do not have reset gpio assume platform firmware + * controls regulators and does power them on for us. + */ + if (IS_ERR_OR_NULL(ts->reset_gpio)) + return 0; + + gpiod_set_value_cansleep(ts->reset_gpio, 1); + + error = regulator_enable(ts->vcc33); + if (error) { + dev_err(&ts->client->dev, + "failed to enable vcc33 regulator: %d\n", + error); + goto release_reset_gpio; + } + + error = regulator_enable(ts->vccio); + if (error) { + dev_err(&ts->client->dev, + "failed to enable vccio regulator: %d\n", + error); + regulator_disable(ts->vcc33); + goto release_reset_gpio; + } + + /* + * We need to wait a bit after powering on controller before + * we are allowed to release reset GPIO. + */ + udelay(ELAN_POWERON_DELAY_USEC); + +release_reset_gpio: + gpiod_set_value_cansleep(ts->reset_gpio, 0); + if (error) + return error; + + msleep(ELAN_RESET_DELAY_MSEC); + + return 0; +} + +static void elants_i2c_power_off(void *_data) +{ + struct elants_data *ts = _data; + + if (!IS_ERR_OR_NULL(ts->reset_gpio)) { + /* + * Activate reset gpio to prevent leakage through the + * pin once we shut off power to the controller. + */ + gpiod_set_value_cansleep(ts->reset_gpio, 1); + regulator_disable(ts->vccio); + regulator_disable(ts->vcc33); + } +} + static int elants_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1066,13 +1143,6 @@ static int elants_i2c_probe(struct i2c_client *client, return -ENXIO; } - /* Make sure there is something at this address */ - if (i2c_smbus_xfer(client->adapter, client->addr, 0, - I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { - dev_err(&client->dev, "nothing at this address\n"); - return -ENXIO; - } - ts = devm_kzalloc(&client->dev, sizeof(struct elants_data), GFP_KERNEL); if (!ts) return -ENOMEM; @@ -1083,6 +1153,62 @@ static int elants_i2c_probe(struct i2c_client *client, ts->client = client; i2c_set_clientdata(client, ts); + ts->vcc33 = devm_regulator_get(&client->dev, "vcc33"); + if (IS_ERR(ts->vcc33)) { + error = PTR_ERR(ts->vcc33); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "Failed to get 'vcc33' regulator: %d\n", + error); + return error; + } + + ts->vccio = devm_regulator_get(&client->dev, "vccio"); + if (IS_ERR(ts->vccio)) { + error = PTR_ERR(ts->vccio); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "Failed to get 'vccio' regulator: %d\n", + error); + return error; + } + + ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + + if (error == -EPROBE_DEFER) + return error; + + if (error != -ENOENT && error != -ENOSYS) { + dev_err(&client->dev, + "failed to get reset gpio: %d\n", + error); + return error; + } + + ts->keep_power_in_suspend = true; + } + + error = elants_i2c_power_on(ts); + if (error) + return error; + + error = devm_add_action(&client->dev, elants_i2c_power_off, ts); + if (error) { + dev_err(&client->dev, + "failed to install power off action: %d\n", error); + elants_i2c_power_off(ts); + return error; + } + + /* Make sure there is something at this address */ + if (i2c_smbus_xfer(client->adapter, client->addr, 0, + I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { + dev_err(&client->dev, "nothing at this address\n"); + return -ENXIO; + } + error = elants_i2c_initialize(ts); if (error) { dev_err(&client->dev, "failed to initialize: %d\n", error); @@ -1190,17 +1316,23 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev) disable_irq(client->irq); - for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { - error = elants_i2c_send(client, set_sleep_cmd, - sizeof(set_sleep_cmd)); - if (!error) - break; + if (device_may_wakeup(dev) || ts->keep_power_in_suspend) { + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_sleep_cmd, + sizeof(set_sleep_cmd)); + if (!error) + break; - dev_err(&client->dev, "suspend command failed: %d\n", error); - } + dev_err(&client->dev, + "suspend command failed: %d\n", error); + } - if (device_may_wakeup(dev)) - ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); + if (device_may_wakeup(dev)) + ts->wake_irq_enabled = + (enable_irq_wake(client->irq) == 0); + } else { + elants_i2c_power_off(ts); + } return 0; } @@ -1216,13 +1348,19 @@ static int __maybe_unused elants_i2c_resume(struct device *dev) if (device_may_wakeup(dev) && ts->wake_irq_enabled) disable_irq_wake(client->irq); - for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { - error = elants_i2c_send(client, set_active_cmd, - sizeof(set_active_cmd)); - if (!error) - break; + if (ts->keep_power_in_suspend) { + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_active_cmd, + sizeof(set_active_cmd)); + if (!error) + break; - dev_err(&client->dev, "resume command failed: %d\n", error); + dev_err(&client->dev, + "resume command failed: %d\n", error); + } + } else { + elants_i2c_power_on(ts); + elants_i2c_initialize(ts); } ts->state = ELAN_STATE_NORMAL; @@ -1261,10 +1399,10 @@ static struct i2c_driver elants_i2c_driver = { .id_table = elants_i2c_id, .driver = { .name = DEVICE_NAME, - .owner = THIS_MODULE, .pm = &elants_i2c_pm_ops, .acpi_match_table = ACPI_PTR(elants_acpi_id), .of_match_table = of_match_ptr(elants_of_match), + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; module_i2c_driver(elants_i2c_driver); diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index e36162b28c2a..4d113c9e4b77 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -420,6 +420,7 @@ static const struct i2c_device_id goodix_ts_id[] = { { "GDIX1001:00", 0 }, { } }; +MODULE_DEVICE_TABLE(i2c, goodix_ts_id); #ifdef CONFIG_ACPI static const struct acpi_device_id goodix_acpi_match[] = { @@ -448,7 +449,6 @@ static struct i2c_driver goodix_ts_driver = { .id_table = goodix_ts_id, .driver = { .name = "Goodix-TS", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(goodix_acpi_match), .of_match_table = of_match_ptr(goodix_of_match), }, diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index da6dc819c846..cf0dc2f0b1be 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -343,7 +343,6 @@ MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); static struct i2c_driver ili210x_ts_driver = { .driver = { .name = "ili210x_i2c", - .owner = THIS_MODULE, .pm = &ili210x_i2c_pm, }, .id_table = ili210x_i2c_id, diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index a68ec142ee9a..82079cde849c 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -229,7 +229,6 @@ MODULE_DEVICE_TABLE(i2c, max11801_ts_id); static struct i2c_driver max11801_ts_driver = { .driver = { .name = "max11801_ts", - .owner = THIS_MODULE, }, .id_table = max11801_ts_id, .probe = max11801_ts_probe, diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 67c0d31613d8..7cce87650fc8 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -572,12 +572,12 @@ static const struct of_device_id mms114_dt_match[] = { { .compatible = "melfas,mms114" }, { } }; +MODULE_DEVICE_TABLE(of, mms114_dt_match); #endif static struct i2c_driver mms114_driver = { .driver = { .name = "mms114", - .owner = THIS_MODULE, .pm = &mms114_pm_ops, .of_match_table = of_match_ptr(mms114_dt_match), }, diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index 806cd0ad160f..bb6f2fe14667 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -9,12 +9,12 @@ * */ -#include <linux/of.h> +#include <linux/property.h> #include <linux/input.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> -static bool touchscreen_get_prop_u32(struct device_node *np, +static bool touchscreen_get_prop_u32(struct device *dev, const char *property, unsigned int default_value, unsigned int *value) @@ -22,7 +22,7 @@ static bool touchscreen_get_prop_u32(struct device_node *np, u32 val; int error; - error = of_property_read_u32(np, property, &val); + error = device_property_read_u32(dev, property, &val); if (error) { *value = default_value; return false; @@ -39,13 +39,9 @@ static void touchscreen_set_params(struct input_dev *dev, struct input_absinfo *absinfo; if (!test_bit(axis, dev->absbit)) { - /* - * Emit a warning only if the axis is not a multitouch - * axis, which might not be set by the driver. - */ - if (!input_is_mt_axis(axis)) - dev_warn(&dev->dev, - "DT specifies parameters but the axis is not set up\n"); + dev_warn(&dev->dev, + "DT specifies parameters but the axis %lu is not set up\n", + axis); return; } @@ -55,52 +51,58 @@ static void touchscreen_set_params(struct input_dev *dev, } /** - * touchscreen_parse_of_params - parse common touchscreen DT properties - * @dev: device that should be parsed + * touchscreen_parse_properties - parse common touchscreen DT properties + * @input: input device that should be parsed + * @multitouch: specifies whether parsed properties should be applied to + * single-touch or multi-touch axes * * This function parses common DT properties for touchscreens and setups the - * input device accordingly. The function keeps previously setuped default + * input device accordingly. The function keeps previously set up default * values if no value is specified via DT. */ -void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch) +void touchscreen_parse_properties(struct input_dev *input, bool multitouch) { - struct device_node *np = dev->dev.parent->of_node; + struct device *dev = input->dev.parent; unsigned int axis; unsigned int maximum, fuzz; bool data_present; - input_alloc_absinfo(dev); - if (!dev->absinfo) + input_alloc_absinfo(input); + if (!input->absinfo) return; axis = multitouch ? ABS_MT_POSITION_X : ABS_X; - data_present = touchscreen_get_prop_u32(np, "touchscreen-size-x", - input_abs_get_max(dev, axis), + data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-x", + input_abs_get_max(input, + axis) + 1, &maximum) | - touchscreen_get_prop_u32(np, "touchscreen-fuzz-x", - input_abs_get_fuzz(dev, axis), + touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x", + input_abs_get_fuzz(input, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum, fuzz); + touchscreen_set_params(input, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; - data_present = touchscreen_get_prop_u32(np, "touchscreen-size-y", - input_abs_get_max(dev, axis), + data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-y", + input_abs_get_max(input, + axis) + 1, &maximum) | - touchscreen_get_prop_u32(np, "touchscreen-fuzz-y", - input_abs_get_fuzz(dev, axis), + touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y", + input_abs_get_fuzz(input, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum, fuzz); + touchscreen_set_params(input, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; - data_present = touchscreen_get_prop_u32(np, "touchscreen-max-pressure", - input_abs_get_max(dev, axis), + data_present = touchscreen_get_prop_u32(dev, + "touchscreen-max-pressure", + input_abs_get_max(input, axis), &maximum) | - touchscreen_get_prop_u32(np, "touchscreen-fuzz-pressure", - input_abs_get_fuzz(dev, axis), + touchscreen_get_prop_u32(dev, + "touchscreen-fuzz-pressure", + input_abs_get_fuzz(input, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum, fuzz); + touchscreen_set_params(input, axis, maximum, fuzz); } -EXPORT_SYMBOL(touchscreen_parse_of_params); +EXPORT_SYMBOL(touchscreen_parse_properties); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 8f3e243a62bf..91621725bfb5 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -24,20 +24,23 @@ #include <linux/i2c.h> #include <linux/input.h> #include <linux/input/mt.h> -#include <linux/input/pixcir_ts.h> +#include <linux/input/touchscreen.h> #include <linux/gpio.h> -#include <linux/of.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> +/*#include <linux/of.h>*/ #include <linux/of_device.h> +#include <linux/platform_data/pixcir_i2c_ts.h> #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; - const struct pixcir_ts_platform_data *pdata; - bool running; + struct gpio_desc *gpio_attb; + struct gpio_desc *gpio_reset; + const struct pixcir_i2c_chip_data *chip; int max_fingers; /* Max fingers supported in this instance */ + bool running; }; struct pixcir_touch { @@ -60,7 +63,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, u8 touch; int ret, i; int readsize; - const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip; + const struct pixcir_i2c_chip_data *chip = tsdata->chip; memset(report, 0, sizeof(struct pixcir_report_data)); @@ -113,13 +116,13 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, struct pixcir_touch *touch; int n, i, slot; struct device *dev = &ts->client->dev; - const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip; + const struct pixcir_i2c_chip_data *chip = ts->chip; n = report->num_touches; if (n > PIXCIR_MAX_SLOTS) n = PIXCIR_MAX_SLOTS; - if (!chip->has_hw_ids) { + if (!ts->chip->has_hw_ids) { for (i = 0; i < n; i++) { touch = &report->touches[i]; pos[i].x = touch->x; @@ -161,7 +164,6 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) { struct pixcir_i2c_ts_data *tsdata = dev_id; - const struct pixcir_ts_platform_data *pdata = tsdata->pdata; struct pixcir_report_data report; while (tsdata->running) { @@ -171,7 +173,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) /* report it */ pixcir_ts_report(tsdata, &report); - if (gpio_get_value(pdata->gpio_attb)) { + if (gpiod_get_value_cansleep(tsdata->gpio_attb)) { if (report.num_touches) { /* * Last report with no finger up? @@ -189,6 +191,17 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static void pixcir_reset(struct pixcir_i2c_ts_data *tsdata) +{ + if (!IS_ERR_OR_NULL(tsdata->gpio_reset)) { + gpiod_set_value_cansleep(tsdata->gpio_reset, 1); + ndelay(100); /* datasheet section 1.2.3 says 80ns min. */ + gpiod_set_value_cansleep(tsdata->gpio_reset, 0); + /* wait for controller ready. 100ms guess. */ + msleep(100); + } +} + static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, enum pixcir_power_mode mode) { @@ -411,85 +424,59 @@ static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, #ifdef CONFIG_OF static const struct of_device_id pixcir_of_match[]; -static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) +static int pixcir_parse_dt(struct device *dev, + struct pixcir_i2c_ts_data *tsdata) { - struct pixcir_ts_platform_data *pdata; - struct device_node *np = dev->of_node; const struct of_device_id *match; match = of_match_device(of_match_ptr(pixcir_of_match), dev); if (!match) - return ERR_PTR(-EINVAL); - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return ERR_PTR(-ENOMEM); - - pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data; - - pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0); - /* gpio_attb validity is checked in probe */ - - if (of_property_read_u32(np, "touchscreen-size-x", &pdata->x_max)) { - dev_err(dev, "Failed to get touchscreen-size-x property\n"); - return ERR_PTR(-EINVAL); - } - pdata->x_max -= 1; - - if (of_property_read_u32(np, "touchscreen-size-y", &pdata->y_max)) { - dev_err(dev, "Failed to get touchscreen-size-y property\n"); - return ERR_PTR(-EINVAL); - } - pdata->y_max -= 1; + return -EINVAL; - dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__, - pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb); + tsdata->chip = (const struct pixcir_i2c_chip_data *)match->data; + if (!tsdata->chip) + return -EINVAL; - return pdata; + return 0; } #else -static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) +static int pixcir_parse_dt(struct device *dev, + struct pixcir_i2c_ts_data *tsdata) { - return ERR_PTR(-EINVAL); + return -EINVAL; } #endif static int pixcir_i2c_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { const struct pixcir_ts_platform_data *pdata = dev_get_platdata(&client->dev); struct device *dev = &client->dev; - struct device_node *np = dev->of_node; struct pixcir_i2c_ts_data *tsdata; struct input_dev *input; int error; - if (np && !pdata) { - pdata = pixcir_parse_dt(dev); - if (IS_ERR(pdata)) - return PTR_ERR(pdata); - } + tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); + if (!tsdata) + return -ENOMEM; - if (!pdata) { + if (pdata) { + tsdata->chip = &pdata->chip; + } else if (dev->of_node) { + error = pixcir_parse_dt(dev, tsdata); + if (error) + return error; + } else { dev_err(&client->dev, "platform data not defined\n"); return -EINVAL; } - if (!gpio_is_valid(pdata->gpio_attb)) { - dev_err(dev, "Invalid gpio_attb in pdata\n"); + if (!tsdata->chip->max_fingers) { + dev_err(dev, "Invalid max_fingers in chip data\n"); return -EINVAL; } - if (!pdata->chip.max_fingers) { - dev_err(dev, "Invalid max_fingers in pdata\n"); - return -EINVAL; - } - - tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); - if (!tsdata) - return -ENOMEM; - input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to allocate input device\n"); @@ -498,7 +485,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, tsdata->client = client; tsdata->input = input; - tsdata->pdata = pdata; input->name = client->name; input->id.bustype = BUS_I2C; @@ -506,15 +492,21 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->close = pixcir_input_close; input->dev.parent = &client->dev; - __set_bit(EV_KEY, input->evbit); - __set_bit(EV_ABS, input->evbit); - __set_bit(BTN_TOUCH, input->keybit); - input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0); - input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0); - 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); + 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); + 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->pdata->chip.max_fingers; + 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", @@ -530,10 +522,18 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input_set_drvdata(input, tsdata); - error = devm_gpio_request_one(dev, pdata->gpio_attb, - GPIOF_DIR_IN, "pixcir_i2c_attb"); - if (error) { - dev_err(dev, "Failed to request ATTB gpio\n"); + 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); + return error; + } + + tsdata->gpio_reset = devm_gpiod_get_optional(dev, "reset", + 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); return error; } @@ -545,6 +545,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return error; } + pixcir_reset(tsdata); + /* Always be in IDLE mode to save power, device supports auto wake */ error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); if (error) { @@ -602,7 +604,6 @@ MODULE_DEVICE_TABLE(of, pixcir_of_match); static struct i2c_driver pixcir_i2c_ts_driver = { .driver = { - .owner = THIS_MODULE, .name = "pixcir_ts", .pm = &pixcir_dev_pm_ops, .of_match_table = of_match_ptr(pixcir_of_match), diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 697e26e52d54..e943678ce54c 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -296,7 +296,6 @@ static struct i2c_driver st1232_ts_driver = { .id_table = st1232_ts_id, .driver = { .name = ST1232_TS_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(st1232_ts_dt_ids), .pm = &st1232_ts_pm_ops, }, diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index f1cb05148b46..3f117637e832 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -1,7 +1,7 @@ /* * Surface2.0/SUR40/PixelSense input driver * - * Copyright (c) 2013 by Florian 'floe' Echtler <floe@butterbrot.org> + * Copyright (c) 2014 by Florian 'floe' Echtler <floe@butterbrot.org> * * Derived from the USB Skeleton driver 1.1, * Copyright (c) 2003 Greg Kroah-Hartman (greg@kroah.com) @@ -12,6 +12,9 @@ * and from the generic hid-multitouch driver, * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> * + * and from the v4l2-pci-skeleton driver, + * Copyright (c) Copyright 2014 Cisco Systems, Inc. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of @@ -31,6 +34,11 @@ #include <linux/input-polldev.h> #include <linux/input/mt.h> #include <linux/usb/input.h> +#include <linux/videodev2.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-sg.h> /* read 512 bytes from endpoint 0x86 -> get header + blobs */ struct sur40_header { @@ -82,9 +90,19 @@ struct sur40_data { struct sur40_blob blobs[]; } __packed; +/* read 512 bytes from endpoint 0x82 -> get header below + * continue reading 16k blocks until header.size bytes read */ +struct sur40_image_header { + __le32 magic; /* "SUBF" */ + __le32 packet_id; + __le32 size; /* always 0x0007e900 = 960x540 */ + __le32 timestamp; /* milliseconds (increases by 16 or 17 each frame) */ + __le32 unknown; /* "epoch?" always 02/03 00 00 00 */ +} __packed; /* version information */ #define DRIVER_SHORT "sur40" +#define DRIVER_LONG "Samsung SUR40" #define DRIVER_AUTHOR "Florian 'floe' Echtler <floe@butterbrot.org>" #define DRIVER_DESC "Surface2.0/SUR40/PixelSense input driver" @@ -99,8 +117,15 @@ struct sur40_data { /* touch data endpoint */ #define TOUCH_ENDPOINT 0x86 +/* video data endpoint */ +#define VIDEO_ENDPOINT 0x82 + +/* video header fields */ +#define VIDEO_HEADER_MAGIC 0x46425553 +#define VIDEO_PACKET_SIZE 16384 + /* polling interval (ms) */ -#define POLL_INTERVAL 10 +#define POLL_INTERVAL 4 /* maximum number of contacts FIXME: this is a guess? */ #define MAX_CONTACTS 64 @@ -113,21 +138,23 @@ struct sur40_data { #define SUR40_GET_STATE 0xc5 /* 4 bytes state (?) */ #define SUR40_GET_SENSORS 0xb1 /* 8 bytes sensors */ -/* - * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT - * here by mistake which is very likely to have corrupted the firmware EEPROM - * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug. - * Should you ever run into a similar problem, the background story to this - * incident and instructions on how to fix the corrupted EEPROM are available - * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html -*/ - +/* master device state */ struct sur40_state { struct usb_device *usbdev; struct device *dev; struct input_polled_dev *input; + struct v4l2_device v4l2; + struct video_device vdev; + struct mutex lock; + + struct vb2_queue queue; + struct vb2_alloc_ctx *alloc_ctx; + struct list_head buf_list; + spinlock_t qlock; + int sequence; + struct sur40_data *bulk_in_buffer; size_t bulk_in_size; u8 bulk_in_epaddr; @@ -135,6 +162,27 @@ struct sur40_state { char phys[64]; }; +struct sur40_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +/* forward declarations */ +static const struct video_device sur40_video_device; +static const struct v4l2_pix_format sur40_video_format; +static const struct vb2_queue sur40_queue; +static void sur40_process_video(struct sur40_state *sur40); + +/* + * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT + * here by mistake which is very likely to have corrupted the firmware EEPROM + * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug. + * Should you ever run into a similar problem, the background story to this + * incident and instructions on how to fix the corrupted EEPROM are available + * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html +*/ + +/* command wrapper */ static int sur40_command(struct sur40_state *dev, u8 command, u16 index, void *buffer, u16 size) { @@ -247,7 +295,6 @@ 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) { - struct sur40_state *sur40 = polldev->private; struct input_dev *input = polldev->input; int result, bulk_read, need_blobs, packet_blobs, i; @@ -295,7 +342,7 @@ static void sur40_poll(struct input_polled_dev *polldev) * instead of at the end. */ if (packet_id != header->packet_id) - dev_warn(sur40->dev, "packet ID mismatch\n"); + dev_dbg(sur40->dev, "packet ID mismatch\n"); packet_blobs = result / sizeof(struct sur40_blob); dev_dbg(sur40->dev, "received %d blobs\n", packet_blobs); @@ -314,6 +361,97 @@ static void sur40_poll(struct input_polled_dev *polldev) input_mt_sync_frame(input); input_sync(input); + + sur40_process_video(sur40); +} + +/* deal with video data */ +static void sur40_process_video(struct sur40_state *sur40) +{ + + struct sur40_image_header *img = (void *)(sur40->bulk_in_buffer); + struct sur40_buffer *new_buf; + struct usb_sg_request sgr; + struct sg_table *sgt; + int result, bulk_read; + + if (!vb2_start_streaming_called(&sur40->queue)) + return; + + /* get a new buffer from the list */ + spin_lock(&sur40->qlock); + if (list_empty(&sur40->buf_list)) { + dev_dbg(sur40->dev, "buffer queue empty\n"); + spin_unlock(&sur40->qlock); + return; + } + new_buf = list_entry(sur40->buf_list.next, struct sur40_buffer, list); + list_del(&new_buf->list); + spin_unlock(&sur40->qlock); + + dev_dbg(sur40->dev, "buffer acquired\n"); + + /* retrieve data via bulk read */ + result = usb_bulk_msg(sur40->usbdev, + usb_rcvbulkpipe(sur40->usbdev, VIDEO_ENDPOINT), + sur40->bulk_in_buffer, sur40->bulk_in_size, + &bulk_read, 1000); + + if (result < 0) { + dev_err(sur40->dev, "error in usb_bulk_read\n"); + goto err_poll; + } + + if (bulk_read != sizeof(struct sur40_image_header)) { + dev_err(sur40->dev, "received %d bytes (%zd expected)\n", + bulk_read, sizeof(struct sur40_image_header)); + goto err_poll; + } + + if (le32_to_cpu(img->magic) != VIDEO_HEADER_MAGIC) { + dev_err(sur40->dev, "image magic mismatch\n"); + goto err_poll; + } + + if (le32_to_cpu(img->size) != sur40_video_format.sizeimage) { + dev_err(sur40->dev, "image size mismatch\n"); + goto err_poll; + } + + dev_dbg(sur40->dev, "header acquired\n"); + + sgt = vb2_dma_sg_plane_desc(&new_buf->vb, 0); + + result = usb_sg_init(&sgr, sur40->usbdev, + usb_rcvbulkpipe(sur40->usbdev, VIDEO_ENDPOINT), 0, + sgt->sgl, sgt->nents, sur40_video_format.sizeimage, 0); + if (result < 0) { + dev_err(sur40->dev, "error %d in usb_sg_init\n", result); + goto err_poll; + } + + usb_sg_wait(&sgr); + if (sgr.status < 0) { + dev_err(sur40->dev, "error %d in usb_sg_wait\n", sgr.status); + goto err_poll; + } + + dev_dbg(sur40->dev, "image acquired\n"); + + /* return error if streaming was stopped in the meantime */ + if (sur40->sequence == -1) + goto err_poll; + + /* mark as finished */ + v4l2_get_timestamp(&new_buf->vb.v4l2_buf.timestamp); + new_buf->vb.v4l2_buf.sequence = sur40->sequence++; + new_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE; + vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_DONE); + dev_dbg(sur40->dev, "buffer marked done\n"); + return; + +err_poll: + vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_ERROR); } /* Initialize input device parameters. */ @@ -377,6 +515,11 @@ static int sur40_probe(struct usb_interface *interface, goto err_free_dev; } + /* initialize locks/lists */ + INIT_LIST_HEAD(&sur40->buf_list); + 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; @@ -387,7 +530,7 @@ static int sur40_probe(struct usb_interface *interface, /* Set up regular input device structure */ sur40_input_setup(poll_dev->input); - poll_dev->input->name = "Samsung SUR40"; + poll_dev->input->name = DRIVER_LONG; usb_to_input_id(usbdev, &poll_dev->input->id); usb_make_path(usbdev, sur40->phys, sizeof(sur40->phys)); strlcat(sur40->phys, "/input0", sizeof(sur40->phys)); @@ -408,6 +551,7 @@ static int sur40_probe(struct usb_interface *interface, goto err_free_polldev; } + /* register the polled input device */ error = input_register_polled_device(poll_dev); if (error) { dev_err(&interface->dev, @@ -415,12 +559,55 @@ static int sur40_probe(struct usb_interface *interface, goto err_free_buffer; } + /* register the video master device */ + snprintf(sur40->v4l2.name, sizeof(sur40->v4l2.name), "%s", DRIVER_LONG); + error = v4l2_device_register(sur40->dev, &sur40->v4l2); + if (error) { + dev_err(&interface->dev, + "Unable to register video master device."); + goto err_unreg_v4l2; + } + + /* initialize the lock and subdevice */ + sur40->queue = sur40_queue; + sur40->queue.drv_priv = sur40; + sur40->queue.lock = &sur40->lock; + + /* initialize the queue */ + error = vb2_queue_init(&sur40->queue); + if (error) + goto err_unreg_v4l2; + + sur40->alloc_ctx = vb2_dma_sg_init_ctx(sur40->dev); + if (IS_ERR(sur40->alloc_ctx)) { + dev_err(sur40->dev, "Can't allocate buffer context"); + error = PTR_ERR(sur40->alloc_ctx); + goto err_unreg_v4l2; + } + + sur40->vdev = sur40_video_device; + sur40->vdev.v4l2_dev = &sur40->v4l2; + sur40->vdev.lock = &sur40->lock; + sur40->vdev.queue = &sur40->queue; + video_set_drvdata(&sur40->vdev, sur40); + + error = video_register_device(&sur40->vdev, VFL_TYPE_GRABBER, -1); + if (error) { + dev_err(&interface->dev, + "Unable to register video subdevice."); + goto err_unreg_video; + } + /* we can register the device now, as it is ready */ usb_set_intfdata(interface, sur40); dev_dbg(&interface->dev, "%s is now attached\n", DRIVER_DESC); return 0; +err_unreg_video: + video_unregister_device(&sur40->vdev); +err_unreg_v4l2: + v4l2_device_unregister(&sur40->v4l2); err_free_buffer: kfree(sur40->bulk_in_buffer); err_free_polldev: @@ -436,6 +623,10 @@ static void sur40_disconnect(struct usb_interface *interface) { struct sur40_state *sur40 = usb_get_intfdata(interface); + video_unregister_device(&sur40->vdev); + v4l2_device_unregister(&sur40->v4l2); + vb2_dma_sg_cleanup_ctx(sur40->alloc_ctx); + input_unregister_polled_device(sur40->input); input_free_polled_device(sur40->input); kfree(sur40->bulk_in_buffer); @@ -445,12 +636,274 @@ static void sur40_disconnect(struct usb_interface *interface) dev_dbg(&interface->dev, "%s is now disconnected\n", DRIVER_DESC); } +/* + * Setup the constraints of the queue: besides setting the number of planes + * per buffer and the size and allocation context of each plane, it also + * checks if sufficient buffers have been allocated. Usually 3 is a good + * minimum number: many DMA engines need a minimum of 2 buffers in the + * queue and you need to have another available for userspace processing. + */ +static int sur40_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(q); + + if (q->num_buffers + *nbuffers < 3) + *nbuffers = 3 - q->num_buffers; + + if (fmt && fmt->fmt.pix.sizeimage < sur40_video_format.sizeimage) + return -EINVAL; + + *nplanes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : sur40_video_format.sizeimage; + alloc_ctxs[0] = sur40->alloc_ctx; + + return 0; +} + +/* + * Prepare the buffer for queueing to the DMA engine: check and set the + * payload size. + */ +static int sur40_buffer_prepare(struct vb2_buffer *vb) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = sur40_video_format.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(&sur40->usbdev->dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + return 0; +} + +/* + * Queue this buffer to the DMA engine. + */ +static void sur40_buffer_queue(struct vb2_buffer *vb) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(vb->vb2_queue); + struct sur40_buffer *buf = (struct sur40_buffer *)vb; + + spin_lock(&sur40->qlock); + list_add_tail(&buf->list, &sur40->buf_list); + spin_unlock(&sur40->qlock); +} + +static void return_all_buffers(struct sur40_state *sur40, + enum vb2_buffer_state state) +{ + struct sur40_buffer *buf, *node; + + spin_lock(&sur40->qlock); + list_for_each_entry_safe(buf, node, &sur40->buf_list, list) { + vb2_buffer_done(&buf->vb, state); + list_del(&buf->list); + } + spin_unlock(&sur40->qlock); +} + +/* + * Start streaming. First check if the minimum number of buffers have been + * queued. If not, then return -ENOBUFS and the vb2 framework will call + * this function again the next time a buffer has been queued until enough + * buffers are available to actually start the DMA engine. + */ +static int sur40_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(vq); + + sur40->sequence = 0; + return 0; +} + +/* + * Stop the DMA engine. Any remaining buffers in the DMA queue are dequeued + * and passed on to the vb2 framework marked as STATE_ERROR. + */ +static void sur40_stop_streaming(struct vb2_queue *vq) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(vq); + sur40->sequence = -1; + + /* Release all active buffers */ + return_all_buffers(sur40, VB2_BUF_STATE_ERROR); +} + +/* V4L ioctl */ +static int sur40_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct sur40_state *sur40 = video_drvdata(file); + + strlcpy(cap->driver, DRIVER_SHORT, sizeof(cap->driver)); + strlcpy(cap->card, DRIVER_LONG, sizeof(cap->card)); + usb_make_path(sur40->usbdev, cap->bus_info, sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int sur40_vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + i->type = V4L2_INPUT_TYPE_CAMERA; + i->std = V4L2_STD_UNKNOWN; + strlcpy(i->name, "In-Cell Sensor", sizeof(i->name)); + i->capabilities = 0; + return 0; +} + +static int sur40_vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + return (i == 0) ? 0 : -EINVAL; +} + +static int sur40_vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int sur40_vidioc_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + f->fmt.pix = sur40_video_format; + return 0; +} + +static int sur40_vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + strlcpy(f->description, "8-bit greyscale", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_GREY; + f->flags = 0; + return 0; +} + +static int sur40_vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *f) +{ + if ((f->index != 0) || (f->pixel_format != V4L2_PIX_FMT_GREY)) + return -EINVAL; + + f->type = V4L2_FRMSIZE_TYPE_DISCRETE; + f->discrete.width = sur40_video_format.width; + f->discrete.height = sur40_video_format.height; + return 0; +} + +static int sur40_vidioc_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *f) +{ + if ((f->index > 1) || (f->pixel_format != V4L2_PIX_FMT_GREY) + || (f->width != sur40_video_format.width) + || (f->height != sur40_video_format.height)) + return -EINVAL; + + f->type = V4L2_FRMIVAL_TYPE_DISCRETE; + f->discrete.denominator = 60/(f->index+1); + f->discrete.numerator = 1; + return 0; +} + + static const struct usb_device_id sur40_table[] = { { USB_DEVICE(ID_MICROSOFT, ID_SUR40) }, /* Samsung SUR40 */ { } /* terminating null entry */ }; MODULE_DEVICE_TABLE(usb, sur40_table); +/* V4L2 structures */ +static const struct vb2_ops sur40_queue_ops = { + .queue_setup = sur40_queue_setup, + .buf_prepare = sur40_buffer_prepare, + .buf_queue = sur40_buffer_queue, + .start_streaming = sur40_start_streaming, + .stop_streaming = sur40_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static const struct vb2_queue sur40_queue = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + /* + * VB2_USERPTR in currently not enabled: passing a user pointer to + * dma-sg will result in segment sizes that are not a multiple of + * 512 bytes, which is required by the host controller. + */ + .io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF, + .buf_struct_size = sizeof(struct sur40_buffer), + .ops = &sur40_queue_ops, + .mem_ops = &vb2_dma_sg_memops, + .timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC, + .min_buffers_needed = 3, +}; + +static const struct v4l2_file_operations sur40_video_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +static const struct v4l2_ioctl_ops sur40_video_ioctl_ops = { + + .vidioc_querycap = sur40_vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = sur40_vidioc_enum_fmt, + .vidioc_try_fmt_vid_cap = sur40_vidioc_fmt, + .vidioc_s_fmt_vid_cap = sur40_vidioc_fmt, + .vidioc_g_fmt_vid_cap = sur40_vidioc_fmt, + + .vidioc_enum_framesizes = sur40_vidioc_enum_framesizes, + .vidioc_enum_frameintervals = sur40_vidioc_enum_frameintervals, + + .vidioc_enum_input = sur40_vidioc_enum_input, + .vidioc_g_input = sur40_vidioc_g_input, + .vidioc_s_input = sur40_vidioc_s_input, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static const struct video_device sur40_video_device = { + .name = DRIVER_LONG, + .fops = &sur40_video_fops, + .ioctl_ops = &sur40_video_ioctl_ops, + .release = video_device_release_empty, +}; + +static const struct v4l2_pix_format sur40_video_format = { + .pixelformat = V4L2_PIX_FMT_GREY, + .width = SENSOR_RES_X / 2, + .height = SENSOR_RES_Y / 2, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .bytesperline = SENSOR_RES_X / 2, + .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2), +}; + /* USB-specific object needed to register this driver with the USB subsystem. */ static struct usb_driver sur40_driver = { .name = DRIVER_SHORT, diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index d8c025b0f88c..0f65d02eeb26 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -30,10 +30,11 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/spi/spi.h> #include <linux/spi/tsc2005.h> #include <linux/regulator/consumer.h> +#include <linux/regmap.h> +#include <linux/gpio/consumer.h> /* * The touchscreen interface operates as follows: @@ -61,16 +62,24 @@ #define TSC2005_CMD_12BIT 0x04 /* control byte 0 */ -#define TSC2005_REG_READ 0x0001 -#define TSC2005_REG_PND0 0x0002 -#define TSC2005_REG_X 0x0000 -#define TSC2005_REG_Y 0x0008 -#define TSC2005_REG_Z1 0x0010 -#define TSC2005_REG_Z2 0x0018 -#define TSC2005_REG_TEMP_HIGH 0x0050 -#define TSC2005_REG_CFR0 0x0060 -#define TSC2005_REG_CFR1 0x0068 -#define TSC2005_REG_CFR2 0x0070 +#define TSC2005_REG_READ 0x01 /* R/W access */ +#define TSC2005_REG_PND0 0x02 /* Power Not Down Control */ +#define TSC2005_REG_X (0x0 << 3) +#define TSC2005_REG_Y (0x1 << 3) +#define TSC2005_REG_Z1 (0x2 << 3) +#define TSC2005_REG_Z2 (0x3 << 3) +#define TSC2005_REG_AUX (0x4 << 3) +#define TSC2005_REG_TEMP1 (0x5 << 3) +#define TSC2005_REG_TEMP2 (0x6 << 3) +#define TSC2005_REG_STATUS (0x7 << 3) +#define TSC2005_REG_AUX_HIGH (0x8 << 3) +#define TSC2005_REG_AUX_LOW (0x9 << 3) +#define TSC2005_REG_TEMP_HIGH (0xA << 3) +#define TSC2005_REG_TEMP_LOW (0xB << 3) +#define TSC2005_REG_CFR0 (0xC << 3) +#define TSC2005_REG_CFR1 (0xD << 3) +#define TSC2005_REG_CFR2 (0xE << 3) +#define TSC2005_REG_CONV_FUNC (0xF << 3) /* configuration register 0 */ #define TSC2005_CFR0_PRECHARGE_276US 0x0040 @@ -112,20 +121,37 @@ #define TSC2005_SPI_MAX_SPEED_HZ 10000000 #define TSC2005_PENUP_TIME_MS 40 -struct tsc2005_spi_rd { - struct spi_transfer spi_xfer; - u32 spi_tx; - u32 spi_rx; +static const struct regmap_range tsc2005_writable_ranges[] = { + regmap_reg_range(TSC2005_REG_AUX_HIGH, TSC2005_REG_CFR2), }; +static const struct regmap_access_table tsc2005_writable_table = { + .yes_ranges = tsc2005_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(tsc2005_writable_ranges), +}; + +static struct regmap_config tsc2005_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .reg_stride = 0x08, + .max_register = 0x78, + .read_flag_mask = TSC2005_REG_READ, + .write_flag_mask = TSC2005_REG_PND0, + .wr_table = &tsc2005_writable_table, + .use_single_rw = true, +}; + +struct tsc2005_data { + u16 x; + u16 y; + u16 z1; + u16 z2; +} __packed; +#define TSC2005_DATA_REGS 4 + struct tsc2005 { struct spi_device *spi; - - struct spi_message spi_read_msg; - struct tsc2005_spi_rd spi_x; - struct tsc2005_spi_rd spi_y; - struct tsc2005_spi_rd spi_z1; - struct tsc2005_spi_rd spi_z2; + struct regmap *regmap; struct input_dev *idev; char phys[32]; @@ -154,7 +180,7 @@ struct tsc2005 { struct regulator *vio; - int reset_gpio; + struct gpio_desc *reset_gpio; void (*set_reset)(bool enable); }; @@ -182,62 +208,6 @@ static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd) return 0; } -static int tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) -{ - u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value; - struct spi_transfer xfer = { - .tx_buf = &tx, - .len = 4, - .bits_per_word = 24, - }; - struct spi_message msg; - int error; - - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - error = spi_sync(ts->spi, &msg); - if (error) { - dev_err(&ts->spi->dev, - "%s: failed, register: %x, value: %x, error: %d\n", - __func__, reg, value, error); - return error; - } - - return 0; -} - -static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) -{ - memset(rd, 0, sizeof(*rd)); - - rd->spi_tx = (reg | TSC2005_REG_READ) << 16; - rd->spi_xfer.tx_buf = &rd->spi_tx; - rd->spi_xfer.rx_buf = &rd->spi_rx; - rd->spi_xfer.len = 4; - rd->spi_xfer.bits_per_word = 24; - rd->spi_xfer.cs_change = !last; -} - -static int tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) -{ - struct tsc2005_spi_rd spi_rd; - struct spi_message msg; - int error; - - tsc2005_setup_read(&spi_rd, reg, true); - - spi_message_init(&msg); - spi_message_add_tail(&spi_rd.spi_xfer, &msg); - - error = spi_sync(ts->spi, &msg); - if (error) - return error; - - *value = spi_rd.spi_rx; - return 0; -} - static void tsc2005_update_pen_state(struct tsc2005 *ts, int x, int y, int pressure) { @@ -266,26 +236,23 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) struct tsc2005 *ts = _ts; unsigned long flags; unsigned int pressure; - u32 x, y; - u32 z1, z2; + struct tsc2005_data tsdata; int error; /* read the coordinates */ - error = spi_sync(ts->spi, &ts->spi_read_msg); + error = regmap_bulk_read(ts->regmap, TSC2005_REG_X, &tsdata, + TSC2005_DATA_REGS); if (unlikely(error)) goto out; - x = ts->spi_x.spi_rx; - y = ts->spi_y.spi_rx; - z1 = ts->spi_z1.spi_rx; - z2 = ts->spi_z2.spi_rx; - /* validate position */ - if (unlikely(x > MAX_12BIT || y > MAX_12BIT)) + if (unlikely(tsdata.x > MAX_12BIT || tsdata.y > MAX_12BIT)) goto out; /* Skip reading if the pressure components are out of range */ - if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2)) + if (unlikely(tsdata.z1 == 0 || tsdata.z2 > MAX_12BIT)) + goto out; + if (unlikely(tsdata.z1 >= tsdata.z2)) goto out; /* @@ -293,8 +260,8 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) * the value before pen-up - that implies SPI fed us stale data */ if (!ts->pen_down && - ts->in_x == x && ts->in_y == y && - ts->in_z1 == z1 && ts->in_z2 == z2) { + ts->in_x == tsdata.x && ts->in_y == tsdata.y && + ts->in_z1 == tsdata.z1 && ts->in_z2 == tsdata.z2) { goto out; } @@ -302,20 +269,20 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) * At this point we are happy we have a valid and useful reading. * Remember it for later comparisons. We may now begin downsampling. */ - ts->in_x = x; - ts->in_y = y; - ts->in_z1 = z1; - ts->in_z2 = z2; + ts->in_x = tsdata.x; + ts->in_y = tsdata.y; + ts->in_z1 = tsdata.z1; + ts->in_z2 = tsdata.z2; /* Compute touch pressure resistance using equation #1 */ - pressure = x * (z2 - z1) / z1; + pressure = tsdata.x * (tsdata.z2 - tsdata.z1) / tsdata.z1; pressure = pressure * ts->x_plate_ohm / 4096; if (unlikely(pressure > MAX_12BIT)) goto out; spin_lock_irqsave(&ts->lock, flags); - tsc2005_update_pen_state(ts, x, y, pressure); + tsc2005_update_pen_state(ts, tsdata.x, tsdata.y, pressure); mod_timer(&ts->penup_timer, jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); @@ -338,9 +305,9 @@ static void tsc2005_penup_timer(unsigned long data) static void tsc2005_start_scan(struct tsc2005 *ts) { - tsc2005_write(ts, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE); - tsc2005_write(ts, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE); - tsc2005_write(ts, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE); + regmap_write(ts->regmap, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE); + regmap_write(ts->regmap, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE); + regmap_write(ts->regmap, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE); tsc2005_cmd(ts, TSC2005_CMD_NORMAL); } @@ -351,8 +318,8 @@ static void tsc2005_stop_scan(struct tsc2005 *ts) static void tsc2005_set_reset(struct tsc2005 *ts, bool enable) { - if (ts->reset_gpio >= 0) - gpio_set_value(ts->reset_gpio, enable); + if (ts->reset_gpio) + gpiod_set_value_cansleep(ts->reset_gpio, enable); else if (ts->set_reset) ts->set_reset(enable); } @@ -388,11 +355,10 @@ static ssize_t tsc2005_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); - u16 temp_high; - u16 temp_high_orig; - u16 temp_high_test; + struct tsc2005 *ts = dev_get_drvdata(dev); + unsigned int temp_high; + unsigned int temp_high_orig; + unsigned int temp_high_test; bool success = true; int error; @@ -403,7 +369,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, */ __tsc2005_disable(ts); - error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); + error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high_orig); if (error) { dev_warn(dev, "selftest failed: read error %d\n", error); success = false; @@ -412,14 +378,14 @@ static ssize_t tsc2005_selftest_show(struct device *dev, temp_high_test = (temp_high_orig - 1) & MAX_12BIT; - error = tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); + error = regmap_write(ts->regmap, TSC2005_REG_TEMP_HIGH, temp_high_test); if (error) { dev_warn(dev, "selftest failed: write error %d\n", error); success = false; goto out; } - error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high); if (error) { dev_warn(dev, "selftest failed: read error %d after write\n", error); @@ -442,7 +408,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, goto out; /* test that the reset really happened */ - error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high); if (error) { dev_warn(dev, "selftest failed: read error %d after reset\n", error); @@ -474,8 +440,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); umode_t mode = attr->mode; if (attr == &dev_attr_selftest.attr) { @@ -495,7 +460,7 @@ static void tsc2005_esd_work(struct work_struct *work) { struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work); int error; - u16 r; + unsigned int r; if (!mutex_trylock(&ts->mutex)) { /* @@ -511,7 +476,7 @@ static void tsc2005_esd_work(struct work_struct *work) goto out; /* We should be able to read register without disabling interrupts. */ - error = tsc2005_read(ts, TSC2005_REG_CFR0, &r); + error = regmap_read(ts->regmap, TSC2005_REG_CFR0, &r); if (!error && !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { goto out; @@ -575,20 +540,6 @@ static void tsc2005_close(struct input_dev *input) mutex_unlock(&ts->mutex); } -static void tsc2005_setup_spi_xfer(struct tsc2005 *ts) -{ - tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false); - tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false); - tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, false); - tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, true); - - spi_message_init(&ts->spi_read_msg); - spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg); - spi_message_add_tail(&ts->spi_y.spi_xfer, &ts->spi_read_msg); - spi_message_add_tail(&ts->spi_z1.spi_xfer, &ts->spi_read_msg); - spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg); -} - static int tsc2005_probe(struct spi_device *spi) { const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev); @@ -653,37 +604,30 @@ static int tsc2005_probe(struct spi_device *spi) ts->spi = spi; ts->idev = input_dev; + ts->regmap = devm_regmap_init_spi(spi, &tsc2005_regmap_config); + if (IS_ERR(ts->regmap)) + return PTR_ERR(ts->regmap); + ts->x_plate_ohm = x_plate_ohm; ts->esd_timeout = esd_timeout; - if (np) { - ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); - if (ts->reset_gpio == -EPROBE_DEFER) - return ts->reset_gpio; - if (ts->reset_gpio < 0) { - dev_err(&spi->dev, "error acquiring reset gpio: %d\n", - ts->reset_gpio); - return ts->reset_gpio; - } + ts->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + dev_err(&spi->dev, "error acquiring reset gpio: %d\n", error); + return error; + } - error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0, - "reset-gpios"); - if (error) { - dev_err(&spi->dev, "error requesting reset gpio: %d\n", - error); - return error; - } + ts->vio = devm_regulator_get_optional(&spi->dev, "vio"); + if (IS_ERR(ts->vio)) { + error = PTR_ERR(ts->vio); + dev_err(&spi->dev, "vio regulator missing (%d)", error); + return error; + } - ts->vio = devm_regulator_get(&spi->dev, "vio"); - if (IS_ERR(ts->vio)) { - error = PTR_ERR(ts->vio); - dev_err(&spi->dev, "vio regulator missing (%d)", error); - return error; - } - } else { - ts->reset_gpio = -1; + if (!ts->reset_gpio && pdata) ts->set_reset = pdata->set_reset; - } mutex_init(&ts->mutex); @@ -692,8 +636,6 @@ static int tsc2005_probe(struct spi_device *spi) INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work); - tsc2005_setup_spi_xfer(ts); - snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", dev_name(&spi->dev)); @@ -709,7 +651,7 @@ static int tsc2005_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); if (np) - touchscreen_parse_of_params(input_dev, false); + touchscreen_parse_properties(input_dev, false); input_dev->open = tsc2005_open; input_dev->close = tsc2005_close; @@ -735,7 +677,7 @@ static int tsc2005_probe(struct spi_device *spi) return error; } - spi_set_drvdata(spi, ts); + dev_set_drvdata(&spi->dev, ts); error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group); if (error) { dev_err(&spi->dev, @@ -763,7 +705,7 @@ disable_regulator: static int tsc2005_remove(struct spi_device *spi) { - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(&spi->dev); sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); @@ -775,8 +717,7 @@ static int tsc2005_remove(struct spi_device *spi) static int __maybe_unused tsc2005_suspend(struct device *dev) { - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); mutex_lock(&ts->mutex); @@ -792,8 +733,7 @@ static int __maybe_unused tsc2005_suspend(struct device *dev) static int __maybe_unused tsc2005_resume(struct device *dev) { - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); mutex_lock(&ts->mutex); diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index ccc8aa615709..5d0cd51c6f41 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -482,7 +482,6 @@ MODULE_DEVICE_TABLE(of, tsc2007_of_match); static struct i2c_driver tsc2007_driver = { .driver = { - .owner = THIS_MODULE, .name = "tsc2007", .of_match_table = of_match_ptr(tsc2007_of_match), }, diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index 32f8ac003936..8d7a2852caef 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -271,7 +271,6 @@ MODULE_DEVICE_TABLE(i2c, wacom_i2c_id); static struct i2c_driver wacom_i2c_driver = { .driver = { .name = "wacom_i2c", - .owner = THIS_MODULE, .pm = &wacom_i2c_pm, }, diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index fb92ae1c5fae..515c20a6e10f 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -23,7 +23,7 @@ #include <asm/unaligned.h> #define WDT87XX_NAME "wdt87xx_i2c" -#define WDT87XX_DRV_VER "0.9.6" +#define WDT87XX_DRV_VER "0.9.7" #define WDT87XX_FW_NAME "wdt87xx_fw.bin" #define WDT87XX_CFG_NAME "wdt87xx_cfg.bin" @@ -85,6 +85,11 @@ #define CTL_PARAM_OFFSET_PHY_H 24 #define CTL_PARAM_OFFSET_FACTOR 32 +/* The definition of the device descriptor */ +#define WDT_GD_DEVICE 1 +#define DEV_DESC_OFFSET_VID 8 +#define DEV_DESC_OFFSET_PID 10 + /* Communication commands */ #define PACKET_SIZE 56 #define VND_REQ_READ 0x06 @@ -152,6 +157,7 @@ /* Controller requires minimum 300us between commands */ #define WDT_COMMAND_DELAY_MS 2 #define WDT_FLASH_WRITE_DELAY_MS 4 +#define WDT_FW_RESET_TIME 2500 struct wdt87xx_sys_param { u16 fw_id; @@ -165,6 +171,8 @@ struct wdt87xx_sys_param { u16 scaling_factor; u32 max_x; u32 max_y; + u16 vendor_id; + u16 product_id; }; struct wdt87xx_data { @@ -208,6 +216,32 @@ static int wdt87xx_i2c_xfer(struct i2c_client *client, return 0; } +static int wdt87xx_get_desc(struct i2c_client *client, u8 desc_idx, + u8 *buf, size_t len) +{ + u8 tx_buf[] = { 0x22, 0x00, 0x10, 0x0E, 0x23, 0x00 }; + int error; + + tx_buf[2] |= desc_idx & 0xF; + + error = wdt87xx_i2c_xfer(client, tx_buf, sizeof(tx_buf), + buf, len); + if (error) { + dev_err(&client->dev, "get desc failed: %d\n", error); + return error; + } + + if (buf[0] != len) { + dev_err(&client->dev, "unexpected response to get desc: %d\n", + buf[0]); + return -EINVAL; + } + + mdelay(WDT_COMMAND_DELAY_MS); + + return 0; +} + static int wdt87xx_get_string(struct i2c_client *client, u8 str_idx, u8 *buf, size_t len) { @@ -373,7 +407,7 @@ static int wdt87xx_sw_reset(struct i2c_client *client) } /* Wait the device to be ready */ - msleep(200); + msleep(WDT_FW_RESET_TIME); return 0; } @@ -403,6 +437,15 @@ static int wdt87xx_get_sysparam(struct i2c_client *client, u8 buf[PKT_READ_SIZE]; int error; + error = wdt87xx_get_desc(client, WDT_GD_DEVICE, buf, 18); + if (error) { + dev_err(&client->dev, "failed to get device desc\n"); + return error; + } + + param->vendor_id = get_unaligned_le16(buf + DEV_DESC_OFFSET_VID); + param->product_id = get_unaligned_le16(buf + DEV_DESC_OFFSET_PID); + error = wdt87xx_get_string(client, STRIDX_PARAMETERS, buf, 34); if (error) { dev_err(&client->dev, "failed to get parameters\n"); @@ -994,6 +1037,8 @@ static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt) input->name = "WDT87xx Touchscreen"; input->id.bustype = BUS_I2C; + input->id.vendor = wdt->param.vendor_id; + input->id.product = wdt->param.product_id; input->phys = wdt->phys; input_set_abs_params(input, ABS_MT_POSITION_X, 0, diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index f58a196521a9..781d0f83050a 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -24,14 +24,13 @@ #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/delay.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/device.h> #include <linux/sysfs.h> #include <linux/input/mt.h> #include <linux/platform_data/zforce_ts.h> #include <linux/regulator/consumer.h> #include <linux/of.h> -#include <linux/of_gpio.h> #define WAIT_TIMEOUT msecs_to_jiffies(1000) @@ -120,6 +119,9 @@ struct zforce_ts { struct regulator *reg_vdd; + struct gpio_desc *gpio_int; + struct gpio_desc *gpio_rst; + bool suspending; bool suspended; bool boot_complete; @@ -161,6 +163,16 @@ static int zforce_command(struct zforce_ts *ts, u8 cmd) return 0; } +static void zforce_reset_assert(struct zforce_ts *ts) +{ + gpiod_set_value_cansleep(ts->gpio_rst, 1); +} + +static void zforce_reset_deassert(struct zforce_ts *ts) +{ + gpiod_set_value_cansleep(ts->gpio_rst, 0); +} + static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len) { struct i2c_client *client = ts->client; @@ -479,7 +491,6 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) { struct zforce_ts *ts = dev_id; struct i2c_client *client = ts->client; - const struct zforce_ts_platdata *pdata = ts->pdata; int ret; u8 payload_buffer[FRAME_MAXSIZE]; u8 *payload; @@ -499,7 +510,16 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) if (!ts->suspending && device_may_wakeup(&client->dev)) pm_stay_awake(&client->dev); - while (!gpio_get_value(pdata->gpio_int)) { + /* + * Run at least once and exit the loop if + * - the optional interrupt GPIO isn't specified + * (there is only one packet read per ISR invocation, then) + * or + * - the GPIO isn't active any more + * (packet read until the level GPIO indicates that there is + * no IRQ any more) + */ + do { ret = zforce_read_packet(ts, payload_buffer); if (ret < 0) { dev_err(&client->dev, @@ -566,7 +586,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) payload[RESPONSE_ID]); break; } - } + } while (gpiod_get_value_cansleep(ts->gpio_int)); if (!ts->suspending && device_may_wakeup(&client->dev)) pm_relax(&client->dev); @@ -690,7 +710,7 @@ static void zforce_reset(void *data) { struct zforce_ts *ts = data; - gpio_set_value(ts->pdata->gpio_rst, 0); + zforce_reset_assert(ts); udelay(10); @@ -712,18 +732,6 @@ static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev) return ERR_PTR(-ENOMEM); } - pdata->gpio_int = of_get_gpio(np, 0); - if (!gpio_is_valid(pdata->gpio_int)) { - dev_err(dev, "failed to get interrupt gpio\n"); - return ERR_PTR(-EINVAL); - } - - pdata->gpio_rst = of_get_gpio(np, 1); - if (!gpio_is_valid(pdata->gpio_rst)) { - dev_err(dev, "failed to get reset gpio\n"); - return ERR_PTR(-EINVAL); - } - if (of_property_read_u32(np, "x-size", &pdata->x_max)) { dev_err(dev, "failed to get x-size property\n"); return ERR_PTR(-EINVAL); @@ -755,20 +763,49 @@ static int zforce_probe(struct i2c_client *client, if (!ts) return -ENOMEM; - ret = devm_gpio_request_one(&client->dev, pdata->gpio_int, GPIOF_IN, - "zforce_ts_int"); - if (ret) { - dev_err(&client->dev, "request of gpio %d failed, %d\n", - pdata->gpio_int, ret); + ts->gpio_rst = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ts->gpio_rst)) { + ret = PTR_ERR(ts->gpio_rst); + dev_err(&client->dev, + "failed to request reset GPIO: %d\n", ret); return ret; } - ret = devm_gpio_request_one(&client->dev, pdata->gpio_rst, - GPIOF_OUT_INIT_LOW, "zforce_ts_rst"); - if (ret) { - dev_err(&client->dev, "request of gpio %d failed, %d\n", - pdata->gpio_rst, ret); - return ret; + if (ts->gpio_rst) { + ts->gpio_int = devm_gpiod_get_optional(&client->dev, "irq", + GPIOD_IN); + if (IS_ERR(ts->gpio_int)) { + ret = PTR_ERR(ts->gpio_int); + dev_err(&client->dev, + "failed to request interrupt GPIO: %d\n", ret); + return ret; + } + } else { + /* + * Deprecated GPIO handling for compatibility + * with legacy binding. + */ + + /* INT GPIO */ + ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, + GPIOD_IN); + if (IS_ERR(ts->gpio_int)) { + ret = PTR_ERR(ts->gpio_int); + dev_err(&client->dev, + "failed to request interrupt GPIO: %d\n", ret); + return ret; + } + + /* RST GPIO */ + ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1, + GPIOD_OUT_HIGH); + if (IS_ERR(ts->gpio_rst)) { + ret = PTR_ERR(ts->gpio_rst); + dev_err(&client->dev, + "failed to request reset GPIO: %d\n", ret); + return ret; + } } ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd"); @@ -863,7 +900,7 @@ static int zforce_probe(struct i2c_client *client, i2c_set_clientdata(client, ts); /* let the controller boot */ - gpio_set_value(pdata->gpio_rst, 1); + zforce_reset_deassert(ts); ts->command_waiting = NOTIFICATION_BOOTCOMPLETE; if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) @@ -917,7 +954,6 @@ MODULE_DEVICE_TABLE(of, zforce_dt_idtable); static struct i2c_driver zforce_driver = { .driver = { - .owner = THIS_MODULE, .name = "zforce-ts", .pm = &zforce_pm_ops, .of_match_table = of_match_ptr(zforce_dt_idtable), |