summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-16 03:18:23 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-16 03:18:23 +0300
commitee249d30fadec7677364063648f5547e243bf93f (patch)
treedccfb94b0a6372f69062ef05fbbfdd770f0b3ece /drivers/input
parent61f914256c56a39a96dc14eae9f394d35b934812 (diff)
parent4b4193256c8d3bc3a5397b5cd9494c2ad386317d (diff)
downloadlinux-ee249d30fadec7677364063648f5547e243bf93f.tar.xz
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: - support for inhibiting input devices at request from userspace. If a device implements open/close methods, it can also put device into low power state. This is needed, for example, to disable keyboard and touchpad on convertibles when they are transitioned into tablet mode - now that ordinary input devices can be configured for polling mode, dedicated input polling device implementation has been removed - GTCO tablet driver has been removed, as it used problematic custom HID parser, devices are EOL, and there is no interest from the manufacturer - a new driver for Dialog DA7280 haptic chips has been introduced - a new driver for power button on Dell Wyse 3020 - support for eKTF2132 in ektf2127 driver - support for SC2721 and SC2730 in sc27xx-vibra driver - enhancements for Atmel touchscreens, AD7846 touchscreens, Elan touchpads, ADP5589, ST1232 touchscreen, TM2 touchkey drivers - fixes and cleanups to allow clean builds with W=1 * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (86 commits) Input: da7280 - fix spelling mistake "sequemce" -> "sequence" Input: cyapa_gen6 - fix out-of-bounds stack access Input: sc27xx - add support for sc2730 and sc2721 dt-bindings: input: Add compatible string for SC2721 and SC2730 dt-bindings: input: Convert sc27xx-vibra.txt to json-schema Input: stmpe - add axis inversion and swapping capability Input: adp5589-keys - do not explicitly control IRQ for wakeup Input: adp5589-keys - do not unconditionally configure as wakeup source Input: ipx4xx-beeper - convert comma to semicolon Input: parkbd - convert comma to semicolon Input: new da7280 haptic driver dt-bindings: input: Add document bindings for DA7280 MAINTAINERS: da7280 updates to the Dialog Semiconductor search terms Input: elantech - fix protocol errors for some trackpoints in SMBus mode Input: elan_i2c - add new trackpoint report type 0x5F Input: elants - document some registers and values Input: atmel_mxt_ts - simplify the return expression of mxt_send_bootloader_cmd() Input: imx_keypad - add COMPILE_TEST support Input: applespi - use new structure for SPI transfer delays Input: synaptics-rmi4 - use new structure for SPI transfer delays ...
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/Kconfig13
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/input-polldev.c362
-rw-r--r--drivers/input/input-poller.c2
-rw-r--r--drivers/input/input.c118
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/joystick/xpad.c6
-rw-r--r--drivers/input/keyboard/Kconfig2
-rw-r--r--drivers/input/keyboard/adp5589-keys.c216
-rw-r--r--drivers/input/keyboard/applespi.c21
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c9
-rw-r--r--drivers/input/keyboard/ep93xx_keypad.c2
-rw-r--r--drivers/input/keyboard/gpio_keys.c6
-rw-r--r--drivers/input/keyboard/imx_keypad.c4
-rw-r--r--drivers/input/keyboard/ipaq-micro-keys.c2
-rw-r--r--drivers/input/keyboard/lpc32xx-keys.c4
-rw-r--r--drivers/input/keyboard/nomadik-ske-keypad.c2
-rw-r--r--drivers/input/keyboard/omap4-keypad.c132
-rw-r--r--drivers/input/keyboard/pmic8xxx-keypad.c26
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c2
-rw-r--r--drivers/input/keyboard/samsung-keypad.c7
-rw-r--r--drivers/input/keyboard/spear-keyboard.c8
-rw-r--r--drivers/input/keyboard/st-keyscan.c4
-rw-r--r--drivers/input/keyboard/tegra-kbc.c4
-rw-r--r--drivers/input/keyboard/tm2-touchkey.c3
-rw-r--r--drivers/input/misc/Kconfig23
-rw-r--r--drivers/input/misc/Makefile2
-rw-r--r--drivers/input/misc/ab8500-ponkey.c2
-rw-r--r--drivers/input/misc/ariel-pwrbutton.c169
-rw-r--r--drivers/input/misc/da7280.c1329
-rw-r--r--drivers/input/misc/drv260x.c30
-rw-r--r--drivers/input/misc/drv2665.c14
-rw-r--r--drivers/input/misc/drv2667.c18
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c2
-rw-r--r--drivers/input/misc/kxtj9.c4
-rw-r--r--drivers/input/misc/mc13783-pwrbutton.c2
-rw-r--r--drivers/input/misc/pcspkr.c1
-rw-r--r--drivers/input/misc/sc27xx-vibra.c71
-rw-r--r--drivers/input/misc/sirfsoc-onkey.c2
-rw-r--r--drivers/input/misc/wm831x-on.c2
-rw-r--r--drivers/input/mouse/Kconfig2
-rw-r--r--drivers/input/mouse/cyapa.c18
-rw-r--r--drivers/input/mouse/cyapa_gen3.c3
-rw-r--r--drivers/input/mouse/cyapa_gen5.c7
-rw-r--r--drivers/input/mouse/cyapa_gen6.c2
-rw-r--r--drivers/input/mouse/elan_i2c.h16
-rw-r--r--drivers/input/mouse/elan_i2c_core.c15
-rw-r--r--drivers/input/mouse/elan_i2c_smbus.c8
-rw-r--r--drivers/input/mouse/elantech.c101
-rw-r--r--drivers/input/mouse/elantech.h4
-rw-r--r--drivers/input/mouse/navpoint.c4
-rw-r--r--drivers/input/mouse/synaptics.c2
-rw-r--r--drivers/input/mouse/vmmouse.c2
-rw-r--r--drivers/input/rmi4/rmi_bus.c2
-rw-r--r--drivers/input/rmi4/rmi_f01.c16
-rw-r--r--drivers/input/rmi4/rmi_f11.c236
-rw-r--r--drivers/input/rmi4/rmi_f54.c6
-rw-r--r--drivers/input/rmi4/rmi_i2c.c4
-rw-r--r--drivers/input/rmi4/rmi_spi.c6
-rw-r--r--drivers/input/serio/libps2.c2
-rw-r--r--drivers/input/serio/parkbd.c2
-rw-r--r--drivers/input/tablet/Kconfig12
-rw-r--r--drivers/input/tablet/Makefile1
-rw-r--r--drivers/input/tablet/gtco.c1043
-rw-r--r--drivers/input/touchscreen/ad7877.c6
-rw-r--r--drivers/input/touchscreen/ad7879.c6
-rw-r--r--drivers/input/touchscreen/ads7846.c247
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c54
-rw-r--r--drivers/input/touchscreen/auo-pixcir-ts.c8
-rw-r--r--drivers/input/touchscreen/bu21029_ts.c4
-rw-r--r--drivers/input/touchscreen/chipone_icn8318.c4
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.c14
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.h14
-rw-r--r--drivers/input/touchscreen/cyttsp_core.c4
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c43
-rw-r--r--drivers/input/touchscreen/eeti_ts.c4
-rw-r--r--drivers/input/touchscreen/ektf2127.c36
-rw-r--r--drivers/input/touchscreen/elants_i2c.c18
-rw-r--r--drivers/input/touchscreen/goodix.c5
-rw-r--r--drivers/input/touchscreen/imx6ul_tsc.c7
-rw-r--r--drivers/input/touchscreen/ipaq-micro-ts.c2
-rw-r--r--drivers/input/touchscreen/iqs5xx.c4
-rw-r--r--drivers/input/touchscreen/lpc32xx_ts.c4
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c8
-rw-r--r--drivers/input/touchscreen/mms114.c6
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c8
-rw-r--r--drivers/input/touchscreen/resistive-adc-touch.c2
-rw-r--r--drivers/input/touchscreen/st1232.c52
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c7
-rw-r--r--drivers/input/touchscreen/surface3_spi.c2
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c4
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c16
-rw-r--r--drivers/input/touchscreen/zforce_ts.c8
-rw-r--r--drivers/input/touchscreen/zinitix.c4
94 files changed, 2550 insertions, 2194 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 1efd3154b68d..ec0e861f185f 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -52,19 +52,6 @@ config INPUT_FF_MEMLESS
To compile this driver as a module, choose M here: the
module will be called ff-memless.
-config INPUT_POLLDEV
- tristate "Polled input device skeleton"
- help
- Say Y here if you are using a driver for an input
- device that periodically polls hardware state. This
- option is only useful for out-of-tree drivers since
- in-tree drivers select it automatically.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called input-polldev.
-
config INPUT_SPARSEKMAP
tristate "Sparse keymap support library"
help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index e35650930371..d8f5310e22ba 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_INPUT) += input-core.o
input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o
obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
-obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
deleted file mode 100644
index 9bf1c9aeb4c4..000000000000
--- a/drivers/input/input-polldev.c
+++ /dev/null
@@ -1,362 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Generic implementation of a polled input device
-
- * Copyright (c) 2007 Dmitry Torokhov
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/jiffies.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/workqueue.h>
-#include <linux/module.h>
-#include <linux/input-polldev.h>
-
-MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
-MODULE_DESCRIPTION("Generic implementation of a polled input device");
-MODULE_LICENSE("GPL v2");
-
-static void input_polldev_queue_work(struct input_polled_dev *dev)
-{
- unsigned long delay;
-
- delay = msecs_to_jiffies(dev->poll_interval);
- if (delay >= HZ)
- delay = round_jiffies_relative(delay);
-
- queue_delayed_work(system_freezable_wq, &dev->work, delay);
-}
-
-static void input_polled_device_work(struct work_struct *work)
-{
- struct input_polled_dev *dev =
- container_of(work, struct input_polled_dev, work.work);
-
- dev->poll(dev);
- input_polldev_queue_work(dev);
-}
-
-static int input_open_polled_device(struct input_dev *input)
-{
- struct input_polled_dev *dev = input_get_drvdata(input);
-
- if (dev->open)
- dev->open(dev);
-
- /* Only start polling if polling is enabled */
- if (dev->poll_interval > 0) {
- dev->poll(dev);
- input_polldev_queue_work(dev);
- }
-
- return 0;
-}
-
-static void input_close_polled_device(struct input_dev *input)
-{
- struct input_polled_dev *dev = input_get_drvdata(input);
-
- cancel_delayed_work_sync(&dev->work);
-
- if (dev->close)
- dev->close(dev);
-}
-
-/* SYSFS interface */
-
-static ssize_t input_polldev_get_poll(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct input_polled_dev *polldev = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n", polldev->poll_interval);
-}
-
-static ssize_t input_polldev_set_poll(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count)
-{
- struct input_polled_dev *polldev = dev_get_drvdata(dev);
- struct input_dev *input = polldev->input;
- unsigned int interval;
- int err;
-
- err = kstrtouint(buf, 0, &interval);
- if (err)
- return err;
-
- if (interval < polldev->poll_interval_min)
- return -EINVAL;
-
- if (interval > polldev->poll_interval_max)
- return -EINVAL;
-
- mutex_lock(&input->mutex);
-
- polldev->poll_interval = interval;
-
- if (input->users) {
- cancel_delayed_work_sync(&polldev->work);
- if (polldev->poll_interval > 0)
- input_polldev_queue_work(polldev);
- }
-
- mutex_unlock(&input->mutex);
-
- return count;
-}
-
-static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll,
- input_polldev_set_poll);
-
-
-static ssize_t input_polldev_get_max(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct input_polled_dev *polldev = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n", polldev->poll_interval_max);
-}
-
-static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL);
-
-static ssize_t input_polldev_get_min(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct input_polled_dev *polldev = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n", polldev->poll_interval_min);
-}
-
-static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL);
-
-static struct attribute *sysfs_attrs[] = {
- &dev_attr_poll.attr,
- &dev_attr_max.attr,
- &dev_attr_min.attr,
- NULL
-};
-
-static struct attribute_group input_polldev_attribute_group = {
- .attrs = sysfs_attrs
-};
-
-static const struct attribute_group *input_polldev_attribute_groups[] = {
- &input_polldev_attribute_group,
- NULL
-};
-
-/**
- * input_allocate_polled_device - allocate memory for polled device
- *
- * The function allocates memory for a polled device and also
- * for an input device associated with this polled device.
- */
-struct input_polled_dev *input_allocate_polled_device(void)
-{
- struct input_polled_dev *dev;
-
- dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL);
- if (!dev)
- return NULL;
-
- dev->input = input_allocate_device();
- if (!dev->input) {
- kfree(dev);
- return NULL;
- }
-
- return dev;
-}
-EXPORT_SYMBOL(input_allocate_polled_device);
-
-struct input_polled_devres {
- struct input_polled_dev *polldev;
-};
-
-static int devm_input_polldev_match(struct device *dev, void *res, void *data)
-{
- struct input_polled_devres *devres = res;
-
- return devres->polldev == data;
-}
-
-static void devm_input_polldev_release(struct device *dev, void *res)
-{
- struct input_polled_devres *devres = res;
- struct input_polled_dev *polldev = devres->polldev;
-
- dev_dbg(dev, "%s: dropping reference/freeing %s\n",
- __func__, dev_name(&polldev->input->dev));
-
- input_put_device(polldev->input);
- kfree(polldev);
-}
-
-static void devm_input_polldev_unregister(struct device *dev, void *res)
-{
- struct input_polled_devres *devres = res;
- struct input_polled_dev *polldev = devres->polldev;
-
- dev_dbg(dev, "%s: unregistering device %s\n",
- __func__, dev_name(&polldev->input->dev));
- input_unregister_device(polldev->input);
-
- /*
- * Note that we are still holding extra reference to the input
- * device so it will stick around until devm_input_polldev_release()
- * is called.
- */
-}
-
-/**
- * devm_input_allocate_polled_device - allocate managed polled device
- * @dev: device owning the polled device being created
- *
- * Returns prepared &struct input_polled_dev or %NULL.
- *
- * Managed polled input devices do not need to be explicitly unregistered
- * or freed as it will be done automatically when owner device unbinds
- * from * its driver (or binding fails). Once such managed polled device
- * is allocated, it is ready to be set up and registered in the same
- * fashion as regular polled input devices (using
- * input_register_polled_device() function).
- *
- * If you want to manually unregister and free such managed polled devices,
- * it can be still done by calling input_unregister_polled_device() and
- * input_free_polled_device(), although it is rarely needed.
- *
- * NOTE: the owner device is set up as parent of input device and users
- * should not override it.
- */
-struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev)
-{
- struct input_polled_dev *polldev;
- struct input_polled_devres *devres;
-
- devres = devres_alloc(devm_input_polldev_release, sizeof(*devres),
- GFP_KERNEL);
- if (!devres)
- return NULL;
-
- polldev = input_allocate_polled_device();
- if (!polldev) {
- devres_free(devres);
- return NULL;
- }
-
- polldev->input->dev.parent = dev;
- polldev->devres_managed = true;
-
- devres->polldev = polldev;
- devres_add(dev, devres);
-
- return polldev;
-}
-EXPORT_SYMBOL(devm_input_allocate_polled_device);
-
-/**
- * input_free_polled_device - free memory allocated for polled device
- * @dev: device to free
- *
- * The function frees memory allocated for polling device and drops
- * reference to the associated input device.
- */
-void input_free_polled_device(struct input_polled_dev *dev)
-{
- if (dev) {
- if (dev->devres_managed)
- WARN_ON(devres_destroy(dev->input->dev.parent,
- devm_input_polldev_release,
- devm_input_polldev_match,
- dev));
- input_put_device(dev->input);
- kfree(dev);
- }
-}
-EXPORT_SYMBOL(input_free_polled_device);
-
-/**
- * input_register_polled_device - register polled device
- * @dev: device to register
- *
- * The function registers previously initialized polled input device
- * with input layer. The device should be allocated with call to
- * input_allocate_polled_device(). Callers should also set up poll()
- * method and set up capabilities (id, name, phys, bits) of the
- * corresponding input_dev structure.
- */
-int input_register_polled_device(struct input_polled_dev *dev)
-{
- struct input_polled_devres *devres = NULL;
- struct input_dev *input = dev->input;
- int error;
-
- if (dev->devres_managed) {
- devres = devres_alloc(devm_input_polldev_unregister,
- sizeof(*devres), GFP_KERNEL);
- if (!devres)
- return -ENOMEM;
-
- devres->polldev = dev;
- }
-
- input_set_drvdata(input, dev);
- INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
-
- if (!dev->poll_interval)
- dev->poll_interval = 500;
- if (!dev->poll_interval_max)
- dev->poll_interval_max = dev->poll_interval;
-
- input->open = input_open_polled_device;
- input->close = input_close_polled_device;
-
- input->dev.groups = input_polldev_attribute_groups;
-
- error = input_register_device(input);
- if (error) {
- devres_free(devres);
- return error;
- }
-
- /*
- * Take extra reference to the underlying input device so
- * that it survives call to input_unregister_polled_device()
- * and is deleted only after input_free_polled_device()
- * has been invoked. This is needed to ease task of freeing
- * sparse keymaps.
- */
- input_get_device(input);
-
- if (dev->devres_managed) {
- dev_dbg(input->dev.parent, "%s: registering %s with devres.\n",
- __func__, dev_name(&input->dev));
- devres_add(input->dev.parent, devres);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(input_register_polled_device);
-
-/**
- * input_unregister_polled_device - unregister polled device
- * @dev: device to unregister
- *
- * The function unregisters previously registered polled input
- * device from input layer. Polling is stopped and device is
- * ready to be freed with call to input_free_polled_device().
- */
-void input_unregister_polled_device(struct input_polled_dev *dev)
-{
- if (dev->devres_managed)
- WARN_ON(devres_destroy(dev->input->dev.parent,
- devm_input_polldev_unregister,
- devm_input_polldev_match,
- dev));
-
- input_unregister_device(dev->input);
-}
-EXPORT_SYMBOL(input_unregister_polled_device);
diff --git a/drivers/input/input-poller.c b/drivers/input/input-poller.c
index 7d6b4e8879f1..688e3cb1c2a0 100644
--- a/drivers/input/input-poller.c
+++ b/drivers/input/input-poller.c
@@ -166,7 +166,7 @@ static ssize_t input_dev_set_poll_interval(struct device *dev,
poller->poll_interval = interval;
- if (input->users) {
+ if (input_device_enabled(input)) {
cancel_delayed_work_sync(&poller->work);
if (poller->poll_interval > 0)
input_dev_poller_queue_work(poller);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 3cfd2c18eebd..ccaeb2426385 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -367,8 +367,13 @@ static int input_get_disposition(struct input_dev *dev,
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
- int disposition = input_get_disposition(dev, type, code, &value);
+ int disposition;
+ /* filter-out events from inhibited devices */
+ if (dev->inhibited)
+ return;
+
+ disposition = input_get_disposition(dev, type, code, &value);
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
add_input_randomness(type, code, value);
@@ -612,10 +617,10 @@ int input_open_device(struct input_handle *handle)
handle->open++;
- if (dev->users++) {
+ if (dev->users++ || dev->inhibited) {
/*
- * Device is already opened, so we can exit immediately and
- * report success.
+ * Device is already opened and/or inhibited,
+ * so we can exit immediately and report success.
*/
goto out;
}
@@ -675,10 +680,9 @@ void input_close_device(struct input_handle *handle)
__input_release_device(handle);
- if (!--dev->users) {
+ if (!dev->inhibited && !--dev->users) {
if (dev->poller)
input_dev_poller_stop(dev->poller);
-
if (dev->close)
dev->close(dev);
}
@@ -1416,12 +1420,49 @@ static ssize_t input_dev_show_properties(struct device *dev,
}
static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);
+static int input_inhibit_device(struct input_dev *dev);
+static int input_uninhibit_device(struct input_dev *dev);
+
+static ssize_t inhibited_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", input_dev->inhibited);
+}
+
+static ssize_t inhibited_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t len)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+ ssize_t rv;
+ bool inhibited;
+
+ if (strtobool(buf, &inhibited))
+ return -EINVAL;
+
+ if (inhibited)
+ rv = input_inhibit_device(input_dev);
+ else
+ rv = input_uninhibit_device(input_dev);
+
+ if (rv != 0)
+ return rv;
+
+ return len;
+}
+
+static DEVICE_ATTR_RW(inhibited);
+
static struct attribute *input_dev_attrs[] = {
&dev_attr_name.attr,
&dev_attr_phys.attr,
&dev_attr_uniq.attr,
&dev_attr_modalias.attr,
&dev_attr_properties.attr,
+ &dev_attr_inhibited.attr,
NULL
};
@@ -1703,6 +1744,63 @@ void input_reset_device(struct input_dev *dev)
}
EXPORT_SYMBOL(input_reset_device);
+static int input_inhibit_device(struct input_dev *dev)
+{
+ int ret = 0;
+
+ mutex_lock(&dev->mutex);
+
+ if (dev->inhibited)
+ goto out;
+
+ if (dev->users) {
+ if (dev->close)
+ dev->close(dev);
+ if (dev->poller)
+ input_dev_poller_stop(dev->poller);
+ }
+
+ spin_lock_irq(&dev->event_lock);
+ input_dev_release_keys(dev);
+ input_dev_toggle(dev, false);
+ spin_unlock_irq(&dev->event_lock);
+
+ dev->inhibited = true;
+
+out:
+ mutex_unlock(&dev->mutex);
+ return ret;
+}
+
+static int input_uninhibit_device(struct input_dev *dev)
+{
+ int ret = 0;
+
+ mutex_lock(&dev->mutex);
+
+ if (!dev->inhibited)
+ goto out;
+
+ if (dev->users) {
+ if (dev->open) {
+ ret = dev->open(dev);
+ if (ret)
+ goto out;
+ }
+ if (dev->poller)
+ input_dev_poller_start(dev->poller);
+ }
+
+ dev->inhibited = false;
+ spin_lock_irq(&dev->event_lock);
+ input_dev_toggle(dev, true);
+ spin_unlock_irq(&dev->event_lock);
+
+out:
+ mutex_unlock(&dev->mutex);
+ return ret;
+}
+
#ifdef CONFIG_PM_SLEEP
static int input_dev_suspend(struct device *dev)
{
@@ -2127,6 +2225,14 @@ void input_enable_softrepeat(struct input_dev *dev, int delay, int period)
}
EXPORT_SYMBOL(input_enable_softrepeat);
+bool input_device_enabled(struct input_dev *dev)
+{
+ lockdep_assert_held(&dev->mutex);
+
+ return !dev->inhibited && dev->users > 0;
+}
+EXPORT_SYMBOL_GPL(input_device_enabled);
+
/**
* input_register_device - register device with input core
* @dev: device to be registered
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 2b625ebef914..f798922a4598 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -665,7 +665,7 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv
int err;
if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL)))
- return - ENOMEM;
+ return -ENOMEM;
err = analog_init_port(gameport, drv, port);
if (err)
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 8c73377ac82c..0687f0ed60b8 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -1339,7 +1339,7 @@ struct xpad_led {
struct usb_xpad *xpad;
};
-/**
+/*
* set the LEDs on Xbox360 / Wireless Controllers
* @param command
* 0: off
@@ -1904,7 +1904,7 @@ static int xpad_suspend(struct usb_interface *intf, pm_message_t message)
xpad360w_poweroff_controller(xpad);
} else {
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
xpad_stop_input(xpad);
mutex_unlock(&input->mutex);
}
@@ -1924,7 +1924,7 @@ static int xpad_resume(struct usb_interface *intf)
retval = xpad360w_start_input(xpad);
} else {
mutex_lock(&input->mutex);
- if (input->users) {
+ if (input_device_enabled(input)) {
retval = xpad_start_input(xpad);
} else if (xpad->xtype == XTYPE_XBOXONE) {
/*
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 793ecbbda32c..2b321c17054a 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -457,7 +457,7 @@ config KEYBOARD_SNVS_PWRKEY
config KEYBOARD_IMX
tristate "IMX keypad support"
- depends on ARCH_MXC
+ depends on ARCH_MXC || COMPILE_TEST
select INPUT_MATRIXKMAP
help
Enable support for IMX keypad port.
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index eb0e9cd66bcb..654e0476406b 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -7,12 +7,14 @@
* Copyright (C) 2010-2011 Analog Devices Inc.
*/
+#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/errno.h>
#include <linux/pm.h>
+#include <linux/pm_wakeirq.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/i2c.h>
@@ -153,48 +155,48 @@
#define ADP5589_5_MAN_ID 0x02
/* GENERAL_CFG Register */
-#define OSC_EN (1 << 7)
+#define OSC_EN BIT(7)
#define CORE_CLK(x) (((x) & 0x3) << 5)
-#define LCK_TRK_LOGIC (1 << 4) /* ADP5589 only */
-#define LCK_TRK_GPI (1 << 3) /* ADP5589 only */
-#define INT_CFG (1 << 1)
-#define RST_CFG (1 << 0)
+#define LCK_TRK_LOGIC BIT(4) /* ADP5589 only */
+#define LCK_TRK_GPI BIT(3) /* ADP5589 only */
+#define INT_CFG BIT(1)
+#define RST_CFG BIT(0)
/* INT_EN Register */
-#define LOGIC2_IEN (1 << 5) /* ADP5589 only */
-#define LOGIC1_IEN (1 << 4)
-#define LOCK_IEN (1 << 3) /* ADP5589 only */
-#define OVRFLOW_IEN (1 << 2)
-#define GPI_IEN (1 << 1)
-#define EVENT_IEN (1 << 0)
+#define LOGIC2_IEN BIT(5) /* ADP5589 only */
+#define LOGIC1_IEN BIT(4)
+#define LOCK_IEN BIT(3) /* ADP5589 only */
+#define OVRFLOW_IEN BIT(2)
+#define GPI_IEN BIT(1)
+#define EVENT_IEN BIT(0)
/* Interrupt Status Register */
-#define LOGIC2_INT (1 << 5) /* ADP5589 only */
-#define LOGIC1_INT (1 << 4)
-#define LOCK_INT (1 << 3) /* ADP5589 only */
-#define OVRFLOW_INT (1 << 2)
-#define GPI_INT (1 << 1)
-#define EVENT_INT (1 << 0)
+#define LOGIC2_INT BIT(5) /* ADP5589 only */
+#define LOGIC1_INT BIT(4)
+#define LOCK_INT BIT(3) /* ADP5589 only */
+#define OVRFLOW_INT BIT(2)
+#define GPI_INT BIT(1)
+#define EVENT_INT BIT(0)
/* STATUS Register */
-#define LOGIC2_STAT (1 << 7) /* ADP5589 only */
-#define LOGIC1_STAT (1 << 6)
-#define LOCK_STAT (1 << 5) /* ADP5589 only */
+#define LOGIC2_STAT BIT(7) /* ADP5589 only */
+#define LOGIC1_STAT BIT(6)
+#define LOCK_STAT BIT(5) /* ADP5589 only */
#define KEC 0x1F
/* PIN_CONFIG_D Register */
-#define C4_EXTEND_CFG (1 << 6) /* RESET2 */
-#define R4_EXTEND_CFG (1 << 5) /* RESET1 */
+#define C4_EXTEND_CFG BIT(6) /* RESET2 */
+#define R4_EXTEND_CFG BIT(5) /* RESET1 */
/* LOCK_CFG */
-#define LOCK_EN (1 << 0)
+#define LOCK_EN BIT(0)
#define PTIME_MASK 0x3
#define LTIME_MASK 0x3 /* ADP5589 only */
/* Key Event Register xy */
-#define KEY_EV_PRESSED (1 << 7)
-#define KEY_EV_MASK (0x7F)
+#define KEY_EV_PRESSED BIT(7)
+#define KEY_EV_MASK 0x7F
#define KEYP_MAX_EVENT 16
#define ADP5589_MAXGPIO 19
@@ -238,7 +240,6 @@ struct adp5589_kpad {
bool support_row5;
#ifdef CONFIG_GPIOLIB
unsigned char gpiomap[ADP5589_MAXGPIO];
- bool export_gpio;
struct gpio_chip gc;
struct mutex gpio_lock; /* Protect cached dir, dat_out */
u8 dat_out[3];
@@ -473,7 +474,7 @@ static int adp5589_build_gpiomap(struct adp5589_kpad *kpad,
memset(pin_used, false, sizeof(pin_used));
for (i = 0; i < kpad->var->maxgpio; i++)
- if (pdata->keypad_en_mask & (1 << i))
+ if (pdata->keypad_en_mask & BIT(i))
pin_used[i] = true;
for (i = 0; i < kpad->gpimapsize; i++)
@@ -512,8 +513,6 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad)
return 0;
}
- kpad->export_gpio = true;
-
kpad->gc.direction_input = adp5589_gpio_direction_input;
kpad->gc.direction_output = adp5589_gpio_direction_output;
kpad->gc.get = adp5589_gpio_get_value;
@@ -526,11 +525,9 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad)
mutex_init(&kpad->gpio_lock);
- error = gpiochip_add_data(&kpad->gc, kpad);
- if (error) {
- dev_err(dev, "gpiochip_add_data() failed, err: %d\n", error);
+ error = devm_gpiochip_add_data(dev, &kpad->gc, kpad);
+ if (error)
return error;
- }
for (i = 0; i <= kpad->var->bank(kpad->var->maxgpio); i++) {
kpad->dat_out[i] = adp5589_read(kpad->client, kpad->var->reg(
@@ -539,46 +536,13 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad)
ADP5589_GPIO_DIRECTION_A) + i);
}
- if (gpio_data->setup) {
- error = gpio_data->setup(kpad->client,
- kpad->gc.base, kpad->gc.ngpio,
- gpio_data->context);
- if (error)
- dev_warn(dev, "setup failed, %d\n", error);
- }
-
return 0;
}
-
-static void adp5589_gpio_remove(struct adp5589_kpad *kpad)
-{
- struct device *dev = &kpad->client->dev;
- const struct adp5589_kpad_platform_data *pdata = dev_get_platdata(dev);
- const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;
- int error;
-
- if (!kpad->export_gpio)
- return;
-
- if (gpio_data->teardown) {
- error = gpio_data->teardown(kpad->client,
- kpad->gc.base, kpad->gc.ngpio,
- gpio_data->context);
- if (error)
- dev_warn(dev, "teardown failed %d\n", error);
- }
-
- gpiochip_remove(&kpad->gc);
-}
#else
static inline int adp5589_gpio_add(struct adp5589_kpad *kpad)
{
return 0;
}
-
-static inline void adp5589_gpio_remove(struct adp5589_kpad *kpad)
-{
-}
#endif
static void adp5589_report_switches(struct adp5589_kpad *kpad,
@@ -689,13 +653,13 @@ static int adp5589_setup(struct adp5589_kpad *kpad)
unsigned short pin = pdata->gpimap[i].pin;
if (pin <= kpad->var->gpi_pin_row_end) {
- evt_mode1 |= (1 << (pin - kpad->var->gpi_pin_row_base));
+ evt_mode1 |= BIT(pin - kpad->var->gpi_pin_row_base);
} else {
evt_mode2 |=
- ((1 << (pin - kpad->var->gpi_pin_col_base)) & 0xFF);
+ BIT(pin - kpad->var->gpi_pin_col_base) & 0xFF;
if (!kpad->is_adp5585)
- evt_mode3 |= ((1 << (pin -
- kpad->var->gpi_pin_col_base)) >> 8);
+ evt_mode3 |=
+ BIT(pin - kpad->var->gpi_pin_col_base) >> 8;
}
}
@@ -715,7 +679,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad)
dev_warn(&client->dev, "Conflicting pull resistor config\n");
for (i = 0; i <= kpad->var->max_row_num; i++) {
- unsigned val = 0, bit = (1 << i);
+ unsigned int val = 0, bit = BIT(i);
if (pdata->pullup_en_300k & bit)
val = 0;
else if (pdata->pulldown_en_300k & bit)
@@ -735,7 +699,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad)
}
for (i = 0; i <= kpad->var->max_col_num; i++) {
- unsigned val = 0, bit = 1 << (i + kpad->var->col_shift);
+ unsigned int val = 0, bit = BIT(i + kpad->var->col_shift);
if (pdata->pullup_en_300k & bit)
val = 0;
else if (pdata->pulldown_en_300k & bit)
@@ -851,7 +815,7 @@ static void adp5589_report_switch_state(struct adp5589_kpad *kpad)
input_report_switch(kpad->input,
kpad->gpimap[i].sw_evt,
- !(gpi_stat_tmp & (1 << pin_loc)));
+ !(gpi_stat_tmp & BIT(pin_loc)));
}
input_sync(kpad->input);
@@ -897,7 +861,7 @@ static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid)
return -EINVAL;
}
- if ((1 << (pin - kpad->var->gpi_pin_row_base)) &
+ if (BIT(pin - kpad->var->gpi_pin_row_base) &
pdata->keypad_en_mask) {
dev_err(&client->dev, "invalid gpi row/col data\n");
return -EINVAL;
@@ -909,7 +873,7 @@ static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid)
return -EINVAL;
}
- input = input_allocate_device();
+ input = devm_input_allocate_device(&client->dev);
if (!input)
return -ENOMEM;
@@ -955,36 +919,27 @@ static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid)
error = input_register_device(input);
if (error) {
dev_err(&client->dev, "unable to register input device\n");
- goto err_free_input;
+ return error;
}
- error = request_threaded_irq(client->irq, NULL, adp5589_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- client->dev.driver->name, kpad);
+ error = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, adp5589_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ client->dev.driver->name, kpad);
if (error) {
- dev_err(&client->dev, "irq %d busy?\n", client->irq);
- goto err_unreg_dev;
+ dev_err(&client->dev, "unable to request irq %d\n", client->irq);
+ return error;
}
- device_init_wakeup(&client->dev, 1);
-
return 0;
-
-err_unreg_dev:
- input_unregister_device(input);
- input = NULL;
-err_free_input:
- input_free_device(input);
-
- return error;
}
-static void adp5589_keypad_remove(struct adp5589_kpad *kpad)
+static void adp5589_clear_config(void *data)
{
- if (kpad->input) {
- free_irq(kpad->client->irq, kpad);
- input_unregister_device(kpad->input);
- }
+ struct i2c_client *client = data;
+ struct adp5589_kpad *kpad = i2c_get_clientdata(client);
+
+ adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0);
}
static int adp5589_probe(struct i2c_client *client,
@@ -1007,7 +962,7 @@ static int adp5589_probe(struct i2c_client *client,
return -EINVAL;
}
- kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
+ kpad = devm_kzalloc(&client->dev, sizeof(*kpad), GFP_KERNEL);
if (!kpad)
return -ENOMEM;
@@ -1027,89 +982,61 @@ static int adp5589_probe(struct i2c_client *client,
break;
}
+ error = devm_add_action_or_reset(&client->dev, adp5589_clear_config,
+ client);
+ if (error)
+ return error;
+
ret = adp5589_read(client, ADP5589_5_ID);
- if (ret < 0) {
- error = ret;
- goto err_free_mem;
- }
+ if (ret < 0)
+ return ret;
revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK;
if (pdata->keymapsize) {
error = adp5589_keypad_add(kpad, revid);
if (error)
- goto err_free_mem;
+ return error;
}
error = adp5589_setup(kpad);
if (error)
- goto err_keypad_remove;
+ return error;
if (kpad->gpimapsize)
adp5589_report_switch_state(kpad);
error = adp5589_gpio_add(kpad);
if (error)
- goto err_keypad_remove;
+ return error;
i2c_set_clientdata(client, kpad);
dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
return 0;
-
-err_keypad_remove:
- adp5589_keypad_remove(kpad);
-err_free_mem:
- kfree(kpad);
-
- return error;
}
-static int adp5589_remove(struct i2c_client *client)
+static int __maybe_unused adp5589_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct adp5589_kpad *kpad = i2c_get_clientdata(client);
- adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0);
- adp5589_keypad_remove(kpad);
- adp5589_gpio_remove(kpad);
- kfree(kpad);
+ if (kpad->input)
+ disable_irq(client->irq);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int adp5589_suspend(struct device *dev)
+static int __maybe_unused adp5589_resume(struct device *dev)
{
- struct adp5589_kpad *kpad = dev_get_drvdata(dev);
- struct i2c_client *client = kpad->client;
-
- if (!kpad->input)
- return 0;
-
- disable_irq(client->irq);
-
- if (device_may_wakeup(&client->dev))
- enable_irq_wake(client->irq);
-
- return 0;
-}
-
-static int adp5589_resume(struct device *dev)
-{
- struct adp5589_kpad *kpad = dev_get_drvdata(dev);
- struct i2c_client *client = kpad->client;
-
- if (!kpad->input)
- return 0;
-
- if (device_may_wakeup(&client->dev))
- disable_irq_wake(client->irq);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adp5589_kpad *kpad = i2c_get_clientdata(client);
- enable_irq(client->irq);
+ if (kpad->input)
+ enable_irq(client->irq);
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume);
@@ -1128,7 +1055,6 @@ static struct i2c_driver adp5589_driver = {
.pm = &adp5589_dev_pm_ops,
},
.probe = adp5589_probe,
- .remove = adp5589_remove,
.id_table = adp5589_id,
};
diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
index 14362ebab9a9..d22223154177 100644
--- a/drivers/input/keyboard/applespi.c
+++ b/drivers/input/keyboard/applespi.c
@@ -286,6 +286,15 @@ struct command_protocol_bl {
* structure (after re-assembly in case of being split over
* multiple spi-packets), minus the trailing crc. The total size
* of the message struct is therefore @length + 10.
+ *
+ * @keyboard: Keyboard message
+ * @touchpad: Touchpad message
+ * @tp_info: Touchpad info (response)
+ * @tp_info_command: Touchpad info (CRC)
+ * @init_mt_command: Initialise Multitouch
+ * @capsl_command: Toggle caps-lock LED
+ * @bl_command: Keyboard brightness
+ * @data: Buffer data
*/
struct message {
__le16 type;
@@ -545,7 +554,8 @@ static void applespi_setup_read_txfrs(struct applespi_data *applespi)
memset(dl_t, 0, sizeof(*dl_t));
memset(rd_t, 0, sizeof(*rd_t));
- dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay;
+ dl_t->delay.value = applespi->spi_settings.spi_cs_delay;
+ dl_t->delay.unit = SPI_DELAY_UNIT_USECS;
rd_t->rx_buf = applespi->rx_buffer;
rd_t->len = APPLESPI_PACKET_SIZE;
@@ -574,14 +584,17 @@ static void applespi_setup_write_txfrs(struct applespi_data *applespi)
* end up with an extra unnecessary (but harmless) cs assertion and
* deassertion.
*/
- wt_t->delay_usecs = SPI_RW_CHG_DELAY_US;
+ wt_t->delay.value = SPI_RW_CHG_DELAY_US;
+ wt_t->delay.unit = SPI_DELAY_UNIT_USECS;
wt_t->cs_change = 1;
- dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay;
+ dl_t->delay.value = applespi->spi_settings.spi_cs_delay;
+ dl_t->delay.unit = SPI_DELAY_UNIT_USECS;
wr_t->tx_buf = applespi->tx_buffer;
wr_t->len = APPLESPI_PACKET_SIZE;
- wr_t->delay_usecs = SPI_RW_CHG_DELAY_US;
+ wr_t->delay.value = SPI_RW_CHG_DELAY_US;
+ wr_t->delay.unit = SPI_DELAY_UNIT_USECS;
st_t->rx_buf = applespi->tx_status;
st_t->len = APPLESPI_STATUS_SIZE;
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 1f0d61b3c213..b379ed762878 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,7 +27,9 @@
#include <asm/unaligned.h>
-/*
+/**
+ * struct cros_ec_keyb - Structure representing EC keyboard device
+ *
* @rows: Number of rows in the keypad
* @cols: Number of columns in the keypad
* @row_shift: log2 or number of rows, rounded up
@@ -58,10 +60,9 @@ struct cros_ec_keyb {
struct notifier_block notifier;
};
-
/**
- * cros_ec_bs_map - Struct mapping Linux keycodes to EC button/switch bitmap
- * #defines
+ * struct cros_ec_bs_map - Mapping between Linux keycodes and EC button/switch
+ * bitmap #defines
*
* @ev_type: The type of the input event to generate (e.g., EV_KEY).
* @code: A linux keycode
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index f831f01501d5..c8194333d612 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -208,7 +208,7 @@ static int ep93xx_keypad_resume(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users) {
+ if (input_device_enabled(input_dev)) {
if (!keypad->enabled) {
ep93xx_keypad_config(keypad);
clk_enable(keypad->clk);
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index f2d4e4daa818..77bac4ddf324 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -108,7 +108,7 @@ static int get_n_events_by_type(int type)
/**
* get_bm_events_by_type() - returns bitmap of supported events per @type
- * @input: input device from which bitmap is retrieved
+ * @dev: input device from which bitmap is retrieved
* @type: type of button (%EV_KEY, %EV_SW)
*
* Return value of this function can be used to allocate bitmap
@@ -965,7 +965,7 @@ static int __maybe_unused gpio_keys_suspend(struct device *dev)
return error;
} else {
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
gpio_keys_close(input);
mutex_unlock(&input->mutex);
}
@@ -983,7 +983,7 @@ static int __maybe_unused gpio_keys_resume(struct device *dev)
gpio_keys_disable_wakeup(ddata);
} else {
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
error = gpio_keys_open(input);
mutex_unlock(&input->mutex);
}
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 5a46d113e909..1f5c9ea5e9e5 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -532,7 +532,7 @@ static int __maybe_unused imx_kbd_noirq_suspend(struct device *dev)
/* imx kbd can wake up system even clock is disabled */
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
clk_disable_unprepare(kbd->clk);
mutex_unlock(&input_dev->mutex);
@@ -562,7 +562,7 @@ static int __maybe_unused imx_kbd_noirq_resume(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users) {
+ if (input_device_enabled(input_dev)) {
ret = clk_prepare_enable(kbd->clk);
if (ret)
goto err_clk;
diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c
index e3f9e445e880..13a66a8e3411 100644
--- a/drivers/input/keyboard/ipaq-micro-keys.c
+++ b/drivers/input/keyboard/ipaq-micro-keys.c
@@ -140,7 +140,7 @@ static int __maybe_unused micro_key_resume(struct device *dev)
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
micro_key_start(keys);
mutex_unlock(&input->mutex);
diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c
index 348af2aeb5de..943aeeb0de79 100644
--- a/drivers/input/keyboard/lpc32xx-keys.c
+++ b/drivers/input/keyboard/lpc32xx-keys.c
@@ -273,7 +273,7 @@ static int lpc32xx_kscan_suspend(struct device *dev)
mutex_lock(&input->mutex);
- if (input->users) {
+ if (input_device_enabled(input)) {
/* Clear IRQ and disable clock */
writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base));
clk_disable_unprepare(kscandat->clk);
@@ -292,7 +292,7 @@ static int lpc32xx_kscan_resume(struct device *dev)
mutex_lock(&input->mutex);
- if (input->users) {
+ if (input_device_enabled(input)) {
/* Enable clock and clear IRQ */
retval = clk_prepare_enable(kscandat->clk);
if (retval == 0)
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
index 608446e14614..0d55a95347f1 100644
--- a/drivers/input/keyboard/nomadik-ske-keypad.c
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -58,6 +58,8 @@
* @board: keypad platform device
* @keymap: matrix scan code table for keycodes
* @clk: clock structure pointer
+ * @pclk: clock structure pointer
+ * @ske_keypad_lock: spinlock protecting the keypad read/writes
*/
struct ske_keypad {
int irq;
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index d6c924032aaa..b17ac2a295b9 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -18,6 +18,7 @@
#include <linux/input/matrix_keypad.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/pm_wakeirq.h>
/* OMAP4 registers */
#define OMAP4_KBD_REVISION 0x00
@@ -69,7 +70,6 @@ struct omap4_keypad {
struct input_dev *input;
void __iomem *base;
- bool irq_wake_enabled;
unsigned int irq;
unsigned int rows;
@@ -186,12 +186,8 @@ static int omap4_keypad_open(struct input_dev *input)
return 0;
}
-static void omap4_keypad_close(struct input_dev *input)
+static void omap4_keypad_stop(struct omap4_keypad *keypad_data)
{
- struct omap4_keypad *keypad_data = input_get_drvdata(input);
-
- disable_irq(keypad_data->irq);
-
/* Disable interrupts and wake-up events */
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
OMAP4_VAL_IRQDISABLE);
@@ -200,7 +196,15 @@ static void omap4_keypad_close(struct input_dev *input)
/* clear pending interrupts */
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
+}
+static void omap4_keypad_close(struct input_dev *input)
+{
+ struct omap4_keypad *keypad_data;
+
+ 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);
@@ -223,13 +227,37 @@ static int omap4_keypad_parse_dt(struct device *dev,
return 0;
}
+static int omap4_keypad_check_revision(struct device *dev,
+ struct omap4_keypad *keypad_data)
+{
+ unsigned int rev;
+
+ rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION);
+ rev &= 0x03 << 30;
+ rev >>= 30;
+ switch (rev) {
+ case KBD_REVISION_OMAP4:
+ keypad_data->reg_offset = 0x00;
+ keypad_data->irqreg_offset = 0x00;
+ break;
+ case KBD_REVISION_OMAP5:
+ keypad_data->reg_offset = 0x10;
+ keypad_data->irqreg_offset = 0x0c;
+ break;
+ default:
+ dev_err(dev, "Keypad reports unsupported revision %d", rev);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int omap4_keypad_probe(struct platform_device *pdev)
{
struct omap4_keypad *keypad_data;
struct input_dev *input_dev;
struct resource *res;
unsigned int max_keys;
- int rev;
int irq;
int error;
@@ -269,41 +297,33 @@ static int omap4_keypad_probe(struct platform_device *pdev)
goto err_release_mem;
}
+ pm_runtime_enable(&pdev->dev);
/*
* Enable clocks for the keypad module so that we can read
* revision register.
*/
- pm_runtime_enable(&pdev->dev);
error = pm_runtime_get_sync(&pdev->dev);
if (error) {
dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
- goto err_unmap;
- }
- rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION);
- rev &= 0x03 << 30;
- rev >>= 30;
- switch (rev) {
- case KBD_REVISION_OMAP4:
- keypad_data->reg_offset = 0x00;
- keypad_data->irqreg_offset = 0x00;
- break;
- case KBD_REVISION_OMAP5:
- keypad_data->reg_offset = 0x10;
- keypad_data->irqreg_offset = 0x0c;
- break;
- default:
- dev_err(&pdev->dev,
- "Keypad reports unsupported revision %d", rev);
- error = -EINVAL;
- goto err_pm_put_sync;
+ 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);
}
+ if (error)
+ goto err_pm_disable;
/* input device allocation */
keypad_data->input = input_dev = input_allocate_device();
if (!input_dev) {
error = -ENOMEM;
- goto err_pm_put_sync;
+ goto err_pm_disable;
}
input_dev->name = pdev->name;
@@ -349,28 +369,30 @@ static int omap4_keypad_probe(struct platform_device *pdev)
goto err_free_keymap;
}
- device_init_wakeup(&pdev->dev, true);
- pm_runtime_put_sync(&pdev->dev);
-
error = input_register_device(keypad_data->input);
if (error < 0) {
dev_err(&pdev->dev, "failed to register input device\n");
- goto err_pm_disable;
+ goto err_free_irq;
}
+ device_init_wakeup(&pdev->dev, true);
+ error = dev_pm_set_wake_irq(&pdev->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);
+
return 0;
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
+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_put_sync:
- pm_runtime_put_sync(&pdev->dev);
-err_unmap:
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
iounmap(keypad_data->base);
err_release_mem:
release_mem_region(res->start, resource_size(res));
@@ -384,6 +406,8 @@ 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);
@@ -407,45 +431,11 @@ static const struct of_device_id omap_keypad_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, omap_keypad_dt_match);
-#ifdef CONFIG_PM_SLEEP
-static int omap4_keypad_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
- int error;
-
- if (device_may_wakeup(&pdev->dev)) {
- error = enable_irq_wake(keypad_data->irq);
- if (!error)
- keypad_data->irq_wake_enabled = true;
- }
-
- return 0;
-}
-
-static int omap4_keypad_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
-
- if (device_may_wakeup(&pdev->dev) && keypad_data->irq_wake_enabled) {
- disable_irq_wake(keypad_data->irq);
- keypad_data->irq_wake_enabled = false;
- }
-
- return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(omap4_keypad_pm_ops,
- omap4_keypad_suspend, omap4_keypad_resume);
-
static struct platform_driver omap4_keypad_driver = {
.probe = omap4_keypad_probe,
.remove = omap4_keypad_remove,
.driver = {
.name = "omap4-keypad",
- .pm = &omap4_keypad_pm_ops,
.of_match_table = omap_keypad_dt_match,
},
};
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 91d5811d6f0e..4766c5048ce2 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -76,17 +76,17 @@
/**
* struct pmic8xxx_kp - internal keypad data structure
- * @num_cols - number of columns of keypad
- * @num_rows - number of row of keypad
- * @input - input device pointer for keypad
- * @regmap - regmap handle
- * @key_sense_irq - key press/release irq number
- * @key_stuck_irq - key stuck notification irq number
- * @keycodes - array to hold the key codes
- * @dev - parent device pointer
- * @keystate - present key press/release state
- * @stuckstate - present state when key stuck irq
- * @ctrl_reg - control register value
+ * @num_cols: number of columns of keypad
+ * @num_rows: number of row of keypad
+ * @input: input device pointer for keypad
+ * @regmap: regmap handle
+ * @key_sense_irq: key press/release irq number
+ * @key_stuck_irq: key stuck notification irq number
+ * @keycodes: array to hold the key codes
+ * @dev: parent device pointer
+ * @keystate: present key press/release state
+ * @stuckstate: present state when key stuck irq
+ * @ctrl_reg: control register value
*/
struct pmic8xxx_kp {
unsigned int num_rows;
@@ -633,7 +633,7 @@ static int pmic8xxx_kp_suspend(struct device *dev)
} else {
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
pmic8xxx_kp_disable(kp);
mutex_unlock(&input_dev->mutex);
@@ -653,7 +653,7 @@ static int pmic8xxx_kp_resume(struct device *dev)
} else {
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
pmic8xxx_kp_enable(kp);
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index 7e65708b25a4..a7f8257c8a02 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -694,7 +694,7 @@ static int pxa27x_keypad_resume(struct device *dev)
} else {
mutex_lock(&input_dev->mutex);
- if (input_dev->users) {
+ if (input_device_enabled(input_dev)) {
/* Enable unit clock */
ret = clk_prepare_enable(keypad->clk);
if (!ret)
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 70c1d086bdd2..df0258dcf89e 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -146,13 +146,12 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
{
struct samsung_keypad *keypad = dev_id;
unsigned int row_state[SAMSUNG_MAX_COLS];
- unsigned int val;
bool key_down;
pm_runtime_get_sync(&keypad->pdev->dev);
do {
- val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
+ readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
/* Clear interrupt. */
writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
@@ -537,7 +536,7 @@ static int samsung_keypad_suspend(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
samsung_keypad_stop(keypad);
samsung_keypad_toggle_wakeup(keypad, true);
@@ -557,7 +556,7 @@ static int samsung_keypad_resume(struct device *dev)
samsung_keypad_toggle_wakeup(keypad, false);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
samsung_keypad_start(keypad);
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 9b8d78f87253..9838c79cb288 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -318,7 +318,7 @@ static int __maybe_unused spear_kbd_suspend(struct device *dev)
writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
} else {
- if (input_dev->users) {
+ if (input_device_enabled(input_dev)) {
writel_relaxed(mode_ctl_reg & ~MODE_CTL_START_SCAN,
kbd->io_base + MODE_CTL_REG);
clk_disable(kbd->clk);
@@ -326,7 +326,7 @@ static int __maybe_unused spear_kbd_suspend(struct device *dev)
}
/* store current configuration */
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
kbd->mode_ctl_reg = mode_ctl_reg;
/* restore previous clk state */
@@ -351,12 +351,12 @@ static int __maybe_unused spear_kbd_resume(struct device *dev)
disable_irq_wake(kbd->irq);
}
} else {
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
clk_enable(kbd->clk);
}
/* restore current configuration */
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
writel_relaxed(kbd->mode_ctl_reg, kbd->io_base + MODE_CTL_REG);
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c
index 27562cd67fb6..a045d61165ac 100644
--- a/drivers/input/keyboard/st-keyscan.c
+++ b/drivers/input/keyboard/st-keyscan.c
@@ -221,7 +221,7 @@ static int keyscan_suspend(struct device *dev)
if (device_may_wakeup(dev))
enable_irq_wake(keypad->irq);
- else if (input->users)
+ else if (input_device_enabled(input))
keyscan_stop(keypad);
mutex_unlock(&input->mutex);
@@ -239,7 +239,7 @@ static int keyscan_resume(struct device *dev)
if (device_may_wakeup(dev))
disable_irq_wake(keypad->irq);
- else if (input->users)
+ else if (input_device_enabled(input))
retval = keyscan_start(keypad);
mutex_unlock(&input->mutex);
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index d34d6947960f..9671842a082a 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -756,7 +756,7 @@ static int tegra_kbc_suspend(struct device *dev)
enable_irq(kbc->irq);
enable_irq_wake(kbc->irq);
} else {
- if (kbc->idev->users)
+ if (input_device_enabled(kbc->idev))
tegra_kbc_stop(kbc);
}
mutex_unlock(&kbc->idev->mutex);
@@ -796,7 +796,7 @@ static int tegra_kbc_resume(struct device *dev)
input_sync(kbc->idev);
}
} else {
- if (kbc->idev->users)
+ if (input_device_enabled(kbc->idev))
err = tegra_kbc_start(kbc);
}
mutex_unlock(&kbc->idev->mutex);
diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c
index fb078e049413..6218b1c682ef 100644
--- a/drivers/input/keyboard/tm2-touchkey.c
+++ b/drivers/input/keyboard/tm2-touchkey.c
@@ -48,7 +48,7 @@ struct tm2_touchkey_data {
struct input_dev *input_dev;
struct led_classdev led_dev;
struct regulator *vdd;
- struct regulator_bulk_data regulators[2];
+ struct regulator_bulk_data regulators[3];
const struct touchkey_variant *variant;
u32 keycodes[4];
int num_keycodes;
@@ -204,6 +204,7 @@ static int tm2_touchkey_probe(struct i2c_client *client,
touchkey->regulators[0].supply = "vcc";
touchkey->regulators[1].supply = "vdd";
+ touchkey->regulators[2].supply = "vddio";
error = devm_regulator_bulk_get(&client->dev,
ARRAY_SIZE(touchkey->regulators),
touchkey->regulators);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 362e8a01980c..ad1b6c90bc4d 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -73,6 +73,17 @@ config INPUT_AD714X_SPI
To compile this driver as a module, choose M here: the
module will be called ad714x-spi.
+config INPUT_ARIEL_PWRBUTTON
+ tristate "Dell Wyse 3020 Power Button Driver"
+ depends on SPI
+ depends on MACH_MMP3_DT || COMPILE_TEST
+ help
+ Say Y to enable support for reporting power button status on
+ on Dell Wyse 3020 ("Ariel") thin client.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ariel-pwrbutton.
+
config INPUT_ARIZONA_HAPTICS
tristate "Arizona haptics support"
depends on MFD_ARIZONA && SND_SOC
@@ -609,6 +620,18 @@ config INPUT_RB532_BUTTON
To compile this driver as a module, choose M here: the
module will be called rb532_button.
+config INPUT_DA7280_HAPTICS
+ tristate "Dialog Semiconductor DA7280 haptics support"
+ depends on INPUT && I2C
+ select REGMAP_I2C
+ help
+ Say Y to enable support for the Dialog DA7280 haptics driver.
+ The haptics can be controlled by PWM or GPIO
+ with I2C communication.
+
+ To compile this driver as a module, choose M here: the
+ module will be called da7280.
+
config INPUT_DA9052_ONKEY
tristate "Dialog DA9052/DA9053 Onkey"
depends on PMIC_DA9052
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index a48e5f2d859d..7f202ba8f775 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o
obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o
obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o
+obj-$(CONFIG_INPUT_ARIEL_PWRBUTTON) += ariel-pwrbutton.o
obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_CPCAP_PWRBUTTON) += cpcap-pwrbutton.o
+obj-$(CONFIG_INPUT_DA7280_HAPTICS) += da7280.o
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
obj-$(CONFIG_INPUT_DA9063_ONKEY) += da9063_onkey.o
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c
index ea3b8292acdd..a9b9013680d6 100644
--- a/drivers/input/misc/ab8500-ponkey.c
+++ b/drivers/input/misc/ab8500-ponkey.c
@@ -19,7 +19,7 @@
/**
* struct ab8500_ponkey - ab8500 ponkey information
- * @input_dev: pointer to input device
+ * @idev: pointer to input device
* @ab8500: ab8500 parent
* @irq_dbf: irq number for falling transition
* @irq_dbr: irq number for rising transition
diff --git a/drivers/input/misc/ariel-pwrbutton.c b/drivers/input/misc/ariel-pwrbutton.c
new file mode 100644
index 000000000000..eda86ab552b9
--- /dev/null
+++ b/drivers/input/misc/ariel-pwrbutton.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0-or-later
+/*
+ * Dell Wyse 3020 a.k.a. "Ariel" Power Button Driver
+ *
+ * Copyright (C) 2020 Lubomir Rintel
+ */
+
+#include <linux/device.h>
+#include <linux/gfp.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#define RESP_COUNTER(response) (response.header & 0x3)
+#define RESP_SIZE(response) ((response.header >> 2) & 0x3)
+#define RESP_TYPE(response) ((response.header >> 4) & 0xf)
+
+struct ec_input_response {
+ u8 reserved;
+ u8 header;
+ u8 data[3];
+} __packed;
+
+struct ariel_pwrbutton {
+ struct spi_device *client;
+ struct input_dev *input;
+ u8 msg_counter;
+};
+
+static int ec_input_read(struct ariel_pwrbutton *priv,
+ struct ec_input_response *response)
+{
+ u8 read_request[] = { 0x00, 0x5a, 0xa5, 0x00, 0x00 };
+ struct spi_device *spi = priv->client;
+ struct spi_transfer t = {
+ .tx_buf = read_request,
+ .rx_buf = response,
+ .len = sizeof(read_request),
+ };
+
+ compiletime_assert(sizeof(read_request) == sizeof(*response),
+ "SPI xfer request/response size mismatch");
+
+ return spi_sync_transfer(spi, &t, 1);
+}
+
+static irqreturn_t ec_input_interrupt(int irq, void *dev_id)
+{
+ struct ariel_pwrbutton *priv = dev_id;
+ struct spi_device *spi = priv->client;
+ struct ec_input_response response;
+ int error;
+ int i;
+
+ error = ec_input_read(priv, &response);
+ if (error < 0) {
+ dev_err(&spi->dev, "EC read failed: %d\n", error);
+ goto out;
+ }
+
+ if (priv->msg_counter == RESP_COUNTER(response)) {
+ dev_warn(&spi->dev, "No new data to read?\n");
+ goto out;
+ }
+
+ priv->msg_counter = RESP_COUNTER(response);
+
+ if (RESP_TYPE(response) != 0x3 && RESP_TYPE(response) != 0xc) {
+ dev_dbg(&spi->dev, "Ignoring message that's not kbd data\n");
+ goto out;
+ }
+
+ for (i = 0; i < RESP_SIZE(response); i++) {
+ switch (response.data[i]) {
+ case 0x74:
+ input_report_key(priv->input, KEY_POWER, 1);
+ input_sync(priv->input);
+ break;
+ case 0xf4:
+ input_report_key(priv->input, KEY_POWER, 0);
+ input_sync(priv->input);
+ break;
+ default:
+ dev_dbg(&spi->dev, "Unknown scan code: %02x\n",
+ response.data[i]);
+ }
+ }
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int ariel_pwrbutton_probe(struct spi_device *spi)
+{
+ struct ec_input_response response;
+ struct ariel_pwrbutton *priv;
+ int error;
+
+ if (!spi->irq) {
+ dev_err(&spi->dev, "Missing IRQ.\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = spi;
+ spi_set_drvdata(spi, priv);
+
+ priv->input = devm_input_allocate_device(&spi->dev);
+ if (!priv->input)
+ return -ENOMEM;
+ priv->input->name = "Power Button";
+ priv->input->dev.parent = &spi->dev;
+ input_set_capability(priv->input, EV_KEY, KEY_POWER);
+ error = input_register_device(priv->input);
+ if (error) {
+ dev_err(&spi->dev, "error registering input device: %d\n", error);
+ return error;
+ }
+
+ error = ec_input_read(priv, &response);
+ if (error < 0) {
+ dev_err(&spi->dev, "EC read failed: %d\n", error);
+ return error;
+ }
+ priv->msg_counter = RESP_COUNTER(response);
+
+ error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
+ ec_input_interrupt,
+ IRQF_ONESHOT,
+ "Ariel EC Input", priv);
+
+ if (error) {
+ dev_err(&spi->dev, "Failed to request IRQ %d: %d\n",
+ spi->irq, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id ariel_pwrbutton_of_match[] = {
+ { .compatible = "dell,wyse-ariel-ec-input" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ariel_pwrbutton_of_match);
+
+static const struct spi_device_id ariel_pwrbutton_id_table[] = {
+ { "wyse-ariel-ec-input", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ariel_pwrbutton_id_table);
+
+static struct spi_driver ariel_pwrbutton_driver = {
+ .driver = {
+ .name = "dell-wyse-ariel-ec-input",
+ .of_match_table = ariel_pwrbutton_of_match,
+ },
+ .probe = ariel_pwrbutton_probe,
+};
+module_spi_driver(ariel_pwrbutton_driver);
+
+MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+MODULE_DESCRIPTION("Dell Wyse 3020 Power Button Input Driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c
new file mode 100644
index 000000000000..37568b00873d
--- /dev/null
+++ b/drivers/input/misc/da7280.c
@@ -0,0 +1,1329 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DA7280 Haptic device driver
+ *
+ * Copyright (c) 2020 Dialog Semiconductor.
+ * Author: Roy Im <Roy.Im.Opensource@diasemi.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <linux/uaccess.h>
+
+/* Registers */
+#define DA7280_IRQ_EVENT1 0x03
+#define DA7280_IRQ_EVENT_WARNING_DIAG 0x04
+#define DA7280_IRQ_EVENT_SEQ_DIAG 0x05
+#define DA7280_IRQ_STATUS1 0x06
+#define DA7280_IRQ_MASK1 0x07
+#define DA7280_FRQ_LRA_PER_H 0x0A
+#define DA7280_FRQ_LRA_PER_L 0x0B
+#define DA7280_ACTUATOR1 0x0C
+#define DA7280_ACTUATOR2 0x0D
+#define DA7280_ACTUATOR3 0x0E
+#define DA7280_CALIB_V2I_H 0x0F
+#define DA7280_CALIB_V2I_L 0x10
+#define DA7280_TOP_CFG1 0x13
+#define DA7280_TOP_CFG2 0x14
+#define DA7280_TOP_CFG4 0x16
+#define DA7280_TOP_INT_CFG1 0x17
+#define DA7280_TOP_CTL1 0x22
+#define DA7280_TOP_CTL2 0x23
+#define DA7280_SEQ_CTL2 0x28
+#define DA7280_GPI_0_CTL 0x29
+#define DA7280_GPI_1_CTL 0x2A
+#define DA7280_GPI_2_CTL 0x2B
+#define DA7280_MEM_CTL1 0x2C
+#define DA7280_MEM_CTL2 0x2D
+#define DA7280_TOP_CFG5 0x6E
+#define DA7280_IRQ_MASK2 0x83
+#define DA7280_SNP_MEM_99 0xE7
+
+/* Register field */
+
+/* DA7280_IRQ_EVENT1 (Address 0x03) */
+#define DA7280_E_SEQ_CONTINUE_MASK BIT(0)
+#define DA7280_E_UVLO_MASK BIT(1)
+#define DA7280_E_SEQ_DONE_MASK BIT(2)
+#define DA7280_E_OVERTEMP_CRIT_MASK BIT(3)
+#define DA7280_E_SEQ_FAULT_MASK BIT(4)
+#define DA7280_E_WARNING_MASK BIT(5)
+#define DA7280_E_ACTUATOR_FAULT_MASK BIT(6)
+#define DA7280_E_OC_FAULT_MASK BIT(7)
+
+/* DA7280_IRQ_EVENT_WARNING_DIAG (Address 0x04) */
+#define DA7280_E_OVERTEMP_WARN_MASK BIT(3)
+#define DA7280_E_MEM_TYPE_MASK BIT(4)
+#define DA7280_E_LIM_DRIVE_ACC_MASK BIT(6)
+#define DA7280_E_LIM_DRIVE_MASK BIT(7)
+
+/* DA7280_IRQ_EVENT_PAT_DIAG (Address 0x05) */
+#define DA7280_E_PWM_FAULT_MASK BIT(5)
+#define DA7280_E_MEM_FAULT_MASK BIT(6)
+#define DA7280_E_SEQ_ID_FAULT_MASK BIT(7)
+
+/* DA7280_IRQ_STATUS1 (Address 0x06) */
+#define DA7280_STA_SEQ_CONTINUE_MASK BIT(0)
+#define DA7280_STA_UVLO_VBAT_OK_MASK BIT(1)
+#define DA7280_STA_SEQ_DONE_MASK BIT(2)
+#define DA7280_STA_OVERTEMP_CRIT_MASK BIT(3)
+#define DA7280_STA_SEQ_FAULT_MASK BIT(4)
+#define DA7280_STA_WARNING_MASK BIT(5)
+#define DA7280_STA_ACTUATOR_MASK BIT(6)
+#define DA7280_STA_OC_MASK BIT(7)
+
+/* DA7280_IRQ_MASK1 (Address 0x07) */
+#define DA7280_SEQ_CONTINUE_M_MASK BIT(0)
+#define DA7280_E_UVLO_M_MASK BIT(1)
+#define DA7280_SEQ_DONE_M_MASK BIT(2)
+#define DA7280_OVERTEMP_CRIT_M_MASK BIT(3)
+#define DA7280_SEQ_FAULT_M_MASK BIT(4)
+#define DA7280_WARNING_M_MASK BIT(5)
+#define DA7280_ACTUATOR_M_MASK BIT(6)
+#define DA7280_OC_M_MASK BIT(7)
+
+/* DA7280_ACTUATOR3 (Address 0x0e) */
+#define DA7280_IMAX_MASK GENMASK(4, 0)
+
+/* DA7280_TOP_CFG1 (Address 0x13) */
+#define DA7280_AMP_PID_EN_MASK BIT(0)
+#define DA7280_RAPID_STOP_EN_MASK BIT(1)
+#define DA7280_ACCELERATION_EN_MASK BIT(2)
+#define DA7280_FREQ_TRACK_EN_MASK BIT(3)
+#define DA7280_BEMF_SENSE_EN_MASK BIT(4)
+#define DA7280_ACTUATOR_TYPE_MASK BIT(5)
+
+/* DA7280_TOP_CFG2 (Address 0x14) */
+#define DA7280_FULL_BRAKE_THR_MASK GENMASK(3, 0)
+#define DA7280_MEM_DATA_SIGNED_MASK BIT(4)
+
+/* DA7280_TOP_CFG4 (Address 0x16) */
+#define DA7280_TST_CALIB_IMPEDANCE_DIS_MASK BIT(6)
+#define DA7280_V2I_FACTOR_FREEZE_MASK BIT(7)
+
+/* DA7280_TOP_INT_CFG1 (Address 0x17) */
+#define DA7280_BEMF_FAULT_LIM_MASK GENMASK(1, 0)
+
+/* DA7280_TOP_CTL1 (Address 0x22) */
+#define DA7280_OPERATION_MODE_MASK GENMASK(2, 0)
+#define DA7280_STANDBY_EN_MASK BIT(3)
+#define DA7280_SEQ_START_MASK BIT(4)
+
+/* DA7280_SEQ_CTL2 (Address 0x28) */
+#define DA7280_PS_SEQ_ID_MASK GENMASK(3, 0)
+#define DA7280_PS_SEQ_LOOP_MASK GENMASK(7, 4)
+
+/* DA7280_GPIO_0_CTL (Address 0x29) */
+#define DA7280_GPI0_POLARITY_MASK GENMASK(1, 0)
+#define DA7280_GPI0_MODE_MASK BIT(2)
+#define DA7280_GPI0_SEQUENCE_ID_MASK GENMASK(6, 3)
+
+/* DA7280_GPIO_1_CTL (Address 0x2a) */
+#define DA7280_GPI1_POLARITY_MASK GENMASK(1, 0)
+#define DA7280_GPI1_MODE_MASK BIT(2)
+#define DA7280_GPI1_SEQUENCE_ID_MASK GENMASK(6, 3)
+
+/* DA7280_GPIO_2_CTL (Address 0x2b) */
+#define DA7280_GPI2_POLARITY_MASK GENMASK(1, 0)
+#define DA7280_GPI2_MODE_MASK BIT(2)
+#define DA7280_GPI2_SEQUENCE_ID_MASK GENMASK(6, 3)
+
+/* DA7280_MEM_CTL2 (Address 0x2d) */
+#define DA7280_WAV_MEM_LOCK_MASK BIT(7)
+
+/* DA7280_TOP_CFG5 (Address 0x6e) */
+#define DA7280_V2I_FACTOR_OFFSET_EN_MASK BIT(0)
+
+/* DA7280_IRQ_MASK2 (Address 0x83) */
+#define DA7280_ADC_SAT_M_MASK BIT(7)
+
+/* Controls */
+
+#define DA7280_VOLTAGE_RATE_MAX 6000000
+#define DA7280_VOLTAGE_RATE_STEP 23400
+#define DA7280_NOMMAX_DFT 0x6B
+#define DA7280_ABSMAX_DFT 0x78
+
+#define DA7280_IMPD_MAX 1500000000
+#define DA7280_IMPD_DEFAULT 22000000
+
+#define DA7280_IMAX_DEFAULT 0x0E
+#define DA7280_IMAX_STEP 7200
+#define DA7280_IMAX_LIMIT 252000
+
+#define DA7280_RESONT_FREQH_DFT 0x39
+#define DA7280_RESONT_FREQL_DFT 0x32
+#define DA7280_MIN_RESONAT_FREQ_HZ 50
+#define DA7280_MAX_RESONAT_FREQ_HZ 300
+
+#define DA7280_SEQ_ID_MAX 15
+#define DA7280_SEQ_LOOP_MAX 15
+#define DA7280_GPI_SEQ_ID_DFT 0
+#define DA7280_GPI_SEQ_ID_MAX 2
+
+#define DA7280_SNP_MEM_SIZE 100
+#define DA7280_SNP_MEM_MAX DA7280_SNP_MEM_99
+
+#define DA7280_IRQ_NUM 3
+
+#define DA7280_SKIP_INIT 0x100
+
+#define DA7280_FF_EFFECT_COUNT_MAX 15
+
+/* Maximum gain is 0x7fff for PWM mode */
+#define DA7280_MAX_MAGNITUDE_SHIFT 15
+
+enum da7280_haptic_dev_t {
+ DA7280_LRA = 0,
+ DA7280_ERM_BAR = 1,
+ DA7280_ERM_COIN = 2,
+ DA7280_DEV_MAX,
+};
+
+enum da7280_op_mode {
+ DA7280_INACTIVE = 0,
+ DA7280_DRO_MODE = 1,
+ DA7280_PWM_MODE = 2,
+ DA7280_RTWM_MODE = 3,
+ DA7280_ETWM_MODE = 4,
+ DA7280_OPMODE_MAX,
+};
+
+#define DA7280_FF_CONSTANT_DRO 1
+#define DA7280_FF_PERIODIC_PWM 2
+#define DA7280_FF_PERIODIC_RTWM 1
+#define DA7280_FF_PERIODIC_ETWM 2
+
+#define DA7280_FF_PERIODIC_MODE DA7280_RTWM_MODE
+#define DA7280_FF_CONSTANT_MODE DA7280_DRO_MODE
+
+enum da7280_custom_effect_param {
+ DA7280_CUSTOM_SEQ_ID_IDX = 0,
+ DA7280_CUSTOM_SEQ_LOOP_IDX = 1,
+ DA7280_CUSTOM_DATA_LEN = 2,
+};
+
+enum da7280_custom_gpi_effect_param {
+ DA7280_CUSTOM_GPI_SEQ_ID_IDX = 0,
+ DA7280_CUSTOM_GPI_NUM_IDX = 2,
+ DA7280_CUSTOM_GP_DATA_LEN = 3,
+};
+
+struct da7280_gpi_ctl {
+ u8 seq_id;
+ u8 mode;
+ u8 polarity;
+};
+
+struct da7280_haptic {
+ struct regmap *regmap;
+ struct input_dev *input_dev;
+ struct device *dev;
+ struct i2c_client *client;
+ struct pwm_device *pwm_dev;
+
+ bool legacy;
+ struct work_struct work;
+ int val;
+ u16 gain;
+ s16 level;
+
+ u8 dev_type;
+ u8 op_mode;
+ u8 const_op_mode;
+ u8 periodic_op_mode;
+ u16 nommax;
+ u16 absmax;
+ u32 imax;
+ u32 impd;
+ u32 resonant_freq_h;
+ u32 resonant_freq_l;
+ bool bemf_sense_en;
+ bool freq_track_en;
+ bool acc_en;
+ bool rapid_stop_en;
+ bool amp_pid_en;
+ u8 ps_seq_id;
+ u8 ps_seq_loop;
+ struct da7280_gpi_ctl gpi_ctl[3];
+ bool mem_update;
+ u8 snp_mem[DA7280_SNP_MEM_SIZE];
+ bool active;
+ bool suspended;
+};
+
+static bool da7280_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DA7280_IRQ_EVENT1:
+ case DA7280_IRQ_EVENT_WARNING_DIAG:
+ case DA7280_IRQ_EVENT_SEQ_DIAG:
+ case DA7280_IRQ_STATUS1:
+ case DA7280_TOP_CTL1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config da7280_haptic_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = DA7280_SNP_MEM_MAX,
+ .volatile_reg = da7280_volatile_register,
+};
+
+static int da7280_haptic_mem_update(struct da7280_haptic *haptics)
+{
+ unsigned int val;
+ int error;
+
+ /* The patterns should be updated when haptic is not working */
+ error = regmap_read(haptics->regmap, DA7280_IRQ_STATUS1, &val);
+ if (error)
+ return error;
+ if (val & DA7280_STA_WARNING_MASK) {
+ dev_warn(haptics->dev,
+ "Warning! Please check HAPTIC status.\n");
+ return -EBUSY;
+ }
+
+ /* Patterns are not updated if the lock bit is enabled */
+ val = 0;
+ error = regmap_read(haptics->regmap, DA7280_MEM_CTL2, &val);
+ if (error)
+ return error;
+ if (~val & DA7280_WAV_MEM_LOCK_MASK) {
+ dev_warn(haptics->dev, "Please unlock the bit first\n");
+ return -EACCES;
+ }
+
+ /* Set to Inactive mode to make sure safety */
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_OPERATION_MODE_MASK,
+ 0);
+ if (error)
+ return error;
+
+ error = regmap_read(haptics->regmap, DA7280_MEM_CTL1, &val);
+ if (error)
+ return error;
+
+ return regmap_bulk_write(haptics->regmap, val, haptics->snp_mem,
+ DA7280_SNP_MEM_MAX - val + 1);
+}
+
+static int da7280_haptic_set_pwm(struct da7280_haptic *haptics, bool enabled)
+{
+ struct pwm_state state;
+ u64 period_mag_multi;
+ int error;
+
+ if (!haptics->gain && enabled) {
+ dev_err(haptics->dev, "Unable to enable pwm with 0 gain\n");
+ return -EINVAL;
+ }
+
+ pwm_get_state(haptics->pwm_dev, &state);
+ state.enabled = enabled;
+ if (enabled) {
+ period_mag_multi = (u64)state.period * haptics->gain;
+ period_mag_multi >>= DA7280_MAX_MAGNITUDE_SHIFT;
+
+ /*
+ * The interpretation of duty cycle depends on the acc_en,
+ * it should be between 50% and 100% for acc_en = 0.
+ * See datasheet 'PWM mode' section.
+ */
+ if (!haptics->acc_en) {
+ period_mag_multi += state.period;
+ period_mag_multi /= 2;
+ }
+
+ state.duty_cycle = period_mag_multi;
+ }
+
+ error = pwm_apply_state(haptics->pwm_dev, &state);
+ if (error)
+ dev_err(haptics->dev, "Failed to apply pwm state: %d\n", error);
+
+ return error;
+}
+
+static void da7280_haptic_activate(struct da7280_haptic *haptics)
+{
+ int error;
+
+ if (haptics->active)
+ return;
+
+ switch (haptics->op_mode) {
+ case DA7280_DRO_MODE:
+ /* the valid range check when acc_en is enabled */
+ if (haptics->acc_en && haptics->level > 0x7F)
+ haptics->level = 0x7F;
+ else if (haptics->level > 0xFF)
+ haptics->level = 0xFF;
+
+ /* Set level as a % of ACTUATOR_NOMMAX (nommax) */
+ error = regmap_write(haptics->regmap, DA7280_TOP_CTL2,
+ haptics->level);
+ if (error) {
+ dev_err(haptics->dev,
+ "Failed to set level to %d: %d\n",
+ haptics->level, error);
+ return;
+ }
+ break;
+
+ case DA7280_PWM_MODE:
+ if (da7280_haptic_set_pwm(haptics, true))
+ return;
+ break;
+
+ case DA7280_RTWM_MODE:
+ /*
+ * The pattern will be played by the PS_SEQ_ID and the
+ * PS_SEQ_LOOP
+ */
+ break;
+
+ case DA7280_ETWM_MODE:
+ /*
+ * The pattern will be played by the GPI[N] state,
+ * GPI(N)_SEQUENCE_ID and the PS_SEQ_LOOP. See the
+ * datasheet for the details.
+ */
+ break;
+
+ default:
+ dev_err(haptics->dev, "Invalid op mode %d\n", haptics->op_mode);
+ return;
+ }
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_OPERATION_MODE_MASK,
+ haptics->op_mode);
+ if (error) {
+ dev_err(haptics->dev,
+ "Failed to set operation mode: %d", error);
+ return;
+ }
+
+ if (haptics->op_mode == DA7280_PWM_MODE ||
+ haptics->op_mode == DA7280_RTWM_MODE) {
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_SEQ_START_MASK,
+ DA7280_SEQ_START_MASK);
+ if (error) {
+ dev_err(haptics->dev,
+ "Failed to start sequence: %d\n", error);
+ return;
+ }
+ }
+
+ haptics->active = true;
+}
+
+static void da7280_haptic_deactivate(struct da7280_haptic *haptics)
+{
+ int error;
+
+ if (!haptics->active)
+ return;
+
+ /* Set to Inactive mode */
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_OPERATION_MODE_MASK, 0);
+ if (error) {
+ dev_err(haptics->dev,
+ "Failed to clear operation mode: %d", error);
+ return;
+ }
+
+ switch (haptics->op_mode) {
+ case DA7280_DRO_MODE:
+ error = regmap_write(haptics->regmap,
+ DA7280_TOP_CTL2, 0);
+ if (error) {
+ dev_err(haptics->dev,
+ "Failed to disable DRO mode: %d\n", error);
+ return;
+ }
+ break;
+
+ case DA7280_PWM_MODE:
+ if (da7280_haptic_set_pwm(haptics, false))
+ return;
+ break;
+
+ case DA7280_RTWM_MODE:
+ case DA7280_ETWM_MODE:
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_SEQ_START_MASK, 0);
+ if (error) {
+ dev_err(haptics->dev,
+ "Failed to disable RTWM/ETWM mode: %d\n",
+ error);
+ return;
+ }
+ break;
+
+ default:
+ dev_err(haptics->dev, "Invalid op mode %d\n", haptics->op_mode);
+ return;
+ }
+
+ haptics->active = false;
+}
+
+static void da7280_haptic_work(struct work_struct *work)
+{
+ struct da7280_haptic *haptics =
+ container_of(work, struct da7280_haptic, work);
+ int val = haptics->val;
+
+ if (val)
+ da7280_haptic_activate(haptics);
+ else
+ da7280_haptic_deactivate(haptics);
+}
+
+static int da7280_haptics_upload_effect(struct input_dev *dev,
+ struct ff_effect *effect,
+ struct ff_effect *old)
+{
+ struct da7280_haptic *haptics = input_get_drvdata(dev);
+ s16 data[DA7280_SNP_MEM_SIZE] = { 0 };
+ unsigned int val;
+ int tmp, i, num;
+ int error;
+
+ /* The effect should be uploaded when haptic is not working */
+ if (haptics->active)
+ return -EBUSY;
+
+ switch (effect->type) {
+ /* DRO/PWM modes support this type */
+ case FF_CONSTANT:
+ haptics->op_mode = haptics->const_op_mode;
+ if (haptics->op_mode == DA7280_DRO_MODE) {
+ tmp = effect->u.constant.level * 254;
+ haptics->level = tmp / 0x7FFF;
+ break;
+ }
+
+ haptics->gain = effect->u.constant.level <= 0 ?
+ 0 : effect->u.constant.level;
+ break;
+
+ /* RTWM/ETWM modes support this type */
+ case FF_PERIODIC:
+ if (effect->u.periodic.waveform != FF_CUSTOM) {
+ dev_err(haptics->dev,
+ "Device can only accept FF_CUSTOM waveform\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Load the data and check the length.
+ * the data will be patterns in this case: 4 < X <= 100,
+ * and will be saved into the waveform memory inside DA728x.
+ * If X = 2, the data will be PS_SEQ_ID and PS_SEQ_LOOP.
+ * If X = 3, the 1st data will be GPIX_SEQUENCE_ID .
+ */
+ if (effect->u.periodic.custom_len == DA7280_CUSTOM_DATA_LEN)
+ goto set_seq_id_loop;
+
+ if (effect->u.periodic.custom_len == DA7280_CUSTOM_GP_DATA_LEN)
+ goto set_gpix_seq_id;
+
+ if (effect->u.periodic.custom_len < DA7280_CUSTOM_DATA_LEN ||
+ effect->u.periodic.custom_len > DA7280_SNP_MEM_SIZE) {
+ dev_err(haptics->dev, "Invalid waveform data size\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(data, effect->u.periodic.custom_data,
+ sizeof(s16) *
+ effect->u.periodic.custom_len))
+ return -EFAULT;
+
+ memset(haptics->snp_mem, 0, DA7280_SNP_MEM_SIZE);
+
+ for (i = 0; i < effect->u.periodic.custom_len; i++) {
+ if (data[i] < 0 || data[i] > 0xff) {
+ dev_err(haptics->dev,
+ "Invalid waveform data %d at offset %d\n",
+ data[i], i);
+ return -EINVAL;
+ }
+ haptics->snp_mem[i] = (u8)data[i];
+ }
+
+ error = da7280_haptic_mem_update(haptics);
+ if (error) {
+ dev_err(haptics->dev,
+ "Failed to upload waveform: %d\n", error);
+ return error;
+ }
+ break;
+
+set_seq_id_loop:
+ if (copy_from_user(data, effect->u.periodic.custom_data,
+ sizeof(s16) * DA7280_CUSTOM_DATA_LEN))
+ return -EFAULT;
+
+ if (data[DA7280_CUSTOM_SEQ_ID_IDX] < 0 ||
+ data[DA7280_CUSTOM_SEQ_ID_IDX] > DA7280_SEQ_ID_MAX ||
+ data[DA7280_CUSTOM_SEQ_LOOP_IDX] < 0 ||
+ data[DA7280_CUSTOM_SEQ_LOOP_IDX] > DA7280_SEQ_LOOP_MAX) {
+ dev_err(haptics->dev,
+ "Invalid custom id (%d) or loop (%d)\n",
+ data[DA7280_CUSTOM_SEQ_ID_IDX],
+ data[DA7280_CUSTOM_SEQ_LOOP_IDX]);
+ return -EINVAL;
+ }
+
+ haptics->ps_seq_id = data[DA7280_CUSTOM_SEQ_ID_IDX] & 0x0f;
+ haptics->ps_seq_loop = data[DA7280_CUSTOM_SEQ_LOOP_IDX] & 0x0f;
+ haptics->op_mode = haptics->periodic_op_mode;
+
+ val = FIELD_PREP(DA7280_PS_SEQ_ID_MASK, haptics->ps_seq_id) |
+ FIELD_PREP(DA7280_PS_SEQ_LOOP_MASK,
+ haptics->ps_seq_loop);
+ error = regmap_write(haptics->regmap, DA7280_SEQ_CTL2, val);
+ if (error) {
+ dev_err(haptics->dev,
+ "Failed to update PS sequence: %d\n", error);
+ return error;
+ }
+ break;
+
+set_gpix_seq_id:
+ if (copy_from_user(data, effect->u.periodic.custom_data,
+ sizeof(s16) * DA7280_CUSTOM_GP_DATA_LEN))
+ return -EFAULT;
+
+ if (data[DA7280_CUSTOM_GPI_SEQ_ID_IDX] < 0 ||
+ data[DA7280_CUSTOM_GPI_SEQ_ID_IDX] > DA7280_SEQ_ID_MAX ||
+ data[DA7280_CUSTOM_GPI_NUM_IDX] < 0 ||
+ data[DA7280_CUSTOM_GPI_NUM_IDX] > DA7280_GPI_SEQ_ID_MAX) {
+ dev_err(haptics->dev,
+ "Invalid custom GPI id (%d) or num (%d)\n",
+ data[DA7280_CUSTOM_GPI_SEQ_ID_IDX],
+ data[DA7280_CUSTOM_GPI_NUM_IDX]);
+ return -EINVAL;
+ }
+
+ num = data[DA7280_CUSTOM_GPI_NUM_IDX] & 0x0f;
+ haptics->gpi_ctl[num].seq_id =
+ data[DA7280_CUSTOM_GPI_SEQ_ID_IDX] & 0x0f;
+ haptics->op_mode = haptics->periodic_op_mode;
+
+ val = FIELD_PREP(DA7280_GPI0_SEQUENCE_ID_MASK,
+ haptics->gpi_ctl[num].seq_id);
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_GPI_0_CTL + num,
+ DA7280_GPI0_SEQUENCE_ID_MASK,
+ val);
+ if (error) {
+ dev_err(haptics->dev,
+ "Failed to update GPI sequence: %d\n", error);
+ return error;
+ }
+ break;
+
+ default:
+ dev_err(haptics->dev, "Unsupported effect type: %d\n",
+ effect->type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int da7280_haptics_playback(struct input_dev *dev,
+ int effect_id, int val)
+{
+ struct da7280_haptic *haptics = input_get_drvdata(dev);
+
+ if (!haptics->op_mode) {
+ dev_warn(haptics->dev, "No effects have been uploaded\n");
+ return -EINVAL;
+ }
+
+ if (likely(!haptics->suspended)) {
+ haptics->val = val;
+ schedule_work(&haptics->work);
+ }
+
+ return 0;
+}
+
+static int da7280_haptic_start(struct da7280_haptic *haptics)
+{
+ int error;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_STANDBY_EN_MASK,
+ DA7280_STANDBY_EN_MASK);
+ if (error) {
+ dev_err(haptics->dev, "Unable to enable device: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static void da7280_haptic_stop(struct da7280_haptic *haptics)
+{
+ int error;
+
+ cancel_work_sync(&haptics->work);
+
+
+ da7280_haptic_deactivate(haptics);
+
+ error = regmap_update_bits(haptics->regmap, DA7280_TOP_CTL1,
+ DA7280_STANDBY_EN_MASK, 0);
+ if (error)
+ dev_err(haptics->dev, "Failed to disable device: %d\n", error);
+}
+
+static int da7280_haptic_open(struct input_dev *dev)
+{
+ struct da7280_haptic *haptics = input_get_drvdata(dev);
+
+ return da7280_haptic_start(haptics);
+}
+
+static void da7280_haptic_close(struct input_dev *dev)
+{
+ struct da7280_haptic *haptics = input_get_drvdata(dev);
+
+ da7280_haptic_stop(haptics);
+}
+
+static u8 da7280_haptic_of_mode_str(struct device *dev,
+ const char *str)
+{
+ if (!strcmp(str, "LRA")) {
+ return DA7280_LRA;
+ } else if (!strcmp(str, "ERM-bar")) {
+ return DA7280_ERM_BAR;
+ } else if (!strcmp(str, "ERM-coin")) {
+ return DA7280_ERM_COIN;
+ } else {
+ dev_warn(dev, "Invalid string - set to LRA\n");
+ return DA7280_LRA;
+ }
+}
+
+static u8 da7280_haptic_of_gpi_mode_str(struct device *dev,
+ const char *str)
+{
+ if (!strcmp(str, "Single-pattern")) {
+ return 0;
+ } else if (!strcmp(str, "Multi-pattern")) {
+ return 1;
+ } else {
+ dev_warn(dev, "Invalid string - set to Single-pattern\n");
+ return 0;
+ }
+}
+
+static u8 da7280_haptic_of_gpi_pol_str(struct device *dev,
+ const char *str)
+{
+ if (!strcmp(str, "Rising-edge")) {
+ return 0;
+ } else if (!strcmp(str, "Falling-edge")) {
+ return 1;
+ } else if (!strcmp(str, "Both-edge")) {
+ return 2;
+ } else {
+ dev_warn(dev, "Invalid string - set to Rising-edge\n");
+ return 0;
+ }
+}
+
+static u8 da7280_haptic_of_volt_rating_set(u32 val)
+{
+ u32 voltage = val / DA7280_VOLTAGE_RATE_STEP + 1;
+
+ return min_t(u32, voltage, 0xff);
+}
+
+static void da7280_parse_properties(struct device *dev,
+ struct da7280_haptic *haptics)
+{
+ unsigned int i, mem[DA7280_SNP_MEM_SIZE];
+ char gpi_str1[] = "dlg,gpi0-seq-id";
+ char gpi_str2[] = "dlg,gpi0-mode";
+ char gpi_str3[] = "dlg,gpi0-polarity";
+ const char *str;
+ u32 val;
+ int error;
+
+ /*
+ * If there is no property, then use the mode programmed into the chip.
+ */
+ haptics->dev_type = DA7280_DEV_MAX;
+ error = device_property_read_string(dev, "dlg,actuator-type", &str);
+ if (!error)
+ haptics->dev_type = da7280_haptic_of_mode_str(dev, str);
+
+ haptics->const_op_mode = DA7280_DRO_MODE;
+ error = device_property_read_u32(dev, "dlg,const-op-mode", &val);
+ if (!error && val == DA7280_FF_PERIODIC_PWM)
+ haptics->const_op_mode = DA7280_PWM_MODE;
+
+ haptics->periodic_op_mode = DA7280_RTWM_MODE;
+ error = device_property_read_u32(dev, "dlg,periodic-op-mode", &val);
+ if (!error && val == DA7280_FF_PERIODIC_ETWM)
+ haptics->periodic_op_mode = DA7280_ETWM_MODE;
+
+ haptics->nommax = DA7280_SKIP_INIT;
+ error = device_property_read_u32(dev, "dlg,nom-microvolt", &val);
+ if (!error && val < DA7280_VOLTAGE_RATE_MAX)
+ haptics->nommax = da7280_haptic_of_volt_rating_set(val);
+
+ haptics->absmax = DA7280_SKIP_INIT;
+ error = device_property_read_u32(dev, "dlg,abs-max-microvolt", &val);
+ if (!error && val < DA7280_VOLTAGE_RATE_MAX)
+ haptics->absmax = da7280_haptic_of_volt_rating_set(val);
+
+ haptics->imax = DA7280_IMAX_DEFAULT;
+ error = device_property_read_u32(dev, "dlg,imax-microamp", &val);
+ if (!error && val < DA7280_IMAX_LIMIT)
+ haptics->imax = (val - 28600) / DA7280_IMAX_STEP + 1;
+
+ haptics->impd = DA7280_IMPD_DEFAULT;
+ error = device_property_read_u32(dev, "dlg,impd-micro-ohms", &val);
+ if (!error && val <= DA7280_IMPD_MAX)
+ haptics->impd = val;
+
+ haptics->resonant_freq_h = DA7280_SKIP_INIT;
+ haptics->resonant_freq_l = DA7280_SKIP_INIT;
+ error = device_property_read_u32(dev, "dlg,resonant-freq-hz", &val);
+ if (!error) {
+ if (val < DA7280_MAX_RESONAT_FREQ_HZ &&
+ val > DA7280_MIN_RESONAT_FREQ_HZ) {
+ haptics->resonant_freq_h =
+ ((1000000000 / (val * 1333)) >> 7) & 0xFF;
+ haptics->resonant_freq_l =
+ (1000000000 / (val * 1333)) & 0x7F;
+ } else {
+ haptics->resonant_freq_h = DA7280_RESONT_FREQH_DFT;
+ haptics->resonant_freq_l = DA7280_RESONT_FREQL_DFT;
+ }
+ }
+
+ /* If no property, set to zero as default is to do nothing. */
+ haptics->ps_seq_id = 0;
+ error = device_property_read_u32(dev, "dlg,ps-seq-id", &val);
+ if (!error && val <= DA7280_SEQ_ID_MAX)
+ haptics->ps_seq_id = val;
+
+ haptics->ps_seq_loop = 0;
+ error = device_property_read_u32(dev, "dlg,ps-seq-loop", &val);
+ if (!error && val <= DA7280_SEQ_LOOP_MAX)
+ haptics->ps_seq_loop = val;
+
+ /* GPI0~2 Control */
+ for (i = 0; i <= DA7280_GPI_SEQ_ID_MAX; i++) {
+ gpi_str1[7] = '0' + i;
+ haptics->gpi_ctl[i].seq_id = DA7280_GPI_SEQ_ID_DFT + i;
+ error = device_property_read_u32 (dev, gpi_str1, &val);
+ if (!error && val <= DA7280_SEQ_ID_MAX)
+ haptics->gpi_ctl[i].seq_id = val;
+
+ gpi_str2[7] = '0' + i;
+ haptics->gpi_ctl[i].mode = 0;
+ error = device_property_read_string(dev, gpi_str2, &str);
+ if (!error)
+ haptics->gpi_ctl[i].mode =
+ da7280_haptic_of_gpi_mode_str(dev, str);
+
+ gpi_str3[7] = '0' + i;
+ haptics->gpi_ctl[i].polarity = 0;
+ error = device_property_read_string(dev, gpi_str3, &str);
+ haptics->gpi_ctl[i].polarity =
+ da7280_haptic_of_gpi_pol_str(dev, str);
+ }
+
+ haptics->bemf_sense_en =
+ device_property_read_bool(dev, "dlg,bemf-sens-enable");
+ haptics->freq_track_en =
+ device_property_read_bool(dev, "dlg,freq-track-enable");
+ haptics->acc_en =
+ device_property_read_bool(dev, "dlg,acc-enable");
+ haptics->rapid_stop_en =
+ device_property_read_bool(dev, "dlg,rapid-stop-enable");
+ haptics->amp_pid_en =
+ device_property_read_bool(dev, "dlg,amp-pid-enable");
+
+ haptics->mem_update = false;
+ error = device_property_read_u32_array(dev, "dlg,mem-array",
+ &mem[0], DA7280_SNP_MEM_SIZE);
+ if (!error) {
+ haptics->mem_update = true;
+ memset(haptics->snp_mem, 0, DA7280_SNP_MEM_SIZE);
+ for (i = 0; i < DA7280_SNP_MEM_SIZE; i++) {
+ if (mem[i] <= 0xff) {
+ haptics->snp_mem[i] = (u8)mem[i];
+ } else {
+ dev_err(haptics->dev,
+ "Invalid data in mem-array at %d: %x\n",
+ i, mem[i]);
+ haptics->mem_update = false;
+ break;
+ }
+ }
+ }
+}
+
+static irqreturn_t da7280_irq_handler(int irq, void *data)
+{
+ struct da7280_haptic *haptics = data;
+ struct device *dev = haptics->dev;
+ u8 events[DA7280_IRQ_NUM];
+ int error;
+
+ /* Check what events have happened */
+ error = regmap_bulk_read(haptics->regmap, DA7280_IRQ_EVENT1,
+ events, sizeof(events));
+ if (error) {
+ dev_err(dev, "failed to read interrupt data: %d\n", error);
+ goto out;
+ }
+
+ /* Clear events */
+ error = regmap_write(haptics->regmap, DA7280_IRQ_EVENT1, events[0]);
+ if (error) {
+ dev_err(dev, "failed to clear interrupts: %d\n", error);
+ goto out;
+ }
+
+ if (events[0] & DA7280_E_SEQ_FAULT_MASK) {
+ /*
+ * Stop first if haptic is active, otherwise, the fault may
+ * happen continually even though the bit is cleared.
+ */
+ error = regmap_update_bits(haptics->regmap, DA7280_TOP_CTL1,
+ DA7280_OPERATION_MODE_MASK, 0);
+ if (error)
+ dev_err(dev, "failed to clear op mode on fault: %d\n",
+ error);
+ }
+
+ if (events[0] & DA7280_E_SEQ_DONE_MASK)
+ haptics->active = false;
+
+ if (events[0] & DA7280_E_WARNING_MASK) {
+ if (events[1] & DA7280_E_LIM_DRIVE_MASK ||
+ events[1] & DA7280_E_LIM_DRIVE_ACC_MASK)
+ dev_warn(dev, "Please reduce the driver level\n");
+ if (events[1] & DA7280_E_MEM_TYPE_MASK)
+ dev_warn(dev, "Please check the mem data format\n");
+ if (events[1] & DA7280_E_OVERTEMP_WARN_MASK)
+ dev_warn(dev, "Over-temperature warning\n");
+ }
+
+ if (events[0] & DA7280_E_SEQ_FAULT_MASK) {
+ if (events[2] & DA7280_E_SEQ_ID_FAULT_MASK)
+ dev_info(dev, "Please reload PS_SEQ_ID & mem data\n");
+ if (events[2] & DA7280_E_MEM_FAULT_MASK)
+ dev_info(dev, "Please reload the mem data\n");
+ if (events[2] & DA7280_E_PWM_FAULT_MASK)
+ dev_info(dev, "Please restart PWM interface\n");
+ }
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int da7280_init(struct da7280_haptic *haptics)
+{
+ unsigned int val = 0;
+ u32 v2i_factor;
+ int error, i;
+ u8 mask = 0;
+
+ /*
+ * If device type is DA7280_DEV_MAX then simply use currently
+ * programmed mode.
+ */
+ if (haptics->dev_type == DA7280_DEV_MAX) {
+ error = regmap_read(haptics->regmap, DA7280_TOP_CFG1, &val);
+ if (error)
+ goto out_err;
+
+ haptics->dev_type = val & DA7280_ACTUATOR_TYPE_MASK ?
+ DA7280_ERM_COIN : DA7280_LRA;
+ }
+
+ /* Apply user settings */
+ if (haptics->dev_type == DA7280_LRA &&
+ haptics->resonant_freq_l != DA7280_SKIP_INIT) {
+ error = regmap_write(haptics->regmap, DA7280_FRQ_LRA_PER_H,
+ haptics->resonant_freq_h);
+ if (error)
+ goto out_err;
+ error = regmap_write(haptics->regmap, DA7280_FRQ_LRA_PER_L,
+ haptics->resonant_freq_l);
+ if (error)
+ goto out_err;
+ } else if (haptics->dev_type == DA7280_ERM_COIN) {
+ error = regmap_update_bits(haptics->regmap, DA7280_TOP_INT_CFG1,
+ DA7280_BEMF_FAULT_LIM_MASK, 0);
+ if (error)
+ goto out_err;
+
+ mask = DA7280_TST_CALIB_IMPEDANCE_DIS_MASK |
+ DA7280_V2I_FACTOR_FREEZE_MASK;
+ val = DA7280_TST_CALIB_IMPEDANCE_DIS_MASK |
+ DA7280_V2I_FACTOR_FREEZE_MASK;
+ error = regmap_update_bits(haptics->regmap, DA7280_TOP_CFG4,
+ mask, val);
+ if (error)
+ goto out_err;
+
+ haptics->acc_en = false;
+ haptics->rapid_stop_en = false;
+ haptics->amp_pid_en = false;
+ }
+
+ mask = DA7280_ACTUATOR_TYPE_MASK |
+ DA7280_BEMF_SENSE_EN_MASK |
+ DA7280_FREQ_TRACK_EN_MASK |
+ DA7280_ACCELERATION_EN_MASK |
+ DA7280_RAPID_STOP_EN_MASK |
+ DA7280_AMP_PID_EN_MASK;
+ val = FIELD_PREP(DA7280_ACTUATOR_TYPE_MASK,
+ (haptics->dev_type ? 1 : 0)) |
+ FIELD_PREP(DA7280_BEMF_SENSE_EN_MASK,
+ (haptics->bemf_sense_en ? 1 : 0)) |
+ FIELD_PREP(DA7280_FREQ_TRACK_EN_MASK,
+ (haptics->freq_track_en ? 1 : 0)) |
+ FIELD_PREP(DA7280_ACCELERATION_EN_MASK,
+ (haptics->acc_en ? 1 : 0)) |
+ FIELD_PREP(DA7280_RAPID_STOP_EN_MASK,
+ (haptics->rapid_stop_en ? 1 : 0)) |
+ FIELD_PREP(DA7280_AMP_PID_EN_MASK,
+ (haptics->amp_pid_en ? 1 : 0));
+
+ error = regmap_update_bits(haptics->regmap, DA7280_TOP_CFG1, mask, val);
+ if (error)
+ goto out_err;
+
+ error = regmap_update_bits(haptics->regmap, DA7280_TOP_CFG5,
+ DA7280_V2I_FACTOR_OFFSET_EN_MASK,
+ haptics->acc_en ?
+ DA7280_V2I_FACTOR_OFFSET_EN_MASK : 0);
+ if (error)
+ goto out_err;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CFG2,
+ DA7280_MEM_DATA_SIGNED_MASK,
+ haptics->acc_en ?
+ 0 : DA7280_MEM_DATA_SIGNED_MASK);
+ if (error)
+ goto out_err;
+
+ if (haptics->nommax != DA7280_SKIP_INIT) {
+ error = regmap_write(haptics->regmap, DA7280_ACTUATOR1,
+ haptics->nommax);
+ if (error)
+ goto out_err;
+ }
+
+ if (haptics->absmax != DA7280_SKIP_INIT) {
+ error = regmap_write(haptics->regmap, DA7280_ACTUATOR2,
+ haptics->absmax);
+ if (error)
+ goto out_err;
+ }
+
+ error = regmap_update_bits(haptics->regmap, DA7280_ACTUATOR3,
+ DA7280_IMAX_MASK, haptics->imax);
+ if (error)
+ goto out_err;
+
+ v2i_factor = haptics->impd * (haptics->imax + 4) / 1610400;
+ error = regmap_write(haptics->regmap, DA7280_CALIB_V2I_L,
+ v2i_factor & 0xff);
+ if (error)
+ goto out_err;
+ error = regmap_write(haptics->regmap, DA7280_CALIB_V2I_H,
+ v2i_factor >> 8);
+ if (error)
+ goto out_err;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_STANDBY_EN_MASK,
+ DA7280_STANDBY_EN_MASK);
+ if (error)
+ goto out_err;
+
+ if (haptics->mem_update) {
+ error = da7280_haptic_mem_update(haptics);
+ if (error)
+ goto out_err;
+ }
+
+ /* Set PS_SEQ_ID and PS_SEQ_LOOP */
+ val = FIELD_PREP(DA7280_PS_SEQ_ID_MASK, haptics->ps_seq_id) |
+ FIELD_PREP(DA7280_PS_SEQ_LOOP_MASK, haptics->ps_seq_loop);
+ error = regmap_write(haptics->regmap, DA7280_SEQ_CTL2, val);
+ if (error)
+ goto out_err;
+
+ /* GPI(N) CTL */
+ for (i = 0; i < 3; i++) {
+ val = FIELD_PREP(DA7280_GPI0_SEQUENCE_ID_MASK,
+ haptics->gpi_ctl[i].seq_id) |
+ FIELD_PREP(DA7280_GPI0_MODE_MASK,
+ haptics->gpi_ctl[i].mode) |
+ FIELD_PREP(DA7280_GPI0_POLARITY_MASK,
+ haptics->gpi_ctl[i].polarity);
+ error = regmap_write(haptics->regmap,
+ DA7280_GPI_0_CTL + i, val);
+ if (error)
+ goto out_err;
+ }
+
+ /* Mask ADC_SAT_M bit as default */
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_IRQ_MASK2,
+ DA7280_ADC_SAT_M_MASK,
+ DA7280_ADC_SAT_M_MASK);
+ if (error)
+ goto out_err;
+
+ /* Clear Interrupts */
+ error = regmap_write(haptics->regmap, DA7280_IRQ_EVENT1, 0xff);
+ if (error)
+ goto out_err;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_IRQ_MASK1,
+ DA7280_SEQ_FAULT_M_MASK |
+ DA7280_SEQ_DONE_M_MASK,
+ 0);
+ if (error)
+ goto out_err;
+
+ haptics->active = false;
+ return 0;
+
+out_err:
+ dev_err(haptics->dev, "chip initialization error: %d\n", error);
+ return error;
+}
+
+static int da7280_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct da7280_haptic *haptics;
+ struct input_dev *input_dev;
+ struct pwm_state state;
+ struct ff_device *ff;
+ int error;
+
+ if (!client->irq) {
+ dev_err(dev, "No IRQ configured\n");
+ return -EINVAL;
+ }
+
+ haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL);
+ if (!haptics)
+ return -ENOMEM;
+
+ haptics->dev = dev;
+
+ da7280_parse_properties(dev, haptics);
+
+ if (haptics->const_op_mode == DA7280_PWM_MODE) {
+ haptics->pwm_dev = devm_pwm_get(dev, NULL);
+ error = PTR_ERR_OR_ZERO(haptics->pwm_dev);
+ if (error) {
+ if (error != -EPROBE_DEFER)
+ dev_err(dev, "Unable to request PWM: %d\n",
+ error);
+ return error;
+ }
+
+ /* Sync up PWM state and ensure it is off. */
+ pwm_init_state(haptics->pwm_dev, &state);
+ state.enabled = false;
+ error = pwm_apply_state(haptics->pwm_dev, &state);
+ if (error) {
+ dev_err(dev, "Failed to apply PWM state: %d\n", error);
+ return error;
+ }
+
+ /*
+ * Check PWM period, PWM freq = 1000000 / state.period.
+ * The valid PWM freq range: 10k ~ 250kHz.
+ */
+ if (state.period > 100000 || state.period < 4000) {
+ dev_err(dev, "Unsupported PWM period: %lld\n",
+ state.period);
+ return -EINVAL;
+ }
+ }
+
+ INIT_WORK(&haptics->work, da7280_haptic_work);
+
+ haptics->client = client;
+ i2c_set_clientdata(client, haptics);
+
+ haptics->regmap = devm_regmap_init_i2c(client,
+ &da7280_haptic_regmap_config);
+ error = PTR_ERR_OR_ZERO(haptics->regmap);
+ if (error) {
+ dev_err(dev, "Failed to allocate register map: %d\n", error);
+ return error;
+ }
+
+ error = da7280_init(haptics);
+ if (error) {
+ dev_err(dev, "Failed to initialize device: %d\n", error);
+ return error;
+ }
+
+ /* Initialize input device for haptic device */
+ input_dev = devm_input_allocate_device(dev);
+ if (!input_dev) {
+ dev_err(dev, "Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ input_dev->name = "da7280-haptic";
+ input_dev->dev.parent = client->dev.parent;
+ input_dev->open = da7280_haptic_open;
+ input_dev->close = da7280_haptic_close;
+ input_set_drvdata(input_dev, haptics);
+ haptics->input_dev = input_dev;
+
+ input_set_capability(haptics->input_dev, EV_FF, FF_PERIODIC);
+ input_set_capability(haptics->input_dev, EV_FF, FF_CUSTOM);
+ input_set_capability(haptics->input_dev, EV_FF, FF_CONSTANT);
+ input_set_capability(haptics->input_dev, EV_FF, FF_GAIN);
+
+ error = input_ff_create(haptics->input_dev,
+ DA7280_FF_EFFECT_COUNT_MAX);
+ if (error) {
+ dev_err(dev, "Failed to create FF input device: %d\n", error);
+ return error;
+ }
+
+ ff = input_dev->ff;
+ ff->upload = da7280_haptics_upload_effect;
+ ff->playback = da7280_haptics_playback;
+
+ error = input_register_device(input_dev);
+ if (error) {
+ dev_err(dev, "Failed to register input device: %d\n", error);
+ return error;
+ }
+
+ error = devm_request_threaded_irq(dev, client->irq,
+ NULL, da7280_irq_handler,
+ IRQF_ONESHOT,
+ "da7280-haptics", haptics);
+ if (error) {
+ dev_err(dev, "Failed to request IRQ %d: %d\n",
+ client->irq, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused da7280_suspend(struct device *dev)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+
+ mutex_lock(&haptics->input_dev->mutex);
+
+ /*
+ * Make sure no new requests will be submitted while device is
+ * suspended.
+ */
+ spin_lock_irq(&haptics->input_dev->event_lock);
+ haptics->suspended = true;
+ spin_unlock_irq(&haptics->input_dev->event_lock);
+
+ da7280_haptic_stop(haptics);
+
+ mutex_unlock(&haptics->input_dev->mutex);
+
+ return 0;
+}
+
+static int __maybe_unused da7280_resume(struct device *dev)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ int retval;
+
+ mutex_lock(&haptics->input_dev->mutex);
+
+ retval = da7280_haptic_start(haptics);
+ if (!retval) {
+ spin_lock_irq(&haptics->input_dev->event_lock);
+ haptics->suspended = false;
+ spin_unlock_irq(&haptics->input_dev->event_lock);
+ }
+
+ mutex_unlock(&haptics->input_dev->mutex);
+ return retval;
+}
+
+static const struct of_device_id da7280_of_match[] = {
+ { .compatible = "dlg,da7280", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da7280_of_match);
+
+static const struct i2c_device_id da7280_i2c_id[] = {
+ { "da7280", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, da7280_i2c_id);
+
+static SIMPLE_DEV_PM_OPS(da7280_pm_ops, da7280_suspend, da7280_resume);
+
+static struct i2c_driver da7280_driver = {
+ .driver = {
+ .name = "da7280",
+ .of_match_table = of_match_ptr(da7280_of_match),
+ .pm = &da7280_pm_ops,
+ },
+ .probe = da7280_probe,
+ .id_table = da7280_i2c_id,
+};
+module_i2c_driver(da7280_driver);
+
+MODULE_DESCRIPTION("DA7280 haptics driver");
+MODULE_AUTHOR("Roy Im <Roy.Im.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index 79d7fa710a71..0efe56f49aa9 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -167,17 +167,17 @@
/**
* struct drv260x_data -
- * @input_dev - Pointer to the input device
- * @client - Pointer to the I2C client
- * @regmap - Register map of the device
- * @work - Work item used to off load the enable/disable of the vibration
- * @enable_gpio - Pointer to the gpio used for enable/disabling
- * @regulator - Pointer to the regulator for the IC
- * @magnitude - Magnitude of the vibration event
- * @mode - The operating mode of the IC (LRA_NO_CAL, ERM or LRA)
- * @library - The vibration library to be used
- * @rated_voltage - The rated_voltage of the actuator
- * @overdriver_voltage - The over drive voltage of the actuator
+ * @input_dev: Pointer to the input device
+ * @client: Pointer to the I2C client
+ * @regmap: Register map of the device
+ * @work: Work item used to off load the enable/disable of the vibration
+ * @enable_gpio: Pointer to the gpio used for enable/disabling
+ * @regulator: Pointer to the regulator for the IC
+ * @magnitude: Magnitude of the vibration event
+ * @mode: The operating mode of the IC (LRA_NO_CAL, ERM or LRA)
+ * @library: The vibration library to be used
+ * @rated_voltage: The rated_voltage of the actuator
+ * @overdrive_voltage: The over drive voltage of the actuator
**/
struct drv260x_data {
struct input_dev *input_dev;
@@ -234,12 +234,12 @@ static const struct reg_default drv260x_reg_defs[] = {
#define DRV260X_DEF_RATED_VOLT 0x90
#define DRV260X_DEF_OD_CLAMP_VOLT 0x90
-/**
+/*
* Rated and Overdriver Voltages:
* Calculated using the formula r = v * 255 / 5.6
* where r is what will be written to the register
* and v is the rated or overdriver voltage of the actuator
- **/
+ */
static int drv260x_calculate_voltage(unsigned int voltage)
{
return (voltage * 255 / 5600);
@@ -580,7 +580,7 @@ static int __maybe_unused drv260x_suspend(struct device *dev)
mutex_lock(&haptics->input_dev->mutex);
- if (haptics->input_dev->users) {
+ if (input_device_enabled(haptics->input_dev)) {
ret = regmap_update_bits(haptics->regmap,
DRV260X_MODE,
DRV260X_STANDBY_MASK,
@@ -612,7 +612,7 @@ static int __maybe_unused drv260x_resume(struct device *dev)
mutex_lock(&haptics->input_dev->mutex);
- if (haptics->input_dev->users) {
+ if (input_device_enabled(haptics->input_dev)) {
ret = regulator_enable(haptics->regulator);
if (ret) {
dev_err(dev, "Failed to enable regulator\n");
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
index 918ad9c3fa81..21913e8085d7 100644
--- a/drivers/input/misc/drv2665.c
+++ b/drivers/input/misc/drv2665.c
@@ -44,11 +44,11 @@
/**
* struct drv2665_data -
- * @input_dev - Pointer to the input device
- * @client - Pointer to the I2C client
- * @regmap - Register map of the device
- * @work - Work item used to off load the enable/disable of the vibration
- * @regulator - Pointer to the regulator for the IC
+ * @input_dev: Pointer to the input device
+ * @client: Pointer to the I2C client
+ * @regmap: Register map of the device
+ * @work: Work item used to off load the enable/disable of the vibration
+ * @regulator: Pointer to the regulator for the IC
*/
struct drv2665_data {
struct input_dev *input_dev;
@@ -230,7 +230,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev)
mutex_lock(&haptics->input_dev->mutex);
- if (haptics->input_dev->users) {
+ if (input_device_enabled(haptics->input_dev)) {
ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
DRV2665_STANDBY, DRV2665_STANDBY);
if (ret) {
@@ -259,7 +259,7 @@ static int __maybe_unused drv2665_resume(struct device *dev)
mutex_lock(&haptics->input_dev->mutex);
- if (haptics->input_dev->users) {
+ if (input_device_enabled(haptics->input_dev)) {
ret = regulator_enable(haptics->regulator);
if (ret) {
dev_err(dev, "Failed to enable regulator\n");
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
index bb9d5784df17..3f67b9b010bf 100644
--- a/drivers/input/misc/drv2667.c
+++ b/drivers/input/misc/drv2667.c
@@ -90,12 +90,14 @@
/**
* struct drv2667_data -
- * @input_dev - Pointer to the input device
- * @client - Pointer to the I2C client
- * @regmap - Register map of the device
- * @work - Work item used to off load the enable/disable of the vibration
- * @regulator - Pointer to the regulator for the IC
- * @magnitude - Magnitude of the vibration event
+ * @input_dev: Pointer to the input device
+ * @client: Pointer to the I2C client
+ * @regmap: Register map of the device
+ * @work: Work item used to off load the enable/disable of the vibration
+ * @regulator: Pointer to the regulator for the IC
+ * @page: Page number
+ * @magnitude: Magnitude of the vibration event
+ * @frequency: Frequency of the vibration event
**/
struct drv2667_data {
struct input_dev *input_dev;
@@ -405,7 +407,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev)
mutex_lock(&haptics->input_dev->mutex);
- if (haptics->input_dev->users) {
+ if (input_device_enabled(haptics->input_dev)) {
ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
DRV2667_STANDBY, DRV2667_STANDBY);
if (ret) {
@@ -434,7 +436,7 @@ static int __maybe_unused drv2667_resume(struct device *dev)
mutex_lock(&haptics->input_dev->mutex);
- if (haptics->input_dev->users) {
+ if (input_device_enabled(haptics->input_dev)) {
ret = regulator_enable(haptics->regulator);
if (ret) {
dev_err(dev, "Failed to enable regulator\n");
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 794ecc9a552d..05018d0c97c7 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -97,7 +97,7 @@ static int ixp4xx_spkr_probe(struct platform_device *dev)
input_set_drvdata(input_dev, (void *) dev->id);
- input_dev->name = "ixp4xx beeper",
+ input_dev->name = "ixp4xx beeper";
input_dev->phys = "ixp4xx/gpio";
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x001f;
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index 52313c6e3fb3..bbb81617c2b2 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -503,7 +503,7 @@ static int __maybe_unused kxtj9_suspend(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
kxtj9_disable(tj9);
mutex_unlock(&input_dev->mutex);
@@ -518,7 +518,7 @@ static int __maybe_unused kxtj9_resume(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
kxtj9_enable(tj9);
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index afdf8ef25ee8..0636eee4bb6c 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Philippe Rétornaz
*
* Based on twl4030-pwrbutton driver by:
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index e5e0d8ba80e1..9c666b2f14fe 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -33,6 +33,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type,
case SND_BELL:
if (value)
value = 1000;
+ break;
case SND_TONE:
break;
default:
diff --git a/drivers/input/misc/sc27xx-vibra.c b/drivers/input/misc/sc27xx-vibra.c
index 295251abbdac..1478017f0968 100644
--- a/drivers/input/misc/sc27xx-vibra.c
+++ b/drivers/input/misc/sc27xx-vibra.c
@@ -3,45 +3,82 @@
* Copyright (C) 2018 Spreadtrum Communications Inc.
*/
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/regmap.h>
-#include <linux/input.h>
#include <linux/workqueue.h>
-#define CUR_DRV_CAL_SEL GENMASK(13, 12)
-#define SLP_LDOVIBR_PD_EN BIT(9)
-#define LDO_VIBR_PD BIT(8)
+#define CUR_DRV_CAL_SEL GENMASK(13, 12)
+#define SLP_LDOVIBR_PD_EN BIT(9)
+#define LDO_VIBR_PD BIT(8)
+#define SC2730_CUR_DRV_CAL_SEL 0
+#define SC2730_SLP_LDOVIBR_PD_EN BIT(14)
+#define SC2730_LDO_VIBR_PD BIT(13)
+
+struct sc27xx_vibra_data {
+ u32 cur_drv_cal_sel;
+ u32 slp_pd_en;
+ u32 ldo_pd;
+};
struct vibra_info {
struct input_dev *input_dev;
struct work_struct play_work;
struct regmap *regmap;
+ const struct sc27xx_vibra_data *data;
u32 base;
u32 strength;
bool enabled;
};
+static const struct sc27xx_vibra_data sc2731_data = {
+ .cur_drv_cal_sel = CUR_DRV_CAL_SEL,
+ .slp_pd_en = SLP_LDOVIBR_PD_EN,
+ .ldo_pd = LDO_VIBR_PD,
+};
+
+static const struct sc27xx_vibra_data sc2730_data = {
+ .cur_drv_cal_sel = SC2730_CUR_DRV_CAL_SEL,
+ .slp_pd_en = SC2730_SLP_LDOVIBR_PD_EN,
+ .ldo_pd = SC2730_LDO_VIBR_PD,
+};
+
+static const struct sc27xx_vibra_data sc2721_data = {
+ .cur_drv_cal_sel = CUR_DRV_CAL_SEL,
+ .slp_pd_en = SLP_LDOVIBR_PD_EN,
+ .ldo_pd = LDO_VIBR_PD,
+};
+
static void sc27xx_vibra_set(struct vibra_info *info, bool on)
{
+ const struct sc27xx_vibra_data *data = info->data;
if (on) {
- regmap_update_bits(info->regmap, info->base, LDO_VIBR_PD, 0);
+ regmap_update_bits(info->regmap, info->base, data->ldo_pd, 0);
regmap_update_bits(info->regmap, info->base,
- SLP_LDOVIBR_PD_EN, 0);
+ data->slp_pd_en, 0);
info->enabled = true;
} else {
- regmap_update_bits(info->regmap, info->base, LDO_VIBR_PD,
- LDO_VIBR_PD);
+ regmap_update_bits(info->regmap, info->base, data->ldo_pd,
+ data->ldo_pd);
regmap_update_bits(info->regmap, info->base,
- SLP_LDOVIBR_PD_EN, SLP_LDOVIBR_PD_EN);
+ data->slp_pd_en, data->slp_pd_en);
info->enabled = false;
}
}
static int sc27xx_vibra_hw_init(struct vibra_info *info)
{
- return regmap_update_bits(info->regmap, info->base, CUR_DRV_CAL_SEL, 0);
+ const struct sc27xx_vibra_data *data = info->data;
+
+ if (!data->cur_drv_cal_sel)
+ return 0;
+
+ return regmap_update_bits(info->regmap, info->base,
+ data->cur_drv_cal_sel, 0);
}
static void sc27xx_vibra_play_work(struct work_struct *work)
@@ -78,8 +115,15 @@ static void sc27xx_vibra_close(struct input_dev *input)
static int sc27xx_vibra_probe(struct platform_device *pdev)
{
struct vibra_info *info;
+ const struct sc27xx_vibra_data *data;
int error;
+ data = device_get_match_data(&pdev->dev);
+ if (!data) {
+ dev_err(&pdev->dev, "no matching driver data found\n");
+ return -EINVAL;
+ }
+
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -105,6 +149,7 @@ static int sc27xx_vibra_probe(struct platform_device *pdev)
info->input_dev->name = "sc27xx:vibrator";
info->input_dev->id.version = 0;
info->input_dev->close = sc27xx_vibra_close;
+ info->data = data;
input_set_drvdata(info->input_dev, info);
input_set_capability(info->input_dev, EV_FF, FF_RUMBLE);
@@ -134,7 +179,9 @@ static int sc27xx_vibra_probe(struct platform_device *pdev)
}
static const struct of_device_id sc27xx_vibra_of_match[] = {
- { .compatible = "sprd,sc2731-vibrator", },
+ { .compatible = "sprd,sc2721-vibrator", .data = &sc2721_data },
+ { .compatible = "sprd,sc2730-vibrator", .data = &sc2730_data },
+ { .compatible = "sprd,sc2731-vibrator", .data = &sc2731_data },
{}
};
MODULE_DEVICE_TABLE(of, sc27xx_vibra_of_match);
diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
index 60e1f31ee60a..7982bf8fb839 100644
--- a/drivers/input/misc/sirfsoc-onkey.c
+++ b/drivers/input/misc/sirfsoc-onkey.c
@@ -181,7 +181,7 @@ static int __maybe_unused sirfsoc_pwrc_resume(struct device *dev)
* if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
*/
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
mutex_unlock(&input->mutex);
diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c
index 1b44de265a0a..a42fe041b73c 100644
--- a/drivers/input/misc/wm831x-on.c
+++ b/drivers/input/misc/wm831x-on.c
@@ -1,4 +1,4 @@
-/**
+/*
* wm831x-on.c - WM831X ON pin driver
*
* Copyright (C) 2009 Wolfson Microelectronics plc
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index d8b6a5dab190..63c9cda555c3 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -372,7 +372,7 @@ config MOUSE_VSXXXAA
select SERIO
help
Say Y (or M) if you want to use a DEC VSXXX-AA (hockey
- puck) or a VSXXX-GA (rectangular) mouse. Theses mice are
+ puck) or a VSXXX-GA (rectangular) mouse. These mice are
typically used on DECstations or VAXstations, but can also
be used on any box capable of RS232 (with some adaptor
described in the source file). This driver also works with the
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index c675f156948b..77cc653edca2 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -119,7 +119,7 @@ static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len,
/**
* cyapa_i2c_write - Execute i2c block data write operation
* @cyapa: Handle to this driver
- * @ret: Offset of the data to written in the register map
+ * @reg: Offset of the data to written in the register map
* @len: number of bytes to write
* @values: Data to be written
*
@@ -526,7 +526,7 @@ static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
{
struct input_dev *input = cyapa->input;
- if (!input || !input->users) {
+ if (!input || !input_device_enabled(input)) {
/*
* When input is NULL, TP must be in deep sleep mode.
* In this mode, later non-power I2C command will always failed
@@ -546,7 +546,7 @@ static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa)
{
struct input_dev *input = cyapa->input;
- if (!input || !input->users) {
+ if (!input || !input_device_enabled(input)) {
if (cyapa->gen >= CYAPA_GEN5)
disable_irq(cyapa->client->irq);
if (!input || cyapa->operational)
@@ -652,7 +652,7 @@ static int cyapa_reinitialize(struct cyapa *cyapa)
}
out:
- if (!input || !input->users) {
+ if (!input || !input_device_enabled(input)) {
/* Reset to power OFF state to save power when no user open. */
if (cyapa->operational)
cyapa->ops->set_power_mode(cyapa,
@@ -840,10 +840,9 @@ static int cyapa_prepare_wakeup_controls(struct cyapa *cyapa)
return error;
}
- error = devm_add_action(dev,
+ error = devm_add_action_or_reset(dev,
cyapa_remove_power_wakeup_group, cyapa);
if (error) {
- cyapa_remove_power_wakeup_group(cyapa);
dev_err(dev, "failed to add power cleanup action: %d\n",
error);
return error;
@@ -957,9 +956,9 @@ static int cyapa_start_runtime(struct cyapa *cyapa)
return error;
}
- error = devm_add_action(dev, cyapa_remove_power_runtime_group, cyapa);
+ error = devm_add_action_or_reset(dev, cyapa_remove_power_runtime_group,
+ cyapa);
if (error) {
- cyapa_remove_power_runtime_group(cyapa);
dev_err(dev,
"failed to add power runtime cleanup action: %d\n",
error);
@@ -1291,9 +1290,8 @@ static int cyapa_probe(struct i2c_client *client,
return error;
}
- error = devm_add_action(dev, cyapa_disable_regulator, cyapa);
+ error = devm_add_action_or_reset(dev, cyapa_disable_regulator, cyapa);
if (error) {
- cyapa_disable_regulator(cyapa);
dev_err(dev, "failed to add disable regulator action: %d\n",
error);
return error;
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
index a0361f9325f8..a97f4acb6452 100644
--- a/drivers/input/mouse/cyapa_gen3.c
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -952,7 +952,8 @@ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
* doing so before issuing the next command may result in errors
* depending on the command's content.
*/
- if (cyapa->operational && input && input->users &&
+ if (cyapa->operational &&
+ input && input_device_enabled(input) &&
(pm_stage == CYAPA_PM_RUNTIME_SUSPEND ||
pm_stage == CYAPA_PM_RUNTIME_RESUME)) {
/* Try to polling in 120Hz, read may fail, just ignore it. */
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index bb3a63d1268d..abf42f77b4c5 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -385,7 +385,7 @@ ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size)
return size;
}
-/**
+/*
* Return a negative errno code else zero on success.
*/
ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
@@ -435,7 +435,7 @@ static enum cyapa_pm_stage cyapa_get_pip_pm_state(struct cyapa *cyapa)
return pm_stage;
}
-/**
+/*
* This function is aimed to dump all not read data in Gen5 trackpad
* before send any command, otherwise, the interrupt line will be blocked.
*/
@@ -518,7 +518,8 @@ int cyapa_empty_pip_output_data(struct cyapa *cyapa,
*len = length;
/* Response found, success. */
return 0;
- } else if (cyapa->operational && input && input->users &&
+ } else if (cyapa->operational &&
+ input && input_device_enabled(input) &&
(pm_stage == CYAPA_PM_RUNTIME_RESUME ||
pm_stage == CYAPA_PM_RUNTIME_SUSPEND)) {
/* Parse the data and report it if it's valid. */
diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c
index 7eba66fbef58..812edfced86e 100644
--- a/drivers/input/mouse/cyapa_gen6.c
+++ b/drivers/input/mouse/cyapa_gen6.c
@@ -573,7 +573,7 @@ static int cyapa_pip_retrieve_data_structure(struct cyapa *cyapa,
memset(&cmd, 0, sizeof(cmd));
put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd.head.addr);
- put_unaligned_le16(sizeof(cmd), &cmd.head.length - 2);
+ put_unaligned_le16(sizeof(cmd) - 2, &cmd.head.length);
cmd.head.report_id = PIP_APP_CMD_REPORT_ID;
cmd.head.cmd_code = PIP_RETRIEVE_DATA_STRUCTURE;
put_unaligned_le16(read_offset, &cmd.read_offset);
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h
index 36e3cd908671..e12da5b024b0 100644
--- a/drivers/input/mouse/elan_i2c.h
+++ b/drivers/input/mouse/elan_i2c.h
@@ -28,6 +28,22 @@
#define ETP_FEATURE_REPORT_MK BIT(0)
+#define ETP_REPORT_ID 0x5D
+#define ETP_TP_REPORT_ID 0x5E
+#define ETP_TP_REPORT_ID2 0x5F
+#define ETP_REPORT_ID2 0x60 /* High precision report */
+
+#define ETP_REPORT_ID_OFFSET 2
+#define ETP_TOUCH_INFO_OFFSET 3
+#define ETP_FINGER_DATA_OFFSET 4
+#define ETP_HOVER_INFO_OFFSET 30
+#define ETP_MK_DATA_OFFSET 33 /* For high precision reports */
+
+#define ETP_MAX_REPORT_LEN 39
+
+#define ETP_MAX_FINGERS 5
+#define ETP_FINGER_DATA_LEN 5
+
/* IAP Firmware handling */
#define ETP_PRODUCT_ID_FORMAT_STRING "%d.0"
#define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin"
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 61ed3f5ca219..bef73822315d 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -34,7 +34,6 @@
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/property.h>
-#include <linux/input/elan-i2c-ids.h>
#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
@@ -47,18 +46,6 @@
#define ETP_FINGER_WIDTH 15
#define ETP_RETRY_COUNT 3
-#define ETP_MAX_FINGERS 5
-#define ETP_FINGER_DATA_LEN 5
-#define ETP_REPORT_ID 0x5D
-#define ETP_REPORT_ID2 0x60 /* High precision report */
-#define ETP_TP_REPORT_ID 0x5E
-#define ETP_REPORT_ID_OFFSET 2
-#define ETP_TOUCH_INFO_OFFSET 3
-#define ETP_FINGER_DATA_OFFSET 4
-#define ETP_HOVER_INFO_OFFSET 30
-#define ETP_MK_DATA_OFFSET 33 /* For high precision reports */
-#define ETP_MAX_REPORT_LEN 39
-
/* The main device structure */
struct elan_tp_data {
struct i2c_client *client;
@@ -1076,6 +1063,7 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
elan_report_absolute(data, report, true);
break;
case ETP_TP_REPORT_ID:
+ case ETP_TP_REPORT_ID2:
elan_report_trackpoint(data, report);
break;
default:
@@ -1414,6 +1402,7 @@ static const struct i2c_device_id elan_id[] = {
MODULE_DEVICE_TABLE(i2c, elan_id);
#ifdef CONFIG_ACPI
+#include <linux/input/elan-i2c-ids.h>
MODULE_DEVICE_TABLE(acpi, elan_acpi_id);
#endif
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c
index 1820f1cfc1dc..6dc148b9d959 100644
--- a/drivers/input/mouse/elan_i2c_smbus.c
+++ b/drivers/input/mouse/elan_i2c_smbus.c
@@ -45,6 +45,7 @@
#define ETP_SMBUS_CALIBRATE_QUERY 0xC5
#define ETP_SMBUS_REPORT_LEN 32
+#define ETP_SMBUS_REPORT_LEN2 7
#define ETP_SMBUS_REPORT_OFFSET 2
#define ETP_SMBUS_HELLOPACKET_LEN 5
#define ETP_SMBUS_IAP_PASSWORD 0x1234
@@ -497,10 +498,13 @@ static int elan_smbus_get_report(struct i2c_client *client,
return len;
}
- if (len != ETP_SMBUS_REPORT_LEN) {
+ if (report[ETP_REPORT_ID_OFFSET] == ETP_TP_REPORT_ID2)
+ report_len = ETP_SMBUS_REPORT_LEN2;
+
+ if (len != report_len) {
dev_err(&client->dev,
"wrong report length (%d vs %d expected)\n",
- len, ETP_SMBUS_REPORT_LEN);
+ len, report_len);
return -EIO;
}
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 90f8765f9efc..97381e2e03ba 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -90,6 +90,47 @@ static int elantech_ps2_command(struct psmouse *psmouse,
}
/*
+ * Send an Elantech style special command to read 3 bytes from a register
+ */
+static int elantech_read_reg_params(struct psmouse *psmouse, u8 reg, u8 *param)
+{
+ if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+ elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
+ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+ elantech_ps2_command(psmouse, NULL, reg) ||
+ elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
+ psmouse_err(psmouse,
+ "failed to read register %#02x\n", reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Send an Elantech style special command to write a register with a parameter
+ */
+static int elantech_write_reg_params(struct psmouse *psmouse, u8 reg, u8 *param)
+{
+ if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+ elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
+ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+ elantech_ps2_command(psmouse, NULL, reg) ||
+ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+ elantech_ps2_command(psmouse, NULL, param[0]) ||
+ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+ elantech_ps2_command(psmouse, NULL, param[1]) ||
+ elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
+ psmouse_err(psmouse,
+ "failed to write register %#02x with value %#02x%#02x\n",
+ reg, param[0], param[1]);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
* Send an Elantech style special command to read a value from a register
*/
static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
@@ -1530,18 +1571,34 @@ static const struct dmi_system_id no_hw_res_dmi_table[] = {
};
/*
+ * Change Report id 0x5E to 0x5F.
+ */
+static int elantech_change_report_id(struct psmouse *psmouse)
+{
+ unsigned char param[2] = { 0x10, 0x03 };
+
+ if (elantech_write_reg_params(psmouse, 0x7, param) ||
+ elantech_read_reg_params(psmouse, 0x7, param) ||
+ param[0] != 0x10 || param[1] != 0x03) {
+ psmouse_err(psmouse, "Unable to change report ID to 0x5f.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+/*
* determine hardware version and set some properties according to it.
*/
static int elantech_set_properties(struct elantech_device_info *info)
{
/* This represents the version of IC body. */
- int ver = (info->fw_version & 0x0f0000) >> 16;
+ info->ic_version = (info->fw_version & 0x0f0000) >> 16;
/* Early version of Elan touchpads doesn't obey the rule. */
if (info->fw_version < 0x020030 || info->fw_version == 0x020600)
info->hw_version = 1;
else {
- switch (ver) {
+ switch (info->ic_version) {
case 2:
case 4:
info->hw_version = 2;
@@ -1557,6 +1614,11 @@ static int elantech_set_properties(struct elantech_device_info *info)
}
}
+ /* Get information pattern for hw_version 4 */
+ info->pattern = 0x00;
+ if (info->ic_version == 0x0f && (info->fw_version & 0xff) <= 0x02)
+ info->pattern = info->fw_version & 0xff;
+
/* decide which send_cmd we're gonna use early */
info->send_cmd = info->hw_version >= 3 ? elantech_send_cmd :
synaptics_send_cmd;
@@ -1598,6 +1660,7 @@ static int elantech_query_info(struct psmouse *psmouse,
{
unsigned char param[3];
unsigned char traces;
+ unsigned char ic_body[3];
memset(info, 0, sizeof(*info));
@@ -1640,6 +1703,21 @@ static int elantech_query_info(struct psmouse *psmouse,
info->samples[2]);
}
+ if (info->pattern > 0x00 && info->ic_version == 0xf) {
+ if (info->send_cmd(psmouse, ETP_ICBODY_QUERY, ic_body)) {
+ psmouse_err(psmouse, "failed to query ic body\n");
+ return -EINVAL;
+ }
+ info->ic_version = be16_to_cpup((__be16 *)ic_body);
+ psmouse_info(psmouse,
+ "Elan ic body: %#04x, current fw version: %#02x\n",
+ info->ic_version, ic_body[2]);
+ }
+
+ info->product_id = be16_to_cpup((__be16 *)info->samples);
+ if (info->pattern == 0x00)
+ info->product_id &= 0xff;
+
if (info->samples[1] == 0x74 && info->hw_version == 0x03) {
/*
* This module has a bug which makes absolute mode
@@ -1654,6 +1732,23 @@ static int elantech_query_info(struct psmouse *psmouse,
/* The MSB indicates the presence of the trackpoint */
info->has_trackpoint = (info->capabilities[0] & 0x80) == 0x80;
+ if (info->has_trackpoint && info->ic_version == 0x0011 &&
+ (info->product_id == 0x08 || info->product_id == 0x09 ||
+ info->product_id == 0x0d || info->product_id == 0x0e)) {
+ /*
+ * This module has a bug which makes trackpoint in SMBus
+ * mode return invalid data unless trackpoint is switched
+ * from using 0x5e reports to 0x5f. If we are not able to
+ * make the switch, let's abort initialization so we'll be
+ * using standard PS/2 protocol.
+ */
+ if (elantech_change_report_id(psmouse)) {
+ psmouse_info(psmouse,
+ "Trackpoint report is broken, forcing standard PS/2 protocol\n");
+ return -ENODEV;
+ }
+ }
+
info->x_res = 31;
info->y_res = 31;
if (info->hw_version == 4) {
@@ -1827,7 +1922,7 @@ static int elantech_create_smbus(struct psmouse *psmouse,
leave_breadcrumbs);
}
-/**
+/*
* elantech_setup_smbus - called once the PS/2 devices are enumerated
* and decides to instantiate a SMBus InterTouch device.
*/
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index e0a3e59d4f1b..571e6ca11d33 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -18,6 +18,7 @@
#define ETP_CAPABILITIES_QUERY 0x02
#define ETP_SAMPLE_QUERY 0x03
#define ETP_RESOLUTION_QUERY 0x04
+#define ETP_ICBODY_QUERY 0x05
/*
* Command values for register reading or writing
@@ -140,7 +141,10 @@ struct elantech_device_info {
unsigned char samples[3];
unsigned char debug;
unsigned char hw_version;
+ unsigned char pattern;
unsigned int fw_version;
+ unsigned int ic_version;
+ unsigned int product_id;
unsigned int x_min;
unsigned int y_min;
unsigned int x_max;
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
index c112980c2341..4d67575bb276 100644
--- a/drivers/input/mouse/navpoint.c
+++ b/drivers/input/mouse/navpoint.c
@@ -322,7 +322,7 @@ static int __maybe_unused navpoint_suspend(struct device *dev)
struct input_dev *input = navpoint->input;
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
navpoint_down(navpoint);
mutex_unlock(&input->mutex);
@@ -336,7 +336,7 @@ static int __maybe_unused navpoint_resume(struct device *dev)
struct input_dev *input = navpoint->input;
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
navpoint_up(navpoint);
mutex_unlock(&input->mutex);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 82577095e175..8fb7b4385ded 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1770,7 +1770,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse,
leave_breadcrumbs);
}
-/**
+/*
* synaptics_setup_intertouch - called once the PS/2 devices are enumerated
* and decides to instantiate a SMBus InterTouch device.
*/
diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c
index 148245c69be7..42443ffba7c4 100644
--- a/drivers/input/mouse/vmmouse.c
+++ b/drivers/input/mouse/vmmouse.c
@@ -76,7 +76,7 @@ struct vmmouse_data {
char dev_name[128];
};
-/**
+/*
* Hypervisor-specific bi-directional communication channel
* implementing the vmmouse protocol. Should never execute on
* bare metal hardware.
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index 47d1b97ed6cf..24f31a5c0e04 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -286,7 +286,7 @@ void rmi_unregister_function(struct rmi_function *fn)
/**
* rmi_register_function_handler - register a handler for an RMI function
* @handler: RMI handler that should be registered.
- * @module: pointer to module that implements the handler
+ * @owner: pointer to module that implements the handler
* @mod_name: name of the module implementing the handler
*
* This function performs additional setup of RMI function handler and
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index e623c956376e..d7603c50f864 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -103,13 +103,15 @@ struct f01_basic_properties {
#define RMI_F01_CTRL0_CONFIGURED_BIT BIT(7)
/**
- * @ctrl0 - see the bit definitions above.
- * @doze_interval - controls the interval between checks for finger presence
- * when the touch sensor is in doze mode, in units of 10ms.
- * @wakeup_threshold - controls the capacitance threshold at which the touch
- * sensor will decide to wake up from that low power state.
- * @doze_holdoff - controls how long the touch sensor waits after the last
- * finger lifts before entering the doze state, in units of 100ms.
+ * struct f01_device_control - controls basic sensor functions
+ *
+ * @ctrl0: see the bit definitions above.
+ * @doze_interval: controls the interval between checks for finger presence
+ * when the touch sensor is in doze mode, in units of 10ms.
+ * @wakeup_threshold: controls the capacitance threshold at which the touch
+ * sensor will decide to wake up from that low power state.
+ * @doze_holdoff: controls how long the touch sensor waits after the last
+ * finger lifts before entering the doze state, in units of 100ms.
*/
struct f01_device_control {
u8 ctrl0;
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index ffa39ab153f2..49ca9168685a 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -30,12 +30,12 @@
#define DEFAULT_MIN_ABS_MT_TRACKING_ID 1
#define DEFAULT_MAX_ABS_MT_TRACKING_ID 10
-/** A note about RMI4 F11 register structure.
+/*
+ * A note about RMI4 F11 register structure.
*
- * The properties for
- * a given sensor are described by its query registers. The number of query
- * registers and the layout of their contents are described by the F11 device
- * queries as well as the sensor query information.
+ * The properties for a given sensor are described by its query registers. The
+ * number of query registers and the layout of their contents are described by
+ * the F11 device queries as well as the sensor query information.
*
* Similarly, each sensor has control registers that govern its behavior. The
* size and layout of the control registers for a given sensor can be determined
@@ -62,8 +62,8 @@
/* maximum ABS_MT_POSITION displacement (in mm) */
#define DMAX 10
-/**
- * @rezero - writing this to the F11 command register will cause the sensor to
+/*
+ * Writing this to the F11 command register will cause the sensor to
* calibrate to the current capacitive state.
*/
#define RMI_F11_REZERO 0x01
@@ -178,135 +178,157 @@
#define F11_UNIFORM_CLICKPAD 0x02
/**
+ * struct f11_2d_sensor_queries - describes sensor capabilities
+ *
* Query registers 1 through 4 are always present.
*
- * @nr_fingers - describes the maximum number of fingers the 2-D sensor
- * supports.
- * @has_rel - the sensor supports relative motion reporting.
- * @has_abs - the sensor supports absolute poition reporting.
- * @has_gestures - the sensor supports gesture reporting.
- * @has_sensitivity_adjust - the sensor supports a global sensitivity
- * adjustment.
- * @configurable - the sensor supports various configuration options.
- * @num_of_x_electrodes - the maximum number of electrodes the 2-D sensor
- * supports on the X axis.
- * @num_of_y_electrodes - the maximum number of electrodes the 2-D sensor
- * supports on the Y axis.
- * @max_electrodes - the total number of X and Y electrodes that may be
- * configured.
+ * @nr_fingers: describes the maximum number of fingers the 2-D sensor
+ * supports.
+ * @has_rel: the sensor supports relative motion reporting.
+ * @has_abs: the sensor supports absolute poition reporting.
+ * @has_gestures: the sensor supports gesture reporting.
+ * @has_sensitivity_adjust: the sensor supports a global sensitivity
+ * adjustment.
+ * @configurable: the sensor supports various configuration options.
+ * @nr_x_electrodes: the maximum number of electrodes the 2-D sensor
+ * supports on the X axis.
+ * @nr_y_electrodes: the maximum number of electrodes the 2-D sensor
+ * supports on the Y axis.
+ * @max_electrodes: the total number of X and Y electrodes that may be
+ * configured.
*
* Query 5 is present if the has_abs bit is set.
*
- * @abs_data_size - describes the format of data reported by the absolute
- * data source. Only one format (the kind used here) is supported at this
- * time.
- * @has_anchored_finger - then the sensor supports the high-precision second
- * finger tracking provided by the manual tracking and motion sensitivity
- * options.
- * @has_adjust_hyst - the difference between the finger release threshold and
- * the touch threshold.
- * @has_dribble - the sensor supports the generation of dribble interrupts,
- * which may be enabled or disabled with the dribble control bit.
- * @has_bending_correction - Bending related data registers 28 and 36, and
- * control register 52..57 are present.
- * @has_large_object_suppression - control register 58 and data register 28
- * exist.
- * @has_jitter_filter - query 13 and control 73..76 exist.
+ * @abs_data_size: describes the format of data reported by the absolute
+ * data source. Only one format (the kind used here) is supported at this
+ * time.
+ * @has_anchored_finger: then the sensor supports the high-precision second
+ * finger tracking provided by the manual tracking and motion sensitivity
+ * options.
+ * @has_adj_hyst: the difference between the finger release threshold and
+ * the touch threshold.
+ * @has_dribble: the sensor supports the generation of dribble interrupts,
+ * which may be enabled or disabled with the dribble control bit.
+ * @has_bending_correction: Bending related data registers 28 and 36, and
+ * control register 52..57 are present.
+ * @has_large_object_suppression: control register 58 and data register 28
+ * exist.
+ * @has_jitter_filter: query 13 and control 73..76 exist.
+ *
+ * Query 6 is present if the has_rel it is set.
+ *
+ * @f11_2d_query6: this register is reserved.
*
* Gesture information queries 7 and 8 are present if has_gestures bit is set.
*
- * @has_single_tap - a basic single-tap gesture is supported.
- * @has_tap_n_hold - tap-and-hold gesture is supported.
- * @has_double_tap - double-tap gesture is supported.
- * @has_early_tap - early tap is supported and reported as soon as the finger
- * lifts for any tap event that could be interpreted as either a single tap
- * or as the first tap of a double-tap or tap-and-hold gesture.
- * @has_flick - flick detection is supported.
- * @has_press - press gesture reporting is supported.
- * @has_pinch - pinch gesture detection is supported.
- * @has_palm_det - the 2-D sensor notifies the host whenever a large conductive
- * object such as a palm or a cheek touches the 2-D sensor.
- * @has_rotate - rotation gesture detection is supported.
- * @has_touch_shapes - TouchShapes are supported. A TouchShape is a fixed
- * rectangular area on the sensor that behaves like a capacitive button.
- * @has_scroll_zones - scrolling areas near the sensor edges are supported.
- * @has_individual_scroll_zones - if 1, then 4 scroll zones are supported;
- * if 0, then only two are supported.
- * @has_mf_scroll - the multifinger_scrolling bit will be set when
- * more than one finger is involved in a scrolling action.
+ * @has_single_tap: a basic single-tap gesture is supported.
+ * @has_tap_n_hold: tap-and-hold gesture is supported.
+ * @has_double_tap: double-tap gesture is supported.
+ * @has_early_tap: early tap is supported and reported as soon as the finger
+ * lifts for any tap event that could be interpreted as either a single
+ * tap or as the first tap of a double-tap or tap-and-hold gesture.
+ * @has_flick: flick detection is supported.
+ * @has_press: press gesture reporting is supported.
+ * @has_pinch: pinch gesture detection is supported.
+ * @has_chiral: chiral (circular) scrolling gesture detection is supported.
+ * @has_palm_det: the 2-D sensor notifies the host whenever a large conductive
+ * object such as a palm or a cheek touches the 2-D sensor.
+ * @has_rotate: rotation gesture detection is supported.
+ * @has_touch_shapes: TouchShapes are supported. A TouchShape is a fixed
+ * rectangular area on the sensor that behaves like a capacitive button.
+ * @has_scroll_zones: scrolling areas near the sensor edges are supported.
+ * @has_individual_scroll_zones: if 1, then 4 scroll zones are supported;
+ * if 0, then only two are supported.
+ * @has_mf_scroll: the multifinger_scrolling bit will be set when
+ * more than one finger is involved in a scrolling action.
+ * @has_mf_edge_motion: indicates whether multi-finger edge motion gesture
+ * is supported.
+ * @has_mf_scroll_inertia: indicates whether multi-finger scroll inertia
+ * feature is supported.
*
* Convenience for checking bytes in the gesture info registers. This is done
* often enough that we put it here to declutter the conditionals
*
- * @query7_nonzero - true if none of the query 7 bits are set
- * @query8_nonzero - true if none of the query 8 bits are set
+ * @query7_nonzero: true if none of the query 7 bits are set
+ * @query8_nonzero: true if none of the query 8 bits are set
*
* Query 9 is present if the has_query9 is set.
*
- * @has_pen - detection of a stylus is supported and registers F11_2D_Ctrl20
- * and F11_2D_Ctrl21 exist.
- * @has_proximity - detection of fingers near the sensor is supported and
- * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist.
- * @has_palm_det_sensitivity - the sensor supports the palm detect sensitivity
- * feature and register F11_2D_Ctrl27 exists.
- * @has_two_pen_thresholds - is has_pen is also set, then F11_2D_Ctrl35 exists.
- * @has_contact_geometry - the sensor supports the use of contact geometry to
- * map absolute X and Y target positions and registers F11_2D_Data18
- * through F11_2D_Data27 exist.
+ * @has_pen: detection of a stylus is supported and registers F11_2D_Ctrl20
+ * and F11_2D_Ctrl21 exist.
+ * @has_proximity: detection of fingers near the sensor is supported and
+ * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist.
+ * @has_palm_det_sensitivity: the sensor supports the palm detect sensitivity
+ * feature and register F11_2D_Ctrl27 exists.
+ * @has_suppress_on_palm_detect: the device supports the large object detect
+ * suppression feature and register F11_2D_Ctrl27 exists.
+ * @has_two_pen_thresholds: if has_pen is also set, then F11_2D_Ctrl35 exists.
+ * @has_contact_geometry: the sensor supports the use of contact geometry to
+ * map absolute X and Y target positions and registers F11_2D_Data18
+ * through F11_2D_Data27 exist.
+ * @has_pen_hover_discrimination: if has_pen is also set, then registers
+ * F11_2D_Data29 through F11_2D_Data31, F11_2D_Ctrl68.*, F11_2D_Ctrl69
+ * and F11_2D_Ctrl72 exist.
+ * @has_pen_filters: if has_pen is also set, then registers F11_2D_Ctrl70 and
+ * F11_2D_Ctrl71 exist.
*
* Touch shape info (query 10) is present if has_touch_shapes is set.
*
- * @nr_touch_shapes - the total number of touch shapes supported.
+ * @nr_touch_shapes: the total number of touch shapes supported.
*
* Query 11 is present if the has_query11 bit is set in query 0.
*
- * @has_z_tuning - if set, the sensor supports Z tuning and registers
- * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist.
- * @has_algorithm_selection - controls choice of noise suppression algorithm
- * @has_w_tuning - the sensor supports Wx and Wy scaling and registers
- * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist.
- * @has_pitch_info - the X and Y pitches of the sensor electrodes can be
- * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist.
- * @has_finger_size - the default finger width settings for the
- * sensor can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44
- * exist.
- * @has_segmentation_aggressiveness - the sensor’s ability to distinguish
- * multiple objects close together can be configured and register F11_2D_Ctrl45
- * exists.
- * @has_XY_clip - the inactive outside borders of the sensor can be
- * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist.
- * @has_drumming_filter - the sensor can be configured to distinguish
- * between a fast flick and a quick drumming movement and registers
- * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist.
+ * @has_z_tuning: if set, the sensor supports Z tuning and registers
+ * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist.
+ * @has_algorithm_selection: controls choice of noise suppression algorithm
+ * @has_w_tuning: the sensor supports Wx and Wy scaling and registers
+ * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist.
+ * @has_pitch_info: the X and Y pitches of the sensor electrodes can be
+ * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist.
+ * @has_finger_size: the default finger width settings for the sensor
+ * can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44
+ * exist.
+ * @has_segmentation_aggressiveness: the sensor’s ability to distinguish
+ * multiple objects close together can be configured and register
+ * F11_2D_Ctrl45 exists.
+ * @has_XY_clip: the inactive outside borders of the sensor can be
+ * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist.
+ * @has_drumming_filter: the sensor can be configured to distinguish
+ * between a fast flick and a quick drumming movement and registers
+ * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist.
*
* Query 12 is present if hasQuery12 bit is set.
*
- * @has_gapless_finger - control registers relating to gapless finger are
- * present.
- * @has_gapless_finger_tuning - additional control and data registers relating
- * to gapless finger are present.
- * @has_8bit_w - larger W value reporting is supported.
- * @has_adjustable_mapping - TBD
- * @has_info2 - the general info query14 is present
- * @has_physical_props - additional queries describing the physical properties
- * of the sensor are present.
- * @has_finger_limit - indicates that F11 Ctrl 80 exists.
- * @has_linear_coeff - indicates that F11 Ctrl 81 exists.
+ * @has_gapless_finger: control registers relating to gapless finger are
+ * present.
+ * @has_gapless_finger_tuning: additional control and data registers relating
+ * to gapless finger are present.
+ * @has_8bit_w: larger W value reporting is supported.
+ * @has_adjustable_mapping: TBD
+ * @has_info2: the general info query14 is present
+ * @has_physical_props: additional queries describing the physical properties
+ * of the sensor are present.
+ * @has_finger_limit: indicates that F11 Ctrl 80 exists.
+ * @has_linear_coeff_2: indicates that F11 Ctrl 81 exists.
*
* Query 13 is present if Query 5's has_jitter_filter bit is set.
- * @jitter_window_size - used by Design Studio 4.
- * @jitter_filter_type - used by Design Studio 4.
+ *
+ * @jitter_window_size: used by Design Studio 4.
+ * @jitter_filter_type: used by Design Studio 4.
*
* Query 14 is present if query 12's has_general_info2 flag is set.
*
- * @light_control - Indicates what light/led control features are present, if
- * any.
- * @is_clear - if set, this is a clear sensor (indicating direct pointing
- * application), otherwise it's opaque (indicating indirect pointing).
- * @clickpad_props - specifies if this is a clickpad, and if so what sort of
- * mechanism it uses
- * @mouse_buttons - specifies the number of mouse buttons present (if any).
- * @has_advanced_gestures - advanced driver gestures are supported.
+ * @light_control: Indicates what light/led control features are present,
+ * if any.
+ * @is_clear: if set, this is a clear sensor (indicating direct pointing
+ * application), otherwise it's opaque (indicating indirect pointing).
+ * @clickpad_props: specifies if this is a clickpad, and if so what sort of
+ * mechanism it uses
+ * @mouse_buttons: specifies the number of mouse buttons present (if any).
+ * @has_advanced_gestures: advanced driver gestures are supported.
+ *
+ * @x_sensor_size_mm: size of the sensor in millimeters on the X axis.
+ * @y_sensor_size_mm: size of the sensor in millimeters on the Y axis.
*/
struct f11_2d_sensor_queries {
/* query1 */
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index 6b23e679606e..93b328c796c6 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -42,6 +42,8 @@
/**
* enum rmi_f54_report_type - RMI4 F54 report types
*
+ * @F54_REPORT_NONE: No Image Report.
+ *
* @F54_8BIT_IMAGE: Normalized 8-Bit Image Report. The capacitance variance
* from baseline for each pixel.
*
@@ -64,6 +66,10 @@
* Report. Set Low reference to its minimum value and high
* references to its maximum value, then report the raw
* capacitance for each pixel.
+ *
+ * @F54_MAX_REPORT_TYPE:
+ * Maximum number of Report Types. Used for sanity
+ * checking.
*/
enum rmi_f54_report_type {
F54_REPORT_NONE = 0,
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index a95c2c9bcab4..50305fcfbef5 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -17,12 +17,16 @@
* struct rmi_i2c_xport - stores information for i2c communication
*
* @xport: The transport interface structure
+ * @client: The I2C client device structure
*
* @page_mutex: Locks current page to avoid changing pages in unexpected ways.
* @page: Keeps track of the current virtual page
*
* @tx_buf: Buffer used for transmitting data to the sensor over i2c.
* @tx_buf_size: Size of the buffer
+ *
+ * @supplies: Array of voltage regulators
+ * @startup_delay: Milliseconds to pause after powering up the regulators
*/
struct rmi_i2c_xport {
struct rmi_transport_dev xport;
diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c
index 27b68dc79b18..c82edda66b23 100644
--- a/drivers/input/rmi4/rmi_spi.c
+++ b/drivers/input/rmi4/rmi_spi.c
@@ -188,7 +188,8 @@ static int rmi_spi_xfer(struct rmi_spi_xport *rmi_spi,
memset(xfer, 0, sizeof(struct spi_transfer));
xfer->tx_buf = &rmi_spi->tx_buf[i];
xfer->len = 1;
- xfer->delay_usecs = spi_data->write_delay_us;
+ xfer->delay.value = spi_data->write_delay_us;
+ xfer->delay.unit = SPI_DELAY_UNIT_USECS;
spi_message_add_tail(xfer, &msg);
}
} else {
@@ -210,7 +211,8 @@ static int rmi_spi_xfer(struct rmi_spi_xport *rmi_spi,
memset(xfer, 0, sizeof(struct spi_transfer));
xfer->rx_buf = &rmi_spi->rx_buf[i];
xfer->len = 1;
- xfer->delay_usecs = spi_data->read_delay_us;
+ xfer->delay.value = spi_data->read_delay_us;
+ xfer->delay.unit = SPI_DELAY_UNIT_USECS;
spi_message_add_tail(xfer, &msg);
}
} else {
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 8a16e41f7b7f..250e213cc80c 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -405,7 +405,7 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
ps2dev->nak = PS2_RET_ERR;
break;
}
- /* Fall through */
+ fallthrough;
/*
* Workaround for mice which don't ACK the Get ID command.
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
index ddbbd4afb4a2..3ac57a91ede4 100644
--- a/drivers/input/serio/parkbd.c
+++ b/drivers/input/serio/parkbd.c
@@ -168,7 +168,7 @@ static struct serio *parkbd_allocate_serio(void)
serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
serio->id.type = parkbd_mode;
- serio->write = parkbd_write,
+ serio->write = parkbd_write;
strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name));
snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name);
}
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
index 51c339182017..ec27eff6ae37 100644
--- a/drivers/input/tablet/Kconfig
+++ b/drivers/input/tablet/Kconfig
@@ -38,18 +38,6 @@ config TABLET_USB_AIPTEK
To compile this driver as a module, choose M here: the
module will be called aiptek.
-config TABLET_USB_GTCO
- tristate "GTCO CalComp/InterWrite USB Support"
- depends on USB && INPUT
- help
- Say Y here if you want to use the USB version of the GTCO
- CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support"
- (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
- (CONFIG_INPUT_EVDEV) as well.
-
- To compile this driver as a module, choose M here: the
- module will be called gtco.
-
config TABLET_USB_HANWANG
tristate "Hanwang Art Master III tablet support (USB)"
depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile
index 8279ccc18b0a..adb636430717 100644
--- a/drivers/input/tablet/Makefile
+++ b/drivers/input/tablet/Makefile
@@ -6,7 +6,6 @@
obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o
obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o
-obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o
obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
obj-$(CONFIG_TABLET_USB_PEGASUS) += pegasus_notetaker.o
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
deleted file mode 100644
index 44bb1f69b4b2..000000000000
--- a/drivers/input/tablet/gtco.c
+++ /dev/null
@@ -1,1043 +0,0 @@
-/* -*- linux-c -*-
-
-GTCO digitizer USB driver
-
-TO CHECK: Is pressure done right on report 5?
-
-Copyright (C) 2006 GTCO CalComp
-
-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; version 2
-of the License.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation, and that the name of GTCO-CalComp not be used in advertising
-or publicity pertaining to distribution of the software without specific,
-written prior permission. GTCO-CalComp makes no representations about the
-suitability of this software for any purpose. It is provided "as is"
-without express or implied warranty.
-
-GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
-INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
-EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
-CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
-DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-
-GTCO CalComp, Inc.
-7125 Riverwood Drive
-Columbia, MD 21046
-
-Jeremy Roberson jroberson@gtcocalcomp.com
-Scott Hill shill@gtcocalcomp.com
-*/
-
-
-
-/*#define DEBUG*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/bitops.h>
-
-#include <linux/usb/input.h>
-
-/* Version with a Major number of 2 is for kernel inclusion only. */
-#define GTCO_VERSION "2.00.0006"
-
-
-/* MACROS */
-
-#define VENDOR_ID_GTCO 0x078C
-#define PID_400 0x400
-#define PID_401 0x401
-#define PID_1000 0x1000
-#define PID_1001 0x1001
-#define PID_1002 0x1002
-
-/* Max size of a single report */
-#define REPORT_MAX_SIZE 10
-#define MAX_COLLECTION_LEVELS 10
-
-
-/* Bitmask whether pen is in range */
-#define MASK_INRANGE 0x20
-#define MASK_BUTTON 0x01F
-
-#define PATHLENGTH 64
-
-/* DATA STRUCTURES */
-
-/* Device table */
-static const struct usb_device_id gtco_usbid_table[] = {
- { USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
- { USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
- { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
- { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
- { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
- { }
-};
-MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
-
-
-/* Structure to hold all of our device specific stuff */
-struct gtco {
-
- struct input_dev *inputdevice; /* input device struct pointer */
- struct usb_interface *intf; /* the usb interface for this device */
- struct urb *urbinfo; /* urb for incoming reports */
- dma_addr_t buf_dma; /* dma addr of the data buffer*/
- unsigned char * buffer; /* databuffer for reports */
-
- char usbpath[PATHLENGTH];
- int openCount;
-
- /* Information pulled from Report Descriptor */
- u32 usage;
- u32 min_X;
- u32 max_X;
- u32 min_Y;
- u32 max_Y;
- s8 mintilt_X;
- s8 maxtilt_X;
- s8 mintilt_Y;
- s8 maxtilt_Y;
- u32 maxpressure;
- u32 minpressure;
-};
-
-
-
-/* Code for parsing the HID REPORT DESCRIPTOR */
-
-/* From HID1.11 spec */
-struct hid_descriptor
-{
- struct usb_descriptor_header header;
- __le16 bcdHID;
- u8 bCountryCode;
- u8 bNumDescriptors;
- u8 bDescriptorType;
- __le16 wDescriptorLength;
-} __attribute__ ((packed));
-
-
-#define HID_DESCRIPTOR_SIZE 9
-#define HID_DEVICE_TYPE 33
-#define REPORT_DEVICE_TYPE 34
-
-
-#define PREF_TAG(x) ((x)>>4)
-#define PREF_TYPE(x) ((x>>2)&0x03)
-#define PREF_SIZE(x) ((x)&0x03)
-
-#define TYPE_MAIN 0
-#define TYPE_GLOBAL 1
-#define TYPE_LOCAL 2
-#define TYPE_RESERVED 3
-
-#define TAG_MAIN_INPUT 0x8
-#define TAG_MAIN_OUTPUT 0x9
-#define TAG_MAIN_FEATURE 0xB
-#define TAG_MAIN_COL_START 0xA
-#define TAG_MAIN_COL_END 0xC
-
-#define TAG_GLOB_USAGE 0
-#define TAG_GLOB_LOG_MIN 1
-#define TAG_GLOB_LOG_MAX 2
-#define TAG_GLOB_PHYS_MIN 3
-#define TAG_GLOB_PHYS_MAX 4
-#define TAG_GLOB_UNIT_EXP 5
-#define TAG_GLOB_UNIT 6
-#define TAG_GLOB_REPORT_SZ 7
-#define TAG_GLOB_REPORT_ID 8
-#define TAG_GLOB_REPORT_CNT 9
-#define TAG_GLOB_PUSH 10
-#define TAG_GLOB_POP 11
-
-#define TAG_GLOB_MAX 12
-
-#define DIGITIZER_USAGE_TIP_PRESSURE 0x30
-#define DIGITIZER_USAGE_TILT_X 0x3D
-#define DIGITIZER_USAGE_TILT_Y 0x3E
-
-
-/*
- * This is an abbreviated parser for the HID Report Descriptor. We
- * know what devices we are talking to, so this is by no means meant
- * to be generic. We can make some safe assumptions:
- *
- * - We know there are no LONG tags, all short
- * - We know that we have no MAIN Feature and MAIN Output items
- * - We know what the IRQ reports are supposed to look like.
- *
- * The main purpose of this is to use the HID report desc to figure
- * out the mins and maxs of the fields in the IRQ reports. The IRQ
- * reports for 400/401 change slightly if the max X is bigger than 64K.
- *
- */
-static void parse_hid_report_descriptor(struct gtco *device, char * report,
- int length)
-{
- struct device *ddev = &device->intf->dev;
- int x, i = 0;
-
- /* Tag primitive vars */
- __u8 prefix;
- __u8 size;
- __u8 tag;
- __u8 type;
- __u8 data = 0;
- __u16 data16 = 0;
- __u32 data32 = 0;
-
- /* For parsing logic */
- int inputnum = 0;
- __u32 usage = 0;
-
- /* Global Values, indexed by TAG */
- __u32 globalval[TAG_GLOB_MAX];
- __u32 oldval[TAG_GLOB_MAX];
-
- /* Debug stuff */
- char maintype = 'x';
- char globtype[12];
- int indent = 0;
- char indentstr[MAX_COLLECTION_LEVELS + 1] = { 0 };
-
- dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n");
-
- /* Walk this report and pull out the info we need */
- while (i < length) {
- prefix = report[i++];
-
- /* Determine data size and save the data in the proper variable */
- size = (1U << PREF_SIZE(prefix)) >> 1;
- if (i + size > length) {
- dev_err(ddev,
- "Not enough data (need %d, have %d)\n",
- i + size, length);
- break;
- }
-
- switch (size) {
- case 1:
- data = report[i];
- break;
- case 2:
- data16 = get_unaligned_le16(&report[i]);
- break;
- case 4:
- data32 = get_unaligned_le32(&report[i]);
- break;
- }
-
- /* Skip size of data */
- i += size;
-
- /* What we do depends on the tag type */
- tag = PREF_TAG(prefix);
- type = PREF_TYPE(prefix);
- switch (type) {
- case TYPE_MAIN:
- strcpy(globtype, "");
- switch (tag) {
-
- case TAG_MAIN_INPUT:
- /*
- * The INPUT MAIN tag signifies this is
- * information from a report. We need to
- * figure out what it is and store the
- * min/max values
- */
-
- maintype = 'I';
- if (data == 2)
- strcpy(globtype, "Variable");
- else if (data == 3)
- strcpy(globtype, "Var|Const");
-
- dev_dbg(ddev, "::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits\n",
- globalval[TAG_GLOB_REPORT_ID], inputnum,
- globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
- globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
- globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
-
-
- /*
- We can assume that the first two input items
- are always the X and Y coordinates. After
- that, we look for everything else by
- local usage value
- */
- switch (inputnum) {
- case 0: /* X coord */
- dev_dbg(ddev, "GER: X Usage: 0x%x\n", usage);
- if (device->max_X == 0) {
- device->max_X = globalval[TAG_GLOB_LOG_MAX];
- device->min_X = globalval[TAG_GLOB_LOG_MIN];
- }
- break;
-
- case 1: /* Y coord */
- dev_dbg(ddev, "GER: Y Usage: 0x%x\n", usage);
- if (device->max_Y == 0) {
- device->max_Y = globalval[TAG_GLOB_LOG_MAX];
- device->min_Y = globalval[TAG_GLOB_LOG_MIN];
- }
- break;
-
- default:
- /* Tilt X */
- if (usage == DIGITIZER_USAGE_TILT_X) {
- if (device->maxtilt_X == 0) {
- device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
- device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
- }
- }
-
- /* Tilt Y */
- if (usage == DIGITIZER_USAGE_TILT_Y) {
- if (device->maxtilt_Y == 0) {
- device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
- device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
- }
- }
-
- /* Pressure */
- if (usage == DIGITIZER_USAGE_TIP_PRESSURE) {
- if (device->maxpressure == 0) {
- device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
- device->minpressure = globalval[TAG_GLOB_LOG_MIN];
- }
- }
-
- break;
- }
-
- inputnum++;
- break;
-
- case TAG_MAIN_OUTPUT:
- maintype = 'O';
- break;
-
- case TAG_MAIN_FEATURE:
- maintype = 'F';
- break;
-
- case TAG_MAIN_COL_START:
- maintype = 'S';
-
- if (indent == MAX_COLLECTION_LEVELS) {
- dev_err(ddev, "Collection level %d would exceed limit of %d\n",
- indent + 1,
- MAX_COLLECTION_LEVELS);
- break;
- }
-
- if (data == 0) {
- dev_dbg(ddev, "======>>>>>> Physical\n");
- strcpy(globtype, "Physical");
- } else
- dev_dbg(ddev, "======>>>>>>\n");
-
- /* Indent the debug output */
- indent++;
- for (x = 0; x < indent; x++)
- indentstr[x] = '-';
- indentstr[x] = 0;
-
- /* Save global tags */
- for (x = 0; x < TAG_GLOB_MAX; x++)
- oldval[x] = globalval[x];
-
- break;
-
- case TAG_MAIN_COL_END:
- maintype = 'E';
-
- if (indent == 0) {
- dev_err(ddev, "Collection level already at zero\n");
- break;
- }
-
- dev_dbg(ddev, "<<<<<<======\n");
-
- indent--;
- for (x = 0; x < indent; x++)
- indentstr[x] = '-';
- indentstr[x] = 0;
-
- /* Copy global tags back */
- for (x = 0; x < TAG_GLOB_MAX; x++)
- globalval[x] = oldval[x];
-
- break;
- }
-
- switch (size) {
- case 1:
- dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
- indentstr, tag, maintype, size, globtype, data);
- break;
-
- case 2:
- dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
- indentstr, tag, maintype, size, globtype, data16);
- break;
-
- case 4:
- dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
- indentstr, tag, maintype, size, globtype, data32);
- break;
- }
- break;
-
- case TYPE_GLOBAL:
- switch (tag) {
- case TAG_GLOB_USAGE:
- /*
- * First time we hit the global usage tag,
- * it should tell us the type of device
- */
- if (device->usage == 0)
- device->usage = data;
-
- strcpy(globtype, "USAGE");
- break;
-
- case TAG_GLOB_LOG_MIN:
- strcpy(globtype, "LOG_MIN");
- break;
-
- case TAG_GLOB_LOG_MAX:
- strcpy(globtype, "LOG_MAX");
- break;
-
- case TAG_GLOB_PHYS_MIN:
- strcpy(globtype, "PHYS_MIN");
- break;
-
- case TAG_GLOB_PHYS_MAX:
- strcpy(globtype, "PHYS_MAX");
- break;
-
- case TAG_GLOB_UNIT_EXP:
- strcpy(globtype, "EXP");
- break;
-
- case TAG_GLOB_UNIT:
- strcpy(globtype, "UNIT");
- break;
-
- case TAG_GLOB_REPORT_SZ:
- strcpy(globtype, "REPORT_SZ");
- break;
-
- case TAG_GLOB_REPORT_ID:
- strcpy(globtype, "REPORT_ID");
- /* New report, restart numbering */
- inputnum = 0;
- break;
-
- case TAG_GLOB_REPORT_CNT:
- strcpy(globtype, "REPORT_CNT");
- break;
-
- case TAG_GLOB_PUSH:
- strcpy(globtype, "PUSH");
- break;
-
- case TAG_GLOB_POP:
- strcpy(globtype, "POP");
- break;
- }
-
- /* Check to make sure we have a good tag number
- so we don't overflow array */
- if (tag < TAG_GLOB_MAX) {
- switch (size) {
- case 1:
- dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
- indentstr, globtype, tag, size, data);
- globalval[tag] = data;
- break;
-
- case 2:
- dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
- indentstr, globtype, tag, size, data16);
- globalval[tag] = data16;
- break;
-
- case 4:
- dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
- indentstr, globtype, tag, size, data32);
- globalval[tag] = data32;
- break;
- }
- } else {
- dev_dbg(ddev, "%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d\n",
- indentstr, tag, size);
- }
- break;
-
- case TYPE_LOCAL:
- switch (tag) {
- case TAG_GLOB_USAGE:
- strcpy(globtype, "USAGE");
- /* Always 1 byte */
- usage = data;
- break;
-
- case TAG_GLOB_LOG_MIN:
- strcpy(globtype, "MIN");
- break;
-
- case TAG_GLOB_LOG_MAX:
- strcpy(globtype, "MAX");
- break;
-
- default:
- strcpy(globtype, "UNKNOWN");
- break;
- }
-
- switch (size) {
- case 1:
- dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
- indentstr, tag, globtype, size, data);
- break;
-
- case 2:
- dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
- indentstr, tag, globtype, size, data16);
- break;
-
- case 4:
- dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
- indentstr, tag, globtype, size, data32);
- break;
- }
-
- break;
- }
- }
-}
-
-/* INPUT DRIVER Routines */
-
-/*
- * Called when opening the input device. This will submit the URB to
- * the usb system so we start getting reports
- */
-static int gtco_input_open(struct input_dev *inputdev)
-{
- struct gtco *device = input_get_drvdata(inputdev);
-
- device->urbinfo->dev = interface_to_usbdev(device->intf);
- if (usb_submit_urb(device->urbinfo, GFP_KERNEL))
- return -EIO;
-
- return 0;
-}
-
-/*
- * Called when closing the input device. This will unlink the URB
- */
-static void gtco_input_close(struct input_dev *inputdev)
-{
- struct gtco *device = input_get_drvdata(inputdev);
-
- usb_kill_urb(device->urbinfo);
-}
-
-
-/*
- * Setup input device capabilities. Tell the input system what this
- * device is capable of generating.
- *
- * This information is based on what is read from the HID report and
- * placed in the struct gtco structure
- *
- */
-static void gtco_setup_caps(struct input_dev *inputdev)
-{
- struct gtco *device = input_get_drvdata(inputdev);
-
- /* Which events */
- inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |
- BIT_MASK(EV_MSC);
-
- /* Misc event menu block */
- inputdev->mscbit[0] = BIT_MASK(MSC_SCAN) | BIT_MASK(MSC_SERIAL) |
- BIT_MASK(MSC_RAW);
-
- /* Absolute values based on HID report info */
- input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
- 0, 0);
- input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
- 0, 0);
-
- /* Proximity */
- input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
-
- /* Tilt & pressure */
- input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
- device->maxtilt_X, 0, 0);
- input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
- device->maxtilt_Y, 0, 0);
- input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
- device->maxpressure, 0, 0);
-
- /* Transducer */
- input_set_abs_params(inputdev, ABS_MISC, 0, 0xFF, 0, 0);
-}
-
-/* USB Routines */
-
-/*
- * URB callback routine. Called when we get IRQ reports from the
- * digitizer.
- *
- * This bridges the USB and input device worlds. It generates events
- * on the input device based on the USB reports.
- */
-static void gtco_urb_callback(struct urb *urbinfo)
-{
- struct gtco *device = urbinfo->context;
- struct input_dev *inputdev;
- int rc;
- u32 val = 0;
- char le_buffer[2];
-
- inputdev = device->inputdevice;
-
- /* Was callback OK? */
- if (urbinfo->status == -ECONNRESET ||
- urbinfo->status == -ENOENT ||
- urbinfo->status == -ESHUTDOWN) {
-
- /* Shutdown is occurring. Return and don't queue up any more */
- return;
- }
-
- if (urbinfo->status != 0) {
- /*
- * Some unknown error. Hopefully temporary. Just go and
- * requeue an URB
- */
- goto resubmit;
- }
-
- /*
- * Good URB, now process
- */
-
- /* PID dependent when we interpret the report */
- if (inputdev->id.product == PID_1000 ||
- inputdev->id.product == PID_1001 ||
- inputdev->id.product == PID_1002) {
-
- /*
- * Switch on the report ID
- * Conveniently, the reports have more information, the higher
- * the report number. We can just fall through the case
- * statements if we start with the highest number report
- */
- switch (device->buffer[0]) {
- case 5:
- /* Pressure is 9 bits */
- val = ((u16)(device->buffer[8]) << 1);
- val |= (u16)(device->buffer[7] >> 7);
- input_report_abs(inputdev, ABS_PRESSURE,
- device->buffer[8]);
-
- /* Mask out the Y tilt value used for pressure */
- device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
- fallthrough;
-
- case 4:
- /* Tilt */
- input_report_abs(inputdev, ABS_TILT_X,
- sign_extend32(device->buffer[6], 6));
-
- input_report_abs(inputdev, ABS_TILT_Y,
- sign_extend32(device->buffer[7], 6));
- fallthrough;
-
- case 2:
- case 3:
- /* Convert buttons, only 5 bits possible */
- val = (device->buffer[5]) & MASK_BUTTON;
-
- /* We don't apply any meaning to the bitmask,
- just report */
- input_event(inputdev, EV_MSC, MSC_SERIAL, val);
- fallthrough;
-
- case 1:
- /* All reports have X and Y coords in the same place */
- val = get_unaligned_le16(&device->buffer[1]);
- input_report_abs(inputdev, ABS_X, val);
-
- val = get_unaligned_le16(&device->buffer[3]);
- input_report_abs(inputdev, ABS_Y, val);
-
- /* Ditto for proximity bit */
- val = device->buffer[5] & MASK_INRANGE ? 1 : 0;
- input_report_abs(inputdev, ABS_DISTANCE, val);
-
- /* Report 1 is an exception to how we handle buttons */
- /* Buttons are an index, not a bitmask */
- if (device->buffer[0] == 1) {
-
- /*
- * Convert buttons, 5 bit index
- * Report value of index set as one,
- * the rest as 0
- */
- val = device->buffer[5] & MASK_BUTTON;
- dev_dbg(&device->intf->dev,
- "======>>>>>>REPORT 1: val 0x%X(%d)\n",
- val, val);
-
- /*
- * We don't apply any meaning to the button
- * index, just report it
- */
- input_event(inputdev, EV_MSC, MSC_SERIAL, val);
- }
- break;
-
- case 7:
- /* Menu blocks */
- input_event(inputdev, EV_MSC, MSC_SCAN,
- device->buffer[1]);
- break;
- }
- }
-
- /* Other pid class */
- if (inputdev->id.product == PID_400 ||
- inputdev->id.product == PID_401) {
-
- /* Report 2 */
- if (device->buffer[0] == 2) {
- /* Menu blocks */
- input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]);
- }
-
- /* Report 1 */
- if (device->buffer[0] == 1) {
- char buttonbyte;
-
- /* IF X max > 64K, we still a bit from the y report */
- if (device->max_X > 0x10000) {
-
- val = (u16)(((u16)(device->buffer[2] << 8)) | (u8)device->buffer[1]);
- val |= (u32)(((u8)device->buffer[3] & 0x1) << 16);
-
- input_report_abs(inputdev, ABS_X, val);
-
- le_buffer[0] = (u8)((u8)(device->buffer[3]) >> 1);
- le_buffer[0] |= (u8)((device->buffer[3] & 0x1) << 7);
-
- le_buffer[1] = (u8)(device->buffer[4] >> 1);
- le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7);
-
- val = get_unaligned_le16(le_buffer);
- input_report_abs(inputdev, ABS_Y, val);
-
- /*
- * Shift the button byte right by one to
- * make it look like the standard report
- */
- buttonbyte = device->buffer[5] >> 1;
- } else {
-
- val = get_unaligned_le16(&device->buffer[1]);
- input_report_abs(inputdev, ABS_X, val);
-
- val = get_unaligned_le16(&device->buffer[3]);
- input_report_abs(inputdev, ABS_Y, val);
-
- buttonbyte = device->buffer[5];
- }
-
- /* BUTTONS and PROXIMITY */
- val = buttonbyte & MASK_INRANGE ? 1 : 0;
- input_report_abs(inputdev, ABS_DISTANCE, val);
-
- /* Convert buttons, only 4 bits possible */
- val = buttonbyte & 0x0F;
-#ifdef USE_BUTTONS
- for (i = 0; i < 5; i++)
- input_report_key(inputdev, BTN_DIGI + i, val & (1 << i));
-#else
- /* We don't apply any meaning to the bitmask, just report */
- input_event(inputdev, EV_MSC, MSC_SERIAL, val);
-#endif
-
- /* TRANSDUCER */
- input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
- }
- }
-
- /* Everybody gets report ID's */
- input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]);
-
- /* Sync it up */
- input_sync(inputdev);
-
- resubmit:
- rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
- if (rc != 0)
- dev_err(&device->intf->dev,
- "usb_submit_urb failed rc=0x%x\n", rc);
-}
-
-/*
- * The probe routine. This is called when the kernel find the matching USB
- * vendor/product. We do the following:
- *
- * - Allocate mem for a local structure to manage the device
- * - Request a HID Report Descriptor from the device and parse it to
- * find out the device parameters
- * - Create an input device and assign it attributes
- * - Allocate an URB so the device can talk to us when the input
- * queue is open
- */
-static int gtco_probe(struct usb_interface *usbinterface,
- const struct usb_device_id *id)
-{
-
- struct gtco *gtco;
- struct input_dev *input_dev;
- struct hid_descriptor *hid_desc;
- char *report;
- int result = 0, retry;
- int error;
- struct usb_endpoint_descriptor *endpoint;
- struct usb_device *udev = interface_to_usbdev(usbinterface);
-
- /* Allocate memory for device structure */
- gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!gtco || !input_dev) {
- dev_err(&usbinterface->dev, "No more memory\n");
- error = -ENOMEM;
- goto err_free_devs;
- }
-
- /* Set pointer to the input device */
- gtco->inputdevice = input_dev;
-
- /* Save interface information */
- gtco->intf = usbinterface;
-
- /* Allocate some data for incoming reports */
- gtco->buffer = usb_alloc_coherent(udev, REPORT_MAX_SIZE,
- GFP_KERNEL, &gtco->buf_dma);
- if (!gtco->buffer) {
- dev_err(&usbinterface->dev, "No more memory for us buffers\n");
- error = -ENOMEM;
- goto err_free_devs;
- }
-
- /* Allocate URB for reports */
- gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
- if (!gtco->urbinfo) {
- dev_err(&usbinterface->dev, "Failed to allocate URB\n");
- error = -ENOMEM;
- goto err_free_buf;
- }
-
- /* Sanity check that a device has an endpoint */
- if (usbinterface->cur_altsetting->desc.bNumEndpoints < 1) {
- dev_err(&usbinterface->dev,
- "Invalid number of endpoints\n");
- error = -EINVAL;
- goto err_free_urb;
- }
-
- endpoint = &usbinterface->cur_altsetting->endpoint[0].desc;
-
- /* Some debug */
- dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting);
- dev_dbg(&usbinterface->dev, "num endpoints: %d\n", usbinterface->cur_altsetting->desc.bNumEndpoints);
- dev_dbg(&usbinterface->dev, "interface class: %d\n", usbinterface->cur_altsetting->desc.bInterfaceClass);
- dev_dbg(&usbinterface->dev, "endpoint: attribute:0x%x type:0x%x\n", endpoint->bmAttributes, endpoint->bDescriptorType);
- if (usb_endpoint_xfer_int(endpoint))
- dev_dbg(&usbinterface->dev, "endpoint: we have interrupt endpoint\n");
-
- dev_dbg(&usbinterface->dev, "interface extra len:%d\n",
- usbinterface->cur_altsetting->extralen);
-
- /*
- * Find the HID descriptor so we can find out the size of the
- * HID report descriptor
- */
- if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
- HID_DEVICE_TYPE, &hid_desc) != 0) {
- dev_err(&usbinterface->dev,
- "Can't retrieve exta USB descriptor to get hid report descriptor length\n");
- error = -EIO;
- goto err_free_urb;
- }
-
- dev_dbg(&usbinterface->dev,
- "Extra descriptor success: type:%d len:%d\n",
- hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
-
- report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL);
- if (!report) {
- dev_err(&usbinterface->dev, "No more memory for report\n");
- error = -ENOMEM;
- goto err_free_urb;
- }
-
- /* Couple of tries to get reply */
- for (retry = 0; retry < 3; retry++) {
- result = usb_control_msg(udev,
- usb_rcvctrlpipe(udev, 0),
- USB_REQ_GET_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_DIR_IN,
- REPORT_DEVICE_TYPE << 8,
- 0, /* interface */
- report,
- le16_to_cpu(hid_desc->wDescriptorLength),
- 5000); /* 5 secs */
-
- dev_dbg(&usbinterface->dev, "usb_control_msg result: %d\n", result);
- if (result == le16_to_cpu(hid_desc->wDescriptorLength)) {
- parse_hid_report_descriptor(gtco, report, result);
- break;
- }
- }
-
- kfree(report);
-
- /* If we didn't get the report, fail */
- if (result != le16_to_cpu(hid_desc->wDescriptorLength)) {
- dev_err(&usbinterface->dev,
- "Failed to get HID Report Descriptor of size: %d\n",
- hid_desc->wDescriptorLength);
- error = -EIO;
- goto err_free_urb;
- }
-
- /* Create a device file node */
- usb_make_path(udev, gtco->usbpath, sizeof(gtco->usbpath));
- strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath));
-
- /* Set Input device functions */
- input_dev->open = gtco_input_open;
- input_dev->close = gtco_input_close;
-
- /* Set input device information */
- input_dev->name = "GTCO_CalComp";
- input_dev->phys = gtco->usbpath;
-
- input_set_drvdata(input_dev, gtco);
-
- /* Now set up all the input device capabilities */
- gtco_setup_caps(input_dev);
-
- /* Set input device required ID information */
- usb_to_input_id(udev, &input_dev->id);
- input_dev->dev.parent = &usbinterface->dev;
-
- /* Setup the URB, it will be posted later on open of input device */
- usb_fill_int_urb(gtco->urbinfo,
- udev,
- usb_rcvintpipe(udev,
- endpoint->bEndpointAddress),
- gtco->buffer,
- REPORT_MAX_SIZE,
- gtco_urb_callback,
- gtco,
- endpoint->bInterval);
-
- gtco->urbinfo->transfer_dma = gtco->buf_dma;
- gtco->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- /* Save gtco pointer in USB interface gtco */
- usb_set_intfdata(usbinterface, gtco);
-
- /* All done, now register the input device */
- error = input_register_device(input_dev);
- if (error)
- goto err_free_urb;
-
- return 0;
-
- err_free_urb:
- usb_free_urb(gtco->urbinfo);
- err_free_buf:
- usb_free_coherent(udev, REPORT_MAX_SIZE,
- gtco->buffer, gtco->buf_dma);
- err_free_devs:
- input_free_device(input_dev);
- kfree(gtco);
- return error;
-}
-
-/*
- * This function is a standard USB function called when the USB device
- * is disconnected. We will get rid of the URV, de-register the input
- * device, and free up allocated memory
- */
-static void gtco_disconnect(struct usb_interface *interface)
-{
- /* Grab private device ptr */
- struct gtco *gtco = usb_get_intfdata(interface);
- struct usb_device *udev = interface_to_usbdev(interface);
-
- /* Now reverse all the registration stuff */
- if (gtco) {
- input_unregister_device(gtco->inputdevice);
- usb_kill_urb(gtco->urbinfo);
- usb_free_urb(gtco->urbinfo);
- usb_free_coherent(udev, REPORT_MAX_SIZE,
- gtco->buffer, gtco->buf_dma);
- kfree(gtco);
- }
-
- dev_info(&interface->dev, "gtco driver disconnected\n");
-}
-
-/* STANDARD MODULE LOAD ROUTINES */
-
-static struct usb_driver gtco_driverinfo_table = {
- .name = "gtco",
- .id_table = gtco_usbid_table,
- .probe = gtco_probe,
- .disconnect = gtco_disconnect,
-};
-
-module_usb_driver(gtco_driverinfo_table);
-
-MODULE_DESCRIPTION("GTCO digitizer USB driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index 9b652f61837f..08f5372f0bfd 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -281,12 +281,14 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
req->xfer[1].tx_buf = &req->ref_on;
req->xfer[1].len = 2;
- req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+ req->xfer[1].delay.value = ts->vref_delay_usecs;
+ req->xfer[1].delay.unit = SPI_DELAY_UNIT_USECS;
req->xfer[1].cs_change = 1;
req->xfer[2].tx_buf = &req->command;
req->xfer[2].len = 2;
- req->xfer[2].delay_usecs = ts->vref_delay_usecs;
+ req->xfer[2].delay.value = ts->vref_delay_usecs;
+ req->xfer[2].delay.unit = SPI_DELAY_UNIT_USECS;
req->xfer[2].cs_change = 1;
req->xfer[3].rx_buf = &req->sample;
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 556a2af46e18..e850853328f1 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -306,7 +306,7 @@ static int __maybe_unused ad7879_suspend(struct device *dev)
mutex_lock(&ts->input->mutex);
- if (!ts->suspended && !ts->disabled && ts->input->users)
+ if (!ts->suspended && !ts->disabled && input_device_enabled(ts->input))
__ad7879_disable(ts);
ts->suspended = true;
@@ -322,7 +322,7 @@ static int __maybe_unused ad7879_resume(struct device *dev)
mutex_lock(&ts->input->mutex);
- if (ts->suspended && !ts->disabled && ts->input->users)
+ if (ts->suspended && !ts->disabled && input_device_enabled(ts->input))
__ad7879_enable(ts);
ts->suspended = false;
@@ -339,7 +339,7 @@ static void ad7879_toggle(struct ad7879 *ts, bool disable)
{
mutex_lock(&ts->input->mutex);
- if (!ts->suspended && ts->input->users != 0) {
+ if (!ts->suspended && input_device_enabled(ts->input)) {
if (disable) {
if (ts->disabled)
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index f2dc2c8ab5ec..a703870ca7bd 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -32,7 +32,7 @@
#include <linux/spi/ads7846.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-#include <asm/irq.h>
+#include <asm/unaligned.h>
/*
* This code has been heavily tested on a Nokia 770, and lightly
@@ -62,19 +62,26 @@
/* this driver doesn't aim at the peak continuous sample rate */
#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
-struct ts_event {
+struct ads7846_buf {
+ u8 cmd;
/*
- * For portability, we can't read 12 bit values using SPI (which
- * would make the controller deliver them as native byte order u16
- * with msbs zeroed). Instead, we read them as two 8-bit values,
- * *** WHICH NEED BYTESWAPPING *** and range adjustment.
+ * This union is a temporary hack. The driver does an in-place
+ * endianness conversion. This will be cleaned up in the next
+ * patch.
*/
- u16 x;
- u16 y;
- u16 z1, z2;
- bool ignore;
- u8 x_buf[3];
- u8 y_buf[3];
+ union {
+ __be16 data_be16;
+ u16 data;
+ };
+} __packed;
+
+
+struct ts_event {
+ bool ignore;
+ struct ads7846_buf x;
+ struct ads7846_buf y;
+ struct ads7846_buf z1;
+ struct ads7846_buf z2;
};
/*
@@ -83,11 +90,12 @@ struct ts_event {
* systems where main memory is not DMA-coherent (most non-x86 boards).
*/
struct ads7846_packet {
- u8 read_x, read_y, read_z1, read_z2, pwrdown;
- u16 dummy; /* for the pwrdown read */
- struct ts_event tc;
- /* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
- u8 read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
+ 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;
+ struct ads7846_buf pwrdown_cmd;
};
struct ads7846 {
@@ -199,6 +207,26 @@ struct ads7846 {
#define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
+static int get_pendown_state(struct ads7846 *ts)
+{
+ if (ts->get_pendown_state)
+ return ts->get_pendown_state();
+
+ return !gpio_get_value(ts->gpio_pendown);
+}
+
+static void ads7846_report_pen_up(struct ads7846 *ts)
+{
+ struct input_dev *input = ts->input;
+
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ input_sync(input);
+
+ ts->pendown = false;
+ dev_vdbg(&ts->spi->dev, "UP\n");
+}
+
/* Must be called with ts->lock held */
static void ads7846_stop(struct ads7846 *ts)
{
@@ -215,6 +243,10 @@ static void ads7846_stop(struct ads7846 *ts)
static void ads7846_restart(struct ads7846 *ts)
{
if (!ts->disabled && !ts->suspended) {
+ /* Check if pen was released since last stop */
+ if (ts->pendown && !get_pendown_state(ts))
+ ads7846_report_pen_up(ts);
+
/* Tell IRQ thread that it may poll the device. */
ts->stopped = false;
mb();
@@ -411,7 +443,7 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)
if (status == 0) {
/* BE12 value, then padding */
- status = be16_to_cpu(*((u16 *)&req->sample[1]));
+ status = get_unaligned_be16(&req->sample[1]);
status = status >> 3;
status &= 0x0fff;
}
@@ -481,7 +513,7 @@ SHOW(in1_input, vbatt, vbatt_adjust)
static umode_t ads7846_is_visible(struct kobject *kobj, struct attribute *attr,
int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct ads7846 *ts = dev_get_drvdata(dev);
if (ts->model == 7843 && index < 2) /* in0, in1 */
@@ -606,14 +638,6 @@ static const struct attribute_group ads784x_attr_group = {
/*--------------------------------------------------------------------------*/
-static int get_pendown_state(struct ads7846 *ts)
-{
- if (ts->get_pendown_state)
- return ts->get_pendown_state();
-
- return !gpio_get_value(ts->gpio_pendown);
-}
-
static void null_wait_for_sync(void)
{
}
@@ -670,16 +694,9 @@ static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
int value;
struct spi_transfer *t =
list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+ struct ads7846_buf *buf = t->rx_buf;
- if (ts->model == 7845) {
- value = be16_to_cpup((__be16 *)&(((char *)t->rx_buf)[1]));
- } else {
- /*
- * adjust: on-wire is a must-ignore bit, a BE12 value, then
- * padding; built from two 8 bit values written msb-first.
- */
- value = be16_to_cpup((__be16 *)t->rx_buf);
- }
+ value = be16_to_cpup(&buf->data_be16);
/* enforce ADC output is 12 bits width */
return (value >> 3) & 0xfff;
@@ -689,8 +706,9 @@ static void ads7846_update_value(struct spi_message *m, int val)
{
struct spi_transfer *t =
list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+ struct ads7846_buf *buf = t->rx_buf;
- *(u16 *)t->rx_buf = val;
+ buf->data = val;
}
static void ads7846_read_state(struct ads7846 *ts)
@@ -758,16 +776,14 @@ static void ads7846_report_state(struct ads7846 *ts)
* from on-the-wire format as part of debouncing to get stable
* readings.
*/
+ x = packet->tc.x.data;
+ y = packet->tc.y.data;
if (ts->model == 7845) {
- x = *(u16 *)packet->tc.x_buf;
- y = *(u16 *)packet->tc.y_buf;
z1 = 0;
z2 = 0;
} else {
- x = packet->tc.x;
- y = packet->tc.y;
- z1 = packet->tc.z1;
- z2 = packet->tc.z2;
+ z1 = packet->tc.z1.data;
+ z2 = packet->tc.z2.data;
}
/* range filtering */
@@ -786,10 +802,11 @@ static void ads7846_report_state(struct ads7846 *ts)
/* compute touch pressure resistance using equation #2 */
Rt = z2;
Rt -= z1;
- Rt *= x;
Rt *= ts->x_plate_ohms;
+ Rt = DIV_ROUND_CLOSEST(Rt, 16);
+ Rt *= x;
Rt /= z1;
- Rt = (Rt + 2047) >> 12;
+ Rt = DIV_ROUND_CLOSEST(Rt, 256);
} else {
Rt = 0;
}
@@ -868,16 +885,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
msecs_to_jiffies(TS_POLL_PERIOD));
}
- if (ts->pendown && !ts->stopped) {
- struct input_dev *input = ts->input;
-
- input_report_key(input, BTN_TOUCH, 0);
- input_report_abs(input, ABS_PRESSURE, 0);
- input_sync(input);
-
- ts->pendown = false;
- dev_vdbg(&ts->spi->dev, "UP\n");
- }
+ if (ts->pendown && !ts->stopped)
+ ads7846_report_pen_up(ts);
return IRQ_HANDLED;
}
@@ -992,26 +1001,11 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
spi_message_init(m);
m->context = ts;
- if (ts->model == 7845) {
- packet->read_y_cmd[0] = READ_Y(vref);
- packet->read_y_cmd[1] = 0;
- packet->read_y_cmd[2] = 0;
- x->tx_buf = &packet->read_y_cmd[0];
- x->rx_buf = &packet->tc.y_buf[0];
- x->len = 3;
- spi_message_add_tail(x, m);
- } else {
- /* y- still on; turn on only y+ (and ADC) */
- packet->read_y = READ_Y(vref);
- x->tx_buf = &packet->read_y;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.y;
- x->len = 2;
- spi_message_add_tail(x, m);
- }
+ 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);
/*
* The first sample after switching drivers can be low quality;
@@ -1021,15 +1015,11 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
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;
- x->len = 1;
- spi_message_add_tail(x, m);
- x++;
+ x->tx_buf = &packet->read_y_cmd;
x->rx_buf = &packet->tc.y;
- x->len = 2;
+ x->len = 3;
spi_message_add_tail(x, m);
}
@@ -1038,28 +1028,13 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
spi_message_init(m);
m->context = ts;
- if (ts->model == 7845) {
- x++;
- packet->read_x_cmd[0] = READ_X(vref);
- packet->read_x_cmd[1] = 0;
- packet->read_x_cmd[2] = 0;
- x->tx_buf = &packet->read_x_cmd[0];
- x->rx_buf = &packet->tc.x_buf[0];
- x->len = 3;
- spi_message_add_tail(x, m);
- } else {
- /* turn y- off, x+ on, then leave in lowpower */
- x++;
- packet->read_x = READ_X(vref);
- x->tx_buf = &packet->read_x;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.x;
- x->len = 2;
- spi_message_add_tail(x, m);
- }
+ /* 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;
+ spi_message_add_tail(x, m);
/* ... maybe discard first sample ... */
if (pdata->settle_delay_usecs) {
@@ -1067,13 +1042,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
x->delay.unit = SPI_DELAY_UNIT_USECS;
x++;
- x->tx_buf = &packet->read_x;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
+ x->tx_buf = &packet->read_x_cmd;
x->rx_buf = &packet->tc.x;
- x->len = 2;
+ x->len = 3;
spi_message_add_tail(x, m);
}
@@ -1085,14 +1056,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
m->context = ts;
x++;
- packet->read_z1 = READ_Z1(vref);
- x->tx_buf = &packet->read_z1;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
+ packet->read_z1_cmd.cmd = READ_Z1(vref);
+ x->tx_buf = &packet->read_z1_cmd;
x->rx_buf = &packet->tc.z1;
- x->len = 2;
+ x->len = 3;
spi_message_add_tail(x, m);
/* ... maybe discard first sample ... */
@@ -1101,13 +1068,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
x->delay.unit = SPI_DELAY_UNIT_USECS;
x++;
- x->tx_buf = &packet->read_z1;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
+ x->tx_buf = &packet->read_z1_cmd;
x->rx_buf = &packet->tc.z1;
- x->len = 2;
+ x->len = 3;
spi_message_add_tail(x, m);
}
@@ -1117,14 +1080,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
m->context = ts;
x++;
- packet->read_z2 = READ_Z2(vref);
- x->tx_buf = &packet->read_z2;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
+ packet->read_z2_cmd.cmd = READ_Z2(vref);
+ x->tx_buf = &packet->read_z2_cmd;
x->rx_buf = &packet->tc.z2;
- x->len = 2;
+ x->len = 3;
spi_message_add_tail(x, m);
/* ... maybe discard first sample ... */
@@ -1133,13 +1092,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
x->delay.unit = SPI_DELAY_UNIT_USECS;
x++;
- x->tx_buf = &packet->read_z2;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
+ x->tx_buf = &packet->read_z2_cmd;
x->rx_buf = &packet->tc.z2;
- x->len = 2;
+ x->len = 3;
spi_message_add_tail(x, m);
}
}
@@ -1150,24 +1105,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
spi_message_init(m);
m->context = ts;
- if (ts->model == 7845) {
- x++;
- packet->pwrdown_cmd[0] = PWRDOWN;
- packet->pwrdown_cmd[1] = 0;
- packet->pwrdown_cmd[2] = 0;
- x->tx_buf = &packet->pwrdown_cmd[0];
- x->len = 3;
- } else {
- x++;
- packet->pwrdown = PWRDOWN;
- x->tx_buf = &packet->pwrdown;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->dummy;
- x->len = 2;
- }
+ x++;
+ packet->pwrdown_cmd.cmd = PWRDOWN;
+ x->tx_buf = &packet->pwrdown_cmd;
+ x->len = 3;
CS_CHANGE(*x);
spi_message_add_tail(x, m);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b6f75367a284..383a848eb601 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -24,6 +24,7 @@
#include <linux/of.h>
#include <linux/property.h>
#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <asm/unaligned.h>
#include <media/v4l2-device.h>
@@ -309,6 +310,7 @@ struct mxt_data {
u8 multitouch;
struct t7_config t7_cfg;
struct mxt_dbg dbg;
+ struct regulator_bulk_data regulators[2];
struct gpio_desc *reset_gpio;
bool use_retrigen_workaround;
@@ -606,7 +608,6 @@ recheck:
static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
{
- int ret;
u8 buf[2];
if (unlock) {
@@ -617,11 +618,7 @@ static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
buf[1] = 0x01;
}
- ret = mxt_bootloader_write(data, buf, 2);
- if (ret)
- return ret;
-
- return 0;
+ return mxt_bootloader_write(data, buf, sizeof(buf));
}
static int __mxt_read_reg(struct i2c_client *client,
@@ -3134,8 +3131,24 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (error)
return error;
+ /*
+ * VDDA is the analog voltage supply 2.57..3.47 V
+ * VDD is the digital voltage supply 1.71..3.47 V
+ */
+ data->regulators[0].supply = "vdda";
+ data->regulators[1].supply = "vdd";
+ error = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (error) {
+ if (error != -EPROBE_DEFER)
+ dev_err(&client->dev, "Failed to get regulators %d\n",
+ error);
+ return error;
+ }
+
+ /* Request the RESET line as asserted so we go into reset */
data->reset_gpio = devm_gpiod_get_optional(&client->dev,
- "reset", GPIOD_OUT_LOW);
+ "reset", GPIOD_OUT_HIGH);
if (IS_ERR(data->reset_gpio)) {
error = PTR_ERR(data->reset_gpio);
dev_err(&client->dev, "Failed to get reset gpio: %d\n", error);
@@ -3152,15 +3165,29 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
disable_irq(client->irq);
+ error = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (error) {
+ dev_err(&client->dev, "failed to enable regulators: %d\n",
+ error);
+ return error;
+ }
+ /*
+ * The device takes 40ms to come up after power-on according
+ * to the mXT224 datasheet, page 13.
+ */
+ msleep(MXT_BACKUP_TIME);
+
if (data->reset_gpio) {
+ /* Wait a while and then de-assert the RESET GPIO line */
msleep(MXT_RESET_GPIO_TIME);
- gpiod_set_value(data->reset_gpio, 1);
+ gpiod_set_value(data->reset_gpio, 0);
msleep(MXT_RESET_INVALID_CHG);
}
error = mxt_initialize(data);
if (error)
- return error;
+ goto err_disable_regulators;
error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
if (error) {
@@ -3174,6 +3201,9 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
err_free_object:
mxt_free_input_device(data);
mxt_free_object_table(data);
+err_disable_regulators:
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators),
+ data->regulators);
return error;
}
@@ -3185,6 +3215,8 @@ static int mxt_remove(struct i2c_client *client)
sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
mxt_free_input_device(data);
mxt_free_object_table(data);
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators),
+ data->regulators);
return 0;
}
@@ -3200,7 +3232,7 @@ static int __maybe_unused mxt_suspend(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
mxt_stop(data);
mutex_unlock(&input_dev->mutex);
@@ -3223,7 +3255,7 @@ static int __maybe_unused mxt_resume(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
mxt_start(data);
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c
index 8e9f3b7b8180..c33e63ca6142 100644
--- a/drivers/input/touchscreen/auo-pixcir-ts.c
+++ b/drivers/input/touchscreen/auo-pixcir-ts.c
@@ -414,7 +414,7 @@ static int __maybe_unused auo_pixcir_suspend(struct device *dev)
*/
if (device_may_wakeup(&client->dev)) {
/* need to start device if not open, to be wakeup source */
- if (!input->users) {
+ if (!input_device_enabled(input)) {
ret = auo_pixcir_start(ts);
if (ret)
goto unlock;
@@ -422,7 +422,7 @@ static int __maybe_unused auo_pixcir_suspend(struct device *dev)
enable_irq_wake(client->irq);
ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP);
- } else if (input->users) {
+ } else if (input_device_enabled(input)) {
ret = auo_pixcir_stop(ts);
}
@@ -445,14 +445,14 @@ static int __maybe_unused auo_pixcir_resume(struct device *dev)
disable_irq_wake(client->irq);
/* need to stop device if it was not open on suspend */
- if (!input->users) {
+ if (!input_device_enabled(input)) {
ret = auo_pixcir_stop(ts);
if (ret)
goto unlock;
}
/* device wakes automatically from SLEEP */
- } else if (input->users) {
+ } else if (input_device_enabled(input)) {
ret = auo_pixcir_start(ts);
}
diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c
index 49a8d4bbca3a..341925edb8e6 100644
--- a/drivers/input/touchscreen/bu21029_ts.c
+++ b/drivers/input/touchscreen/bu21029_ts.c
@@ -430,7 +430,7 @@ static int __maybe_unused bu21029_suspend(struct device *dev)
if (!device_may_wakeup(dev)) {
mutex_lock(&bu21029->in_dev->mutex);
- if (bu21029->in_dev->users)
+ if (input_device_enabled(bu21029->in_dev))
bu21029_stop_chip(bu21029->in_dev);
mutex_unlock(&bu21029->in_dev->mutex);
}
@@ -445,7 +445,7 @@ static int __maybe_unused bu21029_resume(struct device *dev)
if (!device_may_wakeup(dev)) {
mutex_lock(&bu21029->in_dev->mutex);
- if (bu21029->in_dev->users)
+ if (input_device_enabled(bu21029->in_dev))
bu21029_start_chip(bu21029->in_dev);
mutex_unlock(&bu21029->in_dev->mutex);
}
diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c
index d91d2fd78649..f2fb41fb031e 100644
--- a/drivers/input/touchscreen/chipone_icn8318.c
+++ b/drivers/input/touchscreen/chipone_icn8318.c
@@ -154,7 +154,7 @@ static int icn8318_suspend(struct device *dev)
struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&data->input->mutex);
- if (data->input->users)
+ if (input_device_enabled(data->input))
icn8318_stop(data->input);
mutex_unlock(&data->input->mutex);
@@ -166,7 +166,7 @@ static int icn8318_resume(struct device *dev)
struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&data->input->mutex);
- if (data->input->users)
+ if (input_device_enabled(data->input))
icn8318_start(data->input);
mutex_unlock(&data->input->mutex);
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
index 02a73d9a4def..dccbcb942fe5 100644
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ b/drivers/input/touchscreen/cyttsp4_core.c
@@ -30,6 +30,20 @@
#define CY_CORE_STARTUP_RETRY_COUNT 3
+static const char * const cyttsp4_tch_abs_string[] = {
+ [CY_TCH_X] = "X",
+ [CY_TCH_Y] = "Y",
+ [CY_TCH_P] = "P",
+ [CY_TCH_T] = "T",
+ [CY_TCH_E] = "E",
+ [CY_TCH_O] = "O",
+ [CY_TCH_W] = "W",
+ [CY_TCH_MAJ] = "MAJ",
+ [CY_TCH_MIN] = "MIN",
+ [CY_TCH_OR] = "OR",
+ [CY_TCH_NUM_ABS] = "INVALID"
+};
+
static const u8 ldr_exit[] = {
0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17
};
diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h
index f3e444359440..6262f6e45075 100644
--- a/drivers/input/touchscreen/cyttsp4_core.h
+++ b/drivers/input/touchscreen/cyttsp4_core.h
@@ -233,20 +233,6 @@ enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */
CY_TCH_NUM_ABS
};
-static const char * const cyttsp4_tch_abs_string[] = {
- [CY_TCH_X] = "X",
- [CY_TCH_Y] = "Y",
- [CY_TCH_P] = "P",
- [CY_TCH_T] = "T",
- [CY_TCH_E] = "E",
- [CY_TCH_O] = "O",
- [CY_TCH_W] = "W",
- [CY_TCH_MAJ] = "MAJ",
- [CY_TCH_MIN] = "MIN",
- [CY_TCH_OR] = "OR",
- [CY_TCH_NUM_ABS] = "INVALID"
-};
-
struct cyttsp4_touch {
int abs[CY_TCH_NUM_ABS];
};
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index 697aa2c158f7..73c854f35f33 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -479,7 +479,7 @@ static int __maybe_unused cyttsp_suspend(struct device *dev)
mutex_lock(&ts->input->mutex);
- if (ts->input->users) {
+ if (input_device_enabled(ts->input)) {
retval = cyttsp_disable(ts);
if (retval == 0)
ts->suspended = true;
@@ -496,7 +496,7 @@ static int __maybe_unused cyttsp_resume(struct device *dev)
mutex_lock(&ts->input->mutex);
- if (ts->input->users)
+ if (input_device_enabled(ts->input))
cyttsp_enable(ts);
ts->suspended = false;
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 6ff81d48da86..2eefbc2485bc 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -69,6 +69,9 @@
#define EDT_RAW_DATA_RETRIES 100
#define EDT_RAW_DATA_DELAY 1000 /* usec */
+#define EDT_DEFAULT_NUM_X 1024
+#define EDT_DEFAULT_NUM_Y 1024
+
enum edt_pmode {
EDT_PMODE_NOT_SUPPORTED,
EDT_PMODE_HIBERNATE,
@@ -977,8 +980,7 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev,
}
}
-static void
-edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
+static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
{
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
@@ -997,21 +999,17 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
if (reg_addr->reg_report_rate != NO_REGISTER)
tsdata->report_rate = edt_ft5x06_register_read(tsdata,
reg_addr->reg_report_rate);
- if (tsdata->version == EDT_M06 ||
- tsdata->version == EDT_M09 ||
- tsdata->version == EDT_M12) {
+ tsdata->num_x = EDT_DEFAULT_NUM_X;
+ if (reg_addr->reg_num_x != NO_REGISTER)
tsdata->num_x = edt_ft5x06_register_read(tsdata,
reg_addr->reg_num_x);
+ tsdata->num_y = EDT_DEFAULT_NUM_Y;
+ if (reg_addr->reg_num_y != NO_REGISTER)
tsdata->num_y = edt_ft5x06_register_read(tsdata,
reg_addr->reg_num_y);
- } else {
- tsdata->num_x = -1;
- tsdata->num_y = -1;
- }
}
-static void
-edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
+static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
{
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
@@ -1041,22 +1039,25 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
case EV_FT:
reg_addr->reg_threshold = EV_REGISTER_THRESHOLD;
+ reg_addr->reg_report_rate = NO_REGISTER;
reg_addr->reg_gain = EV_REGISTER_GAIN;
reg_addr->reg_offset = NO_REGISTER;
reg_addr->reg_offset_x = EV_REGISTER_OFFSET_X;
reg_addr->reg_offset_y = EV_REGISTER_OFFSET_Y;
reg_addr->reg_num_x = NO_REGISTER;
reg_addr->reg_num_y = NO_REGISTER;
- reg_addr->reg_report_rate = NO_REGISTER;
break;
case GENERIC_FT:
/* this is a guesswork */
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
+ reg_addr->reg_report_rate = NO_REGISTER;
reg_addr->reg_gain = M09_REGISTER_GAIN;
reg_addr->reg_offset = M09_REGISTER_OFFSET;
reg_addr->reg_offset_x = NO_REGISTER;
reg_addr->reg_offset_y = NO_REGISTER;
+ reg_addr->reg_num_x = NO_REGISTER;
+ reg_addr->reg_num_y = NO_REGISTER;
break;
}
}
@@ -1195,20 +1196,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
- if (tsdata->version == EDT_M06 ||
- tsdata->version == EDT_M09 ||
- tsdata->version == EDT_M12) {
- input_set_abs_params(input, ABS_MT_POSITION_X,
- 0, tsdata->num_x * 64 - 1, 0, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y,
- 0, tsdata->num_y * 64 - 1, 0, 0);
- } else {
- /* Unknown maximum values. Specify via devicetree */
- input_set_abs_params(input, ABS_MT_POSITION_X,
- 0, 65535, 0, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y,
- 0, 65535, 0, 0);
- }
+ input_set_abs_params(input, ABS_MT_POSITION_X,
+ 0, tsdata->num_x * 64 - 1, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y,
+ 0, tsdata->num_y * 64 - 1, 0, 0);
touchscreen_parse_properties(input, true, &tsdata->prop);
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 2e1404cd09ec..a639ba7e56ea 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -241,7 +241,7 @@ static int __maybe_unused eeti_ts_suspend(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
eeti_ts_stop(eeti);
mutex_unlock(&input_dev->mutex);
@@ -263,7 +263,7 @@ static int __maybe_unused eeti_ts_resume(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
eeti_ts_start(eeti);
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c
index eadd389cf81f..2d01a8cbfcc6 100644
--- a/drivers/input/touchscreen/ektf2127.c
+++ b/drivers/input/touchscreen/ektf2127.c
@@ -28,6 +28,7 @@
#define EKTF2127_RESPONSE 0x52
#define EKTF2127_REQUEST 0x53
#define EKTF2127_HELLO 0x55
+#define EKTF2127_REPORT2 0x5a
#define EKTF2127_REPORT 0x5d
#define EKTF2127_CALIB_DONE 0x66
@@ -95,6 +96,29 @@ static void ektf2127_report_event(struct ektf2127_ts *ts, const u8 *buf)
input_sync(ts->input);
}
+static void ektf2127_report2_contact(struct ektf2127_ts *ts, int slot,
+ const u8 *buf, bool active)
+{
+ input_mt_slot(ts->input, slot);
+ input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, active);
+
+ if (active) {
+ int x = (buf[0] & 0xf0) << 4 | buf[1];
+ int y = (buf[0] & 0x0f) << 8 | buf[2];
+
+ touchscreen_report_pos(ts->input, &ts->prop, x, y, true);
+ }
+}
+
+static void ektf2127_report2_event(struct ektf2127_ts *ts, const u8 *buf)
+{
+ ektf2127_report2_contact(ts, 0, &buf[1], !!(buf[7] & 2));
+ ektf2127_report2_contact(ts, 1, &buf[4], !!(buf[7] & 4));
+
+ input_mt_sync_frame(ts->input);
+ input_sync(ts->input);
+}
+
static irqreturn_t ektf2127_irq(int irq, void *dev_id)
{
struct ektf2127_ts *ts = dev_id;
@@ -113,6 +137,10 @@ static irqreturn_t ektf2127_irq(int irq, void *dev_id)
ektf2127_report_event(ts, buf);
break;
+ case EKTF2127_REPORT2:
+ ektf2127_report2_event(ts, buf);
+ break;
+
case EKTF2127_NOISE:
if (buf[1] == EKTF2127_ENV_NOISY)
dev_dbg(dev, "Environment is electrically noisy\n");
@@ -154,7 +182,7 @@ static int __maybe_unused ektf2127_suspend(struct device *dev)
struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&ts->input->mutex);
- if (ts->input->users)
+ if (input_device_enabled(ts->input))
ektf2127_stop(ts->input);
mutex_unlock(&ts->input->mutex);
@@ -166,7 +194,7 @@ static int __maybe_unused ektf2127_resume(struct device *dev)
struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&ts->input->mutex);
- if (ts->input->users)
+ if (input_device_enabled(ts->input))
ektf2127_start(ts->input);
mutex_unlock(&ts->input->mutex);
@@ -305,6 +333,7 @@ static int ektf2127_probe(struct i2c_client *client,
#ifdef CONFIG_OF
static const struct of_device_id ektf2127_of_match[] = {
{ .compatible = "elan,ektf2127" },
+ { .compatible = "elan,ektf2132" },
{}
};
MODULE_DEVICE_TABLE(of, ektf2127_of_match);
@@ -312,6 +341,7 @@ MODULE_DEVICE_TABLE(of, ektf2127_of_match);
static const struct i2c_device_id ektf2127_i2c_id[] = {
{ "ektf2127", 0 },
+ { "ektf2132", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id);
@@ -327,6 +357,6 @@ static struct i2c_driver ektf2127_driver = {
};
module_i2c_driver(ektf2127_driver);
-MODULE_DESCRIPTION("ELAN eKTF2127 I2C Touchscreen Driver");
+MODULE_DESCRIPTION("ELAN eKTF2127/eKTF2132 I2C Touchscreen Driver");
MODULE_AUTHOR("Michel Verlaan, Siebren Vroegindeweij");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index 50c348297e38..d51cb910fba1 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -82,7 +82,7 @@
#define HEADER_REPORT_10_FINGER 0x62
-/* Header (4 bytes) plus 3 fill 10-finger packets */
+/* Header (4 bytes) plus 3 full 10-finger packets */
#define MAX_PACKET_SIZE 169
#define BOOT_TIME_DELAY_MS 50
@@ -97,6 +97,10 @@
#define E_INFO_PHY_SCAN 0xD7
#define E_INFO_PHY_DRIVER 0xD8
+/* FW write command, 0x54 0x?? 0x0, 0x01 */
+#define E_POWER_STATE_SLEEP 0x50
+#define E_POWER_STATE_RESUME 0x58
+
#define MAX_RETRIES 3
#define MAX_FW_UPDATE_RETRIES 30
@@ -269,8 +273,8 @@ static int elants_i2c_calibrate(struct elants_data *ts)
{
struct i2c_client *client = ts->client;
int ret, error;
- static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A };
- static const u8 rek[] = { 0x54, 0x29, 0x00, 0x01 };
+ static const u8 w_flashkey[] = { CMD_HEADER_WRITE, 0xC0, 0xE1, 0x5A };
+ static const u8 rek[] = { CMD_HEADER_WRITE, 0x29, 0x00, 0x01 };
static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 };
disable_irq(client->irq);
@@ -1388,7 +1392,9 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct elants_data *ts = i2c_get_clientdata(client);
- const u8 set_sleep_cmd[] = { 0x54, 0x50, 0x00, 0x01 };
+ const u8 set_sleep_cmd[] = {
+ CMD_HEADER_WRITE, E_POWER_STATE_SLEEP, 0x00, 0x01
+ };
int retry_cnt;
int error;
@@ -1425,7 +1431,9 @@ static int __maybe_unused elants_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct elants_data *ts = i2c_get_clientdata(client);
- const u8 set_active_cmd[] = { 0x54, 0x58, 0x00, 0x01 };
+ const u8 set_active_cmd[] = {
+ CMD_HEADER_WRITE, E_POWER_STATE_RESUME, 0x00, 0x01
+ };
int retry_cnt;
int error;
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 6612f9e2d7e8..19765f1c04f7 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -576,6 +576,7 @@ static void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts)
*
* @ts: goodix_ts_data pointer
* @cfg: firmware config data
+ * @len: config data length
*/
static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
{
@@ -594,6 +595,7 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
*
* @ts: goodix_ts_data pointer
* @cfg: config firmware to write to device
+ * @len: config data length
*/
static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
{
@@ -1168,7 +1170,8 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
/**
* goodix_config_cb - Callback to finish device init
*
- * @ts: our goodix_ts_data pointer
+ * @cfg: firmware config
+ * @ctx: our goodix_ts_data pointer
*
* request_firmware_wait callback that finishes
* initialization of the device.
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index cd369f9ac5e6..2d4facf70cdb 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -304,11 +304,10 @@ static irqreturn_t adc_irq_fn(int irq, void *dev_id)
{
struct imx6ul_tsc *tsc = dev_id;
u32 coco;
- u32 value;
coco = readl(tsc->adc_regs + REG_ADC_HS);
if (coco & 0x01) {
- value = readl(tsc->adc_regs + REG_ADC_R0);
+ readl(tsc->adc_regs + REG_ADC_R0);
complete(&tsc->completion);
}
@@ -521,7 +520,7 @@ static int __maybe_unused imx6ul_tsc_suspend(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
imx6ul_tsc_stop(tsc);
mutex_unlock(&input_dev->mutex);
@@ -538,7 +537,7 @@ static int __maybe_unused imx6ul_tsc_resume(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
retval = imx6ul_tsc_start(tsc);
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/touchscreen/ipaq-micro-ts.c b/drivers/input/touchscreen/ipaq-micro-ts.c
index 5c3977e1af6f..0eb5689fe65f 100644
--- a/drivers/input/touchscreen/ipaq-micro-ts.c
+++ b/drivers/input/touchscreen/ipaq-micro-ts.c
@@ -135,7 +135,7 @@ static int __maybe_unused micro_ts_resume(struct device *dev)
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
micro_ts_toggle_receive(ts, true);
mutex_unlock(&input->mutex);
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
index 3162b68f7374..4fd21bc3ce0f 100644
--- a/drivers/input/touchscreen/iqs5xx.c
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -1017,7 +1017,7 @@ static int __maybe_unused iqs5xx_suspend(struct device *dev)
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
error = iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
mutex_unlock(&input->mutex);
@@ -1036,7 +1036,7 @@ static int __maybe_unused iqs5xx_resume(struct device *dev)
mutex_lock(&input->mutex);
- if (input->users)
+ if (input_device_enabled(input))
error = iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
mutex_unlock(&input->mutex);
diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c
index b2cd9472e2d1..b51450b3d943 100644
--- a/drivers/input/touchscreen/lpc32xx_ts.c
+++ b/drivers/input/touchscreen/lpc32xx_ts.c
@@ -334,7 +334,7 @@ static int lpc32xx_ts_suspend(struct device *dev)
*/
mutex_lock(&input->mutex);
- if (input->users) {
+ if (input_device_enabled(input)) {
if (device_may_wakeup(dev))
enable_irq_wake(tsc->irq);
else
@@ -353,7 +353,7 @@ static int lpc32xx_ts_resume(struct device *dev)
mutex_lock(&input->mutex);
- if (input->users) {
+ if (input_device_enabled(input)) {
if (device_may_wakeup(dev))
disable_irq_wake(tsc->irq);
else
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index f67efdd040b2..c0050044a5a9 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -1256,7 +1256,7 @@ static int mip4_execute_fw_update(struct mip4_ts *ts, const struct firmware *fw)
if (error)
return error;
- if (ts->input->users) {
+ if (input_device_enabled(ts->input)) {
disable_irq(ts->client->irq);
} else {
error = mip4_power_on(ts);
@@ -1276,7 +1276,7 @@ static int mip4_execute_fw_update(struct mip4_ts *ts, const struct firmware *fw)
"Failed to flash firmware: %d\n", error);
/* Enable IRQ */
- if (ts->input->users)
+ if (input_device_enabled(ts->input))
enable_irq(ts->client->irq);
else
mip4_power_off(ts);
@@ -1539,7 +1539,7 @@ static int __maybe_unused mip4_suspend(struct device *dev)
if (device_may_wakeup(dev))
ts->wake_irq_enabled = enable_irq_wake(client->irq) == 0;
- else if (input->users)
+ else if (input_device_enabled(input))
mip4_disable(ts);
mutex_unlock(&input->mutex);
@@ -1557,7 +1557,7 @@ static int __maybe_unused mip4_resume(struct device *dev)
if (ts->wake_irq_enabled)
disable_irq_wake(client->irq);
- else if (input->users)
+ else if (input_device_enabled(input))
mip4_enable(ts);
mutex_unlock(&input->mutex);
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c
index 1f96657310b7..16557f51b09d 100644
--- a/drivers/input/touchscreen/mms114.c
+++ b/drivers/input/touchscreen/mms114.c
@@ -199,7 +199,7 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
int error;
mutex_lock(&input_dev->mutex);
- if (!input_dev->users) {
+ if (!input_device_enabled(input_dev)) {
mutex_unlock(&input_dev->mutex);
goto out;
}
@@ -564,7 +564,7 @@ static int __maybe_unused mms114_suspend(struct device *dev)
input_sync(input_dev);
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
mms114_stop(data);
mutex_unlock(&input_dev->mutex);
@@ -579,7 +579,7 @@ static int __maybe_unused mms114_resume(struct device *dev)
int error;
mutex_lock(&input_dev->mutex);
- if (input_dev->users) {
+ if (input_device_enabled(input_dev)) {
error = mms114_start(data);
if (error < 0) {
mutex_unlock(&input_dev->mutex);
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 9aa098577350..dc148b4bed74 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -415,14 +415,14 @@ static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev)
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev)) {
- if (!input->users) {
+ if (!input_device_enabled(input)) {
ret = pixcir_start(ts);
if (ret) {
dev_err(dev, "Failed to start\n");
goto unlock;
}
}
- } else if (input->users) {
+ } else if (input_device_enabled(input)) {
ret = pixcir_stop(ts);
}
@@ -442,14 +442,14 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev)
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev)) {
- if (!input->users) {
+ if (!input_device_enabled(input)) {
ret = pixcir_stop(ts);
if (ret) {
dev_err(dev, "Failed to stop\n");
goto unlock;
}
}
- } else if (input->users) {
+ } else if (input_device_enabled(input)) {
ret = pixcir_start(ts);
}
diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c
index cfc8bb4553f7..e50af30183f4 100644
--- a/drivers/input/touchscreen/resistive-adc-touch.c
+++ b/drivers/input/touchscreen/resistive-adc-touch.c
@@ -23,7 +23,7 @@
#define GRTS_MAX_POS_MASK GENMASK(11, 0)
/**
- * grts_state - generic resistive touch screen information struct
+ * struct grts_state - generic resistive touch screen information struct
* @pressure_min: number representing the minimum for the pressure
* @pressure: are we getting pressure info or not
* @iio_chans: list of channels acquired
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index 63b29c7279e2..bda96762744e 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -26,15 +26,14 @@
#define ST1232_TS_NAME "st1232-ts"
#define ST1633_TS_NAME "st1633-ts"
+#define REG_XY_RESOLUTION 0x04
+#define REG_XY_COORDINATES 0x12
#define ST_TS_MAX_FINGERS 10
struct st_chip_info {
bool have_z;
- u16 max_x;
- u16 max_y;
u16 max_area;
u16 max_fingers;
- u8 start_reg;
};
struct st1232_ts_data {
@@ -48,15 +47,14 @@ struct st1232_ts_data {
u8 *read_buf;
};
-static int st1232_ts_read_data(struct st1232_ts_data *ts)
+static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg)
{
struct i2c_client *client = ts->client;
- u8 start_reg = ts->chip_info->start_reg;
struct i2c_msg msg[] = {
{
.addr = client->addr,
- .len = sizeof(start_reg),
- .buf = &start_reg,
+ .len = sizeof(reg),
+ .buf = &reg,
},
{
.addr = client->addr,
@@ -74,6 +72,25 @@ static int st1232_ts_read_data(struct st1232_ts_data *ts)
return 0;
}
+static int st1232_ts_read_resolution(struct st1232_ts_data *ts, u16 *max_x,
+ u16 *max_y)
+{
+ u8 *buf;
+ int error;
+
+ /* select resolution register */
+ error = st1232_ts_read_data(ts, REG_XY_RESOLUTION);
+ if (error)
+ return error;
+
+ buf = ts->read_buf;
+
+ *max_x = ((buf[0] & 0x0070) << 4) | buf[1];
+ *max_y = ((buf[0] & 0x0007) << 8) | buf[2];
+
+ return 0;
+}
+
static int st1232_ts_parse_and_report(struct st1232_ts_data *ts)
{
struct input_dev *input = ts->input_dev;
@@ -123,7 +140,7 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
int count;
int error;
- error = st1232_ts_read_data(ts);
+ error = st1232_ts_read_data(ts, REG_XY_COORDINATES);
if (error)
goto out;
@@ -157,20 +174,14 @@ static void st1232_ts_power_off(void *data)
static const struct st_chip_info st1232_chip_info = {
.have_z = true,
- .max_x = 0x31f, /* 800 - 1 */
- .max_y = 0x1df, /* 480 -1 */
.max_area = 0xff,
.max_fingers = 2,
- .start_reg = 0x12,
};
static const struct st_chip_info st1633_chip_info = {
.have_z = false,
- .max_x = 0x13f, /* 320 - 1 */
- .max_y = 0x1df, /* 480 -1 */
.max_area = 0x00,
.max_fingers = 5,
- .start_reg = 0x12,
};
static int st1232_ts_probe(struct i2c_client *client,
@@ -179,6 +190,7 @@ static int st1232_ts_probe(struct i2c_client *client,
const struct st_chip_info *match;
struct st1232_ts_data *ts;
struct input_dev *input_dev;
+ u16 max_x, max_y;
int error;
match = device_get_match_data(&client->dev);
@@ -239,14 +251,22 @@ static int st1232_ts_probe(struct i2c_client *client,
input_dev->name = "st1232-touchscreen";
input_dev->id.bustype = BUS_I2C;
+ /* Read resolution from the chip */
+ error = st1232_ts_read_resolution(ts, &max_x, &max_y);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to read resolution: %d\n", error);
+ return error;
+ }
+
if (ts->chip_info->have_z)
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
ts->chip_info->max_area, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
- 0, ts->chip_info->max_x, 0, 0);
+ 0, max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
- 0, ts->chip_info->max_y, 0, 0);
+ 0, max_y, 0, 0);
touchscreen_parse_properties(input_dev, true, &ts->prop);
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index 7e16fcfe3b95..cd747725589b 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -14,6 +14,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/input.h>
+#include <linux/input/touchscreen.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -72,6 +73,7 @@ struct stmpe_touch {
struct input_dev *idev;
struct delayed_work work;
struct device *dev;
+ struct touchscreen_properties prop;
u8 ave_ctrl;
u8 touch_det_delay;
u8 settling;
@@ -150,8 +152,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data)
y = ((data_set[1] & 0xf) << 8) | data_set[2];
z = data_set[3];
- input_report_abs(ts->idev, ABS_X, x);
- input_report_abs(ts->idev, ABS_Y, y);
+ touchscreen_report_pos(ts->idev, &ts->prop, x, y, false);
input_report_abs(ts->idev, ABS_PRESSURE, z);
input_report_key(ts->idev, BTN_TOUCH, 1);
input_sync(ts->idev);
@@ -337,6 +338,8 @@ static int stmpe_input_probe(struct platform_device *pdev)
input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0);
input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0);
+ touchscreen_parse_properties(idev, false, &ts->prop);
+
error = input_register_device(idev);
if (error) {
dev_err(&pdev->dev, "Could not register input device\n");
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
index ce4828b1415a..731454599fce 100644
--- a/drivers/input/touchscreen/surface3_spi.c
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -219,7 +219,7 @@ static void surface3_spi_power(struct surface3_ts_data *data, bool on)
/**
* surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT
*
- * @ts: surface3_spi_ts_data pointer
+ * @data: surface3_spi_ts_data pointer
*/
static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
{
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 807d39e18091..e3f2c940ef3d 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -410,7 +410,7 @@ static int __maybe_unused ucb1400_ts_suspend(struct device *dev)
mutex_lock(&idev->mutex);
- if (idev->users)
+ if (input_device_enabled(idev))
ucb1400_ts_stop(ucb);
mutex_unlock(&idev->mutex);
@@ -424,7 +424,7 @@ static int __maybe_unused ucb1400_ts_resume(struct device *dev)
mutex_lock(&idev->mutex);
- if (idev->users)
+ if (input_device_enabled(idev))
ucb1400_ts_start(ucb);
mutex_unlock(&idev->mutex);
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index 0a174bd82915..78d2ee99f37a 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -194,7 +194,7 @@ EXPORT_SYMBOL_GPL(wm97xx_get_gpio);
* wm97xx_set_gpio - Set the status of a codec GPIO.
* @wm: wm97xx device.
* @gpio: gpio
- *
+ * @status: status
*
* Set the status of a codec GPIO pin
*/
@@ -806,23 +806,25 @@ static int __maybe_unused wm97xx_suspend(struct device *dev)
else
suspend_mode = 0;
- if (wm->input_dev->users)
+ mutex_lock(&wm->input_dev->mutex);
+ if (input_device_enabled(wm->input_dev))
cancel_delayed_work_sync(&wm->ts_reader);
/* Power down the digitiser (bypassing the cache for resume) */
reg = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER2);
reg &= ~WM97XX_PRP_DET_DIG;
- if (wm->input_dev->users)
+ if (input_device_enabled(wm->input_dev))
reg |= suspend_mode;
wm->ac97->bus->ops->write(wm->ac97, AC97_WM97XX_DIGITISER2, reg);
/* WM9713 has an additional power bit - turn it off if there
* are no users or if suspend mode is zero. */
if (wm->id == WM9713_ID2 &&
- (!wm->input_dev->users || !suspend_mode)) {
+ (!input_device_enabled(wm->input_dev) || !suspend_mode)) {
reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) | 0x8000;
wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
}
+ mutex_unlock(&wm->input_dev->mutex);
return 0;
}
@@ -831,11 +833,12 @@ static int __maybe_unused wm97xx_resume(struct device *dev)
{
struct wm97xx *wm = dev_get_drvdata(dev);
+ mutex_lock(&wm->input_dev->mutex);
/* restore digitiser and gpios */
if (wm->id == WM9713_ID2) {
wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]);
wm97xx_reg_write(wm, 0x5a, wm->misc);
- if (wm->input_dev->users) {
+ if (input_device_enabled(wm->input_dev)) {
u16 reg;
reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) & 0x7fff;
wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
@@ -852,11 +855,12 @@ static int __maybe_unused wm97xx_resume(struct device *dev)
wm97xx_reg_write(wm, AC97_GPIO_STATUS, wm->gpio[4]);
wm97xx_reg_write(wm, AC97_MISC_AFE, wm->gpio[5]);
- if (wm->input_dev->users && !wm->pen_irq) {
+ if (input_device_enabled(wm->input_dev) && !wm->pen_irq) {
wm->ts_reader_interval = wm->ts_reader_min_interval;
queue_delayed_work(wm->ts_workq, &wm->ts_reader,
wm->ts_reader_interval);
}
+ mutex_unlock(&wm->input_dev->mutex);
return 0;
}
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index 5230519b0f74..495629628af6 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -626,14 +626,14 @@ static int __maybe_unused zforce_suspend(struct device *dev)
dev_dbg(&client->dev, "suspend while being a wakeup source\n");
/* Need to start device, if not open, to be a wakeup source. */
- if (!input->users) {
+ if (!input_device_enabled(input)) {
ret = zforce_start(ts);
if (ret)
goto unlock;
}
enable_irq_wake(client->irq);
- } else if (input->users) {
+ } else if (input_device_enabled(input)) {
dev_dbg(&client->dev,
"suspend without being a wakeup source\n");
@@ -670,12 +670,12 @@ static int __maybe_unused zforce_resume(struct device *dev)
disable_irq_wake(client->irq);
/* need to stop device if it was not open on suspend */
- if (!input->users) {
+ if (!input_device_enabled(input)) {
ret = zforce_stop(ts);
if (ret)
goto unlock;
}
- } else if (input->users) {
+ } else if (input_device_enabled(input)) {
dev_dbg(&client->dev, "resume without being a wakeup source\n");
enable_irq(client->irq);
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 1acc2eb2bcb3..a3e3adbabc67 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -532,7 +532,7 @@ static int __maybe_unused zinitix_suspend(struct device *dev)
mutex_lock(&bt541->input_dev->mutex);
- if (bt541->input_dev->users)
+ if (input_device_enabled(bt541->input_dev))
zinitix_stop(bt541);
mutex_unlock(&bt541->input_dev->mutex);
@@ -548,7 +548,7 @@ static int __maybe_unused zinitix_resume(struct device *dev)
mutex_lock(&bt541->input_dev->mutex);
- if (bt541->input_dev->users)
+ if (input_device_enabled(bt541->input_dev))
ret = zinitix_start(bt541);
mutex_unlock(&bt541->input_dev->mutex);