Linux Input/HID development
 help / color / mirror / Atom feed
* [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

* [PATCH v3 0/3] Basic DT support for Lenovo Miix 630
From: Jeffrey Hugo @ 2019-04-15 16:09 UTC (permalink / raw)
  Cc: lee.jones, bjorn.andersson, dmitry.torokhov, robh+dt,
	mark.rutland, agross, david.brown, jikos, benjamin.tissoires,
	linux-input, devicetree, linux-arm-msm, linux-kernel,
	Jeffrey Hugo

The Lenovo Miix 630 is one of three ARM based (specifically Qualcomm
MSM8998) laptops that comes with Windows, and seems to have a dedicated
following of folks intrested to get Linux up and running on it.

This series adds support for the basic functionality this is validated
towork using devicetree.  Although the laptops do feed ACPI to Windows,
the existing MSM8998 support in mainline is DT based, so DT provides a
quick path to functionality while ACPI support is investigated.

The three devices are very similar, but do have differences in the set
of peripherals supported, so the idea is that the vast majority of the
support for all three can live in a common include, which should reduce
overall duplication.  Adding support for the other two devices as a
follow on should involve minimal work.

The bleeding edge work for these laptops and work in progress can be
found at https://github.com/aarch64-laptops/prebuilt

v3:
-Changed "clam" to "clamshell"
-Defined a dt binding for the combo Elan keyboard + touchpad device
-Adjusted the HID quirk to be correct for dt boot
-Removed extranious comment in board dts
-Fixed board level compatible

v2:
-Changed "cls" to "clam" since feedback indicated "cls" is too opaque,
but
"clamshell" is a mouthfull.  "clam" seems to be a happy medium.

Jeffrey Hugo (3):
  dt-bindings: input: add Elan 400 combo keyboard/touchpad over i2c
  HID: quirks: Fix keyboard + touchpad on Lenovo Miix 630 for DT
  arm64: dts: qcom: Add Lenovo Miix 630

 .../bindings/input/elan,combo400-i2c.txt      |  11 +
 arch/arm64/boot/dts/qcom/Makefile             |   1 +
 .../boot/dts/qcom/msm8998-clamshell.dtsi      | 278 ++++++++++++++++++
 .../boot/dts/qcom/msm8998-lenovo-miix-630.dts |  30 ++
 drivers/hid/hid-quirks.c                      |   3 +-
 5 files changed, 322 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/input/elan,combo400-i2c.txt
 create mode 100644 arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi
 create mode 100644 arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts

-- 
2.17.1

^ permalink raw reply

* [PATCH 1/1] input: adp5589: Add gpio_set_multiple interface
From: Bogdan Togorean @ 2019-04-15 12:25 UTC (permalink / raw)
  To: linux-input; +Cc: dmitry.torokhov, gustavo, linux-kernel, Bogdan Togorean

This patch implements the gpio_set_multiple interface for ADP558x chip.

Signed-off-by: Bogdan Togorean <bogdan.togorean@analog.com>
---
 drivers/input/keyboard/adp5589-keys.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index 2835fba71c33..143871bd60ef 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -416,6 +416,30 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip,
 	mutex_unlock(&kpad->gpio_lock);
 }
 
+static void adp5589_gpio_set_multiple(struct gpio_chip *chip,
+				      unsigned long *mask, unsigned long *bits)
+{
+	struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+	u8 bank, reg_mask, reg_bits;
+
+	mutex_lock(&kpad->gpio_lock);
+
+	for (bank = 0; bank <= kpad->var->bank(kpad->var->maxgpio); bank++) {
+		if (bank > kpad->var->bank(get_bitmask_order(*mask) - 1))
+			break;
+		reg_mask = mask[bank / sizeof(*mask)] >>
+			   ((bank % sizeof(*mask)) * BITS_PER_BYTE);
+		reg_bits = bits[bank / sizeof(*bits)] >>
+			   ((bank % sizeof(*bits)) * BITS_PER_BYTE);
+		kpad->dat_out[bank] &= ~reg_mask;
+		kpad->dat_out[bank] |= reg_bits & reg_mask;
+		adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + bank,
+			      kpad->dat_out[bank]);
+	}
+
+	mutex_unlock(&kpad->gpio_lock);
+}
+
 static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
 {
 	struct adp5589_kpad *kpad = gpiochip_get_data(chip);
@@ -517,6 +541,7 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad)
 	kpad->gc.direction_output = adp5589_gpio_direction_output;
 	kpad->gc.get = adp5589_gpio_get_value;
 	kpad->gc.set = adp5589_gpio_set_value;
+	kpad->gc.set_multiple = adp5589_gpio_set_multiple;
 	kpad->gc.can_sleep = 1;
 
 	kpad->gc.base = gpio_data->gpio_start;
-- 
2.21.0

^ permalink raw reply related

* Re: [PATCH] ELAN touchpad i2c_hid bugs fix
From: Hans de Goede @ 2019-04-15 11:42 UTC (permalink / raw)
  To: hotwater438, Kai-Heng Feng
  Cc: Dmitry Torokhov, Vladislav Dalechyn, Benjamin Tissoires,
	Jiri Kosina, Swboyd, Bigeasy, open list:HID CORE LAYER, lkml
In-Reply-To: <LcVmBjG--3-1@tutanota.com>

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.

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 v2] Input: uinput: Avoid Object-Already-Free with a global lock
From: Mukesh Ojha @ 2019-04-15 10:05 UTC (permalink / raw)
  To: linux-input, linux-kernel
  Cc: Gaurav Kohli, Peter Hutterer, Martin Kepplinger, Paul E. McKenney,
	dmitry.torokhov@gmail.com
In-Reply-To: <1554883176-24318-1-git-send-email-mojha@codeaurora.org>


Hi Dmitry,

Can you please have a look at this patch ? as this seems to reproducing 
quite frequently

Thanks,
Mukesh

On 4/10/2019 1:29 PM, Mukesh Ojha wrote:
> uinput_destroy_device() gets called from two places. In one place,
> uinput_ioctl_handler() where it is protected under a lock
> udev->mutex but there is no protection on udev device from freeing
> inside uinput_release().
>
> This can result in Object-Already-Free case where uinput parent
> device already got freed while a child being inserted inside it.
> That result in a double free case for parent while kernfs_put()
> being done for child in a failure path of adding a node.
>
> [  160.093398] Call trace:
> [  160.093417]  kernfs_get+0x64/0x88
> [  160.093438]  kernfs_new_node+0x94/0xc8
> [  160.093450]  kernfs_create_dir_ns+0x44/0xfc
> [  160.093463]  sysfs_create_dir_ns+0xa8/0x130
> [  160.093479]  kobject_add_internal+0x278/0x650
> [  160.093491]  kobject_add_varg+0xe0/0x130
> [  160.093502]  kobject_add+0x15c/0x1d0
> [  160.093518]  device_add+0x2bc/0xde0
> [  160.093533]  input_register_device+0x5f4/0xa0c
> [  160.093547]  uinput_ioctl_handler+0x1184/0x2198
> [  160.093560]  uinput_ioctl+0x38/0x48
> [  160.093573]  vfs_ioctl+0x7c/0xb4
> [  160.093585]  do_vfs_ioctl+0x9ec/0x2350
> [  160.093597]  SyS_ioctl+0x6c/0xa4
> [  160.093610]  el0_svc_naked+0x34/0x38
> [  160.093621] ---[ end trace bccf0093cda2c538 ]---
> [  160.099041] =============================================================================
> [  160.107459] BUG kernfs_node_cache (Tainted: G S      W  O   ): Object already free
> [  160.115235] -----------------------------------------------------------------------------
> [  160.115235]
> [  160.125151] Disabling lock debugging due to kernel taint
> [  160.130626] INFO: Allocated in __kernfs_new_node+0x8c/0x3c0 age=11 cpu=2 pid=7098
> [  160.138314] 	kmem_cache_alloc+0x358/0x388
> [  160.142445] 	__kernfs_new_node+0x8c/0x3c0
> [  160.146590] 	kernfs_new_node+0x80/0xc8
> [  160.150462] 	kernfs_create_dir_ns+0x44/0xfc
> [  160.154777] 	sysfs_create_dir_ns+0xa8/0x130
> [  160.158416] CPU5: update max cpu_capacity 1024
> [  160.159085] 	kobject_add_internal+0x278/0x650
> [  160.163567] 	kobject_add_varg+0xe0/0x130
> [  160.167606] 	kobject_add+0x15c/0x1d0
> [  160.168452] CPU5: update max cpu_capacity 780
> [  160.171287] 	get_device_parent+0x2d0/0x34c
> [  160.175510] 	device_add+0x240/0xde0
> [  160.178371] CPU6: update max cpu_capacity 916
> [  160.179108] 	input_register_device+0x5f4/0xa0c
> [  160.183686] 	uinput_ioctl_handler+0x1184/0x2198
> [  160.188346] 	uinput_ioctl+0x38/0x48
> [  160.191941] 	vfs_ioctl+0x7c/0xb4
> [  160.195261] 	do_vfs_ioctl+0x9ec/0x2350
> [  160.199111] 	SyS_ioctl+0x6c/0xa4
> [  160.202436] INFO: Freed in kernfs_put+0x2c8/0x434 age=14 cpu=0 pid=7096
> [  160.209230] 	kernfs_put+0x2c8/0x434
> [  160.212825] 	kobject_del+0x50/0xcc
> [  160.216332] 	cleanup_glue_dir+0x124/0x16c
> [  160.220456] 	device_del+0x55c/0x5c8
> [  160.224047] 	__input_unregister_device+0x274/0x2a8
> [  160.228974] 	input_unregister_device+0x90/0xd0
> [  160.233553] 	uinput_destroy_device+0x15c/0x1dc
> [  160.238131] 	uinput_release+0x44/0x5c
> [  160.241898] 	__fput+0x1f4/0x4e4
> [  160.245127] 	____fput+0x20/0x2c
> [  160.248358] 	task_work_run+0x9c/0x174
> [  160.252127] 	do_notify_resume+0x104/0x6bc
> [  160.256253] 	work_pending+0x8/0x14
> [  160.259751] INFO: Slab 0xffffffbf0215ff00 objects=33 used=11 fp=0xffffffc0857ffd08 flags=0x8101
> [  160.268693] INFO: Object 0xffffffc0857ffd08 @offset=15624 fp=0xffffffc0857fefb0
> [  160.268693]
> [  160.277721] Redzone ffffffc0857ffd00: bb bb bb bb bb bb bb bb                          ........
> [  160.286656] Object ffffffc0857ffd08: 00 00 00 00 01 00 00 80 58 a2 37 45 c1 ff ff ff  ........X.7E....
> [  160.296207] Object ffffffc0857ffd18: ae 21 10 0b 90 ff ff ff 20 fd 7f 85 c0 ff ff ff  .!...... .......
> [  160.305780] Object ffffffc0857ffd28: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
> [  160.315342] Object ffffffc0857ffd38: 00 00 00 00 00 00 00 00 7d a3 25 69 00 00 00 00  ........}.%i....
> [  160.324896] Object ffffffc0857ffd48: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
> [  160.334446] Object ffffffc0857ffd58: 80 c0 28 47 c1 ff ff ff 00 00 00 00 00 00 00 00  ..(G............
> [  160.344000] Object ffffffc0857ffd68: 80 4a ce d1 c0 ff ff ff dc 32 01 00 01 00 00 00  .J.......2......
> [  160.353554] Object ffffffc0857ffd78: 11 00 ed 41 00 00 00 00 00 00 00 00 00 00 00 00  ...A............
> [  160.363099] Redzone ffffffc0857ffd88: bb bb bb bb bb bb bb bb                          ........
> [  160.372032] Padding ffffffc0857ffee0: 5a 5a 5a 5a 5a 5a 5a 5a                          ZZZZZZZZ
> [  160.378299] CPU6: update max cpu_capacity 780
> [  160.380971] CPU: 4 PID: 7098 Comm: syz-executor Tainted: G S  B   W  O    4.14.98+ #1
>
> So, avoid the race by taking a global lock inside uinput_release().
>
> Signed-off-by: Mukesh Ojha <mojha@codeaurora.org>
> Cc: Gaurav Kohli <gkohli@codeaurora.org>
> Cc: Peter Hutterer <peter.hutterer@who-t.net>
> Cc: Martin Kepplinger <martink@posteo.de>
> Cc: "Paul E. McKenney" <paulmck@linux.ibm.com>
> ---
> Also, if this looks good we can further use this global lock inside
> read/write in separate patches and release can happen at any time.
>
> Changes from v1->v2:
>   - Mistakenly added udev lock replaced by global lock.
>
>
>
>
>   drivers/input/misc/uinput.c | 28 ++++++++++++++++++++++++++--
>   1 file changed, 26 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
> index 26ec603f..2e7e096 100644
> --- a/drivers/input/misc/uinput.c
> +++ b/drivers/input/misc/uinput.c
> @@ -81,6 +81,8 @@ struct uinput_device {
>   	spinlock_t		requests_lock;
>   };
>   
> +static DEFINE_MUTEX(uinput_glb_mutex);
> +
>   static int uinput_dev_event(struct input_dev *dev,
>   			    unsigned int type, unsigned int code, int value)
>   {
> @@ -714,10 +716,18 @@ static __poll_t uinput_poll(struct file *file, poll_table *wait)
>   static int uinput_release(struct inode *inode, struct file *file)
>   {
>   	struct uinput_device *udev = file->private_data;
> +	ssize_t retval;
> +
> +	retval = mutex_lock_interruptible(&uinput_glb_mutex);
> +	if (retval)
> +		return retval;
>   
>   	uinput_destroy_device(udev);
> +	file->private_data = NULL;
>   	kfree(udev);
>   
> +	mutex_unlock(&uinput_glb_mutex);
> +
>   	return 0;
>   }
>   
> @@ -848,7 +858,7 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
>   				 unsigned long arg, void __user *p)
>   {
>   	int			retval;
> -	struct uinput_device	*udev = file->private_data;
> +	struct uinput_device	*udev;
>   	struct uinput_ff_upload ff_up;
>   	struct uinput_ff_erase  ff_erase;
>   	struct uinput_request   *req;
> @@ -856,10 +866,20 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
>   	const char		*name;
>   	unsigned int		size;
>   
> -	retval = mutex_lock_interruptible(&udev->mutex);
> +	retval = mutex_lock_interruptible(&uinput_glb_mutex);
>   	if (retval)
>   		return retval;
>   
> +	udev = file->private_data;
> +	if (!udev) {
> +		retval = -EINVAL;
> +		goto unlock_glb_mutex;
> +	}
> +
> +	retval = mutex_lock_interruptible(&udev->mutex);
> +	if (retval)
> +		goto unlock_glb_mutex;
> +
>   	if (!udev->dev) {
>   		udev->dev = input_allocate_device();
>   		if (!udev->dev) {
> @@ -1039,8 +1059,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
>   	}
>   
>   	retval = -EINVAL;
> +
>    out:
>   	mutex_unlock(&udev->mutex);
> +
> + unlock_glb_mutex:
> +	mutex_unlock(&uinput_glb_mutex);
>   	return retval;
>   }
>   

^ permalink raw reply

* Re: [PATCH v5 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Andy Shevchenko @ 2019-04-15  9:03 UTC (permalink / raw)
  To: Ronald Tschalär
  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: <20190415081300.24831-3-ronald@innovation.ch>

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>

> 
> 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>
> ---
>  drivers/input/keyboard/Kconfig          |   15 +
>  drivers/input/keyboard/Makefile         |    1 +
>  drivers/input/keyboard/applespi.c       | 1985 +++++++++++++++++++++++
>  drivers/input/keyboard/applespi.h       |   29 +
>  drivers/input/keyboard/applespi_trace.h |   94 ++
>  5 files changed, 2124 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..5c3d7687e346
> --- /dev/null
> +++ b/drivers/input/keyboard/applespi.c
> @@ -0,0 +1,1985 @@
> +// 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);

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);

> +
> +	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 */
> +	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.

> +
> +		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
> 

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH] HID: fix compiling error in u2fzero_probe()
From: Jiri Kosina @ 2019-04-15  9:03 UTC (permalink / raw)
  To: Mao Wenan
  Cc: benjamin.tissoires, linux-input, linux-kernel, kernel-janitors,
	Hulk Robot, Andrej Shadura
In-Reply-To: <20190413134459.76045-1-maowenan@huawei.com>

On Sat, 13 Apr 2019, Mao Wenan wrote:

> There is one compiling error in u2fzero_probe()->u2fzero_init_hwrng(),
> this is because HW_RANDOM is not set.
> 
> drivers/hid/hid-u2fzero.o: In function `u2fzero_probe':
> hid-u2fzero.c:(.text+0xc70): undefined reference to `devm_hwrng_register'
> 
> Fixes: 42337b9d4d958("HID: add driver for U2F Zero built-in LED and RNG")
> Reported-by: Hulk Robot <hulkci@huawei.com>
> Signed-off-by: Mao Wenan <maowenan@huawei.com>
> ---
>  drivers/hid/Kconfig | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 4dc1035..76d8206 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -1017,6 +1017,7 @@ config HID_U2FZERO
>  	tristate "U2F Zero LED and RNG support"
>  	depends on USB_HID
>  	depends on LEDS_CLASS
> +	depends on HW_RANDOM

[ CCing Andrej ]

This was supposed to be sent by Andrej (together with other fixes), but 
you beat him to it. Applied, thanks.

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply

* Re: [PATCH v5 1/2] drm/bridge: sil_sii8620: make remote control optional.
From: Andrzej Hajda @ 2019-04-15  8:58 UTC (permalink / raw)
  To: Ronald Tschalär, Dmitry Torokhov, Henrik Rydberg,
	Andy Shevchenko, Inki Dae, Greg Kroah-Hartman
  Cc: Lukas Wunner, Federico Lorenzi, Laurent Pinchart, linux-input,
	dri-devel, linux-kernel
In-Reply-To: <20190415081300.24831-2-ronald@innovation.ch>

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>


If there are no objections I will take it to drm-misc tomorrow.


 --
Regards
Andrzej

^ permalink raw reply

* [PATCH v5 2/2] Input: add Apple SPI keyboard and trackpad driver.
From: Ronald Tschalär @ 2019-04-15  8:13 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: <20190415081300.24831-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>
---
 drivers/input/keyboard/Kconfig          |   15 +
 drivers/input/keyboard/Makefile         |    1 +
 drivers/input/keyboard/applespi.c       | 1985 +++++++++++++++++++++++
 drivers/input/keyboard/applespi.h       |   29 +
 drivers/input/keyboard/applespi_trace.h |   94 ++
 5 files changed, 2124 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..5c3d7687e346
--- /dev/null
+++ b/drivers/input/keyboard/applespi.c
@@ -0,0 +1,1985 @@
+// 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);
+
+	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 */
+	for (i = 0; i < MAX_ROLLOVER; i++) {
+		if (keyboard_protocol->keys_pressed[i] != 1)
+			break;
+	}
+
+	if (i == MAX_ROLLOVER)	/* all keys were 1 */
+		return;
+
+	/* 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;
+
+		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 v5 1/2] drm/bridge: sil_sii8620: make remote control optional.
From: Ronald Tschalär @ 2019-04-15  8:12 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: <20190415081300.24831-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>
---
 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 v5 0/2] Add Apple SPI keyboard and trackpad driver
From: Ronald Tschalär @ 2019-04-15  8:12 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.

The second patch contains the new applespi driver.

Changes in v5:
  Applied all feedback from review by Andy Shevchenko (applespi) and
  Andrzej Hajda (sil-sii8620), including:
  - (sil_sii8620) use 'if (IS_DEFINED(...))' instead of conditional
    compilation to handle RC_CORE being undefined
  - (applespi) a number of cleanups of leftovers from changes to earlier
    versions
  - (applespi) replace some bool flags with loop-end detection
  - (applespi) improve error reporting in a couple places
  The full set of changes to applespi can be viewed at
  https://github.com/roadrunner2/macbook12-spi-driver/ as individual
  commits daf60f8..36afd70 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       | 1985 +++++++++++++++++++++++
 drivers/input/keyboard/applespi.h       |   29 +
 drivers/input/keyboard/applespi_trace.h |   94 ++
 7 files changed, 2132 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 v4 1/2] drm/bridge: sil_sii8620: make remote control optional.
From: Life is hard, and then you die @ 2019-04-15  6:50 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Dmitry Torokhov, Henrik Rydberg, Andy Shevchenko,
	Greg Kroah-Hartman, Lukas Wunner, Federico Lorenzi, linux-input,
	linux-kernel, Inki Dae, Laurent Pinchart
In-Reply-To: <c861091d-f659-614d-65f4-6fe983885e09@samsung.com>


  Hi Andrzej,

On Wed, Apr 10, 2019 at 11:42:50AM +0200, Andrzej Hajda wrote:
> On 07.04.2019 07:03, 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).
[snip]
> What about:
> 
> ---------
> 
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 8840f396a7b6..298189067929 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -86,8 +86,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 0cc293a6ac24..df0f9dbbe839 100644
> --- a/drivers/gpu/drm/bridge/sil-sii8620.c
> +++ b/drivers/gpu/drm/bridge/sil-sii8620.c
> @@ -1762,10 +1762,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(RC_CORE) || !ctx->rc_dev)
>                 return false;
> -       }
>  
>         if (pressed)
>                 rc_keydown(ctx->rc_dev, RC_PROTO_CEC, scancode, 0);
> @@ -2102,6 +2100,9 @@ static void sii8620_init_rcp_input_dev(struct
> sii8620 *ctx)
>         struct rc_dev *rc_dev;
>         int ret;
>  
> +       if (!IS_ENABLED(RC_CORE))
> +               return;
> +
>         rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
>         if (!rc_dev) {
>                 dev_err(ctx->dev, "Failed to allocate RC device\n");
> @@ -2216,6 +2217,9 @@ static void sii8620_detach(struct drm_bridge *bridge)
>  {
>         struct sii8620 *ctx = bridge_to_sii8620(bridge);
>  
> +       if (!IS_ENABLED(RC_CORE))
> +               return;
> +
>         rc_unregister_device(ctx->rc_dev);
>  }
> -----------
> 
> Less changes, no conditional compilation - better compiler coverage,
> more readable.

This works for me (with RC_CORE replaced with CONFIG_RC_CORE). Sending
a new patch that includes this shortly.


  Cheers,

  Ronald

^ permalink raw reply

* Re: [RFC v2] iio: input-bridge: optionally bridge iio acceleometers to create a /dev/input interface
From: Roderick Colenbrander @ 2019-04-14 16:26 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: H. Nikolaus Schaller, Dmitry Torokhov, Eric Piel, linux-input,
	letux-kernel, kernel, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, lkml, linux-iio
In-Reply-To: <20190414124029.1f1f6084@archlinux>

Hi Jonathan and Nikolaus,

I would like to jump into this discussion a bit as well. Might be
slightly off topic or not... I'm not too familiar with the details of
IIO, but as Sony we do report accelerometer / gyroscope data through
/dev/input for our DualShock devices through hid-sony. This is among
reasons done for Android, which Nikolaus showed interest in as well.
We are working on exposing this data through user space through
standard Android APIs (see,
https://android-review.googlesource.com/c/platform/hardware/libhardware/+/571762/).
The work will likely be merged later this year and it is already used
in some devices. Main reason it wasn't merged yet it that in our case
we have multiple evdev devices (gamepad, touchpad, motion sensors) and
need to tie those together for applications. Android doesn't support a
good mechanism for that yet.

Since the IIO input work relates to our Android work as well, I will
jump in more from the sidelines to make sure things are done in a
consistent manner. The main concern are resolution and value ranges.

Thanks,
Roderick

On Sun, Apr 14, 2019 at 4:41 AM Jonathan Cameron <jic23@kernel.org> wrote:
>
> On Mon, 8 Apr 2019 15:15:56 +0200
> H. Nikolaus Schaller <hns@goldelico.com> wrote:
>
> > Hi Jonathan,
> >
> > > Am 07.04.2019 um 14:30 schrieb Jonathan Cameron <jic23@kernel.org>:
> > >
> > > On Sun, 31 Mar 2019 12:09:46 +0200
> > > "H. Nikolaus Schaller" <hns@goldelico.com> wrote:
> > >
> > > Hi Nikolaus,
> > >
> > > I'm probably going to repeat a few things I sent for v1 as the audience has
> > > expanded somewhat!
> > >
> > > Good to see this moving forwards though as there has been at least some demand
> > > for it going way back to the early days of IIO.
> > >
> > >> 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 worries me, as it inherently means we end up with this interface being
> > > registered in cases where it makes no sense.  A lot of generic distros get
> > > used across widely differing use cases.
> >
> > I still do not fully understand what is worrying you here.
>
> >
> > Do you worry about functionality, flexibility or resources or something else?
>
> Two main things:
> 1) Lack of generality of the approach.
>    This is a single use trick for input devices. Why does it make sense for
>    input devices?  There are lots of other in kernel users and potential
>    ones in the future.  The ability to register additional IIO consumers like
>    this is useful, lets make it useful to everyone.
>
> 2) To much generality of the specific usecase.  I don't want to put an Input
>    interface on accelerometers where it makes no sense.  The rule of it has
>    2-3 axis so it must make sense isn't good enough to my mind.  How
>    does userspace know which accelerometer to use (more and more devices have
>    multiple?)  You could do something like looking at the location info from
>    DT / ACPI in your driver and pick the 'best' but that's policy. Should be
>    in userspace.  Sure you can just use the right input driver, but the moment
>    we do that, we need aware userspace, if that's the case why not make it
>    aware from the start.
>
> Believe me I've been round this one a good few times and thought about it
> a lot.  I'll take a lot of convincing that this isn't a problem that
> should be pushed into userspace.
>
> >
> > I think having them mapped always does not need much resources (except a handful of bytes
> > in memory and some µs during probing) unless the event device is opened and really used.
> > Only then it starts e.g. I2C traffic to read the sensors.
>
> The bytes don't really mater. The userspace ABI additions do.
>
> >
> > So it is just some unused file sitting around in /dev. Or 2 or could be even 100.
> > For devices which have no iio accelerometers configured, there will be no /dev/input
> > file. So we are discussing the rare case of devices with more than one or two accelerometers.
>
> Well they aren't exactly rare in IIO using systems ;)
>
> >
> > Now, on every system there are many interfaces and files that are not used because it makes
> > no sense to look at them. If I check on one of my systems, I find for example a lot of
> > /dev/tty and only a very small portion is used and generic distros have no issue with it.
> >
> > There is even /dev/iio:device0 to /dev/iio:device5 representing the raw iio devices.
> > Not all of them are actively used, but they are simply there and can be scanned for.
>
> Agreed, in the ideal case we wouldn't have had that either, but we are
> stuck with it.  The long term plan is to allow use of IIO backends without the
> front end being there at all. Lots of SoC ADC users would prefer this. We are
> stuck with the legacy intertwining fo the front end and back end of IIO so
> this isn't as easy to do as I would like.
>
> >
> > So I do not see a resource problem if every accelerometer /dev/iio:device* gets
> > some companion /dev/input/event* for being used on demand - but only if this bridge
> > is configured at all.
>
> That argument does not apply. If we add a config option, distros will enable it.
> So the vast majority of systems will ship with this turned on.  You cannot
> use a config variable to control policy and expect it to be change by anyone
> but a very very small subset of users.  So please drop the 'you can just not
> build it argument'.
>
> Userspace configuration changing is a lot easier if people actually care.
> Sure, many distros will ship the same script to everyone.
>
> >
> > > I think we need some deliberate userspace interaction to instantiate
> > > one of these rather than 'always doing it'.
> >
> > My gut feeling is that this additional user-space interaction needs more resources and
> > adds a lot of complexity, independently of how it is done.
>
> Trivial resources and actually fairly trivial complexity.  Key thing is
> it puts the burden on the users of this functionality to configure what they
> want.
>
> >
> > And I think is even less flexible than "always doing it". Let me explain this claim.
> >
> > For me, the kernel should present everything the hardware supports to user-space
> > in better digestable device files or APIs (without making any assumptions about the
> > user-space code).
>
> Agreed, we just have a different view on how this should be done. I want
> it to be dynamic and extremely flexible, you want the easy way of just
> putting a fixed set out all the time.
>
> >
> > Then, every user-space that will be installed can find out what the hardware supports
> > by looking at standard places.
> >
> > E.g. it can scan for all mice and keyboards. And for all input accelerometers.
>
> Or, you an have the correct 'fairly trivial' userspace setup to scan for all
> registered accelerometers and 'on demand' create the bindings to bring them up as
> Input accelerometers if that is what makes sense for your platform.
>
> >
> > If the kernel is hiding some chips and needs some initial user-space action before
> > presenting them all, this requires that the user-space has some a-priori knowledge
> > about which specific devices it should ask for.
>
> No more that it needs to know which accelerometer to use?
>
> > So it does not really need to scan
> > for them. Because it must already know. Obviously in some mapping table stored at
> > a well known location inside the rootfs image.
>
> No. Let me give some more details of how this would work.  It's really just
> a more flexible version of what you have.
>
> A distro, or individual user decides to put the relevant script in place for the
> following:
>
> 1. Userspace detects a new accelerometer driver, via the standard methods (uevent)
> 2. Userspace looks to see if it has the required properties. Now this includes things
> like detecting that it is the accelerometer in the lid of a laptop - if so do not
> register it as an input device.  If it's in the keyboard then do register it.
> 3. Userspace script then creates the files in configfs
> /sys/kernel/config/iio/maps/
> (this interface needs appropriate definition)
> Maybe...
> /sys/kernel/config/iio/maps/iio_input/iio_device:X/accel_x, accel_y, etc
> When done it writes to the bind file
> /sys/kernel/config/iio/maps/iio_input/iio_device:X/bind
> which instantiates the input driver.
>
> This moves all of the policy decision into userspace, where it belongs.  If
> we want to enable a particular accelerometer on a particular board because it
> actually works better than the one the default policy says to use, then we can
> do so.
>
> The resulting infrastructure is much more general, because it lets us do the
> same for any IIO consumer.  This input bridge is not a special case. It works
> equally well for the existing hwmon bridge any would even let us do things
> like provide the information from userspace that we have an analog accelerometer
> wired up to an ADC on some hacker board.
>
>
> >
> > This seems to make it impossible to develop a generic distro rootfs image - without
> > asking the user for manual configuration. And that where the kernel already knows
> > this (which iio accelerometers do exist for a specific piece of hardware).
> >
> > This is why I believe a mechanism to instantiate only on demand isn't adding but
> > removing flexibility because it prevents copying a rootfs from one device to another.
>
> I disagree, see above.
>
> >
> > >
> > > As I mentioned in V1, look at the possibility of a configfs based method
> > > to build the map.  It's easy for userspace to work out what makes sense to
> > > map in principle.  There may be some missing info that we also need to
> > > look to expose.
> >
> > With a "may be missing" it is impossible to write code for it...
> > Can you please name which information is missing on the input accelerometer
> > API?
>
> See above. It's not the input accelerometer ABI, it's the missing ability
> to instantiate IIO maps from user space.
>
> >
> > >
> > > In general, userspace created channel maps would be very useful for
> > > other things such as maker type boards where they can plug all sorts
> > > of odd things into ADC channels for example.
> >
> > Ok, I understand, but this is a different problem where this iio-input-bridge is not
> > intended to be a solution. Generic ADCs are not input devices. Like SD cards are not
> > keyboards.
> >
> > So we should not try to mix the idea of general mapping with this input-bridge for
> > input accelerometers.
> Yes we should. You are proposing a solution that is a subset of the larger
> problem set.  Why introduce a stop gap like this when we can do it correctly
> and provide something useful for all those other use cases.
>
> The only difference here is the uevent triggered script that creates those maps
> for your particular usecase.
>
>
> >
> > BTW, there is a way to define additional mapping using udev rules which symlink the
> > /dev/input/event* paths to stable names like /dev/input/accelerometer.
> >
> > This comes without additional code and is already provided by udev and the input system.
> >
> > So in summary, I have not yet seen a convincing scenario where being able to dynamically
> > map iio channels to input devices seems beneficial.
>
> That is true for the narrow case you are talking about. I don't want to see that
> narrow case solved in a fashion that effectively breaks solving it properly.
> If we add this, we have to export all accelerometers for ever under all circumstances
> to userspace, because to remove it will break existing userspace.
>
> If we stand back and work out if we can do the general solution now, we avoid
> this problem.
>
> >
> > >
> > >>
> > >> 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.
> > >
> > > Why do we do this, rather than letting input deal with it?  Input is used
> > > to widely differing scales IIRC
> >
> > Well, it can't be done differently... And what I call scale here is nothing more than
> > defining ABSMIN_ACC_VAL and ABSMAX_ACC_VAL.
> >
> > We need to apply some scale since iio reports in (fractional) units of 1g, i.e. values
> > of magnitude 1.
>
> m/s^2 not g, but doesn't matter for the point of view of this discussion.

m/s^2 is conceptually right, but others have been using 'g' for input,
so I would consider that the standard now. Also leaves handling of
location on Earth to user space instead of assuming a fixed conversion
to 9.81 m/s^2.

> > These are not adaequate for input events which use integers. So we must
> > define some factor for iio_convert_raw_to_processed() to scale from raw value range
> > to int value range. We could report raw values but this would be an improper abstraction
> > from chip specific differences.
>
> Hmm. I can see we perhaps need some mapping, but is there a concept of standard scale
> for existing input accelerometers?  How is this done to give for other input devices
> such as touch screens?  I'd expect to see a separation between scale, and range.
>

We at the time were one of the first to expose acceleration and gyro
data through /dev/input for DualShock 4 as supported by hid-sony. We
report acceleration in 'g' and angular velocity in 'degree / s'. We
set the resolution to respectively '1 g' and '1 degree / s'. The range
we set to the range of the device e.g. for DS4 -4g to +4g for
acceleration. I need to check though what coordinate system we use,
but I think it is right handed (gyro counter clockwise relative to
acceleration axes).

The two other drivers using INPUT_PROC_ACCELEROMETER are hid-wacom and
hid-udraw-ps3 Wacom. Both seem to report resolution in 'g'  as well.

Thanks,
Roderick

^ permalink raw reply

* Re: [RFC v2] iio: input-bridge: optionally bridge iio acceleometers to create a /dev/input interface
From: Jonathan Cameron @ 2019-04-14 11:40 UTC (permalink / raw)
  To: H. Nikolaus Schaller
  Cc: Dmitry Torokhov, Eric Piel, linux-input, letux-kernel, kernel,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
	linux-kernel, linux-iio
In-Reply-To: <CD44AFA0-6676-4842-9C80-61BB363DD556@goldelico.com>

On Mon, 8 Apr 2019 15:15:56 +0200
H. Nikolaus Schaller <hns@goldelico.com> wrote:

> Hi Jonathan,
> 
> > Am 07.04.2019 um 14:30 schrieb Jonathan Cameron <jic23@kernel.org>:
> > 
> > On Sun, 31 Mar 2019 12:09:46 +0200
> > "H. Nikolaus Schaller" <hns@goldelico.com> wrote:
> > 
> > Hi Nikolaus,
> > 
> > I'm probably going to repeat a few things I sent for v1 as the audience has
> > expanded somewhat!
> > 
> > Good to see this moving forwards though as there has been at least some demand
> > for it going way back to the early days of IIO.
> >   
> >> 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 worries me, as it inherently means we end up with this interface being
> > registered in cases where it makes no sense.  A lot of generic distros get
> > used across widely differing use cases.  
> 
> I still do not fully understand what is worrying you here.

> 
> Do you worry about functionality, flexibility or resources or something else?

Two main things:
1) Lack of generality of the approach. 
   This is a single use trick for input devices. Why does it make sense for
   input devices?  There are lots of other in kernel users and potential
   ones in the future.  The ability to register additional IIO consumers like
   this is useful, lets make it useful to everyone.

2) To much generality of the specific usecase.  I don't want to put an Input
   interface on accelerometers where it makes no sense.  The rule of it has
   2-3 axis so it must make sense isn't good enough to my mind.  How
   does userspace know which accelerometer to use (more and more devices have
   multiple?)  You could do something like looking at the location info from
   DT / ACPI in your driver and pick the 'best' but that's policy. Should be
   in userspace.  Sure you can just use the right input driver, but the moment
   we do that, we need aware userspace, if that's the case why not make it
   aware from the start.

Believe me I've been round this one a good few times and thought about it
a lot.  I'll take a lot of convincing that this isn't a problem that
should be pushed into userspace.

> 
> I think having them mapped always does not need much resources (except a handful of bytes
> in memory and some µs during probing) unless the event device is opened and really used.
> Only then it starts e.g. I2C traffic to read the sensors.

The bytes don't really mater. The userspace ABI additions do.

> 
> So it is just some unused file sitting around in /dev. Or 2 or could be even 100.
> For devices which have no iio accelerometers configured, there will be no /dev/input
> file. So we are discussing the rare case of devices with more than one or two accelerometers.

Well they aren't exactly rare in IIO using systems ;)

> 
> Now, on every system there are many interfaces and files that are not used because it makes
> no sense to look at them. If I check on one of my systems, I find for example a lot of
> /dev/tty and only a very small portion is used and generic distros have no issue with it.
> 
> There is even /dev/iio:device0 to /dev/iio:device5 representing the raw iio devices.
> Not all of them are actively used, but they are simply there and can be scanned for.

Agreed, in the ideal case we wouldn't have had that either, but we are
stuck with it.  The long term plan is to allow use of IIO backends without the
front end being there at all. Lots of SoC ADC users would prefer this. We are
stuck with the legacy intertwining fo the front end and back end of IIO so
this isn't as easy to do as I would like.

> 
> So I do not see a resource problem if every accelerometer /dev/iio:device* gets
> some companion /dev/input/event* for being used on demand - but only if this bridge
> is configured at all.

That argument does not apply. If we add a config option, distros will enable it.
So the vast majority of systems will ship with this turned on.  You cannot
use a config variable to control policy and expect it to be change by anyone
but a very very small subset of users.  So please drop the 'you can just not
build it argument'.

Userspace configuration changing is a lot easier if people actually care.
Sure, many distros will ship the same script to everyone.

> 
> > I think we need some deliberate userspace interaction to instantiate
> > one of these rather than 'always doing it'.  
> 
> My gut feeling is that this additional user-space interaction needs more resources and
> adds a lot of complexity, independently of how it is done.

Trivial resources and actually fairly trivial complexity.  Key thing is
it puts the burden on the users of this functionality to configure what they
want.

> 
> And I think is even less flexible than "always doing it". Let me explain this claim.
> 
> For me, the kernel should present everything the hardware supports to user-space
> in better digestable device files or APIs (without making any assumptions about the
> user-space code).

Agreed, we just have a different view on how this should be done. I want
it to be dynamic and extremely flexible, you want the easy way of just
putting a fixed set out all the time.

> 
> Then, every user-space that will be installed can find out what the hardware supports
> by looking at standard places.
> 
> E.g. it can scan for all mice and keyboards. And for all input accelerometers.

Or, you an have the correct 'fairly trivial' userspace setup to scan for all
registered accelerometers and 'on demand' create the bindings to bring them up as
Input accelerometers if that is what makes sense for your platform.

> 
> If the kernel is hiding some chips and needs some initial user-space action before
> presenting them all, this requires that the user-space has some a-priori knowledge
> about which specific devices it should ask for.

No more that it needs to know which accelerometer to use?

> So it does not really need to scan
> for them. Because it must already know. Obviously in some mapping table stored at
> a well known location inside the rootfs image.

No. Let me give some more details of how this would work.  It's really just
a more flexible version of what you have.

A distro, or individual user decides to put the relevant script in place for the
following:

1. Userspace detects a new accelerometer driver, via the standard methods (uevent)
2. Userspace looks to see if it has the required properties. Now this includes things
like detecting that it is the accelerometer in the lid of a laptop - if so do not
register it as an input device.  If it's in the keyboard then do register it.
3. Userspace script then creates the files in configfs
/sys/kernel/config/iio/maps/
(this interface needs appropriate definition)
Maybe...
/sys/kernel/config/iio/maps/iio_input/iio_device:X/accel_x, accel_y, etc
When done it writes to the bind file
/sys/kernel/config/iio/maps/iio_input/iio_device:X/bind
which instantiates the input driver.

This moves all of the policy decision into userspace, where it belongs.  If
we want to enable a particular accelerometer on a particular board because it
actually works better than the one the default policy says to use, then we can
do so.

The resulting infrastructure is much more general, because it lets us do the
same for any IIO consumer.  This input bridge is not a special case. It works
equally well for the existing hwmon bridge any would even let us do things
like provide the information from userspace that we have an analog accelerometer
wired up to an ADC on some hacker board.


> 
> This seems to make it impossible to develop a generic distro rootfs image - without
> asking the user for manual configuration. And that where the kernel already knows
> this (which iio accelerometers do exist for a specific piece of hardware).
> 
> This is why I believe a mechanism to instantiate only on demand isn't adding but
> removing flexibility because it prevents copying a rootfs from one device to another.

I disagree, see above.

> 
> > 
> > As I mentioned in V1, look at the possibility of a configfs based method
> > to build the map.  It's easy for userspace to work out what makes sense to
> > map in principle.  There may be some missing info that we also need to
> > look to expose.  
> 
> With a "may be missing" it is impossible to write code for it...
> Can you please name which information is missing on the input accelerometer
> API?

See above. It's not the input accelerometer ABI, it's the missing ability
to instantiate IIO maps from user space.

> 
> > 
> > In general, userspace created channel maps would be very useful for
> > other things such as maker type boards where they can plug all sorts
> > of odd things into ADC channels for example.  
> 
> Ok, I understand, but this is a different problem where this iio-input-bridge is not
> intended to be a solution. Generic ADCs are not input devices. Like SD cards are not
> keyboards.
> 
> So we should not try to mix the idea of general mapping with this input-bridge for
> input accelerometers.
Yes we should. You are proposing a solution that is a subset of the larger
problem set.  Why introduce a stop gap like this when we can do it correctly
and provide something useful for all those other use cases.

The only difference here is the uevent triggered script that creates those maps
for your particular usecase.


> 
> BTW, there is a way to define additional mapping using udev rules which symlink the
> /dev/input/event* paths to stable names like /dev/input/accelerometer.
> 
> This comes without additional code and is already provided by udev and the input system.
> 
> So in summary, I have not yet seen a convincing scenario where being able to dynamically
> map iio channels to input devices seems beneficial.

That is true for the narrow case you are talking about. I don't want to see that
narrow case solved in a fashion that effectively breaks solving it properly.
If we add this, we have to export all accelerometers for ever under all circumstances
to userspace, because to remove it will break existing userspace.

If we stand back and work out if we can do the general solution now, we avoid
this problem.

> 
> >   
> >> 
> >> 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.  
> > 
> > Why do we do this, rather than letting input deal with it?  Input is used
> > to widely differing scales IIRC  
> 
> Well, it can't be done differently... And what I call scale here is nothing more than
> defining ABSMIN_ACC_VAL and ABSMAX_ACC_VAL.
> 
> We need to apply some scale since iio reports in (fractional) units of 1g, i.e. values
> of magnitude 1.

m/s^2 not g, but doesn't matter for the point of view of this discussion.

> These are not adaequate for input events which use integers. So we must
> define some factor for iio_convert_raw_to_processed() to scale from raw value range
> to int value range. We could report raw values but this would be an improper abstraction
> from chip specific differences.

Hmm. I can see we perhaps need some mapping, but is there a concept of standard scale
for existing input accelerometers?  How is this done to give for other input devices
such as touch screens?  I'd expect to see a separation between scale, and range.


> 
> BTW: the range (and therefore the factor) is reported through the evdev driver to user-space
> (evtest reports Min and Max as you can see in the example).
> 
> The most important thing is that this is a hardware independent definition. Every accelerometer
> chip will report this range. So you can easily upgrade hardware or switch accelerometers
> without touching user-space calibration. Like you can replace ethernet controller chips but
> networking works the same with all of them.

Agreed, it needs to be hardware independent by the time it hits userspace, but I would
have thought that scaling would be done in input, rather than IIO. It's hardly
a problem unique to our usecase!

Perhaps Dmitry can give some advice on this.

> 
> >   
> >> 
> >> 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>
> >> ---
> >> drivers/iio/Kconfig                    |   7 +
> >> drivers/iio/Makefile                   |   1 +
> >> drivers/iio/industrialio-core.c        |  12 +
> >> drivers/iio/industrialio-inputbridge.c | 295 +++++++++++++++++++++++++
> >> drivers/iio/industrialio-inputbridge.h |  28 +++
> >> 5 files changed, 343 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..d85afe002613 100644
> >> --- a/drivers/iio/Kconfig
> >> +++ b/drivers/iio/Kconfig
> >> @@ -68,6 +68,13 @@ config IIO_TRIGGERED_EVENT
> >> 	help
> >> 	  Provides helper functions for setting up triggered events.
> >> 
> >> +config IIO_INPUT_BRIDGE
> >> +	bool "Enable accelerometer bridge to input driver"  
> > 
> > Dependency on input?  
> 
> Yes, should be added.
> 
> >   
> >> +	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);
> >> +  
> > This doesn't look like balanced error handling given the goto in the previous
> > case.  If we are treating this as an error we need to unwind the whole
> > of this function properly.  
> 
> Will to check.
> 
> >   
> >> +		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..dd672e25bc70
> >> --- /dev/null
> >> +++ b/drivers/iio/industrialio-inputbridge.c
> >> @@ -0,0 +1,295 @@
> >> +// 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.  
> > No need for the boiler plate if you have SPDX.  That is one of the
> > advantages!  
> 
> Ok.
> 
> >   
> >> + */
> >> +
> >> +#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 sign = false;
> >> +	bool decimal = false;
> >> +	int32_t divisor = 1;
> >> +
> >> +	if (*str == '-')
> >> +		sign = true, str++;
> >> +	while (*str && 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++;
> >> +	}
> >> +
> >> +	mantissa = (mantissa * unit) / divisor;
> >> +	if (sign)
> >> +		mantissa = -mantissa;
> >> +
> >> +	return mantissa;
> >> +}
> >> +
> >> +static void iio_apply_matrix(struct matrix *m, int *in, int *out, uint32_t 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;
> >> +
> >> +printk("%s: map=%px input=%px\n", __func__, map, input);  
> > Remember to tidy these debug statements up at some point.  
> 
> Oops... Shouldn't be there. Maybe I did squash in some commit from my debugging branch.
> 
> >   
> >> +
> >> +	while (cindex < ARRAY_SIZE(values)) {
> >> +		struct iio_channel *channel =
> >> +			&map->channels[cindex];
> >> +		int val;
> >> +		int ret;
> >> +
> >> +		if (!channel->indio_dev) {
> >> +			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 dindex=0;	/* assign unique names to accel/input devices */  
> > Build something from the iio device IDA perhaps?  Those are unique
> > as well.  Useful to know which one this is linked to.  
> 
> We just use this unique number in the poll_dev->input->phys name.
> Mainly this number gives them unique names in /sys/class/input/input*/phys
>  
> Using the iio device IDA seems to be a very good replacement.
> 
> >   
> >> +
> >> +static int iio_input_register_accel_channel(struct iio_dev *indio_dev,
> >> +		 const struct iio_chan_spec *chan)
> >> +{ /* we found some accelerometer channel */
> >> +	int ret;
> >> +	int cindex;
> >> +	struct iio_input_map *map = iio_device_get_drvdata(indio_dev);  
> > 
> > Don't do that.   That is in the domain of the device driver and so
> > will sometimes already be in use.   
> 
> Hm. Is there an alternative to attach such private data to an struct iio_dev
> allocated by someone else? I have not found one yet.
> 
> Or can I add some void *input_mapping; to struct iio_dev? Depending on
> #if defined(CONFIG_IIO_INPUT_BRIDGE)?

Yes, add a new element.

> 
> >   
> >> +
> >> +printk("%s: map=%px\n", __func__, map);
> >> +
> >> +	if (!map) {
> >> +		struct input_polled_dev *poll_dev;
> >> +		const struct iio_chan_spec_ext_info *ext_info;
> >> +
> >> +		map = devm_kzalloc(&indio_dev->dev, sizeof(struct iio_input_map), GFP_KERNEL);
> >> +		if (!map)
> >> +			return -ENOMEM;
> >> +
> >> +		iio_device_set_drvdata(indio_dev, 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, "accel/input%d",  
> 
> If we use the IDA, we can define phys as "iio:device%d", indio_dev->id)
> which makes it easy to locate the associated iio device file name (although
> there are other mechanisms in sysfs tree).
> 
> >> +						    dindex++);
> >> +
> >> +// 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->ext_info;
> >> +		for (; ext_info && ext_info->name; ext_info++) {
> >> +			if (strcmp(ext_info->name, "mount_matrix") == 0)
> >> +				break;
> >> +		}
> >> +
> >> +		if (ext_info && ext_info->name) {
> >> +			/* matrix found */
> >> +			uintptr_t priv = ext_info->private;
> >> +			const struct iio_mount_matrix *mtx;
> >> +
> >> +			mtx = ((iio_get_mount_matrix_t *) priv)(indio_dev,
> >> +								chan);
> >> +
> >> +			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;
> >> +		}
> >> +	}
> >> +
> >> +// brauchen wir das noch? Oder nehmen wir einfach an dass es 3 Kanäle gibt?
> >> +
> >> +	/* find free channel within this device */
> >> +
> >> +	for (cindex = 0; cindex < ARRAY_SIZE(map->channels); cindex++) {
> >> +		if (!map->channels[cindex].indio_dev)
> >> +			break;
> >> +	}
> >> +
> >> +	/* check if we already have collected enough channels */
> >> +	if (cindex == ARRAY_SIZE(map->channels))
> >> +		return 0;	/* silently ignore */
> >> +
> >> +	map->channels[cindex].indio_dev = indio_dev;
> >> +	map->channels[cindex].channel = chan;
> >> +	map->channels[cindex].data = map;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +int iio_device_register_inputbridge(struct iio_dev *indio_dev)
> >> +{
> >> +	int i;
> >> +
> >> +	for (i = 0; i < indio_dev->num_channels; i++) {
> >> +		const struct iio_chan_spec *chan =
> >> +				&indio_dev->channels[i];
> >> +
> >> +		if (chan->type == IIO_ACCEL) {
> >> +			int r = iio_input_register_accel_channel(indio_dev,
> >> +								 chan);  
> > It would be cleaner (and safer) to go find all the necessary channels then
> > set up the map in one go, rather that iterating and trying to build it
> > in a sequential fashion.
> > 
> > So move the search loop inside and have something like.
> > 
> > iio_input_find_accel_channel(indio_dev, chan, &numchans);
> > iio_input_register_device(indio_dev, chan, numchans);  
> 
> Well, that looks like it needs some temporary storage of dynamic size
> and loop twice over channels for no functional benefit.

Use fixed size. The worst that happens is we end up with it being
an entry larger that it needs to be.

> And handle the
> special case of numchans == 0 (the proposed code simply does not call
> iio_input_register_accel_channel and does not register anything).
> 
> So I'd prefer to follow the "KISS" principle and register single channels
> instead of a set of channels.

Well we disagree on this.  A singleton approach like used here
is to my mind not KISS.  I would rather see what is there then
act as two simple steps, rather than interleave two different
actions with a totally different path for the first channel found.
If there is only one channel you just built a load of infrastructure
that makes no sense.  If you scan first then you can know that
before building anything.


> 
> >   
> >> +
> >> +			if (r < 0)
> >> +				return r;
> >> +		}
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +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;
> >> +
> >> +	kfree(input->name);
> >> +	kfree(input->phys);
> >> +	input_unregister_polled_device(map->poll_dev);
> >> +}
> >> +
> >> +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  
> >   
> 
> BR and thanks,
> Nikolaus
> 
Thanks,

Jonathan

^ permalink raw reply

* [PATCH] HID: fix compiling error in u2fzero_probe()
From: Mao Wenan @ 2019-04-13 13:44 UTC (permalink / raw)
  To: jikos, benjamin.tissoires, maowenan
  Cc: linux-input, linux-kernel, kernel-janitors, Hulk Robot

There is one compiling error in u2fzero_probe()->u2fzero_init_hwrng(),
this is because HW_RANDOM is not set.

drivers/hid/hid-u2fzero.o: In function `u2fzero_probe':
hid-u2fzero.c:(.text+0xc70): undefined reference to `devm_hwrng_register'

Fixes: 42337b9d4d958("HID: add driver for U2F Zero built-in LED and RNG")
Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: Mao Wenan <maowenan@huawei.com>
---
 drivers/hid/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 4dc1035..76d8206 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -1017,6 +1017,7 @@ config HID_U2FZERO
 	tristate "U2F Zero LED and RNG support"
 	depends on USB_HID
 	depends on LEDS_CLASS
+	depends on HW_RANDOM
 	help
 	  Support for the LED of the U2F Zero device.
 
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH] ELAN touchpad i2c_hid bugs fix
From: Kai-Heng Feng @ 2019-04-13  8:42 UTC (permalink / raw)
  To: hotwater438
  Cc: Hans de Goede, Dmitry Torokhov, Vladislav Dalechyn,
	Benjamin Tissoires, Jiri Kosina, Swboyd, Bigeasy,
	open list:HID CORE LAYER, lkml
In-Reply-To: <LcKqhgD--3-1@tutanota.com>

at 16:40, <hotwater438@tutanota.com> <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:
> Hi,
>
> at 05:18, <hotwater438@tutanota.com> <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:
> Hi,
>
> On 31-03-19 11:50, 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 v3 2/3] Input: add a driver for GPIO controllable vibrators
From: Stephen Boyd @ 2019-04-12 17:43 UTC (permalink / raw)
  To: Luca Weiss
  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: <20190412150625.28384-2-luca@z3ntu.xyz>

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.

> +               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.

> +};
> +MODULE_DEVICE_TABLE(of, gpio_vibra_dt_match_table);
> +#endif
> +

^ permalink raw reply

* [PATCH v3 3/3] ARM: dts: msm8974-FP2: Add vibration motor
From: Luca Weiss @ 2019-04-12 15:06 UTC (permalink / raw)
  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, Luca Weiss
In-Reply-To: <20190412150625.28384-1-luca@z3ntu.xyz>

Signed-off-by: Luca Weiss <luca@z3ntu.xyz>
---
 arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts b/arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts
index 643c57f84818..bf402ae39226 100644
--- a/arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts
+++ b/arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts
@@ -50,6 +50,12 @@
 		};
 	};
 
+	vibrator {
+		compatible = "gpio-vibrator";
+		enable-gpios = <&msmgpio 86 GPIO_ACTIVE_HIGH>;
+		vcc-supply = <&pm8941_l18>;
+	};
+
 	smd {
 		rpm {
 			rpm_requests {
-- 
2.21.0

^ permalink raw reply related

* [PATCH v3 2/3] Input: add a driver for GPIO controllable vibrators
From: Luca Weiss @ 2019-04-12 15:06 UTC (permalink / raw)
  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, Luca Weiss
In-Reply-To: <20190412150625.28384-1-luca@z3ntu.xyz>

Provide a simple driver for GPIO controllable vibrators.
It will be used by the Fairphone 2.

Signed-off-by: Luca Weiss <luca@z3ntu.xyz>
---
 drivers/input/misc/Kconfig      |  12 ++
 drivers/input/misc/Makefile     |   1 +
 drivers/input/misc/gpio-vibra.c | 209 ++++++++++++++++++++++++++++++++
 3 files changed, 222 insertions(+)
 create mode 100644 drivers/input/misc/gpio-vibra.c

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index e15ed1bb8558..6dfe9e2fe5b1 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -290,6 +290,18 @@ config INPUT_GPIO_DECODER
 	 To compile this driver as a module, choose M here: the module
 	 will be called gpio_decoder.
 
+config INPUT_GPIO_VIBRA
+	tristate "GPIO vibrator support"
+	depends on GPIOLIB || COMPILE_TEST
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y here to get support for GPIO based vibrator devices.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called gpio-vibra.
+
 config INPUT_IXP4XX_BEEPER
 	tristate "IXP4XX Beeper support"
 	depends on ARCH_IXP4XX
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index b936c5b1d4ac..f38ebbdb05e2 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS)	+= drv2667.o
 obj-$(CONFIG_INPUT_GP2A)		+= gp2ap002a00f.o
 obj-$(CONFIG_INPUT_GPIO_BEEPER)		+= gpio-beeper.o
 obj-$(CONFIG_INPUT_GPIO_DECODER)	+= gpio_decoder.o
+obj-$(CONFIG_INPUT_GPIO_VIBRA)		+= gpio-vibra.o
 obj-$(CONFIG_INPUT_HISI_POWERKEY)	+= hisi_powerkey.o
 obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IMS_PCU)		+= ims-pcu.o
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 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  GPIO vibrator driver
+ *
+ *  Copyright (C) 2019 Luca Weiss <luca@z3ntu.xyz>
+ *
+ *  Based on PWM vibrator driver:
+ *  Copyright (C) 2017 Collabora Ltd.
+ *
+ *  Based on previous work from:
+ *  Copyright (C) 2012 Dmitry Torokhov <dmitry.torokhov@gmail.com>
+ *
+ *  Based on PWM beeper driver:
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+struct gpio_vibrator {
+	struct input_dev *input;
+	struct gpio_desc *gpio;
+	struct regulator *vcc;
+
+	struct work_struct play_work;
+	bool running;
+	bool vcc_on;
+};
+
+static int gpio_vibrator_start(struct gpio_vibrator *vibrator)
+{
+	struct device *pdev = vibrator->input->dev.parent;
+	int err;
+
+	if (!vibrator->vcc_on) {
+		err = regulator_enable(vibrator->vcc);
+		if (err) {
+			dev_err(pdev, "failed to enable regulator: %d", err);
+			return err;
+		}
+		vibrator->vcc_on = true;
+	}
+
+	gpiod_set_value_cansleep(vibrator->gpio, 1);
+
+	return 0;
+}
+
+static void gpio_vibrator_stop(struct gpio_vibrator *vibrator)
+{
+	gpiod_set_value_cansleep(vibrator->gpio, 0);
+
+	if (vibrator->vcc_on) {
+		regulator_disable(vibrator->vcc);
+		vibrator->vcc_on = false;
+	}
+}
+
+static void gpio_vibrator_play_work(struct work_struct *work)
+{
+	struct gpio_vibrator *vibrator =
+		container_of(work, struct gpio_vibrator, play_work);
+
+	if (vibrator->running)
+		gpio_vibrator_start(vibrator);
+	else
+		gpio_vibrator_stop(vibrator);
+}
+
+static int gpio_vibrator_play_effect(struct input_dev *dev, void *data,
+				     struct ff_effect *effect)
+{
+	struct gpio_vibrator *vibrator = input_get_drvdata(dev);
+
+	int level = effect->u.rumble.strong_magnitude;
+
+	if (!level)
+		level = effect->u.rumble.weak_magnitude;
+
+	if (level)
+		vibrator->running = true;
+	else
+		vibrator->running = false;
+
+	schedule_work(&vibrator->play_work);
+
+	return 0;
+}
+
+static void gpio_vibrator_close(struct input_dev *input)
+{
+	struct gpio_vibrator *vibrator = input_get_drvdata(input);
+
+	cancel_work_sync(&vibrator->play_work);
+	gpio_vibrator_stop(vibrator);
+	vibrator->running = false;
+}
+
+static int gpio_vibrator_probe(struct platform_device *pdev)
+{
+	struct gpio_vibrator *vibrator;
+	int err;
+
+	vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
+	if (!vibrator)
+		return -ENOMEM;
+
+	vibrator->input = devm_input_allocate_device(&pdev->dev);
+	if (!vibrator->input)
+		return -ENOMEM;
+
+	vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
+	err = PTR_ERR_OR_ZERO(vibrator->vcc);
+	if (err) {
+		if (err != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Failed to request regulator: %d",
+				err);
+		return err;
+	}
+
+	vibrator->gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW);
+	err = PTR_ERR_OR_ZERO(vibrator->gpio);
+	if (err) {
+		if (err != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Failed to request main gpio: %d",
+				err);
+		return err;
+	}
+
+	INIT_WORK(&vibrator->play_work, gpio_vibrator_play_work);
+
+	vibrator->input->name = "gpio-vibrator";
+	vibrator->input->id.bustype = BUS_HOST;
+	vibrator->input->close = gpio_vibrator_close;
+
+	input_set_drvdata(vibrator->input, vibrator);
+	input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
+
+	err = input_ff_create_memless(vibrator->input, NULL,
+				      gpio_vibrator_play_effect);
+	if (err) {
+		dev_err(&pdev->dev, "Couldn't create FF dev: %d", err);
+		return err;
+	}
+
+	err = input_register_device(vibrator->input);
+	if (err) {
+		dev_err(&pdev->dev, "Couldn't register input dev: %d", err);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, vibrator);
+
+	return 0;
+}
+
+static int __maybe_unused gpio_vibrator_suspend(struct device *dev)
+{
+	struct gpio_vibrator *vibrator = dev_get_drvdata(dev);
+
+	cancel_work_sync(&vibrator->play_work);
+	if (vibrator->running)
+		gpio_vibrator_stop(vibrator);
+
+	return 0;
+}
+
+static int __maybe_unused gpio_vibrator_resume(struct device *dev)
+{
+	struct gpio_vibrator *vibrator = dev_get_drvdata(dev);
+
+	if (vibrator->running)
+		gpio_vibrator_start(vibrator);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(gpio_vibrator_pm_ops,
+			 gpio_vibrator_suspend, gpio_vibrator_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id gpio_vibra_dt_match_table[] = {
+	{ .compatible = "gpio-vibrator" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, gpio_vibra_dt_match_table);
+#endif
+
+static struct platform_driver gpio_vibrator_driver = {
+	.probe	= gpio_vibrator_probe,
+	.driver	= {
+		.name	= "gpio-vibrator",
+		.pm	= &gpio_vibrator_pm_ops,
+		.of_match_table = of_match_ptr(gpio_vibra_dt_match_table),
+	},
+};
+module_platform_driver(gpio_vibrator_driver);
+
+MODULE_AUTHOR("Luca Weiss <luca@z3ntu.xy>");
+MODULE_DESCRIPTION("GPIO vibrator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-vibrator");
-- 
2.21.0

^ permalink raw reply related

* [PATCH v3 1/3] dt-bindings: input: add GPIO controllable vibrator
From: Luca Weiss @ 2019-04-12 15:06 UTC (permalink / raw)
  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, Luca Weiss

Provide a simple driver for GPIO controllable vibrators.
It will be used by the Fairphone 2.

Signed-off-by: Luca Weiss <luca@z3ntu.xyz>
---
 .../bindings/input/gpio-vibrator.txt          | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/gpio-vibrator.txt

diff --git a/Documentation/devicetree/bindings/input/gpio-vibrator.txt b/Documentation/devicetree/bindings/input/gpio-vibrator.txt
new file mode 100644
index 000000000000..93e5a8e7622d
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/gpio-vibrator.txt
@@ -0,0 +1,20 @@
+* GPIO vibrator device tree bindings
+
+Registers a GPIO device as vibrator, where the vibration motor just has the
+capability to turn on or off. If the device is connected to a pwm, you should
+use the pwm-vibrator driver instead.
+
+Required properties:
+- compatible: should contain "gpio-vibrator"
+- enable-gpios: Should contain a GPIO handle
+
+Optional properties:
+- vcc-supply: Phandle for the regulator supplying power
+
+Example from Fairphone 2:
+
+vibrator {
+	compatible = "gpio-vibrator";
+	enable-gpios = <&msmgpio 86 GPIO_ACTIVE_HIGH>;
+	vcc-supply = <&pm8941_l18>;
+};
-- 
2.21.0

^ permalink raw reply related

* [PATCH] HID: rmi: fix devm_add_action_or_reset() parameter
From: Fabien Dessenne @ 2019-04-12 12:54 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires, linux-input, linux-kernel
  Cc: Fabien Dessenne

The second parameter of devm_add_action_or_reset() shall be a function,
not a function address.

Signed-off-by: Fabien Dessenne <fabien.dessenne@st.com>
---
 drivers/hid/hid-rmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 9e33165..8748d4d 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -623,7 +623,7 @@ static int rmi_setup_irq_domain(struct hid_device *hdev)
 	if (!hdata->domain)
 		return -ENOMEM;
 
-	ret = devm_add_action_or_reset(&hdev->dev, &rmi_irq_teardown, hdata);
+	ret = devm_add_action_or_reset(&hdev->dev, rmi_irq_teardown, hdata);
 	if (ret)
 		return ret;
 
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v2 3/4] MIPS: SGI-IP27: fix readb/writeb addressing
From: Alexandre Belloni @ 2019-04-11 21:17 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	Lee Jones, David S. Miller, Alessandro Zummo, Greg Kroah-Hartman,
	Jiri Slaby, linux-mips, linux-kernel, linux-input, netdev,
	linux-rtc, linux-serial
In-Reply-To: <20190409154610.6735-4-tbogendoerfer@suse.de>

On 09/04/2019 17:46:07+0200, Thomas Bogendoerfer wrote:
> Our chosen byte swapping, which is what firmware already uses, is to
> do readl/writel by normal lw/sw intructions (data invariance). This
> also means we need to mangle addresses for u8 and u16 accesses. The
> mangling for 16bit has been done aready, but 8bit one was missing.
> Correcting this causes different addresses for accesses to the
> SuperIO and local bus of the IOC3 chip. This is fixed by changing
> byte order in ioc3 and m48rtc_rtc structs.
> 
> Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>

Considering this is probably the only platform to have that RTC and that
is probably not worth having a better fix for a platform this old:

Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

> ---
>  arch/mips/include/asm/mach-ip27/mangle-port.h |   2 +-
>  arch/mips/include/asm/sn/ioc3.h               | 198 +++++++++++++-------------
>  arch/mips/sgi-ip27/ip27-console.c             |   5 +-
>  drivers/rtc/rtc-m48t35.c                      |  11 ++
>  drivers/tty/serial/8250/8250_ioc3.c           |   4 +-
>  5 files changed, 114 insertions(+), 106 deletions(-)
> 
> diff --git a/arch/mips/include/asm/mach-ip27/mangle-port.h b/arch/mips/include/asm/mach-ip27/mangle-port.h
> index f6e4912ea062..7771ae0f3971 100644
> --- a/arch/mips/include/asm/mach-ip27/mangle-port.h
> +++ b/arch/mips/include/asm/mach-ip27/mangle-port.h
> @@ -8,7 +8,7 @@
>  #ifndef __ASM_MACH_IP27_MANGLE_PORT_H
>  #define __ASM_MACH_IP27_MANGLE_PORT_H
>  
> -#define __swizzle_addr_b(port)	(port)
> +#define __swizzle_addr_b(port)	((port) ^ 3)
>  #define __swizzle_addr_w(port)	((port) ^ 2)
>  #define __swizzle_addr_l(port)	(port)
>  #define __swizzle_addr_q(port)	(port)
> diff --git a/arch/mips/include/asm/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h
> index 69069f420930..059885d736de 100644
> --- a/arch/mips/include/asm/sn/ioc3.h
> +++ b/arch/mips/include/asm/sn/ioc3.h
> @@ -10,35 +10,35 @@
>  
>  /* serial port register map */
>  struct ioc3_serialregs {
> -	uint32_t	sscr;
> -	uint32_t	stpir;
> -	uint32_t	stcir;
> -	uint32_t	srpir;
> -	uint32_t	srcir;
> -	uint32_t	srtr;
> -	uint32_t	shadow;
> +	u32	sscr;
> +	u32	stpir;
> +	u32	stcir;
> +	u32	srpir;
> +	u32	srcir;
> +	u32	srtr;
> +	u32	shadow;
>  };
>  
>  /* SUPERIO uart register map */
>  struct ioc3_uartregs {
> +	u8	iu_lcr;
>  	union {
> -		char	rbr;	/* read only, DLAB == 0 */
> -		char	thr;	/* write only, DLAB == 0 */
> -		char	dll;	/* DLAB == 1 */
> -	} u1;
> +		u8	iir;	/* read only */
> +		u8	fcr;	/* write only */
> +	};
>  	union {
> -		char	ier;	/* DLAB == 0 */
> -		char	dlm;	/* DLAB == 1 */
> -	} u2;
> +		u8	ier;	/* DLAB == 0 */
> +		u8	dlm;	/* DLAB == 1 */
> +	};
>  	union {
> -		char	iir;	/* read only */
> -		char	fcr;	/* write only */
> -	} u3;
> -	char	iu_lcr;
> -	char	iu_mcr;
> -	char	iu_lsr;
> -	char	iu_msr;
> -	char	iu_scr;
> +		u8	rbr;	/* read only, DLAB == 0 */
> +		u8	thr;	/* write only, DLAB == 0 */
> +		u8	dll;	/* DLAB == 1 */
> +	} u1;
> +	u8	iu_scr;
> +	u8	iu_msr;
> +	u8	iu_lsr;
> +	u8	iu_mcr;
>  };
>  
>  #define iu_rbr u1.rbr
> @@ -50,122 +50,122 @@ struct ioc3_uartregs {
>  #define iu_fcr u3.fcr
>  
>  struct ioc3_sioregs {
> -	char	fill[0x141];	/* starts at 0x141 */
> +	u8	fill[0x141];	/* starts at 0x141 */
>  
> -	char	uartc;
> -	char	kbdcg;
> +	u8	kbdcg;
> +	u8	uartc;
>  
> -	char	fill0[0x150 - 0x142 - 1];
> +	u8	fill0[0x151 - 0x142 - 1];
>  
> -	char	pp_data;
> -	char	pp_dsr;
> -	char	pp_dcr;
> +	u8	pp_dcr;
> +	u8	pp_dsr;
> +	u8	pp_data;
>  
> -	char	fill1[0x158 - 0x152 - 1];
> +	u8	fill1[0x159 - 0x153 - 1];
>  
> -	char	pp_fifa;
> -	char	pp_cfgb;
> -	char	pp_ecr;
> +	u8	pp_ecr;
> +	u8	pp_cfgb;
> +	u8	pp_fifa;
>  
> -	char	fill2[0x168 - 0x15a - 1];
> +	u8	fill2[0x16a - 0x15b - 1];
>  
> -	char	rtcad;
> -	char	rtcdat;
> +	u8	rtcdat;
> +	u8	rtcad;
>  
> -	char	fill3[0x170 - 0x169 - 1];
> +	u8	fill3[0x170 - 0x16b - 1];
>  
>  	struct ioc3_uartregs	uartb;	/* 0x20170  */
>  	struct ioc3_uartregs	uarta;	/* 0x20178  */
>  };
>  
>  struct ioc3_ethregs {
> -	uint32_t	emcr;		/* 0x000f0  */
> -	uint32_t	eisr;		/* 0x000f4  */
> -	uint32_t	eier;		/* 0x000f8  */
> -	uint32_t	ercsr;		/* 0x000fc  */
> -	uint32_t	erbr_h;		/* 0x00100  */
> -	uint32_t	erbr_l;		/* 0x00104  */
> -	uint32_t	erbar;		/* 0x00108  */
> -	uint32_t	ercir;		/* 0x0010c  */
> -	uint32_t	erpir;		/* 0x00110  */
> -	uint32_t	ertr;		/* 0x00114  */
> -	uint32_t	etcsr;		/* 0x00118  */
> -	uint32_t	ersr;		/* 0x0011c  */
> -	uint32_t	etcdc;		/* 0x00120  */
> -	uint32_t	ebir;		/* 0x00124  */
> -	uint32_t	etbr_h;		/* 0x00128  */
> -	uint32_t	etbr_l;		/* 0x0012c  */
> -	uint32_t	etcir;		/* 0x00130  */
> -	uint32_t	etpir;		/* 0x00134  */
> -	uint32_t	emar_h;		/* 0x00138  */
> -	uint32_t	emar_l;		/* 0x0013c  */
> -	uint32_t	ehar_h;		/* 0x00140  */
> -	uint32_t	ehar_l;		/* 0x00144  */
> -	uint32_t	micr;		/* 0x00148  */
> -	uint32_t	midr_r;		/* 0x0014c  */
> -	uint32_t	midr_w;		/* 0x00150  */
> +	u32	emcr;		/* 0x000f0  */
> +	u32	eisr;		/* 0x000f4  */
> +	u32	eier;		/* 0x000f8  */
> +	u32	ercsr;		/* 0x000fc  */
> +	u32	erbr_h;		/* 0x00100  */
> +	u32	erbr_l;		/* 0x00104  */
> +	u32	erbar;		/* 0x00108  */
> +	u32	ercir;		/* 0x0010c  */
> +	u32	erpir;		/* 0x00110  */
> +	u32	ertr;		/* 0x00114  */
> +	u32	etcsr;		/* 0x00118  */
> +	u32	ersr;		/* 0x0011c  */
> +	u32	etcdc;		/* 0x00120  */
> +	u32	ebir;		/* 0x00124  */
> +	u32	etbr_h;		/* 0x00128  */
> +	u32	etbr_l;		/* 0x0012c  */
> +	u32	etcir;		/* 0x00130  */
> +	u32	etpir;		/* 0x00134  */
> +	u32	emar_h;		/* 0x00138  */
> +	u32	emar_l;		/* 0x0013c  */
> +	u32	ehar_h;		/* 0x00140  */
> +	u32	ehar_l;		/* 0x00144  */
> +	u32	micr;		/* 0x00148  */
> +	u32	midr_r;		/* 0x0014c  */
> +	u32	midr_w;		/* 0x00150  */
>  };
>  
>  struct ioc3_serioregs {
> -	uint32_t	km_csr;		/* 0x0009c  */
> -	uint32_t	k_rd;		/* 0x000a0  */
> -	uint32_t	m_rd;		/* 0x000a4  */
> -	uint32_t	k_wd;		/* 0x000a8  */
> -	uint32_t	m_wd;		/* 0x000ac  */
> +	u32	km_csr;		/* 0x0009c  */
> +	u32	k_rd;		/* 0x000a0  */
> +	u32	m_rd;		/* 0x000a4  */
> +	u32	k_wd;		/* 0x000a8  */
> +	u32	m_wd;		/* 0x000ac  */
>  };
>  
>  /* Register layout of IOC3 in configuration space.  */
>  struct ioc3 {
>  	/* PCI Config Space registers  */
> -	uint32_t	pci_id;		/* 0x00000  */
> -	uint32_t	pci_scr;	/* 0x00004  */
> -	uint32_t	pci_rev;	/* 0x00008  */
> -	uint32_t	pci_lat;	/* 0x0000c  */
> -	uint32_t	pci_addr;	/* 0x00010  */
> -	uint32_t	pci_err_addr_l;	/* 0x00014  */
> -	uint32_t	pci_err_addr_h;	/* 0x00018  */
> -
> -	uint32_t	sio_ir;		/* 0x0001c  */
> -	uint32_t	sio_ies;	/* 0x00020  */
> -	uint32_t	sio_iec;	/* 0x00024  */
> -	uint32_t	sio_cr;		/* 0x00028  */
> -	uint32_t	int_out;	/* 0x0002c  */
> -	uint32_t	mcr;		/* 0x00030  */
> +	u32	pci_id;		/* 0x00000  */
> +	u32	pci_scr;	/* 0x00004  */
> +	u32	pci_rev;	/* 0x00008  */
> +	u32	pci_lat;	/* 0x0000c  */
> +	u32	pci_addr;	/* 0x00010  */
> +	u32	pci_err_addr_l;	/* 0x00014  */
> +	u32	pci_err_addr_h;	/* 0x00018  */
> +
> +	u32	sio_ir;		/* 0x0001c  */
> +	u32	sio_ies;	/* 0x00020  */
> +	u32	sio_iec;	/* 0x00024  */
> +	u32	sio_cr;		/* 0x00028  */
> +	u32	int_out;	/* 0x0002c  */
> +	u32	mcr;		/* 0x00030  */
>  
>  	/* General Purpose I/O registers  */
> -	uint32_t	gpcr_s;		/* 0x00034  */
> -	uint32_t	gpcr_c;		/* 0x00038  */
> -	uint32_t	gpdr;		/* 0x0003c  */
> -	uint32_t	gppr[16];	/* 0x00040  */
> +	u32	gpcr_s;		/* 0x00034  */
> +	u32	gpcr_c;		/* 0x00038  */
> +	u32	gpdr;		/* 0x0003c  */
> +	u32	gppr[16];	/* 0x00040  */
>  
>  	/* Parallel Port Registers  */
> -	uint32_t	ppbr_h_a;	/* 0x00080  */
> -	uint32_t	ppbr_l_a;	/* 0x00084  */
> -	uint32_t	ppcr_a;		/* 0x00088  */
> -	uint32_t	ppcr;		/* 0x0008c  */
> -	uint32_t	ppbr_h_b;	/* 0x00090  */
> -	uint32_t	ppbr_l_b;	/* 0x00094  */
> -	uint32_t	ppcr_b;		/* 0x00098  */
> +	u32	ppbr_h_a;	/* 0x00080  */
> +	u32	ppbr_l_a;	/* 0x00084  */
> +	u32	ppcr_a;		/* 0x00088  */
> +	u32	ppcr;		/* 0x0008c  */
> +	u32	ppbr_h_b;	/* 0x00090  */
> +	u32	ppbr_l_b;	/* 0x00094  */
> +	u32	ppcr_b;		/* 0x00098  */
>  
>  	/* Keyboard and Mouse Registers	 */
>  	struct ioc3_serioregs	serio;
>  
>  	/* Serial Port Registers  */
> -	uint32_t	sbbr_h;		/* 0x000b0  */
> -	uint32_t	sbbr_l;		/* 0x000b4  */
> +	u32	sbbr_h;		/* 0x000b0  */
> +	u32	sbbr_l;		/* 0x000b4  */
>  	struct ioc3_serialregs	port_a;
>  	struct ioc3_serialregs	port_b;
>  
>  	/* Ethernet Registers */
>  	struct ioc3_ethregs	eth;
> -	uint32_t	pad1[(0x20000 - 0x00154) / 4];
> +	u32	pad1[(0x20000 - 0x00154) / 4];
>  
>  	/* SuperIO Registers  XXX */
>  	struct ioc3_sioregs	sregs;	/* 0x20000 */
> -	uint32_t	pad2[(0x40000 - 0x20180) / 4];
> +	u32	pad2[(0x40000 - 0x20180) / 4];
>  
>  	/* SSRAM Diagnostic Access */
> -	uint32_t	ssram[(0x80000 - 0x40000) / 4];
> +	u32	ssram[(0x80000 - 0x40000) / 4];
>  
>  	/* Bytebus device offsets
>  	   0x80000 -   Access to the generic devices selected with   DEV0
> @@ -598,8 +598,4 @@ struct ioc3_etxd {
>  
>  #define MIDR_DATA_MASK		0x0000ffff
>  
> -#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP30)
> -extern int bridge_alloc_irq(struct pci_dev *dev);
> -#endif
> -
>  #endif /* MIPS_SN_IOC3_H */
> diff --git a/arch/mips/sgi-ip27/ip27-console.c b/arch/mips/sgi-ip27/ip27-console.c
> index 6bdb48d41276..5886bee89d06 100644
> --- a/arch/mips/sgi-ip27/ip27-console.c
> +++ b/arch/mips/sgi-ip27/ip27-console.c
> @@ -35,6 +35,7 @@ void prom_putchar(char c)
>  {
>  	struct ioc3_uartregs *uart = console_uart();
>  
> -	while ((uart->iu_lsr & 0x20) == 0);
> -	uart->iu_thr = c;
> +	while ((readb(&uart->iu_lsr) & 0x20) == 0)
> +		;
> +	writeb(c, &uart->iu_thr);
>  }
> diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
> index 0cf6507de3c7..05f0d91366af 100644
> --- a/drivers/rtc/rtc-m48t35.c
> +++ b/drivers/rtc/rtc-m48t35.c
> @@ -24,6 +24,16 @@
>  
>  struct m48t35_rtc {
>  	u8	pad[0x7ff8];    /* starts at 0x7ff8 */
> +#ifdef CONFIG_SGI_IP27
> +	u8	hour;
> +	u8	min;
> +	u8	sec;
> +	u8	control;
> +	u8	year;
> +	u8	month;
> +	u8	date;
> +	u8	day;
> +#else
>  	u8	control;
>  	u8	sec;
>  	u8	min;
> @@ -32,6 +42,7 @@ struct m48t35_rtc {
>  	u8	date;
>  	u8	month;
>  	u8	year;
> +#endif
>  };
>  
>  #define M48T35_RTC_SET		0x80
> diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
> index 2be6ed2967e0..4c405f1b9c67 100644
> --- a/drivers/tty/serial/8250/8250_ioc3.c
> +++ b/drivers/tty/serial/8250/8250_ioc3.c
> @@ -23,12 +23,12 @@ struct ioc3_8250_data {
>  
>  static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
>  {
> -	return readb(p->membase + offset);
> +	return readb(p->membase + (offset ^ 3));
>  }
>  
>  static void ioc3_serial_out(struct uart_port *p, int offset, int value)
>  {
> -	writeb(value, p->membase + offset);
> +	writeb(value, p->membase + (offset ^ 3));
>  }
>  
>  static int serial8250_ioc3_probe(struct platform_device *pdev)
> -- 
> 2.13.7
> 

-- 
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply

* Re: [PATCH v8 02/11] dt-bindings: power: supply: add DT bindings for max77650
From: Rob Herring @ 2019-04-11 16:50 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Mark Rutland, Linus Walleij, Dmitry Torokhov, Jacek Anaszewski,
	Pavel Machek, Lee Jones, Sebastian Reichel, Liam Girdwood,
	Greg Kroah-Hartman, Linux Kernel Mailing List,
	open list:GPIO SUBSYSTEM, devicetree, Linux Input,
	Linux LED Subsystem, Linux PM list, Bartosz Golaszewski
In-Reply-To: <CAMRc=MfkdBMmhrCM7Ut8ZGkgT=gFTRrbgFmu3MbghGwCRkEEKg@mail.gmail.com>

On Tue, Apr 9, 2019 at 10:38 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> wt., 9 kwi 2019 o 13:04 Bartosz Golaszewski <brgl@bgdev.pl> napisał(a):
> >
> > wt., 9 kwi 2019 o 03:10 Rob Herring <robh@kernel.org> napisał(a):
> > >
> > > On Mon, Apr 8, 2019 at 7:25 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > > >
> > > > sob., 6 kwi 2019 o 09:07 Rob Herring <robh@kernel.org> napisał(a):
> > > > >
> > > > > On Wed, Apr 03, 2019 at 11:00:59AM +0200, Bartosz Golaszewski wrote:
> > > > > > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > > > > >
> > > > > > Add the DT binding document for the battery charger module of max77650.
> > > > > >
> > > > > > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > > > > > ---
> > > > > >  .../power/supply/max77650-charger.txt         | 27 +++++++++++++++++++
> > > > > >  1 file changed, 27 insertions(+)
> > > > > >  create mode 100644 Documentation/devicetree/bindings/power/supply/max77650-charger.txt
> > > > > >
> > > > > > diff --git a/Documentation/devicetree/bindings/power/supply/max77650-charger.txt b/Documentation/devicetree/bindings/power/supply/max77650-charger.txt
> > > > > > new file mode 100644
> > > > > > index 000000000000..fef188144386
> > > > > > --- /dev/null
> > > > > > +++ b/Documentation/devicetree/bindings/power/supply/max77650-charger.txt
> > > > > > @@ -0,0 +1,27 @@
> > > > > > +Battery charger driver for MAX77650 PMIC from Maxim Integrated.
> > > > > > +
> > > > > > +This module is part of the MAX77650 MFD device. For more details
> > > > > > +see Documentation/devicetree/bindings/mfd/max77650.txt.
> > > > > > +
> > > > > > +The charger is represented as a sub-node of the PMIC node on the device tree.
> > > > > > +
> > > > > > +Required properties:
> > > > > > +--------------------
> > > > > > +- compatible:                Must be "maxim,max77650-charger"
> > > > > > +
> > > > > > +Optional properties:
> > > > > > +--------------------
> > > > > > +- min-microvolt:     Minimum CHGIN regulation voltage (in microvolts). Must be
> > > > > > +                     one of: 4000000, 4100000, 4200000, 4300000, 4400000,
> > > > > > +                     4500000, 4600000, 4700000.
> > > > > > +- current-limit-microamp:    CHGIN input current limit (in microamps). Must
> > > > > > +                             be one of: 95000, 190000, 285000, 380000, 475000.
> > > > >
> > > > > To repeat what I said on v6, these should be common properties IMO (and
> > > > > therefore documented as such).
> > > > >
> > > >
> > > > Do you mean a separate "charger.txt" document in
> > > > Documentation/devicetree/bindings/power/supply/?
> > >
> > > Yes, though I thought we had something already.
> > >
> > > Rob
> >
> > We don't AFAICT. There's only a binding document for "simple-battery"
> > in power supply.
> >
> > Bart
>
> Can we have it locally for now but without the maxim prefix and then
> reuse it if any other charger needs such functionality? To make it
> even more generic we can name it: "input-voltage-min-microvolt" &
> "input-current-limit-microamp".

I guess. And defining these as 'input' is good because we do have
similar property names already for battery current limit and voltages.

Rob

^ permalink raw reply

* Re: [PATCH] ELAN touchpad i2c_hid bugs fix
From: Kai-Heng Feng @ 2019-04-11 16:17 UTC (permalink / raw)
  To: hotwater438
  Cc: Hans de Goede, Dmitry Torokhov, Vladislav Dalechyn,
	Benjamin Tissoires, Jiri Kosina, Swboyd, Bigeasy,
	open list:HID CORE LAYER, lkml
In-Reply-To: <LbZjy9p--3-1@tutanota.com>

Hi,

at 05:18, <hotwater438@tutanota.com> <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:
> Hi,
>
> On 31-03-19 11:50, 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 related

* Re: linux-next: Tree for Apr 11 (drivers/hid/hid-u2fzero.c)
From: Randy Dunlap @ 2019-04-11 15:52 UTC (permalink / raw)
  To: Stephen Rothwell, Linux Next Mailing List
  Cc: Linux Kernel Mailing List, Andrej Shadura,
	linux-input@vger.kernel.org
In-Reply-To: <20190411164912.5168be0d@canb.auug.org.au>

[-- Attachment #1: Type: text/plain, Size: 216 bytes --]

On 4/10/19 11:49 PM, Stephen Rothwell wrote:
> Hi all,
> 
> Changes since 20190410:
> 


on i386:

ERROR: "devm_hwrng_register" [drivers/hid/hid-u2fzero.ko] undefined!


Full randconfig file is attached.

-- 
~Randy

[-- Attachment #2: config-r4825 --]
[-- Type: text/plain, Size: 134788 bytes --]

#
# Automatically generated file; DO NOT EDIT.
# Linux/i386 5.1.0-rc4 Kernel Configuration
#

#
# Compiler: gcc (SUSE Linux) 4.8.5
#
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=40805
CONFIG_CLANG_VERSION=0
CONFIG_CC_HAS_ASM_GOTO=y
CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y
CONFIG_CC_DISABLE_WARN_MAYBE_UNINITIALIZED=y
CONFIG_IRQ_WORK=y
CONFIG_BUILDTIME_EXTABLE_SORT=y
CONFIG_THREAD_INFO_IN_TASK=y

#
# General setup
#
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_COMPILE_TEST=y
CONFIG_LOCALVERSION=""
CONFIG_BUILD_SALT=""
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_BZIP2=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_XZ=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_KERNEL_LZ4=y
# CONFIG_KERNEL_GZIP is not set
# CONFIG_KERNEL_BZIP2 is not set
CONFIG_KERNEL_LZMA=y
# CONFIG_KERNEL_XZ is not set
# CONFIG_KERNEL_LZO is not set
# CONFIG_KERNEL_LZ4 is not set
CONFIG_DEFAULT_HOSTNAME="(none)"
# CONFIG_SYSVIPC is not set
# CONFIG_CROSS_MEMORY_ATTACH is not set
# CONFIG_USELIB is not set
CONFIG_HAVE_ARCH_AUDITSYSCALL=y

#
# IRQ subsystem
#
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_PENDING_IRQ=y
CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_SIM=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
CONFIG_GENERIC_IRQ_RESERVATION_MODE=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_SPARSE_IRQ=y
CONFIG_GENERIC_IRQ_DEBUGFS=y
CONFIG_CLOCKSOURCE_WATCHDOG=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_CLOCKSOURCE_INIT=y
CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
CONFIG_GENERIC_CMOS_UPDATE=y

#
# Timers subsystem
#
CONFIG_HZ_PERIODIC=y
# CONFIG_NO_HZ_IDLE is not set
CONFIG_NO_HZ=y
# CONFIG_HIGH_RES_TIMERS is not set
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
CONFIG_PREEMPT_COUNT=y

#
# CPU/Task time and stats accounting
#
CONFIG_TICK_CPU_ACCOUNTING=y
# CONFIG_IRQ_TIME_ACCOUNTING is not set
# CONFIG_PSI is not set
CONFIG_CPU_ISOLATION=y

#
# RCU Subsystem
#
CONFIG_TREE_RCU=y
# CONFIG_RCU_EXPERT is not set
CONFIG_SRCU=y
CONFIG_TREE_SRCU=y
CONFIG_TASKS_RCU=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_RCU_NEED_SEGCBLIST=y
CONFIG_BUILD_BIN2C=y
CONFIG_IKCONFIG=m
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
CONFIG_CGROUPS=y
CONFIG_PAGE_COUNTER=y
CONFIG_MEMCG=y
CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
# CONFIG_CFS_BANDWIDTH is not set
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_CGROUP_PIDS=y
# CONFIG_CGROUP_RDMA is not set
# CONFIG_CGROUP_FREEZER is not set
# CONFIG_CPUSETS is not set
# CONFIG_CGROUP_DEVICE is not set
# CONFIG_CGROUP_CPUACCT is not set
# CONFIG_CGROUP_PERF is not set
CONFIG_CGROUP_DEBUG=y
# CONFIG_CHECKPOINT_RESTORE is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_RELAY is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_RD_GZIP=y
CONFIG_RD_BZIP2=y
# CONFIG_RD_LZMA is not set
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y
# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_ANON_INODES=y
CONFIG_HAVE_UID16=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_HAVE_PCSPKR_PLATFORM=y
CONFIG_EXPERT=y
# CONFIG_MULTIUSER is not set
CONFIG_SGETMASK_SYSCALL=y
CONFIG_SYSFS_SYSCALL=y
CONFIG_FHANDLE=y
CONFIG_POSIX_TIMERS=y
# CONFIG_PRINTK is not set
CONFIG_BUG=y
# CONFIG_ELF_CORE is not set
CONFIG_PCSPKR_PLATFORM=y
CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
CONFIG_EPOLL=y
# CONFIG_SIGNALFD is not set
# CONFIG_TIMERFD is not set
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
# CONFIG_AIO is not set
CONFIG_IO_URING=y
# CONFIG_ADVISE_SYSCALLS is not set
CONFIG_MEMBARRIER=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_BASE_RELATIVE=y
# CONFIG_BPF_SYSCALL is not set
CONFIG_USERFAULTFD=y
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
CONFIG_RSEQ=y
# CONFIG_DEBUG_RSEQ is not set
CONFIG_EMBEDDED=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_PERF_USE_VMALLOC=y
# CONFIG_PC104 is not set

#
# Kernel Performance Events And Counters
#
CONFIG_PERF_EVENTS=y
CONFIG_DEBUG_PERF_USE_VMALLOC=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
# CONFIG_SLUB is not set
CONFIG_SLOB=y
CONFIG_SLAB_MERGE_DEFAULT=y
# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
# CONFIG_PROFILING is not set
CONFIG_TRACEPOINTS=y
CONFIG_X86_32=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf32-i386"
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_MMU=y
CONFIG_ARCH_MMAP_RND_BITS_MIN=8
CONFIG_ARCH_MMAP_RND_BITS_MAX=16
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ARCH_HAS_CPU_RELAX=y
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
CONFIG_ARCH_HAS_FILTER_PGPROT=y
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_HAVE_INTEL_TXT=y
CONFIG_X86_32_SMP=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_CC_HAS_SANE_STACKPROTECTOR=y

#
# Processor type and features
#
# CONFIG_ZONE_DMA is not set
CONFIG_SMP=y
# CONFIG_X86_FEATURE_NAMES is not set
# CONFIG_X86_MPPARSE is not set
# CONFIG_GOLDFISH is not set
CONFIG_RETPOLINE=y
# CONFIG_X86_CPU_RESCTRL is not set
# CONFIG_X86_BIGSMP is not set
CONFIG_X86_EXTENDED_PLATFORM=y
CONFIG_X86_GOLDFISH=y
# CONFIG_X86_INTEL_MID is not set
# CONFIG_X86_INTEL_QUARK is not set
# CONFIG_X86_INTEL_LPSS is not set
# CONFIG_X86_AMD_PLATFORM_DEVICE is not set
CONFIG_IOSF_MBI=y
CONFIG_IOSF_MBI_DEBUG=y
# CONFIG_X86_RDC321X is not set
# CONFIG_X86_32_NON_STANDARD is not set
CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
CONFIG_X86_32_IRIS=m
# CONFIG_SCHED_OMIT_FRAME_POINTER is not set
CONFIG_HYPERVISOR_GUEST=y
CONFIG_PARAVIRT=y
# CONFIG_PARAVIRT_DEBUG is not set
# CONFIG_PARAVIRT_SPINLOCKS is not set
CONFIG_KVM_GUEST=y
# CONFIG_PVH is not set
CONFIG_KVM_DEBUG_FS=y
# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
CONFIG_PARAVIRT_CLOCK=y
# CONFIG_M486 is not set
# CONFIG_M586 is not set
# CONFIG_M586TSC is not set
# CONFIG_M586MMX is not set
# CONFIG_M686 is not set
# CONFIG_MPENTIUMII is not set
# CONFIG_MPENTIUMIII is not set
# CONFIG_MPENTIUMM is not set
# CONFIG_MPENTIUM4 is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
CONFIG_MK8=y
# CONFIG_MCRUSOE is not set
# CONFIG_MEFFICEON is not set
# CONFIG_MWINCHIPC6 is not set
# CONFIG_MWINCHIP3D is not set
# CONFIG_MELAN is not set
# CONFIG_MGEODEGX1 is not set
# CONFIG_MGEODE_LX is not set
# CONFIG_MCYRIXIII is not set
# CONFIG_MVIAC3_2 is not set
# CONFIG_MVIAC7 is not set
# CONFIG_MCORE2 is not set
# CONFIG_MATOM is not set
# CONFIG_X86_GENERIC is not set
CONFIG_X86_INTERNODE_CACHE_SHIFT=6
CONFIG_X86_L1_CACHE_SHIFT=6
CONFIG_X86_INTEL_USERCOPY=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
CONFIG_X86_TSC=y
CONFIG_X86_CMPXCHG64=y
CONFIG_X86_CMOV=y
CONFIG_X86_MINIMUM_CPU_FAMILY=6
CONFIG_X86_DEBUGCTLMSR=y
CONFIG_PROCESSOR_SELECT=y
# CONFIG_CPU_SUP_INTEL is not set
CONFIG_CPU_SUP_CYRIX_32=y
CONFIG_CPU_SUP_AMD=y
CONFIG_CPU_SUP_HYGON=y
# CONFIG_CPU_SUP_CENTAUR is not set
CONFIG_CPU_SUP_TRANSMETA_32=y
# CONFIG_CPU_SUP_UMC_32 is not set
CONFIG_HPET_TIMER=y
CONFIG_DMI=y
CONFIG_NR_CPUS_RANGE_BEGIN=2
CONFIG_NR_CPUS_RANGE_END=8
CONFIG_NR_CPUS_DEFAULT=8
CONFIG_NR_CPUS=8
CONFIG_SCHED_SMT=y
# CONFIG_SCHED_MC is not set
CONFIG_X86_LOCAL_APIC=y
CONFIG_X86_IO_APIC=y
# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
CONFIG_X86_MCE=y
# CONFIG_X86_MCELOG_LEGACY is not set
CONFIG_X86_MCE_INTEL=y
CONFIG_X86_MCE_AMD=y
CONFIG_X86_ANCIENT_MCE=y
CONFIG_X86_MCE_THRESHOLD=y
CONFIG_X86_MCE_INJECT=y
CONFIG_X86_THERMAL_VECTOR=y

#
# Performance monitoring
#
CONFIG_PERF_EVENTS_AMD_POWER=y
CONFIG_X86_LEGACY_VM86=y
CONFIG_VM86=y
CONFIG_X86_16BIT=y
CONFIG_X86_ESPFIX32=y
CONFIG_TOSHIBA=y
CONFIG_I8K=m
# CONFIG_X86_REBOOTFIXUPS is not set
CONFIG_MICROCODE=y
CONFIG_MICROCODE_INTEL=y
CONFIG_MICROCODE_AMD=y
CONFIG_MICROCODE_OLD_INTERFACE=y
# CONFIG_X86_MSR is not set
CONFIG_X86_CPUID=m
# CONFIG_NOHIGHMEM is not set
CONFIG_HIGHMEM4G=y
# CONFIG_HIGHMEM64G is not set
# CONFIG_VMSPLIT_3G is not set
# CONFIG_VMSPLIT_3G_OPT is not set
# CONFIG_VMSPLIT_2G is not set
# CONFIG_VMSPLIT_2G_OPT is not set
CONFIG_VMSPLIT_1G=y
CONFIG_PAGE_OFFSET=0x40000000
CONFIG_HIGHMEM=y
# CONFIG_X86_CPA_STATISTICS is not set
CONFIG_ARCH_HAS_MEM_ENCRYPT=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ILLEGAL_POINTER_VALUE=0
# CONFIG_HIGHPTE is not set
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
CONFIG_X86_RESERVE_LOW=64
CONFIG_MATH_EMULATION=y
# CONFIG_MTRR is not set
CONFIG_ARCH_RANDOM=y
# CONFIG_X86_SMAP is not set
# CONFIG_EFI is not set
CONFIG_SECCOMP=y
CONFIG_HZ_100=y
# CONFIG_HZ_250 is not set
# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=100
# CONFIG_KEXEC is not set
CONFIG_CRASH_DUMP=y
CONFIG_PHYSICAL_START=0x1000000
# CONFIG_RELOCATABLE is not set
CONFIG_PHYSICAL_ALIGN=0x200000
CONFIG_HOTPLUG_CPU=y
CONFIG_BOOTPARAM_HOTPLUG_CPU0=y
CONFIG_DEBUG_HOTPLUG_CPU0=y
CONFIG_COMPAT_VDSO=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE=""
CONFIG_CMDLINE_OVERRIDE=y
CONFIG_MODIFY_LDT_SYSCALL=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y

#
# Power management and ACPI options
#
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
CONFIG_SUSPEND_SKIP_SYNC=y
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
CONFIG_PM_AUTOSLEEP=y
CONFIG_PM_WAKELOCKS=y
CONFIG_PM_WAKELOCKS_LIMIT=100
# CONFIG_PM_WAKELOCKS_GC is not set
CONFIG_PM=y
# CONFIG_PM_DEBUG is not set
CONFIG_PM_CLK=y
CONFIG_PM_GENERIC_DOMAINS=y
# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
CONFIG_PM_GENERIC_DOMAINS_OF=y
# CONFIG_ENERGY_MODEL is not set
CONFIG_ARCH_SUPPORTS_ACPI=y
CONFIG_ACPI=y
CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
# CONFIG_ACPI_DEBUGGER is not set
# CONFIG_ACPI_SPCR_TABLE is not set
CONFIG_ACPI_SLEEP=y
# CONFIG_ACPI_REV_OVERRIDE_POSSIBLE is not set
CONFIG_ACPI_EC_DEBUGFS=m
# CONFIG_ACPI_AC is not set
# CONFIG_ACPI_BATTERY is not set
CONFIG_ACPI_BUTTON=m
CONFIG_ACPI_VIDEO=m
CONFIG_ACPI_FAN=m
CONFIG_ACPI_TAD=m
# CONFIG_ACPI_DOCK is not set
CONFIG_ACPI_CPU_FREQ_PSS=y
CONFIG_ACPI_PROCESSOR_CSTATE=y
CONFIG_ACPI_PROCESSOR_IDLE=y
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_IPMI=m
CONFIG_ACPI_HOTPLUG_CPU=y
# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
CONFIG_ACPI_THERMAL=y
CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y
# CONFIG_ACPI_TABLE_UPGRADE is not set
CONFIG_ACPI_DEBUG=y
# CONFIG_ACPI_PCI_SLOT is not set
CONFIG_ACPI_CONTAINER=y
CONFIG_ACPI_HOTPLUG_IOAPIC=y
CONFIG_ACPI_SBS=m
CONFIG_ACPI_HED=y
CONFIG_ACPI_CUSTOM_METHOD=y
CONFIG_ACPI_REDUCED_HARDWARE_ONLY=y
CONFIG_HAVE_ACPI_APEI=y
CONFIG_HAVE_ACPI_APEI_NMI=y
CONFIG_ACPI_APEI=y
CONFIG_ACPI_APEI_GHES=y
CONFIG_ACPI_APEI_PCIEAER=y
# CONFIG_ACPI_APEI_MEMORY_FAILURE is not set
CONFIG_ACPI_APEI_EINJ=y
# CONFIG_ACPI_APEI_ERST_DEBUG is not set
CONFIG_DPTF_POWER=m
CONFIG_ACPI_WATCHDOG=y
CONFIG_ACPI_EXTLOG=y
CONFIG_PMIC_OPREGION=y
# CONFIG_BXT_WC_PMIC_OPREGION is not set
CONFIG_CHT_DC_TI_PMIC_OPREGION=y
CONFIG_ACPI_CONFIGFS=m
# CONFIG_X86_PM_TIMER is not set
# CONFIG_SFI is not set
# CONFIG_APM is not set

#
# CPU Frequency scaling
#
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
# CONFIG_CPU_FREQ_STAT is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=m
CONFIG_CPU_FREQ_GOV_ONDEMAND=m
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y

#
# CPU frequency scaling drivers
#
# CONFIG_CPUFREQ_DT is not set
CONFIG_X86_INTEL_PSTATE=y
# CONFIG_X86_PCC_CPUFREQ is not set
CONFIG_X86_ACPI_CPUFREQ=y
# CONFIG_X86_ACPI_CPUFREQ_CPB is not set
# CONFIG_X86_POWERNOW_K6 is not set
CONFIG_X86_POWERNOW_K7=m
CONFIG_X86_POWERNOW_K7_ACPI=y
# CONFIG_X86_POWERNOW_K8 is not set
# CONFIG_X86_AMD_FREQ_SENSITIVITY is not set
# CONFIG_X86_GX_SUSPMOD is not set
# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
CONFIG_X86_SPEEDSTEP_ICH=m
# CONFIG_X86_SPEEDSTEP_SMI is not set
CONFIG_X86_P4_CLOCKMOD=m
CONFIG_X86_CPUFREQ_NFORCE2=m
# CONFIG_X86_LONGRUN is not set
# CONFIG_X86_LONGHAUL is not set
# CONFIG_X86_E_POWERSAVER is not set

#
# shared options
#
CONFIG_X86_SPEEDSTEP_LIB=m
CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y

#
# CPU Idle
#
CONFIG_CPU_IDLE=y
# CONFIG_CPU_IDLE_GOV_LADDER is not set
CONFIG_CPU_IDLE_GOV_MENU=y
# CONFIG_CPU_IDLE_GOV_TEO is not set

#
# Bus options (PCI etc.)
#
# CONFIG_PCI_GOBIOS is not set
# CONFIG_PCI_GOMMCONFIG is not set
# CONFIG_PCI_GODIRECT is not set
# CONFIG_PCI_GOOLPC is not set
CONFIG_PCI_GOANY=y
CONFIG_PCI_BIOS=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
CONFIG_PCI_OLPC=y
# CONFIG_PCI_CNB20LE_QUIRK is not set
CONFIG_ISA_BUS=y
CONFIG_ISA_DMA_API=y
# CONFIG_ISA is not set
CONFIG_SCx200=m
CONFIG_SCx200HR_TIMER=m
CONFIG_OLPC=y
# CONFIG_OLPC_XO1_PM is not set
# CONFIG_OLPC_XO15_SCI is not set
CONFIG_ALIX=y
# CONFIG_NET5501 is not set
CONFIG_GEOS=y
CONFIG_AMD_NB=y
# CONFIG_X86_SYSFB is not set

#
# Binary Emulations
#
CONFIG_COMPAT_32=y
CONFIG_HAVE_ATOMIC_IOMAP=y
CONFIG_HAVE_GENERIC_GUP=y

#
# Firmware Drivers
#
CONFIG_ARM_SCMI_PROTOCOL=y
CONFIG_ARM_SCMI_POWER_DOMAIN=y
# CONFIG_ARM_SCPI_PROTOCOL is not set
CONFIG_ARM_SCPI_POWER_DOMAIN=y
# CONFIG_EDD is not set
# CONFIG_FIRMWARE_MEMMAP is not set
CONFIG_DMIID=y
CONFIG_DMI_SYSFS=y
CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
# CONFIG_ISCSI_IBFT_FIND is not set
# CONFIG_FW_CFG_SYSFS is not set
# CONFIG_GOOGLE_FIRMWARE is not set
CONFIG_UEFI_CPER=y
CONFIG_UEFI_CPER_X86=y
# CONFIG_IMX_SCU is not set

#
# Tegra firmware driver
#
CONFIG_HAVE_KVM=y
# CONFIG_VIRTUALIZATION is not set

#
# General architecture-dependent options
#
CONFIG_HOTPLUG_SMT=y
CONFIG_HAVE_OPROFILE=y
CONFIG_OPROFILE_NMI_TIMER=y
CONFIG_KPROBES=y
# CONFIG_JUMP_LABEL is not set
CONFIG_OPTPROBES=y
CONFIG_UPROBES=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_KRETPROBES=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_KPROBES_ON_FTRACE=y
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
CONFIG_HAVE_NMI=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
CONFIG_ARCH_HAS_SET_MEMORY=y
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_RSEQ=y
CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_HW_BREAKPOINT=y
CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
CONFIG_HAVE_USER_RETURN_NOTIFIER=y
CONFIG_HAVE_PERF_EVENTS_NMI=y
CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y
CONFIG_HAVE_PERF_REGS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
CONFIG_HAVE_RCU_TABLE_FREE=y
CONFIG_HAVE_RCU_TABLE_INVALIDATE=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_HAVE_CMPXCHG_LOCAL=y
CONFIG_HAVE_CMPXCHG_DOUBLE=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_STACKLEAK=y
CONFIG_HAVE_STACKPROTECTOR=y
CONFIG_CC_HAS_STACKPROTECTOR_NONE=y
CONFIG_STACKPROTECTOR=y
CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_MOVE_PMD=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
CONFIG_HAVE_EXIT_THREAD=y
CONFIG_ARCH_MMAP_RND_BITS=8
CONFIG_HAVE_COPY_THREAD_TLS=y
CONFIG_ISA_BUS_API=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_OLD_SIGACTION=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
CONFIG_STRICT_KERNEL_RWX=y
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
CONFIG_STRICT_MODULE_RWX=y
CONFIG_ARCH_HAS_REFCOUNT=y
# CONFIG_REFCOUNT_FULL is not set
CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y

#
# GCOV-based kernel profiling
#
# CONFIG_GCOV_KERNEL is not set
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
CONFIG_PLUGIN_HOSTCC=""
CONFIG_HAVE_GCC_PLUGINS=y
CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_MODULE_SIG is not set
CONFIG_MODULE_COMPRESS=y
CONFIG_MODULE_COMPRESS_GZIP=y
# CONFIG_MODULE_COMPRESS_XZ is not set
CONFIG_TRIM_UNUSED_KSYMS=y
CONFIG_MODULES_TREE_LOOKUP=y
# CONFIG_BLOCK is not set
CONFIG_PADATA=y
CONFIG_UNINLINE_SPIN_UNLOCK=y
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y
CONFIG_FREEZER=y

#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
CONFIG_ELFCORE=y
CONFIG_BINFMT_SCRIPT=y
CONFIG_BINFMT_MISC=m
CONFIG_COREDUMP=y

#
# Memory Management options
#
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_SPARSEMEM_STATIC=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_MEMORY_ISOLATION=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MEMORY_BALLOON=y
# CONFIG_BALLOON_COMPACTION is not set
CONFIG_COMPACTION=y
CONFIG_MIGRATION=y
CONFIG_CONTIG_ALLOC=y
CONFIG_VIRT_TO_BUS=y
CONFIG_MMU_NOTIFIER=y
# CONFIG_KSM is not set
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
CONFIG_MEMORY_FAILURE=y
# CONFIG_TRANSPARENT_HUGEPAGE is not set
CONFIG_CLEANCACHE=y
CONFIG_CMA=y
CONFIG_CMA_DEBUG=y
CONFIG_CMA_DEBUGFS=y
CONFIG_CMA_AREAS=7
# CONFIG_ZPOOL is not set
CONFIG_ZBUD=m
CONFIG_ZSMALLOC=y
# CONFIG_PGTABLE_MAPPING is not set
# CONFIG_ZSMALLOC_STAT is not set
CONFIG_GENERIC_EARLY_IOREMAP=y
CONFIG_IDLE_PAGE_TRACKING=y
CONFIG_FRAME_VECTOR=y
CONFIG_PERCPU_STATS=y
# CONFIG_GUP_BENCHMARK is not set
CONFIG_ARCH_HAS_PTE_SPECIAL=y
# CONFIG_NET is not set
CONFIG_HAVE_EBPF_JIT=y

#
# Device Drivers
#
CONFIG_HAVE_EISA=y
CONFIG_EISA=y
CONFIG_EISA_VLB_PRIMING=y
CONFIG_EISA_PCI_EISA=y
CONFIG_EISA_VIRTUAL_ROOT=y
CONFIG_EISA_NAMES=y
CONFIG_HAVE_PCI=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEAER=y
CONFIG_PCIEAER_INJECT=m
# CONFIG_PCIE_ECRC is not set
CONFIG_PCIEASPM=y
CONFIG_PCIEASPM_DEBUG=y
# CONFIG_PCIEASPM_DEFAULT is not set
CONFIG_PCIEASPM_POWERSAVE=y
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
# CONFIG_PCIEASPM_PERFORMANCE is not set
CONFIG_PCIE_PME=y
CONFIG_PCIE_DPC=y
# CONFIG_PCIE_PTM is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PCI_QUIRKS=y
# CONFIG_PCI_DEBUG is not set
# CONFIG_PCI_STUB is not set
CONFIG_PCI_ATS=y
CONFIG_PCI_ECAM=y
CONFIG_PCI_LOCKLESS_CONFIG=y
CONFIG_PCI_BRIDGE_EMUL=y
# CONFIG_PCI_IOV is not set
# CONFIG_PCI_PRI is not set
CONFIG_PCI_PASID=y
CONFIG_PCI_LABEL=y
# CONFIG_HOTPLUG_PCI is not set

#
# PCI controller drivers
#
CONFIG_PCI_AARDVARK=y

#
# Cadence PCIe controllers support
#
# CONFIG_PCIE_CADENCE_HOST is not set
# CONFIG_PCIE_CADENCE_EP is not set
CONFIG_PCIE_XILINX_NWL=y
# CONFIG_PCI_FTPCI100 is not set
# CONFIG_PCI_TEGRA is not set
# CONFIG_PCIE_RCAR is not set
CONFIG_PCI_HOST_COMMON=y
CONFIG_PCI_HOST_GENERIC=y
# CONFIG_PCIE_XILINX is not set
# CONFIG_PCI_XGENE is not set
# CONFIG_PCI_V3_SEMI is not set
# CONFIG_PCIE_ALTERA is not set
CONFIG_PCI_HOST_THUNDER_PEM=y
# CONFIG_PCI_HOST_THUNDER_ECAM is not set
# CONFIG_PCIE_ROCKCHIP_HOST is not set
# CONFIG_PCIE_ROCKCHIP_EP is not set
# CONFIG_PCIE_MEDIATEK is not set
CONFIG_PCIE_MOBIVEIL=y

#
# DesignWare PCI Core Support
#
CONFIG_PCIE_DW=y
CONFIG_PCIE_DW_HOST=y
CONFIG_PCIE_DW_EP=y
CONFIG_PCI_DRA7XX=y
# CONFIG_PCI_DRA7XX_HOST is not set
CONFIG_PCI_DRA7XX_EP=y
CONFIG_PCIE_DW_PLAT=y
CONFIG_PCIE_DW_PLAT_HOST=y
CONFIG_PCIE_DW_PLAT_EP=y
CONFIG_PCI_EXYNOS=y
CONFIG_PCI_IMX6=y
# CONFIG_PCIE_SPEAR13XX is not set
CONFIG_PCI_LAYERSCAPE=y
# CONFIG_PCI_HISI is not set
CONFIG_PCIE_QCOM=y
# CONFIG_PCIE_ARMADA_8K is not set
CONFIG_PCIE_ARTPEC6=y
CONFIG_PCIE_ARTPEC6_HOST=y
# CONFIG_PCIE_ARTPEC6_EP is not set
CONFIG_PCIE_KIRIN=y
# CONFIG_PCIE_HISI_STB is not set
CONFIG_PCI_MESON=y
# CONFIG_PCIE_UNIPHIER is not set

#
# PCI Endpoint
#
CONFIG_PCI_ENDPOINT=y
CONFIG_PCI_ENDPOINT_CONFIGFS=y
CONFIG_PCI_EPF_TEST=y

#
# PCI switch controller drivers
#
CONFIG_PCI_SW_SWITCHTEC=y
# CONFIG_PCCARD is not set
CONFIG_RAPIDIO=y
# CONFIG_RAPIDIO_TSI721 is not set
CONFIG_RAPIDIO_DISC_TIMEOUT=30
CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS=y
CONFIG_RAPIDIO_DMA_ENGINE=y
# CONFIG_RAPIDIO_DEBUG is not set
CONFIG_RAPIDIO_ENUM_BASIC=m
CONFIG_RAPIDIO_CHMAN=m
CONFIG_RAPIDIO_MPORT_CDEV=y

#
# RapidIO Switch drivers
#
CONFIG_RAPIDIO_TSI57X=y
CONFIG_RAPIDIO_CPS_XX=m
CONFIG_RAPIDIO_TSI568=m
CONFIG_RAPIDIO_CPS_GEN2=m
# CONFIG_RAPIDIO_RXS_GEN3 is not set

#
# Generic Driver Options
#
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
# CONFIG_DEVTMPFS_MOUNT is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y

#
# Firmware loader
#
CONFIG_FW_LOADER=y
CONFIG_EXTRA_FIRMWARE=""
CONFIG_FW_LOADER_USER_HELPER=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
CONFIG_WANT_DEV_COREDUMP=y
CONFIG_ALLOW_DEV_COREDUMP=y
CONFIG_DEV_COREDUMP=y
CONFIG_DEBUG_DRIVER=y
CONFIG_DEBUG_DEVRES=y
# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
CONFIG_TEST_ASYNC_DRIVER_PROBE=m
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_CPU_VULNERABILITIES=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_SPI=y
CONFIG_REGMAP_SPMI=m
CONFIG_REGMAP_W1=m
CONFIG_REGMAP_MMIO=y
CONFIG_REGMAP_IRQ=y
CONFIG_REGMAP_SCCB=m
CONFIG_DMA_SHARED_BUFFER=y
CONFIG_DMA_FENCE_TRACE=y

#
# Bus devices
#
CONFIG_QCOM_EBI2=y
CONFIG_SIMPLE_PM_BUS=y
# CONFIG_FSL_MC_BUS is not set
# CONFIG_GNSS is not set
# CONFIG_MTD is not set
CONFIG_DTC=y
CONFIG_OF=y
CONFIG_OF_UNITTEST=y
# CONFIG_OF_ALL_DTBS is not set
CONFIG_OF_FLATTREE=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_PROMTREE=y
CONFIG_OF_KOBJ=y
CONFIG_OF_DYNAMIC=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_IRQ=y
CONFIG_OF_RESERVED_MEM=y
CONFIG_OF_RESOLVE=y
CONFIG_OF_OVERLAY=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
# CONFIG_PARPORT is not set
CONFIG_PNP=y
CONFIG_PNP_DEBUG_MESSAGES=y

#
# Protocols
#
CONFIG_ISAPNP=y
CONFIG_PNPACPI=y

#
# NVME Support
#

#
# Misc devices
#
CONFIG_SENSORS_LIS3LV02D=m
# CONFIG_AD525X_DPOT is not set
# CONFIG_DUMMY_IRQ is not set
CONFIG_IBM_ASM=y
CONFIG_PHANTOM=y
# CONFIG_SGI_IOC4 is not set
CONFIG_TIFM_CORE=y
CONFIG_TIFM_7XX1=y
# CONFIG_ICS932S401 is not set
CONFIG_ATMEL_SSC=y
# CONFIG_ENCLOSURE_SERVICES is not set
# CONFIG_CS5535_MFGPT is not set
CONFIG_HP_ILO=y
CONFIG_QCOM_COINCELL=m
# CONFIG_QCOM_FASTRPC is not set
# CONFIG_APDS9802ALS is not set
CONFIG_ISL29003=m
# CONFIG_ISL29020 is not set
CONFIG_SENSORS_TSL2550=y
CONFIG_SENSORS_BH1770=m
# CONFIG_SENSORS_APDS990X is not set
CONFIG_HMC6352=y
CONFIG_DS1682=m
CONFIG_VMWARE_BALLOON=m
# CONFIG_PCH_PHUB is not set
# CONFIG_USB_SWITCH_FSA9480 is not set
# CONFIG_LATTICE_ECP3_CONFIG is not set
# CONFIG_SRAM is not set
CONFIG_ASPEED_LPC_CTRL=m
# CONFIG_ASPEED_LPC_SNOOP is not set
CONFIG_PCI_ENDPOINT_TEST=y
CONFIG_MISC_RTSX=m
CONFIG_PVPANIC=m
CONFIG_C2PORT=m
CONFIG_C2PORT_DURAMAR_2150=m

#
# EEPROM support
#
CONFIG_EEPROM_AT24=y
CONFIG_EEPROM_AT25=m
# CONFIG_EEPROM_LEGACY is not set
# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
# CONFIG_EEPROM_93XX46 is not set
# CONFIG_EEPROM_IDT_89HPESX is not set
CONFIG_EEPROM_EE1004=y
CONFIG_CB710_CORE=y
CONFIG_CB710_DEBUG=y
CONFIG_CB710_DEBUG_ASSUMPTIONS=y

#
# Texas Instruments shared transport line discipline
#
CONFIG_SENSORS_LIS3_I2C=m
CONFIG_ALTERA_STAPL=m
CONFIG_INTEL_MEI=m
CONFIG_INTEL_MEI_ME=m
CONFIG_INTEL_MEI_TXE=m
CONFIG_VMWARE_VMCI=m

#
# Intel MIC & related support
#

#
# Intel MIC Bus Driver
#

#
# SCIF Bus Driver
#

#
# VOP Bus Driver
#
CONFIG_VOP_BUS=m

#
# Intel MIC Host Driver
#

#
# Intel MIC Card Driver
#

#
# SCIF Driver
#

#
# Intel MIC Coprocessor State Management (COSM) Drivers
#

#
# VOP Driver
#
CONFIG_VOP=m
CONFIG_VHOST_RING=m
CONFIG_ECHO=y
CONFIG_MISC_ALCOR_PCI=y
# CONFIG_MISC_RTSX_PCI is not set
CONFIG_MISC_RTSX_USB=m
CONFIG_HABANA_AI=m
CONFIG_HAVE_IDE=y

#
# SCSI device support
#
CONFIG_SCSI_MOD=y
CONFIG_FUSION=y
CONFIG_FUSION_MAX_SGE=128
CONFIG_FUSION_LOGGING=y

#
# IEEE 1394 (FireWire) support
#
CONFIG_FIREWIRE=m
CONFIG_FIREWIRE_OHCI=m
CONFIG_FIREWIRE_NOSY=y
CONFIG_MACINTOSH_DRIVERS=y

#
# Input device support
#
CONFIG_INPUT=y
CONFIG_INPUT_LEDS=m
CONFIG_INPUT_FF_MEMLESS=y
CONFIG_INPUT_POLLDEV=y
CONFIG_INPUT_SPARSEKMAP=y
# CONFIG_INPUT_MATRIXKMAP is not set

#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_JOYDEV is not set
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=y

#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_PS2_ALPS is not set
# CONFIG_MOUSE_PS2_BYD is not set
CONFIG_MOUSE_PS2_LOGIPS2PP=y
# CONFIG_MOUSE_PS2_SYNAPTICS is not set
# CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS is not set
CONFIG_MOUSE_PS2_CYPRESS=y
# CONFIG_MOUSE_PS2_LIFEBOOK is not set
# CONFIG_MOUSE_PS2_TRACKPOINT is not set
# CONFIG_MOUSE_PS2_ELANTECH is not set
# CONFIG_MOUSE_PS2_SENTELIC is not set
CONFIG_MOUSE_PS2_TOUCHKIT=y
# CONFIG_MOUSE_PS2_OLPC is not set
CONFIG_MOUSE_PS2_FOCALTECH=y
# CONFIG_MOUSE_PS2_VMMOUSE is not set
CONFIG_MOUSE_SERIAL=y
CONFIG_MOUSE_APPLETOUCH=m
# CONFIG_MOUSE_BCM5974 is not set
CONFIG_MOUSE_CYAPA=m
# CONFIG_MOUSE_ELAN_I2C is not set
CONFIG_MOUSE_VSXXXAA=m
CONFIG_MOUSE_GPIO=y
# CONFIG_MOUSE_SYNAPTICS_I2C is not set
CONFIG_MOUSE_SYNAPTICS_USB=m
CONFIG_INPUT_JOYSTICK=y
CONFIG_JOYSTICK_ANALOG=m
CONFIG_JOYSTICK_A3D=y
CONFIG_JOYSTICK_ADI=m
# CONFIG_JOYSTICK_COBRA is not set
CONFIG_JOYSTICK_GF2K=m
# CONFIG_JOYSTICK_GRIP is not set
CONFIG_JOYSTICK_GRIP_MP=y
CONFIG_JOYSTICK_GUILLEMOT=m
# CONFIG_JOYSTICK_INTERACT is not set
CONFIG_JOYSTICK_SIDEWINDER=y
CONFIG_JOYSTICK_TMDC=m
# CONFIG_JOYSTICK_IFORCE is not set
CONFIG_JOYSTICK_WARRIOR=m
CONFIG_JOYSTICK_MAGELLAN=y
CONFIG_JOYSTICK_SPACEORB=y
CONFIG_JOYSTICK_SPACEBALL=y
CONFIG_JOYSTICK_STINGER=y
CONFIG_JOYSTICK_TWIDJOY=m
CONFIG_JOYSTICK_ZHENHUA=m
CONFIG_JOYSTICK_AS5011=m
CONFIG_JOYSTICK_JOYDUMP=y
# CONFIG_JOYSTICK_XPAD is not set
# CONFIG_JOYSTICK_PSXPAD_SPI is not set
CONFIG_JOYSTICK_PXRC=y
CONFIG_INPUT_TABLET=y
CONFIG_TABLET_USB_ACECAD=m
CONFIG_TABLET_USB_AIPTEK=m
CONFIG_TABLET_USB_GTCO=m
CONFIG_TABLET_USB_HANWANG=m
# CONFIG_TABLET_USB_KBTAB is not set
CONFIG_TABLET_USB_PEGASUS=m
CONFIG_TABLET_SERIAL_WACOM4=m
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_PROPERTIES=y
CONFIG_TOUCHSCREEN_88PM860X=y
# CONFIG_TOUCHSCREEN_ADS7846 is not set
# CONFIG_TOUCHSCREEN_AD7877 is not set
CONFIG_TOUCHSCREEN_AD7879=m
CONFIG_TOUCHSCREEN_AD7879_I2C=m
# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
CONFIG_TOUCHSCREEN_ADC=m
CONFIG_TOUCHSCREEN_AR1021_I2C=m
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_TOUCHSCREEN_AUO_PIXCIR=m
CONFIG_TOUCHSCREEN_BU21013=y
CONFIG_TOUCHSCREEN_BU21029=m
# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set
# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set
# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
CONFIG_TOUCHSCREEN_CYTTSP4_CORE=y
CONFIG_TOUCHSCREEN_CYTTSP4_I2C=m
CONFIG_TOUCHSCREEN_CYTTSP4_SPI=y
CONFIG_TOUCHSCREEN_DA9034=m
# CONFIG_TOUCHSCREEN_DA9052 is not set
CONFIG_TOUCHSCREEN_DYNAPRO=y
CONFIG_TOUCHSCREEN_HAMPSHIRE=m
CONFIG_TOUCHSCREEN_EETI=m
CONFIG_TOUCHSCREEN_EGALAX=y
CONFIG_TOUCHSCREEN_EGALAX_SERIAL=m
# CONFIG_TOUCHSCREEN_EXC3000 is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
CONFIG_TOUCHSCREEN_GOODIX=m
CONFIG_TOUCHSCREEN_HIDEEP=y
CONFIG_TOUCHSCREEN_ILI210X=m
CONFIG_TOUCHSCREEN_IPROC=y
CONFIG_TOUCHSCREEN_S6SY761=y
CONFIG_TOUCHSCREEN_GUNZE=m
CONFIG_TOUCHSCREEN_EKTF2127=m
CONFIG_TOUCHSCREEN_ELAN=m
CONFIG_TOUCHSCREEN_ELO=m
CONFIG_TOUCHSCREEN_WACOM_W8001=y
CONFIG_TOUCHSCREEN_WACOM_I2C=y
CONFIG_TOUCHSCREEN_MAX11801=y
# CONFIG_TOUCHSCREEN_MCS5000 is not set
# CONFIG_TOUCHSCREEN_MMS114 is not set
CONFIG_TOUCHSCREEN_MELFAS_MIP4=y
CONFIG_TOUCHSCREEN_MTOUCH=m
CONFIG_TOUCHSCREEN_IMX6UL_TSC=y
CONFIG_TOUCHSCREEN_INEXIO=y
# CONFIG_TOUCHSCREEN_MK712 is not set
CONFIG_TOUCHSCREEN_PENMOUNT=m
CONFIG_TOUCHSCREEN_EDT_FT5X06=m
CONFIG_TOUCHSCREEN_RASPBERRYPI_FW=m
# CONFIG_TOUCHSCREEN_MIGOR is not set
CONFIG_TOUCHSCREEN_TOUCHRIGHT=y
CONFIG_TOUCHSCREEN_TOUCHWIN=y
# CONFIG_TOUCHSCREEN_TI_AM335X_TSC is not set
CONFIG_TOUCHSCREEN_PIXCIR=y
CONFIG_TOUCHSCREEN_WDT87XX_I2C=y
CONFIG_TOUCHSCREEN_WM831X=y
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_MXS_LRADC is not set
CONFIG_TOUCHSCREEN_MX25=m
CONFIG_TOUCHSCREEN_MC13783=m
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
CONFIG_TOUCHSCREEN_TS4800=y
CONFIG_TOUCHSCREEN_TSC_SERIO=m
CONFIG_TOUCHSCREEN_TSC200X_CORE=m
CONFIG_TOUCHSCREEN_TSC2004=m
CONFIG_TOUCHSCREEN_TSC2005=m
CONFIG_TOUCHSCREEN_TSC2007=y
CONFIG_TOUCHSCREEN_RM_TS=m
CONFIG_TOUCHSCREEN_SILEAD=y
CONFIG_TOUCHSCREEN_SIS_I2C=y
# CONFIG_TOUCHSCREEN_ST1232 is not set
CONFIG_TOUCHSCREEN_STMFTS=m
CONFIG_TOUCHSCREEN_STMPE=y
# CONFIG_TOUCHSCREEN_SUN4I is not set
CONFIG_TOUCHSCREEN_SUR40=m
CONFIG_TOUCHSCREEN_SURFACE3_SPI=y
# CONFIG_TOUCHSCREEN_SX8654 is not set
CONFIG_TOUCHSCREEN_TPS6507X=m
# CONFIG_TOUCHSCREEN_ZET6223 is not set
# CONFIG_TOUCHSCREEN_ZFORCE is not set
CONFIG_TOUCHSCREEN_COLIBRI_VF50=m
CONFIG_TOUCHSCREEN_ROHM_BU21023=m
CONFIG_INPUT_MISC=y
# CONFIG_INPUT_88PM860X_ONKEY is not set
CONFIG_INPUT_88PM80X_ONKEY=m
# CONFIG_INPUT_AD714X is not set
CONFIG_INPUT_ATMEL_CAPTOUCH=y
CONFIG_INPUT_BMA150=m
# CONFIG_INPUT_E3X0_BUTTON is not set
CONFIG_INPUT_MSM_VIBRATOR=m
# CONFIG_INPUT_PCSPKR is not set
# CONFIG_INPUT_PM8941_PWRKEY is not set
# CONFIG_INPUT_PM8XXX_VIBRATOR is not set
CONFIG_INPUT_MAX77693_HAPTIC=m
# CONFIG_INPUT_MAX8925_ONKEY is not set
CONFIG_INPUT_MAX8997_HAPTIC=m
CONFIG_INPUT_MC13783_PWRBUTTON=m
CONFIG_INPUT_MMA8450=m
CONFIG_INPUT_APANEL=m
CONFIG_INPUT_GP2A=m
# CONFIG_INPUT_GPIO_BEEPER is not set
CONFIG_INPUT_GPIO_DECODER=m
# CONFIG_INPUT_WISTRON_BTNS is not set
CONFIG_INPUT_ATLAS_BTNS=y
CONFIG_INPUT_ATI_REMOTE2=y
CONFIG_INPUT_KEYSPAN_REMOTE=m
CONFIG_INPUT_KXTJ9=y
# CONFIG_INPUT_KXTJ9_POLLED_MODE is not set
CONFIG_INPUT_POWERMATE=y
CONFIG_INPUT_YEALINK=y
CONFIG_INPUT_CM109=m
CONFIG_INPUT_REGULATOR_HAPTIC=m
CONFIG_INPUT_RETU_PWRBUTTON=m
# CONFIG_INPUT_TPS65218_PWRBUTTON is not set
CONFIG_INPUT_TWL4030_PWRBUTTON=m
CONFIG_INPUT_TWL4030_VIBRA=m
# CONFIG_INPUT_TWL6040_VIBRA is not set
CONFIG_INPUT_UINPUT=m
# CONFIG_INPUT_PALMAS_PWRBUTTON is not set
# CONFIG_INPUT_PCF8574 is not set
CONFIG_INPUT_PWM_BEEPER=y
CONFIG_INPUT_PWM_VIBRA=y
CONFIG_INPUT_RK805_PWRKEY=m
# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
CONFIG_INPUT_DA9052_ONKEY=y
CONFIG_INPUT_DA9063_ONKEY=m
CONFIG_INPUT_WM831X_ON=y
CONFIG_INPUT_ADXL34X=m
# CONFIG_INPUT_ADXL34X_I2C is not set
CONFIG_INPUT_ADXL34X_SPI=m
CONFIG_INPUT_IMS_PCU=y
CONFIG_INPUT_CMA3000=m
CONFIG_INPUT_CMA3000_I2C=m
CONFIG_INPUT_IDEAPAD_SLIDEBAR=y
CONFIG_INPUT_DRV260X_HAPTICS=y
CONFIG_INPUT_DRV2665_HAPTICS=m
CONFIG_INPUT_DRV2667_HAPTICS=y
# CONFIG_INPUT_HISI_POWERKEY is not set
CONFIG_INPUT_SC27XX_VIBRA=m
CONFIG_INPUT_STPMIC1_ONKEY=m
CONFIG_RMI4_CORE=y
CONFIG_RMI4_I2C=y
# CONFIG_RMI4_SPI is not set
CONFIG_RMI4_SMB=y
CONFIG_RMI4_F03=y
CONFIG_RMI4_F03_SERIO=y
CONFIG_RMI4_2D_SENSOR=y
CONFIG_RMI4_F11=y
CONFIG_RMI4_F12=y
CONFIG_RMI4_F30=y
CONFIG_RMI4_F34=y
CONFIG_RMI4_F55=y

#
# Hardware I/O ports
#
CONFIG_SERIO=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_SERIO_I8042=y
CONFIG_SERIO_CT82C710=y
CONFIG_SERIO_PCIPS2=m
CONFIG_SERIO_LIBPS2=y
CONFIG_SERIO_RAW=m
CONFIG_SERIO_ALTERA_PS2=y
# CONFIG_SERIO_PS2MULT is not set
# CONFIG_SERIO_ARC_PS2 is not set
CONFIG_SERIO_APBPS2=y
# CONFIG_SERIO_OLPC_APSP is not set
CONFIG_HYPERV_KEYBOARD=m
CONFIG_SERIO_SUN4I_PS2=y
CONFIG_SERIO_GPIO_PS2=m
# CONFIG_USERIO is not set
CONFIG_GAMEPORT=y
# CONFIG_GAMEPORT_NS558 is not set
# CONFIG_GAMEPORT_L4 is not set
CONFIG_GAMEPORT_EMU10K1=y
CONFIG_GAMEPORT_FM801=y

#
# Character devices
#
# CONFIG_TTY is not set
CONFIG_DEVMEM=y
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_DEV_BUS=m
CONFIG_IPMI_HANDLER=m
CONFIG_IPMI_DMI_DECODE=y
CONFIG_IPMI_PLAT_DATA=y
CONFIG_IPMI_PANIC_EVENT=y
# CONFIG_IPMI_PANIC_STRING is not set
CONFIG_IPMI_DEVICE_INTERFACE=m
CONFIG_IPMI_SI=m
CONFIG_IPMI_SSIF=m
CONFIG_IPMI_WATCHDOG=m
CONFIG_IPMI_POWEROFF=m
CONFIG_IPMI_KCS_BMC=y
CONFIG_ASPEED_KCS_IPMI_BMC=m
CONFIG_NPCM7XX_KCS_IPMI_BMC=y
CONFIG_ASPEED_BT_IPMI_BMC=m
# CONFIG_HW_RANDOM is not set
CONFIG_NVRAM=m
CONFIG_APPLICOM=y
# CONFIG_SONYPI is not set
# CONFIG_SCx200_GPIO is not set
CONFIG_PC8736x_GPIO=m
CONFIG_NSC_GPIO=m
CONFIG_HPET=y
# CONFIG_HPET_MMAP is not set
CONFIG_HANGCHECK_TIMER=m
CONFIG_TCG_TPM=y
CONFIG_TCG_TIS_CORE=m
CONFIG_TCG_TIS=m
# CONFIG_TCG_TIS_SPI is not set
CONFIG_TCG_TIS_I2C_ATMEL=y
# CONFIG_TCG_TIS_I2C_INFINEON is not set
# CONFIG_TCG_TIS_I2C_NUVOTON is not set
# CONFIG_TCG_NSC is not set
CONFIG_TCG_ATMEL=y
CONFIG_TCG_INFINEON=m
CONFIG_TCG_CRB=m
CONFIG_TCG_VTPM_PROXY=m
CONFIG_TCG_TIS_ST33ZP24=y
# CONFIG_TCG_TIS_ST33ZP24_I2C is not set
CONFIG_TCG_TIS_ST33ZP24_SPI=y
# CONFIG_TELCLOCK is not set
CONFIG_DEVPORT=y
CONFIG_XILLYBUS=y
CONFIG_XILLYBUS_PCIE=y
CONFIG_XILLYBUS_OF=m
CONFIG_RANDOM_TRUST_CPU=y

#
# I2C support
#
CONFIG_I2C=y
# CONFIG_ACPI_I2C_OPREGION is not set
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=m

#
# Multiplexer I2C Chip support
#
CONFIG_I2C_ARB_GPIO_CHALLENGE=m
CONFIG_I2C_MUX_GPIO=m
# CONFIG_I2C_MUX_GPMUX is not set
CONFIG_I2C_MUX_LTC4306=m
CONFIG_I2C_MUX_PCA9541=m
CONFIG_I2C_MUX_PCA954x=m
# CONFIG_I2C_MUX_PINCTRL is not set
# CONFIG_I2C_MUX_REG is not set
# CONFIG_I2C_DEMUX_PINCTRL is not set
CONFIG_I2C_MUX_MLXCPLD=m
CONFIG_I2C_HELPER_AUTO=y
CONFIG_I2C_SMBUS=y
CONFIG_I2C_ALGOBIT=y
CONFIG_I2C_ALGOPCA=y

#
# I2C Hardware Bus support
#

#
# PC SMBus host controller drivers
#
# CONFIG_I2C_ALI1535 is not set
CONFIG_I2C_ALI1563=y
# CONFIG_I2C_ALI15X3 is not set
CONFIG_I2C_AMD756=y
CONFIG_I2C_AMD756_S4882=y
# CONFIG_I2C_AMD8111 is not set
CONFIG_I2C_AMD_MP2=y
CONFIG_I2C_HIX5HD2=y
CONFIG_I2C_I801=y
# CONFIG_I2C_ISCH is not set
# CONFIG_I2C_ISMT is not set
CONFIG_I2C_PIIX4=m
CONFIG_I2C_NFORCE2=y
CONFIG_I2C_NFORCE2_S4985=y
CONFIG_I2C_NVIDIA_GPU=m
CONFIG_I2C_SIS5595=m
CONFIG_I2C_SIS630=m
CONFIG_I2C_SIS96X=m
CONFIG_I2C_VIA=y
CONFIG_I2C_VIAPRO=y

#
# ACPI drivers
#
# CONFIG_I2C_SCMI is not set

#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
CONFIG_I2C_ASPEED=y
# CONFIG_I2C_AXXIA is not set
# CONFIG_I2C_BCM_IPROC is not set
# CONFIG_I2C_BRCMSTB is not set
CONFIG_I2C_CBUS_GPIO=y
# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
# CONFIG_I2C_DESIGNWARE_PCI is not set
CONFIG_I2C_EFM32=m
CONFIG_I2C_EG20T=y
# CONFIG_I2C_EMEV2 is not set
CONFIG_I2C_GPIO=y
# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set
CONFIG_I2C_IMG=m
# CONFIG_I2C_IMX_LPI2C is not set
CONFIG_I2C_JZ4780=y
CONFIG_I2C_KEMPLD=m
CONFIG_I2C_LPC2K=m
# CONFIG_I2C_MESON is not set
CONFIG_I2C_MT65XX=m
CONFIG_I2C_OCORES=y
CONFIG_I2C_OWL=m
CONFIG_I2C_PCA_PLATFORM=y
# CONFIG_I2C_PXA is not set
CONFIG_I2C_RIIC=m
# CONFIG_I2C_RK3X is not set
CONFIG_I2C_SH_MOBILE=y
CONFIG_I2C_SIMTEC=m
# CONFIG_I2C_STM32F4 is not set
CONFIG_I2C_STM32F7=y
CONFIG_I2C_SUN6I_P2WI=y
CONFIG_I2C_SYNQUACER=m
# CONFIG_I2C_UNIPHIER is not set
CONFIG_I2C_UNIPHIER_F=m
CONFIG_I2C_VERSATILE=m
CONFIG_I2C_XILINX=y
CONFIG_I2C_XLP9XX=m
# CONFIG_I2C_RCAR is not set

#
# External I2C/SMBus adapter drivers
#
# CONFIG_I2C_DIOLAN_U2C is not set
# CONFIG_I2C_DLN2 is not set
CONFIG_I2C_PARPORT_LIGHT=y
CONFIG_I2C_ROBOTFUZZ_OSIF=y
CONFIG_I2C_TINY_USB=m

#
# Other I2C/SMBus bus drivers
#
CONFIG_SCx200_ACB=m
CONFIG_I2C_FSI=m
# CONFIG_I2C_STUB is not set
CONFIG_I2C_SLAVE=y
CONFIG_I2C_SLAVE_EEPROM=y
# CONFIG_I2C_DEBUG_CORE is not set
CONFIG_I2C_DEBUG_ALGO=y
CONFIG_I2C_DEBUG_BUS=y
CONFIG_I3C=m
# CONFIG_CDNS_I3C_MASTER is not set
CONFIG_DW_I3C_MASTER=m
CONFIG_SPI=y
CONFIG_SPI_DEBUG=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y

#
# SPI Master Controller Drivers
#
CONFIG_SPI_ALTERA=y
# CONFIG_SPI_ATH79 is not set
CONFIG_SPI_ARMADA_3700=y
# CONFIG_SPI_ATMEL is not set
# CONFIG_SPI_AT91_USART is not set
CONFIG_SPI_AXI_SPI_ENGINE=y
CONFIG_SPI_BCM2835=y
# CONFIG_SPI_BCM2835AUX is not set
CONFIG_SPI_BCM63XX=y
CONFIG_SPI_BCM63XX_HSSPI=y
# CONFIG_SPI_BCM_QSPI is not set
CONFIG_SPI_BITBANG=y
CONFIG_SPI_CADENCE=m
CONFIG_SPI_CLPS711X=y
# CONFIG_SPI_DESIGNWARE is not set
CONFIG_SPI_DLN2=m
# CONFIG_SPI_EP93XX is not set
CONFIG_SPI_FSL_LPSPI=y
CONFIG_SPI_FSL_QUADSPI=m
# CONFIG_SPI_NXP_FLEXSPI is not set
CONFIG_SPI_GPIO=m
# CONFIG_SPI_IMG_SPFI is not set
CONFIG_SPI_IMX=m
CONFIG_SPI_JCORE=m
CONFIG_SPI_LP8841_RTC=m
CONFIG_SPI_FSL_LIB=y
CONFIG_SPI_FSL_SPI=y
CONFIG_SPI_FSL_DSPI=m
CONFIG_SPI_MESON_SPICC=m
CONFIG_SPI_MESON_SPIFC=m
CONFIG_SPI_MT65XX=y
# CONFIG_SPI_MT7621 is not set
CONFIG_SPI_NPCM_PSPI=m
CONFIG_SPI_LANTIQ_SSC=m
CONFIG_SPI_OC_TINY=y
CONFIG_SPI_OMAP24XX=y
CONFIG_SPI_TI_QSPI=m
# CONFIG_SPI_OMAP_100K is not set
# CONFIG_SPI_ORION is not set
# CONFIG_SPI_PIC32 is not set
# CONFIG_SPI_PIC32_SQI is not set
CONFIG_SPI_PXA2XX=y
CONFIG_SPI_PXA2XX_PCI=y
CONFIG_SPI_ROCKCHIP=y
CONFIG_SPI_RSPI=y
CONFIG_SPI_S3C64XX=m
CONFIG_SPI_SC18IS602=y
# CONFIG_SPI_SH_MSIOF is not set
CONFIG_SPI_SH=y
CONFIG_SPI_SH_HSPI=y
CONFIG_SPI_SIFIVE=y
CONFIG_SPI_SLAVE_MT27XX=m
CONFIG_SPI_SPRD=m
# CONFIG_SPI_SPRD_ADI is not set
# CONFIG_SPI_STM32 is not set
# CONFIG_SPI_STM32_QSPI is not set
CONFIG_SPI_ST_SSC4=y
CONFIG_SPI_SUN4I=m
CONFIG_SPI_SUN6I=m
CONFIG_SPI_MXIC=m
CONFIG_SPI_TEGRA114=m
# CONFIG_SPI_TEGRA20_SFLASH is not set
CONFIG_SPI_TEGRA20_SLINK=m
CONFIG_SPI_TOPCLIFF_PCH=m
CONFIG_SPI_TXX9=m
CONFIG_SPI_UNIPHIER=m
CONFIG_SPI_XCOMM=m
CONFIG_SPI_XILINX=y
# CONFIG_SPI_XLP is not set
CONFIG_SPI_XTENSA_XTFPGA=m
CONFIG_SPI_ZYNQ_QSPI=m
CONFIG_SPI_ZYNQMP_GQSPI=m

#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
CONFIG_SPI_LOOPBACK_TEST=m
# CONFIG_SPI_TLE62X0 is not set
CONFIG_SPI_SLAVE=y
CONFIG_SPI_SLAVE_TIME=y
CONFIG_SPI_SLAVE_SYSTEM_CONTROL=m
CONFIG_SPMI=m
CONFIG_SPMI_MSM_PMIC_ARB=m
CONFIG_HSI=y
CONFIG_HSI_BOARDINFO=y

#
# HSI controllers
#

#
# HSI clients
#
CONFIG_HSI_CHAR=m
CONFIG_PPS=y
# CONFIG_PPS_DEBUG is not set
# CONFIG_NTP_PPS is not set

#
# PPS clients support
#
# CONFIG_PPS_CLIENT_KTIMER is not set
CONFIG_PPS_CLIENT_GPIO=y

#
# PPS generators support
#

#
# PTP clock support
#

#
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
#
CONFIG_PINCTRL=y
CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_PINMUX=y
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
CONFIG_PINCONF=y
CONFIG_GENERIC_PINCONF=y
CONFIG_DEBUG_PINCTRL=y
CONFIG_PINCTRL_AS3722=m
CONFIG_PINCTRL_AMD=m
CONFIG_PINCTRL_DA850_PUPD=y
# CONFIG_PINCTRL_LPC18XX is not set
# CONFIG_PINCTRL_MCP23S08 is not set
CONFIG_PINCTRL_RZA1=y
# CONFIG_PINCTRL_RZA2 is not set
CONFIG_PINCTRL_RZN1=y
CONFIG_PINCTRL_SINGLE=m
# CONFIG_PINCTRL_SX150X is not set
CONFIG_PINCTRL_PALMAS=y
# CONFIG_PINCTRL_INGENIC is not set
# CONFIG_PINCTRL_RK805 is not set
# CONFIG_PINCTRL_OCELOT is not set
CONFIG_PINCTRL_OWL=y
CONFIG_PINCTRL_S700=y
CONFIG_PINCTRL_S900=y
CONFIG_PINCTRL_ASPEED=y
# CONFIG_PINCTRL_ASPEED_G4 is not set
CONFIG_PINCTRL_ASPEED_G5=y
# CONFIG_PINCTRL_BCM281XX is not set
CONFIG_PINCTRL_IPROC_GPIO=y
# CONFIG_PINCTRL_CYGNUS_MUX is not set
# CONFIG_PINCTRL_NS is not set
CONFIG_PINCTRL_NSP_GPIO=y
# CONFIG_PINCTRL_NS2_MUX is not set
# CONFIG_PINCTRL_NSP_MUX is not set
CONFIG_PINCTRL_BERLIN=y
CONFIG_PINCTRL_AS370=y
CONFIG_PINCTRL_BERLIN_BG4CT=y
# CONFIG_PINCTRL_BAYTRAIL is not set
CONFIG_PINCTRL_CHERRYVIEW=m
CONFIG_PINCTRL_INTEL=y
CONFIG_PINCTRL_BROXTON=y
CONFIG_PINCTRL_CANNONLAKE=y
CONFIG_PINCTRL_CEDARFORK=y
CONFIG_PINCTRL_DENVERTON=m
CONFIG_PINCTRL_GEMINILAKE=m
CONFIG_PINCTRL_ICELAKE=m
CONFIG_PINCTRL_LEWISBURG=y
# CONFIG_PINCTRL_SUNRISEPOINT is not set
# CONFIG_PINCTRL_NPCM7XX is not set
CONFIG_PINCTRL_PXA=y
CONFIG_PINCTRL_PXA25X=m
CONFIG_PINCTRL_PXA27X=y
CONFIG_PINCTRL_MSM=y
CONFIG_PINCTRL_APQ8064=m
CONFIG_PINCTRL_APQ8084=m
CONFIG_PINCTRL_IPQ4019=y
# CONFIG_PINCTRL_IPQ8064 is not set
# CONFIG_PINCTRL_IPQ8074 is not set
# CONFIG_PINCTRL_MSM8660 is not set
CONFIG_PINCTRL_MSM8960=y
# CONFIG_PINCTRL_MDM9615 is not set
# CONFIG_PINCTRL_MSM8X74 is not set
CONFIG_PINCTRL_MSM8916=y
CONFIG_PINCTRL_MSM8994=m
CONFIG_PINCTRL_MSM8996=m
# CONFIG_PINCTRL_MSM8998 is not set
CONFIG_PINCTRL_QCS404=m
CONFIG_PINCTRL_QDF2XXX=y
# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set
# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set
# CONFIG_PINCTRL_SDM660 is not set
CONFIG_PINCTRL_SDM845=m
CONFIG_PINCTRL_SH_PFC=y
CONFIG_PINCTRL_SH_PFC_GPIO=y
CONFIG_PINCTRL_SH_FUNC_GPIO=y
# CONFIG_PINCTRL_PFC_EMEV2 is not set
CONFIG_PINCTRL_PFC_R8A73A4=y
CONFIG_PINCTRL_PFC_R8A7740=y
CONFIG_PINCTRL_PFC_R8A7743=y
# CONFIG_PINCTRL_PFC_R8A7744 is not set
# CONFIG_PINCTRL_PFC_R8A7745 is not set
# CONFIG_PINCTRL_PFC_R8A77470 is not set
# CONFIG_PINCTRL_PFC_R8A774A1 is not set
# CONFIG_PINCTRL_PFC_R8A774C0 is not set
# CONFIG_PINCTRL_PFC_R8A7778 is not set
CONFIG_PINCTRL_PFC_R8A7779=y
# CONFIG_PINCTRL_PFC_R8A7790 is not set
CONFIG_PINCTRL_PFC_R8A7791=y
# CONFIG_PINCTRL_PFC_R8A7792 is not set
# CONFIG_PINCTRL_PFC_R8A7793 is not set
# CONFIG_PINCTRL_PFC_R8A7794 is not set
CONFIG_PINCTRL_PFC_R8A7795=y
# CONFIG_PINCTRL_PFC_R8A7796 is not set
# CONFIG_PINCTRL_PFC_R8A77965 is not set
CONFIG_PINCTRL_PFC_R8A77970=y
CONFIG_PINCTRL_PFC_R8A77980=y
CONFIG_PINCTRL_PFC_R8A77990=y
CONFIG_PINCTRL_PFC_R8A77995=y
# CONFIG_PINCTRL_PFC_SH7203 is not set
# CONFIG_PINCTRL_PFC_SH7264 is not set
# CONFIG_PINCTRL_PFC_SH7269 is not set
# CONFIG_PINCTRL_PFC_SH73A0 is not set
# CONFIG_PINCTRL_PFC_SH7720 is not set
# CONFIG_PINCTRL_PFC_SH7722 is not set
# CONFIG_PINCTRL_PFC_SH7723 is not set
CONFIG_PINCTRL_PFC_SH7724=y
# CONFIG_PINCTRL_PFC_SH7734 is not set
# CONFIG_PINCTRL_PFC_SH7757 is not set
CONFIG_PINCTRL_PFC_SH7785=y
# CONFIG_PINCTRL_PFC_SH7786 is not set
# CONFIG_PINCTRL_PFC_SHX3 is not set
CONFIG_PINCTRL_SPRD=y
CONFIG_PINCTRL_SPRD_SC9860=y
CONFIG_PINCTRL_STM32=y
CONFIG_PINCTRL_STM32F429=y
CONFIG_PINCTRL_STM32F469=y
# CONFIG_PINCTRL_STM32F746 is not set
# CONFIG_PINCTRL_STM32F769 is not set
CONFIG_PINCTRL_STM32H743=y
# CONFIG_PINCTRL_STM32MP157 is not set
# CONFIG_PINCTRL_TI_IODELAY is not set
CONFIG_PINCTRL_UNIPHIER=y
# CONFIG_PINCTRL_UNIPHIER_LD4 is not set
CONFIG_PINCTRL_UNIPHIER_PRO4=y
# CONFIG_PINCTRL_UNIPHIER_SLD8 is not set
CONFIG_PINCTRL_UNIPHIER_PRO5=y
# CONFIG_PINCTRL_UNIPHIER_PXS2 is not set
CONFIG_PINCTRL_UNIPHIER_LD6B=y
CONFIG_PINCTRL_UNIPHIER_LD11=y
# CONFIG_PINCTRL_UNIPHIER_LD20 is not set
# CONFIG_PINCTRL_UNIPHIER_PXS3 is not set

#
# MediaTek pinctrl drivers
#
CONFIG_EINT_MTK=y
CONFIG_PINCTRL_MTK=y
CONFIG_PINCTRL_MTK_MOORE=y
CONFIG_PINCTRL_MTK_PARIS=y
# CONFIG_PINCTRL_MT2701 is not set
# CONFIG_PINCTRL_MT7623 is not set
CONFIG_PINCTRL_MT7629=y
# CONFIG_PINCTRL_MT8135 is not set
# CONFIG_PINCTRL_MT8127 is not set
# CONFIG_PINCTRL_MT2712 is not set
CONFIG_PINCTRL_MT6765=y
CONFIG_PINCTRL_MT6797=y
# CONFIG_PINCTRL_MT7622 is not set
CONFIG_PINCTRL_MT8173=y
CONFIG_PINCTRL_MT8183=y
CONFIG_PINCTRL_MT6397=y
CONFIG_PINCTRL_MADERA=y
CONFIG_PINCTRL_CS47L35=y
CONFIG_PINCTRL_CS47L90=y
CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
CONFIG_OF_GPIO=y
CONFIG_GPIO_ACPI=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_DEBUG_GPIO=y
# CONFIG_GPIO_SYSFS is not set
CONFIG_GPIO_GENERIC=y
CONFIG_GPIO_MAX730X=y

#
# Memory mapped GPIO drivers
#
CONFIG_GPIO_74XX_MMIO=y
CONFIG_GPIO_ALTERA=y
CONFIG_GPIO_AMDPT=y
# CONFIG_GPIO_ASPEED is not set
CONFIG_GPIO_ATH79=m
# CONFIG_GPIO_RASPBERRYPI_EXP is not set
CONFIG_GPIO_BCM_KONA=y
CONFIG_GPIO_BRCMSTB=m
CONFIG_GPIO_CADENCE=m
# CONFIG_GPIO_CLPS711X is not set
CONFIG_GPIO_DWAPB=m
# CONFIG_GPIO_EIC_SPRD is not set
CONFIG_GPIO_EM=m
CONFIG_GPIO_FTGPIO010=y
# CONFIG_GPIO_GENERIC_PLATFORM is not set
# CONFIG_GPIO_GRGPIO is not set
CONFIG_GPIO_HLWD=y
CONFIG_GPIO_ICH=m
CONFIG_GPIO_IOP=m
CONFIG_GPIO_LPC18XX=m
# CONFIG_GPIO_LYNXPOINT is not set
CONFIG_GPIO_MB86S7X=m
CONFIG_GPIO_MENZ127=m
CONFIG_GPIO_MPC8XXX=y
# CONFIG_GPIO_MT7621 is not set
CONFIG_GPIO_PMIC_EIC_SPRD=y
CONFIG_GPIO_RCAR=m
# CONFIG_GPIO_SAMA5D2_PIOBU is not set
CONFIG_GPIO_SIOX=m
# CONFIG_GPIO_SNPS_CREG is not set
CONFIG_GPIO_SPRD=m
CONFIG_GPIO_SYSCON=m
CONFIG_GPIO_TEGRA=y
# CONFIG_GPIO_TEGRA186 is not set
CONFIG_GPIO_TS4800=m
CONFIG_GPIO_UNIPHIER=y
CONFIG_GPIO_VX855=y
CONFIG_GPIO_XILINX=y
CONFIG_GPIO_XLP=m
# CONFIG_GPIO_ZX is not set
CONFIG_GPIO_AMD_FCH=y

#
# Port-mapped I/O GPIO drivers
#
CONFIG_GPIO_F7188X=m
CONFIG_GPIO_IT87=y
# CONFIG_GPIO_SCH is not set
# CONFIG_GPIO_SCH311X is not set
CONFIG_GPIO_TS5500=m
CONFIG_GPIO_WINBOND=m
CONFIG_GPIO_WS16C48=m

#
# I2C GPIO expanders
#
CONFIG_GPIO_ADP5588=m
CONFIG_GPIO_ADNP=m
CONFIG_GPIO_GW_PLD=m
CONFIG_GPIO_MAX7300=y
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
CONFIG_GPIO_PCF857X=y
# CONFIG_GPIO_TPIC2810 is not set
CONFIG_GPIO_TS4900=y

#
# MFD GPIO expanders
#
CONFIG_GPIO_ARIZONA=y
CONFIG_GPIO_BD9571MWV=m
CONFIG_GPIO_CS5535=y
CONFIG_GPIO_DA9052=y
CONFIG_GPIO_DLN2=y
# CONFIG_GPIO_JANZ_TTL is not set
# CONFIG_GPIO_KEMPLD is not set
# CONFIG_GPIO_LP3943 is not set
CONFIG_GPIO_LP87565=m
CONFIG_GPIO_MADERA=y
# CONFIG_GPIO_PALMAS is not set
CONFIG_GPIO_STMPE=y
# CONFIG_GPIO_TIMBERDALE is not set
CONFIG_GPIO_TPS6586X=y
# CONFIG_GPIO_TQMX86 is not set
CONFIG_GPIO_TWL4030=y
CONFIG_GPIO_TWL6040=y
CONFIG_GPIO_WHISKEY_COVE=m
CONFIG_GPIO_WM831X=y

#
# PCI GPIO expanders
#
CONFIG_GPIO_AMD8111=m
# CONFIG_GPIO_BT8XX is not set
CONFIG_GPIO_ML_IOH=y
CONFIG_GPIO_PCH=m
CONFIG_GPIO_PCI_IDIO_16=y
# CONFIG_GPIO_PCIE_IDIO_24 is not set
CONFIG_GPIO_RDC321X=m
CONFIG_GPIO_SODAVILLE=y

#
# SPI GPIO expanders
#
CONFIG_GPIO_74X164=y
# CONFIG_GPIO_MAX3191X is not set
CONFIG_GPIO_MAX7301=y
CONFIG_GPIO_MC33880=m
CONFIG_GPIO_PISOSR=m
# CONFIG_GPIO_XRA1403 is not set

#
# USB GPIO expanders
#
CONFIG_GPIO_MOCKUP=y
CONFIG_W1=y

#
# 1-wire Bus Masters
#
# CONFIG_W1_MASTER_MATROX is not set
CONFIG_W1_MASTER_DS2490=m
# CONFIG_W1_MASTER_DS2482 is not set
CONFIG_W1_MASTER_MXC=y
# CONFIG_W1_MASTER_DS1WM is not set
CONFIG_W1_MASTER_GPIO=y

#
# 1-wire Slaves
#
CONFIG_W1_SLAVE_THERM=y
CONFIG_W1_SLAVE_SMEM=y
CONFIG_W1_SLAVE_DS2405=y
CONFIG_W1_SLAVE_DS2408=y
# CONFIG_W1_SLAVE_DS2408_READBACK is not set
CONFIG_W1_SLAVE_DS2413=m
# CONFIG_W1_SLAVE_DS2406 is not set
CONFIG_W1_SLAVE_DS2423=m
CONFIG_W1_SLAVE_DS2805=m
# CONFIG_W1_SLAVE_DS2431 is not set
CONFIG_W1_SLAVE_DS2433=m
CONFIG_W1_SLAVE_DS2433_CRC=y
CONFIG_W1_SLAVE_DS2438=m
CONFIG_W1_SLAVE_DS2780=m
CONFIG_W1_SLAVE_DS2781=m
# CONFIG_W1_SLAVE_DS28E04 is not set
# CONFIG_W1_SLAVE_DS28E17 is not set
# CONFIG_POWER_AVS is not set
CONFIG_POWER_RESET=y
# CONFIG_POWER_RESET_AS3722 is not set
# CONFIG_POWER_RESET_BRCMKONA is not set
# CONFIG_POWER_RESET_BRCMSTB is not set
CONFIG_POWER_RESET_GEMINI_POWEROFF=y
# CONFIG_POWER_RESET_GPIO is not set
# CONFIG_POWER_RESET_GPIO_RESTART is not set
# CONFIG_POWER_RESET_OCELOT_RESET is not set
CONFIG_POWER_RESET_PIIX4_POWEROFF=y
CONFIG_POWER_RESET_LTC2952=y
# CONFIG_POWER_RESET_RESTART is not set
CONFIG_POWER_RESET_KEYSTONE=y
CONFIG_POWER_RESET_SYSCON=y
# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
CONFIG_POWER_RESET_RMOBILE=y
# CONFIG_POWER_RESET_ZX is not set
CONFIG_REBOOT_MODE=y
CONFIG_SYSCON_REBOOT_MODE=y
# CONFIG_POWER_RESET_SC27XX is not set
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
# CONFIG_PDA_POWER is not set
# CONFIG_GENERIC_ADC_BATTERY is not set
CONFIG_MAX8925_POWER=y
CONFIG_WM831X_BACKUP=y
CONFIG_WM831X_POWER=m
CONFIG_TEST_POWER=m
# CONFIG_BATTERY_88PM860X is not set
# CONFIG_CHARGER_ADP5061 is not set
# CONFIG_BATTERY_ACT8945A is not set
CONFIG_BATTERY_DS2760=y
# CONFIG_BATTERY_DS2780 is not set
CONFIG_BATTERY_DS2781=m
CONFIG_BATTERY_DS2782=m
# CONFIG_BATTERY_LEGO_EV3 is not set
CONFIG_BATTERY_OLPC=m
CONFIG_BATTERY_SBS=y
CONFIG_CHARGER_SBS=y
CONFIG_MANAGER_SBS=m
CONFIG_BATTERY_BQ27XXX=m
CONFIG_BATTERY_BQ27XXX_I2C=m
CONFIG_BATTERY_BQ27XXX_HDQ=m
CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM=y
CONFIG_BATTERY_DA9030=m
# CONFIG_BATTERY_DA9052 is not set
CONFIG_BATTERY_MAX17040=m
CONFIG_BATTERY_MAX17042=y
CONFIG_BATTERY_MAX1721X=m
CONFIG_BATTERY_TWL4030_MADC=m
# CONFIG_BATTERY_RX51 is not set
# CONFIG_CHARGER_ISP1704 is not set
# CONFIG_CHARGER_MAX8903 is not set
CONFIG_CHARGER_TWL4030=m
CONFIG_CHARGER_LP8727=m
CONFIG_CHARGER_GPIO=m
# CONFIG_CHARGER_MANAGER is not set
CONFIG_CHARGER_LT3651=y
# CONFIG_CHARGER_MAX14577 is not set
CONFIG_CHARGER_DETECTOR_MAX14656=y
# CONFIG_CHARGER_MAX77693 is not set
# CONFIG_CHARGER_MAX8997 is not set
CONFIG_CHARGER_QCOM_SMBB=y
CONFIG_CHARGER_BQ2415X=y
# CONFIG_CHARGER_BQ24190 is not set
CONFIG_CHARGER_BQ24257=y
# CONFIG_CHARGER_BQ24735 is not set
# CONFIG_CHARGER_BQ25890 is not set
# CONFIG_CHARGER_SMB347 is not set
CONFIG_CHARGER_TPS65090=m
CONFIG_CHARGER_TPS65217=m
# CONFIG_BATTERY_GAUGE_LTC2941 is not set
CONFIG_BATTERY_GOLDFISH=m
CONFIG_BATTERY_RT5033=m
CONFIG_CHARGER_RT9455=y
CONFIG_CHARGER_SC2731=y
# CONFIG_FUEL_GAUGE_SC27XX is not set
CONFIG_HWMON=y
CONFIG_HWMON_VID=y
CONFIG_HWMON_DEBUG_CHIP=y

#
# Native drivers
#
CONFIG_SENSORS_ABITUGURU=y
CONFIG_SENSORS_ABITUGURU3=m
# CONFIG_SENSORS_AD7314 is not set
CONFIG_SENSORS_AD7414=m
# CONFIG_SENSORS_AD7418 is not set
CONFIG_SENSORS_ADM1021=m
CONFIG_SENSORS_ADM1025=m
CONFIG_SENSORS_ADM1026=y
# CONFIG_SENSORS_ADM1029 is not set
CONFIG_SENSORS_ADM1031=m
CONFIG_SENSORS_ADM9240=y
CONFIG_SENSORS_ADT7X10=m
CONFIG_SENSORS_ADT7310=m
CONFIG_SENSORS_ADT7410=m
CONFIG_SENSORS_ADT7411=y
CONFIG_SENSORS_ADT7462=m
CONFIG_SENSORS_ADT7470=y
CONFIG_SENSORS_ADT7475=m
CONFIG_SENSORS_ASC7621=y
CONFIG_SENSORS_K8TEMP=m
CONFIG_SENSORS_K10TEMP=m
CONFIG_SENSORS_FAM15H_POWER=m
CONFIG_SENSORS_APPLESMC=y
# CONFIG_SENSORS_ARM_SCMI is not set
# CONFIG_SENSORS_ASB100 is not set
CONFIG_SENSORS_ASPEED=m
CONFIG_SENSORS_ATXP1=y
CONFIG_SENSORS_DS620=y
CONFIG_SENSORS_DS1621=m
CONFIG_SENSORS_DELL_SMM=m
# CONFIG_SENSORS_DA9052_ADC is not set
CONFIG_SENSORS_I5K_AMB=m
CONFIG_SENSORS_F71805F=m
CONFIG_SENSORS_F71882FG=y
CONFIG_SENSORS_F75375S=m
# CONFIG_SENSORS_MC13783_ADC is not set
CONFIG_SENSORS_FSCHMD=y
# CONFIG_SENSORS_FTSTEUTATES is not set
CONFIG_SENSORS_GL518SM=y
CONFIG_SENSORS_GL520SM=m
CONFIG_SENSORS_G760A=m
CONFIG_SENSORS_G762=y
CONFIG_SENSORS_GPIO_FAN=m
CONFIG_SENSORS_HIH6130=m
CONFIG_SENSORS_IBMAEM=m
# CONFIG_SENSORS_IBMPEX is not set
CONFIG_SENSORS_IIO_HWMON=m
# CONFIG_SENSORS_I5500 is not set
CONFIG_SENSORS_CORETEMP=y
# CONFIG_SENSORS_IT87 is not set
CONFIG_SENSORS_JC42=y
CONFIG_SENSORS_POWR1220=y
CONFIG_SENSORS_LINEAGE=m
# CONFIG_SENSORS_LTC2945 is not set
CONFIG_SENSORS_LTC2990=y
CONFIG_SENSORS_LTC4151=y
# CONFIG_SENSORS_LTC4215 is not set
# CONFIG_SENSORS_LTC4222 is not set
# CONFIG_SENSORS_LTC4245 is not set
# CONFIG_SENSORS_LTC4260 is not set
# CONFIG_SENSORS_LTC4261 is not set
# CONFIG_SENSORS_MAX1111 is not set
# CONFIG_SENSORS_MAX16065 is not set
# CONFIG_SENSORS_MAX1619 is not set
CONFIG_SENSORS_MAX1668=m
# CONFIG_SENSORS_MAX197 is not set
# CONFIG_SENSORS_MAX31722 is not set
CONFIG_SENSORS_MAX6621=y
# CONFIG_SENSORS_MAX6639 is not set
CONFIG_SENSORS_MAX6642=y
CONFIG_SENSORS_MAX6650=m
CONFIG_SENSORS_MAX6697=y
CONFIG_SENSORS_MAX31790=m
CONFIG_SENSORS_MCP3021=y
# CONFIG_SENSORS_TC654 is not set
CONFIG_SENSORS_ADCXX=y
CONFIG_SENSORS_LM63=y
# CONFIG_SENSORS_LM70 is not set
# CONFIG_SENSORS_LM73 is not set
# CONFIG_SENSORS_LM75 is not set
# CONFIG_SENSORS_LM77 is not set
CONFIG_SENSORS_LM78=m
# CONFIG_SENSORS_LM80 is not set
# CONFIG_SENSORS_LM83 is not set
# CONFIG_SENSORS_LM85 is not set
CONFIG_SENSORS_LM87=m
CONFIG_SENSORS_LM90=m
# CONFIG_SENSORS_LM92 is not set
CONFIG_SENSORS_LM93=m
CONFIG_SENSORS_LM95234=y
CONFIG_SENSORS_LM95241=y
CONFIG_SENSORS_LM95245=m
CONFIG_SENSORS_PC87360=m
# CONFIG_SENSORS_PC87427 is not set
CONFIG_SENSORS_NTC_THERMISTOR=m
# CONFIG_SENSORS_NCT6683 is not set
CONFIG_SENSORS_NCT6775=y
CONFIG_SENSORS_NCT7802=m
CONFIG_SENSORS_NCT7904=y
# CONFIG_SENSORS_NPCM7XX is not set
CONFIG_SENSORS_NSA320=y
CONFIG_SENSORS_OCC_P8_I2C=y
CONFIG_SENSORS_OCC_P9_SBE=m
CONFIG_SENSORS_OCC=y
# CONFIG_SENSORS_PCF8591 is not set
CONFIG_PMBUS=m
# CONFIG_SENSORS_PMBUS is not set
CONFIG_SENSORS_ADM1275=m
CONFIG_SENSORS_IBM_CFFPS=m
CONFIG_SENSORS_IR35221=m
CONFIG_SENSORS_LM25066=m
CONFIG_SENSORS_LTC2978=m
CONFIG_SENSORS_LTC2978_REGULATOR=y
# CONFIG_SENSORS_LTC3815 is not set
# CONFIG_SENSORS_MAX16064 is not set
CONFIG_SENSORS_MAX20751=m
# CONFIG_SENSORS_MAX31785 is not set
# CONFIG_SENSORS_MAX34440 is not set
CONFIG_SENSORS_MAX8688=m
CONFIG_SENSORS_TPS40422=m
# CONFIG_SENSORS_TPS53679 is not set
# CONFIG_SENSORS_UCD9000 is not set
# CONFIG_SENSORS_UCD9200 is not set
CONFIG_SENSORS_ZL6100=m
CONFIG_SENSORS_PWM_FAN=m
CONFIG_SENSORS_RASPBERRYPI_HWMON=y
# CONFIG_SENSORS_SHT15 is not set
# CONFIG_SENSORS_SHT21 is not set
# CONFIG_SENSORS_SHT3x is not set
CONFIG_SENSORS_SHTC1=m
CONFIG_SENSORS_SIS5595=m
CONFIG_SENSORS_DME1737=m
# CONFIG_SENSORS_EMC1403 is not set
CONFIG_SENSORS_EMC2103=y
# CONFIG_SENSORS_EMC6W201 is not set
CONFIG_SENSORS_SMSC47M1=m
CONFIG_SENSORS_SMSC47M192=y
# CONFIG_SENSORS_SMSC47B397 is not set
CONFIG_SENSORS_SCH56XX_COMMON=y
# CONFIG_SENSORS_SCH5627 is not set
CONFIG_SENSORS_SCH5636=y
# CONFIG_SENSORS_STTS751 is not set
CONFIG_SENSORS_SMM665=m
CONFIG_SENSORS_ADC128D818=y
# CONFIG_SENSORS_ADS1015 is not set
CONFIG_SENSORS_ADS7828=y
CONFIG_SENSORS_ADS7871=m
# CONFIG_SENSORS_AMC6821 is not set
CONFIG_SENSORS_INA209=m
# CONFIG_SENSORS_INA2XX is not set
CONFIG_SENSORS_INA3221=m
CONFIG_SENSORS_TC74=y
# CONFIG_SENSORS_THMC50 is not set
# CONFIG_SENSORS_TMP102 is not set
# CONFIG_SENSORS_TMP103 is not set
CONFIG_SENSORS_TMP108=m
CONFIG_SENSORS_TMP401=y
CONFIG_SENSORS_TMP421=m
CONFIG_SENSORS_VIA_CPUTEMP=y
CONFIG_SENSORS_VIA686A=m
CONFIG_SENSORS_VT1211=y
CONFIG_SENSORS_VT8231=y
CONFIG_SENSORS_W83773G=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83793 is not set
CONFIG_SENSORS_W83795=m
# CONFIG_SENSORS_W83795_FANCTRL is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83L786NG is not set
# CONFIG_SENSORS_W83627HF is not set
CONFIG_SENSORS_W83627EHF=y
CONFIG_SENSORS_WM831X=m

#
# ACPI drivers
#
# CONFIG_SENSORS_ACPI_POWER is not set
CONFIG_SENSORS_ATK0110=m
CONFIG_THERMAL=y
# CONFIG_THERMAL_STATISTICS is not set
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
CONFIG_THERMAL_HWMON=y
# CONFIG_THERMAL_OF is not set
CONFIG_THERMAL_WRITABLE_TRIPS=y
# CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE is not set
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=y
# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set
CONFIG_THERMAL_GOV_FAIR_SHARE=y
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_GOV_BANG_BANG=y
CONFIG_THERMAL_GOV_USER_SPACE=y
# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set
# CONFIG_THERMAL_EMULATION is not set
CONFIG_HISI_THERMAL=m
CONFIG_IMX_THERMAL=y
CONFIG_SPEAR_THERMAL=m
CONFIG_ROCKCHIP_THERMAL=m
CONFIG_RCAR_THERMAL=y
CONFIG_RCAR_GEN3_THERMAL=y
CONFIG_KIRKWOOD_THERMAL=y
CONFIG_DOVE_THERMAL=y
CONFIG_ARMADA_THERMAL=m
CONFIG_DA9062_THERMAL=y
CONFIG_MTK_THERMAL=m

#
# Intel thermal drivers
#
CONFIG_X86_PKG_TEMP_THERMAL=m
CONFIG_INTEL_SOC_DTS_IOSF_CORE=y
CONFIG_INTEL_SOC_DTS_THERMAL=y

#
# ACPI INT340X thermal drivers
#
# CONFIG_INT340X_THERMAL is not set
# CONFIG_INTEL_BXT_PMIC_THERMAL is not set
CONFIG_INTEL_PCH_THERMAL=m

#
# Broadcom thermal drivers
#
CONFIG_BRCMSTB_THERMAL=y
# CONFIG_BCM_NS_THERMAL is not set
CONFIG_BCM_SR_THERMAL=y

#
# Texas Instruments thermal drivers
#
CONFIG_TI_SOC_THERMAL=y
# CONFIG_TI_THERMAL is not set
CONFIG_OMAP3_THERMAL=y
CONFIG_OMAP4_THERMAL=y
# CONFIG_OMAP5_THERMAL is not set
# CONFIG_DRA752_THERMAL is not set

#
# Samsung thermal drivers
#
CONFIG_TANGO_THERMAL=y
CONFIG_GENERIC_ADC_THERMAL=m

#
# Qualcomm thermal drivers
#
CONFIG_QCOM_SPMI_TEMP_ALARM=m
CONFIG_ZX2967_THERMAL=m
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_CORE=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
# CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED is not set
# CONFIG_WATCHDOG_SYSFS is not set

#
# Watchdog Device Drivers
#
# CONFIG_SOFT_WATCHDOG is not set
# CONFIG_DA9052_WATCHDOG is not set
CONFIG_DA9055_WATCHDOG=m
CONFIG_DA9063_WATCHDOG=m
CONFIG_DA9062_WATCHDOG=y
# CONFIG_GPIO_WATCHDOG is not set
# CONFIG_MENF21BMC_WATCHDOG is not set
CONFIG_MENZ069_WATCHDOG=y
CONFIG_TANGOX_WATCHDOG=y
CONFIG_WDAT_WDT=m
CONFIG_WM831X_WATCHDOG=y
CONFIG_XILINX_WATCHDOG=y
CONFIG_ZIIRAVE_WATCHDOG=y
CONFIG_ARMADA_37XX_WATCHDOG=y
# CONFIG_ASM9260_WATCHDOG is not set
CONFIG_AT91RM9200_WATCHDOG=y
CONFIG_AT91SAM9X_WATCHDOG=y
# CONFIG_SAMA5D4_WATCHDOG is not set
CONFIG_CADENCE_WATCHDOG=y
CONFIG_FTWDT010_WATCHDOG=m
CONFIG_S3C2410_WATCHDOG=y
# CONFIG_DW_WATCHDOG is not set
CONFIG_EP93XX_WATCHDOG=m
CONFIG_OMAP_WATCHDOG=m
# CONFIG_DAVINCI_WATCHDOG is not set
CONFIG_RN5T618_WATCHDOG=m
CONFIG_SUNXI_WATCHDOG=y
CONFIG_NPCM7XX_WATCHDOG=y
# CONFIG_TWL4030_WATCHDOG is not set
CONFIG_STMP3XXX_RTC_WATCHDOG=m
CONFIG_NUC900_WATCHDOG=m
CONFIG_TS4800_WATCHDOG=m
# CONFIG_TS72XX_WATCHDOG is not set
CONFIG_MAX63XX_WATCHDOG=m
CONFIG_MAX77620_WATCHDOG=m
# CONFIG_IMX2_WDT is not set
# CONFIG_RETU_WATCHDOG is not set
CONFIG_MOXART_WDT=y
CONFIG_SIRFSOC_WATCHDOG=m
CONFIG_ST_LPC_WATCHDOG=y
CONFIG_TEGRA_WATCHDOG=m
# CONFIG_QCOM_WDT is not set
CONFIG_MESON_GXBB_WATCHDOG=y
CONFIG_MESON_WATCHDOG=m
# CONFIG_MEDIATEK_WATCHDOG is not set
# CONFIG_DIGICOLOR_WATCHDOG is not set
CONFIG_LPC18XX_WATCHDOG=m
CONFIG_ATLAS7_WATCHDOG=y
# CONFIG_RENESAS_WDT is not set
CONFIG_RENESAS_RZAWDT=m
CONFIG_ASPEED_WATCHDOG=m
CONFIG_STPMIC1_WATCHDOG=m
CONFIG_UNIPHIER_WATCHDOG=m
CONFIG_RTD119X_WATCHDOG=y
CONFIG_SPRD_WATCHDOG=m
CONFIG_PM8916_WATCHDOG=m
# CONFIG_ACQUIRE_WDT is not set
CONFIG_ADVANTECH_WDT=m
CONFIG_ALIM1535_WDT=m
CONFIG_ALIM7101_WDT=m
# CONFIG_EBC_C384_WDT is not set
# CONFIG_F71808E_WDT is not set
CONFIG_SP5100_TCO=m
CONFIG_SC520_WDT=m
CONFIG_SBC_FITPC2_WATCHDOG=m
CONFIG_EUROTECH_WDT=m
CONFIG_IB700_WDT=y
CONFIG_IBMASR=m
CONFIG_WAFER_WDT=y
CONFIG_I6300ESB_WDT=m
CONFIG_IE6XX_WDT=m
CONFIG_ITCO_WDT=m
CONFIG_ITCO_VENDOR_SUPPORT=y
# CONFIG_IT8712F_WDT is not set
CONFIG_IT87_WDT=m
CONFIG_HP_WATCHDOG=y
CONFIG_KEMPLD_WDT=m
CONFIG_HPWDT_NMI_DECODING=y
CONFIG_SC1200_WDT=y
CONFIG_SCx200_WDT=m
# CONFIG_PC87413_WDT is not set
# CONFIG_NV_TCO is not set
CONFIG_RDC321X_WDT=y
CONFIG_60XX_WDT=y
# CONFIG_SBC8360_WDT is not set
CONFIG_SBC7240_WDT=m
CONFIG_CPU5_WDT=y
CONFIG_SMSC_SCH311X_WDT=y
CONFIG_SMSC37B787_WDT=m
# CONFIG_TQMX86_WDT is not set
CONFIG_VIA_WDT=m
CONFIG_W83627HF_WDT=y
CONFIG_W83877F_WDT=m
CONFIG_W83977F_WDT=m
# CONFIG_MACHZ_WDT is not set
CONFIG_SBC_EPX_C3_WATCHDOG=y
CONFIG_INTEL_MEI_WDT=m
CONFIG_NI903X_WDT=m
# CONFIG_NIC7018_WDT is not set
CONFIG_BCM47XX_WDT=y
# CONFIG_BCM2835_WDT is not set
# CONFIG_BCM_KONA_WDT is not set
# CONFIG_BCM_KONA_WDT_DEBUG is not set
# CONFIG_BCM7038_WDT is not set
CONFIG_IMGPDC_WDT=m
CONFIG_MPC5200_WDT=y
# CONFIG_MV64X60_WDT is not set
CONFIG_MEN_A21_WDT=y
CONFIG_UML_WATCHDOG=y

#
# PCI-based Watchdog Cards
#
CONFIG_PCIPCWATCHDOG=y
CONFIG_WDTPCI=y

#
# USB-based Watchdog Cards
#
# CONFIG_USBPCWATCHDOG is not set

#
# Watchdog Pretimeout Governors
#
CONFIG_WATCHDOG_PRETIMEOUT_GOV=y
# CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP is not set
CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y
# CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP is not set
CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y
CONFIG_SSB_POSSIBLE=y
CONFIG_SSB=y
CONFIG_SSB_PCIHOST_POSSIBLE=y
# CONFIG_SSB_PCIHOST is not set
CONFIG_SSB_SDIOHOST_POSSIBLE=y
CONFIG_SSB_SDIOHOST=y
CONFIG_SSB_DRIVER_GPIO=y
CONFIG_BCMA_POSSIBLE=y
# CONFIG_BCMA is not set

#
# Multifunction device drivers
#
CONFIG_MFD_CORE=y
CONFIG_MFD_CS5535=y
# CONFIG_MFD_ACT8945A is not set
CONFIG_MFD_SUN4I_GPADC=m
CONFIG_MFD_AS3711=y
CONFIG_MFD_AS3722=m
# CONFIG_PMIC_ADP5520 is not set
# CONFIG_MFD_AAT2870_CORE is not set
CONFIG_MFD_AT91_USART=m
# CONFIG_MFD_ATMEL_FLEXCOM is not set
# CONFIG_MFD_ATMEL_HLCDC is not set
# CONFIG_MFD_BCM590XX is not set
CONFIG_MFD_BD9571MWV=m
# CONFIG_MFD_AXP20X_I2C is not set
# CONFIG_MFD_CROS_EC is not set
CONFIG_MFD_MADERA=y
CONFIG_MFD_MADERA_I2C=y
CONFIG_MFD_MADERA_SPI=y
CONFIG_MFD_CS47L35=y
# CONFIG_MFD_CS47L85 is not set
CONFIG_MFD_CS47L90=y
CONFIG_PMIC_DA903X=y
CONFIG_PMIC_DA9052=y
CONFIG_MFD_DA9052_SPI=y
CONFIG_MFD_DA9052_I2C=y
# CONFIG_MFD_DA9055 is not set
CONFIG_MFD_DA9062=m
# CONFIG_MFD_DA9063 is not set
# CONFIG_MFD_DA9150 is not set
CONFIG_MFD_DLN2=y
# CONFIG_MFD_EXYNOS_LPASS is not set
CONFIG_MFD_MC13XXX=m
CONFIG_MFD_MC13XXX_SPI=m
CONFIG_MFD_MC13XXX_I2C=m
CONFIG_MFD_MXS_LRADC=m
CONFIG_MFD_MX25_TSADC=m
CONFIG_MFD_HI6421_PMIC=m
# CONFIG_MFD_HI655X_PMIC is not set
CONFIG_HTC_PASIC3=y
CONFIG_HTC_I2CPLD=y
CONFIG_MFD_INTEL_QUARK_I2C_GPIO=y
CONFIG_LPC_ICH=m
CONFIG_LPC_SCH=m
CONFIG_INTEL_SOC_PMIC_BXTWC=m
CONFIG_INTEL_SOC_PMIC_CHTDC_TI=m
CONFIG_MFD_INTEL_LPSS=y
CONFIG_MFD_INTEL_LPSS_ACPI=m
CONFIG_MFD_INTEL_LPSS_PCI=y
CONFIG_MFD_JANZ_CMODIO=m
CONFIG_MFD_KEMPLD=m
CONFIG_MFD_88PM800=y
CONFIG_MFD_88PM805=y
CONFIG_MFD_88PM860X=y
CONFIG_MFD_MAX14577=y
# CONFIG_MFD_MAX77620 is not set
# CONFIG_MFD_MAX77686 is not set
CONFIG_MFD_MAX77693=m
# CONFIG_MFD_MAX77843 is not set
# CONFIG_MFD_MAX8907 is not set
CONFIG_MFD_MAX8925=y
CONFIG_MFD_MAX8997=y
# CONFIG_MFD_MAX8998 is not set
CONFIG_MFD_MT6397=m
# CONFIG_MFD_MENF21BMC is not set
# CONFIG_EZX_PCAP is not set
# CONFIG_MFD_CPCAP is not set
# CONFIG_MFD_VIPERBOARD is not set
CONFIG_MFD_RETU=y
# CONFIG_MFD_PCF50633 is not set
# CONFIG_MFD_PM8XXX is not set
CONFIG_MFD_SPMI_PMIC=m
CONFIG_MFD_RDC321X=y
CONFIG_MFD_RT5033=y
# CONFIG_MFD_RC5T583 is not set
CONFIG_MFD_RK808=m
CONFIG_MFD_RN5T618=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_SI476X_CORE=m
CONFIG_MFD_SM501=m
# CONFIG_MFD_SM501_GPIO is not set
CONFIG_MFD_SKY81452=y
# CONFIG_MFD_SMSC is not set
CONFIG_MFD_SC27XX_PMIC=y
CONFIG_ABX500_CORE=y
CONFIG_AB3100_CORE=y
CONFIG_AB3100_OTP=m
CONFIG_MFD_STMPE=y

#
# STMicroelectronics STMPE Interface Drivers
#
CONFIG_STMPE_I2C=y
# CONFIG_STMPE_SPI is not set
# CONFIG_MFD_SUN6I_PRCM is not set
CONFIG_MFD_SYSCON=y
CONFIG_MFD_TI_AM335X_TSCADC=m
CONFIG_MFD_LP3943=y
# CONFIG_MFD_LP8788 is not set
CONFIG_MFD_TI_LMU=y
CONFIG_MFD_PALMAS=y
CONFIG_TPS6105X=m
CONFIG_TPS65010=y
# CONFIG_TPS6507X is not set
# CONFIG_MFD_TPS65086 is not set
CONFIG_MFD_TPS65090=y
CONFIG_MFD_TPS65217=y
# CONFIG_MFD_TI_LP873X is not set
CONFIG_MFD_TI_LP87565=m
# CONFIG_MFD_TPS65218 is not set
CONFIG_MFD_TPS6586X=y
# CONFIG_MFD_TPS65910 is not set
# CONFIG_MFD_TPS65912_I2C is not set
# CONFIG_MFD_TPS65912_SPI is not set
CONFIG_MFD_TPS80031=y
CONFIG_TWL4030_CORE=y
CONFIG_MFD_TWL4030_AUDIO=y
CONFIG_TWL6040_CORE=y
CONFIG_MFD_WL1273_CORE=y
# CONFIG_MFD_LM3533 is not set
CONFIG_MFD_TIMBERDALE=y
# CONFIG_MFD_TC3589X is not set
# CONFIG_MFD_TQMX86 is not set
CONFIG_MFD_VX855=y
# CONFIG_MFD_LOCHNAGAR is not set
CONFIG_MFD_ARIZONA=y
CONFIG_MFD_ARIZONA_I2C=y
CONFIG_MFD_ARIZONA_SPI=y
# CONFIG_MFD_CS47L24 is not set
CONFIG_MFD_WM5102=y
CONFIG_MFD_WM5110=y
CONFIG_MFD_WM8997=y
# CONFIG_MFD_WM8998 is not set
# CONFIG_MFD_WM8400 is not set
CONFIG_MFD_WM831X=y
CONFIG_MFD_WM831X_I2C=y
CONFIG_MFD_WM831X_SPI=y
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_WM8994 is not set
# CONFIG_MFD_STW481X is not set
CONFIG_MFD_ROHM_BD718XX=m
# CONFIG_MFD_STM32_LPTIMER is not set
CONFIG_MFD_STM32_TIMERS=m
CONFIG_MFD_STPMIC1=m
# CONFIG_RAVE_SP_CORE is not set
CONFIG_REGULATOR=y
CONFIG_REGULATOR_DEBUG=y
CONFIG_REGULATOR_FIXED_VOLTAGE=m
CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
CONFIG_REGULATOR_USERSPACE_CONSUMER=y
# CONFIG_REGULATOR_88PG86X is not set
# CONFIG_REGULATOR_88PM800 is not set
CONFIG_REGULATOR_88PM8607=y
CONFIG_REGULATOR_ACT8865=m
# CONFIG_REGULATOR_AD5398 is not set
# CONFIG_REGULATOR_ANATOP is not set
CONFIG_REGULATOR_AB3100=y
CONFIG_REGULATOR_AS3711=y
CONFIG_REGULATOR_AS3722=m
CONFIG_REGULATOR_BD718XX=m
CONFIG_REGULATOR_BD9571MWV=m
CONFIG_REGULATOR_DA903X=y
CONFIG_REGULATOR_DA9052=m
CONFIG_REGULATOR_DA9062=m
CONFIG_REGULATOR_DA9210=m
CONFIG_REGULATOR_DA9211=m
CONFIG_REGULATOR_FAN53555=y
CONFIG_REGULATOR_GPIO=y
# CONFIG_REGULATOR_HI6421 is not set
CONFIG_REGULATOR_HI6421V530=m
CONFIG_REGULATOR_ISL9305=y
CONFIG_REGULATOR_ISL6271A=y
CONFIG_REGULATOR_LM363X=y
CONFIG_REGULATOR_LP3971=y
# CONFIG_REGULATOR_LP3972 is not set
# CONFIG_REGULATOR_LP872X is not set
CONFIG_REGULATOR_LP8755=y
CONFIG_REGULATOR_LP87565=m
CONFIG_REGULATOR_LTC3589=y
# CONFIG_REGULATOR_LTC3676 is not set
CONFIG_REGULATOR_MAX14577=m
CONFIG_REGULATOR_MAX1586=y
CONFIG_REGULATOR_MAX8649=m
CONFIG_REGULATOR_MAX8660=m
CONFIG_REGULATOR_MAX8925=m
CONFIG_REGULATOR_MAX8952=y
CONFIG_REGULATOR_MAX8997=m
CONFIG_REGULATOR_MAX77693=m
# CONFIG_REGULATOR_MC13783 is not set
# CONFIG_REGULATOR_MC13892 is not set
CONFIG_REGULATOR_MCP16502=y
CONFIG_REGULATOR_MT6311=m
# CONFIG_REGULATOR_MT6323 is not set
CONFIG_REGULATOR_MT6380=m
# CONFIG_REGULATOR_MT6397 is not set
CONFIG_REGULATOR_PALMAS=y
# CONFIG_REGULATOR_PBIAS is not set
# CONFIG_REGULATOR_PFUZE100 is not set
# CONFIG_REGULATOR_PV88060 is not set
CONFIG_REGULATOR_PV88080=m
CONFIG_REGULATOR_PV88090=y
CONFIG_REGULATOR_PWM=y
CONFIG_REGULATOR_QCOM_RPMH=y
# CONFIG_REGULATOR_QCOM_SMD_RPM is not set
CONFIG_REGULATOR_QCOM_SPMI=m
CONFIG_REGULATOR_RK808=m
CONFIG_REGULATOR_RN5T618=y
CONFIG_REGULATOR_RT5033=m
CONFIG_REGULATOR_S2MPA01=y
CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_S5M8767=y
# CONFIG_REGULATOR_SC2731 is not set
CONFIG_REGULATOR_SKY81452=y
# CONFIG_REGULATOR_STM32_VREFBUF is not set
CONFIG_REGULATOR_STPMIC1=m
CONFIG_REGULATOR_STW481X_VMMC=y
CONFIG_REGULATOR_SY8106A=m
CONFIG_REGULATOR_TPS51632=m
CONFIG_REGULATOR_TPS6105X=m
CONFIG_REGULATOR_TPS62360=y
CONFIG_REGULATOR_TPS65023=y
# CONFIG_REGULATOR_TPS6507X is not set
CONFIG_REGULATOR_TPS65090=m
# CONFIG_REGULATOR_TPS65132 is not set
# CONFIG_REGULATOR_TPS65217 is not set
CONFIG_REGULATOR_TPS6524X=m
CONFIG_REGULATOR_TPS6586X=y
CONFIG_REGULATOR_TPS80031=y
# CONFIG_REGULATOR_TWL4030 is not set
CONFIG_REGULATOR_UNIPHIER=y
CONFIG_REGULATOR_VCTRL=m
CONFIG_REGULATOR_WM831X=y
CONFIG_CEC_CORE=m
CONFIG_CEC_NOTIFIER=y
# CONFIG_RC_CORE is not set
CONFIG_MEDIA_SUPPORT=m

#
# Multimedia core support
#
# CONFIG_MEDIA_CAMERA_SUPPORT is not set
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
CONFIG_MEDIA_RADIO_SUPPORT=y
CONFIG_MEDIA_SDR_SUPPORT=y
# CONFIG_MEDIA_CEC_SUPPORT is not set
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=m
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_VIDEO_V4L2=m
# CONFIG_VIDEO_ADV_DEBUG is not set
CONFIG_VIDEO_FIXED_MINOR_RANGES=y
CONFIG_VIDEO_TUNER=m
# CONFIG_V4L2_FLASH_LED_CLASS is not set
CONFIG_V4L2_FWNODE=m
CONFIG_VIDEOBUF_GEN=m
CONFIG_VIDEOBUF_VMALLOC=m

#
# Media drivers
#
CONFIG_MEDIA_USB_SUPPORT=y

#
# Analog TV USB devices
#
CONFIG_VIDEO_PVRUSB2=m
CONFIG_VIDEO_PVRUSB2_SYSFS=y
# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
CONFIG_VIDEO_HDPVR=m
# CONFIG_VIDEO_USBVISION is not set
CONFIG_VIDEO_STK1160_COMMON=m
CONFIG_VIDEO_STK1160=m

#
# Analog/digital TV USB devices
#
CONFIG_VIDEO_CX231XX=m

#
# Webcam, TV (analog/digital) USB devices
#
# CONFIG_VIDEO_EM28XX is not set

#
# Software defined radio USB devices
#
# CONFIG_USB_AIRSPY is not set
CONFIG_USB_HACKRF=m
CONFIG_USB_MSI2500=m
# CONFIG_MEDIA_PCI_SUPPORT is not set
# CONFIG_SDR_PLATFORM_DRIVERS is not set

#
# Supported MMC/SDIO adapters
#
# CONFIG_RADIO_ADAPTERS is not set
CONFIG_VIDEO_CX2341X=m
CONFIG_VIDEO_TVEEPROM=m
CONFIG_CYPRESS_FIRMWARE=m
CONFIG_VIDEOBUF2_CORE=m
CONFIG_VIDEOBUF2_V4L2=m
CONFIG_VIDEOBUF2_MEMOPS=m
CONFIG_VIDEOBUF2_VMALLOC=m
CONFIG_VIDEOBUF2_DMA_SG=m

#
# Media ancillary drivers (tuners, sensors, i2c, spi, frontends)
#
CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
CONFIG_MEDIA_ATTACH=y

#
# I2C Encoders, decoders, sensors and other helper chips
#

#
# Audio decoders, processors and mixers
#
CONFIG_VIDEO_TVAUDIO=m
# CONFIG_VIDEO_TDA7432 is not set
CONFIG_VIDEO_TDA9840=m
# CONFIG_VIDEO_TEA6415C is not set
# CONFIG_VIDEO_TEA6420 is not set
CONFIG_VIDEO_MSP3400=m
CONFIG_VIDEO_CS3308=m
CONFIG_VIDEO_CS5345=m
CONFIG_VIDEO_CS53L32A=m
# CONFIG_VIDEO_TLV320AIC23B is not set
CONFIG_VIDEO_UDA1342=m
CONFIG_VIDEO_WM8775=m
CONFIG_VIDEO_WM8739=m
CONFIG_VIDEO_VP27SMPX=m
CONFIG_VIDEO_SONY_BTF_MPX=m

#
# RDS decoders
#
CONFIG_VIDEO_SAA6588=m

#
# Video decoders
#
CONFIG_VIDEO_ADV7180=m
CONFIG_VIDEO_ADV7183=m
CONFIG_VIDEO_ADV748X=m
CONFIG_VIDEO_ADV7604=m
CONFIG_VIDEO_ADV7604_CEC=y
# CONFIG_VIDEO_ADV7842 is not set
CONFIG_VIDEO_BT819=m
# CONFIG_VIDEO_BT856 is not set
CONFIG_VIDEO_BT866=m
CONFIG_VIDEO_KS0127=m
CONFIG_VIDEO_ML86V7667=m
# CONFIG_VIDEO_SAA7110 is not set
CONFIG_VIDEO_SAA711X=m
CONFIG_VIDEO_TC358743=m
CONFIG_VIDEO_TC358743_CEC=y
CONFIG_VIDEO_TVP514X=m
CONFIG_VIDEO_TVP5150=m
CONFIG_VIDEO_TVP7002=m
CONFIG_VIDEO_TW2804=m
CONFIG_VIDEO_TW9903=m
CONFIG_VIDEO_TW9906=m
CONFIG_VIDEO_TW9910=m
CONFIG_VIDEO_VPX3220=m

#
# Video and audio decoders
#
CONFIG_VIDEO_SAA717X=m
CONFIG_VIDEO_CX25840=m

#
# Video encoders
#
# CONFIG_VIDEO_SAA7127 is not set
CONFIG_VIDEO_SAA7185=m
# CONFIG_VIDEO_ADV7170 is not set
CONFIG_VIDEO_ADV7175=m
CONFIG_VIDEO_ADV7343=m
# CONFIG_VIDEO_ADV7393 is not set
# CONFIG_VIDEO_ADV7511 is not set
CONFIG_VIDEO_AD9389B=m
# CONFIG_VIDEO_AK881X is not set
CONFIG_VIDEO_THS8200=m

#
# Camera sensor devices
#
# CONFIG_VIDEO_OV9640 is not set
CONFIG_VIDEO_OV9650=m
CONFIG_VIDEO_MT9M111=m
CONFIG_VIDEO_S5K4ECGX=m
# CONFIG_VIDEO_S5K5BAF is not set
CONFIG_VIDEO_ET8EK8=m
CONFIG_VIDEO_S5C73M3=m

#
# Lens drivers
#
# CONFIG_VIDEO_AD5820 is not set
CONFIG_VIDEO_AK7375=m
CONFIG_VIDEO_DW9714=m
CONFIG_VIDEO_DW9807_VCM=m

#
# Flash devices
#

#
# Video improvement chips
#
# CONFIG_VIDEO_UPD64031A is not set
CONFIG_VIDEO_UPD64083=m

#
# Audio/Video compression chips
#
# CONFIG_VIDEO_SAA6752HS is not set

#
# SDR tuner chips
#
CONFIG_SDR_MAX2175=m

#
# Miscellaneous helper chips
#
CONFIG_VIDEO_THS7303=m
# CONFIG_VIDEO_M52790 is not set
CONFIG_VIDEO_I2C=m

#
# SPI helper chips
#
CONFIG_VIDEO_GS1662=m

#
# Media SPI Adapters
#
CONFIG_MEDIA_TUNER=m

#
# Customize TV tuners
#
CONFIG_MEDIA_TUNER_SIMPLE=m
CONFIG_MEDIA_TUNER_TDA18250=m
CONFIG_MEDIA_TUNER_TDA8290=m
CONFIG_MEDIA_TUNER_TDA827X=m
CONFIG_MEDIA_TUNER_TDA18271=m
CONFIG_MEDIA_TUNER_TDA9887=m
CONFIG_MEDIA_TUNER_TEA5761=m
CONFIG_MEDIA_TUNER_TEA5767=m
CONFIG_MEDIA_TUNER_MSI001=m
CONFIG_MEDIA_TUNER_MT20XX=m
# CONFIG_MEDIA_TUNER_MT2060 is not set
CONFIG_MEDIA_TUNER_MT2063=m
CONFIG_MEDIA_TUNER_MT2266=m
# CONFIG_MEDIA_TUNER_MT2131 is not set
# CONFIG_MEDIA_TUNER_QT1010 is not set
CONFIG_MEDIA_TUNER_XC2028=m
CONFIG_MEDIA_TUNER_XC5000=m
CONFIG_MEDIA_TUNER_XC4000=m
CONFIG_MEDIA_TUNER_MXL5005S=m
CONFIG_MEDIA_TUNER_MXL5007T=m
CONFIG_MEDIA_TUNER_MC44S803=m
# CONFIG_MEDIA_TUNER_MAX2165 is not set
# CONFIG_MEDIA_TUNER_TDA18218 is not set
CONFIG_MEDIA_TUNER_FC0011=m
# CONFIG_MEDIA_TUNER_FC0012 is not set
# CONFIG_MEDIA_TUNER_FC0013 is not set
# CONFIG_MEDIA_TUNER_TDA18212 is not set
CONFIG_MEDIA_TUNER_E4000=m
CONFIG_MEDIA_TUNER_FC2580=m
CONFIG_MEDIA_TUNER_M88RS6000T=m
CONFIG_MEDIA_TUNER_TUA9001=m
CONFIG_MEDIA_TUNER_SI2157=m
CONFIG_MEDIA_TUNER_IT913X=m
CONFIG_MEDIA_TUNER_R820T=m
CONFIG_MEDIA_TUNER_MXL301RF=m
CONFIG_MEDIA_TUNER_QM1D1C0042=m
# CONFIG_MEDIA_TUNER_QM1D1B0004 is not set

#
# Customise DVB Frontends
#

#
# Tools to develop new frontends
#

#
# Graphics support
#
CONFIG_AGP=y
CONFIG_AGP_ALI=m
CONFIG_AGP_ATI=y
# CONFIG_AGP_AMD is not set
# CONFIG_AGP_AMD64 is not set
CONFIG_AGP_INTEL=m
CONFIG_AGP_NVIDIA=m
CONFIG_AGP_SIS=m
# CONFIG_AGP_SWORKS is not set
# CONFIG_AGP_VIA is not set
CONFIG_AGP_EFFICEON=y
CONFIG_INTEL_GTT=m
# CONFIG_VGA_ARB is not set
# CONFIG_VGA_SWITCHEROO is not set
CONFIG_IMX_IPUV3_CORE=m
CONFIG_DRM=m
CONFIG_DRM_MIPI_DSI=y
# CONFIG_DRM_DP_AUX_CHARDEV is not set
CONFIG_DRM_DEBUG_SELFTEST=m
CONFIG_DRM_KMS_HELPER=m
CONFIG_DRM_KMS_FB_HELPER=y
CONFIG_DRM_FBDEV_EMULATION=y
CONFIG_DRM_FBDEV_OVERALLOC=100
# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set
# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set
# CONFIG_DRM_DP_CEC is not set
CONFIG_DRM_TTM=m
CONFIG_DRM_GEM_CMA_HELPER=y
CONFIG_DRM_KMS_CMA_HELPER=y
CONFIG_DRM_GEM_SHMEM_HELPER=y
CONFIG_DRM_VM=y
CONFIG_DRM_SCHED=m

#
# I2C encoder or helper chips
#
CONFIG_DRM_I2C_CH7006=m
# CONFIG_DRM_I2C_SIL164 is not set
CONFIG_DRM_I2C_NXP_TDA998X=m
# CONFIG_DRM_I2C_NXP_TDA9950 is not set

#
# ARM devices
#
CONFIG_DRM_KOMEDA=m
CONFIG_DRM_RADEON=m
CONFIG_DRM_RADEON_USERPTR=y
CONFIG_DRM_AMDGPU=m
CONFIG_DRM_AMDGPU_SI=y
CONFIG_DRM_AMDGPU_CIK=y
# CONFIG_DRM_AMDGPU_USERPTR is not set
CONFIG_DRM_AMDGPU_GART_DEBUGFS=y

#
# ACP (Audio CoProcessor) Configuration
#
# CONFIG_DRM_AMD_ACP is not set

#
# Display Engine Configuration
#
CONFIG_DRM_AMD_DC=y
CONFIG_DRM_AMD_DC_DCN1_0=y
CONFIG_DRM_AMD_DC_DCN1_01=y
# CONFIG_DEBUG_KERNEL_DC is not set
# CONFIG_DRM_NOUVEAU is not set
# CONFIG_DRM_I915 is not set
CONFIG_DRM_VGEM=m
# CONFIG_DRM_VKMS is not set
CONFIG_DRM_VMWGFX=m
# CONFIG_DRM_VMWGFX_FBCON is not set
CONFIG_DRM_GMA500=m
# CONFIG_DRM_GMA600 is not set
CONFIG_DRM_GMA3600=y
# CONFIG_DRM_UDL is not set
CONFIG_DRM_AST=m
CONFIG_DRM_MGAG200=m
CONFIG_DRM_RCAR_DW_HDMI=m
CONFIG_DRM_RCAR_LVDS=m
CONFIG_DRM_QXL=m
CONFIG_DRM_BOCHS=m
# CONFIG_DRM_VIRTIO_GPU is not set
CONFIG_DRM_PANEL=y

#
# Display Panels
#
CONFIG_DRM_PANEL_ARM_VERSATILE=m
CONFIG_DRM_PANEL_LVDS=m
# CONFIG_DRM_PANEL_SIMPLE is not set
# CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D is not set
CONFIG_DRM_PANEL_ILITEK_IL9322=m
CONFIG_DRM_PANEL_ILITEK_ILI9881C=m
CONFIG_DRM_PANEL_INNOLUX_P079ZCA=m
CONFIG_DRM_PANEL_JDI_LT070ME05000=m
# CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04 is not set
# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set
# CONFIG_DRM_PANEL_LG_LG4573 is not set
CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO=m
# CONFIG_DRM_PANEL_ORISETECH_OTM8009A is not set
# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set
CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m
# CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set
CONFIG_DRM_PANEL_ROCKTECH_JH057N00900=m
CONFIG_DRM_PANEL_RONBO_RB070D30=m
# CONFIG_DRM_PANEL_SAMSUNG_S6D16D0 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03 is not set
CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m
CONFIG_DRM_PANEL_SEIKO_43WVF1G=m
CONFIG_DRM_PANEL_SHARP_LQ101R1SX01=m
# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set
# CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set
# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set
CONFIG_DRM_PANEL_TPO_TPG110=m
# CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set
CONFIG_DRM_BRIDGE=y
CONFIG_DRM_PANEL_BRIDGE=y

#
# Display Interface Bridges
#
CONFIG_DRM_ANALOGIX_ANX78XX=m
CONFIG_DRM_CDNS_DSI=m
CONFIG_DRM_DUMB_VGA_DAC=m
CONFIG_DRM_LVDS_ENCODER=m
CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW=m
CONFIG_DRM_NXP_PTN3460=m
# CONFIG_DRM_PARADE_PS8622 is not set
# CONFIG_DRM_SIL_SII8620 is not set
CONFIG_DRM_SII902X=m
CONFIG_DRM_SII9234=m
CONFIG_DRM_THINE_THC63LVD1024=m
CONFIG_DRM_TOSHIBA_TC358764=m
CONFIG_DRM_TOSHIBA_TC358767=m
# CONFIG_DRM_TI_TFP410 is not set
CONFIG_DRM_TI_SN65DSI86=m
CONFIG_DRM_I2C_ADV7511=m
CONFIG_DRM_I2C_ADV7533=y
CONFIG_DRM_I2C_ADV7511_CEC=y
CONFIG_DRM_DW_HDMI=m
CONFIG_DRM_DW_HDMI_CEC=m
CONFIG_DRM_IMX=m
CONFIG_DRM_IMX_PARALLEL_DISPLAY=m
CONFIG_DRM_IMX_TVE=m
# CONFIG_DRM_IMX_LDB is not set
CONFIG_DRM_IMX_HDMI=m
CONFIG_DRM_V3D=m
CONFIG_DRM_ETNAVIV=m
CONFIG_DRM_ETNAVIV_THERMAL=y
CONFIG_DRM_ARCPGU=m
CONFIG_DRM_HISI_HIBMC=m
CONFIG_DRM_MXS=y
CONFIG_DRM_MXSFB=m
CONFIG_DRM_TINYDRM=m
CONFIG_TINYDRM_MIPI_DBI=m
CONFIG_TINYDRM_HX8357D=m
# CONFIG_TINYDRM_ILI9225 is not set
CONFIG_TINYDRM_ILI9341=m
CONFIG_TINYDRM_MI0283QT=m
CONFIG_TINYDRM_REPAPER=m
# CONFIG_TINYDRM_ST7586 is not set
# CONFIG_TINYDRM_ST7735R is not set
CONFIG_DRM_PL111=m
# CONFIG_DRM_TVE200 is not set
# CONFIG_DRM_VBOXVIDEO is not set
# CONFIG_DRM_LIMA is not set
CONFIG_DRM_LEGACY=y
CONFIG_DRM_TDFX=m
CONFIG_DRM_R128=m
CONFIG_DRM_I810=m
# CONFIG_DRM_MGA is not set
CONFIG_DRM_SIS=m
CONFIG_DRM_VIA=m
CONFIG_DRM_SAVAGE=m
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=m
CONFIG_DRM_LIB_RANDOM=y

#
# Frame buffer Devices
#
CONFIG_FB_CMDLINE=y
CONFIG_FB_NOTIFY=y
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
CONFIG_FB_DDC=y
CONFIG_FB_BOOT_VESA_SUPPORT=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_SYS_FILLRECT=y
CONFIG_FB_SYS_COPYAREA=y
CONFIG_FB_SYS_IMAGEBLIT=y
# CONFIG_FB_FOREIGN_ENDIAN is not set
CONFIG_FB_SYS_FOPS=y
CONFIG_FB_DEFERRED_IO=y
CONFIG_FB_HECUBA=y
CONFIG_FB_SVGALIB=y
CONFIG_FB_BACKLIGHT=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y

#
# Frame buffer hardware drivers
#
CONFIG_FB_CIRRUS=m
CONFIG_FB_PM2=m
# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
# CONFIG_FB_CLPS711X is not set
CONFIG_FB_CYBER2000=y
CONFIG_FB_CYBER2000_DDC=y
CONFIG_FB_ARC=y
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_VGA16 is not set
# CONFIG_FB_VESA is not set
CONFIG_FB_N411=y
# CONFIG_FB_HGA is not set
# CONFIG_FB_OPENCORES is not set
# CONFIG_FB_S1D13XXX is not set
CONFIG_FB_NVIDIA=m
CONFIG_FB_NVIDIA_I2C=y
CONFIG_FB_NVIDIA_DEBUG=y
CONFIG_FB_NVIDIA_BACKLIGHT=y
# CONFIG_FB_RIVA is not set
CONFIG_FB_I740=y
# CONFIG_FB_I810 is not set
# CONFIG_FB_LE80578 is not set
# CONFIG_FB_INTEL is not set
CONFIG_FB_MATROX=y
# CONFIG_FB_MATROX_MILLENIUM is not set
# CONFIG_FB_MATROX_MYSTIQUE is not set
CONFIG_FB_MATROX_G=y
CONFIG_FB_MATROX_I2C=m
CONFIG_FB_MATROX_MAVEN=m
CONFIG_FB_RADEON=m
CONFIG_FB_RADEON_I2C=y
CONFIG_FB_RADEON_BACKLIGHT=y
# CONFIG_FB_RADEON_DEBUG is not set
CONFIG_FB_ATY128=y
CONFIG_FB_ATY128_BACKLIGHT=y
CONFIG_FB_ATY=m
CONFIG_FB_ATY_CT=y
CONFIG_FB_ATY_GENERIC_LCD=y
# CONFIG_FB_ATY_GX is not set
# CONFIG_FB_ATY_BACKLIGHT is not set
# CONFIG_FB_S3 is not set
# CONFIG_FB_SAVAGE is not set
CONFIG_FB_SIS=y
CONFIG_FB_SIS_300=y
# CONFIG_FB_SIS_315 is not set
CONFIG_FB_VIA=y
CONFIG_FB_VIA_DIRECT_PROCFS=y
# CONFIG_FB_VIA_X_COMPATIBILITY is not set
# CONFIG_FB_NEOMAGIC is not set
CONFIG_FB_KYRO=y
CONFIG_FB_3DFX=m
# CONFIG_FB_3DFX_ACCEL is not set
CONFIG_FB_3DFX_I2C=y
CONFIG_FB_VOODOO1=m
CONFIG_FB_VT8623=m
CONFIG_FB_TRIDENT=m
CONFIG_FB_ARK=y
CONFIG_FB_PM3=y
CONFIG_FB_CARMINE=m
# CONFIG_FB_CARMINE_DRAM_EVAL is not set
CONFIG_CARMINE_DRAM_CUSTOM=y
CONFIG_FB_GEODE=y
CONFIG_FB_GEODE_LX=m
CONFIG_FB_GEODE_GX=y
CONFIG_FB_GEODE_GX1=m
CONFIG_FB_TMIO=y
CONFIG_FB_TMIO_ACCELL=y
CONFIG_FB_SM501=m
CONFIG_FB_SMSCUFX=y
CONFIG_FB_UDL=m
CONFIG_FB_IBM_GXT4500=m
CONFIG_FB_GOLDFISH=y
CONFIG_FB_VIRTUAL=y
# CONFIG_FB_METRONOME is not set
CONFIG_FB_MB862XX=y
CONFIG_FB_MB862XX_PCI_GDC=y
CONFIG_FB_MB862XX_I2C=y
CONFIG_FB_BROADSHEET=y
CONFIG_FB_HYPERV=m
# CONFIG_FB_SIMPLE is not set
# CONFIG_FB_SSD1307 is not set
# CONFIG_FB_SM712 is not set
CONFIG_FB_OMAP2=y
CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
CONFIG_FB_OMAP2_NUM_FBS=3
CONFIG_FB_OMAP2_DSS_INIT=y
CONFIG_FB_OMAP2_DSS=y
# CONFIG_FB_OMAP2_DSS_DEBUG is not set
CONFIG_FB_OMAP2_DSS_DEBUGFS=y
CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS=y
# CONFIG_FB_OMAP2_DSS_DPI is not set
CONFIG_FB_OMAP2_DSS_VENC=y
CONFIG_FB_OMAP2_DSS_HDMI_COMMON=y
# CONFIG_FB_OMAP4_DSS_HDMI is not set
CONFIG_FB_OMAP5_DSS_HDMI=y
CONFIG_FB_OMAP2_DSS_SDI=y
CONFIG_FB_OMAP2_DSS_DSI=y
CONFIG_FB_OMAP2_DSS_MIN_FCK_PER_PCK=0
CONFIG_FB_OMAP2_DSS_SLEEP_AFTER_VENC_RESET=y

#
# OMAPFB Panel and Encoder Drivers
#
# CONFIG_FB_OMAP2_ENCODER_OPA362 is not set
# CONFIG_FB_OMAP2_ENCODER_TFP410 is not set
CONFIG_FB_OMAP2_ENCODER_TPD12S015=m
CONFIG_FB_OMAP2_CONNECTOR_DVI=m
CONFIG_FB_OMAP2_CONNECTOR_HDMI=y
CONFIG_FB_OMAP2_CONNECTOR_ANALOG_TV=m
CONFIG_FB_OMAP2_PANEL_DPI=m
CONFIG_FB_OMAP2_PANEL_DSI_CM=y
CONFIG_FB_OMAP2_PANEL_SONY_ACX565AKM=y
# CONFIG_FB_OMAP2_PANEL_LGPHILIPS_LB035Q02 is not set
# CONFIG_FB_OMAP2_PANEL_SHARP_LS037V7DW01 is not set
CONFIG_FB_OMAP2_PANEL_TPO_TD028TTEC1=y
# CONFIG_FB_OMAP2_PANEL_TPO_TD043MTEA1 is not set
CONFIG_FB_OMAP2_PANEL_NEC_NL8048HL11=m
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_BACKLIGHT_GENERIC is not set
# CONFIG_BACKLIGHT_PWM is not set
CONFIG_BACKLIGHT_DA903X=m
CONFIG_BACKLIGHT_DA9052=y
CONFIG_BACKLIGHT_MAX8925=y
# CONFIG_BACKLIGHT_APPLE is not set
# CONFIG_BACKLIGHT_PM8941_WLED is not set
CONFIG_BACKLIGHT_SAHARA=y
CONFIG_BACKLIGHT_WM831X=y
CONFIG_BACKLIGHT_ADP8860=m
CONFIG_BACKLIGHT_ADP8870=m
# CONFIG_BACKLIGHT_88PM860X is not set
# CONFIG_BACKLIGHT_LM3630A is not set
CONFIG_BACKLIGHT_LM3639=y
CONFIG_BACKLIGHT_LP855X=y
CONFIG_BACKLIGHT_PANDORA=m
# CONFIG_BACKLIGHT_SKY81452 is not set
CONFIG_BACKLIGHT_TPS65217=y
CONFIG_BACKLIGHT_AS3711=m
CONFIG_BACKLIGHT_GPIO=y
CONFIG_BACKLIGHT_LV5207LP=m
CONFIG_BACKLIGHT_BD6107=y
CONFIG_BACKLIGHT_ARCXCNN=m
CONFIG_VGASTATE=y
CONFIG_VIDEOMODE_HELPERS=y
CONFIG_HDMI=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
# CONFIG_SOUND is not set

#
# HID support
#
CONFIG_HID=m
# CONFIG_HID_BATTERY_STRENGTH is not set
CONFIG_HIDRAW=y
# CONFIG_UHID is not set
CONFIG_HID_GENERIC=m

#
# Special HID drivers
#
# CONFIG_HID_A4TECH is not set
CONFIG_HID_ACCUTOUCH=m
# CONFIG_HID_ACRUX is not set
CONFIG_HID_APPLE=m
CONFIG_HID_APPLEIR=m
CONFIG_HID_ASUS=m
CONFIG_HID_AUREAL=m
CONFIG_HID_BELKIN=m
# CONFIG_HID_BETOP_FF is not set
CONFIG_HID_BIGBEN_FF=m
CONFIG_HID_CHERRY=m
CONFIG_HID_CHICONY=m
CONFIG_HID_CORSAIR=m
# CONFIG_HID_COUGAR is not set
CONFIG_HID_MACALLY=m
# CONFIG_HID_CMEDIA is not set
# CONFIG_HID_CP2112 is not set
# CONFIG_HID_CYPRESS is not set
CONFIG_HID_DRAGONRISE=m
CONFIG_DRAGONRISE_FF=y
CONFIG_HID_EMS_FF=m
CONFIG_HID_ELAN=m
# CONFIG_HID_ELECOM is not set
# CONFIG_HID_ELO is not set
# CONFIG_HID_EZKEY is not set
CONFIG_HID_GEMBIRD=m
CONFIG_HID_GFRM=m
CONFIG_HID_HOLTEK=m
CONFIG_HOLTEK_FF=y
CONFIG_HID_GT683R=m
CONFIG_HID_KEYTOUCH=m
# CONFIG_HID_KYE is not set
CONFIG_HID_UCLOGIC=m
CONFIG_HID_WALTOP=m
# CONFIG_HID_VIEWSONIC is not set
CONFIG_HID_GYRATION=m
CONFIG_HID_ICADE=m
CONFIG_HID_ITE=m
CONFIG_HID_JABRA=m
CONFIG_HID_TWINHAN=m
CONFIG_HID_KENSINGTON=m
# CONFIG_HID_LCPOWER is not set
CONFIG_HID_LED=m
CONFIG_HID_LENOVO=m
CONFIG_HID_LOGITECH=m
CONFIG_HID_LOGITECH_DJ=m
CONFIG_HID_LOGITECH_HIDPP=m
# CONFIG_LOGITECH_FF is not set
# CONFIG_LOGIRUMBLEPAD2_FF is not set
CONFIG_LOGIG940_FF=y
CONFIG_LOGIWHEELS_FF=y
CONFIG_HID_MAGICMOUSE=m
CONFIG_HID_MALTRON=m
# CONFIG_HID_MAYFLASH is not set
# CONFIG_HID_REDRAGON is not set
# CONFIG_HID_MICROSOFT is not set
CONFIG_HID_MONTEREY=m
CONFIG_HID_MULTITOUCH=m
CONFIG_HID_NTI=m
CONFIG_HID_NTRIG=m
CONFIG_HID_ORTEK=m
CONFIG_HID_PANTHERLORD=m
CONFIG_PANTHERLORD_FF=y
# CONFIG_HID_PENMOUNT is not set
CONFIG_HID_PETALYNX=m
CONFIG_HID_PICOLCD=m
CONFIG_HID_PICOLCD_FB=y
# CONFIG_HID_PICOLCD_BACKLIGHT is not set
# CONFIG_HID_PICOLCD_LEDS is not set
CONFIG_HID_PLANTRONICS=m
# CONFIG_HID_PRIMAX is not set
CONFIG_HID_RETRODE=m
CONFIG_HID_ROCCAT=m
CONFIG_HID_SAITEK=m
# CONFIG_HID_SAMSUNG is not set
CONFIG_HID_SONY=m
# CONFIG_SONY_FF is not set
# CONFIG_HID_SPEEDLINK is not set
CONFIG_HID_STEAM=m
CONFIG_HID_STEELSERIES=m
CONFIG_HID_SUNPLUS=m
CONFIG_HID_RMI=m
CONFIG_HID_GREENASIA=m
# CONFIG_GREENASIA_FF is not set
# CONFIG_HID_HYPERV_MOUSE is not set
CONFIG_HID_SMARTJOYPLUS=m
CONFIG_SMARTJOYPLUS_FF=y
CONFIG_HID_TIVO=m
CONFIG_HID_TOPSEED=m
# CONFIG_HID_THINGM is not set
# CONFIG_HID_THRUSTMASTER is not set
CONFIG_HID_UDRAW_PS3=m
CONFIG_HID_U2FZERO=m
CONFIG_HID_WACOM=m
# CONFIG_HID_WIIMOTE is not set
CONFIG_HID_XINMO=m
CONFIG_HID_ZEROPLUS=m
# CONFIG_ZEROPLUS_FF is not set
CONFIG_HID_ZYDACRON=m
CONFIG_HID_SENSOR_HUB=m
CONFIG_HID_SENSOR_CUSTOM_SENSOR=m
CONFIG_HID_ALPS=m

#
# USB HID support
#
CONFIG_USB_HID=m
CONFIG_HID_PID=y
CONFIG_USB_HIDDEV=y

#
# USB HID Boot Protocol drivers
#
# CONFIG_USB_KBD is not set
CONFIG_USB_MOUSE=m

#
# I2C HID support
#
CONFIG_I2C_HID=m

#
# Intel ISH HID support
#
CONFIG_INTEL_ISH_HID=m
# CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER is not set
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_COMMON=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB=y
CONFIG_USB_PCI=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y

#
# Miscellaneous USB options
#
# CONFIG_USB_DEFAULT_PERSIST is not set
CONFIG_USB_DYNAMIC_MINORS=y
CONFIG_USB_OTG=y
CONFIG_USB_OTG_WHITELIST=y
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
# CONFIG_USB_OTG_FSM is not set
# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set
CONFIG_USB_AUTOSUSPEND_DELAY=2
# CONFIG_USB_MON is not set
CONFIG_USB_WUSB=m
CONFIG_USB_WUSB_CBAF=m
CONFIG_USB_WUSB_CBAF_DEBUG=y

#
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_PCI=y
CONFIG_USB_XHCI_PLATFORM=m
CONFIG_USB_XHCI_HISTB=m
CONFIG_USB_XHCI_MTK=y
# CONFIG_USB_XHCI_MVEBU is not set
CONFIG_USB_XHCI_RCAR=m
# CONFIG_USB_EHCI_HCD is not set
CONFIG_USB_OXU210HP_HCD=m
CONFIG_USB_ISP116X_HCD=y
# CONFIG_USB_ISP1362_HCD is not set
# CONFIG_USB_FOTG210_HCD is not set
# CONFIG_USB_MAX3421_HCD is not set
CONFIG_USB_OHCI_HCD=m
# CONFIG_USB_OHCI_HCD_PCI is not set
# CONFIG_USB_OHCI_HCD_SSB is not set
# CONFIG_USB_OHCI_HCD_PLATFORM is not set
CONFIG_USB_UHCI_HCD=m
CONFIG_USB_U132_HCD=y
CONFIG_USB_SL811_HCD=m
CONFIG_USB_SL811_HCD_ISO=y
CONFIG_USB_R8A66597_HCD=y
# CONFIG_USB_WHCI_HCD is not set
CONFIG_USB_HWA_HCD=m
# CONFIG_USB_HCD_SSB is not set
# CONFIG_USB_HCD_TEST_MODE is not set
# CONFIG_USB_RENESAS_USBHS is not set

#
# USB Device Class drivers
#
CONFIG_USB_PRINTER=m
CONFIG_USB_WDM=y
# CONFIG_USB_TMC is not set

#
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
#

#
# also be needed; see USB_STORAGE Help for more info
#

#
# USB Imaging devices
#
# CONFIG_USB_MDC800 is not set
CONFIG_USB_MTU3=m
# CONFIG_USB_MTU3_HOST is not set
CONFIG_USB_MTU3_GADGET=y
# CONFIG_USB_MTU3_DUAL_ROLE is not set
# CONFIG_USB_MTU3_DEBUG is not set
CONFIG_USB_MUSB_HDRC=m
# CONFIG_USB_MUSB_HOST is not set
CONFIG_USB_MUSB_GADGET=y
# CONFIG_USB_MUSB_DUAL_ROLE is not set

#
# Platform Glue Layer
#
CONFIG_USB_MUSB_TUSB6010=m
# CONFIG_USB_MUSB_DSPS is not set
CONFIG_USB_MUSB_UX500=m

#
# MUSB DMA mode
#
CONFIG_MUSB_PIO_ONLY=y
CONFIG_USB_DWC3=m
# CONFIG_USB_DWC3_ULPI is not set
# CONFIG_USB_DWC3_HOST is not set
CONFIG_USB_DWC3_GADGET=y
# CONFIG_USB_DWC3_DUAL_ROLE is not set

#
# Platform Glue Driver Support
#
CONFIG_USB_DWC3_OMAP=m
# CONFIG_USB_DWC3_EXYNOS is not set
# CONFIG_USB_DWC3_PCI is not set
CONFIG_USB_DWC3_HAPS=m
# CONFIG_USB_DWC3_KEYSTONE is not set
# CONFIG_USB_DWC3_OF_SIMPLE is not set
CONFIG_USB_DWC3_ST=m
# CONFIG_USB_DWC3_QCOM is not set
CONFIG_USB_DWC2=y
CONFIG_USB_DWC2_HOST=y

#
# Gadget/Dual-role mode requires USB Gadget support to be enabled
#
CONFIG_USB_DWC2_PCI=m
# CONFIG_USB_DWC2_DEBUG is not set
# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set
CONFIG_USB_CHIPIDEA=m
CONFIG_USB_CHIPIDEA_OF=m
CONFIG_USB_CHIPIDEA_PCI=m
CONFIG_USB_CHIPIDEA_UDC=y
CONFIG_USB_ISP1760=m
CONFIG_USB_ISP1761_UDC=y
# CONFIG_USB_ISP1760_HOST_ROLE is not set
CONFIG_USB_ISP1760_GADGET_ROLE=y
# CONFIG_USB_ISP1760_DUAL_ROLE is not set

#
# USB port drivers
#

#
# USB Miscellaneous drivers
#
# CONFIG_USB_EMI62 is not set
CONFIG_USB_EMI26=y
CONFIG_USB_ADUTUX=y
CONFIG_USB_SEVSEG=y
# CONFIG_USB_RIO500 is not set
CONFIG_USB_LEGOTOWER=m
# CONFIG_USB_LCD is not set
CONFIG_USB_CYPRESS_CY7C63=m
# CONFIG_USB_CYTHERM is not set
CONFIG_USB_IDMOUSE=y
CONFIG_USB_FTDI_ELAN=y
CONFIG_USB_APPLEDISPLAY=m
CONFIG_USB_SISUSBVGA=m
CONFIG_USB_LD=y
# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_IOWARRIOR is not set
# CONFIG_USB_TEST is not set
CONFIG_USB_EHSET_TEST_FIXTURE=y
# CONFIG_USB_ISIGHTFW is not set
# CONFIG_USB_YUREX is not set
# CONFIG_USB_EZUSB_FX2 is not set
CONFIG_USB_HUB_USB251XB=y
CONFIG_USB_HSIC_USB3503=y
CONFIG_USB_HSIC_USB4604=m
# CONFIG_USB_LINK_LAYER_TEST is not set

#
# USB Physical Layer drivers
#
CONFIG_USB_PHY=y
# CONFIG_KEYSTONE_USB_PHY is not set
CONFIG_NOP_USB_XCEIV=m
CONFIG_AM335X_CONTROL_USB=m
CONFIG_AM335X_PHY_USB=m
# CONFIG_USB_GPIO_VBUS is not set
CONFIG_TAHVO_USB=m
# CONFIG_TAHVO_USB_HOST_BY_DEFAULT is not set
CONFIG_USB_ISP1301=m
CONFIG_USB_GADGET=m
# CONFIG_USB_GADGET_DEBUG is not set
CONFIG_USB_GADGET_DEBUG_FS=y
CONFIG_USB_GADGET_VBUS_DRAW=2
CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2

#
# USB Peripheral Controller
#
CONFIG_USB_FUSB300=m
CONFIG_USB_FOTG210_UDC=m
CONFIG_USB_GR_UDC=m
# CONFIG_USB_R8A66597 is not set
CONFIG_USB_RENESAS_USB3=m
CONFIG_USB_PXA27X=m
CONFIG_USB_MV_UDC=m
CONFIG_USB_MV_U3D=m
CONFIG_USB_SNP_CORE=m
CONFIG_USB_SNP_UDC_PLAT=m
# CONFIG_USB_M66592 is not set
CONFIG_USB_BDC_UDC=m

#
# Platform Support
#
CONFIG_USB_BDC_PCI=m
CONFIG_USB_AMD5536UDC=m
# CONFIG_USB_NET2272 is not set
CONFIG_USB_NET2280=m
# CONFIG_USB_GOKU is not set
CONFIG_USB_EG20T=m
CONFIG_USB_GADGET_XILINX=m
CONFIG_USB_ASPEED_VHUB=m
# CONFIG_USB_DUMMY_HCD is not set
CONFIG_USB_LIBCOMPOSITE=m
CONFIG_USB_CONFIGFS=m
# CONFIG_USB_CONFIGFS_F_LB_SS is not set
# CONFIG_USB_CONFIGFS_F_FS is not set
# CONFIG_USB_CONFIGFS_F_HID is not set
# CONFIG_USB_CONFIGFS_F_UVC is not set
# CONFIG_USB_CONFIGFS_F_PRINTER is not set
CONFIG_TYPEC=y
CONFIG_TYPEC_TCPM=y
CONFIG_TYPEC_TCPCI=m
# CONFIG_TYPEC_RT1711H is not set
# CONFIG_TYPEC_FUSB302 is not set
CONFIG_TYPEC_UCSI=y
CONFIG_UCSI_CCG=m
CONFIG_UCSI_ACPI=m
# CONFIG_TYPEC_TPS6598X is not set

#
# USB Type-C Multiplexer/DeMultiplexer Switch support
#
CONFIG_TYPEC_MUX_PI3USB30532=y

#
# USB Type-C Alternate Mode drivers
#
CONFIG_TYPEC_DP_ALTMODE=y
CONFIG_USB_ROLE_SWITCH=y
# CONFIG_USB_ROLES_INTEL_XHCI is not set
CONFIG_USB_LED_TRIG=y
CONFIG_USB_ULPI_BUS=m
CONFIG_UWB=m
CONFIG_UWB_HWA=m
CONFIG_UWB_WHCI=m
CONFIG_UWB_I1480U=m
CONFIG_MMC=y
CONFIG_PWRSEQ_EMMC=y
CONFIG_PWRSEQ_SIMPLE=y
CONFIG_MMC_TEST=y

#
# MMC/SD/SDIO Host Controller Drivers
#
CONFIG_MMC_DEBUG=y
# CONFIG_MMC_SDHCI is not set
# CONFIG_MMC_MESON_MX_SDIO is not set
CONFIG_MMC_OMAP_HS=y
CONFIG_MMC_WBSD=y
# CONFIG_MMC_ALCOR is not set
CONFIG_MMC_TIFM_SD=y
CONFIG_MMC_GOLDFISH=y
CONFIG_MMC_SPI=y
CONFIG_MMC_TMIO_CORE=m
# CONFIG_MMC_SDHI is not set
CONFIG_MMC_UNIPHIER=m
CONFIG_MMC_CB710=y
CONFIG_MMC_VIA_SDMMC=y
CONFIG_MMC_DW=m
CONFIG_MMC_DW_PLTFM=m
CONFIG_MMC_DW_BLUEFIELD=m
# CONFIG_MMC_DW_EXYNOS is not set
CONFIG_MMC_DW_HI3798CV200=m
CONFIG_MMC_DW_K3=m
CONFIG_MMC_DW_PCI=m
CONFIG_MMC_SH_MMCIF=y
CONFIG_MMC_VUB300=y
CONFIG_MMC_USHC=y
CONFIG_MMC_USDHI6ROL0=m
CONFIG_MMC_REALTEK_USB=m
CONFIG_MMC_CQHCI=m
CONFIG_MMC_TOSHIBA_PCI=m
CONFIG_MMC_BCM2835=m
CONFIG_MMC_MTK=m
# CONFIG_MEMSTICK is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_CLASS_FLASH=y
# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set

#
# LED drivers
#
CONFIG_LEDS_88PM860X=m
# CONFIG_LEDS_AAT1290 is not set
CONFIG_LEDS_AN30259A=m
# CONFIG_LEDS_APU is not set
# CONFIG_LEDS_AS3645A is not set
CONFIG_LEDS_BCM6328=m
# CONFIG_LEDS_BCM6358 is not set
CONFIG_LEDS_CR0014114=m
CONFIG_LEDS_LM3530=m
# CONFIG_LEDS_LM3532 is not set
CONFIG_LEDS_LM3642=m
CONFIG_LEDS_LM3692X=y
CONFIG_LEDS_LM3601X=m
CONFIG_LEDS_MT6323=m
# CONFIG_LEDS_PCA9532 is not set
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_LP3944=m
CONFIG_LEDS_LP3952=y
CONFIG_LEDS_LP55XX_COMMON=y
# CONFIG_LEDS_LP5521 is not set
# CONFIG_LEDS_LP5523 is not set
# CONFIG_LEDS_LP5562 is not set
CONFIG_LEDS_LP8501=y
CONFIG_LEDS_LP8860=m
CONFIG_LEDS_CLEVO_MAIL=m
CONFIG_LEDS_PCA955X=m
# CONFIG_LEDS_PCA955X_GPIO is not set
CONFIG_LEDS_PCA963X=y
CONFIG_LEDS_WM831X_STATUS=y
CONFIG_LEDS_DA903X=m
CONFIG_LEDS_DA9052=m
# CONFIG_LEDS_DAC124S085 is not set
CONFIG_LEDS_PWM=m
CONFIG_LEDS_REGULATOR=m
CONFIG_LEDS_BD2802=m
CONFIG_LEDS_INTEL_SS4200=y
# CONFIG_LEDS_LT3593 is not set
CONFIG_LEDS_MC13783=m
CONFIG_LEDS_TCA6507=y
# CONFIG_LEDS_TLC591XX is not set
# CONFIG_LEDS_MAX77693 is not set
CONFIG_LEDS_MAX8997=y
# CONFIG_LEDS_LM355x is not set
# CONFIG_LEDS_OT200 is not set
CONFIG_LEDS_KTD2692=m
# CONFIG_LEDS_IS31FL319X is not set
CONFIG_LEDS_IS31FL32XX=y
CONFIG_LEDS_SC27XX_BLTC=y

#
# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)
#
CONFIG_LEDS_BLINKM=m
CONFIG_LEDS_SYSCON=y
CONFIG_LEDS_MLXCPLD=m
CONFIG_LEDS_MLXREG=m
# CONFIG_LEDS_USER is not set
CONFIG_LEDS_NIC78BX=y

#
# LED Triggers
#
CONFIG_LEDS_TRIGGERS=y
# CONFIG_LEDS_TRIGGER_TIMER is not set
CONFIG_LEDS_TRIGGER_ONESHOT=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=m
CONFIG_LEDS_TRIGGER_BACKLIGHT=m
CONFIG_LEDS_TRIGGER_CPU=y
CONFIG_LEDS_TRIGGER_ACTIVITY=m
CONFIG_LEDS_TRIGGER_GPIO=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=m

#
# iptables trigger is under Netfilter config (LED target)
#
# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
# CONFIG_LEDS_TRIGGER_CAMERA is not set
# CONFIG_LEDS_TRIGGER_PANIC is not set
CONFIG_LEDS_TRIGGER_PATTERN=m
CONFIG_LEDS_TRIGGER_AUDIO=y
CONFIG_ACCESSIBILITY=y
CONFIG_EDAC_ATOMIC_SCRUB=y
CONFIG_EDAC_SUPPORT=y
CONFIG_EDAC=y
CONFIG_EDAC_LEGACY_SYSFS=y
CONFIG_EDAC_DEBUG=y
CONFIG_EDAC_DECODE_MCE=y
# CONFIG_EDAC_GHES is not set
CONFIG_EDAC_AMD64=y
CONFIG_EDAC_AMD64_ERROR_INJECTION=y
CONFIG_EDAC_AMD76X=y
CONFIG_EDAC_E7XXX=y
CONFIG_EDAC_E752X=y
# CONFIG_EDAC_I82875P is not set
# CONFIG_EDAC_I82975X is not set
CONFIG_EDAC_I3000=y
# CONFIG_EDAC_I3200 is not set
# CONFIG_EDAC_IE31200 is not set
CONFIG_EDAC_X38=m
# CONFIG_EDAC_I5400 is not set
# CONFIG_EDAC_I7CORE is not set
CONFIG_EDAC_I82860=y
# CONFIG_EDAC_R82600 is not set
# CONFIG_EDAC_I5000 is not set
CONFIG_EDAC_I5100=m
CONFIG_EDAC_I7300=y
# CONFIG_EDAC_XGENE is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_MC146818_LIB=y
# CONFIG_RTC_CLASS is not set
CONFIG_DMADEVICES=y
CONFIG_DMADEVICES_DEBUG=y
CONFIG_DMADEVICES_VDEBUG=y

#
# DMA Devices
#
CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=y
CONFIG_DMA_ENGINE=y
CONFIG_DMA_VIRTUAL_CHANNELS=y
CONFIG_DMA_ACPI=y
CONFIG_DMA_OF=y
CONFIG_ALTERA_MSGDMA=m
CONFIG_AXI_DMAC=m
CONFIG_COH901318=y
CONFIG_DMA_JZ4740=y
CONFIG_DMA_JZ4780=m
# CONFIG_DMA_SA11X0 is not set
# CONFIG_DMA_SUN6I is not set
CONFIG_DW_AXI_DMAC=y
CONFIG_EP93XX_DMA=y
# CONFIG_FSL_EDMA is not set
CONFIG_IMG_MDC_DMA=m
CONFIG_INTEL_IDMA64=m
# CONFIG_K3_DMA is not set
CONFIG_MCF_EDMA=m
CONFIG_MMP_PDMA=y
CONFIG_MMP_TDMA=y
CONFIG_MV_XOR=y
CONFIG_MXS_DMA=y
# CONFIG_NBPFAXI_DMA is not set
CONFIG_PCH_DMA=m
CONFIG_STM32_DMA=y
CONFIG_STM32_DMAMUX=y
# CONFIG_STM32_MDMA is not set
CONFIG_SPRD_DMA=m
# CONFIG_S3C24XX_DMAC is not set
CONFIG_TEGRA210_ADMA=y
CONFIG_TIMB_DMA=y
CONFIG_UNIPHIER_MDMAC=y
# CONFIG_XGENE_DMA is not set
# CONFIG_ZX_DMA is not set
CONFIG_MTK_HSDMA=m
# CONFIG_MTK_CQDMA is not set
CONFIG_QCOM_HIDMA_MGMT=m
CONFIG_QCOM_HIDMA=m
CONFIG_DW_DMAC_CORE=m
CONFIG_DW_DMAC=m
CONFIG_DW_DMAC_PCI=m
CONFIG_RENESAS_DMA=y
CONFIG_SH_DMAE_BASE=y
# CONFIG_SH_DMAE is not set
CONFIG_RCAR_DMAC=y
# CONFIG_RENESAS_USB_DMAC is not set
CONFIG_SUDMAC=m
CONFIG_TI_EDMA=m
CONFIG_DMA_OMAP=m
CONFIG_TI_DMA_CROSSBAR=y

#
# DMA Clients
#
# CONFIG_ASYNC_TX_DMA is not set
# CONFIG_DMATEST is not set
CONFIG_DMA_ENGINE_RAID=y

#
# DMABUF options
#
CONFIG_SYNC_FILE=y
CONFIG_SW_SYNC=y
# CONFIG_UDMABUF is not set
CONFIG_AUXDISPLAY=y
CONFIG_HD44780=m
CONFIG_IMG_ASCII_LCD=y
# CONFIG_HT16K33 is not set
CONFIG_PANEL_CHANGE_MESSAGE=y
CONFIG_PANEL_BOOT_MESSAGE=""
# CONFIG_CHARLCD_BL_OFF is not set
CONFIG_CHARLCD_BL_ON=y
# CONFIG_CHARLCD_BL_FLASH is not set
CONFIG_CHARLCD=m
CONFIG_UIO=m
CONFIG_UIO_CIF=m
CONFIG_UIO_PDRV_GENIRQ=m
CONFIG_UIO_DMEM_GENIRQ=m
CONFIG_UIO_AEC=m
CONFIG_UIO_SERCOS3=m
CONFIG_UIO_PCI_GENERIC=m
CONFIG_UIO_NETX=m
# CONFIG_UIO_PRUSS is not set
CONFIG_UIO_MF624=m
# CONFIG_UIO_HV_GENERIC is not set
CONFIG_VFIO_IOMMU_TYPE1=m
CONFIG_VFIO=m
CONFIG_VFIO_NOIOMMU=y
# CONFIG_VFIO_PCI is not set
CONFIG_VFIO_MDEV=m
# CONFIG_VFIO_MDEV_DEVICE is not set
CONFIG_VIRT_DRIVERS=y
# CONFIG_VBOXGUEST is not set
CONFIG_VIRTIO=m
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO_PCI=m
CONFIG_VIRTIO_PCI_LEGACY=y
CONFIG_VIRTIO_BALLOON=m
CONFIG_VIRTIO_INPUT=m
CONFIG_VIRTIO_MMIO=m
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y

#
# Microsoft Hyper-V guest support
#
CONFIG_HYPERV=m
# CONFIG_HYPERV_BALLOON is not set
# CONFIG_STAGING is not set
CONFIG_X86_PLATFORM_DEVICES=y
# CONFIG_ACER_WMI is not set
CONFIG_ACER_WIRELESS=y
CONFIG_ACERHDF=y
# CONFIG_ALIENWARE_WMI is not set
CONFIG_ASUS_LAPTOP=m
CONFIG_DCDBAS=m
CONFIG_DELL_SMBIOS=m
# CONFIG_DELL_SMBIOS_WMI is not set
CONFIG_DELL_SMBIOS_SMM=y
# CONFIG_DELL_LAPTOP is not set
# CONFIG_DELL_WMI is not set
CONFIG_DELL_WMI_AIO=m
# CONFIG_DELL_WMI_LED is not set
# CONFIG_DELL_SMO8800 is not set
# CONFIG_DELL_RBU is not set
CONFIG_FUJITSU_LAPTOP=m
# CONFIG_FUJITSU_TABLET is not set
CONFIG_GPD_POCKET_FAN=m
# CONFIG_TC1100_WMI is not set
# CONFIG_HP_ACCEL is not set
# CONFIG_HP_WIRELESS is not set
CONFIG_HP_WMI=m
# CONFIG_LG_LAPTOP is not set
CONFIG_PANASONIC_LAPTOP=m
# CONFIG_SURFACE3_WMI is not set
CONFIG_SENSORS_HDAPS=m
CONFIG_INTEL_MENLOW=m
CONFIG_ASUS_WIRELESS=y
CONFIG_ACPI_WMI=y
CONFIG_WMI_BMOF=m
CONFIG_INTEL_WMI_THUNDERBOLT=m
# CONFIG_MSI_WMI is not set
# CONFIG_PEAQ_WMI is not set
# CONFIG_TOPSTAR_LAPTOP is not set
# CONFIG_ACPI_TOSHIBA is not set
CONFIG_TOSHIBA_BT_RFKILL=y
# CONFIG_TOSHIBA_HAPS is not set
CONFIG_TOSHIBA_WMI=m
# CONFIG_ACPI_CMPC is not set
CONFIG_INTEL_INT0002_VGPIO=m
CONFIG_INTEL_HID_EVENT=m
CONFIG_INTEL_VBTN=m
CONFIG_INTEL_IPS=y
# CONFIG_INTEL_PMC_CORE is not set
CONFIG_IBM_RTL=m
CONFIG_XO15_EBOOK=m
CONFIG_SAMSUNG_LAPTOP=m
# CONFIG_MXM_WMI is not set
CONFIG_SAMSUNG_Q10=m
CONFIG_APPLE_GMUX=m
# CONFIG_INTEL_RST is not set
# CONFIG_INTEL_SMARTCONNECT is not set
CONFIG_INTEL_PMC_IPC=m
CONFIG_INTEL_BXTWC_PMIC_TMU=m
CONFIG_SURFACE_PRO3_BUTTON=y
# CONFIG_INTEL_PUNIT_IPC is not set
CONFIG_MLX_PLATFORM=m
# CONFIG_TOUCHSCREEN_DMI is not set
# CONFIG_INTEL_CHTDC_TI_PWRBTN is not set
CONFIG_I2C_MULTI_INSTANTIATE=y
# CONFIG_INTEL_ATOMISP2_PM is not set
CONFIG_HUAWEI_WMI=y
CONFIG_PMC_ATOM=y
# CONFIG_CHROME_PLATFORMS is not set
# CONFIG_MELLANOX_PLATFORM is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_COMMON_CLK=y

#
# Common Clock Framework
#
CONFIG_COMMON_CLK_WM831X=y
# CONFIG_COMMON_CLK_VERSATILE is not set
# CONFIG_CLK_HSDK is not set
# CONFIG_COMMON_CLK_MAX77686 is not set
CONFIG_COMMON_CLK_MAX9485=m
CONFIG_COMMON_CLK_RK808=m
CONFIG_COMMON_CLK_HI655X=m
CONFIG_COMMON_CLK_SCMI=m
CONFIG_COMMON_CLK_SCPI=m
CONFIG_COMMON_CLK_SI5351=y
CONFIG_COMMON_CLK_SI514=m
CONFIG_COMMON_CLK_SI544=m
CONFIG_COMMON_CLK_SI570=m
# CONFIG_COMMON_CLK_CDCE706 is not set
CONFIG_COMMON_CLK_CDCE925=m
# CONFIG_COMMON_CLK_CS2000_CP is not set
# CONFIG_COMMON_CLK_GEMINI is not set
CONFIG_COMMON_CLK_ASPEED=y
CONFIG_COMMON_CLK_S2MPS11=y
CONFIG_CLK_TWL6040=m
CONFIG_COMMON_CLK_AXI_CLKGEN=y
# CONFIG_CLK_QORIQ is not set
# CONFIG_COMMON_CLK_XGENE is not set
CONFIG_COMMON_CLK_PALMAS=y
CONFIG_COMMON_CLK_PWM=y
# CONFIG_COMMON_CLK_OXNAS is not set
CONFIG_COMMON_CLK_VC5=m
CONFIG_COMMON_CLK_BD718XX=m
# CONFIG_COMMON_CLK_FIXED_MMIO is not set
CONFIG_CLK_ACTIONS=y
# CONFIG_CLK_OWL_S500 is not set
# CONFIG_CLK_OWL_S700 is not set
# CONFIG_CLK_OWL_S900 is not set
# CONFIG_CLK_BCM_63XX is not set
# CONFIG_CLK_BCM_KONA is not set
CONFIG_COMMON_CLK_IPROC=y
# CONFIG_CLK_BCM_CYGNUS is not set
# CONFIG_CLK_BCM_HR2 is not set
CONFIG_CLK_BCM_NSP=y
# CONFIG_CLK_BCM_NS2 is not set
# CONFIG_CLK_BCM_SR is not set
# CONFIG_COMMON_CLK_HI3516CV300 is not set
CONFIG_COMMON_CLK_HI3519=m
# CONFIG_COMMON_CLK_HI3660 is not set
CONFIG_COMMON_CLK_HI3670=y
CONFIG_COMMON_CLK_HI3798CV200=m
CONFIG_COMMON_CLK_HI6220=y
CONFIG_RESET_HISI=y
# CONFIG_STUB_CLK_HI6220 is not set
CONFIG_STUB_CLK_HI3660=y
CONFIG_COMMON_CLK_BOSTON=y
CONFIG_COMMON_CLK_KEYSTONE=m

#
# Clock driver for MediaTek SoC
#
CONFIG_COMMON_CLK_MEDIATEK=y
# CONFIG_COMMON_CLK_MT2701 is not set
# CONFIG_COMMON_CLK_MT2712 is not set
CONFIG_COMMON_CLK_MT6797=y
# CONFIG_COMMON_CLK_MT6797_MMSYS is not set
# CONFIG_COMMON_CLK_MT6797_IMGSYS is not set
CONFIG_COMMON_CLK_MT6797_VDECSYS=y
CONFIG_COMMON_CLK_MT6797_VENCSYS=y
CONFIG_COMMON_CLK_MT7622=y
CONFIG_COMMON_CLK_MT7622_ETHSYS=y
CONFIG_COMMON_CLK_MT7622_HIFSYS=y
CONFIG_COMMON_CLK_MT7622_AUDSYS=y
# CONFIG_COMMON_CLK_MT7629 is not set
CONFIG_COMMON_CLK_MT8135=y
# CONFIG_COMMON_CLK_MT8173 is not set
CONFIG_QCOM_GDSC=y
CONFIG_QCOM_RPMCC=y
CONFIG_COMMON_CLK_QCOM=y
# CONFIG_QCOM_A53PLL is not set
CONFIG_QCOM_CLK_APCS_MSM8916=y
CONFIG_QCOM_CLK_SMD_RPM=m
CONFIG_APQ_GCC_8084=m
# CONFIG_APQ_MMCC_8084 is not set
CONFIG_IPQ_GCC_4019=y
CONFIG_IPQ_GCC_806X=m
CONFIG_IPQ_LCC_806X=m
CONFIG_IPQ_GCC_8074=m
CONFIG_MSM_GCC_8660=m
# CONFIG_MSM_GCC_8916 is not set
CONFIG_MSM_GCC_8960=y
CONFIG_MSM_LCC_8960=y
CONFIG_MDM_GCC_9615=m
CONFIG_MDM_LCC_9615=m
CONFIG_MSM_MMCC_8960=m
# CONFIG_MSM_GCC_8974 is not set
# CONFIG_MSM_MMCC_8974 is not set
# CONFIG_MSM_GCC_8994 is not set
CONFIG_MSM_GCC_8996=y
CONFIG_MSM_MMCC_8996=y
# CONFIG_MSM_GCC_8998 is not set
CONFIG_QCS_GCC_404=y
# CONFIG_SDM_CAMCC_845 is not set
# CONFIG_SDM_GCC_660 is not set
CONFIG_SDM_GCC_845=y
CONFIG_SDM_GPUCC_845=y
CONFIG_SDM_VIDEOCC_845=y
# CONFIG_SDM_DISPCC_845 is not set
CONFIG_SDM_LPASSCC_845=y
CONFIG_SPMI_PMIC_CLKDIV=m
# CONFIG_QCOM_HFPLL is not set
CONFIG_KPSS_XCC=m
# CONFIG_CLK_RENESAS is not set
CONFIG_COMMON_CLK_SAMSUNG=y
# CONFIG_EXYNOS_ARM64_COMMON_CLK is not set
# CONFIG_EXYNOS_AUDSS_CLK_CON is not set
CONFIG_S3C2410_COMMON_CLK=y
# CONFIG_S3C2412_COMMON_CLK is not set
# CONFIG_S3C2443_COMMON_CLK is not set
# CONFIG_SPRD_COMMON_CLK is not set
# CONFIG_CLK_SUNXI is not set
# CONFIG_SUNXI_CCU is not set
CONFIG_COMMON_CLK_TI_ADPLL=m
# CONFIG_CLK_UNIPHIER is not set
CONFIG_HWSPINLOCK=y

#
# Clock Source drivers
#
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_CLKSRC_I8253=y
CONFIG_CLKEVT_I8253=y
CONFIG_I8253_LOCK=y
CONFIG_CLKBLD_I8253=y
CONFIG_CLKSRC_MMIO=y
# CONFIG_BCM2835_TIMER is not set
CONFIG_BCM_KONA_TIMER=y
CONFIG_DIGICOLOR_TIMER=y
# CONFIG_DW_APB_TIMER is not set
CONFIG_FTTMR010_TIMER=y
CONFIG_MESON6_TIMER=y
# CONFIG_OWL_TIMER is not set
# CONFIG_RDA_TIMER is not set
# CONFIG_SUN4I_TIMER is not set
# CONFIG_SUN5I_HSTIMER is not set
# CONFIG_VT8500_TIMER is not set
CONFIG_NPCM7XX_TIMER=y
# CONFIG_CADENCE_TTC_TIMER is not set
CONFIG_ASM9260_TIMER=y
CONFIG_CLKSRC_DBX500_PRCMU=y
# CONFIG_CLPS711X_TIMER is not set
CONFIG_ATLAS7_TIMER=y
CONFIG_MXS_TIMER=y
CONFIG_PRIMA2_TIMER=y
# CONFIG_NSPIRE_TIMER is not set
CONFIG_INTEGRATOR_AP_TIMER=y
# CONFIG_CLKSRC_PISTACHIO is not set
CONFIG_CLKSRC_NPS=y
# CONFIG_ARMV7M_SYSTICK is not set
CONFIG_ATMEL_ST=y
# CONFIG_CLKSRC_SAMSUNG_PWM is not set
# CONFIG_FSL_FTM_TIMER is not set
CONFIG_OXNAS_RPS_TIMER=y
# CONFIG_MTK_TIMER is not set
# CONFIG_SPRD_TIMER is not set
# CONFIG_CLKSRC_JCORE_PIT is not set
# CONFIG_SH_TIMER_CMT is not set
# CONFIG_SH_TIMER_MTU2 is not set
# CONFIG_RENESAS_OSTM is not set
CONFIG_SH_TIMER_TMU=y
# CONFIG_EM_TIMER_STI is not set
# CONFIG_CLKSRC_PXA is not set
CONFIG_H8300_TMR8=y
CONFIG_H8300_TMR16=y
# CONFIG_H8300_TPU is not set
CONFIG_CLKSRC_ST_LPC=y
CONFIG_ATCPIT100_TIMER=y
CONFIG_MAILBOX=y
CONFIG_IMX_MBOX=y
# CONFIG_PLATFORM_MHU is not set
# CONFIG_ROCKCHIP_MBOX is not set
# CONFIG_PCC is not set
# CONFIG_ALTERA_MBOX is not set
CONFIG_HI3660_MBOX=m
CONFIG_HI6220_MBOX=m
CONFIG_MAILBOX_TEST=y
CONFIG_QCOM_APCS_IPC=y
# CONFIG_BCM_PDC_MBOX is not set
CONFIG_MTK_CMDQ_MBOX=m
CONFIG_IOMMU_IOVA=y
CONFIG_IOMMU_API=y
CONFIG_IOMMU_SUPPORT=y

#
# Generic IOMMU Pagetable Support
#
# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
# CONFIG_IOMMU_DEBUGFS is not set
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_OF_IOMMU=y
CONFIG_DMAR_TABLE=y
CONFIG_INTEL_IOMMU=y
CONFIG_INTEL_IOMMU_SVM=y
# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
CONFIG_INTEL_IOMMU_FLOPPY_WA=y
# CONFIG_QCOM_IOMMU is not set
CONFIG_HYPERV_IOMMU=y

#
# Remoteproc drivers
#
CONFIG_REMOTEPROC=m

#
# Rpmsg drivers
#
CONFIG_RPMSG=y
CONFIG_RPMSG_QCOM_GLINK_NATIVE=y
CONFIG_RPMSG_QCOM_GLINK_RPM=y
CONFIG_RPMSG_QCOM_GLINK_SMEM=m
CONFIG_RPMSG_QCOM_SMD=m
# CONFIG_RPMSG_VIRTIO is not set
CONFIG_SOUNDWIRE=y

#
# SoundWire Devices
#

#
# SOC (System On Chip) specific Drivers
#
# CONFIG_OWL_PM_DOMAINS is not set

#
# Amlogic SoC drivers
#
CONFIG_MESON_CANVAS=m
# CONFIG_MESON_CLK_MEASURE is not set
# CONFIG_MESON_GX_SOCINFO is not set
# CONFIG_MESON_GX_PM_DOMAINS is not set
# CONFIG_MESON_MX_SOCINFO is not set
CONFIG_AT91_SOC_ID=y

#
# Broadcom SoC drivers
#
CONFIG_BCM2835_POWER=y
# CONFIG_SOC_BRCMSTB is not set

#
# NXP/Freescale QorIQ SoC drivers
#

#
# i.MX SoC drivers
#
CONFIG_IMX_GPCV2_PM_DOMAINS=y

#
# MediaTek SoC drivers
#
# CONFIG_MTK_CMDQ is not set
CONFIG_MTK_INFRACFG=y
CONFIG_MTK_PMIC_WRAP=m
CONFIG_MTK_SCPSYS=y

#
# Qualcomm SoC drivers
#
CONFIG_QCOM_COMMAND_DB=y
# CONFIG_QCOM_GENI_SE is not set
CONFIG_QCOM_GSBI=y
CONFIG_QCOM_LLCC=m
# CONFIG_QCOM_SDM845_LLCC is not set
# CONFIG_QCOM_RPMH is not set
# CONFIG_QCOM_RPMPD is not set
CONFIG_QCOM_SMEM=m
CONFIG_QCOM_SMD_RPM=y
CONFIG_QCOM_SMEM_STATE=y
CONFIG_QCOM_SMP2P=m
CONFIG_QCOM_SMSM=m
# CONFIG_QCOM_WCNSS_CTRL is not set
CONFIG_QCOM_APR=m
# CONFIG_SOC_RENESAS is not set
CONFIG_ROCKCHIP_GRF=y
# CONFIG_ROCKCHIP_PM_DOMAINS is not set
CONFIG_SOC_SAMSUNG=y
# CONFIG_EXYNOS_PM_DOMAINS is not set
CONFIG_SOC_TI=y
CONFIG_UX500_SOC_ID=y

#
# Xilinx SoC drivers
#
# CONFIG_XILINX_VCU is not set
CONFIG_SOC_ZTE=y
# CONFIG_ZX2967_PM_DOMAINS is not set
# CONFIG_PM_DEVFREQ is not set
CONFIG_EXTCON=y

#
# Extcon Device Drivers
#
# CONFIG_EXTCON_ADC_JACK is not set
# CONFIG_EXTCON_GPIO is not set
CONFIG_EXTCON_INTEL_INT3496=m
CONFIG_EXTCON_MAX14577=y
CONFIG_EXTCON_MAX3355=y
CONFIG_EXTCON_MAX77693=m
CONFIG_EXTCON_MAX8997=y
CONFIG_EXTCON_PALMAS=y
# CONFIG_EXTCON_PTN5150 is not set
CONFIG_EXTCON_QCOM_SPMI_MISC=m
# CONFIG_EXTCON_RT8973A is not set
# CONFIG_EXTCON_SM5502 is not set
# CONFIG_EXTCON_USB_GPIO is not set
# CONFIG_MEMORY is not set
CONFIG_IIO=m
CONFIG_IIO_BUFFER=y
CONFIG_IIO_BUFFER_CB=m
CONFIG_IIO_BUFFER_HW_CONSUMER=m
CONFIG_IIO_KFIFO_BUF=m
CONFIG_IIO_TRIGGERED_BUFFER=m
CONFIG_IIO_CONFIGFS=m
CONFIG_IIO_TRIGGER=y
CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
CONFIG_IIO_SW_DEVICE=m
# CONFIG_IIO_SW_TRIGGER is not set
CONFIG_IIO_TRIGGERED_EVENT=m

#
# Accelerometers
#
CONFIG_ADIS16201=m
CONFIG_ADIS16209=m
CONFIG_ADXL372=m
CONFIG_ADXL372_SPI=m
# CONFIG_ADXL372_I2C is not set
# CONFIG_BMA180 is not set
CONFIG_BMA220=m
# CONFIG_BMC150_ACCEL is not set
# CONFIG_DA280 is not set
CONFIG_DA311=m
# CONFIG_DMARD06 is not set
CONFIG_DMARD09=m
# CONFIG_DMARD10 is not set
# CONFIG_HID_SENSOR_ACCEL_3D is not set
CONFIG_IIO_CROS_EC_ACCEL_LEGACY=m
CONFIG_IIO_ST_ACCEL_3AXIS=m
CONFIG_IIO_ST_ACCEL_I2C_3AXIS=m
CONFIG_IIO_ST_ACCEL_SPI_3AXIS=m
# CONFIG_KXSD9 is not set
CONFIG_KXCJK1013=m
CONFIG_MC3230=m
CONFIG_MMA7455=m
# CONFIG_MMA7455_I2C is not set
CONFIG_MMA7455_SPI=m
CONFIG_MMA7660=m
# CONFIG_MMA8452 is not set
CONFIG_MMA9551_CORE=m
CONFIG_MMA9551=m
# CONFIG_MMA9553 is not set
CONFIG_MXC4005=m
# CONFIG_MXC6255 is not set
CONFIG_SCA3000=m
CONFIG_STK8312=m
CONFIG_STK8BA50=m

#
# Analog to digital converters
#
CONFIG_AD_SIGMA_DELTA=m
CONFIG_AD7124=m
# CONFIG_AD7266 is not set
CONFIG_AD7291=m
# CONFIG_AD7298 is not set
CONFIG_AD7476=m
CONFIG_AD7606=m
CONFIG_AD7606_IFACE_PARALLEL=m
# CONFIG_AD7606_IFACE_SPI is not set
CONFIG_AD7766=m
CONFIG_AD7768_1=m
CONFIG_AD7780=m
CONFIG_AD7791=m
CONFIG_AD7793=m
CONFIG_AD7887=m
CONFIG_AD7923=m
# CONFIG_AD7949 is not set
CONFIG_AD799X=m
CONFIG_ASPEED_ADC=m
# CONFIG_AT91_SAMA5D2_ADC is not set
CONFIG_BCM_IPROC_ADC=m
CONFIG_CC10001_ADC=m
CONFIG_DLN2_ADC=m
CONFIG_ENVELOPE_DETECTOR=m
CONFIG_EXYNOS_ADC=m
CONFIG_MXS_LRADC_ADC=m
CONFIG_FSL_MX25_ADC=m
CONFIG_HI8435=m
CONFIG_HX711=m
CONFIG_INA2XX_ADC=m
# CONFIG_INGENIC_ADC is not set
CONFIG_IMX7D_ADC=m
# CONFIG_LPC18XX_ADC is not set
CONFIG_LPC32XX_ADC=m
CONFIG_LTC2471=m
CONFIG_LTC2485=m
# CONFIG_LTC2497 is not set
CONFIG_MAX1027=m
# CONFIG_MAX11100 is not set
# CONFIG_MAX1118 is not set
CONFIG_MAX1363=m
CONFIG_MAX9611=m
CONFIG_MCP320X=m
CONFIG_MCP3422=m
# CONFIG_MCP3911 is not set
CONFIG_MEDIATEK_MT6577_AUXADC=m
# CONFIG_MEN_Z188_ADC is not set
# CONFIG_MESON_SARADC is not set
CONFIG_NAU7802=m
CONFIG_NPCM_ADC=m
CONFIG_PALMAS_GPADC=m
CONFIG_QCOM_VADC_COMMON=m
CONFIG_QCOM_SPMI_IADC=m
CONFIG_QCOM_SPMI_VADC=m
CONFIG_QCOM_SPMI_ADC5=m
CONFIG_RCAR_GYRO_ADC=m
CONFIG_SC27XX_ADC=m
CONFIG_SPEAR_ADC=m
CONFIG_SD_ADC_MODULATOR=m
CONFIG_STM32_ADC_CORE=m
# CONFIG_STM32_ADC is not set
CONFIG_STM32_DFSDM_CORE=m
CONFIG_STM32_DFSDM_ADC=m
CONFIG_STMPE_ADC=m
CONFIG_SUN4I_GPADC=m
CONFIG_TI_ADC081C=m
CONFIG_TI_ADC0832=m
CONFIG_TI_ADC084S021=m
# CONFIG_TI_ADC12138 is not set
# CONFIG_TI_ADC108S102 is not set
CONFIG_TI_ADC128S052=m
# CONFIG_TI_ADC161S626 is not set
# CONFIG_TI_ADS1015 is not set
# CONFIG_TI_ADS7950 is not set
# CONFIG_TI_ADS8688 is not set
CONFIG_TI_ADS124S08=m
# CONFIG_TI_AM335X_ADC is not set
CONFIG_TI_TLC4541=m
CONFIG_TWL4030_MADC=m
# CONFIG_TWL6030_GPADC is not set
CONFIG_VF610_ADC=m
CONFIG_XILINX_XADC=m

#
# Analog Front Ends
#
CONFIG_IIO_RESCALE=m

#
# Amplifiers
#
CONFIG_AD8366=m

#
# Chemical Sensors
#
# CONFIG_ATLAS_PH_SENSOR is not set
CONFIG_BME680=m
CONFIG_BME680_I2C=m
CONFIG_BME680_SPI=m
# CONFIG_CCS811 is not set
CONFIG_IAQCORE=m
CONFIG_PMS7003=m
CONFIG_SENSIRION_SGP30=m
CONFIG_SPS30=m
# CONFIG_VZ89X is not set

#
# Hid Sensor IIO Common
#
CONFIG_HID_SENSOR_IIO_COMMON=m
CONFIG_HID_SENSOR_IIO_TRIGGER=m
CONFIG_IIO_MS_SENSORS_I2C=m

#
# SSP Sensor Common
#
# CONFIG_IIO_SSP_SENSORHUB is not set
CONFIG_IIO_ST_SENSORS_I2C=m
CONFIG_IIO_ST_SENSORS_SPI=m
CONFIG_IIO_ST_SENSORS_CORE=m

#
# Counters
#
CONFIG_STM32_LPTIMER_CNT=m

#
# Digital to analog converters
#
CONFIG_AD5064=m
# CONFIG_AD5360 is not set
CONFIG_AD5380=m
CONFIG_AD5421=m
# CONFIG_AD5446 is not set
CONFIG_AD5449=m
CONFIG_AD5592R_BASE=m
CONFIG_AD5592R=m
CONFIG_AD5593R=m
CONFIG_AD5504=m
CONFIG_AD5624R_SPI=m
CONFIG_LTC1660=m
# CONFIG_LTC2632 is not set
CONFIG_AD5686=m
# CONFIG_AD5686_SPI is not set
CONFIG_AD5696_I2C=m
CONFIG_AD5755=m
CONFIG_AD5758=m
CONFIG_AD5761=m
CONFIG_AD5764=m
CONFIG_AD5791=m
CONFIG_AD7303=m
CONFIG_CIO_DAC=m
CONFIG_AD8801=m
# CONFIG_DPOT_DAC is not set
# CONFIG_DS4424 is not set
# CONFIG_LPC18XX_DAC is not set
CONFIG_M62332=m
# CONFIG_MAX517 is not set
# CONFIG_MAX5821 is not set
# CONFIG_MCP4725 is not set
CONFIG_MCP4922=m
# CONFIG_STM32_DAC is not set
CONFIG_TI_DAC082S085=m
# CONFIG_TI_DAC5571 is not set
CONFIG_TI_DAC7311=m
# CONFIG_TI_DAC7612 is not set
CONFIG_VF610_DAC=m

#
# IIO dummy driver
#
CONFIG_IIO_SIMPLE_DUMMY=m
# CONFIG_IIO_SIMPLE_DUMMY_EVENTS is not set
CONFIG_IIO_SIMPLE_DUMMY_BUFFER=y

#
# Frequency Synthesizers DDS/PLL
#

#
# Clock Generator/Distribution
#
# CONFIG_AD9523 is not set

#
# Phase-Locked Loop (PLL) frequency synthesizers
#
CONFIG_ADF4350=m

#
# Digital gyroscope sensors
#
# CONFIG_ADIS16080 is not set
CONFIG_ADIS16130=m
# CONFIG_ADIS16136 is not set
CONFIG_ADIS16260=m
CONFIG_ADXRS450=m
CONFIG_BMG160=m
CONFIG_BMG160_I2C=m
CONFIG_BMG160_SPI=m
CONFIG_HID_SENSOR_GYRO_3D=m
CONFIG_MPU3050=m
CONFIG_MPU3050_I2C=m
CONFIG_IIO_ST_GYRO_3AXIS=m
CONFIG_IIO_ST_GYRO_I2C_3AXIS=m
CONFIG_IIO_ST_GYRO_SPI_3AXIS=m
# CONFIG_ITG3200 is not set

#
# Health Sensors
#

#
# Heart Rate Monitors
#
CONFIG_AFE4403=m
# CONFIG_AFE4404 is not set
CONFIG_MAX30100=m
CONFIG_MAX30102=m

#
# Humidity sensors
#
CONFIG_AM2315=m
CONFIG_DHT11=m
# CONFIG_HDC100X is not set
CONFIG_HID_SENSOR_HUMIDITY=m
# CONFIG_HTS221 is not set
CONFIG_HTU21=m
# CONFIG_SI7005 is not set
CONFIG_SI7020=m

#
# Inertial measurement units
#
CONFIG_ADIS16400=m
# CONFIG_ADIS16480 is not set
CONFIG_BMI160=m
# CONFIG_BMI160_I2C is not set
CONFIG_BMI160_SPI=m
CONFIG_KMX61=m
CONFIG_INV_MPU6050_IIO=m
# CONFIG_INV_MPU6050_I2C is not set
CONFIG_INV_MPU6050_SPI=m
# CONFIG_IIO_ST_LSM6DSX is not set
CONFIG_IIO_ADIS_LIB=m
CONFIG_IIO_ADIS_LIB_BUFFER=y

#
# Light sensors
#
CONFIG_ACPI_ALS=m
CONFIG_ADJD_S311=m
CONFIG_AL3320A=m
# CONFIG_APDS9300 is not set
# CONFIG_APDS9960 is not set
CONFIG_BH1750=m
# CONFIG_BH1780 is not set
CONFIG_CM32181=m
# CONFIG_CM3232 is not set
CONFIG_CM3323=m
CONFIG_CM3605=m
CONFIG_CM36651=m
# CONFIG_GP2AP020A00F is not set
CONFIG_SENSORS_ISL29018=m
CONFIG_SENSORS_ISL29028=m
CONFIG_ISL29125=m
CONFIG_HID_SENSOR_ALS=m
# CONFIG_HID_SENSOR_PROX is not set
CONFIG_JSA1212=m
CONFIG_RPR0521=m
CONFIG_LTR501=m
CONFIG_LV0104CS=m
CONFIG_MAX44000=m
CONFIG_MAX44009=m
CONFIG_OPT3001=m
CONFIG_PA12203001=m
CONFIG_SI1133=m
CONFIG_SI1145=m
# CONFIG_STK3310 is not set
# CONFIG_ST_UVIS25 is not set
# CONFIG_TCS3414 is not set
# CONFIG_TCS3472 is not set
CONFIG_SENSORS_TSL2563=m
CONFIG_TSL2583=m
CONFIG_TSL2772=m
CONFIG_TSL4531=m
# CONFIG_US5182D is not set
CONFIG_VCNL4000=m
# CONFIG_VCNL4035 is not set
CONFIG_VEML6070=m
# CONFIG_VL6180 is not set
CONFIG_ZOPT2201=m

#
# Magnetometer sensors
#
# CONFIG_AK8974 is not set
CONFIG_AK8975=m
CONFIG_AK09911=m
CONFIG_BMC150_MAGN=m
# CONFIG_BMC150_MAGN_I2C is not set
CONFIG_BMC150_MAGN_SPI=m
# CONFIG_MAG3110 is not set
CONFIG_HID_SENSOR_MAGNETOMETER_3D=m
CONFIG_MMC35240=m
CONFIG_IIO_ST_MAGN_3AXIS=m
CONFIG_IIO_ST_MAGN_I2C_3AXIS=m
CONFIG_IIO_ST_MAGN_SPI_3AXIS=m
CONFIG_SENSORS_HMC5843=m
CONFIG_SENSORS_HMC5843_I2C=m
# CONFIG_SENSORS_HMC5843_SPI is not set
CONFIG_SENSORS_RM3100=m
CONFIG_SENSORS_RM3100_I2C=m
# CONFIG_SENSORS_RM3100_SPI is not set

#
# Multiplexers
#
# CONFIG_IIO_MUX is not set

#
# Inclinometer sensors
#
# CONFIG_HID_SENSOR_INCLINOMETER_3D is not set
# CONFIG_HID_SENSOR_DEVICE_ROTATION is not set

#
# Triggers - standalone
#
CONFIG_IIO_INTERRUPT_TRIGGER=m
CONFIG_IIO_STM32_LPTIMER_TRIGGER=m
CONFIG_IIO_STM32_TIMER_TRIGGER=m
CONFIG_IIO_SYSFS_TRIGGER=m

#
# Digital potentiometers
#
# CONFIG_AD5272 is not set
# CONFIG_DS1803 is not set
# CONFIG_MAX5481 is not set
# CONFIG_MAX5487 is not set
# CONFIG_MCP4018 is not set
CONFIG_MCP4131=m
CONFIG_MCP4531=m
CONFIG_MCP41010=m
CONFIG_TPL0102=m

#
# Digital potentiostats
#
CONFIG_LMP91000=m

#
# Pressure sensors
#
# CONFIG_ABP060MG is not set
# CONFIG_BMP280 is not set
# CONFIG_HID_SENSOR_PRESS is not set
# CONFIG_HP03 is not set
# CONFIG_MPL115_I2C is not set
# CONFIG_MPL115_SPI is not set
CONFIG_MPL3115=m
CONFIG_MS5611=m
CONFIG_MS5611_I2C=m
CONFIG_MS5611_SPI=m
CONFIG_MS5637=m
CONFIG_IIO_ST_PRESS=m
CONFIG_IIO_ST_PRESS_I2C=m
CONFIG_IIO_ST_PRESS_SPI=m
# CONFIG_T5403 is not set
CONFIG_HP206C=m
CONFIG_ZPA2326=m
CONFIG_ZPA2326_I2C=m
CONFIG_ZPA2326_SPI=m

#
# Lightning sensors
#
CONFIG_AS3935=m

#
# Proximity and distance sensors
#
# CONFIG_ISL29501 is not set
CONFIG_LIDAR_LITE_V2=m
# CONFIG_MB1232 is not set
# CONFIG_RFD77402 is not set
# CONFIG_SRF04 is not set
# CONFIG_SX9500 is not set
CONFIG_SRF08=m
# CONFIG_VL53L0X_I2C is not set

#
# Resolver to digital converters
#
# CONFIG_AD2S90 is not set
# CONFIG_AD2S1200 is not set

#
# Temperature sensors
#
# CONFIG_MAXIM_THERMOCOUPLE is not set
# CONFIG_HID_SENSOR_TEMP is not set
CONFIG_MLX90614=m
CONFIG_MLX90632=m
CONFIG_TMP006=m
# CONFIG_TMP007 is not set
CONFIG_TSYS01=m
# CONFIG_TSYS02D is not set
CONFIG_MAX31856=m
CONFIG_NTB=m
CONFIG_NTB_IDT=m
# CONFIG_NTB_SWITCHTEC is not set
CONFIG_NTB_PINGPONG=m
# CONFIG_NTB_TOOL is not set
# CONFIG_NTB_PERF is not set
# CONFIG_NTB_TRANSPORT is not set
# CONFIG_VME_BUS is not set
CONFIG_PWM=y
CONFIG_PWM_SYSFS=y
# CONFIG_PWM_BCM_IPROC is not set
CONFIG_PWM_BCM_KONA=m
CONFIG_PWM_CLPS711X=m
CONFIG_PWM_FSL_FTM=m
CONFIG_PWM_HIBVT=y
CONFIG_PWM_IMG=y
# CONFIG_PWM_LP3943 is not set
CONFIG_PWM_LPSS=y
CONFIG_PWM_LPSS_PCI=y
CONFIG_PWM_LPSS_PLATFORM=m
CONFIG_PWM_MTK_DISP=y
CONFIG_PWM_MEDIATEK=y
CONFIG_PWM_PCA9685=m
# CONFIG_PWM_RCAR is not set
# CONFIG_PWM_RENESAS_TPU is not set
CONFIG_PWM_STM32=m
# CONFIG_PWM_STM32_LP is not set
CONFIG_PWM_STMPE=y
# CONFIG_PWM_SUN4I is not set
CONFIG_PWM_TWL=y
# CONFIG_PWM_TWL_LED is not set

#
# IRQ chip support
#
CONFIG_IRQCHIP=y
CONFIG_ARM_GIC_MAX_NR=1
CONFIG_MADERA_IRQ=y
CONFIG_JCORE_AIC=y
CONFIG_TS4800_IRQ=y
CONFIG_EZNPS_GIC=y
# CONFIG_IRQ_UNIPHIER_AIDET is not set
CONFIG_IMX_IRQSTEER=y
CONFIG_IPACK_BUS=y
CONFIG_BOARD_TPCI200=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RESET_ATH79=y
# CONFIG_RESET_AXS10X is not set
CONFIG_RESET_BERLIN=y
CONFIG_RESET_BRCMSTB=m
# CONFIG_RESET_HSDK is not set
CONFIG_RESET_IMX7=y
# CONFIG_RESET_LANTIQ is not set
CONFIG_RESET_LPC18XX=y
# CONFIG_RESET_MESON is not set
# CONFIG_RESET_MESON_AUDIO_ARB is not set
# CONFIG_RESET_PISTACHIO is not set
CONFIG_RESET_QCOM_AOSS=y
CONFIG_RESET_QCOM_PDC=y
CONFIG_RESET_SIMPLE=y
# CONFIG_RESET_STM32MP157 is not set
CONFIG_RESET_SOCFPGA=y
# CONFIG_RESET_SUNXI is not set
CONFIG_RESET_TI_SYSCON=y
CONFIG_RESET_UNIPHIER=y
CONFIG_RESET_UNIPHIER_GLUE=m
# CONFIG_RESET_ZYNQ is not set
CONFIG_COMMON_RESET_HI3660=m
# CONFIG_COMMON_RESET_HI6220 is not set
# CONFIG_FMC is not set

#
# PHY Subsystem
#
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_PHY_MIPI_DPHY=y
CONFIG_PHY_LPC18XX_USB_OTG=m
CONFIG_PHY_XGENE=y
CONFIG_PHY_SUN4I_USB=m
# CONFIG_PHY_SUN6I_MIPI_DPHY is not set
CONFIG_PHY_SUN9I_USB=y
# CONFIG_PHY_MESON8B_USB2 is not set
# CONFIG_PHY_MESON_GXL_USB2 is not set
# CONFIG_PHY_MESON_GXL_USB3 is not set
# CONFIG_PHY_MESON_G12A_USB2 is not set
CONFIG_PHY_MESON_G12A_USB3_PCIE=m
# CONFIG_PHY_CYGNUS_PCIE is not set
CONFIG_PHY_BCM_SR_USB=m
CONFIG_BCM_KONA_USB2_PHY=m
# CONFIG_PHY_BCM_NS_USB2 is not set
CONFIG_PHY_NS2_USB_DRD=m
CONFIG_PHY_BRCM_SATA=y
CONFIG_PHY_BCM_SR_PCIE=y
CONFIG_PHY_CADENCE_DP=m
CONFIG_PHY_CADENCE_DPHY=m
CONFIG_PHY_CADENCE_SIERRA=m
# CONFIG_PHY_FSL_IMX8MQ_USB is not set
CONFIG_PHY_HI6220_USB=y
CONFIG_PHY_HISTB_COMBPHY=m
CONFIG_PHY_HISI_INNO_USB2=m
CONFIG_PHY_LANTIQ_RCU_USB2=y
CONFIG_ARMADA375_USBCLUSTER_PHY=y
CONFIG_PHY_MVEBU_A3700_UTMI=y
CONFIG_PHY_MVEBU_A38X_COMPHY=y
# CONFIG_PHY_MVEBU_CP110_COMPHY is not set
CONFIG_PHY_PXA_28NM_HSIC=m
# CONFIG_PHY_PXA_28NM_USB2 is not set
# CONFIG_PHY_CPCAP_USB is not set
# CONFIG_PHY_MAPPHONE_MDM6600 is not set
CONFIG_PHY_OCELOT_SERDES=m
CONFIG_PHY_ATH79_USB=m
CONFIG_PHY_QCOM_QMP=m
CONFIG_PHY_QCOM_QUSB2=m
CONFIG_PHY_QCOM_USB_HS=m
# CONFIG_PHY_QCOM_USB_HSIC is not set
CONFIG_PHY_RALINK_USB=m
CONFIG_PHY_RCAR_GEN3_USB3=y
CONFIG_PHY_ROCKCHIP_INNO_HDMI=m
# CONFIG_PHY_ROCKCHIP_INNO_USB2 is not set
CONFIG_PHY_ROCKCHIP_PCIE=m
CONFIG_PHY_ROCKCHIP_TYPEC=y
# CONFIG_PHY_EXYNOS_DP_VIDEO is not set
CONFIG_PHY_EXYNOS_MIPI_VIDEO=m
# CONFIG_PHY_EXYNOS_PCIE is not set
CONFIG_PHY_SAMSUNG_USB2=y
CONFIG_PHY_UNIPHIER_USB2=m
# CONFIG_PHY_UNIPHIER_USB3 is not set
CONFIG_PHY_UNIPHIER_PCIE=y
CONFIG_PHY_ST_SPEAR1310_MIPHY=m
CONFIG_PHY_ST_SPEAR1340_MIPHY=m
# CONFIG_PHY_STIH407_USB is not set
CONFIG_PHY_STM32_USBPHYC=y
CONFIG_OMAP_CONTROL_PHY=y
CONFIG_TI_PIPE3=y
CONFIG_PHY_TUSB1210=m
CONFIG_PHY_TI_GMII_SEL=m
CONFIG_POWERCAP=y
CONFIG_INTEL_RAPL=m
CONFIG_IDLE_INJECT=y
CONFIG_MCB=y
CONFIG_MCB_PCI=m
CONFIG_MCB_LPC=y

#
# Performance monitor support
#
CONFIG_RAS=y
# CONFIG_RAS_CEC is not set
# CONFIG_THUNDERBOLT is not set

#
# Android
#
CONFIG_ANDROID=y
# CONFIG_ANDROID_BINDER_IPC is not set
CONFIG_DAX=y
CONFIG_NVMEM=y
CONFIG_NVMEM_IMX_IIM=y
# CONFIG_NVMEM_IMX_OCOTP is not set
# CONFIG_NVMEM_LPC18XX_EEPROM is not set
CONFIG_NVMEM_LPC18XX_OTP=m
# CONFIG_NVMEM_MXS_OCOTP is not set
# CONFIG_MTK_EFUSE is not set
# CONFIG_QCOM_QFPROM is not set
# CONFIG_ROCKCHIP_EFUSE is not set
CONFIG_NVMEM_BCM_OCOTP=m
CONFIG_NVMEM_STM32_ROMEM=m
CONFIG_UNIPHIER_EFUSE=m
CONFIG_NVMEM_VF610_OCOTP=y
CONFIG_MESON_MX_EFUSE=y
# CONFIG_NVMEM_SNVS_LPGPR is not set
CONFIG_SC27XX_EFUSE=y

#
# HW tracing support
#
# CONFIG_STM is not set
CONFIG_INTEL_TH=y
CONFIG_INTEL_TH_PCI=y
CONFIG_INTEL_TH_ACPI=y
CONFIG_INTEL_TH_GTH=y
CONFIG_INTEL_TH_MSU=m
CONFIG_INTEL_TH_PTI=m
# CONFIG_INTEL_TH_DEBUG is not set
CONFIG_FPGA=y
CONFIG_FPGA_MGR_SOCFPGA=m
# CONFIG_FPGA_MGR_SOCFPGA_A10 is not set
# CONFIG_ALTERA_PR_IP_CORE is not set
CONFIG_FPGA_MGR_ALTERA_PS_SPI=m
# CONFIG_FPGA_MGR_ALTERA_CVP is not set
CONFIG_FPGA_MGR_ZYNQ_FPGA=y
CONFIG_FPGA_MGR_XILINX_SPI=m
CONFIG_FPGA_MGR_ICE40_SPI=y
# CONFIG_FPGA_MGR_MACHXO2_SPI is not set
# CONFIG_FPGA_BRIDGE is not set
# CONFIG_FPGA_DFL is not set
CONFIG_FSI=y
# CONFIG_FSI_NEW_DEV_NODE is not set
CONFIG_FSI_MASTER_GPIO=y
# CONFIG_FSI_MASTER_HUB is not set
# CONFIG_FSI_SCOM is not set
CONFIG_FSI_SBEFIFO=m
CONFIG_FSI_OCC=m
CONFIG_TEE=y

#
# TEE drivers
#
CONFIG_SIOX=y
CONFIG_SIOX_BUS_GPIO=m
CONFIG_SLIMBUS=y
CONFIG_SLIM_QCOM_CTRL=m
CONFIG_INTERCONNECT=m

#
# File systems
#
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_VALIDATE_FS_PARSER=y
CONFIG_FS_POSIX_ACL=y
CONFIG_EXPORTFS=y
CONFIG_EXPORTFS_BLOCK_OPS=y
CONFIG_FILE_LOCKING=y
CONFIG_MANDATORY_FILE_LOCKING=y
CONFIG_FS_ENCRYPTION=y
CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
CONFIG_INOTIFY_USER=y
CONFIG_FANOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_AUTOFS4_FS=y
CONFIG_AUTOFS_FS=y
CONFIG_FUSE_FS=y
CONFIG_CUSE=m
CONFIG_OVERLAY_FS=m
CONFIG_OVERLAY_FS_REDIRECT_DIR=y
CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y
CONFIG_OVERLAY_FS_INDEX=y
# CONFIG_OVERLAY_FS_NFS_EXPORT is not set
CONFIG_OVERLAY_FS_XINO_AUTO=y
# CONFIG_OVERLAY_FS_METACOPY is not set

#
# Caches
#
CONFIG_FSCACHE=m
CONFIG_FSCACHE_DEBUG=y

#
# Pseudo filesystems
#
# CONFIG_PROC_FS is not set
CONFIG_PROC_CHILDREN=y
CONFIG_KERNFS=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLBFS is not set
CONFIG_MEMFD_CREATE=y
CONFIG_CONFIGFS_FS=y
CONFIG_MISC_FILESYSTEMS=y
CONFIG_ORANGEFS_FS=y
CONFIG_ECRYPT_FS=m
# CONFIG_ECRYPT_FS_MESSAGING is not set
# CONFIG_CRAMFS is not set
CONFIG_PSTORE=y
CONFIG_PSTORE_DEFLATE_COMPRESS=m
CONFIG_PSTORE_LZO_COMPRESS=y
# CONFIG_PSTORE_LZ4_COMPRESS is not set
CONFIG_PSTORE_LZ4HC_COMPRESS=y
# CONFIG_PSTORE_842_COMPRESS is not set
CONFIG_PSTORE_ZSTD_COMPRESS=y
CONFIG_PSTORE_COMPRESS=y
CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT=y
# CONFIG_PSTORE_LZO_COMPRESS_DEFAULT is not set
# CONFIG_PSTORE_LZ4HC_COMPRESS_DEFAULT is not set
# CONFIG_PSTORE_ZSTD_COMPRESS_DEFAULT is not set
CONFIG_PSTORE_COMPRESS_DEFAULT="deflate"
CONFIG_PSTORE_CONSOLE=y
CONFIG_PSTORE_PMSG=y
# CONFIG_PSTORE_FTRACE is not set
# CONFIG_PSTORE_RAM is not set
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_CODEPAGE_737=m
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
# CONFIG_NLS_CODEPAGE_852 is not set
CONFIG_NLS_CODEPAGE_855=m
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
CONFIG_NLS_CODEPAGE_863=y
# CONFIG_NLS_CODEPAGE_864 is not set
CONFIG_NLS_CODEPAGE_865=m
CONFIG_NLS_CODEPAGE_866=y
CONFIG_NLS_CODEPAGE_869=y
# CONFIG_NLS_CODEPAGE_936 is not set
CONFIG_NLS_CODEPAGE_950=m
CONFIG_NLS_CODEPAGE_932=y
CONFIG_NLS_CODEPAGE_949=m
CONFIG_NLS_CODEPAGE_874=m
# CONFIG_NLS_ISO8859_8 is not set
CONFIG_NLS_CODEPAGE_1250=y
CONFIG_NLS_CODEPAGE_1251=m
# CONFIG_NLS_ASCII is not set
CONFIG_NLS_ISO8859_1=m
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
CONFIG_NLS_ISO8859_5=y
CONFIG_NLS_ISO8859_6=y
CONFIG_NLS_ISO8859_7=m
# CONFIG_NLS_ISO8859_9 is not set
CONFIG_NLS_ISO8859_13=m
CONFIG_NLS_ISO8859_14=m
CONFIG_NLS_ISO8859_15=y
# CONFIG_NLS_KOI8_R is not set
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_MAC_ROMAN=y
CONFIG_NLS_MAC_CELTIC=y
CONFIG_NLS_MAC_CENTEURO=y
# CONFIG_NLS_MAC_CROATIAN is not set
CONFIG_NLS_MAC_CYRILLIC=m
CONFIG_NLS_MAC_GAELIC=y
# CONFIG_NLS_MAC_GREEK is not set
CONFIG_NLS_MAC_ICELAND=y
CONFIG_NLS_MAC_INUIT=y
CONFIG_NLS_MAC_ROMANIAN=m
# CONFIG_NLS_MAC_TURKISH is not set
CONFIG_NLS_UTF8=y

#
# Security options
#
CONFIG_KEYS=y
CONFIG_PERSISTENT_KEYRINGS=y
# CONFIG_BIG_KEYS is not set
# CONFIG_TRUSTED_KEYS is not set
CONFIG_ENCRYPTED_KEYS=m
# CONFIG_KEY_DH_OPERATIONS is not set
CONFIG_SECURITY_DMESG_RESTRICT=y
# CONFIG_SECURITYFS is not set
CONFIG_INTEL_TXT=y
CONFIG_FORTIFY_SOURCE=y
CONFIG_STATIC_USERMODEHELPER=y
CONFIG_STATIC_USERMODEHELPER_PATH="/sbin/usermode-helper"
CONFIG_DEFAULT_SECURITY_DAC=y
CONFIG_LSM="yama,loadpin,safesetid,integrity"
CONFIG_CRYPTO=y

#
# Crypto core or helper
#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_BLKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_RNG_DEFAULT=y
CONFIG_CRYPTO_AKCIPHER2=y
CONFIG_CRYPTO_KPP2=y
CONFIG_CRYPTO_KPP=y
CONFIG_CRYPTO_ACOMP2=y
# CONFIG_CRYPTO_RSA is not set
# CONFIG_CRYPTO_DH is not set
CONFIG_CRYPTO_ECDH=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
CONFIG_CRYPTO_GF128MUL=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_NULL2=y
CONFIG_CRYPTO_PCRYPT=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CRYPTO_CRYPTD=y
# CONFIG_CRYPTO_AUTHENC is not set
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_SIMD=y
CONFIG_CRYPTO_GLUE_HELPER_X86=m

#
# Authenticated Encryption with Associated Data
#
# CONFIG_CRYPTO_CCM is not set
CONFIG_CRYPTO_GCM=m
CONFIG_CRYPTO_CHACHA20POLY1305=y
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_AEGIS128L=y
CONFIG_CRYPTO_AEGIS256=y
# CONFIG_CRYPTO_MORUS640 is not set
# CONFIG_CRYPTO_MORUS1280 is not set
CONFIG_CRYPTO_SEQIV=m
CONFIG_CRYPTO_ECHAINIV=y

#
# Block modes
#
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CFB=m
CONFIG_CRYPTO_CTR=m
CONFIG_CRYPTO_CTS=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_LRW=y
CONFIG_CRYPTO_OFB=m
CONFIG_CRYPTO_PCBC=y
CONFIG_CRYPTO_XTS=y
CONFIG_CRYPTO_KEYWRAP=m
# CONFIG_CRYPTO_ADIANTUM is not set

#
# Hash modes
#
# CONFIG_CRYPTO_CMAC is not set
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=y

#
# Digest
#
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_CRC32C_INTEL=m
CONFIG_CRYPTO_CRC32=y
# CONFIG_CRYPTO_CRC32_PCLMUL is not set
CONFIG_CRYPTO_CRCT10DIF=y
CONFIG_CRYPTO_GHASH=m
CONFIG_CRYPTO_POLY1305=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_MD5=m
CONFIG_CRYPTO_MICHAEL_MIC=y
CONFIG_CRYPTO_RMD128=y
CONFIG_CRYPTO_RMD160=m
# CONFIG_CRYPTO_RMD256 is not set
CONFIG_CRYPTO_RMD320=y
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SHA256=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_SHA3 is not set
# CONFIG_CRYPTO_SM3 is not set
# CONFIG_CRYPTO_STREEBOG is not set
CONFIG_CRYPTO_TGR192=m
# CONFIG_CRYPTO_WP512 is not set

#
# Ciphers
#
CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_AES_TI is not set
CONFIG_CRYPTO_AES_586=y
CONFIG_CRYPTO_AES_NI_INTEL=y
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_BLOWFISH=y
CONFIG_CRYPTO_BLOWFISH_COMMON=y
# CONFIG_CRYPTO_CAMELLIA is not set
CONFIG_CRYPTO_CAST_COMMON=y
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=y
CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_FCRYPT is not set
CONFIG_CRYPTO_KHAZAD=m
# CONFIG_CRYPTO_SALSA20 is not set
CONFIG_CRYPTO_CHACHA20=y
CONFIG_CRYPTO_SEED=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_SERPENT_SSE2_586=m
CONFIG_CRYPTO_SM4=y
CONFIG_CRYPTO_TEA=y
# CONFIG_CRYPTO_TWOFISH is not set
CONFIG_CRYPTO_TWOFISH_COMMON=y
CONFIG_CRYPTO_TWOFISH_586=y

#
# Compression
#
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_842=y
CONFIG_CRYPTO_LZ4=y
CONFIG_CRYPTO_LZ4HC=y
CONFIG_CRYPTO_ZSTD=y

#
# Random Number Generation
#
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_CRYPTO_DRBG_MENU=y
CONFIG_CRYPTO_DRBG_HMAC=y
# CONFIG_CRYPTO_DRBG_HASH is not set
# CONFIG_CRYPTO_DRBG_CTR is not set
CONFIG_CRYPTO_DRBG=y
CONFIG_CRYPTO_JITTERENTROPY=y
CONFIG_CRYPTO_HASH_INFO=y
# CONFIG_CRYPTO_HW is not set
# CONFIG_ASYMMETRIC_KEY_TYPE is not set

#
# Certificates for signature checking
#
# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set
CONFIG_BINARY_PRINTF=y

#
# Library routines
#
CONFIG_BITREVERSE=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_NET_UTILS=y
CONFIG_GENERIC_FIND_FIRST_BIT=y
CONFIG_CORDIC=m
CONFIG_PRIME_NUMBERS=m
CONFIG_RATIONAL=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_IOMAP=y
CONFIG_STMP_DEVICE=y
CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
CONFIG_CRC_CCITT=y
CONFIG_CRC16=y
CONFIG_CRC_T10DIF=y
CONFIG_CRC_ITU_T=y
CONFIG_CRC32=y
CONFIG_CRC32_SELFTEST=m
# CONFIG_CRC32_SLICEBY8 is not set
# CONFIG_CRC32_SLICEBY4 is not set
# CONFIG_CRC32_SARWATE is not set
CONFIG_CRC32_BIT=y
CONFIG_CRC64=y
CONFIG_CRC4=y
CONFIG_CRC7=y
# CONFIG_LIBCRC32C is not set
CONFIG_CRC8=y
CONFIG_XXHASH=y
# CONFIG_RANDOM32_SELFTEST is not set
CONFIG_842_COMPRESS=y
CONFIG_842_DECOMPRESS=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_LZ4_COMPRESS=y
CONFIG_LZ4HC_COMPRESS=y
CONFIG_LZ4_DECOMPRESS=y
CONFIG_ZSTD_COMPRESS=y
CONFIG_ZSTD_DECOMPRESS=y
CONFIG_XZ_DEC=y
# CONFIG_XZ_DEC_X86 is not set
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
CONFIG_XZ_DEC_ARM=y
# CONFIG_XZ_DEC_ARMTHUMB is not set
CONFIG_XZ_DEC_SPARC=y
CONFIG_XZ_DEC_BCJ=y
# CONFIG_XZ_DEC_TEST is not set
CONFIG_DECOMPRESS_GZIP=y
CONFIG_DECOMPRESS_BZIP2=y
CONFIG_DECOMPRESS_XZ=y
CONFIG_DECOMPRESS_LZO=y
CONFIG_DECOMPRESS_LZ4=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_INTERVAL_TREE=y
CONFIG_ASSOCIATIVE_ARRAY=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAS_DMA=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_DMA_DECLARE_COHERENT=y
CONFIG_DMA_CMA=y

#
# Default contiguous memory area size:
#
CONFIG_CMA_SIZE_MBYTES=0
CONFIG_CMA_SIZE_PERCENTAGE=0
# CONFIG_CMA_SIZE_SEL_MBYTES is not set
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
CONFIG_CMA_SIZE_SEL_MIN=y
# CONFIG_CMA_SIZE_SEL_MAX is not set
CONFIG_CMA_ALIGNMENT=8
CONFIG_DMA_API_DEBUG=y
CONFIG_DMA_API_DEBUG_SG=y
CONFIG_SGL_ALLOC=y
CONFIG_CHECK_SIGNATURE=y
CONFIG_GLOB=y
# CONFIG_GLOB_SELFTEST is not set
CONFIG_DDR=y
CONFIG_IRQ_POLL=y
CONFIG_LIBFDT=y
CONFIG_SG_SPLIT=y
CONFIG_STACKDEPOT=y
# CONFIG_PARMAN is not set
CONFIG_STRING_SELFTEST=y
CONFIG_OBJAGG=y

#
# Kernel hacking
#

#
# printk and dmesg options
#
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
CONFIG_CONSOLE_LOGLEVEL_QUIET=4
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4

#
# Compile-time checks and compiler options
#
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_READABLE_ASM is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_SECTION_MISMATCH is not set
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
CONFIG_FRAME_POINTER=y
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_MAGIC_SYSRQ is not set
CONFIG_DEBUG_KERNEL=y

#
# Memory Debugging
#
CONFIG_PAGE_EXTENSION=y
# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_PAGE_OWNER=y
CONFIG_PAGE_POISONING=y
CONFIG_PAGE_POISONING_NO_SANITY=y
# CONFIG_PAGE_POISONING_ZERO is not set
# CONFIG_DEBUG_PAGE_REF is not set
# CONFIG_DEBUG_RODATA_TEST is not set
# CONFIG_DEBUG_OBJECTS is not set
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=400
CONFIG_DEBUG_KMEMLEAK_TEST=m
# CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF is not set
CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_VM=y
# CONFIG_DEBUG_VM_VMACACHE is not set
# CONFIG_DEBUG_VM_RB is not set
# CONFIG_DEBUG_VM_PGFLAGS is not set
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
CONFIG_DEBUG_VIRTUAL=y
# CONFIG_DEBUG_MEMORY_INIT is not set
# CONFIG_DEBUG_PER_CPU_MAPS is not set
# CONFIG_DEBUG_HIGHMEM is not set
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_KASAN_STACK=1
CONFIG_DEBUG_SHIRQ=y

#
# Debug Lockups and Hangs
#
CONFIG_LOCKUP_DETECTOR=y
CONFIG_SOFTLOCKUP_DETECTOR=y
# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
CONFIG_HARDLOCKUP_DETECTOR_PERF=y
CONFIG_HARDLOCKUP_DETECTOR=y
# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1
# CONFIG_WQ_WATCHDOG is not set
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_ON_OOPS_VALUE=1
CONFIG_PANIC_TIMEOUT=0
# CONFIG_SCHED_STACK_END_CHECK is not set
CONFIG_DEBUG_TIMEKEEPING=y

#
# Lock Debugging (spinlocks, mutexes, etc...)
#
CONFIG_LOCK_DEBUGGING_SUPPORT=y
# CONFIG_PROVE_LOCKING is not set
# CONFIG_LOCK_STAT is not set
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
# CONFIG_DEBUG_RWSEMS is not set
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_LOCKDEP=y
# CONFIG_DEBUG_LOCKDEP is not set
CONFIG_DEBUG_ATOMIC_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
CONFIG_LOCK_TORTURE_TEST=y
CONFIG_WW_MUTEX_SELFTEST=m
CONFIG_STACKTRACE=y
# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
CONFIG_DEBUG_KOBJECT=y
# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_PLIST=y
CONFIG_DEBUG_SG=y
CONFIG_DEBUG_NOTIFIERS=y
CONFIG_DEBUG_CREDENTIALS=y

#
# RCU Debugging
#
CONFIG_TORTURE_TEST=y
CONFIG_RCU_PERF_TEST=m
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_RCU_CPU_STALL_TIMEOUT=21
CONFIG_RCU_TRACE=y
# CONFIG_RCU_EQS_DEBUG is not set
CONFIG_DEBUG_WQ_FORCE_RR_CPU=y
CONFIG_CPU_HOTPLUG_STATE_CONTROL=y
CONFIG_NOTIFIER_ERROR_INJECTION=m
CONFIG_PM_NOTIFIER_ERROR_INJECT=m
# CONFIG_OF_RECONFIG_NOTIFIER_ERROR_INJECT is not set
CONFIG_FUNCTION_ERROR_INJECTION=y
# CONFIG_FAULT_INJECTION is not set
CONFIG_USER_STACKTRACE_SUPPORT=y
CONFIG_NOP_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
CONFIG_EVENT_TRACING=y
CONFIG_CONTEXT_SWITCH_TRACER=y
CONFIG_TRACING=y
CONFIG_GENERIC_TRACER=y
CONFIG_TRACING_SUPPORT=y
CONFIG_FTRACE=y
CONFIG_FUNCTION_TRACER=y
# CONFIG_PREEMPTIRQ_EVENTS is not set
# CONFIG_IRQSOFF_TRACER is not set
CONFIG_SCHED_TRACER=y
CONFIG_HWLAT_TRACER=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_TRACER_SNAPSHOT=y
# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set
CONFIG_BRANCH_PROFILE_NONE=y
# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
CONFIG_STACK_TRACER=y
# CONFIG_KPROBE_EVENTS is not set
CONFIG_UPROBE_EVENTS=y
CONFIG_DYNAMIC_EVENTS=y
CONFIG_PROBE_EVENTS=y
# CONFIG_DYNAMIC_FTRACE is not set
# CONFIG_FUNCTION_PROFILER is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_MMIOTRACE is not set
# CONFIG_HIST_TRIGGERS is not set
# CONFIG_TRACEPOINT_BENCHMARK is not set
CONFIG_RING_BUFFER_BENCHMARK=y
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set
# CONFIG_TRACE_EVAL_MAP_FILE is not set
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
# CONFIG_RUNTIME_TESTING_MENU is not set
CONFIG_MEMTEST=y
# CONFIG_BUG_ON_DATA_CORRUPTION is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_KGDB=y
CONFIG_KGDB_TESTS=y
# CONFIG_KGDB_TESTS_ON_BOOT is not set
# CONFIG_KGDB_LOW_LEVEL_TRAP is not set
CONFIG_KGDB_KDB=y
CONFIG_KDB_DEFAULT_ENABLE=0x1
CONFIG_KDB_CONTINUE_CATASTROPHIC=0
CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
CONFIG_UBSAN=y
CONFIG_UBSAN_NO_ALIGNMENT=y
# CONFIG_TEST_UBSAN is not set
CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
# CONFIG_STRICT_DEVMEM is not set
CONFIG_DEBUG_AID_FOR_SYZBOT=y
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_X86_VERBOSE_BOOTUP is not set
# CONFIG_EARLY_PRINTK is not set
CONFIG_X86_PTDUMP_CORE=y
CONFIG_X86_PTDUMP=m
CONFIG_DEBUG_WX=y
CONFIG_DOUBLEFAULT=y
# CONFIG_DEBUG_TLBFLUSH is not set
CONFIG_HAVE_MMIOTRACE_SUPPORT=y
CONFIG_IO_DELAY_TYPE_0X80=0
CONFIG_IO_DELAY_TYPE_0XED=1
CONFIG_IO_DELAY_TYPE_UDELAY=2
CONFIG_IO_DELAY_TYPE_NONE=3
# CONFIG_IO_DELAY_0X80 is not set
# CONFIG_IO_DELAY_0XED is not set
# CONFIG_IO_DELAY_UDELAY is not set
CONFIG_IO_DELAY_NONE=y
CONFIG_DEFAULT_IO_DELAY_TYPE=3
# CONFIG_DEBUG_BOOT_PARAMS is not set
# CONFIG_CPA_DEBUG is not set
# CONFIG_OPTIMIZE_INLINING is not set
# CONFIG_DEBUG_ENTRY is not set
CONFIG_DEBUG_NMI_SELFTEST=y
CONFIG_X86_DEBUG_FPU=y
CONFIG_PUNIT_ATOM_DEBUG=m
CONFIG_UNWINDER_FRAME_POINTER=y

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox