Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index c5992cd..1efd315 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Input device configuration
#
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 40de6a7..e356509 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -6,7 +6,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT) += input-core.o
-input-core-y := input.o input-compat.o input-mt.o ff-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
diff --git a/drivers/input/apm-power.c b/drivers/input/apm-power.c
index 650177a..70a9e1d 100644
--- a/drivers/input/apm-power.c
+++ b/drivers/input/apm-power.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input Power Event -> APM Bridge
*
* Copyright (c) 2007 Richard Purdie
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
index 5419c1c..c0d0b12 100644
--- a/drivers/input/evbug.c
+++ b/drivers/input/evbug.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index f48369d..d7dd6fc 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Event char devices, giving access to raw input device events.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -28,13 +25,6 @@
#include <linux/cdev.h>
#include "input-compat.h"
-enum evdev_clock_type {
- EV_CLK_REAL = 0,
- EV_CLK_MONO,
- EV_CLK_BOOT,
- EV_CLK_MAX
-};
-
struct evdev {
int open;
struct input_handle handle;
@@ -56,7 +46,7 @@
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
- unsigned int clk_type;
+ enum input_clock_type clk_type;
bool revoked;
unsigned long *evmasks[EV_CNT];
unsigned int bufsize;
@@ -152,17 +142,10 @@
static void __evdev_queue_syn_dropped(struct evdev_client *client)
{
+ ktime_t *ev_time = input_get_timestamp(client->evdev->handle.dev);
+ struct timespec64 ts = ktime_to_timespec64(ev_time[client->clk_type]);
struct input_event ev;
- ktime_t time;
- struct timespec64 ts;
- time = client->clk_type == EV_CLK_REAL ?
- ktime_get_real() :
- client->clk_type == EV_CLK_MONO ?
- ktime_get() :
- ktime_get_boottime();
-
- ts = ktime_to_timespec64(time);
ev.input_event_sec = ts.tv_sec;
ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
ev.type = EV_SYN;
@@ -191,18 +174,18 @@
static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
{
unsigned long flags;
- unsigned int clk_type;
+ enum input_clock_type clk_type;
switch (clkid) {
case CLOCK_REALTIME:
- clk_type = EV_CLK_REAL;
+ clk_type = INPUT_CLK_REAL;
break;
case CLOCK_MONOTONIC:
- clk_type = EV_CLK_MONO;
+ clk_type = INPUT_CLK_MONO;
break;
case CLOCK_BOOTTIME:
- clk_type = EV_CLK_BOOT;
+ clk_type = INPUT_CLK_BOOT;
break;
default:
return -EINVAL;
@@ -310,12 +293,7 @@
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
- ktime_t ev_time[EV_CLK_MAX];
-
- ev_time[EV_CLK_MONO] = ktime_get();
- ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]);
- ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO],
- TK_OFFS_BOOT);
+ ktime_t *ev_time = input_get_timestamp(handle->dev);
rcu_read_lock();
@@ -503,14 +481,13 @@
{
struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
- unsigned int size = sizeof(struct evdev_client) +
- bufsize * sizeof(struct input_event);
struct evdev_client *client;
int error;
- client = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+ client = kzalloc(struct_size(client, buffer, bufsize),
+ GFP_KERNEL | __GFP_NOWARN);
if (!client)
- client = vzalloc(size);
+ client = vzalloc(struct_size(client, buffer, bufsize));
if (!client)
return -ENOMEM;
@@ -524,7 +501,7 @@
goto err_free_client;
file->private_data = client;
- nonseekable_open(inode, file);
+ stream_open(inode, file);
return 0;
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index 66a46c8..1cf5ded 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Force feedback support for Linux input subsystem
*
@@ -6,19 +7,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define DEBUG */
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index 2743ed4..8229a90 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Force feedback support for memoryless devices
*
@@ -6,19 +7,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define DEBUG */
@@ -501,6 +489,15 @@
{
struct ml_device *ml = ff->private;
+ /*
+ * Even though we stop all playing effects when tearing down
+ * an input device (via input_device_flush() that calls into
+ * input_ff_flush() that stops and erases all effects), we
+ * do not actually stop the timer, and therefore we should
+ * do it here.
+ */
+ del_timer_sync(&ml->timer);
+
kfree(ml->private);
}
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
index d279454..24acb3b 100644
--- a/drivers/input/gameport/Kconfig
+++ b/drivers/input/gameport/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Gameport configuration
#
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index afdc20c..11bbd1e 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/io.h>
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index 7c03114..e785d36 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -1,23 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* FM801 gameport driver for Linux
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#include <asm/io.h>
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 73862a8..61fa7e7 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic gameport layer
*
@@ -5,11 +6,6 @@
* Copyright (c) 2005 Dmitry Torokhov
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c
index c6e74c7..87eeb4b 100644
--- a/drivers/input/gameport/lightning.c
+++ b/drivers/input/gameport/lightning.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/io.h>
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index 6437645..2f80b7f 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
* Copyright (c) 1999 Brian Gerst
@@ -8,19 +9,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/io.h>
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c
index fda8d6d..2ccd3ee 100644
--- a/drivers/input/input-compat.c
+++ b/drivers/input/input-compat.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 32bit compatibility wrappers for the input subsystem.
*
* Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/export.h>
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
index 08cd755..3b7bb12 100644
--- a/drivers/input/input-compat.h
+++ b/drivers/input/input-compat.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _INPUT_COMPAT_H
#define _INPUT_COMPAT_H
@@ -5,10 +6,6 @@
* 32bit compatibility wrappers for the input subsystem.
*
* Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/compiler.h>
diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c
index 99cc784..0b11990 100644
--- a/drivers/input/input-leds.c
+++ b/drivers/input/input-leds.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LED support for the input layer
*
* Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index 6c7326c..a81e141 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input Multitouch Library
*
* Copyright (c) 2008-2010 Henrik Rydberg
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/input/mt.h>
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 78df5a7..9bf1c9a 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic implementation of a polled input device
* Copyright (c) 2007 Dmitry Torokhov
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/input-poller.c b/drivers/input/input-poller.c
new file mode 100644
index 0000000..1b3d289
--- /dev/null
+++ b/drivers/input/input-poller.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Support for polling mode for input devices.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include "input-poller.h"
+
+struct input_dev_poller {
+ void (*poll)(struct input_dev *dev);
+
+ unsigned int poll_interval; /* msec */
+ unsigned int poll_interval_max; /* msec */
+ unsigned int poll_interval_min; /* msec */
+
+ struct input_dev *input;
+ struct delayed_work work;
+};
+
+static void input_dev_poller_queue_work(struct input_dev_poller *poller)
+{
+ unsigned long delay;
+
+ delay = msecs_to_jiffies(poller->poll_interval);
+ if (delay >= HZ)
+ delay = round_jiffies_relative(delay);
+
+ queue_delayed_work(system_freezable_wq, &poller->work, delay);
+}
+
+static void input_dev_poller_work(struct work_struct *work)
+{
+ struct input_dev_poller *poller =
+ container_of(work, struct input_dev_poller, work.work);
+
+ poller->poll(poller->input);
+ input_dev_poller_queue_work(poller);
+}
+
+void input_dev_poller_finalize(struct input_dev_poller *poller)
+{
+ if (!poller->poll_interval)
+ poller->poll_interval = 500;
+ if (!poller->poll_interval_max)
+ poller->poll_interval_max = poller->poll_interval;
+}
+
+void input_dev_poller_start(struct input_dev_poller *poller)
+{
+ /* Only start polling if polling is enabled */
+ if (poller->poll_interval > 0) {
+ poller->poll(poller->input);
+ input_dev_poller_queue_work(poller);
+ }
+}
+
+void input_dev_poller_stop(struct input_dev_poller *poller)
+{
+ cancel_delayed_work_sync(&poller->work);
+}
+
+int input_setup_polling(struct input_dev *dev,
+ void (*poll_fn)(struct input_dev *dev))
+{
+ struct input_dev_poller *poller;
+
+ poller = kzalloc(sizeof(*poller), GFP_KERNEL);
+ if (!poller) {
+ /*
+ * We want to show message even though kzalloc() may have
+ * printed backtrace as knowing what instance of input
+ * device we were dealing with is helpful.
+ */
+ dev_err(dev->dev.parent ?: &dev->dev,
+ "%s: unable to allocate poller structure\n", __func__);
+ return -ENOMEM;
+ }
+
+ INIT_DELAYED_WORK(&poller->work, input_dev_poller_work);
+ poller->input = dev;
+ poller->poll = poll_fn;
+
+ dev->poller = poller;
+ return 0;
+}
+EXPORT_SYMBOL(input_setup_polling);
+
+static bool input_dev_ensure_poller(struct input_dev *dev)
+{
+ if (!dev->poller) {
+ dev_err(dev->dev.parent ?: &dev->dev,
+ "poller structure has not been set up\n");
+ return false;
+ }
+
+ return true;
+}
+
+void input_set_poll_interval(struct input_dev *dev, unsigned int interval)
+{
+ if (input_dev_ensure_poller(dev))
+ dev->poller->poll_interval = interval;
+}
+EXPORT_SYMBOL(input_set_poll_interval);
+
+void input_set_min_poll_interval(struct input_dev *dev, unsigned int interval)
+{
+ if (input_dev_ensure_poller(dev))
+ dev->poller->poll_interval_min = interval;
+}
+EXPORT_SYMBOL(input_set_min_poll_interval);
+
+void input_set_max_poll_interval(struct input_dev *dev, unsigned int interval)
+{
+ if (input_dev_ensure_poller(dev))
+ dev->poller->poll_interval_max = interval;
+}
+EXPORT_SYMBOL(input_set_max_poll_interval);
+
+/* SYSFS interface */
+
+static ssize_t input_dev_get_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+
+ return sprintf(buf, "%d\n", input->poller->poll_interval);
+}
+
+static ssize_t input_dev_set_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct input_dev *input = to_input_dev(dev);
+ struct input_dev_poller *poller = input->poller;
+ unsigned int interval;
+ int err;
+
+ err = kstrtouint(buf, 0, &interval);
+ if (err)
+ return err;
+
+ if (interval < poller->poll_interval_min)
+ return -EINVAL;
+
+ if (interval > poller->poll_interval_max)
+ return -EINVAL;
+
+ mutex_lock(&input->mutex);
+
+ poller->poll_interval = interval;
+
+ if (input->users) {
+ cancel_delayed_work_sync(&poller->work);
+ if (poller->poll_interval > 0)
+ input_dev_poller_queue_work(poller);
+ }
+
+ mutex_unlock(&input->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(poll, 0644,
+ input_dev_get_poll_interval, input_dev_set_poll_interval);
+
+static ssize_t input_dev_get_poll_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+
+ return sprintf(buf, "%d\n", input->poller->poll_interval_max);
+}
+
+static DEVICE_ATTR(max, 0444, input_dev_get_poll_max, NULL);
+
+static ssize_t input_dev_get_poll_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+
+ return sprintf(buf, "%d\n", input->poller->poll_interval_min);
+}
+
+static DEVICE_ATTR(min, 0444, input_dev_get_poll_min, NULL);
+
+static umode_t input_poller_attrs_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct input_dev *input = to_input_dev(dev);
+
+ return input->poller ? attr->mode : 0;
+}
+
+static struct attribute *input_poller_attrs[] = {
+ &dev_attr_poll.attr,
+ &dev_attr_max.attr,
+ &dev_attr_min.attr,
+ NULL
+};
+
+struct attribute_group input_poller_attribute_group = {
+ .is_visible = input_poller_attrs_visible,
+ .attrs = input_poller_attrs,
+};
diff --git a/drivers/input/input-poller.h b/drivers/input/input-poller.h
new file mode 100644
index 0000000..e3fca0b
--- /dev/null
+++ b/drivers/input/input-poller.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _INPUT_POLLER_H
+#define _INPUT_POLLER_H
+
+/*
+ * Support for polling mode for input devices.
+ */
+#include <linux/sysfs.h>
+
+struct input_dev_poller;
+
+void input_dev_poller_finalize(struct input_dev_poller *poller);
+void input_dev_poller_start(struct input_dev_poller *poller);
+void input_dev_poller_stop(struct input_dev_poller *poller);
+
+extern struct attribute_group input_poller_attribute_group;
+
+#endif /* _INPUT_POLLER_H */
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 3304aaa..5508627 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* The input core
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
@@ -28,6 +24,7 @@
#include <linux/mutex.h>
#include <linux/rcupdate.h>
#include "input-compat.h"
+#include "input-poller.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
@@ -400,6 +397,13 @@
if (dev->num_vals >= 2)
input_pass_values(dev, dev->vals, dev->num_vals);
dev->num_vals = 0;
+ /*
+ * Reset the timestamp on flush so we won't end up
+ * with a stale one. Note we only need to reset the
+ * monolithic one as we use its presence when deciding
+ * whether to generate a synthetic timestamp.
+ */
+ dev->timestamp[INPUT_CLK_MONO] = ktime_set(0, 0);
} else if (dev->num_vals >= dev->max_vals - 2) {
dev->vals[dev->num_vals++] = input_value_sync;
input_pass_values(dev, dev->vals, dev->num_vals);
@@ -607,20 +611,31 @@
handle->open++;
- if (!dev->users++ && dev->open)
- retval = dev->open(dev);
+ if (dev->users++) {
+ /*
+ * Device is already opened, so we can exit immediately and
+ * report success.
+ */
+ goto out;
+ }
- if (retval) {
- dev->users--;
- if (!--handle->open) {
+ if (dev->open) {
+ retval = dev->open(dev);
+ if (retval) {
+ dev->users--;
+ handle->open--;
/*
* Make sure we are not delivering any more events
* through this handle
*/
synchronize_rcu();
+ goto out;
}
}
+ if (dev->poller)
+ input_dev_poller_start(dev->poller);
+
out:
mutex_unlock(&dev->mutex);
return retval;
@@ -659,8 +674,13 @@
__input_release_device(handle);
- if (!--dev->users && dev->close)
- dev->close(dev);
+ if (!--dev->users) {
+ if (dev->poller)
+ input_dev_poller_stop(dev->poller);
+
+ if (dev->close)
+ dev->close(dev);
+ }
if (!--handle->open) {
/*
@@ -1506,6 +1526,7 @@
&input_dev_attr_group,
&input_dev_id_attr_group,
&input_dev_caps_attr_group,
+ &input_poller_attribute_group,
NULL
};
@@ -1515,6 +1536,7 @@
input_ff_destroy(dev);
input_mt_destroy_slots(dev);
+ kfree(dev->poller);
kfree(dev->absinfo);
kfree(dev->vals);
kfree(dev);
@@ -1899,6 +1921,46 @@
EXPORT_SYMBOL(input_free_device);
/**
+ * input_set_timestamp - set timestamp for input events
+ * @dev: input device to set timestamp for
+ * @timestamp: the time at which the event has occurred
+ * in CLOCK_MONOTONIC
+ *
+ * This function is intended to provide to the input system a more
+ * accurate time of when an event actually occurred. The driver should
+ * call this function as soon as a timestamp is acquired ensuring
+ * clock conversions in input_set_timestamp are done correctly.
+ *
+ * The system entering suspend state between timestamp acquisition and
+ * calling input_set_timestamp can result in inaccurate conversions.
+ */
+void input_set_timestamp(struct input_dev *dev, ktime_t timestamp)
+{
+ dev->timestamp[INPUT_CLK_MONO] = timestamp;
+ dev->timestamp[INPUT_CLK_REAL] = ktime_mono_to_real(timestamp);
+ dev->timestamp[INPUT_CLK_BOOT] = ktime_mono_to_any(timestamp,
+ TK_OFFS_BOOT);
+}
+EXPORT_SYMBOL(input_set_timestamp);
+
+/**
+ * input_get_timestamp - get timestamp for input events
+ * @dev: input device to get timestamp from
+ *
+ * A valid timestamp is a timestamp of non-zero value.
+ */
+ktime_t *input_get_timestamp(struct input_dev *dev)
+{
+ const ktime_t invalid_timestamp = ktime_set(0, 0);
+
+ if (!ktime_compare(dev->timestamp[INPUT_CLK_MONO], invalid_timestamp))
+ input_set_timestamp(dev, ktime_get());
+
+ return dev->timestamp;
+}
+EXPORT_SYMBOL(input_get_timestamp);
+
+/**
* input_set_capability - mark device as capable of a certain event
* @dev: device that is capable of emitting or accepting event
* @type: type of the event (EV_KEY, EV_REL, etc...)
@@ -2139,6 +2201,9 @@
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
+ if (dev->poller)
+ input_dev_poller_finalize(dev->poller);
+
error = device_add(&dev->dev);
if (error)
goto err_free_vals;
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 4c1e427..a2b5fbb 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Joystick device driver for the input driver suite.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 1999 Colin Van Dyke
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -279,7 +275,7 @@
goto err_free_client;
file->private_data = client;
- nonseekable_open(inode, file);
+ stream_open(inode, file);
return 0;
@@ -812,6 +808,7 @@
static bool joydev_dev_is_absolute_mouse(struct input_dev *dev)
{
DECLARE_BITMAP(jd_scratch, KEY_CNT);
+ bool ev_match = false;
BUILD_BUG_ON(ABS_CNT > KEY_CNT || EV_CNT > KEY_CNT);
@@ -830,17 +827,36 @@
* considered to be an absolute mouse if the following is
* true:
*
- * 1) Event types are exactly EV_ABS, EV_KEY and EV_SYN.
+ * 1) Event types are exactly
+ * EV_ABS, EV_KEY and EV_SYN
+ * or
+ * EV_ABS, EV_KEY, EV_SYN and EV_MSC
+ * or
+ * EV_ABS, EV_KEY, EV_SYN, EV_MSC and EV_REL.
* 2) Absolute events are exactly ABS_X and ABS_Y.
* 3) Keys are exactly BTN_LEFT, BTN_RIGHT and BTN_MIDDLE.
* 4) Device is not on "Amiga" bus.
*/
bitmap_zero(jd_scratch, EV_CNT);
+ /* VMware VMMouse, HP ILO2 */
__set_bit(EV_ABS, jd_scratch);
__set_bit(EV_KEY, jd_scratch);
__set_bit(EV_SYN, jd_scratch);
- if (!bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+ if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+ ev_match = true;
+
+ /* HP ILO2, AMI BMC firmware */
+ __set_bit(EV_MSC, jd_scratch);
+ if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+ ev_match = true;
+
+ /* VMware Virtual USB Mouse, QEMU USB Tablet, ATEN BMC firmware */
+ __set_bit(EV_REL, jd_scratch);
+ if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT))
+ ev_match = true;
+
+ if (!ev_match)
return false;
bitmap_zero(jd_scratch, ABS_CNT);
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index d8f9c6e..312b854 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Joystick driver configuration
#
@@ -361,4 +362,14 @@
To compile this driver as a module, choose M here: the
module will be called pxrc.
+config JOYSTICK_FSIA6B
+ tristate "FlySky FS-iA6B RC Receiver"
+ select SERIO
+ help
+ Say Y here if you use a FlySky FS-i6 RC remote control along with the
+ FS-iA6B RC receiver as a joystick input device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fsia6b.
+
endif
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index dd0492e..8656023 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -12,6 +12,7 @@
obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o
obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o
obj-$(CONFIG_JOYSTICK_DB9) += db9.o
+obj-$(CONFIG_JOYSTICK_FSIA6B) += fsia6b.o
obj-$(CONFIG_JOYSTICK_GAMECON) += gamecon.o
obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o
obj-$(CONFIG_JOYSTICK_GRIP) += grip.o
@@ -23,7 +24,7 @@
obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o
obj-$(CONFIG_JOYSTICK_MAPLE) += maplecontrol.o
obj-$(CONFIG_JOYSTICK_PSXPAD_SPI) += psxpad-spi.o
-obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o
+obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o
obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o
obj-$(CONFIG_JOYSTICK_SPACEORB) += spaceorb.o
@@ -32,7 +33,7 @@
obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o
obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o
obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o
+obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o
obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o
obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o
-obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index 9830703..68475fa 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index f466c0d..592c95b 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1998-2005 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index 2b82a83..12456a1 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/types.h>
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 2b445c8..2b625eb 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1996-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c
index f051993..34bcd99 100644
--- a/drivers/input/joystick/as5011.c
+++ b/drivers/input/joystick/as5011.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2010, 2011 Fabien Marteau <fabien.marteau@armadeus.com>
* Sponsored by ARMadeus Systems
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
* Driver for Austria Microsystems joysticks AS5011
*
* TODO:
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index 14cb956..41e1936 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index 804b1b8..a7bc576 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -10,19 +11,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
@@ -259,7 +247,7 @@
db9_saturn_write_sub(port, type, 3, powered, 0);
return data[0] = 0xe3;
}
- /* else: fall through */
+ /* fall through */
default:
return data[0];
}
diff --git a/drivers/input/joystick/fsia6b.c b/drivers/input/joystick/fsia6b.c
new file mode 100644
index 0000000..e78c4c76
--- /dev/null
+++ b/drivers/input/joystick/fsia6b.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * FS-iA6B iBus RC receiver driver
+ *
+ * This driver provides all 14 channels of the FlySky FS-ia6B RC receiver
+ * as analog values.
+ *
+ * Additionally, the channels can be converted to discrete switch values.
+ * By default, it is configured for the offical FS-i6 remote control.
+ * If you use a different hardware configuration, you can configure it
+ * using the `switch_config` parameter.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define DRIVER_DESC "FS-iA6B iBus RC receiver"
+
+MODULE_AUTHOR("Markus Koch <markus@notsyncing.net>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define IBUS_SERVO_COUNT 14
+
+static char *switch_config = "00000022320000";
+module_param(switch_config, charp, 0444);
+MODULE_PARM_DESC(switch_config,
+ "Amount of switch positions per channel (14 characters, 0-3)");
+
+static int fsia6b_axes[IBUS_SERVO_COUNT] = {
+ ABS_X, ABS_Y,
+ ABS_Z, ABS_RX,
+ ABS_RY, ABS_RZ,
+ ABS_HAT0X, ABS_HAT0Y,
+ ABS_HAT1X, ABS_HAT1Y,
+ ABS_HAT2X, ABS_HAT2Y,
+ ABS_HAT3X, ABS_HAT3Y
+};
+
+enum ibus_state { SYNC, COLLECT, PROCESS };
+
+struct ibus_packet {
+ enum ibus_state state;
+
+ int offset;
+ u16 ibuf;
+ u16 channel[IBUS_SERVO_COUNT];
+};
+
+struct fsia6b {
+ struct input_dev *dev;
+ struct ibus_packet packet;
+
+ char phys[32];
+};
+
+static irqreturn_t fsia6b_serio_irq(struct serio *serio,
+ unsigned char data, unsigned int flags)
+{
+ struct fsia6b *fsia6b = serio_get_drvdata(serio);
+ int i;
+ int sw_state;
+ int sw_id = BTN_0;
+
+ fsia6b->packet.ibuf = (data << 8) | ((fsia6b->packet.ibuf >> 8) & 0xFF);
+
+ switch (fsia6b->packet.state) {
+ case SYNC:
+ if (fsia6b->packet.ibuf == 0x4020)
+ fsia6b->packet.state = COLLECT;
+ break;
+
+ case COLLECT:
+ fsia6b->packet.state = PROCESS;
+ break;
+
+ case PROCESS:
+ fsia6b->packet.channel[fsia6b->packet.offset] =
+ fsia6b->packet.ibuf;
+ fsia6b->packet.offset++;
+
+ if (fsia6b->packet.offset == IBUS_SERVO_COUNT) {
+ fsia6b->packet.offset = 0;
+ fsia6b->packet.state = SYNC;
+ for (i = 0; i < IBUS_SERVO_COUNT; ++i) {
+ input_report_abs(fsia6b->dev, fsia6b_axes[i],
+ fsia6b->packet.channel[i]);
+
+ sw_state = 0;
+ if (fsia6b->packet.channel[i] > 1900)
+ sw_state = 1;
+ else if (fsia6b->packet.channel[i] < 1100)
+ sw_state = 2;
+
+ switch (switch_config[i]) {
+ case '3':
+ input_report_key(fsia6b->dev,
+ sw_id++,
+ sw_state == 0);
+ /* fall-through */
+ case '2':
+ input_report_key(fsia6b->dev,
+ sw_id++,
+ sw_state == 1);
+ /* fall-through */
+ case '1':
+ input_report_key(fsia6b->dev,
+ sw_id++,
+ sw_state == 2);
+ }
+ }
+ input_sync(fsia6b->dev);
+ } else {
+ fsia6b->packet.state = COLLECT;
+ }
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int fsia6b_serio_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct fsia6b *fsia6b;
+ struct input_dev *input_dev;
+ int err;
+ int i, j;
+ int sw_id = 0;
+
+ fsia6b = kzalloc(sizeof(*fsia6b), GFP_KERNEL);
+ if (!fsia6b)
+ return -ENOMEM;
+
+ fsia6b->packet.ibuf = 0;
+ fsia6b->packet.offset = 0;
+ fsia6b->packet.state = SYNC;
+
+ serio_set_drvdata(serio, fsia6b);
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+ fsia6b->dev = input_dev;
+
+ snprintf(fsia6b->phys, sizeof(fsia6b->phys), "%s/input0", serio->phys);
+
+ input_dev->name = DRIVER_DESC;
+ input_dev->phys = fsia6b->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_FSIA6B;
+ input_dev->id.product = serio->id.id;
+ input_dev->id.version = 0x0100;
+ input_dev->dev.parent = &serio->dev;
+
+ for (i = 0; i < IBUS_SERVO_COUNT; i++)
+ input_set_abs_params(input_dev, fsia6b_axes[i],
+ 1000, 2000, 2, 2);
+
+ /* Register switch configuration */
+ for (i = 0; i < IBUS_SERVO_COUNT; i++) {
+ if (switch_config[i] < '0' || switch_config[i] > '3') {
+ dev_err(&fsia6b->dev->dev,
+ "Invalid switch configuration supplied for fsia6b.\n");
+ err = -EINVAL;
+ goto fail2;
+ }
+
+ for (j = '1'; j <= switch_config[i]; j++) {
+ input_set_capability(input_dev, EV_KEY, BTN_0 + sw_id);
+ sw_id++;
+ }
+ }
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
+ err = input_register_device(fsia6b->dev);
+ if (err)
+ goto fail3;
+
+ return 0;
+
+fail3: serio_close(serio);
+fail2: input_free_device(input_dev);
+fail1: serio_set_drvdata(serio, NULL);
+ kfree(fsia6b);
+ return err;
+}
+
+static void fsia6b_serio_disconnect(struct serio *serio)
+{
+ struct fsia6b *fsia6b = serio_get_drvdata(serio);
+
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_unregister_device(fsia6b->dev);
+ kfree(fsia6b);
+}
+
+static const struct serio_device_id fsia6b_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_FSIA6B,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, fsia6b_serio_ids);
+
+static struct serio_driver fsia6b_serio_drv = {
+ .driver = {
+ .name = "fsia6b"
+ },
+ .description = DRIVER_DESC,
+ .id_table = fsia6b_serio_ids,
+ .interrupt = fsia6b_serio_irq,
+ .connect = fsia6b_serio_connect,
+ .disconnect = fsia6b_serio_disconnect
+};
+
+module_serio_driver(fsia6b_serio_drv)
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index d62e73d..e0a362b 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
*
@@ -11,19 +12,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index 50a6006..920feba 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index e10395b..fe798bc 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1998-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 573191d..056a89a 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the Gravis Grip Multiport, a gamepad "hub" that
* connects up to four 9-pin digital gamepads/joysticks.
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index 43ff817..8eeacdb 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/iforce/Kconfig b/drivers/input/joystick/iforce/Kconfig
index ab4dbcb..f002fb8 100644
--- a/drivers/input/joystick/iforce/Kconfig
+++ b/drivers/input/joystick/iforce/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# I-Force driver configuration
#
@@ -13,15 +14,15 @@
module will be called iforce.
config JOYSTICK_IFORCE_USB
- bool "I-Force USB joysticks and wheels"
- depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB
+ tristate "I-Force USB joysticks and wheels"
+ depends on JOYSTICK_IFORCE && USB
help
Say Y here if you have an I-Force joystick or steering wheel
connected to your USB port.
config JOYSTICK_IFORCE_232
- bool "I-Force Serial joysticks and wheels"
- depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO
+ tristate "I-Force Serial joysticks and wheels"
+ depends on JOYSTICK_IFORCE && SERIO
help
Say Y here if you have an I-Force joystick or steering wheel
connected to your serial (COM) port.
diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile
index bc5bda2..dbbe7c0 100644
--- a/drivers/input/joystick/iforce/Makefile
+++ b/drivers/input/joystick/iforce/Makefile
@@ -1,11 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the I-Force driver
#
# By Johann Deneux <johann.deneux@gmail.com>
#
-obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
-
+obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
iforce-y := iforce-ff.o iforce-main.o iforce-packets.o
-iforce-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o
-iforce-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o
+obj-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o
+obj-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
index 3536d5f..95c0348 100644
--- a/drivers/input/joystick/iforce/iforce-ff.c
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
@@ -5,22 +6,6 @@
* USB/RS232 I-Force joysticks and wheels.
*/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
#include "iforce.h"
/*
@@ -384,12 +369,12 @@
}
switch (effect->u.periodic.waveform) {
- case FF_SQUARE: wave_code = 0x20; break;
- case FF_TRIANGLE: wave_code = 0x21; break;
- case FF_SINE: wave_code = 0x22; break;
- case FF_SAW_UP: wave_code = 0x23; break;
- case FF_SAW_DOWN: wave_code = 0x24; break;
- default: wave_code = 0x20; break;
+ case FF_SQUARE: wave_code = 0x20; break;
+ case FF_TRIANGLE: wave_code = 0x21; break;
+ case FF_SINE: wave_code = 0x22; break;
+ case FF_SAW_UP: wave_code = 0x23; break;
+ case FF_SAW_DOWN: wave_code = 0x24; break;
+ default: wave_code = 0x20; break;
}
if (!old || need_core(old, effect)) {
@@ -488,9 +473,9 @@
int core_err = 0;
switch (effect->type) {
- case FF_SPRING: type = 0x40; break;
- case FF_DAMPER: type = 0x41; break;
- default: return -1;
+ case FF_SPRING: type = 0x40; break;
+ case FF_DAMPER: type = 0x41; break;
+ default: return -1;
}
if (!old || need_condition_modifier(iforce, old, effect)) {
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 58d5cfe..b2a68bc 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
@@ -5,26 +6,11 @@
* USB/RS232 I-Force joysticks and wheels.
*/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
+#include <asm/unaligned.h>
#include "iforce.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
-MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
+MODULE_DESCRIPTION("Core I-Force joysticks and wheels driver");
MODULE_LICENSE("GPL");
static signed short btn_joystick[] =
@@ -67,6 +53,7 @@
{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce },
+ { 0x06a3, 0xff04, "Saitek R440 Force Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0001, "Guillemot Jet Leader Force Feedback", btn_joystick, abs_joystick_rudder, ff_iforce },
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
@@ -132,22 +119,21 @@
* Upload the effect
*/
switch (effect->type) {
+ case FF_PERIODIC:
+ ret = iforce_upload_periodic(iforce, effect, old);
+ break;
- case FF_PERIODIC:
- ret = iforce_upload_periodic(iforce, effect, old);
- break;
+ case FF_CONSTANT:
+ ret = iforce_upload_constant(iforce, effect, old);
+ break;
- case FF_CONSTANT:
- ret = iforce_upload_constant(iforce, effect, old);
- break;
+ case FF_SPRING:
+ case FF_DAMPER:
+ ret = iforce_upload_condition(iforce, effect, old);
+ break;
- case FF_SPRING:
- case FF_DAMPER:
- ret = iforce_upload_condition(iforce, effect, old);
- break;
-
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
if (ret == 0) {
@@ -185,15 +171,7 @@
{
struct iforce *iforce = input_get_drvdata(dev);
- switch (iforce->bus) {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- case IFORCE_USB:
- iforce->irq->dev = iforce->usbdev;
- if (usb_submit_urb(iforce->irq, GFP_KERNEL))
- return -EIO;
- break;
-#endif
- }
+ iforce->xport_ops->start_io(iforce);
if (test_bit(EV_FF, dev->evbit)) {
/* Enable force feedback */
@@ -226,27 +204,17 @@
!test_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags));
}
- switch (iforce->bus) {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- case IFORCE_USB:
- usb_kill_urb(iforce->irq);
- usb_kill_urb(iforce->out);
- usb_kill_urb(iforce->ctrl);
- break;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- case IFORCE_232:
- //TODO: Wait for the last packets to be sent
- break;
-#endif
- }
+ iforce->xport_ops->stop_io(iforce);
}
-int iforce_init_device(struct iforce *iforce)
+int iforce_init_device(struct device *parent, u16 bustype,
+ struct iforce *iforce)
{
struct input_dev *input_dev;
struct ff_device *ff;
- unsigned char c[] = "CEOV";
+ u8 c[] = "CEOV";
+ u8 buf[IFORCE_MAX_LENGTH];
+ size_t len;
int i, error;
int ff_effects = 0;
@@ -264,20 +232,8 @@
* Input device fields.
*/
- switch (iforce->bus) {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- case IFORCE_USB:
- input_dev->id.bustype = BUS_USB;
- input_dev->dev.parent = &iforce->usbdev->dev;
- break;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- case IFORCE_232:
- input_dev->id.bustype = BUS_RS232;
- input_dev->dev.parent = &iforce->serio->dev;
- break;
-#endif
- }
+ input_dev->id.bustype = bustype;
+ input_dev->dev.parent = parent;
input_set_drvdata(input_dev, iforce);
@@ -302,7 +258,7 @@
*/
for (i = 0; i < 20; i++)
- if (!iforce_get_id_packet(iforce, "O"))
+ if (!iforce_get_id_packet(iforce, 'O', buf, &len))
break;
if (i == 20) { /* 5 seconds */
@@ -316,23 +272,23 @@
* Get device info.
*/
- if (!iforce_get_id_packet(iforce, "M"))
- input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
+ if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3)
+ input_dev->id.vendor = get_unaligned_le16(buf + 1);
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n");
- if (!iforce_get_id_packet(iforce, "P"))
- input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
+ if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3)
+ input_dev->id.product = get_unaligned_le16(buf + 1);
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n");
- if (!iforce_get_id_packet(iforce, "B"))
- iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
+ if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3)
+ iforce->device_memory.end = get_unaligned_le16(buf + 1);
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n");
- if (!iforce_get_id_packet(iforce, "N"))
- ff_effects = iforce->edata[1];
+ if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2)
+ ff_effects = buf[1];
else
dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n");
@@ -348,8 +304,9 @@
*/
for (i = 0; c[i]; i++)
- if (!iforce_get_id_packet(iforce, c + i))
- iforce_dump_packet(iforce, "info", iforce->ecmd, iforce->edata);
+ if (!iforce_get_id_packet(iforce, c[i], buf, &len))
+ iforce_dump_packet(iforce, "info",
+ (FF_CMD_QUERY & 0xff00) | len, buf);
/*
* Disable spring, enable force feedback.
@@ -383,34 +340,29 @@
signed short t = iforce->type->abs[i];
switch (t) {
+ case ABS_X:
+ case ABS_Y:
+ case ABS_WHEEL:
+ input_set_abs_params(input_dev, t, -1920, 1920, 16, 128);
+ set_bit(t, input_dev->ffbit);
+ break;
- case ABS_X:
- case ABS_Y:
- case ABS_WHEEL:
+ case ABS_THROTTLE:
+ case ABS_GAS:
+ case ABS_BRAKE:
+ input_set_abs_params(input_dev, t, 0, 255, 0, 0);
+ break;
- input_set_abs_params(input_dev, t, -1920, 1920, 16, 128);
- set_bit(t, input_dev->ffbit);
- break;
+ case ABS_RUDDER:
+ input_set_abs_params(input_dev, t, -128, 127, 0, 0);
+ break;
- case ABS_THROTTLE:
- case ABS_GAS:
- case ABS_BRAKE:
-
- input_set_abs_params(input_dev, t, 0, 255, 0, 0);
- break;
-
- case ABS_RUDDER:
-
- input_set_abs_params(input_dev, t, -128, 127, 0, 0);
- break;
-
- case ABS_HAT0X:
- case ABS_HAT0Y:
- case ABS_HAT1X:
- case ABS_HAT1Y:
-
- input_set_abs_params(input_dev, t, -1, 1, 0, 0);
- break;
+ case ABS_HAT0X:
+ case ABS_HAT0Y:
+ case ABS_HAT1X:
+ case ABS_HAT1Y:
+ input_set_abs_params(input_dev, t, -1, 1, 0, 0);
+ break;
}
}
@@ -443,35 +395,4 @@
fail: input_free_device(input_dev);
return error;
}
-
-static int __init iforce_init(void)
-{
- int err = 0;
-
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- err = usb_register(&iforce_usb_driver);
- if (err)
- return err;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- err = serio_register_driver(&iforce_serio_drv);
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- if (err)
- usb_deregister(&iforce_usb_driver);
-#endif
-#endif
- return err;
-}
-
-static void __exit iforce_exit(void)
-{
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- usb_deregister(&iforce_usb_driver);
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- serio_unregister_driver(&iforce_serio_drv);
-#endif
-}
-
-module_init(iforce_init);
-module_exit(iforce_exit);
+EXPORT_SYMBOL(iforce_init_device);
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index c10169f..763642c 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
@@ -5,22 +6,7 @@
* USB/RS232 I-Force joysticks and wheels.
*/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
+#include <asm/unaligned.h>
#include "iforce.h"
static struct {
@@ -91,27 +77,12 @@
/*
* If necessary, start the transmission
*/
- switch (iforce->bus) {
+ if (empty)
+ iforce->xport_ops->xmit(iforce);
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- case IFORCE_232:
- if (empty)
- iforce_serial_xmit(iforce);
- break;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- case IFORCE_USB:
-
- if (iforce->usbdev && empty &&
- !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
-
- iforce_usb_xmit(iforce);
- }
- break;
-#endif
- }
return 0;
}
+EXPORT_SYMBOL(iforce_send_packet);
/* Start or stop an effect */
int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
@@ -145,157 +116,96 @@
return -1;
}
-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
+static void iforce_report_hats_buttons(struct iforce *iforce, u8 *data)
{
struct input_dev *dev = iforce->dev;
int i;
- static int being_used = 0;
- if (being_used)
- dev_warn(&iforce->dev->dev,
- "re-entrant call to iforce_process %d\n", being_used);
- being_used++;
+ input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
+ input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- if (HI(iforce->expect_packet) == HI(cmd)) {
- iforce->expect_packet = 0;
- iforce->ecmd = cmd;
- memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
+ for (i = 0; iforce->type->btn[i] >= 0; i++)
+ input_report_key(dev, iforce->type->btn[i],
+ data[(i >> 3) + 5] & (1 << (i & 7)));
+
+ /* If there are untouched bits left, interpret them as the second hat */
+ if (i <= 8) {
+ u8 btns = data[6];
+
+ if (test_bit(ABS_HAT1X, dev->absbit)) {
+ if (btns & BIT(3))
+ input_report_abs(dev, ABS_HAT1X, -1);
+ else if (btns & BIT(1))
+ input_report_abs(dev, ABS_HAT1X, 1);
+ else
+ input_report_abs(dev, ABS_HAT1X, 0);
+ }
+
+ if (test_bit(ABS_HAT1Y, dev->absbit)) {
+ if (btns & BIT(0))
+ input_report_abs(dev, ABS_HAT1Y, -1);
+ else if (btns & BIT(2))
+ input_report_abs(dev, ABS_HAT1Y, 1);
+ else
+ input_report_abs(dev, ABS_HAT1Y, 0);
+ }
}
-#endif
- wake_up(&iforce->wait);
-
- if (!iforce->type) {
- being_used--;
- return;
- }
-
- switch (HI(cmd)) {
-
- case 0x01: /* joystick position data */
- case 0x03: /* wheel position data */
- if (HI(cmd) == 1) {
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
- input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
- if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
- input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
- } else {
- input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
- input_report_abs(dev, ABS_GAS, 255 - data[2]);
- input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
- }
-
- input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
- input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
-
- for (i = 0; iforce->type->btn[i] >= 0; i++)
- input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
-
- /* If there are untouched bits left, interpret them as the second hat */
- if (i <= 8) {
- int btns = data[6];
- if (test_bit(ABS_HAT1X, dev->absbit)) {
- if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1);
- else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1);
- else input_report_abs(dev, ABS_HAT1X, 0);
- }
- if (test_bit(ABS_HAT1Y, dev->absbit)) {
- if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1);
- else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1);
- else input_report_abs(dev, ABS_HAT1Y, 0);
- }
- }
-
- input_sync(dev);
-
- break;
-
- case 0x02: /* status report */
- input_report_key(dev, BTN_DEAD, data[0] & 0x02);
- input_sync(dev);
-
- /* Check if an effect was just started or stopped */
- i = data[1] & 0x7f;
- if (data[1] & 0x80) {
- if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
- /* Report play event */
- input_report_ff_status(dev, i, FF_STATUS_PLAYING);
- }
- } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
- /* Report stop event */
- input_report_ff_status(dev, i, FF_STATUS_STOPPED);
- }
- if (LO(cmd) > 3) {
- int j;
- for (j = 3; j < LO(cmd); j += 2)
- mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
- }
- break;
- }
- being_used--;
}
-int iforce_get_id_packet(struct iforce *iforce, char *packet)
+void iforce_process_packet(struct iforce *iforce,
+ u8 packet_id, u8 *data, size_t len)
{
- switch (iforce->bus) {
+ struct input_dev *dev = iforce->dev;
+ int i, j;
- case IFORCE_USB: {
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- int status;
+ switch (packet_id) {
- iforce->cr.bRequest = packet[0];
- iforce->ctrl->dev = iforce->usbdev;
+ case 0x01: /* joystick position data */
+ input_report_abs(dev, ABS_X,
+ (__s16) get_unaligned_le16(data));
+ input_report_abs(dev, ABS_Y,
+ (__s16) get_unaligned_le16(data + 2));
+ input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
- status = usb_submit_urb(iforce->ctrl, GFP_KERNEL);
- if (status) {
- dev_err(&iforce->intf->dev,
- "usb_submit_urb failed %d\n", status);
- return -1;
- }
+ if (len >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
+ input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
- wait_event_interruptible_timeout(iforce->wait,
- iforce->ctrl->status != -EINPROGRESS, HZ);
+ iforce_report_hats_buttons(iforce, data);
- if (iforce->ctrl->status) {
- dev_dbg(&iforce->intf->dev,
- "iforce->ctrl->status = %d\n",
- iforce->ctrl->status);
- usb_unlink_urb(iforce->ctrl);
- return -1;
- }
-#else
- printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n");
-#endif
- }
+ input_sync(dev);
break;
- case IFORCE_232:
+ case 0x03: /* wheel position data */
+ input_report_abs(dev, ABS_WHEEL,
+ (__s16) get_unaligned_le16(data));
+ input_report_abs(dev, ABS_GAS, 255 - data[2]);
+ input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- iforce->expect_packet = FF_CMD_QUERY;
- iforce_send_packet(iforce, FF_CMD_QUERY, packet);
+ iforce_report_hats_buttons(iforce, data);
- wait_event_interruptible_timeout(iforce->wait,
- !iforce->expect_packet, HZ);
-
- if (iforce->expect_packet) {
- iforce->expect_packet = 0;
- return -1;
- }
-#else
- dev_err(&iforce->dev->dev,
- "iforce_get_id_packet: iforce->bus = SERIO!\n");
-#endif
+ input_sync(dev);
break;
- default:
- dev_err(&iforce->dev->dev,
- "iforce_get_id_packet: iforce->bus = %d\n",
- iforce->bus);
+ case 0x02: /* status report */
+ input_report_key(dev, BTN_DEAD, data[0] & 0x02);
+ input_sync(dev);
+
+ /* Check if an effect was just started or stopped */
+ i = data[1] & 0x7f;
+ if (data[1] & 0x80) {
+ if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+ /* Report play event */
+ input_report_ff_status(dev, i, FF_STATUS_PLAYING);
+ }
+ } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+ /* Report stop event */
+ input_report_ff_status(dev, i, FF_STATUS_STOPPED);
+ }
+
+ for (j = 3; j < len; j += 2)
+ mark_core_as_ready(iforce, get_unaligned_le16(data + j));
+
break;
}
-
- return -(iforce->edata[0] != packet[0]);
}
-
+EXPORT_SYMBOL(iforce_process_packet);
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
index f4ba4a7..f95a81b 100644
--- a/drivers/input/joystick/iforce/iforce-serio.c
+++ b/drivers/input/joystick/iforce/iforce-serio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com>
@@ -5,26 +6,26 @@
* USB/RS232 I-Force joysticks and wheels.
*/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
+#include <linux/serio.h>
#include "iforce.h"
-void iforce_serial_xmit(struct iforce *iforce)
+struct iforce_serio {
+ struct iforce iforce;
+
+ struct serio *serio;
+ int idx, pkt, len, id;
+ u8 csum;
+ u8 expect_packet;
+ u8 cmd_response[IFORCE_MAX_LENGTH];
+ u8 cmd_response_len;
+ u8 data_in[IFORCE_MAX_LENGTH];
+};
+
+static void iforce_serio_xmit(struct iforce *iforce)
{
+ struct iforce_serio *iforce_serio = container_of(iforce,
+ struct iforce_serio,
+ iforce);
unsigned char cs;
int i;
unsigned long flags;
@@ -45,19 +46,20 @@
cs = 0x2b;
- serio_write(iforce->serio, 0x2b);
+ serio_write(iforce_serio->serio, 0x2b);
- serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
+ serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]);
cs ^= iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
- serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
+ serio_write(iforce_serio->serio,
+ iforce->xmit.buf[iforce->xmit.tail]);
cs ^= iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
}
- serio_write(iforce->serio, cs);
+ serio_write(iforce_serio->serio, cs);
if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
goto again;
@@ -67,54 +69,118 @@
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
+static int iforce_serio_get_id(struct iforce *iforce, u8 id,
+ u8 *response_data, size_t *response_len)
+{
+ struct iforce_serio *iforce_serio = container_of(iforce,
+ struct iforce_serio,
+ iforce);
+
+ iforce_serio->expect_packet = HI(FF_CMD_QUERY);
+ iforce_serio->cmd_response_len = 0;
+
+ iforce_send_packet(iforce, FF_CMD_QUERY, &id);
+
+ wait_event_interruptible_timeout(iforce->wait,
+ !iforce_serio->expect_packet, HZ);
+
+ if (iforce_serio->expect_packet) {
+ iforce_serio->expect_packet = 0;
+ return -ETIMEDOUT;
+ }
+
+ if (iforce_serio->cmd_response[0] != id)
+ return -EIO;
+
+ memcpy(response_data, iforce_serio->cmd_response,
+ iforce_serio->cmd_response_len);
+ *response_len = iforce_serio->cmd_response_len;
+
+ return 0;
+}
+
+static int iforce_serio_start_io(struct iforce *iforce)
+{
+ /* No special handling required */
+ return 0;
+}
+
+static void iforce_serio_stop_io(struct iforce *iforce)
+{
+ //TODO: Wait for the last packets to be sent
+}
+
+static const struct iforce_xport_ops iforce_serio_xport_ops = {
+ .xmit = iforce_serio_xmit,
+ .get_id = iforce_serio_get_id,
+ .start_io = iforce_serio_start_io,
+ .stop_io = iforce_serio_stop_io,
+};
+
static void iforce_serio_write_wakeup(struct serio *serio)
{
struct iforce *iforce = serio_get_drvdata(serio);
- iforce_serial_xmit(iforce);
+ iforce_serio_xmit(iforce);
}
static irqreturn_t iforce_serio_irq(struct serio *serio,
- unsigned char data, unsigned int flags)
+ unsigned char data, unsigned int flags)
{
- struct iforce *iforce = serio_get_drvdata(serio);
+ struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
+ struct iforce *iforce = &iforce_serio->iforce;
- if (!iforce->pkt) {
+ if (!iforce_serio->pkt) {
if (data == 0x2b)
- iforce->pkt = 1;
+ iforce_serio->pkt = 1;
goto out;
}
- if (!iforce->id) {
+ if (!iforce_serio->id) {
if (data > 3 && data != 0xff)
- iforce->pkt = 0;
+ iforce_serio->pkt = 0;
else
- iforce->id = data;
+ iforce_serio->id = data;
goto out;
}
- if (!iforce->len) {
+ if (!iforce_serio->len) {
if (data > IFORCE_MAX_LENGTH) {
- iforce->pkt = 0;
- iforce->id = 0;
+ iforce_serio->pkt = 0;
+ iforce_serio->id = 0;
} else {
- iforce->len = data;
+ iforce_serio->len = data;
}
goto out;
}
- if (iforce->idx < iforce->len) {
- iforce->csum += iforce->data[iforce->idx++] = data;
+ if (iforce_serio->idx < iforce_serio->len) {
+ iforce_serio->data_in[iforce_serio->idx++] = data;
+ iforce_serio->csum += data;
goto out;
}
- if (iforce->idx == iforce->len) {
- iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
- iforce->pkt = 0;
- iforce->id = 0;
- iforce->len = 0;
- iforce->idx = 0;
- iforce->csum = 0;
+ if (iforce_serio->idx == iforce_serio->len) {
+ /* Handle command completion */
+ if (iforce_serio->expect_packet == iforce_serio->id) {
+ iforce_serio->expect_packet = 0;
+ memcpy(iforce_serio->cmd_response,
+ iforce_serio->data_in, IFORCE_MAX_LENGTH);
+ iforce_serio->cmd_response_len = iforce_serio->len;
+
+ /* Signal that command is done */
+ wake_up(&iforce->wait);
+ } else if (likely(iforce->type)) {
+ iforce_process_packet(iforce, iforce_serio->id,
+ iforce_serio->data_in,
+ iforce_serio->len);
+ }
+
+ iforce_serio->pkt = 0;
+ iforce_serio->id = 0;
+ iforce_serio->len = 0;
+ iforce_serio->idx = 0;
+ iforce_serio->csum = 0;
}
out:
return IRQ_HANDLED;
@@ -122,23 +188,23 @@
static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
{
- struct iforce *iforce;
+ struct iforce_serio *iforce_serio;
int err;
- iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL);
- if (!iforce)
+ iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL);
+ if (!iforce_serio)
return -ENOMEM;
- iforce->bus = IFORCE_232;
- iforce->serio = serio;
+ iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops;
- serio_set_drvdata(serio, iforce);
+ iforce_serio->serio = serio;
+ serio_set_drvdata(serio, iforce_serio);
err = serio_open(serio, drv);
if (err)
goto fail1;
- err = iforce_init_device(iforce);
+ err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce);
if (err)
goto fail2;
@@ -146,18 +212,18 @@
fail2: serio_close(serio);
fail1: serio_set_drvdata(serio, NULL);
- kfree(iforce);
+ kfree(iforce_serio);
return err;
}
static void iforce_serio_disconnect(struct serio *serio)
{
- struct iforce *iforce = serio_get_drvdata(serio);
+ struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
- input_unregister_device(iforce->dev);
+ input_unregister_device(iforce_serio->iforce.dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
- kfree(iforce);
+ kfree(iforce_serio);
}
static const struct serio_device_id iforce_serio_ids[] = {
@@ -183,3 +249,9 @@
.connect = iforce_serio_connect,
.disconnect = iforce_serio_disconnect,
};
+
+module_serio_driver(iforce_serio_drv);
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
+MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 7807325..6c554c1 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
@@ -5,26 +6,24 @@
* USB/RS232 I-Force joysticks and wheels.
*/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
+#include <linux/usb.h>
#include "iforce.h"
-void iforce_usb_xmit(struct iforce *iforce)
+struct iforce_usb {
+ struct iforce iforce;
+
+ struct usb_device *usbdev;
+ struct usb_interface *intf;
+ struct urb *irq, *out;
+
+ u8 data_in[IFORCE_MAX_LENGTH] ____cacheline_aligned;
+ u8 data_out[IFORCE_MAX_LENGTH] ____cacheline_aligned;
+};
+
+static void __iforce_usb_xmit(struct iforce *iforce)
{
+ struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+ iforce);
int n, c;
unsigned long flags;
@@ -36,31 +35,32 @@
return;
}
- ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
+ ((char *)iforce_usb->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
n = iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
- iforce->out->transfer_buffer_length = n + 1;
- iforce->out->dev = iforce->usbdev;
+ iforce_usb->out->transfer_buffer_length = n + 1;
+ iforce_usb->out->dev = iforce_usb->usbdev;
/* Copy rest of data then */
c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
if (n < c) c=n;
- memcpy(iforce->out->transfer_buffer + 1,
+ memcpy(iforce_usb->out->transfer_buffer + 1,
&iforce->xmit.buf[iforce->xmit.tail],
c);
if (n != c) {
- memcpy(iforce->out->transfer_buffer + 1 + c,
+ memcpy(iforce_usb->out->transfer_buffer + 1 + c,
&iforce->xmit.buf[0],
n-c);
}
XMIT_INC(iforce->xmit.tail, n);
- if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
+ if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
- dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n);
+ dev_warn(&iforce_usb->intf->dev,
+ "usb_submit_urb failed %d\n", n);
}
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -69,10 +69,77 @@
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
+static void iforce_usb_xmit(struct iforce *iforce)
+{
+ if (!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags))
+ __iforce_usb_xmit(iforce);
+}
+
+static int iforce_usb_get_id(struct iforce *iforce, u8 id,
+ u8 *response_data, size_t *response_len)
+{
+ struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+ iforce);
+ u8 *buf;
+ int status;
+
+ buf = kmalloc(IFORCE_MAX_LENGTH, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ status = usb_control_msg(iforce_usb->usbdev,
+ usb_rcvctrlpipe(iforce_usb->usbdev, 0),
+ id,
+ USB_TYPE_VENDOR | USB_DIR_IN |
+ USB_RECIP_INTERFACE,
+ 0, 0, buf, IFORCE_MAX_LENGTH, HZ);
+ if (status < 0) {
+ dev_err(&iforce_usb->intf->dev,
+ "usb_submit_urb failed: %d\n", status);
+ } else if (buf[0] != id) {
+ status = -EIO;
+ } else {
+ memcpy(response_data, buf, status);
+ *response_len = status;
+ status = 0;
+ }
+
+ kfree(buf);
+ return status;
+}
+
+static int iforce_usb_start_io(struct iforce *iforce)
+{
+ struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+ iforce);
+
+ if (usb_submit_urb(iforce_usb->irq, GFP_KERNEL))
+ return -EIO;
+
+ return 0;
+}
+
+static void iforce_usb_stop_io(struct iforce *iforce)
+{
+ struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
+ iforce);
+
+ usb_kill_urb(iforce_usb->irq);
+ usb_kill_urb(iforce_usb->out);
+}
+
+static const struct iforce_xport_ops iforce_usb_xport_ops = {
+ .xmit = iforce_usb_xmit,
+ .get_id = iforce_usb_get_id,
+ .start_io = iforce_usb_start_io,
+ .stop_io = iforce_usb_stop_io,
+};
+
static void iforce_usb_irq(struct urb *urb)
{
- struct iforce *iforce = urb->context;
- struct device *dev = &iforce->intf->dev;
+ struct iforce_usb *iforce_usb = urb->context;
+ struct iforce *iforce = &iforce_usb->iforce;
+ struct device *dev = &iforce_usb->intf->dev;
int status;
switch (urb->status) {
@@ -92,11 +159,11 @@
goto exit;
}
- iforce_process_packet(iforce,
- (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
+ iforce_process_packet(iforce, iforce_usb->data_in[0],
+ iforce_usb->data_in + 1, urb->actual_length - 1);
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
+ status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
__func__, status);
@@ -104,35 +171,28 @@
static void iforce_usb_out(struct urb *urb)
{
- struct iforce *iforce = urb->context;
+ struct iforce_usb *iforce_usb = urb->context;
+ struct iforce *iforce = &iforce_usb->iforce;
if (urb->status) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
- dev_dbg(&iforce->intf->dev, "urb->status %d, exiting\n",
+ dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n",
urb->status);
return;
}
- iforce_usb_xmit(iforce);
+ __iforce_usb_xmit(iforce);
wake_up(&iforce->wait);
}
-static void iforce_usb_ctrl(struct urb *urb)
-{
- struct iforce *iforce = urb->context;
- if (urb->status) return;
- iforce->ecmd = 0xff00 | urb->actual_length;
- wake_up(&iforce->wait);
-}
-
static int iforce_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *epirq, *epout;
- struct iforce *iforce;
+ struct iforce_usb *iforce_usb;
int err = -ENOMEM;
interface = intf->cur_altsetting;
@@ -141,50 +201,52 @@
return -ENODEV;
epirq = &interface->endpoint[0].desc;
+ if (!usb_endpoint_is_int_in(epirq))
+ return -ENODEV;
+
epout = &interface->endpoint[1].desc;
+ if (!usb_endpoint_is_int_out(epout))
+ return -ENODEV;
- if (!(iforce = kzalloc(sizeof(struct iforce) + 32, GFP_KERNEL)))
+ iforce_usb = kzalloc(sizeof(*iforce_usb), GFP_KERNEL);
+ if (!iforce_usb)
goto fail;
- if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL)))
+ iforce_usb->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!iforce_usb->irq)
goto fail;
- if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL)))
+ iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL);
+ if (!iforce_usb->out)
goto fail;
- if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL)))
- goto fail;
+ iforce_usb->iforce.xport_ops = &iforce_usb_xport_ops;
- iforce->bus = IFORCE_USB;
- iforce->usbdev = dev;
- iforce->intf = intf;
+ iforce_usb->usbdev = dev;
+ iforce_usb->intf = intf;
- iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
- iforce->cr.wIndex = 0;
- iforce->cr.wLength = cpu_to_le16(16);
+ usb_fill_int_urb(iforce_usb->irq, dev,
+ usb_rcvintpipe(dev, epirq->bEndpointAddress),
+ iforce_usb->data_in, sizeof(iforce_usb->data_in),
+ iforce_usb_irq, iforce_usb, epirq->bInterval);
- usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
- iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
+ usb_fill_int_urb(iforce_usb->out, dev,
+ usb_sndintpipe(dev, epout->bEndpointAddress),
+ iforce_usb->data_out, sizeof(iforce_usb->data_out),
+ iforce_usb_out, iforce_usb, epout->bInterval);
- usb_fill_int_urb(iforce->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress),
- iforce + 1, 32, iforce_usb_out, iforce, epout->bInterval);
-
- usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
- (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce);
-
- err = iforce_init_device(iforce);
+ err = iforce_init_device(&intf->dev, BUS_USB, &iforce_usb->iforce);
if (err)
goto fail;
- usb_set_intfdata(intf, iforce);
+ usb_set_intfdata(intf, iforce_usb);
return 0;
fail:
- if (iforce) {
- usb_free_urb(iforce->irq);
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->ctrl);
- kfree(iforce);
+ if (iforce_usb) {
+ usb_free_urb(iforce_usb->irq);
+ usb_free_urb(iforce_usb->out);
+ kfree(iforce_usb);
}
return err;
@@ -192,17 +254,16 @@
static void iforce_usb_disconnect(struct usb_interface *intf)
{
- struct iforce *iforce = usb_get_intfdata(intf);
+ struct iforce_usb *iforce_usb = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
- input_unregister_device(iforce->dev);
+ input_unregister_device(iforce_usb->iforce.dev);
- usb_free_urb(iforce->irq);
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->ctrl);
+ usb_free_urb(iforce_usb->irq);
+ usb_free_urb(iforce_usb->out);
- kfree(iforce);
+ kfree(iforce_usb);
}
static const struct usb_device_id iforce_usb_ids[] = {
@@ -214,6 +275,7 @@
{ USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
{ USB_DEVICE(0x061c, 0xc084) }, /* ACT LABS Force RS */
+ { USB_DEVICE(0x06a3, 0xff04) }, /* Saitek R440 Force Wheel */
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0003) }, /* Guillemot Jet Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
@@ -229,3 +291,9 @@
.disconnect = iforce_usb_disconnect,
.id_table = iforce_usb_ids,
};
+
+module_usb_driver(iforce_usb_driver);
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
+MODULE_DESCRIPTION("USB I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index 0e9d01f..6aa761e 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
@@ -5,29 +6,11 @@
* USB/RS232 I-Force joysticks and wheels.
*/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/serio.h>
#include <linux/circ_buf.h>
#include <linux/mutex.h>
@@ -40,10 +23,6 @@
#define IFORCE_MAX_LENGTH 16
-/* iforce::bus */
-#define IFORCE_232 1
-#define IFORCE_USB 2
-
#define IFORCE_EFFECTS_MAX 32
/* Each force feedback effect is made of one core effect, which can be
@@ -93,27 +72,21 @@
signed short *ff;
};
+struct iforce;
+
+struct iforce_xport_ops {
+ void (*xmit)(struct iforce *iforce);
+ int (*get_id)(struct iforce *iforce, u8 id,
+ u8 *response_data, size_t *response_len);
+ int (*start_io)(struct iforce *iforce);
+ void (*stop_io)(struct iforce *iforce);
+};
+
struct iforce {
struct input_dev *dev; /* Input device interface */
struct iforce_device *type;
- int bus;
+ const struct iforce_xport_ops *xport_ops;
- unsigned char data[IFORCE_MAX_LENGTH];
- unsigned char edata[IFORCE_MAX_LENGTH];
- u16 ecmd;
- u16 expect_packet;
-
-#ifdef CONFIG_JOYSTICK_IFORCE_232
- struct serio *serio; /* RS232 transfer */
- int idx, pkt, len, id;
- unsigned char csum;
-#endif
-#ifdef CONFIG_JOYSTICK_IFORCE_USB
- struct usb_device *usbdev; /* USB transfer */
- struct usb_interface *intf;
- struct urb *irq, *out, *ctrl;
- struct usb_ctrlrequest cr;
-#endif
spinlock_t xmit_lock;
/* Buffer used for asynchronous sending of bytes to the device */
struct circ_buf xmit;
@@ -139,23 +112,24 @@
/* Encode a time value */
#define TIME_SCALE(a) (a)
+static inline int iforce_get_id_packet(struct iforce *iforce, u8 id,
+ u8 *response_data, size_t *response_len)
+{
+ return iforce->xport_ops->get_id(iforce, id,
+ response_data, response_len);
+}
/* Public functions */
-/* iforce-serio.c */
-void iforce_serial_xmit(struct iforce *iforce);
-
-/* iforce-usb.c */
-void iforce_usb_xmit(struct iforce *iforce);
-
/* iforce-main.c */
-int iforce_init_device(struct iforce *iforce);
+int iforce_init_device(struct device *parent, u16 bustype,
+ struct iforce *iforce);
/* iforce-packets.c */
int iforce_control_playback(struct iforce*, u16 id, unsigned int);
-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data);
+void iforce_process_packet(struct iforce *iforce,
+ u8 packet_id, u8 *data, size_t len);
int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data);
void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data);
-int iforce_get_id_packet(struct iforce *iforce, char *packet);
/* iforce-ff.c */
int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *);
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index 598788b..ca22d84 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2001 Vojtech Pavlik
*
@@ -10,19 +11,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c
index 344ab44..70f63f9 100644
--- a/drivers/input/joystick/joydump.c
+++ b/drivers/input/joystick/joydump.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1996-2001 Vojtech Pavlik
*/
@@ -8,19 +9,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index 95a34ab..edb8e19 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/maplecontrol.c b/drivers/input/joystick/maplecontrol.c
index ff54e19..3833ac4 100644
--- a/drivers/input/joystick/maplecontrol.c
+++ b/drivers/input/joystick/maplecontrol.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SEGA Dreamcast controller driver
* Based on drivers/usb/iforce.c
diff --git a/drivers/input/joystick/psxpad-spi.c b/drivers/input/joystick/psxpad-spi.c
index 28b473f..7eee1b0 100644
--- a/drivers/input/joystick/psxpad-spi.c
+++ b/drivers/input/joystick/psxpad-spi.c
@@ -1,8 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* PlayStation 1/2 joypads via SPI interface Driver
*
* Copyright (C) 2017 Tomohiro Yoshidomi <sylph23k@gmail.com>
- * Licensed under the GPL-2 or later.
*
* PlayStation 1/2 joypad's plug (not socket)
* 123 456 789
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index f46bf4d..1777e68 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1998-2005 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
@@ -235,7 +223,7 @@
static void sw_init_digital(struct gameport *gameport)
{
- int seq[] = { 140, 140+725, 140+300, 0 };
+ static const int seq[] = { 140, 140+725, 140+300, 0 };
unsigned long flags;
int i, t;
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index ffb9c1f..cf7cbcd 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -11,19 +12,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index 20540ee..5571714 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -10,19 +11,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index ba85794..c20425f 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2000 Mark Fletcher
@@ -8,19 +9,6 @@
*/
/*
- * This program is free warftware; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index 6f4a01c..f89e9aa 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1998-2001 Vojtech Pavlik
*
@@ -10,19 +11,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index bf2f992..dfe7a2c 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1998-2001 Vojtech Pavlik
*
@@ -10,19 +11,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index e60cb00..174c69a 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2001 Arndt Schoenewald
* Copyright (c) 2000-2001 Vojtech Pavlik
@@ -32,19 +33,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c
index dce313d..56abc8c 100644
--- a/drivers/input/joystick/walkera0701.c
+++ b/drivers/input/joystick/walkera0701.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Parallel port to Walkera WK-0701 TX joystick
*
@@ -6,11 +7,6 @@
* More about driver: <file:Documentation/input/devices/walkera0701.rst>
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
-*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index b60cab1..42bdbc2 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free warftware; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index cfc8b94..6b40a1c 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* X-Box gamepad driver
*
@@ -11,21 +12,6 @@
* 2007 Jan Kratochvil <honza@jikos.cz>
* 2010 Christoph Fritz <chf.fritz@googlemail.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
* This driver is based on:
* - information from http://euc.jp/periphs/xbox-controller.ja.html
* - the iForce driver drivers/char/joystick/iforce.c
@@ -252,6 +238,8 @@
{ 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
+ { 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
+ { 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
{ 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 },
{ 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 },
@@ -428,6 +416,7 @@
XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */
XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */
+ XPAD_XBOX360_VENDOR(0x1038), /* SteelSeries Controllers */
XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */
XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
diff --git a/drivers/input/joystick/zhenhua.c b/drivers/input/joystick/zhenhua.c
index 5c6d5de..d553117 100644
--- a/drivers/input/joystick/zhenhua.c
+++ b/drivers/input/joystick/zhenhua.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* derived from "twidjoy.c"
*
@@ -5,7 +6,6 @@
* Copyright (c) 2001 Arndt Schoenewald
* Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2000 Mark Fletcher
- *
*/
/*
@@ -29,19 +29,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 4713957..8911bc2 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Input core configuration
#
@@ -70,6 +71,24 @@
config ATARI_KBD_CORE
bool
+config KEYBOARD_APPLESPI
+ tristate "Apple SPI keyboard and trackpad"
+ depends on ACPI && EFI
+ depends on SPI
+ depends on X86 || COMPILE_TEST
+ depends on LEDS_CLASS
+ select CRC16
+ help
+ Say Y here if you are running Linux on any Apple MacBook8,1 or later,
+ or any MacBookPro13,* or MacBookPro14,*.
+
+ You will also need to enable appropriate SPI master controllers:
+ spi_pxa2xx_platform and spi_pxa2xx_pci for MacBook8,1, and
+ spi_pxa2xx_platform and intel_lpss_pci for the rest.
+
+ To compile this driver as a module, choose M here: the
+ module will be called applespi.
+
config KEYBOARD_ATARI
tristate "Atari keyboard"
depends on ATARI
@@ -137,6 +156,17 @@
right-hand column will be interpreted as the key shown in the
left-hand column.
+config KEYBOARD_QT1050
+ tristate "Microchip AT42QT1050 Touch Sensor Chip"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y here if you want to use Microchip AT42QT1050 QTouch
+ Sensor chip as input device.
+
+ To compile this driver as a module, choose M here:
+ the module will be called qt1050
+
config KEYBOARD_QT1070
tristate "Atmel AT42QT1070 Touch Sensor Chip"
depends on I2C
@@ -194,7 +224,7 @@
config KEYBOARD_EP93XX
tristate "EP93xx Matrix Keypad support"
- depends on ARCH_EP93XX
+ depends on ARCH_EP93XX || COMPILE_TEST
select INPUT_MATRIXKMAP
help
Say Y here to enable the matrix keypad on the Cirrus EP93XX.
@@ -420,7 +450,7 @@
config KEYBOARD_SNVS_PWRKEY
tristate "IMX SNVS Power Key Driver"
- depends on SOC_IMX6SX
+ depends on ARCH_MXC || COMPILE_TEST
depends on OF
help
This is the snvs powerkey driver for the Freescale i.MX application
@@ -703,21 +733,10 @@
To compile this driver as a module, choose M here: the
module will be called xtkbd.
-config KEYBOARD_W90P910
- tristate "W90P910 Matrix Keypad support"
- depends on ARCH_W90X900
- select INPUT_MATRIXKMAP
- help
- Say Y here to enable the matrix keypad on evaluation board
- based on W90P910.
-
- To compile this driver as a module, choose M here: the
- module will be called w90p910_keypad.
-
config KEYBOARD_CROS_EC
tristate "ChromeOS EC keyboard"
select INPUT_MATRIXKMAP
- depends on MFD_CROS_EC
+ depends on CROS_EC
help
Say Y here to enable the matrix keyboard used by ChromeOS devices
and implemented on the ChromeOS EC. You must enable one bus option
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 182e929..9510325 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -10,6 +10,7 @@
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
+obj-$(CONFIG_KEYBOARD_APPLESPI) += applespi.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o
@@ -50,6 +51,7 @@
obj-$(CONFIG_KEYBOARD_PMIC8XXX) += pmic8xxx-keypad.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
+obj-$(CONFIG_KEYBOARD_QT1050) += qt1050.o
obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
@@ -66,4 +68,3 @@
obj-$(CONFIG_KEYBOARD_TM2_TOUCHKEY) += tm2-touchkey.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
-obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
index c255af2..9885fd5 100644
--- a/drivers/input/keyboard/adc-keys.c
+++ b/drivers/input/keyboard/adc-keys.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input driver for resistor ladder connected on ADC
*
* Copyright (c) 2016 Alexandre Belloni
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/err.h>
diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c
index f0b9b37..7851ffd 100644
--- a/drivers/input/keyboard/adp5520-keys.c
+++ b/drivers/input/keyboard/adp5520-keys.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Keypad driver for Analog Devices ADP5520 MFD PMICs
*
* Copyright 2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index f9d273c..90a59b9 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* File: drivers/input/keyboard/adp5588_keys.c
* Description: keypad driver for ADP5588 and ADP5587
@@ -5,7 +6,6 @@
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2008-2010 Analog Devices Inc.
- * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index 2835fba..4f96a4a 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -1,10 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Description: keypad driver for ADP5589, ADP5585
* I2C QWERTY Keypad and IO Expander
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2010-2011 Analog Devices Inc.
- * Licensed under the GPL-2.
*/
#include <linux/module.h>
@@ -505,6 +505,7 @@
if (!gpio_data)
return 0;
+ kpad->gc.parent = dev;
kpad->gc.ngpio = adp5589_build_gpiomap(kpad, pdata);
if (kpad->gc.ngpio == 0) {
dev_info(dev, "No unused gpios left to export\n");
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
index 420e33c..09551f6 100644
--- a/drivers/input/keyboard/amikbd.c
+++ b/drivers/input/keyboard/amikbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
@@ -10,19 +11,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
new file mode 100644
index 0000000..d383985
--- /dev/null
+++ b/drivers/input/keyboard/applespi.c
@@ -0,0 +1,1962 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MacBook (Pro) SPI keyboard and touchpad driver
+ *
+ * Copyright (c) 2015-2018 Federico Lorenzi
+ * Copyright (c) 2017-2018 Ronald Tschalär
+ */
+
+/*
+ * The keyboard and touchpad controller on the MacBookAir6, MacBookPro12,
+ * MacBook8 and newer can be driven either by USB or SPI. However the USB
+ * pins are only connected on the MacBookAir6 and 7 and the MacBookPro12.
+ * All others need this driver. The interface is selected using ACPI methods:
+ *
+ * * UIEN ("USB Interface Enable"): If invoked with argument 1, disables SPI
+ * and enables USB. If invoked with argument 0, disables USB.
+ * * UIST ("USB Interface Status"): Returns 1 if USB is enabled, 0 otherwise.
+ * * SIEN ("SPI Interface Enable"): If invoked with argument 1, disables USB
+ * and enables SPI. If invoked with argument 0, disables SPI.
+ * * SIST ("SPI Interface Status"): Returns 1 if SPI is enabled, 0 otherwise.
+ * * ISOL: Resets the four GPIO pins used for SPI. Intended to be invoked with
+ * argument 1, then once more with argument 0.
+ *
+ * UIEN and UIST are only provided on models where the USB pins are connected.
+ *
+ * SPI-based Protocol
+ * ------------------
+ *
+ * The device and driver exchange messages (struct message); each message is
+ * encapsulated in one or more packets (struct spi_packet). There are two types
+ * of exchanges: reads, and writes. A read is signaled by a GPE, upon which one
+ * message can be read from the device. A write exchange consists of writing a
+ * command message, immediately reading a short status packet, and then, upon
+ * receiving a GPE, reading the response message. Write exchanges cannot be
+ * interleaved, i.e. a new write exchange must not be started till the previous
+ * write exchange is complete. Whether a received message is part of a read or
+ * write exchange is indicated in the encapsulating packet's flags field.
+ *
+ * A single message may be too large to fit in a single packet (which has a
+ * fixed, 256-byte size). In that case it will be split over multiple,
+ * consecutive packets.
+ */
+
+#include <linux/acpi.h>
+#include <linux/crc16.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/efi.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <asm/barrier.h>
+#include <asm/unaligned.h>
+
+#define CREATE_TRACE_POINTS
+#include "applespi.h"
+#include "applespi_trace.h"
+
+#define APPLESPI_PACKET_SIZE 256
+#define APPLESPI_STATUS_SIZE 4
+
+#define PACKET_TYPE_READ 0x20
+#define PACKET_TYPE_WRITE 0x40
+#define PACKET_DEV_KEYB 0x01
+#define PACKET_DEV_TPAD 0x02
+#define PACKET_DEV_INFO 0xd0
+
+#define MAX_ROLLOVER 6
+
+#define MAX_FINGERS 11
+#define MAX_FINGER_ORIENTATION 16384
+#define MAX_PKTS_PER_MSG 2
+
+#define KBD_BL_LEVEL_MIN 32U
+#define KBD_BL_LEVEL_MAX 255U
+#define KBD_BL_LEVEL_SCALE 1000000U
+#define KBD_BL_LEVEL_ADJ \
+ ((KBD_BL_LEVEL_MAX - KBD_BL_LEVEL_MIN) * KBD_BL_LEVEL_SCALE / 255U)
+
+#define EFI_BL_LEVEL_NAME L"KeyboardBacklightLevel"
+#define EFI_BL_LEVEL_GUID EFI_GUID(0xa076d2af, 0x9678, 0x4386, 0x8b, 0x58, 0x1f, 0xc8, 0xef, 0x04, 0x16, 0x19)
+
+#define APPLE_FLAG_FKEY 0x01
+
+#define SPI_RW_CHG_DELAY_US 100 /* from experimentation, in µs */
+
+#define SYNAPTICS_VENDOR_ID 0x06cb
+
+static unsigned int fnmode = 1;
+module_param(fnmode, uint, 0644);
+MODULE_PARM_DESC(fnmode, "Mode of Fn key on Apple keyboards (0 = disabled, [1] = fkeyslast, 2 = fkeysfirst)");
+
+static unsigned int fnremap;
+module_param(fnremap, uint, 0644);
+MODULE_PARM_DESC(fnremap, "Remap Fn key ([0] = no-remap; 1 = left-ctrl, 2 = left-shift, 3 = left-alt, 4 = left-meta, 6 = right-shift, 7 = right-alt, 8 = right-meta)");
+
+static bool iso_layout;
+module_param(iso_layout, bool, 0644);
+MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. ([0] = disabled, 1 = enabled)");
+
+static char touchpad_dimensions[40];
+module_param_string(touchpad_dimensions, touchpad_dimensions,
+ sizeof(touchpad_dimensions), 0444);
+MODULE_PARM_DESC(touchpad_dimensions, "The pixel dimensions of the touchpad, as XxY+W+H .");
+
+/**
+ * struct keyboard_protocol - keyboard message.
+ * message.type = 0x0110, message.length = 0x000a
+ *
+ * @unknown1: unknown
+ * @modifiers: bit-set of modifier/control keys pressed
+ * @unknown2: unknown
+ * @keys_pressed: the (non-modifier) keys currently pressed
+ * @fn_pressed: whether the fn key is currently pressed
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct keyboard_protocol {
+ u8 unknown1;
+ u8 modifiers;
+ u8 unknown2;
+ u8 keys_pressed[MAX_ROLLOVER];
+ u8 fn_pressed;
+ __le16 crc16;
+};
+
+/**
+ * struct tp_finger - single trackpad finger structure, le16-aligned
+ *
+ * @origin: zero when switching track finger
+ * @abs_x: absolute x coordinate
+ * @abs_y: absolute y coordinate
+ * @rel_x: relative x coordinate
+ * @rel_y: relative y coordinate
+ * @tool_major: tool area, major axis
+ * @tool_minor: tool area, minor axis
+ * @orientation: 16384 when point, else 15 bit angle
+ * @touch_major: touch area, major axis
+ * @touch_minor: touch area, minor axis
+ * @unused: zeros
+ * @pressure: pressure on forcetouch touchpad
+ * @multi: one finger: varies, more fingers: constant
+ * @crc16: on last finger: crc over the whole message struct
+ * (i.e. message header + this struct) minus the last
+ * @crc16 field; unknown on all other fingers.
+ */
+struct tp_finger {
+ __le16 origin;
+ __le16 abs_x;
+ __le16 abs_y;
+ __le16 rel_x;
+ __le16 rel_y;
+ __le16 tool_major;
+ __le16 tool_minor;
+ __le16 orientation;
+ __le16 touch_major;
+ __le16 touch_minor;
+ __le16 unused[2];
+ __le16 pressure;
+ __le16 multi;
+ __le16 crc16;
+};
+
+/**
+ * struct touchpad_protocol - touchpad message.
+ * message.type = 0x0210
+ *
+ * @unknown1: unknown
+ * @clicked: 1 if a button-click was detected, 0 otherwise
+ * @unknown2: unknown
+ * @number_of_fingers: the number of fingers being reported in @fingers
+ * @clicked2: same as @clicked
+ * @unknown3: unknown
+ * @fingers: the data for each finger
+ */
+struct touchpad_protocol {
+ u8 unknown1[1];
+ u8 clicked;
+ u8 unknown2[28];
+ u8 number_of_fingers;
+ u8 clicked2;
+ u8 unknown3[16];
+ struct tp_finger fingers[0];
+};
+
+/**
+ * struct command_protocol_tp_info - get touchpad info.
+ * message.type = 0x1020, message.length = 0x0000
+ *
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct command_protocol_tp_info {
+ __le16 crc16;
+};
+
+/**
+ * struct touchpad_info - touchpad info response.
+ * message.type = 0x1020, message.length = 0x006e
+ *
+ * @unknown1: unknown
+ * @model_flags: flags (vary by model number, but significance otherwise
+ * unknown)
+ * @model_no: the touchpad model number
+ * @unknown2: unknown
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct touchpad_info_protocol {
+ u8 unknown1[105];
+ u8 model_flags;
+ u8 model_no;
+ u8 unknown2[3];
+ __le16 crc16;
+};
+
+/**
+ * struct command_protocol_mt_init - initialize multitouch.
+ * message.type = 0x0252, message.length = 0x0002
+ *
+ * @cmd: value: 0x0102
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct command_protocol_mt_init {
+ __le16 cmd;
+ __le16 crc16;
+};
+
+/**
+ * struct command_protocol_capsl - toggle caps-lock led
+ * message.type = 0x0151, message.length = 0x0002
+ *
+ * @unknown: value: 0x01 (length?)
+ * @led: 0 off, 2 on
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct command_protocol_capsl {
+ u8 unknown;
+ u8 led;
+ __le16 crc16;
+};
+
+/**
+ * struct command_protocol_bl - set keyboard backlight brightness
+ * message.type = 0xB051, message.length = 0x0006
+ *
+ * @const1: value: 0x01B0
+ * @level: the brightness level to set
+ * @const2: value: 0x0001 (backlight off), 0x01F4 (backlight on)
+ * @crc16: crc over the whole message struct (message header +
+ * this struct) minus this @crc16 field
+ */
+struct command_protocol_bl {
+ __le16 const1;
+ __le16 level;
+ __le16 const2;
+ __le16 crc16;
+};
+
+/**
+ * struct message - a complete spi message.
+ *
+ * Each message begins with fixed header, followed by a message-type specific
+ * payload, and ends with a 16-bit crc. Because of the varying lengths of the
+ * payload, the crc is defined at the end of each payload struct, rather than
+ * in this struct.
+ *
+ * @type: the message type
+ * @zero: always 0
+ * @counter: incremented on each message, rolls over after 255; there is a
+ * separate counter for each message type.
+ * @rsp_buf_len:response buffer length (the exact nature of this field is quite
+ * speculative). On a request/write this is often the same as
+ * @length, though in some cases it has been seen to be much larger
+ * (e.g. 0x400); on a response/read this the same as on the
+ * request; for reads that are not responses it is 0.
+ * @length: length of the remainder of the data in the whole message
+ * 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.
+ */
+struct message {
+ __le16 type;
+ u8 zero;
+ u8 counter;
+ __le16 rsp_buf_len;
+ __le16 length;
+ union {
+ struct keyboard_protocol keyboard;
+ struct touchpad_protocol touchpad;
+ struct touchpad_info_protocol tp_info;
+ struct command_protocol_tp_info tp_info_command;
+ struct command_protocol_mt_init init_mt_command;
+ struct command_protocol_capsl capsl_command;
+ struct command_protocol_bl bl_command;
+ u8 data[0];
+ };
+};
+
+/* type + zero + counter + rsp_buf_len + length */
+#define MSG_HEADER_SIZE 8
+
+/**
+ * struct spi_packet - a complete spi packet; always 256 bytes. This carries
+ * the (parts of the) message in the data. But note that this does not
+ * necessarily contain a complete message, as in some cases (e.g. many
+ * fingers pressed) the message is split over multiple packets (see the
+ * @offset, @remaining, and @length fields). In general the data parts in
+ * spi_packet's are concatenated until @remaining is 0, and the result is an
+ * message.
+ *
+ * @flags: 0x40 = write (to device), 0x20 = read (from device); note that
+ * the response to a write still has 0x40.
+ * @device: 1 = keyboard, 2 = touchpad
+ * @offset: specifies the offset of this packet's data in the complete
+ * message; i.e. > 0 indicates this is a continuation packet (in
+ * the second packet for a message split over multiple packets
+ * this would then be the same as the @length in the first packet)
+ * @remaining: number of message bytes remaining in subsequents packets (in
+ * the first packet of a message split over two packets this would
+ * then be the same as the @length in the second packet)
+ * @length: length of the valid data in the @data in this packet
+ * @data: all or part of a message
+ * @crc16: crc over this whole structure minus this @crc16 field. This
+ * covers just this packet, even on multi-packet messages (in
+ * contrast to the crc in the message).
+ */
+struct spi_packet {
+ u8 flags;
+ u8 device;
+ __le16 offset;
+ __le16 remaining;
+ __le16 length;
+ u8 data[246];
+ __le16 crc16;
+};
+
+struct spi_settings {
+ u64 spi_cs_delay; /* cs-to-clk delay in us */
+ u64 reset_a2r_usec; /* active-to-receive delay? */
+ u64 reset_rec_usec; /* ? (cur val: 10) */
+};
+
+/* this mimics struct drm_rect */
+struct applespi_tp_info {
+ int x_min;
+ int y_min;
+ int x_max;
+ int y_max;
+};
+
+struct applespi_data {
+ struct spi_device *spi;
+ struct spi_settings spi_settings;
+ struct input_dev *keyboard_input_dev;
+ struct input_dev *touchpad_input_dev;
+
+ u8 *tx_buffer;
+ u8 *tx_status;
+ u8 *rx_buffer;
+
+ u8 *msg_buf;
+ unsigned int saved_msg_len;
+
+ struct applespi_tp_info tp_info;
+
+ u8 last_keys_pressed[MAX_ROLLOVER];
+ u8 last_keys_fn_pressed[MAX_ROLLOVER];
+ u8 last_fn_pressed;
+ struct input_mt_pos pos[MAX_FINGERS];
+ int slots[MAX_FINGERS];
+ int gpe;
+ acpi_handle sien;
+ acpi_handle sist;
+
+ struct spi_transfer dl_t;
+ struct spi_transfer rd_t;
+ struct spi_message rd_m;
+
+ struct spi_transfer ww_t;
+ struct spi_transfer wd_t;
+ struct spi_transfer wr_t;
+ struct spi_transfer st_t;
+ struct spi_message wr_m;
+
+ bool want_tp_info_cmd;
+ bool want_mt_init_cmd;
+ bool want_cl_led_on;
+ bool have_cl_led_on;
+ unsigned int want_bl_level;
+ unsigned int have_bl_level;
+ unsigned int cmd_msg_cntr;
+ /* lock to protect the above parameters and flags below */
+ spinlock_t cmd_msg_lock;
+ bool cmd_msg_queued;
+ enum applespi_evt_type cmd_evt_type;
+
+ struct led_classdev backlight_info;
+
+ bool suspended;
+ bool drain;
+ wait_queue_head_t drain_complete;
+ bool read_active;
+ bool write_active;
+
+ struct work_struct work;
+ struct touchpad_info_protocol rcvd_tp_info;
+
+ struct dentry *debugfs_root;
+ bool debug_tp_dim;
+ char tp_dim_val[40];
+ int tp_dim_min_x;
+ int tp_dim_max_x;
+ int tp_dim_min_y;
+ int tp_dim_max_y;
+};
+
+static const unsigned char applespi_scancodes[] = {
+ 0, 0, 0, 0,
+ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
+ KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+ KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,
+ KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
+ KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS,
+ KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0,
+ KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT, KEY_SLASH,
+ KEY_CAPSLOCK,
+ KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9,
+ KEY_F10, KEY_F11, KEY_F12, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_102ND,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RO, 0, KEY_YEN, 0, 0, 0, 0, 0,
+ 0, KEY_KATAKANAHIRAGANA, KEY_MUHENKAN
+};
+
+/*
+ * This must have exactly as many entries as there are bits in
+ * struct keyboard_protocol.modifiers .
+ */
+static const unsigned char applespi_controlcodes[] = {
+ KEY_LEFTCTRL,
+ KEY_LEFTSHIFT,
+ KEY_LEFTALT,
+ KEY_LEFTMETA,
+ 0,
+ KEY_RIGHTSHIFT,
+ KEY_RIGHTALT,
+ KEY_RIGHTMETA
+};
+
+struct applespi_key_translation {
+ u16 from;
+ u16 to;
+ u8 flags;
+};
+
+static const struct applespi_key_translation applespi_fn_codes[] = {
+ { KEY_BACKSPACE, KEY_DELETE },
+ { KEY_ENTER, KEY_INSERT },
+ { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+ { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
+ { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY },
+ { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY },
+ { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY },
+ { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY },
+ { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY },
+ { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY },
+ { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY },
+ { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY },
+ { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
+ { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
+ { KEY_RIGHT, KEY_END },
+ { KEY_LEFT, KEY_HOME },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_UP, KEY_PAGEUP },
+ { }
+};
+
+static const struct applespi_key_translation apple_iso_keyboard[] = {
+ { KEY_GRAVE, KEY_102ND },
+ { KEY_102ND, KEY_GRAVE },
+ { }
+};
+
+struct applespi_tp_model_info {
+ u16 model;
+ struct applespi_tp_info tp_info;
+};
+
+static const struct applespi_tp_model_info applespi_tp_models[] = {
+ {
+ .model = 0x04, /* MB8 MB9 MB10 */
+ .tp_info = { -5087, -182, 5579, 6089 },
+ },
+ {
+ .model = 0x05, /* MBP13,1 MBP13,2 MBP14,1 MBP14,2 */
+ .tp_info = { -6243, -170, 6749, 7685 },
+ },
+ {
+ .model = 0x06, /* MBP13,3 MBP14,3 */
+ .tp_info = { -7456, -163, 7976, 9283 },
+ },
+ {}
+};
+
+typedef void (*applespi_trace_fun)(enum applespi_evt_type,
+ enum applespi_pkt_type, u8 *, size_t);
+
+static applespi_trace_fun applespi_get_trace_fun(enum applespi_evt_type type)
+{
+ switch (type) {
+ case ET_CMD_TP_INI:
+ return trace_applespi_tp_ini_cmd;
+ case ET_CMD_BL:
+ return trace_applespi_backlight_cmd;
+ case ET_CMD_CL:
+ return trace_applespi_caps_lock_cmd;
+ case ET_RD_KEYB:
+ return trace_applespi_keyboard_data;
+ case ET_RD_TPAD:
+ return trace_applespi_touchpad_data;
+ case ET_RD_UNKN:
+ return trace_applespi_unknown_data;
+ default:
+ WARN_ONCE(1, "Unknown msg type %d", type);
+ return trace_applespi_unknown_data;
+ }
+}
+
+static void applespi_setup_read_txfrs(struct applespi_data *applespi)
+{
+ struct spi_message *msg = &applespi->rd_m;
+ struct spi_transfer *dl_t = &applespi->dl_t;
+ struct spi_transfer *rd_t = &applespi->rd_t;
+
+ memset(dl_t, 0, sizeof(*dl_t));
+ memset(rd_t, 0, sizeof(*rd_t));
+
+ dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay;
+
+ rd_t->rx_buf = applespi->rx_buffer;
+ rd_t->len = APPLESPI_PACKET_SIZE;
+
+ spi_message_init(msg);
+ spi_message_add_tail(dl_t, msg);
+ spi_message_add_tail(rd_t, msg);
+}
+
+static void applespi_setup_write_txfrs(struct applespi_data *applespi)
+{
+ struct spi_message *msg = &applespi->wr_m;
+ struct spi_transfer *wt_t = &applespi->ww_t;
+ struct spi_transfer *dl_t = &applespi->wd_t;
+ struct spi_transfer *wr_t = &applespi->wr_t;
+ struct spi_transfer *st_t = &applespi->st_t;
+
+ memset(wt_t, 0, sizeof(*wt_t));
+ memset(dl_t, 0, sizeof(*dl_t));
+ memset(wr_t, 0, sizeof(*wr_t));
+ memset(st_t, 0, sizeof(*st_t));
+
+ /*
+ * All we need here is a delay at the beginning of the message before
+ * asserting cs. But the current spi API doesn't support this, so we
+ * end up with an extra unnecessary (but harmless) cs assertion and
+ * deassertion.
+ */
+ wt_t->delay_usecs = SPI_RW_CHG_DELAY_US;
+ wt_t->cs_change = 1;
+
+ dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay;
+
+ wr_t->tx_buf = applespi->tx_buffer;
+ wr_t->len = APPLESPI_PACKET_SIZE;
+ wr_t->delay_usecs = SPI_RW_CHG_DELAY_US;
+
+ st_t->rx_buf = applespi->tx_status;
+ st_t->len = APPLESPI_STATUS_SIZE;
+
+ spi_message_init(msg);
+ spi_message_add_tail(wt_t, msg);
+ spi_message_add_tail(dl_t, msg);
+ spi_message_add_tail(wr_t, msg);
+ spi_message_add_tail(st_t, msg);
+}
+
+static int applespi_async(struct applespi_data *applespi,
+ struct spi_message *message, void (*complete)(void *))
+{
+ message->complete = complete;
+ message->context = applespi;
+
+ return spi_async(applespi->spi, message);
+}
+
+static inline bool applespi_check_write_status(struct applespi_data *applespi,
+ int sts)
+{
+ static u8 status_ok[] = { 0xac, 0x27, 0x68, 0xd5 };
+
+ if (sts < 0) {
+ dev_warn(&applespi->spi->dev, "Error writing to device: %d\n",
+ sts);
+ return false;
+ }
+
+ if (memcmp(applespi->tx_status, status_ok, APPLESPI_STATUS_SIZE)) {
+ dev_warn(&applespi->spi->dev, "Error writing to device: %*ph\n",
+ APPLESPI_STATUS_SIZE, applespi->tx_status);
+ return false;
+ }
+
+ return true;
+}
+
+static int applespi_get_spi_settings(struct applespi_data *applespi)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&applespi->spi->dev);
+ const union acpi_object *o;
+ struct spi_settings *settings = &applespi->spi_settings;
+
+ if (!acpi_dev_get_property(adev, "spiCSDelay", ACPI_TYPE_BUFFER, &o))
+ settings->spi_cs_delay = *(u64 *)o->buffer.pointer;
+ else
+ dev_warn(&applespi->spi->dev,
+ "Property spiCSDelay not found\n");
+
+ if (!acpi_dev_get_property(adev, "resetA2RUsec", ACPI_TYPE_BUFFER, &o))
+ settings->reset_a2r_usec = *(u64 *)o->buffer.pointer;
+ else
+ dev_warn(&applespi->spi->dev,
+ "Property resetA2RUsec not found\n");
+
+ if (!acpi_dev_get_property(adev, "resetRecUsec", ACPI_TYPE_BUFFER, &o))
+ settings->reset_rec_usec = *(u64 *)o->buffer.pointer;
+ else
+ dev_warn(&applespi->spi->dev,
+ "Property resetRecUsec not found\n");
+
+ dev_dbg(&applespi->spi->dev,
+ "SPI settings: spi_cs_delay=%llu reset_a2r_usec=%llu reset_rec_usec=%llu\n",
+ settings->spi_cs_delay, settings->reset_a2r_usec,
+ settings->reset_rec_usec);
+
+ return 0;
+}
+
+static int applespi_setup_spi(struct applespi_data *applespi)
+{
+ int sts;
+
+ sts = applespi_get_spi_settings(applespi);
+ if (sts)
+ return sts;
+
+ spin_lock_init(&applespi->cmd_msg_lock);
+ init_waitqueue_head(&applespi->drain_complete);
+
+ return 0;
+}
+
+static int applespi_enable_spi(struct applespi_data *applespi)
+{
+ acpi_status acpi_sts;
+ unsigned long long spi_status;
+
+ /* check if SPI is already enabled, so we can skip the delay below */
+ acpi_sts = acpi_evaluate_integer(applespi->sist, NULL, NULL,
+ &spi_status);
+ if (ACPI_SUCCESS(acpi_sts) && spi_status)
+ return 0;
+
+ /* SIEN(1) will enable SPI communication */
+ acpi_sts = acpi_execute_simple_method(applespi->sien, NULL, 1);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(&applespi->spi->dev, "SIEN failed: %s\n",
+ acpi_format_exception(acpi_sts));
+ return -ENODEV;
+ }
+
+ /*
+ * Allow the SPI interface to come up before returning. Without this
+ * delay, the SPI commands to enable multitouch mode may not reach
+ * the trackpad controller, causing pointer movement to break upon
+ * resume from sleep.
+ */
+ msleep(50);
+
+ return 0;
+}
+
+static int applespi_send_cmd_msg(struct applespi_data *applespi);
+
+static void applespi_msg_complete(struct applespi_data *applespi,
+ bool is_write_msg, bool is_read_compl)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (is_read_compl)
+ applespi->read_active = false;
+ if (is_write_msg)
+ applespi->write_active = false;
+
+ if (applespi->drain && !applespi->write_active)
+ wake_up_all(&applespi->drain_complete);
+
+ if (is_write_msg) {
+ applespi->cmd_msg_queued = false;
+ applespi_send_cmd_msg(applespi);
+ }
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static void applespi_async_write_complete(void *context)
+{
+ struct applespi_data *applespi = context;
+ enum applespi_evt_type evt_type = applespi->cmd_evt_type;
+
+ applespi_get_trace_fun(evt_type)(evt_type, PT_WRITE,
+ applespi->tx_buffer,
+ APPLESPI_PACKET_SIZE);
+ applespi_get_trace_fun(evt_type)(evt_type, PT_STATUS,
+ applespi->tx_status,
+ APPLESPI_STATUS_SIZE);
+
+ if (!applespi_check_write_status(applespi, applespi->wr_m.status)) {
+ /*
+ * If we got an error, we presumably won't get the expected
+ * response message either.
+ */
+ applespi_msg_complete(applespi, true, false);
+ }
+}
+
+static int applespi_send_cmd_msg(struct applespi_data *applespi)
+{
+ u16 crc;
+ int sts;
+ struct spi_packet *packet = (struct spi_packet *)applespi->tx_buffer;
+ struct message *message = (struct message *)packet->data;
+ u16 msg_len;
+ u8 device;
+
+ /* check if draining */
+ if (applespi->drain)
+ return 0;
+
+ /* check whether send is in progress */
+ if (applespi->cmd_msg_queued)
+ return 0;
+
+ /* set up packet */
+ memset(packet, 0, APPLESPI_PACKET_SIZE);
+
+ /* are we processing init commands? */
+ if (applespi->want_tp_info_cmd) {
+ applespi->want_tp_info_cmd = false;
+ applespi->want_mt_init_cmd = true;
+ applespi->cmd_evt_type = ET_CMD_TP_INI;
+
+ /* build init command */
+ device = PACKET_DEV_INFO;
+
+ message->type = cpu_to_le16(0x1020);
+ msg_len = sizeof(message->tp_info_command);
+
+ message->zero = 0x02;
+ message->rsp_buf_len = cpu_to_le16(0x0200);
+
+ } else if (applespi->want_mt_init_cmd) {
+ applespi->want_mt_init_cmd = false;
+ applespi->cmd_evt_type = ET_CMD_TP_INI;
+
+ /* build init command */
+ device = PACKET_DEV_TPAD;
+
+ message->type = cpu_to_le16(0x0252);
+ msg_len = sizeof(message->init_mt_command);
+
+ message->init_mt_command.cmd = cpu_to_le16(0x0102);
+
+ /* do we need caps-lock command? */
+ } else if (applespi->want_cl_led_on != applespi->have_cl_led_on) {
+ applespi->have_cl_led_on = applespi->want_cl_led_on;
+ applespi->cmd_evt_type = ET_CMD_CL;
+
+ /* build led command */
+ device = PACKET_DEV_KEYB;
+
+ message->type = cpu_to_le16(0x0151);
+ msg_len = sizeof(message->capsl_command);
+
+ message->capsl_command.unknown = 0x01;
+ message->capsl_command.led = applespi->have_cl_led_on ? 2 : 0;
+
+ /* do we need backlight command? */
+ } else if (applespi->want_bl_level != applespi->have_bl_level) {
+ applespi->have_bl_level = applespi->want_bl_level;
+ applespi->cmd_evt_type = ET_CMD_BL;
+
+ /* build command buffer */
+ device = PACKET_DEV_KEYB;
+
+ message->type = cpu_to_le16(0xB051);
+ msg_len = sizeof(message->bl_command);
+
+ message->bl_command.const1 = cpu_to_le16(0x01B0);
+ message->bl_command.level =
+ cpu_to_le16(applespi->have_bl_level);
+
+ if (applespi->have_bl_level > 0)
+ message->bl_command.const2 = cpu_to_le16(0x01F4);
+ else
+ message->bl_command.const2 = cpu_to_le16(0x0001);
+
+ /* everything's up-to-date */
+ } else {
+ return 0;
+ }
+
+ /* finalize packet */
+ packet->flags = PACKET_TYPE_WRITE;
+ packet->device = device;
+ packet->length = cpu_to_le16(MSG_HEADER_SIZE + msg_len);
+
+ message->counter = applespi->cmd_msg_cntr++ % (U8_MAX + 1);
+
+ message->length = cpu_to_le16(msg_len - 2);
+ if (!message->rsp_buf_len)
+ message->rsp_buf_len = message->length;
+
+ crc = crc16(0, (u8 *)message, le16_to_cpu(packet->length) - 2);
+ put_unaligned_le16(crc, &message->data[msg_len - 2]);
+
+ crc = crc16(0, (u8 *)packet, sizeof(*packet) - 2);
+ packet->crc16 = cpu_to_le16(crc);
+
+ /* send command */
+ sts = applespi_async(applespi, &applespi->wr_m,
+ applespi_async_write_complete);
+ if (sts) {
+ dev_warn(&applespi->spi->dev,
+ "Error queueing async write to device: %d\n", sts);
+ return sts;
+ }
+
+ applespi->cmd_msg_queued = true;
+ applespi->write_active = true;
+
+ return 0;
+}
+
+static void applespi_init(struct applespi_data *applespi, bool is_resume)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (is_resume)
+ applespi->want_mt_init_cmd = true;
+ else
+ applespi->want_tp_info_cmd = true;
+ applespi_send_cmd_msg(applespi);
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static int applespi_set_capsl_led(struct applespi_data *applespi,
+ bool capslock_on)
+{
+ unsigned long flags;
+ int sts;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ applespi->want_cl_led_on = capslock_on;
+ sts = applespi_send_cmd_msg(applespi);
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ return sts;
+}
+
+static void applespi_set_bl_level(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct applespi_data *applespi =
+ container_of(led_cdev, struct applespi_data, backlight_info);
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (value == 0) {
+ applespi->want_bl_level = value;
+ } else {
+ /*
+ * The backlight does not turn on till level 32, so we scale
+ * the range here so that from a user's perspective it turns
+ * on at 1.
+ */
+ applespi->want_bl_level =
+ ((value * KBD_BL_LEVEL_ADJ) / KBD_BL_LEVEL_SCALE +
+ KBD_BL_LEVEL_MIN);
+ }
+
+ applespi_send_cmd_msg(applespi);
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static int applespi_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int value)
+{
+ struct applespi_data *applespi = input_get_drvdata(dev);
+
+ switch (type) {
+ case EV_LED:
+ applespi_set_capsl_led(applespi, !!test_bit(LED_CAPSL, dev->led));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/* lifted from the BCM5974 driver and renamed from raw2int */
+/* convert 16-bit little endian to signed integer */
+static inline int le16_to_int(__le16 x)
+{
+ return (signed short)le16_to_cpu(x);
+}
+
+static void applespi_debug_update_dimensions(struct applespi_data *applespi,
+ const struct tp_finger *f)
+{
+ applespi->tp_dim_min_x = min(applespi->tp_dim_min_x,
+ le16_to_int(f->abs_x));
+ applespi->tp_dim_max_x = max(applespi->tp_dim_max_x,
+ le16_to_int(f->abs_x));
+ applespi->tp_dim_min_y = min(applespi->tp_dim_min_y,
+ le16_to_int(f->abs_y));
+ applespi->tp_dim_max_y = max(applespi->tp_dim_max_y,
+ le16_to_int(f->abs_y));
+}
+
+static int applespi_tp_dim_open(struct inode *inode, struct file *file)
+{
+ struct applespi_data *applespi = inode->i_private;
+
+ file->private_data = applespi;
+
+ snprintf(applespi->tp_dim_val, sizeof(applespi->tp_dim_val),
+ "0x%.4x %dx%d+%u+%u\n",
+ applespi->touchpad_input_dev->id.product,
+ applespi->tp_dim_min_x, applespi->tp_dim_min_y,
+ applespi->tp_dim_max_x - applespi->tp_dim_min_x,
+ applespi->tp_dim_max_y - applespi->tp_dim_min_y);
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t applespi_tp_dim_read(struct file *file, char __user *buf,
+ size_t len, loff_t *off)
+{
+ struct applespi_data *applespi = file->private_data;
+
+ return simple_read_from_buffer(buf, len, off, applespi->tp_dim_val,
+ strlen(applespi->tp_dim_val));
+}
+
+static const struct file_operations applespi_tp_dim_fops = {
+ .owner = THIS_MODULE,
+ .open = applespi_tp_dim_open,
+ .read = applespi_tp_dim_read,
+ .llseek = no_llseek,
+};
+
+static void report_finger_data(struct input_dev *input, int slot,
+ const struct input_mt_pos *pos,
+ const struct tp_finger *f)
+{
+ input_mt_slot(input, slot);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR,
+ le16_to_int(f->touch_major) << 1);
+ input_report_abs(input, ABS_MT_TOUCH_MINOR,
+ le16_to_int(f->touch_minor) << 1);
+ input_report_abs(input, ABS_MT_WIDTH_MAJOR,
+ le16_to_int(f->tool_major) << 1);
+ input_report_abs(input, ABS_MT_WIDTH_MINOR,
+ le16_to_int(f->tool_minor) << 1);
+ input_report_abs(input, ABS_MT_ORIENTATION,
+ MAX_FINGER_ORIENTATION - le16_to_int(f->orientation));
+ input_report_abs(input, ABS_MT_POSITION_X, pos->x);
+ input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
+}
+
+static void report_tp_state(struct applespi_data *applespi,
+ struct touchpad_protocol *t)
+{
+ const struct tp_finger *f;
+ struct input_dev *input;
+ const struct applespi_tp_info *tp_info = &applespi->tp_info;
+ int i, n;
+
+ /* touchpad_input_dev is set async in worker */
+ input = smp_load_acquire(&applespi->touchpad_input_dev);
+ if (!input)
+ return; /* touchpad isn't initialized yet */
+
+ n = 0;
+
+ for (i = 0; i < t->number_of_fingers; i++) {
+ f = &t->fingers[i];
+ if (le16_to_int(f->touch_major) == 0)
+ continue;
+ applespi->pos[n].x = le16_to_int(f->abs_x);
+ applespi->pos[n].y = tp_info->y_min + tp_info->y_max -
+ le16_to_int(f->abs_y);
+ n++;
+
+ if (applespi->debug_tp_dim)
+ applespi_debug_update_dimensions(applespi, f);
+ }
+
+ input_mt_assign_slots(input, applespi->slots, applespi->pos, n, 0);
+
+ for (i = 0; i < n; i++)
+ report_finger_data(input, applespi->slots[i],
+ &applespi->pos[i], &t->fingers[i]);
+
+ input_mt_sync_frame(input);
+ input_report_key(input, BTN_LEFT, t->clicked);
+
+ input_sync(input);
+}
+
+static const struct applespi_key_translation *
+applespi_find_translation(const struct applespi_key_translation *table, u16 key)
+{
+ const struct applespi_key_translation *trans;
+
+ for (trans = table; trans->from; trans++)
+ if (trans->from == key)
+ return trans;
+
+ return NULL;
+}
+
+static unsigned int applespi_translate_fn_key(unsigned int key, int fn_pressed)
+{
+ const struct applespi_key_translation *trans;
+ int do_translate;
+
+ trans = applespi_find_translation(applespi_fn_codes, key);
+ if (trans) {
+ if (trans->flags & APPLE_FLAG_FKEY)
+ do_translate = (fnmode == 2 && fn_pressed) ||
+ (fnmode == 1 && !fn_pressed);
+ else
+ do_translate = fn_pressed;
+
+ if (do_translate)
+ key = trans->to;
+ }
+
+ return key;
+}
+
+static unsigned int applespi_translate_iso_layout(unsigned int key)
+{
+ const struct applespi_key_translation *trans;
+
+ trans = applespi_find_translation(apple_iso_keyboard, key);
+ if (trans)
+ key = trans->to;
+
+ return key;
+}
+
+static unsigned int applespi_code_to_key(u8 code, int fn_pressed)
+{
+ unsigned int key = applespi_scancodes[code];
+
+ if (fnmode)
+ key = applespi_translate_fn_key(key, fn_pressed);
+ if (iso_layout)
+ key = applespi_translate_iso_layout(key);
+ return key;
+}
+
+static void
+applespi_remap_fn_key(struct keyboard_protocol *keyboard_protocol)
+{
+ unsigned char tmp;
+ u8 bit = BIT((fnremap - 1) & 0x07);
+
+ if (!fnremap || fnremap > ARRAY_SIZE(applespi_controlcodes) ||
+ !applespi_controlcodes[fnremap - 1])
+ return;
+
+ tmp = keyboard_protocol->fn_pressed;
+ keyboard_protocol->fn_pressed = !!(keyboard_protocol->modifiers & bit);
+ if (tmp)
+ keyboard_protocol->modifiers |= bit;
+ else
+ keyboard_protocol->modifiers &= ~bit;
+}
+
+static void
+applespi_handle_keyboard_event(struct applespi_data *applespi,
+ struct keyboard_protocol *keyboard_protocol)
+{
+ unsigned int key;
+ int i;
+
+ compiletime_assert(ARRAY_SIZE(applespi_controlcodes) ==
+ sizeof_field(struct keyboard_protocol, modifiers) * 8,
+ "applespi_controlcodes has wrong number of entries");
+
+ /* check for rollover overflow, which is signalled by all keys == 1 */
+ if (!memchr_inv(keyboard_protocol->keys_pressed, 1, MAX_ROLLOVER))
+ return;
+
+ /* remap fn key if desired */
+ applespi_remap_fn_key(keyboard_protocol);
+
+ /* check released keys */
+ for (i = 0; i < MAX_ROLLOVER; i++) {
+ if (memchr(keyboard_protocol->keys_pressed,
+ applespi->last_keys_pressed[i], MAX_ROLLOVER))
+ continue; /* key is still pressed */
+
+ key = applespi_code_to_key(applespi->last_keys_pressed[i],
+ applespi->last_keys_fn_pressed[i]);
+ input_report_key(applespi->keyboard_input_dev, key, 0);
+ applespi->last_keys_fn_pressed[i] = 0;
+ }
+
+ /* check pressed keys */
+ for (i = 0; i < MAX_ROLLOVER; i++) {
+ if (keyboard_protocol->keys_pressed[i] <
+ ARRAY_SIZE(applespi_scancodes) &&
+ keyboard_protocol->keys_pressed[i] > 0) {
+ key = applespi_code_to_key(
+ keyboard_protocol->keys_pressed[i],
+ keyboard_protocol->fn_pressed);
+ input_report_key(applespi->keyboard_input_dev, key, 1);
+ applespi->last_keys_fn_pressed[i] =
+ keyboard_protocol->fn_pressed;
+ }
+ }
+
+ /* check control keys */
+ for (i = 0; i < ARRAY_SIZE(applespi_controlcodes); i++) {
+ if (keyboard_protocol->modifiers & BIT(i))
+ input_report_key(applespi->keyboard_input_dev,
+ applespi_controlcodes[i], 1);
+ else
+ input_report_key(applespi->keyboard_input_dev,
+ applespi_controlcodes[i], 0);
+ }
+
+ /* check function key */
+ if (keyboard_protocol->fn_pressed && !applespi->last_fn_pressed)
+ input_report_key(applespi->keyboard_input_dev, KEY_FN, 1);
+ else if (!keyboard_protocol->fn_pressed && applespi->last_fn_pressed)
+ input_report_key(applespi->keyboard_input_dev, KEY_FN, 0);
+ applespi->last_fn_pressed = keyboard_protocol->fn_pressed;
+
+ /* done */
+ input_sync(applespi->keyboard_input_dev);
+ memcpy(&applespi->last_keys_pressed, keyboard_protocol->keys_pressed,
+ sizeof(applespi->last_keys_pressed));
+}
+
+static const struct applespi_tp_info *applespi_find_touchpad_info(u8 model)
+{
+ const struct applespi_tp_model_info *info;
+
+ for (info = applespi_tp_models; info->model; info++) {
+ if (info->model == model)
+ return &info->tp_info;
+ }
+
+ return NULL;
+}
+
+static int
+applespi_register_touchpad_device(struct applespi_data *applespi,
+ struct touchpad_info_protocol *rcvd_tp_info)
+{
+ const struct applespi_tp_info *tp_info;
+ struct input_dev *touchpad_input_dev;
+ int sts;
+
+ /* set up touchpad dimensions */
+ tp_info = applespi_find_touchpad_info(rcvd_tp_info->model_no);
+ if (!tp_info) {
+ dev_warn(&applespi->spi->dev,
+ "Unknown touchpad model %x - falling back to MB8 touchpad\n",
+ rcvd_tp_info->model_no);
+ tp_info = &applespi_tp_models[0].tp_info;
+ }
+
+ applespi->tp_info = *tp_info;
+
+ if (touchpad_dimensions[0]) {
+ int x, y, w, h;
+
+ sts = sscanf(touchpad_dimensions, "%dx%d+%u+%u", &x, &y, &w, &h);
+ if (sts == 4) {
+ dev_info(&applespi->spi->dev,
+ "Overriding touchpad dimensions from module param\n");
+ applespi->tp_info.x_min = x;
+ applespi->tp_info.y_min = y;
+ applespi->tp_info.x_max = x + w;
+ applespi->tp_info.y_max = y + h;
+ } else {
+ dev_warn(&applespi->spi->dev,
+ "Invalid touchpad dimensions '%s': must be in the form XxY+W+H\n",
+ touchpad_dimensions);
+ touchpad_dimensions[0] = '\0';
+ }
+ }
+ if (!touchpad_dimensions[0]) {
+ snprintf(touchpad_dimensions, sizeof(touchpad_dimensions),
+ "%dx%d+%u+%u",
+ applespi->tp_info.x_min,
+ applespi->tp_info.y_min,
+ applespi->tp_info.x_max - applespi->tp_info.x_min,
+ applespi->tp_info.y_max - applespi->tp_info.y_min);
+ }
+
+ /* create touchpad input device */
+ touchpad_input_dev = devm_input_allocate_device(&applespi->spi->dev);
+ if (!touchpad_input_dev) {
+ dev_err(&applespi->spi->dev,
+ "Failed to allocate touchpad input device\n");
+ return -ENOMEM;
+ }
+
+ touchpad_input_dev->name = "Apple SPI Touchpad";
+ touchpad_input_dev->phys = "applespi/input1";
+ touchpad_input_dev->dev.parent = &applespi->spi->dev;
+ touchpad_input_dev->id.bustype = BUS_SPI;
+ touchpad_input_dev->id.vendor = SYNAPTICS_VENDOR_ID;
+ touchpad_input_dev->id.product =
+ rcvd_tp_info->model_no << 8 | rcvd_tp_info->model_flags;
+
+ /* basic properties */
+ input_set_capability(touchpad_input_dev, EV_REL, REL_X);
+ input_set_capability(touchpad_input_dev, EV_REL, REL_Y);
+
+ __set_bit(INPUT_PROP_POINTER, touchpad_input_dev->propbit);
+ __set_bit(INPUT_PROP_BUTTONPAD, touchpad_input_dev->propbit);
+
+ /* finger touch area */
+ input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, 5000, 0, 0);
+ input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MINOR,
+ 0, 5000, 0, 0);
+
+ /* finger approach area */
+ input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MAJOR,
+ 0, 5000, 0, 0);
+ input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MINOR,
+ 0, 5000, 0, 0);
+
+ /* finger orientation */
+ input_set_abs_params(touchpad_input_dev, ABS_MT_ORIENTATION,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION,
+ 0, 0);
+
+ /* finger position */
+ input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_X,
+ applespi->tp_info.x_min, applespi->tp_info.x_max,
+ 0, 0);
+ input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_Y,
+ applespi->tp_info.y_min, applespi->tp_info.y_max,
+ 0, 0);
+
+ /* touchpad button */
+ input_set_capability(touchpad_input_dev, EV_KEY, BTN_LEFT);
+
+ /* multitouch */
+ sts = input_mt_init_slots(touchpad_input_dev, MAX_FINGERS,
+ INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
+ INPUT_MT_TRACK);
+ if (sts) {
+ dev_err(&applespi->spi->dev,
+ "failed to initialize slots: %d", sts);
+ return sts;
+ }
+
+ /* register input device */
+ sts = input_register_device(touchpad_input_dev);
+ if (sts) {
+ dev_err(&applespi->spi->dev,
+ "Unable to register touchpad input device (%d)\n", sts);
+ return sts;
+ }
+
+ /* touchpad_input_dev is read async in spi callback */
+ smp_store_release(&applespi->touchpad_input_dev, touchpad_input_dev);
+
+ return 0;
+}
+
+static void applespi_worker(struct work_struct *work)
+{
+ struct applespi_data *applespi =
+ container_of(work, struct applespi_data, work);
+
+ applespi_register_touchpad_device(applespi, &applespi->rcvd_tp_info);
+}
+
+static void applespi_handle_cmd_response(struct applespi_data *applespi,
+ struct spi_packet *packet,
+ struct message *message)
+{
+ if (packet->device == PACKET_DEV_INFO &&
+ le16_to_cpu(message->type) == 0x1020) {
+ /*
+ * We're not allowed to sleep here, but registering an input
+ * device can sleep.
+ */
+ applespi->rcvd_tp_info = message->tp_info;
+ schedule_work(&applespi->work);
+ return;
+ }
+
+ if (le16_to_cpu(message->length) != 0x0000) {
+ dev_warn_ratelimited(&applespi->spi->dev,
+ "Received unexpected write response: length=%x\n",
+ le16_to_cpu(message->length));
+ return;
+ }
+
+ if (packet->device == PACKET_DEV_TPAD &&
+ le16_to_cpu(message->type) == 0x0252 &&
+ le16_to_cpu(message->rsp_buf_len) == 0x0002)
+ dev_info(&applespi->spi->dev, "modeswitch done.\n");
+}
+
+static bool applespi_verify_crc(struct applespi_data *applespi, u8 *buffer,
+ size_t buflen)
+{
+ u16 crc;
+
+ crc = crc16(0, buffer, buflen);
+ if (crc) {
+ dev_warn_ratelimited(&applespi->spi->dev,
+ "Received corrupted packet (crc mismatch)\n");
+ trace_applespi_bad_crc(ET_RD_CRC, READ, buffer, buflen);
+
+ return false;
+ }
+
+ return true;
+}
+
+static void applespi_debug_print_read_packet(struct applespi_data *applespi,
+ struct spi_packet *packet)
+{
+ unsigned int evt_type;
+
+ if (packet->flags == PACKET_TYPE_READ &&
+ packet->device == PACKET_DEV_KEYB)
+ evt_type = ET_RD_KEYB;
+ else if (packet->flags == PACKET_TYPE_READ &&
+ packet->device == PACKET_DEV_TPAD)
+ evt_type = ET_RD_TPAD;
+ else if (packet->flags == PACKET_TYPE_WRITE)
+ evt_type = applespi->cmd_evt_type;
+ else
+ evt_type = ET_RD_UNKN;
+
+ applespi_get_trace_fun(evt_type)(evt_type, PT_READ, applespi->rx_buffer,
+ APPLESPI_PACKET_SIZE);
+}
+
+static void applespi_got_data(struct applespi_data *applespi)
+{
+ struct spi_packet *packet;
+ struct message *message;
+ unsigned int msg_len;
+ unsigned int off;
+ unsigned int rem;
+ unsigned int len;
+
+ /* process packet header */
+ if (!applespi_verify_crc(applespi, applespi->rx_buffer,
+ APPLESPI_PACKET_SIZE)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (applespi->drain) {
+ applespi->read_active = false;
+ applespi->write_active = false;
+
+ wake_up_all(&applespi->drain_complete);
+ }
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ return;
+ }
+
+ packet = (struct spi_packet *)applespi->rx_buffer;
+
+ applespi_debug_print_read_packet(applespi, packet);
+
+ off = le16_to_cpu(packet->offset);
+ rem = le16_to_cpu(packet->remaining);
+ len = le16_to_cpu(packet->length);
+
+ if (len > sizeof(packet->data)) {
+ dev_warn_ratelimited(&applespi->spi->dev,
+ "Received corrupted packet (invalid packet length %u)\n",
+ len);
+ goto msg_complete;
+ }
+
+ /* handle multi-packet messages */
+ if (rem > 0 || off > 0) {
+ if (off != applespi->saved_msg_len) {
+ dev_warn_ratelimited(&applespi->spi->dev,
+ "Received unexpected offset (got %u, expected %u)\n",
+ off, applespi->saved_msg_len);
+ goto msg_complete;
+ }
+
+ if (off + rem > MAX_PKTS_PER_MSG * APPLESPI_PACKET_SIZE) {
+ dev_warn_ratelimited(&applespi->spi->dev,
+ "Received message too large (size %u)\n",
+ off + rem);
+ goto msg_complete;
+ }
+
+ if (off + len > MAX_PKTS_PER_MSG * APPLESPI_PACKET_SIZE) {
+ dev_warn_ratelimited(&applespi->spi->dev,
+ "Received message too large (size %u)\n",
+ off + len);
+ goto msg_complete;
+ }
+
+ memcpy(applespi->msg_buf + off, &packet->data, len);
+ applespi->saved_msg_len += len;
+
+ if (rem > 0)
+ return;
+
+ message = (struct message *)applespi->msg_buf;
+ msg_len = applespi->saved_msg_len;
+ } else {
+ message = (struct message *)&packet->data;
+ msg_len = len;
+ }
+
+ /* got complete message - verify */
+ if (!applespi_verify_crc(applespi, (u8 *)message, msg_len))
+ goto msg_complete;
+
+ if (le16_to_cpu(message->length) != msg_len - MSG_HEADER_SIZE - 2) {
+ dev_warn_ratelimited(&applespi->spi->dev,
+ "Received corrupted packet (invalid message length %u - expected %u)\n",
+ le16_to_cpu(message->length),
+ msg_len - MSG_HEADER_SIZE - 2);
+ goto msg_complete;
+ }
+
+ /* handle message */
+ if (packet->flags == PACKET_TYPE_READ &&
+ packet->device == PACKET_DEV_KEYB) {
+ applespi_handle_keyboard_event(applespi, &message->keyboard);
+
+ } else if (packet->flags == PACKET_TYPE_READ &&
+ packet->device == PACKET_DEV_TPAD) {
+ struct touchpad_protocol *tp;
+ size_t tp_len;
+
+ tp = &message->touchpad;
+ tp_len = struct_size(tp, fingers, tp->number_of_fingers);
+
+ if (le16_to_cpu(message->length) + 2 != tp_len) {
+ dev_warn_ratelimited(&applespi->spi->dev,
+ "Received corrupted packet (invalid message length %u - num-fingers %u, tp-len %zu)\n",
+ le16_to_cpu(message->length),
+ tp->number_of_fingers, tp_len);
+ goto msg_complete;
+ }
+
+ if (tp->number_of_fingers > MAX_FINGERS) {
+ dev_warn_ratelimited(&applespi->spi->dev,
+ "Number of reported fingers (%u) exceeds max (%u))\n",
+ tp->number_of_fingers,
+ MAX_FINGERS);
+ tp->number_of_fingers = MAX_FINGERS;
+ }
+
+ report_tp_state(applespi, tp);
+
+ } else if (packet->flags == PACKET_TYPE_WRITE) {
+ applespi_handle_cmd_response(applespi, packet, message);
+ }
+
+msg_complete:
+ applespi->saved_msg_len = 0;
+
+ applespi_msg_complete(applespi, packet->flags == PACKET_TYPE_WRITE,
+ true);
+}
+
+static void applespi_async_read_complete(void *context)
+{
+ struct applespi_data *applespi = context;
+
+ if (applespi->rd_m.status < 0) {
+ dev_warn(&applespi->spi->dev, "Error reading from device: %d\n",
+ applespi->rd_m.status);
+ /*
+ * We don't actually know if this was a pure read, or a response
+ * to a write. But this is a rare error condition that should
+ * never occur, so clearing both flags to avoid deadlock.
+ */
+ applespi_msg_complete(applespi, true, true);
+ } else {
+ applespi_got_data(applespi);
+ }
+
+ acpi_finish_gpe(NULL, applespi->gpe);
+}
+
+static u32 applespi_notify(acpi_handle gpe_device, u32 gpe, void *context)
+{
+ struct applespi_data *applespi = context;
+ int sts;
+ unsigned long flags;
+
+ trace_applespi_irq_received(ET_RD_IRQ, PT_READ);
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ if (!applespi->suspended) {
+ sts = applespi_async(applespi, &applespi->rd_m,
+ applespi_async_read_complete);
+ if (sts)
+ dev_warn(&applespi->spi->dev,
+ "Error queueing async read to device: %d\n",
+ sts);
+ else
+ applespi->read_active = true;
+ }
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ return ACPI_INTERRUPT_HANDLED;
+}
+
+static int applespi_get_saved_bl_level(struct applespi_data *applespi)
+{
+ struct efivar_entry *efivar_entry;
+ u16 efi_data = 0;
+ unsigned long efi_data_len;
+ int sts;
+
+ efivar_entry = kmalloc(sizeof(*efivar_entry), GFP_KERNEL);
+ if (!efivar_entry)
+ return -ENOMEM;
+
+ memcpy(efivar_entry->var.VariableName, EFI_BL_LEVEL_NAME,
+ sizeof(EFI_BL_LEVEL_NAME));
+ efivar_entry->var.VendorGuid = EFI_BL_LEVEL_GUID;
+ efi_data_len = sizeof(efi_data);
+
+ sts = efivar_entry_get(efivar_entry, NULL, &efi_data_len, &efi_data);
+ if (sts && sts != -ENOENT)
+ dev_warn(&applespi->spi->dev,
+ "Error getting backlight level from EFI vars: %d\n",
+ sts);
+
+ kfree(efivar_entry);
+
+ return sts ? sts : efi_data;
+}
+
+static void applespi_save_bl_level(struct applespi_data *applespi,
+ unsigned int level)
+{
+ efi_guid_t efi_guid;
+ u32 efi_attr;
+ unsigned long efi_data_len;
+ u16 efi_data;
+ int sts;
+
+ /* Save keyboard backlight level */
+ efi_guid = EFI_BL_LEVEL_GUID;
+ efi_data = (u16)level;
+ efi_data_len = sizeof(efi_data);
+ efi_attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS;
+
+ sts = efivar_entry_set_safe((efi_char16_t *)EFI_BL_LEVEL_NAME, efi_guid,
+ efi_attr, true, efi_data_len, &efi_data);
+ if (sts)
+ dev_warn(&applespi->spi->dev,
+ "Error saving backlight level to EFI vars: %d\n", sts);
+}
+
+static int applespi_probe(struct spi_device *spi)
+{
+ struct applespi_data *applespi;
+ acpi_handle spi_handle = ACPI_HANDLE(&spi->dev);
+ acpi_status acpi_sts;
+ int sts, i;
+ unsigned long long gpe, usb_status;
+
+ /* check if the USB interface is present and enabled already */
+ acpi_sts = acpi_evaluate_integer(spi_handle, "UIST", NULL, &usb_status);
+ if (ACPI_SUCCESS(acpi_sts) && usb_status) {
+ /* let the USB driver take over instead */
+ dev_info(&spi->dev, "USB interface already enabled\n");
+ return -ENODEV;
+ }
+
+ /* allocate driver data */
+ applespi = devm_kzalloc(&spi->dev, sizeof(*applespi), GFP_KERNEL);
+ if (!applespi)
+ return -ENOMEM;
+
+ applespi->spi = spi;
+
+ INIT_WORK(&applespi->work, applespi_worker);
+
+ /* store the driver data */
+ spi_set_drvdata(spi, applespi);
+
+ /* create our buffers */
+ applespi->tx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE,
+ GFP_KERNEL);
+ applespi->tx_status = devm_kmalloc(&spi->dev, APPLESPI_STATUS_SIZE,
+ GFP_KERNEL);
+ applespi->rx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE,
+ GFP_KERNEL);
+ applespi->msg_buf = devm_kmalloc_array(&spi->dev, MAX_PKTS_PER_MSG,
+ APPLESPI_PACKET_SIZE,
+ GFP_KERNEL);
+
+ if (!applespi->tx_buffer || !applespi->tx_status ||
+ !applespi->rx_buffer || !applespi->msg_buf)
+ return -ENOMEM;
+
+ /* set up our spi messages */
+ applespi_setup_read_txfrs(applespi);
+ applespi_setup_write_txfrs(applespi);
+
+ /* cache ACPI method handles */
+ acpi_sts = acpi_get_handle(spi_handle, "SIEN", &applespi->sien);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(&applespi->spi->dev,
+ "Failed to get SIEN ACPI method handle: %s\n",
+ acpi_format_exception(acpi_sts));
+ return -ENODEV;
+ }
+
+ acpi_sts = acpi_get_handle(spi_handle, "SIST", &applespi->sist);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(&applespi->spi->dev,
+ "Failed to get SIST ACPI method handle: %s\n",
+ acpi_format_exception(acpi_sts));
+ return -ENODEV;
+ }
+
+ /* switch on the SPI interface */
+ sts = applespi_setup_spi(applespi);
+ if (sts)
+ return sts;
+
+ sts = applespi_enable_spi(applespi);
+ if (sts)
+ return sts;
+
+ /* setup the keyboard input dev */
+ applespi->keyboard_input_dev = devm_input_allocate_device(&spi->dev);
+
+ if (!applespi->keyboard_input_dev)
+ return -ENOMEM;
+
+ applespi->keyboard_input_dev->name = "Apple SPI Keyboard";
+ applespi->keyboard_input_dev->phys = "applespi/input0";
+ applespi->keyboard_input_dev->dev.parent = &spi->dev;
+ applespi->keyboard_input_dev->id.bustype = BUS_SPI;
+
+ applespi->keyboard_input_dev->evbit[0] =
+ BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | BIT_MASK(EV_REP);
+ applespi->keyboard_input_dev->ledbit[0] = BIT_MASK(LED_CAPSL);
+
+ input_set_drvdata(applespi->keyboard_input_dev, applespi);
+ applespi->keyboard_input_dev->event = applespi_event;
+
+ for (i = 0; i < ARRAY_SIZE(applespi_scancodes); i++)
+ if (applespi_scancodes[i])
+ input_set_capability(applespi->keyboard_input_dev,
+ EV_KEY, applespi_scancodes[i]);
+
+ for (i = 0; i < ARRAY_SIZE(applespi_controlcodes); i++)
+ if (applespi_controlcodes[i])
+ input_set_capability(applespi->keyboard_input_dev,
+ EV_KEY, applespi_controlcodes[i]);
+
+ for (i = 0; i < ARRAY_SIZE(applespi_fn_codes); i++)
+ if (applespi_fn_codes[i].to)
+ input_set_capability(applespi->keyboard_input_dev,
+ EV_KEY, applespi_fn_codes[i].to);
+
+ input_set_capability(applespi->keyboard_input_dev, EV_KEY, KEY_FN);
+
+ sts = input_register_device(applespi->keyboard_input_dev);
+ if (sts) {
+ dev_err(&applespi->spi->dev,
+ "Unable to register keyboard input device (%d)\n", sts);
+ return -ENODEV;
+ }
+
+ /*
+ * The applespi device doesn't send interrupts normally (as is described
+ * in its DSDT), but rather seems to use ACPI GPEs.
+ */
+ acpi_sts = acpi_evaluate_integer(spi_handle, "_GPE", NULL, &gpe);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(&applespi->spi->dev,
+ "Failed to obtain GPE for SPI slave device: %s\n",
+ acpi_format_exception(acpi_sts));
+ return -ENODEV;
+ }
+ applespi->gpe = (int)gpe;
+
+ acpi_sts = acpi_install_gpe_handler(NULL, applespi->gpe,
+ ACPI_GPE_LEVEL_TRIGGERED,
+ applespi_notify, applespi);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(&applespi->spi->dev,
+ "Failed to install GPE handler for GPE %d: %s\n",
+ applespi->gpe, acpi_format_exception(acpi_sts));
+ return -ENODEV;
+ }
+
+ applespi->suspended = false;
+
+ acpi_sts = acpi_enable_gpe(NULL, applespi->gpe);
+ if (ACPI_FAILURE(acpi_sts)) {
+ dev_err(&applespi->spi->dev,
+ "Failed to enable GPE handler for GPE %d: %s\n",
+ applespi->gpe, acpi_format_exception(acpi_sts));
+ acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
+ return -ENODEV;
+ }
+
+ /* trigger touchpad setup */
+ applespi_init(applespi, false);
+
+ /*
+ * By default this device is not enabled for wakeup; but USB keyboards
+ * generally are, so the expectation is that by default the keyboard
+ * will wake the system.
+ */
+ device_wakeup_enable(&spi->dev);
+
+ /* set up keyboard-backlight */
+ sts = applespi_get_saved_bl_level(applespi);
+ if (sts >= 0)
+ applespi_set_bl_level(&applespi->backlight_info, sts);
+
+ applespi->backlight_info.name = "spi::kbd_backlight";
+ applespi->backlight_info.default_trigger = "kbd-backlight";
+ applespi->backlight_info.brightness_set = applespi_set_bl_level;
+
+ sts = devm_led_classdev_register(&spi->dev, &applespi->backlight_info);
+ if (sts)
+ dev_warn(&applespi->spi->dev,
+ "Unable to register keyboard backlight class dev (%d)\n",
+ sts);
+
+ /* set up debugfs entries for touchpad dimensions logging */
+ applespi->debugfs_root = debugfs_create_dir("applespi", NULL);
+
+ debugfs_create_bool("enable_tp_dim", 0600, applespi->debugfs_root,
+ &applespi->debug_tp_dim);
+
+ debugfs_create_file("tp_dim", 0400, applespi->debugfs_root, applespi,
+ &applespi_tp_dim_fops);
+
+ return 0;
+}
+
+static void applespi_drain_writes(struct applespi_data *applespi)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ applespi->drain = true;
+ wait_event_lock_irq(applespi->drain_complete, !applespi->write_active,
+ applespi->cmd_msg_lock);
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static void applespi_drain_reads(struct applespi_data *applespi)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ wait_event_lock_irq(applespi->drain_complete, !applespi->read_active,
+ applespi->cmd_msg_lock);
+
+ applespi->suspended = true;
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+}
+
+static int applespi_remove(struct spi_device *spi)
+{
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+
+ applespi_drain_writes(applespi);
+
+ acpi_disable_gpe(NULL, applespi->gpe);
+ acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
+ device_wakeup_disable(&spi->dev);
+
+ applespi_drain_reads(applespi);
+
+ debugfs_remove_recursive(applespi->debugfs_root);
+
+ return 0;
+}
+
+static void applespi_shutdown(struct spi_device *spi)
+{
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+
+ applespi_save_bl_level(applespi, applespi->have_bl_level);
+}
+
+static int applespi_poweroff_late(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+
+ applespi_save_bl_level(applespi, applespi->have_bl_level);
+
+ return 0;
+}
+
+static int __maybe_unused applespi_suspend(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+ acpi_status acpi_sts;
+ int sts;
+
+ /* turn off caps-lock - it'll stay on otherwise */
+ sts = applespi_set_capsl_led(applespi, false);
+ if (sts)
+ dev_warn(&applespi->spi->dev,
+ "Failed to turn off caps-lock led (%d)\n", sts);
+
+ applespi_drain_writes(applespi);
+
+ /* disable the interrupt */
+ acpi_sts = acpi_disable_gpe(NULL, applespi->gpe);
+ if (ACPI_FAILURE(acpi_sts))
+ dev_err(&applespi->spi->dev,
+ "Failed to disable GPE handler for GPE %d: %s\n",
+ applespi->gpe, acpi_format_exception(acpi_sts));
+
+ applespi_drain_reads(applespi);
+
+ return 0;
+}
+
+static int __maybe_unused applespi_resume(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct applespi_data *applespi = spi_get_drvdata(spi);
+ acpi_status acpi_sts;
+ unsigned long flags;
+
+ /* ensure our flags and state reflect a newly resumed device */
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+
+ applespi->drain = false;
+ applespi->have_cl_led_on = false;
+ applespi->have_bl_level = 0;
+ applespi->cmd_msg_queued = false;
+ applespi->read_active = false;
+ applespi->write_active = false;
+
+ applespi->suspended = false;
+
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ /* switch on the SPI interface */
+ applespi_enable_spi(applespi);
+
+ /* re-enable the interrupt */
+ acpi_sts = acpi_enable_gpe(NULL, applespi->gpe);
+ if (ACPI_FAILURE(acpi_sts))
+ dev_err(&applespi->spi->dev,
+ "Failed to re-enable GPE handler for GPE %d: %s\n",
+ applespi->gpe, acpi_format_exception(acpi_sts));
+
+ /* switch the touchpad into multitouch mode */
+ applespi_init(applespi, true);
+
+ return 0;
+}
+
+static const struct acpi_device_id applespi_acpi_match[] = {
+ { "APP000D", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, applespi_acpi_match);
+
+static const struct dev_pm_ops applespi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(applespi_suspend, applespi_resume)
+ .poweroff_late = applespi_poweroff_late,
+};
+
+static struct spi_driver applespi_driver = {
+ .driver = {
+ .name = "applespi",
+ .acpi_match_table = applespi_acpi_match,
+ .pm = &applespi_pm_ops,
+ },
+ .probe = applespi_probe,
+ .remove = applespi_remove,
+ .shutdown = applespi_shutdown,
+};
+
+module_spi_driver(applespi_driver)
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MacBook(Pro) SPI Keyboard/Touchpad driver");
+MODULE_AUTHOR("Federico Lorenzi");
+MODULE_AUTHOR("Ronald Tschalär");
diff --git a/drivers/input/keyboard/applespi.h b/drivers/input/keyboard/applespi.h
new file mode 100644
index 0000000..7f5ab10
--- /dev/null
+++ b/drivers/input/keyboard/applespi.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MacBook (Pro) SPI keyboard and touchpad driver
+ *
+ * Copyright (c) 2015-2019 Federico Lorenzi
+ * Copyright (c) 2017-2019 Ronald Tschalär
+ */
+
+#ifndef _APPLESPI_H_
+#define _APPLESPI_H_
+
+enum applespi_evt_type {
+ ET_CMD_TP_INI = BIT(0),
+ ET_CMD_BL = BIT(1),
+ ET_CMD_CL = BIT(2),
+ ET_RD_KEYB = BIT(8),
+ ET_RD_TPAD = BIT(9),
+ ET_RD_UNKN = BIT(10),
+ ET_RD_IRQ = BIT(11),
+ ET_RD_CRC = BIT(12),
+};
+
+enum applespi_pkt_type {
+ PT_READ,
+ PT_WRITE,
+ PT_STATUS,
+};
+
+#endif /* _APPLESPI_H_ */
diff --git a/drivers/input/keyboard/applespi_trace.h b/drivers/input/keyboard/applespi_trace.h
new file mode 100644
index 0000000..0ad1a3d
--- /dev/null
+++ b/drivers/input/keyboard/applespi_trace.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MacBook (Pro) SPI keyboard and touchpad driver
+ *
+ * Copyright (c) 2015-2019 Federico Lorenzi
+ * Copyright (c) 2017-2019 Ronald Tschalär
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM applespi
+
+#if !defined(_APPLESPI_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _APPLESPI_TRACE_H_
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#include "applespi.h"
+
+DECLARE_EVENT_CLASS(dump_message_template,
+ TP_PROTO(enum applespi_evt_type evt_type,
+ enum applespi_pkt_type pkt_type,
+ u8 *buf,
+ size_t len),
+
+ TP_ARGS(evt_type, pkt_type, buf, len),
+
+ TP_STRUCT__entry(
+ __field(enum applespi_evt_type, evt_type)
+ __field(enum applespi_pkt_type, pkt_type)
+ __field(size_t, len)
+ __dynamic_array(u8, buf, len)
+ ),
+
+ TP_fast_assign(
+ __entry->evt_type = evt_type;
+ __entry->pkt_type = pkt_type;
+ __entry->len = len;
+ memcpy(__get_dynamic_array(buf), buf, len);
+ ),
+
+ TP_printk("%-6s: %s",
+ __print_symbolic(__entry->pkt_type,
+ { PT_READ, "read" },
+ { PT_WRITE, "write" },
+ { PT_STATUS, "status" }
+ ),
+ __print_hex(__get_dynamic_array(buf), __entry->len))
+);
+
+#define DEFINE_DUMP_MESSAGE_EVENT(name) \
+DEFINE_EVENT(dump_message_template, name, \
+ TP_PROTO(enum applespi_evt_type evt_type, \
+ enum applespi_pkt_type pkt_type, \
+ u8 *buf, \
+ size_t len), \
+ TP_ARGS(evt_type, pkt_type, buf, len) \
+)
+
+DEFINE_DUMP_MESSAGE_EVENT(applespi_tp_ini_cmd);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_backlight_cmd);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_caps_lock_cmd);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_keyboard_data);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_touchpad_data);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_unknown_data);
+DEFINE_DUMP_MESSAGE_EVENT(applespi_bad_crc);
+
+TRACE_EVENT(applespi_irq_received,
+ TP_PROTO(enum applespi_evt_type evt_type,
+ enum applespi_pkt_type pkt_type),
+
+ TP_ARGS(evt_type, pkt_type),
+
+ TP_STRUCT__entry(
+ __field(enum applespi_evt_type, evt_type)
+ __field(enum applespi_pkt_type, pkt_type)
+ ),
+
+ TP_fast_assign(
+ __entry->evt_type = evt_type;
+ __entry->pkt_type = pkt_type;
+ ),
+
+ "\n"
+);
+
+#endif /* _APPLESPI_TRACE_H_ */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/input/keyboard
+#define TRACE_INCLUDE_FILE applespi_trace
+#include <trace/define_trace.h>
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c
index 6caee80..77ed546 100644
--- a/drivers/input/keyboard/atakbd.c
+++ b/drivers/input/keyboard/atakbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* atakbd.c
*
@@ -21,19 +22,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 7e75835..7e3eae5 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AT and PS/2 keyboard driver
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* This driver can handle standard AT keyboards and PS/2 keyboards in
@@ -401,6 +397,8 @@
if (ps2_handle_response(&atkbd->ps2dev, data))
goto out;
+ pm_wakeup_event(&serio->dev, 0);
+
if (!atkbd->enabled)
goto out;
@@ -841,7 +839,7 @@
if (param[0] != 3) {
param[0] = 2;
if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
- return 2;
+ return 2;
}
ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
diff --git a/drivers/input/keyboard/bcm-keypad.c b/drivers/input/keyboard/bcm-keypad.c
index e1cf63e..2b771c3 100644
--- a/drivers/input/keyboard/bcm-keypad.c
+++ b/drivers/input/keyboard/bcm-keypad.c
@@ -413,10 +413,8 @@
bcm_kp_stop(kp);
kp->irq = platform_get_irq(pdev, 0);
- if (kp->irq < 0) {
- dev_err(&pdev->dev, "no IRQ specified\n");
+ if (kp->irq < 0)
return -EINVAL;
- }
error = devm_request_threaded_irq(&pdev->dev, kp->irq,
NULL, bcm_kp_isr_thread,
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 312916f..688e2be 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input driver for Microchip CAP11xx based capacitive touch sensors
*
* (c) 2014 Daniel Mack <linux@zonque.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/kernel.h>
@@ -75,9 +72,7 @@
struct cap11xx_led {
struct cap11xx_priv *priv;
struct led_classdev cdev;
- struct work_struct work;
u32 reg;
- enum led_brightness new_brightness;
};
#endif
@@ -233,30 +228,21 @@
}
#ifdef CONFIG_LEDS_CLASS
-static void cap11xx_led_work(struct work_struct *work)
-{
- struct cap11xx_led *led = container_of(work, struct cap11xx_led, work);
- struct cap11xx_priv *priv = led->priv;
- int value = led->new_brightness;
-
- /*
- * All LEDs share the same duty cycle as this is a HW limitation.
- * Brightness levels per LED are either 0 (OFF) and 1 (ON).
- */
- regmap_update_bits(priv->regmap, CAP11XX_REG_LED_OUTPUT_CONTROL,
- BIT(led->reg), value ? BIT(led->reg) : 0);
-}
-
-static void cap11xx_led_set(struct led_classdev *cdev,
- enum led_brightness value)
+static int cap11xx_led_set(struct led_classdev *cdev,
+ enum led_brightness value)
{
struct cap11xx_led *led = container_of(cdev, struct cap11xx_led, cdev);
+ struct cap11xx_priv *priv = led->priv;
- if (led->new_brightness == value)
- return;
-
- led->new_brightness = value;
- schedule_work(&led->work);
+ /*
+ * All LEDs share the same duty cycle as this is a HW
+ * limitation. Brightness levels per LED are either
+ * 0 (OFF) and 1 (ON).
+ */
+ return regmap_update_bits(priv->regmap,
+ CAP11XX_REG_LED_OUTPUT_CONTROL,
+ BIT(led->reg),
+ value ? BIT(led->reg) : 0);
}
static int cap11xx_init_leds(struct device *dev,
@@ -299,7 +285,7 @@
led->cdev.default_trigger =
of_get_property(child, "linux,default-trigger", NULL);
led->cdev.flags = 0;
- led->cdev.brightness_set = cap11xx_led_set;
+ led->cdev.brightness_set_blocking = cap11xx_led_set;
led->cdev.max_brightness = 1;
led->cdev.brightness = LED_OFF;
@@ -312,8 +298,6 @@
led->reg = reg;
led->priv = priv;
- INIT_WORK(&led->work, cap11xx_led_work);
-
error = devm_led_classdev_register(dev, &led->cdev);
if (error) {
of_node_put(child);
diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c
index e319f74..c4a5c07 100644
--- a/drivers/input/keyboard/clps711x-keypad.c
+++ b/drivers/input/keyboard/clps711x-keypad.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Cirrus Logic CLPS711X Keypad driver
*
* Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/input.h>
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index d560011..8d4d978 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -22,8 +22,8 @@
#include <linux/slab.h>
#include <linux/sysrq.h>
#include <linux/input/matrix_keypad.h>
-#include <linux/mfd/cros_ec.h>
-#include <linux/mfd/cros_ec_commands.h>
+#include <linux/platform_data/cros_ec_commands.h>
+#include <linux/platform_data/cros_ec_proto.h>
#include <asm/unaligned.h>
@@ -226,6 +226,8 @@
{
struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
notifier);
+ uint8_t mkbp_event_type = ckdev->ec->event_data.event_type &
+ EC_MKBP_EVENT_TYPE_MASK;
u32 val;
unsigned int ev_type;
@@ -237,7 +239,7 @@
if (queued_during_suspend && !device_may_wakeup(ckdev->dev))
return NOTIFY_OK;
- switch (ckdev->ec->event_data.event_type) {
+ switch (mkbp_event_type) {
case EC_MKBP_EVENT_KEY_MATRIX:
pm_wakeup_event(ckdev->dev, 0);
@@ -264,7 +266,7 @@
case EC_MKBP_EVENT_SWITCH:
pm_wakeup_event(ckdev->dev, 0);
- if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) {
+ if (mkbp_event_type == EC_MKBP_EVENT_BUTTON) {
val = get_unaligned_le32(
&ckdev->ec->event_data.data.buttons);
ev_type = EV_KEY;
diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c
index b20a5d0..f489cd5 100644
--- a/drivers/input/keyboard/davinci_keyscan.c
+++ b/drivers/input/keyboard/davinci_keyscan.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* DaVinci Key Scan Driver for TI platforms
*
@@ -6,20 +7,6 @@
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
*
* Initial Code: Sandeep Paulraj <s-paulraj@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/init.h>
@@ -32,10 +19,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
-#include <asm/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/irqs.h>
#include <linux/platform_data/keyscan-davinci.h>
/* Key scan registers */
@@ -209,7 +192,6 @@
davinci_ks->irq = platform_get_irq(pdev, 0);
if (davinci_ks->irq < 0) {
- dev_err(dev, "no key scan irq\n");
error = davinci_ks->irq;
goto fail2;
}
diff --git a/drivers/input/keyboard/dlink-dir685-touchkeys.c b/drivers/input/keyboard/dlink-dir685-touchkeys.c
index 88e321b..b0ead71 100644
--- a/drivers/input/keyboard/dlink-dir685-touchkeys.c
+++ b/drivers/input/keyboard/dlink-dir685-touchkeys.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* D-Link DIR-685 router I2C-based Touchkeys input driver
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index f77b295..7c70492 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the Cirrus EP93xx matrix keypad controller.
*
@@ -5,10 +6,6 @@
*
* Based on the pxa27x matrix keypad controller by Rodolfo Giometti.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* NOTE:
*
* The 3-key reset is triggered by pressing the 3 keys in
@@ -27,8 +24,7 @@
#include <linux/io.h>
#include <linux/input/matrix_keypad.h>
#include <linux/slab.h>
-
-#include <mach/hardware.h>
+#include <linux/soc/cirrus/ep93xx.h>
#include <linux/platform_data/keypad-ep93xx.h>
/*
@@ -137,10 +133,7 @@
struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
unsigned int val = 0;
- if (pdata->flags & EP93XX_KEYPAD_KDIV)
- clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV4);
- else
- clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV16);
+ clk_set_rate(keypad->clk, pdata->clk_rate);
if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY)
val |= KEY_INIT_DIS3KY;
diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c
index e8dae61..bc8c85a 100644
--- a/drivers/input/keyboard/goldfish_events.c
+++ b/drivers/input/keyboard/goldfish_events.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2007 Google, Inc.
* Copyright (C) 2012 Intel, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 492a971..1373dc5 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for keys on GPIO lines capable of generating interrupts.
*
* Copyright 2005 Phil Blundell
* Copyright 2010, 2011 David Jander <david@protonic.nl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
@@ -354,10 +351,7 @@
&dev_attr_disabled_switches.attr,
NULL,
};
-
-static const struct attribute_group gpio_keys_attr_group = {
- .attrs = gpio_keys_attrs,
-};
+ATTRIBUTE_GROUPS(gpio_keys);
static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
{
@@ -774,7 +768,6 @@
struct fwnode_handle *child = NULL;
struct gpio_keys_drvdata *ddata;
struct input_dev *input;
- size_t size;
int i, error;
int wakeup = 0;
@@ -784,9 +777,8 @@
return PTR_ERR(pdata);
}
- size = sizeof(struct gpio_keys_drvdata) +
- pdata->nbuttons * sizeof(struct gpio_button_data);
- ddata = devm_kzalloc(dev, size, GFP_KERNEL);
+ ddata = devm_kzalloc(dev, struct_size(ddata, data, pdata->nbuttons),
+ GFP_KERNEL);
if (!ddata) {
dev_err(dev, "failed to allocate state\n");
return -ENOMEM;
@@ -856,13 +848,6 @@
fwnode_handle_put(child);
- error = devm_device_add_group(dev, &gpio_keys_attr_group);
- if (error) {
- dev_err(dev, "Unable to export keys/switches, error: %d\n",
- error);
- return error;
- }
-
error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device, error: %d\n",
@@ -1015,12 +1000,23 @@
static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
+static void gpio_keys_shutdown(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = gpio_keys_suspend(&pdev->dev);
+ if (ret)
+ dev_err(&pdev->dev, "failed to shutdown\n");
+}
+
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
+ .shutdown = gpio_keys_shutdown,
.driver = {
.name = "gpio-keys",
.pm = &gpio_keys_pm_ops,
.of_match_table = gpio_keys_of_match,
+ .dev_groups = gpio_keys_groups,
}
};
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index edc7262..465eecf 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for buttons on GPIO lines not capable of generating interrupts
*
@@ -9,10 +10,6 @@
*
* also was based on: /drivers/input/keyboard/gpio_keys.c
* Copyright 2005 Phil Blundell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/kernel.h>
@@ -168,6 +165,8 @@
pdata->rep = device_property_present(dev, "autorepeat");
device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
+ device_property_read_string(dev, "label", &pdata->name);
+
device_for_each_child_node(dev, child) {
if (fwnode_property_read_u32(child, "linux,code",
&button->code)) {
@@ -235,7 +234,6 @@
struct gpio_keys_polled_dev *bdev;
struct input_polled_dev *poll_dev;
struct input_dev *input;
- size_t size;
int error;
int i;
@@ -250,9 +248,8 @@
return -EINVAL;
}
- size = sizeof(struct gpio_keys_polled_dev) +
- pdata->nbuttons * sizeof(struct gpio_keys_button_data);
- bdev = devm_kzalloc(dev, size, GFP_KERNEL);
+ bdev = devm_kzalloc(dev, struct_size(bdev, data, pdata->nbuttons),
+ GFP_KERNEL);
if (!bdev) {
dev_err(dev, "no memory for private data\n");
return -ENOMEM;
@@ -272,7 +269,7 @@
input = poll_dev->input;
- input->name = pdev->name;
+ input->name = pdata->name ?: pdev->name;
input->phys = DRV_NAME"/input0";
input->id.bustype = BUS_HOST;
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 5c7afde..62ccfeb 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -1,18 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/hil/hilkbd.c
*
* Copyright (C) 1998 Philip Blundell <philb@gnu.org>
- * Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
+ * Copyright (C) 1999 Matthew Wilcox <willy@infradead.org>
* Copyright (C) 1999-2007 Helge Deller <deller@gmx.de>
*
* Very basic HP Human Interface Loop (HIL) driver.
* This driver handles the keyboard on HP300 (m68k) and on some
* HP700 (parisc) series machines.
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License version 2. See the file COPYING in the main directory of this
- * archive for more details.
*/
#include <linux/pci_ids.h>
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 539cb67..5a46d11 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -422,7 +422,6 @@
dev_get_platdata(&pdev->dev);
struct imx_keypad *keypad;
struct input_dev *input_dev;
- struct resource *res;
int irq, error, i, row, col;
if (!keymap_data && !pdev->dev.of_node) {
@@ -431,10 +430,8 @@
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "no irq defined in platform data\n");
+ if (irq < 0)
return irq;
- }
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev) {
@@ -455,8 +452,7 @@
timer_setup(&keypad->check_matrix_timer,
imx_keypad_check_for_events, 0);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+ keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(keypad->mmio_base))
return PTR_ERR(keypad->mmio_base);
@@ -526,11 +522,12 @@
return 0;
}
-static int __maybe_unused imx_kbd_suspend(struct device *dev)
+static int __maybe_unused imx_kbd_noirq_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input_dev;
+ unsigned short reg_val = readw(kbd->mmio_base + KPSR);
/* imx kbd can wake up system even clock is disabled */
mutex_lock(&input_dev->mutex);
@@ -540,13 +537,20 @@
mutex_unlock(&input_dev->mutex);
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(&pdev->dev)) {
+ if (reg_val & KBD_STAT_KPKD)
+ reg_val |= KBD_STAT_KRIE;
+ if (reg_val & KBD_STAT_KPKR)
+ reg_val |= KBD_STAT_KDIE;
+ writew(reg_val, kbd->mmio_base + KPSR);
+
enable_irq_wake(kbd->irq);
+ }
return 0;
}
-static int __maybe_unused imx_kbd_resume(struct device *dev)
+static int __maybe_unused imx_kbd_noirq_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
@@ -570,7 +574,9 @@
return ret;
}
-static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
+static const struct dev_pm_ops imx_kbd_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_kbd_noirq_suspend, imx_kbd_noirq_resume)
+};
static struct platform_driver imx_keypad_driver = {
.driver = {
diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c
index 602900d..e3f9e44 100644
--- a/drivers/input/keyboard/ipaq-micro-keys.c
+++ b/drivers/input/keyboard/ipaq-micro-keys.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*
* h3600 atmel micro companion support, key subdevice
* based on previous kernel 2.4 version
* Author : Alessandro Gardich <gremlin@gremlin.it>
* Author : Linus Walleij <linus.walleij@linaro.org>
- *
*/
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
index 0116ac9..4232aa8 100644
--- a/drivers/input/keyboard/jornada680_kbd.c
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/input/keyboard/jornada680_kbd.c
*
@@ -10,10 +11,6 @@
* Split from drivers/input/keyboard/hp600_keyb.c
* Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
* Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/device.h>
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index 1277c39..cd9af52 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/input/keyboard/jornada720_kbd.c
*
@@ -9,11 +10,6 @@
Filip Zyzniewsk <Filip.Zyzniewski@tefnet.plX
* based on (C) 2004 jornada 720 kbd driver by
Alex Lange <chicken@handhelds.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/device.h>
#include <linux/errno.h>
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 471d538..e4a1839 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
*/
@@ -46,19 +47,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index 04a5d7e..6c38d03 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/i2c/chips/lm8323.c
*
@@ -7,19 +8,6 @@
* Timo O. Karjalainen <timo.o.karjalainen@nokia.com>
*
* Updated by Felipe Balbi <felipe.balbi@nokia.com>
- *
- * 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 only).
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
index c717e8f..7c5f8c6 100644
--- a/drivers/input/keyboard/lm8333.c
+++ b/drivers/input/keyboard/lm8333.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* LM8333 keypad driver
* Copyright (C) 2012 Wolfram Sang, Pengutronix <kernel@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
*/
#include <linux/module.h>
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index 30d6107..daf6a75 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LoCoMo keyboard driver for Linux-based ARM PDAs:
* - SHARP Zaurus Collie (SL-5500)
@@ -5,22 +6,6 @@
*
* Copyright (c) 2005 John Lenz
* Based on from xtkbd.c
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/slab.h>
diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c
index 1dd57ac..348af2a 100644
--- a/drivers/input/keyboard/lpc32xx-keys.c
+++ b/drivers/input/keyboard/lpc32xx-keys.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* NXP LPC32xx SoC Key Scan Interface
*
@@ -8,17 +9,6 @@
* Copyright (C) 2010 NXP Semiconductors
* Copyright (C) 2012 Roland Stigge
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- *
* This controller supports square key matrices from 1x1 up to 8x8
*/
@@ -182,10 +172,8 @@
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get platform irq\n");
+ if (irq < 0)
return -EINVAL;
- }
kscandat = devm_kzalloc(&pdev->dev, sizeof(*kscandat),
GFP_KERNEL);
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
index 78e3567..d08b565 100644
--- a/drivers/input/keyboard/maple_keyb.c
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -1,23 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* SEGA Dreamcast keyboard driver
* Based on drivers/usb/usbkbd.c
* Copyright (c) YAEGASHI Takeshi, 2001
* Porting to 2.6 Copyright (c) Adrian McMenamin, 2007 - 2009
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 403452e..30924b5 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO driven matrix keyboard driver
*
* Copyright (c) 2008 Marek Vasut <marek.vasut@gmail.com>
*
* Based on corgikbd.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/types.h>
@@ -222,7 +218,7 @@
keypad->stopped = true;
spin_unlock_irq(&keypad->lock);
- flush_work(&keypad->work.work);
+ flush_delayed_work(&keypad->work);
/*
* matrix_keypad_scan() will leave IRQs enabled;
* we should disable them now.
diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c
index cd44d22..62ce934 100644
--- a/drivers/input/keyboard/max7359_keypad.c
+++ b/drivers/input/keyboard/max7359_keypad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* max7359_keypad.c - MAX7359 Key Switch Controller Driver
*
@@ -6,10 +7,6 @@
*
* Based on pxa27x_keypad.c
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/5456
*/
diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c
index be56d4f..8cb0062 100644
--- a/drivers/input/keyboard/mcs_touchkey.c
+++ b/drivers/input/keyboard/mcs_touchkey.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Touchkey driver for MELFAS MCS5000/5080 controller
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: HeungJun Kim <riverful.kim@samsung.com>
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/module.h>
@@ -113,9 +109,8 @@
return -EINVAL;
}
- data = kzalloc(sizeof(struct mcs_touchkey_data) +
- sizeof(data->keycodes[0]) * (pdata->key_maxval + 1),
- GFP_KERNEL);
+ data = kzalloc(struct_size(data, keycodes, pdata->key_maxval + 1),
+ GFP_KERNEL);
input_dev = input_allocate_device();
if (!data || !input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
index 884a74d..ee80de4 100644
--- a/drivers/input/keyboard/mpr121_touchkey.c
+++ b/drivers/input/keyboard/mpr121_touchkey.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchkey driver for Freescale MPR121 Controllor
*
@@ -5,11 +6,6 @@
* Author: Zhang Jiejing <jiejing.zhang@freescale.com>
*
* Based on mcs_touchkey.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/bitops.h>
@@ -257,8 +253,7 @@
mpr121->client = client;
mpr121->input_dev = input_dev;
- mpr121->keycount = device_property_read_u32_array(dev, "linux,keycodes",
- NULL, 0);
+ mpr121->keycount = device_property_count_u32(dev, "linux,keycodes");
if (mpr121->keycount > MPR121_MAX_KEY_COUNT) {
dev_err(dev, "too many keys defined (%d)\n", mpr121->keycount);
return -EINVAL;
diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
index 02c67a1..62391d6 100644
--- a/drivers/input/keyboard/mtk-pmic-keys.c
+++ b/drivers/input/keyboard/mtk-pmic-keys.c
@@ -1,31 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 MediaTek, Inc.
*
* Author: Chen Zhong <chen.zhong@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
-#include <linux/platform_device.h>
#include <linux/kernel.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
#include <linux/mfd/mt6323/registers.h>
-#include <linux/mfd/mt6397/registers.h>
#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6397/registers.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
#define MTK_PMIC_PWRKEY_RST_EN_MASK 0x1
#define MTK_PMIC_PWRKEY_RST_EN_SHIFT 6
@@ -287,8 +277,10 @@
keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index];
keys->keys[index].irq = platform_get_irq(pdev, index);
- if (keys->keys[index].irq < 0)
+ if (keys->keys[index].irq < 0) {
+ of_node_put(child);
return keys->keys[index].irq;
+ }
error = of_property_read_u32(child,
"linux,keycodes", &keys->keys[index].keycode);
@@ -296,6 +288,7 @@
dev_err(keys->dev,
"failed to read key:%d linux,keycode property: %d\n",
index, error);
+ of_node_put(child);
return error;
}
@@ -303,8 +296,10 @@
keys->keys[index].wakeup = true;
error = mtk_pmic_key_setup(keys, &keys->keys[index]);
- if (error)
+ if (error) {
+ of_node_put(child);
return error;
+ }
index++;
}
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index de26e2d..9742261 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000 Justin Cormack
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/slab.h>
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
index 8567ee4..608446e 100644
--- a/drivers/input/keyboard/nomadik-ske-keypad.c
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
* Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
*
- * License terms:GNU General Public License (GPL) version 2
- *
* Keypad controller driver for the SKE (Scroll Key Encoder) module used in
* the Nomadik 8815 and Ux500 platforms.
*/
@@ -100,7 +99,7 @@
while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--)
cpu_relax();
- if (!timeout)
+ if (timeout == -1)
return -EINVAL;
/*
@@ -236,10 +235,8 @@
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get keypad irq\n");
+ if (irq < 0)
return -EINVAL;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c
index c7f26fa..63d5e48 100644
--- a/drivers/input/keyboard/nspire-keypad.c
+++ b/drivers/input/keyboard/nspire-keypad.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
*/
#include <linux/input/matrix_keypad.h>
@@ -168,10 +165,8 @@
int error;
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get keypad irq\n");
+ if (irq < 0)
return -EINVAL;
- }
keypad = devm_kzalloc(&pdev->dev, sizeof(struct nspire_keypad),
GFP_KERNEL);
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 7bd1079..5fe7a56 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/input/keyboard/omap-keypad.c
*
@@ -8,20 +9,6 @@
*
* Added support for H2 & H3 Keypad
* Copyright (C) 2004 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index a7dc286..94c94d7 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OMAP4 Keypad Driver
*
@@ -5,20 +6,6 @@
*
* Author: Abraham Arce <x0066660@ti.com>
* Initial Code: Syed Rafiuddin <rafiuddin.syed@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
@@ -126,12 +113,8 @@
{
struct omap4_keypad *keypad_data = dev_id;
- if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)) {
- /* Disable interrupts */
- kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
- OMAP4_VAL_IRQDISABLE);
+ if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS))
return IRQ_WAKE_THREAD;
- }
return IRQ_NONE;
}
@@ -173,11 +156,6 @@
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
- /* enable interrupts */
- kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
- OMAP4_DEF_IRQENABLE_EVENTEN |
- OMAP4_DEF_IRQENABLE_LONGKEY);
-
return IRQ_HANDLED;
}
@@ -214,9 +192,10 @@
disable_irq(keypad_data->irq);
- /* Disable interrupts */
+ /* Disable interrupts and wake-up events */
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
OMAP4_VAL_IRQDISABLE);
+ kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE, 0);
/* clear pending interrupts */
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
@@ -365,7 +344,7 @@
}
error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler,
- omap4_keypad_irq_thread_fn, 0,
+ omap4_keypad_irq_thread_fn, IRQF_ONESHOT,
"omap4-keypad", keypad_data);
if (error) {
dev_err(&pdev->dev, "failed to register interrupt\n");
diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c
index d62b406..b0ea387 100644
--- a/drivers/input/keyboard/opencores-kbd.c
+++ b/drivers/input/keyboard/opencores-kbd.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenCores Keyboard Controller Driver
* http://www.opencores.org/project,keyboardcontroller
*
* Copyright 2007-2009 HV Sistemas S.L.
- *
- * Licensed under the GPL-2 or later.
*/
#include <linux/input.h>
@@ -50,10 +49,8 @@
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "missing board IRQ resource\n");
+ if (irq < 0)
return -EINVAL;
- }
opencores_kbd = devm_kzalloc(&pdev->dev, sizeof(*opencores_kbd),
GFP_KERNEL);
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 98b24ed..91d5811 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -1,13 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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.
*/
#include <linux/module.h>
@@ -552,16 +544,12 @@
}
kp->key_sense_irq = platform_get_irq(pdev, 0);
- if (kp->key_sense_irq < 0) {
- dev_err(&pdev->dev, "unable to get keypad sense irq\n");
+ if (kp->key_sense_irq < 0)
return kp->key_sense_irq;
- }
kp->key_stuck_irq = platform_get_irq(pdev, 1);
- if (kp->key_stuck_irq < 0) {
- dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
+ if (kp->key_stuck_irq < 0)
return kp->key_stuck_irq;
- }
kp->input->name = "PMIC8XXX keypad";
kp->input->phys = "pmic8xxx_keypad/input0";
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index d0bdaea..7e65708 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/input/keyboard/pxa27x_keypad.c
*
@@ -9,10 +10,6 @@
* Based on a previous implementations by Kevin O'Connor
* <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
* on some suggestions by Nicolas Pitre <nico@fluxnic.net>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
@@ -730,10 +727,8 @@
return -EINVAL;
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get keypad irq\n");
+ if (irq < 0)
return -ENXIO;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c
index 1cf5211..f741409 100644
--- a/drivers/input/keyboard/pxa930_rotary.c
+++ b/drivers/input/keyboard/pxa930_rotary.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the enhanced rotary controller on pxa930 and pxa935
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/kernel.h>
@@ -92,10 +89,8 @@
int err;
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "no irq for rotary controller\n");
+ if (irq < 0)
return -ENXIO;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
diff --git a/drivers/input/keyboard/qt1050.c b/drivers/input/keyboard/qt1050.c
new file mode 100644
index 0000000..403060d
--- /dev/null
+++ b/drivers/input/keyboard/qt1050.c
@@ -0,0 +1,598 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip AT42QT1050 QTouch Sensor Controller
+ *
+ * Copyright (C) 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ *
+ * Base on AT42QT1070 driver by:
+ * Bo Shen <voice.shen@atmel.com>
+ * Copyright (C) 2011 Atmel
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+/* Chip ID */
+#define QT1050_CHIP_ID 0x00
+#define QT1050_CHIP_ID_VER 0x46
+
+/* Firmware version */
+#define QT1050_FW_VERSION 0x01
+
+/* Detection status */
+#define QT1050_DET_STATUS 0x02
+
+/* Key status */
+#define QT1050_KEY_STATUS 0x03
+
+/* Key Signals */
+#define QT1050_KEY_SIGNAL_0_MSB 0x06
+#define QT1050_KEY_SIGNAL_0_LSB 0x07
+#define QT1050_KEY_SIGNAL_1_MSB 0x08
+#define QT1050_KEY_SIGNAL_1_LSB 0x09
+#define QT1050_KEY_SIGNAL_2_MSB 0x0c
+#define QT1050_KEY_SIGNAL_2_LSB 0x0d
+#define QT1050_KEY_SIGNAL_3_MSB 0x0e
+#define QT1050_KEY_SIGNAL_3_LSB 0x0f
+#define QT1050_KEY_SIGNAL_4_MSB 0x10
+#define QT1050_KEY_SIGNAL_4_LSB 0x11
+
+/* Reference data */
+#define QT1050_REF_DATA_0_MSB 0x14
+#define QT1050_REF_DATA_0_LSB 0x15
+#define QT1050_REF_DATA_1_MSB 0x16
+#define QT1050_REF_DATA_1_LSB 0x17
+#define QT1050_REF_DATA_2_MSB 0x1a
+#define QT1050_REF_DATA_2_LSB 0x1b
+#define QT1050_REF_DATA_3_MSB 0x1c
+#define QT1050_REF_DATA_3_LSB 0x1d
+#define QT1050_REF_DATA_4_MSB 0x1e
+#define QT1050_REF_DATA_4_LSB 0x1f
+
+/* Negative threshold level */
+#define QT1050_NTHR_0 0x21
+#define QT1050_NTHR_1 0x22
+#define QT1050_NTHR_2 0x24
+#define QT1050_NTHR_3 0x25
+#define QT1050_NTHR_4 0x26
+
+/* Pulse / Scale */
+#define QT1050_PULSE_SCALE_0 0x28
+#define QT1050_PULSE_SCALE_1 0x29
+#define QT1050_PULSE_SCALE_2 0x2b
+#define QT1050_PULSE_SCALE_3 0x2c
+#define QT1050_PULSE_SCALE_4 0x2d
+
+/* Detection integrator counter / AKS */
+#define QT1050_DI_AKS_0 0x2f
+#define QT1050_DI_AKS_1 0x30
+#define QT1050_DI_AKS_2 0x32
+#define QT1050_DI_AKS_3 0x33
+#define QT1050_DI_AKS_4 0x34
+
+/* Charge Share Delay */
+#define QT1050_CSD_0 0x36
+#define QT1050_CSD_1 0x37
+#define QT1050_CSD_2 0x39
+#define QT1050_CSD_3 0x3a
+#define QT1050_CSD_4 0x3b
+
+/* Low Power Mode */
+#define QT1050_LPMODE 0x3d
+
+/* Calibration and Reset */
+#define QT1050_RES_CAL 0x3f
+#define QT1050_RES_CAL_RESET BIT(7)
+#define QT1050_RES_CAL_CALIBRATE BIT(1)
+
+#define QT1050_MAX_KEYS 5
+#define QT1050_RESET_TIME 255
+
+struct qt1050_key_regs {
+ unsigned int nthr;
+ unsigned int pulse_scale;
+ unsigned int di_aks;
+ unsigned int csd;
+};
+
+struct qt1050_key {
+ u32 num;
+ u32 charge_delay;
+ u32 thr_cnt;
+ u32 samples;
+ u32 scale;
+ u32 keycode;
+};
+
+struct qt1050_priv {
+ struct i2c_client *client;
+ struct input_dev *input;
+ struct regmap *regmap;
+ struct qt1050_key keys[QT1050_MAX_KEYS];
+ unsigned short keycodes[QT1050_MAX_KEYS];
+ u8 reg_keys;
+ u8 last_keys;
+};
+
+static const struct qt1050_key_regs qt1050_key_regs_data[] = {
+ {
+ .nthr = QT1050_NTHR_0,
+ .pulse_scale = QT1050_PULSE_SCALE_0,
+ .di_aks = QT1050_DI_AKS_0,
+ .csd = QT1050_CSD_0,
+ }, {
+ .nthr = QT1050_NTHR_1,
+ .pulse_scale = QT1050_PULSE_SCALE_1,
+ .di_aks = QT1050_DI_AKS_1,
+ .csd = QT1050_CSD_1,
+ }, {
+ .nthr = QT1050_NTHR_2,
+ .pulse_scale = QT1050_PULSE_SCALE_2,
+ .di_aks = QT1050_DI_AKS_2,
+ .csd = QT1050_CSD_2,
+ }, {
+ .nthr = QT1050_NTHR_3,
+ .pulse_scale = QT1050_PULSE_SCALE_3,
+ .di_aks = QT1050_DI_AKS_3,
+ .csd = QT1050_CSD_3,
+ }, {
+ .nthr = QT1050_NTHR_4,
+ .pulse_scale = QT1050_PULSE_SCALE_4,
+ .di_aks = QT1050_DI_AKS_4,
+ .csd = QT1050_CSD_4,
+ }
+};
+
+static bool qt1050_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case QT1050_DET_STATUS:
+ case QT1050_KEY_STATUS:
+ case QT1050_KEY_SIGNAL_0_MSB:
+ case QT1050_KEY_SIGNAL_0_LSB:
+ case QT1050_KEY_SIGNAL_1_MSB:
+ case QT1050_KEY_SIGNAL_1_LSB:
+ case QT1050_KEY_SIGNAL_2_MSB:
+ case QT1050_KEY_SIGNAL_2_LSB:
+ case QT1050_KEY_SIGNAL_3_MSB:
+ case QT1050_KEY_SIGNAL_3_LSB:
+ case QT1050_KEY_SIGNAL_4_MSB:
+ case QT1050_KEY_SIGNAL_4_LSB:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_range qt1050_readable_ranges[] = {
+ regmap_reg_range(QT1050_CHIP_ID, QT1050_KEY_STATUS),
+ regmap_reg_range(QT1050_KEY_SIGNAL_0_MSB, QT1050_KEY_SIGNAL_1_LSB),
+ regmap_reg_range(QT1050_KEY_SIGNAL_2_MSB, QT1050_KEY_SIGNAL_4_LSB),
+ regmap_reg_range(QT1050_REF_DATA_0_MSB, QT1050_REF_DATA_1_LSB),
+ regmap_reg_range(QT1050_REF_DATA_2_MSB, QT1050_REF_DATA_4_LSB),
+ regmap_reg_range(QT1050_NTHR_0, QT1050_NTHR_1),
+ regmap_reg_range(QT1050_NTHR_2, QT1050_NTHR_4),
+ regmap_reg_range(QT1050_PULSE_SCALE_0, QT1050_PULSE_SCALE_1),
+ regmap_reg_range(QT1050_PULSE_SCALE_2, QT1050_PULSE_SCALE_4),
+ regmap_reg_range(QT1050_DI_AKS_0, QT1050_DI_AKS_1),
+ regmap_reg_range(QT1050_DI_AKS_2, QT1050_DI_AKS_4),
+ regmap_reg_range(QT1050_CSD_0, QT1050_CSD_1),
+ regmap_reg_range(QT1050_CSD_2, QT1050_RES_CAL),
+};
+
+static const struct regmap_access_table qt1050_readable_table = {
+ .yes_ranges = qt1050_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(qt1050_readable_ranges),
+};
+
+static const struct regmap_range qt1050_writeable_ranges[] = {
+ regmap_reg_range(QT1050_NTHR_0, QT1050_NTHR_1),
+ regmap_reg_range(QT1050_NTHR_2, QT1050_NTHR_4),
+ regmap_reg_range(QT1050_PULSE_SCALE_0, QT1050_PULSE_SCALE_1),
+ regmap_reg_range(QT1050_PULSE_SCALE_2, QT1050_PULSE_SCALE_4),
+ regmap_reg_range(QT1050_DI_AKS_0, QT1050_DI_AKS_1),
+ regmap_reg_range(QT1050_DI_AKS_2, QT1050_DI_AKS_4),
+ regmap_reg_range(QT1050_CSD_0, QT1050_CSD_1),
+ regmap_reg_range(QT1050_CSD_2, QT1050_RES_CAL),
+};
+
+static const struct regmap_access_table qt1050_writeable_table = {
+ .yes_ranges = qt1050_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(qt1050_writeable_ranges),
+};
+
+static struct regmap_config qt1050_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = QT1050_RES_CAL,
+
+ .cache_type = REGCACHE_RBTREE,
+
+ .wr_table = &qt1050_writeable_table,
+ .rd_table = &qt1050_readable_table,
+ .volatile_reg = qt1050_volatile_reg,
+};
+
+static bool qt1050_identify(struct qt1050_priv *ts)
+{
+ unsigned int val;
+ int err;
+
+ /* Read Chip ID */
+ regmap_read(ts->regmap, QT1050_CHIP_ID, &val);
+ if (val != QT1050_CHIP_ID_VER) {
+ dev_err(&ts->client->dev, "ID %d not supported\n", val);
+ return false;
+ }
+
+ /* Read firmware version */
+ err = regmap_read(ts->regmap, QT1050_FW_VERSION, &val);
+ if (err) {
+ dev_err(&ts->client->dev, "could not read the firmware version\n");
+ return false;
+ }
+
+ dev_info(&ts->client->dev, "AT42QT1050 firmware version %1d.%1d\n",
+ val >> 4, val & 0xf);
+
+ return true;
+}
+
+static irqreturn_t qt1050_irq_threaded(int irq, void *dev_id)
+{
+ struct qt1050_priv *ts = dev_id;
+ struct input_dev *input = ts->input;
+ unsigned long new_keys, changed;
+ unsigned int val;
+ int i, err;
+
+ /* Read the detected status register, thus clearing interrupt */
+ err = regmap_read(ts->regmap, QT1050_DET_STATUS, &val);
+ if (err) {
+ dev_err(&ts->client->dev, "Fail to read detection status: %d\n",
+ err);
+ return IRQ_NONE;
+ }
+
+ /* Read which key changed, keys are not continuous */
+ err = regmap_read(ts->regmap, QT1050_KEY_STATUS, &val);
+ if (err) {
+ dev_err(&ts->client->dev,
+ "Fail to determine the key status: %d\n", err);
+ return IRQ_NONE;
+ }
+ new_keys = (val & 0x70) >> 2 | (val & 0x6) >> 1;
+ changed = ts->last_keys ^ new_keys;
+ /* Report registered keys only */
+ changed &= ts->reg_keys;
+
+ for_each_set_bit(i, &changed, QT1050_MAX_KEYS)
+ input_report_key(input, ts->keys[i].keycode,
+ test_bit(i, &new_keys));
+
+ ts->last_keys = new_keys;
+ input_sync(input);
+
+ return IRQ_HANDLED;
+}
+
+static const struct qt1050_key_regs *qt1050_get_key_regs(int key_num)
+{
+ return &qt1050_key_regs_data[key_num];
+}
+
+static int qt1050_set_key(struct regmap *map, int number, int on)
+{
+ const struct qt1050_key_regs *key_regs;
+
+ key_regs = qt1050_get_key_regs(number);
+
+ return regmap_update_bits(map, key_regs->di_aks, 0xfc,
+ on ? BIT(4) : 0x00);
+}
+
+static int qt1050_apply_fw_data(struct qt1050_priv *ts)
+{
+ struct regmap *map = ts->regmap;
+ struct qt1050_key *button = &ts->keys[0];
+ const struct qt1050_key_regs *key_regs;
+ int i, err;
+
+ /* Disable all keys and enable only the specified ones */
+ for (i = 0; i < QT1050_MAX_KEYS; i++) {
+ err = qt1050_set_key(map, i, 0);
+ if (err)
+ return err;
+ }
+
+ for (i = 0; i < QT1050_MAX_KEYS; i++, button++) {
+ /* Keep KEY_RESERVED keys off */
+ if (button->keycode == KEY_RESERVED)
+ continue;
+
+ err = qt1050_set_key(map, button->num, 1);
+ if (err)
+ return err;
+
+ key_regs = qt1050_get_key_regs(button->num);
+
+ err = regmap_write(map, key_regs->pulse_scale,
+ (button->samples << 4) | (button->scale));
+ if (err)
+ return err;
+ err = regmap_write(map, key_regs->csd, button->charge_delay);
+ if (err)
+ return err;
+ err = regmap_write(map, key_regs->nthr, button->thr_cnt);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int qt1050_parse_fw(struct qt1050_priv *ts)
+{
+ struct device *dev = &ts->client->dev;
+ struct fwnode_handle *child;
+ int nbuttons;
+
+ nbuttons = device_get_child_node_count(dev);
+ if (nbuttons == 0 || nbuttons > QT1050_MAX_KEYS)
+ return -ENODEV;
+
+ device_for_each_child_node(dev, child) {
+ struct qt1050_key button;
+
+ /* Required properties */
+ if (fwnode_property_read_u32(child, "linux,code",
+ &button.keycode)) {
+ dev_err(dev, "Button without keycode\n");
+ goto err;
+ }
+ if (button.keycode >= KEY_MAX) {
+ dev_err(dev, "Invalid keycode 0x%x\n",
+ button.keycode);
+ goto err;
+ }
+
+ if (fwnode_property_read_u32(child, "reg",
+ &button.num)) {
+ dev_err(dev, "Button without pad number\n");
+ goto err;
+ }
+ if (button.num < 0 || button.num > QT1050_MAX_KEYS - 1)
+ goto err;
+
+ ts->reg_keys |= BIT(button.num);
+
+ /* Optional properties */
+ if (fwnode_property_read_u32(child,
+ "microchip,pre-charge-time-ns",
+ &button.charge_delay)) {
+ button.charge_delay = 0;
+ } else {
+ if (button.charge_delay % 2500 == 0)
+ button.charge_delay =
+ button.charge_delay / 2500;
+ else
+ button.charge_delay = 0;
+ }
+
+ if (fwnode_property_read_u32(child, "microchip,average-samples",
+ &button.samples)) {
+ button.samples = 0;
+ } else {
+ if (is_power_of_2(button.samples))
+ button.samples = ilog2(button.samples);
+ else
+ button.samples = 0;
+ }
+
+ if (fwnode_property_read_u32(child, "microchip,average-scaling",
+ &button.scale)) {
+ button.scale = 0;
+ } else {
+ if (is_power_of_2(button.scale))
+ button.scale = ilog2(button.scale);
+ else
+ button.scale = 0;
+
+ }
+
+ if (fwnode_property_read_u32(child, "microchip,threshold",
+ &button.thr_cnt)) {
+ button.thr_cnt = 20;
+ } else {
+ if (button.thr_cnt > 255)
+ button.thr_cnt = 20;
+ }
+
+ ts->keys[button.num] = button;
+ }
+
+ return 0;
+
+err:
+ fwnode_handle_put(child);
+ return -EINVAL;
+}
+
+static int qt1050_probe(struct i2c_client *client)
+{
+ struct qt1050_priv *ts;
+ struct input_dev *input;
+ struct device *dev = &client->dev;
+ struct regmap *map;
+ unsigned int status, i;
+ int err;
+
+ /* Check basic functionality */
+ err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
+ if (!err) {
+ dev_err(&client->dev, "%s adapter not supported\n",
+ dev_driver_string(&client->adapter->dev));
+ return -ENODEV;
+ }
+
+ if (!client->irq) {
+ dev_err(dev, "assign a irq line to this device\n");
+ return -EINVAL;
+ }
+
+ ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
+
+ map = devm_regmap_init_i2c(client, &qt1050_regmap_config);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ ts->client = client;
+ ts->input = input;
+ ts->regmap = map;
+
+ i2c_set_clientdata(client, ts);
+
+ /* Identify the qt1050 chip */
+ if (!qt1050_identify(ts))
+ return -ENODEV;
+
+ /* Get pdata */
+ err = qt1050_parse_fw(ts);
+ if (err) {
+ dev_err(dev, "Failed to parse firmware: %d\n", err);
+ return err;
+ }
+
+ input->name = "AT42QT1050 QTouch Sensor";
+ input->dev.parent = &client->dev;
+ input->id.bustype = BUS_I2C;
+
+ /* Add the keycode */
+ input->keycode = ts->keycodes;
+ input->keycodesize = sizeof(ts->keycodes[0]);
+ input->keycodemax = QT1050_MAX_KEYS;
+
+ __set_bit(EV_KEY, input->evbit);
+ for (i = 0; i < QT1050_MAX_KEYS; i++) {
+ ts->keycodes[i] = ts->keys[i].keycode;
+ __set_bit(ts->keycodes[i], input->keybit);
+ }
+
+ /* Trigger re-calibration */
+ err = regmap_update_bits(ts->regmap, QT1050_RES_CAL, 0x7f,
+ QT1050_RES_CAL_CALIBRATE);
+ if (err) {
+ dev_err(dev, "Trigger calibration failed: %d\n", err);
+ return err;
+ }
+ err = regmap_read_poll_timeout(ts->regmap, QT1050_DET_STATUS, status,
+ status >> 7 == 1, 10000, 200000);
+ if (err) {
+ dev_err(dev, "Calibration failed: %d\n", err);
+ return err;
+ }
+
+ /* Soft reset to set defaults */
+ err = regmap_update_bits(ts->regmap, QT1050_RES_CAL,
+ QT1050_RES_CAL_RESET, QT1050_RES_CAL_RESET);
+ if (err) {
+ dev_err(dev, "Trigger soft reset failed: %d\n", err);
+ return err;
+ }
+ msleep(QT1050_RESET_TIME);
+
+ /* Set pdata */
+ err = qt1050_apply_fw_data(ts);
+ if (err) {
+ dev_err(dev, "Failed to set firmware data: %d\n", err);
+ return err;
+ }
+
+ err = devm_request_threaded_irq(dev, client->irq, NULL,
+ qt1050_irq_threaded, IRQF_ONESHOT,
+ "qt1050", ts);
+ if (err) {
+ dev_err(&client->dev, "Failed to request irq: %d\n", err);
+ return err;
+ }
+
+ /* Clear #CHANGE line */
+ err = regmap_read(ts->regmap, QT1050_DET_STATUS, &status);
+ if (err) {
+ dev_err(dev, "Failed to clear #CHANGE line level: %d\n", err);
+ return err;
+ }
+
+ /* Register the input device */
+ err = input_register_device(ts->input);
+ if (err) {
+ dev_err(&client->dev, "Failed to register input device: %d\n",
+ err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused qt1050_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct qt1050_priv *ts = i2c_get_clientdata(client);
+
+ disable_irq(client->irq);
+
+ /*
+ * Set measurement interval to 1s (125 x 8ms) if wakeup is allowed
+ * else turn off. The 1s interval seems to be a good compromise between
+ * low power and response time.
+ */
+ return regmap_write(ts->regmap, QT1050_LPMODE,
+ device_may_wakeup(dev) ? 125 : 0);
+}
+
+static int __maybe_unused qt1050_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct qt1050_priv *ts = i2c_get_clientdata(client);
+
+ enable_irq(client->irq);
+
+ /* Set measurement interval back to 16ms (2 x 8ms) */
+ return regmap_write(ts->regmap, QT1050_LPMODE, 2);
+}
+
+static SIMPLE_DEV_PM_OPS(qt1050_pm_ops, qt1050_suspend, qt1050_resume);
+
+static const struct of_device_id __maybe_unused qt1050_of_match[] = {
+ { .compatible = "microchip,qt1050", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qt1050_of_match);
+
+static struct i2c_driver qt1050_driver = {
+ .driver = {
+ .name = "qt1050",
+ .of_match_table = of_match_ptr(qt1050_of_match),
+ .pm = &qt1050_pm_ops,
+ },
+ .probe_new = qt1050_probe,
+};
+
+module_i2c_driver(qt1050_driver);
+
+MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de");
+MODULE_DESCRIPTION("Driver for AT42QT1050 QTouch sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
index 76bb513..7174e1d 100644
--- a/drivers/input/keyboard/qt1070.c
+++ b/drivers/input/keyboard/qt1070.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Atmel AT42QT1070 QTouch Sensor Controller
*
@@ -8,20 +9,6 @@
* Base on AT42QT2160 driver by:
* Raphael Derosso Pereira <raphaelpereira@gmail.com>
* Copyright (C) 2009
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
index 43b8648..32d4a07 100644
--- a/drivers/input/keyboard/qt2160.c
+++ b/drivers/input/keyboard/qt2160.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* qt2160.c - Atmel AT42QT2160 Touch Sense Controller
*
* Copyright (C) 2009 Raphael Derosso Pereira <raphaelpereira@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
@@ -58,10 +45,9 @@
struct qt2160_led {
struct qt2160_data *qt2160;
struct led_classdev cdev;
- struct work_struct work;
char name[32];
int id;
- enum led_brightness new_brightness;
+ enum led_brightness brightness;
};
#endif
@@ -69,12 +55,10 @@
struct i2c_client *client;
struct input_dev *input;
struct delayed_work dwork;
- spinlock_t lock; /* Protects canceling/rescheduling of dwork */
unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
u16 key_matrix;
#ifdef CONFIG_LEDS_CLASS
struct qt2160_led leds[QT2160_NUM_LEDS_X];
- struct mutex led_lock;
#endif
};
@@ -83,46 +67,39 @@
#ifdef CONFIG_LEDS_CLASS
-static void qt2160_led_work(struct work_struct *work)
-{
- struct qt2160_led *led = container_of(work, struct qt2160_led, work);
- struct qt2160_data *qt2160 = led->qt2160;
- struct i2c_client *client = qt2160->client;
- int value = led->new_brightness;
- u32 drive, pwmen;
-
- mutex_lock(&qt2160->led_lock);
-
- drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
- pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
- if (value != LED_OFF) {
- drive |= (1 << led->id);
- pwmen |= (1 << led->id);
-
- } else {
- drive &= ~(1 << led->id);
- pwmen &= ~(1 << led->id);
- }
- qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
- qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
-
- /*
- * Changing this register will change the brightness
- * of every LED in the qt2160. It's a HW limitation.
- */
- if (value != LED_OFF)
- qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
-
- mutex_unlock(&qt2160->led_lock);
-}
-
-static void qt2160_led_set(struct led_classdev *cdev,
- enum led_brightness value)
+static int qt2160_led_set(struct led_classdev *cdev,
+ enum led_brightness value)
{
struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
+ struct qt2160_data *qt2160 = led->qt2160;
+ struct i2c_client *client = qt2160->client;
+ u32 drive, pwmen;
- led->new_brightness = value;
- schedule_work(&led->work);
+ if (value != led->brightness) {
+ drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
+ pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
+ if (value != LED_OFF) {
+ drive |= BIT(led->id);
+ pwmen |= BIT(led->id);
+
+ } else {
+ drive &= ~BIT(led->id);
+ pwmen &= ~BIT(led->id);
+ }
+ qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
+ qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
+
+ /*
+ * Changing this register will change the brightness
+ * of every LED in the qt2160. It's a HW limitation.
+ */
+ if (value != LED_OFF)
+ qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
+
+ led->brightness = value;
+ }
+
+ return 0;
}
#endif /* CONFIG_LEDS_CLASS */
@@ -221,22 +198,15 @@
static irqreturn_t qt2160_irq(int irq, void *_qt2160)
{
struct qt2160_data *qt2160 = _qt2160;
- unsigned long flags;
-
- spin_lock_irqsave(&qt2160->lock, flags);
mod_delayed_work(system_wq, &qt2160->dwork, 0);
- spin_unlock_irqrestore(&qt2160->lock, flags);
-
return IRQ_HANDLED;
}
static void qt2160_schedule_read(struct qt2160_data *qt2160)
{
- spin_lock_irq(&qt2160->lock);
schedule_delayed_work(&qt2160->dwork, QT2160_CYCLE_INTERVAL);
- spin_unlock_irq(&qt2160->lock);
}
static void qt2160_worker(struct work_struct *work)
@@ -293,20 +263,16 @@
int ret;
int i;
- mutex_init(&qt2160->led_lock);
-
for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
struct qt2160_led *led = &qt2160->leds[i];
snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
led->cdev.name = led->name;
- led->cdev.brightness_set = qt2160_led_set;
+ led->cdev.brightness_set_blocking = qt2160_led_set;
led->cdev.brightness = LED_OFF;
led->id = i;
led->qt2160 = qt2160;
- INIT_WORK(&led->work, qt2160_led_work);
-
ret = led_classdev_register(&client->dev, &led->cdev);
if (ret < 0)
return ret;
@@ -324,10 +290,8 @@
{
int i;
- for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
+ for (i = 0; i < QT2160_NUM_LEDS_X; i++)
led_classdev_unregister(&qt2160->leds[i].cdev);
- cancel_work_sync(&qt2160->leds[i].work);
- }
}
#else
@@ -406,7 +370,6 @@
qt2160->client = client;
qt2160->input = input;
INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker);
- spin_lock_init(&qt2160->lock);
input->name = "AT42QT2160 Touch Sense Keyboard";
input->id.bustype = BUS_I2C;
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 1fe1aa2..70c1d08 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Samsung keypad driver
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
* Author: Donghwa Lee <dh09.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/clk.h>
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index 7abf03b..27ad73f 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SuperH KEYSC Keypad Driver
*
* Copyright (C) 2008 Magnus Damm
*
* Based on gpio_keys.c, Copyright 2005 Phil Blundell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/kernel.h>
@@ -184,10 +181,8 @@
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get irq\n");
+ if (irq < 0)
goto err0;
- }
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (priv == NULL) {
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index effb632..e76b7a4 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -15,6 +15,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -117,10 +118,8 @@
pdata->wakeup = of_property_read_bool(np, "wakeup-source");
pdata->irq = platform_get_irq(pdev, 0);
- if (pdata->irq < 0) {
- dev_err(&pdev->dev, "no irq defined in platform data\n");
+ if (pdata->irq < 0)
return -EINVAL;
- }
regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN);
@@ -148,6 +147,9 @@
return error;
}
+ pdata->input = input;
+ platform_set_drvdata(pdev, pdata);
+
error = devm_request_irq(&pdev->dev, pdata->irq,
imx_snvs_pwrkey_interrupt,
0, pdev->name, pdev);
@@ -163,32 +165,10 @@
return error;
}
- pdata->input = input;
- platform_set_drvdata(pdev, pdata);
-
device_init_wakeup(&pdev->dev, pdata->wakeup);
-
- return 0;
-}
-
-static int __maybe_unused imx_snvs_pwrkey_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
-
- if (device_may_wakeup(&pdev->dev))
- enable_irq_wake(pdata->irq);
-
- return 0;
-}
-
-static int __maybe_unused imx_snvs_pwrkey_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
-
- if (device_may_wakeup(&pdev->dev))
- disable_irq_wake(pdata->irq);
+ error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
+ if (error)
+ dev_err(&pdev->dev, "irq wake enable failed.\n");
return 0;
}
@@ -199,13 +179,9 @@
};
MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids);
-static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, imx_snvs_pwrkey_suspend,
- imx_snvs_pwrkey_resume);
-
static struct platform_driver imx_snvs_pwrkey_driver = {
.driver = {
.name = "snvs_pwrkey",
- .pm = &imx_snvs_pwrkey_pm_ops,
.of_match_table = imx_snvs_pwrkey_ids,
},
.probe = imx_snvs_pwrkey_probe,
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 7d25fa3..9b8d78f 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -191,10 +191,8 @@
int error;
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "not able to get irq for the device\n");
+ if (irq < 0)
return irq;
- }
kbd = devm_kzalloc(&pdev->dev, sizeof(*kbd), GFP_KERNEL);
if (!kbd) {
diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c
index babcfb1..27562cd 100644
--- a/drivers/input/keyboard/st-keyscan.c
+++ b/drivers/input/keyboard/st-keyscan.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* STMicroelectronics Key Scanning driver
*
@@ -5,10 +6,6 @@
* Author: Stuart Menefy <stuart.menefy@st.com>
*
* Based on sh_keysc.c, copyright 2008 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
@@ -153,6 +150,8 @@
input_dev->id.bustype = BUS_HOST;
+ keypad_data->input_dev = input_dev;
+
error = keypad_matrix_key_parse_dt(keypad_data);
if (error)
return error;
@@ -168,8 +167,6 @@
input_set_drvdata(input_dev, keypad_data);
- keypad_data->input_dev = input_dev;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(keypad_data->base))
@@ -190,10 +187,8 @@
keyscan_stop(keypad_data);
keypad_data->irq = platform_get_irq(pdev, 0);
- if (keypad_data->irq < 0) {
- dev_err(&pdev->dev, "no IRQ specified\n");
+ if (keypad_data->irq < 0)
return -EINVAL;
- }
error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0,
pdev->name, keypad_data);
diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c
index d69e631..7bf9728 100644
--- a/drivers/input/keyboard/stmpe-keypad.c
+++ b/drivers/input/keyboard/stmpe-keypad.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
- * License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c
index 15a5e74..a497719 100644
--- a/drivers/input/keyboard/stowaway.c
+++ b/drivers/input/keyboard/stowaway.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Stowaway keyboard driver for Linux
*/
@@ -10,19 +11,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/slab.h>
diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
index a37c172..4a796be 100644
--- a/drivers/input/keyboard/sun4i-lradc-keys.c
+++ b/drivers/input/keyboard/sun4i-lradc-keys.c
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Allwinner sun4i low res adc attached tablet keys driver
*
* Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
*/
/*
@@ -46,6 +37,7 @@
#define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */
#define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */
#define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */
+#define HOLD_KEY_EN(x) ((x) << 7)
#define HOLD_EN(x) ((x) << 6)
#define LEVELB_VOL(x) ((x) << 4) /* 2 bits */
#define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */
@@ -63,6 +55,25 @@
#define CHAN0_KEYDOWN_IRQ BIT(1)
#define CHAN0_DATA_IRQ BIT(0)
+/* struct lradc_variant - Describe sun4i-a10-lradc-keys hardware variant
+ * @divisor_numerator: The numerator of lradc Vref internally divisor
+ * @divisor_denominator: The denominator of lradc Vref internally divisor
+ */
+struct lradc_variant {
+ u8 divisor_numerator;
+ u8 divisor_denominator;
+};
+
+static const struct lradc_variant lradc_variant_a10 = {
+ .divisor_numerator = 2,
+ .divisor_denominator = 3
+};
+
+static const struct lradc_variant r_lradc_variant_a83t = {
+ .divisor_numerator = 3,
+ .divisor_denominator = 4
+};
+
struct sun4i_lradc_keymap {
u32 voltage;
u32 keycode;
@@ -74,6 +85,7 @@
void __iomem *base;
struct regulator *vref_supply;
struct sun4i_lradc_keymap *chan0_map;
+ const struct lradc_variant *variant;
u32 chan0_map_count;
u32 chan0_keycode;
u32 vref;
@@ -128,9 +140,9 @@
if (error)
return error;
- /* lradc Vref internally is divided by 2/3 */
- lradc->vref = regulator_get_voltage(lradc->vref_supply) * 2 / 3;
-
+ lradc->vref = regulator_get_voltage(lradc->vref_supply) *
+ lradc->variant->divisor_numerator /
+ lradc->variant->divisor_denominator;
/*
* Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to
* stabilize on press, wait (1 + 1) * 4 ms for key release
@@ -185,19 +197,22 @@
error = of_property_read_u32(pp, "channel", &channel);
if (error || channel != 0) {
- dev_err(dev, "%s: Inval channel prop\n", pp->name);
+ dev_err(dev, "%pOFn: Inval channel prop\n", pp);
+ of_node_put(pp);
return -EINVAL;
}
error = of_property_read_u32(pp, "voltage", &map->voltage);
if (error) {
- dev_err(dev, "%s: Inval voltage prop\n", pp->name);
+ dev_err(dev, "%pOFn: Inval voltage prop\n", pp);
+ of_node_put(pp);
return -EINVAL;
}
error = of_property_read_u32(pp, "linux,code", &map->keycode);
if (error) {
- dev_err(dev, "%s: Inval linux,code prop\n", pp->name);
+ dev_err(dev, "%pOFn: Inval linux,code prop\n", pp);
+ of_node_put(pp);
return -EINVAL;
}
@@ -222,6 +237,12 @@
if (error)
return error;
+ lradc->variant = of_device_get_match_data(&pdev->dev);
+ if (!lradc->variant) {
+ dev_err(&pdev->dev, "Missing sun4i-a10-lradc-keys variant\n");
+ return -EINVAL;
+ }
+
lradc->vref_supply = devm_regulator_get(dev, "vref");
if (IS_ERR(lradc->vref_supply))
return PTR_ERR(lradc->vref_supply);
@@ -265,7 +286,10 @@
}
static const struct of_device_id sun4i_lradc_of_match[] = {
- { .compatible = "allwinner,sun4i-a10-lradc-keys", },
+ { .compatible = "allwinner,sun4i-a10-lradc-keys",
+ .data = &lradc_variant_a10 },
+ { .compatible = "allwinner,sun8i-a83t-r-lradc",
+ .data = &r_lradc_variant_a83t },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index ad5d7f9..27126e6 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c
index ec0070e..89b9575 100644
--- a/drivers/input/keyboard/tc3589x-keypad.c
+++ b/drivers/input/keyboard/tc3589x-keypad.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com>
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
*
- * License Terms: GNU General Public License, version 2
- *
* TC35893 MFD Keypad Controller driver
*/
diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c
index dc983ab..2a14769 100644
--- a/drivers/input/keyboard/tca6416-keypad.c
+++ b/drivers/input/keyboard/tca6416-keypad.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for keys on TCA6416 I2C IO expander
*
* Copyright (C) 2010 Texas Instruments
*
* Author : Sriramakrishnan.A.G. <srk@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/types.h>
@@ -219,9 +216,7 @@
return -EINVAL;
}
- chip = kzalloc(sizeof(struct tca6416_keypad_chip) +
- pdata->nbuttons * sizeof(struct tca6416_button),
- GFP_KERNEL);
+ chip = kzalloc(struct_size(chip, buttons, pdata->nbuttons), GFP_KERNEL);
input = input_allocate_device();
if (!chip || !input) {
error = -ENOMEM;
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 6da607d..3bbd7e6 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -266,7 +266,7 @@
struct tca8418_keypad *keypad_data;
struct input_dev *input;
u32 rows = 0, cols = 0;
- int error, row_shift, max_keys;
+ int error, row_shift;
u8 reg;
/* Check i2c driver capabilities */
@@ -291,7 +291,6 @@
}
row_shift = get_count_order(cols);
- max_keys = rows << row_shift;
/* Allocate memory for keypad_data and input device */
keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL);
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index 875205f..d34d694 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Keyboard class input driver for the NVIDIA Tegra SoC internal matrix
* keyboard controller
*
* Copyright (c) 2009-2011, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -644,10 +631,8 @@
return -EINVAL;
kbc->irq = platform_get_irq(pdev, 0);
- if (kbc->irq < 0) {
- dev_err(&pdev->dev, "failed to get keyboard IRQ\n");
+ if (kbc->irq < 0)
return -ENXIO;
- }
kbc->idev = devm_input_allocate_device(&pdev->dev);
if (!kbc->idev) {
diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c
index abc266e..14b55ba 100644
--- a/drivers/input/keyboard/tm2-touchkey.c
+++ b/drivers/input/keyboard/tm2-touchkey.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TM2 touchkey device driver
*
@@ -6,10 +7,6 @@
*
* Author: Beomho Seo <beomho.seo@samsung.com>
* Author: Jaechul Lee <jcsing.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/bitops.h>
@@ -22,12 +19,14 @@
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#define TM2_TOUCHKEY_DEV_NAME "tm2-touchkey"
-#define TM2_TOUCHKEY_KEYCODE_REG 0x03
-#define TM2_TOUCHKEY_BASE_REG 0x00
+
+#define ARIES_TOUCHKEY_CMD_LED_ON 0x1
+#define ARIES_TOUCHKEY_CMD_LED_OFF 0x2
#define TM2_TOUCHKEY_CMD_LED_ON 0x10
#define TM2_TOUCHKEY_CMD_LED_OFF 0x20
#define TM2_TOUCHKEY_BIT_PRESS_EV BIT(3)
@@ -35,9 +34,13 @@
#define TM2_TOUCHKEY_LED_VOLTAGE_MIN 2500000
#define TM2_TOUCHKEY_LED_VOLTAGE_MAX 3300000
-enum {
- TM2_TOUCHKEY_KEY_MENU = 0x1,
- TM2_TOUCHKEY_KEY_BACK,
+struct touchkey_variant {
+ u8 keycode_reg;
+ u8 base_reg;
+ u8 cmd_led_on;
+ u8 cmd_led_off;
+ bool no_reg;
+ bool fixed_regulator;
};
struct tm2_touchkey_data {
@@ -46,9 +49,33 @@
struct led_classdev led_dev;
struct regulator *vdd;
struct regulator_bulk_data regulators[2];
+ const struct touchkey_variant *variant;
+ u32 keycodes[4];
+ int num_keycodes;
};
-static void tm2_touchkey_led_brightness_set(struct led_classdev *led_dev,
+static const struct touchkey_variant tm2_touchkey_variant = {
+ .keycode_reg = 0x03,
+ .base_reg = 0x00,
+ .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON,
+ .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF,
+};
+
+static const struct touchkey_variant midas_touchkey_variant = {
+ .keycode_reg = 0x00,
+ .base_reg = 0x00,
+ .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON,
+ .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF,
+};
+
+static struct touchkey_variant aries_touchkey_variant = {
+ .no_reg = true,
+ .fixed_regulator = true,
+ .cmd_led_on = ARIES_TOUCHKEY_CMD_LED_ON,
+ .cmd_led_off = ARIES_TOUCHKEY_CMD_LED_OFF,
+};
+
+static int tm2_touchkey_led_brightness_set(struct led_classdev *led_dev,
enum led_brightness brightness)
{
struct tm2_touchkey_data *touchkey =
@@ -58,15 +85,19 @@
if (brightness == LED_OFF) {
volt = TM2_TOUCHKEY_LED_VOLTAGE_MIN;
- data = TM2_TOUCHKEY_CMD_LED_OFF;
+ data = touchkey->variant->cmd_led_off;
} else {
volt = TM2_TOUCHKEY_LED_VOLTAGE_MAX;
- data = TM2_TOUCHKEY_CMD_LED_ON;
+ data = touchkey->variant->cmd_led_on;
}
- regulator_set_voltage(touchkey->vdd, volt, volt);
- i2c_smbus_write_byte_data(touchkey->client,
- TM2_TOUCHKEY_BASE_REG, data);
+ if (!touchkey->variant->fixed_regulator)
+ regulator_set_voltage(touchkey->vdd, volt, volt);
+
+ return touchkey->variant->no_reg ?
+ i2c_smbus_write_byte(touchkey->client, data) :
+ i2c_smbus_write_byte_data(touchkey->client,
+ touchkey->variant->base_reg, data);
}
static int tm2_touchkey_power_enable(struct tm2_touchkey_data *touchkey)
@@ -96,49 +127,57 @@
{
struct tm2_touchkey_data *touchkey = devid;
int data;
- int key;
+ int index;
+ int i;
- data = i2c_smbus_read_byte_data(touchkey->client,
- TM2_TOUCHKEY_KEYCODE_REG);
+ if (touchkey->variant->no_reg)
+ data = i2c_smbus_read_byte(touchkey->client);
+ else
+ data = i2c_smbus_read_byte_data(touchkey->client,
+ touchkey->variant->keycode_reg);
if (data < 0) {
dev_err(&touchkey->client->dev,
"failed to read i2c data: %d\n", data);
goto out;
}
- switch (data & TM2_TOUCHKEY_BIT_KEYCODE) {
- case TM2_TOUCHKEY_KEY_MENU:
- key = KEY_PHONE;
- break;
-
- case TM2_TOUCHKEY_KEY_BACK:
- key = KEY_BACK;
- break;
-
- default:
+ index = (data & TM2_TOUCHKEY_BIT_KEYCODE) - 1;
+ if (index < 0 || index >= touchkey->num_keycodes) {
dev_warn(&touchkey->client->dev,
- "unhandled keycode, data %#02x\n", data);
+ "invalid keycode index %d\n", index);
goto out;
}
if (data & TM2_TOUCHKEY_BIT_PRESS_EV) {
- input_report_key(touchkey->input_dev, KEY_PHONE, 0);
- input_report_key(touchkey->input_dev, KEY_BACK, 0);
+ for (i = 0; i < touchkey->num_keycodes; i++)
+ input_report_key(touchkey->input_dev,
+ touchkey->keycodes[i], 0);
} else {
- input_report_key(touchkey->input_dev, key, 1);
+ input_report_key(touchkey->input_dev,
+ touchkey->keycodes[index], 1);
}
input_sync(touchkey->input_dev);
out:
+ if (touchkey->variant->fixed_regulator &&
+ data & TM2_TOUCHKEY_BIT_PRESS_EV) {
+ /* touch turns backlight on, so make sure we're in sync */
+ if (touchkey->led_dev.brightness == LED_OFF)
+ tm2_touchkey_led_brightness_set(&touchkey->led_dev,
+ LED_OFF);
+ }
+
return IRQ_HANDLED;
}
static int tm2_touchkey_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device_node *np = client->dev.of_node;
struct tm2_touchkey_data *touchkey;
int error;
+ int i;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) {
@@ -153,6 +192,8 @@
touchkey->client = client;
i2c_set_clientdata(client, touchkey);
+ touchkey->variant = of_device_get_match_data(&client->dev);
+
touchkey->regulators[0].supply = "vcc";
touchkey->regulators[1].supply = "vdd";
error = devm_regulator_bulk_get(&client->dev,
@@ -166,6 +207,16 @@
/* Save VDD for easy access */
touchkey->vdd = touchkey->regulators[1].consumer;
+ touchkey->num_keycodes = of_property_read_variable_u32_array(np,
+ "linux,keycodes", touchkey->keycodes, 0,
+ ARRAY_SIZE(touchkey->keycodes));
+ if (touchkey->num_keycodes <= 0) {
+ /* default keycodes */
+ touchkey->keycodes[0] = KEY_PHONE;
+ touchkey->keycodes[1] = KEY_BACK;
+ touchkey->num_keycodes = 2;
+ }
+
error = tm2_touchkey_power_enable(touchkey);
if (error) {
dev_err(&client->dev, "failed to power up device: %d\n", error);
@@ -190,8 +241,9 @@
touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME;
touchkey->input_dev->id.bustype = BUS_I2C;
- input_set_capability(touchkey->input_dev, EV_KEY, KEY_PHONE);
- input_set_capability(touchkey->input_dev, EV_KEY, KEY_BACK);
+ for (i = 0; i < touchkey->num_keycodes; i++)
+ input_set_capability(touchkey->input_dev, EV_KEY,
+ touchkey->keycodes[i]);
error = input_register_device(touchkey->input_dev);
if (error) {
@@ -212,9 +264,10 @@
/* led device */
touchkey->led_dev.name = TM2_TOUCHKEY_DEV_NAME;
- touchkey->led_dev.brightness = LED_FULL;
+ touchkey->led_dev.brightness = LED_ON;
touchkey->led_dev.max_brightness = LED_ON;
- touchkey->led_dev.brightness_set = tm2_touchkey_led_brightness_set;
+ touchkey->led_dev.brightness_set_blocking =
+ tm2_touchkey_led_brightness_set;
error = devm_led_classdev_register(&client->dev, &touchkey->led_dev);
if (error) {
@@ -223,6 +276,9 @@
return error;
}
+ if (touchkey->variant->fixed_regulator)
+ tm2_touchkey_led_brightness_set(&touchkey->led_dev, LED_ON);
+
return 0;
}
@@ -262,7 +318,16 @@
MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table);
static const struct of_device_id tm2_touchkey_of_match[] = {
- { .compatible = "cypress,tm2-touchkey", },
+ {
+ .compatible = "cypress,tm2-touchkey",
+ .data = &tm2_touchkey_variant,
+ }, {
+ .compatible = "cypress,midas-touchkey",
+ .data = &midas_touchkey_variant,
+ }, {
+ .compatible = "cypress,aries-touchkey",
+ .data = &aries_touchkey_variant,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, tm2_touchkey_of_match);
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index f9f98ef..af3a682 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* twl4030_keypad.c - driver for 8x8 keypad controller in twl4030 chips
*
@@ -9,20 +10,6 @@
*
* Initial Code:
* Manjunatha G K <manjugk@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c
deleted file mode 100644
index a1ff69c..0000000
--- a/drivers/input/keyboard/w90p910_keypad.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Nuvoton technology corporation.
- *
- * Wan ZongShun <mcuos.com@gmail.com>
- *
- * 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.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <linux/platform_data/keypad-w90p910.h>
-
-/* Keypad Interface Control Registers */
-#define KPI_CONF 0x00
-#define KPI_3KCONF 0x04
-#define KPI_LPCONF 0x08
-#define KPI_STATUS 0x0C
-
-#define IS1KEY (0x01 << 16)
-#define INTTR (0x01 << 21)
-#define KEY0R (0x0f << 3)
-#define KEY0C 0x07
-#define DEBOUNCE_BIT 0x08
-#define KSIZE0 (0x01 << 16)
-#define KSIZE1 (0x01 << 17)
-#define KPSEL (0x01 << 19)
-#define ENKP (0x01 << 18)
-
-#define KGET_RAW(n) (((n) & KEY0R) >> 3)
-#define KGET_COLUMN(n) ((n) & KEY0C)
-
-#define W90P910_NUM_ROWS 8
-#define W90P910_NUM_COLS 8
-#define W90P910_ROW_SHIFT 3
-
-struct w90p910_keypad {
- const struct w90p910_keypad_platform_data *pdata;
- struct clk *clk;
- struct input_dev *input_dev;
- void __iomem *mmio_base;
- int irq;
- unsigned short keymap[W90P910_NUM_ROWS * W90P910_NUM_COLS];
-};
-
-static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad,
- unsigned int status)
-{
- struct input_dev *input_dev = keypad->input_dev;
- unsigned int row = KGET_RAW(status);
- unsigned int col = KGET_COLUMN(status);
- unsigned int code = MATRIX_SCAN_CODE(row, col, W90P910_ROW_SHIFT);
- unsigned int key = keypad->keymap[code];
-
- input_event(input_dev, EV_MSC, MSC_SCAN, code);
- input_report_key(input_dev, key, 1);
- input_sync(input_dev);
-
- input_event(input_dev, EV_MSC, MSC_SCAN, code);
- input_report_key(input_dev, key, 0);
- input_sync(input_dev);
-}
-
-static irqreturn_t w90p910_keypad_irq_handler(int irq, void *dev_id)
-{
- struct w90p910_keypad *keypad = dev_id;
- unsigned int kstatus, val;
-
- kstatus = __raw_readl(keypad->mmio_base + KPI_STATUS);
-
- val = INTTR | IS1KEY;
-
- if (kstatus & val)
- w90p910_keypad_scan_matrix(keypad, kstatus);
-
- return IRQ_HANDLED;
-}
-
-static int w90p910_keypad_open(struct input_dev *dev)
-{
- struct w90p910_keypad *keypad = input_get_drvdata(dev);
- const struct w90p910_keypad_platform_data *pdata = keypad->pdata;
- unsigned int val, config;
-
- /* Enable unit clock */
- clk_enable(keypad->clk);
-
- val = __raw_readl(keypad->mmio_base + KPI_CONF);
- val |= (KPSEL | ENKP);
- val &= ~(KSIZE0 | KSIZE1);
-
- config = pdata->prescale | (pdata->debounce << DEBOUNCE_BIT);
-
- val |= config;
-
- __raw_writel(val, keypad->mmio_base + KPI_CONF);
-
- return 0;
-}
-
-static void w90p910_keypad_close(struct input_dev *dev)
-{
- struct w90p910_keypad *keypad = input_get_drvdata(dev);
-
- /* Disable clock unit */
- clk_disable(keypad->clk);
-}
-
-static int w90p910_keypad_probe(struct platform_device *pdev)
-{
- const struct w90p910_keypad_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
- const struct matrix_keymap_data *keymap_data;
- struct w90p910_keypad *keypad;
- struct input_dev *input_dev;
- struct resource *res;
- int irq;
- int error;
-
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data defined\n");
- return -EINVAL;
- }
-
- keymap_data = pdata->keymap_data;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get keypad irq\n");
- return -ENXIO;
- }
-
- keypad = kzalloc(sizeof(struct w90p910_keypad), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!keypad || !input_dev) {
- dev_err(&pdev->dev, "failed to allocate driver data\n");
- error = -ENOMEM;
- goto failed_free;
- }
-
- keypad->pdata = pdata;
- keypad->input_dev = input_dev;
- keypad->irq = irq;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get I/O memory\n");
- error = -ENXIO;
- goto failed_free;
- }
-
- res = request_mem_region(res->start, resource_size(res), pdev->name);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to request I/O memory\n");
- error = -EBUSY;
- goto failed_free;
- }
-
- keypad->mmio_base = ioremap(res->start, resource_size(res));
- if (keypad->mmio_base == NULL) {
- dev_err(&pdev->dev, "failed to remap I/O memory\n");
- error = -ENXIO;
- goto failed_free_res;
- }
-
- keypad->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(keypad->clk)) {
- dev_err(&pdev->dev, "failed to get keypad clock\n");
- error = PTR_ERR(keypad->clk);
- goto failed_free_io;
- }
-
- /* set multi-function pin for w90p910 kpi. */
- mfp_set_groupi(&pdev->dev);
-
- input_dev->name = pdev->name;
- input_dev->id.bustype = BUS_HOST;
- input_dev->open = w90p910_keypad_open;
- input_dev->close = w90p910_keypad_close;
- input_dev->dev.parent = &pdev->dev;
-
- error = matrix_keypad_build_keymap(keymap_data, NULL,
- W90P910_NUM_ROWS, W90P910_NUM_COLS,
- keypad->keymap, input_dev);
- if (error) {
- dev_err(&pdev->dev, "failed to build keymap\n");
- goto failed_put_clk;
- }
-
- error = request_irq(keypad->irq, w90p910_keypad_irq_handler,
- 0, pdev->name, keypad);
- if (error) {
- dev_err(&pdev->dev, "failed to request IRQ\n");
- goto failed_put_clk;
- }
-
- __set_bit(EV_REP, input_dev->evbit);
- input_set_capability(input_dev, EV_MSC, MSC_SCAN);
- input_set_drvdata(input_dev, keypad);
-
- /* Register the input device */
- error = input_register_device(input_dev);
- if (error) {
- dev_err(&pdev->dev, "failed to register input device\n");
- goto failed_free_irq;
- }
-
- platform_set_drvdata(pdev, keypad);
- return 0;
-
-failed_free_irq:
- free_irq(irq, keypad);
-failed_put_clk:
- clk_put(keypad->clk);
-failed_free_io:
- iounmap(keypad->mmio_base);
-failed_free_res:
- release_mem_region(res->start, resource_size(res));
-failed_free:
- input_free_device(input_dev);
- kfree(keypad);
- return error;
-}
-
-static int w90p910_keypad_remove(struct platform_device *pdev)
-{
- struct w90p910_keypad *keypad = platform_get_drvdata(pdev);
- struct resource *res;
-
- free_irq(keypad->irq, keypad);
-
- clk_put(keypad->clk);
-
- input_unregister_device(keypad->input_dev);
-
- iounmap(keypad->mmio_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- kfree(keypad);
-
- return 0;
-}
-
-static struct platform_driver w90p910_keypad_driver = {
- .probe = w90p910_keypad_probe,
- .remove = w90p910_keypad_remove,
- .driver = {
- .name = "nuc900-kpi",
- },
-};
-module_platform_driver(w90p910_keypad_driver);
-
-MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
-MODULE_DESCRIPTION("w90p910 keypad driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:nuc900-keypad");
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index f759811..280796d 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/slab.h>
diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c
index 8b3a575..4fa5342 100644
--- a/drivers/input/matrix-keymap.c
+++ b/drivers/input/matrix-keymap.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Helpers for matrix keyboard bindings
*
@@ -5,15 +6,6 @@
*
* Author:
* Olof Johansson <olof@lixom.net>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
*/
#include <linux/device.h>
@@ -89,7 +81,7 @@
if (!propname)
propname = "linux,keymap";
- size = device_property_read_u32_array(dev, propname, NULL, 0);
+ size = device_property_count_u32(dev, propname);
if (size <= 0) {
dev_err(dev, "missing or malformed property %s: %d\n",
propname, size);
diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c
index 45a0949..51c8a32 100644
--- a/drivers/input/misc/88pm80x_onkey.c
+++ b/drivers/input/misc/88pm80x_onkey.c
@@ -77,7 +77,6 @@
info->irq = platform_get_irq(pdev, 0);
if (info->irq < 0) {
- dev_err(&pdev->dev, "No IRQ resource!\n");
err = -EINVAL;
goto out;
}
diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c
index cc87443..685995c 100644
--- a/drivers/input/misc/88pm860x_onkey.c
+++ b/drivers/input/misc/88pm860x_onkey.c
@@ -64,10 +64,8 @@
int irq, ret;
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "No IRQ resource!\n");
+ if (irq < 0)
return -EINVAL;
- }
info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_onkey_info),
GFP_KERNEL);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index ca59a2b..7d9ae39 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Input misc drivers configuration
#
@@ -117,6 +118,16 @@
To compile this driver as a module, choose M here: the
module will be called e3x0_button.
+config INPUT_MSM_VIBRATOR
+ tristate "Qualcomm MSM vibrator driver"
+ select INPUT_FF_MEMLESS
+ help
+ Support for the vibrator that is found on various Qualcomm MSM
+ SOCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called msm_vibrator.
+
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
@@ -180,6 +191,15 @@
tristate "M68k Beeper support"
depends on M68K
+config INPUT_MAX77650_ONKEY
+ tristate "Maxim MAX77650 ONKEY support"
+ depends on MFD_MAX77650
+ help
+ Support the ONKEY of the MAX77650 PMIC as an input device.
+
+ To compile this driver as a module, choose M here: the module
+ will be called max77650-onkey.
+
config INPUT_MAX77693_HAPTIC
tristate "MAXIM MAX77693/MAX77843 haptic controller support"
depends on (MFD_MAX77693 || MFD_MAX77843) && PWM
@@ -280,6 +300,18 @@
To compile this driver as a module, choose M here: the module
will be called gpio_decoder.
+config INPUT_GPIO_VIBRA
+ tristate "GPIO vibrator support"
+ depends on GPIOLIB || COMPILE_TEST
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here to get support for GPIO based vibrator devices.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module will be
+ called gpio-vibra.
+
config INPUT_IXP4XX_BEEPER
tristate "IXP4XX Beeper support"
depends on ARCH_IXP4XX
@@ -781,10 +813,10 @@
config INPUT_SOC_BUTTON_ARRAY
tristate "Windows-compatible SoC Button Array"
- depends on KEYBOARD_GPIO
+ depends on KEYBOARD_GPIO && ACPI
help
- Say Y here if you have a SoC-based tablet that originally
- runs Windows 8.
+ Say Y here if you have a SoC-based tablet that originally runs
+ Windows 8 or a Microsoft Surface Book 2, Pro 5, Laptop 1 or later.
To compile this driver as a module, choose M here: the
module will be called soc_button_array.
@@ -851,4 +883,15 @@
To compile this driver as a module, choose M here. The module will
be called sc27xx_vibra.
+config INPUT_STPMIC1_ONKEY
+ tristate "STPMIC1 PMIC Onkey support"
+ depends on MFD_STPMIC1
+ help
+ Say Y to enable support of onkey embedded into STPMIC1 PMIC. onkey
+ can be used to wakeup from low power modes and force a shut-down on
+ long press.
+
+ To compile this driver as a module, choose M here: the
+ module will be called stpmic1_onkey.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 9d0f9d1..8fd187f 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -36,6 +36,7 @@
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o
+obj-$(CONFIG_INPUT_GPIO_VIBRA) += gpio-vibra.o
obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
@@ -43,11 +44,13 @@
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
+obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
+obj-$(CONFIG_INPUT_MSM_VIBRATOR) += msm-vibrator.o
obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
@@ -71,6 +74,7 @@
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
+obj-$(CONFIG_INPUT_STPMIC1_ONKEY) += stpmic1_onkey.o
obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
@@ -81,3 +85,4 @@
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
+
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c
index a33ed57..ea3b829 100644
--- a/drivers/input/misc/ab8500-ponkey.c
+++ b/drivers/input/misc/ab8500-ponkey.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
- * License Terms: GNU General Public License v2
* Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
*
* AB8500 Power-On Key handler
@@ -55,16 +55,12 @@
int error;
irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
- if (irq_dbf < 0) {
- dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf);
+ if (irq_dbf < 0)
return irq_dbf;
- }
irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
- if (irq_dbr < 0) {
- dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr);
+ if (irq_dbr < 0)
return irq_dbr;
- }
ponkey = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_ponkey),
GFP_KERNEL);
diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c
index 2f04773..efeef13 100644
--- a/drivers/input/misc/ad714x-i2c.c
+++ b/drivers/input/misc/ad714x-i2c.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AD714X CapTouch Programmable Controller driver (I2C bus)
*
* Copyright 2009-2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_I2C */
diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c
index aac9103..7d3bf43 100644
--- a/drivers/input/misc/ad714x-spi.c
+++ b/drivers/input/misc/ad714x-spi.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AD714X CapTouch Programmable Controller driver (SPI bus)
*
* Copyright 2009-2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_SPI */
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c
index 84b51dd..43132d9 100644
--- a/drivers/input/misc/ad714x.c
+++ b/drivers/input/misc/ad714x.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A
*
* Copyright 2009-2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
diff --git a/drivers/input/misc/ad714x.h b/drivers/input/misc/ad714x.h
index 5d65d30..af847b5 100644
--- a/drivers/input/misc/ad714x.h
+++ b/drivers/input/misc/ad714x.h
@@ -1,9 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* AD714X CapTouch Programmable Controller driver (bus interfaces)
*
* Copyright 2009-2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#ifndef _AD714X_H_
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
index 7fed92f..e64368a 100644
--- a/drivers/input/misc/adxl34x-i2c.c
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -1,10 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
- * Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_I2C */
diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c
index 3ec03ad..df6afa4 100644
--- a/drivers/input/misc/adxl34x-spi.c
+++ b/drivers/input/misc/adxl34x-spi.c
@@ -1,10 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface)
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
- * Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_SPI */
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
index a3e79bf..5fe92d4 100644
--- a/drivers/input/misc/adxl34x.c
+++ b/drivers/input/misc/adxl34x.c
@@ -1,10 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ADXL345/346 Three-Axis Digital Accelerometers
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
- * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
diff --git a/drivers/input/misc/adxl34x.h b/drivers/input/misc/adxl34x.h
index bbbc80f..83a0eec 100644
--- a/drivers/input/misc/adxl34x.h
+++ b/drivers/input/misc/adxl34x.h
@@ -1,10 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* ADXL345/346 Three-Axis Digital Accelerometers (I2C/SPI Interface)
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
- * Licensed under the GPL-2 or later.
*/
#ifndef _ADXL34X_H_
diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c
index 094bddf..53ec40d 100644
--- a/drivers/input/misc/apanel.c
+++ b/drivers/input/misc/apanel.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Fujitsu Lifebook Application Panel button drive
*
* Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org>
* Copyright (C) 2001-2003 Jochen Eisinger <jochen@penguin-breeder.org>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
* Many Fujitsu Lifebook laptops have a small panel of buttons that are
* accessible via the i2c/smbus interface. This driver polls those
* buttons and generates input events.
@@ -22,7 +19,6 @@
#include <linux/io.h>
#include <linux/input-polldev.h>
#include <linux/i2c.h>
-#include <linux/workqueue.h>
#include <linux/leds.h>
#define APANEL_NAME "Fujitsu Application Panel"
@@ -59,8 +55,6 @@
struct i2c_client *client;
unsigned short keymap[MAX_PANEL_KEYS];
u16 nkeys;
- u16 led_bits;
- struct work_struct led_work;
struct led_classdev mail_led;
};
@@ -109,25 +103,13 @@
report_key(idev, ap->keymap[i]);
}
-/* Track state changes of LED */
-static void led_update(struct work_struct *work)
-{
- struct apanel *ap = container_of(work, struct apanel, led_work);
-
- i2c_smbus_write_word_data(ap->client, 0x10, ap->led_bits);
-}
-
-static void mail_led_set(struct led_classdev *led,
+static int mail_led_set(struct led_classdev *led,
enum led_brightness value)
{
struct apanel *ap = container_of(led, struct apanel, mail_led);
+ u16 led_bits = value != LED_OFF ? 0x8000 : 0x0000;
- if (value != LED_OFF)
- ap->led_bits |= 0x8000;
- else
- ap->led_bits &= ~0x8000;
-
- schedule_work(&ap->led_work);
+ return i2c_smbus_write_word_data(ap->client, 0x10, led_bits);
}
static int apanel_remove(struct i2c_client *client)
@@ -179,7 +161,7 @@
},
.mail_led = {
.name = "mail:blue",
- .brightness_set = mail_led_set,
+ .brightness_set_blocking = mail_led_set,
},
};
@@ -235,7 +217,6 @@
if (err)
goto out3;
- INIT_WORK(&ap->led_work, led_update);
if (device_chip[APANEL_DEV_LED] != CHIP_NONE) {
err = led_classdev_register(&client->dev, &ap->mail_led);
if (err)
diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c
index 21dc1b8..5fa1c94 100644
--- a/drivers/input/misc/arizona-haptics.c
+++ b/drivers/input/misc/arizona-haptics.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Arizona haptics driver
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index d8fd58f..305f016 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ati_remote2 - ATI/Philips USB RF remote driver
*
* Copyright (C) 2005-2008 Ville Syrjala <syrjala@sci.fi>
* Copyright (C) 2007-2008 Peter Stokes <linux@dadeos.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
*/
#include <linux/usb/input.h>
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 6423aac..0e77c40 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* atlas_btns.c - Atlas Wallmount Touchscreen ACPI Extras
*
* Copyright (C) 2006 Jaya Kumar
* Based on Toshiba ACPI by John Belmonte and ASUS ACPI
* This work was sponsored by CIS(M) Sdn Bhd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/misc/atmel_captouch.c b/drivers/input/misc/atmel_captouch.c
index c4c0f4b..051aded 100644
--- a/drivers/input/misc/atmel_captouch.c
+++ b/drivers/input/misc/atmel_captouch.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atmel Atmegaxx Capacitive Touch Button Driver
*
* Copyright (C) 2016 Google, inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
*/
/*
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index debeeae..17c1cca 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -195,15 +195,12 @@
DEVICE_ATTR(shutdown, 0644, axp20x_show_attr_shutdown,
axp20x_store_attr_shutdown);
-static struct attribute *axp20x_attributes[] = {
+static struct attribute *axp20x_attrs[] = {
&dev_attr_startup.attr,
&dev_attr_shutdown.attr,
NULL,
};
-
-static const struct attribute_group axp20x_attribute_group = {
- .attrs = axp20x_attributes,
-};
+ATTRIBUTE_GROUPS(axp20x);
static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
{
@@ -232,20 +229,14 @@
int error;
axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
- if (axp20x_pek->irq_dbr < 0) {
- dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n",
- axp20x_pek->irq_dbr);
+ if (axp20x_pek->irq_dbr < 0)
return axp20x_pek->irq_dbr;
- }
axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc,
axp20x_pek->irq_dbr);
axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF");
- if (axp20x_pek->irq_dbf < 0) {
- dev_err(&pdev->dev, "No IRQ for PEK_DBF, error=%d\n",
- axp20x_pek->irq_dbf);
+ if (axp20x_pek->irq_dbf < 0)
return axp20x_pek->irq_dbf;
- }
axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc,
axp20x_pek->irq_dbf);
@@ -356,13 +347,6 @@
axp20x_pek->info = (struct axp20x_info *)match->driver_data;
- error = devm_device_add_group(&pdev->dev, &axp20x_attribute_group);
- if (error) {
- dev_err(&pdev->dev, "Failed to create sysfs attributes: %d\n",
- error);
- return error;
- }
-
platform_set_drvdata(pdev, axp20x_pek);
return 0;
@@ -411,6 +395,7 @@
.driver = {
.name = "axp20x-pek",
.pm = &axp20x_pek_pm_ops,
+ .dev_groups = axp20x_groups,
},
};
module_platform_driver(axp20x_pek_driver);
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
index 1efcfdf..735d3a4 100644
--- a/drivers/input/misc/bma150.c
+++ b/drivers/input/misc/bma150.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2011 Bosch Sensortec GmbH
* Copyright (c) 2011 Unixphere
@@ -8,20 +9,6 @@
*
* The datasheet for the BMA150 chip can be found here:
* http://www.bosch-sensortec.com/content/language1/downloads/BST-BMA150-DS000-07.pdf
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -481,13 +468,14 @@
idev->close = bma150_irq_close;
input_set_drvdata(idev, bma150);
+ bma150->input = idev;
+
error = input_register_device(idev);
if (error) {
input_free_device(idev);
return error;
}
- bma150->input = idev;
return 0;
}
@@ -510,15 +498,15 @@
bma150_init_input_device(bma150, ipoll_dev->input);
+ bma150->input_polled = ipoll_dev;
+ bma150->input = ipoll_dev->input;
+
error = input_register_polled_device(ipoll_dev);
if (error) {
input_free_polled_device(ipoll_dev);
return error;
}
- bma150->input_polled = ipoll_dev;
- bma150->input = ipoll_dev->input;
-
return 0;
}
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index 23c191a..c09b962 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the VoIP USB phones with CM109 chipsets.
*
* Copyright (C) 2007 - 2008 Alfred E. Heggestad <aeh@db.org>
- *
- * 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.
*/
/*
diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c
index c7d0074..e6feb73 100644
--- a/drivers/input/misc/cma3000_d0x.c
+++ b/drivers/input/misc/cma3000_d0x.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* VTI CMA3000_D0x Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/types.h>
diff --git a/drivers/input/misc/cma3000_d0x.h b/drivers/input/misc/cma3000_d0x.h
index 2304ce3..05ad42a 100644
--- a/drivers/input/misc/cma3000_d0x.h
+++ b/drivers/input/misc/cma3000_d0x.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* VTI CMA3000_D0x Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INPUT_CMA3000_H
diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c
index c702191..03fb491 100644
--- a/drivers/input/misc/cma3000_d0x_i2c.c
+++ b/drivers/input/misc/cma3000_d0x_i2c.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Implements I2C interface for VTI CMA300_D0x Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c
index fbe72af..bcf6174 100644
--- a/drivers/input/misc/cobalt_btns.c
+++ b/drivers/input/misc/cobalt_btns.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Cobalt button interface driver.
*
* Copyright (C) 2007-2008 Yoichi Yuasa <yuasa@linux-mips.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
*/
#include <linux/input-polldev.h>
#include <linux/ioport.h>
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c
index 266e07f..6d11528 100644
--- a/drivers/input/misc/da9052_onkey.c
+++ b/drivers/input/misc/da9052_onkey.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ON pin driver for Dialog DA9052 PMICs
*
* Copyright(c) 2012 Dialog Semiconductor Ltd.
*
* Author: David Dajun Chen <dchen@diasemi.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/input.h>
diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c
index 3251a96..7a0d3a1 100644
--- a/drivers/input/misc/da9055_onkey.c
+++ b/drivers/input/misc/da9055_onkey.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ON pin driver for Dialog DA9055 PMICs
*
* Copyright(c) 2012 Dialog Semiconductor Ltd.
*
* Author: David Dajun Chen <dchen@diasemi.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/input.h>
@@ -80,11 +76,8 @@
int irq, err;
irq = platform_get_irq_byname(pdev, "ONKEY");
- if (irq < 0) {
- dev_err(&pdev->dev,
- "Failed to get an IRQ for input device, %d\n", irq);
+ if (irq < 0)
return -EINVAL;
- }
onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
if (!onkey) {
diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c
index 3e9c353..7985192 100644
--- a/drivers/input/misc/da9063_onkey.c
+++ b/drivers/input/misc/da9063_onkey.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OnKey device driver for DA9063, DA9062 and DA9061 PMICs
* Copyright (C) 2015 Dialog Semiconductor Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
*/
#include <linux/module.h>
@@ -22,7 +13,6 @@
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/mfd/da9063/core.h>
-#include <linux/mfd/da9063/pdata.h>
#include <linux/mfd/da9063/registers.h>
#include <linux/mfd/da9062/core.h>
#include <linux/mfd/da9062/registers.h>
@@ -201,8 +191,6 @@
static int da9063_onkey_probe(struct platform_device *pdev)
{
- struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
- struct da9063_pdata *pdata = dev_get_platdata(da9063->dev);
struct da9063_onkey *onkey;
const struct of_device_id *match;
int irq;
@@ -229,12 +217,8 @@
return -ENXIO;
}
- if (pdata)
- onkey->key_power = pdata->key_power;
- else
- onkey->key_power =
- !of_property_read_bool(pdev->dev.of_node,
- "dlg,disable-key-power");
+ onkey->key_power = !of_property_read_bool(pdev->dev.of_node,
+ "dlg,disable-key-power");
onkey->input = devm_input_allocate_device(&pdev->dev);
if (!onkey->input) {
@@ -248,10 +232,7 @@
onkey->input->phys = onkey->phys;
onkey->input->dev.parent = &pdev->dev;
- if (onkey->key_power)
- input_set_capability(onkey->input, EV_KEY, KEY_POWER);
-
- input_set_capability(onkey->input, EV_KEY, KEY_SLEEP);
+ input_set_capability(onkey->input, EV_KEY, KEY_POWER);
INIT_DELAYED_WORK(&onkey->work, da9063_poll_on);
@@ -264,11 +245,8 @@
}
irq = platform_get_irq_byname(pdev, "ONKEY");
- if (irq < 0) {
- error = irq;
- dev_err(&pdev->dev, "Failed to get platform IRQ: %d\n", error);
- return error;
- }
+ if (irq < 0)
+ return irq;
error = devm_request_threaded_irq(&pdev->dev, irq,
NULL, da9063_onkey_irq_handler,
diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c
index c803db6..397ca7c 100644
--- a/drivers/input/misc/dm355evm_keys.c
+++ b/drivers/input/misc/dm355evm_keys.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* dm355evm_keys.c - support buttons and IR remote on DM355 EVM board
*
* Copyright (c) 2008 by David Brownell
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index 17eb84a..79d7fa7 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DRV260X haptics driver family
*
* Author: Dan Murphy <dmurphy@ti.com>
*
* Copyright: (C) 2014 Texas Instruments, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
index dcb6d8e..918ad9c 100644
--- a/drivers/input/misc/drv2665.c
+++ b/drivers/input/misc/drv2665.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DRV2665 haptics driver family
*
* Author: Dan Murphy <dmurphy@ti.com>
*
* Copyright: (C) 2015 Texas Instruments, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
*/
#include <linux/i2c.h>
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
index 2849bb6..bb9d578 100644
--- a/drivers/input/misc/drv2667.c
+++ b/drivers/input/misc/drv2667.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* DRV2667 haptics driver family
*
* Author: Dan Murphy <dmurphy@ti.com>
*
* Copyright: (C) 2014 Texas Instruments, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
*/
#include <linux/i2c.h>
@@ -177,9 +169,9 @@
error = regmap_write(haptics->regmap, DRV2667_PAGE, read_buf);
if (error) {
dev_err(&haptics->client->dev,
- "Failed to set the page: %d\n", error);
- return -EIO;
- }
+ "Failed to set the page: %d\n", error);
+ return -EIO;
+ }
}
return error;
diff --git a/drivers/input/misc/e3x0-button.c b/drivers/input/misc/e3x0-button.c
index e956cf1..e2fde6e 100644
--- a/drivers/input/misc/e3x0-button.c
+++ b/drivers/input/misc/e3x0-button.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014, National Instruments Corp. All rights reserved.
*
* Driver for NI Ettus Research USRP E3x0 Button Driver
- *
- * 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.
*/
#include <linux/device.h>
@@ -73,18 +65,12 @@
int error;
irq_press = platform_get_irq_byname(pdev, "press");
- if (irq_press < 0) {
- dev_err(&pdev->dev, "No IRQ for 'press', error=%d\n",
- irq_press);
+ if (irq_press < 0)
return irq_press;
- }
irq_release = platform_get_irq_byname(pdev, "release");
- if (irq_release < 0) {
- dev_err(&pdev->dev, "No IRQ for 'release', error=%d\n",
- irq_release);
+ if (irq_release < 0)
return irq_release;
- }
input = devm_input_allocate_device(&pdev->dev);
if (!input)
diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c
index c6a29e5..90abda8 100644
--- a/drivers/input/misc/gp2ap002a00f.c
+++ b/drivers/input/misc/gp2ap002a00f.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Sony Ericsson Mobile Communications Inc.
*
* Author: Courtney Cavin <courtney.cavin@sonyericsson.com>
* Prepared for up-stream by: Oskar Andero <oskar.andero@sonyericsson.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
*/
#include <linux/i2c.h>
diff --git a/drivers/input/misc/gpio-beeper.c b/drivers/input/misc/gpio-beeper.c
index 16272ff..d2d2954 100644
--- a/drivers/input/misc/gpio-beeper.c
+++ b/drivers/input/misc/gpio-beeper.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Generic GPIO beeper driver
*
* Copyright (C) 2013-2014 Alexander Shiyan <shc_work@mail.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/input.h>
diff --git a/drivers/input/misc/gpio-vibra.c b/drivers/input/misc/gpio-vibra.c
new file mode 100644
index 0000000..f79f755
--- /dev/null
+++ b/drivers/input/misc/gpio-vibra.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * GPIO vibrator driver
+ *
+ * Copyright (C) 2019 Luca Weiss <luca@z3ntu.xyz>
+ *
+ * Based on PWM vibrator driver:
+ * Copyright (C) 2017 Collabora Ltd.
+ *
+ * Based on previous work from:
+ * Copyright (C) 2012 Dmitry Torokhov <dmitry.torokhov@gmail.com>
+ *
+ * Based on PWM beeper driver:
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+struct gpio_vibrator {
+ struct input_dev *input;
+ struct gpio_desc *gpio;
+ struct regulator *vcc;
+
+ struct work_struct play_work;
+ bool running;
+ bool vcc_on;
+};
+
+static int gpio_vibrator_start(struct gpio_vibrator *vibrator)
+{
+ struct device *pdev = vibrator->input->dev.parent;
+ int err;
+
+ if (!vibrator->vcc_on) {
+ err = regulator_enable(vibrator->vcc);
+ if (err) {
+ dev_err(pdev, "failed to enable regulator: %d\n", err);
+ return err;
+ }
+ vibrator->vcc_on = true;
+ }
+
+ gpiod_set_value_cansleep(vibrator->gpio, 1);
+
+ return 0;
+}
+
+static void gpio_vibrator_stop(struct gpio_vibrator *vibrator)
+{
+ gpiod_set_value_cansleep(vibrator->gpio, 0);
+
+ if (vibrator->vcc_on) {
+ regulator_disable(vibrator->vcc);
+ vibrator->vcc_on = false;
+ }
+}
+
+static void gpio_vibrator_play_work(struct work_struct *work)
+{
+ struct gpio_vibrator *vibrator =
+ container_of(work, struct gpio_vibrator, play_work);
+
+ if (vibrator->running)
+ gpio_vibrator_start(vibrator);
+ else
+ gpio_vibrator_stop(vibrator);
+}
+
+static int gpio_vibrator_play_effect(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct gpio_vibrator *vibrator = input_get_drvdata(dev);
+ int level;
+
+ level = effect->u.rumble.strong_magnitude;
+ if (!level)
+ level = effect->u.rumble.weak_magnitude;
+
+ vibrator->running = level;
+ schedule_work(&vibrator->play_work);
+
+ return 0;
+}
+
+static void gpio_vibrator_close(struct input_dev *input)
+{
+ struct gpio_vibrator *vibrator = input_get_drvdata(input);
+
+ cancel_work_sync(&vibrator->play_work);
+ gpio_vibrator_stop(vibrator);
+ vibrator->running = false;
+}
+
+static int gpio_vibrator_probe(struct platform_device *pdev)
+{
+ struct gpio_vibrator *vibrator;
+ int err;
+
+ vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
+ if (!vibrator)
+ return -ENOMEM;
+
+ vibrator->input = devm_input_allocate_device(&pdev->dev);
+ if (!vibrator->input)
+ return -ENOMEM;
+
+ vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
+ err = PTR_ERR_OR_ZERO(vibrator->vcc);
+ if (err) {
+ if (err != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to request regulator: %d\n",
+ err);
+ return err;
+ }
+
+ vibrator->gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW);
+ err = PTR_ERR_OR_ZERO(vibrator->gpio);
+ if (err) {
+ if (err != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to request main gpio: %d\n",
+ err);
+ return err;
+ }
+
+ INIT_WORK(&vibrator->play_work, gpio_vibrator_play_work);
+
+ vibrator->input->name = "gpio-vibrator";
+ vibrator->input->id.bustype = BUS_HOST;
+ vibrator->input->close = gpio_vibrator_close;
+
+ input_set_drvdata(vibrator->input, vibrator);
+ input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
+
+ err = input_ff_create_memless(vibrator->input, NULL,
+ gpio_vibrator_play_effect);
+ if (err) {
+ dev_err(&pdev->dev, "Couldn't create FF dev: %d\n", err);
+ return err;
+ }
+
+ err = input_register_device(vibrator->input);
+ if (err) {
+ dev_err(&pdev->dev, "Couldn't register input dev: %d\n", err);
+ return err;
+ }
+
+ platform_set_drvdata(pdev, vibrator);
+
+ return 0;
+}
+
+static int __maybe_unused gpio_vibrator_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
+
+ cancel_work_sync(&vibrator->play_work);
+ if (vibrator->running)
+ gpio_vibrator_stop(vibrator);
+
+ return 0;
+}
+
+static int __maybe_unused gpio_vibrator_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
+
+ if (vibrator->running)
+ gpio_vibrator_start(vibrator);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(gpio_vibrator_pm_ops,
+ gpio_vibrator_suspend, gpio_vibrator_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id gpio_vibra_dt_match_table[] = {
+ { .compatible = "gpio-vibrator" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, gpio_vibra_dt_match_table);
+#endif
+
+static struct platform_driver gpio_vibrator_driver = {
+ .probe = gpio_vibrator_probe,
+ .driver = {
+ .name = "gpio-vibrator",
+ .pm = &gpio_vibrator_pm_ops,
+ .of_match_table = of_match_ptr(gpio_vibra_dt_match_table),
+ },
+};
+module_platform_driver(gpio_vibrator_driver);
+
+MODULE_AUTHOR("Luca Weiss <luca@z3ntu.xy>");
+MODULE_DESCRIPTION("GPIO vibrator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-vibrator");
diff --git a/drivers/input/misc/hisi_powerkey.c b/drivers/input/misc/hisi_powerkey.c
index dee6245..d3c293a 100644
--- a/drivers/input/misc/hisi_powerkey.c
+++ b/drivers/input/misc/hisi_powerkey.c
@@ -90,12 +90,8 @@
for (i = 0; i < ARRAY_SIZE(hi65xx_irq_info); i++) {
irq = platform_get_irq_byname(pdev, hi65xx_irq_info[i].name);
- if (irq < 0) {
- error = irq;
- dev_err(dev, "couldn't get irq %s: %d\n",
- hi65xx_irq_info[i].name, error);
- return error;
- }
+ if (irq < 0)
+ return irq;
error = devm_request_any_context_irq(dev, irq,
hi65xx_irq_info[i].handler,
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index 47eb8ca..abca895 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -441,12 +441,10 @@
seq_puts(m, "BBRTC\t\t: READ FAILED!\n");
} else {
seq_printf(m,
- "rtc_time\t: %02d:%02d:%02d\n"
- "rtc_date\t: %04d-%02d-%02d\n"
+ "rtc_time\t: %ptRt\n"
+ "rtc_date\t: %ptRd\n"
"rtc_epoch\t: %04lu\n",
- tm.tm_hour, tm.tm_min, tm.tm_sec,
- tm.tm_year + 1900, tm.tm_mon + 1,
- tm.tm_mday, epoch);
+ &tm, &tm, epoch);
}
if (hp_sdc_rtc_read_rt(&tv)) {
diff --git a/drivers/input/misc/ideapad_slidebar.c b/drivers/input/misc/ideapad_slidebar.c
index b0acb87..68f1c58 100644
--- a/drivers/input/misc/ideapad_slidebar.c
+++ b/drivers/input/misc/ideapad_slidebar.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Input driver for slidebars on some Lenovo IdeaPad laptops
*
@@ -5,11 +6,6 @@
*
* Reverse-engineered from Lenovo SlideNav software (SBarHook.dll).
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index 3d51175..d8dbfc0 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for IMS Passenger Control Unit Devices
*
* Copyright (C) 2013 The IMS Company
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
*/
#include <linux/completion.h>
@@ -39,8 +36,6 @@
struct ims_pcu_backlight {
struct led_classdev cdev;
- struct work_struct work;
- enum led_brightness desired_brightness;
char name[32];
};
@@ -949,14 +944,14 @@
#define IMS_PCU_MAX_BRIGHTNESS 31998
-static void ims_pcu_backlight_work(struct work_struct *work)
+static int ims_pcu_backlight_set_brightness(struct led_classdev *cdev,
+ enum led_brightness value)
{
struct ims_pcu_backlight *backlight =
- container_of(work, struct ims_pcu_backlight, work);
+ container_of(cdev, struct ims_pcu_backlight, cdev);
struct ims_pcu *pcu =
container_of(backlight, struct ims_pcu, backlight);
- int desired_brightness = backlight->desired_brightness;
- __le16 br_val = cpu_to_le16(desired_brightness);
+ __le16 br_val = cpu_to_le16(value);
int error;
mutex_lock(&pcu->cmd_mutex);
@@ -966,19 +961,11 @@
if (error && error != -ENODEV)
dev_warn(pcu->dev,
"Failed to set desired brightness %u, error: %d\n",
- desired_brightness, error);
+ value, error);
mutex_unlock(&pcu->cmd_mutex);
-}
-static void ims_pcu_backlight_set_brightness(struct led_classdev *cdev,
- enum led_brightness value)
-{
- struct ims_pcu_backlight *backlight =
- container_of(cdev, struct ims_pcu_backlight, cdev);
-
- backlight->desired_brightness = value;
- schedule_work(&backlight->work);
+ return error;
}
static enum led_brightness
@@ -1015,14 +1002,14 @@
struct ims_pcu_backlight *backlight = &pcu->backlight;
int error;
- INIT_WORK(&backlight->work, ims_pcu_backlight_work);
snprintf(backlight->name, sizeof(backlight->name),
"pcu%d::kbd_backlight", pcu->device_no);
backlight->cdev.name = backlight->name;
backlight->cdev.max_brightness = IMS_PCU_MAX_BRIGHTNESS;
backlight->cdev.brightness_get = ims_pcu_backlight_get_brightness;
- backlight->cdev.brightness_set = ims_pcu_backlight_set_brightness;
+ backlight->cdev.brightness_set_blocking =
+ ims_pcu_backlight_set_brightness;
error = led_classdev_register(pcu->dev, &backlight->cdev);
if (error) {
@@ -1040,7 +1027,6 @@
struct ims_pcu_backlight *backlight = &pcu->backlight;
led_classdev_unregister(&backlight->cdev);
- cancel_work_sync(&backlight->work);
}
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 1fe149f..794ecc9 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic IXP4xx beeper driver
*
@@ -8,11 +9,6 @@
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
* Maintainers: http://www.nslu2-linux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/module.h>
@@ -30,6 +26,8 @@
static DEFINE_SPINLOCK(beep_lock);
+static int ixp4xx_timer2_irq;
+
static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
{
unsigned long flags;
@@ -90,6 +88,7 @@
static int ixp4xx_spkr_probe(struct platform_device *dev)
{
struct input_dev *input_dev;
+ int irq;
int err;
input_dev = input_allocate_device();
@@ -110,15 +109,22 @@
input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
input_dev->event = ixp4xx_spkr_event;
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ err = irq;
+ goto err_free_device;
+ }
+
err = gpio_request(dev->id, "ixp4-beeper");
if (err)
goto err_free_device;
- err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
+ err = request_irq(irq, &ixp4xx_spkr_interrupt,
IRQF_NO_SUSPEND, "ixp4xx-beeper",
(void *) dev->id);
if (err)
goto err_free_gpio;
+ ixp4xx_timer2_irq = irq;
err = input_register_device(input_dev);
if (err)
@@ -129,7 +135,7 @@
return 0;
err_free_irq:
- free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
+ free_irq(irq, (void *)dev->id);
err_free_gpio:
gpio_free(dev->id);
err_free_device:
@@ -146,10 +152,10 @@
input_unregister_device(input_dev);
/* turn the speaker off */
- disable_irq(IRQ_IXP4XX_TIMER2);
+ disable_irq(ixp4xx_timer2_irq);
ixp4xx_spkr_control(pin, 0);
- free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
+ free_irq(ixp4xx_timer2_irq, (void *)dev->id);
gpio_free(dev->id);
return 0;
@@ -161,7 +167,7 @@
unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
/* turn off the speaker */
- disable_irq(IRQ_IXP4XX_TIMER2);
+ disable_irq(ixp4xx_timer2_irq);
ixp4xx_spkr_control(pin, 0);
}
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
index a8937ce..83368f1 100644
--- a/drivers/input/misc/keyspan_remote.c
+++ b/drivers/input/misc/keyspan_remote.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* keyspan_remote: USB driver for the Keyspan DMR
*
* Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com)
*
- * 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.
- *
* This driver has been put together with the support of Innosys, Inc.
* and Keyspan, Inc the manufacturers of the Keyspan USB DMR product.
*/
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index efaffcc..db01c4a 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Kionix, Inc.
* Written by Chris Hudson <chudson@kionix.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307, USA
*/
#include <linux/delay.h>
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
index 312d636..25fcf14 100644
--- a/drivers/input/misc/m68kspkr.c
+++ b/drivers/input/misc/m68kspkr.c
@@ -1,17 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* m68k beeper driver for Linux
*
* Copyright (c) 2002 Richard Zidlicky
* Copyright (c) 2002 Vojtech Pavlik
* Copyright (c) 1992 Orest Zborowski
- *
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation
- */
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/input/misc/max77650-onkey.c b/drivers/input/misc/max77650-onkey.c
new file mode 100644
index 0000000..4d875f2
--- /dev/null
+++ b/drivers/input/misc/max77650-onkey.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 BayLibre SAS
+// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+//
+// ONKEY driver for MAXIM 77650/77651 charger/power-supply.
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max77650.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MAX77650_ONKEY_MODE_MASK BIT(3)
+#define MAX77650_ONKEY_MODE_PUSH 0x00
+#define MAX77650_ONKEY_MODE_SLIDE BIT(3)
+
+struct max77650_onkey {
+ struct input_dev *input;
+ unsigned int code;
+};
+
+static irqreturn_t max77650_onkey_falling(int irq, void *data)
+{
+ struct max77650_onkey *onkey = data;
+
+ input_report_key(onkey->input, onkey->code, 0);
+ input_sync(onkey->input);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t max77650_onkey_rising(int irq, void *data)
+{
+ struct max77650_onkey *onkey = data;
+
+ input_report_key(onkey->input, onkey->code, 1);
+ input_sync(onkey->input);
+
+ return IRQ_HANDLED;
+}
+
+static int max77650_onkey_probe(struct platform_device *pdev)
+{
+ int irq_r, irq_f, error, mode;
+ struct max77650_onkey *onkey;
+ struct device *dev, *parent;
+ struct regmap *map;
+ unsigned int type;
+
+ dev = &pdev->dev;
+ parent = dev->parent;
+
+ map = dev_get_regmap(parent, NULL);
+ if (!map)
+ return -ENODEV;
+
+ onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL);
+ if (!onkey)
+ return -ENOMEM;
+
+ error = device_property_read_u32(dev, "linux,code", &onkey->code);
+ if (error)
+ onkey->code = KEY_POWER;
+
+ if (device_property_read_bool(dev, "maxim,onkey-slide")) {
+ mode = MAX77650_ONKEY_MODE_SLIDE;
+ type = EV_SW;
+ } else {
+ mode = MAX77650_ONKEY_MODE_PUSH;
+ type = EV_KEY;
+ }
+
+ error = regmap_update_bits(map, MAX77650_REG_CNFG_GLBL,
+ MAX77650_ONKEY_MODE_MASK, mode);
+ if (error)
+ return error;
+
+ irq_f = platform_get_irq_byname(pdev, "nEN_F");
+ if (irq_f < 0)
+ return irq_f;
+
+ irq_r = platform_get_irq_byname(pdev, "nEN_R");
+ if (irq_r < 0)
+ return irq_r;
+
+ onkey->input = devm_input_allocate_device(dev);
+ if (!onkey->input)
+ return -ENOMEM;
+
+ onkey->input->name = "max77650_onkey";
+ onkey->input->phys = "max77650_onkey/input0";
+ onkey->input->id.bustype = BUS_I2C;
+ input_set_capability(onkey->input, type, onkey->code);
+
+ error = devm_request_any_context_irq(dev, irq_f, max77650_onkey_falling,
+ IRQF_ONESHOT, "onkey-down", onkey);
+ if (error < 0)
+ return error;
+
+ error = devm_request_any_context_irq(dev, irq_r, max77650_onkey_rising,
+ IRQF_ONESHOT, "onkey-up", onkey);
+ if (error < 0)
+ return error;
+
+ return input_register_device(onkey->input);
+}
+
+static struct platform_driver max77650_onkey_driver = {
+ .driver = {
+ .name = "max77650-onkey",
+ },
+ .probe = max77650_onkey_probe,
+};
+module_platform_driver(max77650_onkey_driver);
+
+MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver");
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:max77650-onkey");
diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
index 46b0f48..0d09ffe 100644
--- a/drivers/input/misc/max77693-haptic.c
+++ b/drivers/input/misc/max77693-haptic.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MAXIM MAX77693/MAX77843 Haptic device driver
*
@@ -6,11 +7,6 @@
* Krzysztof Kozlowski <krzk@kernel.org>
*
* This program is not provided / owned by Maxim Integrated Products.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/err.h>
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
index 7c49b8d..ffab4a4 100644
--- a/drivers/input/misc/max8925_onkey.c
+++ b/drivers/input/misc/max8925_onkey.c
@@ -71,16 +71,12 @@
int irq[2], error;
irq[0] = platform_get_irq(pdev, 0);
- if (irq[0] < 0) {
- dev_err(&pdev->dev, "No IRQ resource!\n");
+ if (irq[0] < 0)
return -EINVAL;
- }
irq[1] = platform_get_irq(pdev, 1);
- if (irq[1] < 0) {
- dev_err(&pdev->dev, "No IRQ resource!\n");
+ if (irq[1] < 0)
return -EINVAL;
- }
info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_onkey_info),
GFP_KERNEL);
diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c
index 99bc762..20ff087 100644
--- a/drivers/input/misc/max8997_haptic.c
+++ b/drivers/input/misc/max8997_haptic.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MAX8997-haptic controller driver
*
@@ -5,21 +6,6 @@
* Donggeun Kim <dg77.kim@samsung.com>
*
* This program is not provided / owned by Maxim Integrated Products.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c
index b60cdea..49f5242 100644
--- a/drivers/input/misc/mma8450.c
+++ b/drivers/input/misc/mma8450.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for Freescale's 3-Axis Accelerometer MMA8450
*
* Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/misc/msm-vibrator.c b/drivers/input/misc/msm-vibrator.c
new file mode 100644
index 0000000..b60f1aa
--- /dev/null
+++ b/drivers/input/misc/msm-vibrator.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm MSM vibrator driver
+ *
+ * Copyright (c) 2018 Brian Masney <masneyb@onstation.org>
+ *
+ * Based on qcom,pwm-vibrator.c from:
+ * Copyright (c) 2018 Jonathan Marek <jonathan@marek.ca>
+ *
+ * Based on msm_pwm_vibrator.c from downstream Android sources:
+ * Copyright (C) 2009-2014 LGE, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#define REG_CMD_RCGR 0x00
+#define REG_CFG_RCGR 0x04
+#define REG_M 0x08
+#define REG_N 0x0C
+#define REG_D 0x10
+#define REG_CBCR 0x24
+#define MMSS_CC_M_DEFAULT 1
+
+struct msm_vibrator {
+ struct input_dev *input;
+ struct mutex mutex;
+ struct work_struct worker;
+ void __iomem *base;
+ struct regulator *vcc;
+ struct clk *clk;
+ struct gpio_desc *enable_gpio;
+ u16 magnitude;
+ bool enabled;
+};
+
+static void msm_vibrator_write(struct msm_vibrator *vibrator, int offset,
+ u32 value)
+{
+ writel(value, vibrator->base + offset);
+}
+
+static int msm_vibrator_start(struct msm_vibrator *vibrator)
+{
+ int d_reg_val, ret = 0;
+
+ mutex_lock(&vibrator->mutex);
+
+ if (!vibrator->enabled) {
+ ret = clk_set_rate(vibrator->clk, 24000);
+ if (ret) {
+ dev_err(&vibrator->input->dev,
+ "Failed to set clock rate: %d\n", ret);
+ goto unlock;
+ }
+
+ ret = clk_prepare_enable(vibrator->clk);
+ if (ret) {
+ dev_err(&vibrator->input->dev,
+ "Failed to enable clock: %d\n", ret);
+ goto unlock;
+ }
+
+ ret = regulator_enable(vibrator->vcc);
+ if (ret) {
+ dev_err(&vibrator->input->dev,
+ "Failed to enable regulator: %d\n", ret);
+ clk_disable(vibrator->clk);
+ goto unlock;
+ }
+
+ gpiod_set_value_cansleep(vibrator->enable_gpio, 1);
+
+ vibrator->enabled = true;
+ }
+
+ d_reg_val = 127 - ((126 * vibrator->magnitude) / 0xffff);
+ msm_vibrator_write(vibrator, REG_CFG_RCGR,
+ (2 << 12) | /* dual edge mode */
+ (0 << 8) | /* cxo */
+ (7 << 0));
+ msm_vibrator_write(vibrator, REG_M, 1);
+ msm_vibrator_write(vibrator, REG_N, 128);
+ msm_vibrator_write(vibrator, REG_D, d_reg_val);
+ msm_vibrator_write(vibrator, REG_CMD_RCGR, 1);
+ msm_vibrator_write(vibrator, REG_CBCR, 1);
+
+unlock:
+ mutex_unlock(&vibrator->mutex);
+
+ return ret;
+}
+
+static void msm_vibrator_stop(struct msm_vibrator *vibrator)
+{
+ mutex_lock(&vibrator->mutex);
+
+ if (vibrator->enabled) {
+ gpiod_set_value_cansleep(vibrator->enable_gpio, 0);
+ regulator_disable(vibrator->vcc);
+ clk_disable(vibrator->clk);
+ vibrator->enabled = false;
+ }
+
+ mutex_unlock(&vibrator->mutex);
+}
+
+static void msm_vibrator_worker(struct work_struct *work)
+{
+ struct msm_vibrator *vibrator = container_of(work,
+ struct msm_vibrator,
+ worker);
+
+ if (vibrator->magnitude)
+ msm_vibrator_start(vibrator);
+ else
+ msm_vibrator_stop(vibrator);
+}
+
+static int msm_vibrator_play_effect(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct msm_vibrator *vibrator = input_get_drvdata(dev);
+
+ mutex_lock(&vibrator->mutex);
+
+ if (effect->u.rumble.strong_magnitude > 0)
+ vibrator->magnitude = effect->u.rumble.strong_magnitude;
+ else
+ vibrator->magnitude = effect->u.rumble.weak_magnitude;
+
+ mutex_unlock(&vibrator->mutex);
+
+ schedule_work(&vibrator->worker);
+
+ return 0;
+}
+
+static void msm_vibrator_close(struct input_dev *input)
+{
+ struct msm_vibrator *vibrator = input_get_drvdata(input);
+
+ cancel_work_sync(&vibrator->worker);
+ msm_vibrator_stop(vibrator);
+}
+
+static int msm_vibrator_probe(struct platform_device *pdev)
+{
+ struct msm_vibrator *vibrator;
+ struct resource *res;
+ int ret;
+
+ vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
+ if (!vibrator)
+ return -ENOMEM;
+
+ vibrator->input = devm_input_allocate_device(&pdev->dev);
+ if (!vibrator->input)
+ return -ENOMEM;
+
+ vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
+ if (IS_ERR(vibrator->vcc)) {
+ if (PTR_ERR(vibrator->vcc) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get regulator: %ld\n",
+ PTR_ERR(vibrator->vcc));
+ return PTR_ERR(vibrator->vcc);
+ }
+
+ vibrator->enable_gpio = devm_gpiod_get(&pdev->dev, "enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(vibrator->enable_gpio)) {
+ if (PTR_ERR(vibrator->enable_gpio) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get enable gpio: %ld\n",
+ PTR_ERR(vibrator->enable_gpio));
+ return PTR_ERR(vibrator->enable_gpio);
+ }
+
+ vibrator->clk = devm_clk_get(&pdev->dev, "pwm");
+ if (IS_ERR(vibrator->clk)) {
+ if (PTR_ERR(vibrator->clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to lookup pwm clock: %ld\n",
+ PTR_ERR(vibrator->clk));
+ return PTR_ERR(vibrator->clk);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get platform resource\n");
+ return -ENODEV;
+ }
+
+ vibrator->base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!vibrator->base) {
+ dev_err(&pdev->dev, "Failed to iomap resource.\n");
+ return -ENOMEM;
+ }
+
+ vibrator->enabled = false;
+ mutex_init(&vibrator->mutex);
+ INIT_WORK(&vibrator->worker, msm_vibrator_worker);
+
+ vibrator->input->name = "msm-vibrator";
+ vibrator->input->id.bustype = BUS_HOST;
+ vibrator->input->close = msm_vibrator_close;
+
+ input_set_drvdata(vibrator->input, vibrator);
+ input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
+
+ ret = input_ff_create_memless(vibrator->input, NULL,
+ msm_vibrator_play_effect);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to create ff memless: %d", ret);
+ return ret;
+ }
+
+ ret = input_register_device(vibrator->input);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register input device: %d", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, vibrator);
+
+ return 0;
+}
+
+static int __maybe_unused msm_vibrator_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_vibrator *vibrator = platform_get_drvdata(pdev);
+
+ cancel_work_sync(&vibrator->worker);
+
+ if (vibrator->enabled)
+ msm_vibrator_stop(vibrator);
+
+ return 0;
+}
+
+static int __maybe_unused msm_vibrator_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_vibrator *vibrator = platform_get_drvdata(pdev);
+
+ if (vibrator->enabled)
+ msm_vibrator_start(vibrator);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(msm_vibrator_pm_ops, msm_vibrator_suspend,
+ msm_vibrator_resume);
+
+static const struct of_device_id msm_vibrator_of_match[] = {
+ { .compatible = "qcom,msm8226-vibrator" },
+ { .compatible = "qcom,msm8974-vibrator" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, msm_vibrator_of_match);
+
+static struct platform_driver msm_vibrator_driver = {
+ .probe = msm_vibrator_probe,
+ .driver = {
+ .name = "msm-vibrator",
+ .pm = &msm_vibrator_pm_ops,
+ .of_match_table = of_match_ptr(msm_vibrator_of_match),
+ },
+};
+module_platform_driver(msm_vibrator_driver);
+
+MODULE_AUTHOR("Brian Masney <masneyb@onstation.org>");
+MODULE_DESCRIPTION("Qualcomm MSM vibrator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c
index 3b81daf..b5a5363 100644
--- a/drivers/input/misc/pcap_keys.c
+++ b/drivers/input/misc/pcap_keys.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input driver for PCAP events:
* * Power key
* * Headphone button
*
* Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c
index db92f4f..4c60c70 100644
--- a/drivers/input/misc/pcf50633-input.c
+++ b/drivers/input/misc/pcf50633-input.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* NXP PCF50633 Input Driver
*
* (C) 2006-2008 by Openmoko, Inc.
@@ -6,12 +7,6 @@
*
* Broken down from monstrous PCF50633 driver mainly by
* Harald Welte, Andy Green and Werner Almesberger
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c
index 4abdf1e..abc4231 100644
--- a/drivers/input/misc/pcf8574_keypad.c
+++ b/drivers/input/misc/pcf8574_keypad.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for a keypad w/16 buttons connected to a PCF8574 I2C I/O expander
*
* Copyright 2005-2008 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 56ddba2..e5e0d8b 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -1,16 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PC Speaker beeper driver for Linux
*
* Copyright (c) 2002 Vojtech Pavlik
* Copyright (c) 1992 Orest Zborowski
- *
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation
- */
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c
index 48153e0..cf81044 100644
--- a/drivers/input/misc/pm8941-pwrkey.c
+++ b/drivers/input/misc/pm8941-pwrkey.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2014, Sony Mobile Communications Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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.
*/
#include <linux/delay.h>
@@ -213,10 +205,8 @@
return error;
pwrkey->irq = platform_get_irq(pdev, 0);
- if (pwrkey->irq < 0) {
- dev_err(&pdev->dev, "failed to get irq\n");
+ if (pwrkey->irq < 0)
return pwrkey->irq;
- }
error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_REV2,
&pwrkey->revision);
diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c
index 7dd1c1f..ecd762f 100644
--- a/drivers/input/misc/pm8xxx-vibrator.c
+++ b/drivers/input/misc/pm8xxx-vibrator.c
@@ -1,13 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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.
*/
#include <linux/errno.h>
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 73323b0..0e818a3 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -1,13 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index e8de3aa..c4e0e18 100644
--- a/drivers/input/misc/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
*
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index edca0d7..d6b1247 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
* PWM beeper driver
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * 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.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#include <linux/input.h>
diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c
index 55da191..8ceaf7d 100644
--- a/drivers/input/misc/pwm-vibra.c
+++ b/drivers/input/misc/pwm-vibra.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* PWM vibrator driver
*
@@ -8,11 +9,6 @@
*
* Based on PWM beeper driver:
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/input.h>
@@ -34,6 +30,7 @@
struct work_struct play_work;
u16 level;
u32 direction_duty_cycle;
+ bool vcc_on;
};
static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
@@ -42,10 +39,13 @@
struct pwm_state state;
int err;
- err = regulator_enable(vibrator->vcc);
- if (err) {
- dev_err(pdev, "failed to enable regulator: %d", err);
- return err;
+ if (!vibrator->vcc_on) {
+ err = regulator_enable(vibrator->vcc);
+ if (err) {
+ dev_err(pdev, "failed to enable regulator: %d", err);
+ return err;
+ }
+ vibrator->vcc_on = true;
}
pwm_get_state(vibrator->pwm, &state);
@@ -76,11 +76,14 @@
static void pwm_vibrator_stop(struct pwm_vibrator *vibrator)
{
- regulator_disable(vibrator->vcc);
-
if (vibrator->pwm_dir)
pwm_disable(vibrator->pwm_dir);
pwm_disable(vibrator->pwm);
+
+ if (vibrator->vcc_on) {
+ regulator_disable(vibrator->vcc);
+ vibrator->vcc_on = false;
+ }
}
static void pwm_vibrator_play_work(struct work_struct *work)
diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c
index 62c5814..4412055 100644
--- a/drivers/input/misc/rb532_button.c
+++ b/drivers/input/misc/rb532_button.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Support for the S1 button on Routerboard 532
*
diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c
index a1db1e5..a661e77 100644
--- a/drivers/input/misc/regulator-haptic.c
+++ b/drivers/input/misc/regulator-haptic.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Regulator haptic driver
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* Author: Jaewon Kim <jaewon02.kim@samsung.com>
* Author: Hyunhee Kim <hyunhee.kim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/input.h>
diff --git a/drivers/input/misc/rk805-pwrkey.c b/drivers/input/misc/rk805-pwrkey.c
index 9210039..3fb64db 100644
--- a/drivers/input/misc/rk805-pwrkey.c
+++ b/drivers/input/misc/rk805-pwrkey.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Rockchip RK805 PMIC Power Key driver
*
* Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
*
* Author: Joseph Chen <chenjh@rock-chips.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/errno.h>
@@ -57,16 +53,12 @@
input_set_capability(pwr, EV_KEY, KEY_POWER);
fall_irq = platform_get_irq(pdev, 0);
- if (fall_irq < 0) {
- dev_err(&pdev->dev, "Can't get fall irq: %d\n", fall_irq);
+ if (fall_irq < 0)
return fall_irq;
- }
rise_irq = platform_get_irq(pdev, 1);
- if (rise_irq < 0) {
- dev_err(&pdev->dev, "Can't get rise irq: %d\n", rise_irq);
+ if (rise_irq < 0)
return rise_irq;
- }
err = devm_request_any_context_irq(&pwr->dev, fall_irq,
pwrkey_fall_irq,
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 30ec77a..6d613f2 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rotary_encoder.c
*
@@ -8,10 +9,6 @@
*
* A generic driver for rotary encoders connected to GPIO lines.
* See file:Documentation/input/devices/rotary-encoder.rst for more information
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/kernel.h>
@@ -240,8 +237,10 @@
encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN);
if (IS_ERR(encoder->gpios)) {
- dev_err(dev, "unable to get gpios\n");
- return PTR_ERR(encoder->gpios);
+ err = PTR_ERR(encoder->gpios);
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "unable to get gpios: %d\n", err);
+ return err;
}
if (encoder->gpios->ndescs < 2) {
dev_err(dev, "not enough gpios found\n");
diff --git a/drivers/input/misc/sgi_btns.c b/drivers/input/misc/sgi_btns.c
index 7bbe79d..0fee6dd 100644
--- a/drivers/input/misc/sgi_btns.c
+++ b/drivers/input/misc/sgi_btns.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* SGI Volume Button interface driver
*
* Copyright (C) 2008 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
*/
#include <linux/input-polldev.h>
#include <linux/ioport.h>
diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
index 4fd038d..60e1f31 100644
--- a/drivers/input/misc/sirfsoc-onkey.c
+++ b/drivers/input/misc/sirfsoc-onkey.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Power key driver for SiRF PrimaII
*
* Copyright (c) 2013 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
* company.
- *
- * Licensed under GPLv2 or later.
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index 23520df..08520b3 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Supports for the button array on SoC tablets originally running
* Windows 8.
*
* (C) Copyright 2014 Intel Corporation
- *
- * 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.
*/
#include <linux/module.h>
@@ -29,6 +25,11 @@
bool wakeup;
};
+struct soc_device_data {
+ const struct soc_button_info *button_info;
+ int (*check)(struct device *dev);
+};
+
/*
* Some of the buttons like volume up/down are auto repeat, while others
* are not. To support both, we register two platform devices, and put
@@ -91,8 +92,20 @@
continue;
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
- if (!gpio_is_valid(gpio))
+ if (!gpio_is_valid(gpio)) {
+ /*
+ * Skip GPIO if not present. Note we deliberately
+ * ignore -EPROBE_DEFER errors here. On some devices
+ * Intel is using so called virtual GPIOs which are not
+ * GPIOs at all but some way for AML code to check some
+ * random status bits without need a custom opregion.
+ * In some cases the resources table we parse points to
+ * such a virtual GPIO, since these are not real GPIOs
+ * we do not have a driver for these so they will never
+ * show up, therefore we ignore -EPROBE_DEFER.
+ */
continue;
+ }
gpio_keys[n_buttons].type = info->event_type;
gpio_keys[n_buttons].code = info->event_code;
@@ -114,25 +127,19 @@
gpio_keys_pdata->nbuttons = n_buttons;
gpio_keys_pdata->rep = autorepeat;
- pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
- if (!pd) {
- error = -ENOMEM;
+ pd = platform_device_register_resndata(&pdev->dev, "gpio-keys",
+ PLATFORM_DEVID_AUTO, NULL, 0,
+ gpio_keys_pdata,
+ sizeof(*gpio_keys_pdata));
+ error = PTR_ERR_OR_ZERO(pd);
+ if (error) {
+ dev_err(&pdev->dev,
+ "failed registering gpio-keys: %d\n", error);
goto err_free_mem;
}
- error = platform_device_add_data(pd, gpio_keys_pdata,
- sizeof(*gpio_keys_pdata));
- if (error)
- goto err_free_pdev;
-
- error = platform_device_add(pd);
- if (error)
- goto err_free_pdev;
-
return pd;
-err_free_pdev:
- platform_device_put(pd);
err_free_mem:
devm_kfree(&pdev->dev, gpio_keys_pdata);
return ERR_PTR(error);
@@ -185,6 +192,10 @@
info->name = "power";
info->event_code = KEY_POWER;
info->wakeup = true;
+ } else if (upage == 0x01 && usage == 0xca) {
+ info->name = "rotation lock switch";
+ info->event_type = EV_SW;
+ info->event_code = SW_ROTATE_LOCK;
} else if (upage == 0x07 && usage == 0xe3) {
info->name = "home";
info->event_code = KEY_LEFTMETA;
@@ -309,23 +320,26 @@
static int soc_button_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- const struct acpi_device_id *id;
- struct soc_button_info *button_info;
+ const struct soc_device_data *device_data;
+ const struct soc_button_info *button_info;
struct soc_button_data *priv;
struct platform_device *pd;
int i;
int error;
- id = acpi_match_device(dev->driver->acpi_match_table, dev);
- if (!id)
- return -ENODEV;
+ device_data = acpi_device_get_match_data(dev);
+ if (device_data && device_data->check) {
+ error = device_data->check(dev);
+ if (error)
+ return error;
+ }
- if (!id->driver_data) {
+ if (device_data && device_data->button_info) {
+ button_info = device_data->button_info;
+ } else {
button_info = soc_button_get_button_info(dev);
if (IS_ERR(button_info))
return PTR_ERR(button_info);
- } else {
- button_info = (struct soc_button_info *)id->driver_data;
}
error = gpiod_count(dev, NULL);
@@ -357,7 +371,7 @@
if (!priv->children[0] && !priv->children[1])
return -ENODEV;
- if (!id->driver_data)
+ if (!device_data || !device_data->button_info)
devm_kfree(dev, button_info);
return 0;
@@ -368,18 +382,86 @@
* is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
* Platforms"
*/
-static struct soc_button_info soc_button_PNP0C40[] = {
+static const struct soc_button_info soc_button_PNP0C40[] = {
{ "power", 0, EV_KEY, KEY_POWER, false, true },
{ "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
- { "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false },
+ { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false },
{ }
};
+static const struct soc_device_data soc_device_PNP0C40 = {
+ .button_info = soc_button_PNP0C40,
+};
+
+/*
+ * Special device check for Surface Book 2 and Surface Pro (2017).
+ * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
+ * devices use MSHW0040 for power and volume buttons, however the way they
+ * have to be addressed differs. Make sure that we only load this drivers
+ * for the correct devices by checking the OEM Platform Revision provided by
+ * the _DSM method.
+ */
+#define MSHW0040_DSM_REVISION 0x01
+#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
+static const guid_t MSHW0040_DSM_UUID =
+ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
+ 0x49, 0x80, 0x35);
+
+static int soc_device_check_MSHW0040(struct device *dev)
+{
+ acpi_handle handle = ACPI_HANDLE(dev);
+ union acpi_object *result;
+ u64 oem_platform_rev = 0; // valid revisions are nonzero
+
+ // get OEM platform revision
+ result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
+ MSHW0040_DSM_REVISION,
+ MSHW0040_DSM_GET_OMPR, NULL,
+ ACPI_TYPE_INTEGER);
+
+ if (result) {
+ oem_platform_rev = result->integer.value;
+ ACPI_FREE(result);
+ }
+
+ /*
+ * If the revision is zero here, the _DSM evaluation has failed. This
+ * indicates that we have a Pro 4 or Book 1 and this driver should not
+ * be used.
+ */
+ if (oem_platform_rev == 0)
+ return -ENODEV;
+
+ dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
+
+ return 0;
+}
+
+/*
+ * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
+ * Obtained from DSDT/testing.
+ */
+static const struct soc_button_info soc_button_MSHW0040[] = {
+ { "power", 0, EV_KEY, KEY_POWER, false, true },
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
+ { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false },
+ { }
+};
+
+static const struct soc_device_data soc_device_MSHW0040 = {
+ .button_info = soc_button_MSHW0040,
+ .check = soc_device_check_MSHW0040,
+};
+
static const struct acpi_device_id soc_button_acpi_match[] = {
- { "PNP0C40", (unsigned long)soc_button_PNP0C40 },
+ { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
{ "ACPI0011", 0 },
+
+ /* Microsoft Surface Devices (5th and 6th generation) */
+ { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
+
{ }
};
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index 4a5afc7..fe43e55 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for PC-speaker like devices found on various Sparc systems.
*
diff --git a/drivers/input/misc/stpmic1_onkey.c b/drivers/input/misc/stpmic1_onkey.c
new file mode 100644
index 0000000..d8dc2f2
--- /dev/null
+++ b/drivers/input/misc/stpmic1_onkey.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2018
+// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/stpmic1.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+/**
+ * struct stpmic1_onkey - OnKey data
+ * @input_dev: pointer to input device
+ * @irq_falling: irq that we are hooked on to
+ * @irq_rising: irq that we are hooked on to
+ */
+struct stpmic1_onkey {
+ struct input_dev *input_dev;
+ int irq_falling;
+ int irq_rising;
+};
+
+static irqreturn_t onkey_falling_irq(int irq, void *ponkey)
+{
+ struct stpmic1_onkey *onkey = ponkey;
+ struct input_dev *input_dev = onkey->input_dev;
+
+ input_report_key(input_dev, KEY_POWER, 1);
+ pm_wakeup_event(input_dev->dev.parent, 0);
+ input_sync(input_dev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t onkey_rising_irq(int irq, void *ponkey)
+{
+ struct stpmic1_onkey *onkey = ponkey;
+ struct input_dev *input_dev = onkey->input_dev;
+
+ input_report_key(input_dev, KEY_POWER, 0);
+ pm_wakeup_event(input_dev->dev.parent, 0);
+ input_sync(input_dev);
+
+ return IRQ_HANDLED;
+}
+
+static int stpmic1_onkey_probe(struct platform_device *pdev)
+{
+ struct stpmic1 *pmic = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct input_dev *input_dev;
+ struct stpmic1_onkey *onkey;
+ unsigned int val, reg = 0;
+ int error;
+
+ onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL);
+ if (!onkey)
+ return -ENOMEM;
+
+ onkey->irq_falling = platform_get_irq_byname(pdev, "onkey-falling");
+ if (onkey->irq_falling < 0)
+ return onkey->irq_falling;
+
+ onkey->irq_rising = platform_get_irq_byname(pdev, "onkey-rising");
+ if (onkey->irq_rising < 0)
+ return onkey->irq_rising;
+
+ if (!device_property_read_u32(dev, "power-off-time-sec", &val)) {
+ if (val > 0 && val <= 16) {
+ dev_dbg(dev, "power-off-time=%d seconds\n", val);
+ reg |= PONKEY_PWR_OFF;
+ reg |= ((16 - val) & PONKEY_TURNOFF_TIMER_MASK);
+ } else {
+ dev_err(dev, "power-off-time-sec out of range\n");
+ return -EINVAL;
+ }
+ }
+
+ if (device_property_present(dev, "st,onkey-clear-cc-flag"))
+ reg |= PONKEY_CC_FLAG_CLEAR;
+
+ error = regmap_update_bits(pmic->regmap, PKEY_TURNOFF_CR,
+ PONKEY_TURNOFF_MASK, reg);
+ if (error) {
+ dev_err(dev, "PKEY_TURNOFF_CR write failed: %d\n", error);
+ return error;
+ }
+
+ if (device_property_present(dev, "st,onkey-pu-inactive")) {
+ error = regmap_update_bits(pmic->regmap, PADS_PULL_CR,
+ PONKEY_PU_INACTIVE,
+ PONKEY_PU_INACTIVE);
+ if (error) {
+ dev_err(dev, "ONKEY Pads configuration failed: %d\n",
+ error);
+ return error;
+ }
+ }
+
+ input_dev = devm_input_allocate_device(dev);
+ if (!input_dev) {
+ dev_err(dev, "Can't allocate Pwr Onkey Input Device\n");
+ return -ENOMEM;
+ }
+
+ input_dev->name = "pmic_onkey";
+ input_dev->phys = "pmic_onkey/input0";
+
+ input_set_capability(input_dev, EV_KEY, KEY_POWER);
+
+ onkey->input_dev = input_dev;
+
+ /* interrupt is nested in a thread */
+ error = devm_request_threaded_irq(dev, onkey->irq_falling, NULL,
+ onkey_falling_irq, IRQF_ONESHOT,
+ dev_name(dev), onkey);
+ if (error) {
+ dev_err(dev, "Can't get IRQ Onkey Falling: %d\n", error);
+ return error;
+ }
+
+ error = devm_request_threaded_irq(dev, onkey->irq_rising, NULL,
+ onkey_rising_irq, IRQF_ONESHOT,
+ dev_name(dev), onkey);
+ if (error) {
+ dev_err(dev, "Can't get IRQ Onkey Rising: %d\n", error);
+ return error;
+ }
+
+ error = input_register_device(input_dev);
+ if (error) {
+ dev_err(dev, "Can't register power button: %d\n", error);
+ return error;
+ }
+
+ platform_set_drvdata(pdev, onkey);
+ device_init_wakeup(dev, true);
+
+ return 0;
+}
+
+static int __maybe_unused stpmic1_onkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(dev)) {
+ enable_irq_wake(onkey->irq_falling);
+ enable_irq_wake(onkey->irq_rising);
+ }
+ return 0;
+}
+
+static int __maybe_unused stpmic1_onkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(dev)) {
+ disable_irq_wake(onkey->irq_falling);
+ disable_irq_wake(onkey->irq_rising);
+ }
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm,
+ stpmic1_onkey_suspend,
+ stpmic1_onkey_resume);
+
+static const struct of_device_id of_stpmic1_onkey_match[] = {
+ { .compatible = "st,stpmic1-onkey" },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, of_stpmic1_onkey_match);
+
+static struct platform_driver stpmic1_onkey_driver = {
+ .probe = stpmic1_onkey_probe,
+ .driver = {
+ .name = "stpmic1_onkey",
+ .of_match_table = of_match_ptr(of_stpmic1_onkey_match),
+ .pm = &stpmic1_onkey_pm,
+ },
+};
+module_platform_driver(stpmic1_onkey_driver);
+
+MODULE_DESCRIPTION("Onkey driver for STPMIC1");
+MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c
index a4455bb..f011447 100644
--- a/drivers/input/misc/tps65218-pwrbutton.c
+++ b/drivers/input/misc/tps65218-pwrbutton.c
@@ -124,10 +124,8 @@
device_init_wakeup(dev, true);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(dev, "No IRQ resource!\n");
+ if (irq < 0)
return -EINVAL;
- }
error = devm_request_threaded_irq(dev, irq, NULL, tps6521x_pb_irq,
IRQF_TRIGGER_RISING |
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index c37aea9..e0ff616 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* twl4030-vibra.c - TWL4030 Vibrator driver
*
@@ -6,21 +7,6 @@
* Written by Henrik Saari <henrik.saari@nokia.com>
* Updates by Felipe Balbi <felipe.balbi@nokia.com>
* Input by Jari Vanhala <ext-jari.vanhala@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index 15e0d35..bf66449 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* twl6040-vibra.c - TWL6040 Vibrator driver
*
@@ -9,21 +10,6 @@
* Based on twl4030-vibra.c by Henrik Saari <henrik.saari@nokia.com>
* Felipe Balbi <felipe.balbi@nokia.com>
* Jari Vanhala <ext-javi.vanhala@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
*/
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -286,10 +272,8 @@
}
info->irq = platform_get_irq(pdev, 0);
- if (info->irq < 0) {
- dev_err(info->dev, "invalid irq\n");
+ if (info->irq < 0)
return -EINVAL;
- }
error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
twl6040_vib_irq_handler,
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 8ec483e..84051f2 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* User level driver support for input subsystem
*
* Heavily based on evdev.c by Vojtech Pavlik
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
@@ -39,6 +26,7 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
+#include <linux/overflow.h>
#include <linux/input/mt.h>
#include "../input-compat.h"
@@ -397,7 +385,7 @@
newdev->state = UIST_NEW_DEVICE;
file->private_data = newdev;
- nonseekable_open(inode, file);
+ stream_open(inode, file);
return 0;
}
@@ -405,7 +393,7 @@
static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
const struct input_absinfo *abs)
{
- int min, max;
+ int min, max, range;
min = abs->minimum;
max = abs->maximum;
@@ -417,7 +405,7 @@
return -EINVAL;
}
- if (abs->flat > max - min) {
+ if (!check_sub_overflow(max, min, &range) && abs->flat > range) {
printk(KERN_DEBUG
"%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
UINPUT_NAME, code, abs->flat, min, max);
@@ -1050,13 +1038,31 @@
#ifdef CONFIG_COMPAT
-#define UI_SET_PHYS_COMPAT _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
+/*
+ * These IOCTLs change their size and thus their numbers between
+ * 32 and 64 bits.
+ */
+#define UI_SET_PHYS_COMPAT \
+ _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
+#define UI_BEGIN_FF_UPLOAD_COMPAT \
+ _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload_compat)
+#define UI_END_FF_UPLOAD_COMPAT \
+ _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload_compat)
static long uinput_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- if (cmd == UI_SET_PHYS_COMPAT)
+ switch (cmd) {
+ case UI_SET_PHYS_COMPAT:
cmd = UI_SET_PHYS;
+ break;
+ case UI_BEGIN_FF_UPLOAD_COMPAT:
+ cmd = UI_BEGIN_FF_UPLOAD;
+ break;
+ case UI_END_FF_UPLOAD_COMPAT:
+ cmd = UI_END_FF_UPLOAD;
+ break;
+ }
return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
}
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 43e67f5..7ce6cc6 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Wistron laptop button driver
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
* Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
* Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
- *
- * You can redistribute and/or modify this program under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation.
- *
- * 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.,
- * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/io.h>
#include <linux/dmi.h>
diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c
index 594f72e..24bc5c5 100644
--- a/drivers/input/misc/xen-kbdfront.c
+++ b/drivers/input/misc/xen-kbdfront.c
@@ -524,7 +524,7 @@
case XenbusStateClosed:
if (dev->state == XenbusStateClosed)
break;
- /* Missed the backend's CLOSING state -- fallthrough */
+ /* fall through - Missed the backend's CLOSING state */
case XenbusStateClosing:
xenbus_frontend_closed(dev);
break;
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index 1365cd9..8ab01c7 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* drivers/usb/input/yealink.c
*
* Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Description:
diff --git a/drivers/input/misc/yealink.h b/drivers/input/misc/yealink.h
index 934c247..69f7004 100644
--- a/drivers/input/misc/yealink.h
+++ b/drivers/input/misc/yealink.h
@@ -1,22 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* drivers/usb/input/yealink.h
*
* Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef INPUT_YEALINK_H
#define INPUT_YEALINK_H
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 566a1e3..652c38e 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Mouse driver configuration
#
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 0a6f7ca..34700ed 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ALPS touchpad PS/2 mouse driver
*
@@ -9,10 +10,6 @@
*
* ALPS detection, tap switching and status querying info is taken from
* tpconfig utility (by C. Scott Ananian and Bruce Kall).
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/slab.h>
@@ -24,6 +21,7 @@
#include "psmouse.h"
#include "alps.h"
+#include "trackpoint.h"
/*
* Definitions for ALPS version 3 and 4 command mode protocol
@@ -2864,6 +2862,23 @@
return NULL;
}
+static bool alps_is_cs19_trackpoint(struct psmouse *psmouse)
+{
+ u8 param[2] = { 0 };
+
+ if (ps2_command(&psmouse->ps2dev,
+ param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
+ return false;
+
+ /*
+ * param[0] contains the trackpoint device variant_id while
+ * param[1] contains the firmware_id. So far all alps
+ * trackpoint-only devices have their variant_ids equal
+ * TP_VARIANT_ALPS and their firmware_ids are in 0x20~0x2f range.
+ */
+ return param[0] == TP_VARIANT_ALPS && ((param[1] & 0xf0) == 0x20);
+}
+
static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
{
const struct alps_protocol_info *protocol;
@@ -3165,6 +3180,20 @@
return error;
/*
+ * ALPS cs19 is a trackpoint-only device, and uses different
+ * protocol than DualPoint ones, so we return -EINVAL here and let
+ * trackpoint.c drive this device. If the trackpoint driver is not
+ * enabled, the device will fall back to a bare PS/2 mouse.
+ * If ps2_command() fails here, we depend on the immediately
+ * followed psmouse_reset() to reset the device to normal state.
+ */
+ if (alps_is_cs19_trackpoint(psmouse)) {
+ psmouse_dbg(psmouse,
+ "ALPS CS19 trackpoint-only device detected, ignoring\n");
+ return -EINVAL;
+ }
+
+ /*
* Reset the device to make sure it is fully operational:
* on some laptops, like certain Dell Latitudes, we may
* fail to properly detect presence of trackstick if device
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 79b6d69..0a1048c 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ALPS touchpad PS/2 mouse driver
*
* Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _ALPS_H
@@ -326,18 +323,7 @@
#define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
-#ifdef CONFIG_MOUSE_PS2_ALPS
int alps_detect(struct psmouse *psmouse, bool set_properties);
int alps_init(struct psmouse *psmouse);
-#else
-inline int alps_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENOSYS;
-}
-inline int alps_init(struct psmouse *psmouse)
-{
- return -ENOSYS;
-}
-#endif /* CONFIG_MOUSE_PS2_ALPS */
#endif
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index a33437c..a50e503 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Amiga mouse driver for Linux/m68k
*
@@ -11,11 +12,6 @@
* Russell King
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation
- */
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index f1e66e2..3f06e8a 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Apple USB Touchpad (for post-February 2005 PowerBooks and MacBooks) driver
*
@@ -11,21 +12,6 @@
* Copyright (C) 2007-2008 Sven Anders (anders@anduras.de)
*
* Thanks to Alex Harper <basilisk@foobox.net> for his inputs.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c
index 96f2f51..b1219cc 100644
--- a/drivers/input/mouse/atarimouse.c
+++ b/drivers/input/mouse/atarimouse.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atari mouse driver for Linux/m68k
*
@@ -7,7 +8,6 @@
* Amiga mouse driver for Linux/m68k
*
* Copyright (c) 2000-2002 Vojtech Pavlik
- *
*/
/*
* The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
@@ -34,11 +34,6 @@
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation
- */
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index d012213..59a1450 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver
*
@@ -16,21 +17,6 @@
* Copyright (C) 2005 Peter Osterlund (petero2@telia.com)
* Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch)
* Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c
index f2aabf7..6e0c5f5 100644
--- a/drivers/input/mouse/byd.c
+++ b/drivers/input/mouse/byd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* BYD TouchPad PS/2 mouse driver
*
@@ -6,10 +7,6 @@
* Copyright (C) 2015 Tai Chi Minh Ralph Eastwood
* Copyright (C) 2015 Martin Wimpress
* Copyright (C) 2015 Jay Kuri
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/delay.h>
diff --git a/drivers/input/mouse/byd.h b/drivers/input/mouse/byd.h
index 8cb90d9..ff2771e 100644
--- a/drivers/input/mouse/byd.h
+++ b/drivers/input/mouse/byd.h
@@ -2,18 +2,7 @@
#ifndef _BYD_H
#define _BYD_H
-#ifdef CONFIG_MOUSE_PS2_BYD
int byd_detect(struct psmouse *psmouse, bool set_properties);
int byd_init(struct psmouse *psmouse);
-#else
-static inline int byd_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENOSYS;
-}
-static inline int byd_init(struct psmouse *psmouse)
-{
- return -ENOSYS;
-}
-#endif /* CONFIG_MOUSE_PS2_BYD */
#endif /* _BYD_H */
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index dfd3873..c675f15 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -1238,13 +1238,6 @@
.attrs = cyapa_sysfs_entries,
};
-static void cyapa_remove_sysfs_group(void *data)
-{
- struct cyapa *cyapa = data;
-
- sysfs_remove_group(&cyapa->client->dev.kobj, &cyapa_sysfs_group);
-}
-
static void cyapa_disable_regulator(void *data)
{
struct cyapa *cyapa = data;
@@ -1312,19 +1305,12 @@
return error;
}
- error = sysfs_create_group(&dev->kobj, &cyapa_sysfs_group);
+ error = devm_device_add_group(dev, &cyapa_sysfs_group);
if (error) {
dev_err(dev, "failed to create sysfs entries: %d\n", error);
return error;
}
- error = devm_add_action(dev, cyapa_remove_sysfs_group, cyapa);
- if (error) {
- cyapa_remove_sysfs_group(cyapa);
- dev_err(dev, "failed to add sysfs cleanup action: %d\n", error);
- return error;
- }
-
error = cyapa_prepare_wakeup_controls(cyapa);
if (error) {
dev_err(dev, "failed to prepare wakeup controls: %d\n", error);
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
index 076dda4..00e395d 100644
--- a/drivers/input/mouse/cyapa_gen3.c
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -1067,7 +1067,7 @@
return error;
}
- /* Fallthrough state */
+ /* Fall through */
case CYAPA_STATE_BL_IDLE:
/* Try to get firmware version in bootloader mode. */
cyapa_gen3_bl_query_data(cyapa);
@@ -1078,7 +1078,7 @@
return error;
}
- /* Fallthrough state */
+ /* Fall through */
case CYAPA_STATE_OP:
/*
* Reading query data before going back to the full mode
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
index 21bad3e..5f86800 100644
--- a/drivers/input/mouse/cypress_ps2.c
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cypress Trackpad PS/2 mouse driver
*
@@ -9,10 +10,6 @@
* Additional contributors include:
* Kamal Mostafa <kamal@canonical.com>
* Kyle Fazzari <git@status.e4ward.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/module.h>
diff --git a/drivers/input/mouse/cypress_ps2.h b/drivers/input/mouse/cypress_ps2.h
index 1eaddd8..bb4979d 100644
--- a/drivers/input/mouse/cypress_ps2.h
+++ b/drivers/input/mouse/cypress_ps2.h
@@ -170,18 +170,7 @@
};
-#ifdef CONFIG_MOUSE_PS2_CYPRESS
int cypress_detect(struct psmouse *psmouse, bool set_properties);
int cypress_init(struct psmouse *psmouse);
-#else
-inline int cypress_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENOSYS;
-}
-inline int cypress_init(struct psmouse *psmouse)
-{
- return -ENOSYS;
-}
-#endif /* CONFIG_MOUSE_PS2_CYPRESS */
#endif /* _CYPRESS_PS2_H */
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h
index 243e0fa..a9074ac 100644
--- a/drivers/input/mouse/elan_i2c.h
+++ b/drivers/input/mouse/elan_i2c.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Elan I2C/SMBus Touchpad driver
*
@@ -9,10 +10,6 @@
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
* copyright (c) 2011-2012 Google, Inc.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index a94b649..8719da5 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elan I2C/SMBus Touchpad driver
*
@@ -11,10 +12,6 @@
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
* copyright (c) 2011-2012 Google, Inc.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
* Trademarks are the property of their respective owners.
*/
@@ -37,6 +34,7 @@
#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>
@@ -99,6 +97,7 @@
u8 max_baseline;
bool baseline_ready;
u8 clickpad;
+ bool middle_button;
};
static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
@@ -366,27 +365,62 @@
static int elan_query_device_parameters(struct elan_tp_data *data)
{
+ struct i2c_client *client = data->client;
unsigned int x_traces, y_traces;
+ u32 x_mm, y_mm;
u8 hw_x_res, hw_y_res;
int error;
- error = data->ops->get_max(data->client, &data->max_x, &data->max_y);
- if (error)
- return error;
+ if (device_property_read_u32(&client->dev,
+ "touchscreen-size-x", &data->max_x) ||
+ device_property_read_u32(&client->dev,
+ "touchscreen-size-y", &data->max_y)) {
+ error = data->ops->get_max(data->client,
+ &data->max_x,
+ &data->max_y);
+ if (error)
+ return error;
+ } else {
+ /* size is the maximum + 1 */
+ --data->max_x;
+ --data->max_y;
+ }
- error = data->ops->get_num_traces(data->client, &x_traces, &y_traces);
- if (error)
- return error;
-
+ if (device_property_read_u32(&client->dev,
+ "elan,x_traces",
+ &x_traces) ||
+ device_property_read_u32(&client->dev,
+ "elan,y_traces",
+ &y_traces)) {
+ error = data->ops->get_num_traces(data->client,
+ &x_traces, &y_traces);
+ if (error)
+ return error;
+ }
data->width_x = data->max_x / x_traces;
data->width_y = data->max_y / y_traces;
- error = data->ops->get_resolution(data->client, &hw_x_res, &hw_y_res);
- if (error)
- return error;
+ if (device_property_read_u32(&client->dev,
+ "touchscreen-x-mm", &x_mm) ||
+ device_property_read_u32(&client->dev,
+ "touchscreen-y-mm", &y_mm)) {
+ error = data->ops->get_resolution(data->client,
+ &hw_x_res, &hw_y_res);
+ if (error)
+ return error;
- data->x_res = elan_convert_resolution(hw_x_res);
- data->y_res = elan_convert_resolution(hw_y_res);
+ data->x_res = elan_convert_resolution(hw_x_res);
+ data->y_res = elan_convert_resolution(hw_y_res);
+ } else {
+ data->x_res = (data->max_x + 1) / x_mm;
+ data->y_res = (data->max_y + 1) / y_mm;
+ }
+
+ if (device_property_read_bool(&client->dev, "elan,clickpad"))
+ data->clickpad = 1;
+
+ if (device_property_read_bool(&client->dev, "elan,middle-button"))
+ data->middle_button = true;
return 0;
}
@@ -926,8 +960,9 @@
finger_data += ETP_FINGER_DATA_LEN;
}
- input_report_key(input, BTN_LEFT, tp_info & 0x01);
- input_report_key(input, BTN_RIGHT, tp_info & 0x02);
+ input_report_key(input, BTN_LEFT, tp_info & BIT(0));
+ input_report_key(input, BTN_MIDDLE, tp_info & BIT(2));
+ input_report_key(input, BTN_RIGHT, tp_info & BIT(1));
input_report_abs(input, ABS_DISTANCE, hover_event != 0);
input_mt_report_pointer_emulation(input, true);
input_sync(input);
@@ -981,6 +1016,8 @@
if (error)
goto out;
+ pm_wakeup_event(dev, 0);
+
switch (report[ETP_REPORT_ID_OFFSET]) {
case ETP_REPORT_ID:
elan_report_absolute(data, report);
@@ -1059,10 +1096,13 @@
__set_bit(EV_ABS, input->evbit);
__set_bit(INPUT_PROP_POINTER, input->propbit);
- if (data->clickpad)
+ if (data->clickpad) {
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
- else
+ } else {
__set_bit(BTN_RIGHT, input->keybit);
+ if (data->middle_button)
+ __set_bit(BTN_MIDDLE, input->keybit);
+ }
__set_bit(BTN_LEFT, input->keybit);
/* Set up ST parameters */
@@ -1098,13 +1138,6 @@
regulator_disable(data->vcc);
}
-static void elan_remove_sysfs_groups(void *_data)
-{
- struct elan_tp_data *data = _data;
-
- sysfs_remove_groups(&data->client->dev.kobj, elan_sysfs_groups);
-}
-
static int elan_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
@@ -1154,9 +1187,8 @@
return error;
}
- error = devm_add_action(dev, elan_disable_regulator, data);
+ error = devm_add_action_or_reset(dev, elan_disable_regulator, data);
if (error) {
- regulator_disable(data->vcc);
dev_err(dev, "Failed to add disable regulator action: %d\n",
error);
return error;
@@ -1229,20 +1261,12 @@
return error;
}
- error = sysfs_create_groups(&dev->kobj, elan_sysfs_groups);
+ error = devm_device_add_groups(dev, elan_sysfs_groups);
if (error) {
dev_err(dev, "failed to create sysfs attributes: %d\n", error);
return error;
}
- error = devm_add_action(dev, elan_remove_sysfs_groups, data);
- if (error) {
- elan_remove_sysfs_groups(data);
- dev_err(dev, "Failed to add sysfs cleanup action: %d\n",
- error);
- return error;
- }
-
error = input_register_device(data->input);
if (error) {
dev_err(dev, "failed to register input device: %d\n", error);
@@ -1333,28 +1357,6 @@
MODULE_DEVICE_TABLE(i2c, elan_id);
#ifdef CONFIG_ACPI
-static const struct acpi_device_id elan_acpi_id[] = {
- { "ELAN0000", 0 },
- { "ELAN0100", 0 },
- { "ELAN0600", 0 },
- { "ELAN0602", 0 },
- { "ELAN0605", 0 },
- { "ELAN0608", 0 },
- { "ELAN0609", 0 },
- { "ELAN060B", 0 },
- { "ELAN060C", 0 },
- { "ELAN0611", 0 },
- { "ELAN0612", 0 },
- { "ELAN0618", 0 },
- { "ELAN061C", 0 },
- { "ELAN061D", 0 },
- { "ELAN061E", 0 },
- { "ELAN0620", 0 },
- { "ELAN0621", 0 },
- { "ELAN0622", 0 },
- { "ELAN1000", 0 },
- { }
-};
MODULE_DEVICE_TABLE(acpi, elan_acpi_id);
#endif
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c
index e19eb60..058b35b 100644
--- a/drivers/input/mouse/elan_i2c_i2c.c
+++ b/drivers/input/mouse/elan_i2c_i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elan I2C/SMBus Touchpad driver - I2C interface
*
@@ -9,10 +10,6 @@
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
* copyright (c) 2011-2012 Google, Inc.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c
index 88e315d..8c3185d 100644
--- a/drivers/input/mouse/elan_i2c_smbus.c
+++ b/drivers/input/mouse/elan_i2c_smbus.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elan I2C/SMBus Touchpad driver - SMBus interface
*
@@ -9,10 +10,6 @@
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
* copyright (c) 2011-2012 Google, Inc.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 9fe075c..2d8434b 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elantech Touchpad driver (v6)
*
* Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
* Trademarks are the property of their respective owners.
*/
@@ -230,6 +227,52 @@
}
/*
+ * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in
+ * fw_version for this is based on the following fw_version & caps table:
+ *
+ * Laptop-model: fw_version: caps: buttons:
+ * Acer S3 0x461f00 10, 13, 0e clickpad
+ * Acer S7-392 0x581f01 50, 17, 0d clickpad
+ * Acer V5-131 0x461f02 01, 16, 0c clickpad
+ * Acer V5-551 0x461f00 ? clickpad
+ * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons
+ * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons
+ * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons
+ * Asus TP500LN 0x381f17 10, 14, 0e clickpad
+ * Asus X750JN 0x381f17 10, 14, 0e clickpad
+ * Asus UX31 0x361f00 20, 15, 0e clickpad
+ * Asus UX32VD 0x361f02 00, 15, 0e clickpad
+ * Avatar AVIU-145A2 0x361f00 ? clickpad
+ * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**)
+ * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**)
+ * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
+ * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons
+ * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
+ * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
+ * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
+ * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
+ * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*)
+ * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons
+ * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad
+ * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad
+ * Samsung NP900X3E-A02 0x575f03 ? clickpad
+ * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad
+ * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons
+ * Samsung RF710 0x450f00 ? 2 hw buttons
+ * System76 Pangolin 0x250f01 ? 2 hw buttons
+ * (*) + 3 trackpoint buttons
+ * (**) + 0 trackpoint buttons
+ * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps
+ */
+static inline int elantech_is_buttonpad(struct elantech_device_info *info)
+{
+ return info->fw_version & 0x001000;
+}
+
+/*
* Interpret complete data packets and report absolute mode input events for
* hardware version 1. (4 byte packets)
*/
@@ -526,7 +569,7 @@
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
/* For clickpads map both buttons to BTN_LEFT */
- if (etd->info.fw_version & 0x001000)
+ if (elantech_is_buttonpad(&etd->info))
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
else
psmouse_report_standard_buttons(dev, packet[0]);
@@ -544,7 +587,7 @@
unsigned char *packet = psmouse->packet;
/* For clickpads map both buttons to BTN_LEFT */
- if (etd->info.fw_version & 0x001000)
+ if (elantech_is_buttonpad(&etd->info))
input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
else
psmouse_report_standard_buttons(dev, packet[0]);
@@ -994,88 +1037,6 @@
return rc;
}
-static int elantech_set_range(struct psmouse *psmouse,
- unsigned int *x_min, unsigned int *y_min,
- unsigned int *x_max, unsigned int *y_max,
- unsigned int *width)
-{
- struct elantech_data *etd = psmouse->private;
- struct elantech_device_info *info = &etd->info;
- unsigned char param[3];
- unsigned char traces;
-
- switch (info->hw_version) {
- case 1:
- *x_min = ETP_XMIN_V1;
- *y_min = ETP_YMIN_V1;
- *x_max = ETP_XMAX_V1;
- *y_max = ETP_YMAX_V1;
- break;
-
- case 2:
- if (info->fw_version == 0x020800 ||
- info->fw_version == 0x020b00 ||
- info->fw_version == 0x020030) {
- *x_min = ETP_XMIN_V2;
- *y_min = ETP_YMIN_V2;
- *x_max = ETP_XMAX_V2;
- *y_max = ETP_YMAX_V2;
- } else {
- int i;
- int fixed_dpi;
-
- i = (info->fw_version > 0x020800 &&
- info->fw_version < 0x020900) ? 1 : 2;
-
- if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
- return -1;
-
- fixed_dpi = param[1] & 0x10;
-
- if (((info->fw_version >> 16) == 0x14) && fixed_dpi) {
- if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
- return -1;
-
- *x_max = (info->capabilities[1] - i) * param[1] / 2;
- *y_max = (info->capabilities[2] - i) * param[2] / 2;
- } else if (info->fw_version == 0x040216) {
- *x_max = 819;
- *y_max = 405;
- } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) {
- *x_max = 900;
- *y_max = 500;
- } else {
- *x_max = (info->capabilities[1] - i) * 64;
- *y_max = (info->capabilities[2] - i) * 64;
- }
- }
- break;
-
- case 3:
- if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
- return -1;
-
- *x_max = (0x0f & param[0]) << 8 | param[1];
- *y_max = (0xf0 & param[0]) << 4 | param[2];
- break;
-
- case 4:
- if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
- return -1;
-
- *x_max = (0x0f & param[0]) << 8 | param[1];
- *y_max = (0xf0 & param[0]) << 4 | param[2];
- traces = info->capabilities[1];
- if ((traces < 2) || (traces > *x_max))
- return -1;
-
- *width = *x_max / (traces - 1);
- break;
- }
-
- return 0;
-}
-
/*
* (value from firmware) * 10 + 790 = dpi
* we also have to convert dpi to dots/mm (*10/254 to avoid floating point)
@@ -1102,51 +1063,12 @@
return 0;
}
-/*
- * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in
- * fw_version for this is based on the following fw_version & caps table:
- *
- * Laptop-model: fw_version: caps: buttons:
- * Acer S3 0x461f00 10, 13, 0e clickpad
- * Acer S7-392 0x581f01 50, 17, 0d clickpad
- * Acer V5-131 0x461f02 01, 16, 0c clickpad
- * Acer V5-551 0x461f00 ? clickpad
- * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons
- * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons
- * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons
- * Asus TP500LN 0x381f17 10, 14, 0e clickpad
- * Asus X750JN 0x381f17 10, 14, 0e clickpad
- * Asus UX31 0x361f00 20, 15, 0e clickpad
- * Asus UX32VD 0x361f02 00, 15, 0e clickpad
- * Avatar AVIU-145A2 0x361f00 ? clickpad
- * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
- * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons
- * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons
- * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
- * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons
- * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
- * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
- * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
- * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
- * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*)
- * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons
- * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad
- * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad
- * Samsung NP900X3E-A02 0x575f03 ? clickpad
- * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad
- * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons
- * Samsung RF710 0x450f00 ? 2 hw buttons
- * System76 Pangolin 0x250f01 ? 2 hw buttons
- * (*) + 3 trackpoint buttons
- * (**) + 0 trackpoint buttons
- * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps
- */
static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
- if (etd->info.fw_version & 0x001000) {
+ if (elantech_is_buttonpad(&etd->info)) {
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
__clear_bit(BTN_RIGHT, dev->keybit);
}
@@ -1171,18 +1093,17 @@
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
},
},
+ {
+ /* Fujitsu H780 also has a middle button */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H780"),
+ },
+ },
#endif
{ }
};
-static const char * const middle_button_pnp_ids[] = {
- "LEN2131", /* ThinkPad P52 w/ NFC */
- "LEN2132", /* ThinkPad P52 */
- "LEN2133", /* ThinkPad P72 w/ NFC */
- "LEN2134", /* ThinkPad P72 */
- NULL
-};
-
/*
* Set the appropriate event bits for the input subsystem
*/
@@ -1191,10 +1112,9 @@
struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
struct elantech_device_info *info = &etd->info;
- unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
-
- if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
- return -1;
+ unsigned int x_min = info->x_min, y_min = info->y_min,
+ x_max = info->x_max, y_max = info->y_max,
+ width = info->width;
__set_bit(INPUT_PROP_POINTER, dev->propbit);
__set_bit(EV_KEY, dev->evbit);
@@ -1202,8 +1122,7 @@
__clear_bit(EV_REL, dev->evbit);
__set_bit(BTN_LEFT, dev->keybit);
- if (dmi_check_system(elantech_dmi_has_middle_button) ||
- psmouse_matches_pnp_id(psmouse, middle_button_pnp_ids))
+ if (info->has_middle_button)
__set_bit(BTN_MIDDLE, dev->keybit);
__set_bit(BTN_RIGHT, dev->keybit);
@@ -1678,6 +1597,7 @@
struct elantech_device_info *info)
{
unsigned char param[3];
+ unsigned char traces;
memset(info, 0, sizeof(*info));
@@ -1746,6 +1666,90 @@
}
}
+ /* query range information */
+ switch (info->hw_version) {
+ case 1:
+ info->x_min = ETP_XMIN_V1;
+ info->y_min = ETP_YMIN_V1;
+ info->x_max = ETP_XMAX_V1;
+ info->y_max = ETP_YMAX_V1;
+ break;
+
+ case 2:
+ if (info->fw_version == 0x020800 ||
+ info->fw_version == 0x020b00 ||
+ info->fw_version == 0x020030) {
+ info->x_min = ETP_XMIN_V2;
+ info->y_min = ETP_YMIN_V2;
+ info->x_max = ETP_XMAX_V2;
+ info->y_max = ETP_YMAX_V2;
+ } else {
+ int i;
+ int fixed_dpi;
+
+ i = (info->fw_version > 0x020800 &&
+ info->fw_version < 0x020900) ? 1 : 2;
+
+ if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+ return -EINVAL;
+
+ fixed_dpi = param[1] & 0x10;
+
+ if (((info->fw_version >> 16) == 0x14) && fixed_dpi) {
+ if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
+ return -EINVAL;
+
+ info->x_max = (info->capabilities[1] - i) * param[1] / 2;
+ info->y_max = (info->capabilities[2] - i) * param[2] / 2;
+ } else if (info->fw_version == 0x040216) {
+ info->x_max = 819;
+ info->y_max = 405;
+ } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) {
+ info->x_max = 900;
+ info->y_max = 500;
+ } else {
+ info->x_max = (info->capabilities[1] - i) * 64;
+ info->y_max = (info->capabilities[2] - i) * 64;
+ }
+ }
+ break;
+
+ case 3:
+ if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+ return -EINVAL;
+
+ info->x_max = (0x0f & param[0]) << 8 | param[1];
+ info->y_max = (0xf0 & param[0]) << 4 | param[2];
+ break;
+
+ case 4:
+ if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+ return -EINVAL;
+
+ info->x_max = (0x0f & param[0]) << 8 | param[1];
+ info->y_max = (0xf0 & param[0]) << 4 | param[2];
+ traces = info->capabilities[1];
+ if ((traces < 2) || (traces > info->x_max))
+ return -EINVAL;
+
+ info->width = info->x_max / (traces - 1);
+
+ /* column number of traces */
+ info->x_traces = traces;
+
+ /* row number of traces */
+ traces = info->capabilities[2];
+ if ((traces >= 2) && (traces <= info->y_max))
+ info->y_traces = traces;
+
+ break;
+ }
+
+ /* check for the middle button: DMI matching or new v4 firmwares */
+ info->has_middle_button = dmi_check_system(elantech_dmi_has_middle_button) ||
+ (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version) &&
+ !elantech_is_buttonpad(info));
+
return 0;
}
@@ -1772,10 +1776,6 @@
* These are known to not be working properly as bits are missing
* in elan_i2c.
*/
- "LEN2131", /* ThinkPad P52 w/ NFC */
- "LEN2132", /* ThinkPad P52 */
- "LEN2133", /* ThinkPad P72 w/ NFC */
- "LEN2134", /* ThinkPad P72 */
NULL
};
@@ -1783,17 +1783,45 @@
struct elantech_device_info *info,
bool leave_breadcrumbs)
{
- const struct property_entry i2c_properties[] = {
- PROPERTY_ENTRY_BOOL("elan,trackpoint"),
- { },
- };
+ struct property_entry i2c_props[11] = {};
struct i2c_board_info smbus_board = {
I2C_BOARD_INFO("elan_i2c", 0x15),
.flags = I2C_CLIENT_HOST_NOTIFY,
};
+ unsigned int idx = 0;
+
+ smbus_board.properties = i2c_props;
+
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-x",
+ info->x_max + 1);
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-y",
+ info->y_max + 1);
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-x",
+ info->x_min);
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-y",
+ info->y_min);
+ if (info->x_res)
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-x-mm",
+ (info->x_max + 1) / info->x_res);
+ if (info->y_res)
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-y-mm",
+ (info->y_max + 1) / info->y_res);
if (info->has_trackpoint)
- smbus_board.properties = i2c_properties;
+ i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,trackpoint");
+
+ if (info->has_middle_button)
+ i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,middle-button");
+
+ if (info->x_traces)
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,x_traces",
+ info->x_traces);
+ if (info->y_traces)
+ i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,y_traces",
+ info->y_traces);
+
+ if (elantech_is_buttonpad(info))
+ i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,clickpad");
return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0, false,
leave_breadcrumbs);
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 1197270..e0a3e59 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Elantech Touchpad driver (v6)
*
* Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
* Trademarks are the property of their respective owners.
*/
@@ -144,8 +141,15 @@
unsigned char debug;
unsigned char hw_version;
unsigned int fw_version;
+ unsigned int x_min;
+ unsigned int y_min;
+ unsigned int x_max;
+ unsigned int y_max;
unsigned int x_res;
unsigned int y_res;
+ unsigned int x_traces;
+ unsigned int y_traces;
+ unsigned int width;
unsigned int bus;
bool paritycheck;
bool jumpy_cursor;
@@ -153,6 +157,7 @@
bool crc_enabled;
bool set_hw_resolution;
bool has_trackpoint;
+ bool has_middle_button;
int (*send_cmd)(struct psmouse *psmouse, unsigned char c,
unsigned char *param);
};
@@ -179,32 +184,18 @@
void (*original_set_rate)(struct psmouse *psmouse, unsigned int rate);
};
-#ifdef CONFIG_MOUSE_PS2_ELANTECH
int elantech_detect(struct psmouse *psmouse, bool set_properties);
int elantech_init_ps2(struct psmouse *psmouse);
+
+#ifdef CONFIG_MOUSE_PS2_ELANTECH
int elantech_init(struct psmouse *psmouse);
#else
-static inline int elantech_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENOSYS;
-}
static inline int elantech_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
-static inline int elantech_init_ps2(struct psmouse *psmouse)
-{
- return -ENOSYS;
-}
#endif /* CONFIG_MOUSE_PS2_ELANTECH */
-#if defined(CONFIG_MOUSE_PS2_ELANTECH_SMBUS)
int elantech_init_smbus(struct psmouse *psmouse);
-#else
-static inline int elantech_init_smbus(struct psmouse *psmouse)
-{
- return -ENOSYS;
-}
-#endif /* CONFIG_MOUSE_PS2_ELANTECH_SMBUS */
#endif
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
index a7d3968..6fd5fff 100644
--- a/drivers/input/mouse/focaltech.c
+++ b/drivers/input/mouse/focaltech.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Focaltech TouchPad PS/2 mouse driver
*
* Copyright (c) 2014 Red Hat Inc.
* Copyright (c) 2014 Mathias Gottschlag <mgottschlag@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
* Red Hat authors:
*
* Hans de Goede <hdegoede@redhat.com>
diff --git a/drivers/input/mouse/focaltech.h b/drivers/input/mouse/focaltech.h
index 783b28e..0d90232 100644
--- a/drivers/input/mouse/focaltech.h
+++ b/drivers/input/mouse/focaltech.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Focaltech TouchPad PS/2 mouse driver
*
* Copyright (c) 2014 Red Hat Inc.
* Copyright (c) 2014 Mathias Gottschlag <mgottschlag@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
* Red Hat authors:
*
* Hans de Goede <hdegoede@redhat.com>
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c
index a26d8be..461436f 100644
--- a/drivers/input/mouse/gpio_mouse.c
+++ b/drivers/input/mouse/gpio_mouse.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for simulating a mouse on GPIO lines.
*
* Copyright (C) 2007 Atmel Corporation
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 015509e..72a083f 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* OLPC HGPK (XO-1) touchpad PS/2 mouse driver
*
@@ -12,10 +13,6 @@
* Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
* Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
/*
diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h
index 98b7b38..ce04159 100644
--- a/drivers/input/mouse/hgpk.h
+++ b/drivers/input/mouse/hgpk.h
@@ -47,22 +47,15 @@
int xsaw_secondary, ysaw_secondary; /* jumpiness detection */
};
-#ifdef CONFIG_MOUSE_PS2_OLPC
-void hgpk_module_init(void);
int hgpk_detect(struct psmouse *psmouse, bool set_properties);
int hgpk_init(struct psmouse *psmouse);
+
+#ifdef CONFIG_MOUSE_PS2_OLPC
+void hgpk_module_init(void);
#else
static inline void hgpk_module_init(void)
{
}
-static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENODEV;
-}
-static inline int hgpk_init(struct psmouse *psmouse)
-{
- return -ENODEV;
-}
#endif
#endif
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index b9e6860..df5d116 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -13,19 +14,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index a5765f7..bd99557 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Fujitsu B-series Lifebook PS/2 TouchScreen driver
*
@@ -6,10 +7,6 @@
*
* TouchScreen detection, absolute mode setting and packet layout is taken from
* Harald Hoyer's description of the device.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/input.h>
diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h
index 0baf02a..d989cca 100644
--- a/drivers/input/mouse/lifebook.h
+++ b/drivers/input/mouse/lifebook.h
@@ -1,32 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Fujitsu B-series Lifebook PS/2 TouchScreen driver
*
* Copyright (c) 2005 Vojtech Pavlik
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _LIFEBOOK_H
#define _LIFEBOOK_H
-#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
-void lifebook_module_init(void);
int lifebook_detect(struct psmouse *psmouse, bool set_properties);
int lifebook_init(struct psmouse *psmouse);
+
+#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
+void lifebook_module_init(void);
#else
static inline void lifebook_module_init(void)
{
}
-static inline int lifebook_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENOSYS;
-}
-static inline int lifebook_init(struct psmouse *psmouse)
-{
- return -ENOSYS;
-}
#endif
#endif
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index 2fd6c84..bd647f9 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -14,19 +15,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 3d5637e..ed5a848 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Logitech PS/2++ mouse driver
*
* Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2003 Eric Wong <eric@yhbt.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h
index bf62945..df885c4 100644
--- a/drivers/input/mouse/logips2pp.h
+++ b/drivers/input/mouse/logips2pp.h
@@ -1,23 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Logitech PS/2++ mouse driver header
*
* Copyright (c) 2003 Vojtech Pavlik <vojtech@suse.cz>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _LOGIPS2PP_H
#define _LOGIPS2PP_H
-#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
int ps2pp_detect(struct psmouse *psmouse, bool set_properties);
-#else
-static inline int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENOSYS;
-}
-#endif /* CONFIG_MOUSE_PS2_LOGIPS2PP */
#endif
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
index 25f0ecb..2de64d6 100644
--- a/drivers/input/mouse/maplemouse.c
+++ b/drivers/input/mouse/maplemouse.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SEGA Dreamcast mouse driver
* Based on drivers/usb/usbmouse.c
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
index d6e8f58..0b75248 100644
--- a/drivers/input/mouse/navpoint.c
+++ b/drivers/input/mouse/navpoint.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synaptics NavPoint (PXA27x SSP/SPI) driver.
*
* Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index b8965e6..f755747 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
@@ -10,19 +11,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index d3ff1fc..527ae0b 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PS/2 mouse driver
*
@@ -5,11 +6,6 @@
* Copyright (c) 2003-2004 Dmitry Torokhov
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define psmouse_fmt(fmt) fmt
@@ -373,6 +369,8 @@
if (ps2_handle_response(&psmouse->ps2dev, data))
goto out;
+ pm_wakeup_event(&serio->dev, 0);
+
if (psmouse->state <= PSMOUSE_RESYNCING)
goto out;
diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c
index 852d4b4..027efdd 100644
--- a/drivers/input/mouse/psmouse-smbus.c
+++ b/drivers/input/mouse/psmouse-smbus.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017 Red Hat, Inc
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c
index 9b4d9a5..41acde6 100644
--- a/drivers/input/mouse/pxa930_trkball.c
+++ b/drivers/input/mouse/pxa930_trkball.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PXA930 track ball mouse driver
*
* Copyright (C) 2007 Marvell International Ltd.
* 2008-02-28: Yong Yao <yaoyong@marvell.com>
* initial version
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/input.h>
@@ -150,10 +147,8 @@
int irq, error;
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get trkball irq\n");
+ if (irq < 0)
return -ENXIO;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 21c60fe..6774029 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -1,15 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Acorn RiscPC mouse driver for Linux/ARM
*
* Copyright (c) 2000-2002 Vojtech Pavlik
* Copyright (C) 1996-2002 Russell King
- *
*/
/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*
* This handles the Acorn RiscPCs mouse. We basically have a couple of
* hardware registers that track the sensor count for the X-Y movement and
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 1d6010d..e99d9bf 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*-
* Finger Sensing Pad PS/2 mouse driver.
*
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
* Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index 42df9e3..02cac0e 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -1,22 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*-
* Finger Sensing Pad PS/2 mouse driver.
*
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
* Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __SENTELIC_H
@@ -119,19 +106,8 @@
unsigned int last_mt_fgr; /* Last seen finger(multitouch) */
};
-#ifdef CONFIG_MOUSE_PS2_SENTELIC
extern int fsp_detect(struct psmouse *psmouse, bool set_properties);
extern int fsp_init(struct psmouse *psmouse);
-#else
-static inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENOSYS;
-}
-static inline int fsp_init(struct psmouse *psmouse)
-{
- return -ENOSYS;
-}
-#endif
#endif /* __KERNEL__ */
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index 3e8fb81..ea9242d 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 2bd5bb1..56fae34 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synaptics TouchPad PS/2 mouse driver
*
@@ -16,10 +17,6 @@
* Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
* code for the special synaptics commands (from the tpconfig-source)
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
* Trademarks are the property of their respective owners.
*/
@@ -171,14 +168,21 @@
"LEN0046", /* X250 */
"LEN004a", /* W541 */
"LEN005b", /* P50 */
+ "LEN005e", /* T560 */
"LEN0071", /* T480 */
"LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */
"LEN0073", /* X1 Carbon G5 (Elantech) */
"LEN0092", /* X1 Carbon 6 */
+ "LEN0093", /* T480 */
"LEN0096", /* X280 */
"LEN0097", /* X280 -> ALPS trackpoint */
+ "LEN009b", /* T580 */
"LEN200f", /* T450s */
+ "LEN2054", /* E480 */
+ "LEN2055", /* E580 */
+ "SYN3052", /* HP EliteBook 840 G4 */
"SYN3221", /* HP 15-ay000 */
+ "SYN323d", /* HP Spectre X360 13-w013dx */
NULL
};
@@ -189,7 +193,7 @@
};
/*
- * Send a command to the synpatics touchpad by special commands
+ * Send a command to the synaptics touchpad by special commands
*/
static int synaptics_send_cmd(struct psmouse *psmouse, u8 cmd, u8 *param)
{
@@ -703,7 +707,7 @@
serio->id.type = SERIO_PS_PSTHRU;
strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
- strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
+ strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->phys));
serio->write = synaptics_pt_write;
serio->start = synaptics_pt_start;
serio->stop = synaptics_pt_stop;
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index fc00e00..08533d1 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Synaptics TouchPad PS/2 mouse driver
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _SYNAPTICS_H
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index 8538318..fa30464 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -219,7 +219,6 @@
struct i2c_client *client;
struct input_dev *input;
struct delayed_work dwork;
- spinlock_t lock;
int no_data_count;
int no_decel_param;
int reduce_report_param;
@@ -369,23 +368,11 @@
return xy_delta || gesture;
}
-static void synaptics_i2c_reschedule_work(struct synaptics_i2c *touch,
- unsigned long delay)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&touch->lock, flags);
-
- mod_delayed_work(system_wq, &touch->dwork, delay);
-
- spin_unlock_irqrestore(&touch->lock, flags);
-}
-
static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
{
struct synaptics_i2c *touch = dev_id;
- synaptics_i2c_reschedule_work(touch, 0);
+ mod_delayed_work(system_wq, &touch->dwork, 0);
return IRQ_HANDLED;
}
@@ -461,7 +448,7 @@
* We poll the device once in THREAD_IRQ_SLEEP_SECS and
* if error is detected, we try to reset and reconfigure the touchpad.
*/
- synaptics_i2c_reschedule_work(touch, delay);
+ mod_delayed_work(system_wq, &touch->dwork, delay);
}
static int synaptics_i2c_open(struct input_dev *input)
@@ -474,7 +461,7 @@
return ret;
if (polling_req)
- synaptics_i2c_reschedule_work(touch,
+ mod_delayed_work(system_wq, &touch->dwork,
msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
return 0;
@@ -530,7 +517,6 @@
touch->scan_rate_param = scan_rate;
set_scan_rate(touch, scan_rate);
INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler);
- spin_lock_init(&touch->lock);
return touch;
}
@@ -637,7 +623,7 @@
if (ret)
return ret;
- synaptics_i2c_reschedule_work(touch,
+ mod_delayed_work(system_wq, &touch->dwork,
msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
return 0;
diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c
index 83d2412..b5ff27e 100644
--- a/drivers/input/mouse/synaptics_usb.c
+++ b/drivers/input/mouse/synaptics_usb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* USB Synaptics device driver
*
@@ -16,11 +17,6 @@
* drivers/hid/usbhid/usbmouse.c by Vojtech Pavlik
* drivers/input/mouse/synaptics.c by Peter Osterlund
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/mouse/touchkit_ps2.c b/drivers/input/mouse/touchkit_ps2.c
index 1fd8f5e..760e451 100644
--- a/drivers/input/mouse/touchkit_ps2.c
+++ b/drivers/input/mouse/touchkit_ps2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* ----------------------------------------------------------------------------
* touchkit_ps2.c -- Driver for eGalax TouchKit PS/2 Touchscreens
*
@@ -5,20 +6,6 @@
* Copyright (C) 2004 by Daniel Ritz
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Based upon touchkitusb.c
*
* Vendor documentation is available at:
diff --git a/drivers/input/mouse/touchkit_ps2.h b/drivers/input/mouse/touchkit_ps2.h
index 2efe9ea..c808fe6 100644
--- a/drivers/input/mouse/touchkit_ps2.h
+++ b/drivers/input/mouse/touchkit_ps2.h
@@ -1,25 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* ----------------------------------------------------------------------------
* touchkit_ps2.h -- Driver for eGalax TouchKit PS/2 Touchscreens
*
* Copyright (C) 2005 by Stefan Lucke
* Copyright (c) 2005 Vojtech Pavlik
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _TOUCHKIT_PS2_H
#define _TOUCHKIT_PS2_H
-#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties);
-#else
-static inline int touchkit_ps2_detect(struct psmouse *psmouse,
- bool set_properties)
-{
- return -ENOSYS;
-}
-#endif /* CONFIG_MOUSE_PS2_TOUCHKIT */
#endif
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 6590d10..3eefee2 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Stephen Evanchik <evanchsa@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
* Trademarks are the property of their respective owners.
*/
diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
index 10a0391..5cb93ed 100644
--- a/drivers/input/mouse/trackpoint.h
+++ b/drivers/input/mouse/trackpoint.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* IBM TrackPoint PS/2 mouse driver
*
* Stephen Evanchik <evanchsa@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _TRACKPOINT_H
@@ -158,13 +155,6 @@
bool ext_dev;
};
-#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
-#else
-inline int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENOSYS;
-}
-#endif /* CONFIG_MOUSE_PS2_TRACKPOINT */
#endif /* _TRACKPOINT_H */
diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c
index 1ae5c1e..148245c 100644
--- a/drivers/input/mouse/vmmouse.c
+++ b/drivers/input/mouse/vmmouse.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors.
*
* Copyright (C) 2014, VMware, Inc. All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
* Twin device code is hugely inspired by the ALPS driver.
* Authors:
* Dmitry Torokhov <dmitry.torokhov@gmail.com>
@@ -19,12 +16,12 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <asm/hypervisor.h>
+#include <asm/vmware.h>
#include "psmouse.h"
#include "vmmouse.h"
#define VMMOUSE_PROTO_MAGIC 0x564D5868U
-#define VMMOUSE_PROTO_PORT 0x5658
/*
* Main commands supported by the vmmouse hypervisor port.
@@ -87,7 +84,7 @@
#define VMMOUSE_CMD(cmd, in1, out1, out2, out3, out4) \
({ \
unsigned long __dummy1, __dummy2; \
- __asm__ __volatile__ ("inl %%dx" : \
+ __asm__ __volatile__ (VMWARE_HYPERCALL : \
"=a"(out1), \
"=b"(out2), \
"=c"(out3), \
@@ -97,7 +94,7 @@
"a"(VMMOUSE_PROTO_MAGIC), \
"b"(in1), \
"c"(VMMOUSE_PROTO_CMD_##cmd), \
- "d"(VMMOUSE_PROTO_PORT) : \
+ "d"(0) : \
"memory"); \
})
diff --git a/drivers/input/mouse/vmmouse.h b/drivers/input/mouse/vmmouse.h
index 6f12601..90157ae 100644
--- a/drivers/input/mouse/vmmouse.h
+++ b/drivers/input/mouse/vmmouse.h
@@ -1,30 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors.
*
* Copyright (C) 2014, VMware, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _VMMOUSE_H
#define _VMMOUSE_H
-#ifdef CONFIG_MOUSE_PS2_VMMOUSE
#define VMMOUSE_PSNAME "VirtualPS/2"
int vmmouse_detect(struct psmouse *psmouse, bool set_properties);
int vmmouse_init(struct psmouse *psmouse);
-#else
-static inline int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
-{
- return -ENOSYS;
-}
-static inline int vmmouse_init(struct psmouse *psmouse)
-{
- return -ENOSYS;
-}
-#endif
#endif
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index abd4944..bd415f4 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
* DEC VSXXX-GA mouse (rectangular mouse, with ball)
@@ -12,19 +13,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 412fa71..505c562 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input driver to ExplorerPS/2 device driver module.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -561,7 +558,7 @@
goto err_free_client;
file->private_data = client;
- nonseekable_open(inode, file);
+ stream_open(inode, file);
return 0;
diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
index fad2eae..a212ff7 100644
--- a/drivers/input/rmi4/Kconfig
+++ b/drivers/input/rmi4/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# RMI4 configuration
#
diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
index 8eeffa0..b7fe6eb 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.c
+++ b/drivers/input/rmi4/rmi_2d_sensor.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
@@ -207,7 +204,6 @@
if (sensor->topbuttonpad)
set_bit(INPUT_PROP_TOPBUTTONPAD, input->propbit);
}
-EXPORT_SYMBOL_GPL(rmi_2d_sensor_set_input_params);
int rmi_2d_sensor_configure_input(struct rmi_function *fn,
struct rmi_2d_sensor *sensor)
diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h
index c871bef..7d335d8 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.h
+++ b/drivers/input/rmi4/rmi_2d_sensor.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _RMI_2D_SENSOR_H
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index bd0d5ff..af706a5 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index 96383ea..25df632 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _RMI_BUS_H
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index fc3ab93..190b997 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
@@ -8,10 +9,6 @@
*
* http://www.synaptics.com/sites/default/files/
* 511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/bitmap.h>
@@ -149,7 +146,7 @@
}
mutex_lock(&data->irq_mutex);
- bitmap_and(data->irq_status, data->irq_status, data->current_irq_mask,
+ bitmap_and(data->irq_status, data->irq_status, data->fn_irq_bits,
data->irq_count);
/*
* At this point, irq_status has all bits that are set in the
@@ -388,6 +385,8 @@
bitmap_copy(data->current_irq_mask, data->new_irq_mask,
data->num_of_irq_regs);
+ bitmap_or(data->fn_irq_bits, data->fn_irq_bits, mask, data->irq_count);
+
error_unlock:
mutex_unlock(&data->irq_mutex);
return error;
@@ -401,6 +400,8 @@
struct device *dev = &rmi_dev->dev;
mutex_lock(&data->irq_mutex);
+ bitmap_andnot(data->fn_irq_bits,
+ data->fn_irq_bits, mask, data->irq_count);
bitmap_andnot(data->new_irq_mask,
data->current_irq_mask, mask, data->irq_count);
@@ -860,7 +861,7 @@
error = rmi_register_function(fn);
if (error)
- goto err_put_fn;
+ return error;
if (pdt->function_number == 0x01)
data->f01_container = fn;
@@ -870,10 +871,6 @@
list_add_tail(&fn->node, &data->function_list);
return RMI_SCAN_CONTINUE;
-
-err_put_fn:
- put_device(&fn->dev);
- return error;
}
void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake)
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index d31793a..65bfaa9 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _RMI_DRIVER_H
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index 4edaa14..e623c95 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
index aaa1edc..c194b16 100644
--- a/drivers/input/rmi4/rmi_f03.c
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015-2016 Red Hat
* Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index df64d6a..bbf9ae9 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2015 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
@@ -513,7 +510,6 @@
struct rmi_2d_sensor_platform_data sensor_pdata;
unsigned long *abs_mask;
unsigned long *rel_mask;
- unsigned long *result_bits;
};
enum f11_finger_state {
@@ -1060,7 +1056,7 @@
/*
** init instance data, fill in values and create any sysfs files
*/
- f11 = devm_kzalloc(&fn->dev, sizeof(struct f11_data) + mask_size * 3,
+ f11 = devm_kzalloc(&fn->dev, sizeof(struct f11_data) + mask_size * 2,
GFP_KERNEL);
if (!f11)
return -ENOMEM;
@@ -1079,8 +1075,6 @@
+ sizeof(struct f11_data));
f11->rel_mask = (unsigned long *)((char *)f11
+ sizeof(struct f11_data) + mask_size);
- f11->result_bits = (unsigned long *)((char *)f11
- + sizeof(struct f11_data) + mask_size * 2);
set_bit(fn->irq_pos, f11->abs_mask);
set_bit(fn->irq_pos + 1, f11->rel_mask);
@@ -1230,7 +1224,7 @@
}
rc = f11_write_control_regs(fn, &f11->sens_query,
- &f11->dev_controls, fn->fd.query_base_addr);
+ &f11->dev_controls, fn->fd.control_base_addr);
if (rc)
dev_warn(&fn->dev, "Failed to write control registers\n");
@@ -1287,8 +1281,8 @@
valid_bytes = f11->sensor.attn_size;
memcpy(f11->sensor.data_pkt, drvdata->attn_data.data,
valid_bytes);
- drvdata->attn_data.data += f11->sensor.attn_size;
- drvdata->attn_data.size -= f11->sensor.attn_size;
+ drvdata->attn_data.data += valid_bytes;
+ drvdata->attn_data.size -= valid_bytes;
} else {
error = rmi_read_block(rmi_dev,
data_base_addr, f11->sensor.data_pkt,
diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
index 5c7f489..7e97944 100644
--- a/drivers/input/rmi4/rmi_f12.c
+++ b/drivers/input/rmi4/rmi_f12.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2016 Synaptics Incorporated
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/input.h>
#include <linux/input/mt.h>
@@ -58,6 +55,9 @@
const struct rmi_register_desc_item *data15;
u16 data15_offset;
+
+ unsigned long *abs_mask;
+ unsigned long *rel_mask;
};
static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
@@ -73,7 +73,6 @@
int pitch_y = 0;
int rx_receivers = 0;
int tx_receivers = 0;
- int sensor_flags = 0;
item = rmi_get_register_desc_item(&f12->control_reg_desc, 8);
if (!item) {
@@ -129,10 +128,9 @@
offset += 2;
}
- if (rmi_register_desc_has_subpacket(item, 4)) {
- sensor_flags = buf[offset];
+ /* Skip over sensor flags */
+ if (rmi_register_desc_has_subpacket(item, 4))
offset += 1;
- }
sensor->x_mm = (pitch_x * rx_receivers) >> 12;
sensor->y_mm = (pitch_y * tx_receivers) >> 12;
@@ -214,8 +212,8 @@
valid_bytes = sensor->attn_size;
memcpy(sensor->data_pkt, drvdata->attn_data.data,
valid_bytes);
- drvdata->attn_data.data += sensor->attn_size;
- drvdata->attn_data.size -= sensor->attn_size;
+ drvdata->attn_data.data += valid_bytes;
+ drvdata->attn_data.size -= valid_bytes;
} else {
retval = rmi_read_block(rmi_dev, f12->data_addr,
sensor->data_pkt, sensor->pkt_size);
@@ -296,9 +294,18 @@
static int rmi_f12_config(struct rmi_function *fn)
{
struct rmi_driver *drv = fn->rmi_dev->driver;
+ struct f12_data *f12 = dev_get_drvdata(&fn->dev);
+ struct rmi_2d_sensor *sensor;
int ret;
- drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+ sensor = &f12->sensor;
+
+ if (!sensor->report_abs)
+ drv->clear_irq_bits(fn->rmi_dev, f12->abs_mask);
+ else
+ drv->set_irq_bits(fn->rmi_dev, f12->abs_mask);
+
+ drv->clear_irq_bits(fn->rmi_dev, f12->rel_mask);
ret = rmi_f12_write_control_regs(fn);
if (ret)
@@ -320,9 +327,12 @@
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
u16 data_offset = 0;
+ int mask_size;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
+ mask_size = BITS_TO_LONGS(drvdata->irq_count) * sizeof(unsigned long);
+
ret = rmi_read(fn->rmi_dev, query_addr, &buf);
if (ret < 0) {
dev_err(&fn->dev, "Failed to read general info register: %d\n",
@@ -337,10 +347,19 @@
return -ENODEV;
}
- f12 = devm_kzalloc(&fn->dev, sizeof(struct f12_data), GFP_KERNEL);
+ f12 = devm_kzalloc(&fn->dev, sizeof(struct f12_data) + mask_size * 2,
+ GFP_KERNEL);
if (!f12)
return -ENOMEM;
+ f12->abs_mask = (unsigned long *)((char *)f12
+ + sizeof(struct f12_data));
+ f12->rel_mask = (unsigned long *)((char *)f12
+ + sizeof(struct f12_data) + mask_size);
+
+ set_bit(fn->irq_pos, f12->abs_mask);
+ set_bit(fn->irq_pos + 1, f12->rel_mask);
+
f12->has_dribble = !!(buf & BIT(3));
if (fn->dev.of_node) {
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index 5e3ed5a..a90dad1 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2016 Synaptics Incorporated
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
index 87a7d4b..e5dca98 100644
--- a/drivers/input/rmi4/rmi_f34.c
+++ b/drivers/input/rmi4/rmi_f34.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2007-2016, Synaptics Incorporated
* Copyright (C) 2016 Zodiac Inflight Innovations
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h
index 32c4e95..99faa8c 100644
--- a/drivers/input/rmi4/rmi_f34.h
+++ b/drivers/input/rmi4/rmi_f34.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2007-2016, Synaptics Incorporated
* Copyright (C) 2016 Zodiac Inflight Innovations
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#ifndef _RMI_F34_H
diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c
index 3991d29..a4cabf5 100644
--- a/drivers/input/rmi4/rmi_f34v7.c
+++ b/drivers/input/rmi4/rmi_f34v7.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016, Zodiac Inflight Innovations
* Copyright (c) 2007-2016, Synaptics Incorporated
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index a6f515b..897105b 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2015 Synaptics Incorporated
* Copyright (C) 2016 Zodiac Inflight Innovations
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
@@ -362,7 +359,7 @@
static const struct vb2_queue rmi_f54_queue = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ,
- .buf_struct_size = sizeof(struct vb2_buffer),
+ .buf_struct_size = sizeof(struct vb2_v4l2_buffer),
.ops = &rmi_f54_queue_ops,
.mem_ops = &vb2_vmalloc_memops,
.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
@@ -456,25 +453,15 @@
static int rmi_f54_vidioc_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *fmt)
{
+ struct f54_data *f54 = video_drvdata(file);
+
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- switch (fmt->index) {
- case 0:
- fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
- break;
-
- case 1:
- fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD08;
- break;
-
- case 2:
- fmt->pixelformat = V4L2_TCH_FMT_TU16;
- break;
-
- default:
+ if (fmt->index)
return -EINVAL;
- }
+
+ fmt->pixelformat = f54->format.pixelformat;
return 0;
}
@@ -614,7 +601,7 @@
{
struct rmi_driver *drv = fn->rmi_dev->driver;
- drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+ drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
return 0;
}
@@ -692,6 +679,7 @@
return -ENOMEM;
rmi_f54_create_input_map(f54);
+ rmi_f54_set_input(f54, 0);
/* register video device */
strlcpy(f54->v4l2.name, F54_NAME, sizeof(f54->v4l2.name));
@@ -742,6 +730,7 @@
video_unregister_device(&f54->vdev);
v4l2_device_unregister(&f54->v4l2);
+ destroy_workqueue(f54->workqueue);
}
struct rmi_function_handler rmi_f54_handler = {
diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c
index 37390ca..488adac 100644
--- a/drivers/input/rmi4/rmi_f55.c
+++ b/drivers/input/rmi4/rmi_f55.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2015 Synaptics Incorporated
* Copyright (C) 2016 Zodiac Inflight Innovations
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index d4b3f9d..a95c2c9 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/i2c.h>
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
index b6ccf39..2407ea4 100644
--- a/drivers/input/rmi4/rmi_smbus.c
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015 - 2016 Red Hat, Inc
* Copyright (c) 2011, 2012 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c
index 33b8c6e..27b68dc 100644
--- a/drivers/input/rmi4/rmi_spi.c
+++ b/drivers/input/rmi4/rmi_spi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index d90d9f1..f3e18f8 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Input core configuration
#
@@ -254,7 +255,7 @@
config SERIO_OLPC_APSP
tristate "OLPC AP-SP input support"
- depends on OLPC || COMPILE_TEST
+ depends on ARCH_MMP || COMPILE_TEST
help
Say Y here if you want support for the keyboard and touchpad included
in the OLPC XO-1.75 and XO-4 laptops.
diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c
index 131d782..379e924 100644
--- a/drivers/input/serio/altera_ps2.c
+++ b/drivers/input/serio/altera_ps2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Altera University Program PS2 controller driver
*
@@ -5,10 +6,6 @@
*
* Based on sa1111ps2.c, which is:
* Copyright (C) 2002 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index ff3875c..ecdeca1 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/input/serio/ambakmi.c
*
* Copyright (C) 2000-2003 Deep Blue Solutions Ltd.
* Copyright (C) 2002 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/serio.h>
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c
index f8663d7..1c0be29 100644
--- a/drivers/input/serio/ams_delta_serio.c
+++ b/drivers/input/serio/ams_delta_serio.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Amstrad E3 (Delta) keyboard port driver
*
* Copyright (c) 2006 Matt Callow
* Copyright (c) 2010 Janusz Krzysztofik
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
* Thanks to Cliff Lawson for his help
*
* The Amstrad Delta keyboard (aka mailboard) uses normal PC-AT style serial
diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c
index 45d4e08..f290d5d 100644
--- a/drivers/input/serio/apbps2.c
+++ b/drivers/input/serio/apbps2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2013 Aeroflex Gaisler
*
@@ -10,11 +11,6 @@
* See "Documentation/devicetree/bindings/input/ps2keyb-mouse-apbps2.txt" for
* information on open firmware properties.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
* Contributors: Daniel Hellstrom <daniel@gaisler.com>
*/
#include <linux/platform_device.h>
diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c
index 99e57a4..0af9fba 100644
--- a/drivers/input/serio/arc_ps2.c
+++ b/drivers/input/serio/arc_ps2.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Driver is originally developed by Pavel Sokolov <psokolov@synopsys.com>
*/
@@ -190,10 +187,8 @@
int error, id, i;
irq = platform_get_irq_byname(pdev, "arc_ps2_irq");
- if (irq < 0) {
- dev_err(&pdev->dev, "no IRQ defined\n");
+ if (irq < 0)
return -EINVAL;
- }
arc_ps2 = devm_kzalloc(&pdev->dev, sizeof(struct arc_ps2_data),
GFP_KERNEL);
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
index 2d1e299..d45009d 100644
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/delay.h>
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 49d8d53..96f9b53 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -381,9 +381,9 @@
goto fail;
#endif
- printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n",
+ pr_info("serio: %s port at 0x%08lx irq %d @ %s\n",
ps2port->port->name,
- ps2port->addr,
+ hpa,
ps2port->padev->irq,
ps2port->port->phys);
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 0b8a25c..6542523 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -884,8 +884,8 @@
"HP SDC NMI", &hp_sdc))
goto err2;
- printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n",
- (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
+ pr_info(PREFIX "HP SDC at 0x%08lx, IRQ %d (NMI IRQ %d)\n",
+ hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
hp_sdc_status_in8();
hp_sdc_data_in8();
diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c
index a8b9be3..e486a8a 100644
--- a/drivers/input/serio/hyperv-keyboard.c
+++ b/drivers/input/serio/hyperv-keyboard.c
@@ -1,14 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
*/
#include <linux/init.h>
@@ -83,8 +75,8 @@
#define HK_MAXIMUM_MESSAGE_SIZE 256
-#define KBD_VSC_SEND_RING_BUFFER_SIZE (10 * PAGE_SIZE)
-#define KBD_VSC_RECV_RING_BUFFER_SIZE (10 * PAGE_SIZE)
+#define KBD_VSC_SEND_RING_BUFFER_SIZE (40 * 1024)
+#define KBD_VSC_RECV_RING_BUFFER_SIZE (40 * 1024)
#define XTKBD_EMUL0 0xe0
#define XTKBD_EMUL1 0xe1
@@ -245,40 +237,17 @@
static void hv_kbd_on_channel_callback(void *context)
{
+ struct vmpacket_descriptor *desc;
struct hv_device *hv_dev = context;
- void *buffer;
- int bufferlen = 0x100; /* Start with sensible size */
u32 bytes_recvd;
u64 req_id;
- int error;
- buffer = kmalloc(bufferlen, GFP_ATOMIC);
- if (!buffer)
- return;
+ foreach_vmbus_pkt(desc, hv_dev->channel) {
+ bytes_recvd = desc->len8 * 8;
+ req_id = desc->trans_id;
- while (1) {
- error = vmbus_recvpacket_raw(hv_dev->channel, buffer, bufferlen,
- &bytes_recvd, &req_id);
- switch (error) {
- case 0:
- if (bytes_recvd == 0) {
- kfree(buffer);
- return;
- }
-
- hv_kbd_handle_received_packet(hv_dev, buffer,
- bytes_recvd, req_id);
- break;
-
- case -ENOBUFS:
- kfree(buffer);
- /* Handle large packet */
- bufferlen = bytes_recvd;
- buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
- if (!buffer)
- return;
- break;
- }
+ hv_kbd_handle_received_packet(hv_dev, desc, bytes_recvd,
+ req_id);
}
}
@@ -440,5 +409,7 @@
}
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Keyboard Driver");
+
module_init(hv_kbd_init);
module_exit(hv_kbd_exit);
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index 34da81c..da0bf85 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_IO_H
#define _I8042_IO_H
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* Names.
diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h
index 08a1c10..6c7efa0 100644
--- a/drivers/input/serio/i8042-ip22io.h
+++ b/drivers/input/serio/i8042-ip22io.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_IP22_H
#define _I8042_IP22_H
#include <asm/sgi/ioc.h>
#include <asm/sgi/ip22.h>
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* Names.
diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h
index 13fd710..4c2a96f 100644
--- a/drivers/input/serio/i8042-jazzio.h
+++ b/drivers/input/serio/i8042-jazzio.h
@@ -1,13 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_JAZZ_H
#define _I8042_JAZZ_H
#include <asm/jazz.h>
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* Names.
diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
index 1aabea4..391f94d 100644
--- a/drivers/input/serio/i8042-ppcio.h
+++ b/drivers/input/serio/i8042-ppcio.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_PPCIO_H
#define _I8042_PPCIO_H
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
#if defined(CONFIG_WALNUT)
diff --git a/drivers/input/serio/i8042-snirm.h b/drivers/input/serio/i8042-snirm.h
index 409a934..4b71367 100644
--- a/drivers/input/serio/i8042-snirm.h
+++ b/drivers/input/serio/i8042-snirm.h
@@ -1,13 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_SNIRM_H
#define _I8042_SNIRM_H
#include <asm/sni.h>
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* Names.
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index 7962898..fce7681 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -53,12 +53,11 @@
static int sparc_i8042_probe(struct platform_device *op)
{
- struct device_node *dp = op->dev.of_node;
+ struct device_node *dp;
- dp = dp->child;
- while (dp) {
- if (!strcmp(dp->name, OBP_PS2KBD_NAME1) ||
- !strcmp(dp->name, OBP_PS2KBD_NAME2)) {
+ for_each_child_of_node(op->dev.of_node, dp) {
+ if (of_node_name_eq(dp, OBP_PS2KBD_NAME1) ||
+ of_node_name_eq(dp, OBP_PS2KBD_NAME2)) {
struct platform_device *kbd = of_find_device_by_node(dp);
unsigned int irq = kbd->archdata.irqs[0];
if (irq == 0xffffffff)
@@ -67,16 +66,14 @@
kbd_iobase = of_ioremap(&kbd->resource[0],
0, 8, "kbd");
kbd_res = &kbd->resource[0];
- } else if (!strcmp(dp->name, OBP_PS2MS_NAME1) ||
- !strcmp(dp->name, OBP_PS2MS_NAME2)) {
+ } else if (of_node_name_eq(dp, OBP_PS2MS_NAME1) ||
+ of_node_name_eq(dp, OBP_PS2MS_NAME2)) {
struct platform_device *ms = of_find_device_by_node(dp);
unsigned int irq = ms->archdata.irqs[0];
if (irq == 0xffffffff)
irq = op->archdata.irqs[0];
i8042_aux_irq = irq;
}
-
- dp = dp->sibling;
}
return 0;
@@ -109,8 +106,9 @@
static int __init i8042_platform_init(void)
{
struct device_node *root = of_find_node_by_path("/");
+ const char *name = of_get_property(root, "name", NULL);
- if (!strcmp(root->name, "SUNW,JavaStation-1")) {
+ if (name && !strcmp(name, "SUNW,JavaStation-1")) {
/* Hardcoded values for MrCoffee. */
i8042_kbd_irq = i8042_aux_irq = 13 | 0x20;
kbd_iobase = ioremap(0x71300060, 8);
@@ -139,8 +137,9 @@
static inline void i8042_platform_exit(void)
{
struct device_node *root = of_find_node_by_path("/");
+ const char *name = of_get_property(root, "name", NULL);
- if (strcmp(root->name, "SUNW,JavaStation-1"))
+ if (!name || strcmp(name, "SUNW,JavaStation-1"))
platform_driver_unregister(&sparc_i8042_driver);
}
diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h
index 4557475..50bb3ed 100644
--- a/drivers/input/serio/i8042-unicore32io.h
+++ b/drivers/input/serio/i8042-unicore32io.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Code specific to PKUnity SoC and UniCore ISA
*
* Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
* Copyright (C) 2001-2011 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _I8042_UNICORE32_H
#define _I8042_UNICORE32_H
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 136f6e7..dc974c2 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_X86IA64IO_H
#define _I8042_X86IA64IO_H
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
#ifdef CONFIG_X86
#include <asm/x86_init.h>
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 95a78cc..20ff2be 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* i8042 keyboard and mouse controller driver for Linux
*
* Copyright (c) 1999-2004 Vojtech Pavlik
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -436,6 +432,20 @@
{
struct i8042_port *port = serio->port_data;
+ device_set_wakeup_capable(&serio->dev, true);
+
+ /*
+ * On platforms using suspend-to-idle, allow the keyboard to
+ * wake up the system from sleep by enabling keyboard wakeups
+ * by default. This is consistent with keyboard wakeup
+ * behavior on many platforms using suspend-to-RAM (ACPI S3)
+ * by default.
+ */
+ if (pm_suspend_default_s2idle() &&
+ serio == i8042_ports[I8042_KBD_PORT_NO].serio) {
+ device_set_wakeup_enable(&serio->dev, true);
+ }
+
spin_lock_irq(&i8042_lock);
port->exists = true;
spin_unlock_irq(&i8042_lock);
@@ -573,9 +583,6 @@
port = &i8042_ports[port_no];
serio = port->exists ? port->serio : NULL;
- if (irq && serio)
- pm_wakeup_event(&serio->dev, 0);
-
filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n",
port_no, irq,
dfl & SERIO_PARITY ? ", bad parity" : "",
@@ -1404,17 +1411,6 @@
(unsigned long) I8042_COMMAND_REG,
i8042_ports[i].irq);
serio_register_port(serio);
- device_set_wakeup_capable(&serio->dev, true);
-
- /*
- * On platforms using suspend-to-idle, allow the keyboard to
- * wake up the system from sleep by enabling keyboard wakeups
- * by default. This is consistent with keyboard wakeup
- * behavior on many platforms using suspend-to-RAM (ACPI S3)
- * by default.
- */
- if (pm_suspend_via_s2idle() && i == I8042_KBD_PORT_NO)
- device_set_wakeup_enable(&serio->dev, true);
}
}
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index 1db0a40..38dc27a 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _I8042_H
#define _I8042_H
/*
* Copyright (c) 1999-2002 Vojtech Pavlik
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
/*
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index e6a07e6..a8c94a9 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PS/2 driver library
*
@@ -5,11 +6,6 @@
* Copyright (c) 2004 Dmitry Torokhov
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
#include <linux/delay.h>
#include <linux/module.h>
@@ -409,6 +405,7 @@
ps2dev->nak = PS2_RET_ERR;
break;
}
+ /* Fall through */
/*
* Workaround for mice which don't ACK the Get ID command.
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
index e365c5f..629e150 100644
--- a/drivers/input/serio/maceps2.c
+++ b/drivers/input/serio/maceps2.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SGI O2 MACE PS2 controller driver for linux
*
* Copyright (C) 2002 Vivien Chappelier
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation
*/
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c
index 8e9a420..59de8d9 100644
--- a/drivers/input/serio/olpc_apsp.c
+++ b/drivers/input/serio/olpc_apsp.c
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OLPC serio driver for multiplexed input from Marvell MMP security processor
*
* Copyright (C) 2011-2013 One Laptop Per Child
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
*/
#include <linux/module.h>
@@ -145,8 +136,15 @@
{
struct olpc_apsp *priv = port->port_data;
unsigned int tmp;
+ unsigned long l;
if (priv->open_count++ == 0) {
+ l = readl(priv->base + COMMAND_FIFO_STATUS);
+ if (!(l & CMD_STS_MASK)) {
+ dev_err(priv->dev, "SP cannot accept commands.\n");
+ return -EIO;
+ }
+
/* Enable interrupt 0 by clearing its bit */
tmp = readl(priv->base + PJ_INTERRUPT_MASK);
writel(tmp & ~INT_0, priv->base + PJ_INTERRUPT_MASK);
@@ -172,15 +170,14 @@
struct serio *kb_serio, *pad_serio;
struct olpc_apsp *priv;
struct resource *res;
- struct device_node *np;
- unsigned long l;
int error;
priv = devm_kzalloc(&pdev->dev, sizeof(struct olpc_apsp), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- np = pdev->dev.of_node;
+ priv->dev = &pdev->dev;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->base)) {
@@ -192,12 +189,6 @@
if (priv->irq < 0)
return priv->irq;
- l = readl(priv->base + COMMAND_FIFO_STATUS);
- if (!(l & CMD_STS_MASK)) {
- dev_err(&pdev->dev, "SP cannot accept commands.\n");
- return -EIO;
- }
-
/* KEYBOARD */
kb_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!kb_serio)
@@ -236,7 +227,6 @@
goto err_irq;
}
- priv->dev = &pdev->dev;
device_init_wakeup(priv->dev, 1);
platform_set_drvdata(pdev, priv);
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
index 1edfac7..ddbbd4a 100644
--- a/drivers/input/serio/parkbd.c
+++ b/drivers/input/serio/parkbd.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Parallel port to Keyboard port adapter driver for Linux
*
* Copyright (c) 1999-2004 Vojtech Pavlik
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* To connect an AT or XT keyboard to the parallel port, a fairly simple adapter
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index e862c6e..bedf75d 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/input/serio/pcips2.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
* I'm not sure if this is a generic PS/2 PCI interface or specific to
* the Mobility Electronics docking station.
*/
diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c
index c62cceb..8970b49 100644
--- a/drivers/input/serio/ps2-gpio.c
+++ b/drivers/input/serio/ps2-gpio.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO based serio bus driver for bit banging the PS/2 protocol
*
* Author: Danilo Krummrich <danilokrummrich@dk-develop.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/gpio/consumer.h>
@@ -76,6 +73,7 @@
{
struct ps2_gpio_data *drvdata = serio->port_data;
+ flush_delayed_work(&drvdata->tx_work);
disable_irq(drvdata->irq);
}
@@ -371,8 +369,6 @@
drvdata->irq = platform_get_irq(pdev, 0);
if (drvdata->irq < 0) {
- dev_err(dev, "failed to get irq from platform resource: %d\n",
- drvdata->irq);
error = drvdata->irq;
goto err_free_serio;
}
diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
index a76fb64..0071dd5 100644
--- a/drivers/input/serio/ps2mult.c
+++ b/drivers/input/serio/ps2mult.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TQC PS/2 Multiplexer driver
*
* Copyright (C) 2010 Dmitry Eremin-Solenikov
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index fbb6b33..bd24839 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
@@ -10,19 +11,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index a308d78..37fe6a5 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2002 Russell King
@@ -8,19 +9,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index f9e5c79..7b8ceb7 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/input/serio/sa1111ps2.c
*
* Copyright (C) 2002 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
*/
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 2e1fb06..29f4910 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* The Serio abstraction module
*
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 17b7fbe..e9647eb 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Raw serio device providing access to a raw byte stream from underlying
* serio port. Closely emulates behavior of pre-2.6 /dev/psaux device
*
* Copyright (c) 2004 Dmitry Torokhov
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/kref.h>
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index f8ead9f..8ac970a 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Input device TTY line discipline
*
@@ -7,11 +8,6 @@
* 'serial io port' abstraction that the input device drivers use.
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
#include <linux/uaccess.h>
#include <linux/kernel.h>
@@ -226,7 +222,7 @@
#ifdef CONFIG_COMPAT
#define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t)
-static long serport_ldisc_compat_ioctl(struct tty_struct *tty,
+static int serport_ldisc_compat_ioctl(struct tty_struct *tty,
struct file *file,
unsigned int cmd, unsigned long arg)
{
diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
index 04b96fe..a681a2c 100644
--- a/drivers/input/serio/sun4i-ps2.c
+++ b/drivers/input/serio/sun4i-ps2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Allwinner A10 PS2 host controller
*
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index 07de1b4..960d760 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Xilinx XPS PS/2 device driver
*
* (c) 2005 MontaVista Software, Inc.
* (c) 2008 Xilinx, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * 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.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
*/
@@ -245,7 +237,7 @@
unsigned int irq;
int error;
- dev_info(dev, "Device Tree Probing \'%s\'\n", dev->of_node->name);
+ dev_info(dev, "Device Tree Probing \'%pOFn\'\n", dev->of_node);
/* Get iospace for the device */
error = of_address_to_resource(dev->of_node, 0, &r_mem);
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index 0cad5e7..530fd15 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic support for sparse keymaps
*
@@ -7,10 +8,6 @@
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
* Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
* Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/input.h>
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
index a2b9f97..e4c0d9a 100644
--- a/drivers/input/tablet/Kconfig
+++ b/drivers/input/tablet/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Tablet driver configuration
#
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
index a86255d..a38d1fe 100644
--- a/drivers/input/tablet/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2001-2005 Edouard TISSERANT <edouard.tisserant@wanadoo.fr>
* Copyright (c) 2004-2005 Stephane VOLTZ <svoltz@numericable.fr>
@@ -9,20 +10,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index c82cd50..2ca586f 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Native support for the Aiptek HyperPen USB Tablets
* (4000U/5000U/6000U/8000U/12000U)
@@ -54,20 +55,6 @@
* so therefore it's easier to document them all as one subsystem.
* Please visit the project's "home page", located at,
* http://aiptektablet.sourceforge.net.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/jiffies.h>
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 4b8b9d7..3503122 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -78,6 +78,7 @@
/* Max size of a single report */
#define REPORT_MAX_SIZE 10
+#define MAX_COLLECTION_LEVELS 10
/* Bitmask whether pen is in range */
@@ -223,8 +224,7 @@
char maintype = 'x';
char globtype[12];
int indent = 0;
- char indentstr[10] = "";
-
+ char indentstr[MAX_COLLECTION_LEVELS + 1] = { 0 };
dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n");
@@ -350,6 +350,13 @@
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");
@@ -369,8 +376,15 @@
break;
case TAG_MAIN_COL_END:
- dev_dbg(ddev, "<<<<<<======\n");
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] = '-';
diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c
index 4042c41..6d58443 100644
--- a/drivers/input/tablet/hanwang.c
+++ b/drivers/input/tablet/hanwang.c
@@ -1,25 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* USB Hanwang tablet support
*
* Copyright (c) 2010 Xing Wei <weixing@hanwang.com.cn>
- *
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/types.h>
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index 75b5006..aa57789 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -116,6 +117,10 @@
if (intf->cur_altsetting->desc.bNumEndpoints < 1)
return -ENODEV;
+ endpoint = &intf->cur_altsetting->endpoint[0].desc;
+ if (!usb_endpoint_is_int_in(endpoint))
+ return -ENODEV;
+
kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
input_dev = input_allocate_device();
if (!kbtab || !input_dev)
@@ -154,8 +159,6 @@
input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0);
- endpoint = &intf->cur_altsetting->endpoint[0].desc;
-
usb_fill_int_urb(kbtab->irq, dev,
usb_rcvintpipe(dev, endpoint->bEndpointAddress),
kbtab->data, 8,
diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c
index ffd03cf..a1f3a0c 100644
--- a/drivers/input/tablet/pegasus_notetaker.c
+++ b/drivers/input/tablet/pegasus_notetaker.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Pegasus Mobile Notetaker Pen input tablet driver
*
diff --git a/drivers/input/tablet/wacom_serial4.c b/drivers/input/tablet/wacom_serial4.c
index 38bfaca..959c1d8 100644
--- a/drivers/input/tablet/wacom_serial4.c
+++ b/drivers/input/tablet/wacom_serial4.c
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Wacom protocol 4 serial tablet driver
*
* Copyright 2014 Hans de Goede <hdegoede@redhat.com>
* Copyright 2011-2012 Julian Squires <julian@cipht.net>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version of 2 of the License, or (at your
- * option) any later version. See the file COPYING in the main directory of
- * this archive for more details.
- *
* Many thanks to Bill Seremetis, without whom PenPartner support
* would not have been possible. Thanks to Patrick Mahoney.
*
@@ -187,6 +182,7 @@
MODEL_DIGITIZER_II = 0x5544, /* UD */
MODEL_GRAPHIRE = 0x4554, /* ET */
MODEL_PENPARTNER = 0x4354, /* CT */
+ MODEL_ARTPAD_II = 0x4B54, /* KT */
};
static void wacom_handle_model_response(struct wacom *wacom)
@@ -245,6 +241,7 @@
wacom->flags = F_HAS_STYLUS2 | F_HAS_SCROLLWHEEL;
break;
+ case MODEL_ARTPAD_II:
case MODEL_DIGITIZER_II:
wacom->dev->name = "Wacom Digitizer II";
wacom->dev->id.version = MODEL_DIGITIZER_II;
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
index 3486d94..81a3ea4 100644
--- a/drivers/input/touchscreen/88pm860x-ts.c
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchscreen driver for Marvell 88PM860x
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -188,10 +185,8 @@
int irq, ret, res_x = 0, data = 0;
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "No IRQ resource!\n");
+ if (irq < 0)
return -EINVAL;
- }
if (pm860x_touch_dt_init(pdev, chip, &res_x)) {
if (pdata) {
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 2a80675..46ad909 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Touchscreen driver configuration
#
@@ -696,6 +697,19 @@
To compile this driver as a module, choose M here: the
module will be called edt-ft5x06.
+config TOUCHSCREEN_RASPBERRYPI_FW
+ tristate "Raspberry Pi's firmware base touch screen support"
+ depends on RASPBERRYPI_FIRMWARE || (RASPBERRYPI_FIRMWARE=n && COMPILE_TEST)
+ select INPUT_POLLDEV
+ help
+ Say Y here if you have the official Raspberry Pi 7 inch screen on
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called raspberrypi-ts.
+
config TOUCHSCREEN_MIGOR
tristate "Renesas MIGO-R touchscreen"
depends on (SH_MIGOR || COMPILE_TEST) && I2C
@@ -1098,15 +1112,6 @@
or ambient light monitoring), temperature and raw input
values.
-config TOUCHSCREEN_W90X900
- tristate "W90P910 touchscreen driver"
- depends on ARCH_W90X900
- help
- Say Y here if you have a W90P910 based touchscreen.
-
- To compile this driver as a module, choose M here: the
- module will be called w90p910_ts.
-
config TOUCHSCREEN_PCAP
tristate "Motorola PCAP touchscreen"
depends on EZX_PCAP
@@ -1156,11 +1161,11 @@
module will be called sis_i2c.
config TOUCHSCREEN_ST1232
- tristate "Sitronix ST1232 touchscreen controllers"
+ tristate "Sitronix ST1232 or ST1633 touchscreen controllers"
depends on I2C
help
- Say Y here if you want to support Sitronix ST1232
- touchscreen controller.
+ Say Y here if you want to support the Sitronix ST1232
+ or ST1633 touchscreen controller.
If unsure, say N.
@@ -1299,4 +1304,14 @@
To compile this driver as a module, choose M here: the
module will be called bu21023_ts.
+config TOUCHSCREEN_IQS5XX
+ tristate "Azoteq IQS550/572/525 trackpad/touchscreen controller"
+ depends on I2C
+ help
+ Say Y to enable support for the Azoteq IQS550/572/525
+ family of trackpad/touchscreen controllers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iqs5xx.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 5911a41..94c6162 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -102,10 +102,11 @@
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
-obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_ZET6223) += zet6223.o
obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
+obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o
+obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index 5cfe477..9b652f6 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2006-2008 Michael Hennerich, Analog Devices Inc.
*
@@ -6,21 +7,6 @@
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
* History:
* Copyright (c) 2005 David Brownell
* Copyright (c) 2006 Nokia Corporation
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
index 49b902b..0f20a1f 100644
--- a/drivers/input/touchscreen/ad7879-i2c.c
+++ b/drivers/input/touchscreen/ad7879-i2c.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AD7879-1/AD7889-1 touchscreen (I2C bus)
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_I2C */
diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c
index 3457a56..50e8898 100644
--- a/drivers/input/touchscreen/ad7879-spi.c
+++ b/drivers/input/touchscreen/ad7879-spi.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AD7879/AD7889 touchscreen (SPI bus)
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_SPI */
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 6bad23e..556a2af 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AD7879/AD7889 based touchscreen and GPIO driver
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
- * Licensed under the GPL-2 or later.
- *
* History:
* Copyright (c) 2005 David Brownell
* Copyright (c) 2006 Nokia Corporation
@@ -29,10 +28,9 @@
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/input/touchscreen.h>
-#include <linux/platform_data/ad7879.h>
#include <linux/module.h>
#include "ad7879.h"
@@ -247,11 +245,14 @@
static irqreturn_t ad7879_irq(int irq, void *handle)
{
struct ad7879 *ts = handle;
+ int error;
- regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS,
- ts->conversion_data, AD7879_NR_SENSE);
-
- if (!ad7879_report(ts))
+ error = regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS,
+ ts->conversion_data, AD7879_NR_SENSE);
+ if (error)
+ dev_err_ratelimited(ts->dev, "failed to read %#02x: %d\n",
+ AD7879_REG_XPLUS, error);
+ else if (!ad7879_report(ts))
mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
return IRQ_HANDLED;
@@ -290,7 +291,7 @@
return 0;
}
-static void ad7879_close(struct input_dev* input)
+static void ad7879_close(struct input_dev *input)
{
struct ad7879 *ts = input_get_drvdata(input);
@@ -452,47 +453,36 @@
mutex_unlock(&ts->mutex);
}
-static int ad7879_gpio_add(struct ad7879 *ts,
- const struct ad7879_platform_data *pdata)
+static int ad7879_gpio_add(struct ad7879 *ts)
{
- bool gpio_export;
- int gpio_base;
int ret = 0;
- if (pdata) {
- gpio_export = pdata->gpio_export;
- gpio_base = pdata->gpio_base;
- } else {
- gpio_export = device_property_read_bool(ts->dev,
- "gpio-controller");
- gpio_base = -1;
- }
-
mutex_init(&ts->mutex);
- if (gpio_export) {
- ts->gc.direction_input = ad7879_gpio_direction_input;
- ts->gc.direction_output = ad7879_gpio_direction_output;
- ts->gc.get = ad7879_gpio_get_value;
- ts->gc.set = ad7879_gpio_set_value;
- ts->gc.can_sleep = 1;
- ts->gc.base = gpio_base;
- ts->gc.ngpio = 1;
- ts->gc.label = "AD7879-GPIO";
- ts->gc.owner = THIS_MODULE;
- ts->gc.parent = ts->dev;
+ /* Do not create a chip unless flagged for it */
+ if (!device_property_read_bool(ts->dev, "gpio-controller"))
+ return 0;
- ret = devm_gpiochip_add_data(ts->dev, &ts->gc, ts);
- if (ret)
- dev_err(ts->dev, "failed to register gpio %d\n",
- ts->gc.base);
- }
+ ts->gc.direction_input = ad7879_gpio_direction_input;
+ ts->gc.direction_output = ad7879_gpio_direction_output;
+ ts->gc.get = ad7879_gpio_get_value;
+ ts->gc.set = ad7879_gpio_set_value;
+ ts->gc.can_sleep = 1;
+ ts->gc.base = -1;
+ ts->gc.ngpio = 1;
+ ts->gc.label = "AD7879-GPIO";
+ ts->gc.owner = THIS_MODULE;
+ ts->gc.parent = ts->dev;
+
+ ret = devm_gpiochip_add_data(ts->dev, &ts->gc, ts);
+ if (ret)
+ dev_err(ts->dev, "failed to register gpio %d\n",
+ ts->gc.base);
return ret;
}
#else
-static int ad7879_gpio_add(struct ad7879 *ts,
- const struct ad7879_platform_data *pdata)
+static int ad7879_gpio_add(struct ad7879 *ts)
{
return 0;
}
@@ -527,7 +517,6 @@
int ad7879_probe(struct device *dev, struct regmap *regmap,
int irq, u16 bustype, u8 devid)
{
- struct ad7879_platform_data *pdata = dev_get_platdata(dev);
struct ad7879 *ts;
struct input_dev *input_dev;
int err;
@@ -542,22 +531,9 @@
if (!ts)
return -ENOMEM;
- if (pdata) {
- /* Platform data use swapped axis (backward compatibility) */
- ts->swap_xy = !pdata->swap_xy;
-
- ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
-
- ts->first_conversion_delay = pdata->first_conversion_delay;
- ts->acquisition_time = pdata->acquisition_time;
- ts->averaging = pdata->averaging;
- ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
- ts->median = pdata->median;
- } else {
- err = ad7879_parse_dt(dev, ts);
- if (err)
- return err;
- }
+ err = ad7879_parse_dt(dev, ts);
+ if (err)
+ return err;
input_dev = devm_input_allocate_device(dev);
if (!input_dev) {
@@ -585,28 +561,13 @@
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
- if (pdata) {
- input_set_abs_params(input_dev, ABS_X,
- pdata->x_min ? : 0,
- pdata->x_max ? : MAX_12BIT,
- 0, 0);
- input_set_abs_params(input_dev, ABS_Y,
- pdata->y_min ? : 0,
- pdata->y_max ? : MAX_12BIT,
- 0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE,
- pdata->pressure_min,
- pdata->pressure_max ? : ~0,
- 0, 0);
- } else {
- input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
- input_set_capability(input_dev, EV_ABS, ABS_PRESSURE);
- touchscreen_parse_properties(input_dev, false, NULL);
- if (!input_abs_get_max(input_dev, ABS_PRESSURE)) {
- dev_err(dev, "Touchscreen pressure is not specified\n");
- return -EINVAL;
- }
+ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
+ input_set_capability(input_dev, EV_ABS, ABS_PRESSURE);
+ touchscreen_parse_properties(input_dev, false, NULL);
+ if (!input_abs_get_max(input_dev, ABS_PRESSURE)) {
+ dev_err(dev, "Touchscreen pressure is not specified\n");
+ return -EINVAL;
}
err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET);
@@ -655,7 +616,7 @@
if (err)
return err;
- err = ad7879_gpio_add(ts, pdata);
+ err = ad7879_gpio_add(ts);
if (err)
return err;
diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h
index 7e43066..ae8aa14 100644
--- a/drivers/input/touchscreen/ad7879.h
+++ b/drivers/input/touchscreen/ad7879.h
@@ -1,9 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* AD7879/AD7889 touchscreen (bus interfaces)
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#ifndef _AD7879_H_
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index a2f45ae..51ddb20 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ADS7846 based touchscreen and sensor driver
*
@@ -12,10 +13,6 @@
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/types.h>
#include <linux/hwmon.h>
@@ -23,6 +20,7 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/input.h>
+#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/pm.h>
@@ -132,6 +130,8 @@
u16 penirq_recheck_delay_usecs;
+ struct touchscreen_properties core_prop;
+
struct mutex lock;
bool stopped; /* P: lock */
bool disabled; /* P: lock */
@@ -826,17 +826,13 @@
if (Rt) {
struct input_dev *input = ts->input;
- if (ts->swap_xy)
- swap(x, y);
-
if (!ts->pendown) {
input_report_key(input, BTN_TOUCH, 1);
ts->pendown = true;
dev_vdbg(&ts->spi->dev, "DOWN\n");
}
- input_report_abs(input, ABS_X, x);
- input_report_abs(input, ABS_Y, y);
+ touchscreen_report_pos(input, &ts->core_prop, x, y, false);
input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt);
input_sync(input);
@@ -1188,6 +1184,7 @@
struct ads7846_platform_data *pdata;
struct device_node *node = dev->of_node;
const struct of_device_id *match;
+ u32 value;
if (!node) {
dev_err(dev, "Device does not have associated DT data\n");
@@ -1226,10 +1223,18 @@
of_property_read_u16(node, "ti,x-max", &pdata->x_max);
of_property_read_u16(node, "ti,y-max", &pdata->y_max);
+ /*
+ * touchscreen-max-pressure gets parsed during
+ * touchscreen_parse_properties()
+ */
of_property_read_u16(node, "ti,pressure-min", &pdata->pressure_min);
+ if (!of_property_read_u32(node, "touchscreen-min-pressure", &value))
+ pdata->pressure_min = (u16) value;
of_property_read_u16(node, "ti,pressure-max", &pdata->pressure_max);
of_property_read_u16(node, "ti,debounce-max", &pdata->debounce_max);
+ if (!of_property_read_u32(node, "touchscreen-average-samples", &value))
+ pdata->debounce_max = (u16) value;
of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol);
of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep);
@@ -1312,10 +1317,7 @@
ts->model = pdata->model ? : 7846;
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
- ts->pressure_max = pdata->pressure_max ? : ~0;
-
ts->vref_mv = pdata->vref_mv;
- ts->swap_xy = pdata->swap_xy;
if (pdata->filter != NULL) {
if (pdata->filter_init != NULL) {
@@ -1367,6 +1369,23 @@
input_set_abs_params(input_dev, ABS_PRESSURE,
pdata->pressure_min, pdata->pressure_max, 0, 0);
+ /*
+ * Parse common framework properties. Must be done here to ensure the
+ * correct behaviour in case of using the legacy vendor bindings. The
+ * general binding value overrides the vendor specific one.
+ */
+ touchscreen_parse_properties(ts->input, false, &ts->core_prop);
+ ts->pressure_max = input_abs_get_max(input_dev, ABS_PRESSURE) ? : ~0;
+
+ /*
+ * Check if legacy ti,swap-xy binding is used instead of
+ * touchscreen-swapped-x-y
+ */
+ if (!ts->core_prop.swap_x_y && pdata->swap_xy) {
+ swap(input_dev->absinfo[ABS_X], input_dev->absinfo[ABS_Y]);
+ ts->core_prop.swap_x_y = true;
+ }
+
ads7846_setup_spi_msg(ts, pdata);
ts->reg = regulator_get(&spi->dev, "vcc");
diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c
index b35b640..28644f3 100644
--- a/drivers/input/touchscreen/ar1021_i2c.c
+++ b/drivers/input/touchscreen/ar1021_i2c.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Microchip AR1020 and AR1021 driver for I2C
*
* Author: Christian Gmeiner <christian.gmeiner@gmail.com>
- *
- * License: GPLv2 as published by the FSF.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3232af5..24c4b69 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Atmel maXTouch Touchscreen driver
*
@@ -7,12 +8,6 @@
* Copyright (C) 2016 Zodiac Inflight Innovations
*
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/acpi.h>
@@ -29,7 +24,6 @@
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/gpio/consumer.h>
-#include <linux/property.h>
#include <asm/unaligned.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
@@ -262,16 +256,6 @@
MXT_V4L_INPUT_MAX,
};
-static const struct v4l2_file_operations mxt_video_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = vb2_fop_release,
- .unlocked_ioctl = video_ioctl2,
- .read = vb2_fop_read,
- .mmap = vb2_fop_mmap,
- .poll = vb2_fop_poll,
-};
-
enum mxt_suspend_mode {
MXT_SUSPEND_DEEP_SLEEP = 0,
MXT_SUSPEND_T9_CTRL = 1,
@@ -489,7 +473,7 @@
bootloader = appmode - 0x24;
break;
}
- /* Fall through for normal case */
+ /* Fall through - for normal case */
case 0x4c:
case 0x4d:
case 0x5a:
@@ -1527,7 +1511,8 @@
} else if (config_crc == data->config_crc) {
dev_dbg(dev, "Config CRC 0x%06X: OK\n",
data->config_crc);
- return 0;
+ ret = 0;
+ goto release_raw;
} else {
dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
data->config_crc, config_crc);
@@ -1586,10 +1571,10 @@
/* T7 config may have changed */
mxt_init_t7_power_cfg(data);
-release_raw:
- kfree(cfg.raw);
release_mem:
kfree(cfg.mem);
+release_raw:
+ kfree(cfg.raw);
return ret;
}
@@ -2224,6 +2209,16 @@
}
#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
+static const struct v4l2_file_operations mxt_video_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
unsigned int y)
{
@@ -2995,8 +2990,7 @@
int error;
if (device_property_present(dev, keymap_property)) {
- n_keys = device_property_read_u32_array(dev, keymap_property,
- NULL, 0);
+ n_keys = device_property_count_u32(dev, keymap_property);
if (n_keys <= 0) {
error = n_keys < 0 ? n_keys : -EINVAL;
dev_err(dev, "invalid/malformed '%s' property: %d\n",
diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c
index df8ca85..8e9f3b7 100644
--- a/drivers/input/touchscreen/auo-pixcir-ts.c
+++ b/drivers/input/touchscreen/auo-pixcir-ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for AUO in-cell touchscreens
*
@@ -7,17 +8,6 @@
*
* Copyright (c) 2008 QUALCOMM Incorporated.
* Copyright (c) 2008 QUALCOMM USA, INC.
- *
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
*/
#include <linux/kernel.h>
@@ -612,9 +602,8 @@
return error;
}
- error = devm_add_action(&client->dev, auo_pixcir_reset, ts);
+ error = devm_add_action_or_reset(&client->dev, auo_pixcir_reset, ts);
if (error) {
- auo_pixcir_reset(ts);
dev_err(&client->dev, "failed to register reset action, %d\n",
error);
return error;
diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
index 4d11b27..7de1fd2 100644
--- a/drivers/input/touchscreen/bcm_iproc_tsc.c
+++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
@@ -489,10 +489,8 @@
/* get interrupt */
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "platform_get_irq failed: %d\n", irq);
+ if (irq < 0)
return irq;
- }
error = devm_request_irq(&pdev->dev, irq,
iproc_touchscreen_interrupt,
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
index 4fa5da8..2f1f0d7 100644
--- a/drivers/input/touchscreen/bu21013_ts.c
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -1,24 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
* Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
- * License terms:GNU General Public License (GPL) version 2
*/
-#include <linux/kernel.h>
+#include <linux/bitops.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
-#include <linux/workqueue.h>
#include <linux/input.h>
-#include <linux/input/bu21013.h>
-#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/types.h>
-#define PEN_DOWN_INTR 0
#define MAX_FINGERS 2
#define RESET_DELAY 30
#define PENUP_TIMEOUT (10)
@@ -137,69 +137,63 @@
#define DRIVER_TP "bu21013_tp"
/**
- * struct bu21013_ts_data - touch panel data structure
+ * struct bu21013_ts - touch panel data structure
* @client: pointer to the i2c client
- * @wait: variable to wait_queue_head_t structure
- * @touch_stopped: touch stop flag
- * @chip: pointer to the touch panel controller
* @in_dev: pointer to the input device structure
- * @intr_pin: interrupt pin value
+ * @props: the device coordinate transformation properties
* @regulator: pointer to the Regulator used for touch screen
+ * @cs_gpiod: chip select GPIO line
+ * @int_gpiod: touch interrupt GPIO line
+ * @touch_x_max: maximum X coordinate reported by the device
+ * @touch_y_max: maximum Y coordinate reported by the device
+ * @x_flip: indicates that the driver should invert X coordinate before
+ * reporting
+ * @y_flip: indicates that the driver should invert Y coordinate before
+ * reporting
+ * @touch_stopped: touch stop flag
*
* Touch panel device data structure
*/
-struct bu21013_ts_data {
+struct bu21013_ts {
struct i2c_client *client;
- wait_queue_head_t wait;
- const struct bu21013_platform_device *chip;
struct input_dev *in_dev;
+ struct touchscreen_properties props;
struct regulator *regulator;
- unsigned int irq;
- unsigned int intr_pin;
+ struct gpio_desc *cs_gpiod;
+ struct gpio_desc *int_gpiod;
+ u32 touch_x_max;
+ u32 touch_y_max;
+ bool x_flip;
+ bool y_flip;
bool touch_stopped;
};
-/**
- * bu21013_read_block_data(): read the touch co-ordinates
- * @data: bu21013_ts_data structure pointer
- * @buf: byte pointer
- *
- * Read the touch co-ordinates using i2c read block into buffer
- * and returns integer.
- */
-static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf)
+static int bu21013_read_block_data(struct bu21013_ts *ts, u8 *buf)
{
int ret, i;
for (i = 0; i < I2C_RETRY_COUNT; i++) {
- ret = i2c_smbus_read_i2c_block_data
- (data->client, BU21013_SENSORS_BTN_0_7_REG,
- LENGTH_OF_BUFFER, buf);
+ ret = i2c_smbus_read_i2c_block_data(ts->client,
+ BU21013_SENSORS_BTN_0_7_REG,
+ LENGTH_OF_BUFFER, buf);
if (ret == LENGTH_OF_BUFFER)
return 0;
}
+
return -EINVAL;
}
-/**
- * bu21013_do_touch_report(): Get the touch co-ordinates
- * @data: bu21013_ts_data structure pointer
- *
- * Get the touch co-ordinates from touch sensor registers and writes
- * into device structure and returns integer.
- */
-static int bu21013_do_touch_report(struct bu21013_ts_data *data)
+static int bu21013_do_touch_report(struct bu21013_ts *ts)
{
- u8 buf[LENGTH_OF_BUFFER];
- unsigned int pos_x[2], pos_y[2];
- bool has_x_sensors, has_y_sensors;
- int finger_down_count = 0;
- int i;
+ struct input_dev *input = ts->in_dev;
+ struct input_mt_pos pos[MAX_FINGERS];
+ int slots[MAX_FINGERS];
+ u8 buf[LENGTH_OF_BUFFER];
+ bool has_x_sensors, has_y_sensors;
+ int finger_down_count = 0;
+ int i;
- if (data == NULL)
- return -EINVAL;
-
- if (bu21013_read_block_data(data, buf) < 0)
+ if (bu21013_read_block_data(ts, buf) < 0)
return -EINVAL;
has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);
@@ -209,501 +203,411 @@
return 0;
for (i = 0; i < MAX_FINGERS; i++) {
- const u8 *p = &buf[4 * i + 3];
- unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS);
- unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS);
- if (x == 0 || y == 0)
- continue;
- pos_x[finger_down_count] = x;
- pos_y[finger_down_count] = y;
- finger_down_count++;
+ const u8 *data = &buf[4 * i + 3];
+ unsigned int x, y;
+
+ x = data[0] << SHIFT_2 | (data[1] & MASK_BITS);
+ y = data[2] << SHIFT_2 | (data[3] & MASK_BITS);
+ if (x != 0 && y != 0)
+ touchscreen_set_mt_pos(&pos[finger_down_count++],
+ &ts->props, x, y);
}
- if (finger_down_count) {
- if (finger_down_count == 2 &&
- (abs(pos_x[0] - pos_x[1]) < DELTA_MIN ||
- abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) {
- return 0;
- }
+ if (finger_down_count == 2 &&
+ (abs(pos[0].x - pos[1].x) < DELTA_MIN ||
+ abs(pos[0].y - pos[1].y) < DELTA_MIN)) {
+ return 0;
+ }
- for (i = 0; i < finger_down_count; i++) {
- if (data->chip->x_flip)
- pos_x[i] = data->chip->touch_x_max - pos_x[i];
- if (data->chip->y_flip)
- pos_y[i] = data->chip->touch_y_max - pos_y[i];
+ input_mt_assign_slots(input, slots, pos, finger_down_count, DELTA_MIN);
+ for (i = 0; i < finger_down_count; i++) {
+ input_mt_slot(input, slots[i]);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+ input_report_abs(input, ABS_MT_POSITION_X, pos[i].x);
+ input_report_abs(input, ABS_MT_POSITION_Y, pos[i].y);
+ }
- input_report_abs(data->in_dev,
- ABS_MT_POSITION_X, pos_x[i]);
- input_report_abs(data->in_dev,
- ABS_MT_POSITION_Y, pos_y[i]);
- input_mt_sync(data->in_dev);
- }
- } else
- input_mt_sync(data->in_dev);
-
- input_sync(data->in_dev);
+ input_mt_sync_frame(input);
+ input_sync(input);
return 0;
}
-/**
- * bu21013_gpio_irq() - gpio thread function for touch interrupt
- * @irq: irq value
- * @device_data: void pointer
- *
- * This gpio thread function for touch interrupt
- * and returns irqreturn_t.
- */
+
static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
{
- struct bu21013_ts_data *data = device_data;
- struct i2c_client *i2c = data->client;
- int retval;
+ struct bu21013_ts *ts = device_data;
+ int keep_polling;
+ int error;
do {
- retval = bu21013_do_touch_report(data);
- if (retval < 0) {
- dev_err(&i2c->dev, "bu21013_do_touch_report failed\n");
- return IRQ_NONE;
+ error = bu21013_do_touch_report(ts);
+ if (error) {
+ dev_err(&ts->client->dev, "%s failed\n", __func__);
+ break;
}
- data->intr_pin = gpio_get_value(data->chip->touch_pin);
- if (data->intr_pin == PEN_DOWN_INTR)
- wait_event_timeout(data->wait, data->touch_stopped,
- msecs_to_jiffies(2));
- } while (!data->intr_pin && !data->touch_stopped);
+ if (unlikely(ts->touch_stopped))
+ break;
+
+ keep_polling = ts->int_gpiod ?
+ gpiod_get_value(ts->int_gpiod) : false;
+ if (keep_polling)
+ usleep_range(2000, 2500);
+ } while (keep_polling);
return IRQ_HANDLED;
}
-/**
- * bu21013_init_chip() - power on sequence for the bu21013 controller
- * @data: device structure pointer
- *
- * This function is used to power on
- * the bu21013 controller and returns integer.
- */
-static int bu21013_init_chip(struct bu21013_ts_data *data)
+static int bu21013_init_chip(struct bu21013_ts *ts)
{
- int retval;
- struct i2c_client *i2c = data->client;
+ struct i2c_client *client = ts->client;
+ int error;
- retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG,
- BU21013_RESET_ENABLE);
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_RESET reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_RESET_REG,
+ BU21013_RESET_ENABLE);
+ if (error) {
+ dev_err(&client->dev, "BU21013_RESET reg write failed\n");
+ return error;
}
msleep(RESET_DELAY);
- retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG,
- BU21013_SENSORS_EN_0_7);
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_0_7_REG,
+ BU21013_SENSORS_EN_0_7);
+ if (error) {
+ dev_err(&client->dev, "BU21013_SENSOR_0_7 reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG,
- BU21013_SENSORS_EN_8_15);
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_8_15_REG,
+ BU21013_SENSORS_EN_8_15);
+ if (error) {
+ dev_err(&client->dev, "BU21013_SENSOR_8_15 reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG,
- BU21013_SENSORS_EN_16_23);
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_16_23_REG,
+ BU21013_SENSORS_EN_16_23);
+ if (error) {
+ dev_err(&client->dev, "BU21013_SENSOR_16_23 reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG,
- (BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1));
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_POS_MODE1_REG,
+ BU21013_POS_MODE1_0 |
+ BU21013_POS_MODE1_1);
+ if (error) {
+ dev_err(&client->dev, "BU21013_POS_MODE1 reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG,
- (BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 |
- BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW |
- BU21013_POS_MODE2_MULTI));
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_POS_MODE2_REG,
+ BU21013_POS_MODE2_ZERO |
+ BU21013_POS_MODE2_AVG1 |
+ BU21013_POS_MODE2_AVG2 |
+ BU21013_POS_MODE2_EN_RAW |
+ BU21013_POS_MODE2_MULTI);
+ if (error) {
+ dev_err(&client->dev, "BU21013_POS_MODE2 reg write failed\n");
+ return error;
}
- if (data->chip->ext_clk)
- retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
- (BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB));
- else
- retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
- (BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB));
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_CLK_MODE_REG,
+ BU21013_CLK_MODE_DIV |
+ BU21013_CLK_MODE_CALIB);
+ if (error) {
+ dev_err(&client->dev, "BU21013_CLK_MODE reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG,
- (BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN));
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_IDLE_REG,
+ BU21013_IDLET_0 |
+ BU21013_IDLE_INTERMIT_EN);
+ if (error) {
+ dev_err(&client->dev, "BU21013_IDLE reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG,
- BU21013_INT_MODE_LEVEL);
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_INT_MODE_REG,
+ BU21013_INT_MODE_LEVEL);
+ if (error) {
+ dev_err(&client->dev, "BU21013_INT_MODE reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG,
- (BU21013_DELTA_0_6 |
- BU21013_FILTER_EN));
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_FILTER_REG,
+ BU21013_DELTA_0_6 |
+ BU21013_FILTER_EN);
+ if (error) {
+ dev_err(&client->dev, "BU21013_FILTER reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG,
- BU21013_TH_ON_5);
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_TH_ON_REG,
+ BU21013_TH_ON_5);
+ if (error) {
+ dev_err(&client->dev, "BU21013_TH_ON reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
- BU21013_TH_OFF_4 | BU21013_TH_OFF_3);
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_TH_OFF_REG,
+ BU21013_TH_OFF_4 | BU21013_TH_OFF_3);
+ if (error) {
+ dev_err(&client->dev, "BU21013_TH_OFF reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG,
- (BU21013_GAIN_0 | BU21013_GAIN_1));
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_GAIN_REG,
+ BU21013_GAIN_0 | BU21013_GAIN_1);
+ if (error) {
+ dev_err(&client->dev, "BU21013_GAIN reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG,
- BU21013_OFFSET_MODE_DEFAULT);
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_OFFSET_MODE_REG,
+ BU21013_OFFSET_MODE_DEFAULT);
+ if (error) {
+ dev_err(&client->dev, "BU21013_OFFSET_MODE reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG,
- (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |
- BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3));
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_XY_EDGE_REG,
+ BU21013_X_EDGE_0 |
+ BU21013_X_EDGE_2 |
+ BU21013_Y_EDGE_1 |
+ BU21013_Y_EDGE_3);
+ if (error) {
+ dev_err(&client->dev, "BU21013_XY_EDGE reg write failed\n");
+ return error;
}
- retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG,
- BU21013_DONE);
- if (retval < 0) {
- dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n");
- return retval;
+ error = i2c_smbus_write_byte_data(client, BU21013_DONE_REG,
+ BU21013_DONE);
+ if (error) {
+ dev_err(&client->dev, "BU21013_REG_DONE reg write failed\n");
+ return error;
}
return 0;
}
-/**
- * bu21013_free_irq() - frees IRQ registered for touchscreen
- * @bu21013_data: device structure pointer
- *
- * This function signals interrupt thread to stop processing and
- * frees interrupt.
- */
-static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)
+static void bu21013_power_off(void *_ts)
{
- bu21013_data->touch_stopped = true;
- wake_up(&bu21013_data->wait);
- free_irq(bu21013_data->irq, bu21013_data);
+ struct bu21013_ts *ts = _ts;
+
+ regulator_disable(ts->regulator);
}
-/**
- * bu21013_cs_disable() - deconfigures the touch panel controller
- * @bu21013_data: device structure pointer
- *
- * This function is used to deconfigure the chip selection
- * for touch panel controller.
- */
-static void bu21013_cs_disable(struct bu21013_ts_data *bu21013_data)
+static void bu21013_disable_chip(void *_ts)
{
- int error;
+ struct bu21013_ts *ts = _ts;
- error = gpio_direction_output(bu21013_data->chip->cs_pin, 0);
- if (error < 0)
- dev_warn(&bu21013_data->client->dev,
- "%s: gpio direction failed, error: %d\n",
- __func__, error);
- else
- gpio_set_value(bu21013_data->chip->cs_pin, 0);
-
- gpio_free(bu21013_data->chip->cs_pin);
+ gpiod_set_value(ts->cs_gpiod, 0);
}
-#ifdef CONFIG_OF
-static const struct bu21013_platform_device *
-bu21013_parse_dt(struct device *dev)
-{
- struct device_node *np = dev->of_node;
- struct bu21013_platform_device *pdata;
-
- if (!np) {
- dev_err(dev, "no device tree or platform data\n");
- return ERR_PTR(-EINVAL);
- }
-
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return ERR_PTR(-ENOMEM);
-
- pdata->y_flip = pdata->x_flip = false;
-
- pdata->x_flip = of_property_read_bool(np, "rohm,flip-x");
- pdata->y_flip = of_property_read_bool(np, "rohm,flip-y");
-
- of_property_read_u32(np, "rohm,touch-max-x", &pdata->touch_x_max);
- of_property_read_u32(np, "rohm,touch-max-y", &pdata->touch_y_max);
-
- pdata->touch_pin = of_get_named_gpio(np, "touch-gpio", 0);
- pdata->cs_pin = of_get_named_gpio(np, "reset-gpio", 0);
-
- pdata->ext_clk = false;
-
- return pdata;
-}
-#else
-static inline const struct bu21013_platform_device *
-bu21013_parse_dt(struct device *dev)
-{
- dev_err(dev, "no platform data available\n");
- return ERR_PTR(-EINVAL);
-}
-#endif
-
-/**
- * bu21013_probe() - initializes the i2c-client touchscreen driver
- * @client: i2c client structure pointer
- * @id: i2c device id pointer
- *
- * This function used to initializes the i2c-client touchscreen
- * driver and returns integer.
- */
static int bu21013_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- const struct bu21013_platform_device *pdata =
- dev_get_platdata(&client->dev);
- struct bu21013_ts_data *bu21013_data;
+ struct bu21013_ts *ts;
struct input_dev *in_dev;
+ struct input_absinfo *info;
+ u32 max_x = 0, max_y = 0;
int error;
if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev, "i2c smbus byte data not supported\n");
return -EIO;
}
- if (!pdata) {
- pdata = bu21013_parse_dt(&client->dev);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- }
-
- if (!gpio_is_valid(pdata->touch_pin)) {
- dev_err(&client->dev, "invalid touch_pin supplied\n");
+ if (!client->irq) {
+ dev_err(&client->dev, "No IRQ set up\n");
return -EINVAL;
}
- bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL);
- in_dev = input_allocate_device();
- if (!bu21013_data || !in_dev) {
+ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ ts->client = client;
+
+ ts->x_flip = device_property_read_bool(&client->dev, "rohm,flip-x");
+ ts->y_flip = device_property_read_bool(&client->dev, "rohm,flip-y");
+
+ in_dev = devm_input_allocate_device(&client->dev);
+ if (!in_dev) {
dev_err(&client->dev, "device memory alloc failed\n");
- error = -ENOMEM;
- goto err_free_mem;
+ return -ENOMEM;
}
-
- bu21013_data->in_dev = in_dev;
- bu21013_data->chip = pdata;
- bu21013_data->client = client;
- bu21013_data->irq = gpio_to_irq(pdata->touch_pin);
-
- bu21013_data->regulator = regulator_get(&client->dev, "avdd");
- if (IS_ERR(bu21013_data->regulator)) {
- dev_err(&client->dev, "regulator_get failed\n");
- error = PTR_ERR(bu21013_data->regulator);
- goto err_free_mem;
- }
-
- error = regulator_enable(bu21013_data->regulator);
- if (error < 0) {
- dev_err(&client->dev, "regulator enable failed\n");
- goto err_put_regulator;
- }
-
- bu21013_data->touch_stopped = false;
- init_waitqueue_head(&bu21013_data->wait);
-
- /* configure the gpio pins */
- error = gpio_request_one(pdata->cs_pin, GPIOF_OUT_INIT_HIGH,
- "touchp_reset");
- if (error < 0) {
- dev_err(&client->dev, "Unable to request gpio reset_pin\n");
- goto err_disable_regulator;
- }
-
- /* configure the touch panel controller */
- error = bu21013_init_chip(bu21013_data);
- if (error) {
- dev_err(&client->dev, "error in bu21013 config\n");
- goto err_cs_disable;
- }
+ ts->in_dev = in_dev;
+ input_set_drvdata(in_dev, ts);
/* register the device to input subsystem */
in_dev->name = DRIVER_TP;
in_dev->id.bustype = BUS_I2C;
- in_dev->dev.parent = &client->dev;
- __set_bit(EV_SYN, in_dev->evbit);
- __set_bit(EV_KEY, in_dev->evbit);
- __set_bit(EV_ABS, in_dev->evbit);
+ device_property_read_u32(&client->dev, "rohm,touch-max-x", &max_x);
+ device_property_read_u32(&client->dev, "rohm,touch-max-y", &max_y);
- input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
- pdata->touch_x_max, 0, 0);
- input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
- pdata->touch_y_max, 0, 0);
- input_set_drvdata(in_dev, bu21013_data);
+ input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
- error = request_threaded_irq(bu21013_data->irq, NULL, bu21013_gpio_irq,
- IRQF_TRIGGER_FALLING | IRQF_SHARED |
- IRQF_ONESHOT,
- DRIVER_TP, bu21013_data);
+ touchscreen_parse_properties(in_dev, true, &ts->props);
+
+ /* Adjust for the legacy "flip" properties, if present */
+ if (!ts->props.invert_x &&
+ device_property_read_bool(&client->dev, "rohm,flip-x")) {
+ info = &in_dev->absinfo[ABS_MT_POSITION_X];
+ info->maximum -= info->minimum;
+ info->minimum = 0;
+ }
+
+ if (!ts->props.invert_y &&
+ device_property_read_bool(&client->dev, "rohm,flip-y")) {
+ info = &in_dev->absinfo[ABS_MT_POSITION_Y];
+ info->maximum -= info->minimum;
+ info->minimum = 0;
+ }
+
+ error = input_mt_init_slots(in_dev, MAX_FINGERS,
+ INPUT_MT_DIRECT | INPUT_MT_TRACK |
+ INPUT_MT_DROP_UNUSED);
+ if (error) {
+ dev_err(&client->dev, "failed to initialize MT slots");
+ return error;
+ }
+
+ ts->regulator = devm_regulator_get(&client->dev, "avdd");
+ if (IS_ERR(ts->regulator)) {
+ dev_err(&client->dev, "regulator_get failed\n");
+ return PTR_ERR(ts->regulator);
+ }
+
+ error = regulator_enable(ts->regulator);
+ if (error) {
+ dev_err(&client->dev, "regulator enable failed\n");
+ return error;
+ }
+
+ error = devm_add_action_or_reset(&client->dev, bu21013_power_off, ts);
+ if (error) {
+ dev_err(&client->dev, "failed to install power off handler\n");
+ return error;
+ }
+
+ /* Named "CS" on the chip, DT binding is "reset" */
+ ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
+ error = PTR_ERR_OR_ZERO(ts->cs_gpiod);
+ if (error) {
+ if (error != -EPROBE_DEFER)
+ dev_err(&client->dev, "failed to get CS GPIO\n");
+ return error;
+ }
+ gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS");
+
+ error = devm_add_action_or_reset(&client->dev,
+ bu21013_disable_chip, ts);
+ if (error) {
+ dev_err(&client->dev,
+ "failed to install chip disable handler\n");
+ return error;
+ }
+
+ /* Named "INT" on the chip, DT binding is "touch" */
+ ts->int_gpiod = devm_gpiod_get_optional(&client->dev,
+ "touch", GPIOD_IN);
+ error = PTR_ERR_OR_ZERO(ts->int_gpiod);
+ if (error) {
+ if (error != -EPROBE_DEFER)
+ dev_err(&client->dev, "failed to get INT GPIO\n");
+ return error;
+ }
+
+ if (ts->int_gpiod)
+ gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT");
+
+ /* configure the touch panel controller */
+ error = bu21013_init_chip(ts);
+ if (error) {
+ dev_err(&client->dev, "error in bu21013 config\n");
+ return error;
+ }
+
+ error = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, bu21013_gpio_irq,
+ IRQF_ONESHOT, DRIVER_TP, ts);
if (error) {
dev_err(&client->dev, "request irq %d failed\n",
- bu21013_data->irq);
- goto err_cs_disable;
+ client->irq);
+ return error;
}
error = input_register_device(in_dev);
if (error) {
dev_err(&client->dev, "failed to register input device\n");
- goto err_free_irq;
+ return error;
}
- device_init_wakeup(&client->dev, pdata->wakeup);
- i2c_set_clientdata(client, bu21013_data);
+ i2c_set_clientdata(client, ts);
return 0;
-
-err_free_irq:
- bu21013_free_irq(bu21013_data);
-err_cs_disable:
- bu21013_cs_disable(bu21013_data);
-err_disable_regulator:
- regulator_disable(bu21013_data->regulator);
-err_put_regulator:
- regulator_put(bu21013_data->regulator);
-err_free_mem:
- input_free_device(in_dev);
- kfree(bu21013_data);
-
- return error;
}
-/**
- * bu21013_remove() - removes the i2c-client touchscreen driver
- * @client: i2c client structure pointer
- *
- * This function uses to remove the i2c-client
- * touchscreen driver and returns integer.
- */
+
static int bu21013_remove(struct i2c_client *client)
{
- struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+ struct bu21013_ts *ts = i2c_get_clientdata(client);
- bu21013_free_irq(bu21013_data);
-
- bu21013_cs_disable(bu21013_data);
-
- input_unregister_device(bu21013_data->in_dev);
-
- regulator_disable(bu21013_data->regulator);
- regulator_put(bu21013_data->regulator);
-
- kfree(bu21013_data);
+ /* Make sure IRQ will exit quickly even if there is contact */
+ ts->touch_stopped = true;
+ /* The resources will be freed by devm */
return 0;
}
-#ifdef CONFIG_PM
-/**
- * bu21013_suspend() - suspend the touch screen controller
- * @dev: pointer to device structure
- *
- * This function is used to suspend the
- * touch panel controller and returns integer
- */
-static int bu21013_suspend(struct device *dev)
+static int __maybe_unused bu21013_suspend(struct device *dev)
{
- struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
- struct i2c_client *client = bu21013_data->client;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bu21013_ts *ts = i2c_get_clientdata(client);
- bu21013_data->touch_stopped = true;
- if (device_may_wakeup(&client->dev))
- enable_irq_wake(bu21013_data->irq);
- else
- disable_irq(bu21013_data->irq);
+ ts->touch_stopped = true;
+ mb();
+ disable_irq(client->irq);
- regulator_disable(bu21013_data->regulator);
+ if (!device_may_wakeup(&client->dev))
+ regulator_disable(ts->regulator);
return 0;
}
-/**
- * bu21013_resume() - resume the touch screen controller
- * @dev: pointer to device structure
- *
- * This function is used to resume the touch panel
- * controller and returns integer.
- */
-static int bu21013_resume(struct device *dev)
+static int __maybe_unused bu21013_resume(struct device *dev)
{
- struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
- struct i2c_client *client = bu21013_data->client;
- int retval;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bu21013_ts *ts = i2c_get_clientdata(client);
+ int error;
- retval = regulator_enable(bu21013_data->regulator);
- if (retval < 0) {
- dev_err(&client->dev, "bu21013 regulator enable failed\n");
- return retval;
+ if (!device_may_wakeup(&client->dev)) {
+ error = regulator_enable(ts->regulator);
+ if (error) {
+ dev_err(&client->dev,
+ "failed to re-enable regulator when resuming\n");
+ return error;
+ }
+
+ error = bu21013_init_chip(ts);
+ if (error) {
+ dev_err(&client->dev,
+ "failed to reinitialize chip when resuming\n");
+ return error;
+ }
}
- retval = bu21013_init_chip(bu21013_data);
- if (retval < 0) {
- dev_err(&client->dev, "bu21013 controller config failed\n");
- return retval;
- }
-
- bu21013_data->touch_stopped = false;
-
- if (device_may_wakeup(&client->dev))
- disable_irq_wake(bu21013_data->irq);
- else
- enable_irq(bu21013_data->irq);
+ ts->touch_stopped = false;
+ mb();
+ enable_irq(client->irq);
return 0;
}
-static const struct dev_pm_ops bu21013_dev_pm_ops = {
- .suspend = bu21013_suspend,
- .resume = bu21013_resume,
-};
-#endif
+static SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume);
static const struct i2c_device_id bu21013_id[] = {
{ DRIVER_TP, 0 },
@@ -714,9 +618,7 @@
static struct i2c_driver bu21013_driver = {
.driver = {
.name = DRIVER_TP,
-#ifdef CONFIG_PM
.pm = &bu21013_dev_pm_ops,
-#endif
},
.probe = bu21013_probe,
.remove = bu21013_remove,
diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c
index 0bf1406..d91d2fd 100644
--- a/drivers/input/touchscreen/chipone_icn8318.c
+++ b/drivers/input/touchscreen/chipone_icn8318.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for ChipOne icn8318 i2c touchscreen controller
*
* Copyright (c) 2015 Red Hat Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
* Red Hat authors:
* Hans de Goede <hdegoede@redhat.com>
*/
diff --git a/drivers/input/touchscreen/colibri-vf50-ts.c b/drivers/input/touchscreen/colibri-vf50-ts.c
index 82ca5ab..0e40897 100644
--- a/drivers/input/touchscreen/colibri-vf50-ts.c
+++ b/drivers/input/touchscreen/colibri-vf50-ts.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Toradex Colibri VF50 Touchscreen driver
*
* Copyright 2015 Toradex AG
*
* Originally authored by Stefan Agner for 3.0 kernel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/delay.h>
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
index cc1d135..f465bae 100644
--- a/drivers/input/touchscreen/cy8ctmg110_ts.c
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for cypress touch screen controller
*
* Copyright (c) 2009 Aava Mobile
*
* Some cleanups by Alan Cox <alan@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
index 727c323..6bcffc9 100644
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ b/drivers/input/touchscreen/cyttsp4_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cyttsp4_core.c
* Cypress TrueTouch(TM) Standard Product V4 Core driver module.
@@ -8,18 +9,7 @@
*
* Copyright (C) 2012 Cypress Semiconductor
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- *
*/
#include "cyttsp4_core.h"
@@ -2000,11 +1990,6 @@
/* get sysinfo */
md->si = &cd->sysinfo;
- if (!md->si) {
- dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
- __func__, md->si);
- goto error_get_sysinfo;
- }
rc = cyttsp4_setup_input_device(cd);
if (rc)
@@ -2014,8 +1999,6 @@
error_init_input:
input_free_device(md->input);
-error_get_sysinfo:
- input_set_drvdata(md->input, NULL);
error_alloc_failed:
dev_err(dev, "%s failed.\n", __func__);
return rc;
diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h
index 8e0d4d4..f3e4443 100644
--- a/drivers/input/touchscreen/cyttsp4_core.h
+++ b/drivers/input/touchscreen/cyttsp4_core.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cyttsp4_core.h
* Cypress TrueTouch(TM) Standard Product V4 Core driver module.
@@ -8,18 +9,7 @@
*
* Copyright (C) 2012 Cypress Semiconductor
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- *
*/
#ifndef _LINUX_CYTTSP4_CORE_H
diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c
index 564e490..c65ccb2 100644
--- a/drivers/input/touchscreen/cyttsp4_i2c.c
+++ b/drivers/input/touchscreen/cyttsp4_i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cyttsp_i2c.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
@@ -10,18 +11,7 @@
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- *
*/
#include "cyttsp4_core.h"
diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c
index ec5f7c7..2aec41e 100644
--- a/drivers/input/touchscreen/cyttsp4_spi.c
+++ b/drivers/input/touchscreen/cyttsp4_spi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Source for:
* Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
@@ -10,18 +11,7 @@
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- *
*/
#include "cyttsp4_core.h"
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index 79381cc..3f5d463 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Core Source for:
* Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
@@ -9,22 +10,7 @@
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
- *
*/
#include <linux/delay.h>
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
index 7835e2b..8c65133 100644
--- a/drivers/input/touchscreen/cyttsp_core.h
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Header file for:
* Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
@@ -9,22 +10,7 @@
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
- *
*/
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
index 1edfdba..061debf 100644
--- a/drivers/input/touchscreen/cyttsp_i2c.c
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cyttsp_i2c.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
@@ -9,18 +10,7 @@
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- *
*/
#include "cyttsp_core.h"
diff --git a/drivers/input/touchscreen/cyttsp_i2c_common.c b/drivers/input/touchscreen/cyttsp_i2c_common.c
index ccefa56..1f0b6d6 100644
--- a/drivers/input/touchscreen/cyttsp_i2c_common.c
+++ b/drivers/input/touchscreen/cyttsp_i2c_common.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cyttsp_i2c_common.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
@@ -11,18 +12,7 @@
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- *
*/
#include <linux/device.h>
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
index 3c9d18b..54e4109 100644
--- a/drivers/input/touchscreen/cyttsp_spi.c
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Source for:
* Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
@@ -10,18 +11,7 @@
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- *
*/
#include "cyttsp_core.h"
diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c
index 8264822..2943f6a 100644
--- a/drivers/input/touchscreen/da9034-ts.c
+++ b/drivers/input/touchscreen/da9034-ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchscreen driver for Dialog Semiconductor DA9034
*
@@ -5,10 +6,6 @@
* Fengwei Yin <fengwei.yin@marvell.com>
* Bin Yang <bin.yang@marvell.com>
* Eric Miao <eric.miao@marvell.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c
index b5dfd59..f91d0e0 100644
--- a/drivers/input/touchscreen/da9052_tsi.c
+++ b/drivers/input/touchscreen/da9052_tsi.c
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* TSI driver for Dialog DA9052
*
* Copyright(c) 2012 Dialog Semiconductor Ltd.
*
* Author: David Dajun Chen <dchen@diasemi.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/module.h>
#include <linux/input.h>
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
index 5b1b66f..dc07fca 100644
--- a/drivers/input/touchscreen/dynapro.c
+++ b/drivers/input/touchscreen/dynapro.c
@@ -1,17 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Dynapro serial touchscreen driver
*
* Copyright (c) 2009 Tias Guns
* Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
* Richard Lemon
- *
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* 2009/09/19 Tias Guns <tias@ulyssis.org>
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 1e18ca0..5525f1f 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
* Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support)
* Lothar Waßmann <LW@KARO-electronics.de> (DT support)
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
@@ -31,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/i2c.h>
+#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
@@ -38,7 +27,7 @@
#include <linux/gpio/consumer.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
-#include <linux/of_device.h>
+#include <asm/unaligned.h>
#define WORK_REGISTER_THRESHOLD 0x00
#define WORK_REGISTER_REPORT_RATE 0x08
@@ -53,6 +42,11 @@
#define M09_REGISTER_NUM_X 0x94
#define M09_REGISTER_NUM_Y 0x95
+#define EV_REGISTER_THRESHOLD 0x40
+#define EV_REGISTER_GAIN 0x41
+#define EV_REGISTER_OFFSET_Y 0x45
+#define EV_REGISTER_OFFSET_X 0x46
+
#define NO_REGISTER 0xff
#define WORK_REGISTER_OPMODE 0x3c
@@ -73,6 +67,7 @@
EDT_M06,
EDT_M09,
EDT_M12,
+ EV_FT,
GENERIC_FT,
};
@@ -81,6 +76,8 @@
int reg_report_rate;
int reg_gain;
int reg_offset;
+ int reg_offset_x;
+ int reg_offset_y;
int reg_num_x;
int reg_num_y;
};
@@ -106,6 +103,8 @@
int threshold;
int gain;
int offset;
+ int offset_x;
+ int offset_y;
int report_rate;
int max_support_points;
@@ -190,6 +189,7 @@
case EDT_M09:
case EDT_M12:
+ case EV_FT:
case GENERIC_FT:
cmd = 0x0;
offset = 3;
@@ -229,7 +229,6 @@
for (i = 0; i < tsdata->max_support_points; i++) {
u8 *buf = &rdbuf[i * tplen + offset];
- bool down;
type = buf[0] >> 6;
/* ignore Reserved events */
@@ -240,19 +239,19 @@
if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
continue;
- x = ((buf[0] << 8) | buf[1]) & 0x0fff;
- y = ((buf[2] << 8) | buf[3]) & 0x0fff;
+ x = get_unaligned_be16(buf) & 0x0fff;
+ y = get_unaligned_be16(buf + 2) & 0x0fff;
+ /* The FT5x26 send the y coordinate first */
+ if (tsdata->version == EV_FT)
+ swap(x, y);
+
id = (buf[2] >> 4) & 0x0f;
- down = type != TOUCH_EVENT_UP;
input_mt_slot(tsdata->input, id);
- input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down);
-
- if (!down)
- continue;
-
- touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y,
- true);
+ if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER,
+ type != TOUCH_EVENT_UP))
+ touchscreen_report_pos(tsdata->input, &tsdata->prop,
+ x, y, true);
}
input_mt_report_pointer_emulation(tsdata->input, true);
@@ -275,8 +274,10 @@
wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
return edt_ft5x06_ts_readwrite(tsdata->client, 4,
wrbuf, 0, NULL);
+ /* fallthrough */
case EDT_M09:
case EDT_M12:
+ case EV_FT:
case GENERIC_FT:
wrbuf[0] = addr;
wrbuf[1] = value;
@@ -315,8 +316,10 @@
}
break;
+ /* fallthrough */
case EDT_M09:
case EDT_M12:
+ case EV_FT:
case GENERIC_FT:
wrbuf[0] = addr;
error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
@@ -339,9 +342,10 @@
u8 limit_high;
u8 addr_m06;
u8 addr_m09;
+ u8 addr_ev;
};
-#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \
+#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_ev, \
_limit_low, _limit_high) \
struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \
.dattr = __ATTR(_field, _mode, \
@@ -350,6 +354,7 @@
.field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \
.addr_m06 = _addr_m06, \
.addr_m09 = _addr_m09, \
+ .addr_ev = _addr_ev, \
.limit_low = _limit_low, \
.limit_high = _limit_high, \
}
@@ -386,6 +391,10 @@
addr = attr->addr_m09;
break;
+ case EV_FT:
+ addr = attr->addr_ev;
+ break;
+
default:
error = -ENODEV;
goto out;
@@ -457,6 +466,10 @@
addr = attr->addr_m09;
break;
+ case EV_FT:
+ addr = attr->addr_ev;
+ break;
+
default:
error = -ENODEV;
goto out;
@@ -480,20 +493,28 @@
/* m06, m09: range 0-31, m12: range 0-5 */
static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
- M09_REGISTER_GAIN, 0, 31);
+ M09_REGISTER_GAIN, EV_REGISTER_GAIN, 0, 31);
/* m06, m09: range 0-31, m12: range 0-16 */
static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
- M09_REGISTER_OFFSET, 0, 31);
+ M09_REGISTER_OFFSET, NO_REGISTER, 0, 31);
+/* m06, m09, m12: no supported, ev_ft: range 0-80 */
+static EDT_ATTR(offset_x, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER,
+ EV_REGISTER_OFFSET_X, 0, 80);
+/* m06, m09, m12: no supported, ev_ft: range 0-80 */
+static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER,
+ EV_REGISTER_OFFSET_Y, 0, 80);
/* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */
static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
- M09_REGISTER_THRESHOLD, 0, 255);
+ M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255);
/* m06: range 3 to 14, m12: (0x64: 100Hz) */
static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
- NO_REGISTER, 0, 255);
+ NO_REGISTER, NO_REGISTER, 0, 255);
static struct attribute *edt_ft5x06_attrs[] = {
&edt_ft5x06_attr_gain.dattr.attr,
&edt_ft5x06_attr_offset.dattr.attr,
+ &edt_ft5x06_attr_offset_x.dattr.attr,
+ &edt_ft5x06_attr_offset_y.dattr.attr,
&edt_ft5x06_attr_threshold.dattr.attr,
&edt_ft5x06_attr_report_rate.dattr.attr,
NULL
@@ -605,8 +626,15 @@
tsdata->threshold);
edt_ft5x06_register_write(tsdata, reg_addr->reg_gain,
tsdata->gain);
- edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,
- tsdata->offset);
+ if (reg_addr->reg_offset != NO_REGISTER)
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,
+ tsdata->offset);
+ if (reg_addr->reg_offset_x != NO_REGISTER)
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x,
+ tsdata->offset_x);
+ if (reg_addr->reg_offset_y != NO_REGISTER)
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y,
+ tsdata->offset_y);
if (reg_addr->reg_report_rate != NO_REGISTER)
edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,
tsdata->report_rate);
@@ -736,8 +764,6 @@
const char *debugfs_name)
{
tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
- if (!tsdata->debug_dir)
- return;
debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
@@ -867,6 +893,16 @@
case 0x5a: /* Solomon Goldentek Display */
snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0");
break;
+ case 0x59: /* Evervision Display with FT5xx6 TS */
+ tsdata->version = EV_FT;
+ error = edt_ft5x06_ts_readwrite(client, 1, "\x53",
+ 1, rdbuf);
+ if (error)
+ return error;
+ strlcpy(fw_version, rdbuf, 1);
+ snprintf(model_name, EDT_NAME_LEN,
+ "EVERVISION-FT5726NEi");
+ break;
default:
snprintf(model_name, EDT_NAME_LEN,
"generic ft5x06 (%02x)",
@@ -902,6 +938,18 @@
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val);
tsdata->offset = val;
}
+
+ error = device_property_read_u32(dev, "offset-x", &val);
+ if (!error) {
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, val);
+ tsdata->offset_x = val;
+ }
+
+ error = device_property_read_u32(dev, "offset-y", &val);
+ if (!error) {
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, val);
+ tsdata->offset_y = val;
+ }
}
static void
@@ -912,7 +960,15 @@
tsdata->threshold = edt_ft5x06_register_read(tsdata,
reg_addr->reg_threshold);
tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain);
- tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset);
+ if (reg_addr->reg_offset != NO_REGISTER)
+ tsdata->offset =
+ edt_ft5x06_register_read(tsdata, reg_addr->reg_offset);
+ if (reg_addr->reg_offset_x != NO_REGISTER)
+ tsdata->offset_x = edt_ft5x06_register_read(tsdata,
+ reg_addr->reg_offset_x);
+ if (reg_addr->reg_offset_y != NO_REGISTER)
+ tsdata->offset_y = edt_ft5x06_register_read(tsdata,
+ reg_addr->reg_offset_y);
if (reg_addr->reg_report_rate != NO_REGISTER)
tsdata->report_rate = edt_ft5x06_register_read(tsdata,
reg_addr->reg_report_rate);
@@ -940,6 +996,8 @@
reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
reg_addr->reg_gain = WORK_REGISTER_GAIN;
reg_addr->reg_offset = WORK_REGISTER_OFFSET;
+ reg_addr->reg_offset_x = NO_REGISTER;
+ reg_addr->reg_offset_y = NO_REGISTER;
reg_addr->reg_num_x = WORK_REGISTER_NUM_X;
reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
break;
@@ -950,15 +1008,30 @@
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 = M09_REGISTER_NUM_X;
reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
break;
+ case EV_FT:
+ reg_addr->reg_threshold = EV_REGISTER_THRESHOLD;
+ 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_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;
break;
}
}
@@ -981,7 +1054,7 @@
return -ENOMEM;
}
- chip_data = of_device_get_match_data(&client->dev);
+ chip_data = device_get_match_data(&client->dev);
if (!chip_data)
chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
if (!chip_data || !chip_data->max_support_points) {
@@ -1155,29 +1228,29 @@
static const struct i2c_device_id edt_ft5x06_ts_id[] = {
{ .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
{ .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data },
+ { .name = "ev-ft5726", .driver_data = (long)&edt_ft5506_data },
/* Note no edt- prefix for compatibility with the ft6236.c driver */
{ .name = "ft6236", .driver_data = (long)&edt_ft6236_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
-#ifdef CONFIG_OF
static const struct of_device_id edt_ft5x06_of_match[] = {
{ .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
+ { .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data },
/* Note focaltech vendor prefix for compatibility with ft6236.c */
{ .compatible = "focaltech,ft6236", .data = &edt_ft6236_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
-#endif
static struct i2c_driver edt_ft5x06_ts_driver = {
.driver = {
.name = "edt_ft5x06",
- .of_match_table = of_match_ptr(edt_ft5x06_of_match),
+ .of_match_table = edt_ft5x06_of_match,
.pm = &edt_ft5x06_ts_pm_ops,
},
.id_table = edt_ft5x06_ts_id,
@@ -1189,4 +1262,4 @@
MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>");
MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 7fe4196..2e1404c 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Touch Screen driver for EETI's I2C connected touch screen panels
* Copyright (c) 2009,2018 Daniel Mack <daniel@zonque.org>
@@ -8,20 +9,6 @@
* Based on migor_ts.c
* Copyright (c) 2008 Magnus Damm
* Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>
- *
- * This file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This file 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 library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
@@ -41,6 +28,7 @@
struct input_dev *input;
struct gpio_desc *attn_gpio;
struct touchscreen_properties props;
+ struct mutex mutex;
bool running;
};
@@ -75,42 +63,80 @@
input_sync(eeti->input);
}
+static int eeti_ts_read(struct eeti_ts *eeti)
+{
+ int len, error;
+ char buf[6];
+
+ len = i2c_master_recv(eeti->client, buf, sizeof(buf));
+ if (len != sizeof(buf)) {
+ error = len < 0 ? len : -EIO;
+ dev_err(&eeti->client->dev,
+ "failed to read touchscreen data: %d\n",
+ error);
+ return error;
+ }
+
+ /* Motion packet */
+ if (buf[0] & 0x80)
+ eeti_ts_report_event(eeti, buf);
+
+ return 0;
+}
+
static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
{
struct eeti_ts *eeti = dev_id;
- int len;
int error;
- char buf[6];
+
+ mutex_lock(&eeti->mutex);
do {
- len = i2c_master_recv(eeti->client, buf, sizeof(buf));
- if (len != sizeof(buf)) {
- error = len < 0 ? len : -EIO;
- dev_err(&eeti->client->dev,
- "failed to read touchscreen data: %d\n",
- error);
+ /*
+ * If we have attention GPIO, trust it. Otherwise we'll read
+ * once and exit. We assume that in this case we are using
+ * level triggered interrupt and it will get raised again
+ * if/when there is more data.
+ */
+ if (eeti->attn_gpio &&
+ !gpiod_get_value_cansleep(eeti->attn_gpio)) {
break;
}
- if (buf[0] & 0x80) {
- /* Motion packet */
- eeti_ts_report_event(eeti, buf);
- }
- } while (eeti->running &&
- eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio));
+ error = eeti_ts_read(eeti);
+ if (error)
+ break;
+ } while (eeti->running && eeti->attn_gpio);
+
+ mutex_unlock(&eeti->mutex);
return IRQ_HANDLED;
}
static void eeti_ts_start(struct eeti_ts *eeti)
{
+ mutex_lock(&eeti->mutex);
+
eeti->running = true;
- wmb();
enable_irq(eeti->client->irq);
+
+ /*
+ * Kick the controller in case we are using edge interrupt and
+ * we missed our edge while interrupt was disabled. We expect
+ * the attention GPIO to be wired in this case.
+ */
+ if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio))
+ eeti_ts_read(eeti);
+
+ mutex_unlock(&eeti->mutex);
}
static void eeti_ts_stop(struct eeti_ts *eeti)
{
+ /*
+ * Not locking here, just setting a flag and expect that the
+ * interrupt thread will notice the flag eventually.
+ */
eeti->running = false;
wmb();
disable_irq(eeti->client->irq);
@@ -153,6 +179,8 @@
return -ENOMEM;
}
+ mutex_init(&eeti->mutex);
+
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "Failed to allocate input device.\n");
diff --git a/drivers/input/touchscreen/egalax_ts_serial.c b/drivers/input/touchscreen/egalax_ts_serial.c
index 657bbae..375922d 100644
--- a/drivers/input/touchscreen/egalax_ts_serial.c
+++ b/drivers/input/touchscreen/egalax_ts_serial.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* EETI Egalax serial touchscreen driver
*
@@ -8,11 +9,6 @@
* Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett)
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c
index 0ed34ff..eadd389 100644
--- a/drivers/input/touchscreen/ektf2127.c
+++ b/drivers/input/touchscreen/ektf2127.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for ELAN eKTF2127 i2c touchscreen controller
*
* For this driver the layout of the Chipone icn8318 i2c
* touchscreencontroller is used.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
* Author:
* Michel Verlaan <michel.verl@gmail.com>
* Siebren Vroegindeweij <siebren.vroegindeweij@hotmail.com>
@@ -51,7 +47,7 @@
struct touchscreen_properties prop;
};
-static void ektf2127_parse_coordinates(const u8* buf, unsigned int touch_count,
+static void ektf2127_parse_coordinates(const u8 *buf, unsigned int touch_count,
struct input_mt_pos *touches)
{
int index = 0;
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index d21ca39..d4ad24e 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elan Microelectronics touch panels with I2C interface
*
@@ -10,7 +11,6 @@
* Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France
*
- *
* This code is partly based on i2c-hid.c:
*
* Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
@@ -18,11 +18,6 @@
* Copyright (c) 2012 Red Hat, Inc
*/
-/*
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- */
#include <linux/module.h>
#include <linux/input.h>
@@ -147,10 +142,11 @@
u8 cmd_resp[HEADER_SIZE];
struct completion cmd_done;
- u8 buf[MAX_PACKET_SIZE];
-
bool wake_irq_enabled;
bool keep_power_in_suspend;
+
+ /* Must be last to be used for DMA operations */
+ u8 buf[MAX_PACKET_SIZE] ____cacheline_aligned;
};
static int elants_i2c_send(struct i2c_client *client,
@@ -863,7 +859,7 @@
int i;
int len;
- len = i2c_master_recv(client, ts->buf, sizeof(ts->buf));
+ len = i2c_master_recv_dmasafe(client, ts->buf, sizeof(ts->buf));
if (len < 0) {
dev_err(&client->dev, "%s: failed to read data: %d\n",
__func__, len);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 7f2942f..d6772a2 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Elo serial touchscreen driver
*
* Copyright (c) 2004 Vojtech Pavlik
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* This driver can handle serial Elo touchscreens using either the Elo standard
diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c
index 37437a5..e007e2e 100644
--- a/drivers/input/touchscreen/exc3000.c
+++ b/drivers/input/touchscreen/exc3000.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for I2C connected EETI EXC3000 multiple touch controller
*
* Copyright (C) 2017 Ahmet Inan <inan@distec.de>
*
* minimal implementation based on egalax_ts.c and egalax_i2c.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/bitops.h>
diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c
index 1d6c8f4..60a7246 100644
--- a/drivers/input/touchscreen/fsl-imx25-tcq.c
+++ b/drivers/input/touchscreen/fsl-imx25-tcq.c
@@ -503,7 +503,6 @@
struct input_dev *idev;
struct mx25_tcq_priv *priv;
struct mx25_tsadc *tsadc = dev_get_drvdata(dev->parent);
- struct resource *res;
void __iomem *mem;
int error;
@@ -512,8 +511,7 @@
return -ENOMEM;
priv->dev = dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mem = devm_ioremap_resource(dev, res);
+ mem = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mem))
return PTR_ERR(mem);
@@ -528,10 +526,8 @@
}
priv->irq = platform_get_irq(pdev, 0);
- if (priv->irq <= 0) {
- dev_err(dev, "Failed to get IRQ\n");
+ if (priv->irq <= 0)
return priv->irq;
- }
idev = devm_input_allocate_device(dev);
if (!idev) {
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
index a0fbb45..3b0b8fc 100644
--- a/drivers/input/touchscreen/fujitsu_ts.c
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Fujitsu serial touchscreen driver
*
* Copyright (c) Dmitry Torokhov <dtor@mail.ru>
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index f2d9c2c..fb43aa7 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Goodix Touchscreens
*
@@ -9,11 +10,6 @@
* 2010 - 2012 Goodix Technology.
*/
-/*
- * 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.
- */
#include <linux/kernel.h>
#include <linux/dmi.h>
@@ -27,6 +23,7 @@
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/of.h>
@@ -47,6 +44,8 @@
struct touchscreen_properties prop;
unsigned int max_touch_num;
unsigned int int_trigger_type;
+ struct regulator *avdd28;
+ struct regulator *vddio;
struct gpio_desc *gpiod_int;
struct gpio_desc *gpiod_rst;
u16 id;
@@ -54,6 +53,7 @@
const char *cfg_name;
struct completion firmware_loading_complete;
unsigned long irq_flags;
+ unsigned int contact_size;
};
#define GOODIX_GPIO_INT_NAME "irq"
@@ -63,6 +63,7 @@
#define GOODIX_MAX_WIDTH 4096
#define GOODIX_INT_TRIGGER 1
#define GOODIX_CONTACT_SIZE 8
+#define GOODIX_MAX_CONTACT_SIZE 9
#define GOODIX_MAX_CONTACTS 10
#define GOODIX_CONFIG_MAX_LENGTH 240
@@ -145,6 +146,19 @@
{}
};
+static const struct dmi_system_id nine_bytes_report[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+ {
+ .ident = "Lenovo YogaBook",
+ /* YB1-X91L/F and YB1-X90L/F */
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9")
+ }
+ },
+#endif
+ {}
+};
+
/**
* goodix_i2c_read - read data from a register of the i2c slave device.
*
@@ -216,6 +230,8 @@
{
switch (id) {
case 1151:
+ case 5663:
+ case 5688:
return >1x_chip_data;
case 911:
@@ -248,7 +264,7 @@
max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT);
do {
error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR,
- data, GOODIX_CONTACT_SIZE + 1);
+ data, ts->contact_size + 1);
if (error) {
dev_err(&ts->client->dev, "I2C transfer error: %d\n",
error);
@@ -261,12 +277,12 @@
return -EPROTO;
if (touch_num > 1) {
- data += 1 + GOODIX_CONTACT_SIZE;
+ data += 1 + ts->contact_size;
error = goodix_i2c_read(ts->client,
GOODIX_READ_COOR_ADDR +
- 1 + GOODIX_CONTACT_SIZE,
+ 1 + ts->contact_size,
data,
- GOODIX_CONTACT_SIZE *
+ ts->contact_size *
(touch_num - 1));
if (error)
return error;
@@ -285,7 +301,7 @@
return 0;
}
-static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
+static void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data)
{
int id = coor_data[0] & 0x0F;
int input_x = get_unaligned_le16(&coor_data[1]);
@@ -300,6 +316,21 @@
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
}
+static void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data)
+{
+ int id = coor_data[1] & 0x0F;
+ int input_x = get_unaligned_le16(&coor_data[3]);
+ int input_y = get_unaligned_le16(&coor_data[5]);
+ int input_w = get_unaligned_le16(&coor_data[7]);
+
+ input_mt_slot(ts->input_dev, id);
+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
+ touchscreen_report_pos(ts->input_dev, &ts->prop,
+ input_x, input_y, true);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
+}
+
/**
* goodix_process_events - Process incoming events
*
@@ -310,7 +341,7 @@
*/
static void goodix_process_events(struct goodix_ts_data *ts)
{
- u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
+ u8 point_data[1 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
int touch_num;
int i;
@@ -325,8 +356,12 @@
input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
for (i = 0; i < touch_num; i++)
- goodix_ts_report_touch(ts,
- &point_data[1 + GOODIX_CONTACT_SIZE * i]);
+ if (ts->contact_size == 9)
+ goodix_ts_report_touch_9b(ts,
+ &point_data[1 + ts->contact_size * i]);
+ else
+ goodix_ts_report_touch_8b(ts,
+ &point_data[1 + ts->contact_size * i]);
input_mt_sync_frame(ts->input_dev);
input_sync(ts->input_dev);
@@ -531,6 +566,24 @@
return -EINVAL;
dev = &ts->client->dev;
+ ts->avdd28 = devm_regulator_get(dev, "AVDD28");
+ if (IS_ERR(ts->avdd28)) {
+ error = PTR_ERR(ts->avdd28);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev,
+ "Failed to get AVDD28 regulator: %d\n", error);
+ return error;
+ }
+
+ ts->vddio = devm_regulator_get(dev, "VDDIO");
+ if (IS_ERR(ts->vddio)) {
+ error = PTR_ERR(ts->vddio);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev,
+ "Failed to get VDDIO regulator: %d\n", error);
+ return error;
+ }
+
/* Get the interrupt GPIO pin number */
gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
if (IS_ERR(gpiod)) {
@@ -692,7 +745,9 @@
touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) {
- dev_err(&ts->client->dev, "Invalid config, using defaults\n");
+ dev_err(&ts->client->dev,
+ "Invalid config (%d, %d, %d), using defaults\n",
+ ts->prop.max_x, ts->prop.max_y, ts->max_touch_num);
ts->prop.max_x = GOODIX_MAX_WIDTH - 1;
ts->prop.max_y = GOODIX_MAX_HEIGHT - 1;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
@@ -709,6 +764,13 @@
"Applying '180 degrees rotated screen' quirk\n");
}
+ if (dmi_check_system(nine_bytes_report)) {
+ ts->contact_size = 9;
+
+ dev_dbg(&ts->client->dev,
+ "Non-standard 9-bytes report format quirk\n");
+ }
+
error = input_mt_init_slots(ts->input_dev, ts->max_touch_num,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error) {
@@ -761,6 +823,14 @@
complete_all(&ts->firmware_loading_complete);
}
+static void goodix_disable_regulators(void *arg)
+{
+ struct goodix_ts_data *ts = arg;
+
+ regulator_disable(ts->vddio);
+ regulator_disable(ts->avdd28);
+}
+
static int goodix_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -781,11 +851,35 @@
ts->client = client;
i2c_set_clientdata(client, ts);
init_completion(&ts->firmware_loading_complete);
+ ts->contact_size = GOODIX_CONTACT_SIZE;
error = goodix_get_gpio_config(ts);
if (error)
return error;
+ /* power up the controller */
+ error = regulator_enable(ts->avdd28);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to enable AVDD28 regulator: %d\n",
+ error);
+ return error;
+ }
+
+ error = regulator_enable(ts->vddio);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to enable VDDIO regulator: %d\n",
+ error);
+ regulator_disable(ts->avdd28);
+ return error;
+ }
+
+ error = devm_add_action_or_reset(&client->dev,
+ goodix_disable_regulators, ts);
+ if (error)
+ return error;
+
if (ts->gpiod_int && ts->gpiod_rst) {
/* reset the controller */
error = goodix_reset(ts);
@@ -942,6 +1036,8 @@
#ifdef CONFIG_OF
static const struct of_device_id goodix_of_match[] = {
{ .compatible = "goodix,gt1151" },
+ { .compatible = "goodix,gt5663" },
+ { .compatible = "goodix,gt5688" },
{ .compatible = "goodix,gt911" },
{ .compatible = "goodix,gt9110" },
{ .compatible = "goodix,gt912" },
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index 054c253..e07e8e0 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2000-2001 Vojtech Pavlik
*/
@@ -7,19 +8,6 @@
*/
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/errno.h>
@@ -53,7 +41,7 @@
char phys[32];
};
-static void gunze_process_packet(struct gunze* gunze)
+static void gunze_process_packet(struct gunze *gunze)
{
struct input_dev *dev = gunze->dev;
@@ -72,7 +60,7 @@
static irqreturn_t gunze_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
- struct gunze* gunze = serio_get_drvdata(serio);
+ struct gunze *gunze = serio_get_drvdata(serio);
if (data == '\r') {
gunze_process_packet(gunze);
diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c
index eb052d5..5c4d877 100644
--- a/drivers/input/touchscreen/hampshire.c
+++ b/drivers/input/touchscreen/hampshire.c
@@ -1,16 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Hampshire serial touchscreen driver
*
* Copyright (c) 2010 Adam Bennett
* Based on the dynapro driver (c) Tias Guns
- *
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* 2010/04/08 Adam Bennett <abennett72@gmail.com>
diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
index f1cd4dd..ddad4a8 100644
--- a/drivers/input/touchscreen/hideep.c
+++ b/drivers/input/touchscreen/hideep.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012-2017 Hideep, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2
- * as published by the Free Software Foudation.
*/
#include <linux/module.h>
@@ -814,8 +811,7 @@
if (error)
return error;
- ts->key_num = device_property_read_u32_array(dev, "linux,keycodes",
- NULL, 0);
+ ts->key_num = device_property_count_u32(dev, "linux,keycodes");
if (ts->key_num > HIDEEP_KEY_MAX) {
dev_err(dev, "too many keys defined: %d\n",
ts->key_num);
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index 85cf9be..818f2e4 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c
index 8fd9092..2f261a3 100644
--- a/drivers/input/touchscreen/htcpen.c
+++ b/drivers/input/touchscreen/htcpen.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HTC Shift touchscreen driver
*
* Copyright (C) 2008 Pau Oliva Fora <pof@eslack.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
*/
#include <linux/errno.h>
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
index 6f76eee..e900640 100644
--- a/drivers/input/touchscreen/ili210x.c
+++ b/drivers/input/touchscreen/ili210x.c
@@ -1,14 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
-#include <linux/input/ili210x.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <asm/unaligned.h>
-#define MAX_TOUCHES 2
+#define ILI210X_TOUCHES 2
+#define ILI251X_TOUCHES 10
#define DEFAULT_POLL_PERIOD 20
/* Touchscreen commands */
@@ -17,41 +22,32 @@
#define REG_FIRMWARE_VERSION 0x40
#define REG_CALIBRATE 0xcc
-struct finger {
- u8 x_low;
- u8 x_high;
- u8 y_low;
- u8 y_high;
-} __packed;
-
-struct touchdata {
- u8 status;
- struct finger finger[MAX_TOUCHES];
-} __packed;
-
-struct panel_info {
- struct finger finger_max;
- u8 xchannel_num;
- u8 ychannel_num;
-} __packed;
-
struct firmware_version {
u8 id;
u8 major;
u8 minor;
} __packed;
+enum ili2xxx_model {
+ MODEL_ILI210X,
+ MODEL_ILI251X,
+};
+
struct ili210x {
struct i2c_client *client;
struct input_dev *input;
- bool (*get_pendown_state)(void);
unsigned int poll_period;
struct delayed_work dwork;
+ struct gpio_desc *reset_gpio;
+ struct touchscreen_properties prop;
+ enum ili2xxx_model model;
+ unsigned int max_touches;
};
static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
size_t len)
{
+ struct ili210x *priv = i2c_get_clientdata(client);
struct i2c_msg msg[2] = {
{
.addr = client->addr,
@@ -67,7 +63,38 @@
}
};
- if (i2c_transfer(client->adapter, msg, 2) != 2) {
+ if (priv->model == MODEL_ILI251X) {
+ if (i2c_transfer(client->adapter, msg, 1) != 1) {
+ dev_err(&client->dev, "i2c transfer failed\n");
+ return -EIO;
+ }
+
+ usleep_range(5000, 5500);
+
+ if (i2c_transfer(client->adapter, msg + 1, 1) != 1) {
+ dev_err(&client->dev, "i2c transfer failed\n");
+ return -EIO;
+ }
+ } else {
+ if (i2c_transfer(client->adapter, msg, 2) != 2) {
+ dev_err(&client->dev, "i2c transfer failed\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int ili210x_read(struct i2c_client *client, void *buf, size_t len)
+{
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = buf,
+ };
+
+ if (i2c_transfer(client->adapter, &msg, 1) != 1) {
dev_err(&client->dev, "i2c transfer failed\n");
return -EIO;
}
@@ -75,42 +102,72 @@
return 0;
}
-static void ili210x_report_events(struct input_dev *input,
- const struct touchdata *touchdata)
+static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
+ unsigned int finger,
+ unsigned int *x, unsigned int *y)
{
+ if (finger >= ILI210X_TOUCHES)
+ return false;
+
+ if (touchdata[0] & BIT(finger))
+ return false;
+
+ *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0);
+ *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2);
+
+ return true;
+}
+
+static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
+ unsigned int finger,
+ unsigned int *x, unsigned int *y)
+{
+ if (finger >= ILI251X_TOUCHES)
+ return false;
+
+ *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0);
+ if (!(*x & BIT(15))) /* Touch indication */
+ return false;
+
+ *x &= 0x3fff;
+ *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2);
+
+ return true;
+}
+
+static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
+{
+ struct input_dev *input = priv->input;
int i;
- bool touch;
- unsigned int x, y;
- const struct finger *finger;
+ bool contact = false, touch = false;
+ unsigned int x = 0, y = 0;
- for (i = 0; i < MAX_TOUCHES; i++) {
- input_mt_slot(input, i);
-
- finger = &touchdata->finger[i];
-
- touch = touchdata->status & (1 << i);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
- if (touch) {
- x = finger->x_low | (finger->x_high << 8);
- y = finger->y_low | (finger->y_high << 8);
-
- input_report_abs(input, ABS_MT_POSITION_X, x);
- input_report_abs(input, ABS_MT_POSITION_Y, y);
+ for (i = 0; i < priv->max_touches; i++) {
+ if (priv->model == MODEL_ILI210X) {
+ touch = ili210x_touchdata_to_coords(priv, touchdata,
+ i, &x, &y);
+ } else if (priv->model == MODEL_ILI251X) {
+ touch = ili251x_touchdata_to_coords(priv, touchdata,
+ i, &x, &y);
+ if (touch)
+ contact = true;
}
+
+ input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+ if (!touch)
+ continue;
+ touchscreen_report_pos(input, &priv->prop, x, y,
+ true);
}
input_mt_report_pointer_emulation(input, false);
input_sync(input);
-}
-static bool get_pendown_state(const struct ili210x *priv)
-{
- bool state = false;
+ if (priv->model == MODEL_ILI210X)
+ contact = touchdata[0] & 0xf3;
- if (priv->get_pendown_state)
- state = priv->get_pendown_state();
-
- return state;
+ return contact;
}
static void ili210x_work(struct work_struct *work)
@@ -118,20 +175,29 @@
struct ili210x *priv = container_of(work, struct ili210x,
dwork.work);
struct i2c_client *client = priv->client;
- struct touchdata touchdata;
- int error;
+ u8 touchdata[64] = { 0 };
+ bool touch;
+ int error = -EINVAL;
- error = ili210x_read_reg(client, REG_TOUCHDATA,
- &touchdata, sizeof(touchdata));
+ if (priv->model == MODEL_ILI210X) {
+ error = ili210x_read_reg(client, REG_TOUCHDATA,
+ touchdata, sizeof(touchdata));
+ } else if (priv->model == MODEL_ILI251X) {
+ error = ili210x_read_reg(client, REG_TOUCHDATA,
+ touchdata, 31);
+ if (!error && touchdata[0] == 2)
+ error = ili210x_read(client, &touchdata[31], 20);
+ }
+
if (error) {
dev_err(&client->dev,
"Unable to get touchdata, err = %d\n", error);
return;
}
- ili210x_report_events(priv->input, &touchdata);
+ touch = ili210x_report_events(priv, touchdata);
- if ((touchdata.status & 0xf3) || get_pendown_state(priv))
+ if (touch)
schedule_delayed_work(&priv->dwork,
msecs_to_jiffies(priv->poll_period));
}
@@ -180,30 +246,76 @@
.attrs = ili210x_attributes,
};
+static void ili210x_power_down(void *data)
+{
+ struct gpio_desc *reset_gpio = data;
+
+ gpiod_set_value_cansleep(reset_gpio, 1);
+}
+
+static void ili210x_cancel_work(void *data)
+{
+ struct ili210x *priv = data;
+
+ cancel_delayed_work_sync(&priv->dwork);
+}
+
static int ili210x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
- const struct ili210x_platform_data *pdata = dev_get_platdata(dev);
struct ili210x *priv;
+ struct gpio_desc *reset_gpio;
struct input_dev *input;
- struct panel_info panel;
struct firmware_version firmware;
- int xmax, ymax;
+ enum ili2xxx_model model;
int error;
- dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
+ model = (enum ili2xxx_model)id->driver_data;
- if (!pdata) {
- dev_err(dev, "No platform data!\n");
- return -EINVAL;
- }
+ dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
if (client->irq <= 0) {
dev_err(dev, "No IRQ!\n");
return -EINVAL;
}
+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpio))
+ return PTR_ERR(reset_gpio);
+
+ if (reset_gpio) {
+ error = devm_add_action_or_reset(dev, ili210x_power_down,
+ reset_gpio);
+ if (error)
+ return error;
+
+ usleep_range(50, 100);
+ gpiod_set_value_cansleep(reset_gpio, 0);
+ msleep(100);
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
+
+ priv->client = client;
+ priv->input = input;
+ priv->poll_period = DEFAULT_POLL_PERIOD;
+ INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
+ priv->reset_gpio = reset_gpio;
+ priv->model = model;
+ if (model == MODEL_ILI210X)
+ priv->max_touches = ILI210X_TOUCHES;
+ if (model == MODEL_ILI251X)
+ priv->max_touches = ILI251X_TOUCHES;
+
+ i2c_set_clientdata(client, priv);
+
/* Get firmware version */
error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
&firmware, sizeof(firmware));
@@ -213,70 +325,40 @@
return error;
}
- /* get panel info */
- error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
- if (error) {
- dev_err(dev, "Failed to get panel information, err: %d\n",
- error);
- return error;
- }
-
- xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8);
- ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8);
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- input = input_allocate_device();
- if (!priv || !input) {
- error = -ENOMEM;
- goto err_free_mem;
- }
-
- priv->client = client;
- priv->input = input;
- priv->get_pendown_state = pdata->get_pendown_state;
- priv->poll_period = pdata->poll_period ? : DEFAULT_POLL_PERIOD;
- INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
-
/* Setup input device */
input->name = "ILI210x Touchscreen";
input->id.bustype = BUS_I2C;
input->dev.parent = dev;
- __set_bit(EV_SYN, input->evbit);
- __set_bit(EV_KEY, input->evbit);
- __set_bit(EV_ABS, input->evbit);
- __set_bit(BTN_TOUCH, input->keybit);
-
- /* Single touch */
- input_set_abs_params(input, ABS_X, 0, xmax, 0, 0);
- input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
-
/* Multi touch */
- input_mt_init_slots(input, MAX_TOUCHES, 0);
- input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0);
+ touchscreen_parse_properties(input, true, &priv->prop);
+ input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT);
- i2c_set_clientdata(client, priv);
+ error = devm_add_action(dev, ili210x_cancel_work, priv);
+ if (error)
+ return error;
- error = request_irq(client->irq, ili210x_irq, pdata->irq_flags,
- client->name, priv);
+ error = devm_request_irq(dev, client->irq, ili210x_irq, 0,
+ client->name, priv);
if (error) {
dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
error);
- goto err_free_mem;
+ return error;
}
- error = sysfs_create_group(&dev->kobj, &ili210x_attr_group);
+ error = devm_device_add_group(dev, &ili210x_attr_group);
if (error) {
dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
error);
- goto err_free_irq;
+ return error;
}
error = input_register_device(priv->input);
if (error) {
dev_err(dev, "Cannot register input device, err: %d\n", error);
- goto err_remove_sysfs;
+ return error;
}
device_init_wakeup(dev, 1);
@@ -286,28 +368,6 @@
client->irq, firmware.id, firmware.major, firmware.minor);
return 0;
-
-err_remove_sysfs:
- sysfs_remove_group(&dev->kobj, &ili210x_attr_group);
-err_free_irq:
- free_irq(client->irq, priv);
-err_free_mem:
- input_free_device(input);
- kfree(priv);
- return error;
-}
-
-static int ili210x_i2c_remove(struct i2c_client *client)
-{
- struct ili210x *priv = i2c_get_clientdata(client);
-
- sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group);
- free_irq(priv->client->irq, priv);
- cancel_delayed_work_sync(&priv->dwork);
- input_unregister_device(priv->input);
- kfree(priv);
-
- return 0;
}
static int __maybe_unused ili210x_i2c_suspend(struct device *dev)
@@ -334,19 +394,27 @@
ili210x_i2c_suspend, ili210x_i2c_resume);
static const struct i2c_device_id ili210x_i2c_id[] = {
- { "ili210x", 0 },
+ { "ili210x", MODEL_ILI210X },
+ { "ili251x", MODEL_ILI251X },
{ }
};
MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
+static const struct of_device_id ili210x_dt_ids[] = {
+ { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X },
+ { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ili210x_dt_ids);
+
static struct i2c_driver ili210x_ts_driver = {
.driver = {
.name = "ili210x_i2c",
.pm = &ili210x_i2c_pm,
+ .of_match_table = ili210x_dt_ids,
},
.id_table = ili210x_i2c_id,
.probe = ili210x_i2c_probe,
- .remove = ili210x_i2c_remove,
};
module_i2c_driver(ili210x_ts_driver);
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index c10fc59..9ed2588 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -364,8 +364,6 @@
struct device_node *np = pdev->dev.of_node;
struct imx6ul_tsc *tsc;
struct input_dev *input_dev;
- struct resource *tsc_mem;
- struct resource *adc_mem;
int err;
int tsc_irq;
int adc_irq;
@@ -403,16 +401,14 @@
return err;
}
- tsc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- tsc->tsc_regs = devm_ioremap_resource(&pdev->dev, tsc_mem);
+ tsc->tsc_regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(tsc->tsc_regs)) {
err = PTR_ERR(tsc->tsc_regs);
dev_err(&pdev->dev, "failed to remap tsc memory: %d\n", err);
return err;
}
- adc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- tsc->adc_regs = devm_ioremap_resource(&pdev->dev, adc_mem);
+ tsc->adc_regs = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(tsc->adc_regs)) {
err = PTR_ERR(tsc->adc_regs);
dev_err(&pdev->dev, "failed to remap adc memory: %d\n", err);
@@ -434,16 +430,12 @@
}
tsc_irq = platform_get_irq(pdev, 0);
- if (tsc_irq < 0) {
- dev_err(&pdev->dev, "no tsc irq resource?\n");
+ if (tsc_irq < 0)
return tsc_irq;
- }
adc_irq = platform_get_irq(pdev, 1);
- if (adc_irq < 0) {
- dev_err(&pdev->dev, "no adc irq resource?\n");
+ if (adc_irq < 0)
return adc_irq;
- }
err = devm_request_threaded_irq(tsc->dev, tsc_irq,
NULL, tsc_irq_fn, IRQF_ONESHOT,
diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c
index b9bc562..1d7e4c3 100644
--- a/drivers/input/touchscreen/inexio.c
+++ b/drivers/input/touchscreen/inexio.c
@@ -1,16 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* iNexio serial touchscreen driver
*
* Copyright (c) 2008 Richard Lemon
* Based on the mtouch driver (c) Vojtech Pavlik and Dan Streetman
- *
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* 2008/06/19 Richard Lemon <richard@codelemon.com>
@@ -79,7 +74,7 @@
static irqreturn_t inexio_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
- struct inexio* pinexio = serio_get_drvdata(serio);
+ struct inexio *pinexio = serio_get_drvdata(serio);
pinexio->data[pinexio->idx] = data;
@@ -97,7 +92,7 @@
static void inexio_disconnect(struct serio *serio)
{
- struct inexio* pinexio = serio_get_drvdata(serio);
+ struct inexio *pinexio = serio_get_drvdata(serio);
input_get_device(pinexio->dev);
input_unregister_device(pinexio->dev);
diff --git a/drivers/input/touchscreen/ipaq-micro-ts.c b/drivers/input/touchscreen/ipaq-micro-ts.c
index 33c1348..5c3977e 100644
--- a/drivers/input/touchscreen/ipaq-micro-ts.c
+++ b/drivers/input/touchscreen/ipaq-micro-ts.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*
* h3600 atmel micro companion support, touchscreen subdevice
* Author : Alessandro Gardich <gremlin@gremlin.it>
* Author : Dmitry Artamonow <mad_soft@inbox.ru>
* Author : Linus Walleij <linus.walleij@linaro.org>
- *
*/
#include <asm/byteorder.h>
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
new file mode 100644
index 0000000..5875bb1
--- /dev/null
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -0,0 +1,1133 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
+ *
+ * Copyright (C) 2018
+ * Author: Jeff LaBundy <jeff@labundy.com>
+ *
+ * These devices require firmware exported from a PC-based configuration tool
+ * made available by the vendor. Firmware files may be pushed to the device's
+ * nonvolatile memory by writing the filename to the 'fw_file' sysfs control.
+ *
+ * Link to PC-based configuration tool and data sheet: http://www.azoteq.com/
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define IQS5XX_FW_FILE_LEN 64
+#define IQS5XX_NUM_RETRIES 10
+#define IQS5XX_NUM_POINTS 256
+#define IQS5XX_NUM_CONTACTS 5
+#define IQS5XX_WR_BYTES_MAX 2
+
+#define IQS5XX_PROD_NUM_IQS550 40
+#define IQS5XX_PROD_NUM_IQS572 58
+#define IQS5XX_PROD_NUM_IQS525 52
+#define IQS5XX_PROJ_NUM_A000 0
+#define IQS5XX_PROJ_NUM_B000 15
+#define IQS5XX_MAJOR_VER_MIN 2
+
+#define IQS5XX_RESUME 0x00
+#define IQS5XX_SUSPEND 0x01
+
+#define IQS5XX_SW_INPUT_EVENT 0x10
+#define IQS5XX_SETUP_COMPLETE 0x40
+#define IQS5XX_EVENT_MODE 0x01
+#define IQS5XX_TP_EVENT 0x04
+
+#define IQS5XX_FLIP_X 0x01
+#define IQS5XX_FLIP_Y 0x02
+#define IQS5XX_SWITCH_XY_AXIS 0x04
+
+#define IQS5XX_PROD_NUM 0x0000
+#define IQS5XX_ABS_X 0x0016
+#define IQS5XX_ABS_Y 0x0018
+#define IQS5XX_SYS_CTRL0 0x0431
+#define IQS5XX_SYS_CTRL1 0x0432
+#define IQS5XX_SYS_CFG0 0x058E
+#define IQS5XX_SYS_CFG1 0x058F
+#define IQS5XX_TOTAL_RX 0x063D
+#define IQS5XX_TOTAL_TX 0x063E
+#define IQS5XX_XY_CFG0 0x0669
+#define IQS5XX_X_RES 0x066E
+#define IQS5XX_Y_RES 0x0670
+#define IQS5XX_CHKSM 0x83C0
+#define IQS5XX_APP 0x8400
+#define IQS5XX_CSTM 0xBE00
+#define IQS5XX_PMAP_END 0xBFFF
+#define IQS5XX_END_COMM 0xEEEE
+
+#define IQS5XX_CHKSM_LEN (IQS5XX_APP - IQS5XX_CHKSM)
+#define IQS5XX_APP_LEN (IQS5XX_CSTM - IQS5XX_APP)
+#define IQS5XX_CSTM_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CSTM)
+#define IQS5XX_PMAP_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CHKSM)
+
+#define IQS5XX_REC_HDR_LEN 4
+#define IQS5XX_REC_LEN_MAX 255
+#define IQS5XX_REC_TYPE_DATA 0x00
+#define IQS5XX_REC_TYPE_EOF 0x01
+
+#define IQS5XX_BL_ADDR_MASK 0x40
+#define IQS5XX_BL_CMD_VER 0x00
+#define IQS5XX_BL_CMD_READ 0x01
+#define IQS5XX_BL_CMD_EXEC 0x02
+#define IQS5XX_BL_CMD_CRC 0x03
+#define IQS5XX_BL_BLK_LEN_MAX 64
+#define IQS5XX_BL_ID 0x0200
+#define IQS5XX_BL_STATUS_RESET 0x00
+#define IQS5XX_BL_STATUS_AVAIL 0xA5
+#define IQS5XX_BL_STATUS_NONE 0xEE
+#define IQS5XX_BL_CRC_PASS 0x00
+#define IQS5XX_BL_CRC_FAIL 0x01
+#define IQS5XX_BL_ATTEMPTS 3
+
+struct iqs5xx_private {
+ struct i2c_client *client;
+ struct input_dev *input;
+ struct gpio_desc *reset_gpio;
+ struct mutex lock;
+ u8 bl_status;
+};
+
+struct iqs5xx_dev_id_info {
+ __be16 prod_num;
+ __be16 proj_num;
+ u8 major_ver;
+ u8 minor_ver;
+ u8 bl_status;
+} __packed;
+
+struct iqs5xx_ihex_rec {
+ char start;
+ char len[2];
+ char addr[4];
+ char type[2];
+ char data[2];
+} __packed;
+
+struct iqs5xx_touch_data {
+ __be16 abs_x;
+ __be16 abs_y;
+ __be16 strength;
+ u8 area;
+} __packed;
+
+static int iqs5xx_read_burst(struct i2c_client *client,
+ u16 reg, void *val, u16 len)
+{
+ __be16 reg_buf = cpu_to_be16(reg);
+ int ret, i;
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = sizeof(reg_buf),
+ .buf = (u8 *)®_buf,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = (u8 *)val,
+ },
+ };
+
+ /*
+ * The first addressing attempt outside of a communication window fails
+ * and must be retried, after which the device clock stretches until it
+ * is available.
+ */
+ for (i = 0; i < IQS5XX_NUM_RETRIES; i++) {
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (ret == ARRAY_SIZE(msg))
+ return 0;
+
+ usleep_range(200, 300);
+ }
+
+ if (ret >= 0)
+ ret = -EIO;
+
+ dev_err(&client->dev, "Failed to read from address 0x%04X: %d\n",
+ reg, ret);
+
+ return ret;
+}
+
+static int iqs5xx_read_word(struct i2c_client *client, u16 reg, u16 *val)
+{
+ __be16 val_buf;
+ int error;
+
+ error = iqs5xx_read_burst(client, reg, &val_buf, sizeof(val_buf));
+ if (error)
+ return error;
+
+ *val = be16_to_cpu(val_buf);
+
+ return 0;
+}
+
+static int iqs5xx_read_byte(struct i2c_client *client, u16 reg, u8 *val)
+{
+ return iqs5xx_read_burst(client, reg, val, sizeof(*val));
+}
+
+static int iqs5xx_write_burst(struct i2c_client *client,
+ u16 reg, const void *val, u16 len)
+{
+ int ret, i;
+ u16 mlen = sizeof(reg) + len;
+ u8 mbuf[sizeof(reg) + IQS5XX_WR_BYTES_MAX];
+
+ if (len > IQS5XX_WR_BYTES_MAX)
+ return -EINVAL;
+
+ put_unaligned_be16(reg, mbuf);
+ memcpy(mbuf + sizeof(reg), val, len);
+
+ /*
+ * The first addressing attempt outside of a communication window fails
+ * and must be retried, after which the device clock stretches until it
+ * is available.
+ */
+ for (i = 0; i < IQS5XX_NUM_RETRIES; i++) {
+ ret = i2c_master_send(client, mbuf, mlen);
+ if (ret == mlen)
+ return 0;
+
+ usleep_range(200, 300);
+ }
+
+ if (ret >= 0)
+ ret = -EIO;
+
+ dev_err(&client->dev, "Failed to write to address 0x%04X: %d\n",
+ reg, ret);
+
+ return ret;
+}
+
+static int iqs5xx_write_word(struct i2c_client *client, u16 reg, u16 val)
+{
+ __be16 val_buf = cpu_to_be16(val);
+
+ return iqs5xx_write_burst(client, reg, &val_buf, sizeof(val_buf));
+}
+
+static int iqs5xx_write_byte(struct i2c_client *client, u16 reg, u8 val)
+{
+ return iqs5xx_write_burst(client, reg, &val, sizeof(val));
+}
+
+static void iqs5xx_reset(struct i2c_client *client)
+{
+ struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+
+ gpiod_set_value_cansleep(iqs5xx->reset_gpio, 1);
+ usleep_range(200, 300);
+
+ gpiod_set_value_cansleep(iqs5xx->reset_gpio, 0);
+}
+
+static int iqs5xx_bl_cmd(struct i2c_client *client, u8 bl_cmd, u16 bl_addr)
+{
+ struct i2c_msg msg;
+ int ret;
+ u8 mbuf[sizeof(bl_cmd) + sizeof(bl_addr)];
+
+ msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK;
+ msg.flags = 0;
+ msg.len = sizeof(bl_cmd);
+ msg.buf = mbuf;
+
+ *mbuf = bl_cmd;
+
+ switch (bl_cmd) {
+ case IQS5XX_BL_CMD_VER:
+ case IQS5XX_BL_CMD_CRC:
+ case IQS5XX_BL_CMD_EXEC:
+ break;
+ case IQS5XX_BL_CMD_READ:
+ msg.len += sizeof(bl_addr);
+ put_unaligned_be16(bl_addr, mbuf + sizeof(bl_cmd));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret != 1)
+ goto msg_fail;
+
+ switch (bl_cmd) {
+ case IQS5XX_BL_CMD_VER:
+ msg.len = sizeof(u16);
+ break;
+ case IQS5XX_BL_CMD_CRC:
+ msg.len = sizeof(u8);
+ /*
+ * This delay saves the bus controller the trouble of having to
+ * tolerate a relatively long clock-stretching period while the
+ * CRC is calculated.
+ */
+ msleep(50);
+ break;
+ case IQS5XX_BL_CMD_EXEC:
+ usleep_range(10000, 10100);
+ /* fall through */
+ default:
+ return 0;
+ }
+
+ msg.flags = I2C_M_RD;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret != 1)
+ goto msg_fail;
+
+ if (bl_cmd == IQS5XX_BL_CMD_VER &&
+ get_unaligned_be16(mbuf) != IQS5XX_BL_ID) {
+ dev_err(&client->dev, "Unrecognized bootloader ID: 0x%04X\n",
+ get_unaligned_be16(mbuf));
+ return -EINVAL;
+ }
+
+ if (bl_cmd == IQS5XX_BL_CMD_CRC && *mbuf != IQS5XX_BL_CRC_PASS) {
+ dev_err(&client->dev, "Bootloader CRC failed\n");
+ return -EIO;
+ }
+
+ return 0;
+
+msg_fail:
+ if (ret >= 0)
+ ret = -EIO;
+
+ if (bl_cmd != IQS5XX_BL_CMD_VER)
+ dev_err(&client->dev,
+ "Unsuccessful bootloader command 0x%02X: %d\n",
+ bl_cmd, ret);
+
+ return ret;
+}
+
+static int iqs5xx_bl_open(struct i2c_client *client)
+{
+ int error, i, j;
+
+ /*
+ * The device opens a bootloader polling window for 2 ms following the
+ * release of reset. If the host cannot establish communication during
+ * this time frame, it must cycle reset again.
+ */
+ for (i = 0; i < IQS5XX_BL_ATTEMPTS; i++) {
+ iqs5xx_reset(client);
+
+ for (j = 0; j < IQS5XX_NUM_RETRIES; j++) {
+ error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
+ if (!error || error == -EINVAL)
+ return error;
+ }
+ }
+
+ dev_err(&client->dev, "Failed to open bootloader: %d\n", error);
+
+ return error;
+}
+
+static int iqs5xx_bl_write(struct i2c_client *client,
+ u16 bl_addr, u8 *pmap_data, u16 pmap_len)
+{
+ struct i2c_msg msg;
+ int ret, i;
+ u8 mbuf[sizeof(bl_addr) + IQS5XX_BL_BLK_LEN_MAX];
+
+ if (pmap_len % IQS5XX_BL_BLK_LEN_MAX)
+ return -EINVAL;
+
+ msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK;
+ msg.flags = 0;
+ msg.len = sizeof(mbuf);
+ msg.buf = mbuf;
+
+ for (i = 0; i < pmap_len; i += IQS5XX_BL_BLK_LEN_MAX) {
+ put_unaligned_be16(bl_addr + i, mbuf);
+ memcpy(mbuf + sizeof(bl_addr), pmap_data + i,
+ sizeof(mbuf) - sizeof(bl_addr));
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret != 1)
+ goto msg_fail;
+
+ usleep_range(10000, 10100);
+ }
+
+ return 0;
+
+msg_fail:
+ if (ret >= 0)
+ ret = -EIO;
+
+ dev_err(&client->dev, "Failed to write block at address 0x%04X: %d\n",
+ bl_addr + i, ret);
+
+ return ret;
+}
+
+static int iqs5xx_bl_verify(struct i2c_client *client,
+ u16 bl_addr, u8 *pmap_data, u16 pmap_len)
+{
+ struct i2c_msg msg;
+ int ret, i;
+ u8 bl_data[IQS5XX_BL_BLK_LEN_MAX];
+
+ if (pmap_len % IQS5XX_BL_BLK_LEN_MAX)
+ return -EINVAL;
+
+ msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK;
+ msg.flags = I2C_M_RD;
+ msg.len = sizeof(bl_data);
+ msg.buf = bl_data;
+
+ for (i = 0; i < pmap_len; i += IQS5XX_BL_BLK_LEN_MAX) {
+ ret = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_READ, bl_addr + i);
+ if (ret)
+ return ret;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret != 1)
+ goto msg_fail;
+
+ if (memcmp(bl_data, pmap_data + i, sizeof(bl_data))) {
+ dev_err(&client->dev,
+ "Failed to verify block at address 0x%04X\n",
+ bl_addr + i);
+ return -EIO;
+ }
+ }
+
+ return 0;
+
+msg_fail:
+ if (ret >= 0)
+ ret = -EIO;
+
+ dev_err(&client->dev, "Failed to read block at address 0x%04X: %d\n",
+ bl_addr + i, ret);
+
+ return ret;
+}
+
+static int iqs5xx_set_state(struct i2c_client *client, u8 state)
+{
+ struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+ int error1, error2;
+
+ if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
+ return 0;
+
+ mutex_lock(&iqs5xx->lock);
+
+ /*
+ * Addressing the device outside of a communication window prompts it
+ * to assert the RDY output, so disable the interrupt line to prevent
+ * the handler from servicing a false interrupt.
+ */
+ disable_irq(client->irq);
+
+ error1 = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL1, state);
+ error2 = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
+
+ usleep_range(50, 100);
+ enable_irq(client->irq);
+
+ mutex_unlock(&iqs5xx->lock);
+
+ if (error1)
+ return error1;
+
+ return error2;
+}
+
+static int iqs5xx_open(struct input_dev *input)
+{
+ struct iqs5xx_private *iqs5xx = input_get_drvdata(input);
+
+ return iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
+}
+
+static void iqs5xx_close(struct input_dev *input)
+{
+ struct iqs5xx_private *iqs5xx = input_get_drvdata(input);
+
+ iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
+}
+
+static int iqs5xx_axis_init(struct i2c_client *client)
+{
+ struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+ struct touchscreen_properties prop;
+ struct input_dev *input;
+ int error;
+ u16 max_x, max_x_hw;
+ u16 max_y, max_y_hw;
+ u8 val;
+
+ if (!iqs5xx->input) {
+ input = devm_input_allocate_device(&client->dev);
+ if (!input)
+ return -ENOMEM;
+
+ input->name = client->name;
+ input->id.bustype = BUS_I2C;
+ input->open = iqs5xx_open;
+ input->close = iqs5xx_close;
+
+ input_set_capability(input, EV_ABS, ABS_MT_POSITION_X);
+ input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y);
+ input_set_capability(input, EV_ABS, ABS_MT_PRESSURE);
+
+ input_set_drvdata(input, iqs5xx);
+ iqs5xx->input = input;
+ }
+
+ touchscreen_parse_properties(iqs5xx->input, true, &prop);
+
+ error = iqs5xx_read_byte(client, IQS5XX_TOTAL_RX, &val);
+ if (error)
+ return error;
+ max_x_hw = (val - 1) * IQS5XX_NUM_POINTS;
+
+ error = iqs5xx_read_byte(client, IQS5XX_TOTAL_TX, &val);
+ if (error)
+ return error;
+ max_y_hw = (val - 1) * IQS5XX_NUM_POINTS;
+
+ error = iqs5xx_read_byte(client, IQS5XX_XY_CFG0, &val);
+ if (error)
+ return error;
+
+ if (val & IQS5XX_SWITCH_XY_AXIS)
+ swap(max_x_hw, max_y_hw);
+
+ if (prop.swap_x_y)
+ val ^= IQS5XX_SWITCH_XY_AXIS;
+
+ if (prop.invert_x)
+ val ^= prop.swap_x_y ? IQS5XX_FLIP_Y : IQS5XX_FLIP_X;
+
+ if (prop.invert_y)
+ val ^= prop.swap_x_y ? IQS5XX_FLIP_X : IQS5XX_FLIP_Y;
+
+ error = iqs5xx_write_byte(client, IQS5XX_XY_CFG0, val);
+ if (error)
+ return error;
+
+ if (prop.max_x > max_x_hw) {
+ dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n",
+ prop.max_x, max_x_hw);
+ return -EINVAL;
+ } else if (prop.max_x == 0) {
+ error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x);
+ if (error)
+ return error;
+
+ input_abs_set_max(iqs5xx->input,
+ prop.swap_x_y ? ABS_MT_POSITION_Y :
+ ABS_MT_POSITION_X,
+ max_x);
+ } else {
+ max_x = (u16)prop.max_x;
+ }
+
+ if (prop.max_y > max_y_hw) {
+ dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n",
+ prop.max_y, max_y_hw);
+ return -EINVAL;
+ } else if (prop.max_y == 0) {
+ error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y);
+ if (error)
+ return error;
+
+ input_abs_set_max(iqs5xx->input,
+ prop.swap_x_y ? ABS_MT_POSITION_X :
+ ABS_MT_POSITION_Y,
+ max_y);
+ } else {
+ max_y = (u16)prop.max_y;
+ }
+
+ /*
+ * Write horizontal and vertical resolution to the device in case its
+ * original defaults were overridden or swapped as per the properties
+ * specified in the device tree.
+ */
+ error = iqs5xx_write_word(client,
+ prop.swap_x_y ? IQS5XX_Y_RES : IQS5XX_X_RES,
+ max_x);
+ if (error)
+ return error;
+
+ error = iqs5xx_write_word(client,
+ prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES,
+ max_y);
+ if (error)
+ return error;
+
+ error = input_mt_init_slots(iqs5xx->input, IQS5XX_NUM_CONTACTS,
+ INPUT_MT_DIRECT);
+ if (error)
+ dev_err(&client->dev, "Failed to initialize slots: %d\n",
+ error);
+
+ return error;
+}
+
+static int iqs5xx_dev_init(struct i2c_client *client)
+{
+ struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+ struct iqs5xx_dev_id_info *dev_id_info;
+ int error;
+ u8 val;
+ u8 buf[sizeof(*dev_id_info) + 1];
+
+ error = iqs5xx_read_burst(client, IQS5XX_PROD_NUM,
+ &buf[1], sizeof(*dev_id_info));
+ if (error)
+ return iqs5xx_bl_open(client);
+
+ /*
+ * A000 and B000 devices use 8-bit and 16-bit addressing, respectively.
+ * Querying an A000 device's version information with 16-bit addressing
+ * gives the appearance that the data is shifted by one byte; a nonzero
+ * leading array element suggests this could be the case (in which case
+ * the missing zero is prepended).
+ */
+ buf[0] = 0;
+ dev_id_info = (struct iqs5xx_dev_id_info *)&buf[(buf[1] > 0) ? 0 : 1];
+
+ switch (be16_to_cpu(dev_id_info->prod_num)) {
+ case IQS5XX_PROD_NUM_IQS550:
+ case IQS5XX_PROD_NUM_IQS572:
+ case IQS5XX_PROD_NUM_IQS525:
+ break;
+ default:
+ dev_err(&client->dev, "Unrecognized product number: %u\n",
+ be16_to_cpu(dev_id_info->prod_num));
+ return -EINVAL;
+ }
+
+ switch (be16_to_cpu(dev_id_info->proj_num)) {
+ case IQS5XX_PROJ_NUM_A000:
+ dev_err(&client->dev, "Unsupported project number: %u\n",
+ be16_to_cpu(dev_id_info->proj_num));
+ return iqs5xx_bl_open(client);
+ case IQS5XX_PROJ_NUM_B000:
+ break;
+ default:
+ dev_err(&client->dev, "Unrecognized project number: %u\n",
+ be16_to_cpu(dev_id_info->proj_num));
+ return -EINVAL;
+ }
+
+ if (dev_id_info->major_ver < IQS5XX_MAJOR_VER_MIN) {
+ dev_err(&client->dev, "Unsupported major version: %u\n",
+ dev_id_info->major_ver);
+ return iqs5xx_bl_open(client);
+ }
+
+ switch (dev_id_info->bl_status) {
+ case IQS5XX_BL_STATUS_AVAIL:
+ case IQS5XX_BL_STATUS_NONE:
+ break;
+ default:
+ dev_err(&client->dev,
+ "Unrecognized bootloader status: 0x%02X\n",
+ dev_id_info->bl_status);
+ return -EINVAL;
+ }
+
+ error = iqs5xx_axis_init(client);
+ if (error)
+ return error;
+
+ error = iqs5xx_read_byte(client, IQS5XX_SYS_CFG0, &val);
+ if (error)
+ return error;
+
+ val |= IQS5XX_SETUP_COMPLETE;
+ val &= ~IQS5XX_SW_INPUT_EVENT;
+ error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0, val);
+ if (error)
+ return error;
+
+ val = IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE;
+ error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1, val);
+ if (error)
+ return error;
+
+ error = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
+ if (error)
+ return error;
+
+ iqs5xx->bl_status = dev_id_info->bl_status;
+
+ /*
+ * Closure of the first communication window that appears following the
+ * release of reset appears to kick off an initialization period during
+ * which further communication is met with clock stretching. The return
+ * from this function is delayed so that further communication attempts
+ * avoid this period.
+ */
+ msleep(100);
+
+ return 0;
+}
+
+static irqreturn_t iqs5xx_irq(int irq, void *data)
+{
+ struct iqs5xx_private *iqs5xx = data;
+ struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
+ struct i2c_client *client = iqs5xx->client;
+ struct input_dev *input = iqs5xx->input;
+ int error, i;
+
+ /*
+ * This check is purely a precaution, as the device does not assert the
+ * RDY output during bootloader mode. If the device operates outside of
+ * bootloader mode, the input device is guaranteed to be allocated.
+ */
+ if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
+ return IRQ_NONE;
+
+ error = iqs5xx_read_burst(client, IQS5XX_ABS_X,
+ touch_data, sizeof(touch_data));
+ if (error)
+ return IRQ_NONE;
+
+ for (i = 0; i < ARRAY_SIZE(touch_data); i++) {
+ u16 pressure = be16_to_cpu(touch_data[i].strength);
+
+ input_mt_slot(input, i);
+ if (input_mt_report_slot_state(input, MT_TOOL_FINGER,
+ pressure != 0)) {
+ input_report_abs(input, ABS_MT_POSITION_X,
+ be16_to_cpu(touch_data[i].abs_x));
+ input_report_abs(input, ABS_MT_POSITION_Y,
+ be16_to_cpu(touch_data[i].abs_y));
+ input_report_abs(input, ABS_MT_PRESSURE, pressure);
+ }
+ }
+
+ input_mt_sync_frame(input);
+ input_sync(input);
+
+ error = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
+ if (error)
+ return IRQ_NONE;
+
+ /*
+ * Once the communication window is closed, a small delay is added to
+ * ensure the device's RDY output has been deasserted by the time the
+ * interrupt handler returns.
+ */
+ usleep_range(50, 100);
+
+ return IRQ_HANDLED;
+}
+
+static int iqs5xx_fw_file_parse(struct i2c_client *client,
+ const char *fw_file, u8 *pmap)
+{
+ const struct firmware *fw;
+ struct iqs5xx_ihex_rec *rec;
+ size_t pos = 0;
+ int error, i;
+ u16 rec_num = 1;
+ u16 rec_addr;
+ u8 rec_len, rec_type, rec_chksm, chksm;
+ u8 rec_hdr[IQS5XX_REC_HDR_LEN];
+ u8 rec_data[IQS5XX_REC_LEN_MAX];
+
+ /*
+ * Firmware exported from the vendor's configuration tool deviates from
+ * standard ihex as follows: (1) the checksum for records corresponding
+ * to user-exported settings is not recalculated, and (2) an address of
+ * 0xFFFF is used for the EOF record.
+ *
+ * Because the ihex2fw tool tolerates neither (1) nor (2), the slightly
+ * nonstandard ihex firmware is parsed directly by the driver.
+ */
+ error = request_firmware(&fw, fw_file, &client->dev);
+ if (error) {
+ dev_err(&client->dev, "Failed to request firmware %s: %d\n",
+ fw_file, error);
+ return error;
+ }
+
+ do {
+ if (pos + sizeof(*rec) > fw->size) {
+ dev_err(&client->dev, "Insufficient firmware size\n");
+ error = -EINVAL;
+ break;
+ }
+ rec = (struct iqs5xx_ihex_rec *)(fw->data + pos);
+ pos += sizeof(*rec);
+
+ if (rec->start != ':') {
+ dev_err(&client->dev, "Invalid start at record %u\n",
+ rec_num);
+ error = -EINVAL;
+ break;
+ }
+
+ error = hex2bin(rec_hdr, rec->len, sizeof(rec_hdr));
+ if (error) {
+ dev_err(&client->dev, "Invalid header at record %u\n",
+ rec_num);
+ break;
+ }
+
+ rec_len = *rec_hdr;
+ rec_addr = get_unaligned_be16(rec_hdr + sizeof(rec_len));
+ rec_type = *(rec_hdr + sizeof(rec_len) + sizeof(rec_addr));
+
+ if (pos + rec_len * 2 > fw->size) {
+ dev_err(&client->dev, "Insufficient firmware size\n");
+ error = -EINVAL;
+ break;
+ }
+ pos += (rec_len * 2);
+
+ error = hex2bin(rec_data, rec->data, rec_len);
+ if (error) {
+ dev_err(&client->dev, "Invalid data at record %u\n",
+ rec_num);
+ break;
+ }
+
+ error = hex2bin(&rec_chksm,
+ rec->data + rec_len * 2, sizeof(rec_chksm));
+ if (error) {
+ dev_err(&client->dev, "Invalid checksum at record %u\n",
+ rec_num);
+ break;
+ }
+
+ chksm = 0;
+ for (i = 0; i < sizeof(rec_hdr); i++)
+ chksm += rec_hdr[i];
+ for (i = 0; i < rec_len; i++)
+ chksm += rec_data[i];
+ chksm = ~chksm + 1;
+
+ if (chksm != rec_chksm && rec_addr < IQS5XX_CSTM) {
+ dev_err(&client->dev,
+ "Incorrect checksum at record %u\n",
+ rec_num);
+ error = -EINVAL;
+ break;
+ }
+
+ switch (rec_type) {
+ case IQS5XX_REC_TYPE_DATA:
+ if (rec_addr < IQS5XX_CHKSM ||
+ rec_addr > IQS5XX_PMAP_END) {
+ dev_err(&client->dev,
+ "Invalid address at record %u\n",
+ rec_num);
+ error = -EINVAL;
+ } else {
+ memcpy(pmap + rec_addr - IQS5XX_CHKSM,
+ rec_data, rec_len);
+ }
+ break;
+ case IQS5XX_REC_TYPE_EOF:
+ break;
+ default:
+ dev_err(&client->dev, "Invalid type at record %u\n",
+ rec_num);
+ error = -EINVAL;
+ }
+
+ if (error)
+ break;
+
+ rec_num++;
+ while (pos < fw->size) {
+ if (*(fw->data + pos) == ':')
+ break;
+ pos++;
+ }
+ } while (rec_type != IQS5XX_REC_TYPE_EOF);
+
+ release_firmware(fw);
+
+ return error;
+}
+
+static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
+{
+ struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+ int error;
+ u8 *pmap;
+
+ if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE)
+ return -EPERM;
+
+ pmap = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL);
+ if (!pmap)
+ return -ENOMEM;
+
+ error = iqs5xx_fw_file_parse(client, fw_file, pmap);
+ if (error)
+ goto err_kfree;
+
+ mutex_lock(&iqs5xx->lock);
+
+ /*
+ * Disable the interrupt line in case the first attempt(s) to enter the
+ * bootloader don't happen quickly enough, in which case the device may
+ * assert the RDY output until the next attempt.
+ */
+ disable_irq(client->irq);
+
+ iqs5xx->bl_status = IQS5XX_BL_STATUS_RESET;
+
+ error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
+ if (error) {
+ error = iqs5xx_bl_open(client);
+ if (error)
+ goto err_reset;
+ }
+
+ error = iqs5xx_bl_write(client, IQS5XX_CHKSM, pmap, IQS5XX_PMAP_LEN);
+ if (error)
+ goto err_reset;
+
+ error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_CRC, 0);
+ if (error)
+ goto err_reset;
+
+ error = iqs5xx_bl_verify(client, IQS5XX_CSTM,
+ pmap + IQS5XX_CHKSM_LEN + IQS5XX_APP_LEN,
+ IQS5XX_CSTM_LEN);
+ if (error)
+ goto err_reset;
+
+ error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_EXEC, 0);
+
+err_reset:
+ if (error) {
+ iqs5xx_reset(client);
+ usleep_range(10000, 10100);
+ }
+
+ error = iqs5xx_dev_init(client);
+ if (!error && iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
+ error = -EINVAL;
+
+ enable_irq(client->irq);
+
+ mutex_unlock(&iqs5xx->lock);
+
+err_kfree:
+ kfree(pmap);
+
+ return error;
+}
+
+static ssize_t fw_file_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
+ struct i2c_client *client = iqs5xx->client;
+ size_t len = count;
+ bool input_reg = !iqs5xx->input;
+ char fw_file[IQS5XX_FW_FILE_LEN + 1];
+ int error;
+
+ if (!len)
+ return -EINVAL;
+
+ if (buf[len - 1] == '\n')
+ len--;
+
+ if (len > IQS5XX_FW_FILE_LEN)
+ return -ENAMETOOLONG;
+
+ memcpy(fw_file, buf, len);
+ fw_file[len] = '\0';
+
+ error = iqs5xx_fw_file_write(client, fw_file);
+ if (error)
+ return error;
+
+ /*
+ * If the input device was not allocated already, it is guaranteed to
+ * be allocated by this point and can finally be registered.
+ */
+ if (input_reg) {
+ error = input_register_device(iqs5xx->input);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to register device: %d\n",
+ error);
+ return error;
+ }
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR_WO(fw_file);
+
+static struct attribute *iqs5xx_attrs[] = {
+ &dev_attr_fw_file.attr,
+ NULL,
+};
+
+static const struct attribute_group iqs5xx_attr_group = {
+ .attrs = iqs5xx_attrs,
+};
+
+static int __maybe_unused iqs5xx_suspend(struct device *dev)
+{
+ struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
+ struct input_dev *input = iqs5xx->input;
+ int error = 0;
+
+ if (!input)
+ return error;
+
+ mutex_lock(&input->mutex);
+
+ if (input->users)
+ error = iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
+
+ mutex_unlock(&input->mutex);
+
+ return error;
+}
+
+static int __maybe_unused iqs5xx_resume(struct device *dev)
+{
+ struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
+ struct input_dev *input = iqs5xx->input;
+ int error = 0;
+
+ if (!input)
+ return error;
+
+ mutex_lock(&input->mutex);
+
+ if (input->users)
+ error = iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
+
+ mutex_unlock(&input->mutex);
+
+ return error;
+}
+
+static SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume);
+
+static int iqs5xx_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iqs5xx_private *iqs5xx;
+ int error;
+
+ iqs5xx = devm_kzalloc(&client->dev, sizeof(*iqs5xx), GFP_KERNEL);
+ if (!iqs5xx)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, iqs5xx);
+ iqs5xx->client = client;
+
+ iqs5xx->reset_gpio = devm_gpiod_get(&client->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(iqs5xx->reset_gpio)) {
+ error = PTR_ERR(iqs5xx->reset_gpio);
+ dev_err(&client->dev, "Failed to request GPIO: %d\n", error);
+ return error;
+ }
+
+ mutex_init(&iqs5xx->lock);
+
+ iqs5xx_reset(client);
+ usleep_range(10000, 10100);
+
+ error = iqs5xx_dev_init(client);
+ if (error)
+ return error;
+
+ error = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, iqs5xx_irq, IRQF_ONESHOT,
+ client->name, iqs5xx);
+ if (error) {
+ dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+ return error;
+ }
+
+ error = devm_device_add_group(&client->dev, &iqs5xx_attr_group);
+ if (error) {
+ dev_err(&client->dev, "Failed to add attributes: %d\n", error);
+ return error;
+ }
+
+ if (iqs5xx->input) {
+ error = input_register_device(iqs5xx->input);
+ if (error)
+ dev_err(&client->dev,
+ "Failed to register device: %d\n",
+ error);
+ }
+
+ return error;
+}
+
+static const struct i2c_device_id iqs5xx_id[] = {
+ { "iqs550", 0 },
+ { "iqs572", 1 },
+ { "iqs525", 2 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, iqs5xx_id);
+
+static const struct of_device_id iqs5xx_of_match[] = {
+ { .compatible = "azoteq,iqs550" },
+ { .compatible = "azoteq,iqs572" },
+ { .compatible = "azoteq,iqs525" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, iqs5xx_of_match);
+
+static struct i2c_driver iqs5xx_i2c_driver = {
+ .driver = {
+ .name = "iqs5xx",
+ .of_match_table = iqs5xx_of_match,
+ .pm = &iqs5xx_pm,
+ },
+ .id_table = iqs5xx_id,
+ .probe = iqs5xx_probe,
+};
+module_i2c_driver(iqs5xx_i2c_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS550/572/525 Trackpad/Touchscreen Controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index 729b3c8..9745211 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/input/touchscreen/jornada720_ts.c
*
@@ -6,10 +7,6 @@
* Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
* based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* HP Jornada 710/720/729 Touchscreen Driver
*/
diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c
index 4eb31ec..b2cd947 100644
--- a/drivers/input/touchscreen/lpc32xx_ts.c
+++ b/drivers/input/touchscreen/lpc32xx_ts.c
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LPC32xx built-in touchscreen driver
*
* Copyright (C) 2010 NXP Semiconductors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
*/
#include <linux/platform_device.h>
@@ -221,10 +212,8 @@
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "Can't get interrupt resource\n");
+ if (irq < 0)
return irq;
- }
tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
input = input_allocate_device();
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
index 0786010..f8564b3 100644
--- a/drivers/input/touchscreen/mainstone-wm97xx.c
+++ b/drivers/input/touchscreen/mainstone-wm97xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* mainstone-wm97xx.c -- Mainstone Continuous Touch screen driver for
* Wolfson WM97xx AC97 Codecs.
@@ -7,11 +8,6 @@
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
* Notes:
* This is a wm97xx extended touch driver to capture touch
* data in a continuous manner on the Intel XScale architecture
@@ -19,7 +15,6 @@
* Features:
* - codecs supported:- WM9705, WM9712, WM9713
* - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
index 72ca3ef..1af08d3 100644
--- a/drivers/input/touchscreen/max11801_ts.c
+++ b/drivers/input/touchscreen/max11801_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for MAXI MAX11801 - A Resistive touch screen controller with
* i2c interface
@@ -6,11 +7,6 @@
* Author: Zhang Jiejing <jiejing.zhang@freescale.com>
*
* Based on mcs5000_ts.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
/*
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index ef64f36..ae0d978 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for the Freescale Semiconductor MC13783 touchscreen.
*
@@ -6,10 +7,6 @@
*
* Initial development of this code was funded by
* Phytec Messtechnik GmbH, http://www.phytec.de/
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/platform_device.h>
#include <linux/mfd/mc13783.h>
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index 8868573..5376d8f 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* mcs5000_ts.c - Touchscreen driver for MELFAS MCS-5000 controller
*
@@ -5,12 +6,6 @@
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* Based on wm97xx-core.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index 430a2bc..247c3aa 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MELFAS MIP4 Touchscreen
*
* Copyright (C) 2016 MELFAS Inc.
*
* Author : Sangwon Jee <jeesw@melfas.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
*/
#include <linux/acpi.h>
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c
index 02fb119..42d3fd7 100644
--- a/drivers/input/touchscreen/migor_ts.c
+++ b/drivers/input/touchscreen/migor_ts.c
@@ -1,23 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Touch Screen driver for Renesas MIGO-R Platform
*
* Copyright (c) 2008 Magnus Damm
* Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>,
* Kenati Technologies Pvt Ltd.
- *
- * This file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This file 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 library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index c179060..753d9cc 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ICS MK712 touchscreen controller driver
*
@@ -6,11 +7,6 @@
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* This driver supports the ICS MicroClock MK712 TouchScreen controller,
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index a3707fa..28e449e 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* MicroTouch (3M) serial touchscreen driver
*
* Copyright (c) 2004 Vojtech Pavlik
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
/*
* 2005/02/19 Dan Streetman <ddstreet@ieee.org>
@@ -90,7 +86,7 @@
static irqreturn_t mtouch_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
- struct mtouch* mtouch = serio_get_drvdata(serio);
+ struct mtouch *mtouch = serio_get_drvdata(serio);
mtouch->data[mtouch->idx] = data;
@@ -110,7 +106,7 @@
static void mtouch_disconnect(struct serio *serio)
{
- struct mtouch* mtouch = serio_get_drvdata(serio);
+ struct mtouch *mtouch = serio_get_drvdata(serio);
input_get_device(mtouch->dev);
input_unregister_device(mtouch->dev);
diff --git a/drivers/input/touchscreen/mxs-lradc-ts.c b/drivers/input/touchscreen/mxs-lradc-ts.c
index c850b51..9e36fee 100644
--- a/drivers/input/touchscreen/mxs-lradc-ts.c
+++ b/drivers/input/touchscreen/mxs-lradc-ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Freescale MXS LRADC touchscreen driver
*
@@ -7,16 +8,6 @@
* Authors:
* Marek Vasut <marex@denx.de>
* Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
*/
#include <linux/device.h>
@@ -615,7 +606,6 @@
struct device_node *node = dev->parent->of_node;
struct mxs_lradc *lradc = dev_get_drvdata(dev->parent);
struct mxs_lradc_ts *ts;
- struct resource *iores;
int ret, irq, virq, i;
u32 ts_wires = 0, adapt;
@@ -629,12 +619,9 @@
ts->dev = dev;
spin_lock_init(&ts->lock);
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iores)
- return -EINVAL;
- ts->base = devm_ioremap(dev, iores->start, resource_size(iores));
- if (!ts->base)
- return -ENOMEM;
+ ts->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(ts->base))
+ return PTR_ERR(ts->base);
ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires",
&ts_wires);
diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c
index 9642f10..e16ec4c 100644
--- a/drivers/input/touchscreen/of_touchscreen.c
+++ b/drivers/input/touchscreen/of_touchscreen.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic DT helper functions for touchscreen devices
*
* Copyright (c) 2014 Sebastian Reichel <sre@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/property.h>
@@ -35,7 +31,7 @@
static void touchscreen_set_params(struct input_dev *dev,
unsigned long axis,
- int max, int fuzz)
+ int min, int max, int fuzz)
{
struct input_absinfo *absinfo;
@@ -47,6 +43,7 @@
}
absinfo = &dev->absinfo[axis];
+ absinfo->minimum = min;
absinfo->maximum = max;
absinfo->fuzz = fuzz;
}
@@ -68,8 +65,9 @@
struct touchscreen_properties *prop)
{
struct device *dev = input->dev.parent;
+ struct input_absinfo *absinfo;
unsigned int axis;
- unsigned int maximum, fuzz;
+ unsigned int minimum, maximum, fuzz;
bool data_present;
input_alloc_absinfo(input);
@@ -77,7 +75,10 @@
return;
axis = multitouch ? ABS_MT_POSITION_X : ABS_X;
- data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-x",
+ data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x",
+ input_abs_get_min(input, axis),
+ &minimum) |
+ touchscreen_get_prop_u32(dev, "touchscreen-size-x",
input_abs_get_max(input,
axis) + 1,
&maximum) |
@@ -85,10 +86,13 @@
input_abs_get_fuzz(input, axis),
&fuzz);
if (data_present)
- touchscreen_set_params(input, axis, maximum - 1, fuzz);
+ touchscreen_set_params(input, axis, minimum, maximum - 1, fuzz);
axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y;
- data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-y",
+ data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y",
+ input_abs_get_min(input, axis),
+ &minimum) |
+ touchscreen_get_prop_u32(dev, "touchscreen-size-y",
input_abs_get_max(input,
axis) + 1,
&maximum) |
@@ -96,7 +100,7 @@
input_abs_get_fuzz(input, axis),
&fuzz);
if (data_present)
- touchscreen_set_params(input, axis, maximum - 1, fuzz);
+ touchscreen_set_params(input, axis, minimum, maximum - 1, fuzz);
axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE;
data_present = touchscreen_get_prop_u32(dev,
@@ -108,7 +112,7 @@
input_abs_get_fuzz(input, axis),
&fuzz);
if (data_present)
- touchscreen_set_params(input, axis, maximum, fuzz);
+ touchscreen_set_params(input, axis, 0, maximum, fuzz);
if (!prop)
return;
@@ -117,13 +121,25 @@
prop->max_x = input_abs_get_max(input, axis);
prop->max_y = input_abs_get_max(input, axis + 1);
+
prop->invert_x =
device_property_read_bool(dev, "touchscreen-inverted-x");
+ if (prop->invert_x) {
+ absinfo = &input->absinfo[axis];
+ absinfo->maximum -= absinfo->minimum;
+ absinfo->minimum = 0;
+ }
+
prop->invert_y =
device_property_read_bool(dev, "touchscreen-inverted-y");
+ if (prop->invert_y) {
+ absinfo = &input->absinfo[axis + 1];
+ absinfo->maximum -= absinfo->minimum;
+ absinfo->minimum = 0;
+ }
+
prop->swap_x_y =
device_property_read_bool(dev, "touchscreen-swapped-x-y");
-
if (prop->swap_x_y)
swap(input->absinfo[axis], input->absinfo[axis + 1]);
}
diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c
index 0e3fc41..b2da019 100644
--- a/drivers/input/touchscreen/pcap_ts.c
+++ b/drivers/input/touchscreen/pcap_ts.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform.
*
* Copyright (C) 2006 Harald Welte <laforge@openezx.org>
* Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index 6e6d7fd..12abb3b 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Penmount serial touchscreen driver
*
@@ -8,11 +9,6 @@
* Copyright (c) 2004 Vojtech Pavlik
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 37ff672..e146dfa 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Pixcir I2C touchscreen controllers.
*
* Copyright (C) 2010-2011 Pixcir, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c
new file mode 100644
index 0000000..6988126
--- /dev/null
+++ b/drivers/input/touchscreen/raspberrypi-ts.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Raspberry Pi firmware based touchscreen driver
+ *
+ * Copyright (C) 2015, 2017 Raspberry Pi
+ * Copyright (C) 2018 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input-polldev.h>
+#include <linux/input/touchscreen.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define RPI_TS_DEFAULT_WIDTH 800
+#define RPI_TS_DEFAULT_HEIGHT 480
+
+#define RPI_TS_MAX_SUPPORTED_POINTS 10
+
+#define RPI_TS_FTS_TOUCH_DOWN 0
+#define RPI_TS_FTS_TOUCH_CONTACT 2
+
+#define RPI_TS_POLL_INTERVAL 17 /* 60fps */
+
+#define RPI_TS_NPOINTS_REG_INVALIDATE 99
+
+struct rpi_ts {
+ struct platform_device *pdev;
+ struct input_polled_dev *poll_dev;
+ struct touchscreen_properties prop;
+
+ void __iomem *fw_regs_va;
+ dma_addr_t fw_regs_phys;
+
+ int known_ids;
+};
+
+struct rpi_ts_regs {
+ u8 device_mode;
+ u8 gesture_id;
+ u8 num_points;
+ struct rpi_ts_touch {
+ u8 xh;
+ u8 xl;
+ u8 yh;
+ u8 yl;
+ u8 pressure; /* Not supported */
+ u8 area; /* Not supported */
+ } point[RPI_TS_MAX_SUPPORTED_POINTS];
+};
+
+static void rpi_ts_poll(struct input_polled_dev *dev)
+{
+ struct input_dev *input = dev->input;
+ struct rpi_ts *ts = dev->private;
+ struct rpi_ts_regs regs;
+ int modified_ids = 0;
+ long released_ids;
+ int event_type;
+ int touchid;
+ int x, y;
+ int i;
+
+ memcpy_fromio(®s, ts->fw_regs_va, sizeof(regs));
+ /*
+ * We poll the memory based register copy of the touchscreen chip using
+ * the number of points register to know whether the copy has been
+ * updated (we write 99 to the memory copy, the GPU will write between
+ * 0 - 10 points)
+ */
+ iowrite8(RPI_TS_NPOINTS_REG_INVALIDATE,
+ ts->fw_regs_va + offsetof(struct rpi_ts_regs, num_points));
+
+ if (regs.num_points == RPI_TS_NPOINTS_REG_INVALIDATE ||
+ (regs.num_points == 0 && ts->known_ids == 0))
+ return;
+
+ for (i = 0; i < regs.num_points; i++) {
+ x = (((int)regs.point[i].xh & 0xf) << 8) + regs.point[i].xl;
+ y = (((int)regs.point[i].yh & 0xf) << 8) + regs.point[i].yl;
+ touchid = (regs.point[i].yh >> 4) & 0xf;
+ event_type = (regs.point[i].xh >> 6) & 0x03;
+
+ modified_ids |= BIT(touchid);
+
+ if (event_type == RPI_TS_FTS_TOUCH_DOWN ||
+ event_type == RPI_TS_FTS_TOUCH_CONTACT) {
+ input_mt_slot(input, touchid);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, 1);
+ touchscreen_report_pos(input, &ts->prop, x, y, true);
+ }
+ }
+
+ released_ids = ts->known_ids & ~modified_ids;
+ for_each_set_bit(i, &released_ids, RPI_TS_MAX_SUPPORTED_POINTS) {
+ input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, 0);
+ modified_ids &= ~(BIT(i));
+ }
+ ts->known_ids = modified_ids;
+
+ input_mt_sync_frame(input);
+ input_sync(input);
+}
+
+static void rpi_ts_dma_cleanup(void *data)
+{
+ struct rpi_ts *ts = data;
+ struct device *dev = &ts->pdev->dev;
+
+ dma_free_coherent(dev, PAGE_SIZE, ts->fw_regs_va, ts->fw_regs_phys);
+}
+
+static int rpi_ts_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct input_polled_dev *poll_dev;
+ struct device_node *fw_node;
+ struct rpi_firmware *fw;
+ struct input_dev *input;
+ struct rpi_ts *ts;
+ u32 touchbuf;
+ int error;
+
+ fw_node = of_get_parent(np);
+ if (!fw_node) {
+ dev_err(dev, "Missing firmware node\n");
+ return -ENOENT;
+ }
+
+ fw = rpi_firmware_get(fw_node);
+ of_node_put(fw_node);
+ if (!fw)
+ return -EPROBE_DEFER;
+
+ ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+ ts->pdev = pdev;
+
+ ts->fw_regs_va = dma_alloc_coherent(dev, PAGE_SIZE, &ts->fw_regs_phys,
+ GFP_KERNEL);
+ if (!ts->fw_regs_va) {
+ dev_err(dev, "failed to dma_alloc_coherent\n");
+ return -ENOMEM;
+ }
+
+ error = devm_add_action_or_reset(dev, rpi_ts_dma_cleanup, ts);
+ if (error) {
+ dev_err(dev, "failed to devm_add_action_or_reset, %d\n", error);
+ return error;
+ }
+
+
+ touchbuf = (u32)ts->fw_regs_phys;
+ error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF,
+ &touchbuf, sizeof(touchbuf));
+
+ if (error || touchbuf != 0) {
+ dev_warn(dev, "Failed to set touchbuf, %d\n", error);
+ return error;
+ }
+
+ poll_dev = devm_input_allocate_polled_device(dev);
+ if (!poll_dev) {
+ dev_err(dev, "Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+ ts->poll_dev = poll_dev;
+ input = poll_dev->input;
+
+ input->name = "raspberrypi-ts";
+ input->id.bustype = BUS_HOST;
+ poll_dev->poll_interval = RPI_TS_POLL_INTERVAL;
+ poll_dev->poll = rpi_ts_poll;
+ poll_dev->private = ts;
+
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0,
+ RPI_TS_DEFAULT_WIDTH, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
+ RPI_TS_DEFAULT_HEIGHT, 0, 0);
+ touchscreen_parse_properties(input, true, &ts->prop);
+
+ error = input_mt_init_slots(input, RPI_TS_MAX_SUPPORTED_POINTS,
+ INPUT_MT_DIRECT);
+ if (error) {
+ dev_err(dev, "could not init mt slots, %d\n", error);
+ return error;
+ }
+
+ error = input_register_polled_device(poll_dev);
+ if (error) {
+ dev_err(dev, "could not register input device, %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id rpi_ts_match[] = {
+ { .compatible = "raspberrypi,firmware-ts", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rpi_ts_match);
+
+static struct platform_driver rpi_ts_driver = {
+ .driver = {
+ .name = "raspberrypi-ts",
+ .of_match_table = rpi_ts_match,
+ },
+ .probe = rpi_ts_probe,
+};
+module_platform_driver(rpi_ts_driver);
+
+MODULE_AUTHOR("Gordon Hollingworth");
+MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>");
+MODULE_DESCRIPTION("Raspberry Pi firmware based touchscreen driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c
index c89853a..6ed9f22 100644
--- a/drivers/input/touchscreen/raydium_i2c_ts.c
+++ b/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Raydium touchscreen I2C driver.
*
* Copyright (C) 2012-2014, Raydium Semiconductor Corporation.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, and only version 2, as published by the
- * Free Software Foundation.
- *
- * 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.
- *
* Raydium reserves the right to make changes without further notice
* to the materials described herein. Raydium does not assume any
* liability arising out of the application described herein.
diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c
index 714affd..730596d 100644
--- a/drivers/input/touchscreen/rohm_bu21023.c
+++ b/drivers/input/touchscreen/rohm_bu21023.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ROHM BU21023/24 Dual touch support resistive touch screen driver
* Copyright (C) 2012 ROHM CO.,LTD.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
index 1173890..b346e7c 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Samsung S3C24XX touchscreen driver
*
- * This program is free software; you can redistribute it and/or modify
- * it under the term of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
* Copyright 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
* Copyright 2008 Ben Dooks <ben-linux@fluff.org>
* Copyright 2009 Simtec Electronics <linux@simtec.co.uk>
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index d196ac3..ad8b6a2 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* -------------------------------------------------------------------------
* Copyright (C) 2014-2015, Intel Corporation
*
@@ -5,15 +6,6 @@
* gslX68X.c
* Copyright (C) 2010-2015, Shanghai Sileadinc Co.Ltd
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
* -------------------------------------------------------------------------
*/
@@ -558,20 +550,33 @@
static int __maybe_unused silead_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ bool second_try = false;
int error, status;
silead_ts_set_power(client, SILEAD_POWER_ON);
+ retry:
error = silead_ts_reset(client);
if (error)
return error;
+ if (second_try) {
+ error = silead_ts_load_fw(client);
+ if (error)
+ return error;
+ }
+
error = silead_ts_startup(client);
if (error)
return error;
status = silead_ts_get_status(client);
if (status != SILEAD_STATUS_OK) {
+ if (!second_try) {
+ second_try = true;
+ dev_dbg(dev, "Reloading firmware after unsuccessful resume\n");
+ goto retry;
+ }
dev_err(dev, "Resume error, status: 0x%02x\n", status);
return -ENODEV;
}
@@ -604,6 +609,7 @@
{ "MSSL1680", 0 },
{ "MSSL0001", 0 },
{ "MSSL0002", 0 },
+ { "MSSL0017", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match);
diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c
index 67c2563..6274555 100644
--- a/drivers/input/touchscreen/sis_i2c.c
+++ b/drivers/input/touchscreen/sis_i2c.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touch Screen driver for SiS 9200 family I2C Touch panels
*
* Copyright (C) 2015 SiS, Inc.
* Copyright (C) 2016 Nextfour Group
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
*/
#include <linux/crc-itu-t.h>
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index d5dfa40..1139714 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ST1232 Touchscreen Controller Driver
*
@@ -7,37 +8,22 @@
* Using code from:
* - android.git.kernel.org: projects/kernel/common.git: synaptics_i2c_rmi.c
* Copyright (C) 2007 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
*/
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/input/touchscreen.h>
#define ST1232_TS_NAME "st1232-ts"
-
-#define MIN_X 0x00
-#define MIN_Y 0x00
-#define MAX_X 0x31f /* (800 - 1) */
-#define MAX_Y 0x1df /* (480 - 1) */
-#define MAX_AREA 0xff
-#define MAX_FINGERS 2
+#define ST1633_TS_NAME "st1633-ts"
struct st1232_ts_finger {
u16 x;
@@ -46,12 +32,25 @@
bool is_valid;
};
+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 {
struct i2c_client *client;
struct input_dev *input_dev;
- struct st1232_ts_finger finger[MAX_FINGERS];
+ struct touchscreen_properties prop;
struct dev_pm_qos_request low_latency_req;
- int reset_gpio;
+ struct gpio_desc *reset_gpio;
+ const struct st_chip_info *chip_info;
+ int read_buf_len;
+ u8 *read_buf;
+ struct st1232_ts_finger *finger;
};
static int st1232_ts_read_data(struct st1232_ts_data *ts)
@@ -60,40 +59,37 @@
struct i2c_client *client = ts->client;
struct i2c_msg msg[2];
int error;
- u8 start_reg;
- u8 buf[10];
+ int i, y;
+ u8 start_reg = ts->chip_info->start_reg;
+ u8 *buf = ts->read_buf;
- /* read touchscreen data from ST1232 */
+ /* read touchscreen data */
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = &start_reg;
- start_reg = 0x10;
msg[1].addr = ts->client->addr;
msg[1].flags = I2C_M_RD;
- msg[1].len = sizeof(buf);
+ msg[1].len = ts->read_buf_len;
msg[1].buf = buf;
error = i2c_transfer(client->adapter, msg, 2);
if (error < 0)
return error;
- /* get "valid" bits */
- finger[0].is_valid = buf[2] >> 7;
- finger[1].is_valid = buf[5] >> 7;
+ for (i = 0, y = 0; i < ts->chip_info->max_fingers; i++, y += 3) {
+ finger[i].is_valid = buf[i + y] >> 7;
+ if (finger[i].is_valid) {
+ finger[i].x = ((buf[i + y] & 0x0070) << 4) |
+ buf[i + y + 1];
+ finger[i].y = ((buf[i + y] & 0x0007) << 8) |
+ buf[i + y + 2];
- /* get xy coordinate */
- if (finger[0].is_valid) {
- finger[0].x = ((buf[2] & 0x0070) << 4) | buf[3];
- finger[0].y = ((buf[2] & 0x0007) << 8) | buf[4];
- finger[0].t = buf[8];
- }
-
- if (finger[1].is_valid) {
- finger[1].x = ((buf[5] & 0x0070) << 4) | buf[6];
- finger[1].y = ((buf[5] & 0x0007) << 8) | buf[7];
- finger[1].t = buf[9];
+ /* st1232 includes a z-axis / touch strength */
+ if (ts->chip_info->have_z)
+ finger[i].t = buf[i + 6];
+ }
}
return 0;
@@ -112,13 +108,16 @@
goto end;
/* multi touch protocol */
- for (i = 0; i < MAX_FINGERS; i++) {
+ for (i = 0; i < ts->chip_info->max_fingers; i++) {
if (!finger[i].is_valid)
continue;
- input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);
- input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);
+ if (ts->chip_info->have_z)
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+ finger[i].t);
+
+ touchscreen_report_pos(input_dev, &ts->prop,
+ finger[i].x, finger[i].y, true);
input_mt_sync(input_dev);
count++;
}
@@ -146,17 +145,45 @@
static void st1232_ts_power(struct st1232_ts_data *ts, bool poweron)
{
- if (gpio_is_valid(ts->reset_gpio))
- gpio_direction_output(ts->reset_gpio, poweron);
+ if (ts->reset_gpio)
+ gpiod_set_value_cansleep(ts->reset_gpio, !poweron);
}
+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,
const struct i2c_device_id *id)
{
+ const struct st_chip_info *match;
struct st1232_ts_data *ts;
+ struct st1232_ts_finger *finger;
struct input_dev *input_dev;
int error;
+ match = device_get_match_data(&client->dev);
+ if (!match && id)
+ match = (const void *)id->driver_data;
+ if (!match) {
+ dev_err(&client->dev, "unknown device model\n");
+ return -ENODEV;
+ }
+
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "need I2C_FUNC_I2C\n");
return -EIO;
@@ -171,6 +198,19 @@
if (!ts)
return -ENOMEM;
+ ts->chip_info = match;
+ ts->finger = devm_kcalloc(&client->dev,
+ ts->chip_info->max_fingers, sizeof(*finger),
+ GFP_KERNEL);
+ if (!ts->finger)
+ return -ENOMEM;
+
+ /* allocate a buffer according to the number of registers to read */
+ ts->read_buf_len = ts->chip_info->max_fingers * 4;
+ ts->read_buf = devm_kzalloc(&client->dev, ts->read_buf_len, GFP_KERNEL);
+ if (!ts->read_buf)
+ return -ENOMEM;
+
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev)
return -ENOMEM;
@@ -178,15 +218,13 @@
ts->client = client;
ts->input_dev = input_dev;
- ts->reset_gpio = of_get_gpio(client->dev.of_node, 0);
- if (gpio_is_valid(ts->reset_gpio)) {
- error = devm_gpio_request(&client->dev, ts->reset_gpio, NULL);
- if (error) {
- dev_err(&client->dev,
- "Unable to request GPIO pin %d.\n",
- ts->reset_gpio);
- return error;
- }
+ ts->reset_gpio = devm_gpiod_get_optional(&client->dev, NULL,
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ts->reset_gpio)) {
+ error = PTR_ERR(ts->reset_gpio);
+ dev_err(&client->dev, "Unable to request GPIO pin: %d.\n",
+ error);
+ return error;
}
st1232_ts_power(ts, true);
@@ -195,13 +233,21 @@
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
__set_bit(EV_SYN, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_ABS, input_dev->evbit);
- input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_X, MIN_X, MAX_X, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_Y, MIN_Y, MAX_Y, 0, 0);
+ 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);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, ts->chip_info->max_y, 0, 0);
+
+ touchscreen_parse_properties(input_dev, true, &ts->prop);
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, st1232_ts_irq_handler,
@@ -268,13 +314,15 @@
st1232_ts_suspend, st1232_ts_resume);
static const struct i2c_device_id st1232_ts_id[] = {
- { ST1232_TS_NAME, 0 },
+ { ST1232_TS_NAME, (unsigned long)&st1232_chip_info },
+ { ST1633_TS_NAME, (unsigned long)&st1633_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
static const struct of_device_id st1232_ts_dt_ids[] = {
- { .compatible = "sitronix,st1232", },
+ { .compatible = "sitronix,st1232", .data = &st1232_chip_info },
+ { .compatible = "sitronix,st1633", .data = &st1633_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
@@ -293,5 +341,6 @@
module_i2c_driver(st1232_ts_driver);
MODULE_AUTHOR("Tony SIM <chinyeow.sim.xt@renesas.com>");
+MODULE_AUTHOR("Martin Kepplinger <martin.kepplinger@ginzinger.com>");
MODULE_DESCRIPTION("SITRONIX ST1232 Touchscreen Controller Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 704e990..b6f95f2 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -106,27 +106,29 @@
bool running;
};
-static void stmfts_brightness_set(struct led_classdev *led_cdev,
+static int stmfts_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct stmfts_data *sdata = container_of(led_cdev,
struct stmfts_data, led_cdev);
int err;
- if (value == sdata->led_status || !sdata->ledvdd)
- return;
-
- if (!value) {
- regulator_disable(sdata->ledvdd);
- } else {
- err = regulator_enable(sdata->ledvdd);
- if (err)
- dev_warn(&sdata->client->dev,
- "failed to disable ledvdd regulator: %d\n",
- err);
+ if (value != sdata->led_status && sdata->ledvdd) {
+ if (!value) {
+ regulator_disable(sdata->ledvdd);
+ } else {
+ err = regulator_enable(sdata->ledvdd);
+ if (err) {
+ dev_warn(&sdata->client->dev,
+ "failed to disable ledvdd regulator: %d\n",
+ err);
+ return err;
+ }
+ }
+ sdata->led_status = value;
}
- sdata->led_status = value;
+ return 0;
}
static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev)
@@ -608,7 +610,7 @@
sdata->led_cdev.name = STMFTS_DEV_NAME;
sdata->led_cdev.max_brightness = LED_ON;
sdata->led_cdev.brightness = LED_OFF;
- sdata->led_cdev.brightness_set = stmfts_brightness_set;
+ sdata->led_cdev.brightness_set_blocking = stmfts_brightness_set;
sdata->led_cdev.brightness_get = stmfts_brightness_get;
err = devm_led_classdev_register(&sdata->client->dev, &sdata->led_cdev);
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index 2a78e27..7e16fcf 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -1,14 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* STMicroelectronics STMPE811 Touchscreen Driver
*
* (C) 2010 Luotao Fu <l.fu@pengutronix.de>
* All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/kernel.h>
@@ -30,8 +25,6 @@
* with touchscreen controller
*/
#define STMPE_REG_INT_STA 0x0B
-#define STMPE_REG_ADC_CTRL1 0x20
-#define STMPE_REG_ADC_CTRL2 0x21
#define STMPE_REG_TSC_CTRL 0x40
#define STMPE_REG_TSC_CFG 0x41
#define STMPE_REG_FIFO_TH 0x4A
@@ -49,17 +42,6 @@
#define STMPE_IRQ_TOUCH_DET 0
-#define SAMPLE_TIME(x) ((x & 0xf) << 4)
-#define MOD_12B(x) ((x & 0x1) << 3)
-#define REF_SEL(x) ((x & 0x1) << 1)
-#define ADC_FREQ(x) (x & 0x3)
-#define AVE_CTRL(x) ((x & 0x3) << 6)
-#define DET_DELAY(x) ((x & 0x7) << 3)
-#define SETTLING(x) (x & 0x7)
-#define FRACTION_Z(x) (x & 0x7)
-#define I_DRIVE(x) (x & 0x1)
-#define OP_MODE(x) ((x & 0x7) << 1)
-
#define STMPE_TS_NAME "stmpe-ts"
#define XY_MASK 0xfff
@@ -69,15 +51,6 @@
* @idev: registered input device
* @work: a work item used to scan the device
* @dev: a pointer back to the MFD cell struct device*
- * @sample_time: ADC converstion time in number of clock.
- * (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks,
- * 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks),
- * recommended is 4.
- * @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC)
- * @ref_sel: ADC reference source
- * (0 -> internal reference, 1 -> external reference)
- * @adc_freq: ADC Clock speed
- * (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz)
* @ave_ctrl: Sample average control
* (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples)
* @touch_det_delay: Touch detect interrupt delay
@@ -99,10 +72,6 @@
struct input_dev *idev;
struct delayed_work work;
struct device *dev;
- u8 sample_time;
- u8 mod_12b;
- u8 ref_sel;
- u8 adc_freq;
u8 ave_ctrl;
u8 touch_det_delay;
u8 settling;
@@ -203,7 +172,7 @@
static int stmpe_init_hw(struct stmpe_touch *ts)
{
int ret;
- u8 adc_ctrl1, adc_ctrl1_mask, tsc_cfg, tsc_cfg_mask;
+ u8 tsc_cfg, tsc_cfg_mask;
struct stmpe *stmpe = ts->stmpe;
struct device *dev = ts->dev;
@@ -213,27 +182,17 @@
return ret;
}
- adc_ctrl1 = SAMPLE_TIME(ts->sample_time) | MOD_12B(ts->mod_12b) |
- REF_SEL(ts->ref_sel);
- adc_ctrl1_mask = SAMPLE_TIME(0xff) | MOD_12B(0xff) | REF_SEL(0xff);
-
- ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1,
- adc_ctrl1_mask, adc_ctrl1);
+ ret = stmpe811_adc_common_init(stmpe);
if (ret) {
- dev_err(dev, "Could not setup ADC\n");
+ stmpe_disable(stmpe, STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC);
return ret;
}
- ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2,
- ADC_FREQ(0xff), ADC_FREQ(ts->adc_freq));
- if (ret) {
- dev_err(dev, "Could not setup ADC\n");
- return ret;
- }
-
- tsc_cfg = AVE_CTRL(ts->ave_ctrl) | DET_DELAY(ts->touch_det_delay) |
- SETTLING(ts->settling);
- tsc_cfg_mask = AVE_CTRL(0xff) | DET_DELAY(0xff) | SETTLING(0xff);
+ tsc_cfg = STMPE_AVE_CTRL(ts->ave_ctrl) |
+ STMPE_DET_DELAY(ts->touch_det_delay) |
+ STMPE_SETTLING(ts->settling);
+ tsc_cfg_mask = STMPE_AVE_CTRL(0xff) | STMPE_DET_DELAY(0xff) |
+ STMPE_SETTLING(0xff);
ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CFG, tsc_cfg_mask, tsc_cfg);
if (ret) {
@@ -242,14 +201,14 @@
}
ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_FRACTION_Z,
- FRACTION_Z(0xff), FRACTION_Z(ts->fraction_z));
+ STMPE_FRACTION_Z(0xff), STMPE_FRACTION_Z(ts->fraction_z));
if (ret) {
dev_err(dev, "Could not config touch\n");
return ret;
}
ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_I_DRIVE,
- I_DRIVE(0xff), I_DRIVE(ts->i_drive));
+ STMPE_I_DRIVE(0xff), STMPE_I_DRIVE(ts->i_drive));
if (ret) {
dev_err(dev, "Could not config touch\n");
return ret;
@@ -263,7 +222,7 @@
}
ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CTRL,
- OP_MODE(0xff), OP_MODE(OP_MOD_XYZ));
+ STMPE_OP_MODE(0xff), STMPE_OP_MODE(OP_MOD_XYZ));
if (ret) {
dev_err(dev, "Could not set mode\n");
return ret;
@@ -303,13 +262,13 @@
if (np) {
if (!of_property_read_u32(np, "st,sample-time", &val))
- ts->sample_time = val;
+ ts->stmpe->sample_time = val;
if (!of_property_read_u32(np, "st,mod-12b", &val))
- ts->mod_12b = val;
+ ts->stmpe->mod_12b = val;
if (!of_property_read_u32(np, "st,ref-sel", &val))
- ts->ref_sel = val;
+ ts->stmpe->ref_sel = val;
if (!of_property_read_u32(np, "st,adc-freq", &val))
- ts->adc_freq = val;
+ ts->stmpe->adc_freq = val;
if (!of_property_read_u32(np, "st,ave-ctrl", &val))
ts->ave_ctrl = val;
if (!of_property_read_u32(np, "st,touch-det-delay", &val))
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
index d2e14d9..0af0fe8 100644
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Allwinner sunxi resistive touchscreen controller driver
*
@@ -5,16 +6,6 @@
*
* The hwmon parts are based on work by Corentin LABBE which is:
* Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
*/
/*
@@ -31,7 +22,7 @@
* in the kernel). So this driver offers straight forward, reliable single
* touch functionality only.
*
- * s.a. A20 User Manual "1.15 TP" (Documentation/arm/sunxi/README)
+ * s.a. A20 User Manual "1.15 TP" (Documentation/arm/sunxi.rst)
* (looks like the description in the A20 User Manual v1.3 is better
* than the one in the A10 User Manual v.1.5)
*/
@@ -309,8 +300,7 @@
input_set_drvdata(ts->input, ts);
}
- ts->base = devm_ioremap_resource(dev,
- platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ ts->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ts->base))
return PTR_ERR(ts->base);
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 894843a..3fd3e86 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Surface2.0/SUR40/PixelSense input driver
*
@@ -14,11 +15,6 @@
*
* and from the v4l2-pci-skeleton driver,
* Copyright (c) Copyright 2014 Cisco Systems, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
@@ -190,7 +186,7 @@
.width = SENSOR_RES_X / 2,
.height = SENSOR_RES_Y / 2,
.field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_SRGB,
+ .colorspace = V4L2_COLORSPACE_RAW,
.bytesperline = SENSOR_RES_X / 2,
.sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2),
},
@@ -199,7 +195,7 @@
.width = SENSOR_RES_X / 2,
.height = SENSOR_RES_Y / 2,
.field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_SRGB,
+ .colorspace = V4L2_COLORSPACE_RAW,
.bytesperline = SENSOR_RES_X / 2,
.sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2),
}
@@ -933,10 +929,6 @@
strlcpy(cap->driver, DRIVER_SHORT, sizeof(cap->driver));
strlcpy(cap->card, DRIVER_LONG, sizeof(cap->card));
usb_make_path(sur40->usbdev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1166,6 +1158,8 @@
.fops = &sur40_video_fops,
.ioctl_ops = &sur40_video_ioctl_ops,
.release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TOUCH |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING,
};
/* USB-specific object needed to register this driver with the USB subsystem. */
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
index 5db0f1c..ce4828b 100644
--- a/drivers/input/touchscreen/surface3_spi.c
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Ntrig/Microsoft Touchscreens over SPI
*
* Copyright (c) 2016 Red Hat Inc.
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; version 2 of the License.
- */
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index ed29db3..de85e57 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Semtech SX8654 I2C touchscreen controller.
*
@@ -21,18 +22,18 @@
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
/* register addresses */
#define I2C_REG_TOUCH0 0x00
@@ -42,25 +43,28 @@
#define I2C_REG_IRQSRC 0x23
#define I2C_REG_SOFTRESET 0x3f
+#define I2C_REG_SX8650_STAT 0x05
+#define SX8650_STAT_CONVIRQ BIT(7)
+
/* commands */
#define CMD_READ_REGISTER 0x40
-#define CMD_MANUAL 0xc0
#define CMD_PENTRG 0xe0
/* value for I2C_REG_SOFTRESET */
#define SOFTRESET_VALUE 0xde
/* bits for I2C_REG_IRQSRC */
-#define IRQ_PENTOUCH_TOUCHCONVDONE 0x08
-#define IRQ_PENRELEASE 0x04
+#define IRQ_PENTOUCH_TOUCHCONVDONE BIT(3)
+#define IRQ_PENRELEASE BIT(2)
/* bits for RegTouch1 */
#define CONDIRQ 0x20
+#define RPDNT_100K 0x00
#define FILT_7SA 0x03
/* bits for I2C_REG_CHANMASK */
-#define CONV_X 0x80
-#define CONV_Y 0x40
+#define CONV_X BIT(7)
+#define CONV_Y BIT(6)
/* coordinates rate: higher nibble of CTRL0 register */
#define RATE_MANUAL 0x00
@@ -69,13 +73,122 @@
/* power delay: lower nibble of CTRL0 register */
#define POWDLY_1_1MS 0x0b
+/* for sx8650, as we have no pen release IRQ there: timeout in ns following the
+ * last PENIRQ after which we assume the pen is lifted.
+ */
+#define SX8650_PENIRQ_TIMEOUT msecs_to_jiffies(10)
+
#define MAX_12BIT ((1 << 12) - 1)
+#define MAX_I2C_READ_LEN 10 /* see datasheet section 5.1.5 */
+
+/* channel definition */
+#define CH_X 0x00
+#define CH_Y 0x01
+
+struct sx865x_data {
+ u8 cmd_manual;
+ u8 chan_mask;
+ bool has_irq_penrelease;
+ bool has_reg_irqmask;
+ irq_handler_t irqh;
+};
struct sx8654 {
struct input_dev *input;
struct i2c_client *client;
+ struct gpio_desc *gpio_reset;
+
+ spinlock_t lock; /* for input reporting from irq/timer */
+ struct timer_list timer;
+
+ struct touchscreen_properties props;
+
+ const struct sx865x_data *data;
};
+static inline void sx865x_penrelease(struct sx8654 *ts)
+{
+ struct input_dev *input_dev = ts->input;
+
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_sync(input_dev);
+}
+
+static void sx865x_penrelease_timer_handler(struct timer_list *t)
+{
+ struct sx8654 *ts = from_timer(ts, t, timer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ts->lock, flags);
+ sx865x_penrelease(ts);
+ spin_unlock_irqrestore(&ts->lock, flags);
+ dev_dbg(&ts->client->dev, "penrelease by timer\n");
+}
+
+static irqreturn_t sx8650_irq(int irq, void *handle)
+{
+ struct sx8654 *ts = handle;
+ struct device *dev = &ts->client->dev;
+ int len, i;
+ unsigned long flags;
+ u8 stat;
+ u16 x, y;
+ u16 ch;
+ u16 chdata;
+ __be16 data[MAX_I2C_READ_LEN / sizeof(__be16)];
+ u8 nchan = hweight32(ts->data->chan_mask);
+ u8 readlen = nchan * sizeof(*data);
+
+ stat = i2c_smbus_read_byte_data(ts->client, CMD_READ_REGISTER
+ | I2C_REG_SX8650_STAT);
+
+ if (!(stat & SX8650_STAT_CONVIRQ)) {
+ dev_dbg(dev, "%s ignore stat [0x%02x]", __func__, stat);
+ return IRQ_HANDLED;
+ }
+
+ len = i2c_master_recv(ts->client, (u8 *)data, readlen);
+ if (len != readlen) {
+ dev_dbg(dev, "ignore short recv (%d)\n", len);
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&ts->lock, flags);
+
+ x = 0;
+ y = 0;
+ for (i = 0; i < nchan; i++) {
+ chdata = be16_to_cpu(data[i]);
+
+ if (unlikely(chdata == 0xFFFF)) {
+ dev_dbg(dev, "invalid qualified data @ %d\n", i);
+ continue;
+ } else if (unlikely(chdata & 0x8000)) {
+ dev_warn(dev, "hibit @ %d [0x%04x]\n", i, chdata);
+ continue;
+ }
+
+ ch = chdata >> 12;
+ if (ch == CH_X)
+ x = chdata & MAX_12BIT;
+ else if (ch == CH_Y)
+ y = chdata & MAX_12BIT;
+ else
+ dev_warn(dev, "unknown channel %d [0x%04x]\n", ch,
+ chdata);
+ }
+
+ touchscreen_report_pos(ts->input, &ts->props, x, y, false);
+ input_report_key(ts->input, BTN_TOUCH, 1);
+ input_sync(ts->input);
+ dev_dbg(dev, "point(%4d,%4d)\n", x, y);
+
+ mod_timer(&ts->timer, jiffies + SX8650_PENIRQ_TIMEOUT);
+ spin_unlock_irqrestore(&ts->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t sx8654_irq(int irq, void *handle)
{
struct sx8654 *sx8654 = handle;
@@ -112,8 +225,8 @@
x = ((data[0] & 0xf) << 8) | (data[1]);
y = ((data[2] & 0xf) << 8) | (data[3]);
- input_report_abs(sx8654->input, ABS_X, x);
- input_report_abs(sx8654->input, ABS_Y, y);
+ touchscreen_report_pos(sx8654->input, &sx8654->props, x, y,
+ false);
input_report_key(sx8654->input, BTN_TOUCH, 1);
input_sync(sx8654->input);
@@ -124,6 +237,25 @@
return IRQ_HANDLED;
}
+static int sx8654_reset(struct sx8654 *ts)
+{
+ int err;
+
+ if (ts->gpio_reset) {
+ gpiod_set_value_cansleep(ts->gpio_reset, 1);
+ udelay(2); /* Tpulse > 1µs */
+ gpiod_set_value_cansleep(ts->gpio_reset, 0);
+ } else {
+ dev_dbg(&ts->client->dev, "NRST unavailable, try softreset\n");
+ err = i2c_smbus_write_byte_data(ts->client, I2C_REG_SOFTRESET,
+ SOFTRESET_VALUE);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int sx8654_open(struct input_dev *dev)
{
struct sx8654 *sx8654 = input_get_drvdata(dev);
@@ -157,14 +289,17 @@
disable_irq(client->irq);
+ if (!sx8654->data->has_irq_penrelease)
+ del_timer_sync(&sx8654->timer);
+
/* enable manual mode mode */
- error = i2c_smbus_write_byte(client, CMD_MANUAL);
+ error = i2c_smbus_write_byte(client, sx8654->data->cmd_manual);
if (error) {
dev_err(&client->dev, "writing command CMD_MANUAL failed");
return;
}
- error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, 0);
+ error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, RATE_MANUAL);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
return;
@@ -186,6 +321,31 @@
if (!sx8654)
return -ENOMEM;
+ sx8654->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(sx8654->gpio_reset)) {
+ error = PTR_ERR(sx8654->gpio_reset);
+ if (error != -EPROBE_DEFER)
+ dev_err(&client->dev, "unable to get reset-gpio: %d\n",
+ error);
+ return error;
+ }
+ dev_dbg(&client->dev, "got GPIO reset pin\n");
+
+ sx8654->data = device_get_match_data(&client->dev);
+ if (!sx8654->data)
+ sx8654->data = (const struct sx865x_data *)id->driver_data;
+ if (!sx8654->data) {
+ dev_err(&client->dev, "invalid or missing device data\n");
+ return -EINVAL;
+ }
+
+ if (!sx8654->data->has_irq_penrelease) {
+ dev_dbg(&client->dev, "use timer for penrelease\n");
+ timer_setup(&sx8654->timer, sx865x_penrelease_timer_handler, 0);
+ spin_lock_init(&sx8654->lock);
+ }
+
input = devm_input_allocate_device(&client->dev);
if (!input)
return -ENOMEM;
@@ -201,43 +361,46 @@
input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0);
+ touchscreen_parse_properties(input, false, &sx8654->props);
+
sx8654->client = client;
sx8654->input = input;
input_set_drvdata(sx8654->input, sx8654);
- error = i2c_smbus_write_byte_data(client, I2C_REG_SOFTRESET,
- SOFTRESET_VALUE);
+ error = sx8654_reset(sx8654);
if (error) {
- dev_err(&client->dev, "writing softreset value failed");
+ dev_err(&client->dev, "reset failed");
return error;
}
error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK,
- CONV_X | CONV_Y);
+ sx8654->data->chan_mask);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed");
return error;
}
- error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
- IRQ_PENTOUCH_TOUCHCONVDONE |
- IRQ_PENRELEASE);
- if (error) {
- dev_err(&client->dev, "writing to I2C_REG_IRQMASK failed");
- return error;
+ if (sx8654->data->has_reg_irqmask) {
+ error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
+ IRQ_PENTOUCH_TOUCHCONVDONE |
+ IRQ_PENRELEASE);
+ if (error) {
+ dev_err(&client->dev, "writing I2C_REG_IRQMASK failed");
+ return error;
+ }
}
error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1,
- CONDIRQ | FILT_7SA);
+ CONDIRQ | RPDNT_100K | FILT_7SA);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed");
return error;
}
error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, sx8654_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ NULL, sx8654->data->irqh,
+ IRQF_ONESHOT,
client->name, sx8654);
if (error) {
dev_err(&client->dev,
@@ -256,17 +419,48 @@
return 0;
}
+static const struct sx865x_data sx8650_data = {
+ .cmd_manual = 0xb0,
+ .has_irq_penrelease = false,
+ .has_reg_irqmask = false,
+ .chan_mask = (CONV_X | CONV_Y),
+ .irqh = sx8650_irq,
+};
+
+static const struct sx865x_data sx8654_data = {
+ .cmd_manual = 0xc0,
+ .has_irq_penrelease = true,
+ .has_reg_irqmask = true,
+ .chan_mask = (CONV_X | CONV_Y),
+ .irqh = sx8654_irq,
+};
+
#ifdef CONFIG_OF
static const struct of_device_id sx8654_of_match[] = {
- { .compatible = "semtech,sx8654", },
- { },
+ {
+ .compatible = "semtech,sx8650",
+ .data = &sx8650_data,
+ }, {
+ .compatible = "semtech,sx8654",
+ .data = &sx8654_data,
+ }, {
+ .compatible = "semtech,sx8655",
+ .data = &sx8654_data,
+ }, {
+ .compatible = "semtech,sx8656",
+ .data = &sx8654_data,
+ },
+ { }
};
MODULE_DEVICE_TABLE(of, sx8654_of_match);
#endif
static const struct i2c_device_id sx8654_id_table[] = {
- { "semtech_sx8654", 0 },
- { },
+ { .name = "semtech_sx8650", .driver_data = (long)&sx8650_data },
+ { .name = "semtech_sx8654", .driver_data = (long)&sx8654_data },
+ { .name = "semtech_sx8655", .driver_data = (long)&sx8654_data },
+ { .name = "semtech_sx8656", .driver_data = (long)&sx8654_data },
+ { }
};
MODULE_DEVICE_TABLE(i2c, sx8654_id_table);
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index b86c1e5..83e6855 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -27,6 +27,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/sort.h>
+#include <linux/pm_wakeirq.h>
#include <linux/mfd/ti_am335x_tscadc.h>
@@ -46,6 +47,7 @@
struct titsc {
struct input_dev *input;
struct ti_tscadc_dev *mfd_tscadc;
+ struct device *dev;
unsigned int irq;
unsigned int wires;
unsigned int x_plate_resistance;
@@ -276,7 +278,7 @@
if (status & IRQENB_HW_PEN) {
ts_dev->pen_down = true;
irqclr |= IRQENB_HW_PEN;
- pm_stay_awake(ts_dev->mfd_tscadc->dev);
+ pm_stay_awake(ts_dev->dev);
}
if (status & IRQENB_PENUP) {
@@ -286,7 +288,7 @@
input_report_key(input_dev, BTN_TOUCH, 0);
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_sync(input_dev);
- pm_relax(ts_dev->mfd_tscadc->dev);
+ pm_relax(ts_dev->dev);
} else {
ts_dev->pen_down = true;
}
@@ -422,6 +424,7 @@
ts_dev->mfd_tscadc = tscadc_dev;
ts_dev->input = input_dev;
ts_dev->irq = tscadc_dev->irq;
+ ts_dev->dev = &pdev->dev;
err = titsc_parse_dt(pdev, ts_dev);
if (err) {
@@ -436,6 +439,11 @@
goto err_free_mem;
}
+ device_init_wakeup(&pdev->dev, true);
+ err = dev_pm_set_wake_irq(&pdev->dev, ts_dev->irq);
+ if (err)
+ dev_err(&pdev->dev, "irq wake enable failed.\n");
+
titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK);
titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES);
titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS);
@@ -467,6 +475,8 @@
return 0;
err_free_irq:
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
free_irq(ts_dev->irq, ts_dev);
err_free_mem:
input_free_device(input_dev);
@@ -479,6 +489,8 @@
struct titsc *ts_dev = platform_get_drvdata(pdev);
u32 steps;
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
free_irq(ts_dev->irq, ts_dev);
/* total steps followed by the enable mask */
@@ -495,11 +507,9 @@
static int __maybe_unused titsc_suspend(struct device *dev)
{
struct titsc *ts_dev = dev_get_drvdata(dev);
- struct ti_tscadc_dev *tscadc_dev;
unsigned int idle;
- tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
- if (device_may_wakeup(tscadc_dev->dev)) {
+ if (device_may_wakeup(dev)) {
titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK);
idle = titsc_readl(ts_dev, REG_IRQENABLE);
titsc_writel(ts_dev, REG_IRQENABLE,
@@ -512,14 +522,12 @@
static int __maybe_unused titsc_resume(struct device *dev)
{
struct titsc *ts_dev = dev_get_drvdata(dev);
- struct ti_tscadc_dev *tscadc_dev;
- tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
- if (device_may_wakeup(tscadc_dev->dev)) {
+ if (device_may_wakeup(dev)) {
titsc_writel(ts_dev, REG_IRQWAKEUP,
0x00);
titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
- pm_relax(ts_dev->mfd_tscadc->dev);
+ pm_relax(dev);
}
titsc_step_config(ts_dev);
titsc_writel(ts_dev, REG_FIFO0THR,
diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c
index 98a1669..fb49687 100644
--- a/drivers/input/touchscreen/touchit213.c
+++ b/drivers/input/touchscreen/touchit213.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sahara TouchIT-213 serial touchscreen driver
*
@@ -9,11 +10,6 @@
* and Dan Streetman <ddstreet@ieee.org>
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 45c325c..3cd58a1 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchright serial touchscreen driver
*
@@ -8,11 +9,6 @@
* and Dan Streetman <ddstreet@ieee.org>
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index 2ba6b4c..bde3c6e 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Touchwindow serial touchscreen driver
*
@@ -8,11 +9,6 @@
* and Dan Streetman <ddstreet@ieee.org>
*/
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
/*
* 2005/02/19 Rick Koch:
diff --git a/drivers/input/touchscreen/ts4800-ts.c b/drivers/input/touchscreen/ts4800-ts.c
index fed73ee..5b4f536 100644
--- a/drivers/input/touchscreen/ts4800-ts.c
+++ b/drivers/input/touchscreen/ts4800-ts.c
@@ -148,7 +148,6 @@
{
struct input_polled_dev *poll_dev;
struct ts4800_ts *ts;
- struct resource *res;
int error;
ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
@@ -159,8 +158,7 @@
if (error)
return error;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ts->base = devm_ioremap_resource(&pdev->dev, res);
+ ts->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ts->base))
return PTR_ERR(ts->base);
diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c
index 6fe55d5..0272ced 100644
--- a/drivers/input/touchscreen/tsc2004.c
+++ b/drivers/input/touchscreen/tsc2004.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* TSC2004 touchscreen driver
*
* Copyright (C) 2015 QWERTY Embedded Design
* Copyright (C) 2015 EMAC Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index e02b69f..923496b 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* TSC2005 touchscreen driver
*
@@ -6,16 +7,6 @@
* Copyright (C) 2015 EMAC Inc.
*
* Based on original tsc2005.c by Lauri Leukkunen <lauri.leukkunen@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
*/
#include <linux/input.h>
diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h
index 30fdf5b..91c60bf 100644
--- a/drivers/input/touchscreen/tsc2007.h
+++ b/drivers/input/touchscreen/tsc2007.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2008 MtekVision Co., Ltd.
@@ -13,10 +14,6 @@
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _TSC2007_H
diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c
index 8342e0c..3b80abf 100644
--- a/drivers/input/touchscreen/tsc2007_core.c
+++ b/drivers/input/touchscreen/tsc2007_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/input/touchscreen/tsc2007.c
*
@@ -14,10 +15,6 @@
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c
index e27a956..3b0e3fa 100644
--- a/drivers/input/touchscreen/tsc2007_iio.c
+++ b/drivers/input/touchscreen/tsc2007_iio.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016 Golden Delicious Comp. GmbH&Co. KG
* Nikolaus Schaller <hns@goldelico.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/i2c.h>
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c
index e0fde59..ce2fe30 100644
--- a/drivers/input/touchscreen/tsc200x-core.c
+++ b/drivers/input/touchscreen/tsc200x-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* TSC2004/TSC2005 touchscreen driver core
*
@@ -7,16 +8,6 @@
*
* Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
* based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -68,7 +59,8 @@
.read_flag_mask = TSC200X_REG_READ,
.write_flag_mask = TSC200X_REG_PND0,
.wr_table = &tsc200x_writable_table,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
};
EXPORT_SYMBOL_GPL(tsc200x_regmap_config);
diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c
index d4ae4ba..1395770 100644
--- a/drivers/input/touchscreen/tsc40.c
+++ b/drivers/input/touchscreen/tsc40.c
@@ -1,9 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TSC-40 serial touchscreen driver. It should be compatible with
* TSC-10 and 25.
*
* Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
- * License: GPLv2 as published by the FSF.
*/
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 1a86cbd..807d39e 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Philips UCB1400 touchscreen driver
*
@@ -9,10 +10,6 @@
* If something doesn't work and it worked before spliting, e-mail me,
* dont bother Nicolas please ;-)
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* This code is heavily based on ucb1x00-*.c copyrighted by Russell King
* covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has
* been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index d61570d..16d7020 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/******************************************************************************
* usbtouchscreen.c
* Driver for USB Touchscreens, supporting those devices:
@@ -22,20 +23,6 @@
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Driver is based on touchkitusb.c
* - ITM parts are from itmtouch.c
* - 3M parts are from mtouchusb.c
@@ -1672,6 +1659,8 @@
if (!usbtouch || !input_dev)
goto out_free;
+ mutex_init(&usbtouch->pm_mutex);
+
type = &usbtouch_dev_info[id->driver_info];
usbtouch->type = type;
if (!type->process_pkt)
diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c
deleted file mode 100644
index 638c1d7..0000000
--- a/drivers/input/touchscreen/w90p910_ts.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (c) 2008 Nuvoton technology corporation.
- *
- * Wan ZongShun <mcuos.com@gmail.com>
- *
- * 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.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-/* ADC controller bit defines */
-#define ADC_DELAY 0xf00
-#define ADC_DOWN 0x01
-#define ADC_TSC_Y (0x01 << 8)
-#define ADC_TSC_X (0x00 << 8)
-#define TSC_FOURWIRE (~(0x03 << 1))
-#define ADC_CLK_EN (0x01 << 28) /* ADC clock enable */
-#define ADC_READ_CON (0x01 << 12)
-#define ADC_CONV (0x01 << 13)
-#define ADC_SEMIAUTO (0x01 << 14)
-#define ADC_WAITTRIG (0x03 << 14)
-#define ADC_RST1 (0x01 << 16)
-#define ADC_RST0 (0x00 << 16)
-#define ADC_EN (0x01 << 17)
-#define ADC_INT (0x01 << 18)
-#define WT_INT (0x01 << 20)
-#define ADC_INT_EN (0x01 << 21)
-#define LVD_INT_EN (0x01 << 22)
-#define WT_INT_EN (0x01 << 23)
-#define ADC_DIV (0x04 << 1) /* div = 6 */
-
-enum ts_state {
- TS_WAIT_NEW_PACKET, /* We are waiting next touch report */
- TS_WAIT_X_COORD, /* We are waiting for ADC to report X coord */
- TS_WAIT_Y_COORD, /* We are waiting for ADC to report Y coord */
- TS_IDLE, /* Input device is closed, don't do anything */
-};
-
-struct w90p910_ts {
- struct input_dev *input;
- struct timer_list timer;
- struct clk *clk;
- int irq_num;
- void __iomem *ts_reg;
- spinlock_t lock;
- enum ts_state state;
-};
-
-static void w90p910_report_event(struct w90p910_ts *w90p910_ts, bool down)
-{
- struct input_dev *dev = w90p910_ts->input;
-
- if (down) {
- input_report_abs(dev, ABS_X,
- __raw_readl(w90p910_ts->ts_reg + 0x0c));
- input_report_abs(dev, ABS_Y,
- __raw_readl(w90p910_ts->ts_reg + 0x10));
- }
-
- input_report_key(dev, BTN_TOUCH, down);
- input_sync(dev);
-}
-
-static void w90p910_prepare_x_reading(struct w90p910_ts *w90p910_ts)
-{
- unsigned long ctlreg;
-
- __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg + 0x04);
- ctlreg = __raw_readl(w90p910_ts->ts_reg);
- ctlreg &= ~(ADC_WAITTRIG | WT_INT | WT_INT_EN);
- ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV;
- __raw_writel(ctlreg, w90p910_ts->ts_reg);
-
- w90p910_ts->state = TS_WAIT_X_COORD;
-}
-
-static void w90p910_prepare_y_reading(struct w90p910_ts *w90p910_ts)
-{
- unsigned long ctlreg;
-
- __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg + 0x04);
- ctlreg = __raw_readl(w90p910_ts->ts_reg);
- ctlreg &= ~(ADC_WAITTRIG | ADC_INT | WT_INT_EN);
- ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV;
- __raw_writel(ctlreg, w90p910_ts->ts_reg);
-
- w90p910_ts->state = TS_WAIT_Y_COORD;
-}
-
-static void w90p910_prepare_next_packet(struct w90p910_ts *w90p910_ts)
-{
- unsigned long ctlreg;
-
- ctlreg = __raw_readl(w90p910_ts->ts_reg);
- ctlreg &= ~(ADC_INT | ADC_INT_EN | ADC_SEMIAUTO | ADC_CONV);
- ctlreg |= ADC_WAITTRIG | WT_INT_EN;
- __raw_writel(ctlreg, w90p910_ts->ts_reg);
-
- w90p910_ts->state = TS_WAIT_NEW_PACKET;
-}
-
-static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id)
-{
- struct w90p910_ts *w90p910_ts = dev_id;
- unsigned long flags;
-
- spin_lock_irqsave(&w90p910_ts->lock, flags);
-
- switch (w90p910_ts->state) {
- case TS_WAIT_NEW_PACKET:
- /*
- * The controller only generates interrupts when pen
- * is down.
- */
- del_timer(&w90p910_ts->timer);
- w90p910_prepare_x_reading(w90p910_ts);
- break;
-
-
- case TS_WAIT_X_COORD:
- w90p910_prepare_y_reading(w90p910_ts);
- break;
-
- case TS_WAIT_Y_COORD:
- w90p910_report_event(w90p910_ts, true);
- w90p910_prepare_next_packet(w90p910_ts);
- mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(100));
- break;
-
- case TS_IDLE:
- break;
- }
-
- spin_unlock_irqrestore(&w90p910_ts->lock, flags);
-
- return IRQ_HANDLED;
-}
-
-static void w90p910_check_pen_up(struct timer_list *t)
-{
- struct w90p910_ts *w90p910_ts = from_timer(w90p910_ts, t, timer);
- unsigned long flags;
-
- spin_lock_irqsave(&w90p910_ts->lock, flags);
-
- if (w90p910_ts->state == TS_WAIT_NEW_PACKET &&
- !(__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN)) {
-
- w90p910_report_event(w90p910_ts, false);
- }
-
- spin_unlock_irqrestore(&w90p910_ts->lock, flags);
-}
-
-static int w90p910_open(struct input_dev *dev)
-{
- struct w90p910_ts *w90p910_ts = input_get_drvdata(dev);
- unsigned long val;
-
- /* enable the ADC clock */
- clk_enable(w90p910_ts->clk);
-
- __raw_writel(ADC_RST1, w90p910_ts->ts_reg);
- msleep(1);
- __raw_writel(ADC_RST0, w90p910_ts->ts_reg);
- msleep(1);
-
- /* set delay and screen type */
- val = __raw_readl(w90p910_ts->ts_reg + 0x04);
- __raw_writel(val & TSC_FOURWIRE, w90p910_ts->ts_reg + 0x04);
- __raw_writel(ADC_DELAY, w90p910_ts->ts_reg + 0x08);
-
- w90p910_ts->state = TS_WAIT_NEW_PACKET;
- wmb();
-
- /* set trigger mode */
- val = __raw_readl(w90p910_ts->ts_reg);
- val |= ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN;
- __raw_writel(val, w90p910_ts->ts_reg);
-
- return 0;
-}
-
-static void w90p910_close(struct input_dev *dev)
-{
- struct w90p910_ts *w90p910_ts = input_get_drvdata(dev);
- unsigned long val;
-
- /* disable trigger mode */
-
- spin_lock_irq(&w90p910_ts->lock);
-
- w90p910_ts->state = TS_IDLE;
-
- val = __raw_readl(w90p910_ts->ts_reg);
- val &= ~(ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN | ADC_INT_EN);
- __raw_writel(val, w90p910_ts->ts_reg);
-
- spin_unlock_irq(&w90p910_ts->lock);
-
- /* Now that interrupts are shut off we can safely delete timer */
- del_timer_sync(&w90p910_ts->timer);
-
- /* stop the ADC clock */
- clk_disable(w90p910_ts->clk);
-}
-
-static int w90x900ts_probe(struct platform_device *pdev)
-{
- struct w90p910_ts *w90p910_ts;
- struct input_dev *input_dev;
- struct resource *res;
- int err;
-
- w90p910_ts = kzalloc(sizeof(struct w90p910_ts), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!w90p910_ts || !input_dev) {
- err = -ENOMEM;
- goto fail1;
- }
-
- w90p910_ts->input = input_dev;
- w90p910_ts->state = TS_IDLE;
- spin_lock_init(&w90p910_ts->lock);
- timer_setup(&w90p910_ts->timer, w90p910_check_pen_up, 0);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- err = -ENXIO;
- goto fail1;
- }
-
- if (!request_mem_region(res->start, resource_size(res),
- pdev->name)) {
- err = -EBUSY;
- goto fail1;
- }
-
- w90p910_ts->ts_reg = ioremap(res->start, resource_size(res));
- if (!w90p910_ts->ts_reg) {
- err = -ENOMEM;
- goto fail2;
- }
-
- w90p910_ts->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(w90p910_ts->clk)) {
- err = PTR_ERR(w90p910_ts->clk);
- goto fail3;
- }
-
- input_dev->name = "W90P910 TouchScreen";
- input_dev->phys = "w90p910ts/event0";
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x0005;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0100;
- input_dev->dev.parent = &pdev->dev;
- input_dev->open = w90p910_open;
- input_dev->close = w90p910_close;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
- input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0);
-
- input_set_drvdata(input_dev, w90p910_ts);
-
- w90p910_ts->irq_num = platform_get_irq(pdev, 0);
- if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
- 0, "w90p910ts", w90p910_ts)) {
- err = -EBUSY;
- goto fail4;
- }
-
- err = input_register_device(w90p910_ts->input);
- if (err)
- goto fail5;
-
- platform_set_drvdata(pdev, w90p910_ts);
-
- return 0;
-
-fail5: free_irq(w90p910_ts->irq_num, w90p910_ts);
-fail4: clk_put(w90p910_ts->clk);
-fail3: iounmap(w90p910_ts->ts_reg);
-fail2: release_mem_region(res->start, resource_size(res));
-fail1: input_free_device(input_dev);
- kfree(w90p910_ts);
- return err;
-}
-
-static int w90x900ts_remove(struct platform_device *pdev)
-{
- struct w90p910_ts *w90p910_ts = platform_get_drvdata(pdev);
- struct resource *res;
-
- free_irq(w90p910_ts->irq_num, w90p910_ts);
- del_timer_sync(&w90p910_ts->timer);
- iounmap(w90p910_ts->ts_reg);
-
- clk_put(w90p910_ts->clk);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- input_unregister_device(w90p910_ts->input);
- kfree(w90p910_ts);
-
- return 0;
-}
-
-static struct platform_driver w90x900ts_driver = {
- .probe = w90x900ts_probe,
- .remove = w90x900ts_remove,
- .driver = {
- .name = "nuc900-ts",
- },
-};
-module_platform_driver(w90x900ts_driver);
-
-MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
-MODULE_DESCRIPTION("w90p910 touch screen driver!");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:nuc900-ts");
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index 8d7a285..f017af8 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -1,14 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Wacom Penabled Driver for I2C
*
* Copyright (c) 2011 - 2013 Tatsunosuke Tobita, Wacom.
* <tobita.tatsunosuke@wacom.co.jp>
- *
- * This program is free software; you can redistribute it
- * and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software
- * Foundation; either version of 2 of the License,
- * or (at your option) any later version.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 3715d1e..691285a 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -27,6 +27,8 @@
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
+#define W8001_MAX_PHYS 42
+
#define W8001_MAX_LENGTH 13
#define W8001_LEAD_MASK 0x80
#define W8001_LEAD_BYTE 0x80
@@ -89,7 +91,7 @@
unsigned char response_type;
unsigned char response[W8001_MAX_LENGTH];
unsigned char data[W8001_MAX_LENGTH];
- char phys[32];
+ char phys[W8001_MAX_PHYS];
int type;
unsigned int pktlen;
u16 max_touch_x;
diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
index 1db0a14..607d1ae 100644
--- a/drivers/input/touchscreen/wm831x-ts.c
+++ b/drivers/input/touchscreen/wm831x-ts.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Touchscreen driver for WM831x PMICs
*
* Copyright 2011 Wolfson Microelectronics plc.
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c
index adc13a5..4b55d5e 100644
--- a/drivers/input/touchscreen/wm9705.c
+++ b/drivers/input/touchscreen/wm9705.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec.
*
@@ -6,12 +7,6 @@
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
index 705ffa1..6947714 100644
--- a/drivers/input/touchscreen/wm9712.c
+++ b/drivers/input/touchscreen/wm9712.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs.
*
@@ -6,12 +7,6 @@
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c
index 572a5a6..a67fbe3 100644
--- a/drivers/input/touchscreen/wm9713.c
+++ b/drivers/input/touchscreen/wm9713.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* wm9713.c -- Codec touch driver for Wolfson WM9713 AC97 Codec.
*
@@ -6,12 +7,6 @@
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index 73856c2..0a174bd 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* wm97xx-core.c -- Touch screen driver core for Wolfson WM9705, WM9712
* and WM9713 AC97 Codecs.
@@ -8,11 +9,6 @@
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
* Notes:
*
* Features:
@@ -31,7 +27,6 @@
* - codec event notification
* Todo
* - Support for async sampling control for noisy LCDs.
- *
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/zet6223.c b/drivers/input/touchscreen/zet6223.c
index 19ffcc7..3b6f7ee 100644
--- a/drivers/input/touchscreen/zet6223.c
+++ b/drivers/input/touchscreen/zet6223.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2016, Jelle van der Waa <jelle@vdwaa.nl>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index 7b3845a..5230519 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012-2013 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
@@ -6,15 +7,6 @@
*
* Copyright (C) 2010 Barnes & Noble, Inc.
* Author: Pieter Truter<ptruter@intrinsyc.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c
index e2ccd68..0f4ac7f 100644
--- a/drivers/input/touchscreen/zylonite-wm97xx.c
+++ b/drivers/input/touchscreen/zylonite-wm97xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* zylonite-wm97xx.c -- Zylonite Continuous Touch screen driver
*
@@ -6,11 +7,6 @@
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
* Notes:
* This is a wm97xx extended touch driver supporting interrupt driven
* and continuous operation on Marvell Zylonite development systems