History

Merge tag 'platform-drivers-x86-v4.16-1' of git://git.infradead.org/linux-platform-drivers-x86

Pull x86 platform-driver updates from Darren Hart: "New model support added for Dell, Ideapad, Acer, Asus, Thinkpad, and GPD laptops. Improvements to the common intel-vbtn driver, including tablet mode, rotate, and front button support. Intel CPU support added for Cannonlake and platform support for Dollar Cove power button. Overhaul of the mellanox platform driver, creating a new platform/mellanox directory for the newly multi-architecture regmap interface. Significant Intel PMC update with CannonLake support, Coffeelake update, CPUID enumeration, module support, new read64 API, refactoring and cleanups. Revert the apple-gmux iGP IO lock, addressing reported issues with non-binary drivers, leaving Nvidia binary driver users to comment out conflicting code. Miscellaneous fixes and cleanups" * tag 'platform-drivers-x86-v4.16-1' of git://git.infradead.org/linux-platform-drivers-x86: (81 commits) platform/x86: mlx-platform: Fix an ERR_PTR vs NULL issue platform/x86: intel_pmc_core: Special case for Coffeelake platform/x86: intel_pmc_core: Add CannonLake PCH support x86/cpu: Add Cannonlake to Intel family platform/x86: intel_pmc_core: Read base address from LPIT ACPI / LPIT: Export lpit_read_residency_count_address() platform/x86: intel-vbtn: Replace License by SDPX identifier platform/x86: intel-vbtn: Remove redundant inclusions platform/x86: intel-vbtn: Support tablet mode switch platform/x86: dell-laptop: Allocate buffer on heap rather than globally platform/x86: intel_pmc_core: Remove unused header file platform/x86: mlx-platform: Add hotplug device unregister to error path platform/x86: mlx-platform: fix module aliases platform/mellanox: mlxreg-hotplug: Add check for negative adapter number platform/x86: mlx-platform: Add IO access verification callbacks platform/x86: mlx-platform: Document pdev_hotplug field platform/x86: mlx-platform: Allow compilation for 32 bit arch platform/mellanox: mlxreg-hotplug: Enable building for ARM platform/mellanox: mlxreg-hotplug: Modify to use a regmap interface platform/mellanox: Group create/destroy with attribute functions ...

Linus Torvalds committed 8 years ago

Commit cbd7b8a2 parents 3f551e3 8a0f5b638 files · +2301 −1111Browse files

Unified · Split

38 files
  1. Documentation/ABI/testing/sysfs-driver-samsung-laptop +1 −1
  2. MAINTAINERS +11 −4
  3. arch/x86/include/asm/intel-family.h +6 −0
  4. arch/x86/include/asm/intel_pmc_ipc.h +6 −0
  5. arch/x86/include/asm/pmc_core.h +0 −27
  6. drivers/acpi/acpi_lpit.c +1 −0
  7. drivers/platform/Kconfig +2 −0
  8. drivers/platform/Makefile +1 −0
  9. drivers/platform/mellanox/Kconfig +26 −0
  10. drivers/platform/mellanox/Makefile +6 −0
  11. drivers/platform/mellanox/mlxreg-hotplug.c +638 −0
  12. drivers/platform/x86/Kconfig +43 −13
  13. drivers/platform/x86/Makefile +3 −1
  14. drivers/platform/x86/acer-wireless.c +71 −0
  15. drivers/platform/x86/alienware-wmi.c +17 −0
  16. drivers/platform/x86/apple-gmux.c +1 −47
  17. drivers/platform/x86/asus-nb-wmi.c +11 −2
  18. drivers/platform/x86/dell-laptop.c +167 −93
  19. drivers/platform/x86/dell-smbios.c +4 −4
  20. drivers/platform/x86/dell-wmi.c +3 −0
  21. drivers/platform/x86/gpd-pocket-fan.c +216 −0
  22. drivers/platform/x86/ideapad-laptop.c +21 −7
  23. drivers/platform/x86/intel-hid.c +38 −3
  24. drivers/platform/x86/intel-vbtn.c +47 −18
  25. drivers/platform/x86/intel_chtdc_ti_pwrbtn.c +93 −0
  26. drivers/platform/x86/intel_int0002_vgpio.c +1 −1
  27. drivers/platform/x86/intel_pmc_core.c +161 −119
  28. drivers/platform/x86/intel_pmc_core.h +20 −9
  29. drivers/platform/x86/intel_pmc_ipc.c +31 −2
  30. drivers/platform/x86/intel_telemetry_debugfs.c +35 −48
  31. drivers/platform/x86/mlx-platform.c +267 −57
  32. drivers/platform/x86/mlxcpld-hotplug.c +0 −515
  33. drivers/platform/x86/pmc_atom.c +20 −36
  34. drivers/platform/x86/silead_dmi.c +175 −0
  35. drivers/platform/x86/thinkpad_acpi.c +13 −5
  36. include/linux/platform_data/mlxcpld-hotplug.h +0 −99
  37. include/linux/platform_data/mlxreg.h +144 −0
  38. include/uapi/linux/input-event-codes.h +1 −0
Documentation/ABI/testing/sysfs-driver-samsung-laptop+1−1
@@ -3,7 +3,7 @@ Date: January 1, 2010 · 2 unmodified lines
33 KernelVersion: 2.6.33
44 Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
55 Description: Some Samsung laptops have different "performance levels"
6− that are can be modified by a function key, and by this
6+ that can be modified by a function key, and by this
77 sysfs file. These values don't always make a whole lot
88 of sense, but some users like to modify them to keep
99 their fans quiet at all costs. Reading from this file
MAINTAINERS+11−4
@@ -6001,6 +6001,12 @@ L: linux-input@vger.kernel.org · 6000 unmodified lines
60016001 S: Maintained
60026002 F: drivers/input/touchscreen/goodix.c
60036003
6004+GPD POCKET FAN DRIVER
6005+M: Hans de Goede <hdegoede@redhat.com>
6006+L: platform-driver-x86@vger.kernel.org
6007+S: Maintained
6008+F: drivers/platform/x86/gpd-pocket-fan.c
6009+
60046010 GPIO ACPI SUPPORT
60056011 M: Mika Westerberg <mika.westerberg@linux.intel.com>
60066012 M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
@@ -8939,12 +8945,13 @@ W: http://www.mellanox.com · 2932 unmodified lines
89398945 Q: http://patchwork.ozlabs.org/project/netdev/list/
89408946 F: drivers/net/ethernet/mellanox/mlxfw/
89418947
8942−MELLANOX MLX CPLD HOTPLUG DRIVER
8948+MELLANOX HARDWARE PLATFORM SUPPORT
8949+M: Andy Shevchenko <andy@infradead.org>
8950+M: Darren Hart <dvhart@infradead.org>
89438951 M: Vadim Pasternak <vadimp@mellanox.com>
89448952 L: platform-driver-x86@vger.kernel.org
89458953 S: Supported
8946−F: drivers/platform/x86/mlxcpld-hotplug.c
8947−F: include/linux/platform_data/mlxcpld-hotplug.h
8954+F: drivers/platform/mellanox/
89488955
89498956 MELLANOX MLX4 core VPI driver
89508957 M: Tariq Toukan <tariqt@mellanox.com>
@@ -15134,7 +15141,7 @@ X86 PLATFORM DRIVERS · 6183 unmodified lines
1513415141 M: Darren Hart <dvhart@infradead.org>
1513515142 M: Andy Shevchenko <andy@infradead.org>
1513615143 L: platform-driver-x86@vger.kernel.org
15137−T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git
15144+T: git git://git.infradead.org/linux-platform-drivers-x86.git
1513815145 S: Maintained
1513915146 F: drivers/platform/x86/
1514015147 F: drivers/platform/olpc/
arch/x86/include/asm/intel-family.h+6−0
@@ -10,6 +10,10 @@ · 9 unmodified lines
1010 *
1111 * Things ending in "2" are usually because we have no better
1212 * name for them. There's no processor called "SILVERMONT2".
13+ *
14+ * While adding a new CPUID for a new microarchitecture, add a new
15+ * group to keep logically sorted out in chronological order. Within
16+ * that group keep the CPUID for the variants sorted by model number.
1317 */
1418
1519 #define INTEL_FAM6_CORE_YONAH 0x0E
@@ -49,6 +53,8 @@ · 33 unmodified lines
4953 #define INTEL_FAM6_KABYLAKE_MOBILE 0x8E
5054 #define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E
5155
56+#define INTEL_FAM6_CANNONLAKE_MOBILE 0x66
57+
5258 /* "Small Core" Processors (Atom) */
5359
5460 #define INTEL_FAM6_ATOM_PINEVIEW 0x1C
arch/x86/include/asm/intel_pmc_ipc.h+6−0
@@ -38,6 +38,7 @@ int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, · 37 unmodified lines
3838 u32 *out, u32 outlen);
3939 int intel_pmc_s0ix_counter_read(u64 *data);
4040 int intel_pmc_gcr_read(u32 offset, u32 *data);
41+int intel_pmc_gcr_read64(u32 offset, u64 *data);
4142 int intel_pmc_gcr_write(u32 offset, u32 data);
4243 int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val);
4344
@@ -70,6 +71,11 @@ static inline int intel_pmc_gcr_read(u32 offset, u32 *data) · 26 unmodified lines
7071 return -EINVAL;
7172 }
7273
74+static inline int intel_pmc_gcr_read64(u32 offset, u64 *data)
75+{
76+ return -EINVAL;
77+}
78+
7379 static inline int intel_pmc_gcr_write(u32 offset, u32 data)
7480 {
7581 return -EINVAL;
arch/x86/include/asm/pmc_core.h+0−27
@@ -1,27 +0,0 @@
1−/*
2− * Intel Core SoC Power Management Controller Header File
3− *
4− * Copyright (c) 2016, Intel Corporation.
5− * All Rights Reserved.
6− *
7− * Authors: Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com>
8− * Vishwanath Somayaji <vishwanath.somayaji@intel.com>
9− *
10− * This program is free software; you can redistribute it and/or modify it
11− * under the terms and conditions of the GNU General Public License,
12− * version 2, as published by the Free Software Foundation.
13− *
14− * This program is distributed in the hope it will be useful, but WITHOUT
15− * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16− * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17− * more details.
18− *
19− */
20−
21−#ifndef _ASM_PMC_CORE_H
22−#define _ASM_PMC_CORE_H
23−
24−/* API to read SLP_S0_RESIDENCY counter */
25−int intel_pmc_slp_s0_counter_read(u32 *data);
26−
27−#endif /* _ASM_PMC_CORE_H */
drivers/acpi/acpi_lpit.c+1−0
@@ -100,6 +100,7 @@ int lpit_read_residency_count_address(u64 *address) · 99 unmodified lines
100100
101101 return 0;
102102 }
103+EXPORT_SYMBOL_GPL(lpit_read_residency_count_address);
103104
104105 static void lpit_update_residency(struct lpit_residency_info *info,
105106 struct acpi_lpit_native *lpit_native)
drivers/platform/Kconfig+2−0
@@ -8,3 +8,5 @@ endif · 7 unmodified lines
88 source "drivers/platform/goldfish/Kconfig"
99
1010 source "drivers/platform/chrome/Kconfig"
11+
12+source "drivers/platform/mellanox/Kconfig"
drivers/platform/Makefile+1−0
@@ -4,6 +4,7 @@ · 3 unmodified lines
44 #
55
66 obj-$(CONFIG_X86) += x86/
7+obj-$(CONFIG_MELLANOX_PLATFORM) += mellanox/
78 obj-$(CONFIG_MIPS) += mips/
89 obj-$(CONFIG_OLPC) += olpc/
910 obj-$(CONFIG_GOLDFISH) += goldfish/
drivers/platform/mellanox/Kconfig+26−0
@@ -0,0 +1,26 @@
1+# SPDX-License-Identifier: GPL-2.0
2+#
3+# Platform support for Mellanox hardware
4+#
5+
6+menuconfig MELLANOX_PLATFORM
7+ bool "Platform support for Mellanox hardware"
8+ depends on X86 || ARM || COMPILE_TEST
9+ ---help---
10+ Say Y here to get to see options for platform support for
11+ Mellanox systems. This option alone does not add any kernel code.
12+
13+ If you say N, all options in this submenu will be skipped and disabled.
14+
15+if MELLANOX_PLATFORM
16+
17+config MLXREG_HOTPLUG
18+ tristate "Mellanox platform hotplug driver support"
19+ depends on REGMAP
20+ depends on HWMON
21+ depends on I2C
22+ ---help---
23+ This driver handles hot-plug events for the power suppliers, power
24+ cables and fans on the wide range Mellanox IB and Ethernet systems.
25+
26+endif # MELLANOX_PLATFORM
drivers/platform/mellanox/Makefile+6−0
@@ -0,0 +1,6 @@
1+# SPDX-License-Identifier: GPL-2.0
2+#
3+# Makefile for linux/drivers/platform/mellanox
4+# Mellanox Platform-Specific Drivers
5+#
6+obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
drivers/platform/mellanox/mlxreg-hotplug.c+638−0
@@ -0,0 +1,638 @@
1+/*
2+ * Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved.
3+ * Copyright (c) 2016-2018 Vadim Pasternak <vadimp@mellanox.com>
4+ *
5+ * Redistribution and use in source and binary forms, with or without
6+ * modification, are permitted provided that the following conditions are met:
7+ *
8+ * 1. Redistributions of source code must retain the above copyright
9+ * notice, this list of conditions and the following disclaimer.
10+ * 2. Redistributions in binary form must reproduce the above copyright
11+ * notice, this list of conditions and the following disclaimer in the
12+ * documentation and/or other materials provided with the distribution.
13+ * 3. Neither the names of the copyright holders nor the names of its
14+ * contributors may be used to endorse or promote products derived from
15+ * this software without specific prior written permission.
16+ *
17+ * Alternatively, this software may be distributed under the terms of the
18+ * GNU General Public License ("GPL") version 2 as published by the Free
19+ * Software Foundation.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31+ * POSSIBILITY OF SUCH DAMAGE.
32+ */
33+
34+#include <linux/bitops.h>
35+#include <linux/device.h>
36+#include <linux/hwmon.h>
37+#include <linux/hwmon-sysfs.h>
38+#include <linux/i2c.h>
39+#include <linux/interrupt.h>
40+#include <linux/module.h>
41+#include <linux/of_device.h>
42+#include <linux/platform_data/mlxreg.h>
43+#include <linux/platform_device.h>
44+#include <linux/spinlock.h>
45+#include <linux/regmap.h>
46+#include <linux/workqueue.h>
47+
48+/* Offset of event and mask registers from status register. */
49+#define MLXREG_HOTPLUG_EVENT_OFF 1
50+#define MLXREG_HOTPLUG_MASK_OFF 2
51+#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1
52+
53+/* ASIC health parameters. */
54+#define MLXREG_HOTPLUG_HEALTH_MASK 0x02
55+#define MLXREG_HOTPLUG_RST_CNTR 3
56+
57+#define MLXREG_HOTPLUG_ATTRS_MAX 24
58+
59+/**
60+ * struct mlxreg_hotplug_priv_data - platform private data:
61+ * @irq: platform device interrupt number;
62+ * @pdev: platform device;
63+ * @plat: platform data;
64+ * @dwork: delayed work template;
65+ * @lock: spin lock;
66+ * @hwmon: hwmon device;
67+ * @mlxreg_hotplug_attr: sysfs attributes array;
68+ * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
69+ * @group: sysfs attribute group;
70+ * @groups: list of sysfs attribute group for hwmon registration;
71+ * @cell: location of top aggregation interrupt register;
72+ * @mask: top aggregation interrupt common mask;
73+ * @aggr_cache: last value of aggregation register status;
74+ */
75+struct mlxreg_hotplug_priv_data {
76+ int irq;
77+ struct device *dev;
78+ struct platform_device *pdev;
79+ struct mlxreg_hotplug_platform_data *plat;
80+ struct regmap *regmap;
81+ struct delayed_work dwork_irq;
82+ struct delayed_work dwork;
83+ spinlock_t lock; /* sync with interrupt */
84+ struct device *hwmon;
85+ struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
86+ struct sensor_device_attribute_2
87+ mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
88+ struct attribute_group group;
89+ const struct attribute_group *groups[2];
90+ u32 cell;
91+ u32 mask;
92+ u32 aggr_cache;
93+ bool after_probe;
94+};
95+
96+static int mlxreg_hotplug_device_create(struct device *dev,
97+ struct mlxreg_core_data *data)
98+{
99+ /*
100+ * Return if adapter number is negative. It could be in case hotplug
101+ * event is not associated with hotplug device.
102+ */
103+ if (data->hpdev.nr < 0)
104+ return 0;
105+
106+ data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
107+ if (!data->hpdev.adapter) {
108+ dev_err(dev, "Failed to get adapter for bus %d\n",
109+ data->hpdev.nr);
110+ return -EFAULT;
111+ }
112+
113+ data->hpdev.client = i2c_new_device(data->hpdev.adapter,
114+ data->hpdev.brdinfo);
115+ if (!data->hpdev.client) {
116+ dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
117+ data->hpdev.brdinfo->type, data->hpdev.nr,
118+ data->hpdev.brdinfo->addr);
119+
120+ i2c_put_adapter(data->hpdev.adapter);
121+ data->hpdev.adapter = NULL;
122+ return -EFAULT;
123+ }
124+
125+ return 0;
126+}
127+
128+static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data)
129+{
130+ if (data->hpdev.client) {
131+ i2c_unregister_device(data->hpdev.client);
132+ data->hpdev.client = NULL;
133+ }
134+
135+ if (data->hpdev.adapter) {
136+ i2c_put_adapter(data->hpdev.adapter);
137+ data->hpdev.adapter = NULL;
138+ }
139+}
140+
141+static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
142+ struct device_attribute *attr,
143+ char *buf)
144+{
145+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
146+ struct mlxreg_core_hotplug_platform_data *pdata;
147+ int index = to_sensor_dev_attr_2(attr)->index;
148+ int nr = to_sensor_dev_attr_2(attr)->nr;
149+ struct mlxreg_core_item *item;
150+ struct mlxreg_core_data *data;
151+ u32 regval;
152+ int ret;
153+
154+ pdata = dev_get_platdata(&priv->pdev->dev);
155+ item = pdata->items + nr;
156+ data = item->data + index;
157+
158+ ret = regmap_read(priv->regmap, data->reg, &regval);
159+ if (ret)
160+ return ret;
161+
162+ if (item->health) {
163+ regval &= data->mask;
164+ } else {
165+ /* Bit = 0 : functional if item->inversed is true. */
166+ if (item->inversed)
167+ regval = !(regval & data->mask);
168+ else
169+ regval = !!(regval & data->mask);
170+ }
171+
172+ return sprintf(buf, "%u\n", regval);
173+}
174+
175+#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
176+#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
177+
178+static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
179+{
180+ struct mlxreg_core_hotplug_platform_data *pdata;
181+ struct mlxreg_core_item *item;
182+ struct mlxreg_core_data *data;
183+ int num_attrs = 0, id = 0, i, j;
184+
185+ pdata = dev_get_platdata(&priv->pdev->dev);
186+ item = pdata->items;
187+
188+ /* Go over all kinds of items - psu, pwr, fan. */
189+ for (i = 0; i < pdata->counter; i++, item++) {
190+ num_attrs += item->count;
191+ data = item->data;
192+ /* Go over all units within the item. */
193+ for (j = 0; j < item->count; j++, data++, id++) {
194+ PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
195+ PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
196+ GFP_KERNEL,
197+ data->label);
198+
199+ if (!PRIV_ATTR(id)->name) {
200+ dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
201+ id);
202+ return -ENOMEM;
203+ }
204+
205+ PRIV_DEV_ATTR(id).dev_attr.attr.name =
206+ PRIV_ATTR(id)->name;
207+ PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
208+ PRIV_DEV_ATTR(id).dev_attr.show =
209+ mlxreg_hotplug_attr_show;
210+ PRIV_DEV_ATTR(id).nr = i;
211+ PRIV_DEV_ATTR(id).index = j;
212+ sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
213+ }
214+ }
215+
216+ priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
217+ sizeof(struct attribute *),
218+ GFP_KERNEL);
219+ if (!priv->group.attrs)
220+ return -ENOMEM;
221+
222+ priv->group.attrs = priv->mlxreg_hotplug_attr;
223+ priv->groups[0] = &priv->group;
224+ priv->groups[1] = NULL;
225+
226+ return 0;
227+}
228+
229+static void
230+mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
231+ struct mlxreg_core_item *item)
232+{
233+ struct mlxreg_core_data *data;
234+ u32 asserted, regval, bit;
235+ int ret;
236+
237+ /*
238+ * Validate if item related to received signal type is valid.
239+ * It should never happen, excepted the situation when some
240+ * piece of hardware is broken. In such situation just produce
241+ * error message and return. Caller must continue to handle the
242+ * signals from other devices if any.
243+ */
244+ if (unlikely(!item)) {
245+ dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
246+ item->reg, item->mask);
247+
248+ return;
249+ }
250+
251+ /* Mask event. */
252+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
253+ 0);
254+ if (ret)
255+ goto out;
256+
257+ /* Read status. */
258+ ret = regmap_read(priv->regmap, item->reg, &regval);
259+ if (ret)
260+ goto out;
261+
262+ /* Set asserted bits and save last status. */
263+ regval &= item->mask;
264+ asserted = item->cache ^ regval;
265+ item->cache = regval;
266+
267+ for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
268+ data = item->data + bit;
269+ if (regval & BIT(bit)) {
270+ if (item->inversed)
271+ mlxreg_hotplug_device_destroy(data);
272+ else
273+ mlxreg_hotplug_device_create(priv->dev, data);
274+ } else {
275+ if (item->inversed)
276+ mlxreg_hotplug_device_create(priv->dev, data);
277+ else
278+ mlxreg_hotplug_device_destroy(data);
279+ }
280+ }
281+
282+ /* Acknowledge event. */
283+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
284+ 0);
285+ if (ret)
286+ goto out;
287+
288+ /* Unmask event. */
289+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
290+ item->mask);
291+
292+ out:
293+ if (ret)
294+ dev_err(priv->dev, "Failed to complete workqueue.\n");
295+}
296+
297+static void
298+mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
299+ struct mlxreg_core_item *item)
300+{
301+ struct mlxreg_core_data *data = item->data;
302+ u32 regval;
303+ int i, ret;
304+
305+ for (i = 0; i < item->count; i++, data++) {
306+ /* Mask event. */
307+ ret = regmap_write(priv->regmap, data->reg +
308+ MLXREG_HOTPLUG_MASK_OFF, 0);
309+ if (ret)
310+ goto out;
311+
312+ /* Read status. */
313+ ret = regmap_read(priv->regmap, data->reg, &regval);
314+ if (ret)
315+ goto out;
316+
317+ regval &= data->mask;
318+ item->cache = regval;
319+ if (regval == MLXREG_HOTPLUG_HEALTH_MASK) {
320+ if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) ||
321+ !priv->after_probe) {
322+ mlxreg_hotplug_device_create(priv->dev, data);
323+ data->attached = true;
324+ }
325+ } else {
326+ if (data->attached) {
327+ mlxreg_hotplug_device_destroy(data);
328+ data->attached = false;
329+ data->health_cntr = 0;
330+ }
331+ }
332+
333+ /* Acknowledge event. */
334+ ret = regmap_write(priv->regmap, data->reg +
335+ MLXREG_HOTPLUG_EVENT_OFF, 0);
336+ if (ret)
337+ goto out;
338+
339+ /* Unmask event. */
340+ ret = regmap_write(priv->regmap, data->reg +
341+ MLXREG_HOTPLUG_MASK_OFF, data->mask);
342+ if (ret)
343+ goto out;
344+ }
345+
346+ out:
347+ if (ret)
348+ dev_err(priv->dev, "Failed to complete workqueue.\n");
349+}
350+
351+/*
352+ * mlxreg_hotplug_work_handler - performs traversing of device interrupt
353+ * registers according to the below hierarchy schema:
354+ *
355+ * Aggregation registers (status/mask)
356+ * PSU registers: *---*
357+ * *-----------------* | |
358+ * |status/event/mask|-----> | * |
359+ * *-----------------* | |
360+ * Power registers: | |
361+ * *-----------------* | |
362+ * |status/event/mask|-----> | * |
363+ * *-----------------* | |
364+ * FAN registers: | |--> CPU
365+ * *-----------------* | |
366+ * |status/event/mask|-----> | * |
367+ * *-----------------* | |
368+ * ASIC registers: | |
369+ * *-----------------* | |
370+ * |status/event/mask|-----> | * |
371+ * *-----------------* | |
372+ * *---*
373+ *
374+ * In case some system changed are detected: FAN in/out, PSU in/out, power
375+ * cable attached/detached, ASIC health good/bad, relevant device is created
376+ * or destroyed.
377+ */
378+static void mlxreg_hotplug_work_handler(struct work_struct *work)
379+{
380+ struct mlxreg_core_hotplug_platform_data *pdata;
381+ struct mlxreg_hotplug_priv_data *priv;
382+ struct mlxreg_core_item *item;
383+ u32 regval, aggr_asserted;
384+ unsigned long flags;
385+ int i, ret;
386+
387+ priv = container_of(work, struct mlxreg_hotplug_priv_data,
388+ dwork_irq.work);
389+ pdata = dev_get_platdata(&priv->pdev->dev);
390+ item = pdata->items;
391+
392+ /* Mask aggregation event. */
393+ ret = regmap_write(priv->regmap, pdata->cell +
394+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
395+ if (ret < 0)
396+ goto out;
397+
398+ /* Read aggregation status. */
399+ ret = regmap_read(priv->regmap, pdata->cell, &regval);
400+ if (ret)
401+ goto out;
402+
403+ regval &= pdata->mask;
404+ aggr_asserted = priv->aggr_cache ^ regval;
405+ priv->aggr_cache = regval;
406+
407+ /* Handle topology and health configuration changes. */
408+ for (i = 0; i < pdata->counter; i++, item++) {
409+ if (aggr_asserted & item->aggr_mask) {
410+ if (item->health)
411+ mlxreg_hotplug_health_work_helper(priv, item);
412+ else
413+ mlxreg_hotplug_work_helper(priv, item);
414+ }
415+ }
416+
417+ if (aggr_asserted) {
418+ spin_lock_irqsave(&priv->lock, flags);
419+
420+ /*
421+ * It is possible, that some signals have been inserted, while
422+ * interrupt has been masked by mlxreg_hotplug_work_handler.
423+ * In this case such signals will be missed. In order to handle
424+ * these signals delayed work is canceled and work task
425+ * re-scheduled for immediate execution. It allows to handle
426+ * missed signals, if any. In other case work handler just
427+ * validates that no new signals have been received during
428+ * masking.
429+ */
430+ cancel_delayed_work(&priv->dwork_irq);
431+ schedule_delayed_work(&priv->dwork_irq, 0);
432+
433+ spin_unlock_irqrestore(&priv->lock, flags);
434+
435+ return;
436+ }
437+
438+ /* Unmask aggregation event (no need acknowledge). */
439+ ret = regmap_write(priv->regmap, pdata->cell +
440+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
441+
442+ out:
443+ if (ret)
444+ dev_err(priv->dev, "Failed to complete workqueue.\n");
445+}
446+
447+static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
448+{
449+ struct mlxreg_core_hotplug_platform_data *pdata;
450+ struct mlxreg_core_item *item;
451+ int i, ret;
452+
453+ pdata = dev_get_platdata(&priv->pdev->dev);
454+ item = pdata->items;
455+
456+ for (i = 0; i < pdata->counter; i++, item++) {
457+ /* Clear group presense event. */
458+ ret = regmap_write(priv->regmap, item->reg +
459+ MLXREG_HOTPLUG_EVENT_OFF, 0);
460+ if (ret)
461+ goto out;
462+
463+ /* Set group initial status as mask and unmask group event. */
464+ if (item->inversed) {
465+ item->cache = item->mask;
466+ ret = regmap_write(priv->regmap, item->reg +
467+ MLXREG_HOTPLUG_MASK_OFF,
468+ item->mask);
469+ if (ret)
470+ goto out;
471+ }
472+ }
473+
474+ /* Keep aggregation initial status as zero and unmask events. */
475+ ret = regmap_write(priv->regmap, pdata->cell +
476+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
477+ if (ret)
478+ goto out;
479+
480+ /* Keep low aggregation initial status as zero and unmask events. */
481+ if (pdata->cell_low) {
482+ ret = regmap_write(priv->regmap, pdata->cell_low +
483+ MLXREG_HOTPLUG_AGGR_MASK_OFF,
484+ pdata->mask_low);
485+ if (ret)
486+ goto out;
487+ }
488+
489+ /* Invoke work handler for initializing hot plug devices setting. */
490+ mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
491+
492+ out:
493+ if (ret)
494+ dev_err(priv->dev, "Failed to set interrupts.\n");
495+ enable_irq(priv->irq);
496+ return ret;
497+}
498+
499+static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
500+{
501+ struct mlxreg_core_hotplug_platform_data *pdata;
502+ struct mlxreg_core_item *item;
503+ struct mlxreg_core_data *data;
504+ int count, i, j;
505+
506+ pdata = dev_get_platdata(&priv->pdev->dev);
507+ item = pdata->items;
508+ disable_irq(priv->irq);
509+ cancel_delayed_work_sync(&priv->dwork_irq);
510+
511+ /* Mask low aggregation event, if defined. */
512+ if (pdata->cell_low)
513+ regmap_write(priv->regmap, pdata->cell_low +
514+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
515+
516+ /* Mask aggregation event. */
517+ regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
518+ 0);
519+
520+ /* Clear topology configurations. */
521+ for (i = 0; i < pdata->counter; i++, item++) {
522+ data = item->data;
523+ /* Mask group presense event. */
524+ regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
525+ 0);
526+ /* Clear group presense event. */
527+ regmap_write(priv->regmap, data->reg +
528+ MLXREG_HOTPLUG_EVENT_OFF, 0);
529+
530+ /* Remove all the attached devices in group. */
531+ count = item->count;
532+ for (j = 0; j < count; j++, data++)
533+ mlxreg_hotplug_device_destroy(data);
534+ }
535+}
536+
537+static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
538+{
539+ struct mlxreg_hotplug_priv_data *priv;
540+
541+ priv = (struct mlxreg_hotplug_priv_data *)dev;
542+
543+ /* Schedule work task for immediate execution.*/
544+ schedule_delayed_work(&priv->dwork_irq, 0);
545+
546+ return IRQ_HANDLED;
547+}
548+
549+static int mlxreg_hotplug_probe(struct platform_device *pdev)
550+{
551+ struct mlxreg_core_hotplug_platform_data *pdata;
552+ struct mlxreg_hotplug_priv_data *priv;
553+ int err;
554+
555+ pdata = dev_get_platdata(&pdev->dev);
556+ if (!pdata) {
557+ dev_err(&pdev->dev, "Failed to get platform data.\n");
558+ return -EINVAL;
559+ }
560+
561+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
562+ if (!priv)
563+ return -ENOMEM;
564+
565+ if (pdata->irq) {
566+ priv->irq = pdata->irq;
567+ } else {
568+ priv->irq = platform_get_irq(pdev, 0);
569+ if (priv->irq < 0) {
570+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
571+ priv->irq);
572+ return priv->irq;
573+ }
574+ }
575+
576+ priv->regmap = pdata->regmap;
577+ priv->dev = pdev->dev.parent;
578+ priv->pdev = pdev;
579+
580+ err = devm_request_irq(&pdev->dev, priv->irq,
581+ mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
582+ | IRQF_SHARED, "mlxreg-hotplug", priv);
583+ if (err) {
584+ dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
585+ return err;
586+ }
587+
588+ disable_irq(priv->irq);
589+ spin_lock_init(&priv->lock);
590+ INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
591+ /* Perform initial interrupts setup. */
592+ mlxreg_hotplug_set_irq(priv);
593+
594+ priv->after_probe = true;
595+ dev_set_drvdata(&pdev->dev, priv);
596+
597+ err = mlxreg_hotplug_attr_init(priv);
598+ if (err) {
599+ dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
600+ err);
601+ return err;
602+ }
603+
604+ priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
605+ "mlxreg_hotplug", priv, priv->groups);
606+ if (IS_ERR(priv->hwmon)) {
607+ dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
608+ PTR_ERR(priv->hwmon));
609+ return PTR_ERR(priv->hwmon);
610+ }
611+
612+ return 0;
613+}
614+
615+static int mlxreg_hotplug_remove(struct platform_device *pdev)
616+{
617+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
618+
619+ /* Clean interrupts setup. */
620+ mlxreg_hotplug_unset_irq(priv);
621+
622+ return 0;
623+}
624+
625+static struct platform_driver mlxreg_hotplug_driver = {
626+ .driver = {
627+ .name = "mlxreg-hotplug",
628+ },
629+ .probe = mlxreg_hotplug_probe,
630+ .remove = mlxreg_hotplug_remove,
631+};
632+
633+module_platform_driver(mlxreg_hotplug_driver);
634+
635+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
636+MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
637+MODULE_LICENSE("Dual BSD/GPL");
638+MODULE_ALIAS("platform:mlxreg-hotplug");
drivers/platform/x86/Kconfig+43−13
@@ -36,6 +36,20 @@ config ACER_WMI · 35 unmodified lines
3636 If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
3737 here.
3838
39+config ACER_WIRELESS
40+ tristate "Acer Wireless Radio Control Driver"
41+ depends on ACPI
42+ depends on INPUT
43+ ---help---
44+ The Acer Wireless Radio Control handles the airplane mode hotkey
45+ present on new Acer laptops.
46+
47+ Say Y or M here if you have an Acer notebook with an airplane mode
48+ hotkey.
49+
50+ If you choose to compile this driver as a module the module will be
51+ called acer-wireless.
52+
3953 config ACERHDF
4054 tristate "Acer Aspire One temperature and fan driver"
4155 depends on ACPI && THERMAL
@@ -244,6 +258,18 @@ config AMILO_RFKILL · 202 unmodified lines
244258 This is a driver for enabling wifi on some Fujitsu-Siemens Amilo
245259 laptops.
246260
261+config GPD_POCKET_FAN
262+ tristate "GPD Pocket Fan Controller support"
263+ depends on ACPI
264+ depends on THERMAL
265+ ---help---
266+ Driver for the GPD Pocket vendor specific FAN02501 ACPI device
267+ which controls the fan speed on the GPD Pocket.
268+
269+ Without this driver the fan on the Pocket will stay off independent
270+ of the CPU temperature. Say Y or M if the kernel may be used on a
271+ GPD pocket.
272+
247273 config TC1100_WMI
248274 tristate "HP Compaq TC1100 Tablet WMI Extras"
249275 depends on !X86_64
@@ -812,9 +838,8 @@ config TOSHIBA_WMI · 562 unmodified lines
812838
813839 config ACPI_CMPC
814840 tristate "CMPC Laptop Extras"
815− depends on ACPI
841+ depends on ACPI && INPUT
816842 depends on RFKILL || RFKILL=n
817− select INPUT
818843 select BACKLIGHT_CLASS_DEVICE
819844 help
820845 Support for Intel Classmate PC ACPI devices, including some
@@ -949,7 +974,7 @@ config INTEL_IMR · 128 unmodified lines
949974 If you are running on a Galileo/Quark say Y here.
950975
951976 config INTEL_PMC_CORE
952− bool "Intel PMC Core driver"
977+ tristate "Intel PMC Core driver"
953978 depends on PCI
954979 ---help---
955980 The Intel Platform Controller Hub for Intel Core SoCs provides access
@@ -958,7 +983,10 @@ config INTEL_PMC_CORE · 2 unmodified lines
958983 exposed by the Power Management Controller.
959984
960985 Supported features:
961− - SLP_S0_RESIDENCY counter.
986+ - SLP_S0_RESIDENCY counter
987+ - PCH IP Power Gating status
988+ - LTR Ignore
989+ - MPHY/PLL gating status (Sunrisepoint PCH only)
962990
963991 config IBM_RTL
964992 tristate "Device driver to enable PRTL support"
@@ -1131,7 +1159,6 @@ config INTEL_TELEMETRY · 166 unmodified lines
11311159
11321160 config MLX_PLATFORM
11331161 tristate "Mellanox Technologies platform support"
1134− depends on X86_64
11351162 ---help---
11361163 This option enables system support for the Mellanox Technologies
11371164 platform. The Mellanox systems provide data center networking
@@ -1141,14 +1168,6 @@ config MLX_PLATFORM · 3 unmodified lines
11411168
11421169 If you have a Mellanox system, say Y or M here.
11431170
1144−config MLX_CPLD_PLATFORM
1145− tristate "Mellanox platform hotplug driver support"
1146− select HWMON
1147− select I2C
1148− ---help---
1149− This driver handles hot-plug events for the power suppliers, power
1150− cables and fans on the wide range Mellanox IB and Ethernet systems.
1151−
11521171 config INTEL_TURBO_MAX_3
11531172 bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
11541173 depends on X86_64 && SCHED_MC_PRIO
@@ -1170,6 +1189,17 @@ config SILEAD_DMI · 15 unmodified lines
11701189 with the OS-image for the device. This option supplies the missing
11711190 information. Enable this for x86 tablets with Silead touchscreens.
11721191
1192+config INTEL_CHTDC_TI_PWRBTN
1193+ tristate "Intel Cherry Trail Dollar Cove TI power button driver"
1194+ depends on INTEL_SOC_PMIC_CHTDC_TI
1195+ depends on INPUT
1196+ ---help---
1197+ This option adds a power button driver driver for Dollar Cove TI
1198+ PMIC on Intel Cherry Trail devices.
1199+
1200+ To compile this driver as a module, choose M here: the module
1201+ will be called intel_chtdc_ti_pwrbtn.
1202+
11731203 endif # X86_PLATFORM_DEVICES
11741204
11751205 config PMC_ATOM
drivers/platform/x86/Makefile+3−1
@@ -23,11 +23,13 @@ obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o · 22 unmodified lines
2323 obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
2424 obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o
2525 obj-$(CONFIG_ACER_WMI) += acer-wmi.o
26+obj-$(CONFIG_ACER_WIRELESS) += acer-wireless.o
2627 obj-$(CONFIG_ACERHDF) += acerhdf.o
2728 obj-$(CONFIG_HP_ACCEL) += hp_accel.o
2829 obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o
2930 obj-$(CONFIG_HP_WMI) += hp-wmi.o
3031 obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o
32+obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o
3133 obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
3234 obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
3335 obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o
@@ -86,5 +88,5 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ · 52 unmodified lines
8688 obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
8789 obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
8890 obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
89−obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o
9091 obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
92+obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
drivers/platform/x86/acer-wireless.c+71−0
@@ -0,0 +1,71 @@
1+/*
2+ * Acer Wireless Radio Control Driver
3+ *
4+ * Copyright (C) 2017 Endless Mobile, Inc.
5+ *
6+ * This program is free software; you can redistribute it and/or modify
7+ * it under the terms of the GNU General Public License version 2 as
8+ * published by the Free Software Foundation.
9+ */
10+
11+#include <linux/acpi.h>
12+#include <linux/input.h>
13+#include <linux/kernel.h>
14+#include <linux/module.h>
15+#include <linux/pci_ids.h>
16+#include <linux/types.h>
17+
18+static const struct acpi_device_id acer_wireless_acpi_ids[] = {
19+ {"10251229", 0},
20+ {"", 0},
21+};
22+MODULE_DEVICE_TABLE(acpi, acer_wireless_acpi_ids);
23+
24+static void acer_wireless_notify(struct acpi_device *adev, u32 event)
25+{
26+ struct input_dev *idev = acpi_driver_data(adev);
27+
28+ dev_dbg(&adev->dev, "event=%#x\n", event);
29+ if (event != 0x80) {
30+ dev_notice(&adev->dev, "Unknown SMKB event: %#x\n", event);
31+ return;
32+ }
33+ input_report_key(idev, KEY_RFKILL, 1);
34+ input_report_key(idev, KEY_RFKILL, 0);
35+ input_sync(idev);
36+}
37+
38+static int acer_wireless_add(struct acpi_device *adev)
39+{
40+ struct input_dev *idev;
41+
42+ idev = devm_input_allocate_device(&adev->dev);
43+ if (!idev)
44+ return -ENOMEM;
45+
46+ adev->driver_data = idev;
47+ idev->name = "Acer Wireless Radio Control";
48+ idev->phys = "acer-wireless/input0";
49+ idev->id.bustype = BUS_HOST;
50+ idev->id.vendor = PCI_VENDOR_ID_AI;
51+ idev->id.product = 0x1229;
52+ set_bit(EV_KEY, idev->evbit);
53+ set_bit(KEY_RFKILL, idev->keybit);
54+
55+ return input_register_device(idev);
56+}
57+
58+static struct acpi_driver acer_wireless_driver = {
59+ .name = "Acer Wireless Radio Control Driver",
60+ .class = "hotkey",
61+ .ids = acer_wireless_acpi_ids,
62+ .ops = {
63+ .add = acer_wireless_add,
64+ .notify = acer_wireless_notify,
65+ },
66+};
67+module_acpi_driver(acer_wireless_driver);
68+
69+MODULE_DESCRIPTION("Acer Wireless Radio Control Driver");
70+MODULE_AUTHOR("Chris Chiu <chiu@gmail.com>");
71+MODULE_LICENSE("GPL v2");
drivers/platform/x86/alienware-wmi.c+17−0
@@ -68,6 +68,14 @@ struct quirk_entry { · 67 unmodified lines
6868
6969 static struct quirk_entry *quirks;
7070
71+
72+static struct quirk_entry quirk_inspiron5675 = {
73+ .num_zones = 2,
74+ .hdmi_mux = 0,
75+ .amplifier = 0,
76+ .deepslp = 0,
77+};
78+
7179 static struct quirk_entry quirk_unknown = {
7280 .num_zones = 2,
7381 .hdmi_mux = 0,
@@ -171,6 +179,15 @@ static const struct dmi_system_id alienware_quirks[] __initconst = { · 97 unmodified lines
171179 },
172180 .driver_data = &quirk_asm201,
173181 },
182+ {
183+ .callback = dmi_matched,
184+ .ident = "Dell Inc. Inspiron 5675",
185+ .matches = {
186+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
187+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"),
188+ },
189+ .driver_data = &quirk_inspiron5675,
190+ },
174191 {}
175192 };
176193
drivers/platform/x86/apple-gmux.c+1−47
@@ -24,7 +24,6 @@ · 23 unmodified lines
2424 #include <linux/delay.h>
2525 #include <linux/pci.h>
2626 #include <linux/vga_switcheroo.h>
27−#include <linux/vgaarb.h>
2827 #include <acpi/video.h>
2928 #include <asm/io.h>
3029
@@ -54,7 +53,6 @@ struct apple_gmux_data { · 23 unmodified lines
5453 bool indexed;
5554 struct mutex index_lock;
5655
57− struct pci_dev *pdev;
5856 struct backlight_device *bdev;
5957
6058 /* switcheroo data */
@@ -599,23 +597,6 @@ static int gmux_resume(struct device *dev) · 538 unmodified lines
599597 return 0;
600598 }
601599
602−static struct pci_dev *gmux_get_io_pdev(void)
603−{
604− struct pci_dev *pdev = NULL;
605−
606− while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) {
607− u16 cmd;
608−
609− pci_read_config_word(pdev, PCI_COMMAND, &cmd);
610− if (!(cmd & PCI_COMMAND_IO))
611− continue;
612−
613− return pdev;
614− }
615−
616− return NULL;
617−}
618−
619600 static int is_thunderbolt(struct device *dev, void *data)
620601 {
621602 return to_pci_dev(dev)->is_thunderbolt;
@@ -631,7 +612,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) · 9 unmodified lines
631612 int ret = -ENXIO;
632613 acpi_status status;
633614 unsigned long long gpe;
634− struct pci_dev *pdev = NULL;
635615
636616 if (apple_gmux_data)
637617 return -EBUSY;
@@ -682,7 +662,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) · 44 unmodified lines
682662 ver_minor = (version >> 16) & 0xff;
683663 ver_release = (version >> 8) & 0xff;
684664 } else {
685− pr_info("gmux device not present or IO disabled\n");
665+ pr_info("gmux device not present\n");
686666 ret = -ENODEV;
687667 goto err_release;
688668 }
@@ -690,23 +670,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) · 1 unmodified line
690670 pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
691671 ver_release, (gmux_data->indexed ? "indexed" : "classic"));
692672
693− /*
694− * Apple systems with gmux are EFI based and normally don't use
695− * VGA. In addition changing IO+MEM ownership between IGP and dGPU
696− * disables IO/MEM used for backlight control on some systems.
697− * Lock IO+MEM to GPU with active IO to prevent switch.
698− */
699− pdev = gmux_get_io_pdev();
700− if (pdev && vga_tryget(pdev,
701− VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) {
702− pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n",
703− pci_name(pdev));
704− ret = -EBUSY;
705− goto err_release;
706− } else if (pdev)
707− pr_info("locked IO for PCI:%s\n", pci_name(pdev));
708− gmux_data->pdev = pdev;
709−
710673 memset(&props, 0, sizeof(props));
711674 props.type = BACKLIGHT_PLATFORM;
712675 props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
@@ -822,10 +785,6 @@ err_enable_gpe: · 109 unmodified lines
822785 err_notify:
823786 backlight_device_unregister(bdev);
824787 err_release:
825− if (gmux_data->pdev)
826− vga_put(gmux_data->pdev,
827− VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
828− pci_dev_put(pdev);
829788 release_region(gmux_data->iostart, gmux_data->iolen);
830789 err_free:
831790 kfree(gmux_data);
@@ -845,11 +804,6 @@ static void gmux_remove(struct pnp_dev *pnp) · 13 unmodified lines
845804 &gmux_notify_handler);
846805 }
847806
848− if (gmux_data->pdev) {
849− vga_put(gmux_data->pdev,
850− VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
851− pci_dev_put(gmux_data->pdev);
852− }
853807 backlight_device_unregister(gmux_data->bdev);
854808
855809 release_region(gmux_data->iostart, gmux_data->iolen);
drivers/platform/x86/asus-nb-wmi.c+11−2
@@ -111,7 +111,7 @@ static struct quirk_entry quirk_asus_x550lb = { · 110 unmodified lines
111111 .xusb2pr = 0x01D9,
112112 };
113113
114−static struct quirk_entry quirk_asus_ux330uak = {
114+static struct quirk_entry quirk_asus_forceals = {
115115 .wmi_force_als_set = true,
116116 };
117117
@@ -387,7 +387,7 @@ static const struct dmi_system_id asus_quirks[] = { · 269 unmodified lines
387387 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
388388 DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"),
389389 },
390− .driver_data = &quirk_asus_ux330uak,
390+ .driver_data = &quirk_asus_forceals,
391391 },
392392 {
393393 .callback = dmi_matched,
@@ -398,6 +398,15 @@ static const struct dmi_system_id asus_quirks[] = { · 4 unmodified lines
398398 },
399399 .driver_data = &quirk_asus_x550lb,
400400 },
401+ {
402+ .callback = dmi_matched,
403+ .ident = "ASUSTeK COMPUTER INC. UX430UQ",
404+ .matches = {
405+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
406+ DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ"),
407+ },
408+ .driver_data = &quirk_asus_forceals,
409+ },
401410 {},
402411 };
403412
drivers/platform/x86/dell-laptop.c+167−93
@@ -36,10 +36,10 @@ · 35 unmodified lines
3636 #include "dell-smbios.h"
3737
3838 struct quirk_entry {
39− u8 touchpad_led;
40− u8 kbd_led_levels_off_1;
39+ bool touchpad_led;
40+ bool kbd_led_levels_off_1;
4141
42− int needs_kbd_timeouts;
42+ bool needs_kbd_timeouts;
4343 /*
4444 * Ordered list of timeouts expressed in seconds.
4545 * The list must end with -1
@@ -50,7 +50,7 @@ struct quirk_entry { · 4 unmodified lines
5050 static struct quirk_entry *quirks;
5151
5252 static struct quirk_entry quirk_dell_vostro_v130 = {
53− .touchpad_led = 1,
53+ .touchpad_led = true,
5454 };
5555
5656 static int __init dmi_matched(const struct dmi_system_id *dmi)
@@ -64,12 +64,12 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) · 7 unmodified lines
6464 * is used then BIOS silently set timeout to 0 without any error message.
6565 */
6666 static struct quirk_entry quirk_dell_xps13_9333 = {
67− .needs_kbd_timeouts = 1,
67+ .needs_kbd_timeouts = true,
6868 .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 },
6969 };
7070
7171 static struct quirk_entry quirk_dell_latitude_e6410 = {
72− .kbd_led_levels_off_1 = 1,
72+ .kbd_led_levels_off_1 = true,
7373 };
7474
7575 static struct platform_driver platform_driver = {
@@ -78,7 +78,6 @@ static struct platform_driver platform_driver = { · 2 unmodified lines
7878 }
7979 };
8080
81−static struct calling_interface_buffer *buffer;
8281 static struct platform_device *platform_device;
8382 static struct backlight_device *dell_backlight_device;
8483 static struct rfkill *wifi_rfkill;
@@ -109,6 +108,42 @@ static const struct dmi_system_id dell_device_table[] __initconst = { · 24 unmodified lines
109108 DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/
110109 },
111110 },
111+ {
112+ .matches = {
113+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
114+ DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/
115+ },
116+ },
117+ {
118+ .matches = {
119+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
120+ DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/
121+ },
122+ },
123+ {
124+ .matches = {
125+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
126+ DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/
127+ },
128+ },
129+ {
130+ .matches = {
131+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
132+ DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/
133+ },
134+ },
135+ {
136+ .matches = {
137+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
138+ DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/
139+ },
140+ },
141+ {
142+ .matches = {
143+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
144+ DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/
145+ },
146+ },
112147 {
113148 .ident = "Dell Computer Corporation",
114149 .matches = {
@@ -286,7 +321,8 @@ static const struct dmi_system_id dell_quirks[] __initconst = { · 171 unmodified lines
286321 { }
287322 };
288323
289−void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3)
324+static void dell_fill_request(struct calling_interface_buffer *buffer,
325+ u32 arg0, u32 arg1, u32 arg2, u32 arg3)
290326 {
291327 memset(buffer, 0, sizeof(struct calling_interface_buffer));
292328 buffer->input[0] = arg0;
@@ -295,7 +331,8 @@ void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) · 2 unmodified lines
295331 buffer->input[3] = arg3;
296332 }
297333
298−int dell_send_request(u16 class, u16 select)
334+static int dell_send_request(struct calling_interface_buffer *buffer,
335+ u16 class, u16 select)
299336 {
300337 int ret;
301338
@@ -432,21 +469,22 @@ static int dell_rfkill_set(void *data, bool blocked) · 130 unmodified lines
432469 int disable = blocked ? 1 : 0;
433470 unsigned long radio = (unsigned long)data;
434471 int hwswitch_bit = (unsigned long)data - 1;
472+ struct calling_interface_buffer buffer;
435473 int hwswitch;
436474 int status;
437475 int ret;
438476
439− dell_set_arguments(0, 0, 0, 0);
440− ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
477+ dell_fill_request(&buffer, 0, 0, 0, 0);
478+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
441479 if (ret)
442480 return ret;
443− status = buffer->output[1];
481+ status = buffer.output[1];
444482
445− dell_set_arguments(0x2, 0, 0, 0);
446− ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
483+ dell_fill_request(&buffer, 0x2, 0, 0, 0);
484+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
447485 if (ret)
448486 return ret;
449− hwswitch = buffer->output[1];
487+ hwswitch = buffer.output[1];
450488
451489 /* If the hardware switch controls this radio, and the hardware
452490 switch is disabled, always disable the radio */
@@ -454,8 +492,8 @@ static int dell_rfkill_set(void *data, bool blocked) · 1 unmodified line
454492 (status & BIT(0)) && !(status & BIT(16)))
455493 disable = 1;
456494
457− dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0);
458− ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
495+ dell_fill_request(&buffer, 1 | (radio<<8) | (disable << 16), 0, 0, 0);
496+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
459497 return ret;
460498 }
461499
@@ -464,9 +502,11 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, · 2 unmodified lines
464502 {
465503 if (status & BIT(0)) {
466504 /* Has hw-switch, sync sw_state to BIOS */
505+ struct calling_interface_buffer buffer;
467506 int block = rfkill_blocked(rfkill);
468− dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0);
469− dell_send_request(CLASS_INFO, SELECT_RFKILL);
507+ dell_fill_request(&buffer,
508+ 1 | (radio << 8) | (block << 16), 0, 0, 0);
509+ dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
470510 } else {
471511 /* No hw-switch, sync BIOS state to sw_state */
472512 rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16)));
@@ -483,21 +523,22 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio, · 10 unmodified lines
483523 static void dell_rfkill_query(struct rfkill *rfkill, void *data)
484524 {
485525 int radio = ((unsigned long)data & 0xF);
526+ struct calling_interface_buffer buffer;
486527 int hwswitch;
487528 int status;
488529 int ret;
489530
490− dell_set_arguments(0, 0, 0, 0);
491− ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
492− status = buffer->output[1];
531+ dell_fill_request(&buffer, 0, 0, 0, 0);
532+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
533+ status = buffer.output[1];
493534
494535 if (ret != 0 || !(status & BIT(0))) {
495536 return;
496537 }
497538
498− dell_set_arguments(0, 0x2, 0, 0);
499− ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
500− hwswitch = buffer->output[1];
539+ dell_fill_request(&buffer, 0, 0x2, 0, 0);
540+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
541+ hwswitch = buffer.output[1];
501542
502543 if (ret != 0)
503544 return;
@@ -514,22 +555,23 @@ static struct dentry *dell_laptop_dir; · 10 unmodified lines
514555
515556 static int dell_debugfs_show(struct seq_file *s, void *data)
516557 {
558+ struct calling_interface_buffer buffer;
517559 int hwswitch_state;
518560 int hwswitch_ret;
519561 int status;
520562 int ret;
521563
522− dell_set_arguments(0, 0, 0, 0);
523− ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
564+ dell_fill_request(&buffer, 0, 0, 0, 0);
565+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
524566 if (ret)
525567 return ret;
526− status = buffer->output[1];
568+ status = buffer.output[1];
527569
528− dell_set_arguments(0, 0x2, 0, 0);
529− hwswitch_ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
570+ dell_fill_request(&buffer, 0, 0x2, 0, 0);
571+ hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
530572 if (hwswitch_ret)
531573 return hwswitch_ret;
532− hwswitch_state = buffer->output[1];
574+ hwswitch_state = buffer.output[1];
533575
534576 seq_printf(s, "return:\t%d\n", ret);
535577 seq_printf(s, "status:\t0x%X\n", status);
@@ -610,22 +652,23 @@ static const struct file_operations dell_debugfs_fops = { · 74 unmodified lines
610652
611653 static void dell_update_rfkill(struct work_struct *ignored)
612654 {
655+ struct calling_interface_buffer buffer;
613656 int hwswitch = 0;
614657 int status;
615658 int ret;
616659
617− dell_set_arguments(0, 0, 0, 0);
618− ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
619− status = buffer->output[1];
660+ dell_fill_request(&buffer, 0, 0, 0, 0);
661+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
662+ status = buffer.output[1];
620663
621664 if (ret != 0)
622665 return;
623666
624− dell_set_arguments(0, 0x2, 0, 0);
625− ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
667+ dell_fill_request(&buffer, 0, 0x2, 0, 0);
668+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
626669
627670 if (ret == 0 && (status & BIT(0)))
628− hwswitch = buffer->output[1];
671+ hwswitch = buffer.output[1];
629672
630673 if (wifi_rfkill) {
631674 dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch);
@@ -683,6 +726,7 @@ static struct notifier_block dell_laptop_rbtn_notifier = { · 51 unmodified lines
683726
684727 static int __init dell_setup_rfkill(void)
685728 {
729+ struct calling_interface_buffer buffer;
686730 int status, ret, whitelisted;
687731 const char *product;
688732
@@ -698,9 +742,9 @@ static int __init dell_setup_rfkill(void) · 9 unmodified lines
698742 if (!force_rfkill && !whitelisted)
699743 return 0;
700744
701− dell_set_arguments(0, 0, 0, 0);
702− ret = dell_send_request(CLASS_INFO, SELECT_RFKILL);
703− status = buffer->output[1];
745+ dell_fill_request(&buffer, 0, 0, 0, 0);
746+ ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
747+ status = buffer.output[1];
704748
705749 /* dell wireless info smbios call is not supported */
706750 if (ret != 0)
@@ -853,6 +897,7 @@ static void dell_cleanup_rfkill(void) · 146 unmodified lines
853897
854898 static int dell_send_intensity(struct backlight_device *bd)
855899 {
900+ struct calling_interface_buffer buffer;
856901 struct calling_interface_token *token;
857902 int ret;
858903
@@ -860,17 +905,21 @@ static int dell_send_intensity(struct backlight_device *bd) · 1 unmodified line
860905 if (!token)
861906 return -ENODEV;
862907
863− dell_set_arguments(token->location, bd->props.brightness, 0, 0);
908+ dell_fill_request(&buffer,
909+ token->location, bd->props.brightness, 0, 0);
864910 if (power_supply_is_system_supplied() > 0)
865− ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_AC);
911+ ret = dell_send_request(&buffer,
912+ CLASS_TOKEN_WRITE, SELECT_TOKEN_AC);
866913 else
867− ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT);
914+ ret = dell_send_request(&buffer,
915+ CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT);
868916
869917 return ret;
870918 }
871919
872920 static int dell_get_intensity(struct backlight_device *bd)
873921 {
922+ struct calling_interface_buffer buffer;
874923 struct calling_interface_token *token;
875924 int ret;
876925
@@ -878,14 +927,17 @@ static int dell_get_intensity(struct backlight_device *bd) · 1 unmodified line
878927 if (!token)
879928 return -ENODEV;
880929
881− dell_set_arguments(token->location, 0, 0, 0);
930+ dell_fill_request(&buffer, token->location, 0, 0, 0);
882931 if (power_supply_is_system_supplied() > 0)
883− ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC);
932+ ret = dell_send_request(&buffer,
933+ CLASS_TOKEN_READ, SELECT_TOKEN_AC);
884934 else
885− ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_BAT);
935+ ret = dell_send_request(&buffer,
936+ CLASS_TOKEN_READ, SELECT_TOKEN_BAT);
886937
887938 if (ret == 0)
888− ret = buffer->output[1];
939+ ret = buffer.output[1];
940+
889941 return ret;
890942 }
891943
@@ -1133,6 +1185,7 @@ static u8 kbd_previous_mode_bit; · 241 unmodified lines
11331185
11341186 static bool kbd_led_present;
11351187 static DEFINE_MUTEX(kbd_led_mutex);
1188+static enum led_brightness kbd_led_level;
11361189
11371190 /*
11381191 * NOTE: there are three ways to set the keyboard backlight level.
@@ -1149,31 +1202,33 @@ static DEFINE_MUTEX(kbd_led_mutex); · 10 unmodified lines
11491202
11501203 static int kbd_get_info(struct kbd_info *info)
11511204 {
1205+ struct calling_interface_buffer buffer;
11521206 u8 units;
11531207 int ret;
11541208
1155− dell_set_arguments(0, 0, 0, 0);
1156− ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
1209+ dell_fill_request(&buffer, 0, 0, 0, 0);
1210+ ret = dell_send_request(&buffer,
1211+ CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
11571212 if (ret)
11581213 return ret;
11591214
1160− info->modes = buffer->output[1] & 0xFFFF;
1161− info->type = (buffer->output[1] >> 24) & 0xFF;
1162− info->triggers = buffer->output[2] & 0xFF;
1163− units = (buffer->output[2] >> 8) & 0xFF;
1164− info->levels = (buffer->output[2] >> 16) & 0xFF;
1215+ info->modes = buffer.output[1] & 0xFFFF;
1216+ info->type = (buffer.output[1] >> 24) & 0xFF;
1217+ info->triggers = buffer.output[2] & 0xFF;
1218+ units = (buffer.output[2] >> 8) & 0xFF;
1219+ info->levels = (buffer.output[2] >> 16) & 0xFF;
11651220
11661221 if (quirks && quirks->kbd_led_levels_off_1 && info->levels)
11671222 info->levels--;
11681223
11691224 if (units & BIT(0))
1170− info->seconds = (buffer->output[3] >> 0) & 0xFF;
1225+ info->seconds = (buffer.output[3] >> 0) & 0xFF;
11711226 if (units & BIT(1))
1172− info->minutes = (buffer->output[3] >> 8) & 0xFF;
1227+ info->minutes = (buffer.output[3] >> 8) & 0xFF;
11731228 if (units & BIT(2))
1174− info->hours = (buffer->output[3] >> 16) & 0xFF;
1229+ info->hours = (buffer.output[3] >> 16) & 0xFF;
11751230 if (units & BIT(3))
1176− info->days = (buffer->output[3] >> 24) & 0xFF;
1231+ info->days = (buffer.output[3] >> 24) & 0xFF;
11771232
11781233 return ret;
11791234 }
@@ -1233,31 +1288,34 @@ static int kbd_set_level(struct kbd_state *state, u8 level) · 53 unmodified lines
12331288
12341289 static int kbd_get_state(struct kbd_state *state)
12351290 {
1291+ struct calling_interface_buffer buffer;
12361292 int ret;
12371293
1238− dell_set_arguments(0x1, 0, 0, 0);
1239− ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
1294+ dell_fill_request(&buffer, 0, 0, 0, 0);
1295+ ret = dell_send_request(&buffer,
1296+ CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
12401297 if (ret)
12411298 return ret;
12421299
1243− state->mode_bit = ffs(buffer->output[1] & 0xFFFF);
1300+ state->mode_bit = ffs(buffer.output[1] & 0xFFFF);
12441301 if (state->mode_bit != 0)
12451302 state->mode_bit--;
12461303
1247− state->triggers = (buffer->output[1] >> 16) & 0xFF;
1248− state->timeout_value = (buffer->output[1] >> 24) & 0x3F;
1249− state->timeout_unit = (buffer->output[1] >> 30) & 0x3;
1250− state->als_setting = buffer->output[2] & 0xFF;
1251− state->als_value = (buffer->output[2] >> 8) & 0xFF;
1252− state->level = (buffer->output[2] >> 16) & 0xFF;
1253− state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F;
1254− state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3;
1304+ state->triggers = (buffer.output[1] >> 16) & 0xFF;
1305+ state->timeout_value = (buffer.output[1] >> 24) & 0x3F;
1306+ state->timeout_unit = (buffer.output[1] >> 30) & 0x3;
1307+ state->als_setting = buffer.output[2] & 0xFF;
1308+ state->als_value = (buffer.output[2] >> 8) & 0xFF;
1309+ state->level = (buffer.output[2] >> 16) & 0xFF;
1310+ state->timeout_value_ac = (buffer.output[2] >> 24) & 0x3F;
1311+ state->timeout_unit_ac = (buffer.output[2] >> 30) & 0x3;
12551312
12561313 return ret;
12571314 }
12581315
12591316 static int kbd_set_state(struct kbd_state *state)
12601317 {
1318+ struct calling_interface_buffer buffer;
12611319 int ret;
12621320 u32 input1;
12631321 u32 input2;
@@ -1270,8 +1328,9 @@ static int kbd_set_state(struct kbd_state *state) · 6 unmodified lines
12701328 input2 |= (state->level & 0xFF) << 16;
12711329 input2 |= (state->timeout_value_ac & 0x3F) << 24;
12721330 input2 |= (state->timeout_unit_ac & 0x3) << 30;
1273− dell_set_arguments(0x2, input1, input2, 0);
1274− ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
1331+ dell_fill_request(&buffer, 0x2, input1, input2, 0);
1332+ ret = dell_send_request(&buffer,
1333+ CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
12751334
12761335 return ret;
12771336 }
@@ -1298,6 +1357,7 @@ static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) · 20 unmodified lines
12981357
12991358 static int kbd_set_token_bit(u8 bit)
13001359 {
1360+ struct calling_interface_buffer buffer;
13011361 struct calling_interface_token *token;
13021362 int ret;
13031363
@@ -1308,14 +1368,15 @@ static int kbd_set_token_bit(u8 bit) · 4 unmodified lines
13081368 if (!token)
13091369 return -EINVAL;
13101370
1311− dell_set_arguments(token->location, token->value, 0, 0);
1312− ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
1371+ dell_fill_request(&buffer, token->location, token->value, 0, 0);
1372+ ret = dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
13131373
13141374 return ret;
13151375 }
13161376
13171377 static int kbd_get_token_bit(u8 bit)
13181378 {
1379+ struct calling_interface_buffer buffer;
13191380 struct calling_interface_token *token;
13201381 int ret;
13211382 int val;
@@ -1327,9 +1388,9 @@ static int kbd_get_token_bit(u8 bit) · 5 unmodified lines
13271388 if (!token)
13281389 return -EINVAL;
13291390
1330− dell_set_arguments(token->location, 0, 0, 0);
1331− ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_STD);
1332− val = buffer->output[1];
1391+ dell_fill_request(&buffer, token->location, 0, 0, 0);
1392+ ret = dell_send_request(&buffer, CLASS_TOKEN_READ, SELECT_TOKEN_STD);
1393+ val = buffer.output[1];
13331394
13341395 if (ret)
13351396 return ret;
@@ -1947,6 +2008,7 @@ static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev) · 611 unmodified lines
19472008 static int kbd_led_level_set(struct led_classdev *led_cdev,
19482009 enum led_brightness value)
19492010 {
2011+ enum led_brightness new_value = value;
19502012 struct kbd_state state;
19512013 struct kbd_state new_state;
19522014 u16 num;
@@ -1976,6 +2038,9 @@ static int kbd_led_level_set(struct led_classdev *led_cdev, · 23 unmodified lines
19762038 }
19772039
19782040 out:
2041+ if (ret == 0)
2042+ kbd_led_level = new_value;
2043+
19792044 mutex_unlock(&kbd_led_mutex);
19802045 return ret;
19812046 }
@@ -2003,6 +2068,9 @@ static int __init kbd_led_init(struct device *dev) · 21 unmodified lines
20032068 if (kbd_led.max_brightness)
20042069 kbd_led.max_brightness--;
20052070 }
2071+
2072+ kbd_led_level = kbd_led_level_get(NULL);
2073+
20062074 ret = led_classdev_register(dev, &kbd_led);
20072075 if (ret)
20082076 kbd_led_present = false;
@@ -2027,13 +2095,25 @@ static void kbd_led_exit(void) · 18 unmodified lines
20272095 static int dell_laptop_notifier_call(struct notifier_block *nb,
20282096 unsigned long action, void *data)
20292097 {
2098+ bool changed = false;
2099+ enum led_brightness new_kbd_led_level;
2100+
20302101 switch (action) {
20312102 case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED:
20322103 if (!kbd_led_present)
20332104 break;
20342105
2035− led_classdev_notify_brightness_hw_changed(&kbd_led,
2036− kbd_led_level_get(&kbd_led));
2106+ mutex_lock(&kbd_led_mutex);
2107+ new_kbd_led_level = kbd_led_level_get(&kbd_led);
2108+ if (kbd_led_level != new_kbd_led_level) {
2109+ kbd_led_level = new_kbd_led_level;
2110+ changed = true;
2111+ }
2112+ mutex_unlock(&kbd_led_mutex);
2113+
2114+ if (changed)
2115+ led_classdev_notify_brightness_hw_changed(&kbd_led,
2116+ kbd_led_level);
20372117 break;
20382118 }
20392119
@@ -2046,6 +2126,7 @@ static struct notifier_block dell_laptop_notifier = { · 6 unmodified lines
20462126
20472127 int dell_micmute_led_set(int state)
20482128 {
2129+ struct calling_interface_buffer buffer;
20492130 struct calling_interface_token *token;
20502131
20512132 if (state == 0)
@@ -2058,8 +2139,8 @@ int dell_micmute_led_set(int state) · 6 unmodified lines
20582139 if (!token)
20592140 return -ENODEV;
20602141
2061− dell_set_arguments(token->location, token->value, 0, 0);
2062− dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
2142+ dell_fill_request(&buffer, token->location, token->value, 0, 0);
2143+ dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
20632144
20642145 return state;
20652146 }
@@ -2090,13 +2171,6 @@ static int __init dell_init(void) · 24 unmodified lines
20902171 if (ret)
20912172 goto fail_platform_device2;
20922173
2093− buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
2094− if (!buffer) {
2095− ret = -ENOMEM;
2096− goto fail_buffer;
2097− }
2098−
2099−
21002174 ret = dell_setup_rfkill();
21012175
21022176 if (ret) {
@@ -2121,10 +2195,13 @@ static int __init dell_init(void) · 18 unmodified lines
21212195
21222196 token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
21232197 if (token) {
2124− dell_set_arguments(token->location, 0, 0, 0);
2125− ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC);
2198+ struct calling_interface_buffer buffer;
2199+
2200+ dell_fill_request(&buffer, token->location, 0, 0, 0);
2201+ ret = dell_send_request(&buffer,
2202+ CLASS_TOKEN_READ, SELECT_TOKEN_AC);
21262203 if (ret)
2127− max_intensity = buffer->output[3];
2204+ max_intensity = buffer.output[3];
21282205 }
21292206
21302207 if (max_intensity) {
@@ -2158,8 +2235,6 @@ static int __init dell_init(void) · 27 unmodified lines
21582235 fail_get_brightness:
21592236 backlight_device_unregister(dell_backlight_device);
21602237 fail_backlight:
2161− kfree(buffer);
2162−fail_buffer:
21632238 dell_cleanup_rfkill();
21642239 fail_rfkill:
21652240 platform_device_del(platform_device);
@@ -2179,7 +2254,6 @@ static void __exit dell_exit(void) · 13 unmodified lines
21792254 touchpad_led_exit();
21802255 kbd_led_exit();
21812256 backlight_device_unregister(dell_backlight_device);
2182− kfree(buffer);
21832257 dell_cleanup_rfkill();
21842258 if (platform_device) {
21852259 platform_device_unregister(platform_device);
drivers/platform/x86/dell-smbios.c+4−4
@@ -65,10 +65,10 @@ static struct smbios_call call_whitelist[] = { · 64 unmodified lines
6565
6666 /* calls that are explicitly blacklisted */
6767 static struct smbios_call call_blacklist[] = {
68− {0x0000, 01, 07}, /* manufacturing use */
69− {0x0000, 06, 05}, /* manufacturing use */
70− {0x0000, 11, 03}, /* write once */
71− {0x0000, 11, 07}, /* write once */
68+ {0x0000, 1, 7}, /* manufacturing use */
69+ {0x0000, 6, 5}, /* manufacturing use */
70+ {0x0000, 11, 3}, /* write once */
71+ {0x0000, 11, 7}, /* write once */
7272 {0x0000, 11, 11}, /* write once */
7373 {0x0000, 19, -1}, /* diagnostics */
7474 /* handled by kernel: dell-laptop */
drivers/platform/x86/dell-wmi.c+3−0
@@ -261,6 +261,9 @@ static const u16 bios_to_linux_keycode[256] = { · 260 unmodified lines
261261 * override them.
262262 */
263263 static const struct key_entry dell_wmi_keymap_type_0010[] = {
264+ /* Mic mute */
265+ { KE_KEY, 0x150, { KEY_MICMUTE } },
266+
264267 /* Fn-lock */
265268 { KE_IGNORE, 0x151, { KEY_RESERVED } },
266269
drivers/platform/x86/gpd-pocket-fan.c+216−0
@@ -0,0 +1,216 @@
1+// SPDX-License-Identifier: GPL-2.0+
2+/*
3+ * GPD Pocket fan controller driver
4+ *
5+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
6+ */
7+
8+#include <linux/acpi.h>
9+#include <linux/gpio/consumer.h>
10+#include <linux/module.h>
11+#include <linux/moduleparam.h>
12+#include <linux/platform_device.h>
13+#include <linux/power_supply.h>
14+#include <linux/thermal.h>
15+#include <linux/workqueue.h>
16+
17+#define MAX_SPEED 3
18+
19+static int temp_limits[3] = { 55000, 60000, 65000 };
20+module_param_array(temp_limits, int, NULL, 0444);
21+MODULE_PARM_DESC(temp_limits,
22+ "Milli-celcius values above which the fan speed increases");
23+
24+static int hysteresis = 3000;
25+module_param(hysteresis, int, 0444);
26+MODULE_PARM_DESC(hysteresis,
27+ "Hysteresis in milli-celcius before lowering the fan speed");
28+
29+static int speed_on_ac = 2;
30+module_param(speed_on_ac, int, 0444);
31+MODULE_PARM_DESC(speed_on_ac,
32+ "minimum fan speed to allow when system is powered by AC");
33+
34+struct gpd_pocket_fan_data {
35+ struct device *dev;
36+ struct thermal_zone_device *dts0;
37+ struct thermal_zone_device *dts1;
38+ struct gpio_desc *gpio0;
39+ struct gpio_desc *gpio1;
40+ struct delayed_work work;
41+ int last_speed;
42+};
43+
44+static void gpd_pocket_fan_set_speed(struct gpd_pocket_fan_data *fan, int speed)
45+{
46+ if (speed == fan->last_speed)
47+ return;
48+
49+ gpiod_direction_output(fan->gpio0, !!(speed & 1));
50+ gpiod_direction_output(fan->gpio1, !!(speed & 2));
51+
52+ fan->last_speed = speed;
53+}
54+
55+static int gpd_pocket_fan_min_speed(void)
56+{
57+ if (power_supply_is_system_supplied())
58+ return speed_on_ac;
59+ else
60+ return 0;
61+}
62+
63+static void gpd_pocket_fan_worker(struct work_struct *work)
64+{
65+ struct gpd_pocket_fan_data *fan =
66+ container_of(work, struct gpd_pocket_fan_data, work.work);
67+ int t0, t1, temp, speed, min_speed, i;
68+
69+ if (thermal_zone_get_temp(fan->dts0, &t0) ||
70+ thermal_zone_get_temp(fan->dts1, &t1)) {
71+ dev_warn(fan->dev, "Error getting temperature\n");
72+ speed = MAX_SPEED;
73+ goto set_speed;
74+ }
75+
76+ temp = max(t0, t1);
77+
78+ speed = fan->last_speed;
79+ min_speed = gpd_pocket_fan_min_speed();
80+
81+ /* Determine minimum speed */
82+ for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) {
83+ if (temp < temp_limits[i])
84+ break;
85+ }
86+ if (speed < i)
87+ speed = i;
88+
89+ /* Use hysteresis before lowering speed again */
90+ for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) {
91+ if (temp <= (temp_limits[i] - hysteresis))
92+ break;
93+ }
94+ if (speed > i)
95+ speed = i;
96+
97+ if (fan->last_speed <= 0 && speed)
98+ speed = MAX_SPEED; /* kick start motor */
99+
100+set_speed:
101+ gpd_pocket_fan_set_speed(fan, speed);
102+
103+ /* When mostly idle (low temp/speed), slow down the poll interval. */
104+ queue_delayed_work(system_wq, &fan->work,
105+ msecs_to_jiffies(4000 / (speed + 1)));
106+}
107+
108+static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data *fan)
109+{
110+ fan->last_speed = -1;
111+ mod_delayed_work(system_wq, &fan->work, 0);
112+}
113+
114+static int gpd_pocket_fan_probe(struct platform_device *pdev)
115+{
116+ struct gpd_pocket_fan_data *fan;
117+ int i;
118+
119+ for (i = 0; i < ARRAY_SIZE(temp_limits); i++) {
120+ if (temp_limits[i] < 40000 || temp_limits[i] > 70000) {
121+ dev_err(&pdev->dev, "Invalid temp-limit %d (must be between 40000 and 70000)\n",
122+ temp_limits[i]);
123+ return -EINVAL;
124+ }
125+ }
126+ if (hysteresis < 1000 || hysteresis > 10000) {
127+ dev_err(&pdev->dev, "Invalid hysteresis %d (must be between 1000 and 10000)\n",
128+ hysteresis);
129+ return -EINVAL;
130+ }
131+ if (speed_on_ac < 0 || speed_on_ac > MAX_SPEED) {
132+ dev_err(&pdev->dev, "Invalid speed_on_ac %d (must be between 0 and 3)\n",
133+ speed_on_ac);
134+ return -EINVAL;
135+ }
136+
137+ fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
138+ if (!fan)
139+ return -ENOMEM;
140+
141+ fan->dev = &pdev->dev;
142+ INIT_DELAYED_WORK(&fan->work, gpd_pocket_fan_worker);
143+
144+ /* Note this returns a "weak" reference which we don't need to free */
145+ fan->dts0 = thermal_zone_get_zone_by_name("soc_dts0");
146+ if (IS_ERR(fan->dts0))
147+ return -EPROBE_DEFER;
148+
149+ fan->dts1 = thermal_zone_get_zone_by_name("soc_dts1");
150+ if (IS_ERR(fan->dts1))
151+ return -EPROBE_DEFER;
152+
153+ fan->gpio0 = devm_gpiod_get_index(fan->dev, NULL, 0, GPIOD_ASIS);
154+ if (IS_ERR(fan->gpio0))
155+ return PTR_ERR(fan->gpio0);
156+
157+ fan->gpio1 = devm_gpiod_get_index(fan->dev, NULL, 1, GPIOD_ASIS);
158+ if (IS_ERR(fan->gpio1))
159+ return PTR_ERR(fan->gpio1);
160+
161+ gpd_pocket_fan_force_update(fan);
162+
163+ platform_set_drvdata(pdev, fan);
164+ return 0;
165+}
166+
167+static int gpd_pocket_fan_remove(struct platform_device *pdev)
168+{
169+ struct gpd_pocket_fan_data *fan = platform_get_drvdata(pdev);
170+
171+ cancel_delayed_work_sync(&fan->work);
172+ return 0;
173+}
174+
175+#ifdef CONFIG_PM_SLEEP
176+static int gpd_pocket_fan_suspend(struct device *dev)
177+{
178+ struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev);
179+
180+ cancel_delayed_work_sync(&fan->work);
181+ gpd_pocket_fan_set_speed(fan, gpd_pocket_fan_min_speed());
182+ return 0;
183+}
184+
185+static int gpd_pocket_fan_resume(struct device *dev)
186+{
187+ struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev);
188+
189+ gpd_pocket_fan_force_update(fan);
190+ return 0;
191+}
192+#endif
193+static SIMPLE_DEV_PM_OPS(gpd_pocket_fan_pm_ops,
194+ gpd_pocket_fan_suspend,
195+ gpd_pocket_fan_resume);
196+
197+static struct acpi_device_id gpd_pocket_fan_acpi_match[] = {
198+ { "FAN02501" },
199+ {},
200+};
201+MODULE_DEVICE_TABLE(acpi, gpd_pocket_fan_acpi_match);
202+
203+static struct platform_driver gpd_pocket_fan_driver = {
204+ .probe = gpd_pocket_fan_probe,
205+ .remove = gpd_pocket_fan_remove,
206+ .driver = {
207+ .name = "gpd_pocket_fan",
208+ .acpi_match_table = gpd_pocket_fan_acpi_match,
209+ .pm = &gpd_pocket_fan_pm_ops,
210+ },
211+};
212+
213+module_platform_driver(gpd_pocket_fan_driver);
214+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
215+MODULE_DESCRIPTION("GPD pocket fan driver");
216+MODULE_LICENSE("GPL");
drivers/platform/x86/ideapad-laptop.c+21−7
@@ -124,10 +124,10 @@ static int read_method_int(acpi_handle handle, const char *method, int *val) · 123 unmodified lines
124124 if (ACPI_FAILURE(status)) {
125125 *val = -1;
126126 return -1;
127− } else {
128− *val = result;
129− return 0;
130127 }
128+ *val = result;
129+ return 0;
130+
131131 }
132132
133133 static int method_gbmd(acpi_handle handle, unsigned long *ret)
@@ -164,10 +164,10 @@ static int method_vpcr(acpi_handle handle, int cmd, int *ret) · 30 unmodified lines
164164 if (ACPI_FAILURE(status)) {
165165 *ret = -1;
166166 return -1;
167− } else {
168− *ret = result;
169− return 0;
170167 }
168+ *ret = result;
169+ return 0;
170+
171171 }
172172
173173 static int method_vpcw(acpi_handle handle, int cmd, int data)
@@ -231,7 +231,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data) · 57 unmodified lines
231231 if (val == 0)
232232 return 0;
233233 }
234− pr_err("timeout in write_ec_cmd\n");
234+ pr_err("timeout in %s\n", __func__);
235235 return -1;
236236 }
237237
@@ -963,6 +963,13 @@ static void ideapad_wmi_notify(u32 value, void *context) · 725 unmodified lines
963963 * report all radios as hardware-blocked.
964964 */
965965 static const struct dmi_system_id no_hw_rfkill_list[] = {
966+ {
967+ .ident = "Lenovo RESCUER R720-15IKBN",
968+ .matches = {
969+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
970+ DMI_MATCH(DMI_BOARD_NAME, "80WW"),
971+ },
972+ },
966973 {
967974 .ident = "Lenovo G40-30",
968975 .matches = {
@@ -1103,6 +1110,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { · 134 unmodified lines
11031110 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"),
11041111 },
11051112 },
1113+ {
1114+ .ident = "Lenovo Legion Y720-15IKB",
1115+ .matches = {
1116+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1117+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKB"),
1118+ },
1119+ },
11061120 {
11071121 .ident = "Lenovo Legion Y720-15IKBN",
11081122 .matches = {
drivers/platform/x86/intel-hid.c+38−3
@@ -25,6 +25,7 @@ · 24 unmodified lines
2525 #include <linux/acpi.h>
2626 #include <linux/suspend.h>
2727 #include <acpi/acpi_bus.h>
28+#include <linux/dmi.h>
2829
2930 MODULE_LICENSE("GPL");
3031 MODULE_AUTHOR("Alex Hung");
@@ -73,6 +74,24 @@ static const struct key_entry intel_array_keymap[] = { · 42 unmodified lines
7374 { KE_END },
7475 };
7576
77+static const struct dmi_system_id button_array_table[] = {
78+ {
79+ .ident = "Wacom MobileStudio Pro 13",
80+ .matches = {
81+ DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
82+ DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 13"),
83+ },
84+ },
85+ {
86+ .ident = "Wacom MobileStudio Pro 16",
87+ .matches = {
88+ DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
89+ DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 16"),
90+ },
91+ },
92+ { }
93+};
94+
7695 struct intel_hid_priv {
7796 struct input_dev *input_dev;
7897 struct input_dev *array;
@@ -263,10 +282,27 @@ wakeup: · 184 unmodified lines
263282 ev_index);
264283 }
265284
285+static bool button_array_present(struct platform_device *device)
286+{
287+ acpi_handle handle = ACPI_HANDLE(&device->dev);
288+ unsigned long long event_cap;
289+ acpi_status status;
290+ bool supported = false;
291+
292+ status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap);
293+ if (ACPI_SUCCESS(status) && (event_cap & 0x20000))
294+ supported = true;
295+
296+ if (dmi_check_system(button_array_table))
297+ supported = true;
298+
299+ return supported;
300+}
301+
266302 static int intel_hid_probe(struct platform_device *device)
267303 {
268304 acpi_handle handle = ACPI_HANDLE(&device->dev);
269− unsigned long long event_cap, mode;
305+ unsigned long long mode;
270306 struct intel_hid_priv *priv;
271307 acpi_status status;
272308 int err;
@@ -299,8 +335,7 @@ static int intel_hid_probe(struct platform_device *device) · 26 unmodified lines
299335 }
300336
301337 /* Setup 5 button array */
302− status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap);
303− if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) {
338+ if (button_array_present(device)) {
304339 dev_info(&device->dev, "platform supports 5 button array\n");
305340 err = intel_button_array_input_setup(device);
306341 if (err)
drivers/platform/x86/intel-vbtn.c+47−18
@@ -1,30 +1,21 @@
1+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * Intel Virtual Button driver for Windows 8.1+
34 *
45 * Copyright (C) 2016 AceLan Kao <acelan.kao@canonical.com>
56 * Copyright (C) 2016 Alex Hung <alex.hung@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; either version 2 of the License, or
10− * (at your option) any later version.
11− *
12− * This program is distributed in the hope that it will be useful,
13− * but WITHOUT ANY WARRANTY; without even the implied warranty of
14− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15− * GNU General Public License for more details.
16− *
177 */
188
9+#include <linux/acpi.h>
10+#include <linux/input.h>
11+#include <linux/input/sparse-keymap.h>
1912 #include <linux/kernel.h>
2013 #include <linux/module.h>
21−#include <linux/init.h>
22−#include <linux/input.h>
2314 #include <linux/platform_device.h>
24−#include <linux/input/sparse-keymap.h>
25−#include <linux/acpi.h>
2615 #include <linux/suspend.h>
27−#include <acpi/acpi_bus.h>
16+
17+/* When NOT in tablet mode, VGBS returns with the flag 0x40 */
18+#define TABLET_MODE_FLAG 0x40
2819
2920 MODULE_LICENSE("GPL");
3021 MODULE_AUTHOR("AceLan Kao");
@@ -38,10 +29,16 @@ static const struct acpi_device_id intel_vbtn_ids[] = { · 7 unmodified lines
3829 static const struct key_entry intel_vbtn_keymap[] = {
3930 { KE_KEY, 0xC0, { KEY_POWER } }, /* power key press */
4031 { KE_IGNORE, 0xC1, { KEY_POWER } }, /* power key release */
32+ { KE_KEY, 0xC2, { KEY_LEFTMETA } }, /* 'Windows' key press */
33+ { KE_KEY, 0xC3, { KEY_LEFTMETA } }, /* 'Windows' key release */
4134 { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */
4235 { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */
4336 { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */
4437 { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */
38+ { KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key press */
39+ { KE_KEY, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key release */
40+ { KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */
41+ { KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */
4542 { KE_END },
4643 };
4744
@@ -74,20 +71,35 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) · 26 unmodified lines
7471 {
7572 struct platform_device *device = context;
7673 struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
74+ unsigned int val = !(event & 1); /* Even=press, Odd=release */
75+ const struct key_entry *ke_rel;
76+ bool autorelease;
7777
7878 if (priv->wakeup_mode) {
7979 if (sparse_keymap_entry_from_scancode(priv->input_dev, event)) {
8080 pm_wakeup_hard_event(&device->dev);
8181 return;
8282 }
83− } else if (sparse_keymap_report_event(priv->input_dev, event, 1, true)) {
84− return;
83+ goto out_unknown;
8584 }
85+
86+ /*
87+ * Even press events are autorelease if there is no corresponding odd
88+ * release event, or if the odd event is KE_IGNORE.
89+ */
90+ ke_rel = sparse_keymap_entry_from_scancode(priv->input_dev, event | 1);
91+ autorelease = val && (!ke_rel || ke_rel->type == KE_IGNORE);
92+
93+ if (sparse_keymap_report_event(priv->input_dev, event, val, autorelease))
94+ return;
95+
96+out_unknown:
8697 dev_dbg(&device->dev, "unknown event index 0x%x\n", event);
8798 }
8899
89100 static int intel_vbtn_probe(struct platform_device *device)
90101 {
102+ struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL };
91103 acpi_handle handle = ACPI_HANDLE(&device->dev);
92104 struct intel_vbtn_priv *priv;
93105 acpi_status status;
@@ -110,6 +122,23 @@ static int intel_vbtn_probe(struct platform_device *device) · 16 unmodified lines
110122 return err;
111123 }
112124
125+ /*
126+ * VGBS being present and returning something means we have
127+ * a tablet mode switch.
128+ */
129+ status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output);
130+ if (ACPI_SUCCESS(status)) {
131+ union acpi_object *obj = vgbs_output.pointer;
132+
133+ if (obj && obj->type == ACPI_TYPE_INTEGER) {
134+ int m = !(obj->integer.value & TABLET_MODE_FLAG);
135+
136+ input_report_switch(priv->input_dev, SW_TABLET_MODE, m);
137+ }
138+ }
139+
140+ kfree(vgbs_output.pointer);
141+
113142 status = acpi_install_notify_handler(handle,
114143 ACPI_DEVICE_NOTIFY,
115144 notify_handler,
drivers/platform/x86/intel_chtdc_ti_pwrbtn.c+93−0
@@ -0,0 +1,93 @@
1+/*
2+ * Power-button driver for Dollar Cove TI PMIC
3+ * Copyright (C) 2014 Intel Corp
4+ * Copyright (c) 2017 Takashi Iwai <tiwai@suse.de>
5+ */
6+
7+#include <linux/input.h>
8+#include <linux/interrupt.h>
9+#include <linux/device.h>
10+#include <linux/mfd/intel_soc_pmic.h>
11+#include <linux/module.h>
12+#include <linux/platform_device.h>
13+#include <linux/pm_wakeirq.h>
14+#include <linux/slab.h>
15+
16+#define CHTDC_TI_SIRQ_REG 0x3
17+#define SIRQ_PWRBTN_REL BIT(0)
18+
19+static irqreturn_t chtdc_ti_pwrbtn_interrupt(int irq, void *dev_id)
20+{
21+ struct input_dev *input = dev_id;
22+ struct device *dev = input->dev.parent;
23+ struct regmap *regmap = dev_get_drvdata(dev);
24+ int state;
25+
26+ if (!regmap_read(regmap, CHTDC_TI_SIRQ_REG, &state)) {
27+ dev_dbg(dev, "SIRQ_REG=0x%x\n", state);
28+ input_report_key(input, KEY_POWER, !(state & SIRQ_PWRBTN_REL));
29+ input_sync(input);
30+ }
31+
32+ return IRQ_HANDLED;
33+}
34+
35+static int chtdc_ti_pwrbtn_probe(struct platform_device *pdev)
36+{
37+ struct device *dev = &pdev->dev;
38+ struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
39+ struct input_dev *input;
40+ int irq, err;
41+
42+ irq = platform_get_irq(pdev, 0);
43+ if (irq < 0)
44+ return irq;
45+ input = devm_input_allocate_device(dev);
46+ if (!input)
47+ return -ENOMEM;
48+ input->name = pdev->name;
49+ input->phys = "power-button/input0";
50+ input->id.bustype = BUS_HOST;
51+ input_set_capability(input, EV_KEY, KEY_POWER);
52+ err = input_register_device(input);
53+ if (err)
54+ return err;
55+
56+ dev_set_drvdata(dev, pmic->regmap);
57+
58+ err = devm_request_threaded_irq(dev, irq, NULL,
59+ chtdc_ti_pwrbtn_interrupt,
60+ 0, KBUILD_MODNAME, input);
61+ if (err)
62+ return err;
63+
64+ device_init_wakeup(dev, true);
65+ dev_pm_set_wake_irq(dev, irq);
66+ return 0;
67+}
68+
69+static int chtdc_ti_pwrbtn_remove(struct platform_device *pdev)
70+{
71+ dev_pm_clear_wake_irq(&pdev->dev);
72+ device_init_wakeup(&pdev->dev, false);
73+ return 0;
74+}
75+
76+static const struct platform_device_id chtdc_ti_pwrbtn_id_table[] = {
77+ { .name = "chtdc_ti_pwrbtn" },
78+ {},
79+};
80+MODULE_DEVICE_TABLE(platform, chtdc_ti_pwrbtn_id_table);
81+
82+static struct platform_driver chtdc_ti_pwrbtn_driver = {
83+ .driver = {
84+ .name = KBUILD_MODNAME,
85+ },
86+ .probe = chtdc_ti_pwrbtn_probe,
87+ .remove = chtdc_ti_pwrbtn_remove,
88+ .id_table = chtdc_ti_pwrbtn_id_table,
89+};
90+module_platform_driver(chtdc_ti_pwrbtn_driver);
91+
92+MODULE_DESCRIPTION("Power-button driver for Dollar Cove TI PMIC");
93+MODULE_LICENSE("GPL v2");
drivers/platform/x86/intel_int0002_vgpio.c+1−1
@@ -180,7 +180,7 @@ static int int0002_probe(struct platform_device *pdev) · 179 unmodified lines
180180 * to gpiochip_set_chained_irqchip, because the irq is shared.
181181 */
182182 ret = devm_request_irq(dev, irq, int0002_irq,
183− IRQF_SHARED | IRQF_NO_THREAD, "INT0002", chip);
183+ IRQF_SHARED, "INT0002", chip);
184184 if (ret) {
185185 dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret);
186186 return ret;
drivers/platform/x86/intel_pmc_core.c+161−119
@@ -18,20 +18,24 @@ · 17 unmodified lines
1818 *
1919 */
2020
21+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22+
23+#include <linux/acpi.h>
2124 #include <linux/debugfs.h>
2225 #include <linux/delay.h>
23−#include <linux/device.h>
24−#include <linux/init.h>
2526 #include <linux/io.h>
27+#include <linux/module.h>
2628 #include <linux/pci.h>
2729 #include <linux/uaccess.h>
2830
2931 #include <asm/cpu_device_id.h>
3032 #include <asm/intel-family.h>
31−#include <asm/pmc_core.h>
3233
3334 #include "intel_pmc_core.h"
3435
36+#define ICPU(model, data) \
37+ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (kernel_ulong_t)data }
38+
3539 static struct pmc_dev pmc;
3640
3741 static const struct pmc_bit_map spt_pll_map[] = {
@@ -119,10 +123,88 @@ static const struct pmc_reg_map spt_reg_map = { · 81 unmodified lines
119123 .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT,
120124 };
121125
122−static const struct pci_device_id pmc_pci_ids[] = {
123− { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID),
124− (kernel_ulong_t)&spt_reg_map },
125− { 0, },
126+/* Cannonlake: PGD PFET Enable Ack Status Register(s) bitmap */
127+static const struct pmc_bit_map cnp_pfear_map[] = {
128+ {"PMC", BIT(0)},
129+ {"OPI-DMI", BIT(1)},
130+ {"SPI/eSPI", BIT(2)},
131+ {"XHCI", BIT(3)},
132+ {"SPA", BIT(4)},
133+ {"SPB", BIT(5)},
134+ {"SPC", BIT(6)},
135+ {"GBE", BIT(7)},
136+
137+ {"SATA", BIT(0)},
138+ {"HDA_PGD0", BIT(1)},
139+ {"HDA_PGD1", BIT(2)},
140+ {"HDA_PGD2", BIT(3)},
141+ {"HDA_PGD3", BIT(4)},
142+ {"SPD", BIT(5)},
143+ {"LPSS", BIT(6)},
144+ {"LPC", BIT(7)},
145+
146+ {"SMB", BIT(0)},
147+ {"ISH", BIT(1)},
148+ {"P2SB", BIT(2)},
149+ {"NPK_VNN", BIT(3)},
150+ {"SDX", BIT(4)},
151+ {"SPE", BIT(5)},
152+ {"Fuse", BIT(6)},
153+ {"Res_23", BIT(7)},
154+
155+ {"CSME_FSC", BIT(0)},
156+ {"USB3_OTG", BIT(1)},
157+ {"EXI", BIT(2)},
158+ {"CSE", BIT(3)},
159+ {"csme_kvm", BIT(4)},
160+ {"csme_pmt", BIT(5)},
161+ {"csme_clink", BIT(6)},
162+ {"csme_ptio", BIT(7)},
163+
164+ {"csme_usbr", BIT(0)},
165+ {"csme_susram", BIT(1)},
166+ {"csme_smt1", BIT(2)},
167+ {"CSME_SMT4", BIT(3)},
168+ {"csme_sms2", BIT(4)},
169+ {"csme_sms1", BIT(5)},
170+ {"csme_rtc", BIT(6)},
171+ {"csme_psf", BIT(7)},
172+
173+ {"SBR0", BIT(0)},
174+ {"SBR1", BIT(1)},
175+ {"SBR2", BIT(2)},
176+ {"SBR3", BIT(3)},
177+ {"SBR4", BIT(4)},
178+ {"SBR5", BIT(5)},
179+ {"CSME_PECI", BIT(6)},
180+ {"PSF1", BIT(7)},
181+
182+ {"PSF2", BIT(0)},
183+ {"PSF3", BIT(1)},
184+ {"PSF4", BIT(2)},
185+ {"CNVI", BIT(3)},
186+ {"UFS0", BIT(4)},
187+ {"EMMC", BIT(5)},
188+ {"Res_6", BIT(6)},
189+ {"SBR6", BIT(7)},
190+
191+ {"SBR7", BIT(0)},
192+ {"NPK_AON", BIT(1)},
193+ {"HDA_PGD4", BIT(2)},
194+ {"HDA_PGD5", BIT(3)},
195+ {"HDA_PGD6", BIT(4)},
196+ {}
197+};
198+
199+static const struct pmc_reg_map cnp_reg_map = {
200+ .pfear_sts = cnp_pfear_map,
201+ .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
202+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
203+ .regmap_length = CNP_PMC_MMIO_REG_LEN,
204+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
205+ .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
206+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
207+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
126208 };
127209
128210 static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset)
@@ -146,37 +228,6 @@ static inline u32 pmc_core_adjust_slp_s0_step(u32 value) · 17 unmodified lines
146228 return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP;
147229 }
148230
149−/**
150− * intel_pmc_slp_s0_counter_read() - Read SLP_S0 residency.
151− * @data: Out param that contains current SLP_S0 count.
152− *
153− * This API currently supports Intel Skylake SoC and Sunrise
154− * Point Platform Controller Hub. Future platform support
155− * should be added for platforms that support low power modes
156− * beyond Package C10 state.
157− *
158− * SLP_S0_RESIDENCY counter counts in 100 us granularity per
159− * step hence function populates the multiplied value in out
160− * parameter @data.
161− *
162− * Return: an error code or 0 on success.
163− */
164−int intel_pmc_slp_s0_counter_read(u32 *data)
165−{
166− struct pmc_dev *pmcdev = &pmc;
167− const struct pmc_reg_map *map = pmcdev->map;
168− u32 value;
169−
170− if (!pmcdev->has_slp_s0_res)
171− return -EACCES;
172−
173− value = pmc_core_reg_read(pmcdev, map->slp_s0_offset);
174− *data = pmc_core_adjust_slp_s0_step(value);
175−
176− return 0;
177−}
178−EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read);
179−
180231 static int pmc_core_dev_state_get(void *data, u64 *val)
181232 {
182233 struct pmc_dev *pmcdev = data;
@@ -437,47 +488,33 @@ static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) · 254 unmodified lines
437488
438489 static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
439490 {
440− struct dentry *dir, *file;
491+ struct dentry *dir;
441492
442493 dir = debugfs_create_dir("pmc_core", NULL);
443494 if (!dir)
444495 return -ENOMEM;
445496
446497 pmcdev->dbgfs_dir = dir;
447− file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO,
448− dir, pmcdev, &pmc_core_dev_state);
449− if (!file)
450− goto err;
451−
452− file = debugfs_create_file("pch_ip_power_gating_status",
453− S_IFREG | S_IRUGO, dir, pmcdev,
454− &pmc_core_ppfear_ops);
455− if (!file)
456− goto err;
457−
458− file = debugfs_create_file("mphy_core_lanes_power_gating_status",
459− S_IFREG | S_IRUGO, dir, pmcdev,
460− &pmc_core_mphy_pg_ops);
461− if (!file)
462− goto err;
463−
464− file = debugfs_create_file("pll_status",
465− S_IFREG | S_IRUGO, dir, pmcdev,
466− &pmc_core_pll_ops);
467− if (!file)
468− goto err;
469−
470− file = debugfs_create_file("ltr_ignore",
471− S_IFREG | S_IRUGO, dir, pmcdev,
472− &pmc_core_ltr_ignore_ops);
473−
474− if (!file)
475− goto err;
498+
499+ debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev,
500+ &pmc_core_dev_state);
501+
502+ debugfs_create_file("pch_ip_power_gating_status", 0444, dir, pmcdev,
503+ &pmc_core_ppfear_ops);
504+
505+ debugfs_create_file("ltr_ignore", 0644, dir, pmcdev,
506+ &pmc_core_ltr_ignore_ops);
507+
508+ if (pmcdev->map->pll_sts)
509+ debugfs_create_file("pll_status", 0444, dir, pmcdev,
510+ &pmc_core_pll_ops);
511+
512+ if (pmcdev->map->mphy_sts)
513+ debugfs_create_file("mphy_core_lanes_power_gating_status",
514+ 0444, dir, pmcdev,
515+ &pmc_core_mphy_pg_ops);
476516
477517 return 0;
478−err:
479− pmc_core_dbgfs_unregister(pmcdev);
480− return -ENODEV;
481518 }
482519 #else
483520 static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
@@ -491,71 +528,76 @@ static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) · 7 unmodified lines
491528 #endif /* CONFIG_DEBUG_FS */
492529
493530 static const struct x86_cpu_id intel_pmc_core_ids[] = {
494− { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT,
495− (kernel_ulong_t)NULL},
496− { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT,
497− (kernel_ulong_t)NULL},
498− { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_MOBILE, X86_FEATURE_MWAIT,
499− (kernel_ulong_t)NULL},
500− { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_DESKTOP, X86_FEATURE_MWAIT,
501− (kernel_ulong_t)NULL},
531+ ICPU(INTEL_FAM6_SKYLAKE_MOBILE, &spt_reg_map),
532+ ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, &spt_reg_map),
533+ ICPU(INTEL_FAM6_KABYLAKE_MOBILE, &spt_reg_map),
534+ ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, &spt_reg_map),
535+ ICPU(INTEL_FAM6_CANNONLAKE_MOBILE, &cnp_reg_map),
502536 {}
503537 };
504538
505−static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id)
539+MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids);
540+
541+static const struct pci_device_id pmc_pci_ids[] = {
542+ { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), 0},
543+ { 0, },
544+};
545+
546+static int __init pmc_core_probe(void)
506547 {
507− struct device *ptr_dev = &dev->dev;
508548 struct pmc_dev *pmcdev = &pmc;
509549 const struct x86_cpu_id *cpu_id;
510− const struct pmc_reg_map *map = (struct pmc_reg_map *)id->driver_data;
550+ u64 slp_s0_addr;
511551 int err;
512552
513553 cpu_id = x86_match_cpu(intel_pmc_core_ids);
514− if (!cpu_id) {
515− dev_dbg(&dev->dev, "PMC Core: cpuid mismatch.\n");
516− return -EINVAL;
517− }
518−
519− err = pcim_enable_device(dev);
520− if (err < 0) {
521− dev_dbg(&dev->dev, "PMC Core: failed to enable Power Management Controller.\n");
522− return err;
523− }
524−
525− err = pci_read_config_dword(dev,
526− SPT_PMC_BASE_ADDR_OFFSET,
527− &pmcdev->base_addr);
528− if (err < 0) {
529− dev_dbg(&dev->dev, "PMC Core: failed to read PCI config space.\n");
530− return err;
531− }
532− pmcdev->base_addr &= PMC_BASE_ADDR_MASK;
533− dev_dbg(&dev->dev, "PMC Core: PWRMBASE is %#x\n", pmcdev->base_addr);
534−
535− pmcdev->regbase = devm_ioremap_nocache(ptr_dev,
536− pmcdev->base_addr,
537− SPT_PMC_MMIO_REG_LEN);
538− if (!pmcdev->regbase) {
539− dev_dbg(&dev->dev, "PMC Core: ioremap failed.\n");
554+ if (!cpu_id)
555+ return -ENODEV;
556+
557+ pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data;
558+
559+ /*
560+ * Coffeelake has CPU ID of Kabylake and Cannonlake PCH. So here
561+ * Sunrisepoint PCH regmap can't be used. Use Cannonlake PCH regmap
562+ * in this case.
563+ */
564+ if (!pci_dev_present(pmc_pci_ids))
565+ pmcdev->map = &cnp_reg_map;
566+
567+ if (lpit_read_residency_count_address(&slp_s0_addr))
568+ pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT;
569+ else
570+ pmcdev->base_addr = slp_s0_addr - pmcdev->map->slp_s0_offset;
571+
572+ pmcdev->regbase = ioremap(pmcdev->base_addr,
573+ pmcdev->map->regmap_length);
574+ if (!pmcdev->regbase)
540575 return -ENOMEM;
541− }
542576
543577 mutex_init(&pmcdev->lock);
544− pmcdev->map = map;
545578 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
546579
547580 err = pmc_core_dbgfs_register(pmcdev);
548− if (err < 0)
549− dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n");
581+ if (err < 0) {
582+ pr_warn(" debugfs register failed.\n");
583+ iounmap(pmcdev->regbase);
584+ return err;
585+ }
550586
551− pmc.has_slp_s0_res = true;
587+ pr_info(" initialized\n");
552588 return 0;
553589 }
590+module_init(pmc_core_probe)
554591
555−static struct pci_driver intel_pmc_core_driver = {
556− .name = "intel_pmc_core",
557− .id_table = pmc_pci_ids,
558− .probe = pmc_core_probe,
559−};
592+static void __exit pmc_core_remove(void)
593+{
594+ struct pmc_dev *pmcdev = &pmc;
595+
596+ pmc_core_dbgfs_unregister(pmcdev);
597+ mutex_destroy(&pmcdev->lock);
598+ iounmap(pmcdev->regbase);
599+}
600+module_exit(pmc_core_remove)
560601
561−builtin_pci_driver(intel_pmc_core_driver);
602+MODULE_LICENSE("GPL v2");
603+MODULE_DESCRIPTION("Intel PMC Core Driver");
drivers/platform/x86/intel_pmc_core.h+20−9
@@ -21,9 +21,10 @@ · 20 unmodified lines
2121 #ifndef PMC_CORE_H
2222 #define PMC_CORE_H
2323
24+#define PMC_BASE_ADDR_DEFAULT 0xFE000000
25+
2426 /* Sunrise Point Power Management Controller PCI Device ID */
2527 #define SPT_PMC_PCI_DEVICE_ID 0x9d21
26−
2728 #define SPT_PMC_BASE_ADDR_OFFSET 0x48
2829 #define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c
2930 #define SPT_PMC_PM_CFG_OFFSET 0x18
@@ -122,6 +123,17 @@ enum ppfear_regs { · 92 unmodified lines
122123 #define SPT_PMC_BIT_MPHY_CMN_LANE2 BIT(2)
123124 #define SPT_PMC_BIT_MPHY_CMN_LANE3 BIT(3)
124125
126+/* Cannonlake Power Management Controller register offsets */
127+#define CNP_PMC_SLP_S0_RES_COUNTER_OFFSET 0x193C
128+#define CNP_PMC_LTR_IGNORE_OFFSET 0x1B0C
129+#define CNP_PMC_PM_CFG_OFFSET 0x1818
130+/* Cannonlake: PGD PFET Enable Ack Status Register(s) start */
131+#define CNP_PMC_HOST_PPFEAR0A 0x1D90
132+
133+#define CNP_PMC_MMIO_REG_LEN 0x2000
134+#define CNP_PPFEAR_NUM_ENTRIES 8
135+#define CNP_PMC_READ_DISABLE_BIT 22
136+
125137 struct pmc_bit_map {
126138 const char *name;
127139 u32 bit_mask;
@@ -135,7 +147,6 @@ struct pmc_bit_map { · 7 unmodified lines
135147 * @pll_sts: Maps name of PLL to corresponding bit status
136148 * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency
137149 * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit
138− * @base_address: Base address of PWRMBASE defined in BIOS writer guide
139150 * @regmap_length: Length of memory to map from PWRMBASE address to access
140151 * @ppfear0_offset: PWRMBASE offset to to read PPFEAR*
141152 * @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from
@@ -152,7 +163,6 @@ struct pmc_reg_map { · 10 unmodified lines
152163 const struct pmc_bit_map *pll_sts;
153164 const u32 slp_s0_offset;
154165 const u32 ltr_ignore_offset;
155− const u32 base_address;
156166 const int regmap_length;
157167 const u32 ppfear0_offset;
158168 const int ppfear_buckets;
@@ -162,12 +172,14 @@ struct pmc_reg_map { · 3 unmodified lines
162172
163173 /**
164174 * struct pmc_dev - pmc device structure
165− * @base_addr: comtains pmc base address
175+ * @base_addr: contains pmc base address
166176 * @regbase: pointer to io-remapped memory location
167− * @dbgfs_dir: path to debug fs interface
168− * @feature_available: flag to indicate whether
169− * the feature is available
170− * on a particular platform or not.
177+ * @map: pointer to pmc_reg_map struct that contains platform
178+ * specific attributes
179+ * @dbgfs_dir: path to debugfs interface
180+ * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
181+ * used to read MPHY PG and PLL status are available
182+ * @mutex_lock: mutex to complete one transcation
171183 *
172184 * pmc_dev contains info about power management controller device.
173185 */
@@ -178,7 +190,6 @@ struct pmc_dev { · 4 unmodified lines
178190 #if IS_ENABLED(CONFIG_DEBUG_FS)
179191 struct dentry *dbgfs_dir;
180192 #endif /* CONFIG_DEBUG_FS */
181− bool has_slp_s0_res;
182193 int pmc_xram_read_bit;
183194 struct mutex lock; /* generic mutex lock for PMC Core */
184195 };
drivers/platform/x86/intel_pmc_ipc.c+31−2
@@ -215,11 +215,11 @@ static inline int is_gcr_valid(u32 offset) · 214 unmodified lines
215215 }
216216
217217 /**
218− * intel_pmc_gcr_read() - Read PMC GCR register
218+ * intel_pmc_gcr_read() - Read a 32-bit PMC GCR register
219219 * @offset: offset of GCR register from GCR address base
220220 * @data: data pointer for storing the register output
221221 *
222− * Reads the PMC GCR register of given offset.
222+ * Reads the 32-bit PMC GCR register at given offset.
223223 *
224224 * Return: negative value on error or 0 on success.
225225 */
@@ -243,6 +243,35 @@ int intel_pmc_gcr_read(u32 offset, u32 *data) · 17 unmodified lines
243243 }
244244 EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
245245
246+/**
247+ * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register
248+ * @offset: offset of GCR register from GCR address base
249+ * @data: data pointer for storing the register output
250+ *
251+ * Reads the 64-bit PMC GCR register at given offset.
252+ *
253+ * Return: negative value on error or 0 on success.
254+ */
255+int intel_pmc_gcr_read64(u32 offset, u64 *data)
256+{
257+ int ret;
258+
259+ spin_lock(&ipcdev.gcr_lock);
260+
261+ ret = is_gcr_valid(offset);
262+ if (ret < 0) {
263+ spin_unlock(&ipcdev.gcr_lock);
264+ return ret;
265+ }
266+
267+ *data = readq(ipcdev.gcr_mem_base + offset);
268+
269+ spin_unlock(&ipcdev.gcr_lock);
270+
271+ return 0;
272+}
273+EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64);
274+
246275 /**
247276 * intel_pmc_gcr_write() - Write PMC GCR register
248277 * @offset: offset of GCR register from GCR address base
drivers/platform/x86/intel_telemetry_debugfs.c+35−48
@@ -23,7 +23,6 @@ · 22 unmodified lines
2323 */
2424 #include <linux/debugfs.h>
2525 #include <linux/device.h>
26−#include <linux/io.h>
2726 #include <linux/module.h>
2827 #include <linux/pci.h>
2928 #include <linux/seq_file.h>
@@ -32,11 +31,10 @@ · 2 unmodified lines
3231 #include <asm/cpu_device_id.h>
3332 #include <asm/intel-family.h>
3433 #include <asm/intel_pmc_ipc.h>
35−#include <asm/intel_punit_ipc.h>
3634 #include <asm/intel_telemetry.h>
3735
38−#define DRIVER_NAME "telemetry_soc_debugfs"
39−#define DRIVER_VERSION "1.0.0"
36+#define DRIVER_NAME "telemetry_soc_debugfs"
37+#define DRIVER_VERSION "1.0.0"
4038
4139 /* ApolloLake SoC Event-IDs */
4240 #define TELEM_APL_PSS_PSTATES_ID 0x2802
@@ -98,10 +96,6 @@ static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp; · 55 unmodified lines
9896 static u64 suspend_shlw_res_temp, suspend_deep_res_temp;
9997
10098 struct telemetry_susp_stats {
101− u32 shlw_swake_ctr;
102− u32 deep_swake_ctr;
103− u64 shlw_swake_res;
104− u64 deep_swake_res;
10599 u32 shlw_ctr;
106100 u32 deep_ctr;
107101 u64 shlw_res;
@@ -250,7 +244,6 @@ static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = { · 142 unmodified lines
250244 {"PRTC", 25},
251245 };
252246
253−
254247 struct telemetry_debugfs_conf {
255248 struct telemetry_susp_stats suspend_stats;
256249 struct dentry *telemetry_dbg_dir;
@@ -385,7 +378,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused) · 128 unmodified lines
385378 TELEM_APL_MASK_PCS_STATE;
386379 }
387380
388−
389381 TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id,
390382 conf->pss_idle_evts - 1,
391383 pss_idle, evtlog[index].telem_evtlog,
@@ -405,7 +397,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused) · 13 unmodified lines
405397 conf->pcs_s0ix_blkd_data,
406398 TELEM_MASK_BYTE);
407399
408−
409400 TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id,
410401 conf->pss_wakeup_evts,
411402 pss_s0ix_wakeup,
@@ -498,7 +489,6 @@ static const struct file_operations telem_pss_ops = { · 86 unmodified lines
498489 .release = single_release,
499490 };
500491
501−
502492 static int telem_ioss_states_show(struct seq_file *s, void *unused)
503493 {
504494 struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
@@ -598,19 +588,15 @@ static int telem_soc_states_show(struct seq_file *s, void *unused) · 93 unmodified lines
598588
599589 seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n",
600590 s0ix_shlw_ctr -
601− conf->suspend_stats.shlw_ctr -
602− conf->suspend_stats.shlw_swake_ctr,
591+ conf->suspend_stats.shlw_ctr,
603592 (u64)((s0ix_shlw_res -
604− conf->suspend_stats.shlw_res -
605− conf->suspend_stats.shlw_swake_res)*10/192));
593+ conf->suspend_stats.shlw_res)*10/192));
606594
607595 seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n",
608596 s0ix_deep_ctr -
609− conf->suspend_stats.deep_ctr -
610− conf->suspend_stats.deep_swake_ctr,
597+ conf->suspend_stats.deep_ctr,
611598 (u64)((s0ix_deep_res -
612− conf->suspend_stats.deep_res -
613− conf->suspend_stats.deep_swake_res)*10/192));
599+ conf->suspend_stats.deep_res)*10/192));
614600
615601 seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n",
616602 conf->suspend_stats.shlw_ctr,
@@ -620,14 +606,8 @@ static int telem_soc_states_show(struct seq_file *s, void *unused) · 3 unmodified lines
620606 conf->suspend_stats.deep_ctr,
621607 (u64)(conf->suspend_stats.deep_res*10)/192);
622608
623− seq_printf(s, "Suspend(With Shallow-Wakes)\t %10u\t %10llu\n",
624− conf->suspend_stats.shlw_swake_ctr +
625− conf->suspend_stats.deep_swake_ctr,
626− (u64)((conf->suspend_stats.shlw_swake_res +
627− conf->suspend_stats.deep_swake_res)*10/192));
628−
629− seq_printf(s, "S0IX+Suspend Total\t\t %10u\t %10llu\n", s0ix_total_ctr,
630− (u64)(s0ix_total_res*10/192));
609+ seq_printf(s, "TOTAL S0IX\t\t\t %10u\t %10llu\n", s0ix_total_ctr,
610+ (u64)(s0ix_total_res*10/192));
631611 seq_puts(s, "\n-------------------------------------------------\n");
632612 seq_puts(s, "\t\tDEVICE STATES\n");
633613 seq_puts(s, "-------------------------------------------------\n");
@@ -772,7 +752,6 @@ static const struct file_operations telem_pss_trc_verb_ops = { · 138 unmodified lines
772752 .release = single_release,
773753 };
774754
775−
776755 static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused)
777756 {
778757 u32 verbosity;
@@ -890,28 +869,45 @@ static int pm_suspend_exit_cb(void) · 111 unmodified lines
890869 goto out;
891870 }
892871
872+ /*
873+ * Due to some design limitations in the firmware, sometimes the
874+ * counters do not get updated by the time we reach here. As a
875+ * workaround, we try to see if this was a genuine case of sleep
876+ * failure or not by cross-checking from PMC GCR registers directly.
877+ */
878+ if (suspend_shlw_ctr_exit == suspend_shlw_ctr_temp &&
879+ suspend_deep_ctr_exit == suspend_deep_ctr_temp) {
880+ ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_SHLW_S0IX_REG,
881+ &suspend_shlw_res_exit);
882+ if (ret < 0)
883+ goto out;
884+
885+ ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_DEEP_S0IX_REG,
886+ &suspend_deep_res_exit);
887+ if (ret < 0)
888+ goto out;
889+
890+ if (suspend_shlw_res_exit > suspend_shlw_res_temp)
891+ suspend_shlw_ctr_exit++;
892+
893+ if (suspend_deep_res_exit > suspend_deep_res_temp)
894+ suspend_deep_ctr_exit++;
895+ }
896+
893897 suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp;
894898 suspend_deep_ctr_exit -= suspend_deep_ctr_temp;
895899 suspend_shlw_res_exit -= suspend_shlw_res_temp;
896900 suspend_deep_res_exit -= suspend_deep_res_temp;
897901
898− if (suspend_shlw_ctr_exit == 1) {
902+ if (suspend_shlw_ctr_exit != 0) {
899903 conf->suspend_stats.shlw_ctr +=
900904 suspend_shlw_ctr_exit;
901905
902906 conf->suspend_stats.shlw_res +=
903907 suspend_shlw_res_exit;
904908 }
905− /* Shallow Wakes Case */
906− else if (suspend_shlw_ctr_exit > 1) {
907− conf->suspend_stats.shlw_swake_ctr +=
908− suspend_shlw_ctr_exit;
909909
910− conf->suspend_stats.shlw_swake_res +=
911− suspend_shlw_res_exit;
912− }
913−
914− if (suspend_deep_ctr_exit == 1) {
910+ if (suspend_deep_ctr_exit != 0) {
915911 conf->suspend_stats.deep_ctr +=
916912 suspend_deep_ctr_exit;
917913
@@ -919,15 +915,6 @@ static int pm_suspend_exit_cb(void) · 1 unmodified line
919915 suspend_deep_res_exit;
920916 }
921917
922− /* Shallow Wakes Case */
923− else if (suspend_deep_ctr_exit > 1) {
924− conf->suspend_stats.deep_swake_ctr +=
925− suspend_deep_ctr_exit;
926−
927− conf->suspend_stats.deep_swake_res +=
928− suspend_deep_res_exit;
929− }
930−
931918 out:
932919 suspend_prep_ok = 0;
933920 return NOTIFY_OK;
drivers/platform/x86/mlx-platform.c+267−57
@@ -35,20 +35,31 @@ · 34 unmodified lines
3535 #include <linux/dmi.h>
3636 #include <linux/i2c.h>
3737 #include <linux/i2c-mux.h>
38+#include <linux/io.h>
3839 #include <linux/module.h>
3940 #include <linux/platform_device.h>
4041 #include <linux/platform_data/i2c-mux-reg.h>
41−#include <linux/platform_data/mlxcpld-hotplug.h>
42+#include <linux/platform_data/mlxreg.h>
43+#include <linux/regmap.h>
4244
4345 #define MLX_PLAT_DEVICE_NAME "mlxplat"
4446
4547 /* LPC bus IO offsets */
4648 #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
4749 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
48−#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a
49−#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558
50−#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564
51−#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588
50+#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
51+#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b
52+#define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40
53+#define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41
54+#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
55+#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59
56+#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a
57+#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
58+#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65
59+#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66
60+#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
61+#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
62+#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a
5263 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
5364 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
5465 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
@@ -81,6 +92,7 @@ · 26 unmodified lines
8192 /* mlxplat_priv - platform private data
8293 * @pdev_i2c - i2c controller platform device
8394 * @pdev_mux - array of mux platform devices
95+ * @pdev_hotplug - hotplug platform devices
8496 */
8597 struct mlxplat_priv {
8698 struct platform_device *pdev_i2c;
@@ -138,86 +150,264 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { · 51 unmodified lines
138150 };
139151
140152 /* Platform hotplug devices */
141−static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = {
153+static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
142154 {
143− .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
144− .bus = 10,
155+ I2C_BOARD_INFO("24c02", 0x51),
145156 },
146157 {
147− .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) },
148− .bus = 10,
158+ I2C_BOARD_INFO("24c02", 0x50),
149159 },
150160 };
151161
152−static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = {
162+static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
153163 {
154− .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
155− .bus = 10,
164+ I2C_BOARD_INFO("dps460", 0x59),
156165 },
157166 {
158− .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) },
159− .bus = 10,
167+ I2C_BOARD_INFO("dps460", 0x58),
160168 },
161169 };
162170
163−static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = {
171+static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
164172 {
165− .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
166− .bus = 11,
173+ I2C_BOARD_INFO("24c32", 0x50),
167174 },
168175 {
169− .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
170− .bus = 12,
176+ I2C_BOARD_INFO("24c32", 0x50),
171177 },
172178 {
173− .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
174− .bus = 13,
179+ I2C_BOARD_INFO("24c32", 0x50),
175180 },
176181 {
177− .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
178− .bus = 14,
182+ I2C_BOARD_INFO("24c32", 0x50),
179183 },
180184 };
181185
182186 /* Platform hotplug default data */
187+static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
188+ {
189+ .label = "psu1",
190+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
191+ .mask = BIT(0),
192+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
193+ .hpdev.nr = 10,
194+ },
195+ {
196+ .label = "psu2",
197+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
198+ .mask = BIT(1),
199+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
200+ .hpdev.nr = 10,
201+ },
202+};
203+
204+static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
205+ {
206+ .label = "pwr1",
207+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
208+ .mask = BIT(0),
209+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
210+ .hpdev.nr = 10,
211+ },
212+ {
213+ .label = "pwr2",
214+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
215+ .mask = BIT(1),
216+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
217+ .hpdev.nr = 10,
218+ },
219+};
220+
221+static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
222+ {
223+ .label = "fan1",
224+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
225+ .mask = BIT(0),
226+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
227+ .hpdev.nr = 11,
228+ },
229+ {
230+ .label = "fan2",
231+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
232+ .mask = BIT(1),
233+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
234+ .hpdev.nr = 12,
235+ },
236+ {
237+ .label = "fan3",
238+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
239+ .mask = BIT(2),
240+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
241+ .hpdev.nr = 13,
242+ },
243+ {
244+ .label = "fan4",
245+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
246+ .mask = BIT(3),
247+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
248+ .hpdev.nr = 14,
249+ },
250+};
251+
252+static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
253+ {
254+ .data = mlxplat_mlxcpld_default_psu_items_data,
255+ .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
256+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
257+ .mask = MLXPLAT_CPLD_PSU_MASK,
258+ .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
259+ .inversed = 1,
260+ .health = false,
261+ },
262+ {
263+ .data = mlxplat_mlxcpld_default_pwr_items_data,
264+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
265+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
266+ .mask = MLXPLAT_CPLD_PWR_MASK,
267+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
268+ .inversed = 0,
269+ .health = false,
270+ },
271+ {
272+ .data = mlxplat_mlxcpld_default_fan_items_data,
273+ .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
274+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
275+ .mask = MLXPLAT_CPLD_FAN_MASK,
276+ .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
277+ .inversed = 1,
278+ .health = false,
279+ },
280+};
281+
183282 static
184−struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = {
185− .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
186− .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
187− .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
188− .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR,
189− .psu_mask = MLXPLAT_CPLD_PSU_MASK,
190− .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
191− .psu = mlxplat_mlxcpld_psu,
192− .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
193− .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
194− .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
195− .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
196− .pwr = mlxplat_mlxcpld_pwr,
197− .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
198− .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR,
199− .fan_mask = MLXPLAT_CPLD_FAN_MASK,
200− .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
201− .fan = mlxplat_mlxcpld_fan,
283+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
284+ .items = mlxplat_mlxcpld_default_items,
285+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
286+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
287+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
202288 };
203289
204290 /* Platform hotplug MSN21xx system family data */
291+static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
292+ {
293+ .data = mlxplat_mlxcpld_default_pwr_items_data,
294+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
295+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
296+ .mask = MLXPLAT_CPLD_PWR_MASK,
297+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
298+ .inversed = 0,
299+ .health = false,
300+ },
301+};
302+
205303 static
206−struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
207− .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
208− .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
209− .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
210− .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
211− .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
212− .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
304+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
305+ .items = mlxplat_mlxcpld_msn21xx_items,
306+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
307+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
308+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
309+};
310+
311+static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
312+{
313+ switch (reg) {
314+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
315+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
316+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
317+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
318+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
319+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
320+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
321+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
322+ return true;
323+ }
324+ return false;
325+}
326+
327+static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
328+{
329+ switch (reg) {
330+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
331+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
332+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
333+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
334+ case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
335+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
336+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
337+ case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
338+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
339+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
340+ case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
341+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
342+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
343+ return true;
344+ }
345+ return false;
346+}
347+
348+static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
349+{
350+ switch (reg) {
351+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
352+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
353+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
354+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
355+ case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
356+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
357+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
358+ case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
359+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
360+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
361+ case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
362+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
363+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
364+ return true;
365+ }
366+ return false;
367+}
368+
369+struct mlxplat_mlxcpld_regmap_context {
370+ void __iomem *base;
371+};
372+
373+static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
374+
375+static int
376+mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
377+{
378+ struct mlxplat_mlxcpld_regmap_context *ctx = context;
379+
380+ *val = ioread8(ctx->base + reg);
381+ return 0;
382+}
383+
384+static int
385+mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
386+{
387+ struct mlxplat_mlxcpld_regmap_context *ctx = context;
388+
389+ iowrite8(val, ctx->base + reg);
390+ return 0;
391+}
392+
393+static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
394+ .reg_bits = 8,
395+ .val_bits = 8,
396+ .max_register = 255,
397+ .cache_type = REGCACHE_FLAT,
398+ .writeable_reg = mlxplat_mlxcpld_writeable_reg,
399+ .readable_reg = mlxplat_mlxcpld_readable_reg,
400+ .volatile_reg = mlxplat_mlxcpld_volatile_reg,
401+ .reg_read = mlxplat_mlxcpld_reg_read,
402+ .reg_write = mlxplat_mlxcpld_reg_write,
213403 };
214404
215405 static struct resource mlxplat_mlxcpld_resources[] = {
216− [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
406+ [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
217407 };
218408
219409 static struct platform_device *mlxplat_dev;
220−static struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
410+static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
221411
222412 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
223413 {
@@ -286,6 +476,8 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { · 62 unmodified lines
286476 { }
287477 };
288478
479+MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
480+
289481 static int __init mlxplat_init(void)
290482 {
291483 struct mlxplat_priv *priv;
@@ -328,8 +520,23 @@ static int __init mlxplat_init(void) · 36 unmodified lines
328520 }
329521 }
330522
523+ mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
524+ mlxplat_lpc_resources[1].start, 1);
525+ if (!mlxplat_mlxcpld_regmap_ctx.base) {
526+ err = -ENOMEM;
527+ goto fail_platform_mux_register;
528+ }
529+
530+ mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
531+ &mlxplat_mlxcpld_regmap_ctx,
532+ &mlxplat_mlxcpld_regmap_config);
533+ if (IS_ERR(mlxplat_hotplug->regmap)) {
534+ err = PTR_ERR(mlxplat_hotplug->regmap);
535+ goto fail_platform_mux_register;
536+ }
537+
331538 priv->pdev_hotplug = platform_device_register_resndata(
332− &mlxplat_dev->dev, "mlxcpld-hotplug",
539+ &mlxplat_dev->dev, "mlxreg-hotplug",
333540 PLATFORM_DEVID_NONE,
334541 mlxplat_mlxcpld_resources,
335542 ARRAY_SIZE(mlxplat_mlxcpld_resources),
@@ -339,8 +546,16 @@ static int __init mlxplat_init(void) · 3 unmodified lines
339546 goto fail_platform_mux_register;
340547 }
341548
549+ /* Sync registers with hardware. */
550+ regcache_mark_dirty(mlxplat_hotplug->regmap);
551+ err = regcache_sync(mlxplat_hotplug->regmap);
552+ if (err)
553+ goto fail_platform_hotplug_register;
554+
342555 return 0;
343556
557+fail_platform_hotplug_register:
558+ platform_device_unregister(priv->pdev_hotplug);
344559 fail_platform_mux_register:
345560 while (--i >= 0)
346561 platform_device_unregister(priv->pdev_mux[i]);
@@ -370,8 +585,3 @@ module_exit(mlxplat_exit); · 23 unmodified lines
370585 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
371586 MODULE_DESCRIPTION("Mellanox platform driver");
372587 MODULE_LICENSE("Dual BSD/GPL");
373−MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
374−MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
375−MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
376−MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
377−MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
drivers/platform/x86/mlxcpld-hotplug.c+0−515
@@ -1,515 +0,0 @@
1−/*
2− * drivers/platform/x86/mlxcpld-hotplug.c
3− * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4− * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
5− *
6− * Redistribution and use in source and binary forms, with or without
7− * modification, are permitted provided that the following conditions are met:
8− *
9− * 1. Redistributions of source code must retain the above copyright
10− * notice, this list of conditions and the following disclaimer.
11− * 2. Redistributions in binary form must reproduce the above copyright
12− * notice, this list of conditions and the following disclaimer in the
13− * documentation and/or other materials provided with the distribution.
14− * 3. Neither the names of the copyright holders nor the names of its
15− * contributors may be used to endorse or promote products derived from
16− * this software without specific prior written permission.
17− *
18− * Alternatively, this software may be distributed under the terms of the
19− * GNU General Public License ("GPL") version 2 as published by the Free
20− * Software Foundation.
21− *
22− * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23− * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24− * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25− * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26− * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27− * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28− * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29− * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30− * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31− * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32− * POSSIBILITY OF SUCH DAMAGE.
33− */
34−
35−#include <linux/bitops.h>
36−#include <linux/device.h>
37−#include <linux/hwmon.h>
38−#include <linux/hwmon-sysfs.h>
39−#include <linux/i2c.h>
40−#include <linux/interrupt.h>
41−#include <linux/io.h>
42−#include <linux/module.h>
43−#include <linux/platform_data/mlxcpld-hotplug.h>
44−#include <linux/platform_device.h>
45−#include <linux/spinlock.h>
46−#include <linux/wait.h>
47−#include <linux/workqueue.h>
48−
49−/* Offset of event and mask registers from status register */
50−#define MLXCPLD_HOTPLUG_EVENT_OFF 1
51−#define MLXCPLD_HOTPLUG_MASK_OFF 2
52−#define MLXCPLD_HOTPLUG_AGGR_MASK_OFF 1
53−
54−#define MLXCPLD_HOTPLUG_ATTRS_NUM 8
55−
56−/**
57− * enum mlxcpld_hotplug_attr_type - sysfs attributes for hotplug events:
58− * @MLXCPLD_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute;
59− * @MLXCPLD_HOTPLUG_ATTR_TYPE_PWR: power cable attribute;
60− * @MLXCPLD_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute;
61− */
62−enum mlxcpld_hotplug_attr_type {
63− MLXCPLD_HOTPLUG_ATTR_TYPE_PSU,
64− MLXCPLD_HOTPLUG_ATTR_TYPE_PWR,
65− MLXCPLD_HOTPLUG_ATTR_TYPE_FAN,
66−};
67−
68−/**
69− * struct mlxcpld_hotplug_priv_data - platform private data:
70− * @irq: platform interrupt number;
71− * @pdev: platform device;
72− * @plat: platform data;
73− * @hwmon: hwmon device;
74− * @mlxcpld_hotplug_attr: sysfs attributes array;
75− * @mlxcpld_hotplug_dev_attr: sysfs sensor device attribute array;
76− * @group: sysfs attribute group;
77− * @groups: list of sysfs attribute group for hwmon registration;
78− * @dwork: delayed work template;
79− * @lock: spin lock;
80− * @aggr_cache: last value of aggregation register status;
81− * @psu_cache: last value of PSU register status;
82− * @pwr_cache: last value of power register status;
83− * @fan_cache: last value of FAN register status;
84− */
85−struct mlxcpld_hotplug_priv_data {
86− int irq;
87− struct platform_device *pdev;
88− struct mlxcpld_hotplug_platform_data *plat;
89− struct device *hwmon;
90− struct attribute *mlxcpld_hotplug_attr[MLXCPLD_HOTPLUG_ATTRS_NUM + 1];
91− struct sensor_device_attribute_2
92− mlxcpld_hotplug_dev_attr[MLXCPLD_HOTPLUG_ATTRS_NUM];
93− struct attribute_group group;
94− const struct attribute_group *groups[2];
95− struct delayed_work dwork;
96− spinlock_t lock;
97− u8 aggr_cache;
98− u8 psu_cache;
99− u8 pwr_cache;
100− u8 fan_cache;
101−};
102−
103−static ssize_t mlxcpld_hotplug_attr_show(struct device *dev,
104− struct device_attribute *attr,
105− char *buf)
106−{
107− struct platform_device *pdev = to_platform_device(dev);
108− struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev);
109− int index = to_sensor_dev_attr_2(attr)->index;
110− int nr = to_sensor_dev_attr_2(attr)->nr;
111− u8 reg_val = 0;
112−
113− switch (nr) {
114− case MLXCPLD_HOTPLUG_ATTR_TYPE_PSU:
115− /* Bit = 0 : PSU is present. */
116− reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index));
117− break;
118−
119− case MLXCPLD_HOTPLUG_ATTR_TYPE_PWR:
120− /* Bit = 1 : power cable is attached. */
121− reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index %
122− priv->plat->pwr_count));
123− break;
124−
125− case MLXCPLD_HOTPLUG_ATTR_TYPE_FAN:
126− /* Bit = 0 : FAN is present. */
127− reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index %
128− priv->plat->fan_count));
129− break;
130− }
131−
132− return sprintf(buf, "%u\n", reg_val);
133−}
134−
135−#define PRIV_ATTR(i) priv->mlxcpld_hotplug_attr[i]
136−#define PRIV_DEV_ATTR(i) priv->mlxcpld_hotplug_dev_attr[i]
137−static int mlxcpld_hotplug_attr_init(struct mlxcpld_hotplug_priv_data *priv)
138−{
139− int num_attrs = priv->plat->psu_count + priv->plat->pwr_count +
140− priv->plat->fan_count;
141− int i;
142−
143− priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
144− sizeof(struct attribute *),
145− GFP_KERNEL);
146− if (!priv->group.attrs)
147− return -ENOMEM;
148−
149− for (i = 0; i < num_attrs; i++) {
150− PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr;
151−
152− if (i < priv->plat->psu_count) {
153− PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
154− GFP_KERNEL, "psu%u", i + 1);
155− PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PSU;
156− } else if (i < priv->plat->psu_count + priv->plat->pwr_count) {
157− PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
158− GFP_KERNEL, "pwr%u", i %
159− priv->plat->pwr_count + 1);
160− PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PWR;
161− } else {
162− PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
163− GFP_KERNEL, "fan%u", i %
164− priv->plat->fan_count + 1);
165− PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_FAN;
166− }
167−
168− if (!PRIV_ATTR(i)->name) {
169− dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n",
170− i + 1);
171− return -ENOMEM;
172− }
173−
174− PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name;
175− PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO;
176− PRIV_DEV_ATTR(i).dev_attr.show = mlxcpld_hotplug_attr_show;
177− PRIV_DEV_ATTR(i).index = i;
178− sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr);
179− }
180−
181− priv->group.attrs = priv->mlxcpld_hotplug_attr;
182− priv->groups[0] = &priv->group;
183− priv->groups[1] = NULL;
184−
185− return 0;
186−}
187−
188−static int mlxcpld_hotplug_device_create(struct device *dev,
189− struct mlxcpld_hotplug_device *item)
190−{
191− item->adapter = i2c_get_adapter(item->bus);
192− if (!item->adapter) {
193− dev_err(dev, "Failed to get adapter for bus %d\n",
194− item->bus);
195− return -EFAULT;
196− }
197−
198− item->client = i2c_new_device(item->adapter, &item->brdinfo);
199− if (!item->client) {
200− dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
201− item->brdinfo.type, item->bus, item->brdinfo.addr);
202− i2c_put_adapter(item->adapter);
203− item->adapter = NULL;
204− return -EFAULT;
205− }
206−
207− return 0;
208−}
209−
210−static void mlxcpld_hotplug_device_destroy(struct mlxcpld_hotplug_device *item)
211−{
212− if (item->client) {
213− i2c_unregister_device(item->client);
214− item->client = NULL;
215− }
216−
217− if (item->adapter) {
218− i2c_put_adapter(item->adapter);
219− item->adapter = NULL;
220− }
221−}
222−
223−static inline void
224−mlxcpld_hotplug_work_helper(struct device *dev,
225− struct mlxcpld_hotplug_device *item, u8 is_inverse,
226− u16 offset, u8 mask, u8 *cache)
227−{
228− u8 val, asserted;
229− int bit;
230−
231− /* Mask event. */
232− outb(0, offset + MLXCPLD_HOTPLUG_MASK_OFF);
233− /* Read status. */
234− val = inb(offset) & mask;
235− asserted = *cache ^ val;
236− *cache = val;
237−
238− /*
239− * Validate if item related to received signal type is valid.
240− * It should never happen, excepted the situation when some
241− * piece of hardware is broken. In such situation just produce
242− * error message and return. Caller must continue to handle the
243− * signals from other devices if any.
244− */
245− if (unlikely(!item)) {
246− dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n",
247− offset, mask);
248− return;
249− }
250−
251− for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
252− if (val & BIT(bit)) {
253− if (is_inverse)
254− mlxcpld_hotplug_device_destroy(item + bit);
255− else
256− mlxcpld_hotplug_device_create(dev, item + bit);
257− } else {
258− if (is_inverse)
259− mlxcpld_hotplug_device_create(dev, item + bit);
260− else
261− mlxcpld_hotplug_device_destroy(item + bit);
262− }
263− }
264−
265− /* Acknowledge event. */
266− outb(0, offset + MLXCPLD_HOTPLUG_EVENT_OFF);
267− /* Unmask event. */
268− outb(mask, offset + MLXCPLD_HOTPLUG_MASK_OFF);
269−}
270−
271−/*
272− * mlxcpld_hotplug_work_handler - performs traversing of CPLD interrupt
273− * registers according to the below hierarchy schema:
274− *
275− * Aggregation registers (status/mask)
276− * PSU registers: *---*
277− * *-----------------* | |
278− * |status/event/mask|----->| * |
279− * *-----------------* | |
280− * Power registers: | |
281− * *-----------------* | |
282− * |status/event/mask|----->| * |---> CPU
283− * *-----------------* | |
284− * FAN registers:
285− * *-----------------* | |
286− * |status/event/mask|----->| * |
287− * *-----------------* | |
288− * *---*
289− * In case some system changed are detected: FAN in/out, PSU in/out, power
290− * cable attached/detached, relevant device is created or destroyed.
291− */
292−static void mlxcpld_hotplug_work_handler(struct work_struct *work)
293−{
294− struct mlxcpld_hotplug_priv_data *priv = container_of(work,
295− struct mlxcpld_hotplug_priv_data, dwork.work);
296− u8 val, aggr_asserted;
297− unsigned long flags;
298−
299− /* Mask aggregation event. */
300− outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
301− /* Read aggregation status. */
302− val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask;
303− aggr_asserted = priv->aggr_cache ^ val;
304− priv->aggr_cache = val;
305−
306− /* Handle PSU configuration changes. */
307− if (aggr_asserted & priv->plat->top_aggr_psu_mask)
308− mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu,
309− 1, priv->plat->psu_reg_offset,
310− priv->plat->psu_mask,
311− &priv->psu_cache);
312−
313− /* Handle power cable configuration changes. */
314− if (aggr_asserted & priv->plat->top_aggr_pwr_mask)
315− mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr,
316− 0, priv->plat->pwr_reg_offset,
317− priv->plat->pwr_mask,
318− &priv->pwr_cache);
319−
320− /* Handle FAN configuration changes. */
321− if (aggr_asserted & priv->plat->top_aggr_fan_mask)
322− mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan,
323− 1, priv->plat->fan_reg_offset,
324− priv->plat->fan_mask,
325− &priv->fan_cache);
326−
327− if (aggr_asserted) {
328− spin_lock_irqsave(&priv->lock, flags);
329−
330− /*
331− * It is possible, that some signals have been inserted, while
332− * interrupt has been masked by mlxcpld_hotplug_work_handler.
333− * In this case such signals will be missed. In order to handle
334− * these signals delayed work is canceled and work task
335− * re-scheduled for immediate execution. It allows to handle
336− * missed signals, if any. In other case work handler just
337− * validates that no new signals have been received during
338− * masking.
339− */
340− cancel_delayed_work(&priv->dwork);
341− schedule_delayed_work(&priv->dwork, 0);
342−
343− spin_unlock_irqrestore(&priv->lock, flags);
344−
345− return;
346− }
347−
348− /* Unmask aggregation event (no need acknowledge). */
349− outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset +
350− MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
351−}
352−
353−static void mlxcpld_hotplug_set_irq(struct mlxcpld_hotplug_priv_data *priv)
354−{
355− /* Clear psu presense event. */
356− outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
357− /* Set psu initial status as mask and unmask psu event. */
358− priv->psu_cache = priv->plat->psu_mask;
359− outb(priv->plat->psu_mask, priv->plat->psu_reg_offset +
360− MLXCPLD_HOTPLUG_MASK_OFF);
361−
362− /* Clear power cable event. */
363− outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
364− /* Keep power initial status as zero and unmask power event. */
365− outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset +
366− MLXCPLD_HOTPLUG_MASK_OFF);
367−
368− /* Clear fan presense event. */
369− outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
370− /* Set fan initial status as mask and unmask fan event. */
371− priv->fan_cache = priv->plat->fan_mask;
372− outb(priv->plat->fan_mask, priv->plat->fan_reg_offset +
373− MLXCPLD_HOTPLUG_MASK_OFF);
374−
375− /* Keep aggregation initial status as zero and unmask events. */
376− outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset +
377− MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
378−
379− /* Invoke work handler for initializing hot plug devices setting. */
380− mlxcpld_hotplug_work_handler(&priv->dwork.work);
381−
382− enable_irq(priv->irq);
383−}
384−
385−static void mlxcpld_hotplug_unset_irq(struct mlxcpld_hotplug_priv_data *priv)
386−{
387− int i;
388−
389− disable_irq(priv->irq);
390− cancel_delayed_work_sync(&priv->dwork);
391−
392− /* Mask aggregation event. */
393− outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
394−
395− /* Mask psu presense event. */
396− outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF);
397− /* Clear psu presense event. */
398− outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
399−
400− /* Mask power cable event. */
401− outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF);
402− /* Clear power cable event. */
403− outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
404−
405− /* Mask fan presense event. */
406− outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF);
407− /* Clear fan presense event. */
408− outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
409−
410− /* Remove all the attached devices. */
411− for (i = 0; i < priv->plat->psu_count; i++)
412− mlxcpld_hotplug_device_destroy(priv->plat->psu + i);
413−
414− for (i = 0; i < priv->plat->pwr_count; i++)
415− mlxcpld_hotplug_device_destroy(priv->plat->pwr + i);
416−
417− for (i = 0; i < priv->plat->fan_count; i++)
418− mlxcpld_hotplug_device_destroy(priv->plat->fan + i);
419−}
420−
421−static irqreturn_t mlxcpld_hotplug_irq_handler(int irq, void *dev)
422−{
423− struct mlxcpld_hotplug_priv_data *priv =
424− (struct mlxcpld_hotplug_priv_data *)dev;
425−
426− /* Schedule work task for immediate execution.*/
427− schedule_delayed_work(&priv->dwork, 0);
428−
429− return IRQ_HANDLED;
430−}
431−
432−static int mlxcpld_hotplug_probe(struct platform_device *pdev)
433−{
434− struct mlxcpld_hotplug_platform_data *pdata;
435− struct mlxcpld_hotplug_priv_data *priv;
436− int err;
437−
438− pdata = dev_get_platdata(&pdev->dev);
439− if (!pdata) {
440− dev_err(&pdev->dev, "Failed to get platform data.\n");
441− return -EINVAL;
442− }
443−
444− priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
445− if (!priv)
446− return -ENOMEM;
447−
448− priv->pdev = pdev;
449− priv->plat = pdata;
450−
451− priv->irq = platform_get_irq(pdev, 0);
452− if (priv->irq < 0) {
453− dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
454− priv->irq);
455− return priv->irq;
456− }
457−
458− err = devm_request_irq(&pdev->dev, priv->irq,
459− mlxcpld_hotplug_irq_handler, 0, pdev->name,
460− priv);
461− if (err) {
462− dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
463− return err;
464− }
465− disable_irq(priv->irq);
466−
467− INIT_DELAYED_WORK(&priv->dwork, mlxcpld_hotplug_work_handler);
468− spin_lock_init(&priv->lock);
469−
470− err = mlxcpld_hotplug_attr_init(priv);
471− if (err) {
472− dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err);
473− return err;
474− }
475−
476− priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
477− "mlxcpld_hotplug", priv, priv->groups);
478− if (IS_ERR(priv->hwmon)) {
479− dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
480− PTR_ERR(priv->hwmon));
481− return PTR_ERR(priv->hwmon);
482− }
483−
484− platform_set_drvdata(pdev, priv);
485−
486− /* Perform initial interrupts setup. */
487− mlxcpld_hotplug_set_irq(priv);
488−
489− return 0;
490−}
491−
492−static int mlxcpld_hotplug_remove(struct platform_device *pdev)
493−{
494− struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev);
495−
496− /* Clean interrupts setup. */
497− mlxcpld_hotplug_unset_irq(priv);
498−
499− return 0;
500−}
501−
502−static struct platform_driver mlxcpld_hotplug_driver = {
503− .driver = {
504− .name = "mlxcpld-hotplug",
505− },
506− .probe = mlxcpld_hotplug_probe,
507− .remove = mlxcpld_hotplug_remove,
508−};
509−
510−module_platform_driver(mlxcpld_hotplug_driver);
511−
512−MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
513−MODULE_DESCRIPTION("Mellanox CPLD hotplug platform driver");
514−MODULE_LICENSE("Dual BSD/GPL");
515−MODULE_ALIAS("platform:mlxcpld-hotplug");
drivers/platform/x86/pmc_atom.c+20−36
@@ -208,6 +208,20 @@ static const struct pmc_data cht_data = { · 207 unmodified lines
208208 .clks = cht_clks,
209209 };
210210
211+#define DEFINE_SHOW_ATTRIBUTE(__name) \
212+static int __name ## _open(struct inode *inode, struct file *file) \
213+{ \
214+ return single_open(file, __name ## _show, inode->i_private); \
215+} \
216+ \
217+static const struct file_operations __name ## _fops = { \
218+ .owner = THIS_MODULE, \
219+ .open = __name ## _open, \
220+ .read = seq_read, \
221+ .llseek = seq_lseek, \
222+ .release = single_release, \
223+}
224+
211225 static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset)
212226 {
213227 return readl(pmc->regmap + reg_offset);
@@ -309,17 +323,7 @@ static int pmc_dev_state_show(struct seq_file *s, void *unused) · 95 unmodified lines
309323 return 0;
310324 }
311325
312−static int pmc_dev_state_open(struct inode *inode, struct file *file)
313−{
314− return single_open(file, pmc_dev_state_show, inode->i_private);
315−}
316−
317−static const struct file_operations pmc_dev_state_ops = {
318− .open = pmc_dev_state_open,
319− .read = seq_read,
320− .llseek = seq_lseek,
321− .release = single_release,
322−};
326+DEFINE_SHOW_ATTRIBUTE(pmc_dev_state);
323327
324328 static int pmc_pss_state_show(struct seq_file *s, void *unused)
325329 {
@@ -336,17 +340,7 @@ static int pmc_pss_state_show(struct seq_file *s, void *unused) · 10 unmodified lines
336340 return 0;
337341 }
338342
339−static int pmc_pss_state_open(struct inode *inode, struct file *file)
340−{
341− return single_open(file, pmc_pss_state_show, inode->i_private);
342−}
343−
344−static const struct file_operations pmc_pss_state_ops = {
345− .open = pmc_pss_state_open,
346− .read = seq_read,
347− .llseek = seq_lseek,
348− .release = single_release,
349−};
343+DEFINE_SHOW_ATTRIBUTE(pmc_pss_state);
350344
351345 static int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
352346 {
@@ -367,17 +361,7 @@ static int pmc_sleep_tmr_show(struct seq_file *s, void *unused) · 14 unmodified lines
367361 return 0;
368362 }
369363
370−static int pmc_sleep_tmr_open(struct inode *inode, struct file *file)
371−{
372− return single_open(file, pmc_sleep_tmr_show, inode->i_private);
373−}
374−
375−static const struct file_operations pmc_sleep_tmr_ops = {
376− .open = pmc_sleep_tmr_open,
377− .read = seq_read,
378− .llseek = seq_lseek,
379− .release = single_release,
380−};
364+DEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr);
381365
382366 static void pmc_dbgfs_unregister(struct pmc_dev *pmc)
383367 {
@@ -395,17 +379,17 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc) · 11 unmodified lines
395379 pmc->dbgfs_dir = dir;
396380
397381 f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO,
398− dir, pmc, &pmc_dev_state_ops);
382+ dir, pmc, &pmc_dev_state_fops);
399383 if (!f)
400384 goto err;
401385
402386 f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO,
403− dir, pmc, &pmc_pss_state_ops);
387+ dir, pmc, &pmc_pss_state_fops);
404388 if (!f)
405389 goto err;
406390
407391 f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO,
408− dir, pmc, &pmc_sleep_tmr_ops);
392+ dir, pmc, &pmc_sleep_tmr_fops);
409393 if (!f)
410394 goto err;
411395
drivers/platform/x86/silead_dmi.c+175−0
@@ -67,6 +67,21 @@ static const struct silead_ts_dmi_data dexp_ursus_7w_data = { · 66 unmodified lines
6767 .properties = dexp_ursus_7w_props,
6868 };
6969
70+static const struct property_entry surftab_twin_10_1_st10432_8_props[] = {
71+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1900),
72+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
73+ PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1),
74+ PROPERTY_ENTRY_STRING("firmware-name",
75+ "gsl3670-surftab-twin-10-1-st10432-8.fw"),
76+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
77+ { }
78+};
79+
80+static const struct silead_ts_dmi_data surftab_twin_10_1_st10432_8_data = {
81+ .acpi_name = "MSSL1680:00",
82+ .properties = surftab_twin_10_1_st10432_8_props,
83+};
84+
7085 static const struct property_entry surftab_wintron70_st70416_6_props[] = {
7186 PROPERTY_ENTRY_U32("touchscreen-size-x", 884),
7287 PROPERTY_ENTRY_U32("touchscreen-size-y", 632),
@@ -171,6 +186,97 @@ static const struct silead_ts_dmi_data digma_citi_e200_data = { · 98 unmodified lines
171186 .properties = digma_citi_e200_props,
172187 };
173188
189+static const struct property_entry onda_obook_20_plus_props[] = {
190+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
191+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
192+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
193+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
194+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
195+ PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-obook-20-plus.fw"),
196+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
197+ PROPERTY_ENTRY_BOOL("silead,home-button"),
198+ { }
199+};
200+
201+static const struct silead_ts_dmi_data onda_obook_20_plus_data = {
202+ .acpi_name = "MSSL1680:00",
203+ .properties = onda_obook_20_plus_props,
204+};
205+
206+static const struct property_entry chuwi_hi8_props[] = {
207+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
208+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
209+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
210+ PROPERTY_ENTRY_BOOL("silead,home-button"),
211+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"),
212+ { }
213+};
214+
215+static const struct silead_ts_dmi_data chuwi_hi8_data = {
216+ .acpi_name = "MSSL0001:00",
217+ .properties = chuwi_hi8_props,
218+};
219+
220+static const struct property_entry chuwi_vi8_props[] = {
221+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1724),
222+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
223+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
224+ PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-chuwi-vi8.fw"),
225+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
226+ PROPERTY_ENTRY_BOOL("silead,home-button"),
227+ { }
228+};
229+
230+static const struct silead_ts_dmi_data chuwi_vi8_data = {
231+ .acpi_name = "MSSL1680:00",
232+ .properties = chuwi_vi8_props,
233+};
234+
235+static const struct property_entry trekstor_primebook_c13_props[] = {
236+ PROPERTY_ENTRY_U32("touchscreen-size-x", 2624),
237+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1920),
238+ PROPERTY_ENTRY_STRING("firmware-name",
239+ "gsl1680-trekstor-primebook-c13.fw"),
240+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
241+ PROPERTY_ENTRY_BOOL("silead,home-button"),
242+ { }
243+};
244+
245+static const struct silead_ts_dmi_data trekstor_primebook_c13_data = {
246+ .acpi_name = "MSSL1680:00",
247+ .properties = trekstor_primebook_c13_props,
248+};
249+
250+static const struct property_entry teclast_x98plus2_props[] = {
251+ PROPERTY_ENTRY_U32("touchscreen-size-x", 2048),
252+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
253+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
254+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
255+ PROPERTY_ENTRY_STRING("firmware-name",
256+ "gsl1686-teclast_x98plus2.fw"),
257+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
258+ { }
259+};
260+
261+static const struct silead_ts_dmi_data teclast_x98plus2_data = {
262+ .acpi_name = "MSSL1680:00",
263+ .properties = teclast_x98plus2_props,
264+};
265+
266+static const struct property_entry teclast_x3_plus_props[] = {
267+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
268+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
269+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-teclast-x3-plus.fw"),
270+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
271+ PROPERTY_ENTRY_BOOL("silead,home-button"),
272+ { }
273+};
274+
275+static const struct silead_ts_dmi_data teclast_x3_plus_data = {
276+ .acpi_name = "MSSL1680:00",
277+ .properties = teclast_x3_plus_props,
278+};
279+
174280 static const struct dmi_system_id silead_ts_dmi_table[] = {
175281 {
176282 /* CUBE iwork8 Air */
@@ -198,6 +304,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { · 21 unmodified lines
198304 DMI_MATCH(DMI_PRODUCT_NAME, "7W"),
199305 },
200306 },
307+ {
308+ /* TrekStor SurfTab twin 10.1 ST10432-8 */
309+ .driver_data = (void *)&surftab_twin_10_1_st10432_8_data,
310+ .matches = {
311+ DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"),
312+ DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab twin 10.1"),
313+ },
314+ },
201315 {
202316 /* Trekstor Surftab Wintron 7.0 ST70416-6 */
203317 .driver_data = (void *)&surftab_wintron70_st70416_6_data,
@@ -208,6 +322,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { · 4 unmodified lines
208322 DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"),
209323 },
210324 },
325+ {
326+ /* Trekstor Surftab Wintron 7.0 ST70416-6, newer BIOS */
327+ .driver_data = (void *)&surftab_wintron70_st70416_6_data,
328+ .matches = {
329+ DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"),
330+ DMI_MATCH(DMI_PRODUCT_NAME,
331+ "SurfTab wintron 7.0 ST70416-6"),
332+ /* Exact match, different versions need different fw */
333+ DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"),
334+ },
335+ },
211336 {
212337 /* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */
213338 .driver_data = (void *)&surftab_wintron70_st70416_6_data,
@@ -271,6 +396,56 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { · 57 unmodified lines
271396 DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
272397 },
273398 },
399+ {
400+ /* Onda oBook 20 Plus */
401+ .driver_data = (void *)&onda_obook_20_plus_data,
402+ .matches = {
403+ DMI_MATCH(DMI_SYS_VENDOR, "ONDA"),
404+ DMI_MATCH(DMI_PRODUCT_NAME, "OBOOK 20 PLUS"),
405+ },
406+ },
407+ {
408+ /* Chuwi Hi8 */
409+ .driver_data = (void *)&chuwi_hi8_data,
410+ .matches = {
411+ DMI_MATCH(DMI_SYS_VENDOR, "ilife"),
412+ DMI_MATCH(DMI_PRODUCT_NAME, "S806"),
413+ },
414+ },
415+ {
416+ /* Chuwi Vi8 (CWI506) */
417+ .driver_data = (void *)&chuwi_vi8_data,
418+ .matches = {
419+ DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
420+ DMI_MATCH(DMI_PRODUCT_NAME, "i86"),
421+ DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"),
422+ },
423+ },
424+ {
425+ /* Trekstor Primebook C13 */
426+ .driver_data = (void *)&trekstor_primebook_c13_data,
427+ .matches = {
428+ DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
429+ DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),
430+ },
431+ },
432+ {
433+ /* Teclast X98 Plus II */
434+ .driver_data = (void *)&teclast_x98plus2_data,
435+ .matches = {
436+ DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
437+ DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"),
438+ },
439+ },
440+ {
441+ /* Teclast X3 Plus */
442+ .driver_data = (void *)&teclast_x3_plus_data,
443+ .matches = {
444+ DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
445+ DMI_MATCH(DMI_PRODUCT_NAME, "X3 Plus"),
446+ DMI_MATCH(DMI_BOARD_NAME, "X3 Plus"),
447+ },
448+ },
274449 { },
275450 };
276451
drivers/platform/x86/thinkpad_acpi.c+13−5
@@ -214,6 +214,10 @@ enum tpacpi_hkey_event_t { · 213 unmodified lines
214214 /* AC-related events */
215215 TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */
216216
217+ /* Further user-interface events */
218+ TP_HKEY_EV_PALM_DETECTED = 0x60b0, /* palm hoveres keyboard */
219+ TP_HKEY_EV_PALM_UNDETECTED = 0x60b1, /* palm removed */
220+
217221 /* Misc */
218222 TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */
219223 };
@@ -2113,12 +2117,10 @@ static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode) · 1893 unmodified lines
21132117 TP_ACPI_MULTI_MODE_FLAT;
21142118 break;
21152119 case 4:
2116− valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
2117− TP_ACPI_MULTI_MODE_TABLET |
2118− TP_ACPI_MULTI_MODE_STAND |
2119− TP_ACPI_MULTI_MODE_TENT;
2120− break;
21212120 case 5:
2121+ /* In mode 4, FLAT is not specified as a valid mode. However,
2122+ * it can be seen at least on the X1 Yoga 2nd Generation.
2123+ */
21222124 valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
21232125 TP_ACPI_MULTI_MODE_FLAT |
21242126 TP_ACPI_MULTI_MODE_TABLET |
@@ -4079,6 +4081,12 @@ static bool hotkey_notify_6xxx(const u32 hkey, · 1954 unmodified lines
40794081 *send_acpi_ev = false;
40804082 break;
40814083
4084+ case TP_HKEY_EV_PALM_DETECTED:
4085+ case TP_HKEY_EV_PALM_UNDETECTED:
4086+ /* palm detected hovering the keyboard, forward to user-space
4087+ * via netlink for consumption */
4088+ return true;
4089+
40824090 default:
40834091 pr_warn("unknown possible thermal alarm or keyboard event received\n");
40844092 known = false;
include/linux/platform_data/mlxcpld-hotplug.h+0−99
@@ -1,99 +0,0 @@
1−/*
2− * include/linux/platform_data/mlxcpld-hotplug.h
3− * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4− * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
5− *
6− * Redistribution and use in source and binary forms, with or without
7− * modification, are permitted provided that the following conditions are met:
8− *
9− * 1. Redistributions of source code must retain the above copyright
10− * notice, this list of conditions and the following disclaimer.
11− * 2. Redistributions in binary form must reproduce the above copyright
12− * notice, this list of conditions and the following disclaimer in the
13− * documentation and/or other materials provided with the distribution.
14− * 3. Neither the names of the copyright holders nor the names of its
15− * contributors may be used to endorse or promote products derived from
16− * this software without specific prior written permission.
17− *
18− * Alternatively, this software may be distributed under the terms of the
19− * GNU General Public License ("GPL") version 2 as published by the Free
20− * Software Foundation.
21− *
22− * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23− * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24− * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25− * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26− * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27− * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28− * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29− * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30− * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31− * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32− * POSSIBILITY OF SUCH DAMAGE.
33− */
34−
35−#ifndef __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H
36−#define __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H
37−
38−/**
39− * struct mlxcpld_hotplug_device - I2C device data:
40− * @adapter: I2C device adapter;
41− * @client: I2C device client;
42− * @brdinfo: device board information;
43− * @bus: I2C bus, where device is attached;
44− *
45− * Structure represents I2C hotplug device static data (board topology) and
46− * dynamic data (related kernel objects handles).
47− */
48−struct mlxcpld_hotplug_device {
49− struct i2c_adapter *adapter;
50− struct i2c_client *client;
51− struct i2c_board_info brdinfo;
52− u16 bus;
53−};
54−
55−/**
56− * struct mlxcpld_hotplug_platform_data - device platform data:
57− * @top_aggr_offset: offset of top aggregation interrupt register;
58− * @top_aggr_mask: top aggregation interrupt common mask;
59− * @top_aggr_psu_mask: top aggregation interrupt PSU mask;
60− * @psu_reg_offset: offset of PSU interrupt register;
61− * @psu_mask: PSU interrupt mask;
62− * @psu_count: number of equipped replaceable PSUs;
63− * @psu: pointer to PSU devices data array;
64− * @top_aggr_pwr_mask: top aggregation interrupt power mask;
65− * @pwr_reg_offset: offset of power interrupt register
66− * @pwr_mask: power interrupt mask;
67− * @pwr_count: number of power sources;
68− * @pwr: pointer to power devices data array;
69− * @top_aggr_fan_mask: top aggregation interrupt FAN mask;
70− * @fan_reg_offset: offset of FAN interrupt register;
71− * @fan_mask: FAN interrupt mask;
72− * @fan_count: number of equipped replaceable FANs;
73− * @fan: pointer to FAN devices data array;
74− *
75− * Structure represents board platform data, related to system hotplug events,
76− * like FAN, PSU, power cable insertion and removing. This data provides the
77− * number of hot-pluggable devices and hardware description for event handling.
78− */
79−struct mlxcpld_hotplug_platform_data {
80− u16 top_aggr_offset;
81− u8 top_aggr_mask;
82− u8 top_aggr_psu_mask;
83− u16 psu_reg_offset;
84− u8 psu_mask;
85− u8 psu_count;
86− struct mlxcpld_hotplug_device *psu;
87− u8 top_aggr_pwr_mask;
88− u16 pwr_reg_offset;
89− u8 pwr_mask;
90− u8 pwr_count;
91− struct mlxcpld_hotplug_device *pwr;
92− u8 top_aggr_fan_mask;
93− u16 fan_reg_offset;
94− u8 fan_mask;
95− u8 fan_count;
96− struct mlxcpld_hotplug_device *fan;
97−};
98−
99−#endif /* __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H */
include/linux/platform_data/mlxreg.h+144−0
@@ -0,0 +1,144 @@
1+/*
2+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
3+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
4+ *
5+ * Redistribution and use in source and binary forms, with or without
6+ * modification, are permitted provided that the following conditions are met:
7+ *
8+ * 1. Redistributions of source code must retain the above copyright
9+ * notice, this list of conditions and the following disclaimer.
10+ * 2. Redistributions in binary form must reproduce the above copyright
11+ * notice, this list of conditions and the following disclaimer in the
12+ * documentation and/or other materials provided with the distribution.
13+ * 3. Neither the names of the copyright holders nor the names of its
14+ * contributors may be used to endorse or promote products derived from
15+ * this software without specific prior written permission.
16+ *
17+ * Alternatively, this software may be distributed under the terms of the
18+ * GNU General Public License ("GPL") version 2 as published by the Free
19+ * Software Foundation.
20+ *
21+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31+ * POSSIBILITY OF SUCH DAMAGE.
32+ */
33+
34+#ifndef __LINUX_PLATFORM_DATA_MLXREG_H
35+#define __LINUX_PLATFORM_DATA_MLXREG_H
36+
37+#define MLXREG_CORE_LABEL_MAX_SIZE 32
38+
39+/**
40+ * struct mlxreg_hotplug_device - I2C device data:
41+ *
42+ * @adapter: I2C device adapter;
43+ * @client: I2C device client;
44+ * @brdinfo: device board information;
45+ * @nr: I2C device adapter number, to which device is to be attached;
46+ *
47+ * Structure represents I2C hotplug device static data (board topology) and
48+ * dynamic data (related kernel objects handles).
49+ */
50+struct mlxreg_hotplug_device {
51+ struct i2c_adapter *adapter;
52+ struct i2c_client *client;
53+ struct i2c_board_info *brdinfo;
54+ int nr;
55+};
56+
57+/**
58+ * struct mlxreg_core_data - attributes control data:
59+ *
60+ * @label: attribute label;
61+ * @label: attribute register offset;
62+ * @reg: attribute register;
63+ * @mask: attribute access mask;
64+ * @mode: access mode;
65+ * @bit: attribute effective bit;
66+ * @np - pointer to node platform associated with attribute;
67+ * @hpdev - hotplug device data;
68+ * @health_cntr: dynamic device health indication counter;
69+ * @attached: true if device has been attached after good health indication;
70+ */
71+struct mlxreg_core_data {
72+ char label[MLXREG_CORE_LABEL_MAX_SIZE];
73+ u32 reg;
74+ u32 mask;
75+ u32 bit;
76+ umode_t mode;
77+ struct device_node *np;
78+ struct mlxreg_hotplug_device hpdev;
79+ u8 health_cntr;
80+ bool attached;
81+};
82+
83+/**
84+ * struct mlxreg_core_item - same type components controlled by the driver:
85+ *
86+ * @data: component data;
87+ * @aggr_mask: group aggregation mask;
88+ * @reg: group interrupt status register;
89+ * @mask: group interrupt mask;
90+ * @cache: last status value for elements fro the same group;
91+ * @count: number of available elements in the group;
92+ * @ind: element's index inside the group;
93+ * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;
94+ * @health: true if device has health indication, false in other case;
95+ */
96+struct mlxreg_core_item {
97+ struct mlxreg_core_data *data;
98+ u32 aggr_mask;
99+ u32 reg;
100+ u32 mask;
101+ u32 cache;
102+ u8 count;
103+ u8 ind;
104+ u8 inversed;
105+ u8 health;
106+};
107+
108+/**
109+ * struct mlxreg_core_platform_data - platform data:
110+ *
111+ * @led_data: led private data;
112+ * @regmap: register map of parent device;
113+ * @counter: number of led instances;
114+ */
115+struct mlxreg_core_platform_data {
116+ struct mlxreg_core_data *data;
117+ void *regmap;
118+ int counter;
119+};
120+
121+/**
122+ * struct mlxreg_core_hotplug_platform_data - hotplug platform data:
123+ *
124+ * @items: same type components with the hotplug capability;
125+ * @irq: platform interrupt number;
126+ * @regmap: register map of parent device;
127+ * @counter: number of the components with the hotplug capability;
128+ * @cell: location of top aggregation interrupt register;
129+ * @mask: top aggregation interrupt common mask;
130+ * @cell_low: location of low aggregation interrupt register;
131+ * @mask_low: low aggregation interrupt common mask;
132+ */
133+struct mlxreg_core_hotplug_platform_data {
134+ struct mlxreg_core_item *items;
135+ int irq;
136+ void *regmap;
137+ int counter;
138+ u32 cell;
139+ u32 mask;
140+ u32 cell_low;
141+ u32 mask_low;
142+};
143+
144+#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
include/uapi/linux/input-event-codes.h+1−0
@@ -594,6 +594,7 @@ · 593 unmodified lines
594594 #define BTN_DPAD_RIGHT 0x223
595595
596596 #define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
597+#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
597598
598599 #define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
599600 #define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t