summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-02-23 14:56:23 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2021-02-23 14:56:23 -0800
commite0fbd25bb37e7bb1f5ad9c9f7e5fc89152aec87e (patch)
tree03da18454a18ebbda8048f36b886b4b21625604f /drivers/input
parent69aea9d2843669387d100e353b5113d1adc9502f (diff)
parent1bff77f41a805b16b5355497c217656711601282 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: "Mostly existing driver fixes plus a new driver for game controllers directly connected to Nintendo 64, and an enhancement for keyboards driven by Chrome OS EC to communicate layout of the top row to userspace" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (47 commits) Input: st1232 - fix NORMAL vs. IDLE state handling Input: aiptek - convert sysfs sprintf/snprintf family to sysfs_emit Input: alps - fix spelling of "positive" ARM: dts: cros-ec-keyboard: Use keymap macros dt-bindings: input: Fix the keymap for LOCK key dt-bindings: input: Create macros for cros-ec keymap Input: cros-ec-keyb - expose function row physical map to userspace dt-bindings: input: cros-ec-keyb: Add a new property describing top row Input: applespi - fix occasional crc errors under load. Input: applespi - don't wait for responses to commands indefinitely. Input: st1232 - add IDLE state as ready condition Input: zinitix - fix return type of zinitix_init_touch() Input: i8042 - add ASUS Zenbook Flip to noselftest list Input: add missing dependencies on CONFIG_HAS_IOMEM Input: joydev - prevent potential read overflow in ioctl Input: elo - fix an error code in elo_connect() Input: xpad - add support for PowerA Enhanced Wired Controller for Xbox Series X|S Input: sur40 - fix an error code in sur40_probe() Input: elants_i2c - detect enum overflow Input: zinitix - remove unneeded semicolon ...
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/joydev.c7
-rw-r--r--drivers/input/joystick/Kconfig7
-rw-r--r--drivers/input/joystick/Makefile2
-rw-r--r--drivers/input/joystick/n64joy.c345
-rw-r--r--drivers/input/joystick/xpad.c1
-rw-r--r--drivers/input/keyboard/Kconfig6
-rw-r--r--drivers/input/keyboard/applespi.c23
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c79
-rw-r--r--drivers/input/keyboard/omap4-keypad.c302
-rw-r--r--drivers/input/misc/da7280.c3
-rw-r--r--drivers/input/mouse/alps.c2
-rw-r--r--drivers/input/mouse/synaptics.c7
-rw-r--r--drivers/input/serio/Kconfig2
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h4
-rw-r--r--drivers/input/tablet/aiptek.c80
-rw-r--r--drivers/input/touchscreen/Kconfig2
-rw-r--r--drivers/input/touchscreen/ads7846.c376
-rw-r--r--drivers/input/touchscreen/elants_i2c.c151
-rw-r--r--drivers/input/touchscreen/elo.c4
-rw-r--r--drivers/input/touchscreen/iqs5xx.c209
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c8
-rw-r--r--drivers/input/touchscreen/raydium_i2c_ts.c3
-rw-r--r--drivers/input/touchscreen/st1232.c9
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c1
-rw-r--r--drivers/input/touchscreen/sur40.c1
-rw-r--r--drivers/input/touchscreen/surface3_spi.c2
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c3
-rw-r--r--drivers/input/touchscreen/zinitix.c4
28 files changed, 1126 insertions, 517 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index a2b5fbba2d3b..430dc6975004 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -456,7 +456,7 @@ static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
if (IS_ERR(abspam))
return PTR_ERR(abspam);
- for (i = 0; i < joydev->nabs; i++) {
+ for (i = 0; i < len && i < joydev->nabs; i++) {
if (abspam[i] > ABS_MAX) {
retval = -EINVAL;
goto out;
@@ -480,6 +480,9 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
int i;
int retval = 0;
+ if (len % sizeof(*keypam))
+ return -EINVAL;
+
len = min(len, sizeof(joydev->keypam));
/* Validate the map. */
@@ -487,7 +490,7 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
if (IS_ERR(keypam))
return PTR_ERR(keypam);
- for (i = 0; i < joydev->nkey; i++) {
+ for (i = 0; i < (len / 2) && i < joydev->nkey; i++) {
if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
retval = -EINVAL;
goto out;
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index b080f0cfb068..5e38899058c1 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -382,4 +382,11 @@ config JOYSTICK_FSIA6B
To compile this driver as a module, choose M here: the
module will be called fsia6b.
+config JOYSTICK_N64
+ bool "N64 controller"
+ depends on MACH_NINTENDO64
+ help
+ Say Y here if you want enable support for the four
+ built-in controller ports on the Nintendo 64 console.
+
endif
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index 58232b3057d3..31d720c9e493 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o
obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o
obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o
obj-$(CONFIG_JOYSTICK_MAPLE) += maplecontrol.o
+obj-$(CONFIG_JOYSTICK_N64) += n64joy.o
obj-$(CONFIG_JOYSTICK_PSXPAD_SPI) += psxpad-spi.o
obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o
obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
@@ -37,4 +38,3 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o
obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o
obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o
obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o
-
diff --git a/drivers/input/joystick/n64joy.c b/drivers/input/joystick/n64joy.c
new file mode 100644
index 000000000000..8bcc529942bc
--- /dev/null
+++ b/drivers/input/joystick/n64joy.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for the four N64 controllers.
+ *
+ * Copyright (c) 2021 Lauri Kasanen
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/limits.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+MODULE_AUTHOR("Lauri Kasanen <cand@gmx.com>");
+MODULE_DESCRIPTION("Driver for N64 controllers");
+MODULE_LICENSE("GPL");
+
+#define PIF_RAM 0x1fc007c0
+
+#define SI_DRAM_REG 0
+#define SI_READ_REG 1
+#define SI_WRITE_REG 4
+#define SI_STATUS_REG 6
+
+#define SI_STATUS_DMA_BUSY BIT(0)
+#define SI_STATUS_IO_BUSY BIT(1)
+
+#define N64_CONTROLLER_ID 0x0500
+
+#define MAX_CONTROLLERS 4
+
+static const char *n64joy_phys[MAX_CONTROLLERS] = {
+ "n64joy/port0",
+ "n64joy/port1",
+ "n64joy/port2",
+ "n64joy/port3",
+};
+
+struct n64joy_priv {
+ u64 si_buf[8] ____cacheline_aligned;
+ struct timer_list timer;
+ struct mutex n64joy_mutex;
+ struct input_dev *n64joy_dev[MAX_CONTROLLERS];
+ u32 __iomem *reg_base;
+ u8 n64joy_opened;
+};
+
+struct joydata {
+ unsigned int: 16; /* unused */
+ unsigned int err: 2;
+ unsigned int: 14; /* unused */
+
+ union {
+ u32 data;
+
+ struct {
+ unsigned int a: 1;
+ unsigned int b: 1;
+ unsigned int z: 1;
+ unsigned int start: 1;
+ unsigned int up: 1;
+ unsigned int down: 1;
+ unsigned int left: 1;
+ unsigned int right: 1;
+ unsigned int: 2; /* unused */
+ unsigned int l: 1;
+ unsigned int r: 1;
+ unsigned int c_up: 1;
+ unsigned int c_down: 1;
+ unsigned int c_left: 1;
+ unsigned int c_right: 1;
+ signed int x: 8;
+ signed int y: 8;
+ };
+ };
+};
+
+static void n64joy_write_reg(u32 __iomem *reg_base, const u8 reg, const u32 value)
+{
+ writel(value, reg_base + reg);
+}
+
+static u32 n64joy_read_reg(u32 __iomem *reg_base, const u8 reg)
+{
+ return readl(reg_base + reg);
+}
+
+static void n64joy_wait_si_dma(u32 __iomem *reg_base)
+{
+ while (n64joy_read_reg(reg_base, SI_STATUS_REG) &
+ (SI_STATUS_DMA_BUSY | SI_STATUS_IO_BUSY))
+ cpu_relax();
+}
+
+static void n64joy_exec_pif(struct n64joy_priv *priv, const u64 in[8])
+{
+ unsigned long flags;
+
+ dma_cache_wback_inv((unsigned long) in, 8 * 8);
+ dma_cache_inv((unsigned long) priv->si_buf, 8 * 8);
+
+ local_irq_save(flags);
+
+ n64joy_wait_si_dma(priv->reg_base);
+
+ barrier();
+ n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(in));
+ barrier();
+ n64joy_write_reg(priv->reg_base, SI_WRITE_REG, PIF_RAM);
+ barrier();
+
+ n64joy_wait_si_dma(priv->reg_base);
+
+ barrier();
+ n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(priv->si_buf));
+ barrier();
+ n64joy_write_reg(priv->reg_base, SI_READ_REG, PIF_RAM);
+ barrier();
+
+ n64joy_wait_si_dma(priv->reg_base);
+
+ local_irq_restore(flags);
+}
+
+static const u64 polldata[] ____cacheline_aligned = {
+ 0xff010401ffffffff,
+ 0xff010401ffffffff,
+ 0xff010401ffffffff,
+ 0xff010401ffffffff,
+ 0xfe00000000000000,
+ 0,
+ 0,
+ 1
+};
+
+static void n64joy_poll(struct timer_list *t)
+{
+ const struct joydata *data;
+ struct n64joy_priv *priv = container_of(t, struct n64joy_priv, timer);
+ struct input_dev *dev;
+ u32 i;
+
+ n64joy_exec_pif(priv, polldata);
+
+ data = (struct joydata *) priv->si_buf;
+
+ for (i = 0; i < MAX_CONTROLLERS; i++) {
+ if (!priv->n64joy_dev[i])
+ continue;
+
+ dev = priv->n64joy_dev[i];
+
+ /* d-pad */
+ input_report_key(dev, BTN_DPAD_UP, data[i].up);
+ input_report_key(dev, BTN_DPAD_DOWN, data[i].down);
+ input_report_key(dev, BTN_DPAD_LEFT, data[i].left);
+ input_report_key(dev, BTN_DPAD_RIGHT, data[i].right);
+
+ /* c buttons */
+ input_report_key(dev, BTN_FORWARD, data[i].c_up);
+ input_report_key(dev, BTN_BACK, data[i].c_down);
+ input_report_key(dev, BTN_LEFT, data[i].c_left);
+ input_report_key(dev, BTN_RIGHT, data[i].c_right);
+
+ /* matching buttons */
+ input_report_key(dev, BTN_START, data[i].start);
+ input_report_key(dev, BTN_Z, data[i].z);
+
+ /* remaining ones: a, b, l, r */
+ input_report_key(dev, BTN_0, data[i].a);
+ input_report_key(dev, BTN_1, data[i].b);
+ input_report_key(dev, BTN_2, data[i].l);
+ input_report_key(dev, BTN_3, data[i].r);
+
+ input_report_abs(dev, ABS_X, data[i].x);
+ input_report_abs(dev, ABS_Y, data[i].y);
+
+ input_sync(dev);
+ }
+
+ mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
+}
+
+static int n64joy_open(struct input_dev *dev)
+{
+ struct n64joy_priv *priv = input_get_drvdata(dev);
+ int err;
+
+ err = mutex_lock_interruptible(&priv->n64joy_mutex);
+ if (err)
+ return err;
+
+ if (!priv->n64joy_opened) {
+ /*
+ * We could use the vblank irq, but it's not important if
+ * the poll point slightly changes.
+ */
+ timer_setup(&priv->timer, n64joy_poll, 0);
+ mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
+ }
+
+ priv->n64joy_opened++;
+
+ mutex_unlock(&priv->n64joy_mutex);
+ return err;
+}
+
+static void n64joy_close(struct input_dev *dev)
+{
+ struct n64joy_priv *priv = input_get_drvdata(dev);
+
+ mutex_lock(&priv->n64joy_mutex);
+ if (!--priv->n64joy_opened)
+ del_timer_sync(&priv->timer);
+ mutex_unlock(&priv->n64joy_mutex);
+}
+
+static const u64 __initconst scandata[] ____cacheline_aligned = {
+ 0xff010300ffffffff,
+ 0xff010300ffffffff,
+ 0xff010300ffffffff,
+ 0xff010300ffffffff,
+ 0xfe00000000000000,
+ 0,
+ 0,
+ 1
+};
+
+/*
+ * The target device is embedded and RAM-constrained. We save RAM
+ * by initializing in __init code that gets dropped late in boot.
+ * For the same reason there is no module or unloading support.
+ */
+static int __init n64joy_probe(struct platform_device *pdev)
+{
+ const struct joydata *data;
+ struct n64joy_priv *priv;
+ struct input_dev *dev;
+ int err = 0;
+ u32 i, j, found = 0;
+
+ priv = kzalloc(sizeof(struct n64joy_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ mutex_init(&priv->n64joy_mutex);
+
+ priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (!priv->reg_base) {
+ err = -EINVAL;
+ goto fail;
+ }
+
+ /* The controllers are not hotpluggable, so we can scan in init */
+ n64joy_exec_pif(priv, scandata);
+
+ data = (struct joydata *) priv->si_buf;
+
+ for (i = 0; i < MAX_CONTROLLERS; i++) {
+ if (!data[i].err && data[i].data >> 16 == N64_CONTROLLER_ID) {
+ found++;
+
+ dev = priv->n64joy_dev[i] = input_allocate_device();
+ if (!priv->n64joy_dev[i]) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ input_set_drvdata(dev, priv);
+
+ dev->name = "N64 controller";
+ dev->phys = n64joy_phys[i];
+ dev->id.bustype = BUS_HOST;
+ dev->id.vendor = 0;
+ dev->id.product = data[i].data >> 16;
+ dev->id.version = 0;
+ dev->dev.parent = &pdev->dev;
+
+ dev->open = n64joy_open;
+ dev->close = n64joy_close;
+
+ /* d-pad */
+ input_set_capability(dev, EV_KEY, BTN_DPAD_UP);
+ input_set_capability(dev, EV_KEY, BTN_DPAD_DOWN);
+ input_set_capability(dev, EV_KEY, BTN_DPAD_LEFT);
+ input_set_capability(dev, EV_KEY, BTN_DPAD_RIGHT);
+ /* c buttons */
+ input_set_capability(dev, EV_KEY, BTN_LEFT);
+ input_set_capability(dev, EV_KEY, BTN_RIGHT);
+ input_set_capability(dev, EV_KEY, BTN_FORWARD);
+ input_set_capability(dev, EV_KEY, BTN_BACK);
+ /* matching buttons */
+ input_set_capability(dev, EV_KEY, BTN_START);
+ input_set_capability(dev, EV_KEY, BTN_Z);
+ /* remaining ones: a, b, l, r */
+ input_set_capability(dev, EV_KEY, BTN_0);
+ input_set_capability(dev, EV_KEY, BTN_1);
+ input_set_capability(dev, EV_KEY, BTN_2);
+ input_set_capability(dev, EV_KEY, BTN_3);
+
+ for (j = 0; j < 2; j++)
+ input_set_abs_params(dev, ABS_X + j,
+ S8_MIN, S8_MAX, 0, 0);
+
+ err = input_register_device(dev);
+ if (err) {
+ input_free_device(dev);
+ goto fail;
+ }
+ }
+ }
+
+ pr_info("%u controller(s) connected\n", found);
+
+ if (!found)
+ return -ENODEV;
+
+ return 0;
+fail:
+ for (i = 0; i < MAX_CONTROLLERS; i++) {
+ if (!priv->n64joy_dev[i])
+ continue;
+ input_unregister_device(priv->n64joy_dev[i]);
+ }
+ return err;
+}
+
+static struct platform_driver n64joy_driver = {
+ .driver = {
+ .name = "n64joy",
+ },
+};
+
+static int __init n64joy_init(void)
+{
+ return platform_driver_probe(&n64joy_driver, n64joy_probe);
+}
+
+module_init(n64joy_init);
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 8cc8ca4a9ac0..9f0d07dcbf06 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -305,6 +305,7 @@ static const struct xpad_device {
{ 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
{ 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
+ { 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE },
{ 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 },
{ 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 2b321c17054a..32d15809ae58 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -446,7 +446,7 @@ config KEYBOARD_MPR121
config KEYBOARD_SNVS_PWRKEY
tristate "IMX SNVS Power Key Driver"
- depends on ARCH_MXC || COMPILE_TEST
+ depends on ARCH_MXC || (COMPILE_TEST && HAS_IOMEM)
depends on OF
help
This is the snvs powerkey driver for the Freescale i.MX application
@@ -685,7 +685,7 @@ config KEYBOARD_OMAP
config KEYBOARD_OMAP4
tristate "TI OMAP4+ keypad support"
- depends on OF || ARCH_OMAP2PLUS
+ depends on (OF && HAS_IOMEM) || ARCH_OMAP2PLUS
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the OMAP4+ keypad.
@@ -773,7 +773,7 @@ config KEYBOARD_CAP11XX
config KEYBOARD_BCM
tristate "Broadcom keypad driver"
- depends on OF && HAVE_CLK
+ depends on OF && HAVE_CLK && HAS_IOMEM
select INPUT_MATRIXKMAP
default ARCH_BCM_CYGNUS
help
diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
index d22223154177..eda1b23002b5 100644
--- a/drivers/input/keyboard/applespi.c
+++ b/drivers/input/keyboard/applespi.c
@@ -48,6 +48,7 @@
#include <linux/efi.h>
#include <linux/input.h>
#include <linux/input/mt.h>
+#include <linux/ktime.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/spinlock.h>
@@ -409,7 +410,7 @@ struct applespi_data {
unsigned int cmd_msg_cntr;
/* lock to protect the above parameters and flags below */
spinlock_t cmd_msg_lock;
- bool cmd_msg_queued;
+ ktime_t cmd_msg_queued;
enum applespi_evt_type cmd_evt_type;
struct led_classdev backlight_info;
@@ -729,7 +730,7 @@ static void applespi_msg_complete(struct applespi_data *applespi,
wake_up_all(&applespi->drain_complete);
if (is_write_msg) {
- applespi->cmd_msg_queued = false;
+ applespi->cmd_msg_queued = 0;
applespi_send_cmd_msg(applespi);
}
@@ -748,6 +749,8 @@ static void applespi_async_write_complete(void *context)
applespi->tx_status,
APPLESPI_STATUS_SIZE);
+ udelay(SPI_RW_CHG_DELAY_US);
+
if (!applespi_check_write_status(applespi, applespi->wr_m.status)) {
/*
* If we got an error, we presumably won't get the expected
@@ -771,8 +774,16 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi)
return 0;
/* check whether send is in progress */
- if (applespi->cmd_msg_queued)
- return 0;
+ if (applespi->cmd_msg_queued) {
+ if (ktime_ms_delta(ktime_get(), applespi->cmd_msg_queued) < 1000)
+ return 0;
+
+ dev_warn(&applespi->spi->dev, "Command %d timed out\n",
+ applespi->cmd_evt_type);
+
+ applespi->cmd_msg_queued = 0;
+ applespi->write_active = false;
+ }
/* set up packet */
memset(packet, 0, APPLESPI_PACKET_SIZE);
@@ -869,7 +880,7 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi)
return sts;
}
- applespi->cmd_msg_queued = true;
+ applespi->cmd_msg_queued = ktime_get_coarse();
applespi->write_active = true;
return 0;
@@ -1921,7 +1932,7 @@ static int __maybe_unused applespi_resume(struct device *dev)
applespi->drain = false;
applespi->have_cl_led_on = false;
applespi->have_bl_level = 0;
- applespi->cmd_msg_queued = false;
+ applespi->cmd_msg_queued = 0;
applespi->read_active = false;
applespi->write_active = false;
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index b379ed762878..38457d9641bd 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,6 +27,8 @@
#include <asm/unaligned.h>
+#define MAX_NUM_TOP_ROW_KEYS 15
+
/**
* struct cros_ec_keyb - Structure representing EC keyboard device
*
@@ -42,6 +44,9 @@
* @idev: The input device for the matrix keys.
* @bs_idev: The input device for non-matrix buttons and switches (or NULL).
* @notifier: interrupt event notifier for transport devices
+ * @function_row_physmap: An array of the encoded rows/columns for the top
+ * row function keys, in an order from left to right
+ * @num_function_row_keys: The number of top row keys in a custom keyboard
*/
struct cros_ec_keyb {
unsigned int rows;
@@ -58,6 +63,9 @@ struct cros_ec_keyb {
struct input_dev *idev;
struct input_dev *bs_idev;
struct notifier_block notifier;
+
+ u16 function_row_physmap[MAX_NUM_TOP_ROW_KEYS];
+ size_t num_function_row_keys;
};
/**
@@ -527,6 +535,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
struct input_dev *idev;
const char *phys;
int err;
+ struct property *prop;
+ const __be32 *p;
+ u16 *physmap;
+ u32 key_pos;
+ int row, col;
err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols);
if (err)
@@ -578,6 +591,21 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
ckdev->idev = idev;
cros_ec_keyb_compute_valid_keys(ckdev);
+ physmap = ckdev->function_row_physmap;
+ of_property_for_each_u32(dev->of_node, "function-row-physmap",
+ prop, p, key_pos) {
+ if (ckdev->num_function_row_keys == MAX_NUM_TOP_ROW_KEYS) {
+ dev_warn(dev, "Only support up to %d top row keys\n",
+ MAX_NUM_TOP_ROW_KEYS);
+ break;
+ }
+ row = KEY_ROW(key_pos);
+ col = KEY_COL(key_pos);
+ *physmap = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
+ physmap++;
+ ckdev->num_function_row_keys++;
+ }
+
err = input_register_device(ckdev->idev);
if (err) {
dev_err(dev, "cannot register input device\n");
@@ -587,6 +615,51 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
return 0;
}
+static ssize_t function_row_physmap_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t size = 0;
+ int i;
+ struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
+ u16 *physmap = ckdev->function_row_physmap;
+
+ for (i = 0; i < ckdev->num_function_row_keys; i++)
+ size += scnprintf(buf + size, PAGE_SIZE - size,
+ "%s%02X", size ? " " : "", physmap[i]);
+ if (size)
+ size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
+
+ return size;
+}
+
+static DEVICE_ATTR_RO(function_row_physmap);
+
+static struct attribute *cros_ec_keyb_attrs[] = {
+ &dev_attr_function_row_physmap.attr,
+ NULL,
+};
+
+static umode_t cros_ec_keyb_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
+
+ if (attr == &dev_attr_function_row_physmap.attr &&
+ !ckdev->num_function_row_keys)
+ return 0;
+
+ return attr->mode;
+}
+
+static const struct attribute_group cros_ec_keyb_attr_group = {
+ .is_visible = cros_ec_keyb_attr_is_visible,
+ .attrs = cros_ec_keyb_attrs,
+};
+
+
static int cros_ec_keyb_probe(struct platform_device *pdev)
{
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
@@ -617,6 +690,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
return err;
}
+ err = devm_device_add_group(dev, &cros_ec_keyb_attr_group);
+ if (err) {
+ dev_err(dev, "failed to create attributes. err=%d\n", err);
+ return err;
+ }
+
ckdev->notifier.notifier_call = cros_ec_keyb_work;
err = blocking_notifier_chain_register(&ckdev->ec->event_notifier,
&ckdev->notifier);
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index b17ac2a295b9..43375b38ee59 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -60,6 +60,8 @@
((((dbms) * 1000) / ((1 << ((ptv) + 1)) * (1000000 / 32768))) - 1)
#define OMAP4_VAL_DEBOUNCINGTIME_16MS \
OMAP4_KEYPAD_DEBOUNCINGTIME_MS(16, OMAP4_KEYPAD_PTV_DIV_128)
+#define OMAP4_KEYPAD_AUTOIDLE_MS 50 /* Approximate measured time */
+#define OMAP4_KEYPAD_IDLE_CHECK_MS (OMAP4_KEYPAD_AUTOIDLE_MS / 2)
enum {
KBD_REVISION_OMAP4 = 0,
@@ -71,6 +73,7 @@ struct omap4_keypad {
void __iomem *base;
unsigned int irq;
+ struct mutex lock; /* for key scan */
unsigned int rows;
unsigned int cols;
@@ -78,7 +81,7 @@ struct omap4_keypad {
u32 irqreg_offset;
unsigned int row_shift;
bool no_autorepeat;
- unsigned char key_state[8];
+ u64 keys;
unsigned short *keymap;
};
@@ -107,6 +110,55 @@ static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
keypad_data->base + keypad_data->irqreg_offset + offset);
}
+static int omap4_keypad_report_keys(struct omap4_keypad *keypad_data,
+ u64 keys, bool down)
+{
+ struct input_dev *input_dev = keypad_data->input;
+ unsigned int col, row, code;
+ DECLARE_BITMAP(mask, 64);
+ unsigned long bit;
+ int events = 0;
+
+ bitmap_from_u64(mask, keys);
+
+ for_each_set_bit(bit, mask, keypad_data->rows * BITS_PER_BYTE) {
+ row = bit / BITS_PER_BYTE;
+ col = bit % BITS_PER_BYTE;
+ code = MATRIX_SCAN_CODE(row, col, keypad_data->row_shift);
+
+ input_event(input_dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(input_dev, keypad_data->keymap[code], down);
+
+ events++;
+ }
+
+ if (events)
+ input_sync(input_dev);
+
+ return events;
+}
+
+static void omap4_keypad_scan_keys(struct omap4_keypad *keypad_data, u64 keys)
+{
+ u64 changed;
+
+ mutex_lock(&keypad_data->lock);
+
+ changed = keys ^ keypad_data->keys;
+
+ /*
+ * Report key up events separately and first. This matters in case we
+ * lost key-up interrupt and just now catching up.
+ */
+ omap4_keypad_report_keys(keypad_data, changed & ~keys, false);
+
+ /* Report key down events */
+ omap4_keypad_report_keys(keypad_data, changed & keys, true);
+
+ keypad_data->keys = keys;
+
+ mutex_unlock(&keypad_data->lock);
+}
/* Interrupt handlers */
static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
@@ -122,48 +174,44 @@ static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
{
struct omap4_keypad *keypad_data = dev_id;
- struct input_dev *input_dev = keypad_data->input;
- unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)];
- unsigned int col, row, code, changed;
- u32 *new_state = (u32 *) key_state;
-
- *new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
- *(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
-
- for (row = 0; row < keypad_data->rows; row++) {
- changed = key_state[row] ^ keypad_data->key_state[row];
- if (!changed)
- continue;
-
- for (col = 0; col < keypad_data->cols; col++) {
- if (changed & (1 << col)) {
- code = MATRIX_SCAN_CODE(row, col,
- keypad_data->row_shift);
- input_event(input_dev, EV_MSC, MSC_SCAN, code);
- input_report_key(input_dev,
- keypad_data->keymap[code],
- key_state[row] & (1 << col));
- }
- }
+ struct device *dev = keypad_data->input->dev.parent;
+ u32 low, high;
+ int error;
+ u64 keys;
+
+ error = pm_runtime_get_sync(dev);
+ if (error < 0) {
+ pm_runtime_put_noidle(dev);
+ return IRQ_NONE;
}
- input_sync(input_dev);
+ low = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
+ high = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
+ keys = low | (u64)high << 32;
- memcpy(keypad_data->key_state, key_state,
- sizeof(keypad_data->key_state));
+ omap4_keypad_scan_keys(keypad_data, keys);
/* clear pending interrupts */
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
return IRQ_HANDLED;
}
static int omap4_keypad_open(struct input_dev *input)
{
struct omap4_keypad *keypad_data = input_get_drvdata(input);
+ struct device *dev = input->dev.parent;
+ int error;
- pm_runtime_get_sync(input->dev.parent);
+ error = pm_runtime_get_sync(dev);
+ if (error < 0) {
+ pm_runtime_put_noidle(dev);
+ return error;
+ }
disable_irq(keypad_data->irq);
@@ -176,13 +224,15 @@ static int omap4_keypad_open(struct input_dev *input)
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
- OMAP4_DEF_IRQENABLE_EVENTEN |
- OMAP4_DEF_IRQENABLE_LONGKEY);
+ OMAP4_DEF_IRQENABLE_EVENTEN);
kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE,
- OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA);
+ OMAP4_DEF_WUP_EVENT_ENA);
enable_irq(keypad_data->irq);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
return 0;
}
@@ -200,14 +250,20 @@ static void omap4_keypad_stop(struct omap4_keypad *keypad_data)
static void omap4_keypad_close(struct input_dev *input)
{
- struct omap4_keypad *keypad_data;
+ struct omap4_keypad *keypad_data = input_get_drvdata(input);
+ struct device *dev = input->dev.parent;
+ int error;
+
+ error = pm_runtime_get_sync(dev);
+ if (error < 0)
+ pm_runtime_put_noidle(dev);
- keypad_data = input_get_drvdata(input);
disable_irq(keypad_data->irq);
omap4_keypad_stop(keypad_data);
enable_irq(keypad_data->irq);
- pm_runtime_put_sync(input->dev.parent);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
}
static int omap4_keypad_parse_dt(struct device *dev,
@@ -252,8 +308,41 @@ static int omap4_keypad_check_revision(struct device *dev,
return 0;
}
+/*
+ * Errata ID i689 "1.32 Keyboard Key Up Event Can Be Missed".
+ * Interrupt may not happen for key-up events. We must clear stuck
+ * key-up events after the keyboard hardware has auto-idled.
+ */
+static int __maybe_unused omap4_keypad_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
+ u32 active;
+
+ active = kbd_readl(keypad_data, OMAP4_KBD_STATEMACHINE);
+ if (active) {
+ pm_runtime_mark_last_busy(dev);
+ return -EBUSY;
+ }
+
+ omap4_keypad_scan_keys(keypad_data, 0);
+
+ return 0;
+}
+
+static const struct dev_pm_ops omap4_keypad_pm_ops = {
+ SET_RUNTIME_PM_OPS(omap4_keypad_runtime_suspend, NULL, NULL)
+};
+
+static void omap4_disable_pm(void *d)
+{
+ pm_runtime_dont_use_autosuspend(d);
+ pm_runtime_disable(d);
+}
+
static int omap4_keypad_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct omap4_keypad *keypad_data;
struct input_dev *input_dev;
struct resource *res;
@@ -271,63 +360,62 @@ static int omap4_keypad_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL);
+ keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL);
if (!keypad_data) {
- dev_err(&pdev->dev, "keypad_data memory allocation failed\n");
+ dev_err(dev, "keypad_data memory allocation failed\n");
return -ENOMEM;
}
keypad_data->irq = irq;
+ mutex_init(&keypad_data->lock);
+ platform_set_drvdata(pdev, keypad_data);
- error = omap4_keypad_parse_dt(&pdev->dev, keypad_data);
+ error = omap4_keypad_parse_dt(dev, keypad_data);
if (error)
- goto err_free_keypad;
+ return error;
- res = request_mem_region(res->start, resource_size(res), pdev->name);
- if (!res) {
- dev_err(&pdev->dev, "can't request mem region\n");
- error = -EBUSY;
- goto err_free_keypad;
- }
+ keypad_data->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(keypad_data->base))
+ return PTR_ERR(keypad_data->base);
- keypad_data->base = ioremap(res->start, resource_size(res));
- if (!keypad_data->base) {
- dev_err(&pdev->dev, "can't ioremap mem resource\n");
- error = -ENOMEM;
- goto err_release_mem;
- }
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_autosuspend_delay(dev, OMAP4_KEYPAD_IDLE_CHECK_MS);
+ pm_runtime_enable(dev);
- pm_runtime_enable(&pdev->dev);
+ error = devm_add_action_or_reset(dev, omap4_disable_pm, dev);
+ if (error) {
+ dev_err(dev, "unable to register cleanup action\n");
+ return error;
+ }
/*
* Enable clocks for the keypad module so that we can read
* revision register.
*/
- error = pm_runtime_get_sync(&pdev->dev);
+ error = pm_runtime_get_sync(dev);
if (error) {
- dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
- pm_runtime_put_noidle(&pdev->dev);
- } else {
- error = omap4_keypad_check_revision(&pdev->dev,
- keypad_data);
- if (!error) {
- /* Ensure device does not raise interrupts */
- omap4_keypad_stop(keypad_data);
- }
- pm_runtime_put_sync(&pdev->dev);
+ dev_err(dev, "pm_runtime_get_sync() failed\n");
+ pm_runtime_put_noidle(dev);
+ return error;
+ }
+
+ error = omap4_keypad_check_revision(dev, keypad_data);
+ if (!error) {
+ /* Ensure device does not raise interrupts */
+ omap4_keypad_stop(keypad_data);
}
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
if (error)
- goto err_pm_disable;
+ return error;
/* input device allocation */
- keypad_data->input = input_dev = input_allocate_device();
- if (!input_dev) {
- error = -ENOMEM;
- goto err_pm_disable;
- }
+ keypad_data->input = input_dev = devm_input_allocate_device(dev);
+ if (!input_dev)
+ return -ENOMEM;
input_dev->name = pdev->name;
- input_dev->dev.parent = &pdev->dev;
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
@@ -344,84 +432,51 @@ static int omap4_keypad_probe(struct platform_device *pdev)
keypad_data->row_shift = get_count_order(keypad_data->cols);
max_keys = keypad_data->rows << keypad_data->row_shift;
- keypad_data->keymap = kcalloc(max_keys,
- sizeof(keypad_data->keymap[0]),
- GFP_KERNEL);
+ keypad_data->keymap = devm_kcalloc(dev,
+ max_keys,
+ sizeof(keypad_data->keymap[0]),
+ GFP_KERNEL);
if (!keypad_data->keymap) {
- dev_err(&pdev->dev, "Not enough memory for keymap\n");
- error = -ENOMEM;
- goto err_free_input;
+ dev_err(dev, "Not enough memory for keymap\n");
+ return -ENOMEM;
}
error = matrix_keypad_build_keymap(NULL, NULL,
keypad_data->rows, keypad_data->cols,
keypad_data->keymap, input_dev);
if (error) {
- dev_err(&pdev->dev, "failed to build keymap\n");
- goto err_free_keymap;
+ dev_err(dev, "failed to build keymap\n");
+ return error;
}
- error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler,
- omap4_keypad_irq_thread_fn, IRQF_ONESHOT,
- "omap4-keypad", keypad_data);
+ error = devm_request_threaded_irq(dev, keypad_data->irq,
+ omap4_keypad_irq_handler,
+ omap4_keypad_irq_thread_fn,
+ IRQF_ONESHOT,
+ "omap4-keypad", keypad_data);
if (error) {
- dev_err(&pdev->dev, "failed to register interrupt\n");
- goto err_free_keymap;
+ dev_err(dev, "failed to register interrupt\n");
+ return error;
}
error = input_register_device(keypad_data->input);
- if (error < 0) {
- dev_err(&pdev->dev, "failed to register input device\n");
- goto err_free_irq;
+ if (error) {
+ dev_err(dev, "failed to register input device\n");
+ return error;
}
- device_init_wakeup(&pdev->dev, true);
- error = dev_pm_set_wake_irq(&pdev->dev, keypad_data->irq);
+ device_init_wakeup(dev, true);
+ error = dev_pm_set_wake_irq(dev, keypad_data->irq);
if (error)
- dev_warn(&pdev->dev,
- "failed to set up wakeup irq: %d\n", error);
-
- platform_set_drvdata(pdev, keypad_data);
+ dev_warn(dev, "failed to set up wakeup irq: %d\n", error);
return 0;
-
-err_free_irq:
- free_irq(keypad_data->irq, keypad_data);
-err_free_keymap:
- kfree(keypad_data->keymap);
-err_free_input:
- input_free_device(input_dev);
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
- iounmap(keypad_data->base);
-err_release_mem:
- release_mem_region(res->start, resource_size(res));
-err_free_keypad:
- kfree(keypad_data);
- return error;
}
static int omap4_keypad_remove(struct platform_device *pdev)
{
- struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
- struct resource *res;
-
dev_pm_clear_wake_irq(&pdev->dev);
- free_irq(keypad_data->irq, keypad_data);
-
- pm_runtime_disable(&pdev->dev);
-
- input_unregister_device(keypad_data->input);
-
- iounmap(keypad_data->base);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- kfree(keypad_data->keymap);
- kfree(keypad_data);
-
return 0;
}
@@ -437,6 +492,7 @@ static struct platform_driver omap4_keypad_driver = {
.driver = {
.name = "omap4-keypad",
.of_match_table = omap_keypad_dt_match,
+ .pm = &omap4_keypad_pm_ops,
},
};
module_platform_driver(omap4_keypad_driver);
diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c
index 37568b00873d..b08610d6e575 100644
--- a/drivers/input/misc/da7280.c
+++ b/drivers/input/misc/da7280.c
@@ -863,6 +863,7 @@ static void da7280_parse_properties(struct device *dev,
gpi_str3[7] = '0' + i;
haptics->gpi_ctl[i].polarity = 0;
error = device_property_read_string(dev, gpi_str3, &str);
+ if (!error)
haptics->gpi_ctl[i].polarity =
da7280_haptic_of_gpi_pol_str(dev, str);
}
@@ -1299,11 +1300,13 @@ static int __maybe_unused da7280_resume(struct device *dev)
return retval;
}
+#ifdef CONFIG_OF
static const struct of_device_id da7280_of_match[] = {
{ .compatible = "dlg,da7280", },
{ }
};
MODULE_DEVICE_TABLE(of, da7280_of_match);
+#endif
static const struct i2c_device_id da7280_i2c_id[] = {
{ "da7280", },
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index b067bfd2699c..4a6b33bbe7ea 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -986,7 +986,7 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
case V7_PACKET_ID_TWO:
mt[1].x &= ~0x000F;
mt[1].y |= 0x000F;
- /* Detect false-postive touches where x & y report max value */
+ /* Detect false-positive touches where x & y report max value */
if (mt[1].y == 0x7ff && mt[1].x == 0xff0) {
mt[1].x = 0;
/* y gets set to 0 at the end of this function */
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 8fb7b4385ded..ffad142801b3 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1106,8 +1106,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
num_fingers = hw.w + 2;
break;
case 2:
- if (SYN_MODEL_PEN(info->model_id))
- ; /* Nothing, treat a pen as a single finger */
+ /*
+ * SYN_MODEL_PEN(info->model_id): even if
+ * the device supports pen, we treat it as
+ * a single finger.
+ */
break;
case 4 ... 15:
if (SYN_CAP_PALMDETECT(info->capabilities))
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 0754744b9ce5..f39b7b3f7942 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -255,7 +255,7 @@ config SERIO_ARC_PS2
config SERIO_APBPS2
tristate "GRLIB APBPS2 PS/2 keyboard/mouse controller"
- depends on OF
+ depends on OF && HAS_IOMEM
help
Say Y here if you want support for GRLIB APBPS2 peripherals used
to connect to PS/2 keyboard and/or mouse.
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index c74b020796a9..9119e12a5778 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -588,6 +588,10 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
},
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /* Convertible Notebook */
+ },
},
{ }
};
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index e08b0ef078e8..fcb1b646436a 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -1036,9 +1036,9 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%dx%d\n",
- input_abs_get_max(aiptek->inputdev, ABS_X) + 1,
- input_abs_get_max(aiptek->inputdev, ABS_Y) + 1);
+ return sysfs_emit(buf, "%dx%d\n",
+ input_abs_get_max(aiptek->inputdev, ABS_X) + 1,
+ input_abs_get_max(aiptek->inputdev, ABS_Y) + 1);
}
/* These structs define the sysfs files, param #1 is the name of the
@@ -1064,9 +1064,8 @@ static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribut
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- map_val_to_str(pointer_mode_map,
- aiptek->curSetting.pointerMode));
+ return sysfs_emit(buf, "%s\n", map_val_to_str(pointer_mode_map,
+ aiptek->curSetting.pointerMode));
}
static ssize_t
@@ -1101,9 +1100,8 @@ static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attri
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- map_val_to_str(coordinate_mode_map,
- aiptek->curSetting.coordinateMode));
+ return sysfs_emit(buf, "%s\n", map_val_to_str(coordinate_mode_map,
+ aiptek->curSetting.coordinateMode));
}
static ssize_t
@@ -1143,9 +1141,8 @@ static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- map_val_to_str(tool_mode_map,
- aiptek->curSetting.toolMode));
+ return sysfs_emit(buf, "%s\n", map_val_to_str(tool_mode_map,
+ aiptek->curSetting.toolMode));
}
static ssize_t
@@ -1174,10 +1171,9 @@ static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *att
struct aiptek *aiptek = dev_get_drvdata(dev);
if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) {
- return snprintf(buf, PAGE_SIZE, "disable\n");
+ return sysfs_emit(buf, "disable\n");
} else {
- return snprintf(buf, PAGE_SIZE, "%d\n",
- aiptek->curSetting.xTilt);
+ return sysfs_emit(buf, "%d\n", aiptek->curSetting.xTilt);
}
}
@@ -1216,10 +1212,9 @@ static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *att
struct aiptek *aiptek = dev_get_drvdata(dev);
if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) {
- return snprintf(buf, PAGE_SIZE, "disable\n");
+ return sysfs_emit(buf, "disable\n");
} else {
- return snprintf(buf, PAGE_SIZE, "%d\n",
- aiptek->curSetting.yTilt);
+ return sysfs_emit(buf, "%d\n", aiptek->curSetting.yTilt);
}
}
@@ -1257,7 +1252,7 @@ static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribut
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay);
+ return sysfs_emit(buf, "%d\n", aiptek->curSetting.jitterDelay);
}
static ssize_t
@@ -1286,8 +1281,7 @@ static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_at
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n",
- aiptek->curSetting.programmableDelay);
+ return sysfs_emit(buf, "%d\n", aiptek->curSetting.programmableDelay);
}
static ssize_t
@@ -1316,7 +1310,7 @@ static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attri
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount);
+ return sysfs_emit(buf, "%ld\n", aiptek->eventCount);
}
static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL);
@@ -1355,7 +1349,7 @@ static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_at
default:
return 0;
}
- return snprintf(buf, PAGE_SIZE, retMsg);
+ return sysfs_emit(buf, retMsg);
}
static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL);
@@ -1375,9 +1369,8 @@ static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribut
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- map_val_to_str(stylus_button_map,
- aiptek->curSetting.stylusButtonUpper));
+ return sysfs_emit(buf, "%s\n", map_val_to_str(stylus_button_map,
+ aiptek->curSetting.stylusButtonUpper));
}
static ssize_t
@@ -1406,9 +1399,8 @@ static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribut
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- map_val_to_str(stylus_button_map,
- aiptek->curSetting.stylusButtonLower));
+ return sysfs_emit(buf, "%s\n", map_val_to_str(stylus_button_map,
+ aiptek->curSetting.stylusButtonLower));
}
static ssize_t
@@ -1444,9 +1436,8 @@ static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- map_val_to_str(mouse_button_map,
- aiptek->curSetting.mouseButtonLeft));
+ return sysfs_emit(buf, "%s\n", map_val_to_str(mouse_button_map,
+ aiptek->curSetting.mouseButtonLeft));
}
static ssize_t
@@ -1474,9 +1465,8 @@ static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribut
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- map_val_to_str(mouse_button_map,
- aiptek->curSetting.mouseButtonMiddle));
+ return sysfs_emit(buf, "%s\n", map_val_to_str(mouse_button_map,
+ aiptek->curSetting.mouseButtonMiddle));
}
static ssize_t
@@ -1504,9 +1494,8 @@ static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- map_val_to_str(mouse_button_map,
- aiptek->curSetting.mouseButtonRight));
+ return sysfs_emit(buf, "%s\n", map_val_to_str(mouse_button_map,
+ aiptek->curSetting.mouseButtonRight));
}
static ssize_t
@@ -1535,10 +1524,9 @@ static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *att
struct aiptek *aiptek = dev_get_drvdata(dev);
if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) {
- return snprintf(buf, PAGE_SIZE, "disable\n");
+ return sysfs_emit(buf, "disable\n");
} else {
- return snprintf(buf, PAGE_SIZE, "%d\n",
- aiptek->curSetting.wheel);
+ return sysfs_emit(buf, "%d\n", aiptek->curSetting.wheel);
}
}
@@ -1568,8 +1556,7 @@ static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *a
/* There is nothing useful to display, so a one-line manual
* is in order...
*/
- return snprintf(buf, PAGE_SIZE,
- "Write anything to this file to program your tablet.\n");
+ return sysfs_emit(buf, "Write anything to this file to program your tablet.\n");
}
static ssize_t
@@ -1600,7 +1587,7 @@ static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *a
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode);
+ return sysfs_emit(buf, "0x%04x\n", aiptek->features.odmCode);
}
static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL);
@@ -1613,7 +1600,7 @@ static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode);
+ return sysfs_emit(buf, "0x%04x\n", aiptek->features.modelCode);
}
static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL);
@@ -1626,8 +1613,7 @@ static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *at
{
struct aiptek *aiptek = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%04x\n",
- aiptek->features.firmwareCode);
+ return sysfs_emit(buf, "%04x\n", aiptek->features.firmwareCode);
}
static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index cc18f54ea887..529614d364fe 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -608,7 +608,7 @@ config TOUCHSCREEN_MTOUCH
config TOUCHSCREEN_IMX6UL_TSC
tristate "Freescale i.MX6UL touchscreen controller"
- depends on (OF && GPIOLIB) || COMPILE_TEST
+ depends on ((OF && GPIOLIB) || COMPILE_TEST) && HAS_IOMEM
help
Say Y here if you have a Freescale i.MX6UL, and want to
use the internal touchscreen controller.
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index a703870ca7bd..f113a27aeb1e 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -64,24 +64,13 @@
struct ads7846_buf {
u8 cmd;
- /*
- * This union is a temporary hack. The driver does an in-place
- * endianness conversion. This will be cleaned up in the next
- * patch.
- */
- union {
- __be16 data_be16;
- u16 data;
- };
+ __be16 data;
} __packed;
-
-struct ts_event {
- bool ignore;
- struct ads7846_buf x;
- struct ads7846_buf y;
- struct ads7846_buf z1;
- struct ads7846_buf z2;
+struct ads7846_buf_layout {
+ unsigned int offset;
+ unsigned int count;
+ unsigned int skip;
};
/*
@@ -90,12 +79,18 @@ struct ts_event {
* systems where main memory is not DMA-coherent (most non-x86 boards).
*/
struct ads7846_packet {
- struct ts_event tc;
- struct ads7846_buf read_x_cmd;
- struct ads7846_buf read_y_cmd;
- struct ads7846_buf read_z1_cmd;
- struct ads7846_buf read_z2_cmd;
+ unsigned int count;
+ unsigned int count_skip;
+ unsigned int cmds;
+ unsigned int last_cmd_idx;
+ struct ads7846_buf_layout l[5];
+ struct ads7846_buf *rx;
+ struct ads7846_buf *tx;
+
struct ads7846_buf pwrdown_cmd;
+
+ bool ignore;
+ u16 x, y, z1, z2;
};
struct ads7846 {
@@ -194,7 +189,6 @@ struct ads7846 {
#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))
#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))
#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))
-
#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))
#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */
@@ -207,6 +201,21 @@ struct ads7846 {
#define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
+/* Order commands in the most optimal way to reduce Vref switching and
+ * settling time:
+ * Measure: X; Vref: X+, X-; IN: Y+
+ * Measure: Y; Vref: Y+, Y-; IN: X+
+ * Measure: Z1; Vref: Y+, X-; IN: X+
+ * Measure: Z2; Vref: Y+, X-; IN: Y-
+ */
+enum ads7846_cmds {
+ ADS7846_X,
+ ADS7846_Y,
+ ADS7846_Z1,
+ ADS7846_Z2,
+ ADS7846_PWDOWN,
+};
+
static int get_pendown_state(struct ads7846 *ts)
{
if (ts->get_pendown_state)
@@ -689,26 +698,109 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val)
return ADS7846_FILTER_OK;
}
-static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
+static int ads7846_get_value(struct ads7846_buf *buf)
{
int value;
- struct spi_transfer *t =
- list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
- struct ads7846_buf *buf = t->rx_buf;
- value = be16_to_cpup(&buf->data_be16);
+ value = be16_to_cpup(&buf->data);
/* enforce ADC output is 12 bits width */
return (value >> 3) & 0xfff;
}
-static void ads7846_update_value(struct spi_message *m, int val)
+static void ads7846_set_cmd_val(struct ads7846 *ts, enum ads7846_cmds cmd_idx,
+ u16 val)
+{
+ struct ads7846_packet *packet = ts->packet;
+
+ switch (cmd_idx) {
+ case ADS7846_Y:
+ packet->y = val;
+ break;
+ case ADS7846_X:
+ packet->x = val;
+ break;
+ case ADS7846_Z1:
+ packet->z1 = val;
+ break;
+ case ADS7846_Z2:
+ packet->z2 = val;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+}
+
+static u8 ads7846_get_cmd(enum ads7846_cmds cmd_idx, int vref)
+{
+ switch (cmd_idx) {
+ case ADS7846_Y:
+ return READ_Y(vref);
+ case ADS7846_X:
+ return READ_X(vref);
+
+ /* 7846 specific commands */
+ case ADS7846_Z1:
+ return READ_Z1(vref);
+ case ADS7846_Z2:
+ return READ_Z2(vref);
+ case ADS7846_PWDOWN:
+ return PWRDOWN;
+ default:
+ WARN_ON_ONCE(1);
+ }
+
+ return 0;
+}
+
+static bool ads7846_cmd_need_settle(enum ads7846_cmds cmd_idx)
+{
+ switch (cmd_idx) {
+ case ADS7846_X:
+ case ADS7846_Y:
+ case ADS7846_Z1:
+ case ADS7846_Z2:
+ return true;
+ case ADS7846_PWDOWN:
+ return false;
+ default:
+ WARN_ON_ONCE(1);
+ }
+
+ return false;
+}
+
+static int ads7846_filter(struct ads7846 *ts)
{
- struct spi_transfer *t =
- list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
- struct ads7846_buf *buf = t->rx_buf;
+ struct ads7846_packet *packet = ts->packet;
+ int action;
+ int val;
+ unsigned int cmd_idx, b;
- buf->data = val;
+ packet->ignore = false;
+ for (cmd_idx = packet->last_cmd_idx; cmd_idx < packet->cmds - 1; cmd_idx++) {
+ struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+
+ packet->last_cmd_idx = cmd_idx;
+
+ for (b = l->skip; b < l->count; b++) {
+ val = ads7846_get_value(&packet->rx[l->offset + b]);
+
+ action = ts->filter(ts->filter_data, cmd_idx, &val);
+ if (action == ADS7846_FILTER_REPEAT) {
+ if (b == l->count - 1)
+ return -EAGAIN;
+ } else if (action == ADS7846_FILTER_OK) {
+ ads7846_set_cmd_val(ts, cmd_idx, val);
+ break;
+ } else {
+ packet->ignore = true;
+ return 0;
+ }
+ }
+ }
+
+ return 0;
}
static void ads7846_read_state(struct ads7846 *ts)
@@ -716,52 +808,26 @@ static void ads7846_read_state(struct ads7846 *ts)
struct ads7846_packet *packet = ts->packet;
struct spi_message *m;
int msg_idx = 0;
- int val;
- int action;
int error;
- while (msg_idx < ts->msg_count) {
+ packet->last_cmd_idx = 0;
+ while (true) {
ts->wait_for_sync();
m = &ts->msg[msg_idx];
error = spi_sync(ts->spi, m);
if (error) {
dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
- packet->tc.ignore = true;
+ packet->ignore = true;
return;
}
- /*
- * Last message is power down request, no need to convert
- * or filter the value.
- */
- if (msg_idx < ts->msg_count - 1) {
-
- val = ads7846_get_value(ts, m);
-
- action = ts->filter(ts->filter_data, msg_idx, &val);
- switch (action) {
- case ADS7846_FILTER_REPEAT:
- continue;
-
- case ADS7846_FILTER_IGNORE:
- packet->tc.ignore = true;
- msg_idx = ts->msg_count - 1;
- continue;
-
- case ADS7846_FILTER_OK:
- ads7846_update_value(m, val);
- packet->tc.ignore = false;
- msg_idx++;
- break;
+ error = ads7846_filter(ts);
+ if (error)
+ continue;
- default:
- BUG();
- }
- } else {
- msg_idx++;
- }
+ return;
}
}
@@ -771,19 +837,14 @@ static void ads7846_report_state(struct ads7846 *ts)
unsigned int Rt;
u16 x, y, z1, z2;
- /*
- * ads7846_get_value() does in-place conversion (including byte swap)
- * from on-the-wire format as part of debouncing to get stable
- * readings.
- */
- x = packet->tc.x.data;
- y = packet->tc.y.data;
+ x = packet->x;
+ y = packet->y;
if (ts->model == 7845) {
z1 = 0;
z2 = 0;
} else {
- z1 = packet->tc.z1.data;
- z2 = packet->tc.z2.data;
+ z1 = packet->z1;
+ z2 = packet->z2;
}
/* range filtering */
@@ -816,9 +877,9 @@ static void ads7846_report_state(struct ads7846 *ts)
* the maximum. Don't report it to user space, repeat at least
* once more the measurement
*/
- if (packet->tc.ignore || Rt > ts->pressure_max) {
+ if (packet->ignore || Rt > ts->pressure_max) {
dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
- packet->tc.ignore, Rt);
+ packet->ignore, Rt);
return;
}
@@ -979,13 +1040,59 @@ static int ads7846_setup_pendown(struct spi_device *spi,
* Set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
*/
-static void ads7846_setup_spi_msg(struct ads7846 *ts,
+static int ads7846_setup_spi_msg(struct ads7846 *ts,
const struct ads7846_platform_data *pdata)
{
struct spi_message *m = &ts->msg[0];
struct spi_transfer *x = ts->xfer;
struct ads7846_packet *packet = ts->packet;
int vref = pdata->keep_vref_on;
+ unsigned int count, offset = 0;
+ unsigned int cmd_idx, b;
+ unsigned long time;
+ size_t size = 0;
+
+ /* time per bit */
+ time = NSEC_PER_SEC / ts->spi->max_speed_hz;
+
+ count = pdata->settle_delay_usecs * NSEC_PER_USEC / time;
+ packet->count_skip = DIV_ROUND_UP(count, 24);
+
+ if (ts->debounce_max && ts->debounce_rep)
+ /* ads7846_debounce_filter() is making ts->debounce_rep + 2
+ * reads. So we need to get all samples for normal case. */
+ packet->count = ts->debounce_rep + 2;
+ else
+ packet->count = 1;
+
+ if (ts->model == 7846)
+ packet->cmds = 5; /* x, y, z1, z2, pwdown */
+ else
+ packet->cmds = 3; /* x, y, pwdown */
+
+ for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
+ struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+ unsigned int max_count;
+
+ if (ads7846_cmd_need_settle(cmd_idx))
+ max_count = packet->count + packet->count_skip;
+ else
+ max_count = packet->count;
+
+ l->offset = offset;
+ offset += max_count;
+ l->count = max_count;
+ l->skip = packet->count_skip;
+ size += sizeof(*packet->tx) * max_count;
+ }
+
+ packet->tx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
+ if (!packet->tx)
+ return -ENOMEM;
+
+ packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
+ if (!packet->rx)
+ return -ENOMEM;
if (ts->model == 7873) {
/*
@@ -1001,117 +1108,20 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
spi_message_init(m);
m->context = ts;
- packet->read_y_cmd.cmd = READ_Y(vref);
- x->tx_buf = &packet->read_y_cmd;
- x->rx_buf = &packet->tc.y;
- x->len = 3;
- spi_message_add_tail(x, m);
+ for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
+ struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+ u8 cmd = ads7846_get_cmd(cmd_idx, vref);
- /*
- * The first sample after switching drivers can be low quality;
- * optionally discard it, using a second one after the signals
- * have had enough time to stabilize.
- */
- if (pdata->settle_delay_usecs) {
- x->delay.value = pdata->settle_delay_usecs;
- x->delay.unit = SPI_DELAY_UNIT_USECS;
- x++;
-
- x->tx_buf = &packet->read_y_cmd;
- x->rx_buf = &packet->tc.y;
- x->len = 3;
- spi_message_add_tail(x, m);
+ for (b = 0; b < l->count; b++)
+ packet->tx[l->offset + b].cmd = cmd;
}
- ts->msg_count++;
- m++;
- spi_message_init(m);
- m->context = ts;
-
- /* turn y- off, x+ on, then leave in lowpower */
- x++;
- packet->read_x_cmd.cmd = READ_X(vref);
- x->tx_buf = &packet->read_x_cmd;
- x->rx_buf = &packet->tc.x;
- x->len = 3;
+ x->tx_buf = packet->tx;
+ x->rx_buf = packet->rx;
+ x->len = size;
spi_message_add_tail(x, m);
- /* ... maybe discard first sample ... */
- if (pdata->settle_delay_usecs) {
- x->delay.value = pdata->settle_delay_usecs;
- x->delay.unit = SPI_DELAY_UNIT_USECS;
-
- x++;
- x->tx_buf = &packet->read_x_cmd;
- x->rx_buf = &packet->tc.x;
- x->len = 3;
- spi_message_add_tail(x, m);
- }
-
- /* turn y+ off, x- on; we'll use formula #2 */
- if (ts->model == 7846) {
- ts->msg_count++;
- m++;
- spi_message_init(m);
- m->context = ts;
-
- x++;
- packet->read_z1_cmd.cmd = READ_Z1(vref);
- x->tx_buf = &packet->read_z1_cmd;
- x->rx_buf = &packet->tc.z1;
- x->len = 3;
- spi_message_add_tail(x, m);
-
- /* ... maybe discard first sample ... */
- if (pdata->settle_delay_usecs) {
- x->delay.value = pdata->settle_delay_usecs;
- x->delay.unit = SPI_DELAY_UNIT_USECS;
-
- x++;
- x->tx_buf = &packet->read_z1_cmd;
- x->rx_buf = &packet->tc.z1;
- x->len = 3;
- spi_message_add_tail(x, m);
- }
-
- ts->msg_count++;
- m++;
- spi_message_init(m);
- m->context = ts;
-
- x++;
- packet->read_z2_cmd.cmd = READ_Z2(vref);
- x->tx_buf = &packet->read_z2_cmd;
- x->rx_buf = &packet->tc.z2;
- x->len = 3;
- spi_message_add_tail(x, m);
-
- /* ... maybe discard first sample ... */
- if (pdata->settle_delay_usecs) {
- x->delay.value = pdata->settle_delay_usecs;
- x->delay.unit = SPI_DELAY_UNIT_USECS;
-
- x++;
- x->tx_buf = &packet->read_z2_cmd;
- x->rx_buf = &packet->tc.z2;
- x->len = 3;
- spi_message_add_tail(x, m);
- }
- }
-
- /* power down */
- ts->msg_count++;
- m++;
- spi_message_init(m);
- m->context = ts;
-
- x++;
- packet->pwrdown_cmd.cmd = PWRDOWN;
- x->tx_buf = &packet->pwrdown_cmd;
- x->len = 3;
-
- CS_CHANGE(*x);
- spi_message_add_tail(x, m);
+ return 0;
}
#ifdef CONFIG_OF
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index d51cb910fba1..4c2b579f6c8b 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -56,6 +56,7 @@
#define QUEUE_HEADER_SINGLE 0x62
#define QUEUE_HEADER_NORMAL 0X63
#define QUEUE_HEADER_WAIT 0x64
+#define QUEUE_HEADER_NORMAL2 0x66
/* Command header definition */
#define CMD_HEADER_WRITE 0x54
@@ -69,6 +70,7 @@
#define CMD_HEADER_REK 0x66
/* FW position data */
+#define PACKET_SIZE_OLD 40
#define PACKET_SIZE 55
#define MAX_CONTACT_NUM 10
#define FW_POS_HEADER 0
@@ -90,6 +92,8 @@
/* FW read command, 0x53 0x?? 0x0, 0x01 */
#define E_ELAN_INFO_FW_VER 0x00
#define E_ELAN_INFO_BC_VER 0x10
+#define E_ELAN_INFO_X_RES 0x60
+#define E_ELAN_INFO_Y_RES 0x63
#define E_ELAN_INFO_REK 0xD0
#define E_ELAN_INFO_TEST_VER 0xE0
#define E_ELAN_INFO_FW_ID 0xF0
@@ -112,6 +116,11 @@
#define ELAN_POWERON_DELAY_USEC 500
#define ELAN_RESET_DELAY_MSEC 20
+enum elants_chip_id {
+ EKTH3500,
+ EKTF3624,
+};
+
enum elants_state {
ELAN_STATE_NORMAL,
ELAN_WAIT_QUEUE_HEADER,
@@ -143,9 +152,12 @@ struct elants_data {
unsigned int y_res;
unsigned int x_max;
unsigned int y_max;
+ unsigned int phy_x;
+ unsigned int phy_y;
struct touchscreen_properties prop;
enum elants_state state;
+ enum elants_chip_id chip_id;
enum elants_iap_mode iap_mode;
/* Guards against concurrent access to the device via sysfs */
@@ -433,7 +445,51 @@ static int elants_i2c_query_bc_version(struct elants_data *ts)
return 0;
}
-static int elants_i2c_query_ts_info(struct elants_data *ts)
+static int elants_i2c_query_ts_info_ektf(struct elants_data *ts)
+{
+ struct i2c_client *client = ts->client;
+ int error;
+ u8 resp[4];
+ u16 phy_x, phy_y;
+ const u8 get_xres_cmd[] = {
+ CMD_HEADER_READ, E_ELAN_INFO_X_RES, 0x00, 0x00
+ };
+ const u8 get_yres_cmd[] = {
+ CMD_HEADER_READ, E_ELAN_INFO_Y_RES, 0x00, 0x00
+ };
+
+ /* Get X/Y size in mm */
+ error = elants_i2c_execute_command(client, get_xres_cmd,
+ sizeof(get_xres_cmd),
+ resp, sizeof(resp), 1,
+ "get X size");
+ if (error)
+ return error;
+
+ phy_x = resp[2] | ((resp[3] & 0xF0) << 4);
+
+ error = elants_i2c_execute_command(client, get_yres_cmd,
+ sizeof(get_yres_cmd),
+ resp, sizeof(resp), 1,
+ "get Y size");
+ if (error)
+ return error;
+
+ phy_y = resp[2] | ((resp[3] & 0xF0) << 4);
+
+ dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y);
+
+ ts->phy_x = phy_x;
+ ts->phy_y = phy_y;
+
+ /* eKTF doesn't report max size, set it to default values */
+ ts->x_max = 2240 - 1;
+ ts->y_max = 1408 - 1;
+
+ return 0;
+}
+
+static int elants_i2c_query_ts_info_ekth(struct elants_data *ts)
{
struct i2c_client *client = ts->client;
int error;
@@ -508,6 +564,8 @@ static int elants_i2c_query_ts_info(struct elants_data *ts)
ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x);
ts->y_max = ELAN_TS_RESOLUTION(cols, osr);
ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y);
+ ts->phy_x = phy_x;
+ ts->phy_y = phy_y;
}
return 0;
@@ -587,8 +645,19 @@ static int elants_i2c_initialize(struct elants_data *ts)
error = elants_i2c_query_fw_version(ts);
if (!error)
error = elants_i2c_query_test_version(ts);
- if (!error)
- error = elants_i2c_query_ts_info(ts);
+
+ switch (ts->chip_id) {
+ case EKTH3500:
+ if (!error)
+ error = elants_i2c_query_ts_info_ekth(ts);
+ break;
+ case EKTF3624:
+ if (!error)
+ error = elants_i2c_query_ts_info_ektf(ts);
+ break;
+ default:
+ BUG();
+ }
if (error)
ts->iap_mode = ELAN_IAP_RECOVERY;
@@ -853,7 +922,8 @@ out:
* Event reporting.
*/
-static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf)
+static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf,
+ size_t packet_size)
{
struct input_dev *input = ts->input;
unsigned int n_fingers;
@@ -880,8 +950,24 @@ static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf)
pos = &buf[FW_POS_XY + i * 3];
x = (((u16)pos[0] & 0xf0) << 4) | pos[1];
y = (((u16)pos[0] & 0x0f) << 8) | pos[2];
- p = buf[FW_POS_PRESSURE + i];
- w = buf[FW_POS_WIDTH + i];
+
+ /*
+ * eKTF3624 may have use "old" touch-report format,
+ * depending on a device and TS firmware version.
+ * For example, ASUS Transformer devices use the "old"
+ * format, while ASUS Nexus 7 uses the "new" formant.
+ */
+ if (packet_size == PACKET_SIZE_OLD &&
+ ts->chip_id == EKTF3624) {
+ w = buf[FW_POS_WIDTH + i / 2];
+ w >>= 4 * (~i & 1);
+ w |= w << 4;
+ w |= !w;
+ p = w;
+ } else {
+ p = buf[FW_POS_PRESSURE + i];
+ w = buf[FW_POS_WIDTH + i];
+ }
dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n",
i, x, y, p, w);
@@ -913,7 +999,8 @@ static u8 elants_i2c_calculate_checksum(u8 *buf)
return checksum;
}
-static void elants_i2c_event(struct elants_data *ts, u8 *buf)
+static void elants_i2c_event(struct elants_data *ts, u8 *buf,
+ size_t packet_size)
{
u8 checksum = elants_i2c_calculate_checksum(buf);
@@ -927,7 +1014,7 @@ static void elants_i2c_event(struct elants_data *ts, u8 *buf)
"%s: unknown packet type: %02x\n",
__func__, buf[FW_POS_HEADER]);
else
- elants_i2c_mt_event(ts, buf);
+ elants_i2c_mt_event(ts, buf, packet_size);
}
static irqreturn_t elants_i2c_irq(int irq, void *_dev)
@@ -970,7 +1057,6 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
switch (ts->buf[FW_HDR_TYPE]) {
case CMD_HEADER_HELLO:
case CMD_HEADER_RESP:
- case CMD_HEADER_REK:
break;
case QUEUE_HEADER_WAIT:
@@ -985,9 +1071,24 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
break;
case QUEUE_HEADER_SINGLE:
- elants_i2c_event(ts, &ts->buf[HEADER_SIZE]);
+ elants_i2c_event(ts, &ts->buf[HEADER_SIZE],
+ ts->buf[FW_HDR_LENGTH]);
break;
+ case QUEUE_HEADER_NORMAL2: /* CMD_HEADER_REK */
+ /*
+ * Depending on firmware version, eKTF3624 touchscreens
+ * may utilize one of these opcodes for the touch events:
+ * 0x63 (NORMAL) and 0x66 (NORMAL2). The 0x63 is used by
+ * older firmware version and differs from 0x66 such that
+ * touch pressure value needs to be adjusted. The 0x66
+ * opcode of newer firmware is equal to 0x63 of eKTH3500.
+ */
+ if (ts->chip_id != EKTF3624)
+ break;
+
+ fallthrough;
+
case QUEUE_HEADER_NORMAL:
report_count = ts->buf[FW_HDR_COUNT];
if (report_count == 0 || report_count > 3) {
@@ -998,7 +1099,12 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
}
report_len = ts->buf[FW_HDR_LENGTH] / report_count;
- if (report_len != PACKET_SIZE) {
+
+ if (report_len == PACKET_SIZE_OLD &&
+ ts->chip_id == EKTF3624) {
+ dev_dbg_once(&client->dev,
+ "using old report format\n");
+ } else if (report_len != PACKET_SIZE) {
dev_err(&client->dev,
"mismatching report length: %*ph\n",
HEADER_SIZE, ts->buf);
@@ -1007,8 +1113,8 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
for (i = 0; i < report_count; i++) {
u8 *buf = ts->buf + HEADER_SIZE +
- i * PACKET_SIZE;
- elants_i2c_event(ts, buf);
+ i * report_len;
+ elants_i2c_event(ts, buf, report_len);
}
break;
@@ -1250,6 +1356,7 @@ static int elants_i2c_probe(struct i2c_client *client,
init_completion(&ts->cmd_done);
ts->client = client;
+ ts->chip_id = (enum elants_chip_id)id->driver_data;
i2c_set_clientdata(client, ts);
ts->vcc33 = devm_regulator_get(&client->dev, "vcc33");
@@ -1331,13 +1438,20 @@ static int elants_i2c_probe(struct i2c_client *client,
input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE,
0, MT_TOOL_PALM, 0, 0);
+
+ touchscreen_parse_properties(ts->input, true, &ts->prop);
+
+ if (ts->chip_id == EKTF3624) {
+ /* calculate resolution from size */
+ ts->x_res = DIV_ROUND_CLOSEST(ts->prop.max_x, ts->phy_x);
+ ts->y_res = DIV_ROUND_CLOSEST(ts->prop.max_y, ts->phy_y);
+ }
+
input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res);
input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res);
if (ts->major_res > 0)
input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res);
- touchscreen_parse_properties(ts->input, true, &ts->prop);
-
error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error) {
@@ -1466,14 +1580,16 @@ static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
elants_i2c_suspend, elants_i2c_resume);
static const struct i2c_device_id elants_i2c_id[] = {
- { DEVICE_NAME, 0 },
+ { DEVICE_NAME, EKTH3500 },
+ { "ekth3500", EKTH3500 },
+ { "ektf3624", EKTF3624 },
{ }
};
MODULE_DEVICE_TABLE(i2c, elants_i2c_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id elants_acpi_id[] = {
- { "ELAN0001", 0 },
+ { "ELAN0001", EKTH3500 },
{ }
};
MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
@@ -1482,6 +1598,7 @@ MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
#ifdef CONFIG_OF
static const struct of_device_id elants_of_match[] = {
{ .compatible = "elan,ekth3500" },
+ { .compatible = "elan,ektf3624" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, elants_of_match);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index e0bacd34866a..96173232e53f 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -341,8 +341,10 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
switch (elo->id) {
case 0: /* 10-byte protocol */
- if (elo_setup_10(elo))
+ if (elo_setup_10(elo)) {
+ err = -EIO;
goto fail3;
+ }
break;
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
index 4fd21bc3ce0f..54f30038dca4 100644
--- a/drivers/input/touchscreen/iqs5xx.c
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -2,8 +2,7 @@
/*
* Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
*
- * Copyright (C) 2018
- * Author: Jeff LaBundy <jeff@labundy.com>
+ * Copyright (C) 2018 Jeff LaBundy <jeff@labundy.com>
*
* These devices require firmware exported from a PC-based configuration tool
* made available by the vendor. Firmware files may be pushed to the device's
@@ -12,6 +11,7 @@
* Link to PC-based configuration tool and data sheet: http://www.azoteq.com/
*/
+#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -30,9 +30,9 @@
#define IQS5XX_FW_FILE_LEN 64
#define IQS5XX_NUM_RETRIES 10
-#define IQS5XX_NUM_POINTS 256
#define IQS5XX_NUM_CONTACTS 5
#define IQS5XX_WR_BYTES_MAX 2
+#define IQS5XX_XY_RES_MAX 0xFFFE
#define IQS5XX_PROD_NUM_IQS550 40
#define IQS5XX_PROD_NUM_IQS572 58
@@ -41,28 +41,27 @@
#define IQS5XX_PROJ_NUM_B000 15
#define IQS5XX_MAJOR_VER_MIN 2
-#define IQS5XX_RESUME 0x00
-#define IQS5XX_SUSPEND 0x01
+#define IQS5XX_SHOW_RESET BIT(7)
+#define IQS5XX_ACK_RESET BIT(7)
-#define IQS5XX_SW_INPUT_EVENT 0x10
-#define IQS5XX_SETUP_COMPLETE 0x40
-#define IQS5XX_EVENT_MODE 0x01
-#define IQS5XX_TP_EVENT 0x04
+#define IQS5XX_SUSPEND BIT(0)
+#define IQS5XX_RESUME 0
-#define IQS5XX_FLIP_X 0x01
-#define IQS5XX_FLIP_Y 0x02
-#define IQS5XX_SWITCH_XY_AXIS 0x04
+#define IQS5XX_SETUP_COMPLETE BIT(6)
+#define IQS5XX_WDT BIT(5)
+#define IQS5XX_ALP_REATI BIT(3)
+#define IQS5XX_REATI BIT(2)
+
+#define IQS5XX_TP_EVENT BIT(2)
+#define IQS5XX_EVENT_MODE BIT(0)
#define IQS5XX_PROD_NUM 0x0000
-#define IQS5XX_ABS_X 0x0016
-#define IQS5XX_ABS_Y 0x0018
+#define IQS5XX_SYS_INFO0 0x000F
+#define IQS5XX_SYS_INFO1 0x0010
#define IQS5XX_SYS_CTRL0 0x0431
#define IQS5XX_SYS_CTRL1 0x0432
#define IQS5XX_SYS_CFG0 0x058E
#define IQS5XX_SYS_CFG1 0x058F
-#define IQS5XX_TOTAL_RX 0x063D
-#define IQS5XX_TOTAL_TX 0x063E
-#define IQS5XX_XY_CFG0 0x0669
#define IQS5XX_X_RES 0x066E
#define IQS5XX_Y_RES 0x0670
#define IQS5XX_CHKSM 0x83C0
@@ -99,6 +98,7 @@ struct iqs5xx_private {
struct i2c_client *client;
struct input_dev *input;
struct gpio_desc *reset_gpio;
+ struct touchscreen_properties prop;
struct mutex lock;
u8 bl_status;
};
@@ -126,6 +126,14 @@ struct iqs5xx_touch_data {
u8 area;
} __packed;
+struct iqs5xx_status {
+ u8 sys_info[2];
+ u8 num_active;
+ __be16 rel_x;
+ __be16 rel_y;
+ struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
+} __packed;
+
static int iqs5xx_read_burst(struct i2c_client *client,
u16 reg, void *val, u16 len)
{
@@ -182,11 +190,6 @@ static int iqs5xx_read_word(struct i2c_client *client, u16 reg, u16 *val)
return 0;
}
-static int iqs5xx_read_byte(struct i2c_client *client, u16 reg, u8 *val)
-{
- return iqs5xx_read_burst(client, reg, val, sizeof(*val));
-}
-
static int iqs5xx_write_burst(struct i2c_client *client,
u16 reg, const void *val, u16 len)
{
@@ -337,11 +340,16 @@ static int iqs5xx_bl_open(struct i2c_client *client)
*/
for (i = 0; i < IQS5XX_BL_ATTEMPTS; i++) {
iqs5xx_reset(client);
+ usleep_range(350, 400);
for (j = 0; j < IQS5XX_NUM_RETRIES; j++) {
error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
- if (!error || error == -EINVAL)
- return error;
+ if (!error)
+ usleep_range(10000, 10100);
+ else if (error != -EINVAL)
+ continue;
+
+ return error;
}
}
@@ -481,12 +489,10 @@ static void iqs5xx_close(struct input_dev *input)
static int iqs5xx_axis_init(struct i2c_client *client)
{
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
- struct touchscreen_properties prop;
+ struct touchscreen_properties *prop = &iqs5xx->prop;
struct input_dev *input;
+ u16 max_x, max_y;
int error;
- u16 max_x, max_x_hw;
- u16 max_y, max_y_hw;
- u8 val;
if (!iqs5xx->input) {
input = devm_input_allocate_device(&client->dev);
@@ -506,89 +512,39 @@ static int iqs5xx_axis_init(struct i2c_client *client)
iqs5xx->input = input;
}
- touchscreen_parse_properties(iqs5xx->input, true, &prop);
-
- error = iqs5xx_read_byte(client, IQS5XX_TOTAL_RX, &val);
- if (error)
- return error;
- max_x_hw = (val - 1) * IQS5XX_NUM_POINTS;
-
- error = iqs5xx_read_byte(client, IQS5XX_TOTAL_TX, &val);
+ error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x);
if (error)
return error;
- max_y_hw = (val - 1) * IQS5XX_NUM_POINTS;
- error = iqs5xx_read_byte(client, IQS5XX_XY_CFG0, &val);
+ error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y);
if (error)
return error;
- if (val & IQS5XX_SWITCH_XY_AXIS)
- swap(max_x_hw, max_y_hw);
+ input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_X, max_x);
+ input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_Y, max_y);
- if (prop.swap_x_y)
- val ^= IQS5XX_SWITCH_XY_AXIS;
-
- if (prop.invert_x)
- val ^= prop.swap_x_y ? IQS5XX_FLIP_Y : IQS5XX_FLIP_X;
-
- if (prop.invert_y)
- val ^= prop.swap_x_y ? IQS5XX_FLIP_X : IQS5XX_FLIP_Y;
-
- error = iqs5xx_write_byte(client, IQS5XX_XY_CFG0, val);
- if (error)
- return error;
+ touchscreen_parse_properties(iqs5xx->input, true, prop);
- if (prop.max_x > max_x_hw) {
+ if (prop->max_x > IQS5XX_XY_RES_MAX) {
dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n",
- prop.max_x, max_x_hw);
+ prop->max_x, IQS5XX_XY_RES_MAX);
return -EINVAL;
- } else if (prop.max_x == 0) {
- error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x);
+ } else if (prop->max_x != max_x) {
+ error = iqs5xx_write_word(client, IQS5XX_X_RES, prop->max_x);
if (error)
return error;
-
- input_abs_set_max(iqs5xx->input,
- prop.swap_x_y ? ABS_MT_POSITION_Y :
- ABS_MT_POSITION_X,
- max_x);
- } else {
- max_x = (u16)prop.max_x;
}
- if (prop.max_y > max_y_hw) {
+ if (prop->max_y > IQS5XX_XY_RES_MAX) {
dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n",
- prop.max_y, max_y_hw);
+ prop->max_y, IQS5XX_XY_RES_MAX);
return -EINVAL;
- } else if (prop.max_y == 0) {
- error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y);
+ } else if (prop->max_y != max_y) {
+ error = iqs5xx_write_word(client, IQS5XX_Y_RES, prop->max_y);
if (error)
return error;
-
- input_abs_set_max(iqs5xx->input,
- prop.swap_x_y ? ABS_MT_POSITION_X :
- ABS_MT_POSITION_Y,
- max_y);
- } else {
- max_y = (u16)prop.max_y;
}
- /*
- * Write horizontal and vertical resolution to the device in case its
- * original defaults were overridden or swapped as per the properties
- * specified in the device tree.
- */
- error = iqs5xx_write_word(client,
- prop.swap_x_y ? IQS5XX_Y_RES : IQS5XX_X_RES,
- max_x);
- if (error)
- return error;
-
- error = iqs5xx_write_word(client,
- prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES,
- max_y);
- if (error)
- return error;
-
error = input_mt_init_slots(iqs5xx->input, IQS5XX_NUM_CONTACTS,
INPUT_MT_DIRECT);
if (error)
@@ -603,7 +559,6 @@ static int iqs5xx_dev_init(struct i2c_client *client)
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
struct iqs5xx_dev_id_info *dev_id_info;
int error;
- u8 val;
u8 buf[sizeof(*dev_id_info) + 1];
error = iqs5xx_read_burst(client, IQS5XX_PROD_NUM,
@@ -666,18 +621,18 @@ static int iqs5xx_dev_init(struct i2c_client *client)
if (error)
return error;
- error = iqs5xx_read_byte(client, IQS5XX_SYS_CFG0, &val);
+ error = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL0, IQS5XX_ACK_RESET);
if (error)
return error;
- val |= IQS5XX_SETUP_COMPLETE;
- val &= ~IQS5XX_SW_INPUT_EVENT;
- error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0, val);
+ error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0,
+ IQS5XX_SETUP_COMPLETE | IQS5XX_WDT |
+ IQS5XX_ALP_REATI | IQS5XX_REATI);
if (error)
return error;
- val = IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE;
- error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1, val);
+ error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1,
+ IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE);
if (error)
return error;
@@ -688,13 +643,12 @@ static int iqs5xx_dev_init(struct i2c_client *client)
iqs5xx->bl_status = dev_id_info->bl_status;
/*
- * Closure of the first communication window that appears following the
- * release of reset appears to kick off an initialization period during
- * which further communication is met with clock stretching. The return
- * from this function is delayed so that further communication attempts
- * avoid this period.
+ * The following delay allows ATI to complete before the open and close
+ * callbacks are free to elicit I2C communication. Any attempts to read
+ * from or write to the device during this time may face extended clock
+ * stretching and prompt the I2C controller to report an error.
*/
- msleep(100);
+ msleep(250);
return 0;
}
@@ -702,7 +656,7 @@ static int iqs5xx_dev_init(struct i2c_client *client)
static irqreturn_t iqs5xx_irq(int irq, void *data)
{
struct iqs5xx_private *iqs5xx = data;
- struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
+ struct iqs5xx_status status;
struct i2c_client *client = iqs5xx->client;
struct input_dev *input = iqs5xx->input;
int error, i;
@@ -715,21 +669,35 @@ static irqreturn_t iqs5xx_irq(int irq, void *data)
if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
return IRQ_NONE;
- error = iqs5xx_read_burst(client, IQS5XX_ABS_X,
- touch_data, sizeof(touch_data));
+ error = iqs5xx_read_burst(client, IQS5XX_SYS_INFO0,
+ &status, sizeof(status));
if (error)
return IRQ_NONE;
- for (i = 0; i < ARRAY_SIZE(touch_data); i++) {
- u16 pressure = be16_to_cpu(touch_data[i].strength);
+ if (status.sys_info[0] & IQS5XX_SHOW_RESET) {
+ dev_err(&client->dev, "Unexpected device reset\n");
+
+ error = iqs5xx_dev_init(client);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to re-initialize device: %d\n", error);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(status.touch_data); i++) {
+ struct iqs5xx_touch_data *touch_data = &status.touch_data[i];
+ u16 pressure = be16_to_cpu(touch_data->strength);
input_mt_slot(input, i);
if (input_mt_report_slot_state(input, MT_TOOL_FINGER,
pressure != 0)) {
- input_report_abs(input, ABS_MT_POSITION_X,
- be16_to_cpu(touch_data[i].abs_x));
- input_report_abs(input, ABS_MT_POSITION_Y,
- be16_to_cpu(touch_data[i].abs_y));
+ touchscreen_report_pos(iqs5xx->input, &iqs5xx->prop,
+ be16_to_cpu(touch_data->abs_x),
+ be16_to_cpu(touch_data->abs_y),
+ true);
input_report_abs(input, ABS_MT_PRESSURE, pressure);
}
}
@@ -884,7 +852,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
{
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
- int error;
+ int error, error_bl = 0;
u8 *pmap;
if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE)
@@ -938,6 +906,7 @@ err_reset:
usleep_range(10000, 10100);
}
+ error_bl = error;
error = iqs5xx_dev_init(client);
if (!error && iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
error = -EINVAL;
@@ -949,11 +918,15 @@ err_reset:
err_kfree:
kfree(pmap);
+ if (error_bl)
+ return error_bl;
+
return error;
}
-static ssize_t fw_file_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t fw_file_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
struct i2c_client *client = iqs5xx->client;
@@ -1012,7 +985,7 @@ static int __maybe_unused iqs5xx_suspend(struct device *dev)
struct input_dev *input = iqs5xx->input;
int error = 0;
- if (!input)
+ if (!input || device_may_wakeup(dev))
return error;
mutex_lock(&input->mutex);
@@ -1031,7 +1004,7 @@ static int __maybe_unused iqs5xx_resume(struct device *dev)
struct input_dev *input = iqs5xx->input;
int error = 0;
- if (!input)
+ if (!input || device_may_wakeup(dev))
return error;
mutex_lock(&input->mutex);
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index c0050044a5a9..225796a3f546 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -465,13 +465,13 @@ static void mip4_report_keys(struct mip4_ts *ts, u8 *packet)
static void mip4_report_touch(struct mip4_ts *ts, u8 *packet)
{
int id;
- bool hover;
- bool palm;
+ bool __always_unused hover;
+ bool __always_unused palm;
bool state;
u16 x, y;
- u8 pressure_stage = 0;
+ u8 __always_unused pressure_stage = 0;
u8 pressure;
- u8 size;
+ u8 __always_unused size;
u8 touch_major;
u8 touch_minor;
diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c
index 603a948460d6..4d2d22a86977 100644
--- a/drivers/input/touchscreen/raydium_i2c_ts.c
+++ b/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -445,6 +445,7 @@ static int raydium_i2c_write_object(struct i2c_client *client,
enum raydium_bl_ack state)
{
int error;
+ static const u8 cmd[] = { 0xFF, 0x39 };
error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len);
if (error) {
@@ -453,7 +454,7 @@ static int raydium_i2c_write_object(struct i2c_client *client,
return error;
}
- error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, NULL, 0);
+ error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, cmd, sizeof(cmd));
if (error) {
dev_err(&client->dev, "Ack obj command failed: %d\n", error);
return error;
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index b4e7bcbe9b91..6abae665ca71 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -94,8 +94,13 @@ static int st1232_ts_wait_ready(struct st1232_ts_data *ts)
for (retries = 10; retries; retries--) {
error = st1232_ts_read_data(ts, REG_STATUS, 1);
- if (!error && ts->read_buf[0] == (STATUS_NORMAL | ERROR_NONE))
- return 0;
+ if (!error) {
+ switch (ts->read_buf[0]) {
+ case STATUS_NORMAL | ERROR_NONE:
+ case STATUS_IDLE | ERROR_NONE:
+ return 0;
+ }
+ }
usleep_range(1000, 2000);
}
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index cd747725589b..25c45c3a3561 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -52,6 +52,7 @@
* @idev: registered input device
* @work: a work item used to scan the device
* @dev: a pointer back to the MFD cell struct device*
+ * @prop: Touchscreen properties
* @ave_ctrl: Sample average control
* (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples)
* @touch_det_delay: Touch detect interrupt delay
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 620cdd7d214a..12f2562b0141 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -787,6 +787,7 @@ static int sur40_probe(struct usb_interface *interface,
dev_err(&interface->dev,
"Unable to register video controls.");
v4l2_ctrl_handler_free(&sur40->hdl);
+ error = sur40->hdl.error;
goto err_unreg_v4l2;
}
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
index 731454599fce..1da23e5585a0 100644
--- a/drivers/input/touchscreen/surface3_spi.c
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -94,9 +94,7 @@ static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data)
{
- u16 timestamp;
unsigned int i;
- timestamp = get_unaligned_le16(&data[15]);
for (i = 0; i < 13; i++) {
struct surface3_ts_data_finger *finger;
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 397cb1d3f481..c847453a03c2 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -1044,6 +1044,7 @@ static void nexio_exit(struct usbtouch_usb *usbtouch)
static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
{
+ struct device *dev = &usbtouch->interface->dev;
struct nexio_touch_packet *packet = (void *) pkt;
struct nexio_priv *priv = usbtouch->priv;
unsigned int data_len = be16_to_cpu(packet->data_len);
@@ -1062,6 +1063,8 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
/* send ACK */
ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
+ if (ret)
+ dev_warn(dev, "Failed to submit ACK URB: %d\n", ret);
if (!usbtouch->type->max_xc) {
usbtouch->type->max_xc = 2 * x_len;
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index a3e3adbabc67..3b636beb583c 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -161,7 +161,7 @@ static int zinitix_read_data(struct i2c_client *client,
ret = i2c_master_recv(client, (u8 *)values, length);
if (ret != length)
- return ret < 0 ? ret : -EIO; ;
+ return ret < 0 ? ret : -EIO;
return 0;
}
@@ -190,7 +190,7 @@ static int zinitix_write_cmd(struct i2c_client *client, u16 reg)
return 0;
}
-static bool zinitix_init_touch(struct bt541_ts_data *bt541)
+static int zinitix_init_touch(struct bt541_ts_data *bt541)
{
struct i2c_client *client = bt541->client;
int i;