aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-02-06 18:30:52 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-02-06 18:30:52 -0500
commitcbd7b8a76b79a2ff6112ef2e77031b694843b8a1 (patch)
tree41a7e9bae92abe001c36a094b1135f0b93375c31
parent3f551e3cefcf119c1d397ed8b5633d9fa73fca0a (diff)
parent8a0f5b6f33275eb0251e0e1b0716744f9d95415f (diff)
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 ...
-rw-r--r--Documentation/ABI/testing/sysfs-driver-samsung-laptop2
-rw-r--r--MAINTAINERS15
-rw-r--r--arch/x86/include/asm/intel-family.h6
-rw-r--r--arch/x86/include/asm/intel_pmc_ipc.h6
-rw-r--r--arch/x86/include/asm/pmc_core.h27
-rw-r--r--drivers/acpi/acpi_lpit.c1
-rw-r--r--drivers/platform/Kconfig2
-rw-r--r--drivers/platform/Makefile1
-rw-r--r--drivers/platform/mellanox/Kconfig26
-rw-r--r--drivers/platform/mellanox/Makefile6
-rw-r--r--drivers/platform/mellanox/mlxreg-hotplug.c638
-rw-r--r--drivers/platform/x86/Kconfig56
-rw-r--r--drivers/platform/x86/Makefile4
-rw-r--r--drivers/platform/x86/acer-wireless.c71
-rw-r--r--drivers/platform/x86/alienware-wmi.c17
-rw-r--r--drivers/platform/x86/apple-gmux.c48
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c13
-rw-r--r--drivers/platform/x86/dell-laptop.c260
-rw-r--r--drivers/platform/x86/dell-smbios.c8
-rw-r--r--drivers/platform/x86/dell-wmi.c3
-rw-r--r--drivers/platform/x86/gpd-pocket-fan.c216
-rw-r--r--drivers/platform/x86/ideapad-laptop.c28
-rw-r--r--drivers/platform/x86/intel-hid.c41
-rw-r--r--drivers/platform/x86/intel-vbtn.c65
-rw-r--r--drivers/platform/x86/intel_chtdc_ti_pwrbtn.c93
-rw-r--r--drivers/platform/x86/intel_int0002_vgpio.c2
-rw-r--r--drivers/platform/x86/intel_pmc_core.c280
-rw-r--r--drivers/platform/x86/intel_pmc_core.h29
-rw-r--r--drivers/platform/x86/intel_pmc_ipc.c33
-rw-r--r--drivers/platform/x86/intel_telemetry_debugfs.c83
-rw-r--r--drivers/platform/x86/mlx-platform.c324
-rw-r--r--drivers/platform/x86/mlxcpld-hotplug.c515
-rw-r--r--drivers/platform/x86/pmc_atom.c56
-rw-r--r--drivers/platform/x86/silead_dmi.c175
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c18
-rw-r--r--include/linux/platform_data/mlxcpld-hotplug.h99
-rw-r--r--include/linux/platform_data/mlxreg.h144
-rw-r--r--include/uapi/linux/input-event-codes.h1
38 files changed, 2301 insertions, 1111 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
index 63c1ad0212fc..34d3a3359cf4 100644
--- a/Documentation/ABI/testing/sysfs-driver-samsung-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop
@@ -3,7 +3,7 @@ Date: January 1, 2010
3KernelVersion: 2.6.33 3KernelVersion: 2.6.33
4Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 4Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
5Description: Some Samsung laptops have different "performance levels" 5Description: 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
7 sysfs file. These values don't always make a whole lot 7 sysfs file. These values don't always make a whole lot
8 of sense, but some users like to modify them to keep 8 of sense, but some users like to modify them to keep
9 their fans quiet at all costs. Reading from this file 9 their fans quiet at all costs. Reading from this file
diff --git a/MAINTAINERS b/MAINTAINERS
index 836f6c7bbf2d..a2d0aeabf3cc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6001,6 +6001,12 @@ L: linux-input@vger.kernel.org
6001S: Maintained 6001S: Maintained
6002F: drivers/input/touchscreen/goodix.c 6002F: drivers/input/touchscreen/goodix.c
6003 6003
6004GPD POCKET FAN DRIVER
6005M: Hans de Goede <hdegoede@redhat.com>
6006L: platform-driver-x86@vger.kernel.org
6007S: Maintained
6008F: drivers/platform/x86/gpd-pocket-fan.c
6009
6004GPIO ACPI SUPPORT 6010GPIO ACPI SUPPORT
6005M: Mika Westerberg <mika.westerberg@linux.intel.com> 6011M: Mika Westerberg <mika.westerberg@linux.intel.com>
6006M: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 6012M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
@@ -8939,12 +8945,13 @@ W: http://www.mellanox.com
8939Q: http://patchwork.ozlabs.org/project/netdev/list/ 8945Q: http://patchwork.ozlabs.org/project/netdev/list/
8940F: drivers/net/ethernet/mellanox/mlxfw/ 8946F: drivers/net/ethernet/mellanox/mlxfw/
8941 8947
8942MELLANOX MLX CPLD HOTPLUG DRIVER 8948MELLANOX HARDWARE PLATFORM SUPPORT
8949M: Andy Shevchenko <andy@infradead.org>
8950M: Darren Hart <dvhart@infradead.org>
8943M: Vadim Pasternak <vadimp@mellanox.com> 8951M: Vadim Pasternak <vadimp@mellanox.com>
8944L: platform-driver-x86@vger.kernel.org 8952L: platform-driver-x86@vger.kernel.org
8945S: Supported 8953S: Supported
8946F: drivers/platform/x86/mlxcpld-hotplug.c 8954F: drivers/platform/mellanox/
8947F: include/linux/platform_data/mlxcpld-hotplug.h
8948 8955
8949MELLANOX MLX4 core VPI driver 8956MELLANOX MLX4 core VPI driver
8950M: Tariq Toukan <tariqt@mellanox.com> 8957M: Tariq Toukan <tariqt@mellanox.com>
@@ -15134,7 +15141,7 @@ X86 PLATFORM DRIVERS
15134M: Darren Hart <dvhart@infradead.org> 15141M: Darren Hart <dvhart@infradead.org>
15135M: Andy Shevchenko <andy@infradead.org> 15142M: Andy Shevchenko <andy@infradead.org>
15136L: platform-driver-x86@vger.kernel.org 15143L: platform-driver-x86@vger.kernel.org
15137T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git 15144T: git git://git.infradead.org/linux-platform-drivers-x86.git
15138S: Maintained 15145S: Maintained
15139F: drivers/platform/x86/ 15146F: drivers/platform/x86/
15140F: drivers/platform/olpc/ 15147F: drivers/platform/olpc/
diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h
index 35a6bc4da8ad..cf090e584202 100644
--- a/arch/x86/include/asm/intel-family.h
+++ b/arch/x86/include/asm/intel-family.h
@@ -10,6 +10,10 @@
10 * 10 *
11 * Things ending in "2" are usually because we have no better 11 * Things ending in "2" are usually because we have no better
12 * name for them. There's no processor called "SILVERMONT2". 12 * 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.
13 */ 17 */
14 18
15#define INTEL_FAM6_CORE_YONAH 0x0E 19#define INTEL_FAM6_CORE_YONAH 0x0E
@@ -49,6 +53,8 @@
49#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E 53#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E
50#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E 54#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E
51 55
56#define INTEL_FAM6_CANNONLAKE_MOBILE 0x66
57
52/* "Small Core" Processors (Atom) */ 58/* "Small Core" Processors (Atom) */
53 59
54#define INTEL_FAM6_ATOM_PINEVIEW 0x1C 60#define INTEL_FAM6_ATOM_PINEVIEW 0x1C
diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h
index 528ed4be4393..9e7adcdbe031 100644
--- a/arch/x86/include/asm/intel_pmc_ipc.h
+++ b/arch/x86/include/asm/intel_pmc_ipc.h
@@ -38,6 +38,7 @@ int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
38 u32 *out, u32 outlen); 38 u32 *out, u32 outlen);
39int intel_pmc_s0ix_counter_read(u64 *data); 39int intel_pmc_s0ix_counter_read(u64 *data);
40int intel_pmc_gcr_read(u32 offset, u32 *data); 40int intel_pmc_gcr_read(u32 offset, u32 *data);
41int intel_pmc_gcr_read64(u32 offset, u64 *data);
41int intel_pmc_gcr_write(u32 offset, u32 data); 42int intel_pmc_gcr_write(u32 offset, u32 data);
42int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val); 43int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val);
43 44
@@ -70,6 +71,11 @@ static inline int intel_pmc_gcr_read(u32 offset, u32 *data)
70 return -EINVAL; 71 return -EINVAL;
71} 72}
72 73
74static inline int intel_pmc_gcr_read64(u32 offset, u64 *data)
75{
76 return -EINVAL;
77}
78
73static inline int intel_pmc_gcr_write(u32 offset, u32 data) 79static inline int intel_pmc_gcr_write(u32 offset, u32 data)
74{ 80{
75 return -EINVAL; 81 return -EINVAL;
diff --git a/arch/x86/include/asm/pmc_core.h b/arch/x86/include/asm/pmc_core.h
deleted file mode 100644
index d4855f11136d..000000000000
--- a/arch/x86/include/asm/pmc_core.h
+++ /dev/null
@@ -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 */
25int intel_pmc_slp_s0_counter_read(u32 *data);
26
27#endif /* _ASM_PMC_CORE_H */
diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c
index e94e478dd18b..cf4fc0161164 100644
--- a/drivers/acpi/acpi_lpit.c
+++ b/drivers/acpi/acpi_lpit.c
@@ -100,6 +100,7 @@ int lpit_read_residency_count_address(u64 *address)
100 100
101 return 0; 101 return 0;
102} 102}
103EXPORT_SYMBOL_GPL(lpit_read_residency_count_address);
103 104
104static void lpit_update_residency(struct lpit_residency_info *info, 105static void lpit_update_residency(struct lpit_residency_info *info,
105 struct acpi_lpit_native *lpit_native) 106 struct acpi_lpit_native *lpit_native)
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index c11db8bceea1..d4c2e424a700 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -8,3 +8,5 @@ endif
8source "drivers/platform/goldfish/Kconfig" 8source "drivers/platform/goldfish/Kconfig"
9 9
10source "drivers/platform/chrome/Kconfig" 10source "drivers/platform/chrome/Kconfig"
11
12source "drivers/platform/mellanox/Kconfig"
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index d3a6630266a0..4b2ce58bcd9c 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -4,6 +4,7 @@
4# 4#
5 5
6obj-$(CONFIG_X86) += x86/ 6obj-$(CONFIG_X86) += x86/
7obj-$(CONFIG_MELLANOX_PLATFORM) += mellanox/
7obj-$(CONFIG_MIPS) += mips/ 8obj-$(CONFIG_MIPS) += mips/
8obj-$(CONFIG_OLPC) += olpc/ 9obj-$(CONFIG_OLPC) += olpc/
9obj-$(CONFIG_GOLDFISH) += goldfish/ 10obj-$(CONFIG_GOLDFISH) += goldfish/
diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
new file mode 100644
index 000000000000..591bccdeaff9
--- /dev/null
+++ b/drivers/platform/mellanox/Kconfig
@@ -0,0 +1,26 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Platform support for Mellanox hardware
4#
5
6menuconfig 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
15if MELLANOX_PLATFORM
16
17config 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
26endif # MELLANOX_PLATFORM
diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile
new file mode 100644
index 000000000000..7c8385e497a8
--- /dev/null
+++ b/drivers/platform/mellanox/Makefile
@@ -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#
6obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
new file mode 100644
index 000000000000..0dfa1ca0d05b
--- /dev/null
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -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 */
75struct 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
96static 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
128static 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
141static 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
178static 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
229static void
230mlxreg_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
297static void
298mlxreg_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 */
378static 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
447static 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
499static 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
537static 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
549static 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
615static 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
625static 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
633module_platform_driver(mlxreg_hotplug_driver);
634
635MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
636MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
637MODULE_LICENSE("Dual BSD/GPL");
638MODULE_ALIAS("platform:mlxreg-hotplug");
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 2c745e8ccad6..9a8f96465cdc 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -36,6 +36,20 @@ config ACER_WMI
36 If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M 36 If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
37 here. 37 here.
38 38
39config 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
39config ACERHDF 53config ACERHDF
40 tristate "Acer Aspire One temperature and fan driver" 54 tristate "Acer Aspire One temperature and fan driver"
41 depends on ACPI && THERMAL 55 depends on ACPI && THERMAL
@@ -244,6 +258,18 @@ config AMILO_RFKILL
244 This is a driver for enabling wifi on some Fujitsu-Siemens Amilo 258 This is a driver for enabling wifi on some Fujitsu-Siemens Amilo
245 laptops. 259 laptops.
246 260
261config 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
247config TC1100_WMI 273config TC1100_WMI
248 tristate "HP Compaq TC1100 Tablet WMI Extras" 274 tristate "HP Compaq TC1100 Tablet WMI Extras"
249 depends on !X86_64 275 depends on !X86_64
@@ -812,9 +838,8 @@ config TOSHIBA_WMI
812 838
813config ACPI_CMPC 839config ACPI_CMPC
814 tristate "CMPC Laptop Extras" 840 tristate "CMPC Laptop Extras"
815 depends on ACPI 841 depends on ACPI && INPUT
816 depends on RFKILL || RFKILL=n 842 depends on RFKILL || RFKILL=n
817 select INPUT
818 select BACKLIGHT_CLASS_DEVICE 843 select BACKLIGHT_CLASS_DEVICE
819 help 844 help
820 Support for Intel Classmate PC ACPI devices, including some 845 Support for Intel Classmate PC ACPI devices, including some
@@ -949,7 +974,7 @@ config INTEL_IMR
949 If you are running on a Galileo/Quark say Y here. 974 If you are running on a Galileo/Quark say Y here.
950 975
951config INTEL_PMC_CORE 976config INTEL_PMC_CORE
952 bool "Intel PMC Core driver" 977 tristate "Intel PMC Core driver"
953 depends on PCI 978 depends on PCI
954 ---help--- 979 ---help---
955 The Intel Platform Controller Hub for Intel Core SoCs provides access 980 The Intel Platform Controller Hub for Intel Core SoCs provides access
@@ -958,7 +983,10 @@ config INTEL_PMC_CORE
958 exposed by the Power Management Controller. 983 exposed by the Power Management Controller.
959 984
960 Supported features: 985 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)
962 990
963config IBM_RTL 991config IBM_RTL
964 tristate "Device driver to enable PRTL support" 992 tristate "Device driver to enable PRTL support"
@@ -1131,7 +1159,6 @@ config INTEL_TELEMETRY
1131 1159
1132config MLX_PLATFORM 1160config MLX_PLATFORM
1133 tristate "Mellanox Technologies platform support" 1161 tristate "Mellanox Technologies platform support"
1134 depends on X86_64
1135 ---help--- 1162 ---help---
1136 This option enables system support for the Mellanox Technologies 1163 This option enables system support for the Mellanox Technologies
1137 platform. The Mellanox systems provide data center networking 1164 platform. The Mellanox systems provide data center networking
@@ -1141,14 +1168,6 @@ config MLX_PLATFORM
1141 1168
1142 If you have a Mellanox system, say Y or M here. 1169 If you have a Mellanox system, say Y or M here.
1143 1170
1144config 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
1152config INTEL_TURBO_MAX_3 1171config INTEL_TURBO_MAX_3
1153 bool "Intel Turbo Boost Max Technology 3.0 enumeration driver" 1172 bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
1154 depends on X86_64 && SCHED_MC_PRIO 1173 depends on X86_64 && SCHED_MC_PRIO
@@ -1170,6 +1189,17 @@ config SILEAD_DMI
1170 with the OS-image for the device. This option supplies the missing 1189 with the OS-image for the device. This option supplies the missing
1171 information. Enable this for x86 tablets with Silead touchscreens. 1190 information. Enable this for x86 tablets with Silead touchscreens.
1172 1191
1192config 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
1173endif # X86_PLATFORM_DEVICES 1203endif # X86_PLATFORM_DEVICES
1174 1204
1175config PMC_ATOM 1205config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index c32b34a72467..c388608ad2a3 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -23,11 +23,13 @@ obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
23obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o 23obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
24obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o 24obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o
25obj-$(CONFIG_ACER_WMI) += acer-wmi.o 25obj-$(CONFIG_ACER_WMI) += acer-wmi.o
26obj-$(CONFIG_ACER_WIRELESS) += acer-wireless.o
26obj-$(CONFIG_ACERHDF) += acerhdf.o 27obj-$(CONFIG_ACERHDF) += acerhdf.o
27obj-$(CONFIG_HP_ACCEL) += hp_accel.o 28obj-$(CONFIG_HP_ACCEL) += hp_accel.o
28obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o 29obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o
29obj-$(CONFIG_HP_WMI) += hp-wmi.o 30obj-$(CONFIG_HP_WMI) += hp-wmi.o
30obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o 31obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o
32obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o
31obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o 33obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
32obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o 34obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
33obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o 35obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o
@@ -86,5 +88,5 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
86obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o 88obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
87obj-$(CONFIG_PMC_ATOM) += pmc_atom.o 89obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
88obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o 90obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
89obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o
90obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o 91obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
92obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
diff --git a/drivers/platform/x86/acer-wireless.c b/drivers/platform/x86/acer-wireless.c
new file mode 100644
index 000000000000..858037987b33
--- /dev/null
+++ b/drivers/platform/x86/acer-wireless.c
@@ -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
18static const struct acpi_device_id acer_wireless_acpi_ids[] = {
19 {"10251229", 0},
20 {"", 0},
21};
22MODULE_DEVICE_TABLE(acpi, acer_wireless_acpi_ids);
23
24static 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
38static 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
58static 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};
67module_acpi_driver(acer_wireless_driver);
68
69MODULE_DESCRIPTION("Acer Wireless Radio Control Driver");
70MODULE_AUTHOR("Chris Chiu <chiu@gmail.com>");
71MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c
index 4eb8e1a472b2..9d7dbd925065 100644
--- a/drivers/platform/x86/alienware-wmi.c
+++ b/drivers/platform/x86/alienware-wmi.c
@@ -68,6 +68,14 @@ struct quirk_entry {
68 68
69static struct quirk_entry *quirks; 69static struct quirk_entry *quirks;
70 70
71
72static struct quirk_entry quirk_inspiron5675 = {
73 .num_zones = 2,
74 .hdmi_mux = 0,
75 .amplifier = 0,
76 .deepslp = 0,
77};
78
71static struct quirk_entry quirk_unknown = { 79static struct quirk_entry quirk_unknown = {
72 .num_zones = 2, 80 .num_zones = 2,
73 .hdmi_mux = 0, 81 .hdmi_mux = 0,
@@ -171,6 +179,15 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
171 }, 179 },
172 .driver_data = &quirk_asm201, 180 .driver_data = &quirk_asm201,
173 }, 181 },
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 },
174 {} 191 {}
175}; 192};
176 193
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 623d322447a2..7c4eb86c851e 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -24,7 +24,6 @@
24#include <linux/delay.h> 24#include <linux/delay.h>
25#include <linux/pci.h> 25#include <linux/pci.h>
26#include <linux/vga_switcheroo.h> 26#include <linux/vga_switcheroo.h>
27#include <linux/vgaarb.h>
28#include <acpi/video.h> 27#include <acpi/video.h>
29#include <asm/io.h> 28#include <asm/io.h>
30 29
@@ -54,7 +53,6 @@ struct apple_gmux_data {
54 bool indexed; 53 bool indexed;
55 struct mutex index_lock; 54 struct mutex index_lock;
56 55
57 struct pci_dev *pdev;
58 struct backlight_device *bdev; 56 struct backlight_device *bdev;
59 57
60 /* switcheroo data */ 58 /* switcheroo data */
@@ -599,23 +597,6 @@ static int gmux_resume(struct device *dev)
599 return 0; 597 return 0;
600} 598}
601 599
602static 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
619static int is_thunderbolt(struct device *dev, void *data) 600static int is_thunderbolt(struct device *dev, void *data)
620{ 601{
621 return to_pci_dev(dev)->is_thunderbolt; 602 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)
631 int ret = -ENXIO; 612 int ret = -ENXIO;
632 acpi_status status; 613 acpi_status status;
633 unsigned long long gpe; 614 unsigned long long gpe;
634 struct pci_dev *pdev = NULL;
635 615
636 if (apple_gmux_data) 616 if (apple_gmux_data)
637 return -EBUSY; 617 return -EBUSY;
@@ -682,7 +662,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
682 ver_minor = (version >> 16) & 0xff; 662 ver_minor = (version >> 16) & 0xff;
683 ver_release = (version >> 8) & 0xff; 663 ver_release = (version >> 8) & 0xff;
684 } else { 664 } else {
685 pr_info("gmux device not present or IO disabled\n"); 665 pr_info("gmux device not present\n");
686 ret = -ENODEV; 666 ret = -ENODEV;
687 goto err_release; 667 goto err_release;
688 } 668 }
@@ -690,23 +670,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
690 pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, 670 pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
691 ver_release, (gmux_data->indexed ? "indexed" : "classic")); 671 ver_release, (gmux_data->indexed ? "indexed" : "classic"));
692 672
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
710 memset(&props, 0, sizeof(props)); 673 memset(&props, 0, sizeof(props));
711 props.type = BACKLIGHT_PLATFORM; 674 props.type = BACKLIGHT_PLATFORM;
712 props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); 675 props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
@@ -822,10 +785,6 @@ err_enable_gpe:
822err_notify: 785err_notify:
823 backlight_device_unregister(bdev); 786 backlight_device_unregister(bdev);
824err_release: 787err_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);
829 release_region(gmux_data->iostart, gmux_data->iolen); 788 release_region(gmux_data->iostart, gmux_data->iolen);
830err_free: 789err_free:
831 kfree(gmux_data); 790 kfree(gmux_data);
@@ -845,11 +804,6 @@ static void gmux_remove(struct pnp_dev *pnp)
845 &gmux_notify_handler); 804 &gmux_notify_handler);
846 } 805 }
847 806
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 }
853 backlight_device_unregister(gmux_data->bdev); 807 backlight_device_unregister(gmux_data->bdev);
854 808
855 release_region(gmux_data->iostart, gmux_data->iolen); 809 release_region(gmux_data->iostart, gmux_data->iolen);
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index 5269a01d9bdd..136ff2b4cce5 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -111,7 +111,7 @@ static struct quirk_entry quirk_asus_x550lb = {
111 .xusb2pr = 0x01D9, 111 .xusb2pr = 0x01D9,
112}; 112};
113 113
114static struct quirk_entry quirk_asus_ux330uak = { 114static struct quirk_entry quirk_asus_forceals = {
115 .wmi_force_als_set = true, 115 .wmi_force_als_set = true,
116}; 116};
117 117
@@ -387,7 +387,7 @@ static const struct dmi_system_id asus_quirks[] = {
387 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 387 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
388 DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"), 388 DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"),
389 }, 389 },
390 .driver_data = &quirk_asus_ux330uak, 390 .driver_data = &quirk_asus_forceals,
391 }, 391 },
392 { 392 {
393 .callback = dmi_matched, 393 .callback = dmi_matched,
@@ -398,6 +398,15 @@ static const struct dmi_system_id asus_quirks[] = {
398 }, 398 },
399 .driver_data = &quirk_asus_x550lb, 399 .driver_data = &quirk_asus_x550lb,
400 }, 400 },
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 },
401 {}, 410 {},
402}; 411};
403 412
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index cd4725e7e0b5..a7b141992cb3 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -36,10 +36,10 @@
36#include "dell-smbios.h" 36#include "dell-smbios.h"
37 37
38struct quirk_entry { 38struct quirk_entry {
39 u8 touchpad_led; 39 bool touchpad_led;
40 u8 kbd_led_levels_off_1; 40 bool kbd_led_levels_off_1;
41 41
42 int needs_kbd_timeouts; 42 bool needs_kbd_timeouts;
43 /* 43 /*
44 * Ordered list of timeouts expressed in seconds. 44 * Ordered list of timeouts expressed in seconds.
45 * The list must end with -1 45 * The list must end with -1
@@ -50,7 +50,7 @@ struct quirk_entry {
50static struct quirk_entry *quirks; 50static struct quirk_entry *quirks;
51 51
52static struct quirk_entry quirk_dell_vostro_v130 = { 52static struct quirk_entry quirk_dell_vostro_v130 = {
53 .touchpad_led = 1, 53 .touchpad_led = true,
54}; 54};
55 55
56static int __init dmi_matched(const struct dmi_system_id *dmi) 56static 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)
64 * is used then BIOS silently set timeout to 0 without any error message. 64 * is used then BIOS silently set timeout to 0 without any error message.
65 */ 65 */
66static struct quirk_entry quirk_dell_xps13_9333 = { 66static struct quirk_entry quirk_dell_xps13_9333 = {
67 .needs_kbd_timeouts = 1, 67 .needs_kbd_timeouts = true,
68 .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, 68 .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 },
69}; 69};
70 70
71static struct quirk_entry quirk_dell_latitude_e6410 = { 71static struct quirk_entry quirk_dell_latitude_e6410 = {
72 .kbd_led_levels_off_1 = 1, 72 .kbd_led_levels_off_1 = true,
73}; 73};
74 74
75static struct platform_driver platform_driver = { 75static struct platform_driver platform_driver = {
@@ -78,7 +78,6 @@ static struct platform_driver platform_driver = {
78 } 78 }
79}; 79};
80 80
81static struct calling_interface_buffer *buffer;
82static struct platform_device *platform_device; 81static struct platform_device *platform_device;
83static struct backlight_device *dell_backlight_device; 82static struct backlight_device *dell_backlight_device;
84static struct rfkill *wifi_rfkill; 83static struct rfkill *wifi_rfkill;
@@ -110,6 +109,42 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
110 }, 109 },
111 }, 110 },
112 { 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 },
147 {
113 .ident = "Dell Computer Corporation", 148 .ident = "Dell Computer Corporation",
114 .matches = { 149 .matches = {
115 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 150 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
@@ -286,7 +321,8 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
286 { } 321 { }
287}; 322};
288 323
289void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) 324static void dell_fill_request(struct calling_interface_buffer *buffer,
325 u32 arg0, u32 arg1, u32 arg2, u32 arg3)
290{ 326{
291 memset(buffer, 0, sizeof(struct calling_interface_buffer)); 327 memset(buffer, 0, sizeof(struct calling_interface_buffer));
292 buffer->input[0] = arg0; 328 buffer->input[0] = arg0;
@@ -295,7 +331,8 @@ void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3)
295 buffer->input[3] = arg3; 331 buffer->input[3] = arg3;
296} 332}
297 333
298int dell_send_request(u16 class, u16 select) 334static int dell_send_request(struct calling_interface_buffer *buffer,
335 u16 class, u16 select)
299{ 336{
300 int ret; 337 int ret;
301 338
@@ -432,21 +469,22 @@ static int dell_rfkill_set(void *data, bool blocked)
432 int disable = blocked ? 1 : 0; 469 int disable = blocked ? 1 : 0;
433 unsigned long radio = (unsigned long)data; 470 unsigned long radio = (unsigned long)data;
434 int hwswitch_bit = (unsigned long)data - 1; 471 int hwswitch_bit = (unsigned long)data - 1;
472 struct calling_interface_buffer buffer;
435 int hwswitch; 473 int hwswitch;
436 int status; 474 int status;
437 int ret; 475 int ret;
438 476
439 dell_set_arguments(0, 0, 0, 0); 477 dell_fill_request(&buffer, 0, 0, 0, 0);
440 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 478 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
441 if (ret) 479 if (ret)
442 return ret; 480 return ret;
443 status = buffer->output[1]; 481 status = buffer.output[1];
444 482
445 dell_set_arguments(0x2, 0, 0, 0); 483 dell_fill_request(&buffer, 0x2, 0, 0, 0);
446 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 484 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
447 if (ret) 485 if (ret)
448 return ret; 486 return ret;
449 hwswitch = buffer->output[1]; 487 hwswitch = buffer.output[1];
450 488
451 /* If the hardware switch controls this radio, and the hardware 489 /* If the hardware switch controls this radio, and the hardware
452 switch is disabled, always disable the radio */ 490 switch is disabled, always disable the radio */
@@ -454,8 +492,8 @@ static int dell_rfkill_set(void *data, bool blocked)
454 (status & BIT(0)) && !(status & BIT(16))) 492 (status & BIT(0)) && !(status & BIT(16)))
455 disable = 1; 493 disable = 1;
456 494
457 dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0); 495 dell_fill_request(&buffer, 1 | (radio<<8) | (disable << 16), 0, 0, 0);
458 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 496 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
459 return ret; 497 return ret;
460} 498}
461 499
@@ -464,9 +502,11 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
464{ 502{
465 if (status & BIT(0)) { 503 if (status & BIT(0)) {
466 /* Has hw-switch, sync sw_state to BIOS */ 504 /* Has hw-switch, sync sw_state to BIOS */
505 struct calling_interface_buffer buffer;
467 int block = rfkill_blocked(rfkill); 506 int block = rfkill_blocked(rfkill);
468 dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0); 507 dell_fill_request(&buffer,
469 dell_send_request(CLASS_INFO, SELECT_RFKILL); 508 1 | (radio << 8) | (block << 16), 0, 0, 0);
509 dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
470 } else { 510 } else {
471 /* No hw-switch, sync BIOS state to sw_state */ 511 /* No hw-switch, sync BIOS state to sw_state */
472 rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); 512 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,
483static void dell_rfkill_query(struct rfkill *rfkill, void *data) 523static void dell_rfkill_query(struct rfkill *rfkill, void *data)
484{ 524{
485 int radio = ((unsigned long)data & 0xF); 525 int radio = ((unsigned long)data & 0xF);
526 struct calling_interface_buffer buffer;
486 int hwswitch; 527 int hwswitch;
487 int status; 528 int status;
488 int ret; 529 int ret;
489 530
490 dell_set_arguments(0, 0, 0, 0); 531 dell_fill_request(&buffer, 0, 0, 0, 0);
491 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 532 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
492 status = buffer->output[1]; 533 status = buffer.output[1];
493 534
494 if (ret != 0 || !(status & BIT(0))) { 535 if (ret != 0 || !(status & BIT(0))) {
495 return; 536 return;
496 } 537 }
497 538
498 dell_set_arguments(0, 0x2, 0, 0); 539 dell_fill_request(&buffer, 0, 0x2, 0, 0);
499 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 540 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
500 hwswitch = buffer->output[1]; 541 hwswitch = buffer.output[1];
501 542
502 if (ret != 0) 543 if (ret != 0)
503 return; 544 return;
@@ -514,22 +555,23 @@ static struct dentry *dell_laptop_dir;
514 555
515static int dell_debugfs_show(struct seq_file *s, void *data) 556static int dell_debugfs_show(struct seq_file *s, void *data)
516{ 557{
558 struct calling_interface_buffer buffer;
517 int hwswitch_state; 559 int hwswitch_state;
518 int hwswitch_ret; 560 int hwswitch_ret;
519 int status; 561 int status;
520 int ret; 562 int ret;
521 563
522 dell_set_arguments(0, 0, 0, 0); 564 dell_fill_request(&buffer, 0, 0, 0, 0);
523 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 565 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
524 if (ret) 566 if (ret)
525 return ret; 567 return ret;
526 status = buffer->output[1]; 568 status = buffer.output[1];
527 569
528 dell_set_arguments(0, 0x2, 0, 0); 570 dell_fill_request(&buffer, 0, 0x2, 0, 0);
529 hwswitch_ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 571 hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
530 if (hwswitch_ret) 572 if (hwswitch_ret)
531 return hwswitch_ret; 573 return hwswitch_ret;
532 hwswitch_state = buffer->output[1]; 574 hwswitch_state = buffer.output[1];
533 575
534 seq_printf(s, "return:\t%d\n", ret); 576 seq_printf(s, "return:\t%d\n", ret);
535 seq_printf(s, "status:\t0x%X\n", status); 577 seq_printf(s, "status:\t0x%X\n", status);
@@ -610,22 +652,23 @@ static const struct file_operations dell_debugfs_fops = {
610 652
611static void dell_update_rfkill(struct work_struct *ignored) 653static void dell_update_rfkill(struct work_struct *ignored)
612{ 654{
655 struct calling_interface_buffer buffer;
613 int hwswitch = 0; 656 int hwswitch = 0;
614 int status; 657 int status;
615 int ret; 658 int ret;
616 659
617 dell_set_arguments(0, 0, 0, 0); 660 dell_fill_request(&buffer, 0, 0, 0, 0);
618 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 661 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
619 status = buffer->output[1]; 662 status = buffer.output[1];
620 663
621 if (ret != 0) 664 if (ret != 0)
622 return; 665 return;
623 666
624 dell_set_arguments(0, 0x2, 0, 0); 667 dell_fill_request(&buffer, 0, 0x2, 0, 0);
625 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 668 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
626 669
627 if (ret == 0 && (status & BIT(0))) 670 if (ret == 0 && (status & BIT(0)))
628 hwswitch = buffer->output[1]; 671 hwswitch = buffer.output[1];
629 672
630 if (wifi_rfkill) { 673 if (wifi_rfkill) {
631 dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch); 674 dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch);
@@ -683,6 +726,7 @@ static struct notifier_block dell_laptop_rbtn_notifier = {
683 726
684static int __init dell_setup_rfkill(void) 727static int __init dell_setup_rfkill(void)
685{ 728{
729 struct calling_interface_buffer buffer;
686 int status, ret, whitelisted; 730 int status, ret, whitelisted;
687 const char *product; 731 const char *product;
688 732
@@ -698,9 +742,9 @@ static int __init dell_setup_rfkill(void)
698 if (!force_rfkill && !whitelisted) 742 if (!force_rfkill && !whitelisted)
699 return 0; 743 return 0;
700 744
701 dell_set_arguments(0, 0, 0, 0); 745 dell_fill_request(&buffer, 0, 0, 0, 0);
702 ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 746 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
703 status = buffer->output[1]; 747 status = buffer.output[1];
704 748
705 /* dell wireless info smbios call is not supported */ 749 /* dell wireless info smbios call is not supported */
706 if (ret != 0) 750 if (ret != 0)
@@ -853,6 +897,7 @@ static void dell_cleanup_rfkill(void)
853 897
854static int dell_send_intensity(struct backlight_device *bd) 898static int dell_send_intensity(struct backlight_device *bd)
855{ 899{
900 struct calling_interface_buffer buffer;
856 struct calling_interface_token *token; 901 struct calling_interface_token *token;
857 int ret; 902 int ret;
858 903
@@ -860,17 +905,21 @@ static int dell_send_intensity(struct backlight_device *bd)
860 if (!token) 905 if (!token)
861 return -ENODEV; 906 return -ENODEV;
862 907
863 dell_set_arguments(token->location, bd->props.brightness, 0, 0); 908 dell_fill_request(&buffer,
909 token->location, bd->props.brightness, 0, 0);
864 if (power_supply_is_system_supplied() > 0) 910 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);
866 else 913 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);
868 916
869 return ret; 917 return ret;
870} 918}
871 919
872static int dell_get_intensity(struct backlight_device *bd) 920static int dell_get_intensity(struct backlight_device *bd)
873{ 921{
922 struct calling_interface_buffer buffer;
874 struct calling_interface_token *token; 923 struct calling_interface_token *token;
875 int ret; 924 int ret;
876 925
@@ -878,14 +927,17 @@ static int dell_get_intensity(struct backlight_device *bd)
878 if (!token) 927 if (!token)
879 return -ENODEV; 928 return -ENODEV;
880 929
881 dell_set_arguments(token->location, 0, 0, 0); 930 dell_fill_request(&buffer, token->location, 0, 0, 0);
882 if (power_supply_is_system_supplied() > 0) 931 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);
884 else 934 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);
886 937
887 if (ret == 0) 938 if (ret == 0)
888 ret = buffer->output[1]; 939 ret = buffer.output[1];
940
889 return ret; 941 return ret;
890} 942}
891 943
@@ -1133,6 +1185,7 @@ static u8 kbd_previous_mode_bit;
1133 1185
1134static bool kbd_led_present; 1186static bool kbd_led_present;
1135static DEFINE_MUTEX(kbd_led_mutex); 1187static DEFINE_MUTEX(kbd_led_mutex);
1188static enum led_brightness kbd_led_level;
1136 1189
1137/* 1190/*
1138 * NOTE: there are three ways to set the keyboard backlight level. 1191 * NOTE: there are three ways to set the keyboard backlight level.
@@ -1149,31 +1202,33 @@ static DEFINE_MUTEX(kbd_led_mutex);
1149 1202
1150static int kbd_get_info(struct kbd_info *info) 1203static int kbd_get_info(struct kbd_info *info)
1151{ 1204{
1205 struct calling_interface_buffer buffer;
1152 u8 units; 1206 u8 units;
1153 int ret; 1207 int ret;
1154 1208
1155 dell_set_arguments(0, 0, 0, 0); 1209 dell_fill_request(&buffer, 0, 0, 0, 0);
1156 ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); 1210 ret = dell_send_request(&buffer,
1211 CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
1157 if (ret) 1212 if (ret)
1158 return ret; 1213 return ret;
1159 1214
1160 info->modes = buffer->output[1] & 0xFFFF; 1215 info->modes = buffer.output[1] & 0xFFFF;
1161 info->type = (buffer->output[1] >> 24) & 0xFF; 1216 info->type = (buffer.output[1] >> 24) & 0xFF;
1162 info->triggers = buffer->output[2] & 0xFF; 1217 info->triggers = buffer.output[2] & 0xFF;
1163 units = (buffer->output[2] >> 8) & 0xFF; 1218 units = (buffer.output[2] >> 8) & 0xFF;
1164 info->levels = (buffer->output[2] >> 16) & 0xFF; 1219 info->levels = (buffer.output[2] >> 16) & 0xFF;
1165 1220
1166 if (quirks && quirks->kbd_led_levels_off_1 && info->levels) 1221 if (quirks && quirks->kbd_led_levels_off_1 && info->levels)
1167 info->levels--; 1222 info->levels--;
1168 1223
1169 if (units & BIT(0)) 1224 if (units & BIT(0))
1170 info->seconds = (buffer->output[3] >> 0) & 0xFF; 1225 info->seconds = (buffer.output[3] >> 0) & 0xFF;
1171 if (units & BIT(1)) 1226 if (units & BIT(1))
1172 info->minutes = (buffer->output[3] >> 8) & 0xFF; 1227 info->minutes = (buffer.output[3] >> 8) & 0xFF;
1173 if (units & BIT(2)) 1228 if (units & BIT(2))
1174 info->hours = (buffer->output[3] >> 16) & 0xFF; 1229 info->hours = (buffer.output[3] >> 16) & 0xFF;
1175 if (units & BIT(3)) 1230 if (units & BIT(3))
1176 info->days = (buffer->output[3] >> 24) & 0xFF; 1231 info->days = (buffer.output[3] >> 24) & 0xFF;
1177 1232
1178 return ret; 1233 return ret;
1179} 1234}
@@ -1233,31 +1288,34 @@ static int kbd_set_level(struct kbd_state *state, u8 level)
1233 1288
1234static int kbd_get_state(struct kbd_state *state) 1289static int kbd_get_state(struct kbd_state *state)
1235{ 1290{
1291 struct calling_interface_buffer buffer;
1236 int ret; 1292 int ret;
1237 1293
1238 dell_set_arguments(0x1, 0, 0, 0); 1294 dell_fill_request(&buffer, 0, 0, 0, 0);
1239 ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); 1295 ret = dell_send_request(&buffer,
1296 CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
1240 if (ret) 1297 if (ret)
1241 return ret; 1298 return ret;
1242 1299
1243 state->mode_bit = ffs(buffer->output[1] & 0xFFFF); 1300 state->mode_bit = ffs(buffer.output[1] & 0xFFFF);
1244 if (state->mode_bit != 0) 1301 if (state->mode_bit != 0)
1245 state->mode_bit--; 1302 state->mode_bit--;
1246 1303
1247 state->triggers = (buffer->output[1] >> 16) & 0xFF; 1304 state->triggers = (buffer.output[1] >> 16) & 0xFF;
1248 state->timeout_value = (buffer->output[1] >> 24) & 0x3F; 1305 state->timeout_value = (buffer.output[1] >> 24) & 0x3F;
1249 state->timeout_unit = (buffer->output[1] >> 30) & 0x3; 1306 state->timeout_unit = (buffer.output[1] >> 30) & 0x3;
1250 state->als_setting = buffer->output[2] & 0xFF; 1307 state->als_setting = buffer.output[2] & 0xFF;
1251 state->als_value = (buffer->output[2] >> 8) & 0xFF; 1308 state->als_value = (buffer.output[2] >> 8) & 0xFF;
1252 state->level = (buffer->output[2] >> 16) & 0xFF; 1309 state->level = (buffer.output[2] >> 16) & 0xFF;
1253 state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F; 1310 state->timeout_value_ac = (buffer.output[2] >> 24) & 0x3F;
1254 state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3; 1311 state->timeout_unit_ac = (buffer.output[2] >> 30) & 0x3;
1255 1312
1256 return ret; 1313 return ret;
1257} 1314}
1258 1315
1259static int kbd_set_state(struct kbd_state *state) 1316static int kbd_set_state(struct kbd_state *state)
1260{ 1317{
1318 struct calling_interface_buffer buffer;
1261 int ret; 1319 int ret;
1262 u32 input1; 1320 u32 input1;
1263 u32 input2; 1321 u32 input2;
@@ -1270,8 +1328,9 @@ static int kbd_set_state(struct kbd_state *state)
1270 input2 |= (state->level & 0xFF) << 16; 1328 input2 |= (state->level & 0xFF) << 16;
1271 input2 |= (state->timeout_value_ac & 0x3F) << 24; 1329 input2 |= (state->timeout_value_ac & 0x3F) << 24;
1272 input2 |= (state->timeout_unit_ac & 0x3) << 30; 1330 input2 |= (state->timeout_unit_ac & 0x3) << 30;
1273 dell_set_arguments(0x2, input1, input2, 0); 1331 dell_fill_request(&buffer, 0x2, input1, input2, 0);
1274 ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); 1332 ret = dell_send_request(&buffer,
1333 CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
1275 1334
1276 return ret; 1335 return ret;
1277} 1336}
@@ -1298,6 +1357,7 @@ static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old)
1298 1357
1299static int kbd_set_token_bit(u8 bit) 1358static int kbd_set_token_bit(u8 bit)
1300{ 1359{
1360 struct calling_interface_buffer buffer;
1301 struct calling_interface_token *token; 1361 struct calling_interface_token *token;
1302 int ret; 1362 int ret;
1303 1363
@@ -1308,14 +1368,15 @@ static int kbd_set_token_bit(u8 bit)
1308 if (!token) 1368 if (!token)
1309 return -EINVAL; 1369 return -EINVAL;
1310 1370
1311 dell_set_arguments(token->location, token->value, 0, 0); 1371 dell_fill_request(&buffer, token->location, token->value, 0, 0);
1312 ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); 1372 ret = dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
1313 1373
1314 return ret; 1374 return ret;
1315} 1375}
1316 1376
1317static int kbd_get_token_bit(u8 bit) 1377static int kbd_get_token_bit(u8 bit)
1318{ 1378{
1379 struct calling_interface_buffer buffer;
1319 struct calling_interface_token *token; 1380 struct calling_interface_token *token;
1320 int ret; 1381 int ret;
1321 int val; 1382 int val;
@@ -1327,9 +1388,9 @@ static int kbd_get_token_bit(u8 bit)
1327 if (!token) 1388 if (!token)
1328 return -EINVAL; 1389 return -EINVAL;
1329 1390
1330 dell_set_arguments(token->location, 0, 0, 0); 1391 dell_fill_request(&buffer, token->location, 0, 0, 0);
1331 ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_STD); 1392 ret = dell_send_request(&buffer, CLASS_TOKEN_READ, SELECT_TOKEN_STD);
1332 val = buffer->output[1]; 1393 val = buffer.output[1];
1333 1394
1334 if (ret) 1395 if (ret)
1335 return ret; 1396 return ret;
@@ -1947,6 +2008,7 @@ static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev)
1947static int kbd_led_level_set(struct led_classdev *led_cdev, 2008static int kbd_led_level_set(struct led_classdev *led_cdev,
1948 enum led_brightness value) 2009 enum led_brightness value)
1949{ 2010{
2011 enum led_brightness new_value = value;
1950 struct kbd_state state; 2012 struct kbd_state state;
1951 struct kbd_state new_state; 2013 struct kbd_state new_state;
1952 u16 num; 2014 u16 num;
@@ -1976,6 +2038,9 @@ static int kbd_led_level_set(struct led_classdev *led_cdev,
1976 } 2038 }
1977 2039
1978out: 2040out:
2041 if (ret == 0)
2042 kbd_led_level = new_value;
2043
1979 mutex_unlock(&kbd_led_mutex); 2044 mutex_unlock(&kbd_led_mutex);
1980 return ret; 2045 return ret;
1981} 2046}
@@ -2003,6 +2068,9 @@ static int __init kbd_led_init(struct device *dev)
2003 if (kbd_led.max_brightness) 2068 if (kbd_led.max_brightness)
2004 kbd_led.max_brightness--; 2069 kbd_led.max_brightness--;
2005 } 2070 }
2071
2072 kbd_led_level = kbd_led_level_get(NULL);
2073
2006 ret = led_classdev_register(dev, &kbd_led); 2074 ret = led_classdev_register(dev, &kbd_led);
2007 if (ret) 2075 if (ret)
2008 kbd_led_present = false; 2076 kbd_led_present = false;
@@ -2027,13 +2095,25 @@ static void kbd_led_exit(void)
2027static int dell_laptop_notifier_call(struct notifier_block *nb, 2095static int dell_laptop_notifier_call(struct notifier_block *nb,
2028 unsigned long action, void *data) 2096 unsigned long action, void *data)
2029{ 2097{
2098 bool changed = false;
2099 enum led_brightness new_kbd_led_level;
2100
2030 switch (action) { 2101 switch (action) {
2031 case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED: 2102 case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED:
2032 if (!kbd_led_present) 2103 if (!kbd_led_present)
2033 break; 2104 break;
2034 2105
2035 led_classdev_notify_brightness_hw_changed(&kbd_led, 2106 mutex_lock(&kbd_led_mutex);
2036 kbd_led_level_get(&kbd_led)); 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);
2037 break; 2117 break;
2038 } 2118 }
2039 2119
@@ -2046,6 +2126,7 @@ static struct notifier_block dell_laptop_notifier = {
2046 2126
2047int dell_micmute_led_set(int state) 2127int dell_micmute_led_set(int state)
2048{ 2128{
2129 struct calling_interface_buffer buffer;
2049 struct calling_interface_token *token; 2130 struct calling_interface_token *token;
2050 2131
2051 if (state == 0) 2132 if (state == 0)
@@ -2058,8 +2139,8 @@ int dell_micmute_led_set(int state)
2058 if (!token) 2139 if (!token)
2059 return -ENODEV; 2140 return -ENODEV;
2060 2141
2061 dell_set_arguments(token->location, token->value, 0, 0); 2142 dell_fill_request(&buffer, token->location, token->value, 0, 0);
2062 dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); 2143 dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
2063 2144
2064 return state; 2145 return state;
2065} 2146}
@@ -2090,13 +2171,6 @@ static int __init dell_init(void)
2090 if (ret) 2171 if (ret)
2091 goto fail_platform_device2; 2172 goto fail_platform_device2;
2092 2173
2093 buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
2094 if (!buffer) {
2095 ret = -ENOMEM;
2096 goto fail_buffer;
2097 }
2098
2099
2100 ret = dell_setup_rfkill(); 2174 ret = dell_setup_rfkill();
2101 2175
2102 if (ret) { 2176 if (ret) {
@@ -2121,10 +2195,13 @@ static int __init dell_init(void)
2121 2195
2122 token = dell_smbios_find_token(BRIGHTNESS_TOKEN); 2196 token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
2123 if (token) { 2197 if (token) {
2124 dell_set_arguments(token->location, 0, 0, 0); 2198 struct calling_interface_buffer buffer;
2125 ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC); 2199
2200 dell_fill_request(&buffer, token->location, 0, 0, 0);
2201 ret = dell_send_request(&buffer,
2202 CLASS_TOKEN_READ, SELECT_TOKEN_AC);
2126 if (ret) 2203 if (ret)
2127 max_intensity = buffer->output[3]; 2204 max_intensity = buffer.output[3];
2128 } 2205 }
2129 2206
2130 if (max_intensity) { 2207 if (max_intensity) {
@@ -2158,8 +2235,6 @@ static int __init dell_init(void)
2158fail_get_brightness: 2235fail_get_brightness:
2159 backlight_device_unregister(dell_backlight_device); 2236 backlight_device_unregister(dell_backlight_device);
2160fail_backlight: 2237fail_backlight:
2161 kfree(buffer);
2162fail_buffer:
2163 dell_cleanup_rfkill(); 2238 dell_cleanup_rfkill();
2164fail_rfkill: 2239fail_rfkill:
2165 platform_device_del(platform_device); 2240 platform_device_del(platform_device);
@@ -2179,7 +2254,6 @@ static void __exit dell_exit(void)
2179 touchpad_led_exit(); 2254 touchpad_led_exit();
2180 kbd_led_exit(); 2255 kbd_led_exit();
2181 backlight_device_unregister(dell_backlight_device); 2256 backlight_device_unregister(dell_backlight_device);
2182 kfree(buffer);
2183 dell_cleanup_rfkill(); 2257 dell_cleanup_rfkill();
2184 if (platform_device) { 2258 if (platform_device) {
2185 platform_device_unregister(platform_device); 2259 platform_device_unregister(platform_device);
diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c
index 6a60db515bda..8541cde4cb7d 100644
--- a/drivers/platform/x86/dell-smbios.c
+++ b/drivers/platform/x86/dell-smbios.c
@@ -65,10 +65,10 @@ static struct smbios_call call_whitelist[] = {
65 65
66/* calls that are explicitly blacklisted */ 66/* calls that are explicitly blacklisted */
67static struct smbios_call call_blacklist[] = { 67static struct smbios_call call_blacklist[] = {
68 {0x0000, 01, 07}, /* manufacturing use */ 68 {0x0000, 1, 7}, /* manufacturing use */
69 {0x0000, 06, 05}, /* manufacturing use */ 69 {0x0000, 6, 5}, /* manufacturing use */
70 {0x0000, 11, 03}, /* write once */ 70 {0x0000, 11, 3}, /* write once */
71 {0x0000, 11, 07}, /* write once */ 71 {0x0000, 11, 7}, /* write once */
72 {0x0000, 11, 11}, /* write once */ 72 {0x0000, 11, 11}, /* write once */
73 {0x0000, 19, -1}, /* diagnostics */ 73 {0x0000, 19, -1}, /* diagnostics */
74 /* handled by kernel: dell-laptop */ 74 /* handled by kernel: dell-laptop */
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index fb25b20df316..2c9927430d85 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -261,6 +261,9 @@ static const u16 bios_to_linux_keycode[256] = {
261 * override them. 261 * override them.
262 */ 262 */
263static const struct key_entry dell_wmi_keymap_type_0010[] = { 263static const struct key_entry dell_wmi_keymap_type_0010[] = {
264 /* Mic mute */
265 { KE_KEY, 0x150, { KEY_MICMUTE } },
266
264 /* Fn-lock */ 267 /* Fn-lock */
265 { KE_IGNORE, 0x151, { KEY_RESERVED } }, 268 { KE_IGNORE, 0x151, { KEY_RESERVED } },
266 269
diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c
new file mode 100644
index 000000000000..2d645c505f81
--- /dev/null
+++ b/drivers/platform/x86/gpd-pocket-fan.c
@@ -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
19static int temp_limits[3] = { 55000, 60000, 65000 };
20module_param_array(temp_limits, int, NULL, 0444);
21MODULE_PARM_DESC(temp_limits,
22 "Milli-celcius values above which the fan speed increases");
23
24static int hysteresis = 3000;
25module_param(hysteresis, int, 0444);
26MODULE_PARM_DESC(hysteresis,
27 "Hysteresis in milli-celcius before lowering the fan speed");
28
29static int speed_on_ac = 2;
30module_param(speed_on_ac, int, 0444);
31MODULE_PARM_DESC(speed_on_ac,
32 "minimum fan speed to allow when system is powered by AC");
33
34struct 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
44static 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
55static 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
63static 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
100set_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
108static 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
114static 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
167static 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
176static 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
185static 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
193static SIMPLE_DEV_PM_OPS(gpd_pocket_fan_pm_ops,
194 gpd_pocket_fan_suspend,
195 gpd_pocket_fan_resume);
196
197static struct acpi_device_id gpd_pocket_fan_acpi_match[] = {
198 { "FAN02501" },
199 {},
200};
201MODULE_DEVICE_TABLE(acpi, gpd_pocket_fan_acpi_match);
202
203static 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
213module_platform_driver(gpd_pocket_fan_driver);
214MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
215MODULE_DESCRIPTION("GPD pocket fan driver");
216MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 53ab4e0f8962..b2bbddd09a52 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -124,10 +124,10 @@ static int read_method_int(acpi_handle handle, const char *method, int *val)
124 if (ACPI_FAILURE(status)) { 124 if (ACPI_FAILURE(status)) {
125 *val = -1; 125 *val = -1;
126 return -1; 126 return -1;
127 } else {
128 *val = result;
129 return 0;
130 } 127 }
128 *val = result;
129 return 0;
130
131} 131}
132 132
133static int method_gbmd(acpi_handle handle, unsigned long *ret) 133static int method_gbmd(acpi_handle handle, unsigned long *ret)
@@ -164,10 +164,10 @@ static int method_vpcr(acpi_handle handle, int cmd, int *ret)
164 if (ACPI_FAILURE(status)) { 164 if (ACPI_FAILURE(status)) {
165 *ret = -1; 165 *ret = -1;
166 return -1; 166 return -1;
167 } else {
168 *ret = result;
169 return 0;
170 } 167 }
168 *ret = result;
169 return 0;
170
171} 171}
172 172
173static int method_vpcw(acpi_handle handle, int cmd, int data) 173static 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)
231 if (val == 0) 231 if (val == 0)
232 return 0; 232 return 0;
233 } 233 }
234 pr_err("timeout in write_ec_cmd\n"); 234 pr_err("timeout in %s\n", __func__);
235 return -1; 235 return -1;
236} 236}
237 237
@@ -964,6 +964,13 @@ static void ideapad_wmi_notify(u32 value, void *context)
964 */ 964 */
965static const struct dmi_system_id no_hw_rfkill_list[] = { 965static const struct dmi_system_id no_hw_rfkill_list[] = {
966 { 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 },
973 {
967 .ident = "Lenovo G40-30", 974 .ident = "Lenovo G40-30",
968 .matches = { 975 .matches = {
969 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 976 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -1104,6 +1111,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
1104 }, 1111 },
1105 }, 1112 },
1106 { 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 },
1120 {
1107 .ident = "Lenovo Legion Y720-15IKBN", 1121 .ident = "Lenovo Legion Y720-15IKBN",
1108 .matches = { 1122 .matches = {
1109 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 1123 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index f470279c4c10..d1a01311c1a2 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -25,6 +25,7 @@
25#include <linux/acpi.h> 25#include <linux/acpi.h>
26#include <linux/suspend.h> 26#include <linux/suspend.h>
27#include <acpi/acpi_bus.h> 27#include <acpi/acpi_bus.h>
28#include <linux/dmi.h>
28 29
29MODULE_LICENSE("GPL"); 30MODULE_LICENSE("GPL");
30MODULE_AUTHOR("Alex Hung"); 31MODULE_AUTHOR("Alex Hung");
@@ -73,6 +74,24 @@ static const struct key_entry intel_array_keymap[] = {
73 { KE_END }, 74 { KE_END },
74}; 75};
75 76
77static 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
76struct intel_hid_priv { 95struct intel_hid_priv {
77 struct input_dev *input_dev; 96 struct input_dev *input_dev;
78 struct input_dev *array; 97 struct input_dev *array;
@@ -263,10 +282,27 @@ wakeup:
263 ev_index); 282 ev_index);
264} 283}
265 284
285static 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
266static int intel_hid_probe(struct platform_device *device) 302static int intel_hid_probe(struct platform_device *device)
267{ 303{
268 acpi_handle handle = ACPI_HANDLE(&device->dev); 304 acpi_handle handle = ACPI_HANDLE(&device->dev);
269 unsigned long long event_cap, mode; 305 unsigned long long mode;
270 struct intel_hid_priv *priv; 306 struct intel_hid_priv *priv;
271 acpi_status status; 307 acpi_status status;
272 int err; 308 int err;
@@ -299,8 +335,7 @@ static int intel_hid_probe(struct platform_device *device)
299 } 335 }
300 336
301 /* Setup 5 button array */ 337 /* Setup 5 button array */
302 status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap); 338 if (button_array_present(device)) {
303 if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) {
304 dev_info(&device->dev, "platform supports 5 button array\n"); 339 dev_info(&device->dev, "platform supports 5 button array\n");
305 err = intel_button_array_input_setup(device); 340 err = intel_button_array_input_setup(device);
306 if (err) 341 if (err)
diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c
index 58c5ff36523a..b703d6f5b099 100644
--- a/drivers/platform/x86/intel-vbtn.c
+++ b/drivers/platform/x86/intel-vbtn.c
@@ -1,30 +1,21 @@
1// SPDX-License-Identifier: GPL-2.0+
1/* 2/*
2 * Intel Virtual Button driver for Windows 8.1+ 3 * Intel Virtual Button driver for Windows 8.1+
3 * 4 *
4 * Copyright (C) 2016 AceLan Kao <acelan.kao@canonical.com> 5 * Copyright (C) 2016 AceLan Kao <acelan.kao@canonical.com>
5 * Copyright (C) 2016 Alex Hung <alex.hung@canonical.com> 6 * 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 *
17 */ 7 */
18 8
9#include <linux/acpi.h>
10#include <linux/input.h>
11#include <linux/input/sparse-keymap.h>
19#include <linux/kernel.h> 12#include <linux/kernel.h>
20#include <linux/module.h> 13#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/input.h>
23#include <linux/platform_device.h> 14#include <linux/platform_device.h>
24#include <linux/input/sparse-keymap.h>
25#include <linux/acpi.h>
26#include <linux/suspend.h> 15#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
28 19
29MODULE_LICENSE("GPL"); 20MODULE_LICENSE("GPL");
30MODULE_AUTHOR("AceLan Kao"); 21MODULE_AUTHOR("AceLan Kao");
@@ -38,10 +29,16 @@ static const struct acpi_device_id intel_vbtn_ids[] = {
38static const struct key_entry intel_vbtn_keymap[] = { 29static const struct key_entry intel_vbtn_keymap[] = {
39 { KE_KEY, 0xC0, { KEY_POWER } }, /* power key press */ 30 { KE_KEY, 0xC0, { KEY_POWER } }, /* power key press */
40 { KE_IGNORE, 0xC1, { KEY_POWER } }, /* power key release */ 31 { 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 */
41 { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */ 34 { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */
42 { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */ 35 { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */
43 { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */ 36 { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */
44 { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */ 37 { 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 */
45 { KE_END }, 42 { KE_END },
46}; 43};
47 44
@@ -74,20 +71,35 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
74{ 71{
75 struct platform_device *device = context; 72 struct platform_device *device = context;
76 struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); 73 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;
77 77
78 if (priv->wakeup_mode) { 78 if (priv->wakeup_mode) {
79 if (sparse_keymap_entry_from_scancode(priv->input_dev, event)) { 79 if (sparse_keymap_entry_from_scancode(priv->input_dev, event)) {
80 pm_wakeup_hard_event(&device->dev); 80 pm_wakeup_hard_event(&device->dev);
81 return; 81 return;
82 } 82 }
83 } else if (sparse_keymap_report_event(priv->input_dev, event, 1, true)) { 83 goto out_unknown;
84 return;
85 } 84 }
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
96out_unknown:
86 dev_dbg(&device->dev, "unknown event index 0x%x\n", event); 97 dev_dbg(&device->dev, "unknown event index 0x%x\n", event);
87} 98}
88 99
89static int intel_vbtn_probe(struct platform_device *device) 100static int intel_vbtn_probe(struct platform_device *device)
90{ 101{
102 struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL };
91 acpi_handle handle = ACPI_HANDLE(&device->dev); 103 acpi_handle handle = ACPI_HANDLE(&device->dev);
92 struct intel_vbtn_priv *priv; 104 struct intel_vbtn_priv *priv;
93 acpi_status status; 105 acpi_status status;
@@ -110,6 +122,23 @@ static int intel_vbtn_probe(struct platform_device *device)
110 return err; 122 return err;
111 } 123 }
112 124
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
113 status = acpi_install_notify_handler(handle, 142 status = acpi_install_notify_handler(handle,
114 ACPI_DEVICE_NOTIFY, 143 ACPI_DEVICE_NOTIFY,
115 notify_handler, 144 notify_handler,
diff --git a/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c
new file mode 100644
index 000000000000..38b8e7cfe88c
--- /dev/null
+++ b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c
@@ -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
19static 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
35static 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
69static 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
76static const struct platform_device_id chtdc_ti_pwrbtn_id_table[] = {
77 { .name = "chtdc_ti_pwrbtn" },
78 {},
79};
80MODULE_DEVICE_TABLE(platform, chtdc_ti_pwrbtn_id_table);
81
82static 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};
90module_platform_driver(chtdc_ti_pwrbtn_driver);
91
92MODULE_DESCRIPTION("Power-button driver for Dollar Cove TI PMIC");
93MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c
index f7b67e898abc..a473dc51b18d 100644
--- a/drivers/platform/x86/intel_int0002_vgpio.c
+++ b/drivers/platform/x86/intel_int0002_vgpio.c
@@ -180,7 +180,7 @@ static int int0002_probe(struct platform_device *pdev)
180 * to gpiochip_set_chained_irqchip, because the irq is shared. 180 * to gpiochip_set_chained_irqchip, because the irq is shared.
181 */ 181 */
182 ret = devm_request_irq(dev, irq, int0002_irq, 182 ret = devm_request_irq(dev, irq, int0002_irq,
183 IRQF_SHARED | IRQF_NO_THREAD, "INT0002", chip); 183 IRQF_SHARED, "INT0002", chip);
184 if (ret) { 184 if (ret) {
185 dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret); 185 dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret);
186 return ret; 186 return ret;
diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 17e08b42b0a9..43bbe74743d9 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -18,20 +18,24 @@
18 * 18 *
19 */ 19 */
20 20
21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
23#include <linux/acpi.h>
21#include <linux/debugfs.h> 24#include <linux/debugfs.h>
22#include <linux/delay.h> 25#include <linux/delay.h>
23#include <linux/device.h>
24#include <linux/init.h>
25#include <linux/io.h> 26#include <linux/io.h>
27#include <linux/module.h>
26#include <linux/pci.h> 28#include <linux/pci.h>
27#include <linux/uaccess.h> 29#include <linux/uaccess.h>
28 30
29#include <asm/cpu_device_id.h> 31#include <asm/cpu_device_id.h>
30#include <asm/intel-family.h> 32#include <asm/intel-family.h>
31#include <asm/pmc_core.h>
32 33
33#include "intel_pmc_core.h" 34#include "intel_pmc_core.h"
34 35
36#define ICPU(model, data) \
37 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (kernel_ulong_t)data }
38
35static struct pmc_dev pmc; 39static struct pmc_dev pmc;
36 40
37static const struct pmc_bit_map spt_pll_map[] = { 41static const struct pmc_bit_map spt_pll_map[] = {
@@ -119,10 +123,88 @@ static const struct pmc_reg_map spt_reg_map = {
119 .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT, 123 .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT,
120}; 124};
121 125
122static const struct pci_device_id pmc_pci_ids[] = { 126/* Cannonlake: PGD PFET Enable Ack Status Register(s) bitmap */
123 { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), 127static const struct pmc_bit_map cnp_pfear_map[] = {
124 (kernel_ulong_t)&spt_reg_map }, 128 {"PMC", BIT(0)},
125 { 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
199static 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,
126}; 208};
127 209
128static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset) 210static 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)
146 return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP; 228 return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP;
147} 229}
148 230
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 */
164int 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}
178EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read);
179
180static int pmc_core_dev_state_get(void *data, u64 *val) 231static int pmc_core_dev_state_get(void *data, u64 *val)
181{ 232{
182 struct pmc_dev *pmcdev = data; 233 struct pmc_dev *pmcdev = data;
@@ -437,47 +488,33 @@ static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
437 488
438static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) 489static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
439{ 490{
440 struct dentry *dir, *file; 491 struct dentry *dir;
441 492
442 dir = debugfs_create_dir("pmc_core", NULL); 493 dir = debugfs_create_dir("pmc_core", NULL);
443 if (!dir) 494 if (!dir)
444 return -ENOMEM; 495 return -ENOMEM;
445 496
446 pmcdev->dbgfs_dir = dir; 497 pmcdev->dbgfs_dir = dir;
447 file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO, 498
448 dir, pmcdev, &pmc_core_dev_state); 499 debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev,
449 if (!file) 500 &pmc_core_dev_state);
450 goto err; 501
451 502 debugfs_create_file("pch_ip_power_gating_status", 0444, dir, pmcdev,
452 file = debugfs_create_file("pch_ip_power_gating_status", 503 &pmc_core_ppfear_ops);
453 S_IFREG | S_IRUGO, dir, pmcdev, 504
454 &pmc_core_ppfear_ops); 505 debugfs_create_file("ltr_ignore", 0644, dir, pmcdev,
455 if (!file) 506 &pmc_core_ltr_ignore_ops);
456 goto err; 507
457 508 if (pmcdev->map->pll_sts)
458 file = debugfs_create_file("mphy_core_lanes_power_gating_status", 509 debugfs_create_file("pll_status", 0444, dir, pmcdev,
459 S_IFREG | S_IRUGO, dir, pmcdev, 510 &pmc_core_pll_ops);
460 &pmc_core_mphy_pg_ops); 511
461 if (!file) 512 if (pmcdev->map->mphy_sts)
462 goto err; 513 debugfs_create_file("mphy_core_lanes_power_gating_status",
463 514 0444, dir, pmcdev,
464 file = debugfs_create_file("pll_status", 515 &pmc_core_mphy_pg_ops);
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;
476 516
477 return 0; 517 return 0;
478err:
479 pmc_core_dbgfs_unregister(pmcdev);
480 return -ENODEV;
481} 518}
482#else 519#else
483static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) 520static 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)
491#endif /* CONFIG_DEBUG_FS */ 528#endif /* CONFIG_DEBUG_FS */
492 529
493static const struct x86_cpu_id intel_pmc_core_ids[] = { 530static const struct x86_cpu_id intel_pmc_core_ids[] = {
494 { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT, 531 ICPU(INTEL_FAM6_SKYLAKE_MOBILE, &spt_reg_map),
495 (kernel_ulong_t)NULL}, 532 ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, &spt_reg_map),
496 { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT, 533 ICPU(INTEL_FAM6_KABYLAKE_MOBILE, &spt_reg_map),
497 (kernel_ulong_t)NULL}, 534 ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, &spt_reg_map),
498 { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_MOBILE, X86_FEATURE_MWAIT, 535 ICPU(INTEL_FAM6_CANNONLAKE_MOBILE, &cnp_reg_map),
499 (kernel_ulong_t)NULL},
500 { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_DESKTOP, X86_FEATURE_MWAIT,
501 (kernel_ulong_t)NULL},
502 {} 536 {}
503}; 537};
504 538
505static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) 539MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids);
540
541static const struct pci_device_id pmc_pci_ids[] = {
542 { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), 0},
543 { 0, },
544};
545
546static int __init pmc_core_probe(void)
506{ 547{
507 struct device *ptr_dev = &dev->dev;
508 struct pmc_dev *pmcdev = &pmc; 548 struct pmc_dev *pmcdev = &pmc;
509 const struct x86_cpu_id *cpu_id; 549 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;
511 int err; 551 int err;
512 552
513 cpu_id = x86_match_cpu(intel_pmc_core_ids); 553 cpu_id = x86_match_cpu(intel_pmc_core_ids);
514 if (!cpu_id) { 554 if (!cpu_id)
515 dev_dbg(&dev->dev, "PMC Core: cpuid mismatch.\n"); 555 return -ENODEV;
516 return -EINVAL; 556
517 } 557 pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data;
518 558
519 err = pcim_enable_device(dev); 559 /*
520 if (err < 0) { 560 * Coffeelake has CPU ID of Kabylake and Cannonlake PCH. So here
521 dev_dbg(&dev->dev, "PMC Core: failed to enable Power Management Controller.\n"); 561 * Sunrisepoint PCH regmap can't be used. Use Cannonlake PCH regmap
522 return err; 562 * in this case.
523 } 563 */
524 564 if (!pci_dev_present(pmc_pci_ids))
525 err = pci_read_config_dword(dev, 565 pmcdev->map = &cnp_reg_map;
526 SPT_PMC_BASE_ADDR_OFFSET, 566
527 &pmcdev->base_addr); 567 if (lpit_read_residency_count_address(&slp_s0_addr))
528 if (err < 0) { 568 pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT;
529 dev_dbg(&dev->dev, "PMC Core: failed to read PCI config space.\n"); 569 else
530 return err; 570 pmcdev->base_addr = slp_s0_addr - pmcdev->map->slp_s0_offset;
531 } 571
532 pmcdev->base_addr &= PMC_BASE_ADDR_MASK; 572 pmcdev->regbase = ioremap(pmcdev->base_addr,
533 dev_dbg(&dev->dev, "PMC Core: PWRMBASE is %#x\n", pmcdev->base_addr); 573 pmcdev->map->regmap_length);
534 574 if (!pmcdev->regbase)
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");
540 return -ENOMEM; 575 return -ENOMEM;
541 }
542 576
543 mutex_init(&pmcdev->lock); 577 mutex_init(&pmcdev->lock);
544 pmcdev->map = map;
545 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(); 578 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
546 579
547 err = pmc_core_dbgfs_register(pmcdev); 580 err = pmc_core_dbgfs_register(pmcdev);
548 if (err < 0) 581 if (err < 0) {
549 dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n"); 582 pr_warn(" debugfs register failed.\n");
583 iounmap(pmcdev->regbase);
584 return err;
585 }
550 586
551 pmc.has_slp_s0_res = true; 587 pr_info(" initialized\n");
552 return 0; 588 return 0;
553} 589}
590module_init(pmc_core_probe)
554 591
555static struct pci_driver intel_pmc_core_driver = { 592static void __exit pmc_core_remove(void)
556 .name = "intel_pmc_core", 593{
557 .id_table = pmc_pci_ids, 594 struct pmc_dev *pmcdev = &pmc;
558 .probe = pmc_core_probe, 595
559}; 596 pmc_core_dbgfs_unregister(pmcdev);
597 mutex_destroy(&pmcdev->lock);
598 iounmap(pmcdev->regbase);
599}
600module_exit(pmc_core_remove)
560 601
561builtin_pci_driver(intel_pmc_core_driver); 602MODULE_LICENSE("GPL v2");
603MODULE_DESCRIPTION("Intel PMC Core Driver");
diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
index 3d225a9cc09f..5fa5f97870aa 100644
--- a/drivers/platform/x86/intel_pmc_core.h
+++ b/drivers/platform/x86/intel_pmc_core.h
@@ -21,9 +21,10 @@
21#ifndef PMC_CORE_H 21#ifndef PMC_CORE_H
22#define PMC_CORE_H 22#define PMC_CORE_H
23 23
24#define PMC_BASE_ADDR_DEFAULT 0xFE000000
25
24/* Sunrise Point Power Management Controller PCI Device ID */ 26/* Sunrise Point Power Management Controller PCI Device ID */
25#define SPT_PMC_PCI_DEVICE_ID 0x9d21 27#define SPT_PMC_PCI_DEVICE_ID 0x9d21
26
27#define SPT_PMC_BASE_ADDR_OFFSET 0x48 28#define SPT_PMC_BASE_ADDR_OFFSET 0x48
28#define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c 29#define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c
29#define SPT_PMC_PM_CFG_OFFSET 0x18 30#define SPT_PMC_PM_CFG_OFFSET 0x18
@@ -122,6 +123,17 @@ enum ppfear_regs {
122#define SPT_PMC_BIT_MPHY_CMN_LANE2 BIT(2) 123#define SPT_PMC_BIT_MPHY_CMN_LANE2 BIT(2)
123#define SPT_PMC_BIT_MPHY_CMN_LANE3 BIT(3) 124#define SPT_PMC_BIT_MPHY_CMN_LANE3 BIT(3)
124 125
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
125struct pmc_bit_map { 137struct pmc_bit_map {
126 const char *name; 138 const char *name;
127 u32 bit_mask; 139 u32 bit_mask;
@@ -135,7 +147,6 @@ struct pmc_bit_map {
135 * @pll_sts: Maps name of PLL to corresponding bit status 147 * @pll_sts: Maps name of PLL to corresponding bit status
136 * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency 148 * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency
137 * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit 149 * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit
138 * @base_address: Base address of PWRMBASE defined in BIOS writer guide
139 * @regmap_length: Length of memory to map from PWRMBASE address to access 150 * @regmap_length: Length of memory to map from PWRMBASE address to access
140 * @ppfear0_offset: PWRMBASE offset to to read PPFEAR* 151 * @ppfear0_offset: PWRMBASE offset to to read PPFEAR*
141 * @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from 152 * @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from
@@ -152,7 +163,6 @@ struct pmc_reg_map {
152 const struct pmc_bit_map *pll_sts; 163 const struct pmc_bit_map *pll_sts;
153 const u32 slp_s0_offset; 164 const u32 slp_s0_offset;
154 const u32 ltr_ignore_offset; 165 const u32 ltr_ignore_offset;
155 const u32 base_address;
156 const int regmap_length; 166 const int regmap_length;
157 const u32 ppfear0_offset; 167 const u32 ppfear0_offset;
158 const int ppfear_buckets; 168 const int ppfear_buckets;
@@ -162,12 +172,14 @@ struct pmc_reg_map {
162 172
163/** 173/**
164 * struct pmc_dev - pmc device structure 174 * struct pmc_dev - pmc device structure
165 * @base_addr: comtains pmc base address 175 * @base_addr: contains pmc base address
166 * @regbase: pointer to io-remapped memory location 176 * @regbase: pointer to io-remapped memory location
167 * @dbgfs_dir: path to debug fs interface 177 * @map: pointer to pmc_reg_map struct that contains platform
168 * @feature_available: flag to indicate whether 178 * specific attributes
169 * the feature is available 179 * @dbgfs_dir: path to debugfs interface
170 * on a particular platform or not. 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
171 * 183 *
172 * pmc_dev contains info about power management controller device. 184 * pmc_dev contains info about power management controller device.
173 */ 185 */
@@ -178,7 +190,6 @@ struct pmc_dev {
178#if IS_ENABLED(CONFIG_DEBUG_FS) 190#if IS_ENABLED(CONFIG_DEBUG_FS)
179 struct dentry *dbgfs_dir; 191 struct dentry *dbgfs_dir;
180#endif /* CONFIG_DEBUG_FS */ 192#endif /* CONFIG_DEBUG_FS */
181 bool has_slp_s0_res;
182 int pmc_xram_read_bit; 193 int pmc_xram_read_bit;
183 struct mutex lock; /* generic mutex lock for PMC Core */ 194 struct mutex lock; /* generic mutex lock for PMC Core */
184}; 195};
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index e03fa31446ca..e7edc8c63936 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -215,11 +215,11 @@ static inline int is_gcr_valid(u32 offset)
215} 215}
216 216
217/** 217/**
218 * intel_pmc_gcr_read() - Read PMC GCR register 218 * intel_pmc_gcr_read() - Read a 32-bit PMC GCR register
219 * @offset: offset of GCR register from GCR address base 219 * @offset: offset of GCR register from GCR address base
220 * @data: data pointer for storing the register output 220 * @data: data pointer for storing the register output
221 * 221 *
222 * Reads the PMC GCR register of given offset. 222 * Reads the 32-bit PMC GCR register at given offset.
223 * 223 *
224 * Return: negative value on error or 0 on success. 224 * Return: negative value on error or 0 on success.
225 */ 225 */
@@ -244,6 +244,35 @@ int intel_pmc_gcr_read(u32 offset, u32 *data)
244EXPORT_SYMBOL_GPL(intel_pmc_gcr_read); 244EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
245 245
246/** 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 */
255int 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}
273EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64);
274
275/**
247 * intel_pmc_gcr_write() - Write PMC GCR register 276 * intel_pmc_gcr_write() - Write PMC GCR register
248 * @offset: offset of GCR register from GCR address base 277 * @offset: offset of GCR register from GCR address base
249 * @data: register update value 278 * @data: register update value
diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c
index 4249e8267bbc..ffd0474b0531 100644
--- a/drivers/platform/x86/intel_telemetry_debugfs.c
+++ b/drivers/platform/x86/intel_telemetry_debugfs.c
@@ -23,7 +23,6 @@
23 */ 23 */
24#include <linux/debugfs.h> 24#include <linux/debugfs.h>
25#include <linux/device.h> 25#include <linux/device.h>
26#include <linux/io.h>
27#include <linux/module.h> 26#include <linux/module.h>
28#include <linux/pci.h> 27#include <linux/pci.h>
29#include <linux/seq_file.h> 28#include <linux/seq_file.h>
@@ -32,11 +31,10 @@
32#include <asm/cpu_device_id.h> 31#include <asm/cpu_device_id.h>
33#include <asm/intel-family.h> 32#include <asm/intel-family.h>
34#include <asm/intel_pmc_ipc.h> 33#include <asm/intel_pmc_ipc.h>
35#include <asm/intel_punit_ipc.h>
36#include <asm/intel_telemetry.h> 34#include <asm/intel_telemetry.h>
37 35
38#define DRIVER_NAME "telemetry_soc_debugfs" 36#define DRIVER_NAME "telemetry_soc_debugfs"
39#define DRIVER_VERSION "1.0.0" 37#define DRIVER_VERSION "1.0.0"
40 38
41/* ApolloLake SoC Event-IDs */ 39/* ApolloLake SoC Event-IDs */
42#define TELEM_APL_PSS_PSTATES_ID 0x2802 40#define TELEM_APL_PSS_PSTATES_ID 0x2802
@@ -98,10 +96,6 @@ static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp;
98static u64 suspend_shlw_res_temp, suspend_deep_res_temp; 96static u64 suspend_shlw_res_temp, suspend_deep_res_temp;
99 97
100struct telemetry_susp_stats { 98struct telemetry_susp_stats {
101 u32 shlw_swake_ctr;
102 u32 deep_swake_ctr;
103 u64 shlw_swake_res;
104 u64 deep_swake_res;
105 u32 shlw_ctr; 99 u32 shlw_ctr;
106 u32 deep_ctr; 100 u32 deep_ctr;
107 u64 shlw_res; 101 u64 shlw_res;
@@ -250,7 +244,6 @@ static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = {
250 {"PRTC", 25}, 244 {"PRTC", 25},
251}; 245};
252 246
253
254struct telemetry_debugfs_conf { 247struct telemetry_debugfs_conf {
255 struct telemetry_susp_stats suspend_stats; 248 struct telemetry_susp_stats suspend_stats;
256 struct dentry *telemetry_dbg_dir; 249 struct dentry *telemetry_dbg_dir;
@@ -385,7 +378,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused)
385 TELEM_APL_MASK_PCS_STATE; 378 TELEM_APL_MASK_PCS_STATE;
386 } 379 }
387 380
388
389 TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id, 381 TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id,
390 conf->pss_idle_evts - 1, 382 conf->pss_idle_evts - 1,
391 pss_idle, evtlog[index].telem_evtlog, 383 pss_idle, evtlog[index].telem_evtlog,
@@ -405,7 +397,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused)
405 conf->pcs_s0ix_blkd_data, 397 conf->pcs_s0ix_blkd_data,
406 TELEM_MASK_BYTE); 398 TELEM_MASK_BYTE);
407 399
408
409 TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id, 400 TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id,
410 conf->pss_wakeup_evts, 401 conf->pss_wakeup_evts,
411 pss_s0ix_wakeup, 402 pss_s0ix_wakeup,
@@ -498,7 +489,6 @@ static const struct file_operations telem_pss_ops = {
498 .release = single_release, 489 .release = single_release,
499}; 490};
500 491
501
502static int telem_ioss_states_show(struct seq_file *s, void *unused) 492static int telem_ioss_states_show(struct seq_file *s, void *unused)
503{ 493{
504 struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS]; 494 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)
598 588
599 seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n", 589 seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n",
600 s0ix_shlw_ctr - 590 s0ix_shlw_ctr -
601 conf->suspend_stats.shlw_ctr - 591 conf->suspend_stats.shlw_ctr,
602 conf->suspend_stats.shlw_swake_ctr,
603 (u64)((s0ix_shlw_res - 592 (u64)((s0ix_shlw_res -
604 conf->suspend_stats.shlw_res - 593 conf->suspend_stats.shlw_res)*10/192));
605 conf->suspend_stats.shlw_swake_res)*10/192));
606 594
607 seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n", 595 seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n",
608 s0ix_deep_ctr - 596 s0ix_deep_ctr -
609 conf->suspend_stats.deep_ctr - 597 conf->suspend_stats.deep_ctr,
610 conf->suspend_stats.deep_swake_ctr,
611 (u64)((s0ix_deep_res - 598 (u64)((s0ix_deep_res -
612 conf->suspend_stats.deep_res - 599 conf->suspend_stats.deep_res)*10/192));
613 conf->suspend_stats.deep_swake_res)*10/192));
614 600
615 seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n", 601 seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n",
616 conf->suspend_stats.shlw_ctr, 602 conf->suspend_stats.shlw_ctr,
@@ -620,14 +606,8 @@ static int telem_soc_states_show(struct seq_file *s, void *unused)
620 conf->suspend_stats.deep_ctr, 606 conf->suspend_stats.deep_ctr,
621 (u64)(conf->suspend_stats.deep_res*10)/192); 607 (u64)(conf->suspend_stats.deep_res*10)/192);
622 608
623 seq_printf(s, "Suspend(With Shallow-Wakes)\t %10u\t %10llu\n", 609 seq_printf(s, "TOTAL S0IX\t\t\t %10u\t %10llu\n", s0ix_total_ctr,
624 conf->suspend_stats.shlw_swake_ctr + 610 (u64)(s0ix_total_res*10/192));
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));
631 seq_puts(s, "\n-------------------------------------------------\n"); 611 seq_puts(s, "\n-------------------------------------------------\n");
632 seq_puts(s, "\t\tDEVICE STATES\n"); 612 seq_puts(s, "\t\tDEVICE STATES\n");
633 seq_puts(s, "-------------------------------------------------\n"); 613 seq_puts(s, "-------------------------------------------------\n");
@@ -772,7 +752,6 @@ static const struct file_operations telem_pss_trc_verb_ops = {
772 .release = single_release, 752 .release = single_release,
773}; 753};
774 754
775
776static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused) 755static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused)
777{ 756{
778 u32 verbosity; 757 u32 verbosity;
@@ -890,28 +869,45 @@ static int pm_suspend_exit_cb(void)
890 goto out; 869 goto out;
891 } 870 }
892 871
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
893 suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp; 897 suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp;
894 suspend_deep_ctr_exit -= suspend_deep_ctr_temp; 898 suspend_deep_ctr_exit -= suspend_deep_ctr_temp;
895 suspend_shlw_res_exit -= suspend_shlw_res_temp; 899 suspend_shlw_res_exit -= suspend_shlw_res_temp;
896 suspend_deep_res_exit -= suspend_deep_res_temp; 900 suspend_deep_res_exit -= suspend_deep_res_temp;
897 901
898 if (suspend_shlw_ctr_exit == 1) { 902 if (suspend_shlw_ctr_exit != 0) {
899 conf->suspend_stats.shlw_ctr += 903 conf->suspend_stats.shlw_ctr +=
900 suspend_shlw_ctr_exit; 904 suspend_shlw_ctr_exit;
901 905
902 conf->suspend_stats.shlw_res += 906 conf->suspend_stats.shlw_res +=
903 suspend_shlw_res_exit; 907 suspend_shlw_res_exit;
904 } 908 }
905 /* Shallow Wakes Case */
906 else if (suspend_shlw_ctr_exit > 1) {
907 conf->suspend_stats.shlw_swake_ctr +=
908 suspend_shlw_ctr_exit;
909 909
910 conf->suspend_stats.shlw_swake_res += 910 if (suspend_deep_ctr_exit != 0) {
911 suspend_shlw_res_exit;
912 }
913
914 if (suspend_deep_ctr_exit == 1) {
915 conf->suspend_stats.deep_ctr += 911 conf->suspend_stats.deep_ctr +=
916 suspend_deep_ctr_exit; 912 suspend_deep_ctr_exit;
917 913
@@ -919,15 +915,6 @@ static int pm_suspend_exit_cb(void)
919 suspend_deep_res_exit; 915 suspend_deep_res_exit;
920 } 916 }
921 917
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
931out: 918out:
932 suspend_prep_ok = 0; 919 suspend_prep_ok = 0;
933 return NOTIFY_OK; 920 return NOTIFY_OK;
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 504256c3660d..27de29961f5e 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -35,20 +35,31 @@
35#include <linux/dmi.h> 35#include <linux/dmi.h>
36#include <linux/i2c.h> 36#include <linux/i2c.h>
37#include <linux/i2c-mux.h> 37#include <linux/i2c-mux.h>
38#include <linux/io.h>
38#include <linux/module.h> 39#include <linux/module.h>
39#include <linux/platform_device.h> 40#include <linux/platform_device.h>
40#include <linux/platform_data/i2c-mux-reg.h> 41#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>
42 44
43#define MLX_PLAT_DEVICE_NAME "mlxplat" 45#define MLX_PLAT_DEVICE_NAME "mlxplat"
44 46
45/* LPC bus IO offsets */ 47/* LPC bus IO offsets */
46#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 48#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
47#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 49#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
48#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a 50#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
49#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558 51#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b
50#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564 52#define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40
51#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588 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
52#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 63#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
53#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb 64#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
54#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda 65#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
@@ -81,6 +92,7 @@
81/* mlxplat_priv - platform private data 92/* mlxplat_priv - platform private data
82 * @pdev_i2c - i2c controller platform device 93 * @pdev_i2c - i2c controller platform device
83 * @pdev_mux - array of mux platform devices 94 * @pdev_mux - array of mux platform devices
95 * @pdev_hotplug - hotplug platform devices
84 */ 96 */
85struct mlxplat_priv { 97struct mlxplat_priv {
86 struct platform_device *pdev_i2c; 98 struct platform_device *pdev_i2c;
@@ -138,86 +150,264 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
138}; 150};
139 151
140/* Platform hotplug devices */ 152/* Platform hotplug devices */
141static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = { 153static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
142 { 154 {
143 .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, 155 I2C_BOARD_INFO("24c02", 0x51),
144 .bus = 10,
145 }, 156 },
146 { 157 {
147 .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) }, 158 I2C_BOARD_INFO("24c02", 0x50),
148 .bus = 10,
149 }, 159 },
150}; 160};
151 161
152static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = { 162static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
153 { 163 {
154 .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, 164 I2C_BOARD_INFO("dps460", 0x59),
155 .bus = 10,
156 }, 165 },
157 { 166 {
158 .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) }, 167 I2C_BOARD_INFO("dps460", 0x58),
159 .bus = 10,
160 }, 168 },
161}; 169};
162 170
163static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = { 171static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
164 { 172 {
165 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 173 I2C_BOARD_INFO("24c32", 0x50),
166 .bus = 11,
167 }, 174 },
168 { 175 {
169 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 176 I2C_BOARD_INFO("24c32", 0x50),
170 .bus = 12,
171 }, 177 },
172 { 178 {
173 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 179 I2C_BOARD_INFO("24c32", 0x50),
174 .bus = 13,
175 }, 180 },
176 { 181 {
177 .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 182 I2C_BOARD_INFO("24c32", 0x50),
178 .bus = 14,
179 }, 183 },
180}; 184};
181 185
182/* Platform hotplug default data */ 186/* Platform hotplug default data */
187static 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
204static 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
221static 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
252static 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
183static 282static
184struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = { 283struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
185 .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 284 .items = mlxplat_mlxcpld_default_items,
186 .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 285 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
187 .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, 286 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
188 .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR, 287 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
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,
202}; 288};
203 289
204/* Platform hotplug MSN21xx system family data */ 290/* Platform hotplug MSN21xx system family data */
291static 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
205static 303static
206struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { 304struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
207 .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 305 .items = mlxplat_mlxcpld_msn21xx_items,
208 .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 306 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
209 .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 307 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
210 .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, 308 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
211 .pwr_mask = MLXPLAT_CPLD_PWR_MASK, 309};
212 .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 310
311static 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
327static 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
348static 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
369struct mlxplat_mlxcpld_regmap_context {
370 void __iomem *base;
371};
372
373static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
374
375static int
376mlxplat_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
384static int
385mlxplat_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
393static 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,
213}; 403};
214 404
215static struct resource mlxplat_mlxcpld_resources[] = { 405static struct resource mlxplat_mlxcpld_resources[] = {
216 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"), 406 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
217}; 407};
218 408
219static struct platform_device *mlxplat_dev; 409static struct platform_device *mlxplat_dev;
220static struct mlxcpld_hotplug_platform_data *mlxplat_hotplug; 410static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
221 411
222static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) 412static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
223{ 413{
@@ -286,6 +476,8 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
286 { } 476 { }
287}; 477};
288 478
479MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
480
289static int __init mlxplat_init(void) 481static int __init mlxplat_init(void)
290{ 482{
291 struct mlxplat_priv *priv; 483 struct mlxplat_priv *priv;
@@ -328,8 +520,23 @@ static int __init mlxplat_init(void)
328 } 520 }
329 } 521 }
330 522
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
331 priv->pdev_hotplug = platform_device_register_resndata( 538 priv->pdev_hotplug = platform_device_register_resndata(
332 &mlxplat_dev->dev, "mlxcpld-hotplug", 539 &mlxplat_dev->dev, "mlxreg-hotplug",
333 PLATFORM_DEVID_NONE, 540 PLATFORM_DEVID_NONE,
334 mlxplat_mlxcpld_resources, 541 mlxplat_mlxcpld_resources,
335 ARRAY_SIZE(mlxplat_mlxcpld_resources), 542 ARRAY_SIZE(mlxplat_mlxcpld_resources),
@@ -339,8 +546,16 @@ static int __init mlxplat_init(void)
339 goto fail_platform_mux_register; 546 goto fail_platform_mux_register;
340 } 547 }
341 548
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
342 return 0; 555 return 0;
343 556
557fail_platform_hotplug_register:
558 platform_device_unregister(priv->pdev_hotplug);
344fail_platform_mux_register: 559fail_platform_mux_register:
345 while (--i >= 0) 560 while (--i >= 0)
346 platform_device_unregister(priv->pdev_mux[i]); 561 platform_device_unregister(priv->pdev_mux[i]);
@@ -370,8 +585,3 @@ module_exit(mlxplat_exit);
370MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); 585MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
371MODULE_DESCRIPTION("Mellanox platform driver"); 586MODULE_DESCRIPTION("Mellanox platform driver");
372MODULE_LICENSE("Dual BSD/GPL"); 587MODULE_LICENSE("Dual BSD/GPL");
373MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
374MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
375MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
376MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
377MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
diff --git a/drivers/platform/x86/mlxcpld-hotplug.c b/drivers/platform/x86/mlxcpld-hotplug.c
deleted file mode 100644
index aff3686b3b37..000000000000
--- a/drivers/platform/x86/mlxcpld-hotplug.c
+++ /dev/null
@@ -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 */
62enum 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 */
85struct 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
103static 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]
137static 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
188static 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
210static 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
223static inline void
224mlxcpld_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 */
292static 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
353static 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
385static 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
421static 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
432static 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
492static 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
502static 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
510module_platform_driver(mlxcpld_hotplug_driver);
511
512MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
513MODULE_DESCRIPTION("Mellanox CPLD hotplug platform driver");
514MODULE_LICENSE("Dual BSD/GPL");
515MODULE_ALIAS("platform:mlxcpld-hotplug");
diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c
index 77bac859342d..4b3c37b6288c 100644
--- a/drivers/platform/x86/pmc_atom.c
+++ b/drivers/platform/x86/pmc_atom.c
@@ -208,6 +208,20 @@ static const struct pmc_data cht_data = {
208 .clks = cht_clks, 208 .clks = cht_clks,
209}; 209};
210 210
211#define DEFINE_SHOW_ATTRIBUTE(__name) \
212static int __name ## _open(struct inode *inode, struct file *file) \
213{ \
214 return single_open(file, __name ## _show, inode->i_private); \
215} \
216 \
217static 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
211static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset) 225static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset)
212{ 226{
213 return readl(pmc->regmap + reg_offset); 227 return readl(pmc->regmap + reg_offset);
@@ -309,17 +323,7 @@ static int pmc_dev_state_show(struct seq_file *s, void *unused)
309 return 0; 323 return 0;
310} 324}
311 325
312static int pmc_dev_state_open(struct inode *inode, struct file *file) 326DEFINE_SHOW_ATTRIBUTE(pmc_dev_state);
313{
314 return single_open(file, pmc_dev_state_show, inode->i_private);
315}
316
317static 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};
323 327
324static int pmc_pss_state_show(struct seq_file *s, void *unused) 328static int pmc_pss_state_show(struct seq_file *s, void *unused)
325{ 329{
@@ -336,17 +340,7 @@ static int pmc_pss_state_show(struct seq_file *s, void *unused)
336 return 0; 340 return 0;
337} 341}
338 342
339static int pmc_pss_state_open(struct inode *inode, struct file *file) 343DEFINE_SHOW_ATTRIBUTE(pmc_pss_state);
340{
341 return single_open(file, pmc_pss_state_show, inode->i_private);
342}
343
344static 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};
350 344
351static int pmc_sleep_tmr_show(struct seq_file *s, void *unused) 345static int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
352{ 346{
@@ -367,17 +361,7 @@ static int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
367 return 0; 361 return 0;
368} 362}
369 363
370static int pmc_sleep_tmr_open(struct inode *inode, struct file *file) 364DEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr);
371{
372 return single_open(file, pmc_sleep_tmr_show, inode->i_private);
373}
374
375static 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};
381 365
382static void pmc_dbgfs_unregister(struct pmc_dev *pmc) 366static void pmc_dbgfs_unregister(struct pmc_dev *pmc)
383{ 367{
@@ -395,17 +379,17 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc)
395 pmc->dbgfs_dir = dir; 379 pmc->dbgfs_dir = dir;
396 380
397 f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO, 381 f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO,
398 dir, pmc, &pmc_dev_state_ops); 382 dir, pmc, &pmc_dev_state_fops);
399 if (!f) 383 if (!f)
400 goto err; 384 goto err;
401 385
402 f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO, 386 f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO,
403 dir, pmc, &pmc_pss_state_ops); 387 dir, pmc, &pmc_pss_state_fops);
404 if (!f) 388 if (!f)
405 goto err; 389 goto err;
406 390
407 f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO, 391 f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO,
408 dir, pmc, &pmc_sleep_tmr_ops); 392 dir, pmc, &pmc_sleep_tmr_fops);
409 if (!f) 393 if (!f)
410 goto err; 394 goto err;
411 395
diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c
index 266535c2a72f..3a624090191d 100644
--- a/drivers/platform/x86/silead_dmi.c
+++ b/drivers/platform/x86/silead_dmi.c
@@ -67,6 +67,21 @@ static const struct silead_ts_dmi_data dexp_ursus_7w_data = {
67 .properties = dexp_ursus_7w_props, 67 .properties = dexp_ursus_7w_props,
68}; 68};
69 69
70static 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
80static 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
70static const struct property_entry surftab_wintron70_st70416_6_props[] = { 85static const struct property_entry surftab_wintron70_st70416_6_props[] = {
71 PROPERTY_ENTRY_U32("touchscreen-size-x", 884), 86 PROPERTY_ENTRY_U32("touchscreen-size-x", 884),
72 PROPERTY_ENTRY_U32("touchscreen-size-y", 632), 87 PROPERTY_ENTRY_U32("touchscreen-size-y", 632),
@@ -171,6 +186,97 @@ static const struct silead_ts_dmi_data digma_citi_e200_data = {
171 .properties = digma_citi_e200_props, 186 .properties = digma_citi_e200_props,
172}; 187};
173 188
189static 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
201static 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
206static 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
215static const struct silead_ts_dmi_data chuwi_hi8_data = {
216 .acpi_name = "MSSL0001:00",
217 .properties = chuwi_hi8_props,
218};
219
220static 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
230static const struct silead_ts_dmi_data chuwi_vi8_data = {
231 .acpi_name = "MSSL1680:00",
232 .properties = chuwi_vi8_props,
233};
234
235static 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
245static const struct silead_ts_dmi_data trekstor_primebook_c13_data = {
246 .acpi_name = "MSSL1680:00",
247 .properties = trekstor_primebook_c13_props,
248};
249
250static 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
261static const struct silead_ts_dmi_data teclast_x98plus2_data = {
262 .acpi_name = "MSSL1680:00",
263 .properties = teclast_x98plus2_props,
264};
265
266static 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
275static const struct silead_ts_dmi_data teclast_x3_plus_data = {
276 .acpi_name = "MSSL1680:00",
277 .properties = teclast_x3_plus_props,
278};
279
174static const struct dmi_system_id silead_ts_dmi_table[] = { 280static const struct dmi_system_id silead_ts_dmi_table[] = {
175 { 281 {
176 /* CUBE iwork8 Air */ 282 /* CUBE iwork8 Air */
@@ -199,6 +305,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
199 }, 305 },
200 }, 306 },
201 { 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 },
315 {
202 /* Trekstor Surftab Wintron 7.0 ST70416-6 */ 316 /* Trekstor Surftab Wintron 7.0 ST70416-6 */
203 .driver_data = (void *)&surftab_wintron70_st70416_6_data, 317 .driver_data = (void *)&surftab_wintron70_st70416_6_data,
204 .matches = { 318 .matches = {
@@ -209,6 +323,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
209 }, 323 },
210 }, 324 },
211 { 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 },
336 {
212 /* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */ 337 /* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */
213 .driver_data = (void *)&surftab_wintron70_st70416_6_data, 338 .driver_data = (void *)&surftab_wintron70_st70416_6_data,
214 .matches = { 339 .matches = {
@@ -271,6 +396,56 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
271 DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), 396 DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
272 }, 397 },
273 }, 398 },
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 },
274 { }, 449 { },
275}; 450};
276 451
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 117be48ff4de..d5eaf3b1edba 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -214,6 +214,10 @@ enum tpacpi_hkey_event_t {
214 /* AC-related events */ 214 /* AC-related events */
215 TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */ 215 TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */
216 216
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
217 /* Misc */ 221 /* Misc */
218 TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ 222 TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */
219}; 223};
@@ -2113,12 +2117,10 @@ static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode)
2113 TP_ACPI_MULTI_MODE_FLAT; 2117 TP_ACPI_MULTI_MODE_FLAT;
2114 break; 2118 break;
2115 case 4: 2119 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;
2121 case 5: 2120 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 */
2122 valid_modes = TP_ACPI_MULTI_MODE_LAPTOP | 2124 valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
2123 TP_ACPI_MULTI_MODE_FLAT | 2125 TP_ACPI_MULTI_MODE_FLAT |
2124 TP_ACPI_MULTI_MODE_TABLET | 2126 TP_ACPI_MULTI_MODE_TABLET |
@@ -4079,6 +4081,12 @@ static bool hotkey_notify_6xxx(const u32 hkey,
4079 *send_acpi_ev = false; 4081 *send_acpi_ev = false;
4080 break; 4082 break;
4081 4083
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
4082 default: 4090 default:
4083 pr_warn("unknown possible thermal alarm or keyboard event received\n"); 4091 pr_warn("unknown possible thermal alarm or keyboard event received\n");
4084 known = false; 4092 known = false;
diff --git a/include/linux/platform_data/mlxcpld-hotplug.h b/include/linux/platform_data/mlxcpld-hotplug.h
deleted file mode 100644
index e4cfcffaa6f4..000000000000
--- a/include/linux/platform_data/mlxcpld-hotplug.h
+++ /dev/null
@@ -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 */
48struct 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 */
79struct 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 */
diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
new file mode 100644
index 000000000000..fcdc707eab99
--- /dev/null
+++ b/include/linux/platform_data/mlxreg.h
@@ -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 */
50struct 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 */
71struct 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 */
96struct 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 */
115struct 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 */
133struct 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 */
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index 061fa62958a2..53fbae27b280 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -594,6 +594,7 @@
594#define BTN_DPAD_RIGHT 0x223 594#define BTN_DPAD_RIGHT 0x223
595 595
596#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ 596#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
597#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
597 598
598#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ 599#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
599#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ 600#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */