Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+2293 -1103
+1 -1
Documentation/ABI/testing/sysfs-driver-samsung-laptop
··· 3 3 KernelVersion: 2.6.33 4 4 Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 5 5 Description: Some Samsung laptops have different "performance levels" 6 - that are can be modified by a function key, and by this 6 + that can be modified by a function key, and by this 7 7 sysfs file. These values don't always make a whole lot 8 8 of sense, but some users like to modify them to keep 9 9 their fans quiet at all costs. Reading from this file
+11 -4
MAINTAINERS
··· 6001 6001 S: Maintained 6002 6002 F: drivers/input/touchscreen/goodix.c 6003 6003 6004 + GPD POCKET FAN DRIVER 6005 + M: Hans de Goede <hdegoede@redhat.com> 6006 + L: platform-driver-x86@vger.kernel.org 6007 + S: Maintained 6008 + F: drivers/platform/x86/gpd-pocket-fan.c 6009 + 6004 6010 GPIO ACPI SUPPORT 6005 6011 M: Mika Westerberg <mika.westerberg@linux.intel.com> 6006 6012 M: Andy Shevchenko <andriy.shevchenko@linux.intel.com> ··· 8945 8939 Q: http://patchwork.ozlabs.org/project/netdev/list/ 8946 8940 F: drivers/net/ethernet/mellanox/mlxfw/ 8947 8941 8948 - MELLANOX MLX CPLD HOTPLUG DRIVER 8942 + MELLANOX HARDWARE PLATFORM SUPPORT 8943 + M: Andy Shevchenko <andy@infradead.org> 8944 + M: Darren Hart <dvhart@infradead.org> 8949 8945 M: Vadim Pasternak <vadimp@mellanox.com> 8950 8946 L: platform-driver-x86@vger.kernel.org 8951 8947 S: Supported 8952 - F: drivers/platform/x86/mlxcpld-hotplug.c 8953 - F: include/linux/platform_data/mlxcpld-hotplug.h 8948 + F: drivers/platform/mellanox/ 8954 8949 8955 8950 MELLANOX MLX4 core VPI driver 8956 8951 M: Tariq Toukan <tariqt@mellanox.com> ··· 15141 15134 M: Darren Hart <dvhart@infradead.org> 15142 15135 M: Andy Shevchenko <andy@infradead.org> 15143 15136 L: platform-driver-x86@vger.kernel.org 15144 - T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git 15137 + T: git git://git.infradead.org/linux-platform-drivers-x86.git 15145 15138 S: Maintained 15146 15139 F: drivers/platform/x86/ 15147 15140 F: drivers/platform/olpc/
+6
arch/x86/include/asm/intel-family.h
··· 10 10 * 11 11 * Things ending in "2" are usually because we have no better 12 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 19 #define INTEL_FAM6_CORE_YONAH 0x0E ··· 52 48 #define INTEL_FAM6_SKYLAKE_X 0x55 53 49 #define INTEL_FAM6_KABYLAKE_MOBILE 0x8E 54 50 #define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E 51 + 52 + #define INTEL_FAM6_CANNONLAKE_MOBILE 0x66 55 53 56 54 /* "Small Core" Processors (Atom) */ 57 55
+6
arch/x86/include/asm/intel_pmc_ipc.h
··· 38 38 u32 *out, u32 outlen); 39 39 int intel_pmc_s0ix_counter_read(u64 *data); 40 40 int intel_pmc_gcr_read(u32 offset, u32 *data); 41 + int intel_pmc_gcr_read64(u32 offset, u64 *data); 41 42 int intel_pmc_gcr_write(u32 offset, u32 data); 42 43 int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val); 43 44 ··· 67 66 } 68 67 69 68 static inline int intel_pmc_gcr_read(u32 offset, u32 *data) 69 + { 70 + return -EINVAL; 71 + } 72 + 73 + static inline int intel_pmc_gcr_read64(u32 offset, u64 *data) 70 74 { 71 75 return -EINVAL; 72 76 }
-27
arch/x86/include/asm/pmc_core.h
··· 1 - /* 2 - * Intel Core SoC Power Management Controller Header File 3 - * 4 - * Copyright (c) 2016, Intel Corporation. 5 - * All Rights Reserved. 6 - * 7 - * Authors: Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com> 8 - * Vishwanath Somayaji <vishwanath.somayaji@intel.com> 9 - * 10 - * This program is free software; you can redistribute it and/or modify it 11 - * under the terms and conditions of the GNU General Public License, 12 - * version 2, as published by the Free Software Foundation. 13 - * 14 - * This program is distributed in the hope it will be useful, but WITHOUT 15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 - * more details. 18 - * 19 - */ 20 - 21 - #ifndef _ASM_PMC_CORE_H 22 - #define _ASM_PMC_CORE_H 23 - 24 - /* API to read SLP_S0_RESIDENCY counter */ 25 - int intel_pmc_slp_s0_counter_read(u32 *data); 26 - 27 - #endif /* _ASM_PMC_CORE_H */
+1
drivers/acpi/acpi_lpit.c
··· 100 100 101 101 return 0; 102 102 } 103 + EXPORT_SYMBOL_GPL(lpit_read_residency_count_address); 103 104 104 105 static void lpit_update_residency(struct lpit_residency_info *info, 105 106 struct acpi_lpit_native *lpit_native)
+2
drivers/platform/Kconfig
··· 8 8 source "drivers/platform/goldfish/Kconfig" 9 9 10 10 source "drivers/platform/chrome/Kconfig" 11 + 12 + source "drivers/platform/mellanox/Kconfig"
+1
drivers/platform/Makefile
··· 4 4 # 5 5 6 6 obj-$(CONFIG_X86) += x86/ 7 + obj-$(CONFIG_MELLANOX_PLATFORM) += mellanox/ 7 8 obj-$(CONFIG_MIPS) += mips/ 8 9 obj-$(CONFIG_OLPC) += olpc/ 9 10 obj-$(CONFIG_GOLDFISH) += goldfish/
+26
drivers/platform/mellanox/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Platform support for Mellanox hardware 4 + # 5 + 6 + menuconfig MELLANOX_PLATFORM 7 + bool "Platform support for Mellanox hardware" 8 + depends on X86 || ARM || COMPILE_TEST 9 + ---help--- 10 + Say Y here to get to see options for platform support for 11 + Mellanox systems. This option alone does not add any kernel code. 12 + 13 + If you say N, all options in this submenu will be skipped and disabled. 14 + 15 + if MELLANOX_PLATFORM 16 + 17 + config MLXREG_HOTPLUG 18 + tristate "Mellanox platform hotplug driver support" 19 + depends on REGMAP 20 + depends on HWMON 21 + depends on I2C 22 + ---help--- 23 + This driver handles hot-plug events for the power suppliers, power 24 + cables and fans on the wide range Mellanox IB and Ethernet systems. 25 + 26 + endif # MELLANOX_PLATFORM
+6
drivers/platform/mellanox/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Makefile for linux/drivers/platform/mellanox 4 + # Mellanox Platform-Specific Drivers 5 + # 6 + obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
+638
drivers/platform/mellanox/mlxreg-hotplug.c
··· 1 + /* 2 + * Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved. 3 + * Copyright (c) 2016-2018 Vadim Pasternak <vadimp@mellanox.com> 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions are met: 7 + * 8 + * 1. Redistributions of source code must retain the above copyright 9 + * notice, this list of conditions and the following disclaimer. 10 + * 2. Redistributions in binary form must reproduce the above copyright 11 + * notice, this list of conditions and the following disclaimer in the 12 + * documentation and/or other materials provided with the distribution. 13 + * 3. Neither the names of the copyright holders nor the names of its 14 + * contributors may be used to endorse or promote products derived from 15 + * this software without specific prior written permission. 16 + * 17 + * Alternatively, this software may be distributed under the terms of the 18 + * GNU General Public License ("GPL") version 2 as published by the Free 19 + * Software Foundation. 20 + * 21 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 + * POSSIBILITY OF SUCH DAMAGE. 32 + */ 33 + 34 + #include <linux/bitops.h> 35 + #include <linux/device.h> 36 + #include <linux/hwmon.h> 37 + #include <linux/hwmon-sysfs.h> 38 + #include <linux/i2c.h> 39 + #include <linux/interrupt.h> 40 + #include <linux/module.h> 41 + #include <linux/of_device.h> 42 + #include <linux/platform_data/mlxreg.h> 43 + #include <linux/platform_device.h> 44 + #include <linux/spinlock.h> 45 + #include <linux/regmap.h> 46 + #include <linux/workqueue.h> 47 + 48 + /* Offset of event and mask registers from status register. */ 49 + #define MLXREG_HOTPLUG_EVENT_OFF 1 50 + #define MLXREG_HOTPLUG_MASK_OFF 2 51 + #define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 52 + 53 + /* ASIC health parameters. */ 54 + #define MLXREG_HOTPLUG_HEALTH_MASK 0x02 55 + #define MLXREG_HOTPLUG_RST_CNTR 3 56 + 57 + #define MLXREG_HOTPLUG_ATTRS_MAX 24 58 + 59 + /** 60 + * struct mlxreg_hotplug_priv_data - platform private data: 61 + * @irq: platform device interrupt number; 62 + * @pdev: platform device; 63 + * @plat: platform data; 64 + * @dwork: delayed work template; 65 + * @lock: spin lock; 66 + * @hwmon: hwmon device; 67 + * @mlxreg_hotplug_attr: sysfs attributes array; 68 + * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array; 69 + * @group: sysfs attribute group; 70 + * @groups: list of sysfs attribute group for hwmon registration; 71 + * @cell: location of top aggregation interrupt register; 72 + * @mask: top aggregation interrupt common mask; 73 + * @aggr_cache: last value of aggregation register status; 74 + */ 75 + struct mlxreg_hotplug_priv_data { 76 + int irq; 77 + struct device *dev; 78 + struct platform_device *pdev; 79 + struct mlxreg_hotplug_platform_data *plat; 80 + struct regmap *regmap; 81 + struct delayed_work dwork_irq; 82 + struct delayed_work dwork; 83 + spinlock_t lock; /* sync with interrupt */ 84 + struct device *hwmon; 85 + struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1]; 86 + struct sensor_device_attribute_2 87 + mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX]; 88 + struct attribute_group group; 89 + const struct attribute_group *groups[2]; 90 + u32 cell; 91 + u32 mask; 92 + u32 aggr_cache; 93 + bool after_probe; 94 + }; 95 + 96 + static int mlxreg_hotplug_device_create(struct device *dev, 97 + struct mlxreg_core_data *data) 98 + { 99 + /* 100 + * Return if adapter number is negative. It could be in case hotplug 101 + * event is not associated with hotplug device. 102 + */ 103 + if (data->hpdev.nr < 0) 104 + return 0; 105 + 106 + data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); 107 + if (!data->hpdev.adapter) { 108 + dev_err(dev, "Failed to get adapter for bus %d\n", 109 + data->hpdev.nr); 110 + return -EFAULT; 111 + } 112 + 113 + data->hpdev.client = i2c_new_device(data->hpdev.adapter, 114 + data->hpdev.brdinfo); 115 + if (!data->hpdev.client) { 116 + dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", 117 + data->hpdev.brdinfo->type, data->hpdev.nr, 118 + data->hpdev.brdinfo->addr); 119 + 120 + i2c_put_adapter(data->hpdev.adapter); 121 + data->hpdev.adapter = NULL; 122 + return -EFAULT; 123 + } 124 + 125 + return 0; 126 + } 127 + 128 + static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data) 129 + { 130 + if (data->hpdev.client) { 131 + i2c_unregister_device(data->hpdev.client); 132 + data->hpdev.client = NULL; 133 + } 134 + 135 + if (data->hpdev.adapter) { 136 + i2c_put_adapter(data->hpdev.adapter); 137 + data->hpdev.adapter = NULL; 138 + } 139 + } 140 + 141 + static ssize_t mlxreg_hotplug_attr_show(struct device *dev, 142 + struct device_attribute *attr, 143 + char *buf) 144 + { 145 + struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev); 146 + struct mlxreg_core_hotplug_platform_data *pdata; 147 + int index = to_sensor_dev_attr_2(attr)->index; 148 + int nr = to_sensor_dev_attr_2(attr)->nr; 149 + struct mlxreg_core_item *item; 150 + struct mlxreg_core_data *data; 151 + u32 regval; 152 + int ret; 153 + 154 + pdata = dev_get_platdata(&priv->pdev->dev); 155 + item = pdata->items + nr; 156 + data = item->data + index; 157 + 158 + ret = regmap_read(priv->regmap, data->reg, &regval); 159 + if (ret) 160 + return ret; 161 + 162 + if (item->health) { 163 + regval &= data->mask; 164 + } else { 165 + /* Bit = 0 : functional if item->inversed is true. */ 166 + if (item->inversed) 167 + regval = !(regval & data->mask); 168 + else 169 + regval = !!(regval & data->mask); 170 + } 171 + 172 + return sprintf(buf, "%u\n", regval); 173 + } 174 + 175 + #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i] 176 + #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i] 177 + 178 + static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) 179 + { 180 + struct mlxreg_core_hotplug_platform_data *pdata; 181 + struct mlxreg_core_item *item; 182 + struct mlxreg_core_data *data; 183 + int num_attrs = 0, id = 0, i, j; 184 + 185 + pdata = dev_get_platdata(&priv->pdev->dev); 186 + item = pdata->items; 187 + 188 + /* Go over all kinds of items - psu, pwr, fan. */ 189 + for (i = 0; i < pdata->counter; i++, item++) { 190 + num_attrs += item->count; 191 + data = item->data; 192 + /* Go over all units within the item. */ 193 + for (j = 0; j < item->count; j++, data++, id++) { 194 + PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr; 195 + PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev, 196 + GFP_KERNEL, 197 + data->label); 198 + 199 + if (!PRIV_ATTR(id)->name) { 200 + dev_err(priv->dev, "Memory allocation failed for attr %d.\n", 201 + id); 202 + return -ENOMEM; 203 + } 204 + 205 + PRIV_DEV_ATTR(id).dev_attr.attr.name = 206 + PRIV_ATTR(id)->name; 207 + PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444; 208 + PRIV_DEV_ATTR(id).dev_attr.show = 209 + mlxreg_hotplug_attr_show; 210 + PRIV_DEV_ATTR(id).nr = i; 211 + PRIV_DEV_ATTR(id).index = j; 212 + sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr); 213 + } 214 + } 215 + 216 + priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * 217 + sizeof(struct attribute *), 218 + GFP_KERNEL); 219 + if (!priv->group.attrs) 220 + return -ENOMEM; 221 + 222 + priv->group.attrs = priv->mlxreg_hotplug_attr; 223 + priv->groups[0] = &priv->group; 224 + priv->groups[1] = NULL; 225 + 226 + return 0; 227 + } 228 + 229 + static void 230 + mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, 231 + struct mlxreg_core_item *item) 232 + { 233 + struct mlxreg_core_data *data; 234 + u32 asserted, regval, bit; 235 + int ret; 236 + 237 + /* 238 + * Validate if item related to received signal type is valid. 239 + * It should never happen, excepted the situation when some 240 + * piece of hardware is broken. In such situation just produce 241 + * error message and return. Caller must continue to handle the 242 + * signals from other devices if any. 243 + */ 244 + if (unlikely(!item)) { 245 + dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n", 246 + item->reg, item->mask); 247 + 248 + return; 249 + } 250 + 251 + /* Mask event. */ 252 + ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, 253 + 0); 254 + if (ret) 255 + goto out; 256 + 257 + /* Read status. */ 258 + ret = regmap_read(priv->regmap, item->reg, &regval); 259 + if (ret) 260 + goto out; 261 + 262 + /* Set asserted bits and save last status. */ 263 + regval &= item->mask; 264 + asserted = item->cache ^ regval; 265 + item->cache = regval; 266 + 267 + for_each_set_bit(bit, (unsigned long *)&asserted, 8) { 268 + data = item->data + bit; 269 + if (regval & BIT(bit)) { 270 + if (item->inversed) 271 + mlxreg_hotplug_device_destroy(data); 272 + else 273 + mlxreg_hotplug_device_create(priv->dev, data); 274 + } else { 275 + if (item->inversed) 276 + mlxreg_hotplug_device_create(priv->dev, data); 277 + else 278 + mlxreg_hotplug_device_destroy(data); 279 + } 280 + } 281 + 282 + /* Acknowledge event. */ 283 + ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF, 284 + 0); 285 + if (ret) 286 + goto out; 287 + 288 + /* Unmask event. */ 289 + ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, 290 + item->mask); 291 + 292 + out: 293 + if (ret) 294 + dev_err(priv->dev, "Failed to complete workqueue.\n"); 295 + } 296 + 297 + static void 298 + mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, 299 + struct mlxreg_core_item *item) 300 + { 301 + struct mlxreg_core_data *data = item->data; 302 + u32 regval; 303 + int i, ret; 304 + 305 + for (i = 0; i < item->count; i++, data++) { 306 + /* Mask event. */ 307 + ret = regmap_write(priv->regmap, data->reg + 308 + MLXREG_HOTPLUG_MASK_OFF, 0); 309 + if (ret) 310 + goto out; 311 + 312 + /* Read status. */ 313 + ret = regmap_read(priv->regmap, data->reg, &regval); 314 + if (ret) 315 + goto out; 316 + 317 + regval &= data->mask; 318 + item->cache = regval; 319 + if (regval == MLXREG_HOTPLUG_HEALTH_MASK) { 320 + if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) || 321 + !priv->after_probe) { 322 + mlxreg_hotplug_device_create(priv->dev, data); 323 + data->attached = true; 324 + } 325 + } else { 326 + if (data->attached) { 327 + mlxreg_hotplug_device_destroy(data); 328 + data->attached = false; 329 + data->health_cntr = 0; 330 + } 331 + } 332 + 333 + /* Acknowledge event. */ 334 + ret = regmap_write(priv->regmap, data->reg + 335 + MLXREG_HOTPLUG_EVENT_OFF, 0); 336 + if (ret) 337 + goto out; 338 + 339 + /* Unmask event. */ 340 + ret = regmap_write(priv->regmap, data->reg + 341 + MLXREG_HOTPLUG_MASK_OFF, data->mask); 342 + if (ret) 343 + goto out; 344 + } 345 + 346 + out: 347 + if (ret) 348 + dev_err(priv->dev, "Failed to complete workqueue.\n"); 349 + } 350 + 351 + /* 352 + * mlxreg_hotplug_work_handler - performs traversing of device interrupt 353 + * registers according to the below hierarchy schema: 354 + * 355 + * Aggregation registers (status/mask) 356 + * PSU registers: *---* 357 + * *-----------------* | | 358 + * |status/event/mask|-----> | * | 359 + * *-----------------* | | 360 + * Power registers: | | 361 + * *-----------------* | | 362 + * |status/event/mask|-----> | * | 363 + * *-----------------* | | 364 + * FAN registers: | |--> CPU 365 + * *-----------------* | | 366 + * |status/event/mask|-----> | * | 367 + * *-----------------* | | 368 + * ASIC registers: | | 369 + * *-----------------* | | 370 + * |status/event/mask|-----> | * | 371 + * *-----------------* | | 372 + * *---* 373 + * 374 + * In case some system changed are detected: FAN in/out, PSU in/out, power 375 + * cable attached/detached, ASIC health good/bad, relevant device is created 376 + * or destroyed. 377 + */ 378 + static void mlxreg_hotplug_work_handler(struct work_struct *work) 379 + { 380 + struct mlxreg_core_hotplug_platform_data *pdata; 381 + struct mlxreg_hotplug_priv_data *priv; 382 + struct mlxreg_core_item *item; 383 + u32 regval, aggr_asserted; 384 + unsigned long flags; 385 + int i, ret; 386 + 387 + priv = container_of(work, struct mlxreg_hotplug_priv_data, 388 + dwork_irq.work); 389 + pdata = dev_get_platdata(&priv->pdev->dev); 390 + item = pdata->items; 391 + 392 + /* Mask aggregation event. */ 393 + ret = regmap_write(priv->regmap, pdata->cell + 394 + MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); 395 + if (ret < 0) 396 + goto out; 397 + 398 + /* Read aggregation status. */ 399 + ret = regmap_read(priv->regmap, pdata->cell, &regval); 400 + if (ret) 401 + goto out; 402 + 403 + regval &= pdata->mask; 404 + aggr_asserted = priv->aggr_cache ^ regval; 405 + priv->aggr_cache = regval; 406 + 407 + /* Handle topology and health configuration changes. */ 408 + for (i = 0; i < pdata->counter; i++, item++) { 409 + if (aggr_asserted & item->aggr_mask) { 410 + if (item->health) 411 + mlxreg_hotplug_health_work_helper(priv, item); 412 + else 413 + mlxreg_hotplug_work_helper(priv, item); 414 + } 415 + } 416 + 417 + if (aggr_asserted) { 418 + spin_lock_irqsave(&priv->lock, flags); 419 + 420 + /* 421 + * It is possible, that some signals have been inserted, while 422 + * interrupt has been masked by mlxreg_hotplug_work_handler. 423 + * In this case such signals will be missed. In order to handle 424 + * these signals delayed work is canceled and work task 425 + * re-scheduled for immediate execution. It allows to handle 426 + * missed signals, if any. In other case work handler just 427 + * validates that no new signals have been received during 428 + * masking. 429 + */ 430 + cancel_delayed_work(&priv->dwork_irq); 431 + schedule_delayed_work(&priv->dwork_irq, 0); 432 + 433 + spin_unlock_irqrestore(&priv->lock, flags); 434 + 435 + return; 436 + } 437 + 438 + /* Unmask aggregation event (no need acknowledge). */ 439 + ret = regmap_write(priv->regmap, pdata->cell + 440 + MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); 441 + 442 + out: 443 + if (ret) 444 + dev_err(priv->dev, "Failed to complete workqueue.\n"); 445 + } 446 + 447 + static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) 448 + { 449 + struct mlxreg_core_hotplug_platform_data *pdata; 450 + struct mlxreg_core_item *item; 451 + int i, ret; 452 + 453 + pdata = dev_get_platdata(&priv->pdev->dev); 454 + item = pdata->items; 455 + 456 + for (i = 0; i < pdata->counter; i++, item++) { 457 + /* Clear group presense event. */ 458 + ret = regmap_write(priv->regmap, item->reg + 459 + MLXREG_HOTPLUG_EVENT_OFF, 0); 460 + if (ret) 461 + goto out; 462 + 463 + /* Set group initial status as mask and unmask group event. */ 464 + if (item->inversed) { 465 + item->cache = item->mask; 466 + ret = regmap_write(priv->regmap, item->reg + 467 + MLXREG_HOTPLUG_MASK_OFF, 468 + item->mask); 469 + if (ret) 470 + goto out; 471 + } 472 + } 473 + 474 + /* Keep aggregation initial status as zero and unmask events. */ 475 + ret = regmap_write(priv->regmap, pdata->cell + 476 + MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); 477 + if (ret) 478 + goto out; 479 + 480 + /* Keep low aggregation initial status as zero and unmask events. */ 481 + if (pdata->cell_low) { 482 + ret = regmap_write(priv->regmap, pdata->cell_low + 483 + MLXREG_HOTPLUG_AGGR_MASK_OFF, 484 + pdata->mask_low); 485 + if (ret) 486 + goto out; 487 + } 488 + 489 + /* Invoke work handler for initializing hot plug devices setting. */ 490 + mlxreg_hotplug_work_handler(&priv->dwork_irq.work); 491 + 492 + out: 493 + if (ret) 494 + dev_err(priv->dev, "Failed to set interrupts.\n"); 495 + enable_irq(priv->irq); 496 + return ret; 497 + } 498 + 499 + static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) 500 + { 501 + struct mlxreg_core_hotplug_platform_data *pdata; 502 + struct mlxreg_core_item *item; 503 + struct mlxreg_core_data *data; 504 + int count, i, j; 505 + 506 + pdata = dev_get_platdata(&priv->pdev->dev); 507 + item = pdata->items; 508 + disable_irq(priv->irq); 509 + cancel_delayed_work_sync(&priv->dwork_irq); 510 + 511 + /* Mask low aggregation event, if defined. */ 512 + if (pdata->cell_low) 513 + regmap_write(priv->regmap, pdata->cell_low + 514 + MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); 515 + 516 + /* Mask aggregation event. */ 517 + regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF, 518 + 0); 519 + 520 + /* Clear topology configurations. */ 521 + for (i = 0; i < pdata->counter; i++, item++) { 522 + data = item->data; 523 + /* Mask group presense event. */ 524 + regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF, 525 + 0); 526 + /* Clear group presense event. */ 527 + regmap_write(priv->regmap, data->reg + 528 + MLXREG_HOTPLUG_EVENT_OFF, 0); 529 + 530 + /* Remove all the attached devices in group. */ 531 + count = item->count; 532 + for (j = 0; j < count; j++, data++) 533 + mlxreg_hotplug_device_destroy(data); 534 + } 535 + } 536 + 537 + static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) 538 + { 539 + struct mlxreg_hotplug_priv_data *priv; 540 + 541 + priv = (struct mlxreg_hotplug_priv_data *)dev; 542 + 543 + /* Schedule work task for immediate execution.*/ 544 + schedule_delayed_work(&priv->dwork_irq, 0); 545 + 546 + return IRQ_HANDLED; 547 + } 548 + 549 + static int mlxreg_hotplug_probe(struct platform_device *pdev) 550 + { 551 + struct mlxreg_core_hotplug_platform_data *pdata; 552 + struct mlxreg_hotplug_priv_data *priv; 553 + int err; 554 + 555 + pdata = dev_get_platdata(&pdev->dev); 556 + if (!pdata) { 557 + dev_err(&pdev->dev, "Failed to get platform data.\n"); 558 + return -EINVAL; 559 + } 560 + 561 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 562 + if (!priv) 563 + return -ENOMEM; 564 + 565 + if (pdata->irq) { 566 + priv->irq = pdata->irq; 567 + } else { 568 + priv->irq = platform_get_irq(pdev, 0); 569 + if (priv->irq < 0) { 570 + dev_err(&pdev->dev, "Failed to get platform irq: %d\n", 571 + priv->irq); 572 + return priv->irq; 573 + } 574 + } 575 + 576 + priv->regmap = pdata->regmap; 577 + priv->dev = pdev->dev.parent; 578 + priv->pdev = pdev; 579 + 580 + err = devm_request_irq(&pdev->dev, priv->irq, 581 + mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING 582 + | IRQF_SHARED, "mlxreg-hotplug", priv); 583 + if (err) { 584 + dev_err(&pdev->dev, "Failed to request irq: %d\n", err); 585 + return err; 586 + } 587 + 588 + disable_irq(priv->irq); 589 + spin_lock_init(&priv->lock); 590 + INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); 591 + /* Perform initial interrupts setup. */ 592 + mlxreg_hotplug_set_irq(priv); 593 + 594 + priv->after_probe = true; 595 + dev_set_drvdata(&pdev->dev, priv); 596 + 597 + err = mlxreg_hotplug_attr_init(priv); 598 + if (err) { 599 + dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", 600 + err); 601 + return err; 602 + } 603 + 604 + priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, 605 + "mlxreg_hotplug", priv, priv->groups); 606 + if (IS_ERR(priv->hwmon)) { 607 + dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", 608 + PTR_ERR(priv->hwmon)); 609 + return PTR_ERR(priv->hwmon); 610 + } 611 + 612 + return 0; 613 + } 614 + 615 + static int mlxreg_hotplug_remove(struct platform_device *pdev) 616 + { 617 + struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev); 618 + 619 + /* Clean interrupts setup. */ 620 + mlxreg_hotplug_unset_irq(priv); 621 + 622 + return 0; 623 + } 624 + 625 + static struct platform_driver mlxreg_hotplug_driver = { 626 + .driver = { 627 + .name = "mlxreg-hotplug", 628 + }, 629 + .probe = mlxreg_hotplug_probe, 630 + .remove = mlxreg_hotplug_remove, 631 + }; 632 + 633 + module_platform_driver(mlxreg_hotplug_driver); 634 + 635 + MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); 636 + MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver"); 637 + MODULE_LICENSE("Dual BSD/GPL"); 638 + MODULE_ALIAS("platform:mlxreg-hotplug");
+43 -13
drivers/platform/x86/Kconfig
··· 36 36 If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M 37 37 here. 38 38 39 + config ACER_WIRELESS 40 + tristate "Acer Wireless Radio Control Driver" 41 + depends on ACPI 42 + depends on INPUT 43 + ---help--- 44 + The Acer Wireless Radio Control handles the airplane mode hotkey 45 + present on new Acer laptops. 46 + 47 + Say Y or M here if you have an Acer notebook with an airplane mode 48 + hotkey. 49 + 50 + If you choose to compile this driver as a module the module will be 51 + called acer-wireless. 52 + 39 53 config ACERHDF 40 54 tristate "Acer Aspire One temperature and fan driver" 41 55 depends on ACPI && THERMAL ··· 257 243 ---help--- 258 244 This is a driver for enabling wifi on some Fujitsu-Siemens Amilo 259 245 laptops. 246 + 247 + config GPD_POCKET_FAN 248 + tristate "GPD Pocket Fan Controller support" 249 + depends on ACPI 250 + depends on THERMAL 251 + ---help--- 252 + Driver for the GPD Pocket vendor specific FAN02501 ACPI device 253 + which controls the fan speed on the GPD Pocket. 254 + 255 + Without this driver the fan on the Pocket will stay off independent 256 + of the CPU temperature. Say Y or M if the kernel may be used on a 257 + GPD pocket. 260 258 261 259 config TC1100_WMI 262 260 tristate "HP Compaq TC1100 Tablet WMI Extras" ··· 838 812 839 813 config ACPI_CMPC 840 814 tristate "CMPC Laptop Extras" 841 - depends on ACPI 815 + depends on ACPI && INPUT 842 816 depends on RFKILL || RFKILL=n 843 - select INPUT 844 817 select BACKLIGHT_CLASS_DEVICE 845 818 help 846 819 Support for Intel Classmate PC ACPI devices, including some ··· 974 949 If you are running on a Galileo/Quark say Y here. 975 950 976 951 config INTEL_PMC_CORE 977 - bool "Intel PMC Core driver" 952 + tristate "Intel PMC Core driver" 978 953 depends on PCI 979 954 ---help--- 980 955 The Intel Platform Controller Hub for Intel Core SoCs provides access ··· 983 958 exposed by the Power Management Controller. 984 959 985 960 Supported features: 986 - - SLP_S0_RESIDENCY counter. 961 + - SLP_S0_RESIDENCY counter 962 + - PCH IP Power Gating status 963 + - LTR Ignore 964 + - MPHY/PLL gating status (Sunrisepoint PCH only) 987 965 988 966 config IBM_RTL 989 967 tristate "Device driver to enable PRTL support" ··· 1159 1131 1160 1132 config MLX_PLATFORM 1161 1133 tristate "Mellanox Technologies platform support" 1162 - depends on X86_64 1163 1134 ---help--- 1164 1135 This option enables system support for the Mellanox Technologies 1165 1136 platform. The Mellanox systems provide data center networking ··· 1167 1140 connection. 1168 1141 1169 1142 If you have a Mellanox system, say Y or M here. 1170 - 1171 - config MLX_CPLD_PLATFORM 1172 - tristate "Mellanox platform hotplug driver support" 1173 - select HWMON 1174 - select I2C 1175 - ---help--- 1176 - This driver handles hot-plug events for the power suppliers, power 1177 - cables and fans on the wide range Mellanox IB and Ethernet systems. 1178 1143 1179 1144 config INTEL_TURBO_MAX_3 1180 1145 bool "Intel Turbo Boost Max Technology 3.0 enumeration driver" ··· 1188 1169 into the tablet model specific version of the driver shipped 1189 1170 with the OS-image for the device. This option supplies the missing 1190 1171 information. Enable this for x86 tablets with Silead touchscreens. 1172 + 1173 + config INTEL_CHTDC_TI_PWRBTN 1174 + tristate "Intel Cherry Trail Dollar Cove TI power button driver" 1175 + depends on INTEL_SOC_PMIC_CHTDC_TI 1176 + depends on INPUT 1177 + ---help--- 1178 + This option adds a power button driver driver for Dollar Cove TI 1179 + PMIC on Intel Cherry Trail devices. 1180 + 1181 + To compile this driver as a module, choose M here: the module 1182 + will be called intel_chtdc_ti_pwrbtn. 1191 1183 1192 1184 endif # X86_PLATFORM_DEVICES 1193 1185
+3 -1
drivers/platform/x86/Makefile
··· 23 23 obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o 24 24 obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o 25 25 obj-$(CONFIG_ACER_WMI) += acer-wmi.o 26 + obj-$(CONFIG_ACER_WIRELESS) += acer-wireless.o 26 27 obj-$(CONFIG_ACERHDF) += acerhdf.o 27 28 obj-$(CONFIG_HP_ACCEL) += hp_accel.o 28 29 obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o 29 30 obj-$(CONFIG_HP_WMI) += hp-wmi.o 30 31 obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o 32 + obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o 31 33 obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o 32 34 obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o 33 35 obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o ··· 88 86 obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o 89 87 obj-$(CONFIG_PMC_ATOM) += pmc_atom.o 90 88 obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o 91 - obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o 92 89 obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o 90 + obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
+71
drivers/platform/x86/acer-wireless.c
··· 1 + /* 2 + * Acer Wireless Radio Control Driver 3 + * 4 + * Copyright (C) 2017 Endless Mobile, Inc. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/acpi.h> 12 + #include <linux/input.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/pci_ids.h> 16 + #include <linux/types.h> 17 + 18 + static const struct acpi_device_id acer_wireless_acpi_ids[] = { 19 + {"10251229", 0}, 20 + {"", 0}, 21 + }; 22 + MODULE_DEVICE_TABLE(acpi, acer_wireless_acpi_ids); 23 + 24 + static void acer_wireless_notify(struct acpi_device *adev, u32 event) 25 + { 26 + struct input_dev *idev = acpi_driver_data(adev); 27 + 28 + dev_dbg(&adev->dev, "event=%#x\n", event); 29 + if (event != 0x80) { 30 + dev_notice(&adev->dev, "Unknown SMKB event: %#x\n", event); 31 + return; 32 + } 33 + input_report_key(idev, KEY_RFKILL, 1); 34 + input_report_key(idev, KEY_RFKILL, 0); 35 + input_sync(idev); 36 + } 37 + 38 + static int acer_wireless_add(struct acpi_device *adev) 39 + { 40 + struct input_dev *idev; 41 + 42 + idev = devm_input_allocate_device(&adev->dev); 43 + if (!idev) 44 + return -ENOMEM; 45 + 46 + adev->driver_data = idev; 47 + idev->name = "Acer Wireless Radio Control"; 48 + idev->phys = "acer-wireless/input0"; 49 + idev->id.bustype = BUS_HOST; 50 + idev->id.vendor = PCI_VENDOR_ID_AI; 51 + idev->id.product = 0x1229; 52 + set_bit(EV_KEY, idev->evbit); 53 + set_bit(KEY_RFKILL, idev->keybit); 54 + 55 + return input_register_device(idev); 56 + } 57 + 58 + static struct acpi_driver acer_wireless_driver = { 59 + .name = "Acer Wireless Radio Control Driver", 60 + .class = "hotkey", 61 + .ids = acer_wireless_acpi_ids, 62 + .ops = { 63 + .add = acer_wireless_add, 64 + .notify = acer_wireless_notify, 65 + }, 66 + }; 67 + module_acpi_driver(acer_wireless_driver); 68 + 69 + MODULE_DESCRIPTION("Acer Wireless Radio Control Driver"); 70 + MODULE_AUTHOR("Chris Chiu <chiu@gmail.com>"); 71 + MODULE_LICENSE("GPL v2");
+17
drivers/platform/x86/alienware-wmi.c
··· 68 68 69 69 static struct quirk_entry *quirks; 70 70 71 + 72 + static struct quirk_entry quirk_inspiron5675 = { 73 + .num_zones = 2, 74 + .hdmi_mux = 0, 75 + .amplifier = 0, 76 + .deepslp = 0, 77 + }; 78 + 71 79 static struct quirk_entry quirk_unknown = { 72 80 .num_zones = 2, 73 81 .hdmi_mux = 0, ··· 178 170 DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"), 179 171 }, 180 172 .driver_data = &quirk_asm201, 173 + }, 174 + { 175 + .callback = dmi_matched, 176 + .ident = "Dell Inc. Inspiron 5675", 177 + .matches = { 178 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 179 + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"), 180 + }, 181 + .driver_data = &quirk_inspiron5675, 181 182 }, 182 183 {} 183 184 };
+1 -47
drivers/platform/x86/apple-gmux.c
··· 24 24 #include <linux/delay.h> 25 25 #include <linux/pci.h> 26 26 #include <linux/vga_switcheroo.h> 27 - #include <linux/vgaarb.h> 28 27 #include <acpi/video.h> 29 28 #include <asm/io.h> 30 29 ··· 53 54 bool indexed; 54 55 struct mutex index_lock; 55 56 56 - struct pci_dev *pdev; 57 57 struct backlight_device *bdev; 58 58 59 59 /* switcheroo data */ ··· 597 599 return 0; 598 600 } 599 601 600 - static struct pci_dev *gmux_get_io_pdev(void) 601 - { 602 - struct pci_dev *pdev = NULL; 603 - 604 - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) { 605 - u16 cmd; 606 - 607 - pci_read_config_word(pdev, PCI_COMMAND, &cmd); 608 - if (!(cmd & PCI_COMMAND_IO)) 609 - continue; 610 - 611 - return pdev; 612 - } 613 - 614 - return NULL; 615 - } 616 - 617 602 static int is_thunderbolt(struct device *dev, void *data) 618 603 { 619 604 return to_pci_dev(dev)->is_thunderbolt; ··· 612 631 int ret = -ENXIO; 613 632 acpi_status status; 614 633 unsigned long long gpe; 615 - struct pci_dev *pdev = NULL; 616 634 617 635 if (apple_gmux_data) 618 636 return -EBUSY; ··· 662 682 ver_minor = (version >> 16) & 0xff; 663 683 ver_release = (version >> 8) & 0xff; 664 684 } else { 665 - pr_info("gmux device not present or IO disabled\n"); 685 + pr_info("gmux device not present\n"); 666 686 ret = -ENODEV; 667 687 goto err_release; 668 688 } 669 689 } 670 690 pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, 671 691 ver_release, (gmux_data->indexed ? "indexed" : "classic")); 672 - 673 - /* 674 - * Apple systems with gmux are EFI based and normally don't use 675 - * VGA. In addition changing IO+MEM ownership between IGP and dGPU 676 - * disables IO/MEM used for backlight control on some systems. 677 - * Lock IO+MEM to GPU with active IO to prevent switch. 678 - */ 679 - pdev = gmux_get_io_pdev(); 680 - if (pdev && vga_tryget(pdev, 681 - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) { 682 - pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n", 683 - pci_name(pdev)); 684 - ret = -EBUSY; 685 - goto err_release; 686 - } else if (pdev) 687 - pr_info("locked IO for PCI:%s\n", pci_name(pdev)); 688 - gmux_data->pdev = pdev; 689 692 690 693 memset(&props, 0, sizeof(props)); 691 694 props.type = BACKLIGHT_PLATFORM; ··· 785 822 err_notify: 786 823 backlight_device_unregister(bdev); 787 824 err_release: 788 - if (gmux_data->pdev) 789 - vga_put(gmux_data->pdev, 790 - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); 791 - pci_dev_put(pdev); 792 825 release_region(gmux_data->iostart, gmux_data->iolen); 793 826 err_free: 794 827 kfree(gmux_data); ··· 804 845 &gmux_notify_handler); 805 846 } 806 847 807 - if (gmux_data->pdev) { 808 - vga_put(gmux_data->pdev, 809 - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM); 810 - pci_dev_put(gmux_data->pdev); 811 - } 812 848 backlight_device_unregister(gmux_data->bdev); 813 849 814 850 release_region(gmux_data->iostart, gmux_data->iolen);
+11 -2
drivers/platform/x86/asus-nb-wmi.c
··· 111 111 .xusb2pr = 0x01D9, 112 112 }; 113 113 114 - static struct quirk_entry quirk_asus_ux330uak = { 114 + static struct quirk_entry quirk_asus_forceals = { 115 115 .wmi_force_als_set = true, 116 116 }; 117 117 ··· 387 387 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 388 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 393 .callback = dmi_matched, ··· 397 397 DMI_MATCH(DMI_PRODUCT_NAME, "X550LB"), 398 398 }, 399 399 .driver_data = &quirk_asus_x550lb, 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, 400 409 }, 401 410 {}, 402 411 };
+167 -93
drivers/platform/x86/dell-laptop.c
··· 36 36 #include "dell-smbios.h" 37 37 38 38 struct quirk_entry { 39 - u8 touchpad_led; 40 - u8 kbd_led_levels_off_1; 39 + bool touchpad_led; 40 + bool kbd_led_levels_off_1; 41 41 42 - int needs_kbd_timeouts; 42 + bool needs_kbd_timeouts; 43 43 /* 44 44 * Ordered list of timeouts expressed in seconds. 45 45 * The list must end with -1 ··· 50 50 static struct quirk_entry *quirks; 51 51 52 52 static struct quirk_entry quirk_dell_vostro_v130 = { 53 - .touchpad_led = 1, 53 + .touchpad_led = true, 54 54 }; 55 55 56 56 static int __init dmi_matched(const struct dmi_system_id *dmi) ··· 64 64 * is used then BIOS silently set timeout to 0 without any error message. 65 65 */ 66 66 static struct quirk_entry quirk_dell_xps13_9333 = { 67 - .needs_kbd_timeouts = 1, 67 + .needs_kbd_timeouts = true, 68 68 .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, 69 69 }; 70 70 71 71 static 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 75 75 static struct platform_driver platform_driver = { ··· 78 78 } 79 79 }; 80 80 81 - static struct calling_interface_buffer *buffer; 82 81 static struct platform_device *platform_device; 83 82 static struct backlight_device *dell_backlight_device; 84 83 static struct rfkill *wifi_rfkill; ··· 106 107 .matches = { 107 108 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 108 109 DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/ 110 + }, 111 + }, 112 + { 113 + .matches = { 114 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 115 + DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/ 116 + }, 117 + }, 118 + { 119 + .matches = { 120 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 121 + DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/ 122 + }, 123 + }, 124 + { 125 + .matches = { 126 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 127 + DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/ 128 + }, 129 + }, 130 + { 131 + .matches = { 132 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 133 + DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/ 134 + }, 135 + }, 136 + { 137 + .matches = { 138 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 139 + DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/ 140 + }, 141 + }, 142 + { 143 + .matches = { 144 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 145 + DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/ 109 146 }, 110 147 }, 111 148 { ··· 321 286 { } 322 287 }; 323 288 324 - void dell_set_arguments(u32 arg0, u32 arg1, u32 arg2, u32 arg3) 289 + static void dell_fill_request(struct calling_interface_buffer *buffer, 290 + u32 arg0, u32 arg1, u32 arg2, u32 arg3) 325 291 { 326 292 memset(buffer, 0, sizeof(struct calling_interface_buffer)); 327 293 buffer->input[0] = arg0; ··· 331 295 buffer->input[3] = arg3; 332 296 } 333 297 334 - int dell_send_request(u16 class, u16 select) 298 + static int dell_send_request(struct calling_interface_buffer *buffer, 299 + u16 class, u16 select) 335 300 { 336 301 int ret; 337 302 ··· 469 432 int disable = blocked ? 1 : 0; 470 433 unsigned long radio = (unsigned long)data; 471 434 int hwswitch_bit = (unsigned long)data - 1; 435 + struct calling_interface_buffer buffer; 472 436 int hwswitch; 473 437 int status; 474 438 int ret; 475 439 476 - dell_set_arguments(0, 0, 0, 0); 477 - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 440 + dell_fill_request(&buffer, 0, 0, 0, 0); 441 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 478 442 if (ret) 479 443 return ret; 480 - status = buffer->output[1]; 444 + status = buffer.output[1]; 481 445 482 - dell_set_arguments(0x2, 0, 0, 0); 483 - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 446 + dell_fill_request(&buffer, 0x2, 0, 0, 0); 447 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 484 448 if (ret) 485 449 return ret; 486 - hwswitch = buffer->output[1]; 450 + hwswitch = buffer.output[1]; 487 451 488 452 /* If the hardware switch controls this radio, and the hardware 489 453 switch is disabled, always disable the radio */ ··· 492 454 (status & BIT(0)) && !(status & BIT(16))) 493 455 disable = 1; 494 456 495 - dell_set_arguments(1 | (radio<<8) | (disable << 16), 0, 0, 0); 496 - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 457 + dell_fill_request(&buffer, 1 | (radio<<8) | (disable << 16), 0, 0, 0); 458 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 497 459 return ret; 498 460 } 499 461 ··· 502 464 { 503 465 if (status & BIT(0)) { 504 466 /* Has hw-switch, sync sw_state to BIOS */ 467 + struct calling_interface_buffer buffer; 505 468 int block = rfkill_blocked(rfkill); 506 - dell_set_arguments(1 | (radio << 8) | (block << 16), 0, 0, 0); 507 - dell_send_request(CLASS_INFO, SELECT_RFKILL); 469 + dell_fill_request(&buffer, 470 + 1 | (radio << 8) | (block << 16), 0, 0, 0); 471 + dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 508 472 } else { 509 473 /* No hw-switch, sync BIOS state to sw_state */ 510 474 rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); ··· 523 483 static void dell_rfkill_query(struct rfkill *rfkill, void *data) 524 484 { 525 485 int radio = ((unsigned long)data & 0xF); 486 + struct calling_interface_buffer buffer; 526 487 int hwswitch; 527 488 int status; 528 489 int ret; 529 490 530 - dell_set_arguments(0, 0, 0, 0); 531 - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 532 - status = buffer->output[1]; 491 + dell_fill_request(&buffer, 0, 0, 0, 0); 492 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 493 + status = buffer.output[1]; 533 494 534 495 if (ret != 0 || !(status & BIT(0))) { 535 496 return; 536 497 } 537 498 538 - dell_set_arguments(0, 0x2, 0, 0); 539 - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 540 - hwswitch = buffer->output[1]; 499 + dell_fill_request(&buffer, 0, 0x2, 0, 0); 500 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 501 + hwswitch = buffer.output[1]; 541 502 542 503 if (ret != 0) 543 504 return; ··· 555 514 556 515 static int dell_debugfs_show(struct seq_file *s, void *data) 557 516 { 517 + struct calling_interface_buffer buffer; 558 518 int hwswitch_state; 559 519 int hwswitch_ret; 560 520 int status; 561 521 int ret; 562 522 563 - dell_set_arguments(0, 0, 0, 0); 564 - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 523 + dell_fill_request(&buffer, 0, 0, 0, 0); 524 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 565 525 if (ret) 566 526 return ret; 567 - status = buffer->output[1]; 527 + status = buffer.output[1]; 568 528 569 - dell_set_arguments(0, 0x2, 0, 0); 570 - hwswitch_ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 529 + dell_fill_request(&buffer, 0, 0x2, 0, 0); 530 + hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 571 531 if (hwswitch_ret) 572 532 return hwswitch_ret; 573 - hwswitch_state = buffer->output[1]; 533 + hwswitch_state = buffer.output[1]; 574 534 575 535 seq_printf(s, "return:\t%d\n", ret); 576 536 seq_printf(s, "status:\t0x%X\n", status); ··· 652 610 653 611 static void dell_update_rfkill(struct work_struct *ignored) 654 612 { 613 + struct calling_interface_buffer buffer; 655 614 int hwswitch = 0; 656 615 int status; 657 616 int ret; 658 617 659 - dell_set_arguments(0, 0, 0, 0); 660 - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 661 - status = buffer->output[1]; 618 + dell_fill_request(&buffer, 0, 0, 0, 0); 619 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 620 + status = buffer.output[1]; 662 621 663 622 if (ret != 0) 664 623 return; 665 624 666 - dell_set_arguments(0, 0x2, 0, 0); 667 - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 625 + dell_fill_request(&buffer, 0, 0x2, 0, 0); 626 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 668 627 669 628 if (ret == 0 && (status & BIT(0))) 670 - hwswitch = buffer->output[1]; 629 + hwswitch = buffer.output[1]; 671 630 672 631 if (wifi_rfkill) { 673 632 dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch); ··· 726 683 727 684 static int __init dell_setup_rfkill(void) 728 685 { 686 + struct calling_interface_buffer buffer; 729 687 int status, ret, whitelisted; 730 688 const char *product; 731 689 ··· 742 698 if (!force_rfkill && !whitelisted) 743 699 return 0; 744 700 745 - dell_set_arguments(0, 0, 0, 0); 746 - ret = dell_send_request(CLASS_INFO, SELECT_RFKILL); 747 - status = buffer->output[1]; 701 + dell_fill_request(&buffer, 0, 0, 0, 0); 702 + ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL); 703 + status = buffer.output[1]; 748 704 749 705 /* dell wireless info smbios call is not supported */ 750 706 if (ret != 0) ··· 897 853 898 854 static int dell_send_intensity(struct backlight_device *bd) 899 855 { 856 + struct calling_interface_buffer buffer; 900 857 struct calling_interface_token *token; 901 858 int ret; 902 859 ··· 905 860 if (!token) 906 861 return -ENODEV; 907 862 908 - dell_set_arguments(token->location, bd->props.brightness, 0, 0); 863 + dell_fill_request(&buffer, 864 + token->location, bd->props.brightness, 0, 0); 909 865 if (power_supply_is_system_supplied() > 0) 910 - ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_AC); 866 + ret = dell_send_request(&buffer, 867 + CLASS_TOKEN_WRITE, SELECT_TOKEN_AC); 911 868 else 912 - ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT); 869 + ret = dell_send_request(&buffer, 870 + CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT); 913 871 914 872 return ret; 915 873 } 916 874 917 875 static int dell_get_intensity(struct backlight_device *bd) 918 876 { 877 + struct calling_interface_buffer buffer; 919 878 struct calling_interface_token *token; 920 879 int ret; 921 880 ··· 927 878 if (!token) 928 879 return -ENODEV; 929 880 930 - dell_set_arguments(token->location, 0, 0, 0); 881 + dell_fill_request(&buffer, token->location, 0, 0, 0); 931 882 if (power_supply_is_system_supplied() > 0) 932 - ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC); 883 + ret = dell_send_request(&buffer, 884 + CLASS_TOKEN_READ, SELECT_TOKEN_AC); 933 885 else 934 - ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_BAT); 886 + ret = dell_send_request(&buffer, 887 + CLASS_TOKEN_READ, SELECT_TOKEN_BAT); 935 888 936 889 if (ret == 0) 937 - ret = buffer->output[1]; 890 + ret = buffer.output[1]; 891 + 938 892 return ret; 939 893 } 940 894 ··· 1185 1133 1186 1134 static bool kbd_led_present; 1187 1135 static DEFINE_MUTEX(kbd_led_mutex); 1136 + static enum led_brightness kbd_led_level; 1188 1137 1189 1138 /* 1190 1139 * NOTE: there are three ways to set the keyboard backlight level. ··· 1202 1149 1203 1150 static int kbd_get_info(struct kbd_info *info) 1204 1151 { 1152 + struct calling_interface_buffer buffer; 1205 1153 u8 units; 1206 1154 int ret; 1207 1155 1208 - dell_set_arguments(0, 0, 0, 0); 1209 - ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); 1156 + dell_fill_request(&buffer, 0, 0, 0, 0); 1157 + ret = dell_send_request(&buffer, 1158 + CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); 1210 1159 if (ret) 1211 1160 return ret; 1212 1161 1213 - info->modes = buffer->output[1] & 0xFFFF; 1214 - info->type = (buffer->output[1] >> 24) & 0xFF; 1215 - info->triggers = buffer->output[2] & 0xFF; 1216 - units = (buffer->output[2] >> 8) & 0xFF; 1217 - info->levels = (buffer->output[2] >> 16) & 0xFF; 1162 + info->modes = buffer.output[1] & 0xFFFF; 1163 + info->type = (buffer.output[1] >> 24) & 0xFF; 1164 + info->triggers = buffer.output[2] & 0xFF; 1165 + units = (buffer.output[2] >> 8) & 0xFF; 1166 + info->levels = (buffer.output[2] >> 16) & 0xFF; 1218 1167 1219 1168 if (quirks && quirks->kbd_led_levels_off_1 && info->levels) 1220 1169 info->levels--; 1221 1170 1222 1171 if (units & BIT(0)) 1223 - info->seconds = (buffer->output[3] >> 0) & 0xFF; 1172 + info->seconds = (buffer.output[3] >> 0) & 0xFF; 1224 1173 if (units & BIT(1)) 1225 - info->minutes = (buffer->output[3] >> 8) & 0xFF; 1174 + info->minutes = (buffer.output[3] >> 8) & 0xFF; 1226 1175 if (units & BIT(2)) 1227 - info->hours = (buffer->output[3] >> 16) & 0xFF; 1176 + info->hours = (buffer.output[3] >> 16) & 0xFF; 1228 1177 if (units & BIT(3)) 1229 - info->days = (buffer->output[3] >> 24) & 0xFF; 1178 + info->days = (buffer.output[3] >> 24) & 0xFF; 1230 1179 1231 1180 return ret; 1232 1181 } ··· 1288 1233 1289 1234 static int kbd_get_state(struct kbd_state *state) 1290 1235 { 1236 + struct calling_interface_buffer buffer; 1291 1237 int ret; 1292 1238 1293 - dell_set_arguments(0x1, 0, 0, 0); 1294 - ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); 1239 + dell_fill_request(&buffer, 0, 0, 0, 0); 1240 + ret = dell_send_request(&buffer, 1241 + CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); 1295 1242 if (ret) 1296 1243 return ret; 1297 1244 1298 - state->mode_bit = ffs(buffer->output[1] & 0xFFFF); 1245 + state->mode_bit = ffs(buffer.output[1] & 0xFFFF); 1299 1246 if (state->mode_bit != 0) 1300 1247 state->mode_bit--; 1301 1248 1302 - state->triggers = (buffer->output[1] >> 16) & 0xFF; 1303 - state->timeout_value = (buffer->output[1] >> 24) & 0x3F; 1304 - state->timeout_unit = (buffer->output[1] >> 30) & 0x3; 1305 - state->als_setting = buffer->output[2] & 0xFF; 1306 - state->als_value = (buffer->output[2] >> 8) & 0xFF; 1307 - state->level = (buffer->output[2] >> 16) & 0xFF; 1308 - state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F; 1309 - state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3; 1249 + state->triggers = (buffer.output[1] >> 16) & 0xFF; 1250 + state->timeout_value = (buffer.output[1] >> 24) & 0x3F; 1251 + state->timeout_unit = (buffer.output[1] >> 30) & 0x3; 1252 + state->als_setting = buffer.output[2] & 0xFF; 1253 + state->als_value = (buffer.output[2] >> 8) & 0xFF; 1254 + state->level = (buffer.output[2] >> 16) & 0xFF; 1255 + state->timeout_value_ac = (buffer.output[2] >> 24) & 0x3F; 1256 + state->timeout_unit_ac = (buffer.output[2] >> 30) & 0x3; 1310 1257 1311 1258 return ret; 1312 1259 } 1313 1260 1314 1261 static int kbd_set_state(struct kbd_state *state) 1315 1262 { 1263 + struct calling_interface_buffer buffer; 1316 1264 int ret; 1317 1265 u32 input1; 1318 1266 u32 input2; ··· 1328 1270 input2 |= (state->level & 0xFF) << 16; 1329 1271 input2 |= (state->timeout_value_ac & 0x3F) << 24; 1330 1272 input2 |= (state->timeout_unit_ac & 0x3) << 30; 1331 - dell_set_arguments(0x2, input1, input2, 0); 1332 - ret = dell_send_request(CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); 1273 + dell_fill_request(&buffer, 0x2, input1, input2, 0); 1274 + ret = dell_send_request(&buffer, 1275 + CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT); 1333 1276 1334 1277 return ret; 1335 1278 } ··· 1357 1298 1358 1299 static int kbd_set_token_bit(u8 bit) 1359 1300 { 1301 + struct calling_interface_buffer buffer; 1360 1302 struct calling_interface_token *token; 1361 1303 int ret; 1362 1304 ··· 1368 1308 if (!token) 1369 1309 return -EINVAL; 1370 1310 1371 - dell_set_arguments(token->location, token->value, 0, 0); 1372 - ret = dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); 1311 + dell_fill_request(&buffer, token->location, token->value, 0, 0); 1312 + ret = dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); 1373 1313 1374 1314 return ret; 1375 1315 } 1376 1316 1377 1317 static int kbd_get_token_bit(u8 bit) 1378 1318 { 1319 + struct calling_interface_buffer buffer; 1379 1320 struct calling_interface_token *token; 1380 1321 int ret; 1381 1322 int val; ··· 1388 1327 if (!token) 1389 1328 return -EINVAL; 1390 1329 1391 - dell_set_arguments(token->location, 0, 0, 0); 1392 - ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_STD); 1393 - val = buffer->output[1]; 1330 + dell_fill_request(&buffer, token->location, 0, 0, 0); 1331 + ret = dell_send_request(&buffer, CLASS_TOKEN_READ, SELECT_TOKEN_STD); 1332 + val = buffer.output[1]; 1394 1333 1395 1334 if (ret) 1396 1335 return ret; ··· 2008 1947 static int kbd_led_level_set(struct led_classdev *led_cdev, 2009 1948 enum led_brightness value) 2010 1949 { 1950 + enum led_brightness new_value = value; 2011 1951 struct kbd_state state; 2012 1952 struct kbd_state new_state; 2013 1953 u16 num; ··· 2038 1976 } 2039 1977 2040 1978 out: 1979 + if (ret == 0) 1980 + kbd_led_level = new_value; 1981 + 2041 1982 mutex_unlock(&kbd_led_mutex); 2042 1983 return ret; 2043 1984 } ··· 2068 2003 if (kbd_led.max_brightness) 2069 2004 kbd_led.max_brightness--; 2070 2005 } 2006 + 2007 + kbd_led_level = kbd_led_level_get(NULL); 2008 + 2071 2009 ret = led_classdev_register(dev, &kbd_led); 2072 2010 if (ret) 2073 2011 kbd_led_present = false; ··· 2095 2027 static int dell_laptop_notifier_call(struct notifier_block *nb, 2096 2028 unsigned long action, void *data) 2097 2029 { 2030 + bool changed = false; 2031 + enum led_brightness new_kbd_led_level; 2032 + 2098 2033 switch (action) { 2099 2034 case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED: 2100 2035 if (!kbd_led_present) 2101 2036 break; 2102 2037 2103 - led_classdev_notify_brightness_hw_changed(&kbd_led, 2104 - kbd_led_level_get(&kbd_led)); 2038 + mutex_lock(&kbd_led_mutex); 2039 + new_kbd_led_level = kbd_led_level_get(&kbd_led); 2040 + if (kbd_led_level != new_kbd_led_level) { 2041 + kbd_led_level = new_kbd_led_level; 2042 + changed = true; 2043 + } 2044 + mutex_unlock(&kbd_led_mutex); 2045 + 2046 + if (changed) 2047 + led_classdev_notify_brightness_hw_changed(&kbd_led, 2048 + kbd_led_level); 2105 2049 break; 2106 2050 } 2107 2051 ··· 2126 2046 2127 2047 int dell_micmute_led_set(int state) 2128 2048 { 2049 + struct calling_interface_buffer buffer; 2129 2050 struct calling_interface_token *token; 2130 2051 2131 2052 if (state == 0) ··· 2139 2058 if (!token) 2140 2059 return -ENODEV; 2141 2060 2142 - dell_set_arguments(token->location, token->value, 0, 0); 2143 - dell_send_request(CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); 2061 + dell_fill_request(&buffer, token->location, token->value, 0, 0); 2062 + dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD); 2144 2063 2145 2064 return state; 2146 2065 } ··· 2171 2090 if (ret) 2172 2091 goto fail_platform_device2; 2173 2092 2174 - buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL); 2175 - if (!buffer) { 2176 - ret = -ENOMEM; 2177 - goto fail_buffer; 2178 - } 2179 - 2180 - 2181 2093 ret = dell_setup_rfkill(); 2182 2094 2183 2095 if (ret) { ··· 2195 2121 2196 2122 token = dell_smbios_find_token(BRIGHTNESS_TOKEN); 2197 2123 if (token) { 2198 - dell_set_arguments(token->location, 0, 0, 0); 2199 - ret = dell_send_request(CLASS_TOKEN_READ, SELECT_TOKEN_AC); 2124 + struct calling_interface_buffer buffer; 2125 + 2126 + dell_fill_request(&buffer, token->location, 0, 0, 0); 2127 + ret = dell_send_request(&buffer, 2128 + CLASS_TOKEN_READ, SELECT_TOKEN_AC); 2200 2129 if (ret) 2201 - max_intensity = buffer->output[3]; 2130 + max_intensity = buffer.output[3]; 2202 2131 } 2203 2132 2204 2133 if (max_intensity) { ··· 2235 2158 fail_get_brightness: 2236 2159 backlight_device_unregister(dell_backlight_device); 2237 2160 fail_backlight: 2238 - kfree(buffer); 2239 - fail_buffer: 2240 2161 dell_cleanup_rfkill(); 2241 2162 fail_rfkill: 2242 2163 platform_device_del(platform_device); ··· 2254 2179 touchpad_led_exit(); 2255 2180 kbd_led_exit(); 2256 2181 backlight_device_unregister(dell_backlight_device); 2257 - kfree(buffer); 2258 2182 dell_cleanup_rfkill(); 2259 2183 if (platform_device) { 2260 2184 platform_device_unregister(platform_device);
+4 -4
drivers/platform/x86/dell-smbios.c
··· 65 65 66 66 /* calls that are explicitly blacklisted */ 67 67 static struct smbios_call call_blacklist[] = { 68 - {0x0000, 01, 07}, /* manufacturing use */ 69 - {0x0000, 06, 05}, /* manufacturing use */ 70 - {0x0000, 11, 03}, /* write once */ 71 - {0x0000, 11, 07}, /* write once */ 68 + {0x0000, 1, 7}, /* manufacturing use */ 69 + {0x0000, 6, 5}, /* manufacturing use */ 70 + {0x0000, 11, 3}, /* write once */ 71 + {0x0000, 11, 7}, /* write once */ 72 72 {0x0000, 11, 11}, /* write once */ 73 73 {0x0000, 19, -1}, /* diagnostics */ 74 74 /* handled by kernel: dell-laptop */
+3
drivers/platform/x86/dell-wmi.c
··· 261 261 * override them. 262 262 */ 263 263 static const struct key_entry dell_wmi_keymap_type_0010[] = { 264 + /* Mic mute */ 265 + { KE_KEY, 0x150, { KEY_MICMUTE } }, 266 + 264 267 /* Fn-lock */ 265 268 { KE_IGNORE, 0x151, { KEY_RESERVED } }, 266 269
+216
drivers/platform/x86/gpd-pocket-fan.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * GPD Pocket fan controller driver 4 + * 5 + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> 6 + */ 7 + 8 + #include <linux/acpi.h> 9 + #include <linux/gpio/consumer.h> 10 + #include <linux/module.h> 11 + #include <linux/moduleparam.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/power_supply.h> 14 + #include <linux/thermal.h> 15 + #include <linux/workqueue.h> 16 + 17 + #define MAX_SPEED 3 18 + 19 + static int temp_limits[3] = { 55000, 60000, 65000 }; 20 + module_param_array(temp_limits, int, NULL, 0444); 21 + MODULE_PARM_DESC(temp_limits, 22 + "Milli-celcius values above which the fan speed increases"); 23 + 24 + static int hysteresis = 3000; 25 + module_param(hysteresis, int, 0444); 26 + MODULE_PARM_DESC(hysteresis, 27 + "Hysteresis in milli-celcius before lowering the fan speed"); 28 + 29 + static int speed_on_ac = 2; 30 + module_param(speed_on_ac, int, 0444); 31 + MODULE_PARM_DESC(speed_on_ac, 32 + "minimum fan speed to allow when system is powered by AC"); 33 + 34 + struct gpd_pocket_fan_data { 35 + struct device *dev; 36 + struct thermal_zone_device *dts0; 37 + struct thermal_zone_device *dts1; 38 + struct gpio_desc *gpio0; 39 + struct gpio_desc *gpio1; 40 + struct delayed_work work; 41 + int last_speed; 42 + }; 43 + 44 + static void gpd_pocket_fan_set_speed(struct gpd_pocket_fan_data *fan, int speed) 45 + { 46 + if (speed == fan->last_speed) 47 + return; 48 + 49 + gpiod_direction_output(fan->gpio0, !!(speed & 1)); 50 + gpiod_direction_output(fan->gpio1, !!(speed & 2)); 51 + 52 + fan->last_speed = speed; 53 + } 54 + 55 + static int gpd_pocket_fan_min_speed(void) 56 + { 57 + if (power_supply_is_system_supplied()) 58 + return speed_on_ac; 59 + else 60 + return 0; 61 + } 62 + 63 + static void gpd_pocket_fan_worker(struct work_struct *work) 64 + { 65 + struct gpd_pocket_fan_data *fan = 66 + container_of(work, struct gpd_pocket_fan_data, work.work); 67 + int t0, t1, temp, speed, min_speed, i; 68 + 69 + if (thermal_zone_get_temp(fan->dts0, &t0) || 70 + thermal_zone_get_temp(fan->dts1, &t1)) { 71 + dev_warn(fan->dev, "Error getting temperature\n"); 72 + speed = MAX_SPEED; 73 + goto set_speed; 74 + } 75 + 76 + temp = max(t0, t1); 77 + 78 + speed = fan->last_speed; 79 + min_speed = gpd_pocket_fan_min_speed(); 80 + 81 + /* Determine minimum speed */ 82 + for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) { 83 + if (temp < temp_limits[i]) 84 + break; 85 + } 86 + if (speed < i) 87 + speed = i; 88 + 89 + /* Use hysteresis before lowering speed again */ 90 + for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) { 91 + if (temp <= (temp_limits[i] - hysteresis)) 92 + break; 93 + } 94 + if (speed > i) 95 + speed = i; 96 + 97 + if (fan->last_speed <= 0 && speed) 98 + speed = MAX_SPEED; /* kick start motor */ 99 + 100 + set_speed: 101 + gpd_pocket_fan_set_speed(fan, speed); 102 + 103 + /* When mostly idle (low temp/speed), slow down the poll interval. */ 104 + queue_delayed_work(system_wq, &fan->work, 105 + msecs_to_jiffies(4000 / (speed + 1))); 106 + } 107 + 108 + static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data *fan) 109 + { 110 + fan->last_speed = -1; 111 + mod_delayed_work(system_wq, &fan->work, 0); 112 + } 113 + 114 + static int gpd_pocket_fan_probe(struct platform_device *pdev) 115 + { 116 + struct gpd_pocket_fan_data *fan; 117 + int i; 118 + 119 + for (i = 0; i < ARRAY_SIZE(temp_limits); i++) { 120 + if (temp_limits[i] < 40000 || temp_limits[i] > 70000) { 121 + dev_err(&pdev->dev, "Invalid temp-limit %d (must be between 40000 and 70000)\n", 122 + temp_limits[i]); 123 + return -EINVAL; 124 + } 125 + } 126 + if (hysteresis < 1000 || hysteresis > 10000) { 127 + dev_err(&pdev->dev, "Invalid hysteresis %d (must be between 1000 and 10000)\n", 128 + hysteresis); 129 + return -EINVAL; 130 + } 131 + if (speed_on_ac < 0 || speed_on_ac > MAX_SPEED) { 132 + dev_err(&pdev->dev, "Invalid speed_on_ac %d (must be between 0 and 3)\n", 133 + speed_on_ac); 134 + return -EINVAL; 135 + } 136 + 137 + fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); 138 + if (!fan) 139 + return -ENOMEM; 140 + 141 + fan->dev = &pdev->dev; 142 + INIT_DELAYED_WORK(&fan->work, gpd_pocket_fan_worker); 143 + 144 + /* Note this returns a "weak" reference which we don't need to free */ 145 + fan->dts0 = thermal_zone_get_zone_by_name("soc_dts0"); 146 + if (IS_ERR(fan->dts0)) 147 + return -EPROBE_DEFER; 148 + 149 + fan->dts1 = thermal_zone_get_zone_by_name("soc_dts1"); 150 + if (IS_ERR(fan->dts1)) 151 + return -EPROBE_DEFER; 152 + 153 + fan->gpio0 = devm_gpiod_get_index(fan->dev, NULL, 0, GPIOD_ASIS); 154 + if (IS_ERR(fan->gpio0)) 155 + return PTR_ERR(fan->gpio0); 156 + 157 + fan->gpio1 = devm_gpiod_get_index(fan->dev, NULL, 1, GPIOD_ASIS); 158 + if (IS_ERR(fan->gpio1)) 159 + return PTR_ERR(fan->gpio1); 160 + 161 + gpd_pocket_fan_force_update(fan); 162 + 163 + platform_set_drvdata(pdev, fan); 164 + return 0; 165 + } 166 + 167 + static int gpd_pocket_fan_remove(struct platform_device *pdev) 168 + { 169 + struct gpd_pocket_fan_data *fan = platform_get_drvdata(pdev); 170 + 171 + cancel_delayed_work_sync(&fan->work); 172 + return 0; 173 + } 174 + 175 + #ifdef CONFIG_PM_SLEEP 176 + static int gpd_pocket_fan_suspend(struct device *dev) 177 + { 178 + struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev); 179 + 180 + cancel_delayed_work_sync(&fan->work); 181 + gpd_pocket_fan_set_speed(fan, gpd_pocket_fan_min_speed()); 182 + return 0; 183 + } 184 + 185 + static int gpd_pocket_fan_resume(struct device *dev) 186 + { 187 + struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev); 188 + 189 + gpd_pocket_fan_force_update(fan); 190 + return 0; 191 + } 192 + #endif 193 + static SIMPLE_DEV_PM_OPS(gpd_pocket_fan_pm_ops, 194 + gpd_pocket_fan_suspend, 195 + gpd_pocket_fan_resume); 196 + 197 + static struct acpi_device_id gpd_pocket_fan_acpi_match[] = { 198 + { "FAN02501" }, 199 + {}, 200 + }; 201 + MODULE_DEVICE_TABLE(acpi, gpd_pocket_fan_acpi_match); 202 + 203 + static struct platform_driver gpd_pocket_fan_driver = { 204 + .probe = gpd_pocket_fan_probe, 205 + .remove = gpd_pocket_fan_remove, 206 + .driver = { 207 + .name = "gpd_pocket_fan", 208 + .acpi_match_table = gpd_pocket_fan_acpi_match, 209 + .pm = &gpd_pocket_fan_pm_ops, 210 + }, 211 + }; 212 + 213 + module_platform_driver(gpd_pocket_fan_driver); 214 + MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com"); 215 + MODULE_DESCRIPTION("GPD pocket fan driver"); 216 + MODULE_LICENSE("GPL");
+21 -7
drivers/platform/x86/ideapad-laptop.c
··· 124 124 if (ACPI_FAILURE(status)) { 125 125 *val = -1; 126 126 return -1; 127 - } else { 128 - *val = result; 129 - return 0; 130 127 } 128 + *val = result; 129 + return 0; 130 + 131 131 } 132 132 133 133 static int method_gbmd(acpi_handle handle, unsigned long *ret) ··· 164 164 if (ACPI_FAILURE(status)) { 165 165 *ret = -1; 166 166 return -1; 167 - } else { 168 - *ret = result; 169 - return 0; 170 167 } 168 + *ret = result; 169 + return 0; 170 + 171 171 } 172 172 173 173 static int method_vpcw(acpi_handle handle, int cmd, int data) ··· 231 231 if (val == 0) 232 232 return 0; 233 233 } 234 - pr_err("timeout in write_ec_cmd\n"); 234 + pr_err("timeout in %s\n", __func__); 235 235 return -1; 236 236 } 237 237 ··· 964 964 */ 965 965 static 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 974 .ident = "Lenovo G40-30", 968 975 .matches = { 969 976 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), ··· 1108 1101 .matches = { 1109 1102 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 1110 1103 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"), 1104 + }, 1105 + }, 1106 + { 1107 + .ident = "Lenovo Legion Y720-15IKB", 1108 + .matches = { 1109 + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 1110 + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKB"), 1111 1111 }, 1112 1112 }, 1113 1113 {
+38 -3
drivers/platform/x86/intel-hid.c
··· 25 25 #include <linux/acpi.h> 26 26 #include <linux/suspend.h> 27 27 #include <acpi/acpi_bus.h> 28 + #include <linux/dmi.h> 28 29 29 30 MODULE_LICENSE("GPL"); 30 31 MODULE_AUTHOR("Alex Hung"); ··· 72 71 { KE_KEY, 0xCE, { KEY_POWER } }, /* Press */ 73 72 { KE_IGNORE, 0xCF, { KEY_POWER } }, /* Release */ 74 73 { KE_END }, 74 + }; 75 + 76 + static const struct dmi_system_id button_array_table[] = { 77 + { 78 + .ident = "Wacom MobileStudio Pro 13", 79 + .matches = { 80 + DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"), 81 + DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 13"), 82 + }, 83 + }, 84 + { 85 + .ident = "Wacom MobileStudio Pro 16", 86 + .matches = { 87 + DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"), 88 + DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 16"), 89 + }, 90 + }, 91 + { } 75 92 }; 76 93 77 94 struct intel_hid_priv { ··· 282 263 ev_index); 283 264 } 284 265 266 + static bool button_array_present(struct platform_device *device) 267 + { 268 + acpi_handle handle = ACPI_HANDLE(&device->dev); 269 + unsigned long long event_cap; 270 + acpi_status status; 271 + bool supported = false; 272 + 273 + status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap); 274 + if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) 275 + supported = true; 276 + 277 + if (dmi_check_system(button_array_table)) 278 + supported = true; 279 + 280 + return supported; 281 + } 282 + 285 283 static int intel_hid_probe(struct platform_device *device) 286 284 { 287 285 acpi_handle handle = ACPI_HANDLE(&device->dev); 288 - unsigned long long event_cap, mode; 286 + unsigned long long mode; 289 287 struct intel_hid_priv *priv; 290 288 acpi_status status; 291 289 int err; ··· 335 299 } 336 300 337 301 /* Setup 5 button array */ 338 - status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap); 339 - if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) { 302 + if (button_array_present(device)) { 340 303 dev_info(&device->dev, "platform supports 5 button array\n"); 341 304 err = intel_button_array_input_setup(device); 342 305 if (err)
+47 -18
drivers/platform/x86/intel-vbtn.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 1 2 /* 2 3 * Intel Virtual Button driver for Windows 8.1+ 3 4 * 4 5 * Copyright (C) 2016 AceLan Kao <acelan.kao@canonical.com> 5 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 12 #include <linux/kernel.h> 20 13 #include <linux/module.h> 21 - #include <linux/init.h> 22 - #include <linux/input.h> 23 14 #include <linux/platform_device.h> 24 - #include <linux/input/sparse-keymap.h> 25 - #include <linux/acpi.h> 26 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 29 20 MODULE_LICENSE("GPL"); 30 21 MODULE_AUTHOR("AceLan Kao"); ··· 29 38 static const struct key_entry intel_vbtn_keymap[] = { 30 39 { KE_KEY, 0xC0, { KEY_POWER } }, /* power key press */ 31 40 { KE_IGNORE, 0xC1, { KEY_POWER } }, /* power key release */ 41 + { KE_KEY, 0xC2, { KEY_LEFTMETA } }, /* 'Windows' key press */ 42 + { KE_KEY, 0xC3, { KEY_LEFTMETA } }, /* 'Windows' key release */ 32 43 { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */ 33 44 { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */ 34 45 { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */ 35 46 { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */ 47 + { KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key press */ 48 + { KE_KEY, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key release */ 49 + { KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */ 50 + { KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */ 36 51 { KE_END }, 37 52 }; 38 53 ··· 71 74 { 72 75 struct platform_device *device = context; 73 76 struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); 77 + unsigned int val = !(event & 1); /* Even=press, Odd=release */ 78 + const struct key_entry *ke_rel; 79 + bool autorelease; 74 80 75 81 if (priv->wakeup_mode) { 76 82 if (sparse_keymap_entry_from_scancode(priv->input_dev, event)) { 77 83 pm_wakeup_hard_event(&device->dev); 78 84 return; 79 85 } 80 - } else if (sparse_keymap_report_event(priv->input_dev, event, 1, true)) { 81 - return; 86 + goto out_unknown; 82 87 } 88 + 89 + /* 90 + * Even press events are autorelease if there is no corresponding odd 91 + * release event, or if the odd event is KE_IGNORE. 92 + */ 93 + ke_rel = sparse_keymap_entry_from_scancode(priv->input_dev, event | 1); 94 + autorelease = val && (!ke_rel || ke_rel->type == KE_IGNORE); 95 + 96 + if (sparse_keymap_report_event(priv->input_dev, event, val, autorelease)) 97 + return; 98 + 99 + out_unknown: 83 100 dev_dbg(&device->dev, "unknown event index 0x%x\n", event); 84 101 } 85 102 86 103 static int intel_vbtn_probe(struct platform_device *device) 87 104 { 105 + struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL }; 88 106 acpi_handle handle = ACPI_HANDLE(&device->dev); 89 107 struct intel_vbtn_priv *priv; 90 108 acpi_status status; ··· 121 109 pr_err("Failed to setup Intel Virtual Button\n"); 122 110 return err; 123 111 } 112 + 113 + /* 114 + * VGBS being present and returning something means we have 115 + * a tablet mode switch. 116 + */ 117 + status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output); 118 + if (ACPI_SUCCESS(status)) { 119 + union acpi_object *obj = vgbs_output.pointer; 120 + 121 + if (obj && obj->type == ACPI_TYPE_INTEGER) { 122 + int m = !(obj->integer.value & TABLET_MODE_FLAG); 123 + 124 + input_report_switch(priv->input_dev, SW_TABLET_MODE, m); 125 + } 126 + } 127 + 128 + kfree(vgbs_output.pointer); 124 129 125 130 status = acpi_install_notify_handler(handle, 126 131 ACPI_DEVICE_NOTIFY,
+93
drivers/platform/x86/intel_chtdc_ti_pwrbtn.c
··· 1 + /* 2 + * Power-button driver for Dollar Cove TI PMIC 3 + * Copyright (C) 2014 Intel Corp 4 + * Copyright (c) 2017 Takashi Iwai <tiwai@suse.de> 5 + */ 6 + 7 + #include <linux/input.h> 8 + #include <linux/interrupt.h> 9 + #include <linux/device.h> 10 + #include <linux/mfd/intel_soc_pmic.h> 11 + #include <linux/module.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/pm_wakeirq.h> 14 + #include <linux/slab.h> 15 + 16 + #define CHTDC_TI_SIRQ_REG 0x3 17 + #define SIRQ_PWRBTN_REL BIT(0) 18 + 19 + static irqreturn_t chtdc_ti_pwrbtn_interrupt(int irq, void *dev_id) 20 + { 21 + struct input_dev *input = dev_id; 22 + struct device *dev = input->dev.parent; 23 + struct regmap *regmap = dev_get_drvdata(dev); 24 + int state; 25 + 26 + if (!regmap_read(regmap, CHTDC_TI_SIRQ_REG, &state)) { 27 + dev_dbg(dev, "SIRQ_REG=0x%x\n", state); 28 + input_report_key(input, KEY_POWER, !(state & SIRQ_PWRBTN_REL)); 29 + input_sync(input); 30 + } 31 + 32 + return IRQ_HANDLED; 33 + } 34 + 35 + static int chtdc_ti_pwrbtn_probe(struct platform_device *pdev) 36 + { 37 + struct device *dev = &pdev->dev; 38 + struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent); 39 + struct input_dev *input; 40 + int irq, err; 41 + 42 + irq = platform_get_irq(pdev, 0); 43 + if (irq < 0) 44 + return irq; 45 + input = devm_input_allocate_device(dev); 46 + if (!input) 47 + return -ENOMEM; 48 + input->name = pdev->name; 49 + input->phys = "power-button/input0"; 50 + input->id.bustype = BUS_HOST; 51 + input_set_capability(input, EV_KEY, KEY_POWER); 52 + err = input_register_device(input); 53 + if (err) 54 + return err; 55 + 56 + dev_set_drvdata(dev, pmic->regmap); 57 + 58 + err = devm_request_threaded_irq(dev, irq, NULL, 59 + chtdc_ti_pwrbtn_interrupt, 60 + 0, KBUILD_MODNAME, input); 61 + if (err) 62 + return err; 63 + 64 + device_init_wakeup(dev, true); 65 + dev_pm_set_wake_irq(dev, irq); 66 + return 0; 67 + } 68 + 69 + static int chtdc_ti_pwrbtn_remove(struct platform_device *pdev) 70 + { 71 + dev_pm_clear_wake_irq(&pdev->dev); 72 + device_init_wakeup(&pdev->dev, false); 73 + return 0; 74 + } 75 + 76 + static const struct platform_device_id chtdc_ti_pwrbtn_id_table[] = { 77 + { .name = "chtdc_ti_pwrbtn" }, 78 + {}, 79 + }; 80 + MODULE_DEVICE_TABLE(platform, chtdc_ti_pwrbtn_id_table); 81 + 82 + static struct platform_driver chtdc_ti_pwrbtn_driver = { 83 + .driver = { 84 + .name = KBUILD_MODNAME, 85 + }, 86 + .probe = chtdc_ti_pwrbtn_probe, 87 + .remove = chtdc_ti_pwrbtn_remove, 88 + .id_table = chtdc_ti_pwrbtn_id_table, 89 + }; 90 + module_platform_driver(chtdc_ti_pwrbtn_driver); 91 + 92 + MODULE_DESCRIPTION("Power-button driver for Dollar Cove TI PMIC"); 93 + MODULE_LICENSE("GPL v2");
+1 -1
drivers/platform/x86/intel_int0002_vgpio.c
··· 180 180 * to gpiochip_set_chained_irqchip, because the irq is shared. 181 181 */ 182 182 ret = devm_request_irq(dev, irq, int0002_irq, 183 - IRQF_SHARED | IRQF_NO_THREAD, "INT0002", chip); 183 + IRQF_SHARED, "INT0002", chip); 184 184 if (ret) { 185 185 dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret); 186 186 return ret;
+153 -111
drivers/platform/x86/intel_pmc_core.c
··· 18 18 * 19 19 */ 20 20 21 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22 + 23 + #include <linux/acpi.h> 21 24 #include <linux/debugfs.h> 22 25 #include <linux/delay.h> 23 - #include <linux/device.h> 24 - #include <linux/init.h> 25 26 #include <linux/io.h> 27 + #include <linux/module.h> 26 28 #include <linux/pci.h> 27 29 #include <linux/uaccess.h> 28 30 29 31 #include <asm/cpu_device_id.h> 30 32 #include <asm/intel-family.h> 31 - #include <asm/pmc_core.h> 32 33 33 34 #include "intel_pmc_core.h" 35 + 36 + #define ICPU(model, data) \ 37 + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (kernel_ulong_t)data } 34 38 35 39 static struct pmc_dev pmc; 36 40 ··· 123 119 .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT, 124 120 }; 125 121 126 - static const struct pci_device_id pmc_pci_ids[] = { 127 - { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), 128 - (kernel_ulong_t)&spt_reg_map }, 129 - { 0, }, 122 + /* Cannonlake: PGD PFET Enable Ack Status Register(s) bitmap */ 123 + static const struct pmc_bit_map cnp_pfear_map[] = { 124 + {"PMC", BIT(0)}, 125 + {"OPI-DMI", BIT(1)}, 126 + {"SPI/eSPI", BIT(2)}, 127 + {"XHCI", BIT(3)}, 128 + {"SPA", BIT(4)}, 129 + {"SPB", BIT(5)}, 130 + {"SPC", BIT(6)}, 131 + {"GBE", BIT(7)}, 132 + 133 + {"SATA", BIT(0)}, 134 + {"HDA_PGD0", BIT(1)}, 135 + {"HDA_PGD1", BIT(2)}, 136 + {"HDA_PGD2", BIT(3)}, 137 + {"HDA_PGD3", BIT(4)}, 138 + {"SPD", BIT(5)}, 139 + {"LPSS", BIT(6)}, 140 + {"LPC", BIT(7)}, 141 + 142 + {"SMB", BIT(0)}, 143 + {"ISH", BIT(1)}, 144 + {"P2SB", BIT(2)}, 145 + {"NPK_VNN", BIT(3)}, 146 + {"SDX", BIT(4)}, 147 + {"SPE", BIT(5)}, 148 + {"Fuse", BIT(6)}, 149 + {"Res_23", BIT(7)}, 150 + 151 + {"CSME_FSC", BIT(0)}, 152 + {"USB3_OTG", BIT(1)}, 153 + {"EXI", BIT(2)}, 154 + {"CSE", BIT(3)}, 155 + {"csme_kvm", BIT(4)}, 156 + {"csme_pmt", BIT(5)}, 157 + {"csme_clink", BIT(6)}, 158 + {"csme_ptio", BIT(7)}, 159 + 160 + {"csme_usbr", BIT(0)}, 161 + {"csme_susram", BIT(1)}, 162 + {"csme_smt1", BIT(2)}, 163 + {"CSME_SMT4", BIT(3)}, 164 + {"csme_sms2", BIT(4)}, 165 + {"csme_sms1", BIT(5)}, 166 + {"csme_rtc", BIT(6)}, 167 + {"csme_psf", BIT(7)}, 168 + 169 + {"SBR0", BIT(0)}, 170 + {"SBR1", BIT(1)}, 171 + {"SBR2", BIT(2)}, 172 + {"SBR3", BIT(3)}, 173 + {"SBR4", BIT(4)}, 174 + {"SBR5", BIT(5)}, 175 + {"CSME_PECI", BIT(6)}, 176 + {"PSF1", BIT(7)}, 177 + 178 + {"PSF2", BIT(0)}, 179 + {"PSF3", BIT(1)}, 180 + {"PSF4", BIT(2)}, 181 + {"CNVI", BIT(3)}, 182 + {"UFS0", BIT(4)}, 183 + {"EMMC", BIT(5)}, 184 + {"Res_6", BIT(6)}, 185 + {"SBR6", BIT(7)}, 186 + 187 + {"SBR7", BIT(0)}, 188 + {"NPK_AON", BIT(1)}, 189 + {"HDA_PGD4", BIT(2)}, 190 + {"HDA_PGD5", BIT(3)}, 191 + {"HDA_PGD6", BIT(4)}, 192 + {} 193 + }; 194 + 195 + static const struct pmc_reg_map cnp_reg_map = { 196 + .pfear_sts = cnp_pfear_map, 197 + .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, 198 + .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET, 199 + .regmap_length = CNP_PMC_MMIO_REG_LEN, 200 + .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, 201 + .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES, 202 + .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, 203 + .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, 130 204 }; 131 205 132 206 static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset) ··· 227 145 { 228 146 return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP; 229 147 } 230 - 231 - /** 232 - * intel_pmc_slp_s0_counter_read() - Read SLP_S0 residency. 233 - * @data: Out param that contains current SLP_S0 count. 234 - * 235 - * This API currently supports Intel Skylake SoC and Sunrise 236 - * Point Platform Controller Hub. Future platform support 237 - * should be added for platforms that support low power modes 238 - * beyond Package C10 state. 239 - * 240 - * SLP_S0_RESIDENCY counter counts in 100 us granularity per 241 - * step hence function populates the multiplied value in out 242 - * parameter @data. 243 - * 244 - * Return: an error code or 0 on success. 245 - */ 246 - int intel_pmc_slp_s0_counter_read(u32 *data) 247 - { 248 - struct pmc_dev *pmcdev = &pmc; 249 - const struct pmc_reg_map *map = pmcdev->map; 250 - u32 value; 251 - 252 - if (!pmcdev->has_slp_s0_res) 253 - return -EACCES; 254 - 255 - value = pmc_core_reg_read(pmcdev, map->slp_s0_offset); 256 - *data = pmc_core_adjust_slp_s0_step(value); 257 - 258 - return 0; 259 - } 260 - EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read); 261 148 262 149 static int pmc_core_dev_state_get(void *data, u64 *val) 263 150 { ··· 488 437 489 438 static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) 490 439 { 491 - struct dentry *dir, *file; 440 + struct dentry *dir; 492 441 493 442 dir = debugfs_create_dir("pmc_core", NULL); 494 443 if (!dir) 495 444 return -ENOMEM; 496 445 497 446 pmcdev->dbgfs_dir = dir; 498 - file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO, 499 - dir, pmcdev, &pmc_core_dev_state); 500 - if (!file) 501 - goto err; 502 447 503 - file = debugfs_create_file("pch_ip_power_gating_status", 504 - S_IFREG | S_IRUGO, dir, pmcdev, 505 - &pmc_core_ppfear_ops); 506 - if (!file) 507 - goto err; 448 + debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev, 449 + &pmc_core_dev_state); 508 450 509 - file = debugfs_create_file("mphy_core_lanes_power_gating_status", 510 - S_IFREG | S_IRUGO, dir, pmcdev, 511 - &pmc_core_mphy_pg_ops); 512 - if (!file) 513 - goto err; 451 + debugfs_create_file("pch_ip_power_gating_status", 0444, dir, pmcdev, 452 + &pmc_core_ppfear_ops); 514 453 515 - file = debugfs_create_file("pll_status", 516 - S_IFREG | S_IRUGO, dir, pmcdev, 517 - &pmc_core_pll_ops); 518 - if (!file) 519 - goto err; 454 + debugfs_create_file("ltr_ignore", 0644, dir, pmcdev, 455 + &pmc_core_ltr_ignore_ops); 520 456 521 - file = debugfs_create_file("ltr_ignore", 522 - S_IFREG | S_IRUGO, dir, pmcdev, 523 - &pmc_core_ltr_ignore_ops); 457 + if (pmcdev->map->pll_sts) 458 + debugfs_create_file("pll_status", 0444, dir, pmcdev, 459 + &pmc_core_pll_ops); 524 460 525 - if (!file) 526 - goto err; 461 + if (pmcdev->map->mphy_sts) 462 + debugfs_create_file("mphy_core_lanes_power_gating_status", 463 + 0444, dir, pmcdev, 464 + &pmc_core_mphy_pg_ops); 527 465 528 466 return 0; 529 - err: 530 - pmc_core_dbgfs_unregister(pmcdev); 531 - return -ENODEV; 532 467 } 533 468 #else 534 469 static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) ··· 528 491 #endif /* CONFIG_DEBUG_FS */ 529 492 530 493 static const struct x86_cpu_id intel_pmc_core_ids[] = { 531 - { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT, 532 - (kernel_ulong_t)NULL}, 533 - { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT, 534 - (kernel_ulong_t)NULL}, 535 - { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_MOBILE, X86_FEATURE_MWAIT, 536 - (kernel_ulong_t)NULL}, 537 - { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_DESKTOP, X86_FEATURE_MWAIT, 538 - (kernel_ulong_t)NULL}, 494 + ICPU(INTEL_FAM6_SKYLAKE_MOBILE, &spt_reg_map), 495 + ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, &spt_reg_map), 496 + ICPU(INTEL_FAM6_KABYLAKE_MOBILE, &spt_reg_map), 497 + ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, &spt_reg_map), 498 + ICPU(INTEL_FAM6_CANNONLAKE_MOBILE, &cnp_reg_map), 539 499 {} 540 500 }; 541 501 542 - static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) 502 + MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids); 503 + 504 + static const struct pci_device_id pmc_pci_ids[] = { 505 + { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), 0}, 506 + { 0, }, 507 + }; 508 + 509 + static int __init pmc_core_probe(void) 543 510 { 544 - struct device *ptr_dev = &dev->dev; 545 511 struct pmc_dev *pmcdev = &pmc; 546 512 const struct x86_cpu_id *cpu_id; 547 - const struct pmc_reg_map *map = (struct pmc_reg_map *)id->driver_data; 513 + u64 slp_s0_addr; 548 514 int err; 549 515 550 516 cpu_id = x86_match_cpu(intel_pmc_core_ids); 551 - if (!cpu_id) { 552 - dev_dbg(&dev->dev, "PMC Core: cpuid mismatch.\n"); 553 - return -EINVAL; 554 - } 517 + if (!cpu_id) 518 + return -ENODEV; 555 519 556 - err = pcim_enable_device(dev); 557 - if (err < 0) { 558 - dev_dbg(&dev->dev, "PMC Core: failed to enable Power Management Controller.\n"); 559 - return err; 560 - } 520 + pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data; 561 521 562 - err = pci_read_config_dword(dev, 563 - SPT_PMC_BASE_ADDR_OFFSET, 564 - &pmcdev->base_addr); 565 - if (err < 0) { 566 - dev_dbg(&dev->dev, "PMC Core: failed to read PCI config space.\n"); 567 - return err; 568 - } 569 - pmcdev->base_addr &= PMC_BASE_ADDR_MASK; 570 - dev_dbg(&dev->dev, "PMC Core: PWRMBASE is %#x\n", pmcdev->base_addr); 522 + /* 523 + * Coffeelake has CPU ID of Kabylake and Cannonlake PCH. So here 524 + * Sunrisepoint PCH regmap can't be used. Use Cannonlake PCH regmap 525 + * in this case. 526 + */ 527 + if (!pci_dev_present(pmc_pci_ids)) 528 + pmcdev->map = &cnp_reg_map; 571 529 572 - pmcdev->regbase = devm_ioremap_nocache(ptr_dev, 573 - pmcdev->base_addr, 574 - SPT_PMC_MMIO_REG_LEN); 575 - if (!pmcdev->regbase) { 576 - dev_dbg(&dev->dev, "PMC Core: ioremap failed.\n"); 530 + if (lpit_read_residency_count_address(&slp_s0_addr)) 531 + pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT; 532 + else 533 + pmcdev->base_addr = slp_s0_addr - pmcdev->map->slp_s0_offset; 534 + 535 + pmcdev->regbase = ioremap(pmcdev->base_addr, 536 + pmcdev->map->regmap_length); 537 + if (!pmcdev->regbase) 577 538 return -ENOMEM; 578 - } 579 539 580 540 mutex_init(&pmcdev->lock); 581 - pmcdev->map = map; 582 541 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(); 583 542 584 543 err = pmc_core_dbgfs_register(pmcdev); 585 - if (err < 0) 586 - dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n"); 544 + if (err < 0) { 545 + pr_warn(" debugfs register failed.\n"); 546 + iounmap(pmcdev->regbase); 547 + return err; 548 + } 587 549 588 - pmc.has_slp_s0_res = true; 550 + pr_info(" initialized\n"); 589 551 return 0; 590 552 } 553 + module_init(pmc_core_probe) 591 554 592 - static struct pci_driver intel_pmc_core_driver = { 593 - .name = "intel_pmc_core", 594 - .id_table = pmc_pci_ids, 595 - .probe = pmc_core_probe, 596 - }; 555 + static void __exit pmc_core_remove(void) 556 + { 557 + struct pmc_dev *pmcdev = &pmc; 597 558 598 - builtin_pci_driver(intel_pmc_core_driver); 559 + pmc_core_dbgfs_unregister(pmcdev); 560 + mutex_destroy(&pmcdev->lock); 561 + iounmap(pmcdev->regbase); 562 + } 563 + module_exit(pmc_core_remove) 564 + 565 + MODULE_LICENSE("GPL v2"); 566 + MODULE_DESCRIPTION("Intel PMC Core Driver");
+20 -9
drivers/platform/x86/intel_pmc_core.h
··· 21 21 #ifndef PMC_CORE_H 22 22 #define PMC_CORE_H 23 23 24 + #define PMC_BASE_ADDR_DEFAULT 0xFE000000 25 + 24 26 /* Sunrise Point Power Management Controller PCI Device ID */ 25 27 #define SPT_PMC_PCI_DEVICE_ID 0x9d21 26 - 27 28 #define SPT_PMC_BASE_ADDR_OFFSET 0x48 28 29 #define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c 29 30 #define SPT_PMC_PM_CFG_OFFSET 0x18 ··· 123 122 #define SPT_PMC_BIT_MPHY_CMN_LANE2 BIT(2) 124 123 #define SPT_PMC_BIT_MPHY_CMN_LANE3 BIT(3) 125 124 125 + /* Cannonlake Power Management Controller register offsets */ 126 + #define CNP_PMC_SLP_S0_RES_COUNTER_OFFSET 0x193C 127 + #define CNP_PMC_LTR_IGNORE_OFFSET 0x1B0C 128 + #define CNP_PMC_PM_CFG_OFFSET 0x1818 129 + /* Cannonlake: PGD PFET Enable Ack Status Register(s) start */ 130 + #define CNP_PMC_HOST_PPFEAR0A 0x1D90 131 + 132 + #define CNP_PMC_MMIO_REG_LEN 0x2000 133 + #define CNP_PPFEAR_NUM_ENTRIES 8 134 + #define CNP_PMC_READ_DISABLE_BIT 22 135 + 126 136 struct pmc_bit_map { 127 137 const char *name; 128 138 u32 bit_mask; ··· 147 135 * @pll_sts: Maps name of PLL to corresponding bit status 148 136 * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency 149 137 * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit 150 - * @base_address: Base address of PWRMBASE defined in BIOS writer guide 151 138 * @regmap_length: Length of memory to map from PWRMBASE address to access 152 139 * @ppfear0_offset: PWRMBASE offset to to read PPFEAR* 153 140 * @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from ··· 163 152 const struct pmc_bit_map *pll_sts; 164 153 const u32 slp_s0_offset; 165 154 const u32 ltr_ignore_offset; 166 - const u32 base_address; 167 155 const int regmap_length; 168 156 const u32 ppfear0_offset; 169 157 const int ppfear_buckets; ··· 172 162 173 163 /** 174 164 * struct pmc_dev - pmc device structure 175 - * @base_addr: comtains pmc base address 165 + * @base_addr: contains pmc base address 176 166 * @regbase: pointer to io-remapped memory location 177 - * @dbgfs_dir: path to debug fs interface 178 - * @feature_available: flag to indicate whether 179 - * the feature is available 180 - * on a particular platform or not. 167 + * @map: pointer to pmc_reg_map struct that contains platform 168 + * specific attributes 169 + * @dbgfs_dir: path to debugfs interface 170 + * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers 171 + * used to read MPHY PG and PLL status are available 172 + * @mutex_lock: mutex to complete one transcation 181 173 * 182 174 * pmc_dev contains info about power management controller device. 183 175 */ ··· 190 178 #if IS_ENABLED(CONFIG_DEBUG_FS) 191 179 struct dentry *dbgfs_dir; 192 180 #endif /* CONFIG_DEBUG_FS */ 193 - bool has_slp_s0_res; 194 181 int pmc_xram_read_bit; 195 182 struct mutex lock; /* generic mutex lock for PMC Core */ 196 183 };
+31 -2
drivers/platform/x86/intel_pmc_ipc.c
··· 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 219 * @offset: offset of GCR register from GCR address base 220 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 224 * Return: negative value on error or 0 on success. 225 225 */ ··· 242 242 return 0; 243 243 } 244 244 EXPORT_SYMBOL_GPL(intel_pmc_gcr_read); 245 + 246 + /** 247 + * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register 248 + * @offset: offset of GCR register from GCR address base 249 + * @data: data pointer for storing the register output 250 + * 251 + * Reads the 64-bit PMC GCR register at given offset. 252 + * 253 + * Return: negative value on error or 0 on success. 254 + */ 255 + int intel_pmc_gcr_read64(u32 offset, u64 *data) 256 + { 257 + int ret; 258 + 259 + spin_lock(&ipcdev.gcr_lock); 260 + 261 + ret = is_gcr_valid(offset); 262 + if (ret < 0) { 263 + spin_unlock(&ipcdev.gcr_lock); 264 + return ret; 265 + } 266 + 267 + *data = readq(ipcdev.gcr_mem_base + offset); 268 + 269 + spin_unlock(&ipcdev.gcr_lock); 270 + 271 + return 0; 272 + } 273 + EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64); 245 274 246 275 /** 247 276 * intel_pmc_gcr_write() - Write PMC GCR register
+35 -48
drivers/platform/x86/intel_telemetry_debugfs.c
··· 23 23 */ 24 24 #include <linux/debugfs.h> 25 25 #include <linux/device.h> 26 - #include <linux/io.h> 27 26 #include <linux/module.h> 28 27 #include <linux/pci.h> 29 28 #include <linux/seq_file.h> ··· 31 32 #include <asm/cpu_device_id.h> 32 33 #include <asm/intel-family.h> 33 34 #include <asm/intel_pmc_ipc.h> 34 - #include <asm/intel_punit_ipc.h> 35 35 #include <asm/intel_telemetry.h> 36 36 37 - #define DRIVER_NAME "telemetry_soc_debugfs" 38 - #define DRIVER_VERSION "1.0.0" 37 + #define DRIVER_NAME "telemetry_soc_debugfs" 38 + #define DRIVER_VERSION "1.0.0" 39 39 40 40 /* ApolloLake SoC Event-IDs */ 41 41 #define TELEM_APL_PSS_PSTATES_ID 0x2802 ··· 96 98 static u64 suspend_shlw_res_temp, suspend_deep_res_temp; 97 99 98 100 struct telemetry_susp_stats { 99 - u32 shlw_swake_ctr; 100 - u32 deep_swake_ctr; 101 - u64 shlw_swake_res; 102 - u64 deep_swake_res; 103 101 u32 shlw_ctr; 104 102 u32 deep_ctr; 105 103 u64 shlw_res; ··· 244 250 {"PRTC", 25}, 245 251 }; 246 252 247 - 248 253 struct telemetry_debugfs_conf { 249 254 struct telemetry_susp_stats suspend_stats; 250 255 struct dentry *telemetry_dbg_dir; ··· 378 385 TELEM_APL_MASK_PCS_STATE; 379 386 } 380 387 381 - 382 388 TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id, 383 389 conf->pss_idle_evts - 1, 384 390 pss_idle, evtlog[index].telem_evtlog, ··· 396 404 evtlog[index].telem_evtlog, 397 405 conf->pcs_s0ix_blkd_data, 398 406 TELEM_MASK_BYTE); 399 - 400 407 401 408 TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id, 402 409 conf->pss_wakeup_evts, ··· 488 497 .llseek = seq_lseek, 489 498 .release = single_release, 490 499 }; 491 - 492 500 493 501 static int telem_ioss_states_show(struct seq_file *s, void *unused) 494 502 { ··· 588 598 589 599 seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n", 590 600 s0ix_shlw_ctr - 591 - conf->suspend_stats.shlw_ctr - 592 - conf->suspend_stats.shlw_swake_ctr, 601 + conf->suspend_stats.shlw_ctr, 593 602 (u64)((s0ix_shlw_res - 594 - conf->suspend_stats.shlw_res - 595 - conf->suspend_stats.shlw_swake_res)*10/192)); 603 + conf->suspend_stats.shlw_res)*10/192)); 596 604 597 605 seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n", 598 606 s0ix_deep_ctr - 599 - conf->suspend_stats.deep_ctr - 600 - conf->suspend_stats.deep_swake_ctr, 607 + conf->suspend_stats.deep_ctr, 601 608 (u64)((s0ix_deep_res - 602 - conf->suspend_stats.deep_res - 603 - conf->suspend_stats.deep_swake_res)*10/192)); 609 + conf->suspend_stats.deep_res)*10/192)); 604 610 605 611 seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n", 606 612 conf->suspend_stats.shlw_ctr, ··· 606 620 conf->suspend_stats.deep_ctr, 607 621 (u64)(conf->suspend_stats.deep_res*10)/192); 608 622 609 - seq_printf(s, "Suspend(With Shallow-Wakes)\t %10u\t %10llu\n", 610 - conf->suspend_stats.shlw_swake_ctr + 611 - conf->suspend_stats.deep_swake_ctr, 612 - (u64)((conf->suspend_stats.shlw_swake_res + 613 - conf->suspend_stats.deep_swake_res)*10/192)); 614 - 615 - seq_printf(s, "S0IX+Suspend Total\t\t %10u\t %10llu\n", s0ix_total_ctr, 616 - (u64)(s0ix_total_res*10/192)); 623 + seq_printf(s, "TOTAL S0IX\t\t\t %10u\t %10llu\n", s0ix_total_ctr, 624 + (u64)(s0ix_total_res*10/192)); 617 625 seq_puts(s, "\n-------------------------------------------------\n"); 618 626 seq_puts(s, "\t\tDEVICE STATES\n"); 619 627 seq_puts(s, "-------------------------------------------------\n"); ··· 752 772 .release = single_release, 753 773 }; 754 774 755 - 756 775 static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused) 757 776 { 758 777 u32 verbosity; ··· 869 890 goto out; 870 891 } 871 892 893 + /* 894 + * Due to some design limitations in the firmware, sometimes the 895 + * counters do not get updated by the time we reach here. As a 896 + * workaround, we try to see if this was a genuine case of sleep 897 + * failure or not by cross-checking from PMC GCR registers directly. 898 + */ 899 + if (suspend_shlw_ctr_exit == suspend_shlw_ctr_temp && 900 + suspend_deep_ctr_exit == suspend_deep_ctr_temp) { 901 + ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_SHLW_S0IX_REG, 902 + &suspend_shlw_res_exit); 903 + if (ret < 0) 904 + goto out; 905 + 906 + ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_DEEP_S0IX_REG, 907 + &suspend_deep_res_exit); 908 + if (ret < 0) 909 + goto out; 910 + 911 + if (suspend_shlw_res_exit > suspend_shlw_res_temp) 912 + suspend_shlw_ctr_exit++; 913 + 914 + if (suspend_deep_res_exit > suspend_deep_res_temp) 915 + suspend_deep_ctr_exit++; 916 + } 917 + 872 918 suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp; 873 919 suspend_deep_ctr_exit -= suspend_deep_ctr_temp; 874 920 suspend_shlw_res_exit -= suspend_shlw_res_temp; 875 921 suspend_deep_res_exit -= suspend_deep_res_temp; 876 922 877 - if (suspend_shlw_ctr_exit == 1) { 923 + if (suspend_shlw_ctr_exit != 0) { 878 924 conf->suspend_stats.shlw_ctr += 879 925 suspend_shlw_ctr_exit; 880 926 881 927 conf->suspend_stats.shlw_res += 882 928 suspend_shlw_res_exit; 883 929 } 884 - /* Shallow Wakes Case */ 885 - else if (suspend_shlw_ctr_exit > 1) { 886 - conf->suspend_stats.shlw_swake_ctr += 887 - suspend_shlw_ctr_exit; 888 930 889 - conf->suspend_stats.shlw_swake_res += 890 - suspend_shlw_res_exit; 891 - } 892 - 893 - if (suspend_deep_ctr_exit == 1) { 931 + if (suspend_deep_ctr_exit != 0) { 894 932 conf->suspend_stats.deep_ctr += 895 933 suspend_deep_ctr_exit; 896 934 897 935 conf->suspend_stats.deep_res += 898 - suspend_deep_res_exit; 899 - } 900 - 901 - /* Shallow Wakes Case */ 902 - else if (suspend_deep_ctr_exit > 1) { 903 - conf->suspend_stats.deep_swake_ctr += 904 - suspend_deep_ctr_exit; 905 - 906 - conf->suspend_stats.deep_swake_res += 907 936 suspend_deep_res_exit; 908 937 } 909 938
+267 -57
drivers/platform/x86/mlx-platform.c
··· 35 35 #include <linux/dmi.h> 36 36 #include <linux/i2c.h> 37 37 #include <linux/i2c-mux.h> 38 + #include <linux/io.h> 38 39 #include <linux/module.h> 39 40 #include <linux/platform_device.h> 40 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 45 #define MLX_PLAT_DEVICE_NAME "mlxplat" 44 46 45 47 /* LPC bus IO offsets */ 46 48 #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 47 49 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 48 - #define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a 49 - #define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558 50 - #define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564 51 - #define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588 50 + #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a 51 + #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b 52 + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 53 + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 54 + #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 55 + #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59 56 + #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a 57 + #define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64 58 + #define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65 59 + #define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66 60 + #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 61 + #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 62 + #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a 52 63 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 53 64 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb 54 65 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda ··· 92 81 /* mlxplat_priv - platform private data 93 82 * @pdev_i2c - i2c controller platform device 94 83 * @pdev_mux - array of mux platform devices 84 + * @pdev_hotplug - hotplug platform devices 95 85 */ 96 86 struct mlxplat_priv { 97 87 struct platform_device *pdev_i2c; ··· 150 138 }; 151 139 152 140 /* Platform hotplug devices */ 153 - static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = { 141 + static struct i2c_board_info mlxplat_mlxcpld_psu[] = { 154 142 { 155 - .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, 156 - .bus = 10, 143 + I2C_BOARD_INFO("24c02", 0x51), 157 144 }, 158 145 { 159 - .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) }, 160 - .bus = 10, 146 + I2C_BOARD_INFO("24c02", 0x50), 161 147 }, 162 148 }; 163 149 164 - static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = { 150 + static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { 165 151 { 166 - .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, 167 - .bus = 10, 152 + I2C_BOARD_INFO("dps460", 0x59), 168 153 }, 169 154 { 170 - .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) }, 171 - .bus = 10, 155 + I2C_BOARD_INFO("dps460", 0x58), 172 156 }, 173 157 }; 174 158 175 - static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = { 159 + static struct i2c_board_info mlxplat_mlxcpld_fan[] = { 176 160 { 177 - .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 178 - .bus = 11, 161 + I2C_BOARD_INFO("24c32", 0x50), 179 162 }, 180 163 { 181 - .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 182 - .bus = 12, 164 + I2C_BOARD_INFO("24c32", 0x50), 183 165 }, 184 166 { 185 - .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 186 - .bus = 13, 167 + I2C_BOARD_INFO("24c32", 0x50), 187 168 }, 188 169 { 189 - .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, 190 - .bus = 14, 170 + I2C_BOARD_INFO("24c32", 0x50), 191 171 }, 192 172 }; 193 173 194 174 /* Platform hotplug default data */ 175 + static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { 176 + { 177 + .label = "psu1", 178 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 179 + .mask = BIT(0), 180 + .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], 181 + .hpdev.nr = 10, 182 + }, 183 + { 184 + .label = "psu2", 185 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 186 + .mask = BIT(1), 187 + .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], 188 + .hpdev.nr = 10, 189 + }, 190 + }; 191 + 192 + static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { 193 + { 194 + .label = "pwr1", 195 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 196 + .mask = BIT(0), 197 + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], 198 + .hpdev.nr = 10, 199 + }, 200 + { 201 + .label = "pwr2", 202 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 203 + .mask = BIT(1), 204 + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], 205 + .hpdev.nr = 10, 206 + }, 207 + }; 208 + 209 + static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { 210 + { 211 + .label = "fan1", 212 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 213 + .mask = BIT(0), 214 + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0], 215 + .hpdev.nr = 11, 216 + }, 217 + { 218 + .label = "fan2", 219 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 220 + .mask = BIT(1), 221 + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1], 222 + .hpdev.nr = 12, 223 + }, 224 + { 225 + .label = "fan3", 226 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 227 + .mask = BIT(2), 228 + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2], 229 + .hpdev.nr = 13, 230 + }, 231 + { 232 + .label = "fan4", 233 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 234 + .mask = BIT(3), 235 + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3], 236 + .hpdev.nr = 14, 237 + }, 238 + }; 239 + 240 + static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { 241 + { 242 + .data = mlxplat_mlxcpld_default_psu_items_data, 243 + .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, 244 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 245 + .mask = MLXPLAT_CPLD_PSU_MASK, 246 + .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), 247 + .inversed = 1, 248 + .health = false, 249 + }, 250 + { 251 + .data = mlxplat_mlxcpld_default_pwr_items_data, 252 + .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 253 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 254 + .mask = MLXPLAT_CPLD_PWR_MASK, 255 + .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 256 + .inversed = 0, 257 + .health = false, 258 + }, 259 + { 260 + .data = mlxplat_mlxcpld_default_fan_items_data, 261 + .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, 262 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 263 + .mask = MLXPLAT_CPLD_FAN_MASK, 264 + .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), 265 + .inversed = 1, 266 + .health = false, 267 + }, 268 + }; 269 + 195 270 static 196 - struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = { 197 - .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 198 - .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 199 - .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, 200 - .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR, 201 - .psu_mask = MLXPLAT_CPLD_PSU_MASK, 202 - .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu), 203 - .psu = mlxplat_mlxcpld_psu, 204 - .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 205 - .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, 206 - .pwr_mask = MLXPLAT_CPLD_PWR_MASK, 207 - .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 208 - .pwr = mlxplat_mlxcpld_pwr, 209 - .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, 210 - .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR, 211 - .fan_mask = MLXPLAT_CPLD_FAN_MASK, 212 - .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan), 213 - .fan = mlxplat_mlxcpld_fan, 271 + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { 272 + .items = mlxplat_mlxcpld_default_items, 273 + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), 274 + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 275 + .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 214 276 }; 215 277 216 278 /* Platform hotplug MSN21xx system family data */ 279 + static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = { 280 + { 281 + .data = mlxplat_mlxcpld_default_pwr_items_data, 282 + .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, 283 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 284 + .mask = MLXPLAT_CPLD_PWR_MASK, 285 + .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 286 + .inversed = 0, 287 + .health = false, 288 + }, 289 + }; 290 + 217 291 static 218 - struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { 219 - .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, 220 - .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 221 - .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, 222 - .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, 223 - .pwr_mask = MLXPLAT_CPLD_PWR_MASK, 224 - .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), 292 + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { 293 + .items = mlxplat_mlxcpld_msn21xx_items, 294 + .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), 295 + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 296 + .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 297 + }; 298 + 299 + static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) 300 + { 301 + switch (reg) { 302 + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: 303 + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 304 + case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 305 + case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 306 + case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 307 + case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 308 + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 309 + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 310 + return true; 311 + } 312 + return false; 313 + } 314 + 315 + static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) 316 + { 317 + switch (reg) { 318 + case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: 319 + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: 320 + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: 321 + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 322 + case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 323 + case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 324 + case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 325 + case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: 326 + case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 327 + case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 328 + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: 329 + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 330 + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 331 + return true; 332 + } 333 + return false; 334 + } 335 + 336 + static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) 337 + { 338 + switch (reg) { 339 + case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: 340 + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: 341 + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: 342 + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: 343 + case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 344 + case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 345 + case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 346 + case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: 347 + case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 348 + case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 349 + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: 350 + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 351 + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 352 + return true; 353 + } 354 + return false; 355 + } 356 + 357 + struct mlxplat_mlxcpld_regmap_context { 358 + void __iomem *base; 359 + }; 360 + 361 + static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx; 362 + 363 + static int 364 + mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val) 365 + { 366 + struct mlxplat_mlxcpld_regmap_context *ctx = context; 367 + 368 + *val = ioread8(ctx->base + reg); 369 + return 0; 370 + } 371 + 372 + static int 373 + mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val) 374 + { 375 + struct mlxplat_mlxcpld_regmap_context *ctx = context; 376 + 377 + iowrite8(val, ctx->base + reg); 378 + return 0; 379 + } 380 + 381 + static const struct regmap_config mlxplat_mlxcpld_regmap_config = { 382 + .reg_bits = 8, 383 + .val_bits = 8, 384 + .max_register = 255, 385 + .cache_type = REGCACHE_FLAT, 386 + .writeable_reg = mlxplat_mlxcpld_writeable_reg, 387 + .readable_reg = mlxplat_mlxcpld_readable_reg, 388 + .volatile_reg = mlxplat_mlxcpld_volatile_reg, 389 + .reg_read = mlxplat_mlxcpld_reg_read, 390 + .reg_write = mlxplat_mlxcpld_reg_write, 225 391 }; 226 392 227 393 static struct resource mlxplat_mlxcpld_resources[] = { 228 - [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"), 394 + [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), 229 395 }; 230 396 231 397 static struct platform_device *mlxplat_dev; 232 - static struct mlxcpld_hotplug_platform_data *mlxplat_hotplug; 398 + static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; 233 399 234 400 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) 235 401 { ··· 476 286 { } 477 287 }; 478 288 289 + MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); 290 + 479 291 static int __init mlxplat_init(void) 480 292 { 481 293 struct mlxplat_priv *priv; ··· 520 328 } 521 329 } 522 330 331 + mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, 332 + mlxplat_lpc_resources[1].start, 1); 333 + if (!mlxplat_mlxcpld_regmap_ctx.base) { 334 + err = -ENOMEM; 335 + goto fail_platform_mux_register; 336 + } 337 + 338 + mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, 339 + &mlxplat_mlxcpld_regmap_ctx, 340 + &mlxplat_mlxcpld_regmap_config); 341 + if (IS_ERR(mlxplat_hotplug->regmap)) { 342 + err = PTR_ERR(mlxplat_hotplug->regmap); 343 + goto fail_platform_mux_register; 344 + } 345 + 523 346 priv->pdev_hotplug = platform_device_register_resndata( 524 - &mlxplat_dev->dev, "mlxcpld-hotplug", 347 + &mlxplat_dev->dev, "mlxreg-hotplug", 525 348 PLATFORM_DEVID_NONE, 526 349 mlxplat_mlxcpld_resources, 527 350 ARRAY_SIZE(mlxplat_mlxcpld_resources), ··· 546 339 goto fail_platform_mux_register; 547 340 } 548 341 342 + /* Sync registers with hardware. */ 343 + regcache_mark_dirty(mlxplat_hotplug->regmap); 344 + err = regcache_sync(mlxplat_hotplug->regmap); 345 + if (err) 346 + goto fail_platform_hotplug_register; 347 + 549 348 return 0; 550 349 350 + fail_platform_hotplug_register: 351 + platform_device_unregister(priv->pdev_hotplug); 551 352 fail_platform_mux_register: 552 353 while (--i >= 0) 553 354 platform_device_unregister(priv->pdev_mux[i]); ··· 585 370 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); 586 371 MODULE_DESCRIPTION("Mellanox platform driver"); 587 372 MODULE_LICENSE("Dual BSD/GPL"); 588 - MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:"); 589 - MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:"); 590 - MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:"); 591 - MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:"); 592 - MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
-515
drivers/platform/x86/mlxcpld-hotplug.c
··· 1 - /* 2 - * drivers/platform/x86/mlxcpld-hotplug.c 3 - * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 4 - * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com> 5 - * 6 - * Redistribution and use in source and binary forms, with or without 7 - * modification, are permitted provided that the following conditions are met: 8 - * 9 - * 1. Redistributions of source code must retain the above copyright 10 - * notice, this list of conditions and the following disclaimer. 11 - * 2. Redistributions in binary form must reproduce the above copyright 12 - * notice, this list of conditions and the following disclaimer in the 13 - * documentation and/or other materials provided with the distribution. 14 - * 3. Neither the names of the copyright holders nor the names of its 15 - * contributors may be used to endorse or promote products derived from 16 - * this software without specific prior written permission. 17 - * 18 - * Alternatively, this software may be distributed under the terms of the 19 - * GNU General Public License ("GPL") version 2 as published by the Free 20 - * Software Foundation. 21 - * 22 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 - * POSSIBILITY OF SUCH DAMAGE. 33 - */ 34 - 35 - #include <linux/bitops.h> 36 - #include <linux/device.h> 37 - #include <linux/hwmon.h> 38 - #include <linux/hwmon-sysfs.h> 39 - #include <linux/i2c.h> 40 - #include <linux/interrupt.h> 41 - #include <linux/io.h> 42 - #include <linux/module.h> 43 - #include <linux/platform_data/mlxcpld-hotplug.h> 44 - #include <linux/platform_device.h> 45 - #include <linux/spinlock.h> 46 - #include <linux/wait.h> 47 - #include <linux/workqueue.h> 48 - 49 - /* Offset of event and mask registers from status register */ 50 - #define MLXCPLD_HOTPLUG_EVENT_OFF 1 51 - #define MLXCPLD_HOTPLUG_MASK_OFF 2 52 - #define MLXCPLD_HOTPLUG_AGGR_MASK_OFF 1 53 - 54 - #define MLXCPLD_HOTPLUG_ATTRS_NUM 8 55 - 56 - /** 57 - * enum mlxcpld_hotplug_attr_type - sysfs attributes for hotplug events: 58 - * @MLXCPLD_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute; 59 - * @MLXCPLD_HOTPLUG_ATTR_TYPE_PWR: power cable attribute; 60 - * @MLXCPLD_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute; 61 - */ 62 - enum mlxcpld_hotplug_attr_type { 63 - MLXCPLD_HOTPLUG_ATTR_TYPE_PSU, 64 - MLXCPLD_HOTPLUG_ATTR_TYPE_PWR, 65 - MLXCPLD_HOTPLUG_ATTR_TYPE_FAN, 66 - }; 67 - 68 - /** 69 - * struct mlxcpld_hotplug_priv_data - platform private data: 70 - * @irq: platform interrupt number; 71 - * @pdev: platform device; 72 - * @plat: platform data; 73 - * @hwmon: hwmon device; 74 - * @mlxcpld_hotplug_attr: sysfs attributes array; 75 - * @mlxcpld_hotplug_dev_attr: sysfs sensor device attribute array; 76 - * @group: sysfs attribute group; 77 - * @groups: list of sysfs attribute group for hwmon registration; 78 - * @dwork: delayed work template; 79 - * @lock: spin lock; 80 - * @aggr_cache: last value of aggregation register status; 81 - * @psu_cache: last value of PSU register status; 82 - * @pwr_cache: last value of power register status; 83 - * @fan_cache: last value of FAN register status; 84 - */ 85 - struct mlxcpld_hotplug_priv_data { 86 - int irq; 87 - struct platform_device *pdev; 88 - struct mlxcpld_hotplug_platform_data *plat; 89 - struct device *hwmon; 90 - struct attribute *mlxcpld_hotplug_attr[MLXCPLD_HOTPLUG_ATTRS_NUM + 1]; 91 - struct sensor_device_attribute_2 92 - mlxcpld_hotplug_dev_attr[MLXCPLD_HOTPLUG_ATTRS_NUM]; 93 - struct attribute_group group; 94 - const struct attribute_group *groups[2]; 95 - struct delayed_work dwork; 96 - spinlock_t lock; 97 - u8 aggr_cache; 98 - u8 psu_cache; 99 - u8 pwr_cache; 100 - u8 fan_cache; 101 - }; 102 - 103 - static ssize_t mlxcpld_hotplug_attr_show(struct device *dev, 104 - struct device_attribute *attr, 105 - char *buf) 106 - { 107 - struct platform_device *pdev = to_platform_device(dev); 108 - struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev); 109 - int index = to_sensor_dev_attr_2(attr)->index; 110 - int nr = to_sensor_dev_attr_2(attr)->nr; 111 - u8 reg_val = 0; 112 - 113 - switch (nr) { 114 - case MLXCPLD_HOTPLUG_ATTR_TYPE_PSU: 115 - /* Bit = 0 : PSU is present. */ 116 - reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index)); 117 - break; 118 - 119 - case MLXCPLD_HOTPLUG_ATTR_TYPE_PWR: 120 - /* Bit = 1 : power cable is attached. */ 121 - reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index % 122 - priv->plat->pwr_count)); 123 - break; 124 - 125 - case MLXCPLD_HOTPLUG_ATTR_TYPE_FAN: 126 - /* Bit = 0 : FAN is present. */ 127 - reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index % 128 - priv->plat->fan_count)); 129 - break; 130 - } 131 - 132 - return sprintf(buf, "%u\n", reg_val); 133 - } 134 - 135 - #define PRIV_ATTR(i) priv->mlxcpld_hotplug_attr[i] 136 - #define PRIV_DEV_ATTR(i) priv->mlxcpld_hotplug_dev_attr[i] 137 - static int mlxcpld_hotplug_attr_init(struct mlxcpld_hotplug_priv_data *priv) 138 - { 139 - int num_attrs = priv->plat->psu_count + priv->plat->pwr_count + 140 - priv->plat->fan_count; 141 - int i; 142 - 143 - priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * 144 - sizeof(struct attribute *), 145 - GFP_KERNEL); 146 - if (!priv->group.attrs) 147 - return -ENOMEM; 148 - 149 - for (i = 0; i < num_attrs; i++) { 150 - PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr; 151 - 152 - if (i < priv->plat->psu_count) { 153 - PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, 154 - GFP_KERNEL, "psu%u", i + 1); 155 - PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PSU; 156 - } else if (i < priv->plat->psu_count + priv->plat->pwr_count) { 157 - PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, 158 - GFP_KERNEL, "pwr%u", i % 159 - priv->plat->pwr_count + 1); 160 - PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PWR; 161 - } else { 162 - PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, 163 - GFP_KERNEL, "fan%u", i % 164 - priv->plat->fan_count + 1); 165 - PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_FAN; 166 - } 167 - 168 - if (!PRIV_ATTR(i)->name) { 169 - dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n", 170 - i + 1); 171 - return -ENOMEM; 172 - } 173 - 174 - PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name; 175 - PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO; 176 - PRIV_DEV_ATTR(i).dev_attr.show = mlxcpld_hotplug_attr_show; 177 - PRIV_DEV_ATTR(i).index = i; 178 - sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr); 179 - } 180 - 181 - priv->group.attrs = priv->mlxcpld_hotplug_attr; 182 - priv->groups[0] = &priv->group; 183 - priv->groups[1] = NULL; 184 - 185 - return 0; 186 - } 187 - 188 - static int mlxcpld_hotplug_device_create(struct device *dev, 189 - struct mlxcpld_hotplug_device *item) 190 - { 191 - item->adapter = i2c_get_adapter(item->bus); 192 - if (!item->adapter) { 193 - dev_err(dev, "Failed to get adapter for bus %d\n", 194 - item->bus); 195 - return -EFAULT; 196 - } 197 - 198 - item->client = i2c_new_device(item->adapter, &item->brdinfo); 199 - if (!item->client) { 200 - dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", 201 - item->brdinfo.type, item->bus, item->brdinfo.addr); 202 - i2c_put_adapter(item->adapter); 203 - item->adapter = NULL; 204 - return -EFAULT; 205 - } 206 - 207 - return 0; 208 - } 209 - 210 - static void mlxcpld_hotplug_device_destroy(struct mlxcpld_hotplug_device *item) 211 - { 212 - if (item->client) { 213 - i2c_unregister_device(item->client); 214 - item->client = NULL; 215 - } 216 - 217 - if (item->adapter) { 218 - i2c_put_adapter(item->adapter); 219 - item->adapter = NULL; 220 - } 221 - } 222 - 223 - static inline void 224 - mlxcpld_hotplug_work_helper(struct device *dev, 225 - struct mlxcpld_hotplug_device *item, u8 is_inverse, 226 - u16 offset, u8 mask, u8 *cache) 227 - { 228 - u8 val, asserted; 229 - int bit; 230 - 231 - /* Mask event. */ 232 - outb(0, offset + MLXCPLD_HOTPLUG_MASK_OFF); 233 - /* Read status. */ 234 - val = inb(offset) & mask; 235 - asserted = *cache ^ val; 236 - *cache = val; 237 - 238 - /* 239 - * Validate if item related to received signal type is valid. 240 - * It should never happen, excepted the situation when some 241 - * piece of hardware is broken. In such situation just produce 242 - * error message and return. Caller must continue to handle the 243 - * signals from other devices if any. 244 - */ 245 - if (unlikely(!item)) { 246 - dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n", 247 - offset, mask); 248 - return; 249 - } 250 - 251 - for_each_set_bit(bit, (unsigned long *)&asserted, 8) { 252 - if (val & BIT(bit)) { 253 - if (is_inverse) 254 - mlxcpld_hotplug_device_destroy(item + bit); 255 - else 256 - mlxcpld_hotplug_device_create(dev, item + bit); 257 - } else { 258 - if (is_inverse) 259 - mlxcpld_hotplug_device_create(dev, item + bit); 260 - else 261 - mlxcpld_hotplug_device_destroy(item + bit); 262 - } 263 - } 264 - 265 - /* Acknowledge event. */ 266 - outb(0, offset + MLXCPLD_HOTPLUG_EVENT_OFF); 267 - /* Unmask event. */ 268 - outb(mask, offset + MLXCPLD_HOTPLUG_MASK_OFF); 269 - } 270 - 271 - /* 272 - * mlxcpld_hotplug_work_handler - performs traversing of CPLD interrupt 273 - * registers according to the below hierarchy schema: 274 - * 275 - * Aggregation registers (status/mask) 276 - * PSU registers: *---* 277 - * *-----------------* | | 278 - * |status/event/mask|----->| * | 279 - * *-----------------* | | 280 - * Power registers: | | 281 - * *-----------------* | | 282 - * |status/event/mask|----->| * |---> CPU 283 - * *-----------------* | | 284 - * FAN registers: 285 - * *-----------------* | | 286 - * |status/event/mask|----->| * | 287 - * *-----------------* | | 288 - * *---* 289 - * In case some system changed are detected: FAN in/out, PSU in/out, power 290 - * cable attached/detached, relevant device is created or destroyed. 291 - */ 292 - static void mlxcpld_hotplug_work_handler(struct work_struct *work) 293 - { 294 - struct mlxcpld_hotplug_priv_data *priv = container_of(work, 295 - struct mlxcpld_hotplug_priv_data, dwork.work); 296 - u8 val, aggr_asserted; 297 - unsigned long flags; 298 - 299 - /* Mask aggregation event. */ 300 - outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF); 301 - /* Read aggregation status. */ 302 - val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask; 303 - aggr_asserted = priv->aggr_cache ^ val; 304 - priv->aggr_cache = val; 305 - 306 - /* Handle PSU configuration changes. */ 307 - if (aggr_asserted & priv->plat->top_aggr_psu_mask) 308 - mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu, 309 - 1, priv->plat->psu_reg_offset, 310 - priv->plat->psu_mask, 311 - &priv->psu_cache); 312 - 313 - /* Handle power cable configuration changes. */ 314 - if (aggr_asserted & priv->plat->top_aggr_pwr_mask) 315 - mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr, 316 - 0, priv->plat->pwr_reg_offset, 317 - priv->plat->pwr_mask, 318 - &priv->pwr_cache); 319 - 320 - /* Handle FAN configuration changes. */ 321 - if (aggr_asserted & priv->plat->top_aggr_fan_mask) 322 - mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan, 323 - 1, priv->plat->fan_reg_offset, 324 - priv->plat->fan_mask, 325 - &priv->fan_cache); 326 - 327 - if (aggr_asserted) { 328 - spin_lock_irqsave(&priv->lock, flags); 329 - 330 - /* 331 - * It is possible, that some signals have been inserted, while 332 - * interrupt has been masked by mlxcpld_hotplug_work_handler. 333 - * In this case such signals will be missed. In order to handle 334 - * these signals delayed work is canceled and work task 335 - * re-scheduled for immediate execution. It allows to handle 336 - * missed signals, if any. In other case work handler just 337 - * validates that no new signals have been received during 338 - * masking. 339 - */ 340 - cancel_delayed_work(&priv->dwork); 341 - schedule_delayed_work(&priv->dwork, 0); 342 - 343 - spin_unlock_irqrestore(&priv->lock, flags); 344 - 345 - return; 346 - } 347 - 348 - /* Unmask aggregation event (no need acknowledge). */ 349 - outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + 350 - MLXCPLD_HOTPLUG_AGGR_MASK_OFF); 351 - } 352 - 353 - static void mlxcpld_hotplug_set_irq(struct mlxcpld_hotplug_priv_data *priv) 354 - { 355 - /* Clear psu presense event. */ 356 - outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); 357 - /* Set psu initial status as mask and unmask psu event. */ 358 - priv->psu_cache = priv->plat->psu_mask; 359 - outb(priv->plat->psu_mask, priv->plat->psu_reg_offset + 360 - MLXCPLD_HOTPLUG_MASK_OFF); 361 - 362 - /* Clear power cable event. */ 363 - outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); 364 - /* Keep power initial status as zero and unmask power event. */ 365 - outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset + 366 - MLXCPLD_HOTPLUG_MASK_OFF); 367 - 368 - /* Clear fan presense event. */ 369 - outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); 370 - /* Set fan initial status as mask and unmask fan event. */ 371 - priv->fan_cache = priv->plat->fan_mask; 372 - outb(priv->plat->fan_mask, priv->plat->fan_reg_offset + 373 - MLXCPLD_HOTPLUG_MASK_OFF); 374 - 375 - /* Keep aggregation initial status as zero and unmask events. */ 376 - outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + 377 - MLXCPLD_HOTPLUG_AGGR_MASK_OFF); 378 - 379 - /* Invoke work handler for initializing hot plug devices setting. */ 380 - mlxcpld_hotplug_work_handler(&priv->dwork.work); 381 - 382 - enable_irq(priv->irq); 383 - } 384 - 385 - static void mlxcpld_hotplug_unset_irq(struct mlxcpld_hotplug_priv_data *priv) 386 - { 387 - int i; 388 - 389 - disable_irq(priv->irq); 390 - cancel_delayed_work_sync(&priv->dwork); 391 - 392 - /* Mask aggregation event. */ 393 - outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF); 394 - 395 - /* Mask psu presense event. */ 396 - outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF); 397 - /* Clear psu presense event. */ 398 - outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); 399 - 400 - /* Mask power cable event. */ 401 - outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF); 402 - /* Clear power cable event. */ 403 - outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); 404 - 405 - /* Mask fan presense event. */ 406 - outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF); 407 - /* Clear fan presense event. */ 408 - outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); 409 - 410 - /* Remove all the attached devices. */ 411 - for (i = 0; i < priv->plat->psu_count; i++) 412 - mlxcpld_hotplug_device_destroy(priv->plat->psu + i); 413 - 414 - for (i = 0; i < priv->plat->pwr_count; i++) 415 - mlxcpld_hotplug_device_destroy(priv->plat->pwr + i); 416 - 417 - for (i = 0; i < priv->plat->fan_count; i++) 418 - mlxcpld_hotplug_device_destroy(priv->plat->fan + i); 419 - } 420 - 421 - static irqreturn_t mlxcpld_hotplug_irq_handler(int irq, void *dev) 422 - { 423 - struct mlxcpld_hotplug_priv_data *priv = 424 - (struct mlxcpld_hotplug_priv_data *)dev; 425 - 426 - /* Schedule work task for immediate execution.*/ 427 - schedule_delayed_work(&priv->dwork, 0); 428 - 429 - return IRQ_HANDLED; 430 - } 431 - 432 - static int mlxcpld_hotplug_probe(struct platform_device *pdev) 433 - { 434 - struct mlxcpld_hotplug_platform_data *pdata; 435 - struct mlxcpld_hotplug_priv_data *priv; 436 - int err; 437 - 438 - pdata = dev_get_platdata(&pdev->dev); 439 - if (!pdata) { 440 - dev_err(&pdev->dev, "Failed to get platform data.\n"); 441 - return -EINVAL; 442 - } 443 - 444 - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 445 - if (!priv) 446 - return -ENOMEM; 447 - 448 - priv->pdev = pdev; 449 - priv->plat = pdata; 450 - 451 - priv->irq = platform_get_irq(pdev, 0); 452 - if (priv->irq < 0) { 453 - dev_err(&pdev->dev, "Failed to get platform irq: %d\n", 454 - priv->irq); 455 - return priv->irq; 456 - } 457 - 458 - err = devm_request_irq(&pdev->dev, priv->irq, 459 - mlxcpld_hotplug_irq_handler, 0, pdev->name, 460 - priv); 461 - if (err) { 462 - dev_err(&pdev->dev, "Failed to request irq: %d\n", err); 463 - return err; 464 - } 465 - disable_irq(priv->irq); 466 - 467 - INIT_DELAYED_WORK(&priv->dwork, mlxcpld_hotplug_work_handler); 468 - spin_lock_init(&priv->lock); 469 - 470 - err = mlxcpld_hotplug_attr_init(priv); 471 - if (err) { 472 - dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err); 473 - return err; 474 - } 475 - 476 - priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, 477 - "mlxcpld_hotplug", priv, priv->groups); 478 - if (IS_ERR(priv->hwmon)) { 479 - dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", 480 - PTR_ERR(priv->hwmon)); 481 - return PTR_ERR(priv->hwmon); 482 - } 483 - 484 - platform_set_drvdata(pdev, priv); 485 - 486 - /* Perform initial interrupts setup. */ 487 - mlxcpld_hotplug_set_irq(priv); 488 - 489 - return 0; 490 - } 491 - 492 - static int mlxcpld_hotplug_remove(struct platform_device *pdev) 493 - { 494 - struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev); 495 - 496 - /* Clean interrupts setup. */ 497 - mlxcpld_hotplug_unset_irq(priv); 498 - 499 - return 0; 500 - } 501 - 502 - static struct platform_driver mlxcpld_hotplug_driver = { 503 - .driver = { 504 - .name = "mlxcpld-hotplug", 505 - }, 506 - .probe = mlxcpld_hotplug_probe, 507 - .remove = mlxcpld_hotplug_remove, 508 - }; 509 - 510 - module_platform_driver(mlxcpld_hotplug_driver); 511 - 512 - MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); 513 - MODULE_DESCRIPTION("Mellanox CPLD hotplug platform driver"); 514 - MODULE_LICENSE("Dual BSD/GPL"); 515 - MODULE_ALIAS("platform:mlxcpld-hotplug");
+20 -36
drivers/platform/x86/pmc_atom.c
··· 208 208 .clks = cht_clks, 209 209 }; 210 210 211 + #define DEFINE_SHOW_ATTRIBUTE(__name) \ 212 + static int __name ## _open(struct inode *inode, struct file *file) \ 213 + { \ 214 + return single_open(file, __name ## _show, inode->i_private); \ 215 + } \ 216 + \ 217 + static const struct file_operations __name ## _fops = { \ 218 + .owner = THIS_MODULE, \ 219 + .open = __name ## _open, \ 220 + .read = seq_read, \ 221 + .llseek = seq_lseek, \ 222 + .release = single_release, \ 223 + } 224 + 211 225 static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset) 212 226 { 213 227 return readl(pmc->regmap + reg_offset); ··· 323 309 return 0; 324 310 } 325 311 326 - static int pmc_dev_state_open(struct inode *inode, struct file *file) 327 - { 328 - return single_open(file, pmc_dev_state_show, inode->i_private); 329 - } 330 - 331 - static const struct file_operations pmc_dev_state_ops = { 332 - .open = pmc_dev_state_open, 333 - .read = seq_read, 334 - .llseek = seq_lseek, 335 - .release = single_release, 336 - }; 312 + DEFINE_SHOW_ATTRIBUTE(pmc_dev_state); 337 313 338 314 static int pmc_pss_state_show(struct seq_file *s, void *unused) 339 315 { ··· 340 336 return 0; 341 337 } 342 338 343 - static int pmc_pss_state_open(struct inode *inode, struct file *file) 344 - { 345 - return single_open(file, pmc_pss_state_show, inode->i_private); 346 - } 347 - 348 - static const struct file_operations pmc_pss_state_ops = { 349 - .open = pmc_pss_state_open, 350 - .read = seq_read, 351 - .llseek = seq_lseek, 352 - .release = single_release, 353 - }; 339 + DEFINE_SHOW_ATTRIBUTE(pmc_pss_state); 354 340 355 341 static int pmc_sleep_tmr_show(struct seq_file *s, void *unused) 356 342 { ··· 361 367 return 0; 362 368 } 363 369 364 - static int pmc_sleep_tmr_open(struct inode *inode, struct file *file) 365 - { 366 - return single_open(file, pmc_sleep_tmr_show, inode->i_private); 367 - } 368 - 369 - static const struct file_operations pmc_sleep_tmr_ops = { 370 - .open = pmc_sleep_tmr_open, 371 - .read = seq_read, 372 - .llseek = seq_lseek, 373 - .release = single_release, 374 - }; 370 + DEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr); 375 371 376 372 static void pmc_dbgfs_unregister(struct pmc_dev *pmc) 377 373 { ··· 379 395 pmc->dbgfs_dir = dir; 380 396 381 397 f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO, 382 - dir, pmc, &pmc_dev_state_ops); 398 + dir, pmc, &pmc_dev_state_fops); 383 399 if (!f) 384 400 goto err; 385 401 386 402 f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO, 387 - dir, pmc, &pmc_pss_state_ops); 403 + dir, pmc, &pmc_pss_state_fops); 388 404 if (!f) 389 405 goto err; 390 406 391 407 f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO, 392 - dir, pmc, &pmc_sleep_tmr_ops); 408 + dir, pmc, &pmc_sleep_tmr_fops); 393 409 if (!f) 394 410 goto err; 395 411
+175
drivers/platform/x86/silead_dmi.c
··· 67 67 .properties = dexp_ursus_7w_props, 68 68 }; 69 69 70 + static const struct property_entry surftab_twin_10_1_st10432_8_props[] = { 71 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1900), 72 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), 73 + PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1), 74 + PROPERTY_ENTRY_STRING("firmware-name", 75 + "gsl3670-surftab-twin-10-1-st10432-8.fw"), 76 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 77 + { } 78 + }; 79 + 80 + static const struct silead_ts_dmi_data surftab_twin_10_1_st10432_8_data = { 81 + .acpi_name = "MSSL1680:00", 82 + .properties = surftab_twin_10_1_st10432_8_props, 83 + }; 84 + 70 85 static const struct property_entry surftab_wintron70_st70416_6_props[] = { 71 86 PROPERTY_ENTRY_U32("touchscreen-size-x", 884), 72 87 PROPERTY_ENTRY_U32("touchscreen-size-y", 632), ··· 186 171 .properties = digma_citi_e200_props, 187 172 }; 188 173 174 + static const struct property_entry onda_obook_20_plus_props[] = { 175 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), 176 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), 177 + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), 178 + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), 179 + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 180 + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-obook-20-plus.fw"), 181 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 182 + PROPERTY_ENTRY_BOOL("silead,home-button"), 183 + { } 184 + }; 185 + 186 + static const struct silead_ts_dmi_data onda_obook_20_plus_data = { 187 + .acpi_name = "MSSL1680:00", 188 + .properties = onda_obook_20_plus_props, 189 + }; 190 + 191 + static const struct property_entry chuwi_hi8_props[] = { 192 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), 193 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), 194 + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 195 + PROPERTY_ENTRY_BOOL("silead,home-button"), 196 + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"), 197 + { } 198 + }; 199 + 200 + static const struct silead_ts_dmi_data chuwi_hi8_data = { 201 + .acpi_name = "MSSL0001:00", 202 + .properties = chuwi_hi8_props, 203 + }; 204 + 205 + static const struct property_entry chuwi_vi8_props[] = { 206 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1724), 207 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), 208 + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 209 + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-chuwi-vi8.fw"), 210 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 211 + PROPERTY_ENTRY_BOOL("silead,home-button"), 212 + { } 213 + }; 214 + 215 + static const struct silead_ts_dmi_data chuwi_vi8_data = { 216 + .acpi_name = "MSSL1680:00", 217 + .properties = chuwi_vi8_props, 218 + }; 219 + 220 + static const struct property_entry trekstor_primebook_c13_props[] = { 221 + PROPERTY_ENTRY_U32("touchscreen-size-x", 2624), 222 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1920), 223 + PROPERTY_ENTRY_STRING("firmware-name", 224 + "gsl1680-trekstor-primebook-c13.fw"), 225 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 226 + PROPERTY_ENTRY_BOOL("silead,home-button"), 227 + { } 228 + }; 229 + 230 + static const struct silead_ts_dmi_data trekstor_primebook_c13_data = { 231 + .acpi_name = "MSSL1680:00", 232 + .properties = trekstor_primebook_c13_props, 233 + }; 234 + 235 + static const struct property_entry teclast_x98plus2_props[] = { 236 + PROPERTY_ENTRY_U32("touchscreen-size-x", 2048), 237 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), 238 + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), 239 + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), 240 + PROPERTY_ENTRY_STRING("firmware-name", 241 + "gsl1686-teclast_x98plus2.fw"), 242 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 243 + { } 244 + }; 245 + 246 + static const struct silead_ts_dmi_data teclast_x98plus2_data = { 247 + .acpi_name = "MSSL1680:00", 248 + .properties = teclast_x98plus2_props, 249 + }; 250 + 251 + static const struct property_entry teclast_x3_plus_props[] = { 252 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), 253 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), 254 + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-teclast-x3-plus.fw"), 255 + PROPERTY_ENTRY_U32("silead,max-fingers", 10), 256 + PROPERTY_ENTRY_BOOL("silead,home-button"), 257 + { } 258 + }; 259 + 260 + static const struct silead_ts_dmi_data teclast_x3_plus_data = { 261 + .acpi_name = "MSSL1680:00", 262 + .properties = teclast_x3_plus_props, 263 + }; 264 + 189 265 static const struct dmi_system_id silead_ts_dmi_table[] = { 190 266 { 191 267 /* CUBE iwork8 Air */ ··· 305 199 }, 306 200 }, 307 201 { 202 + /* TrekStor SurfTab twin 10.1 ST10432-8 */ 203 + .driver_data = (void *)&surftab_twin_10_1_st10432_8_data, 204 + .matches = { 205 + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), 206 + DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab twin 10.1"), 207 + }, 208 + }, 209 + { 308 210 /* Trekstor Surftab Wintron 7.0 ST70416-6 */ 309 211 .driver_data = (void *)&surftab_wintron70_st70416_6_data, 310 212 .matches = { ··· 320 206 DMI_MATCH(DMI_PRODUCT_NAME, "ST70416-6"), 321 207 /* Exact match, different versions need different fw */ 322 208 DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"), 209 + }, 210 + }, 211 + { 212 + /* Trekstor Surftab Wintron 7.0 ST70416-6, newer BIOS */ 213 + .driver_data = (void *)&surftab_wintron70_st70416_6_data, 214 + .matches = { 215 + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), 216 + DMI_MATCH(DMI_PRODUCT_NAME, 217 + "SurfTab wintron 7.0 ST70416-6"), 218 + /* Exact match, different versions need different fw */ 219 + DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"), 323 220 }, 324 221 }, 325 222 { ··· 394 269 DMI_MATCH(DMI_SYS_VENDOR, "Digma"), 395 270 DMI_MATCH(DMI_PRODUCT_NAME, "CITI E200"), 396 271 DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), 272 + }, 273 + }, 274 + { 275 + /* Onda oBook 20 Plus */ 276 + .driver_data = (void *)&onda_obook_20_plus_data, 277 + .matches = { 278 + DMI_MATCH(DMI_SYS_VENDOR, "ONDA"), 279 + DMI_MATCH(DMI_PRODUCT_NAME, "OBOOK 20 PLUS"), 280 + }, 281 + }, 282 + { 283 + /* Chuwi Hi8 */ 284 + .driver_data = (void *)&chuwi_hi8_data, 285 + .matches = { 286 + DMI_MATCH(DMI_SYS_VENDOR, "ilife"), 287 + DMI_MATCH(DMI_PRODUCT_NAME, "S806"), 288 + }, 289 + }, 290 + { 291 + /* Chuwi Vi8 (CWI506) */ 292 + .driver_data = (void *)&chuwi_vi8_data, 293 + .matches = { 294 + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), 295 + DMI_MATCH(DMI_PRODUCT_NAME, "i86"), 296 + DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), 297 + }, 298 + }, 299 + { 300 + /* Trekstor Primebook C13 */ 301 + .driver_data = (void *)&trekstor_primebook_c13_data, 302 + .matches = { 303 + DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), 304 + DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), 305 + }, 306 + }, 307 + { 308 + /* Teclast X98 Plus II */ 309 + .driver_data = (void *)&teclast_x98plus2_data, 310 + .matches = { 311 + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), 312 + DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), 313 + }, 314 + }, 315 + { 316 + /* Teclast X3 Plus */ 317 + .driver_data = (void *)&teclast_x3_plus_data, 318 + .matches = { 319 + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), 320 + DMI_MATCH(DMI_PRODUCT_NAME, "X3 Plus"), 321 + DMI_MATCH(DMI_BOARD_NAME, "X3 Plus"), 397 322 }, 398 323 }, 399 324 { },
+13 -5
drivers/platform/x86/thinkpad_acpi.c
··· 214 214 /* AC-related events */ 215 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 221 /* Misc */ 218 222 TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ 219 223 }; ··· 2117 2113 TP_ACPI_MULTI_MODE_FLAT; 2118 2114 break; 2119 2115 case 4: 2120 - valid_modes = TP_ACPI_MULTI_MODE_LAPTOP | 2121 - TP_ACPI_MULTI_MODE_TABLET | 2122 - TP_ACPI_MULTI_MODE_STAND | 2123 - TP_ACPI_MULTI_MODE_TENT; 2124 - break; 2125 2116 case 5: 2117 + /* In mode 4, FLAT is not specified as a valid mode. However, 2118 + * it can be seen at least on the X1 Yoga 2nd Generation. 2119 + */ 2126 2120 valid_modes = TP_ACPI_MULTI_MODE_LAPTOP | 2127 2121 TP_ACPI_MULTI_MODE_FLAT | 2128 2122 TP_ACPI_MULTI_MODE_TABLET | ··· 4080 4078 hotkey_tablet_mode_notify_change(); 4081 4079 *send_acpi_ev = false; 4082 4080 break; 4081 + 4082 + case TP_HKEY_EV_PALM_DETECTED: 4083 + case TP_HKEY_EV_PALM_UNDETECTED: 4084 + /* palm detected hovering the keyboard, forward to user-space 4085 + * via netlink for consumption */ 4086 + return true; 4083 4087 4084 4088 default: 4085 4089 pr_warn("unknown possible thermal alarm or keyboard event received\n");
-99
include/linux/platform_data/mlxcpld-hotplug.h
··· 1 - /* 2 - * include/linux/platform_data/mlxcpld-hotplug.h 3 - * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 4 - * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com> 5 - * 6 - * Redistribution and use in source and binary forms, with or without 7 - * modification, are permitted provided that the following conditions are met: 8 - * 9 - * 1. Redistributions of source code must retain the above copyright 10 - * notice, this list of conditions and the following disclaimer. 11 - * 2. Redistributions in binary form must reproduce the above copyright 12 - * notice, this list of conditions and the following disclaimer in the 13 - * documentation and/or other materials provided with the distribution. 14 - * 3. Neither the names of the copyright holders nor the names of its 15 - * contributors may be used to endorse or promote products derived from 16 - * this software without specific prior written permission. 17 - * 18 - * Alternatively, this software may be distributed under the terms of the 19 - * GNU General Public License ("GPL") version 2 as published by the Free 20 - * Software Foundation. 21 - * 22 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 - * POSSIBILITY OF SUCH DAMAGE. 33 - */ 34 - 35 - #ifndef __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H 36 - #define __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H 37 - 38 - /** 39 - * struct mlxcpld_hotplug_device - I2C device data: 40 - * @adapter: I2C device adapter; 41 - * @client: I2C device client; 42 - * @brdinfo: device board information; 43 - * @bus: I2C bus, where device is attached; 44 - * 45 - * Structure represents I2C hotplug device static data (board topology) and 46 - * dynamic data (related kernel objects handles). 47 - */ 48 - struct mlxcpld_hotplug_device { 49 - struct i2c_adapter *adapter; 50 - struct i2c_client *client; 51 - struct i2c_board_info brdinfo; 52 - u16 bus; 53 - }; 54 - 55 - /** 56 - * struct mlxcpld_hotplug_platform_data - device platform data: 57 - * @top_aggr_offset: offset of top aggregation interrupt register; 58 - * @top_aggr_mask: top aggregation interrupt common mask; 59 - * @top_aggr_psu_mask: top aggregation interrupt PSU mask; 60 - * @psu_reg_offset: offset of PSU interrupt register; 61 - * @psu_mask: PSU interrupt mask; 62 - * @psu_count: number of equipped replaceable PSUs; 63 - * @psu: pointer to PSU devices data array; 64 - * @top_aggr_pwr_mask: top aggregation interrupt power mask; 65 - * @pwr_reg_offset: offset of power interrupt register 66 - * @pwr_mask: power interrupt mask; 67 - * @pwr_count: number of power sources; 68 - * @pwr: pointer to power devices data array; 69 - * @top_aggr_fan_mask: top aggregation interrupt FAN mask; 70 - * @fan_reg_offset: offset of FAN interrupt register; 71 - * @fan_mask: FAN interrupt mask; 72 - * @fan_count: number of equipped replaceable FANs; 73 - * @fan: pointer to FAN devices data array; 74 - * 75 - * Structure represents board platform data, related to system hotplug events, 76 - * like FAN, PSU, power cable insertion and removing. This data provides the 77 - * number of hot-pluggable devices and hardware description for event handling. 78 - */ 79 - struct mlxcpld_hotplug_platform_data { 80 - u16 top_aggr_offset; 81 - u8 top_aggr_mask; 82 - u8 top_aggr_psu_mask; 83 - u16 psu_reg_offset; 84 - u8 psu_mask; 85 - u8 psu_count; 86 - struct mlxcpld_hotplug_device *psu; 87 - u8 top_aggr_pwr_mask; 88 - u16 pwr_reg_offset; 89 - u8 pwr_mask; 90 - u8 pwr_count; 91 - struct mlxcpld_hotplug_device *pwr; 92 - u8 top_aggr_fan_mask; 93 - u16 fan_reg_offset; 94 - u8 fan_mask; 95 - u8 fan_count; 96 - struct mlxcpld_hotplug_device *fan; 97 - }; 98 - 99 - #endif /* __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H */
+144
include/linux/platform_data/mlxreg.h
··· 1 + /* 2 + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 3 + * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com> 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions are met: 7 + * 8 + * 1. Redistributions of source code must retain the above copyright 9 + * notice, this list of conditions and the following disclaimer. 10 + * 2. Redistributions in binary form must reproduce the above copyright 11 + * notice, this list of conditions and the following disclaimer in the 12 + * documentation and/or other materials provided with the distribution. 13 + * 3. Neither the names of the copyright holders nor the names of its 14 + * contributors may be used to endorse or promote products derived from 15 + * this software without specific prior written permission. 16 + * 17 + * Alternatively, this software may be distributed under the terms of the 18 + * GNU General Public License ("GPL") version 2 as published by the Free 19 + * Software Foundation. 20 + * 21 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 + * POSSIBILITY OF SUCH DAMAGE. 32 + */ 33 + 34 + #ifndef __LINUX_PLATFORM_DATA_MLXREG_H 35 + #define __LINUX_PLATFORM_DATA_MLXREG_H 36 + 37 + #define MLXREG_CORE_LABEL_MAX_SIZE 32 38 + 39 + /** 40 + * struct mlxreg_hotplug_device - I2C device data: 41 + * 42 + * @adapter: I2C device adapter; 43 + * @client: I2C device client; 44 + * @brdinfo: device board information; 45 + * @nr: I2C device adapter number, to which device is to be attached; 46 + * 47 + * Structure represents I2C hotplug device static data (board topology) and 48 + * dynamic data (related kernel objects handles). 49 + */ 50 + struct mlxreg_hotplug_device { 51 + struct i2c_adapter *adapter; 52 + struct i2c_client *client; 53 + struct i2c_board_info *brdinfo; 54 + int nr; 55 + }; 56 + 57 + /** 58 + * struct mlxreg_core_data - attributes control data: 59 + * 60 + * @label: attribute label; 61 + * @label: attribute register offset; 62 + * @reg: attribute register; 63 + * @mask: attribute access mask; 64 + * @mode: access mode; 65 + * @bit: attribute effective bit; 66 + * @np - pointer to node platform associated with attribute; 67 + * @hpdev - hotplug device data; 68 + * @health_cntr: dynamic device health indication counter; 69 + * @attached: true if device has been attached after good health indication; 70 + */ 71 + struct mlxreg_core_data { 72 + char label[MLXREG_CORE_LABEL_MAX_SIZE]; 73 + u32 reg; 74 + u32 mask; 75 + u32 bit; 76 + umode_t mode; 77 + struct device_node *np; 78 + struct mlxreg_hotplug_device hpdev; 79 + u8 health_cntr; 80 + bool attached; 81 + }; 82 + 83 + /** 84 + * struct mlxreg_core_item - same type components controlled by the driver: 85 + * 86 + * @data: component data; 87 + * @aggr_mask: group aggregation mask; 88 + * @reg: group interrupt status register; 89 + * @mask: group interrupt mask; 90 + * @cache: last status value for elements fro the same group; 91 + * @count: number of available elements in the group; 92 + * @ind: element's index inside the group; 93 + * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK; 94 + * @health: true if device has health indication, false in other case; 95 + */ 96 + struct mlxreg_core_item { 97 + struct mlxreg_core_data *data; 98 + u32 aggr_mask; 99 + u32 reg; 100 + u32 mask; 101 + u32 cache; 102 + u8 count; 103 + u8 ind; 104 + u8 inversed; 105 + u8 health; 106 + }; 107 + 108 + /** 109 + * struct mlxreg_core_platform_data - platform data: 110 + * 111 + * @led_data: led private data; 112 + * @regmap: register map of parent device; 113 + * @counter: number of led instances; 114 + */ 115 + struct mlxreg_core_platform_data { 116 + struct mlxreg_core_data *data; 117 + void *regmap; 118 + int counter; 119 + }; 120 + 121 + /** 122 + * struct mlxreg_core_hotplug_platform_data - hotplug platform data: 123 + * 124 + * @items: same type components with the hotplug capability; 125 + * @irq: platform interrupt number; 126 + * @regmap: register map of parent device; 127 + * @counter: number of the components with the hotplug capability; 128 + * @cell: location of top aggregation interrupt register; 129 + * @mask: top aggregation interrupt common mask; 130 + * @cell_low: location of low aggregation interrupt register; 131 + * @mask_low: low aggregation interrupt common mask; 132 + */ 133 + struct mlxreg_core_hotplug_platform_data { 134 + struct mlxreg_core_item *items; 135 + int irq; 136 + void *regmap; 137 + int counter; 138 + u32 cell; 139 + u32 mask; 140 + u32 cell_low; 141 + u32 mask_low; 142 + }; 143 + 144 + #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
+1
include/uapi/linux/input-event-codes.h
··· 594 594 #define BTN_DPAD_RIGHT 0x223 595 595 596 596 #define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ 597 + #define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */ 597 598 598 599 #define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ 599 600 #define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */