* Re: [RFC v3] iio: input-bridge: optionally bridge iio acceleometers to create a /dev/input interface
From: Bastien Nocera @ 2019-04-16 16:04 UTC (permalink / raw)
To: H. Nikolaus Schaller, Jonathan Cameron, Dmitry Torokhov
Cc: Eric Piel, linux-input, letux-kernel, kernel, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald-Stadler, linux-kernel,
linux-iio
In-Reply-To: <d52cf9ee5944c90c69f6e74a46d844cef51e487e.1555362312.git.hns@goldelico.com>
Having written a "bridge" myself (I called it a "proxy"[1]), I have a
few comments.
[1]: https://github.com/hadess/iio-sensor-proxy
Let's start with the easy ones ;) there's a typo in the subject line.
The subject line also says "optionally" but there doesn't seem to be
any ways to disable the feature if it's shipped by the kernel used.
On Mon, 2019-04-15 at 23:05 +0200, H. Nikolaus Schaller wrote:
> Some user spaces (e.g. some Android devices) use /dev/input/event*
> for handling
> the 3D position of the device with respect to the center of gravity
> (earth).
> This can be used for gaming input, auto-rotation of screens etc.
>
> This interface should be the standard for such use cases because it
> is an abstraction
> of how orientation data is acquired from sensor chips. Sensor chips
> may be connected
> through different interfaces and in different positions. They may
> also have different
> parameters. And, if a chip is replaced by a different one, the values
> reported by
> the device position interface should remain the same, provided the
> device tree reflects
> the changed chip.
I don't understand this section of the commit message. The IIO drivers
are already that abstraction interface, no?
> This did initially lead to input accelerometer drivers like
> drivers/input/misc/bma150.c
> or drivers/misc/lis3lv02d/
>
> But nowadays, new accelerometer chips mostly get iio drivers and
> rarely input drivers.
>
> Therefore we need something like a protocol stack which bridges raw
> data and input devices.
> It can be seen as a similar layering like TCP/IP vs. bare Ethernet.
> Or keyboard
> input events vs. raw gpio or raw USB access.
This can be done in user-space, reading the data from the IIO driver,
and using uinput to feed it back. Why is doing this at the kernel level
better?
> This patch bridges the gap between raw iio data and the input device
> abstraction
> so that accelerometer measurements can additionally be presented as
> X/Y/Z accelerometer
> channels (INPUT_PROP_ACCELEROMETER) through /dev/input/event*.
>
> There are no special requirements or changes needed for an iio
> driver.
The user-space daemon I wrote supports both IIO drivers and input
drivers for accelerometers. How do I know from user-space whether a
device is proxied or not?
> There is no need to define a mapping (e.g. in device tree).
>
> This driver simply collects the first 3 accelerometer channels as X,
> Y and Z.
> If only 1 or 2 channels are available, they are used for X and Y
> only. Additional
> channels are ignored.
In what cases are 2 dimensional accelerometers used?
> Scaling is done automatically so that 1g is represented by value 256
> and
> range is assumed to be -511 .. +511 which gives a reasonable
> precision as an
> input device.
>
> If a mount-matrix is provided by the iio driver, it is also taken
> into account
> so that the input event automatically gets the correct orientation
> with respect
> to the device.
>
> If this extension is not configured into the kernel it takes no
> resources (except
> source code).
>
> If it is configured, but there is no accelerometer, there is only a
> tiny penalty
> for scanning for accelerometer channels once during probe of each iio
> device.
>
> If it runs, the driver polls the device(s) once every 100 ms. A mode
> where the
> iio device defines the update rate is not implemented and for further
> study.
>
> If there is no user-space client, polling is not running.
Is the bridge going to modify the IIO device's settings behind other
possible consumer's backs, such as threshold values, and triggers?
> The driver is capable to handle multiple iio accelerometers and they
> are
> presented by unique /dev/input/event* files. The iio chip name is
> used to define
> the input device name so that it can be identified (e.g. by udev
> rules or evtest).
As you can probably guess, I'm not overly enthusiastic about this piece
of code. If it had existed 5 years ago, I probably wouldn't have
written iio-sensor-proxy, but then somebody else would have had to for
the rest of the IIO sensors that can be consumed.
To me, this bridge has all the drawbacks of a simple user-space
implementation using uinput, without much of the benefits of being an
exclusive user of the IIO accelerometers, such as being able to change
the update rate, or using triggers depending on the usage.
What am I missing? Why shouldn't this live in user-space?
Cheers
^ permalink raw reply
* Re: [PATCH v3 2/3] Input: add a driver for GPIO controllable vibrators
From: Luca Weiss @ 2019-04-16 16:02 UTC (permalink / raw)
To: Stephen Boyd
Cc: Dmitry Torokhov, Rob Herring, Mark Rutland, Mauro Carvalho Chehab,
Pascal PAILLET-LME, Coly Li, Lee Jones, Xiaotong Lu, Brian Masney,
Rob Herring, Baolin Wang, David Brown,
open list:ARM/QUALCOMM SUPPORT,
open list:INPUT KEYBOARD, MOUSE, JOYSTICK , TOUCHSCREEN...,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list
In-Reply-To: <155509103299.20095.15957232326393337000@swboyd.mtv.corp.google.com>
On Freitag, 12. April 2019 19:43:52 CEST Stephen Boyd wrote:
> Quoting Luca Weiss (2019-04-12 08:06:24)
>
> > diff --git a/drivers/input/misc/gpio-vibra.c
> > b/drivers/input/misc/gpio-vibra.c new file mode 100644
> > index 000000000000..3fd2dfd4f670
> > --- /dev/null
> > +++ b/drivers/input/misc/gpio-vibra.c
> > @@ -0,0 +1,209 @@
> > +
> > +static int gpio_vibrator_probe(struct platform_device *pdev)
> > +{
>
> [...]
>
> > + 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", err);
> > + return err;
> > + }
> > +
> > + err = input_register_device(vibrator->input);
> > + if (err) {
> > + dev_err(&pdev->dev, "Couldn't register input dev: %d",
> > err);
> All the printks in this file need a newline.
Fixed.
> > + return err;
> > + }
> > +
> > + platform_set_drvdata(pdev, vibrator);
> > +
> > + return 0;
> > +}
> > +
> > +
> > +#ifdef CONFIG_OF
> > +static const struct of_device_id gpio_vibra_dt_match_table[] = {
> > + { .compatible = "gpio-vibrator" },
> > + {},
>
> Nitpick: Drop the comma on the sentinel so nothing can go after it
> without causing a compilation error.
Changed as well.
> > +};
> > +MODULE_DEVICE_TABLE(of, gpio_vibra_dt_match_table);
> > +#endif
> > +
Thanks for the review! Will send a v4 shortly.
Luca
^ permalink raw reply
* Re: [PATCH v2 2/4] mfd: ioc3: Add driver for SGI IOC3 chip
From: Greg Kroah-Hartman @ 2019-04-16 13:16 UTC (permalink / raw)
To: Thomas Bogendoerfer
Cc: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
Lee Jones, David S. Miller, Alessandro Zummo, Alexandre Belloni,
Jiri Slaby, linux-mips, linux-kernel, linux-input, netdev,
linux-rtc, linux-serial
In-Reply-To: <20190409154610.6735-3-tbogendoerfer@suse.de>
On Tue, Apr 09, 2019 at 05:46:06PM +0200, Thomas Bogendoerfer wrote:
> SGI IOC3 chip has integrated ethernet, keyboard and mouse interface.
> It also supports connecting a SuperIO chip for serial and parallel
> interfaces. IOC3 is used inside various SGI systemboards and add-on
> cards with different equipped external interfaces.
>
> Support for ethernet and serial interfaces were implemented inside
> the network driver. This patchset moves out the not network related
> parts to a new MFD driver, which takes care of card detection,
> setup of platform devices and interrupt distribution for the subdevices.
>
> Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
> ---
> arch/mips/include/asm/sn/ioc3.h | 345 +++---
> arch/mips/sgi-ip27/ip27-timer.c | 20 -
> drivers/mfd/Kconfig | 13 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/ioc3.c | 802 ++++++++++++++
> drivers/net/ethernet/sgi/Kconfig | 4 +-
> drivers/net/ethernet/sgi/ioc3-eth.c | 1867 ++++++++++++---------------------
> drivers/tty/serial/8250/8250_ioc3.c | 98 ++
> drivers/tty/serial/8250/Kconfig | 11 +
> drivers/tty/serial/8250/Makefile | 1 +
> include/linux/platform_data/ioc3eth.h | 15 +
> 11 files changed, 1762 insertions(+), 1415 deletions(-)
> create mode 100644 drivers/mfd/ioc3.c
> create mode 100644 drivers/tty/serial/8250/8250_ioc3.c
> create mode 100644 include/linux/platform_data/ioc3eth.h
Serial portion:
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
^ permalink raw reply
* Re: [PATCH 3/3] iio: Add PAT9125 optical tracker sensor
From: Alexandre @ 2019-04-16 12:54 UTC (permalink / raw)
Cc: linux-kernel, linux-iio, linux-input
In-Reply-To: <20190407112024.6297cbfa@archlinux>
Hello Jonathan,
On 4/7/19 12:20, Jonathan Cameron wrote:
> Hi Alexandre,
>
> So I have no problem with this as an IIO driver, but for devices that
> are somewhat 'on the edge' I always like to get a clear answer to the
> question: Why not input?
>
> I would also argue that, to actually be 'useful' we would typically need
> some representation of the 'mechanicals' that are providing the motion
> being measured. Looking at the datasheet this includes, rotating shafts
> (side or end on), disk edges and flat surface tracking (mouse like).
>
> That's easy enough to do with the iio in kernel consumer interface. These
> are similar to when we handle analog electronic front ends.
>
> I you can, please describe what it is being used for in your application
> as that may give us somewhere to start!
>
> + CC Dmitry and linux-input.
I developed this driver to detect the board movement which can't be
detected by accelerometer (very slow motion). I admit this use case can
be handled by an input, and I'm agree with you, PAT9125 driver could be
an input. But, like you said, this chip is able to track different kind
of motion, and additionally have an interrupt GPIO, so using it like
input limit the driver potential. This chip is designed to work in
industrial measurement or embedded systems, and the IIO API match with
these environments, so it's the best way to exploit the entire potential
of this chip.
As I understand (from
https://www.kernel.org/doc/html/v4.12/input/event-codes.html#mice ),
mouse driver must report values when the device move. This feature
souldn't be mandatory for an optical tracker driver, specially for cases
where user prefers to use buffer or poll only when he need data.
> If 1 or 2, I would suggest that you provide absolute position to
> Linux. So add the value to a software counter and provide that.
> 32 bits should be plenty of resolution for that.
I can't provide absolute position, only relative. Do you mean using
input driver to do that ? If not, how is built the position data?
> Silly question for you. What happens if you set the delta values to 0?
> Do we get an interrupt which is effectively data ready?
> If we do, you might want to think about a scheme where that is an option.
> As things currently stand we have a confusing interface where changing this
> threshold effects the buffered data output. That should only be the
> case if this interface is for a trigger, not an event.
I'm not sure to understand your question. Is it possible to read delta_x
and delta_y = 0 in special/corner case because internal value continue
to be updated after toggled motion_detect pin (used for IRQ) until
values registers are read and then motion_detect pin is released:
* Chip move (i.e. +2 on X axis and 0 on Y axis)
* Motion_detect IRQ trigger and internal reg value is updated (i.e.
delta_x = 2 and delta_y = 0)
* GPIO IRQ handled but read_value isn't executed yet (timing reason)
* Chip move back to it origin point (i.e. -2 on X axis and 0 on Y axis)
* Motion_detect IRQ still low because it hasn't been reset by read
value and internal reg value is updated (i.e. delta_x = 0 and
delta_y = 0)
* Read_value is executed, we get delta values = 0.
> If it is actually not possible to report the two channels separately
> then don't report them at all except via the buffered interface and
> set the available scan masks so that both are on.
I found a way to keep the consistency between delta x and delta y
(without losing data). The first part is to reset a value only when user
read it (also when it's buffered). The second part is to add the new
value to the old value. With these two mechanism, X and Y will always be
consistent:
* as possible during a move.
* perfectly when move is finished.
Regards,
Alexandre
^ permalink raw reply
* Re: [PATCH v5 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Andy Shevchenko @ 2019-04-16 12:52 UTC (permalink / raw)
To: Life is hard, and then you die
Cc: Dmitry Torokhov, Henrik Rydberg, Andrzej Hajda, Inki Dae,
Greg Kroah-Hartman, Lukas Wunner, Federico Lorenzi,
Laurent Pinchart, linux-input, dri-devel, linux-kernel
In-Reply-To: <20190415230955.GA13033@innovation.ch>
On Mon, Apr 15, 2019 at 04:09:55PM -0700, Life is hard, and then you die wrote:
> On Mon, Apr 15, 2019 at 12:03:46PM +0300, Andy Shevchenko wrote:
> > On Mon, Apr 15, 2019 at 01:13:00AM -0700, Ronald Tschalär wrote:
> > > +static void
> > > +applespi_remap_fn_key(struct keyboard_protocol *keyboard_protocol)
> > > +{
> > > + unsigned char tmp;
> >
> > > + u8 bit = BIT(fnremap - 1);
> >
> > The above is UB and I'm sorry I didn't find this earlier.
> >
> > So, something like this would work
> >
> > u8 bit = BIT((fnremap - 1) & 0x07);
>
> fnremap is already constrained by the following:
"already" is a wrong word here. Compiler checks in the order of appearing, so,
for it it is UB and we need to limit bits to allowed range, up to 31 for
unsigned int.
>
> > > +
> > > + if (!fnremap || fnremap > ARRAY_SIZE(applespi_controlcodes) ||
> > > + !applespi_controlcodes[fnremap - 1])
> > > + return;
>
> and the array-size of applespi_controlcodes is constrained to the
> number of bits in u8 according to this assertion
>
> > > + compiletime_assert(ARRAY_SIZE(applespi_controlcodes) ==
> > > + sizeof_field(struct keyboard_protocol, modifiers) * 8,
> > > + "applespi_controlcodes has wrong number of entries");
>
> So I don't see that the masking buys anything new.
It buys us the follow to the standard. But gcc is clever enough to strip number
to allowed one.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH v6 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Ronald Tschalär @ 2019-04-16 10:26 UTC (permalink / raw)
To: Dmitry Torokhov, Henrik Rydberg, Andy Shevchenko, Andrzej Hajda,
Inki Dae, Greg Kroah-Hartman
Cc: Lukas Wunner, Federico Lorenzi, Laurent Pinchart, linux-input,
dri-devel, linux-kernel
In-Reply-To: <20190416102647.5602-1-ronald@innovation.ch>
The keyboard and trackpad on recent MacBook's (since 8,1) and
MacBookPro's (13,* and 14,*) are attached to an SPI controller instead
of USB, as previously. The higher level protocol is not publicly
documented and hence has been reverse engineered. As a consequence there
are still a number of unknown fields and commands. However, the known
parts have been working well and received extensive testing and use.
In order for this driver to work, the proper SPI drivers need to be
loaded too; for MB8,1 these are spi_pxa2xx_platform and spi_pxa2xx_pci;
for all others they are spi_pxa2xx_platform and intel_lpss_pci. For this
reason enabling this driver in the config implies enabling the above
drivers.
CC: Federico Lorenzi <federico@travelground.com>
CC: Lukas Wunner <lukas@wunner.de>
CC: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=99891
Link: https://bugzilla.kernel.org/show_bug.cgi?id=108331
Signed-off-by: Ronald Tschalär <ronald@innovation.ch>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/input/keyboard/Kconfig | 15 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/applespi.c | 1975 +++++++++++++++++++++++
drivers/input/keyboard/applespi.h | 29 +
drivers/input/keyboard/applespi_trace.h | 94 ++
5 files changed, 2114 insertions(+)
create mode 100644 drivers/input/keyboard/applespi.c
create mode 100644 drivers/input/keyboard/applespi.h
create mode 100644 drivers/input/keyboard/applespi_trace.h
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a878351f1643..d0a9e7fa2508 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -70,6 +70,21 @@ config KEYBOARD_AMIGA
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
+ imply SPI_PXA2XX
+ imply SPI_PXA2XX_PCI
+ imply MFD_INTEL_LPSS_PCI
+ help
+ Say Y here if you are running Linux on any Apple MacBook8,1 or later,
+ or any MacBookPro13,* or MacBookPro14,*.
+
+ 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
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 182e92985dbf..9283fee2505a 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
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
diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
new file mode 100644
index 000000000000..74e235e2e543
--- /dev/null
+++ b/drivers/input/keyboard/applespi.c
@@ -0,0 +1,1975 @@
+// 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 coodinate
+ * @abs_y: absolute y coodinate
+ * @rel_x: relative x coodinate
+ * @rel_y: relative y coodinate
+ * @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;
+ int sts;
+
+ 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);
+ }
+
+ sts = 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_t(int, applespi->tp_dim_min_x, f->abs_x);
+ applespi->tp_dim_max_x = max_t(int, applespi->tp_dim_max_x, f->abs_x);
+ applespi->tp_dim_min_y = min_t(int, applespi->tp_dim_min_y, f->abs_y);
+ applespi->tp_dim_max_y = max_t(int, applespi->tp_dim_max_y, 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, j;
+
+ 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 */
+ input_mt_init_slots(touchpad_input_dev, MAX_FINGERS,
+ INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
+ INPUT_MT_TRACK);
+
+ /* 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 = sizeof(*tp) +
+ tp->number_of_fingers * sizeof(tp->fingers[0]);
+
+ 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_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);
+ if (IS_ERR(applespi->debugfs_root)) {
+ if (PTR_ERR(applespi->debugfs_root) != -ENODEV)
+ dev_warn(&applespi->spi->dev,
+ "Error creating debugfs root entry (%ld)\n",
+ PTR_ERR(applespi->debugfs_root));
+ } else {
+ struct dentry *ret;
+
+ ret = debugfs_create_bool("enable_tp_dim", 0600,
+ applespi->debugfs_root,
+ &applespi->debug_tp_dim);
+ if (IS_ERR(ret))
+ dev_dbg(&applespi->spi->dev,
+ "Error creating debugfs entry enable_tp_dim (%ld)\n",
+ PTR_ERR(ret));
+
+ ret = debugfs_create_file("tp_dim", 0400,
+ applespi->debugfs_root, applespi,
+ &applespi_tp_dim_fops);
+ if (IS_ERR(ret))
+ dev_dbg(&applespi->spi->dev,
+ "Error creating debugfs entry tp_dim (%ld)\n",
+ PTR_ERR(ret));
+ }
+
+ 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;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int 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 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;
+}
+#endif
+
+static const struct acpi_device_id applespi_acpi_match[] = {
+ { "APP000D", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, applespi_acpi_match);
+
+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 000000000000..7f5ab10c597a
--- /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 000000000000..5e965e1974c7
--- /dev/null
+++ b/drivers/input/keyboard/applespi_trace.h
@@ -0,0 +1,94 @@
+/* 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>
+
--
2.20.1
^ permalink raw reply related
* [PATCH v6 1/2] drm/bridge: sil_sii8620: make remote control optional.
From: Ronald Tschalär @ 2019-04-16 10:26 UTC (permalink / raw)
To: Dmitry Torokhov, Henrik Rydberg, Andy Shevchenko, Andrzej Hajda,
Inki Dae, Greg Kroah-Hartman
Cc: Lukas Wunner, Federico Lorenzi, Laurent Pinchart, linux-input,
dri-devel, linux-kernel
In-Reply-To: <20190416102647.5602-1-ronald@innovation.ch>
commit d6abe6df706c (drm/bridge: sil_sii8620: do not have a dependency
of RC_CORE) changed the driver to select both RC_CORE and INPUT.
However, this causes problems with other drivers, in particular an input
driver that depends on MFD_INTEL_LPSS_PCI (to be added in a separate
commit):
drivers/clk/Kconfig:9:error: recursive dependency detected!
drivers/clk/Kconfig:9: symbol COMMON_CLK is selected by MFD_INTEL_LPSS
drivers/mfd/Kconfig:566: symbol MFD_INTEL_LPSS is selected by MFD_INTEL_LPSS_PCI
drivers/mfd/Kconfig:580: symbol MFD_INTEL_LPSS_PCI is implied by KEYBOARD_APPLESPI
drivers/input/keyboard/Kconfig:73: symbol KEYBOARD_APPLESPI depends on INPUT
drivers/input/Kconfig:8: symbol INPUT is selected by DRM_SIL_SII8620
drivers/gpu/drm/bridge/Kconfig:83: symbol DRM_SIL_SII8620 depends on DRM_BRIDGE
drivers/gpu/drm/bridge/Kconfig:1: symbol DRM_BRIDGE is selected by DRM_PL111
drivers/gpu/drm/pl111/Kconfig:1: symbol DRM_PL111 depends on COMMON_CLK
According to the docs and general consensus, select should only be used
for non user-visible symbols, but both RC_CORE and INPUT are
user-visible. Furthermore almost all other references to INPUT
throughout the kernel config are depends, not selects. For this reason
the first part of this change reverts commit d6abe6df706c.
In order to address the original reason for commit d6abe6df706c, namely
that not all boards use the remote controller functionality and hence
should not need have to deal with RC_CORE, the second part of this
change now makes the remote control support in the driver optional and
contingent on RC_CORE being defined. And with this the hard dependency
on INPUT also goes away as that is only needed if RC_CORE is defined
(which in turn already depends on INPUT).
CC: Inki Dae <inki.dae@samsung.com>
CC: Andrzej Hajda <a.hajda@samsung.com>
CC: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
CC: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Ronald Tschalär <ronald@innovation.ch>
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
---
drivers/gpu/drm/bridge/Kconfig | 3 +--
drivers/gpu/drm/bridge/sil-sii8620.c | 10 +++++++---
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 2fee47b0d50b..9cf07105b73a 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -85,8 +85,7 @@ config DRM_SIL_SII8620
depends on OF
select DRM_KMS_HELPER
imply EXTCON
- select INPUT
- select RC_CORE
+ imply RC_CORE
help
Silicon Image SII8620 HDMI/MHL bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
index a6e8f4591e63..cff3131aae6c 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -1763,10 +1763,8 @@ static bool sii8620_rcp_consume(struct sii8620 *ctx, u8 scancode)
scancode &= MHL_RCP_KEY_ID_MASK;
- if (!ctx->rc_dev) {
- dev_dbg(ctx->dev, "RCP input device not initialized\n");
+ if (!IS_ENABLED(CONFIG_RC_CORE) || !ctx->rc_dev)
return false;
- }
if (pressed)
rc_keydown(ctx->rc_dev, RC_PROTO_CEC, scancode, 0);
@@ -2103,6 +2101,9 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx)
struct rc_dev *rc_dev;
int ret;
+ if (!IS_ENABLED(CONFIG_RC_CORE))
+ return;
+
rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
if (!rc_dev) {
dev_err(ctx->dev, "Failed to allocate RC device\n");
@@ -2217,6 +2218,9 @@ static void sii8620_detach(struct drm_bridge *bridge)
{
struct sii8620 *ctx = bridge_to_sii8620(bridge);
+ if (!IS_ENABLED(CONFIG_RC_CORE))
+ return;
+
rc_unregister_device(ctx->rc_dev);
}
--
2.20.1
^ permalink raw reply related
* [PATCH v6 0/2] Add Apple SPI keyboard and trackpad driver
From: Ronald Tschalär @ 2019-04-16 10:26 UTC (permalink / raw)
To: Dmitry Torokhov, Henrik Rydberg, Andy Shevchenko, Andrzej Hajda,
Inki Dae, Greg Kroah-Hartman
Cc: Lukas Wunner, Federico Lorenzi, Laurent Pinchart, linux-input,
dri-devel, linux-kernel
This changeset adds a driver for the SPI keyboard and trackpad on recent
MacBook's and MacBook Pro's. The driver has seen a fair amount of use
over the last 2 years (basically anybody running linux on these
machines), with only relatively small changes in the last year or so.
For those interested, the driver development has been hosted at
https://github.com/cb22/macbook12-spi-driver/ (as well as my clone at
https://github.com/roadrunner2/macbook12-spi-driver/).
The first patch fixes a problem during config. While it affects the drm
tree, Andrzej Hajda has given his ok for this patch to be taken via the
input tree because the second patch here depends on it.
The second patch contains the new applespi driver.
Changes in v6:
Applied all feedback from review by Andy Shevchenko:
- use memchr() and friends instead of hand-rolled loops
- minor code tweak
The full set of changes to applespi can be viewed at
https://github.com/roadrunner2/macbook12-spi-driver/ as individual
commits 36afd70..fa81d40 in the upstreaming-review branch.
Ronald Tschalär (2):
drm/bridge: sil_sii8620: make remote control optional.
Input: add Apple SPI keyboard and trackpad driver.
drivers/gpu/drm/bridge/Kconfig | 3 +-
drivers/gpu/drm/bridge/sil-sii8620.c | 10 +-
drivers/input/keyboard/Kconfig | 15 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/applespi.c | 1975 +++++++++++++++++++++++
drivers/input/keyboard/applespi.h | 29 +
drivers/input/keyboard/applespi_trace.h | 94 ++
7 files changed, 2122 insertions(+), 5 deletions(-)
create mode 100644 drivers/input/keyboard/applespi.c
create mode 100644 drivers/input/keyboard/applespi.h
create mode 100644 drivers/input/keyboard/applespi_trace.h
--
2.20.1
^ permalink raw reply
* Re: [PATCH v5 1/2] drm/bridge: sil_sii8620: make remote control optional.
From: Life is hard, and then you die @ 2019-04-16 10:25 UTC (permalink / raw)
To: Andrzej Hajda
Cc: Dmitry Torokhov, Henrik Rydberg, Andy Shevchenko, Inki Dae,
Greg Kroah-Hartman, Lukas Wunner, Federico Lorenzi,
Laurent Pinchart, linux-input, dri-devel, linux-kernel
In-Reply-To: <dd5189a2-8422-5e3c-1c79-d68680117deb@samsung.com>
Hi Andrzej,
On Tue, Apr 16, 2019 at 07:56:31AM +0200, Andrzej Hajda wrote:
> On 16.04.2019 01:24, Life is hard, and then you die wrote:
> > Hi Andrzej,
> >
> > On Mon, Apr 15, 2019 at 10:58:09AM +0200, Andrzej Hajda wrote:
> >> On 15.04.2019 10:12, Ronald Tschalär wrote:
> >>> commit d6abe6df706c (drm/bridge: sil_sii8620: do not have a dependency
> >>> of RC_CORE) changed the driver to select both RC_CORE and INPUT.
> >>> However, this causes problems with other drivers, in particular an input
> >>> driver that depends on MFD_INTEL_LPSS_PCI (to be added in a separate
> >>> commit):
> >>>
> >>> drivers/clk/Kconfig:9:error: recursive dependency detected!
> >>> drivers/clk/Kconfig:9: symbol COMMON_CLK is selected by MFD_INTEL_LPSS
> >>> drivers/mfd/Kconfig:566: symbol MFD_INTEL_LPSS is selected by MFD_INTEL_LPSS_PCI
> >>> drivers/mfd/Kconfig:580: symbol MFD_INTEL_LPSS_PCI is implied by KEYBOARD_APPLESPI
> >>> drivers/input/keyboard/Kconfig:73: symbol KEYBOARD_APPLESPI depends on INPUT
> >>> drivers/input/Kconfig:8: symbol INPUT is selected by DRM_SIL_SII8620
> >>> drivers/gpu/drm/bridge/Kconfig:83: symbol DRM_SIL_SII8620 depends on DRM_BRIDGE
> >>> drivers/gpu/drm/bridge/Kconfig:1: symbol DRM_BRIDGE is selected by DRM_PL111
> >>> drivers/gpu/drm/pl111/Kconfig:1: symbol DRM_PL111 depends on COMMON_CLK
> >>>
> >>> According to the docs and general consensus, select should only be used
> >>> for non user-visible symbols, but both RC_CORE and INPUT are
> >>> user-visible. Furthermore almost all other references to INPUT
> >>> throughout the kernel config are depends, not selects. For this reason
> >>> the first part of this change reverts commit d6abe6df706c.
> >>>
> >>> In order to address the original reason for commit d6abe6df706c, namely
> >>> that not all boards use the remote controller functionality and hence
> >>> should not need have to deal with RC_CORE, the second part of this
> >>> change now makes the remote control support in the driver optional and
> >>> contingent on RC_CORE being defined. And with this the hard dependency
> >>> on INPUT also goes away as that is only needed if RC_CORE is defined
> >>> (which in turn already depends on INPUT).
> >>>
> >>> CC: Inki Dae <inki.dae@samsung.com>
> >>> CC: Andrzej Hajda <a.hajda@samsung.com>
> >>> CC: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >>> CC: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> >>> Signed-off-by: Ronald Tschalär <ronald@innovation.ch>
> >>
> >> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
> > Thanks for your reviews!
> >
> >> If there are no objections I will take it to drm-misc tomorrow.
> > This brings us back to the discussion started in response to the first
> > version of my patch (see
> > https://lore.kernel.org/lkml/20190124082423.23139-1-ronald@innovation.ch/T/#m24f45fecd987a787a9554c8088f463fd10de2b00).
> > To recap: the problem is that the applespi patch depends on this patch
> > here, as make-config will break as described above otherwise. So if
> > this patch is submitted through drm-misc, then it's unclear to me how
> > to ensure that the two patches make it upstream in proper order,
> > unless the applespi patch is also upstreamed through drm-misc, or the
> > Kconfig for applespi is (temporarily) modified to not trigger the
> > config error and another patch is later submitted to fix the Kconfig
> > again (which seems somewhat ugly to me). Assuming that consensus is to
> > merge both patches through one tree, then it would seem that because
> > this patch here is relatively small that maybe it could be merged
> > through the input tree along with the applespi patch?
>
>
> Oh, I have forgot. Please take it then via input tree.
Thank you!
Cheers,
Ronald
^ permalink raw reply
* Re: [PATCH v5 1/2] drm/bridge: sil_sii8620: make remote control optional.
From: Andrzej Hajda @ 2019-04-16 5:56 UTC (permalink / raw)
To: Life is hard, and then you die
Cc: Dmitry Torokhov, Henrik Rydberg, Andy Shevchenko, Inki Dae,
Greg Kroah-Hartman, Lukas Wunner, Federico Lorenzi,
Laurent Pinchart, linux-input, dri-devel, linux-kernel
In-Reply-To: <20190415232444.GB13033@innovation.ch>
On 16.04.2019 01:24, Life is hard, and then you die wrote:
> Hi Andrzej,
>
> On Mon, Apr 15, 2019 at 10:58:09AM +0200, Andrzej Hajda wrote:
>> On 15.04.2019 10:12, Ronald Tschalär wrote:
>>> commit d6abe6df706c (drm/bridge: sil_sii8620: do not have a dependency
>>> of RC_CORE) changed the driver to select both RC_CORE and INPUT.
>>> However, this causes problems with other drivers, in particular an input
>>> driver that depends on MFD_INTEL_LPSS_PCI (to be added in a separate
>>> commit):
>>>
>>> drivers/clk/Kconfig:9:error: recursive dependency detected!
>>> drivers/clk/Kconfig:9: symbol COMMON_CLK is selected by MFD_INTEL_LPSS
>>> drivers/mfd/Kconfig:566: symbol MFD_INTEL_LPSS is selected by MFD_INTEL_LPSS_PCI
>>> drivers/mfd/Kconfig:580: symbol MFD_INTEL_LPSS_PCI is implied by KEYBOARD_APPLESPI
>>> drivers/input/keyboard/Kconfig:73: symbol KEYBOARD_APPLESPI depends on INPUT
>>> drivers/input/Kconfig:8: symbol INPUT is selected by DRM_SIL_SII8620
>>> drivers/gpu/drm/bridge/Kconfig:83: symbol DRM_SIL_SII8620 depends on DRM_BRIDGE
>>> drivers/gpu/drm/bridge/Kconfig:1: symbol DRM_BRIDGE is selected by DRM_PL111
>>> drivers/gpu/drm/pl111/Kconfig:1: symbol DRM_PL111 depends on COMMON_CLK
>>>
>>> According to the docs and general consensus, select should only be used
>>> for non user-visible symbols, but both RC_CORE and INPUT are
>>> user-visible. Furthermore almost all other references to INPUT
>>> throughout the kernel config are depends, not selects. For this reason
>>> the first part of this change reverts commit d6abe6df706c.
>>>
>>> In order to address the original reason for commit d6abe6df706c, namely
>>> that not all boards use the remote controller functionality and hence
>>> should not need have to deal with RC_CORE, the second part of this
>>> change now makes the remote control support in the driver optional and
>>> contingent on RC_CORE being defined. And with this the hard dependency
>>> on INPUT also goes away as that is only needed if RC_CORE is defined
>>> (which in turn already depends on INPUT).
>>>
>>> CC: Inki Dae <inki.dae@samsung.com>
>>> CC: Andrzej Hajda <a.hajda@samsung.com>
>>> CC: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>> CC: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>>> Signed-off-by: Ronald Tschalär <ronald@innovation.ch>
>>
>> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
> Thanks for your reviews!
>
>> If there are no objections I will take it to drm-misc tomorrow.
> This brings us back to the discussion started in response to the first
> version of my patch (see
> https://lore.kernel.org/lkml/20190124082423.23139-1-ronald@innovation.ch/T/#m24f45fecd987a787a9554c8088f463fd10de2b00).
> To recap: the problem is that the applespi patch depends on this patch
> here, as make-config will break as described above otherwise. So if
> this patch is submitted through drm-misc, then it's unclear to me how
> to ensure that the two patches make it upstream in proper order,
> unless the applespi patch is also upstreamed through drm-misc, or the
> Kconfig for applespi is (temporarily) modified to not trigger the
> config error and another patch is later submitted to fix the Kconfig
> again (which seems somewhat ugly to me). Assuming that consensus is to
> merge both patches through one tree, then it would seem that because
> this patch here is relatively small that maybe it could be merged
> through the input tree along with the applespi patch?
Oh, I have forgot. Please take it then via input tree.
Regards
Andrzej
>
>
> Cheers,
>
> Ronald
>
>
>
^ permalink raw reply
* Re: [PATCH] ELAN touchpad i2c_hid bugs fix
From: Kai-Heng Feng @ 2019-04-16 3:59 UTC (permalink / raw)
To: Hans de Goede
Cc: hotwater438, Dmitry Torokhov, Vladislav Dalechyn,
Benjamin Tissoires, Jiri Kosina, Swboyd, Bigeasy,
open list:HID CORE LAYER, lkml
In-Reply-To: <b495a521-16b5-8005-16be-e0b899f954f7@redhat.com>
at 19:42, Hans de Goede <hdegoede@redhat.com> wrote:
> Hi,
>
> On 15-04-19 13:36, hotwater438@tutanota.com wrote:
>> Sorry for the delay.
>> By applying this patch I get next results:
>> Five finger tap and two finger scroll issues disappear, but after
>> suspend touchpad dies. Restarting module doesn't help.
>
> So bascally the same results as with the edge-triggered interrupt
> patch/hack,
> right?
>
> Are you still using the edge-triggered interrupt patch, or just the new
> patch Kai-Heng Feng provided.
>
> To me it sounds like the patch Kai-Heng Feng provided at least removes
> the need for the edge-triggered interrupt patch/hack and what remains to
> be solved is the suspend/resume issues.
Great! I’ll send a patch to address this issue.
Kai-Heng
>
> Regards,
>
> Hans
>
>
>
>> Here's the log:
>> Apr 15 14:35:54 parrot sudo[3473]: h0tw4t3r : TTY=pts/1 ;
>> PWD=/home/h0tw4t3r ; USER=root ; COMMAND=/sbin/rmmod i2c_hid
>> Apr 15 14:35:54 parrot sudo[3478]: h0tw4t3r : TTY=pts/1 ;
>> PWD=/home/h0tw4t3r ; USER=root ; COMMAND=/sbin/modprobe i2c_hid
>> Apr 15 14:35:54 parrot kernel: i2c_hid i2c-ELAN1200:00: i2c-ELAN1200:00
>> supply vdd not found, using dummy regulator
>> Apr 15 14:35:54 parrot kernel: i2c_hid i2c-ELAN1200:00: i2c-ELAN1200:00
>> supply vddl not found, using dummy regulator
>> Could you please explain what this patch does?
>> Regards,
>> Vladislav.
>> Apr 13, 2019, 11:42 AM by kai.heng.feng@canonical.com:
>> at 16:40, <hotwater438@tutanota.com <mailto:hotwater438@tutanota.com>> <hotwater438@tutanota.com <mailto:hotwater438@tutanota.com>> wrote:
>> Hi.
>> I've applied this patch, but still getting incomplete report messages.
>> Does the patch fix the other two issues:
>> - Five finger tap kill's module so you have to restart it;
>> - Two finger scoll is working incorrect and sometimes even when you
>> raised one of two finger still thinks that you are scrolling.
>> Kai-Heng
>> Regards,
>> Vladislav
>> Apr 11, 2019, 7:17 PM by kai.heng.feng@canonical.com <mailto:kai.heng.feng@canonical.com>:
>> Hi,
>> at 05:18, <hotwater438@tutanota.com <mailto:hotwater438@tutanota.com>> <hotwater438@tutanota.com <mailto:hotwater438@tutanota.com>> wrote:
>> Hi.
>> 1) Run "cat /proc/interrupts | grep ELAN" , note down the value
>> 2) Very quickly/briefly touch the touchpad once
>> 3) Run "cat /proc/interrupts | grep ELAN" , note down the value again
>> 4) Subtract result from 1. from result from 3, this difference is
>> the value we are interested in. E.g. my testing got 254 and 257, so
>> a difference of 3.
>> I've tested that, main diffs are 30, 24, 16 (the most frequent), 2 (the least frequent).
>> I was using 4.19.13 kernel, because I use ParrotOS (which happens to be Debian distribution).
>> But I've installed experimental 5.0.0 kernel and I can't say right now if suspend problem is resolved (i have to rebuild latest kernel with patch).
>> Can you try below fix?
>> This can solve what commit 1475af255e18 ("HID: i2c-hid: Ignore input report if there's no data present on Elan touchpanels”) tries to workaround.
>> diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
>> index c19a4c45f7bb..30e3664f1ae5 100644
>> --- a/drivers/pinctrl/intel/pinctrl-intel.c
>> +++ b/drivers/pinctrl/intel/pinctrl-intel.c
>> @@ -957,6 +957,10 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
>> reg = community->regs + community->ie_offset + gpp * 4;
>> raw_spin_lock_irqsave(&pctrl->lock, flags);
>> +
>> + if (!mask)
>> + writel(BIT(gpp_offset), community->regs + community->is_offset + gpp * 4);
>> +
>> value = readl(reg);
>> if (mask)
>> value &= ~BIT(gpp_offset);
>> Regards,
>> Vladislav.
>> Apr 3, 2019, 2:18 PM by hdegoede@redhat.com <mailto:hdegoede@redhat.com>:
>> Hi,
>> On 31-03-19 11:50, hotwater438@tutanota.com <mailto:hotwater438@tutanota.com> wrote:
>> Hi. I've done everything you said, here are results:
>> Vladislav can you check the output of /cat/interrupts on a kernel
>> without the patch and while *not* using the touchpad; and check
>> if the amount of touchpads-interrupts still keeps increasing in this
>> case?
>> IWI or IRQ work interrupts keep increasing with speed at least 3 interrupts/s.
>> I'm really only interested in the touchpad related IRQs, so e.g. the line
>> about "intel-gpio 129 ELAN1200:00", if you're seeing 3 interrupts/s on
>> some others that is fine, so I take it the ELAN1200:00 interrupt count
>> does not increase on an *unpatched* kernel, unless you use the touchpad?
>> Also when I am moving touchpad IR-IO-APIC 14-fasteoi INT345D:00 get's triggered and increased.
>> That is the GPIO controller interrupt, so that one increasing is normal.
>> If I understand things correctly then this all means that the IRQ indeed
>> is a normal level IRQ and Dmitry is likely correct that there is an
>> pinctrl / gpiochip driver problem here.
>> Can you try the following with an *unpatched* kernel? :
>> 1) Run "cat /proc/interrupts | grep ELAN" , note down the value
>> 2) Very quickly/briefly touch the touchpad once
>> 3) Run "cat /proc/interrupts | grep ELAN" , note down the value again
>> 4) Subtract result from 1. from result from 3, this difference is
>> the value we are interested in. E.g. my testing got 254 and 257, so
>> a difference of 3.
>> The goal here is to get an as low as possible difference. Feel free
>> to repeat this a couple of times.
>> On an Apollo Lake laptop with an I2C hid mt touchpad I can get the
>> amount of interrupts triggered for a single touch down to 3,
>> given the huge interrupt counts of 130000+ reported in:
>> https://bugzilla.redhat.com/show_bug.cgi?id=1543769
>> I expect you to get a much bigger smallest possible difference
>> between 2 "cat /proc/interrupts | grep ELAN" commands, note a
>> difference of 0 means your touch did not register.
>> Assuming you indeed see much more interrupts for a very quick
>> touch + release, then we indeed have an interrupt handling problem
>> we need to investigate further.
>> I don't know if it's important or not, but for some reason these interrupts keep popping only on CPU2 (i have 4cpu processor).
>> That does not matter.
>> 1) Suspending the machine by selecting suspend from a menu in your
>> desktop environment, or by briefly pressing the power-button, do
>> not close the lid
>> 2) As soon as the system starts suspending and while it is suspended, move
>> your finger around the touchpad
>> 3) Wake the system up with the powerbutton while moving your finger around
>> 4) Check if the touchpad still works after this
>> It works, but as it seems, looses edge. JournalCTL is being flooded with i2c_hid_get_input: incomplete report (16/65535)
>> That is probably a different issue. If you loose the edge IRQ, then the touchpad
>> would stop working without any messages. I believe that the suspend / resume
>> issue may be fixed by:
>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=52cf93e63ee672a92f349edc6ddad86ec8808fd8
>> Does your kernel have this commit? (please always use the latest kernel while
>> testing).
>> Also a thing to notice, that after manually removing and modprobing i2c_hid module, it says next in journalctl:
>> i2c_hid i2c-ELAN1200:00: i2c-ELAN1200:00 supply vdd not found, using dummy regulator
>> i2c_hid i2c-ELAN1200:00: i2c-ELAN1200:00 supply vddl not found, using dummy regulator
>> Those messages can safely be ignored.
>> Regards,
>> Hans
^ permalink raw reply
* Re: [PATCH v5 1/2] drm/bridge: sil_sii8620: make remote control optional.
From: Life is hard, and then you die @ 2019-04-15 23:24 UTC (permalink / raw)
To: Andrzej Hajda
Cc: Dmitry Torokhov, Henrik Rydberg, Andy Shevchenko, Inki Dae,
Greg Kroah-Hartman, Lukas Wunner, Federico Lorenzi,
Laurent Pinchart, linux-input, dri-devel, linux-kernel
In-Reply-To: <76cf3079-f190-bed4-7a00-149d7fa0a650@samsung.com>
Hi Andrzej,
On Mon, Apr 15, 2019 at 10:58:09AM +0200, Andrzej Hajda wrote:
> On 15.04.2019 10:12, Ronald Tschalär wrote:
> > commit d6abe6df706c (drm/bridge: sil_sii8620: do not have a dependency
> > of RC_CORE) changed the driver to select both RC_CORE and INPUT.
> > However, this causes problems with other drivers, in particular an input
> > driver that depends on MFD_INTEL_LPSS_PCI (to be added in a separate
> > commit):
> >
> > drivers/clk/Kconfig:9:error: recursive dependency detected!
> > drivers/clk/Kconfig:9: symbol COMMON_CLK is selected by MFD_INTEL_LPSS
> > drivers/mfd/Kconfig:566: symbol MFD_INTEL_LPSS is selected by MFD_INTEL_LPSS_PCI
> > drivers/mfd/Kconfig:580: symbol MFD_INTEL_LPSS_PCI is implied by KEYBOARD_APPLESPI
> > drivers/input/keyboard/Kconfig:73: symbol KEYBOARD_APPLESPI depends on INPUT
> > drivers/input/Kconfig:8: symbol INPUT is selected by DRM_SIL_SII8620
> > drivers/gpu/drm/bridge/Kconfig:83: symbol DRM_SIL_SII8620 depends on DRM_BRIDGE
> > drivers/gpu/drm/bridge/Kconfig:1: symbol DRM_BRIDGE is selected by DRM_PL111
> > drivers/gpu/drm/pl111/Kconfig:1: symbol DRM_PL111 depends on COMMON_CLK
> >
> > According to the docs and general consensus, select should only be used
> > for non user-visible symbols, but both RC_CORE and INPUT are
> > user-visible. Furthermore almost all other references to INPUT
> > throughout the kernel config are depends, not selects. For this reason
> > the first part of this change reverts commit d6abe6df706c.
> >
> > In order to address the original reason for commit d6abe6df706c, namely
> > that not all boards use the remote controller functionality and hence
> > should not need have to deal with RC_CORE, the second part of this
> > change now makes the remote control support in the driver optional and
> > contingent on RC_CORE being defined. And with this the hard dependency
> > on INPUT also goes away as that is only needed if RC_CORE is defined
> > (which in turn already depends on INPUT).
> >
> > CC: Inki Dae <inki.dae@samsung.com>
> > CC: Andrzej Hajda <a.hajda@samsung.com>
> > CC: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > CC: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > Signed-off-by: Ronald Tschalär <ronald@innovation.ch>
>
>
> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Thanks for your reviews!
> If there are no objections I will take it to drm-misc tomorrow.
This brings us back to the discussion started in response to the first
version of my patch (see
https://lore.kernel.org/lkml/20190124082423.23139-1-ronald@innovation.ch/T/#m24f45fecd987a787a9554c8088f463fd10de2b00).
To recap: the problem is that the applespi patch depends on this patch
here, as make-config will break as described above otherwise. So if
this patch is submitted through drm-misc, then it's unclear to me how
to ensure that the two patches make it upstream in proper order,
unless the applespi patch is also upstreamed through drm-misc, or the
Kconfig for applespi is (temporarily) modified to not trigger the
config error and another patch is later submitted to fix the Kconfig
again (which seems somewhat ugly to me). Assuming that consensus is to
merge both patches through one tree, then it would seem that because
this patch here is relatively small that maybe it could be merged
through the input tree along with the applespi patch?
Cheers,
Ronald
^ permalink raw reply
* Re: [PATCH v5 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Life is hard, and then you die @ 2019-04-15 23:09 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Dmitry Torokhov, Henrik Rydberg, Andrzej Hajda, Inki Dae,
Greg Kroah-Hartman, Lukas Wunner, Federico Lorenzi,
Laurent Pinchart, linux-input, dri-devel, linux-kernel
In-Reply-To: <20190415090346.GL9224@smile.fi.intel.com>
Hi Andy,
On Mon, Apr 15, 2019 at 12:03:46PM +0300, Andy Shevchenko wrote:
> On Mon, Apr 15, 2019 at 01:13:00AM -0700, Ronald Tschalär wrote:
> > The keyboard and trackpad on recent MacBook's (since 8,1) and
> > MacBookPro's (13,* and 14,*) are attached to an SPI controller instead
> > of USB, as previously. The higher level protocol is not publicly
> > documented and hence has been reverse engineered. As a consequence there
> > are still a number of unknown fields and commands. However, the known
> > parts have been working well and received extensive testing and use.
> >
> > In order for this driver to work, the proper SPI drivers need to be
> > loaded too; for MB8,1 these are spi_pxa2xx_platform and spi_pxa2xx_pci;
> > for all others they are spi_pxa2xx_platform and intel_lpss_pci. For this
> > reason enabling this driver in the config implies enabling the above
> > drivers.
>
> Thank you for an update.
> I suddenly realized couple of places where something maybe optimized.
>
> Nevertheless, FWIW,
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Many thanks for all your reviews!
[snip]
> > +static void
> > +applespi_remap_fn_key(struct keyboard_protocol *keyboard_protocol)
> > +{
> > + unsigned char tmp;
>
> > + u8 bit = BIT(fnremap - 1);
>
> The above is UB and I'm sorry I didn't find this earlier.
>
> So, something like this would work
>
> u8 bit = BIT((fnremap - 1) & 0x07);
fnremap is already constrained by the following:
> > +
> > + if (!fnremap || fnremap > ARRAY_SIZE(applespi_controlcodes) ||
> > + !applespi_controlcodes[fnremap - 1])
> > + return;
and the array-size of applespi_controlcodes is constrained to the
number of bits in u8 according to this assertion
> > + compiletime_assert(ARRAY_SIZE(applespi_controlcodes) ==
> > + sizeof_field(struct keyboard_protocol, modifiers) * 8,
> > + "applespi_controlcodes has wrong number of entries");
So I don't see that the masking buys anything new.
[snip]
> > + /* check for rollover overflow, which is signalled by all keys == 1 */
> > + for (i = 0; i < MAX_ROLLOVER; i++) {
> > + if (keyboard_protocol->keys_pressed[i] != 1)
> > + break;
> > + }
> > +
> > + if (i == MAX_ROLLOVER) /* all keys were 1 */
> > + return;
>
> Since keys_pressed is an array of byte values, it may be replaced with
> memchr_inv().
>
> > +
> > + /* remap fn key if desired */
> > + applespi_remap_fn_key(keyboard_protocol);
> > +
> > + /* check released keys */
> > + for (i = 0; i < MAX_ROLLOVER; i++) {
> > + for (j = 0; j < MAX_ROLLOVER; j++) {
> > + if (applespi->last_keys_pressed[i] ==
> > + keyboard_protocol->keys_pressed[j])
> > + break;
> > + }
> > +
> > + if (j < MAX_ROLLOVER) /* key is still pressed */
> > + continue;
>
> And memchr() here.
Ah, yes, excellent suggestion. Thanks.
Cheers,
Ronald
^ permalink raw reply
* [RFC v3] iio: input-bridge: optionally bridge iio acceleometers to create a /dev/input interface
From: H. Nikolaus Schaller @ 2019-04-15 21:05 UTC (permalink / raw)
To: Jonathan Cameron, Dmitry Torokhov
Cc: Eric Piel, linux-input, letux-kernel, kernel, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald-Stadler, linux-kernel,
linux-iio, H. Nikolaus Schaller
Some user spaces (e.g. some Android devices) use /dev/input/event* for handling
the 3D position of the device with respect to the center of gravity (earth).
This can be used for gaming input, auto-rotation of screens etc.
This interface should be the standard for such use cases because it is an abstraction
of how orientation data is acquired from sensor chips. Sensor chips may be connected
through different interfaces and in different positions. They may also have different
parameters. And, if a chip is replaced by a different one, the values reported by
the device position interface should remain the same, provided the device tree reflects
the changed chip.
This did initially lead to input accelerometer drivers like drivers/input/misc/bma150.c
or drivers/misc/lis3lv02d/
But nowadays, new accelerometer chips mostly get iio drivers and rarely input drivers.
Therefore we need something like a protocol stack which bridges raw data and input devices.
It can be seen as a similar layering like TCP/IP vs. bare Ethernet. Or keyboard
input events vs. raw gpio or raw USB access.
This patch bridges the gap between raw iio data and the input device abstraction
so that accelerometer measurements can additionally be presented as X/Y/Z accelerometer
channels (INPUT_PROP_ACCELEROMETER) through /dev/input/event*.
There are no special requirements or changes needed for an iio driver.
There is no need to define a mapping (e.g. in device tree).
This driver simply collects the first 3 accelerometer channels as X, Y and Z.
If only 1 or 2 channels are available, they are used for X and Y only. Additional
channels are ignored.
Scaling is done automatically so that 1g is represented by value 256 and
range is assumed to be -511 .. +511 which gives a reasonable precision as an
input device.
If a mount-matrix is provided by the iio driver, it is also taken into account
so that the input event automatically gets the correct orientation with respect
to the device.
If this extension is not configured into the kernel it takes no resources (except
source code).
If it is configured, but there is no accelerometer, there is only a tiny penalty
for scanning for accelerometer channels once during probe of each iio device.
If it runs, the driver polls the device(s) once every 100 ms. A mode where the
iio device defines the update rate is not implemented and for further study.
If there is no user-space client, polling is not running.
The driver is capable to handle multiple iio accelerometers and they are
presented by unique /dev/input/event* files. The iio chip name is used to define
the input device name so that it can be identified (e.g. by udev rules or evtest).
Here is some example what you can expect from the driver (device:
arch/arm/boot/dts/omap3-gta04a5.dts):
root@letux:~# dmesg|fgrep iio
[ 6.324584] input: iio-bridge: bmc150_accel as /devices/platform/68000000.ocp/48072000.i2c/i2c-1/1-0010/iio:device1/input/input5
[ 6.516632] input: iio-bridge: bno055 as /devices/platform/68000000.ocp/48072000.i2c/i2c-1/1-0029/iio:device3/input/input7
root@letux:~# evtest /dev/input/event5 | head -19
Input driver version is 1.0.1
Input device ID: bus 0x0 vendor 0x0 product 0x0 version 0x0
Input device name: "iio-bridge: bmc150_accel"
Supported events:
Event type 0 (EV_SYN)
Event type 3 (EV_ABS)
Event code 0 (ABS_X)
Value 8
Min -511
Max 511
Event code 1 (ABS_Y)
Value -44
Min -511
Max 511
Event code 2 (ABS_Z)
Value -265
Min -511
Max 511
Properties:
root@letux:~# evtest /dev/input/event7 | head -19
Input driver version is 1.0.1
Input device ID: bus 0x0 vendor 0x0 product 0x0 version 0x0
Input device name: "iio-bridge: bno055"
Supported events:
Event type 0 (EV_SYN)
Event type 3 (EV_ABS)
Event code 0 (ABS_X)
Value -6
Min -511
Max 511
Event code 1 (ABS_Y)
Value 17
Min -511
Max 511
Event code 2 (ABS_Z)
Value -250
Min -511
Max 511
Properties:
root@letux:~#
Although the sensor chips are mounted with different axis orientation,
the application of the mount matrix provides equivalent (despite noise
and precision) information on device orientation.
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
V1: initial RFC version
V2:
- rework based on comments by Jonathan Cameron
- mainly: use input_polldev instead of using own polling timer
- no need for checking number of open()/close()
- no need for locks (already handled by input framework)
V3:
- use new iio_dev->input_mapping instead of mis-using iio_dev->private
- removed some spurious printk from debugging
- collect channels first and then register them all in one step
- fix issue with unsigned int type propagation in atofix()
- simplify code for handling negative numbers
- fix sequence in unregister
---
drivers/iio/Kconfig | 8 +
drivers/iio/Makefile | 1 +
drivers/iio/industrialio-core.c | 12 ++
drivers/iio/industrialio-inputbridge.c | 270 +++++++++++++++++++++++++
drivers/iio/industrialio-inputbridge.h | 28 +++
include/linux/iio/iio.h | 4 +
6 files changed, 323 insertions(+)
create mode 100644 drivers/iio/industrialio-inputbridge.c
create mode 100644 drivers/iio/industrialio-inputbridge.h
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index d08aeb41cd07..2f0295da6ebc 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -68,6 +68,14 @@ config IIO_TRIGGERED_EVENT
help
Provides helper functions for setting up triggered events.
+config IIO_INPUT_BRIDGE
+ depends on INPUT
+ bool "Enable accelerometer bridge to input driver"
+ help
+ Provides a /dev/input/event* device for accelerometers
+ to use as a 3D input device, e.g. for gaming or auto-rotation
+ of screen contents.
+
source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/Kconfig"
source "drivers/iio/afe/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index cb5993251381..d695e5a27da5 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
+industrialio-$(CONFIG_IIO_INPUT_BRIDGE) += industrialio-inputbridge.o
obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o
obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 4700fd5d8c90..81f412b41a78 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -29,6 +29,7 @@
#include <linux/iio/iio.h>
#include "iio_core.h"
#include "iio_core_trigger.h"
+#include "industrialio-inputbridge.h"
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/buffer.h>
@@ -1723,6 +1724,15 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
if (ret < 0)
goto error_unreg_eventset;
+ ret = iio_device_register_inputbridge(indio_dev);
+ if (ret) {
+ dev_err(indio_dev->dev.parent,
+ "Failed to register as input driver\n");
+ device_del(&indio_dev->dev);
+
+ return ret;
+ }
+
return 0;
error_unreg_eventset:
@@ -1745,6 +1755,8 @@ void iio_device_unregister(struct iio_dev *indio_dev)
{
mutex_lock(&indio_dev->info_exist_lock);
+ iio_device_unregister_inputbridge(indio_dev);
+
cdev_device_del(&indio_dev->chrdev, &indio_dev->dev);
iio_device_unregister_debugfs(indio_dev);
diff --git a/drivers/iio/industrialio-inputbridge.c b/drivers/iio/industrialio-inputbridge.c
new file mode 100644
index 000000000000..592d5ee91a30
--- /dev/null
+++ b/drivers/iio/industrialio-inputbridge.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Industrial I/O core, bridge to input devices
+ *
+ * Copyright (c) 2016-2019 Golden Delicious Computers GmbH&Co. KG
+ */
+
+#include <linux/iio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "industrialio-inputbridge.h"
+
+/* currently, only polling is implemented */
+#define POLLING_MSEC 100
+
+struct iio_input_map {
+ struct input_polled_dev *poll_dev; /* the input device */
+ struct iio_channel channels[3]; /* x, y, z channels */
+ struct matrix {
+ int mxx, myx, mzx; /* fixed point mount-matrix */
+ int mxy, myy, mzy;
+ int mxz, myz, mzz;
+ } matrix;
+};
+
+static inline struct iio_input_map *to_iio_input_map(
+ struct iio_channel *channel)
+{
+ return (struct iio_input_map *) channel->data;
+}
+
+/* minimum and maximum range we want to report */
+#define ABSMAX_ACC_VAL (512 - 1)
+#define ABSMIN_ACC_VAL -(ABSMAX_ACC_VAL)
+
+/* scale processed iio values so that 1g maps to ABSMAX_ACC_VAL / 2 */
+#define SCALE ((100 * ABSMAX_ACC_VAL) / (2 * 981))
+
+/*
+ * convert float string to scaled fixed point format, e.g.
+ * 1 -> 1000 (value passed as unit)
+ * 1.23 -> 1230
+ * 0.1234 -> 123
+ * -.01234 -> -12
+ */
+
+static int32_t atofix(const char *str, uint32_t unit)
+{
+ int32_t mantissa = 0;
+ bool decimal = false;
+ int divisor = 1;
+
+ if (*str == '-')
+ divisor = -1, str++;
+ while (*str && abs(divisor) < unit) {
+ if (*str >= '0' && *str <= '9') {
+ mantissa = 10 * mantissa + (*str - '0');
+ if (decimal)
+ divisor *= 10;
+ } else if (*str == '.')
+ decimal = true;
+ else
+ return 0; /* error */
+ str++;
+ }
+
+ return (mantissa * (int32_t) unit) / divisor;
+}
+
+static void iio_apply_matrix(struct matrix *m, int *in, int *out, int unit)
+{
+ /* apply mount matrix */
+ out[0] = (m->mxx * in[0] + m->myx * in[1] + m->mzx * in[2]) / unit;
+ out[1] = (m->mxy * in[0] + m->myy * in[1] + m->mzy * in[2]) / unit;
+ out[2] = (m->mxz * in[0] + m->myz * in[1] + m->mzz * in[2]) / unit;
+}
+
+#define FIXED_POINT_UNIT 1000 /* seems reasonable for accelerometer input */
+
+static void iio_accel_poll(struct input_polled_dev *dev)
+{
+ struct iio_input_map *map = dev->private;
+ struct input_dev *input = dev->input;
+
+ int values[3]; /* values while processing */
+ int aligned_values[3]; /* mount matrix applied */
+
+ int cindex = 0;
+
+ while (cindex < ARRAY_SIZE(values)) {
+ struct iio_channel *channel =
+ &map->channels[cindex];
+ int val;
+ int ret;
+
+ if (!channel) {
+ values[cindex] = 0;
+ continue;
+ }
+
+ ret = iio_read_channel_raw(channel, &val);
+
+ if (ret < 0) {
+ pr_err("%s(): channel read error %d\n",
+ __func__, cindex);
+ return;
+ }
+
+ ret = iio_convert_raw_to_processed(channel, val,
+ &values[cindex], SCALE);
+
+ if (ret < 0) {
+ pr_err("%s(): channel processing error\n",
+ __func__);
+ return;
+ }
+
+ cindex++;
+ }
+
+ iio_apply_matrix(&map->matrix, values, aligned_values, FIXED_POINT_UNIT);
+
+ input_report_abs(input, ABS_X, aligned_values[0]);
+ input_report_abs(input, ABS_Y, aligned_values[1]);
+ input_report_abs(input, ABS_Z, aligned_values[2]);
+ input_sync(input);
+}
+
+static int iio_input_register_accel_channels(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan[], int num_channels)
+{ /* we found some accelerometer channel */
+ int ret;
+ int cindex;
+ struct input_polled_dev *poll_dev;
+ struct iio_input_map *map = indio_dev->input_mapping;
+ const struct iio_chan_spec_ext_info *ext_info;
+
+ if (unlikely(map))
+ return -EINVAL; /* already registered */
+
+ if (num_channels < 1)
+ return 0; /* silently ignore */
+
+ map = devm_kzalloc(&indio_dev->dev, sizeof(struct iio_input_map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+
+ indio_dev->input_mapping = map;
+
+ poll_dev = devm_input_allocate_polled_device(&indio_dev->dev);
+ if (!poll_dev)
+ return -ENOMEM;
+
+ poll_dev->private = map;
+ poll_dev->poll = iio_accel_poll;
+ poll_dev->poll_interval = POLLING_MSEC;
+
+ poll_dev->input->name = kasprintf(GFP_KERNEL, "iio-bridge: %s",
+ indio_dev->name);
+ poll_dev->input->phys = kasprintf(GFP_KERNEL, "iio:device%d",
+ indio_dev->id);
+
+// do we need something like this?
+// poll_dev->input->id.bustype = BUS_IIO;
+// poll_dev->input->id.vendor = 0x0001;
+// poll_dev->input->id.product = 0x0001;
+// poll_dev->input->id.version = 0x0001;
+
+ set_bit(INPUT_PROP_ACCELEROMETER, poll_dev->input->propbit);
+ poll_dev->input->evbit[0] = BIT_MASK(EV_ABS);
+ input_alloc_absinfo(poll_dev->input);
+ input_set_abs_params(poll_dev->input, ABS_X, ABSMIN_ACC_VAL,
+ ABSMAX_ACC_VAL, 0, 0);
+ input_set_abs_params(poll_dev->input, ABS_Y, ABSMIN_ACC_VAL,
+ ABSMAX_ACC_VAL, 0, 0);
+ input_set_abs_params(poll_dev->input, ABS_Z, ABSMIN_ACC_VAL,
+ ABSMAX_ACC_VAL, 0, 0);
+
+ map->poll_dev = poll_dev;
+
+ ret = input_register_polled_device(poll_dev);
+
+ if (ret < 0) {
+ kfree(poll_dev->input->name);
+ kfree(poll_dev->input->phys);
+ return ret;
+ }
+
+ /* assume all channels of a device share the same matrix */
+
+ ext_info = chan[0]->ext_info;
+ while (ext_info && ext_info->name) {
+ if (strcmp(ext_info->name, "mount_matrix") == 0)
+ break; /* found */
+ ext_info++;
+ }
+
+ if (ext_info && ext_info->name) {
+ uintptr_t priv = ext_info->private;
+ const struct iio_mount_matrix *mtx;
+
+ mtx = ((iio_get_mount_matrix_t *) priv)(indio_dev,
+ chan[0]);
+
+ map->matrix.mxx = atofix(mtx->rotation[0], FIXED_POINT_UNIT);
+ map->matrix.myx = atofix(mtx->rotation[1], FIXED_POINT_UNIT);
+ map->matrix.mzx = atofix(mtx->rotation[2], FIXED_POINT_UNIT);
+ map->matrix.mxy = atofix(mtx->rotation[3], FIXED_POINT_UNIT);
+ map->matrix.myy = atofix(mtx->rotation[4], FIXED_POINT_UNIT);
+ map->matrix.mzy = atofix(mtx->rotation[5], FIXED_POINT_UNIT);
+ map->matrix.mxz = atofix(mtx->rotation[6], FIXED_POINT_UNIT);
+ map->matrix.myz = atofix(mtx->rotation[7], FIXED_POINT_UNIT);
+ map->matrix.mzz = atofix(mtx->rotation[8], FIXED_POINT_UNIT);
+ } else {
+ map->matrix.mxx = FIXED_POINT_UNIT;
+ map->matrix.myx = 0;
+ map->matrix.mzx = 0;
+ map->matrix.mxy = 0;
+ map->matrix.myy = FIXED_POINT_UNIT;
+ map->matrix.mzy = 0;
+ map->matrix.mxz = 0;
+ map->matrix.myz = 0;
+ map->matrix.mzz = FIXED_POINT_UNIT;
+ }
+
+ for (cindex = 0; cindex < ARRAY_SIZE(map->channels); cindex++) {
+ if (cindex < num_channels)
+ map->channels[cindex].channel = chan[cindex];
+ map->channels[cindex].indio_dev = indio_dev;
+ map->channels[cindex].data = map;
+ }
+
+ return 0;
+}
+
+int iio_device_register_inputbridge(struct iio_dev *indio_dev)
+{
+ int cindex;
+ int num_channels = 0;
+ const struct iio_chan_spec *channels[3];
+
+ for (cindex = 0; cindex < indio_dev->num_channels; cindex++) {
+ const struct iio_chan_spec *chan =
+ &indio_dev->channels[cindex];
+
+ if (chan->type == IIO_ACCEL && num_channels < ARRAY_SIZE(channels))
+ channels[num_channels++] = chan;
+ }
+
+ return iio_input_register_accel_channels(indio_dev, channels, num_channels);
+}
+
+void iio_device_unregister_inputbridge(struct iio_dev *indio_dev)
+{
+ struct iio_input_map *map = iio_device_get_drvdata(indio_dev);
+ struct input_dev *input = map->poll_dev->input;
+
+ input_unregister_polled_device(map->poll_dev);
+ kfree(input->name);
+ kfree(input->phys);
+}
+
+MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
+MODULE_DESCRIPTION("Bridge to present Industrial I/O accelerometers as properly oriented Input devices");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/industrialio-inputbridge.h b/drivers/iio/industrialio-inputbridge.h
new file mode 100644
index 000000000000..1363b10ab3f7
--- /dev/null
+++ b/drivers/iio/industrialio-inputbridge.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The Industrial I/O core, bridge to input devices
+ *
+ * Copyright (c) 2016-2019 Golden Delicious Computers GmbH&Co. KG
+ *
+ * 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_IIO_INPUT_BRIDGE)
+
+extern int iio_device_register_inputbridge(struct iio_dev *indio_dev);
+extern void iio_device_unregister_inputbridge(struct iio_dev *indio_dev);
+
+#else
+
+static inline int iio_device_register_inputbridge(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void iio_device_unregister_inputbridge(struct iio_dev *indio_dev)
+{
+}
+
+#endif
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index a74cb177dc6f..a4d2f11384e9 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -524,6 +524,7 @@ struct iio_buffer_setup_ops {
* @flags: [INTERN] file ops related flags including busy flag.
* @debugfs_dentry: [INTERN] device specific debugfs dentry.
* @cached_reg_addr: [INTERN] cached register address for debugfs reads.
+ * @input_mapping: [INTERN] mapping for input device
*/
struct iio_dev {
int id;
@@ -570,6 +571,9 @@ struct iio_dev {
struct dentry *debugfs_dentry;
unsigned cached_reg_addr;
#endif
+#if defined(CONFIG_IIO_INPUT_BRIDGE)
+ void *input_mapping;
+#endif
};
const struct iio_chan_spec
--
2.19.1
^ permalink raw reply related
* Re: [PATCH 2/4] ARM: ep93xx: keypad: stop using mach/platform.h
From: Guenter Roeck @ 2019-04-15 20:01 UTC (permalink / raw)
To: Alexander Sverdlin
Cc: Arnd Bergmann, Hartley Sweeten, Linus Walleij, Dmitry Torokhov,
Stefan Agner, Enric Balletbo i Serra, Guenter Roeck,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <3665a5ad-ff6d-97a1-ca31-971973a7167f@gmail.com>
On Mon, Apr 15, 2019 at 12:56 PM Alexander Sverdlin
<alexander.sverdlin@gmail.com> wrote:
>
> Hi!
>
> On 15/04/2019 21:47, Arnd Bergmann wrote:
> >>> We can communicate the clock rate using platform data rather than setting a
> >>> flag to use a particular value in the driver, which is cleaner and avoids the dependency.
> >>>
> >>> No platform in the kernel currently defines the ep93xx keypad device structure, so this
> >>> is a rather pointless excercise. Any out of tree users are probably dead now, but if not,
> >>> they have to change their platform code to match the new platform_data structure.
> >> <snip>
> >>
> >>> diff --git a/include/linux/platform_data/keypad-ep93xx.h b/include/linux/platform_data/keypad-ep93xx.h
> >>> index 0e36818e3680..3054fced8509 100644
> >>> --- a/include/linux/platform_data/keypad-ep93xx.h
> >>> +++ b/include/linux/platform_data/keypad-ep93xx.h
> >>> @@ -9,8 +9,7 @@ struct matrix_keymap_data;
> >>> #define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */
> >>> #define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */
> >>> #define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */
> >>> -#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */
> >>> -#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */
> >>> +#define EP93XX_KEYPAD_AUTOREPEAT (1<<4) /* enable key autorepeat */
> >> You have re-defined the keypad register bits here.
> >>
> >> The KDIV bit changes the clock rate. The AUTOREPEAT bit enables key autorepeat.
> > As far as I can tell, they are not register bits, just software flags
> > for communicating between a board file and the driver, so I
> > assumed I could freely reorganize them.
> >
> > Did I miss something?
>
> They are indeed only software flags (just checked datasheet), so you are only changing
> platform data format. But as I do not know any keypad user in person, I'd rely on
> Hartley's opinion in this case (if it's a good idea to change platform data or not).
>
If there are out-of-tree users, it would be their responsibility to
upstream their code. If they don't, any changes in platform data is
their problem, not ours. Either case, platform data does, if anything,
reflect an in-kernel API, and thus is fair game for cleanup.
Guenter
^ permalink raw reply
* RE: [PATCH 2/4] ARM: ep93xx: keypad: stop using mach/platform.h
From: Hartley Sweeten @ 2019-04-15 19:58 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Alexander Sverdlin, Linus Walleij, Dmitry Torokhov, Stefan Agner,
Enric Balletbo i Serra, Guenter Roeck,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CAK8P3a1DSN3jcfGngrJFp93Mt98qsibvKvtJGtjHYjOmcM1kNQ@mail.gmail.com>
On Monday, April 15, 2019 12:47 PM, Arnd Bergmann wrote:
> On Mon, Apr 15, 2019 at 9:39 PM Hartley Sweeten <HartleyS@visionengravers.com> wrote:
>>> -#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */
>>> -#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */
>>> +#define EP93XX_KEYPAD_AUTOREPEAT (1<<4) /* enable key autorepeat */
>>
>> You have re-defined the keypad register bits here.
>>
>> The KDIV bit changes the clock rate. The AUTOREPEAT bit enables key autorepeat.
>
> As far as I can tell, they are not register bits, just software flags for communicating between a
> board file and the driver, so I assumed I could freely reorganize them.
>
> Did I miss something?
Ugh.. It's been quite a while since I looked at that code...
Your correct, these are just flags to the driver.
The KeyScanInit register does have some bits that these flags effect but the driver deals
with them.
I have been buried updating an old PowerPC hardware/software design and haven't looked
at the EP93xx lately. My EP9307 board does have the keypad interface. Hopefully I will get
some time to check the latest mainline on it sometime soon.
Overall these patches look good. So, for the series...
Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com>
^ permalink raw reply
* Re: [PATCH 2/4] ARM: ep93xx: keypad: stop using mach/platform.h
From: Alexander Sverdlin @ 2019-04-15 19:54 UTC (permalink / raw)
To: Arnd Bergmann, Hartley Sweeten
Cc: Linus Walleij, Dmitry Torokhov, Stefan Agner,
Enric Balletbo i Serra, Guenter Roeck,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CAK8P3a1DSN3jcfGngrJFp93Mt98qsibvKvtJGtjHYjOmcM1kNQ@mail.gmail.com>
Hi!
On 15/04/2019 21:47, Arnd Bergmann wrote:
>>> We can communicate the clock rate using platform data rather than setting a
>>> flag to use a particular value in the driver, which is cleaner and avoids the dependency.
>>>
>>> No platform in the kernel currently defines the ep93xx keypad device structure, so this
>>> is a rather pointless excercise. Any out of tree users are probably dead now, but if not,
>>> they have to change their platform code to match the new platform_data structure.
>> <snip>
>>
>>> diff --git a/include/linux/platform_data/keypad-ep93xx.h b/include/linux/platform_data/keypad-ep93xx.h
>>> index 0e36818e3680..3054fced8509 100644
>>> --- a/include/linux/platform_data/keypad-ep93xx.h
>>> +++ b/include/linux/platform_data/keypad-ep93xx.h
>>> @@ -9,8 +9,7 @@ struct matrix_keymap_data;
>>> #define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */
>>> #define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */
>>> #define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */
>>> -#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */
>>> -#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */
>>> +#define EP93XX_KEYPAD_AUTOREPEAT (1<<4) /* enable key autorepeat */
>> You have re-defined the keypad register bits here.
>>
>> The KDIV bit changes the clock rate. The AUTOREPEAT bit enables key autorepeat.
> As far as I can tell, they are not register bits, just software flags
> for communicating between a board file and the driver, so I
> assumed I could freely reorganize them.
>
> Did I miss something?
They are indeed only software flags (just checked datasheet), so you are only changing
platform data format. But as I do not know any keypad user in person, I'd rely on
Hartley's opinion in this case (if it's a good idea to change platform data or not).
--
Alex.
^ permalink raw reply
* Re: [PATCH 2/4] ARM: ep93xx: keypad: stop using mach/platform.h
From: Arnd Bergmann @ 2019-04-15 19:47 UTC (permalink / raw)
To: Hartley Sweeten
Cc: Alexander Sverdlin, Linus Walleij, Dmitry Torokhov, Stefan Agner,
Enric Balletbo i Serra, Guenter Roeck,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CO2PR01MB21683E465191EA8246503774D02B0@CO2PR01MB2168.prod.exchangelabs.com>
On Mon, Apr 15, 2019 at 9:39 PM Hartley Sweeten
<HartleyS@visionengravers.com> wrote:
>
> On Monday, April 15, 2019 12:25 PM, Arnd Bergmann wrote:
> > We can communicate the clock rate using platform data rather than setting a
> > flag to use a particular value in the driver, which is cleaner and avoids the dependency.
> >
> > No platform in the kernel currently defines the ep93xx keypad device structure, so this
> > is a rather pointless excercise. Any out of tree users are probably dead now, but if not,
> > they have to change their platform code to match the new platform_data structure.
>
> <snip>
>
> > diff --git a/include/linux/platform_data/keypad-ep93xx.h b/include/linux/platform_data/keypad-ep93xx.h
> > index 0e36818e3680..3054fced8509 100644
> > --- a/include/linux/platform_data/keypad-ep93xx.h
> > +++ b/include/linux/platform_data/keypad-ep93xx.h
> > @@ -9,8 +9,7 @@ struct matrix_keymap_data;
> > #define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */
> > #define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */
> > #define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */
> > -#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */
> > -#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */
> > +#define EP93XX_KEYPAD_AUTOREPEAT (1<<4) /* enable key autorepeat */
>
> You have re-defined the keypad register bits here.
>
> The KDIV bit changes the clock rate. The AUTOREPEAT bit enables key autorepeat.
As far as I can tell, they are not register bits, just software flags
for communicating between a board file and the driver, so I
assumed I could freely reorganize them.
Did I miss something?
Arnd
^ permalink raw reply
* Re: [PATCH 3/4] ARM: ep93xx: move pinctrl interfaces into include/linux/soc
From: Alexander Sverdlin @ 2019-04-15 19:41 UTC (permalink / raw)
To: Arnd Bergmann, Hartley Sweeten
Cc: Linus Walleij, Bartlomiej Zolnierkiewicz, Jens Axboe,
Dmitry Torokhov, Thierry Reding, Mark Brown, Olof Johansson,
linux-arm-kernel, linux-kernel, linux-ide, linux-input, linux-pwm,
alsa-devel
In-Reply-To: <20190415192734.935387-3-arnd@arndb.de>
On 15/04/2019 21:25, Arnd Bergmann wrote:
> ep93xx does not have a proper pinctrl driver, but does things
> ad-hoc through mach/platform.h, which is also used for setting
> up the boards.
>
> To avoid using mach/*.h headers completely, let's move the interfaces
> into include/linux/soc/. This is far from great, but gets the job
> done here, without the need for a proper pinctrl driver.
Acked-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> arch/arm/mach-ep93xx/clock.c | 1 +
> arch/arm/mach-ep93xx/core.c | 2 ++
> arch/arm/mach-ep93xx/include/mach/platform.h | 16 ---------
> drivers/ata/pata_ep93xx.c | 2 +-
> drivers/input/keyboard/ep93xx_keypad.c | 3 +-
> drivers/pwm/pwm-ep93xx.c | 2 +-
> include/linux/soc/cirrus/ep93xx.h | 37 ++++++++++++++++++++
> sound/soc/cirrus/edb93xx.c | 2 +-
> sound/soc/cirrus/ep93xx-ac97.c | 1 +
> sound/soc/cirrus/ep93xx-i2s.c | 3 +-
> sound/soc/cirrus/simone.c | 2 +-
> sound/soc/cirrus/snappercl15.c | 2 +-
> 12 files changed, 48 insertions(+), 25 deletions(-)
> create mode 100644 include/linux/soc/cirrus/ep93xx.h
>
> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
> index d2eee707d27f..9f43362eb62d 100644
> --- a/arch/arm/mach-ep93xx/clock.c
> +++ b/arch/arm/mach-ep93xx/clock.c
> @@ -20,6 +20,7 @@
> #include <linux/io.h>
> #include <linux/spinlock.h>
> #include <linux/clkdev.h>
> +#include <linux/soc/cirrus/ep93xx.h>
>
> #include <mach/hardware.h>
>
> diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
> index 706515faee06..3d245668846d 100644
> --- a/arch/arm/mach-ep93xx/core.c
> +++ b/arch/arm/mach-ep93xx/core.c
> @@ -43,6 +43,8 @@
> #include <linux/platform_data/video-ep93xx.h>
> #include <linux/platform_data/keypad-ep93xx.h>
> #include <linux/platform_data/spi-ep93xx.h>
> +#include <linux/soc/cirrus/ep93xx.h>
> +
> #include <mach/gpio-ep93xx.h>
>
> #include <asm/mach/arch.h>
> diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
> index 43446f33c2be..b4045a186239 100644
> --- a/arch/arm/mach-ep93xx/include/mach/platform.h
> +++ b/arch/arm/mach-ep93xx/include/mach/platform.h
> @@ -19,14 +19,6 @@ struct ep93xx_spi_info;
> void ep93xx_map_io(void);
> void ep93xx_init_irq(void);
>
> -#define EP93XX_CHIP_REV_D0 3
> -#define EP93XX_CHIP_REV_D1 4
> -#define EP93XX_CHIP_REV_E0 5
> -#define EP93XX_CHIP_REV_E1 6
> -#define EP93XX_CHIP_REV_E2 7
> -
> -unsigned int ep93xx_chip_revision(void);
> -
> void ep93xx_register_flash(unsigned int width,
> resource_size_t start, resource_size_t size);
>
> @@ -36,19 +28,11 @@ void ep93xx_register_spi(struct ep93xx_spi_info *info,
> struct spi_board_info *devices, int num);
> void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
> void ep93xx_register_pwm(int pwm0, int pwm1);
> -int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
> -void ep93xx_pwm_release_gpio(struct platform_device *pdev);
> void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
> -int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
> -void ep93xx_keypad_release_gpio(struct platform_device *pdev);
> void ep93xx_register_i2s(void);
> -int ep93xx_i2s_acquire(void);
> -void ep93xx_i2s_release(void);
> void ep93xx_register_ac97(void);
> void ep93xx_register_ide(void);
> void ep93xx_register_adc(void);
> -int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
> -void ep93xx_ide_release_gpio(struct platform_device *pdev);
>
> struct device *ep93xx_init_devices(void);
> extern void ep93xx_timer_init(void);
> diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
> index cc6d06c1b2c7..db271b705529 100644
> --- a/drivers/ata/pata_ep93xx.c
> +++ b/drivers/ata/pata_ep93xx.c
> @@ -44,7 +44,7 @@
> #include <linux/ktime.h>
>
> #include <linux/platform_data/dma-ep93xx.h>
> -#include <mach/platform.h>
> +#include <linux/soc/cirrus/ep93xx.h>
>
> #define DRV_NAME "ep93xx-ide"
> #define DRV_VERSION "1.0"
> diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
> index 71472f6257c0..575dac52f7b4 100644
> --- a/drivers/input/keyboard/ep93xx_keypad.c
> +++ b/drivers/input/keyboard/ep93xx_keypad.c
> @@ -27,8 +27,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>
>
> /*
> diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c
> index bbf10ae02f0e..fa168581e6b8 100644
> --- a/drivers/pwm/pwm-ep93xx.c
> +++ b/drivers/pwm/pwm-ep93xx.c
> @@ -35,7 +35,7 @@
>
> #include <asm/div64.h>
>
> -#include <mach/platform.h> /* for ep93xx_pwm_{acquire,release}_gpio() */
> +#include <linux/soc/cirrus/ep93xx.h> /* for ep93xx_pwm_{acquire,release}_gpio() */
>
> #define EP93XX_PWMx_TERM_COUNT 0x00
> #define EP93XX_PWMx_DUTY_CYCLE 0x04
> diff --git a/include/linux/soc/cirrus/ep93xx.h b/include/linux/soc/cirrus/ep93xx.h
> new file mode 100644
> index 000000000000..56fbe2dc59b1
> --- /dev/null
> +++ b/include/linux/soc/cirrus/ep93xx.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _SOC_EP93XX_H
> +#define _SOC_EP93XX_H
> +
> +struct platform_device;
> +
> +#define EP93XX_CHIP_REV_D0 3
> +#define EP93XX_CHIP_REV_D1 4
> +#define EP93XX_CHIP_REV_E0 5
> +#define EP93XX_CHIP_REV_E1 6
> +#define EP93XX_CHIP_REV_E2 7
> +
> +#ifdef CONFIG_ARCH_EP93XX
> +int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
> +void ep93xx_pwm_release_gpio(struct platform_device *pdev);
> +int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
> +void ep93xx_ide_release_gpio(struct platform_device *pdev);
> +int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
> +void ep93xx_keypad_release_gpio(struct platform_device *pdev);
> +int ep93xx_i2s_acquire(void);
> +void ep93xx_i2s_release(void);
> +unsigned int ep93xx_chip_revision(void);
> +
> +#else
> +static inline int ep93xx_pwm_acquire_gpio(struct platform_device *pdev) { return 0; }
> +static inline void ep93xx_pwm_release_gpio(struct platform_device *pdev) {}
> +static inline int ep93xx_ide_acquire_gpio(struct platform_device *pdev) { return 0; }
> +static inline void ep93xx_ide_release_gpio(struct platform_device *pdev) {}
> +static inline int ep93xx_keypad_acquire_gpio(struct platform_device *pdev) { return 0; }
> +static inline void ep93xx_keypad_release_gpio(struct platform_device *pdev) {}
> +static inline int ep93xx_i2s_acquire(void) { return 0; }
> +static inline void ep93xx_i2s_release(void) {}
> +static inline unsigned int ep93xx_chip_revision(void) { return 0; }
> +
> +#endif
> +
> +#endif
> diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
> index 3d011abaa266..f678b4c1514a 100644
> --- a/sound/soc/cirrus/edb93xx.c
> +++ b/sound/soc/cirrus/edb93xx.c
> @@ -22,11 +22,11 @@
> #include <linux/platform_device.h>
> #include <linux/gpio.h>
> #include <linux/module.h>
> +#include <linux/soc/cirrus/ep93xx.h>
> #include <sound/core.h>
> #include <sound/pcm.h>
> #include <sound/soc.h>
> #include <asm/mach-types.h>
> -#include <mach/hardware.h>
>
> static int edb93xx_hw_params(struct snd_pcm_substream *substream,
> struct snd_pcm_hw_params *params)
> diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
> index cd5a939ad608..c6bc447429af 100644
> --- a/sound/soc/cirrus/ep93xx-ac97.c
> +++ b/sound/soc/cirrus/ep93xx-ac97.c
> @@ -24,6 +24,7 @@
> #include <sound/soc.h>
>
> #include <linux/platform_data/dma-ep93xx.h>
> +#include <linux/soc/cirrus/ep93xx.h>
>
> #include "ep93xx-pcm.h"
>
> diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
> index 0918c5da575a..beab7c516855 100644
> --- a/sound/soc/cirrus/ep93xx-i2s.c
> +++ b/sound/soc/cirrus/ep93xx-i2s.c
> @@ -27,9 +27,8 @@
> #include <sound/initval.h>
> #include <sound/soc.h>
>
> -#include <mach/hardware.h>
> -#include <mach/ep93xx-regs.h>
> #include <linux/platform_data/dma-ep93xx.h>
> +#include <linux/soc/cirrus/ep93xx.h>
>
> #include "ep93xx-pcm.h"
>
> diff --git a/sound/soc/cirrus/simone.c b/sound/soc/cirrus/simone.c
> index 1ec661834e5a..cb850530331b 100644
> --- a/sound/soc/cirrus/simone.c
> +++ b/sound/soc/cirrus/simone.c
> @@ -13,13 +13,13 @@
> #include <linux/init.h>
> #include <linux/module.h>
> #include <linux/platform_device.h>
> +#include <linux/soc/cirrus/ep93xx.h>
>
> #include <sound/core.h>
> #include <sound/pcm.h>
> #include <sound/soc.h>
>
> #include <asm/mach-types.h>
> -#include <mach/hardware.h>
>
> static struct snd_soc_dai_link simone_dai = {
> .name = "AC97",
> diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
> index 11ff7b2672b2..dea4909154c8 100644
> --- a/sound/soc/cirrus/snappercl15.c
> +++ b/sound/soc/cirrus/snappercl15.c
> @@ -13,12 +13,12 @@
>
> #include <linux/platform_device.h>
> #include <linux/module.h>
> +#include <linux/soc/cirrus/ep93xx.h>
> #include <sound/core.h>
> #include <sound/pcm.h>
> #include <sound/soc.h>
>
> #include <asm/mach-types.h>
> -#include <mach/hardware.h>
>
> #include "../codecs/tlv320aic23.h"
>
>
^ permalink raw reply
* RE: [PATCH 2/4] ARM: ep93xx: keypad: stop using mach/platform.h
From: Hartley Sweeten @ 2019-04-15 19:39 UTC (permalink / raw)
To: Arnd Bergmann, Alexander Sverdlin
Cc: Linus Walleij, Dmitry Torokhov, Stefan Agner,
Enric Balletbo i Serra, Guenter Roeck,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <20190415192734.935387-2-arnd@arndb.de>
On Monday, April 15, 2019 12:25 PM, Arnd Bergmann wrote:
> We can communicate the clock rate using platform data rather than setting a
> flag to use a particular value in the driver, which is cleaner and avoids the dependency.
>
> No platform in the kernel currently defines the ep93xx keypad device structure, so this
> is a rather pointless excercise. Any out of tree users are probably dead now, but if not,
> they have to change their platform code to match the new platform_data structure.
<snip>
> diff --git a/include/linux/platform_data/keypad-ep93xx.h b/include/linux/platform_data/keypad-ep93xx.h
> index 0e36818e3680..3054fced8509 100644
> --- a/include/linux/platform_data/keypad-ep93xx.h
> +++ b/include/linux/platform_data/keypad-ep93xx.h
> @@ -9,8 +9,7 @@ struct matrix_keymap_data;
> #define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */
> #define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */
> #define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */
> -#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */
> -#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */
> +#define EP93XX_KEYPAD_AUTOREPEAT (1<<4) /* enable key autorepeat */
You have re-defined the keypad register bits here.
The KDIV bit changes the clock rate. The AUTOREPEAT bit enables key autorepeat.
Hartley
^ permalink raw reply
* [PATCH 3/4] ARM: ep93xx: move pinctrl interfaces into include/linux/soc
From: Arnd Bergmann @ 2019-04-15 19:25 UTC (permalink / raw)
To: Hartley Sweeten, Alexander Sverdlin
Cc: Jens Axboe, linux-pwm, alsa-devel, Arnd Bergmann,
Bartlomiej Zolnierkiewicz, Linus Walleij, Dmitry Torokhov,
linux-kernel, linux-ide, Thierry Reding, Mark Brown, linux-input,
Olof Johansson, linux-arm-kernel
In-Reply-To: <20190415192734.935387-1-arnd@arndb.de>
ep93xx does not have a proper pinctrl driver, but does things
ad-hoc through mach/platform.h, which is also used for setting
up the boards.
To avoid using mach/*.h headers completely, let's move the interfaces
into include/linux/soc/. This is far from great, but gets the job
done here, without the need for a proper pinctrl driver.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-ep93xx/clock.c | 1 +
arch/arm/mach-ep93xx/core.c | 2 ++
arch/arm/mach-ep93xx/include/mach/platform.h | 16 ---------
drivers/ata/pata_ep93xx.c | 2 +-
drivers/input/keyboard/ep93xx_keypad.c | 3 +-
drivers/pwm/pwm-ep93xx.c | 2 +-
include/linux/soc/cirrus/ep93xx.h | 37 ++++++++++++++++++++
sound/soc/cirrus/edb93xx.c | 2 +-
sound/soc/cirrus/ep93xx-ac97.c | 1 +
sound/soc/cirrus/ep93xx-i2s.c | 3 +-
sound/soc/cirrus/simone.c | 2 +-
sound/soc/cirrus/snappercl15.c | 2 +-
12 files changed, 48 insertions(+), 25 deletions(-)
create mode 100644 include/linux/soc/cirrus/ep93xx.h
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index d2eee707d27f..9f43362eb62d 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/clkdev.h>
+#include <linux/soc/cirrus/ep93xx.h>
#include <mach/hardware.h>
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 706515faee06..3d245668846d 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -43,6 +43,8 @@
#include <linux/platform_data/video-ep93xx.h>
#include <linux/platform_data/keypad-ep93xx.h>
#include <linux/platform_data/spi-ep93xx.h>
+#include <linux/soc/cirrus/ep93xx.h>
+
#include <mach/gpio-ep93xx.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index 43446f33c2be..b4045a186239 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -19,14 +19,6 @@ struct ep93xx_spi_info;
void ep93xx_map_io(void);
void ep93xx_init_irq(void);
-#define EP93XX_CHIP_REV_D0 3
-#define EP93XX_CHIP_REV_D1 4
-#define EP93XX_CHIP_REV_E0 5
-#define EP93XX_CHIP_REV_E1 6
-#define EP93XX_CHIP_REV_E2 7
-
-unsigned int ep93xx_chip_revision(void);
-
void ep93xx_register_flash(unsigned int width,
resource_size_t start, resource_size_t size);
@@ -36,19 +28,11 @@ void ep93xx_register_spi(struct ep93xx_spi_info *info,
struct spi_board_info *devices, int num);
void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
void ep93xx_register_pwm(int pwm0, int pwm1);
-int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
-void ep93xx_pwm_release_gpio(struct platform_device *pdev);
void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
-int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
-void ep93xx_keypad_release_gpio(struct platform_device *pdev);
void ep93xx_register_i2s(void);
-int ep93xx_i2s_acquire(void);
-void ep93xx_i2s_release(void);
void ep93xx_register_ac97(void);
void ep93xx_register_ide(void);
void ep93xx_register_adc(void);
-int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
-void ep93xx_ide_release_gpio(struct platform_device *pdev);
struct device *ep93xx_init_devices(void);
extern void ep93xx_timer_init(void);
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
index cc6d06c1b2c7..db271b705529 100644
--- a/drivers/ata/pata_ep93xx.c
+++ b/drivers/ata/pata_ep93xx.c
@@ -44,7 +44,7 @@
#include <linux/ktime.h>
#include <linux/platform_data/dma-ep93xx.h>
-#include <mach/platform.h>
+#include <linux/soc/cirrus/ep93xx.h>
#define DRV_NAME "ep93xx-ide"
#define DRV_VERSION "1.0"
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index 71472f6257c0..575dac52f7b4 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -27,8 +27,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>
/*
diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c
index bbf10ae02f0e..fa168581e6b8 100644
--- a/drivers/pwm/pwm-ep93xx.c
+++ b/drivers/pwm/pwm-ep93xx.c
@@ -35,7 +35,7 @@
#include <asm/div64.h>
-#include <mach/platform.h> /* for ep93xx_pwm_{acquire,release}_gpio() */
+#include <linux/soc/cirrus/ep93xx.h> /* for ep93xx_pwm_{acquire,release}_gpio() */
#define EP93XX_PWMx_TERM_COUNT 0x00
#define EP93XX_PWMx_DUTY_CYCLE 0x04
diff --git a/include/linux/soc/cirrus/ep93xx.h b/include/linux/soc/cirrus/ep93xx.h
new file mode 100644
index 000000000000..56fbe2dc59b1
--- /dev/null
+++ b/include/linux/soc/cirrus/ep93xx.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SOC_EP93XX_H
+#define _SOC_EP93XX_H
+
+struct platform_device;
+
+#define EP93XX_CHIP_REV_D0 3
+#define EP93XX_CHIP_REV_D1 4
+#define EP93XX_CHIP_REV_E0 5
+#define EP93XX_CHIP_REV_E1 6
+#define EP93XX_CHIP_REV_E2 7
+
+#ifdef CONFIG_ARCH_EP93XX
+int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
+void ep93xx_pwm_release_gpio(struct platform_device *pdev);
+int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
+void ep93xx_ide_release_gpio(struct platform_device *pdev);
+int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
+void ep93xx_keypad_release_gpio(struct platform_device *pdev);
+int ep93xx_i2s_acquire(void);
+void ep93xx_i2s_release(void);
+unsigned int ep93xx_chip_revision(void);
+
+#else
+static inline int ep93xx_pwm_acquire_gpio(struct platform_device *pdev) { return 0; }
+static inline void ep93xx_pwm_release_gpio(struct platform_device *pdev) {}
+static inline int ep93xx_ide_acquire_gpio(struct platform_device *pdev) { return 0; }
+static inline void ep93xx_ide_release_gpio(struct platform_device *pdev) {}
+static inline int ep93xx_keypad_acquire_gpio(struct platform_device *pdev) { return 0; }
+static inline void ep93xx_keypad_release_gpio(struct platform_device *pdev) {}
+static inline int ep93xx_i2s_acquire(void) { return 0; }
+static inline void ep93xx_i2s_release(void) {}
+static inline unsigned int ep93xx_chip_revision(void) { return 0; }
+
+#endif
+
+#endif
diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
index 3d011abaa266..f678b4c1514a 100644
--- a/sound/soc/cirrus/edb93xx.c
+++ b/sound/soc/cirrus/edb93xx.c
@@ -22,11 +22,11 @@
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/module.h>
+#include <linux/soc/cirrus/ep93xx.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
static int edb93xx_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
index cd5a939ad608..c6bc447429af 100644
--- a/sound/soc/cirrus/ep93xx-ac97.c
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -24,6 +24,7 @@
#include <sound/soc.h>
#include <linux/platform_data/dma-ep93xx.h>
+#include <linux/soc/cirrus/ep93xx.h>
#include "ep93xx-pcm.h"
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index 0918c5da575a..beab7c516855 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -27,9 +27,8 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include <mach/hardware.h>
-#include <mach/ep93xx-regs.h>
#include <linux/platform_data/dma-ep93xx.h>
+#include <linux/soc/cirrus/ep93xx.h>
#include "ep93xx-pcm.h"
diff --git a/sound/soc/cirrus/simone.c b/sound/soc/cirrus/simone.c
index 1ec661834e5a..cb850530331b 100644
--- a/sound/soc/cirrus/simone.c
+++ b/sound/soc/cirrus/simone.c
@@ -13,13 +13,13 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/soc/cirrus/ep93xx.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
static struct snd_soc_dai_link simone_dai = {
.name = "AC97",
diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
index 11ff7b2672b2..dea4909154c8 100644
--- a/sound/soc/cirrus/snappercl15.c
+++ b/sound/soc/cirrus/snappercl15.c
@@ -13,12 +13,12 @@
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/soc/cirrus/ep93xx.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
#include "../codecs/tlv320aic23.h"
--
2.20.0
^ permalink raw reply related
* [PATCH 2/4] ARM: ep93xx: keypad: stop using mach/platform.h
From: Arnd Bergmann @ 2019-04-15 19:25 UTC (permalink / raw)
To: Hartley Sweeten, Alexander Sverdlin
Cc: Linus Walleij, Arnd Bergmann, Dmitry Torokhov, Stefan Agner,
Enric Balletbo i Serra, Guenter Roeck, linux-input, linux-kernel
In-Reply-To: <20190415192734.935387-1-arnd@arndb.de>
We can communicate the clock rate using platform data rather than setting
a flag to use a particular value in the driver, which is cleaner and
avoids the dependency.
No platform in the kernel currently defines the ep93xx keypad device
structure, so this is a rather pointless excercise. Any out of tree
users are probably dead now, but if not, they have to change their
platform code to match the new platform_data structure.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/input/keyboard/Kconfig | 2 +-
drivers/input/keyboard/ep93xx_keypad.c | 5 +----
include/linux/platform_data/keypad-ep93xx.h | 4 ++--
3 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a878351f1643..b373f3274542 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -194,7 +194,7 @@ config KEYBOARD_LKKBD
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.
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index f77b295e0123..71472f6257c0 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -137,10 +137,7 @@ static void ep93xx_keypad_config(struct ep93xx_keypad *keypad)
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/include/linux/platform_data/keypad-ep93xx.h b/include/linux/platform_data/keypad-ep93xx.h
index 0e36818e3680..3054fced8509 100644
--- a/include/linux/platform_data/keypad-ep93xx.h
+++ b/include/linux/platform_data/keypad-ep93xx.h
@@ -9,8 +9,7 @@ struct matrix_keymap_data;
#define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */
#define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */
#define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */
-#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */
-#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */
+#define EP93XX_KEYPAD_AUTOREPEAT (1<<4) /* enable key autorepeat */
/**
* struct ep93xx_keypad_platform_data - platform specific device structure
@@ -24,6 +23,7 @@ struct ep93xx_keypad_platform_data {
unsigned int debounce;
unsigned int prescale;
unsigned int flags;
+ unsigned int clk_rate;
};
#define EP93XX_MATRIX_ROWS (8)
--
2.20.0
^ permalink raw reply related
* [PATCH v3 3/3] arm64: dts: qcom: Add Lenovo Miix 630
From: Jeffrey Hugo @ 2019-04-15 16:11 UTC (permalink / raw)
To: bjorn.andersson, robh+dt, mark.rutland, agross, david.brown
Cc: lee.jones, dmitry.torokhov, jikos, benjamin.tissoires,
linux-input, devicetree, linux-arm-msm, linux-kernel,
Jeffrey Hugo
In-Reply-To: <20190415160915.16324-1-jeffrey.l.hugo@gmail.com>
This adds the initial DT for the Lenovo Miix 630 laptop. Supported
functionality includes USB (host), microSD-card, keyboard, and trackpad.
Signed-off-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com>
---
arch/arm64/boot/dts/qcom/Makefile | 1 +
.../boot/dts/qcom/msm8998-clamshell.dtsi | 278 ++++++++++++++++++
.../boot/dts/qcom/msm8998-lenovo-miix-630.dts | 30 ++
3 files changed, 309 insertions(+)
create mode 100644 arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
create mode 100644 arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 21d548f02d39..c3e4307bcbd4 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -6,6 +6,7 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8916-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8992-bullhead-rev-101.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8994-angler-rev-101.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb
+dtb-$(CONFIG_ARCH_QCOM) += msm8998-lenovo-miix-630.dtb
dtb-$(CONFIG_ARCH_QCOM) += msm8998-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm845-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb
diff --git a/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
new file mode 100644
index 000000000000..1a341d4b1597
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Jeffrey Hugo. All rights reserved. */
+
+/*
+ * Common include for MSM8998 clamshell devices, ie the Lenovo Miix 630,
+ * Asus NovaGo TP370QL, and HP Envy x2. All three devices are basically the
+ * same, with differences in peripherals.
+ */
+
+#include "msm8998.dtsi"
+#include "pm8998.dtsi"
+#include "pm8005.dtsi"
+
+/ {
+ chosen {
+ };
+
+ thermal-zones {
+ battery-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens0 0>;
+
+ trips {
+ battery_crit: trip0 {
+ temperature = <60000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+
+ skin-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&tsens1 5>;
+
+ trips {
+ skin_alert: trip0 {
+ temperature = <44000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ skip_crit: trip1 {
+ temperature = <70000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
+ vph_pwr: vph-pwr-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&qusb2phy {
+ status = "okay";
+
+ vdda-pll-supply = <&vreg_l12a_1p8>;
+ vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
+};
+
+&rpm_requests {
+ pm8998-regulators {
+ compatible = "qcom,rpm-pm8998-regulators";
+
+ vdd_s1-supply = <&vph_pwr>;
+ vdd_s2-supply = <&vph_pwr>;
+ vdd_s3-supply = <&vph_pwr>;
+ vdd_s4-supply = <&vph_pwr>;
+ vdd_s5-supply = <&vph_pwr>;
+ vdd_s6-supply = <&vph_pwr>;
+ vdd_s7-supply = <&vph_pwr>;
+ vdd_s8-supply = <&vph_pwr>;
+ vdd_s9-supply = <&vph_pwr>;
+ vdd_s10-supply = <&vph_pwr>;
+ vdd_s11-supply = <&vph_pwr>;
+ vdd_s12-supply = <&vph_pwr>;
+ vdd_s13-supply = <&vph_pwr>;
+ vdd_l1_l27-supply = <&vreg_s7a_1p025>;
+ vdd_l2_l8_l17-supply = <&vreg_s3a_1p35>;
+ vdd_l3_l11-supply = <&vreg_s7a_1p025>;
+ vdd_l4_l5-supply = <&vreg_s7a_1p025>;
+ vdd_l6-supply = <&vreg_s5a_2p04>;
+ vdd_l7_l12_l14_l15-supply = <&vreg_s5a_2p04>;
+ vdd_l9-supply = <&vph_pwr>;
+ vdd_l10_l23_l25-supply = <&vph_pwr>;
+ vdd_l13_l19_l21-supply = <&vph_pwr>;
+ vdd_l16_l28-supply = <&vph_pwr>;
+ vdd_l18_l22-supply = <&vph_pwr>;
+ vdd_l20_l24-supply = <&vph_pwr>;
+ vdd_l26-supply = <&vreg_s3a_1p35>;
+ vdd_lvs1_lvs2-supply = <&vreg_s4a_1p8>;
+
+ vreg_s3a_1p35: s3 {
+ regulator-min-microvolt = <1352000>;
+ regulator-max-microvolt = <1352000>;
+ };
+ vreg_s4a_1p8: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-allow-set-load;
+ };
+ vreg_s5a_2p04: s5 {
+ regulator-min-microvolt = <1904000>;
+ regulator-max-microvolt = <2040000>;
+ };
+ vreg_s7a_1p025: s7 {
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1028000>;
+ };
+ vreg_l1a_0p875: l1 {
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ regulator-allow-set-load;
+ };
+ vreg_l2a_1p2: l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-allow-set-load;
+ };
+ vreg_l3a_1p0: l3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+ vreg_l5a_0p8: l5 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ };
+ vreg_l6a_1p8: l6 {
+ regulator-min-microvolt = <1808000>;
+ regulator-max-microvolt = <1808000>;
+ };
+ vreg_l7a_1p8: l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ vreg_l8a_1p2: l8 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+ vreg_l9a_1p8: l9 {
+ regulator-min-microvolt = <1808000>;
+ regulator-max-microvolt = <2960000>;
+ };
+ vreg_l10a_1p8: l10 {
+ regulator-min-microvolt = <1808000>;
+ regulator-max-microvolt = <2960000>;
+ };
+ vreg_l11a_1p0: l11 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+ vreg_l12a_1p8: l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ vreg_l13a_2p95: l13 {
+ regulator-min-microvolt = <1808000>;
+ regulator-max-microvolt = <2960000>;
+ };
+ vreg_l14a_1p88: l14 {
+ regulator-min-microvolt = <1880000>;
+ regulator-max-microvolt = <1880000>;
+ };
+ vreg_15a_1p8: l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ vreg_l16a_2p7: l16 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2704000>;
+ };
+ vreg_l17a_1p3: l17 {
+ regulator-min-microvolt = <1304000>;
+ regulator-max-microvolt = <1304000>;
+ };
+ vreg_l18a_2p7: l18 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2704000>;
+ };
+ vreg_l19a_3p0: l19 {
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3008000>;
+ };
+ vreg_l20a_2p95: l20 {
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-allow-set-load;
+ };
+ vreg_l21a_2p95: l21 {
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-allow-set-load;
+ regulator-system-load = <800000>;
+ };
+ vreg_l22a_2p85: l22 {
+ regulator-min-microvolt = <2864000>;
+ regulator-max-microvolt = <2864000>;
+ };
+ vreg_l23a_3p3: l23 {
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3312000>;
+ };
+ vreg_l24a_3p075: l24 {
+ regulator-min-microvolt = <3088000>;
+ regulator-max-microvolt = <3088000>;
+ };
+ vreg_l25a_3p3: l25 {
+ regulator-min-microvolt = <3104000>;
+ regulator-max-microvolt = <3312000>;
+ };
+ vreg_l26a_1p2: l26 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+ vreg_l28_3p0: l28 {
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3008000>;
+ };
+
+ vreg_lvs1a_1p8: lvs1 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vreg_lvs2a_1p8: lvs2 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ };
+};
+
+&tlmm {
+ gpio-reserved-ranges = <0 4>, <81 4>;
+
+ touchpad: touchpad {
+ config {
+ pins = "gpio123";
+ bias-pull-up; /* pull up */
+ };
+ };
+};
+
+&sdhc2 {
+ status = "okay";
+
+ vmmc-supply = <&vreg_l21a_2p95>;
+ vqmmc-supply = <&vreg_l13a_2p95>;
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+};
+
+&usb3 {
+ status = "okay";
+};
+
+&usb3_dwc3 {
+ dr_mode = "host"; /* Force to host until we have Type-C hooked up */
+};
+
+&usb3phy {
+ status = "okay";
+
+ vdda-phy-supply = <&vreg_l1a_0p875>;
+ vdda-pll-supply = <&vreg_l2a_1p2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts b/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts
new file mode 100644
index 000000000000..c2b43f7ed137
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Jeffrey Hugo. All rights reserved. */
+
+/dts-v1/;
+
+#include "msm8998-clamshell.dtsi"
+
+/ {
+ model = "Lenovo Miix 630";
+ compatible = "lenovo,miix-630", "qcom,msm8998";
+};
+
+&blsp1_i2c6 {
+ status = "okay";
+
+ keyboard@3a {
+ compatible = "elan,combo400-i2c", "hid-over-i2c";
+ interrupt-parent = <&tlmm>;
+ interrupts = <0x79 IRQ_TYPE_LEVEL_LOW>;
+ reg = <0x3a>;
+ hid-descr-addr = <0x0001>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&touchpad>;
+ };
+};
+
+&sdhc2 {
+ cd-gpios = <&tlmm 95 GPIO_ACTIVE_HIGH>;
+};
--
2.17.1
^ permalink raw reply related
* [PATCH v3 2/3] HID: quirks: Fix keyboard + touchpad on Lenovo Miix 630 for DT
From: Jeffrey Hugo @ 2019-04-15 16:11 UTC (permalink / raw)
To: robh+dt, mark.rutland, jikos, benjamin.tissoires
Cc: lee.jones, bjorn.andersson, dmitry.torokhov, agross, david.brown,
linux-input, devicetree, linux-arm-msm, linux-kernel,
Jeffrey Hugo
In-Reply-To: <20190415160915.16324-1-jeffrey.l.hugo@gmail.com>
Following up on commit 2bafa1e96254 ("HID: quirks: Fix keyboard + touchpad
on Lenovo Miix 630"), the devicetree (DT) identifier for the combo keyboard
+ touchpad device is "elan,combo400-i2c", which differs from the ACPI ID,
thus if we want the quirk to work properly when booting via DT instead of
ACPI, we need to key off the DT id as well.
Signed-off-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com>
---
drivers/hid/hid-quirks.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 77ffba48cc73..00c08f8318b8 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -997,7 +997,8 @@ bool hid_ignore(struct hid_device *hdev)
return true;
/* Same with product id 0x0400 */
if (hdev->product == 0x0400 &&
- strncmp(hdev->name, "QTEC0001", 8) != 0)
+ (strncmp(hdev->name, "QTEC0001", 8) != 0 ||
+ strncmp(hdev->name, "elan,combo400-i2c", 17) != 0))
return true;
break;
}
--
2.17.1
^ permalink raw reply related
* [PATCH v3 1/3] dt-bindings: input: add Elan 400 combo keyboard/touchpad over i2c
From: Jeffrey Hugo @ 2019-04-15 16:10 UTC (permalink / raw)
To: robh+dt, mark.rutland
Cc: lee.jones, bjorn.andersson, dmitry.torokhov, agross, david.brown,
jikos, benjamin.tissoires, linux-input, devicetree, linux-arm-msm,
linux-kernel, Jeffrey Hugo
In-Reply-To: <20190415160915.16324-1-jeffrey.l.hugo@gmail.com>
The Elan 400 combo keyboard/touchpad over i2c device is a distinct device
from the Elan 400 standalone touchpad device. The combo device has been
found in the Lenovo Miix 630 and HP Envy x2 laptops.
Signed-off-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com>
---
.../devicetree/bindings/input/elan,combo400-i2c.txt | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/elan,combo400-i2c.txt
diff --git a/Documentation/devicetree/bindings/input/elan,combo400-i2c.txt b/Documentation/devicetree/bindings/input/elan,combo400-i2c.txt
new file mode 100644
index 000000000000..fb700a29148d
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/elan,combo400-i2c.txt
@@ -0,0 +1,11 @@
+Elantech 0400 I2C combination Keyboard/Touchpad
+
+This binding describes an Elan device with pid 0x0400, that is a combination
+keyboard + touchpad device. This binding does not cover an Elan device with
+pid 0x0400 that is solely a standalone touchpad device.
+
+Required properties:
+- compatible: should be "elan,combo400-i2c"
+
+This binding is compatible with the HID over I2C binding, which is specified
+in hid-over-i2c.txt in this directory.
--
2.17.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox