summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2015-09-03 20:01:44 +0300
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-09-03 20:01:44 +0300
commit01b944fe1cd4e21a2a9ed51adbdbafe2d5e905ba (patch)
tree85f506cf9fce3d8fd47cf624dd8698472bffc13f /drivers/input/touchscreen
parente51e38494a8ecc18650efb0c840600637891de2c (diff)
parent58f1eae48e5372200553de07b5ecc7574803ee91 (diff)
downloadlinux-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')
-rw-r--r--drivers/input/touchscreen/Kconfig24
-rw-r--r--drivers/input/touchscreen/Makefile2
-rw-r--r--drivers/input/touchscreen/ad7879-i2c.c1
-rw-r--r--drivers/input/touchscreen/ads7846.c3
-rw-r--r--drivers/input/touchscreen/ar1021_i2c.c1
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c240
-rw-r--r--drivers/input/touchscreen/auo-pixcir-ts.c1
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c1
-rw-r--r--drivers/input/touchscreen/chipone_icn8318.c1
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c1
-rw-r--r--drivers/input/touchscreen/cyttsp4_i2c.c1
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c.c1
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c3
-rw-r--r--drivers/input/touchscreen/egalax_ts.c2
-rw-r--r--drivers/input/touchscreen/elants_i2c.c186
-rw-r--r--drivers/input/touchscreen/goodix.c2
-rw-r--r--drivers/input/touchscreen/ili210x.c1
-rw-r--r--drivers/input/touchscreen/max11801_ts.c1
-rw-r--r--drivers/input/touchscreen/mms114.c2
-rw-r--r--drivers/input/touchscreen/of_touchscreen.c68
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c147
-rw-r--r--drivers/input/touchscreen/st1232.c1
-rw-r--r--drivers/input/touchscreen/sur40.c481
-rw-r--r--drivers/input/touchscreen/tsc2005.c264
-rw-r--r--drivers/input/touchscreen/tsc2007.c1
-rw-r--r--drivers/input/touchscreen/wacom_i2c.c1
-rw-r--r--drivers/input/touchscreen/wdt87xx_i2c.c49
-rw-r--r--drivers/input/touchscreen/zforce_ts.c98
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),