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

Merge tag 'platform-drivers-x86-v5.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull x86 platform driver updates from Hans de Goede:
"Highlights:

New drivers:
- asus-tf103c-dock
- intel_crystal_cove_charger
- lenovo-yogabook-wmi
- simatic-ipc platform-code + led driver + watchdog driver
- x86-android-tablets (kernel module to workaround DSDT bugs on
these)

amd-pmc:
- bug-fixes
- smar trace buffer support

asus-wmi:
- support for custom fan curves

int3472 (camera info ACPI object for Intel IPU3/SkyCam cameras):
- ACPI core + int3472 changes to delay enumeration of camera sensor
I2C clients until the PMIC for the sensor has been fully probed
- Add support for board data (DSDT info is incomplete) for setting up
the tps68470 PMIC used on some boards with these cameras
- Add board data for the Microsoft Surface Go (original, v2 and v3)

thinkpad_acpi:
- various cleanups
- support for forced battery discharging (for battery calibration)
- support to inhibit battery charging
- this includes power_supply core changes to add new APIs for this

think_lmi:
- enhanced BIOS password support

various other small fixes and hardware-id additions"

* tag 'platform-drivers-x86-v5.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (78 commits)
power: supply: Provide stubs for charge_behaviour helpers
platform/x86: x86-android-tablets: Fix GPIO lookup leak on error-exit
platform/x86: int3472: Add board data for Surface Go 3
platform/x86: Add Asus TF103C dock driver
platform/x86: x86-android-tablets: Add TM800A550L data
platform/x86: x86-android-tablets: Add Asus MeMO Pad 7 ME176C data
platform/x86: x86-android-tablets: Add Asus TF103C data
platform/x86: x86-android-tablets: Add support for preloading modules
platform/x86: x86-android-tablets: Add support for registering GPIO lookup tables
platform/x86: x86-android-tablets: Add support for instantiating serdevs
platform/x86: x86-android-tablets: Add support for instantiating platform-devs
platform/x86: x86-android-tablets: Add support for PMIC interrupts
platform/x86: x86-android-tablets: Don't return -EPROBE_DEFER from a non probe() function
platform/x86: touchscreen_dmi: Remove the Glavey TM800A550L entry
platform/x86: touchscreen_dmi: Enable pen support on the Chuwi Hi10 Plus and Pro
platform/x86: touchscreen_dmi: Correct min/max values for Chuwi Hi10 Pro (CWI529) tablet
platform/x86: Add intel_crystal_cove_charger driver
power: supply: fix charge_behaviour attribute initialization
platform/x86: intel-uncore-frequency: use default_groups in kobj_type
x86/platform/uv: use default_groups in kobj_type
...

+5049 -669
+32
Documentation/ABI/testing/sysfs-class-firmware-attributes
··· 161 161 power-on: 162 162 Representing a password required to use 163 163 the system 164 + system-mgmt: 165 + Representing System Management password. 166 + See Lenovo extensions section for details 167 + HDD: 168 + Representing HDD password 169 + See Lenovo extensions section for details 170 + NVMe: 171 + Representing NVMe password 172 + See Lenovo extensions section for details 164 173 165 174 mechanism: 166 175 The means of authentication. This attribute is mandatory. ··· 216 207 217 208 On Lenovo systems the following additional settings are available: 218 209 210 + role: system-mgmt This gives the same authority as the bios-admin password to control 211 + security related features. The authorities allocated can be set via 212 + the BIOS menu SMP Access Control Policy 213 + 214 + role: HDD & NVMe This password is used to unlock access to the drive at boot. Note see 215 + 'level' and 'index' extensions below. 216 + 219 217 lenovo_encoding: 220 218 The encoding method that is used. This can be either "ascii" 221 219 or "scancode". Default is set to "ascii" ··· 231 215 The keyboard language method that is used. This is generally a 232 216 two char code (e.g. "us", "fr", "gr") and may vary per platform. 233 217 Default is set to "us" 218 + 219 + level: 220 + Available for HDD and NVMe authentication to set 'user' or 'master' 221 + privilege level. 222 + If only the user password is configured then this should be used to 223 + unlock the drive at boot. If both master and user passwords are set 224 + then either can be used. If a master password is set a user password 225 + is required. 226 + This attribute defaults to 'user' level 227 + 228 + index: 229 + Used with HDD and NVME authentication to set the drive index 230 + that is being referenced (e.g hdd0, hdd1 etc) 231 + This attribute defaults to device 0. 232 + 233 + 234 234 235 235 What: /sys/class/firmware-attributes/*/attributes/pending_reboot 236 236 Date: February 2021
+14
Documentation/ABI/testing/sysfs-class-power
··· 455 455 "Unknown", "Charging", "Discharging", 456 456 "Not charging", "Full" 457 457 458 + What: /sys/class/power_supply/<supply_name>/charge_behaviour 459 + Date: November 2021 460 + Contact: linux-pm@vger.kernel.org 461 + Description: 462 + Represents the charging behaviour. 463 + 464 + Access: Read, Write 465 + 466 + Valid values: 467 + ================ ==================================== 468 + auto: Charge normally, respect thresholds 469 + inhibit-charge: Do not charge while AC is attached 470 + force-discharge: Force discharge while AC is attached 471 + 458 472 What: /sys/class/power_supply/<supply_name>/technology 459 473 Date: May 2007 460 474 Contact: linux-pm@vger.kernel.org
+14
MAINTAINERS
··· 3013 3013 F: drivers/platform/x86/asus*.c 3014 3014 F: drivers/platform/x86/eeepc*.c 3015 3015 3016 + ASUS TF103C DOCK DRIVER 3017 + M: Hans de Goede <hdegoede@redhat.com> 3018 + L: platform-driver-x86@vger.kernel.org 3019 + S: Maintained 3020 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git 3021 + F: drivers/platform/x86/asus-tf103c-dock.c 3022 + 3016 3023 ASUS WMI HARDWARE MONITOR DRIVER 3017 3024 M: Ed Brindley <kernel@maidavale.org> 3018 3025 M: Denis Pauk <pauk.denis@gmail.com> ··· 20842 20835 S: Maintained 20843 20836 T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/mm 20844 20837 F: arch/x86/mm/ 20838 + 20839 + X86 PLATFORM ANDROID TABLETS DSDT FIXUP DRIVER 20840 + M: Hans de Goede <hdegoede@redhat.com> 20841 + L: platform-driver-x86@vger.kernel.org 20842 + S: Maintained 20843 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git 20844 + F: drivers/platform/x86/x86-android-tablets.c 20845 20845 20846 20846 X86 PLATFORM DRIVERS 20847 20847 M: Hans de Goede <hdegoede@redhat.com>
+3
drivers/leds/Kconfig
··· 879 879 comment "LED Triggers" 880 880 source "drivers/leds/trigger/Kconfig" 881 881 882 + comment "Simple LED drivers" 883 + source "drivers/leds/simple/Kconfig" 884 + 882 885 endif # NEW_LEDS
+3
drivers/leds/Makefile
··· 105 105 106 106 # LED Blink 107 107 obj-y += blink/ 108 + 109 + # Simple LED drivers 110 + obj-y += simple/
+11
drivers/leds/simple/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + config LEDS_SIEMENS_SIMATIC_IPC 3 + tristate "LED driver for Siemens Simatic IPCs" 4 + depends on LEDS_CLASS 5 + depends on SIEMENS_SIMATIC_IPC 6 + help 7 + This option enables support for the LEDs of several Industrial PCs 8 + from Siemens. 9 + 10 + To compile this driver as a module, choose M here: the module 11 + will be called simatic-ipc-leds.
+2
drivers/leds/simple/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds.o
+202
drivers/leds/simple/simatic-ipc-leds.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for LEDs 4 + * 5 + * Copyright (c) Siemens AG, 2018-2021 6 + * 7 + * Authors: 8 + * Henning Schild <henning.schild@siemens.com> 9 + * Jan Kiszka <jan.kiszka@siemens.com> 10 + * Gerd Haeussler <gerd.haeussler.ext@siemens.com> 11 + */ 12 + 13 + #include <linux/ioport.h> 14 + #include <linux/kernel.h> 15 + #include <linux/leds.h> 16 + #include <linux/module.h> 17 + #include <linux/pci.h> 18 + #include <linux/platform_data/x86/simatic-ipc-base.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/sizes.h> 21 + #include <linux/spinlock.h> 22 + 23 + #define SIMATIC_IPC_LED_PORT_BASE 0x404E 24 + 25 + struct simatic_ipc_led { 26 + unsigned int value; /* mask for io and offset for mem */ 27 + char *name; 28 + struct led_classdev cdev; 29 + }; 30 + 31 + static struct simatic_ipc_led simatic_ipc_leds_io[] = { 32 + {1 << 15, "green:" LED_FUNCTION_STATUS "-1" }, 33 + {1 << 7, "yellow:" LED_FUNCTION_STATUS "-1" }, 34 + {1 << 14, "red:" LED_FUNCTION_STATUS "-2" }, 35 + {1 << 6, "yellow:" LED_FUNCTION_STATUS "-2" }, 36 + {1 << 13, "red:" LED_FUNCTION_STATUS "-3" }, 37 + {1 << 5, "yellow:" LED_FUNCTION_STATUS "-3" }, 38 + { } 39 + }; 40 + 41 + /* the actual start will be discovered with PCI, 0 is a placeholder */ 42 + struct resource simatic_ipc_led_mem_res = DEFINE_RES_MEM_NAMED(0, SZ_4K, KBUILD_MODNAME); 43 + 44 + static void *simatic_ipc_led_memory; 45 + 46 + static struct simatic_ipc_led simatic_ipc_leds_mem[] = { 47 + {0x500 + 0x1A0, "red:" LED_FUNCTION_STATUS "-1"}, 48 + {0x500 + 0x1A8, "green:" LED_FUNCTION_STATUS "-1"}, 49 + {0x500 + 0x1C8, "red:" LED_FUNCTION_STATUS "-2"}, 50 + {0x500 + 0x1D0, "green:" LED_FUNCTION_STATUS "-2"}, 51 + {0x500 + 0x1E0, "red:" LED_FUNCTION_STATUS "-3"}, 52 + {0x500 + 0x198, "green:" LED_FUNCTION_STATUS "-3"}, 53 + { } 54 + }; 55 + 56 + static struct resource simatic_ipc_led_io_res = 57 + DEFINE_RES_IO_NAMED(SIMATIC_IPC_LED_PORT_BASE, SZ_2, KBUILD_MODNAME); 58 + 59 + static DEFINE_SPINLOCK(reg_lock); 60 + 61 + static inline struct simatic_ipc_led *cdev_to_led(struct led_classdev *led_cd) 62 + { 63 + return container_of(led_cd, struct simatic_ipc_led, cdev); 64 + } 65 + 66 + static void simatic_ipc_led_set_io(struct led_classdev *led_cd, 67 + enum led_brightness brightness) 68 + { 69 + struct simatic_ipc_led *led = cdev_to_led(led_cd); 70 + unsigned long flags; 71 + unsigned int val; 72 + 73 + spin_lock_irqsave(&reg_lock, flags); 74 + 75 + val = inw(SIMATIC_IPC_LED_PORT_BASE); 76 + if (brightness == LED_OFF) 77 + outw(val | led->value, SIMATIC_IPC_LED_PORT_BASE); 78 + else 79 + outw(val & ~led->value, SIMATIC_IPC_LED_PORT_BASE); 80 + 81 + spin_unlock_irqrestore(&reg_lock, flags); 82 + } 83 + 84 + static enum led_brightness simatic_ipc_led_get_io(struct led_classdev *led_cd) 85 + { 86 + struct simatic_ipc_led *led = cdev_to_led(led_cd); 87 + 88 + return inw(SIMATIC_IPC_LED_PORT_BASE) & led->value ? LED_OFF : led_cd->max_brightness; 89 + } 90 + 91 + static void simatic_ipc_led_set_mem(struct led_classdev *led_cd, 92 + enum led_brightness brightness) 93 + { 94 + struct simatic_ipc_led *led = cdev_to_led(led_cd); 95 + 96 + u32 *p; 97 + 98 + p = simatic_ipc_led_memory + led->value; 99 + *p = (*p & ~1) | (brightness == LED_OFF); 100 + } 101 + 102 + static enum led_brightness simatic_ipc_led_get_mem(struct led_classdev *led_cd) 103 + { 104 + struct simatic_ipc_led *led = cdev_to_led(led_cd); 105 + 106 + u32 *p; 107 + 108 + p = simatic_ipc_led_memory + led->value; 109 + return (*p & 1) ? LED_OFF : led_cd->max_brightness; 110 + } 111 + 112 + static int simatic_ipc_leds_probe(struct platform_device *pdev) 113 + { 114 + const struct simatic_ipc_platform *plat = pdev->dev.platform_data; 115 + struct device *dev = &pdev->dev; 116 + struct simatic_ipc_led *ipcled; 117 + struct led_classdev *cdev; 118 + struct resource *res; 119 + int err, type; 120 + u32 *p; 121 + 122 + switch (plat->devmode) { 123 + case SIMATIC_IPC_DEVICE_227D: 124 + case SIMATIC_IPC_DEVICE_427E: 125 + res = &simatic_ipc_led_io_res; 126 + ipcled = simatic_ipc_leds_io; 127 + /* on 227D the two bytes work the other way araound */ 128 + if (plat->devmode == SIMATIC_IPC_DEVICE_227D) { 129 + while (ipcled->value) { 130 + ipcled->value = swab16(ipcled->value); 131 + ipcled++; 132 + } 133 + ipcled = simatic_ipc_leds_io; 134 + } 135 + type = IORESOURCE_IO; 136 + if (!devm_request_region(dev, res->start, resource_size(res), KBUILD_MODNAME)) { 137 + dev_err(dev, "Unable to register IO resource at %pR\n", res); 138 + return -EBUSY; 139 + } 140 + break; 141 + case SIMATIC_IPC_DEVICE_127E: 142 + res = &simatic_ipc_led_mem_res; 143 + ipcled = simatic_ipc_leds_mem; 144 + type = IORESOURCE_MEM; 145 + 146 + /* get GPIO base from PCI */ 147 + res->start = simatic_ipc_get_membase0(PCI_DEVFN(13, 0)); 148 + if (res->start == 0) 149 + return -ENODEV; 150 + 151 + /* do the final address calculation */ 152 + res->start = res->start + (0xC5 << 16); 153 + res->end += res->start; 154 + 155 + simatic_ipc_led_memory = devm_ioremap_resource(dev, res); 156 + if (IS_ERR(simatic_ipc_led_memory)) 157 + return PTR_ERR(simatic_ipc_led_memory); 158 + 159 + /* initialize power/watchdog LED */ 160 + p = simatic_ipc_led_memory + 0x500 + 0x1D8; /* PM_WDT_OUT */ 161 + *p = (*p & ~1); 162 + p = simatic_ipc_led_memory + 0x500 + 0x1C0; /* PM_BIOS_BOOT_N */ 163 + *p = (*p | 1); 164 + 165 + break; 166 + default: 167 + return -ENODEV; 168 + } 169 + 170 + while (ipcled->value) { 171 + cdev = &ipcled->cdev; 172 + if (type == IORESOURCE_MEM) { 173 + cdev->brightness_set = simatic_ipc_led_set_mem; 174 + cdev->brightness_get = simatic_ipc_led_get_mem; 175 + } else { 176 + cdev->brightness_set = simatic_ipc_led_set_io; 177 + cdev->brightness_get = simatic_ipc_led_get_io; 178 + } 179 + cdev->max_brightness = LED_ON; 180 + cdev->name = ipcled->name; 181 + 182 + err = devm_led_classdev_register(dev, cdev); 183 + if (err < 0) 184 + return err; 185 + ipcled++; 186 + } 187 + 188 + return 0; 189 + } 190 + 191 + static struct platform_driver simatic_ipc_led_driver = { 192 + .probe = simatic_ipc_leds_probe, 193 + .driver = { 194 + .name = KBUILD_MODNAME, 195 + } 196 + }; 197 + 198 + module_platform_driver(simatic_ipc_led_driver); 199 + 200 + MODULE_LICENSE("GPL v2"); 201 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 202 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+6 -1
drivers/platform/surface/Kconfig
··· 5 5 6 6 menuconfig SURFACE_PLATFORMS 7 7 bool "Microsoft Surface Platform-Specific Device Drivers" 8 - depends on ACPI 9 8 default y 10 9 help 11 10 Say Y here to get to see options for platform-specific device drivers ··· 29 30 30 31 config SURFACE_3_BUTTON 31 32 tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet" 33 + depends on ACPI 32 34 depends on KEYBOARD_GPIO && I2C 33 35 help 34 36 This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet. 35 37 36 38 config SURFACE_3_POWER_OPREGION 37 39 tristate "Surface 3 battery platform operation region support" 40 + depends on ACPI 38 41 depends on I2C 39 42 help 40 43 This driver provides support for ACPI operation ··· 127 126 128 127 config SURFACE_GPE 129 128 tristate "Surface GPE/Lid Support Driver" 129 + depends on ACPI 130 130 depends on DMI 131 131 help 132 132 This driver marks the GPEs related to the ACPI lid device found on ··· 137 135 138 136 config SURFACE_HOTPLUG 139 137 tristate "Surface Hot-Plug Driver" 138 + depends on ACPI 140 139 depends on GPIOLIB 141 140 help 142 141 Driver for out-of-band hot-plug event signaling on Microsoft Surface ··· 157 154 158 155 config SURFACE_PLATFORM_PROFILE 159 156 tristate "Surface Platform Profile Driver" 157 + depends on ACPI 160 158 depends on SURFACE_AGGREGATOR_REGISTRY 161 159 select ACPI_PLATFORM_PROFILE 162 160 help ··· 180 176 181 177 config SURFACE_PRO3_BUTTON 182 178 tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet" 179 + depends on ACPI 183 180 depends on INPUT 184 181 help 185 182 This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
+1
drivers/platform/surface/aggregator/Kconfig
··· 4 4 menuconfig SURFACE_AGGREGATOR 5 5 tristate "Microsoft Surface System Aggregator Module Subsystem and Drivers" 6 6 depends on SERIAL_DEV_BUS 7 + depends on ACPI 7 8 select CRC_CCITT 8 9 help 9 10 The Surface System Aggregator Module (Surface SAM or SSAM) is an
+8 -16
drivers/platform/surface/aggregator/bus.c
··· 374 374 } 375 375 376 376 /** 377 - * ssam_controller_remove_clients() - Remove SSAM client devices registered as 378 - * direct children under the given controller. 379 - * @ctrl: The controller to remove all direct clients for. 377 + * ssam_remove_clients() - Remove SSAM client devices registered as direct 378 + * children under the given parent device. 379 + * @dev: The (parent) device to remove all direct clients for. 380 380 * 381 - * Remove all SSAM client devices registered as direct children under the 382 - * given controller. Note that this only accounts for direct children of the 383 - * controller device. This does not take care of any client devices where the 384 - * parent device has been manually set before calling ssam_device_add. Refer 385 - * to ssam_device_add()/ssam_device_remove() for more details on those cases. 386 - * 387 - * To avoid new devices being added in parallel to this call, the main 388 - * controller lock (not statelock) must be held during this (and if 389 - * necessary, any subsequent deinitialization) call. 381 + * Remove all SSAM client devices registered as direct children under the given 382 + * device. Note that this only accounts for direct children of the device. 383 + * Refer to ssam_device_add()/ssam_device_remove() for more details. 390 384 */ 391 - void ssam_controller_remove_clients(struct ssam_controller *ctrl) 385 + void ssam_remove_clients(struct device *dev) 392 386 { 393 - struct device *dev; 394 - 395 - dev = ssam_controller_device(ctrl); 396 387 device_for_each_child_reverse(dev, NULL, ssam_remove_device); 397 388 } 389 + EXPORT_SYMBOL_GPL(ssam_remove_clients); 398 390 399 391 /** 400 392 * ssam_bus_register() - Register and set-up the SSAM client device bus.
-3
drivers/platform/surface/aggregator/bus.h
··· 12 12 13 13 #ifdef CONFIG_SURFACE_AGGREGATOR_BUS 14 14 15 - void ssam_controller_remove_clients(struct ssam_controller *ctrl); 16 - 17 15 int ssam_bus_register(void); 18 16 void ssam_bus_unregister(void); 19 17 20 18 #else /* CONFIG_SURFACE_AGGREGATOR_BUS */ 21 19 22 - static inline void ssam_controller_remove_clients(struct ssam_controller *ctrl) {} 23 20 static inline int ssam_bus_register(void) { return 0; } 24 21 static inline void ssam_bus_unregister(void) {} 25 22
+2 -1
drivers/platform/surface/aggregator/core.c
··· 22 22 #include <linux/sysfs.h> 23 23 24 24 #include <linux/surface_aggregator/controller.h> 25 + #include <linux/surface_aggregator/device.h> 25 26 26 27 #include "bus.h" 27 28 #include "controller.h" ··· 736 735 ssam_controller_lock(ctrl); 737 736 738 737 /* Remove all client devices. */ 739 - ssam_controller_remove_clients(ctrl); 738 + ssam_remove_clients(&serdev->dev); 740 739 741 740 /* Act as if suspending to silence events. */ 742 741 status = ssam_ctrl_notif_display_off(ctrl);
+9 -23
drivers/platform/surface/surface_aggregator_registry.c
··· 258 258 return 0; 259 259 } 260 260 261 - static int ssam_hub_remove_devices_fn(struct device *dev, void *data) 262 - { 263 - if (!is_ssam_device(dev)) 264 - return 0; 265 - 266 - ssam_device_remove(to_ssam_device(dev)); 267 - return 0; 268 - } 269 - 270 - static void ssam_hub_remove_devices(struct device *parent) 271 - { 272 - device_for_each_child_reverse(parent, NULL, ssam_hub_remove_devices_fn); 273 - } 274 - 275 261 static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ctrl, 276 262 struct fwnode_handle *node) 277 263 { ··· 283 297 return status; 284 298 } 285 299 286 - static int ssam_hub_add_devices(struct device *parent, struct ssam_controller *ctrl, 287 - struct fwnode_handle *node) 300 + static int ssam_hub_register_clients(struct device *parent, struct ssam_controller *ctrl, 301 + struct fwnode_handle *node) 288 302 { 289 303 struct fwnode_handle *child; 290 304 int status; ··· 303 317 304 318 return 0; 305 319 err: 306 - ssam_hub_remove_devices(parent); 320 + ssam_remove_clients(parent); 307 321 return status; 308 322 } 309 323 ··· 398 412 hub->state = state; 399 413 400 414 if (hub->state == SSAM_BASE_HUB_CONNECTED) 401 - status = ssam_hub_add_devices(&hub->sdev->dev, hub->sdev->ctrl, node); 415 + status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node); 402 416 else 403 - ssam_hub_remove_devices(&hub->sdev->dev); 417 + ssam_remove_clients(&hub->sdev->dev); 404 418 405 419 if (status) 406 420 dev_err(&hub->sdev->dev, "failed to update base-hub devices: %d\n", status); ··· 482 496 err: 483 497 ssam_notifier_unregister(sdev->ctrl, &hub->notif); 484 498 cancel_delayed_work_sync(&hub->update_work); 485 - ssam_hub_remove_devices(&sdev->dev); 499 + ssam_remove_clients(&sdev->dev); 486 500 return status; 487 501 } 488 502 ··· 494 508 495 509 ssam_notifier_unregister(sdev->ctrl, &hub->notif); 496 510 cancel_delayed_work_sync(&hub->update_work); 497 - ssam_hub_remove_devices(&sdev->dev); 511 + ssam_remove_clients(&sdev->dev); 498 512 } 499 513 500 514 static const struct ssam_device_id ssam_base_hub_match[] = { ··· 597 611 598 612 set_secondary_fwnode(&pdev->dev, root); 599 613 600 - status = ssam_hub_add_devices(&pdev->dev, ctrl, root); 614 + status = ssam_hub_register_clients(&pdev->dev, ctrl, root); 601 615 if (status) { 602 616 set_secondary_fwnode(&pdev->dev, NULL); 603 617 software_node_unregister_node_group(nodes); ··· 611 625 { 612 626 const struct software_node **nodes = platform_get_drvdata(pdev); 613 627 614 - ssam_hub_remove_devices(&pdev->dev); 628 + ssam_remove_clients(&pdev->dev); 615 629 set_secondary_fwnode(&pdev->dev, NULL); 616 630 software_node_unregister_node_group(nodes); 617 631 return 0;
+61
drivers/platform/x86/Kconfig
··· 127 127 To compile this driver as a module, choose M here: the module will 128 128 be called gigabyte-wmi. 129 129 130 + config YOGABOOK_WMI 131 + tristate "Lenovo Yoga Book tablet WMI key driver" 132 + depends on ACPI_WMI 133 + depends on INPUT 134 + select LEDS_CLASS 135 + select NEW_LEDS 136 + help 137 + Say Y here if you want to support the 'Pen' key and keyboard backlight 138 + control on the Lenovo Yoga Book tablets. 139 + 140 + To compile this driver as a module, choose M here: the module will 141 + be called lenovo-yogabook-wmi. 142 + 130 143 config ACERHDF 131 144 tristate "Acer Aspire One temperature and fan driver" 132 145 depends on ACPI && THERMAL ··· 308 295 309 296 If you have an ACPI-WMI compatible Asus Notebook, say Y or M 310 297 here. 298 + 299 + config ASUS_TF103C_DOCK 300 + tristate "Asus TF103C 2-in-1 keyboard dock" 301 + depends on ACPI 302 + depends on I2C 303 + depends on INPUT 304 + depends on HID 305 + depends on GPIOLIB 306 + help 307 + This is a driver for the keyboard, touchpad and USB port of the 308 + keyboard dock for the Asus TF103C 2-in-1 tablet. 309 + 310 + This keyboard dock has its own I2C attached embedded controller 311 + and the keyboard and touchpad are also connected over I2C, 312 + instead of using the usual USB connection. This means that the 313 + keyboard dock requires this special driver to function. 314 + 315 + If you have an Asus TF103C tablet say Y or M here, for a generic x86 316 + distro config say M here. 311 317 312 318 config MERAKI_MX100 313 319 tristate "Cisco Meraki MX100 Platform Driver" ··· 1025 993 the OS-image for the device. This option supplies the missing info. 1026 994 Enable this for x86 tablets with Silead or Chipone touchscreens. 1027 995 996 + config X86_ANDROID_TABLETS 997 + tristate "X86 Android tablet support" 998 + depends on I2C && SERIAL_DEV_BUS && ACPI && GPIOLIB 999 + help 1000 + X86 tablets which ship with Android as (part of) the factory image 1001 + typically have various problems with their DSDTs. The factory kernels 1002 + shipped on these devices typically have device addresses and GPIOs 1003 + hardcoded in the kernel, rather than specified in their DSDT. 1004 + 1005 + With the DSDT containing a random collection of devices which may or 1006 + may not actually be present. This driver contains various fixes for 1007 + such tablets, including instantiating kernel devices for devices which 1008 + are missing from the DSDT. 1009 + 1010 + If you have a x86 Android tablet say Y or M here, for a generic x86 1011 + distro config say M here. 1012 + 1028 1013 config FW_ATTR_CLASS 1029 1014 tristate 1030 1015 ··· 1125 1076 The IPC Util driver provides an interface with the SCU enabling 1126 1077 low level access for debug work and updating the firmware. Say 1127 1078 N unless you will be doing this on an Intel MID platform. 1079 + 1080 + config SIEMENS_SIMATIC_IPC 1081 + tristate "Siemens Simatic IPC Class driver" 1082 + depends on PCI 1083 + help 1084 + This Simatic IPC class driver is the central of several drivers. It 1085 + is mainly used for system identification, after which drivers in other 1086 + classes will take care of driving specifics of those machines. 1087 + i.e. LEDs and watchdog. 1088 + 1089 + To compile this driver as a module, choose M here: the module 1090 + will be called simatic-ipc. 1128 1091 1129 1092 endif # X86_PLATFORM_DEVICES 1130 1093
+6
drivers/platform/x86/Makefile
··· 15 15 obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o 16 16 obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o 17 17 obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o 18 + obj-$(CONFIG_YOGABOOK_WMI) += lenovo-yogabook-wmi.o 18 19 19 20 # Acer 20 21 obj-$(CONFIG_ACERHDF) += acerhdf.o ··· 36 35 obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o 37 36 obj-$(CONFIG_ASUS_WMI) += asus-wmi.o 38 37 obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o 38 + obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o 39 39 obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o 40 40 obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o 41 41 ··· 114 112 obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o 115 113 obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o 116 114 obj-$(CONFIG_WIRELESS_HOTKEY) += wireless-hotkey.o 115 + obj-$(CONFIG_X86_ANDROID_TABLETS) += x86-android-tablets.o 117 116 118 117 # Intel uncore drivers 119 118 obj-$(CONFIG_INTEL_IPS) += intel_ips.o ··· 126 123 obj-$(CONFIG_INTEL_SCU_WDT) += intel_scu_wdt.o 127 124 obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o 128 125 obj-$(CONFIG_PMC_ATOM) += pmc_atom.o 126 + 127 + # Siemens Simatic Industrial PCs 128 + obj-$(CONFIG_SIEMENS_SIMATIC_IPC) += simatic-ipc.o
+145 -15
drivers/platform/x86/amd-pmc.c
··· 35 35 #define AMD_PMC_SCRATCH_REG_CZN 0x94 36 36 #define AMD_PMC_SCRATCH_REG_YC 0xD14 37 37 38 + /* STB Registers */ 39 + #define AMD_PMC_STB_INDEX_ADDRESS 0xF8 40 + #define AMD_PMC_STB_INDEX_DATA 0xFC 41 + #define AMD_PMC_STB_PMI_0 0x03E30600 42 + #define AMD_PMC_STB_PREDEF 0xC6000001 43 + 38 44 /* Base address of SMU for mapping physical address to virtual address */ 39 45 #define AMD_PMC_SMU_INDEX_ADDRESS 0xB8 40 46 #define AMD_PMC_SMU_INDEX_DATA 0xBC ··· 88 82 #define SOC_SUBSYSTEM_IP_MAX 12 89 83 #define DELAY_MIN_US 2000 90 84 #define DELAY_MAX_US 3000 85 + #define FIFO_SIZE 4096 91 86 enum amd_pmc_def { 92 87 MSG_TEST = 0x01, 93 88 MSG_OS_HINT_PCO, ··· 128 121 u16 minor; 129 122 u16 rev; 130 123 struct device *dev; 124 + struct pci_dev *rdev; 131 125 struct mutex lock; /* generic mutex lock */ 132 126 #if IS_ENABLED(CONFIG_DEBUG_FS) 133 127 struct dentry *dbgfs_dir; 134 128 #endif /* CONFIG_DEBUG_FS */ 135 129 }; 136 130 131 + static bool enable_stb; 132 + module_param(enable_stb, bool, 0644); 133 + MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism"); 134 + 137 135 static struct amd_pmc_dev pmc; 138 136 static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret); 137 + static int amd_pmc_write_stb(struct amd_pmc_dev *dev, u32 data); 138 + static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf); 139 139 140 140 static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset) 141 141 { ··· 188 174 189 175 return 0; 190 176 } 177 + 178 + static int amd_pmc_stb_debugfs_open(struct inode *inode, struct file *filp) 179 + { 180 + struct amd_pmc_dev *dev = filp->f_inode->i_private; 181 + u32 size = FIFO_SIZE * sizeof(u32); 182 + u32 *buf; 183 + int rc; 184 + 185 + buf = kzalloc(size, GFP_KERNEL); 186 + if (!buf) 187 + return -ENOMEM; 188 + 189 + rc = amd_pmc_read_stb(dev, buf); 190 + if (rc) { 191 + kfree(buf); 192 + return rc; 193 + } 194 + 195 + filp->private_data = buf; 196 + return rc; 197 + } 198 + 199 + static ssize_t amd_pmc_stb_debugfs_read(struct file *filp, char __user *buf, size_t size, 200 + loff_t *pos) 201 + { 202 + if (!filp->private_data) 203 + return -EINVAL; 204 + 205 + return simple_read_from_buffer(buf, size, pos, filp->private_data, 206 + FIFO_SIZE * sizeof(u32)); 207 + } 208 + 209 + static int amd_pmc_stb_debugfs_release(struct inode *inode, struct file *filp) 210 + { 211 + kfree(filp->private_data); 212 + return 0; 213 + } 214 + 215 + const struct file_operations amd_pmc_stb_debugfs_fops = { 216 + .owner = THIS_MODULE, 217 + .open = amd_pmc_stb_debugfs_open, 218 + .read = amd_pmc_stb_debugfs_read, 219 + .release = amd_pmc_stb_debugfs_release, 220 + }; 191 221 192 222 static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, 193 223 struct seq_file *s) ··· 346 288 &s0ix_stats_fops); 347 289 debugfs_create_file("amd_pmc_idlemask", 0644, dev->dbgfs_dir, dev, 348 290 &amd_pmc_idlemask_fops); 291 + /* Enable STB only when the module_param is set */ 292 + if (enable_stb) 293 + debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, 294 + &amd_pmc_stb_debugfs_fops); 349 295 } 350 296 #else 351 297 static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) ··· 546 484 if (rc) 547 485 dev_err(pdev->dev, "suspend failed\n"); 548 486 487 + if (enable_stb) 488 + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF); 489 + if (rc) { 490 + dev_err(pdev->dev, "error writing to STB\n"); 491 + return rc; 492 + } 493 + 549 494 return rc; 550 495 } 551 496 ··· 573 504 /* Dump the IdleMask to see the blockers */ 574 505 amd_pmc_idlemask_read(pdev, dev, NULL); 575 506 507 + /* Write data incremented by 1 to distinguish in stb_read */ 508 + if (enable_stb) 509 + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF + 1); 510 + if (rc) { 511 + dev_err(pdev->dev, "error writing to STB\n"); 512 + return rc; 513 + } 514 + 576 515 return 0; 577 516 } 578 517 ··· 598 521 { } 599 522 }; 600 523 524 + static int amd_pmc_write_stb(struct amd_pmc_dev *dev, u32 data) 525 + { 526 + int err; 527 + 528 + err = pci_write_config_dword(dev->rdev, AMD_PMC_STB_INDEX_ADDRESS, AMD_PMC_STB_PMI_0); 529 + if (err) { 530 + dev_err(dev->dev, "failed to write addr in stb: 0x%X\n", 531 + AMD_PMC_STB_INDEX_ADDRESS); 532 + return pcibios_err_to_errno(err); 533 + } 534 + 535 + err = pci_write_config_dword(dev->rdev, AMD_PMC_STB_INDEX_DATA, data); 536 + if (err) { 537 + dev_err(dev->dev, "failed to write data in stb: 0x%X\n", 538 + AMD_PMC_STB_INDEX_DATA); 539 + return pcibios_err_to_errno(err); 540 + } 541 + 542 + return 0; 543 + } 544 + 545 + static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf) 546 + { 547 + int i, err; 548 + 549 + err = pci_write_config_dword(dev->rdev, AMD_PMC_STB_INDEX_ADDRESS, AMD_PMC_STB_PMI_0); 550 + if (err) { 551 + dev_err(dev->dev, "error writing addr to stb: 0x%X\n", 552 + AMD_PMC_STB_INDEX_ADDRESS); 553 + return pcibios_err_to_errno(err); 554 + } 555 + 556 + for (i = 0; i < FIFO_SIZE; i++) { 557 + err = pci_read_config_dword(dev->rdev, AMD_PMC_STB_INDEX_DATA, buf++); 558 + if (err) { 559 + dev_err(dev->dev, "error reading data from stb: 0x%X\n", 560 + AMD_PMC_STB_INDEX_DATA); 561 + return pcibios_err_to_errno(err); 562 + } 563 + } 564 + 565 + return 0; 566 + } 567 + 601 568 static int amd_pmc_probe(struct platform_device *pdev) 602 569 { 603 570 struct amd_pmc_dev *dev = &pmc; ··· 655 534 656 535 rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); 657 536 if (!rdev || !pci_match_id(pmc_pci_ids, rdev)) { 658 - pci_dev_put(rdev); 659 - return -ENODEV; 537 + err = -ENODEV; 538 + goto err_pci_dev_put; 660 539 } 661 540 662 541 dev->cpu_id = rdev->device; 542 + dev->rdev = rdev; 663 543 err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_LO); 664 544 if (err) { 665 545 dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS); 666 - pci_dev_put(rdev); 667 - return pcibios_err_to_errno(err); 546 + err = pcibios_err_to_errno(err); 547 + goto err_pci_dev_put; 668 548 } 669 549 670 550 err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val); 671 551 if (err) { 672 - pci_dev_put(rdev); 673 - return pcibios_err_to_errno(err); 552 + err = pcibios_err_to_errno(err); 553 + goto err_pci_dev_put; 674 554 } 675 555 676 556 base_addr_lo = val & AMD_PMC_BASE_ADDR_HI_MASK; ··· 679 557 err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_HI); 680 558 if (err) { 681 559 dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS); 682 - pci_dev_put(rdev); 683 - return pcibios_err_to_errno(err); 560 + err = pcibios_err_to_errno(err); 561 + goto err_pci_dev_put; 684 562 } 685 563 686 564 err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val); 687 565 if (err) { 688 - pci_dev_put(rdev); 689 - return pcibios_err_to_errno(err); 566 + err = pcibios_err_to_errno(err); 567 + goto err_pci_dev_put; 690 568 } 691 569 692 570 base_addr_hi = val & AMD_PMC_BASE_ADDR_LO_MASK; 693 - pci_dev_put(rdev); 694 571 base_addr = ((u64)base_addr_hi << 32 | base_addr_lo); 695 572 696 573 dev->regbase = devm_ioremap(dev->dev, base_addr + AMD_PMC_BASE_ADDR_OFFSET, 697 574 AMD_PMC_MAPPING_SIZE); 698 - if (!dev->regbase) 699 - return -ENOMEM; 575 + if (!dev->regbase) { 576 + err = -ENOMEM; 577 + goto err_pci_dev_put; 578 + } 700 579 701 580 mutex_init(&dev->lock); 702 581 ··· 706 583 base_addr_hi = FCH_BASE_PHY_ADDR_HIGH; 707 584 fch_phys_addr = ((u64)base_addr_hi << 32 | base_addr_lo); 708 585 dev->fch_virt_addr = devm_ioremap(dev->dev, fch_phys_addr, FCH_SSC_MAPPING_SIZE); 709 - if (!dev->fch_virt_addr) 710 - return -ENOMEM; 586 + if (!dev->fch_virt_addr) { 587 + err = -ENOMEM; 588 + goto err_pci_dev_put; 589 + } 711 590 712 591 /* Use SMU to get the s0i3 debug stats */ 713 592 err = amd_pmc_setup_smu_logging(dev); ··· 720 595 platform_set_drvdata(pdev, dev); 721 596 amd_pmc_dbgfs_register(dev); 722 597 return 0; 598 + 599 + err_pci_dev_put: 600 + pci_dev_put(rdev); 601 + return err; 723 602 } 724 603 725 604 static int amd_pmc_remove(struct platform_device *pdev) ··· 731 602 struct amd_pmc_dev *dev = platform_get_drvdata(pdev); 732 603 733 604 amd_pmc_dbgfs_unregister(dev); 605 + pci_dev_put(dev->rdev); 734 606 mutex_destroy(&dev->lock); 735 607 return 0; 736 608 }
+945
drivers/platform/x86/asus-tf103c-dock.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * This is a driver for the keyboard, touchpad and USB port of the 4 + * keyboard dock for the Asus TF103C 2-in-1 tablet. 5 + * 6 + * This keyboard dock has its own I2C attached embedded controller 7 + * and the keyboard and touchpad are also connected over I2C, 8 + * instead of using the usual USB connection. This means that the 9 + * keyboard dock requires this special driver to function. 10 + * 11 + * Copyright (C) 2021 Hans de Goede <hdegoede@redhat.com> 12 + */ 13 + 14 + #include <linux/acpi.h> 15 + #include <linux/delay.h> 16 + #include <linux/dmi.h> 17 + #include <linux/gpio/consumer.h> 18 + #include <linux/gpio/machine.h> 19 + #include <linux/hid.h> 20 + #include <linux/i2c.h> 21 + #include <linux/input.h> 22 + #include <linux/irq.h> 23 + #include <linux/irqdomain.h> 24 + #include <linux/mod_devicetable.h> 25 + #include <linux/moduleparam.h> 26 + #include <linux/module.h> 27 + #include <linux/pm.h> 28 + #include <linux/workqueue.h> 29 + #include <asm/unaligned.h> 30 + 31 + static bool fnlock; 32 + module_param(fnlock, bool, 0644); 33 + MODULE_PARM_DESC(fnlock, 34 + "By default the kbd toprow sends multimedia key presses. AltGr " 35 + "can be pressed to change this to F1-F12. Set this to 1 to " 36 + "change the default. Press AltGr + Esc to toggle at runtime."); 37 + 38 + #define TF103C_DOCK_DEV_NAME "NPCE69A:00" 39 + 40 + #define TF103C_DOCK_HPD_DEBOUNCE msecs_to_jiffies(20) 41 + 42 + /*** Touchpad I2C device defines ***/ 43 + #define TF103C_DOCK_TP_ADDR 0x15 44 + 45 + /*** Keyboard I2C device defines **A*/ 46 + #define TF103C_DOCK_KBD_ADDR 0x16 47 + 48 + #define TF103C_DOCK_KBD_DATA_REG 0x73 49 + #define TF103C_DOCK_KBD_DATA_MIN_LENGTH 4 50 + #define TF103C_DOCK_KBD_DATA_MAX_LENGTH 11 51 + #define TF103C_DOCK_KBD_DATA_MODIFIERS 3 52 + #define TF103C_DOCK_KBD_DATA_KEYS 5 53 + #define TF103C_DOCK_KBD_CMD_REG 0x75 54 + 55 + #define TF103C_DOCK_KBD_CMD_ENABLE 0x0800 56 + 57 + /*** EC innterrupt data I2C device defines ***/ 58 + #define TF103C_DOCK_INTR_ADDR 0x19 59 + #define TF103C_DOCK_INTR_DATA_REG 0x6a 60 + 61 + #define TF103C_DOCK_INTR_DATA1_OBF_MASK 0x01 62 + #define TF103C_DOCK_INTR_DATA1_KEY_MASK 0x04 63 + #define TF103C_DOCK_INTR_DATA1_KBC_MASK 0x08 64 + #define TF103C_DOCK_INTR_DATA1_AUX_MASK 0x20 65 + #define TF103C_DOCK_INTR_DATA1_SCI_MASK 0x40 66 + #define TF103C_DOCK_INTR_DATA1_SMI_MASK 0x80 67 + /* Special values for the OOB data on kbd_client / tp_client */ 68 + #define TF103C_DOCK_INTR_DATA1_OOB_VALUE 0xc1 69 + #define TF103C_DOCK_INTR_DATA2_OOB_VALUE 0x04 70 + 71 + #define TF103C_DOCK_SMI_AC_EVENT 0x31 72 + #define TF103C_DOCK_SMI_HANDSHAKING 0x50 73 + #define TF103C_DOCK_SMI_EC_WAKEUP 0x53 74 + #define TF103C_DOCK_SMI_BOOTBLOCK_RESET 0x5e 75 + #define TF103C_DOCK_SMI_WATCHDOG_RESET 0x5f 76 + #define TF103C_DOCK_SMI_ADAPTER_CHANGE 0x60 77 + #define TF103C_DOCK_SMI_DOCK_INSERT 0x61 78 + #define TF103C_DOCK_SMI_DOCK_REMOVE 0x62 79 + #define TF103C_DOCK_SMI_PAD_BL_CHANGE 0x63 80 + #define TF103C_DOCK_SMI_HID_STATUS_CHANGED 0x64 81 + #define TF103C_DOCK_SMI_HID_WAKEUP 0x65 82 + #define TF103C_DOCK_SMI_S3 0x83 83 + #define TF103C_DOCK_SMI_S5 0x85 84 + #define TF103C_DOCK_SMI_NOTIFY_SHUTDOWN 0x90 85 + #define TF103C_DOCK_SMI_RESUME 0x91 86 + 87 + /*** EC (dockram) I2C device defines ***/ 88 + #define TF103C_DOCK_EC_ADDR 0x1b 89 + 90 + #define TF103C_DOCK_EC_CMD_REG 0x0a 91 + #define TF103C_DOCK_EC_CMD_LEN 9 92 + 93 + enum { 94 + TF103C_DOCK_FLAG_HID_OPEN, 95 + }; 96 + 97 + struct tf103c_dock_data { 98 + struct delayed_work hpd_work; 99 + struct irq_chip tp_irqchip; 100 + struct irq_domain *tp_irq_domain; 101 + struct i2c_client *ec_client; 102 + struct i2c_client *intr_client; 103 + struct i2c_client *kbd_client; 104 + struct i2c_client *tp_client; 105 + struct gpio_desc *pwr_en; 106 + struct gpio_desc *irq_gpio; 107 + struct gpio_desc *hpd_gpio; 108 + struct input_dev *input; 109 + struct hid_device *hid; 110 + unsigned long flags; 111 + int board_rev; 112 + int irq; 113 + int hpd_irq; 114 + int tp_irq; 115 + int last_press_0x13; 116 + int last_press_0x14; 117 + bool enabled; 118 + bool tp_enabled; 119 + bool altgr_pressed; 120 + bool esc_pressed; 121 + bool filter_esc; 122 + u8 kbd_buf[TF103C_DOCK_KBD_DATA_MAX_LENGTH]; 123 + }; 124 + 125 + static struct gpiod_lookup_table tf103c_dock_gpios = { 126 + .dev_id = "i2c-" TF103C_DOCK_DEV_NAME, 127 + .table = { 128 + GPIO_LOOKUP("INT33FC:00", 55, "dock_pwr_en", GPIO_ACTIVE_HIGH), 129 + GPIO_LOOKUP("INT33FC:02", 1, "dock_irq", GPIO_ACTIVE_HIGH), 130 + GPIO_LOOKUP("INT33FC:02", 29, "dock_hpd", GPIO_ACTIVE_HIGH), 131 + GPIO_LOOKUP("gpio_crystalcove", 2, "board_rev", GPIO_ACTIVE_HIGH), 132 + {} 133 + }, 134 + }; 135 + 136 + /* Byte 0 is the length of the rest of the packet */ 137 + static const u8 tf103c_dock_enable_cmd[9] = { 8, 0x20, 0, 0, 0, 0, 0x20, 0, 0 }; 138 + static const u8 tf103c_dock_usb_enable_cmd[9] = { 8, 0, 0, 0, 0, 0, 0, 0x40, 0 }; 139 + static const u8 tf103c_dock_suspend_cmd[9] = { 8, 0, 0x20, 0, 0, 0x22, 0, 0, 0 }; 140 + 141 + /*** keyboard related code ***/ 142 + 143 + static u8 tf103c_dock_kbd_hid_desc[] = { 144 + 0x05, 0x01, /* Usage Page (Desktop), */ 145 + 0x09, 0x06, /* Usage (Keyboard), */ 146 + 0xA1, 0x01, /* Collection (Application), */ 147 + 0x85, 0x11, /* Report ID (17), */ 148 + 0x95, 0x08, /* Report Count (8), */ 149 + 0x75, 0x01, /* Report Size (1), */ 150 + 0x15, 0x00, /* Logical Minimum (0), */ 151 + 0x25, 0x01, /* Logical Maximum (1), */ 152 + 0x05, 0x07, /* Usage Page (Keyboard), */ 153 + 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */ 154 + 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */ 155 + 0x81, 0x02, /* Input (Variable), */ 156 + 0x95, 0x01, /* Report Count (1), */ 157 + 0x75, 0x08, /* Report Size (8), */ 158 + 0x81, 0x01, /* Input (Constant), */ 159 + 0x95, 0x06, /* Report Count (6), */ 160 + 0x75, 0x08, /* Report Size (8), */ 161 + 0x15, 0x00, /* Logical Minimum (0), */ 162 + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 163 + 0x05, 0x07, /* Usage Page (Keyboard), */ 164 + 0x19, 0x00, /* Usage Minimum (None), */ 165 + 0x2A, 0xFF, 0x00, /* Usage Maximum (FFh), */ 166 + 0x81, 0x00, /* Input, */ 167 + 0xC0 /* End Collection */ 168 + }; 169 + 170 + static int tf103c_dock_kbd_read(struct tf103c_dock_data *dock) 171 + { 172 + struct i2c_client *client = dock->kbd_client; 173 + struct device *dev = &dock->ec_client->dev; 174 + struct i2c_msg msgs[2]; 175 + u8 reg[2]; 176 + int ret; 177 + 178 + reg[0] = TF103C_DOCK_KBD_DATA_REG & 0xff; 179 + reg[1] = TF103C_DOCK_KBD_DATA_REG >> 8; 180 + 181 + msgs[0].addr = client->addr; 182 + msgs[0].flags = 0; 183 + msgs[0].len = sizeof(reg); 184 + msgs[0].buf = reg; 185 + 186 + msgs[1].addr = client->addr; 187 + msgs[1].flags = I2C_M_RD; 188 + msgs[1].len = TF103C_DOCK_KBD_DATA_MAX_LENGTH; 189 + msgs[1].buf = dock->kbd_buf; 190 + 191 + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 192 + if (ret != ARRAY_SIZE(msgs)) { 193 + dev_err(dev, "error %d reading kbd data\n", ret); 194 + return -EIO; 195 + } 196 + 197 + return 0; 198 + } 199 + 200 + static void tf103c_dock_kbd_write(struct tf103c_dock_data *dock, u16 cmd) 201 + { 202 + struct device *dev = &dock->ec_client->dev; 203 + u8 buf[4]; 204 + int ret; 205 + 206 + put_unaligned_le16(TF103C_DOCK_KBD_CMD_REG, &buf[0]); 207 + put_unaligned_le16(cmd, &buf[2]); 208 + 209 + ret = i2c_master_send(dock->kbd_client, buf, sizeof(buf)); 210 + if (ret != sizeof(buf)) 211 + dev_err(dev, "error %d writing kbd cmd\n", ret); 212 + } 213 + 214 + /* HID ll_driver functions for forwarding input-reports from the kbd_client */ 215 + static int tf103c_dock_hid_parse(struct hid_device *hid) 216 + { 217 + return hid_parse_report(hid, tf103c_dock_kbd_hid_desc, 218 + sizeof(tf103c_dock_kbd_hid_desc)); 219 + } 220 + 221 + static int tf103c_dock_hid_start(struct hid_device *hid) 222 + { 223 + return 0; 224 + } 225 + 226 + static void tf103c_dock_hid_stop(struct hid_device *hid) 227 + { 228 + hid->claimed = 0; 229 + } 230 + 231 + static int tf103c_dock_hid_open(struct hid_device *hid) 232 + { 233 + struct tf103c_dock_data *dock = hid->driver_data; 234 + 235 + set_bit(TF103C_DOCK_FLAG_HID_OPEN, &dock->flags); 236 + return 0; 237 + } 238 + 239 + static void tf103c_dock_hid_close(struct hid_device *hid) 240 + { 241 + struct tf103c_dock_data *dock = hid->driver_data; 242 + 243 + clear_bit(TF103C_DOCK_FLAG_HID_OPEN, &dock->flags); 244 + } 245 + 246 + /* Mandatory, but not used */ 247 + static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum, 248 + u8 *buf, size_t len, u8 rtype, int reqtype) 249 + { 250 + return 0; 251 + } 252 + 253 + struct hid_ll_driver tf103c_dock_hid_ll_driver = { 254 + .parse = tf103c_dock_hid_parse, 255 + .start = tf103c_dock_hid_start, 256 + .stop = tf103c_dock_hid_stop, 257 + .open = tf103c_dock_hid_open, 258 + .close = tf103c_dock_hid_close, 259 + .raw_request = tf103c_dock_hid_raw_request, 260 + }; 261 + 262 + static int tf103c_dock_toprow_codes[13][2] = { 263 + /* Normal, AltGr pressed */ 264 + { KEY_POWER, KEY_F1 }, 265 + { KEY_RFKILL, KEY_F2 }, 266 + { KEY_F21, KEY_F3 }, /* Touchpad toggle, userspace expects F21 */ 267 + { KEY_BRIGHTNESSDOWN, KEY_F4 }, 268 + { KEY_BRIGHTNESSUP, KEY_F5 }, 269 + { KEY_CAMERA, KEY_F6 }, 270 + { KEY_CONFIG, KEY_F7 }, 271 + { KEY_PREVIOUSSONG, KEY_F8 }, 272 + { KEY_PLAYPAUSE, KEY_F9 }, 273 + { KEY_NEXTSONG, KEY_F10 }, 274 + { KEY_MUTE, KEY_F11 }, 275 + { KEY_VOLUMEDOWN, KEY_F12 }, 276 + { KEY_VOLUMEUP, KEY_SYSRQ }, 277 + }; 278 + 279 + static void tf103c_dock_report_toprow_kbd_hook(struct tf103c_dock_data *dock) 280 + { 281 + u8 *esc, *buf = dock->kbd_buf; 282 + int size; 283 + 284 + /* 285 + * Stop AltGr reports from getting reported on the "Asus TF103C Dock 286 + * Keyboard" input_dev, since this gets used as "Fn" key for the toprow 287 + * keys. Instead we report this on the "Asus TF103C Dock Top Row Keys" 288 + * input_dev, when not used to modify the toprow keys. 289 + */ 290 + dock->altgr_pressed = buf[TF103C_DOCK_KBD_DATA_MODIFIERS] & 0x40; 291 + buf[TF103C_DOCK_KBD_DATA_MODIFIERS] &= ~0x40; 292 + 293 + input_report_key(dock->input, KEY_RIGHTALT, dock->altgr_pressed); 294 + input_sync(dock->input); 295 + 296 + /* Toggle fnlock on AltGr + Esc press */ 297 + buf = buf + TF103C_DOCK_KBD_DATA_KEYS; 298 + size = TF103C_DOCK_KBD_DATA_MAX_LENGTH - TF103C_DOCK_KBD_DATA_KEYS; 299 + esc = memchr(buf, 0x29, size); 300 + if (!dock->esc_pressed && esc) { 301 + if (dock->altgr_pressed) { 302 + fnlock = !fnlock; 303 + dock->filter_esc = true; 304 + } 305 + } 306 + if (esc && dock->filter_esc) 307 + *esc = 0; 308 + else 309 + dock->filter_esc = false; 310 + 311 + dock->esc_pressed = esc != NULL; 312 + } 313 + 314 + static void tf103c_dock_toprow_press(struct tf103c_dock_data *dock, int key_code) 315 + { 316 + /* 317 + * Release AltGr before reporting the toprow key, so that userspace 318 + * sees e.g. just KEY_SUSPEND and not AltGr + KEY_SUSPEND. 319 + */ 320 + if (dock->altgr_pressed) { 321 + input_report_key(dock->input, KEY_RIGHTALT, false); 322 + input_sync(dock->input); 323 + } 324 + 325 + input_report_key(dock->input, key_code, true); 326 + input_sync(dock->input); 327 + } 328 + 329 + static void tf103c_dock_toprow_release(struct tf103c_dock_data *dock, int key_code) 330 + { 331 + input_report_key(dock->input, key_code, false); 332 + input_sync(dock->input); 333 + 334 + if (dock->altgr_pressed) { 335 + input_report_key(dock->input, KEY_RIGHTALT, true); 336 + input_sync(dock->input); 337 + } 338 + } 339 + 340 + static void tf103c_dock_toprow_event(struct tf103c_dock_data *dock, 341 + int toprow_index, int *last_press) 342 + { 343 + int key_code, fn = dock->altgr_pressed ^ fnlock; 344 + 345 + if (last_press && *last_press) { 346 + tf103c_dock_toprow_release(dock, *last_press); 347 + *last_press = 0; 348 + } 349 + 350 + if (toprow_index < 0) 351 + return; 352 + 353 + key_code = tf103c_dock_toprow_codes[toprow_index][fn]; 354 + tf103c_dock_toprow_press(dock, key_code); 355 + 356 + if (last_press) 357 + *last_press = key_code; 358 + else 359 + tf103c_dock_toprow_release(dock, key_code); 360 + } 361 + 362 + /* 363 + * The keyboard sends what appears to be standard I2C-HID input-reports, 364 + * except that a 16 bit register address of where the I2C-HID format 365 + * input-reports are stored must be send before reading it in a single 366 + * (I2C repeated-start) I2C transaction. 367 + * 368 + * Its unknown how to get the HID descriptors but they are easy to reconstruct: 369 + * 370 + * Input report id 0x11 is 8 bytes long and contain standard USB HID intf-class, 371 + * Boot Interface Subclass reports. 372 + * Input report id 0x13 is 2 bytes long and sends Consumer Control events 373 + * Input report id 0x14 is 1 byte long and sends System Control events 374 + * 375 + * However the top row keys (where a normal keyboard has F1-F12 + Print-Screen) 376 + * are a mess, using a mix of the 0x13 and 0x14 input reports as well as EC SCI 377 + * events; and these need special handling to allow actually sending F1-F12, 378 + * since the Fn key on the keyboard only works on the cursor keys and the top 379 + * row keys always send their special "Multimedia hotkey" codes. 380 + * 381 + * So only forward the 0x11 reports to HID and handle the top-row keys here. 382 + */ 383 + static void tf103c_dock_kbd_interrupt(struct tf103c_dock_data *dock) 384 + { 385 + struct device *dev = &dock->ec_client->dev; 386 + u8 *buf = dock->kbd_buf; 387 + int size; 388 + 389 + if (tf103c_dock_kbd_read(dock)) 390 + return; 391 + 392 + size = buf[0] | buf[1] << 8; 393 + if (size < TF103C_DOCK_KBD_DATA_MIN_LENGTH || 394 + size > TF103C_DOCK_KBD_DATA_MAX_LENGTH) { 395 + dev_err(dev, "error reported kbd pkt size %d is out of range %d-%d\n", size, 396 + TF103C_DOCK_KBD_DATA_MIN_LENGTH, 397 + TF103C_DOCK_KBD_DATA_MAX_LENGTH); 398 + return; 399 + } 400 + 401 + switch (buf[2]) { 402 + case 0x11: 403 + if (size != 11) 404 + break; 405 + 406 + tf103c_dock_report_toprow_kbd_hook(dock); 407 + 408 + if (test_bit(TF103C_DOCK_FLAG_HID_OPEN, &dock->flags)) 409 + hid_input_report(dock->hid, HID_INPUT_REPORT, buf + 2, size - 2, 1); 410 + return; 411 + case 0x13: 412 + if (size != 5) 413 + break; 414 + 415 + switch (buf[3] | buf[4] << 8) { 416 + case 0: 417 + tf103c_dock_toprow_event(dock, -1, &dock->last_press_0x13); 418 + return; 419 + case 0x70: 420 + tf103c_dock_toprow_event(dock, 3, &dock->last_press_0x13); 421 + return; 422 + case 0x6f: 423 + tf103c_dock_toprow_event(dock, 4, &dock->last_press_0x13); 424 + return; 425 + case 0xb6: 426 + tf103c_dock_toprow_event(dock, 7, &dock->last_press_0x13); 427 + return; 428 + case 0xcd: 429 + tf103c_dock_toprow_event(dock, 8, &dock->last_press_0x13); 430 + return; 431 + case 0xb5: 432 + tf103c_dock_toprow_event(dock, 9, &dock->last_press_0x13); 433 + return; 434 + case 0xe2: 435 + tf103c_dock_toprow_event(dock, 10, &dock->last_press_0x13); 436 + return; 437 + case 0xea: 438 + tf103c_dock_toprow_event(dock, 11, &dock->last_press_0x13); 439 + return; 440 + case 0xe9: 441 + tf103c_dock_toprow_event(dock, 12, &dock->last_press_0x13); 442 + return; 443 + } 444 + break; 445 + case 0x14: 446 + if (size != 4) 447 + break; 448 + 449 + switch (buf[3]) { 450 + case 0: 451 + tf103c_dock_toprow_event(dock, -1, &dock->last_press_0x14); 452 + return; 453 + case 1: 454 + tf103c_dock_toprow_event(dock, 0, &dock->last_press_0x14); 455 + return; 456 + } 457 + break; 458 + } 459 + 460 + dev_warn(dev, "warning unknown kbd data: %*ph\n", size, buf); 461 + } 462 + 463 + /*** touchpad related code ***/ 464 + 465 + static const struct property_entry tf103c_dock_touchpad_props[] = { 466 + PROPERTY_ENTRY_BOOL("elan,clickpad"), 467 + { } 468 + }; 469 + 470 + static const struct software_node tf103c_dock_touchpad_sw_node = { 471 + .properties = tf103c_dock_touchpad_props, 472 + }; 473 + 474 + /* 475 + * tf103c_enable_touchpad() is only called from the threaded interrupt handler 476 + * and tf103c_disable_touchpad() is only called after the irq is disabled, 477 + * so no locking is necessary. 478 + */ 479 + static void tf103c_dock_enable_touchpad(struct tf103c_dock_data *dock) 480 + { 481 + struct i2c_board_info board_info = { }; 482 + struct device *dev = &dock->ec_client->dev; 483 + int ret; 484 + 485 + if (dock->tp_enabled) { 486 + /* Happens after resume, the tp needs to be reinitialized */ 487 + ret = device_reprobe(&dock->tp_client->dev); 488 + if (ret) 489 + dev_err_probe(dev, ret, "reprobing tp-client\n"); 490 + return; 491 + } 492 + 493 + strscpy(board_info.type, "elan_i2c", I2C_NAME_SIZE); 494 + board_info.addr = TF103C_DOCK_TP_ADDR; 495 + board_info.dev_name = TF103C_DOCK_DEV_NAME "-tp"; 496 + board_info.irq = dock->tp_irq; 497 + board_info.swnode = &tf103c_dock_touchpad_sw_node; 498 + 499 + dock->tp_client = i2c_new_client_device(dock->ec_client->adapter, &board_info); 500 + if (IS_ERR(dock->tp_client)) { 501 + dev_err(dev, "error %ld creating tp client\n", PTR_ERR(dock->tp_client)); 502 + return; 503 + } 504 + 505 + dock->tp_enabled = true; 506 + } 507 + 508 + static void tf103c_dock_disable_touchpad(struct tf103c_dock_data *dock) 509 + { 510 + if (!dock->tp_enabled) 511 + return; 512 + 513 + i2c_unregister_device(dock->tp_client); 514 + 515 + dock->tp_enabled = false; 516 + } 517 + 518 + /*** interrupt handling code ***/ 519 + static void tf103c_dock_ec_cmd(struct tf103c_dock_data *dock, const u8 *cmd) 520 + { 521 + struct device *dev = &dock->ec_client->dev; 522 + int ret; 523 + 524 + ret = i2c_smbus_write_i2c_block_data(dock->ec_client, TF103C_DOCK_EC_CMD_REG, 525 + TF103C_DOCK_EC_CMD_LEN, cmd); 526 + if (ret) 527 + dev_err(dev, "error %d sending %*ph cmd\n", ret, 528 + TF103C_DOCK_EC_CMD_LEN, cmd); 529 + } 530 + 531 + static void tf103c_dock_sci(struct tf103c_dock_data *dock, u8 val) 532 + { 533 + struct device *dev = &dock->ec_client->dev; 534 + 535 + switch (val) { 536 + case 2: 537 + tf103c_dock_toprow_event(dock, 1, NULL); 538 + return; 539 + case 4: 540 + tf103c_dock_toprow_event(dock, 2, NULL); 541 + return; 542 + case 8: 543 + tf103c_dock_toprow_event(dock, 5, NULL); 544 + return; 545 + case 17: 546 + tf103c_dock_toprow_event(dock, 6, NULL); 547 + return; 548 + } 549 + 550 + dev_warn(dev, "warning unknown SCI value: 0x%02x\n", val); 551 + } 552 + 553 + static void tf103c_dock_smi(struct tf103c_dock_data *dock, u8 val) 554 + { 555 + struct device *dev = &dock->ec_client->dev; 556 + 557 + switch (val) { 558 + case TF103C_DOCK_SMI_EC_WAKEUP: 559 + tf103c_dock_ec_cmd(dock, tf103c_dock_enable_cmd); 560 + tf103c_dock_ec_cmd(dock, tf103c_dock_usb_enable_cmd); 561 + tf103c_dock_kbd_write(dock, TF103C_DOCK_KBD_CMD_ENABLE); 562 + break; 563 + case TF103C_DOCK_SMI_PAD_BL_CHANGE: 564 + /* There is no backlight, but the EC still sends this */ 565 + break; 566 + case TF103C_DOCK_SMI_HID_STATUS_CHANGED: 567 + tf103c_dock_enable_touchpad(dock); 568 + break; 569 + default: 570 + dev_warn(dev, "warning unknown SMI value: 0x%02x\n", val); 571 + break; 572 + } 573 + } 574 + 575 + static irqreturn_t tf103c_dock_irq(int irq, void *data) 576 + { 577 + struct tf103c_dock_data *dock = data; 578 + struct device *dev = &dock->ec_client->dev; 579 + u8 intr_data[8]; 580 + int ret; 581 + 582 + ret = i2c_smbus_read_i2c_block_data(dock->intr_client, TF103C_DOCK_INTR_DATA_REG, 583 + sizeof(intr_data), intr_data); 584 + if (ret != sizeof(intr_data)) { 585 + dev_err(dev, "error %d reading intr data\n", ret); 586 + return IRQ_NONE; 587 + } 588 + 589 + if (!(intr_data[1] & TF103C_DOCK_INTR_DATA1_OBF_MASK)) 590 + return IRQ_NONE; 591 + 592 + /* intr_data[0] is the length of the rest of the packet */ 593 + if (intr_data[0] == 3 && intr_data[1] == TF103C_DOCK_INTR_DATA1_OOB_VALUE && 594 + intr_data[2] == TF103C_DOCK_INTR_DATA2_OOB_VALUE) { 595 + /* intr_data[3] seems to contain a HID input report id */ 596 + switch (intr_data[3]) { 597 + case 0x01: 598 + handle_nested_irq(dock->tp_irq); 599 + break; 600 + case 0x11: 601 + case 0x13: 602 + case 0x14: 603 + tf103c_dock_kbd_interrupt(dock); 604 + break; 605 + default: 606 + dev_warn(dev, "warning unknown intr_data[3]: 0x%02x\n", intr_data[3]); 607 + break; 608 + } 609 + return IRQ_HANDLED; 610 + } 611 + 612 + if (intr_data[1] & TF103C_DOCK_INTR_DATA1_SCI_MASK) { 613 + tf103c_dock_sci(dock, intr_data[2]); 614 + return IRQ_HANDLED; 615 + } 616 + 617 + if (intr_data[1] & TF103C_DOCK_INTR_DATA1_SMI_MASK) { 618 + tf103c_dock_smi(dock, intr_data[2]); 619 + return IRQ_HANDLED; 620 + } 621 + 622 + dev_warn(dev, "warning unknown intr data: %*ph\n", 8, intr_data); 623 + return IRQ_NONE; 624 + } 625 + 626 + /* 627 + * tf103c_dock_[dis|en]able only run from hpd_work or at times when 628 + * hpd_work cannot run (hpd_irq disabled), so no locking is necessary. 629 + */ 630 + static void tf103c_dock_enable(struct tf103c_dock_data *dock) 631 + { 632 + if (dock->enabled) 633 + return; 634 + 635 + if (dock->board_rev != 2) 636 + gpiod_set_value(dock->pwr_en, 1); 637 + 638 + msleep(500); 639 + enable_irq(dock->irq); 640 + 641 + dock->enabled = true; 642 + } 643 + 644 + static void tf103c_dock_disable(struct tf103c_dock_data *dock) 645 + { 646 + if (!dock->enabled) 647 + return; 648 + 649 + disable_irq(dock->irq); 650 + tf103c_dock_disable_touchpad(dock); 651 + if (dock->board_rev != 2) 652 + gpiod_set_value(dock->pwr_en, 0); 653 + 654 + dock->enabled = false; 655 + } 656 + 657 + static void tf103c_dock_hpd_work(struct work_struct *work) 658 + { 659 + struct tf103c_dock_data *dock = 660 + container_of(work, struct tf103c_dock_data, hpd_work.work); 661 + 662 + if (gpiod_get_value(dock->hpd_gpio)) 663 + tf103c_dock_enable(dock); 664 + else 665 + tf103c_dock_disable(dock); 666 + } 667 + 668 + static irqreturn_t tf103c_dock_hpd_irq(int irq, void *data) 669 + { 670 + struct tf103c_dock_data *dock = data; 671 + 672 + mod_delayed_work(system_long_wq, &dock->hpd_work, TF103C_DOCK_HPD_DEBOUNCE); 673 + return IRQ_HANDLED; 674 + } 675 + 676 + static void tf103c_dock_start_hpd(struct tf103c_dock_data *dock) 677 + { 678 + enable_irq(dock->hpd_irq); 679 + /* Sync current HPD status */ 680 + queue_delayed_work(system_long_wq, &dock->hpd_work, TF103C_DOCK_HPD_DEBOUNCE); 681 + } 682 + 683 + static void tf103c_dock_stop_hpd(struct tf103c_dock_data *dock) 684 + { 685 + disable_irq(dock->hpd_irq); 686 + cancel_delayed_work_sync(&dock->hpd_work); 687 + } 688 + 689 + /*** probe ***/ 690 + 691 + static const struct dmi_system_id tf103c_dock_dmi_ids[] = { 692 + { 693 + .matches = { 694 + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 695 + DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), 696 + }, 697 + }, 698 + { } 699 + }; 700 + 701 + static void tf103c_dock_non_devm_cleanup(void *data) 702 + { 703 + struct tf103c_dock_data *dock = data; 704 + 705 + if (dock->tp_irq_domain) 706 + irq_domain_remove(dock->tp_irq_domain); 707 + 708 + if (!IS_ERR_OR_NULL(dock->hid)) 709 + hid_destroy_device(dock->hid); 710 + 711 + i2c_unregister_device(dock->kbd_client); 712 + i2c_unregister_device(dock->intr_client); 713 + gpiod_remove_lookup_table(&tf103c_dock_gpios); 714 + } 715 + 716 + static int tf103c_dock_probe(struct i2c_client *client) 717 + { 718 + struct i2c_board_info board_info = { }; 719 + struct device *dev = &client->dev; 720 + struct gpio_desc *board_rev_gpio; 721 + struct tf103c_dock_data *dock; 722 + enum gpiod_flags flags; 723 + int i, ret; 724 + 725 + /* GPIOs are hardcoded for the Asus TF103C, don't bind on other devs */ 726 + if (!dmi_check_system(tf103c_dock_dmi_ids)) 727 + return -ENODEV; 728 + 729 + dock = devm_kzalloc(dev, sizeof(*dock), GFP_KERNEL); 730 + if (!dock) 731 + return -ENOMEM; 732 + 733 + INIT_DELAYED_WORK(&dock->hpd_work, tf103c_dock_hpd_work); 734 + 735 + /* 1. Get GPIOs and their IRQs */ 736 + gpiod_add_lookup_table(&tf103c_dock_gpios); 737 + 738 + ret = devm_add_action_or_reset(dev, tf103c_dock_non_devm_cleanup, dock); 739 + if (ret) 740 + return ret; 741 + 742 + /* 743 + * The pin is configured as input by default, use ASIS because otherwise 744 + * the gpio-crystalcove.c switches off the internal pull-down replacing 745 + * it with a pull-up. 746 + */ 747 + board_rev_gpio = gpiod_get(dev, "board_rev", GPIOD_ASIS); 748 + if (IS_ERR(board_rev_gpio)) 749 + return dev_err_probe(dev, PTR_ERR(board_rev_gpio), "requesting board_rev GPIO\n"); 750 + dock->board_rev = gpiod_get_value_cansleep(board_rev_gpio) + 1; 751 + gpiod_put(board_rev_gpio); 752 + 753 + /* 754 + * The Android driver drives the dock-pwr-en pin high at probe for 755 + * revision 2 boards and then never touches it again? 756 + * This code has only been tested on a revision 1 board, so for now 757 + * just mimick what Android does on revision 2 boards. 758 + */ 759 + flags = (dock->board_rev == 2) ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; 760 + dock->pwr_en = devm_gpiod_get(dev, "dock_pwr_en", flags); 761 + if (IS_ERR(dock->pwr_en)) 762 + return dev_err_probe(dev, PTR_ERR(dock->pwr_en), "requesting pwr_en GPIO\n"); 763 + 764 + dock->irq_gpio = devm_gpiod_get(dev, "dock_irq", GPIOD_IN); 765 + if (IS_ERR(dock->irq_gpio)) 766 + return dev_err_probe(dev, PTR_ERR(dock->irq_gpio), "requesting IRQ GPIO\n"); 767 + 768 + dock->irq = gpiod_to_irq(dock->irq_gpio); 769 + if (dock->irq < 0) 770 + return dev_err_probe(dev, dock->irq, "getting dock IRQ"); 771 + 772 + ret = devm_request_threaded_irq(dev, dock->irq, NULL, tf103c_dock_irq, 773 + IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_NO_AUTOEN, 774 + "dock_irq", dock); 775 + if (ret) 776 + return dev_err_probe(dev, ret, "requesting dock IRQ"); 777 + 778 + dock->hpd_gpio = devm_gpiod_get(dev, "dock_hpd", GPIOD_IN); 779 + if (IS_ERR(dock->hpd_gpio)) 780 + return dev_err_probe(dev, PTR_ERR(dock->hpd_gpio), "requesting HPD GPIO\n"); 781 + 782 + dock->hpd_irq = gpiod_to_irq(dock->hpd_gpio); 783 + if (dock->hpd_irq < 0) 784 + return dev_err_probe(dev, dock->hpd_irq, "getting HPD IRQ"); 785 + 786 + ret = devm_request_irq(dev, dock->hpd_irq, tf103c_dock_hpd_irq, 787 + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN, 788 + "dock_hpd", dock); 789 + if (ret) 790 + return ret; 791 + 792 + /* 793 + * 2. Create I2C clients. The dock uses 4 different i2c addresses, 794 + * the ACPI NPCE69A node being probed points to the EC address. 795 + */ 796 + dock->ec_client = client; 797 + 798 + strscpy(board_info.type, "tf103c-dock-intr", I2C_NAME_SIZE); 799 + board_info.addr = TF103C_DOCK_INTR_ADDR; 800 + board_info.dev_name = TF103C_DOCK_DEV_NAME "-intr"; 801 + 802 + dock->intr_client = i2c_new_client_device(client->adapter, &board_info); 803 + if (IS_ERR(dock->intr_client)) 804 + return dev_err_probe(dev, PTR_ERR(dock->intr_client), "creating intr client\n"); 805 + 806 + strscpy(board_info.type, "tf103c-dock-kbd", I2C_NAME_SIZE); 807 + board_info.addr = TF103C_DOCK_KBD_ADDR; 808 + board_info.dev_name = TF103C_DOCK_DEV_NAME "-kbd"; 809 + 810 + dock->kbd_client = i2c_new_client_device(client->adapter, &board_info); 811 + if (IS_ERR(dock->kbd_client)) 812 + return dev_err_probe(dev, PTR_ERR(dock->kbd_client), "creating kbd client\n"); 813 + 814 + /* 3. Create input_dev for the top row of the keyboard */ 815 + dock->input = devm_input_allocate_device(dev); 816 + if (!dock->input) 817 + return -ENOMEM; 818 + 819 + dock->input->name = "Asus TF103C Dock Top Row Keys"; 820 + dock->input->phys = dev_name(dev); 821 + dock->input->dev.parent = dev; 822 + dock->input->id.bustype = BUS_I2C; 823 + dock->input->id.vendor = /* USB_VENDOR_ID_ASUSTEK */ 824 + dock->input->id.product = /* From TF-103-C */ 825 + dock->input->id.version = 0x0100; /* 1.0 */ 826 + 827 + for (i = 0; i < ARRAY_SIZE(tf103c_dock_toprow_codes); i++) { 828 + input_set_capability(dock->input, EV_KEY, tf103c_dock_toprow_codes[i][0]); 829 + input_set_capability(dock->input, EV_KEY, tf103c_dock_toprow_codes[i][1]); 830 + } 831 + input_set_capability(dock->input, EV_KEY, KEY_RIGHTALT); 832 + 833 + ret = input_register_device(dock->input); 834 + if (ret) 835 + return ret; 836 + 837 + /* 4. Create HID device for the keyboard */ 838 + dock->hid = hid_allocate_device(); 839 + if (IS_ERR(dock->hid)) 840 + return dev_err_probe(dev, PTR_ERR(dock->hid), "allocating hid dev\n"); 841 + 842 + dock->hid->driver_data = dock; 843 + dock->hid->ll_driver = &tf103c_dock_hid_ll_driver; 844 + dock->hid->dev.parent = &client->dev; 845 + dock->hid->bus = BUS_I2C; 846 + dock->hid->vendor = 0x0b05; /* USB_VENDOR_ID_ASUSTEK */ 847 + dock->hid->product = 0x0103; /* From TF-103-C */ 848 + dock->hid->version = 0x0100; /* 1.0 */ 849 + strscpy(dock->hid->name, "Asus TF103C Dock Keyboard", sizeof(dock->hid->name)); 850 + strscpy(dock->hid->phys, dev_name(dev), sizeof(dock->hid->phys)); 851 + 852 + ret = hid_add_device(dock->hid); 853 + if (ret) 854 + return dev_err_probe(dev, ret, "adding hid dev\n"); 855 + 856 + /* 5. Setup irqchip for touchpad IRQ pass-through */ 857 + dock->tp_irqchip.name = KBUILD_MODNAME; 858 + 859 + dock->tp_irq_domain = irq_domain_add_linear(NULL, 1, &irq_domain_simple_ops, NULL); 860 + if (!dock->tp_irq_domain) 861 + return -ENOMEM; 862 + 863 + dock->tp_irq = irq_create_mapping(dock->tp_irq_domain, 0); 864 + if (!dock->tp_irq) 865 + return -ENOMEM; 866 + 867 + irq_set_chip_data(dock->tp_irq, dock); 868 + irq_set_chip_and_handler(dock->tp_irq, &dock->tp_irqchip, handle_simple_irq); 869 + irq_set_nested_thread(dock->tp_irq, true); 870 + irq_set_noprobe(dock->tp_irq); 871 + 872 + dev_info(dev, "Asus TF103C board-revision: %d\n", dock->board_rev); 873 + 874 + tf103c_dock_start_hpd(dock); 875 + 876 + device_init_wakeup(dev, true); 877 + i2c_set_clientdata(client, dock); 878 + return 0; 879 + } 880 + 881 + static int tf103c_dock_remove(struct i2c_client *client) 882 + { 883 + struct tf103c_dock_data *dock = i2c_get_clientdata(client); 884 + 885 + tf103c_dock_stop_hpd(dock); 886 + tf103c_dock_disable(dock); 887 + 888 + return 0; 889 + } 890 + 891 + static int __maybe_unused tf103c_dock_suspend(struct device *dev) 892 + { 893 + struct tf103c_dock_data *dock = dev_get_drvdata(dev); 894 + 895 + tf103c_dock_stop_hpd(dock); 896 + 897 + if (dock->enabled) { 898 + tf103c_dock_ec_cmd(dock, tf103c_dock_suspend_cmd); 899 + 900 + if (device_may_wakeup(dev)) 901 + enable_irq_wake(dock->irq); 902 + } 903 + 904 + return 0; 905 + } 906 + 907 + static int __maybe_unused tf103c_dock_resume(struct device *dev) 908 + { 909 + struct tf103c_dock_data *dock = dev_get_drvdata(dev); 910 + 911 + if (dock->enabled) { 912 + if (device_may_wakeup(dev)) 913 + disable_irq_wake(dock->irq); 914 + 915 + /* Don't try to resume if the dock was unplugged during suspend */ 916 + if (gpiod_get_value(dock->hpd_gpio)) 917 + tf103c_dock_ec_cmd(dock, tf103c_dock_enable_cmd); 918 + } 919 + 920 + tf103c_dock_start_hpd(dock); 921 + return 0; 922 + } 923 + 924 + SIMPLE_DEV_PM_OPS(tf103c_dock_pm_ops, tf103c_dock_suspend, tf103c_dock_resume); 925 + 926 + static const struct acpi_device_id tf103c_dock_acpi_match[] = { 927 + {"NPCE69A"}, 928 + { } 929 + }; 930 + MODULE_DEVICE_TABLE(acpi, tf103c_dock_acpi_match); 931 + 932 + static struct i2c_driver tf103c_dock_driver = { 933 + .driver = { 934 + .name = "asus-tf103c-dock", 935 + .pm = &tf103c_dock_pm_ops, 936 + .acpi_match_table = tf103c_dock_acpi_match, 937 + }, 938 + .probe_new = tf103c_dock_probe, 939 + .remove = tf103c_dock_remove, 940 + }; 941 + module_i2c_driver(tf103c_dock_driver); 942 + 943 + MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com"); 944 + MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver"); 945 + MODULE_LICENSE("GPL");
+584 -29
drivers/platform/x86/asus-wmi.c
··· 13 13 14 14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 15 16 - #include <linux/kernel.h> 17 - #include <linux/module.h> 18 - #include <linux/init.h> 19 - #include <linux/types.h> 20 - #include <linux/slab.h> 21 - #include <linux/input.h> 22 - #include <linux/input/sparse-keymap.h> 23 - #include <linux/fb.h> 16 + #include <linux/acpi.h> 24 17 #include <linux/backlight.h> 25 - #include <linux/leds.h> 26 - #include <linux/rfkill.h> 27 - #include <linux/pci.h> 28 - #include <linux/pci_hotplug.h> 29 - #include <linux/platform_profile.h> 30 - #include <linux/power_supply.h> 18 + #include <linux/debugfs.h> 19 + #include <linux/dmi.h> 20 + #include <linux/fb.h> 31 21 #include <linux/hwmon.h> 32 22 #include <linux/hwmon-sysfs.h> 33 - #include <linux/debugfs.h> 34 - #include <linux/seq_file.h> 23 + #include <linux/init.h> 24 + #include <linux/input.h> 25 + #include <linux/input/sparse-keymap.h> 26 + #include <linux/kernel.h> 27 + #include <linux/leds.h> 28 + #include <linux/module.h> 29 + #include <linux/pci.h> 30 + #include <linux/pci_hotplug.h> 35 31 #include <linux/platform_data/x86/asus-wmi.h> 36 32 #include <linux/platform_device.h> 37 - #include <linux/acpi.h> 38 - #include <linux/dmi.h> 33 + #include <linux/platform_profile.h> 34 + #include <linux/power_supply.h> 35 + #include <linux/rfkill.h> 36 + #include <linux/seq_file.h> 37 + #include <linux/slab.h> 38 + #include <linux/types.h> 39 39 #include <linux/units.h> 40 40 41 41 #include <acpi/battery.h> ··· 43 43 44 44 #include "asus-wmi.h" 45 45 46 - MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>, " 47 - "Yong Wang <yong.y.wang@intel.com>"); 46 + MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>"); 47 + MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); 48 48 MODULE_DESCRIPTION("Asus Generic WMI Driver"); 49 49 MODULE_LICENSE("GPL"); 50 50 ··· 106 106 107 107 #define WMI_EVENT_MASK 0xFFFF 108 108 109 + #define FAN_CURVE_POINTS 8 110 + #define FAN_CURVE_BUF_LEN (FAN_CURVE_POINTS * 2) 111 + #define FAN_CURVE_DEV_CPU 0x00 112 + #define FAN_CURVE_DEV_GPU 0x01 113 + /* Mask to determine if setting temperature or percentage */ 114 + #define FAN_CURVE_PWM_MASK 0x04 115 + 109 116 static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; 117 + 118 + static int throttle_thermal_policy_write(struct asus_wmi *); 110 119 111 120 static bool ashs_present(void) 112 121 { ··· 131 122 u32 arg0; 132 123 u32 arg1; 133 124 u32 arg2; /* At least TUF Gaming series uses 3 dword input buffer. */ 134 - u32 arg4; 125 + u32 arg3; 126 + u32 arg4; /* Some ROG laptops require a full 5 input args */ 135 127 u32 arg5; 136 128 } __packed; 137 129 ··· 183 173 FAN_TYPE_SPEC83, /* starting in Spec 8.3, use CPU_FAN_CTRL */ 184 174 }; 185 175 176 + struct fan_curve_data { 177 + bool enabled; 178 + u32 device_id; 179 + u8 temps[FAN_CURVE_POINTS]; 180 + u8 percents[FAN_CURVE_POINTS]; 181 + }; 182 + 186 183 struct asus_wmi { 187 184 int dsts_id; 188 185 int spec; ··· 236 219 237 220 bool throttle_thermal_policy_available; 238 221 u8 throttle_thermal_policy_mode; 222 + 223 + bool cpu_fan_curve_available; 224 + bool gpu_fan_curve_available; 225 + struct fan_curve_data custom_fan_curves[2]; 239 226 240 227 struct platform_profile_handler platform_profile_handler; 241 228 bool platform_profile_support; ··· 305 284 return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval); 306 285 } 307 286 EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method); 287 + 288 + static int asus_wmi_evaluate_method5(u32 method_id, 289 + u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval) 290 + { 291 + struct bios_args args = { 292 + .arg0 = arg0, 293 + .arg1 = arg1, 294 + .arg2 = arg2, 295 + .arg3 = arg3, 296 + .arg4 = arg4, 297 + }; 298 + struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; 299 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 300 + acpi_status status; 301 + union acpi_object *obj; 302 + u32 tmp = 0; 303 + 304 + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, 305 + &input, &output); 306 + 307 + if (ACPI_FAILURE(status)) 308 + return -EIO; 309 + 310 + obj = (union acpi_object *)output.pointer; 311 + if (obj && obj->type == ACPI_TYPE_INTEGER) 312 + tmp = (u32) obj->integer.value; 313 + 314 + if (retval) 315 + *retval = tmp; 316 + 317 + kfree(obj); 318 + 319 + if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) 320 + return -ENODEV; 321 + 322 + return 0; 323 + } 324 + 325 + /* 326 + * Returns as an error if the method output is not a buffer. Typically this 327 + * means that the method called is unsupported. 328 + */ 329 + static int asus_wmi_evaluate_method_buf(u32 method_id, 330 + u32 arg0, u32 arg1, u8 *ret_buffer, size_t size) 331 + { 332 + struct bios_args args = { 333 + .arg0 = arg0, 334 + .arg1 = arg1, 335 + .arg2 = 0, 336 + }; 337 + struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; 338 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 339 + acpi_status status; 340 + union acpi_object *obj; 341 + int err = 0; 342 + 343 + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, 344 + &input, &output); 345 + 346 + if (ACPI_FAILURE(status)) 347 + return -EIO; 348 + 349 + obj = (union acpi_object *)output.pointer; 350 + 351 + switch (obj->type) { 352 + case ACPI_TYPE_BUFFER: 353 + if (obj->buffer.length > size) 354 + err = -ENOSPC; 355 + if (obj->buffer.length == 0) 356 + err = -ENODATA; 357 + 358 + memcpy(ret_buffer, obj->buffer.pointer, obj->buffer.length); 359 + break; 360 + case ACPI_TYPE_INTEGER: 361 + err = (u32)obj->integer.value; 362 + 363 + if (err == ASUS_WMI_UNSUPPORTED_METHOD) 364 + err = -ENODEV; 365 + /* 366 + * At least one method returns a 0 with no buffer if no arg 367 + * is provided, such as ASUS_WMI_DEVID_CPU_FAN_CURVE 368 + */ 369 + if (err == 0) 370 + err = -ENODATA; 371 + break; 372 + default: 373 + err = -ENODATA; 374 + break; 375 + } 376 + 377 + kfree(obj); 378 + 379 + if (err) 380 + return err; 381 + 382 + return 0; 383 + } 308 384 309 385 static int asus_wmi_evaluate_method_agfn(const struct acpi_buffer args) 310 386 { ··· 1154 1036 absent = (l == 0xffffffff); 1155 1037 1156 1038 if (blocked != absent) { 1157 - pr_warn("BIOS says wireless lan is %s, " 1158 - "but the pci device is %s\n", 1039 + pr_warn("BIOS says wireless lan is %s, but the pci device is %s\n", 1159 1040 blocked ? "blocked" : "unblocked", 1160 1041 absent ? "absent" : "present"); 1161 - pr_warn("skipped wireless hotplug as probably " 1162 - "inappropriate for this model\n"); 1042 + pr_warn("skipped wireless hotplug as probably inappropriate for this model\n"); 1163 1043 goto out_unlock; 1164 1044 } 1165 1045 ··· 1922 1806 } 1923 1807 1924 1808 asus->fan_pwm_mode = state; 1809 + 1810 + /* Must set to disabled if mode is toggled */ 1811 + if (asus->cpu_fan_curve_available) 1812 + asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; 1813 + if (asus->gpu_fan_curve_available) 1814 + asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; 1815 + 1925 1816 return count; 1926 1817 } 1927 1818 ··· 2076 1953 2077 1954 static int fan_boost_mode_write(struct asus_wmi *asus) 2078 1955 { 2079 - int err; 2080 - u8 value; 2081 1956 u32 retval; 1957 + u8 value; 1958 + int err; 2082 1959 2083 1960 value = asus->fan_boost_mode; 2084 1961 ··· 2136 2013 struct device_attribute *attr, 2137 2014 const char *buf, size_t count) 2138 2015 { 2139 - int result; 2140 - u8 new_mode; 2141 2016 struct asus_wmi *asus = dev_get_drvdata(dev); 2142 2017 u8 mask = asus->fan_boost_mode_mask; 2018 + u8 new_mode; 2019 + int result; 2143 2020 2144 2021 result = kstrtou8(buf, 10, &new_mode); 2145 2022 if (result < 0) { ··· 2165 2042 2166 2043 // Fan boost mode: 0 - normal, 1 - overboost, 2 - silent 2167 2044 static DEVICE_ATTR_RW(fan_boost_mode); 2045 + 2046 + /* Custom fan curves **********************************************************/ 2047 + 2048 + static void fan_curve_copy_from_buf(struct fan_curve_data *data, u8 *buf) 2049 + { 2050 + int i; 2051 + 2052 + for (i = 0; i < FAN_CURVE_POINTS; i++) { 2053 + data->temps[i] = buf[i]; 2054 + } 2055 + 2056 + for (i = 0; i < FAN_CURVE_POINTS; i++) { 2057 + data->percents[i] = 2058 + 255 * buf[i + FAN_CURVE_POINTS] / 100; 2059 + } 2060 + } 2061 + 2062 + static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) 2063 + { 2064 + struct fan_curve_data *curves; 2065 + u8 buf[FAN_CURVE_BUF_LEN]; 2066 + int fan_idx = 0; 2067 + u8 mode = 0; 2068 + int err; 2069 + 2070 + if (asus->throttle_thermal_policy_available) 2071 + mode = asus->throttle_thermal_policy_mode; 2072 + /* DEVID_<C/G>PU_FAN_CURVE is switched for OVERBOOST vs SILENT */ 2073 + if (mode == 2) 2074 + mode = 1; 2075 + else if (mode == 1) 2076 + mode = 2; 2077 + 2078 + if (fan_dev == ASUS_WMI_DEVID_GPU_FAN_CURVE) 2079 + fan_idx = FAN_CURVE_DEV_GPU; 2080 + 2081 + curves = &asus->custom_fan_curves[fan_idx]; 2082 + err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf, 2083 + FAN_CURVE_BUF_LEN); 2084 + if (err) 2085 + return err; 2086 + 2087 + fan_curve_copy_from_buf(curves, buf); 2088 + curves->device_id = fan_dev; 2089 + 2090 + return 0; 2091 + } 2092 + 2093 + /* Check if capability exists, and populate defaults */ 2094 + static int fan_curve_check_present(struct asus_wmi *asus, bool *available, 2095 + u32 fan_dev) 2096 + { 2097 + int err; 2098 + 2099 + *available = false; 2100 + 2101 + err = fan_curve_get_factory_default(asus, fan_dev); 2102 + if (err) { 2103 + if (err == -ENODEV) 2104 + return 0; 2105 + return err; 2106 + } 2107 + 2108 + *available = true; 2109 + return 0; 2110 + } 2111 + 2112 + /* Determine which fan the attribute is for if SENSOR_ATTR */ 2113 + static struct fan_curve_data *fan_curve_attr_select(struct asus_wmi *asus, 2114 + struct device_attribute *attr) 2115 + { 2116 + int index = to_sensor_dev_attr(attr)->index; 2117 + 2118 + return &asus->custom_fan_curves[index & FAN_CURVE_DEV_GPU]; 2119 + } 2120 + 2121 + /* Determine which fan the attribute is for if SENSOR_ATTR_2 */ 2122 + static struct fan_curve_data *fan_curve_attr_2_select(struct asus_wmi *asus, 2123 + struct device_attribute *attr) 2124 + { 2125 + int nr = to_sensor_dev_attr_2(attr)->nr; 2126 + 2127 + return &asus->custom_fan_curves[nr & FAN_CURVE_DEV_GPU]; 2128 + } 2129 + 2130 + static ssize_t fan_curve_show(struct device *dev, 2131 + struct device_attribute *attr, char *buf) 2132 + { 2133 + struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr); 2134 + struct asus_wmi *asus = dev_get_drvdata(dev); 2135 + struct fan_curve_data *data; 2136 + int value, index, nr; 2137 + 2138 + data = fan_curve_attr_2_select(asus, attr); 2139 + index = dev_attr->index; 2140 + nr = dev_attr->nr; 2141 + 2142 + if (nr & FAN_CURVE_PWM_MASK) 2143 + value = data->percents[index]; 2144 + else 2145 + value = data->temps[index]; 2146 + 2147 + return sysfs_emit(buf, "%d\n", value); 2148 + } 2149 + 2150 + /* 2151 + * "fan_dev" is the related WMI method such as ASUS_WMI_DEVID_CPU_FAN_CURVE. 2152 + */ 2153 + static int fan_curve_write(struct asus_wmi *asus, 2154 + struct fan_curve_data *data) 2155 + { 2156 + u32 arg1 = 0, arg2 = 0, arg3 = 0, arg4 = 0; 2157 + u8 *percents = data->percents; 2158 + u8 *temps = data->temps; 2159 + int ret, i, shift = 0; 2160 + 2161 + if (!data->enabled) 2162 + return 0; 2163 + 2164 + for (i = 0; i < FAN_CURVE_POINTS / 2; i++) { 2165 + arg1 += (temps[i]) << shift; 2166 + arg2 += (temps[i + 4]) << shift; 2167 + /* Scale to percentage for device */ 2168 + arg3 += (100 * percents[i] / 255) << shift; 2169 + arg4 += (100 * percents[i + 4] / 255) << shift; 2170 + shift += 8; 2171 + } 2172 + 2173 + return asus_wmi_evaluate_method5(ASUS_WMI_METHODID_DEVS, 2174 + data->device_id, 2175 + arg1, arg2, arg3, arg4, &ret); 2176 + } 2177 + 2178 + static ssize_t fan_curve_store(struct device *dev, 2179 + struct device_attribute *attr, const char *buf, 2180 + size_t count) 2181 + { 2182 + struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr); 2183 + struct asus_wmi *asus = dev_get_drvdata(dev); 2184 + struct fan_curve_data *data; 2185 + u8 value; 2186 + int err; 2187 + 2188 + int pwm = dev_attr->nr & FAN_CURVE_PWM_MASK; 2189 + int index = dev_attr->index; 2190 + 2191 + data = fan_curve_attr_2_select(asus, attr); 2192 + 2193 + err = kstrtou8(buf, 10, &value); 2194 + if (err < 0) 2195 + return err; 2196 + 2197 + if (pwm) { 2198 + data->percents[index] = value; 2199 + } else { 2200 + data->temps[index] = value; 2201 + } 2202 + 2203 + /* 2204 + * Mark as disabled so the user has to explicitly enable to apply a 2205 + * changed fan curve. This prevents potential lockups from writing out 2206 + * many changes as one-write-per-change. 2207 + */ 2208 + data->enabled = false; 2209 + 2210 + return count; 2211 + } 2212 + 2213 + static ssize_t fan_curve_enable_show(struct device *dev, 2214 + struct device_attribute *attr, char *buf) 2215 + { 2216 + struct asus_wmi *asus = dev_get_drvdata(dev); 2217 + struct fan_curve_data *data; 2218 + int out = 2; 2219 + 2220 + data = fan_curve_attr_select(asus, attr); 2221 + 2222 + if (data->enabled) 2223 + out = 1; 2224 + 2225 + return sysfs_emit(buf, "%d\n", out); 2226 + } 2227 + 2228 + static ssize_t fan_curve_enable_store(struct device *dev, 2229 + struct device_attribute *attr, 2230 + const char *buf, size_t count) 2231 + { 2232 + struct asus_wmi *asus = dev_get_drvdata(dev); 2233 + struct fan_curve_data *data; 2234 + int value, err; 2235 + 2236 + data = fan_curve_attr_select(asus, attr); 2237 + 2238 + err = kstrtoint(buf, 10, &value); 2239 + if (err < 0) 2240 + return err; 2241 + 2242 + switch (value) { 2243 + case 1: 2244 + data->enabled = true; 2245 + break; 2246 + case 2: 2247 + data->enabled = false; 2248 + break; 2249 + /* 2250 + * Auto + reset the fan curve data to defaults. Make it an explicit 2251 + * option so that users don't accidentally overwrite a set fan curve. 2252 + */ 2253 + case 3: 2254 + err = fan_curve_get_factory_default(asus, data->device_id); 2255 + if (err) 2256 + return err; 2257 + data->enabled = false; 2258 + break; 2259 + default: 2260 + return -EINVAL; 2261 + } 2262 + 2263 + if (data->enabled) { 2264 + err = fan_curve_write(asus, data); 2265 + if (err) 2266 + return err; 2267 + } else { 2268 + /* 2269 + * For machines with throttle this is the only way to reset fans 2270 + * to default mode of operation (does not erase curve data). 2271 + */ 2272 + if (asus->throttle_thermal_policy_available) { 2273 + err = throttle_thermal_policy_write(asus); 2274 + if (err) 2275 + return err; 2276 + /* Similar is true for laptops with this fan */ 2277 + } else if (asus->fan_type == FAN_TYPE_SPEC83) { 2278 + err = asus_fan_set_auto(asus); 2279 + if (err) 2280 + return err; 2281 + } else { 2282 + /* Safeguard against fautly ACPI tables */ 2283 + err = fan_curve_get_factory_default(asus, data->device_id); 2284 + if (err) 2285 + return err; 2286 + err = fan_curve_write(asus, data); 2287 + if (err) 2288 + return err; 2289 + } 2290 + } 2291 + return count; 2292 + } 2293 + 2294 + /* CPU */ 2295 + static SENSOR_DEVICE_ATTR_RW(pwm1_enable, fan_curve_enable, FAN_CURVE_DEV_CPU); 2296 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point1_temp, fan_curve, 2297 + FAN_CURVE_DEV_CPU, 0); 2298 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point2_temp, fan_curve, 2299 + FAN_CURVE_DEV_CPU, 1); 2300 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point3_temp, fan_curve, 2301 + FAN_CURVE_DEV_CPU, 2); 2302 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point4_temp, fan_curve, 2303 + FAN_CURVE_DEV_CPU, 3); 2304 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point5_temp, fan_curve, 2305 + FAN_CURVE_DEV_CPU, 4); 2306 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point6_temp, fan_curve, 2307 + FAN_CURVE_DEV_CPU, 5); 2308 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point7_temp, fan_curve, 2309 + FAN_CURVE_DEV_CPU, 6); 2310 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point8_temp, fan_curve, 2311 + FAN_CURVE_DEV_CPU, 7); 2312 + 2313 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point1_pwm, fan_curve, 2314 + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 0); 2315 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point2_pwm, fan_curve, 2316 + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 1); 2317 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point3_pwm, fan_curve, 2318 + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 2); 2319 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point4_pwm, fan_curve, 2320 + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 3); 2321 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point5_pwm, fan_curve, 2322 + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 4); 2323 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point6_pwm, fan_curve, 2324 + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 5); 2325 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point7_pwm, fan_curve, 2326 + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 6); 2327 + static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point8_pwm, fan_curve, 2328 + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 7); 2329 + 2330 + /* GPU */ 2331 + static SENSOR_DEVICE_ATTR_RW(pwm2_enable, fan_curve_enable, FAN_CURVE_DEV_GPU); 2332 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point1_temp, fan_curve, 2333 + FAN_CURVE_DEV_GPU, 0); 2334 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point2_temp, fan_curve, 2335 + FAN_CURVE_DEV_GPU, 1); 2336 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point3_temp, fan_curve, 2337 + FAN_CURVE_DEV_GPU, 2); 2338 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point4_temp, fan_curve, 2339 + FAN_CURVE_DEV_GPU, 3); 2340 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point5_temp, fan_curve, 2341 + FAN_CURVE_DEV_GPU, 4); 2342 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point6_temp, fan_curve, 2343 + FAN_CURVE_DEV_GPU, 5); 2344 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_temp, fan_curve, 2345 + FAN_CURVE_DEV_GPU, 6); 2346 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_temp, fan_curve, 2347 + FAN_CURVE_DEV_GPU, 7); 2348 + 2349 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point1_pwm, fan_curve, 2350 + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 0); 2351 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point2_pwm, fan_curve, 2352 + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 1); 2353 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point3_pwm, fan_curve, 2354 + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 2); 2355 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point4_pwm, fan_curve, 2356 + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 3); 2357 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point5_pwm, fan_curve, 2358 + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 4); 2359 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point6_pwm, fan_curve, 2360 + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 5); 2361 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_pwm, fan_curve, 2362 + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 6); 2363 + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_pwm, fan_curve, 2364 + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7); 2365 + 2366 + static struct attribute *asus_fan_curve_attr[] = { 2367 + /* CPU */ 2368 + &sensor_dev_attr_pwm1_enable.dev_attr.attr, 2369 + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, 2370 + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, 2371 + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, 2372 + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, 2373 + &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, 2374 + &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr, 2375 + &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr, 2376 + &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr, 2377 + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, 2378 + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, 2379 + &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, 2380 + &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, 2381 + &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, 2382 + &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr, 2383 + &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr, 2384 + &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr, 2385 + /* GPU */ 2386 + &sensor_dev_attr_pwm2_enable.dev_attr.attr, 2387 + &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, 2388 + &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, 2389 + &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, 2390 + &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr, 2391 + &sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr, 2392 + &sensor_dev_attr_pwm2_auto_point6_temp.dev_attr.attr, 2393 + &sensor_dev_attr_pwm2_auto_point7_temp.dev_attr.attr, 2394 + &sensor_dev_attr_pwm2_auto_point8_temp.dev_attr.attr, 2395 + &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, 2396 + &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, 2397 + &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr, 2398 + &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr, 2399 + &sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr, 2400 + &sensor_dev_attr_pwm2_auto_point6_pwm.dev_attr.attr, 2401 + &sensor_dev_attr_pwm2_auto_point7_pwm.dev_attr.attr, 2402 + &sensor_dev_attr_pwm2_auto_point8_pwm.dev_attr.attr, 2403 + NULL 2404 + }; 2405 + 2406 + static umode_t asus_fan_curve_is_visible(struct kobject *kobj, 2407 + struct attribute *attr, int idx) 2408 + { 2409 + struct device *dev = container_of(kobj, struct device, kobj); 2410 + struct asus_wmi *asus = dev_get_drvdata(dev->parent); 2411 + 2412 + /* 2413 + * Check the char instead of casting attr as there are two attr types 2414 + * involved here (attr1 and attr2) 2415 + */ 2416 + if (asus->cpu_fan_curve_available && attr->name[3] == '1') 2417 + return 0644; 2418 + 2419 + if (asus->gpu_fan_curve_available && attr->name[3] == '2') 2420 + return 0644; 2421 + 2422 + return 0; 2423 + } 2424 + 2425 + static const struct attribute_group asus_fan_curve_attr_group = { 2426 + .is_visible = asus_fan_curve_is_visible, 2427 + .attrs = asus_fan_curve_attr, 2428 + }; 2429 + __ATTRIBUTE_GROUPS(asus_fan_curve_attr); 2430 + 2431 + /* 2432 + * Must be initialised after throttle_thermal_policy_check_present() as 2433 + * we check the status of throttle_thermal_policy_available during init. 2434 + */ 2435 + static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) 2436 + { 2437 + struct device *dev = &asus->platform_device->dev; 2438 + struct device *hwmon; 2439 + int err; 2440 + 2441 + err = fan_curve_check_present(asus, &asus->cpu_fan_curve_available, 2442 + ASUS_WMI_DEVID_CPU_FAN_CURVE); 2443 + if (err) 2444 + return err; 2445 + 2446 + err = fan_curve_check_present(asus, &asus->gpu_fan_curve_available, 2447 + ASUS_WMI_DEVID_GPU_FAN_CURVE); 2448 + if (err) 2449 + return err; 2450 + 2451 + if (!asus->cpu_fan_curve_available && !asus->gpu_fan_curve_available) 2452 + return 0; 2453 + 2454 + hwmon = devm_hwmon_device_register_with_groups( 2455 + dev, "asus_custom_fan_curve", asus, asus_fan_curve_attr_groups); 2456 + 2457 + if (IS_ERR(hwmon)) { 2458 + dev_err(dev, 2459 + "Could not register asus_custom_fan_curve device\n"); 2460 + return PTR_ERR(hwmon); 2461 + } 2462 + 2463 + return 0; 2464 + } 2168 2465 2169 2466 /* Throttle thermal policy ****************************************************/ 2170 2467 ··· 2634 2091 retval); 2635 2092 return -EIO; 2636 2093 } 2094 + 2095 + /* Must set to disabled if mode is toggled */ 2096 + if (asus->cpu_fan_curve_available) 2097 + asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; 2098 + if (asus->gpu_fan_curve_available) 2099 + asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; 2637 2100 2638 2101 return 0; 2639 2102 } ··· 3584 3035 if (err) 3585 3036 goto fail_hwmon; 3586 3037 3038 + err = asus_wmi_custom_fan_curve_init(asus); 3039 + if (err) 3040 + goto fail_custom_fan_curve; 3041 + 3587 3042 err = asus_wmi_led_init(asus); 3588 3043 if (err) 3589 3044 goto fail_leds; ··· 3659 3106 asus_wmi_sysfs_exit(asus->platform_device); 3660 3107 fail_sysfs: 3661 3108 fail_throttle_thermal_policy: 3109 + fail_custom_fan_curve: 3662 3110 fail_platform_profile_setup: 3663 3111 if (asus->platform_profile_support) 3664 3112 platform_profile_remove(); ··· 3685 3131 asus_wmi_debugfs_exit(asus); 3686 3132 asus_wmi_sysfs_exit(asus->platform_device); 3687 3133 asus_fan_set_auto(asus); 3134 + throttle_thermal_policy_set_default(asus); 3688 3135 asus_wmi_battery_exit(asus); 3689 3136 3690 3137 if (asus->platform_profile_support)
+4 -23
drivers/platform/x86/hp_accel.c
··· 355 355 return 0; 356 356 } 357 357 358 - #ifdef CONFIG_PM_SLEEP 359 - static int lis3lv02d_suspend(struct device *dev) 358 + static int __maybe_unused lis3lv02d_suspend(struct device *dev) 360 359 { 361 360 /* make sure the device is off when we suspend */ 362 361 lis3lv02d_poweroff(&lis3_dev); 363 362 return 0; 364 363 } 365 364 366 - static int lis3lv02d_resume(struct device *dev) 365 + static int __maybe_unused lis3lv02d_resume(struct device *dev) 367 366 { 368 367 lis3lv02d_poweron(&lis3_dev); 369 368 return 0; 370 369 } 371 370 372 - static int lis3lv02d_restore(struct device *dev) 373 - { 374 - lis3lv02d_poweron(&lis3_dev); 375 - return 0; 376 - } 377 - 378 - static const struct dev_pm_ops hp_accel_pm = { 379 - .suspend = lis3lv02d_suspend, 380 - .resume = lis3lv02d_resume, 381 - .freeze = lis3lv02d_suspend, 382 - .thaw = lis3lv02d_resume, 383 - .poweroff = lis3lv02d_suspend, 384 - .restore = lis3lv02d_restore, 385 - }; 386 - 387 - #define HP_ACCEL_PM (&hp_accel_pm) 388 - #else 389 - #define HP_ACCEL_PM NULL 390 - #endif 371 + static SIMPLE_DEV_PM_OPS(hp_accel_pm, lis3lv02d_suspend, lis3lv02d_resume); 391 372 392 373 /* For the HP MDPS aka 3D Driveguard */ 393 374 static struct platform_driver lis3lv02d_driver = { ··· 376 395 .remove = lis3lv02d_remove, 377 396 .driver = { 378 397 .name = "hp_accel", 379 - .pm = HP_ACCEL_PM, 398 + .pm = &hp_accel_pm, 380 399 .acpi_match_table = lis3lv02d_device_ids, 381 400 }, 382 401 };
+2
drivers/platform/x86/intel/Makefile
··· 30 30 # Intel PMIC / PMC / P-Unit drivers 31 31 intel_bxtwc_tmu-y := bxtwc_tmu.o 32 32 obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o 33 + intel_crystal_cove_charger-y := crystal_cove_charger.o 34 + obj-$(CONFIG_X86_ANDROID_TABLETS) += intel_crystal_cove_charger.o 33 35 intel_chtdc_ti_pwrbtn-y := chtdc_ti_pwrbtn.o 34 36 obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o 35 37 intel_mrfld_pwrbtn-y := mrfld_pwrbtn.o
+153
drivers/platform/x86/intel/crystal_cove_charger.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Driver for the external-charger IRQ pass-through function of the 4 + * Intel Bay Trail Crystal Cove PMIC. 5 + * 6 + * Note this is NOT a power_supply class driver, it just deals with IRQ 7 + * pass-through, this requires a separate driver because the PMIC's 8 + * level 2 interrupt for this must be explicitly acked. 9 + */ 10 + 11 + #include <linux/interrupt.h> 12 + #include <linux/irq.h> 13 + #include <linux/irqdomain.h> 14 + #include <linux/mfd/intel_soc_pmic.h> 15 + #include <linux/module.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/regmap.h> 18 + 19 + #define CHGRIRQ_REG 0x0a 20 + 21 + struct crystal_cove_charger_data { 22 + struct mutex buslock; /* irq_bus_lock */ 23 + struct irq_chip irqchip; 24 + struct regmap *regmap; 25 + struct irq_domain *irq_domain; 26 + int irq; 27 + int charger_irq; 28 + bool irq_enabled; 29 + bool irq_is_enabled; 30 + }; 31 + 32 + static irqreturn_t crystal_cove_charger_irq(int irq, void *data) 33 + { 34 + struct crystal_cove_charger_data *charger = data; 35 + 36 + /* No need to read CHGRIRQ_REG as there is only 1 IRQ */ 37 + handle_nested_irq(charger->charger_irq); 38 + 39 + /* Ack CHGRIRQ 0 */ 40 + regmap_write(charger->regmap, CHGRIRQ_REG, BIT(0)); 41 + 42 + return IRQ_HANDLED; 43 + } 44 + 45 + static void crystal_cove_charger_irq_bus_lock(struct irq_data *data) 46 + { 47 + struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data); 48 + 49 + mutex_lock(&charger->buslock); 50 + } 51 + 52 + static void crystal_cove_charger_irq_bus_sync_unlock(struct irq_data *data) 53 + { 54 + struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data); 55 + 56 + if (charger->irq_is_enabled != charger->irq_enabled) { 57 + if (charger->irq_enabled) 58 + enable_irq(charger->irq); 59 + else 60 + disable_irq(charger->irq); 61 + 62 + charger->irq_is_enabled = charger->irq_enabled; 63 + } 64 + 65 + mutex_unlock(&charger->buslock); 66 + } 67 + 68 + static void crystal_cove_charger_irq_unmask(struct irq_data *data) 69 + { 70 + struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data); 71 + 72 + charger->irq_enabled = true; 73 + } 74 + 75 + static void crystal_cove_charger_irq_mask(struct irq_data *data) 76 + { 77 + struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data); 78 + 79 + charger->irq_enabled = false; 80 + } 81 + 82 + static void crystal_cove_charger_rm_irq_domain(void *data) 83 + { 84 + struct crystal_cove_charger_data *charger = data; 85 + 86 + irq_domain_remove(charger->irq_domain); 87 + } 88 + 89 + static int crystal_cove_charger_probe(struct platform_device *pdev) 90 + { 91 + struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); 92 + struct crystal_cove_charger_data *charger; 93 + int ret; 94 + 95 + charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); 96 + if (!charger) 97 + return -ENOMEM; 98 + 99 + charger->regmap = pmic->regmap; 100 + mutex_init(&charger->buslock); 101 + 102 + charger->irq = platform_get_irq(pdev, 0); 103 + if (charger->irq < 0) 104 + return charger->irq; 105 + 106 + charger->irq_domain = irq_domain_create_linear(dev_fwnode(pdev->dev.parent), 1, 107 + &irq_domain_simple_ops, NULL); 108 + if (!charger->irq_domain) 109 + return -ENOMEM; 110 + 111 + /* Distuingish IRQ domain from others sharing (MFD) the same fwnode */ 112 + irq_domain_update_bus_token(charger->irq_domain, DOMAIN_BUS_WAKEUP); 113 + 114 + ret = devm_add_action_or_reset(&pdev->dev, crystal_cove_charger_rm_irq_domain, charger); 115 + if (ret) 116 + return ret; 117 + 118 + charger->charger_irq = irq_create_mapping(charger->irq_domain, 0); 119 + if (!charger->charger_irq) 120 + return -ENOMEM; 121 + 122 + charger->irqchip.name = KBUILD_MODNAME; 123 + charger->irqchip.irq_unmask = crystal_cove_charger_irq_unmask; 124 + charger->irqchip.irq_mask = crystal_cove_charger_irq_mask; 125 + charger->irqchip.irq_bus_lock = crystal_cove_charger_irq_bus_lock; 126 + charger->irqchip.irq_bus_sync_unlock = crystal_cove_charger_irq_bus_sync_unlock; 127 + 128 + irq_set_chip_data(charger->charger_irq, charger); 129 + irq_set_chip_and_handler(charger->charger_irq, &charger->irqchip, handle_simple_irq); 130 + irq_set_nested_thread(charger->charger_irq, true); 131 + irq_set_noprobe(charger->charger_irq); 132 + 133 + ret = devm_request_threaded_irq(&pdev->dev, charger->irq, NULL, 134 + crystal_cove_charger_irq, 135 + IRQF_ONESHOT | IRQF_NO_AUTOEN, 136 + KBUILD_MODNAME, charger); 137 + if (ret) 138 + return dev_err_probe(&pdev->dev, ret, "requesting irq\n"); 139 + 140 + return 0; 141 + } 142 + 143 + static struct platform_driver crystal_cove_charger_driver = { 144 + .probe = crystal_cove_charger_probe, 145 + .driver = { 146 + .name = "crystal_cove_charger", 147 + }, 148 + }; 149 + module_platform_driver(crystal_cove_charger_driver); 150 + 151 + MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com"); 152 + MODULE_DESCRIPTION("Intel Bay Trail Crystal Cove external charger IRQ pass-through"); 153 + MODULE_LICENSE("GPL");
+13
drivers/platform/x86/intel/int3472/tps68470_board_data.c
··· 110 110 .tps68470_regulator_pdata = &surface_go_tps68470_pdata, 111 111 }; 112 112 113 + static const struct int3472_tps68470_board_data surface_go3_tps68470_board_data = { 114 + .dev_name = "i2c-INT3472:01", 115 + .tps68470_gpio_lookup_table = &surface_go_tps68470_gpios, 116 + .tps68470_regulator_pdata = &surface_go_tps68470_pdata, 117 + }; 118 + 113 119 static const struct dmi_system_id int3472_tps68470_board_data_table[] = { 114 120 { 115 121 .matches = { ··· 130 124 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Go 2"), 131 125 }, 132 126 .driver_data = (void *)&surface_go_tps68470_board_data, 127 + }, 128 + { 129 + .matches = { 130 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 131 + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"), 132 + }, 133 + .driver_data = (void *)&surface_go3_tps68470_board_data, 133 134 }, 134 135 { } 135 136 };
+2 -1
drivers/platform/x86/intel/uncore-frequency.c
··· 225 225 &min_freq_khz.attr, 226 226 NULL 227 227 }; 228 + ATTRIBUTE_GROUPS(uncore); 228 229 229 230 static void uncore_sysfs_entry_release(struct kobject *kobj) 230 231 { ··· 237 236 static struct kobj_type uncore_ktype = { 238 237 .release = uncore_sysfs_entry_release, 239 238 .sysfs_ops = &kobj_sysfs_ops, 240 - .default_attrs = uncore_attrs, 239 + .default_groups = uncore_groups, 241 240 }; 242 241 243 242 /* Caller provides protection */
+408
drivers/platform/x86/lenovo-yogabook-wmi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* WMI driver for Lenovo Yoga Book YB1-X90* / -X91* tablets */ 3 + 4 + #include <linux/acpi.h> 5 + #include <linux/devm-helpers.h> 6 + #include <linux/gpio/consumer.h> 7 + #include <linux/gpio/machine.h> 8 + #include <linux/interrupt.h> 9 + #include <linux/module.h> 10 + #include <linux/leds.h> 11 + #include <linux/wmi.h> 12 + #include <linux/workqueue.h> 13 + 14 + #define YB_MBTN_EVENT_GUID "243FEC1D-1963-41C1-8100-06A9D82A94B4" 15 + #define YB_MBTN_METHOD_GUID "742B0CA1-0B20-404B-9CAA-AEFCABF30CE0" 16 + 17 + #define YB_PAD_ENABLE 1 18 + #define YB_PAD_DISABLE 2 19 + #define YB_LIGHTUP_BTN 3 20 + 21 + #define YB_KBD_BL_DEFAULT 128 22 + 23 + /* flags */ 24 + enum { 25 + YB_KBD_IS_ON, 26 + YB_DIGITIZER_IS_ON, 27 + YB_DIGITIZER_MODE, 28 + YB_TABLET_MODE, 29 + YB_SUSPENDED, 30 + }; 31 + 32 + struct yogabook_wmi { 33 + struct wmi_device *wdev; 34 + struct acpi_device *kbd_adev; 35 + struct acpi_device *dig_adev; 36 + struct device *kbd_dev; 37 + struct device *dig_dev; 38 + struct gpio_desc *backside_hall_gpio; 39 + int backside_hall_irq; 40 + struct work_struct work; 41 + struct led_classdev kbd_bl_led; 42 + unsigned long flags; 43 + uint8_t brightness; 44 + }; 45 + 46 + static int yogabook_wmi_do_action(struct wmi_device *wdev, int action) 47 + { 48 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 49 + struct acpi_buffer input; 50 + acpi_status status; 51 + u32 dummy_arg = 0; 52 + 53 + dev_dbg(&wdev->dev, "Do action: %d\n", action); 54 + 55 + input.pointer = &dummy_arg; 56 + input.length = sizeof(dummy_arg); 57 + 58 + status = wmi_evaluate_method(YB_MBTN_METHOD_GUID, 0, action, &input, 59 + &output); 60 + if (ACPI_FAILURE(status)) { 61 + dev_err(&wdev->dev, "Calling WMI method failure: 0x%x\n", 62 + status); 63 + return status; 64 + } 65 + 66 + kfree(output.pointer); 67 + 68 + return 0; 69 + } 70 + 71 + /* 72 + * To control keyboard backlight, call the method KBLC() of the TCS1 ACPI 73 + * device (Goodix touchpad acts as virtual sensor keyboard). 74 + */ 75 + static int yogabook_wmi_set_kbd_backlight(struct wmi_device *wdev, 76 + uint8_t level) 77 + { 78 + struct yogabook_wmi *data = dev_get_drvdata(&wdev->dev); 79 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 80 + struct acpi_object_list input; 81 + union acpi_object param; 82 + acpi_status status; 83 + 84 + if (data->kbd_adev->power.state != ACPI_STATE_D0) { 85 + dev_warn(&wdev->dev, "keyboard touchscreen not in D0, cannot set brightness\n"); 86 + return -ENXIO; 87 + } 88 + 89 + dev_dbg(&wdev->dev, "Set KBLC level to %u\n", level); 90 + 91 + input.count = 1; 92 + input.pointer = &param; 93 + 94 + param.type = ACPI_TYPE_INTEGER; 95 + param.integer.value = 255 - level; 96 + 97 + status = acpi_evaluate_object(acpi_device_handle(data->kbd_adev), "KBLC", 98 + &input, &output); 99 + if (ACPI_FAILURE(status)) { 100 + dev_err(&wdev->dev, "Failed to call KBLC method: 0x%x\n", status); 101 + return status; 102 + } 103 + 104 + kfree(output.pointer); 105 + return 0; 106 + } 107 + 108 + static void yogabook_wmi_work(struct work_struct *work) 109 + { 110 + struct yogabook_wmi *data = container_of(work, struct yogabook_wmi, work); 111 + struct device *dev = &data->wdev->dev; 112 + bool kbd_on, digitizer_on; 113 + int r; 114 + 115 + if (test_bit(YB_SUSPENDED, &data->flags)) 116 + return; 117 + 118 + if (test_bit(YB_TABLET_MODE, &data->flags)) { 119 + kbd_on = false; 120 + digitizer_on = false; 121 + } else if (test_bit(YB_DIGITIZER_MODE, &data->flags)) { 122 + digitizer_on = true; 123 + kbd_on = false; 124 + } else { 125 + kbd_on = true; 126 + digitizer_on = false; 127 + } 128 + 129 + if (!kbd_on && test_bit(YB_KBD_IS_ON, &data->flags)) { 130 + /* 131 + * Must be done before releasing the keyboard touchscreen driver, 132 + * so that the keyboard touchscreen dev is still in D0. 133 + */ 134 + yogabook_wmi_set_kbd_backlight(data->wdev, 0); 135 + device_release_driver(data->kbd_dev); 136 + clear_bit(YB_KBD_IS_ON, &data->flags); 137 + } 138 + 139 + if (!digitizer_on && test_bit(YB_DIGITIZER_IS_ON, &data->flags)) { 140 + yogabook_wmi_do_action(data->wdev, YB_PAD_DISABLE); 141 + device_release_driver(data->dig_dev); 142 + clear_bit(YB_DIGITIZER_IS_ON, &data->flags); 143 + } 144 + 145 + if (kbd_on && !test_bit(YB_KBD_IS_ON, &data->flags)) { 146 + r = device_reprobe(data->kbd_dev); 147 + if (r) 148 + dev_warn(dev, "Reprobe of keyboard touchscreen failed: %d\n", r); 149 + 150 + yogabook_wmi_set_kbd_backlight(data->wdev, data->brightness); 151 + set_bit(YB_KBD_IS_ON, &data->flags); 152 + } 153 + 154 + if (digitizer_on && !test_bit(YB_DIGITIZER_IS_ON, &data->flags)) { 155 + r = device_reprobe(data->dig_dev); 156 + if (r) 157 + dev_warn(dev, "Reprobe of digitizer failed: %d\n", r); 158 + 159 + yogabook_wmi_do_action(data->wdev, YB_PAD_ENABLE); 160 + set_bit(YB_DIGITIZER_IS_ON, &data->flags); 161 + } 162 + } 163 + 164 + static void yogabook_wmi_notify(struct wmi_device *wdev, union acpi_object *dummy) 165 + { 166 + struct yogabook_wmi *data = dev_get_drvdata(&wdev->dev); 167 + 168 + if (test_bit(YB_SUSPENDED, &data->flags)) 169 + return; 170 + 171 + if (test_bit(YB_DIGITIZER_MODE, &data->flags)) 172 + clear_bit(YB_DIGITIZER_MODE, &data->flags); 173 + else 174 + set_bit(YB_DIGITIZER_MODE, &data->flags); 175 + 176 + /* 177 + * We are called from the ACPI core and the driver [un]binding which is 178 + * done also needs ACPI functions, use a workqueue to avoid deadlocking. 179 + */ 180 + schedule_work(&data->work); 181 + } 182 + 183 + static irqreturn_t yogabook_backside_hall_irq(int irq, void *_data) 184 + { 185 + struct yogabook_wmi *data = _data; 186 + 187 + if (gpiod_get_value(data->backside_hall_gpio)) 188 + set_bit(YB_TABLET_MODE, &data->flags); 189 + else 190 + clear_bit(YB_TABLET_MODE, &data->flags); 191 + 192 + schedule_work(&data->work); 193 + 194 + return IRQ_HANDLED; 195 + } 196 + 197 + static enum led_brightness kbd_brightness_get(struct led_classdev *cdev) 198 + { 199 + struct yogabook_wmi *data = 200 + container_of(cdev, struct yogabook_wmi, kbd_bl_led); 201 + 202 + return data->brightness; 203 + } 204 + 205 + static int kbd_brightness_set(struct led_classdev *cdev, 206 + enum led_brightness value) 207 + { 208 + struct yogabook_wmi *data = 209 + container_of(cdev, struct yogabook_wmi, kbd_bl_led); 210 + struct wmi_device *wdev = data->wdev; 211 + 212 + if ((value < 0) || (value > 255)) 213 + return -EINVAL; 214 + 215 + data->brightness = value; 216 + 217 + if (data->kbd_adev->power.state != ACPI_STATE_D0) 218 + return 0; 219 + 220 + return yogabook_wmi_set_kbd_backlight(wdev, data->brightness); 221 + } 222 + 223 + static struct gpiod_lookup_table yogabook_wmi_gpios = { 224 + .dev_id = "243FEC1D-1963-41C1-8100-06A9D82A94B4", 225 + .table = { 226 + GPIO_LOOKUP("INT33FF:02", 18, "backside_hall_sw", GPIO_ACTIVE_LOW), 227 + {} 228 + }, 229 + }; 230 + 231 + static void yogabook_wmi_rm_gpio_lookup(void *unused) 232 + { 233 + gpiod_remove_lookup_table(&yogabook_wmi_gpios); 234 + } 235 + 236 + static int yogabook_wmi_probe(struct wmi_device *wdev, const void *context) 237 + { 238 + struct yogabook_wmi *data; 239 + int r; 240 + 241 + data = devm_kzalloc(&wdev->dev, sizeof(struct yogabook_wmi), GFP_KERNEL); 242 + if (data == NULL) 243 + return -ENOMEM; 244 + 245 + dev_set_drvdata(&wdev->dev, data); 246 + 247 + data->wdev = wdev; 248 + data->brightness = YB_KBD_BL_DEFAULT; 249 + set_bit(YB_KBD_IS_ON, &data->flags); 250 + set_bit(YB_DIGITIZER_IS_ON, &data->flags); 251 + 252 + r = devm_work_autocancel(&wdev->dev, &data->work, yogabook_wmi_work); 253 + if (r) 254 + return r; 255 + 256 + data->kbd_adev = acpi_dev_get_first_match_dev("GDIX1001", NULL, -1); 257 + if (!data->kbd_adev) { 258 + dev_err(&wdev->dev, "Cannot find the touchpad device in ACPI tables\n"); 259 + return -ENODEV; 260 + } 261 + 262 + data->dig_adev = acpi_dev_get_first_match_dev("WCOM0019", NULL, -1); 263 + if (!data->dig_adev) { 264 + dev_err(&wdev->dev, "Cannot find the digitizer device in ACPI tables\n"); 265 + r = -ENODEV; 266 + goto error_put_devs; 267 + } 268 + 269 + data->kbd_dev = get_device(acpi_get_first_physical_node(data->kbd_adev)); 270 + if (!data->kbd_dev || !data->kbd_dev->driver) { 271 + r = -EPROBE_DEFER; 272 + goto error_put_devs; 273 + } 274 + 275 + data->dig_dev = get_device(acpi_get_first_physical_node(data->dig_adev)); 276 + if (!data->dig_dev || !data->dig_dev->driver) { 277 + r = -EPROBE_DEFER; 278 + goto error_put_devs; 279 + } 280 + 281 + gpiod_add_lookup_table(&yogabook_wmi_gpios); 282 + 283 + r = devm_add_action_or_reset(&wdev->dev, yogabook_wmi_rm_gpio_lookup, NULL); 284 + if (r) 285 + goto error_put_devs; 286 + 287 + data->backside_hall_gpio = 288 + devm_gpiod_get(&wdev->dev, "backside_hall_sw", GPIOD_IN); 289 + if (IS_ERR(data->backside_hall_gpio)) { 290 + r = PTR_ERR(data->backside_hall_gpio); 291 + dev_err_probe(&wdev->dev, r, "Getting backside_hall_sw GPIO\n"); 292 + goto error_put_devs; 293 + } 294 + 295 + r = gpiod_to_irq(data->backside_hall_gpio); 296 + if (r < 0) { 297 + dev_err_probe(&wdev->dev, r, "Getting backside_hall_sw IRQ\n"); 298 + goto error_put_devs; 299 + } 300 + data->backside_hall_irq = r; 301 + 302 + r = devm_request_irq(&wdev->dev, data->backside_hall_irq, 303 + yogabook_backside_hall_irq, 304 + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 305 + "backside_hall_sw", data); 306 + if (r) { 307 + dev_err_probe(&wdev->dev, r, "Requesting backside_hall_sw IRQ\n"); 308 + goto error_put_devs; 309 + } 310 + 311 + schedule_work(&data->work); 312 + 313 + data->kbd_bl_led.name = "ybwmi::kbd_backlight"; 314 + data->kbd_bl_led.brightness_set_blocking = kbd_brightness_set; 315 + data->kbd_bl_led.brightness_get = kbd_brightness_get; 316 + data->kbd_bl_led.max_brightness = 255; 317 + 318 + r = devm_led_classdev_register(&wdev->dev, &data->kbd_bl_led); 319 + if (r < 0) { 320 + dev_err_probe(&wdev->dev, r, "Registering backlight LED device\n"); 321 + goto error_put_devs; 322 + } 323 + 324 + return 0; 325 + 326 + error_put_devs: 327 + put_device(data->dig_dev); 328 + put_device(data->kbd_dev); 329 + acpi_dev_put(data->dig_adev); 330 + acpi_dev_put(data->kbd_adev); 331 + return r; 332 + } 333 + 334 + static void yogabook_wmi_remove(struct wmi_device *wdev) 335 + { 336 + struct yogabook_wmi *data = dev_get_drvdata(&wdev->dev); 337 + 338 + put_device(data->dig_dev); 339 + put_device(data->kbd_dev); 340 + acpi_dev_put(data->dig_adev); 341 + acpi_dev_put(data->kbd_adev); 342 + } 343 + 344 + static int __maybe_unused yogabook_wmi_suspend(struct device *dev) 345 + { 346 + struct wmi_device *wdev = container_of(dev, struct wmi_device, dev); 347 + struct yogabook_wmi *data = dev_get_drvdata(dev); 348 + 349 + set_bit(YB_SUSPENDED, &data->flags); 350 + 351 + flush_work(&data->work); 352 + 353 + /* Turn off the pen button at sleep */ 354 + if (test_bit(YB_DIGITIZER_IS_ON, &data->flags)) 355 + yogabook_wmi_do_action(wdev, YB_PAD_DISABLE); 356 + 357 + return 0; 358 + } 359 + 360 + static int __maybe_unused yogabook_wmi_resume(struct device *dev) 361 + { 362 + struct wmi_device *wdev = container_of(dev, struct wmi_device, dev); 363 + struct yogabook_wmi *data = dev_get_drvdata(dev); 364 + 365 + if (test_bit(YB_KBD_IS_ON, &data->flags)) { 366 + /* Ensure keyboard touchpad is on before we call KBLC() */ 367 + acpi_device_set_power(data->kbd_adev, ACPI_STATE_D0); 368 + yogabook_wmi_set_kbd_backlight(wdev, data->brightness); 369 + } 370 + 371 + if (test_bit(YB_DIGITIZER_IS_ON, &data->flags)) 372 + yogabook_wmi_do_action(wdev, YB_PAD_ENABLE); 373 + 374 + clear_bit(YB_SUSPENDED, &data->flags); 375 + 376 + /* Check for YB_TABLET_MODE changes made during suspend */ 377 + schedule_work(&data->work); 378 + 379 + return 0; 380 + } 381 + 382 + static const struct wmi_device_id yogabook_wmi_id_table[] = { 383 + { 384 + .guid_string = YB_MBTN_EVENT_GUID, 385 + }, 386 + { } /* Terminating entry */ 387 + }; 388 + 389 + static SIMPLE_DEV_PM_OPS(yogabook_wmi_pm_ops, 390 + yogabook_wmi_suspend, yogabook_wmi_resume); 391 + 392 + static struct wmi_driver yogabook_wmi_driver = { 393 + .driver = { 394 + .name = "yogabook-wmi", 395 + .pm = &yogabook_wmi_pm_ops, 396 + }, 397 + .no_notify_data = true, 398 + .id_table = yogabook_wmi_id_table, 399 + .probe = yogabook_wmi_probe, 400 + .remove = yogabook_wmi_remove, 401 + .notify = yogabook_wmi_notify, 402 + }; 403 + module_wmi_driver(yogabook_wmi_driver); 404 + 405 + MODULE_DEVICE_TABLE(wmi, yogabook_wmi_id_table); 406 + MODULE_AUTHOR("Yauhen Kharuzhy"); 407 + MODULE_DESCRIPTION("Lenovo Yoga Book WMI driver"); 408 + MODULE_LICENSE("GPL v2");
+33 -21
drivers/platform/x86/pmc_atom.c
··· 13 13 #include <linux/io.h> 14 14 #include <linux/platform_data/x86/clk-pmc-atom.h> 15 15 #include <linux/platform_data/x86/pmc_atom.h> 16 + #include <linux/platform_data/x86/simatic-ipc.h> 16 17 #include <linux/platform_device.h> 17 18 #include <linux/pci.h> 18 19 #include <linux/seq_file.h> ··· 363 362 } 364 363 #endif /* CONFIG_DEBUG_FS */ 365 364 365 + static bool pmc_clk_is_critical = true; 366 + 367 + static int dmi_callback(const struct dmi_system_id *d) 368 + { 369 + pr_info("%s critclks quirk enabled\n", d->ident); 370 + 371 + return 1; 372 + } 373 + 374 + static int dmi_callback_siemens(const struct dmi_system_id *d) 375 + { 376 + u32 st_id; 377 + 378 + if (dmi_walk(simatic_ipc_find_dmi_entry_helper, &st_id)) 379 + goto out; 380 + 381 + if (st_id == SIMATIC_IPC_IPC227E || st_id == SIMATIC_IPC_IPC277E) 382 + return dmi_callback(d); 383 + 384 + out: 385 + pmc_clk_is_critical = false; 386 + return 1; 387 + } 388 + 366 389 /* 367 390 * Some systems need one or more of their pmc_plt_clks to be 368 391 * marked as critical. ··· 395 370 { 396 371 /* pmc_plt_clk0 is used for an external HSIC USB HUB */ 397 372 .ident = "MPL CEC1x", 373 + .callback = dmi_callback, 398 374 .matches = { 399 375 DMI_MATCH(DMI_SYS_VENDOR, "MPL AG"), 400 376 DMI_MATCH(DMI_PRODUCT_NAME, "CEC10 Family"), ··· 404 378 { 405 379 /* pmc_plt_clk0 - 3 are used for the 4 ethernet controllers */ 406 380 .ident = "Lex 3I380D", 381 + .callback = dmi_callback, 407 382 .matches = { 408 383 DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"), 409 384 DMI_MATCH(DMI_PRODUCT_NAME, "3I380D"), ··· 413 386 { 414 387 /* pmc_plt_clk* - are used for ethernet controllers */ 415 388 .ident = "Lex 2I385SW", 389 + .callback = dmi_callback, 416 390 .matches = { 417 391 DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"), 418 392 DMI_MATCH(DMI_PRODUCT_NAME, "2I385SW"), ··· 422 394 { 423 395 /* pmc_plt_clk* - are used for ethernet controllers */ 424 396 .ident = "Beckhoff Baytrail", 397 + .callback = dmi_callback, 425 398 .matches = { 426 399 DMI_MATCH(DMI_SYS_VENDOR, "Beckhoff Automation"), 427 400 DMI_MATCH(DMI_PRODUCT_FAMILY, "CBxx63"), 428 401 }, 429 402 }, 430 403 { 431 - .ident = "SIMATIC IPC227E", 404 + .ident = "SIEMENS AG", 405 + .callback = dmi_callback_siemens, 432 406 .matches = { 433 407 DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"), 434 - DMI_MATCH(DMI_PRODUCT_VERSION, "6ES7647-8B"), 435 - }, 436 - }, 437 - { 438 - .ident = "SIMATIC IPC277E", 439 - .matches = { 440 - DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"), 441 - DMI_MATCH(DMI_PRODUCT_VERSION, "6AV7882-0"), 442 - }, 443 - }, 444 - { 445 - .ident = "CONNECT X300", 446 - .matches = { 447 - DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"), 448 - DMI_MATCH(DMI_PRODUCT_VERSION, "A5E45074588"), 449 408 }, 450 409 }, 451 410 ··· 444 429 { 445 430 struct platform_device *clkdev; 446 431 struct pmc_clk_data *clk_data; 447 - const struct dmi_system_id *d = dmi_first_match(critclk_systems); 448 432 449 433 clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 450 434 if (!clk_data) ··· 451 437 452 438 clk_data->base = pmc_regmap; /* offset is added by client */ 453 439 clk_data->clks = pmc_data->clks; 454 - if (d) { 455 - clk_data->critical = true; 456 - pr_info("%s critclks quirk enabled\n", d->ident); 457 - } 440 + if (dmi_check_system(critclk_systems)) 441 + clk_data->critical = pmc_clk_is_critical; 458 442 459 443 clkdev = platform_device_register_data(&pdev->dev, "clk-pmc-atom", 460 444 PLATFORM_DEVID_NONE,
+176
drivers/platform/x86/simatic-ipc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC platform driver 4 + * 5 + * Copyright (c) Siemens AG, 2018-2021 6 + * 7 + * Authors: 8 + * Henning Schild <henning.schild@siemens.com> 9 + * Jan Kiszka <jan.kiszka@siemens.com> 10 + * Gerd Haeussler <gerd.haeussler.ext@siemens.com> 11 + */ 12 + 13 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 + 15 + #include <linux/dmi.h> 16 + #include <linux/kernel.h> 17 + #include <linux/module.h> 18 + #include <linux/pci.h> 19 + #include <linux/platform_data/x86/simatic-ipc.h> 20 + #include <linux/platform_device.h> 21 + 22 + static struct platform_device *ipc_led_platform_device; 23 + static struct platform_device *ipc_wdt_platform_device; 24 + 25 + static const struct dmi_system_id simatic_ipc_whitelist[] = { 26 + { 27 + .matches = { 28 + DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"), 29 + }, 30 + }, 31 + {} 32 + }; 33 + 34 + static struct simatic_ipc_platform platform_data; 35 + 36 + static struct { 37 + u32 station_id; 38 + u8 led_mode; 39 + u8 wdt_mode; 40 + } device_modes[] = { 41 + {SIMATIC_IPC_IPC127E, SIMATIC_IPC_DEVICE_127E, SIMATIC_IPC_DEVICE_NONE}, 42 + {SIMATIC_IPC_IPC227D, SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE}, 43 + {SIMATIC_IPC_IPC227E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E}, 44 + {SIMATIC_IPC_IPC277E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E}, 45 + {SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE}, 46 + {SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E}, 47 + {SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E}, 48 + }; 49 + 50 + static int register_platform_devices(u32 station_id) 51 + { 52 + u8 ledmode = SIMATIC_IPC_DEVICE_NONE; 53 + u8 wdtmode = SIMATIC_IPC_DEVICE_NONE; 54 + int i; 55 + 56 + platform_data.devmode = SIMATIC_IPC_DEVICE_NONE; 57 + 58 + for (i = 0; i < ARRAY_SIZE(device_modes); i++) { 59 + if (device_modes[i].station_id == station_id) { 60 + ledmode = device_modes[i].led_mode; 61 + wdtmode = device_modes[i].wdt_mode; 62 + break; 63 + } 64 + } 65 + 66 + if (ledmode != SIMATIC_IPC_DEVICE_NONE) { 67 + platform_data.devmode = ledmode; 68 + ipc_led_platform_device = 69 + platform_device_register_data(NULL, 70 + KBUILD_MODNAME "_leds", PLATFORM_DEVID_NONE, 71 + &platform_data, 72 + sizeof(struct simatic_ipc_platform)); 73 + if (IS_ERR(ipc_led_platform_device)) 74 + return PTR_ERR(ipc_led_platform_device); 75 + 76 + pr_debug("device=%s created\n", 77 + ipc_led_platform_device->name); 78 + } 79 + 80 + if (wdtmode != SIMATIC_IPC_DEVICE_NONE) { 81 + platform_data.devmode = wdtmode; 82 + ipc_wdt_platform_device = 83 + platform_device_register_data(NULL, 84 + KBUILD_MODNAME "_wdt", PLATFORM_DEVID_NONE, 85 + &platform_data, 86 + sizeof(struct simatic_ipc_platform)); 87 + if (IS_ERR(ipc_wdt_platform_device)) 88 + return PTR_ERR(ipc_wdt_platform_device); 89 + 90 + pr_debug("device=%s created\n", 91 + ipc_wdt_platform_device->name); 92 + } 93 + 94 + if (ledmode == SIMATIC_IPC_DEVICE_NONE && 95 + wdtmode == SIMATIC_IPC_DEVICE_NONE) { 96 + pr_warn("unsupported IPC detected, station id=%08x\n", 97 + station_id); 98 + return -EINVAL; 99 + } 100 + 101 + return 0; 102 + } 103 + 104 + /* FIXME: this should eventually be done with generic P2SB discovery code 105 + * the individual drivers for watchdogs and LEDs access memory that implements 106 + * GPIO, but pinctrl will not come up because of missing ACPI entries 107 + * 108 + * While there is no conflict a cleaner solution would be to somehow bring up 109 + * pinctrl even with these ACPI entries missing, and base the drivers on pinctrl. 110 + * After which the following function could be dropped, together with the code 111 + * poking the memory. 112 + */ 113 + /* 114 + * Get membase address from PCI, used in leds and wdt module. Here we read 115 + * the bar0. The final address calculation is done in the appropriate modules 116 + */ 117 + u32 simatic_ipc_get_membase0(unsigned int p2sb) 118 + { 119 + struct pci_bus *bus; 120 + u32 bar0 = 0; 121 + /* 122 + * The GPIO memory is in bar0 of the hidden P2SB device. 123 + * Unhide the device to have a quick look at it, before we hide it 124 + * again. 125 + * Also grab the pci rescan lock so that device does not get discovered 126 + * and remapped while it is visible. 127 + * This code is inspired by drivers/mfd/lpc_ich.c 128 + */ 129 + bus = pci_find_bus(0, 0); 130 + pci_lock_rescan_remove(); 131 + pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x0); 132 + pci_bus_read_config_dword(bus, p2sb, PCI_BASE_ADDRESS_0, &bar0); 133 + 134 + bar0 &= ~0xf; 135 + pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x1); 136 + pci_unlock_rescan_remove(); 137 + 138 + return bar0; 139 + } 140 + EXPORT_SYMBOL(simatic_ipc_get_membase0); 141 + 142 + static int __init simatic_ipc_init_module(void) 143 + { 144 + const struct dmi_system_id *match; 145 + u32 station_id; 146 + int err; 147 + 148 + match = dmi_first_match(simatic_ipc_whitelist); 149 + if (!match) 150 + return 0; 151 + 152 + err = dmi_walk(simatic_ipc_find_dmi_entry_helper, &station_id); 153 + 154 + if (err || station_id == SIMATIC_IPC_INVALID_STATION_ID) { 155 + pr_warn("DMI entry %d not found\n", SIMATIC_IPC_DMI_ENTRY_OEM); 156 + return 0; 157 + } 158 + 159 + return register_platform_devices(station_id); 160 + } 161 + 162 + static void __exit simatic_ipc_exit_module(void) 163 + { 164 + platform_device_unregister(ipc_led_platform_device); 165 + ipc_led_platform_device = NULL; 166 + 167 + platform_device_unregister(ipc_wdt_platform_device); 168 + ipc_wdt_platform_device = NULL; 169 + } 170 + 171 + module_init(simatic_ipc_init_module); 172 + module_exit(simatic_ipc_exit_module); 173 + 174 + MODULE_LICENSE("GPL v2"); 175 + MODULE_AUTHOR("Gerd Haeussler <gerd.haeussler.ext@siemens.com>"); 176 + MODULE_ALIAS("dmi:*:svnSIEMENSAG:*");
+283 -44
drivers/platform/x86/think-lmi.c
··· 128 128 */ 129 129 #define LENOVO_DEBUG_CMD_GUID "7FF47003-3B6C-4E5E-A227-E979824A85D1" 130 130 131 + /* 132 + * Name: 133 + * Lenovo_OpcodeIF 134 + * Description: 135 + * Opcode interface which provides the ability to set multiple 136 + * parameters and then trigger an action with a final command. 137 + * This is particularly useful for simplifying setting passwords. 138 + * With this support comes the ability to set System, HDD and NVMe 139 + * passwords. 140 + * This is currently available on ThinkCenter and ThinkStations platforms 141 + */ 142 + #define LENOVO_OPCODE_IF_GUID "DFDDEF2C-57D4-48ce-B196-0FB787D90836" 143 + 131 144 #define TLMI_POP_PWD (1 << 0) 132 145 #define TLMI_PAP_PWD (1 << 1) 146 + #define TLMI_HDD_PWD (1 << 2) 147 + #define TLMI_SYS_PWD (1 << 3) 133 148 #define to_tlmi_pwd_setting(kobj) container_of(kobj, struct tlmi_pwd_setting, kobj) 134 149 #define to_tlmi_attr_setting(kobj) container_of(kobj, struct tlmi_attr_setting, kobj) 135 150 ··· 159 144 static const char * const encoding_options[] = { 160 145 [TLMI_ENCODING_ASCII] = "ascii", 161 146 [TLMI_ENCODING_SCANCODE] = "scancode", 147 + }; 148 + static const char * const level_options[] = { 149 + [TLMI_LEVEL_USER] = "user", 150 + [TLMI_LEVEL_MASTER] = "master", 162 151 }; 163 152 static struct think_lmi tlmi_priv; 164 153 static struct class *fw_attr_class; ··· 252 233 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 253 234 const union acpi_object *obj; 254 235 acpi_status status; 236 + int copy_size; 255 237 256 238 if (!tlmi_priv.can_get_password_settings) 257 239 return -EOPNOTSUPP; ··· 273 253 * The size of thinkpad_wmi_pcfg on ThinkStation is larger than ThinkPad. 274 254 * To make the driver compatible on different brands, we permit it to get 275 255 * the data in below case. 256 + * Settings must have at minimum the core fields available 276 257 */ 277 - if (obj->buffer.length < sizeof(struct tlmi_pwdcfg)) { 258 + if (obj->buffer.length < sizeof(struct tlmi_pwdcfg_core)) { 278 259 pr_warn("Unknown pwdcfg buffer length %d\n", obj->buffer.length); 279 260 kfree(obj); 280 261 return -EIO; 281 262 } 282 - memcpy(pwdcfg, obj->buffer.pointer, sizeof(struct tlmi_pwdcfg)); 263 + 264 + copy_size = obj->buffer.length < sizeof(struct tlmi_pwdcfg) ? 265 + obj->buffer.length : sizeof(struct tlmi_pwdcfg); 266 + memcpy(pwdcfg, obj->buffer.pointer, copy_size); 283 267 kfree(obj); 268 + 269 + if (WARN_ON(pwdcfg->core.max_length >= TLMI_PWD_BUFSIZE)) 270 + pwdcfg->core.max_length = TLMI_PWD_BUFSIZE - 1; 284 271 return 0; 285 272 } 286 273 ··· 295 268 { 296 269 return tlmi_simple_call(LENOVO_SAVE_BIOS_SETTINGS_GUID, 297 270 password); 271 + } 272 + 273 + static int tlmi_opcode_setting(char *setting, const char *value) 274 + { 275 + char *opcode_str; 276 + int ret; 277 + 278 + opcode_str = kasprintf(GFP_KERNEL, "%s:%s;", setting, value); 279 + if (!opcode_str) 280 + return -ENOMEM; 281 + 282 + ret = tlmi_simple_call(LENOVO_OPCODE_IF_GUID, opcode_str); 283 + kfree(opcode_str); 284 + return ret; 298 285 } 299 286 300 287 static int tlmi_setting(int item, char **value, const char *guid_string) ··· 411 370 goto out; 412 371 } 413 372 414 - /* Format: 'PasswordType,CurrentPw,NewPw,Encoding,KbdLang;' */ 415 - auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s,%s,%s;", 416 - setting->pwd_type, setting->password, new_pwd, 417 - encoding_options[setting->encoding], setting->kbdlang); 418 - if (!auth_str) { 419 - ret = -ENOMEM; 420 - goto out; 373 + /* If opcode support is present use that interface */ 374 + if (tlmi_priv.opcode_support) { 375 + char pwd_type[8]; 376 + 377 + /* Special handling required for HDD and NVMe passwords */ 378 + if (setting == tlmi_priv.pwd_hdd) { 379 + if (setting->level == TLMI_LEVEL_USER) 380 + sprintf(pwd_type, "uhdp%d", setting->index); 381 + else 382 + sprintf(pwd_type, "mhdp%d", setting->index); 383 + } else if (setting == tlmi_priv.pwd_nvme) { 384 + if (setting->level == TLMI_LEVEL_USER) 385 + sprintf(pwd_type, "unvp%d", setting->index); 386 + else 387 + sprintf(pwd_type, "mnvp%d", setting->index); 388 + } else { 389 + sprintf(pwd_type, "%s", setting->pwd_type); 390 + } 391 + 392 + ret = tlmi_opcode_setting("WmiOpcodePasswordType", pwd_type); 393 + if (ret) 394 + goto out; 395 + 396 + if (tlmi_priv.pwd_admin->valid) { 397 + ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin", 398 + tlmi_priv.pwd_admin->password); 399 + if (ret) 400 + goto out; 401 + } 402 + ret = tlmi_opcode_setting("WmiOpcodePasswordCurrent01", setting->password); 403 + if (ret) 404 + goto out; 405 + ret = tlmi_opcode_setting("WmiOpcodePasswordNew01", new_pwd); 406 + if (ret) 407 + goto out; 408 + ret = tlmi_simple_call(LENOVO_OPCODE_IF_GUID, "WmiOpcodePasswordSetUpdate;"); 409 + } else { 410 + /* Format: 'PasswordType,CurrentPw,NewPw,Encoding,KbdLang;' */ 411 + auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s,%s,%s;", 412 + setting->pwd_type, setting->password, new_pwd, 413 + encoding_options[setting->encoding], setting->kbdlang); 414 + if (!auth_str) { 415 + ret = -ENOMEM; 416 + goto out; 417 + } 418 + ret = tlmi_simple_call(LENOVO_SET_BIOS_PASSWORD_GUID, auth_str); 419 + kfree(auth_str); 421 420 } 422 - ret = tlmi_simple_call(LENOVO_SET_BIOS_PASSWORD_GUID, auth_str); 423 - kfree(auth_str); 424 421 out: 425 422 kfree(new_pwd); 426 423 return ret ?: count; ··· 554 475 } 555 476 static struct kobj_attribute auth_role = __ATTR_RO(role); 556 477 478 + static ssize_t index_show(struct kobject *kobj, struct kobj_attribute *attr, 479 + char *buf) 480 + { 481 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 482 + 483 + return sysfs_emit(buf, "%d\n", setting->index); 484 + } 485 + 486 + static ssize_t index_store(struct kobject *kobj, 487 + struct kobj_attribute *attr, 488 + const char *buf, size_t count) 489 + { 490 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 491 + int err, val; 492 + 493 + err = kstrtoint(buf, 10, &val); 494 + if (err < 0) 495 + return err; 496 + 497 + if (val < 0 || val > TLMI_INDEX_MAX) 498 + return -EINVAL; 499 + 500 + setting->index = val; 501 + return count; 502 + } 503 + 504 + static struct kobj_attribute auth_index = __ATTR_RW(index); 505 + 506 + static ssize_t level_show(struct kobject *kobj, struct kobj_attribute *attr, 507 + char *buf) 508 + { 509 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 510 + 511 + return sysfs_emit(buf, "%s\n", level_options[setting->level]); 512 + } 513 + 514 + static ssize_t level_store(struct kobject *kobj, 515 + struct kobj_attribute *attr, 516 + const char *buf, size_t count) 517 + { 518 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 519 + int i; 520 + 521 + /* Scan for a matching profile */ 522 + i = sysfs_match_string(level_options, buf); 523 + if (i < 0) 524 + return -EINVAL; 525 + 526 + setting->level = i; 527 + return count; 528 + } 529 + 530 + static struct kobj_attribute auth_level = __ATTR_RW(level); 531 + 532 + static umode_t auth_attr_is_visible(struct kobject *kobj, 533 + struct attribute *attr, int n) 534 + { 535 + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); 536 + 537 + /*We only want to display level and index settings on HDD/NVMe */ 538 + if ((attr == (struct attribute *)&auth_index) || 539 + (attr == (struct attribute *)&auth_level)) { 540 + if ((setting == tlmi_priv.pwd_hdd) || (setting == tlmi_priv.pwd_nvme)) 541 + return attr->mode; 542 + return 0; 543 + } 544 + return attr->mode; 545 + } 546 + 557 547 static struct attribute *auth_attrs[] = { 558 548 &auth_is_pass_set.attr, 559 549 &auth_min_pass_length.attr, ··· 633 485 &auth_mechanism.attr, 634 486 &auth_encoding.attr, 635 487 &auth_kbdlang.attr, 488 + &auth_index.attr, 489 + &auth_level.attr, 636 490 NULL 637 491 }; 638 492 639 493 static const struct attribute_group auth_attr_group = { 494 + .is_visible = auth_attr_is_visible, 640 495 .attrs = auth_attrs, 641 496 }; 642 497 ··· 903 752 kobject_put(&tlmi_priv.pwd_admin->kobj); 904 753 sysfs_remove_group(&tlmi_priv.pwd_power->kobj, &auth_attr_group); 905 754 kobject_put(&tlmi_priv.pwd_power->kobj); 755 + 756 + if (tlmi_priv.opcode_support) { 757 + sysfs_remove_group(&tlmi_priv.pwd_system->kobj, &auth_attr_group); 758 + kobject_put(&tlmi_priv.pwd_system->kobj); 759 + sysfs_remove_group(&tlmi_priv.pwd_hdd->kobj, &auth_attr_group); 760 + kobject_put(&tlmi_priv.pwd_hdd->kobj); 761 + sysfs_remove_group(&tlmi_priv.pwd_nvme->kobj, &auth_attr_group); 762 + kobject_put(&tlmi_priv.pwd_nvme->kobj); 763 + } 764 + 906 765 kset_unregister(tlmi_priv.authentication_kset); 907 766 } 908 767 ··· 992 831 goto fail_create_attr; 993 832 994 833 tlmi_priv.pwd_power->kobj.kset = tlmi_priv.authentication_kset; 995 - ret = kobject_add(&tlmi_priv.pwd_power->kobj, NULL, "%s", "System"); 834 + ret = kobject_add(&tlmi_priv.pwd_power->kobj, NULL, "%s", "Power-on"); 996 835 if (ret) 997 836 goto fail_create_attr; 998 837 999 838 ret = sysfs_create_group(&tlmi_priv.pwd_power->kobj, &auth_attr_group); 1000 839 if (ret) 1001 840 goto fail_create_attr; 841 + 842 + if (tlmi_priv.opcode_support) { 843 + tlmi_priv.pwd_system->kobj.kset = tlmi_priv.authentication_kset; 844 + ret = kobject_add(&tlmi_priv.pwd_system->kobj, NULL, "%s", "System"); 845 + if (ret) 846 + goto fail_create_attr; 847 + 848 + ret = sysfs_create_group(&tlmi_priv.pwd_system->kobj, &auth_attr_group); 849 + if (ret) 850 + goto fail_create_attr; 851 + 852 + tlmi_priv.pwd_hdd->kobj.kset = tlmi_priv.authentication_kset; 853 + ret = kobject_add(&tlmi_priv.pwd_hdd->kobj, NULL, "%s", "HDD"); 854 + if (ret) 855 + goto fail_create_attr; 856 + 857 + ret = sysfs_create_group(&tlmi_priv.pwd_hdd->kobj, &auth_attr_group); 858 + if (ret) 859 + goto fail_create_attr; 860 + 861 + tlmi_priv.pwd_nvme->kobj.kset = tlmi_priv.authentication_kset; 862 + ret = kobject_add(&tlmi_priv.pwd_nvme->kobj, NULL, "%s", "NVMe"); 863 + if (ret) 864 + goto fail_create_attr; 865 + 866 + ret = sysfs_create_group(&tlmi_priv.pwd_nvme->kobj, &auth_attr_group); 867 + if (ret) 868 + goto fail_create_attr; 869 + } 1002 870 1003 871 return ret; 1004 872 ··· 1041 851 } 1042 852 1043 853 /* ---- Base Driver -------------------------------------------------------- */ 854 + static struct tlmi_pwd_setting *tlmi_create_auth(const char *pwd_type, 855 + const char *pwd_role) 856 + { 857 + struct tlmi_pwd_setting *new_pwd; 858 + 859 + new_pwd = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL); 860 + if (!new_pwd) 861 + return NULL; 862 + 863 + strscpy(new_pwd->kbdlang, "us", TLMI_LANG_MAXLEN); 864 + new_pwd->encoding = TLMI_ENCODING_ASCII; 865 + new_pwd->pwd_type = pwd_type; 866 + new_pwd->role = pwd_role; 867 + new_pwd->minlen = tlmi_priv.pwdcfg.core.min_length; 868 + new_pwd->maxlen = tlmi_priv.pwdcfg.core.max_length; 869 + new_pwd->index = 0; 870 + 871 + kobject_init(&new_pwd->kobj, &tlmi_pwd_setting_ktype); 872 + 873 + return new_pwd; 874 + } 875 + 1044 876 static int tlmi_analyze(void) 1045 877 { 1046 - struct tlmi_pwdcfg pwdcfg; 1047 878 acpi_status status; 1048 879 int i, ret; 1049 880 ··· 1083 872 1084 873 if (wmi_has_guid(LENOVO_DEBUG_CMD_GUID)) 1085 874 tlmi_priv.can_debug_cmd = true; 875 + 876 + if (wmi_has_guid(LENOVO_OPCODE_IF_GUID)) 877 + tlmi_priv.opcode_support = true; 1086 878 1087 879 /* 1088 880 * Try to find the number of valid settings of this machine ··· 1137 923 } 1138 924 1139 925 /* Create password setting structure */ 1140 - ret = tlmi_get_pwd_settings(&pwdcfg); 926 + ret = tlmi_get_pwd_settings(&tlmi_priv.pwdcfg); 1141 927 if (ret) 1142 928 goto fail_clear_attr; 1143 929 1144 - tlmi_priv.pwd_admin = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL); 1145 - if (!tlmi_priv.pwd_admin) { 1146 - ret = -ENOMEM; 930 + /* All failures below boil down to kmalloc failures */ 931 + ret = -ENOMEM; 932 + 933 + tlmi_priv.pwd_admin = tlmi_create_auth("pap", "bios-admin"); 934 + if (!tlmi_priv.pwd_admin) 1147 935 goto fail_clear_attr; 1148 - } 1149 - strscpy(tlmi_priv.pwd_admin->kbdlang, "us", TLMI_LANG_MAXLEN); 1150 - tlmi_priv.pwd_admin->encoding = TLMI_ENCODING_ASCII; 1151 - tlmi_priv.pwd_admin->pwd_type = "pap"; 1152 - tlmi_priv.pwd_admin->role = "bios-admin"; 1153 - tlmi_priv.pwd_admin->minlen = pwdcfg.min_length; 1154 - if (WARN_ON(pwdcfg.max_length >= TLMI_PWD_BUFSIZE)) 1155 - pwdcfg.max_length = TLMI_PWD_BUFSIZE - 1; 1156 - tlmi_priv.pwd_admin->maxlen = pwdcfg.max_length; 1157 - if (pwdcfg.password_state & TLMI_PAP_PWD) 936 + 937 + if (tlmi_priv.pwdcfg.core.password_state & TLMI_PAP_PWD) 1158 938 tlmi_priv.pwd_admin->valid = true; 1159 939 1160 - kobject_init(&tlmi_priv.pwd_admin->kobj, &tlmi_pwd_setting_ktype); 940 + tlmi_priv.pwd_power = tlmi_create_auth("pop", "power-on"); 941 + if (!tlmi_priv.pwd_power) 942 + goto fail_clear_attr; 1161 943 1162 - tlmi_priv.pwd_power = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL); 1163 - if (!tlmi_priv.pwd_power) { 1164 - ret = -ENOMEM; 1165 - goto fail_free_pwd_admin; 1166 - } 1167 - strscpy(tlmi_priv.pwd_power->kbdlang, "us", TLMI_LANG_MAXLEN); 1168 - tlmi_priv.pwd_power->encoding = TLMI_ENCODING_ASCII; 1169 - tlmi_priv.pwd_power->pwd_type = "pop"; 1170 - tlmi_priv.pwd_power->role = "power-on"; 1171 - tlmi_priv.pwd_power->minlen = pwdcfg.min_length; 1172 - tlmi_priv.pwd_power->maxlen = pwdcfg.max_length; 1173 - 1174 - if (pwdcfg.password_state & TLMI_POP_PWD) 944 + if (tlmi_priv.pwdcfg.core.password_state & TLMI_POP_PWD) 1175 945 tlmi_priv.pwd_power->valid = true; 1176 946 1177 - kobject_init(&tlmi_priv.pwd_power->kobj, &tlmi_pwd_setting_ktype); 947 + if (tlmi_priv.opcode_support) { 948 + tlmi_priv.pwd_system = tlmi_create_auth("sys", "system"); 949 + if (!tlmi_priv.pwd_system) 950 + goto fail_clear_attr; 1178 951 952 + if (tlmi_priv.pwdcfg.core.password_state & TLMI_SYS_PWD) 953 + tlmi_priv.pwd_system->valid = true; 954 + 955 + tlmi_priv.pwd_hdd = tlmi_create_auth("hdd", "hdd"); 956 + if (!tlmi_priv.pwd_hdd) 957 + goto fail_clear_attr; 958 + 959 + tlmi_priv.pwd_nvme = tlmi_create_auth("nvm", "nvme"); 960 + if (!tlmi_priv.pwd_nvme) 961 + goto fail_clear_attr; 962 + 963 + if (tlmi_priv.pwdcfg.core.password_state & TLMI_HDD_PWD) { 964 + /* Check if PWD is configured and set index to first drive found */ 965 + if (tlmi_priv.pwdcfg.ext.hdd_user_password || 966 + tlmi_priv.pwdcfg.ext.hdd_master_password) { 967 + tlmi_priv.pwd_hdd->valid = true; 968 + if (tlmi_priv.pwdcfg.ext.hdd_master_password) 969 + tlmi_priv.pwd_hdd->index = 970 + ffs(tlmi_priv.pwdcfg.ext.hdd_master_password) - 1; 971 + else 972 + tlmi_priv.pwd_hdd->index = 973 + ffs(tlmi_priv.pwdcfg.ext.hdd_user_password) - 1; 974 + } 975 + if (tlmi_priv.pwdcfg.ext.nvme_user_password || 976 + tlmi_priv.pwdcfg.ext.nvme_master_password) { 977 + tlmi_priv.pwd_nvme->valid = true; 978 + if (tlmi_priv.pwdcfg.ext.nvme_master_password) 979 + tlmi_priv.pwd_nvme->index = 980 + ffs(tlmi_priv.pwdcfg.ext.nvme_master_password) - 1; 981 + else 982 + tlmi_priv.pwd_nvme->index = 983 + ffs(tlmi_priv.pwdcfg.ext.nvme_user_password) - 1; 984 + } 985 + } 986 + } 1179 987 return 0; 1180 988 1181 - fail_free_pwd_admin: 1182 - kfree(tlmi_priv.pwd_admin); 1183 989 fail_clear_attr: 1184 990 for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) { 1185 991 if (tlmi_priv.setting[i]) { ··· 1207 973 kfree(tlmi_priv.setting[i]); 1208 974 } 1209 975 } 976 + kfree(tlmi_priv.pwd_admin); 977 + kfree(tlmi_priv.pwd_power); 978 + kfree(tlmi_priv.pwd_system); 979 + kfree(tlmi_priv.pwd_hdd); 980 + kfree(tlmi_priv.pwd_nvme); 1210 981 return ret; 1211 982 } 1212 983
+27 -1
drivers/platform/x86/think-lmi.h
··· 9 9 #define TLMI_SETTINGS_MAXLEN 512 10 10 #define TLMI_PWD_BUFSIZE 129 11 11 #define TLMI_LANG_MAXLEN 4 12 + #define TLMI_INDEX_MAX 32 12 13 13 14 /* Possible error values */ 14 15 struct tlmi_err_codes { ··· 22 21 TLMI_ENCODING_SCANCODE, 23 22 }; 24 23 24 + enum level_option { 25 + TLMI_LEVEL_USER, 26 + TLMI_LEVEL_MASTER, 27 + }; 28 + 25 29 /* password configuration details */ 26 - struct tlmi_pwdcfg { 30 + struct tlmi_pwdcfg_core { 27 31 uint32_t password_mode; 28 32 uint32_t password_state; 29 33 uint32_t min_length; 30 34 uint32_t max_length; 31 35 uint32_t supported_encodings; 32 36 uint32_t supported_keyboard; 37 + }; 38 + 39 + struct tlmi_pwdcfg_ext { 40 + uint32_t hdd_user_password; 41 + uint32_t hdd_master_password; 42 + uint32_t nvme_user_password; 43 + uint32_t nvme_master_password; 44 + }; 45 + 46 + struct tlmi_pwdcfg { 47 + struct tlmi_pwdcfg_core core; 48 + struct tlmi_pwdcfg_ext ext; 33 49 }; 34 50 35 51 /* password setting details */ ··· 60 42 int maxlen; 61 43 enum encoding_option encoding; 62 44 char kbdlang[TLMI_LANG_MAXLEN]; 45 + int index; /*Used for HDD and NVME auth */ 46 + enum level_option level; 63 47 }; 64 48 65 49 /* Attribute setting details */ ··· 81 61 bool can_get_password_settings; 82 62 bool pending_changes; 83 63 bool can_debug_cmd; 64 + bool opcode_support; 84 65 85 66 struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT]; 86 67 struct device *class_dev; 87 68 struct kset *attribute_kset; 88 69 struct kset *authentication_kset; 70 + 71 + struct tlmi_pwdcfg pwdcfg; 89 72 struct tlmi_pwd_setting *pwd_admin; 90 73 struct tlmi_pwd_setting *pwd_power; 74 + struct tlmi_pwd_setting *pwd_system; 75 + struct tlmi_pwd_setting *pwd_hdd; 76 + struct tlmi_pwd_setting *pwd_nvme; 91 77 }; 92 78 93 79 #endif /* !_THINK_LMI_H_ */
+552 -454
drivers/platform/x86/thinkpad_acpi.c
··· 334 334 u32 battery_force_primary:1; 335 335 u32 input_device_registered:1; 336 336 u32 platform_drv_registered:1; 337 - u32 platform_drv_attrs_registered:1; 338 337 u32 sensors_pdrv_registered:1; 339 - u32 sensors_pdrv_attrs_registered:1; 340 - u32 sensors_pdev_attrs_registered:1; 341 338 u32 hotkey_poll_active:1; 342 339 u32 has_adaptive_kbd:1; 340 + u32 kbd_lang:1; 343 341 } tp_features; 344 342 345 343 static struct { ··· 983 985 } 984 986 } 985 987 986 - static struct platform_driver tpacpi_pdriver = { 987 - .driver = { 988 - .name = TPACPI_DRVR_NAME, 989 - .pm = &tpacpi_pm, 990 - }, 991 - .shutdown = tpacpi_shutdown_handler, 992 - }; 993 - 994 - static struct platform_driver tpacpi_hwmon_pdriver = { 995 - .driver = { 996 - .name = TPACPI_HWMON_DRVR_NAME, 997 - }, 998 - }; 999 - 1000 988 /************************************************************************* 1001 989 * sysfs support helpers 1002 990 */ ··· 1464 1480 } 1465 1481 static DRIVER_ATTR_RW(uwb_emulstate); 1466 1482 #endif 1467 - 1468 - /* --------------------------------------------------------------------- */ 1469 - 1470 - static struct driver_attribute *tpacpi_driver_attributes[] = { 1471 - &driver_attr_debug_level, &driver_attr_version, 1472 - &driver_attr_interface_version, 1473 - }; 1474 - 1475 - static int __init tpacpi_create_driver_attributes(struct device_driver *drv) 1476 - { 1477 - int i, res; 1478 - 1479 - i = 0; 1480 - res = 0; 1481 - while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { 1482 - res = driver_create_file(drv, tpacpi_driver_attributes[i]); 1483 - i++; 1484 - } 1485 - 1486 - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 1487 - if (!res && dbg_wlswemul) 1488 - res = driver_create_file(drv, &driver_attr_wlsw_emulstate); 1489 - if (!res && dbg_bluetoothemul) 1490 - res = driver_create_file(drv, &driver_attr_bluetooth_emulstate); 1491 - if (!res && dbg_wwanemul) 1492 - res = driver_create_file(drv, &driver_attr_wwan_emulstate); 1493 - if (!res && dbg_uwbemul) 1494 - res = driver_create_file(drv, &driver_attr_uwb_emulstate); 1495 - #endif 1496 - 1497 - return res; 1498 - } 1499 - 1500 - static void tpacpi_remove_driver_attributes(struct device_driver *drv) 1501 - { 1502 - int i; 1503 - 1504 - for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) 1505 - driver_remove_file(drv, tpacpi_driver_attributes[i]); 1506 - 1507 - #ifdef THINKPAD_ACPI_DEBUGFACILITIES 1508 - driver_remove_file(drv, &driver_attr_wlsw_emulstate); 1509 - driver_remove_file(drv, &driver_attr_bluetooth_emulstate); 1510 - driver_remove_file(drv, &driver_attr_wwan_emulstate); 1511 - driver_remove_file(drv, &driver_attr_uwb_emulstate); 1512 - #endif 1513 - } 1514 1483 1515 1484 /************************************************************************* 1516 1485 * Firmware Data ··· 2938 3001 NULL 2939 3002 }; 2940 3003 3004 + static umode_t hadaptive_kbd_attr_is_visible(struct kobject *kobj, 3005 + struct attribute *attr, int n) 3006 + { 3007 + return tp_features.has_adaptive_kbd ? attr->mode : 0; 3008 + } 3009 + 2941 3010 static const struct attribute_group adaptive_kbd_attr_group = { 3011 + .is_visible = hadaptive_kbd_attr_is_visible, 2942 3012 .attrs = adaptive_kbd_attributes, 2943 3013 }; 2944 3014 ··· 3042 3098 hotkey_poll_stop_sync(); 3043 3099 mutex_unlock(&hotkey_mutex); 3044 3100 #endif 3045 - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group); 3046 - 3047 3101 dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, 3048 3102 "restoring original HKEY status and mask\n"); 3049 3103 /* yes, there is a bitwise or below, we want the ··· 3380 3438 str_supported(tp_features.hotkey)); 3381 3439 3382 3440 if (!tp_features.hotkey) 3383 - return 1; 3441 + return -ENODEV; 3384 3442 3385 3443 quirks = tpacpi_check_quirks(tpacpi_hotkey_qtable, 3386 3444 ARRAY_SIZE(tpacpi_hotkey_qtable)); ··· 3436 3494 */ 3437 3495 if (acpi_evalf(hkey_handle, &hotkey_adaptive_all_mask, 3438 3496 "MHKA", "dd", 2)) { 3439 - if (hotkey_adaptive_all_mask != 0) { 3497 + if (hotkey_adaptive_all_mask != 0) 3440 3498 tp_features.has_adaptive_kbd = true; 3441 - res = sysfs_create_group( 3442 - &tpacpi_pdev->dev.kobj, 3443 - &adaptive_kbd_attr_group); 3444 - if (res) 3445 - goto err_exit; 3446 - } 3447 3499 } else { 3448 3500 tp_features.has_adaptive_kbd = false; 3449 3501 hotkey_adaptive_all_mask = 0x0U; ··· 3467 3531 * the first hotkey_mask_get to return hotkey_orig_mask */ 3468 3532 res = hotkey_mask_get(); 3469 3533 if (res) 3470 - goto err_exit; 3534 + return res; 3471 3535 3472 3536 hotkey_orig_mask = hotkey_acpi_mask; 3473 3537 } else { ··· 3491 3555 } 3492 3556 3493 3557 tabletsw_state = hotkey_init_tablet_mode(); 3494 - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group); 3495 - if (res) 3496 - goto err_exit; 3497 3558 3498 3559 /* Set up key map */ 3499 3560 keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, ··· 3503 3570 TPACPI_HOTKEY_MAP_SIZE, GFP_KERNEL); 3504 3571 if (!hotkey_keycode_map) { 3505 3572 pr_err("failed to allocate memory for key map\n"); 3506 - res = -ENOMEM; 3507 - goto err_exit; 3573 + return -ENOMEM; 3508 3574 } 3509 3575 3510 3576 input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN); ··· 3584 3652 hotkey_poll_setup_safe(true); 3585 3653 3586 3654 return 0; 3587 - 3588 - err_exit: 3589 - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group); 3590 - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &adaptive_kbd_attr_group); 3591 - 3592 - return (res < 0) ? res : 1; 3593 3655 } 3594 3656 3595 3657 /* Thinkpad X1 Carbon support 5 modes including Home mode, Web browser ··· 4328 4402 NULL 4329 4403 }; 4330 4404 4405 + static umode_t bluetooth_attr_is_visible(struct kobject *kobj, 4406 + struct attribute *attr, int n) 4407 + { 4408 + return tp_features.bluetooth ? attr->mode : 0; 4409 + } 4410 + 4331 4411 static const struct attribute_group bluetooth_attr_group = { 4412 + .is_visible = bluetooth_attr_is_visible, 4332 4413 .attrs = bluetooth_attributes, 4333 4414 }; 4334 4415 ··· 4357 4424 4358 4425 static void bluetooth_exit(void) 4359 4426 { 4360 - sysfs_remove_group(&tpacpi_pdev->dev.kobj, 4361 - &bluetooth_attr_group); 4362 - 4363 4427 tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); 4364 - 4365 4428 bluetooth_shutdown(); 4366 4429 } 4367 4430 ··· 4464 4535 } 4465 4536 4466 4537 if (!tp_features.bluetooth) 4467 - return 1; 4538 + return -ENODEV; 4468 4539 4469 4540 res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, 4470 4541 &bluetooth_tprfk_ops, 4471 4542 RFKILL_TYPE_BLUETOOTH, 4472 4543 TPACPI_RFK_BLUETOOTH_SW_NAME, 4473 4544 true); 4474 - if (res) 4475 - return res; 4476 - 4477 - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, 4478 - &bluetooth_attr_group); 4479 - if (res) { 4480 - tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); 4481 - return res; 4482 - } 4483 - 4484 - return 0; 4545 + return res; 4485 4546 } 4486 4547 4487 4548 /* procfs -------------------------------------------------------------- */ ··· 4578 4659 NULL 4579 4660 }; 4580 4661 4662 + static umode_t wan_attr_is_visible(struct kobject *kobj, struct attribute *attr, 4663 + int n) 4664 + { 4665 + return tp_features.wan ? attr->mode : 0; 4666 + } 4667 + 4581 4668 static const struct attribute_group wan_attr_group = { 4669 + .is_visible = wan_attr_is_visible, 4582 4670 .attrs = wan_attributes, 4583 4671 }; 4584 4672 ··· 4607 4681 4608 4682 static void wan_exit(void) 4609 4683 { 4610 - sysfs_remove_group(&tpacpi_pdev->dev.kobj, 4611 - &wan_attr_group); 4612 - 4613 4684 tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); 4614 - 4615 4685 wan_shutdown(); 4616 4686 } 4617 4687 ··· 4644 4722 } 4645 4723 4646 4724 if (!tp_features.wan) 4647 - return 1; 4725 + return -ENODEV; 4648 4726 4649 4727 res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, 4650 4728 &wan_tprfk_ops, 4651 4729 RFKILL_TYPE_WWAN, 4652 4730 TPACPI_RFK_WWAN_SW_NAME, 4653 4731 true); 4654 - if (res) 4655 - return res; 4656 - 4657 - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, 4658 - &wan_attr_group); 4659 - 4660 - if (res) { 4661 - tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); 4662 - return res; 4663 - } 4664 - 4665 - return 0; 4732 + return res; 4666 4733 } 4667 4734 4668 4735 /* procfs -------------------------------------------------------------- */ ··· 4773 4862 } 4774 4863 4775 4864 if (!tp_features.uwb) 4776 - return 1; 4865 + return -ENODEV; 4777 4866 4778 4867 res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, 4779 4868 &uwb_tprfk_ops, ··· 4866 4955 str_supported(video_supported != TPACPI_VIDEO_NONE), 4867 4956 video_supported); 4868 4957 4869 - return (video_supported != TPACPI_VIDEO_NONE) ? 0 : 1; 4958 + return (video_supported != TPACPI_VIDEO_NONE) ? 0 : -ENODEV; 4870 4959 } 4871 4960 4872 4961 static void video_exit(void) ··· 5274 5363 if (!kbdlight_is_supported()) { 5275 5364 tp_features.kbdlight = 0; 5276 5365 vdbg_printk(TPACPI_DBG_INIT, "kbdlight is unsupported\n"); 5277 - return 1; 5366 + return -ENODEV; 5278 5367 } 5279 5368 5280 5369 kbdlight_brightness = kbdlight_sysfs_get(NULL); ··· 5464 5553 str_supported(tp_features.light_status)); 5465 5554 5466 5555 if (!tp_features.light) 5467 - return 1; 5556 + return -ENODEV; 5468 5557 5469 5558 rc = led_classdev_register(&tpacpi_pdev->dev, 5470 5559 &tpacpi_led_thinklight.led_classdev); ··· 5552 5641 5553 5642 static DEVICE_ATTR_WO(cmos_command); 5554 5643 5644 + static struct attribute *cmos_attributes[] = { 5645 + &dev_attr_cmos_command.attr, 5646 + NULL 5647 + }; 5648 + 5649 + static umode_t cmos_attr_is_visible(struct kobject *kobj, 5650 + struct attribute *attr, int n) 5651 + { 5652 + return cmos_handle ? attr->mode : 0; 5653 + } 5654 + 5655 + static const struct attribute_group cmos_attr_group = { 5656 + .is_visible = cmos_attr_is_visible, 5657 + .attrs = cmos_attributes, 5658 + }; 5659 + 5555 5660 /* --------------------------------------------------------------------- */ 5556 5661 5557 5662 static int __init cmos_init(struct ibm_init_struct *iibm) 5558 5663 { 5559 - int res; 5560 - 5561 5664 vdbg_printk(TPACPI_DBG_INIT, 5562 - "initializing cmos commands subdriver\n"); 5665 + "initializing cmos commands subdriver\n"); 5563 5666 5564 5667 TPACPI_ACPIHANDLE_INIT(cmos); 5565 5668 5566 5669 vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", 5567 - str_supported(cmos_handle != NULL)); 5670 + str_supported(cmos_handle != NULL)); 5568 5671 5569 - res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); 5570 - if (res) 5571 - return res; 5572 - 5573 - return (cmos_handle) ? 0 : 1; 5574 - } 5575 - 5576 - static void cmos_exit(void) 5577 - { 5578 - device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); 5672 + return cmos_handle ? 0 : -ENODEV; 5579 5673 } 5580 5674 5581 5675 static int cmos_read(struct seq_file *m) ··· 5621 5705 .name = "cmos", 5622 5706 .read = cmos_read, 5623 5707 .write = cmos_write, 5624 - .exit = cmos_exit, 5625 5708 }; 5626 5709 5627 5710 /************************************************************************* ··· 5825 5910 tpacpi_leds[led].led_classdev.brightness_get = &led_sysfs_get; 5826 5911 5827 5912 tpacpi_leds[led].led_classdev.name = tpacpi_led_names[led]; 5913 + tpacpi_leds[led].led_classdev.flags = LED_RETAIN_AT_SHUTDOWN; 5828 5914 tpacpi_leds[led].led = led; 5829 5915 5830 5916 return led_classdev_register(&tpacpi_pdev->dev, &tpacpi_leds[led].led_classdev); ··· 5926 6010 str_supported(led_supported), led_supported); 5927 6011 5928 6012 if (led_supported == TPACPI_LED_NONE) 5929 - return 1; 6013 + return -ENODEV; 5930 6014 5931 6015 tpacpi_leds = kcalloc(TPACPI_LED_NUMLEDS, sizeof(*tpacpi_leds), 5932 6016 GFP_KERNEL); ··· 6055 6139 6056 6140 tp_features.beep_needs_two_args = !!(quirks & TPACPI_BEEP_Q1); 6057 6141 6058 - return (beep_handle) ? 0 : 1; 6142 + return (beep_handle) ? 0 : -ENODEV; 6059 6143 } 6060 6144 6061 6145 static int beep_read(struct seq_file *m) ··· 6132 6216 }; 6133 6217 6134 6218 static enum thermal_access_mode thermal_read_mode; 6135 - static const struct attribute_group *thermal_attr_group; 6136 6219 static bool thermal_use_labels; 6137 6220 6138 6221 /* idx is zero-based */ ··· 6285 6370 &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr 6286 6371 6287 6372 static struct attribute *thermal_temp_input_attr[] = { 6288 - THERMAL_ATTRS(8), 6289 - THERMAL_ATTRS(9), 6290 - THERMAL_ATTRS(10), 6291 - THERMAL_ATTRS(11), 6292 - THERMAL_ATTRS(12), 6293 - THERMAL_ATTRS(13), 6294 - THERMAL_ATTRS(14), 6295 - THERMAL_ATTRS(15), 6296 6373 THERMAL_ATTRS(0), 6297 6374 THERMAL_ATTRS(1), 6298 6375 THERMAL_ATTRS(2), ··· 6293 6386 THERMAL_ATTRS(5), 6294 6387 THERMAL_ATTRS(6), 6295 6388 THERMAL_ATTRS(7), 6389 + THERMAL_ATTRS(8), 6390 + THERMAL_ATTRS(9), 6391 + THERMAL_ATTRS(10), 6392 + THERMAL_ATTRS(11), 6393 + THERMAL_ATTRS(12), 6394 + THERMAL_ATTRS(13), 6395 + THERMAL_ATTRS(14), 6396 + THERMAL_ATTRS(15), 6296 6397 NULL 6297 6398 }; 6298 6399 6299 - static const struct attribute_group thermal_temp_input16_group = { 6300 - .attrs = thermal_temp_input_attr 6301 - }; 6400 + static umode_t thermal_attr_is_visible(struct kobject *kobj, 6401 + struct attribute *attr, int n) 6402 + { 6403 + if (thermal_read_mode == TPACPI_THERMAL_NONE) 6404 + return 0; 6302 6405 6303 - static const struct attribute_group thermal_temp_input8_group = { 6304 - .attrs = &thermal_temp_input_attr[8] 6406 + if (attr == THERMAL_ATTRS(8) || attr == THERMAL_ATTRS(9) || 6407 + attr == THERMAL_ATTRS(10) || attr == THERMAL_ATTRS(11) || 6408 + attr == THERMAL_ATTRS(12) || attr == THERMAL_ATTRS(13) || 6409 + attr == THERMAL_ATTRS(14) || attr == THERMAL_ATTRS(15)) { 6410 + if (thermal_read_mode != TPACPI_THERMAL_TPEC_16) 6411 + return 0; 6412 + } 6413 + 6414 + return attr->mode; 6415 + } 6416 + 6417 + static const struct attribute_group thermal_attr_group = { 6418 + .is_visible = thermal_attr_is_visible, 6419 + .attrs = thermal_temp_input_attr, 6305 6420 }; 6306 6421 6307 6422 #undef THERMAL_SENSOR_ATTR_TEMP ··· 6347 6418 NULL 6348 6419 }; 6349 6420 6421 + static umode_t temp_label_attr_is_visible(struct kobject *kobj, 6422 + struct attribute *attr, int n) 6423 + { 6424 + return thermal_use_labels ? attr->mode : 0; 6425 + } 6426 + 6350 6427 static const struct attribute_group temp_label_attr_group = { 6428 + .is_visible = temp_label_attr_is_visible, 6351 6429 .attrs = temp_label_attributes, 6352 6430 }; 6353 6431 ··· 6365 6429 u8 t, ta1, ta2, ver = 0; 6366 6430 int i; 6367 6431 int acpi_tmp7; 6368 - int res; 6369 6432 6370 6433 vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); 6371 6434 ··· 6439 6504 str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), 6440 6505 thermal_read_mode); 6441 6506 6442 - switch (thermal_read_mode) { 6443 - case TPACPI_THERMAL_TPEC_16: 6444 - thermal_attr_group = &thermal_temp_input16_group; 6445 - break; 6446 - case TPACPI_THERMAL_TPEC_8: 6447 - case TPACPI_THERMAL_ACPI_TMP07: 6448 - case TPACPI_THERMAL_ACPI_UPDT: 6449 - thermal_attr_group = &thermal_temp_input8_group; 6450 - break; 6451 - case TPACPI_THERMAL_NONE: 6452 - default: 6453 - return 1; 6454 - } 6455 - 6456 - res = sysfs_create_group(&tpacpi_hwmon->kobj, thermal_attr_group); 6457 - if (res) 6458 - return res; 6459 - 6460 - if (thermal_use_labels) { 6461 - res = sysfs_create_group(&tpacpi_hwmon->kobj, &temp_label_attr_group); 6462 - if (res) { 6463 - sysfs_remove_group(&tpacpi_hwmon->kobj, thermal_attr_group); 6464 - return res; 6465 - } 6466 - } 6467 - 6468 - return 0; 6469 - } 6470 - 6471 - static void thermal_exit(void) 6472 - { 6473 - if (thermal_attr_group) 6474 - sysfs_remove_group(&tpacpi_hwmon->kobj, thermal_attr_group); 6475 - 6476 - if (thermal_use_labels) 6477 - sysfs_remove_group(&tpacpi_hwmon->kobj, &temp_label_attr_group); 6507 + return thermal_read_mode != TPACPI_THERMAL_NONE ? 0 : -ENODEV; 6478 6508 } 6479 6509 6480 6510 static int thermal_read(struct seq_file *m) ··· 6466 6566 static struct ibm_struct thermal_driver_data = { 6467 6567 .name = "thermal", 6468 6568 .read = thermal_read, 6469 - .exit = thermal_exit, 6470 6569 }; 6471 6570 6472 6571 /************************************************************************* ··· 6850 6951 6851 6952 /* if it is unknown, we don't handle it: it wouldn't be safe */ 6852 6953 if (tp_features.bright_unkfw) 6853 - return 1; 6954 + return -ENODEV; 6854 6955 6855 6956 if (!brightness_enable) { 6856 6957 dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, 6857 6958 "brightness support disabled by module parameter\n"); 6858 - return 1; 6959 + return -ENODEV; 6859 6960 } 6860 6961 6861 6962 if (acpi_video_get_backlight_type() != acpi_backlight_vendor) { 6862 6963 if (brightness_enable > 1) { 6863 6964 pr_info("Standard ACPI backlight interface available, not loading native one\n"); 6864 - return 1; 6965 + return -ENODEV; 6865 6966 } else if (brightness_enable == 1) { 6866 6967 pr_warn("Cannot enable backlight brightness support, ACPI is already handling it. Refer to the acpi_backlight kernel parameter.\n"); 6867 - return 1; 6968 + return -ENODEV; 6868 6969 } 6869 6970 } else if (!tp_features.bright_acpimode) { 6870 6971 pr_notice("ACPI backlight interface not available\n"); 6871 - return 1; 6972 + return -ENODEV; 6872 6973 } 6873 6974 6874 6975 pr_notice("ACPI native brightness control enabled\n"); ··· 6901 7002 return -EINVAL; 6902 7003 6903 7004 if (tpacpi_brightness_get_raw(&b) < 0) 6904 - return 1; 7005 + return -ENODEV; 6905 7006 6906 7007 memset(&props, 0, sizeof(struct backlight_properties)); 6907 7008 props.type = BACKLIGHT_PLATFORM; ··· 7491 7592 sizeof(struct tpacpi_alsa_data), &card); 7492 7593 if (rc < 0 || !card) { 7493 7594 pr_err("Failed to create ALSA card structures: %d\n", rc); 7494 - return 1; 7595 + return -ENODEV; 7495 7596 } 7496 7597 7497 7598 BUG_ON(!card->private_data); ··· 7550 7651 7551 7652 err_exit: 7552 7653 snd_card_free(card); 7553 - return 1; 7654 + return -ENODEV; 7554 7655 } 7555 7656 7556 7657 #define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */ ··· 7599 7700 if (volume_mode == TPACPI_VOL_MODE_UCMS_STEP) { 7600 7701 pr_err("UCMS step volume mode not implemented, please contact %s\n", 7601 7702 TPACPI_MAIL); 7602 - return 1; 7703 + return -ENODEV; 7603 7704 } 7604 7705 7605 7706 if (volume_capabilities >= TPACPI_VOL_CAP_MAX) ··· 7612 7713 if (!alsa_enable) { 7613 7714 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, 7614 7715 "ALSA mixer disabled by parameter, not loading volume subdriver...\n"); 7615 - return 1; 7716 + return -ENODEV; 7616 7717 } 7617 7718 7618 7719 quirks = tpacpi_check_quirks(volume_quirk_table, ··· 7625 7726 else if (quirks & TPACPI_VOL_Q_LEVEL) 7626 7727 tp_features.mixer_no_level_control = 0; 7627 7728 else 7628 - return 1; /* no mixer */ 7729 + return -ENODEV; /* no mixer */ 7629 7730 break; 7630 7731 case TPACPI_VOL_CAP_VOLMUTE: 7631 7732 tp_features.mixer_no_level_control = 0; ··· 7634 7735 tp_features.mixer_no_level_control = 1; 7635 7736 break; 7636 7737 default: 7637 - return 1; 7738 + return -ENODEV; 7638 7739 } 7639 7740 7640 7741 if (volume_capabilities != TPACPI_VOL_CAP_AUTO) ··· 7806 7907 { 7807 7908 pr_info("volume: disabled as there is no ALSA support in this kernel\n"); 7808 7909 7809 - return 1; 7910 + return -ENODEV; 7810 7911 } 7811 7912 7812 7913 static struct ibm_struct volume_driver_data = { ··· 8640 8741 static DRIVER_ATTR_RW(fan_watchdog); 8641 8742 8642 8743 /* --------------------------------------------------------------------- */ 8744 + 8643 8745 static struct attribute *fan_attributes[] = { 8644 - &dev_attr_pwm1_enable.attr, &dev_attr_pwm1.attr, 8746 + &dev_attr_pwm1_enable.attr, 8747 + &dev_attr_pwm1.attr, 8645 8748 &dev_attr_fan1_input.attr, 8646 - NULL, /* for fan2_input */ 8749 + &dev_attr_fan2_input.attr, 8647 8750 NULL 8648 8751 }; 8649 8752 8753 + static umode_t fan_attr_is_visible(struct kobject *kobj, struct attribute *attr, 8754 + int n) 8755 + { 8756 + if (fan_status_access_mode == TPACPI_FAN_NONE && 8757 + fan_control_access_mode == TPACPI_FAN_WR_NONE) 8758 + return 0; 8759 + 8760 + if (attr == &dev_attr_fan2_input.attr) { 8761 + if (!tp_features.second_fan) 8762 + return 0; 8763 + } 8764 + 8765 + return attr->mode; 8766 + } 8767 + 8650 8768 static const struct attribute_group fan_attr_group = { 8769 + .is_visible = fan_attr_is_visible, 8651 8770 .attrs = fan_attributes, 8771 + }; 8772 + 8773 + static struct attribute *fan_driver_attributes[] = { 8774 + &driver_attr_fan_watchdog.attr, 8775 + NULL 8776 + }; 8777 + 8778 + static const struct attribute_group fan_driver_attr_group = { 8779 + .is_visible = fan_attr_is_visible, 8780 + .attrs = fan_driver_attributes, 8652 8781 }; 8653 8782 8654 8783 #define TPACPI_FAN_Q1 0x0001 /* Unitialized HFSP */ ··· 8706 8779 8707 8780 static int __init fan_init(struct ibm_init_struct *iibm) 8708 8781 { 8709 - int rc; 8710 8782 unsigned long quirks; 8711 8783 8712 8784 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, ··· 8752 8826 } 8753 8827 } else { 8754 8828 pr_err("ThinkPad ACPI EC access misbehaving, fan status and control unavailable\n"); 8755 - return 1; 8829 + return -ENODEV; 8756 8830 } 8757 8831 } 8758 8832 ··· 8801 8875 if (fan_status_access_mode != TPACPI_FAN_NONE) 8802 8876 fan_get_status_safe(NULL); 8803 8877 8804 - if (fan_status_access_mode != TPACPI_FAN_NONE || 8805 - fan_control_access_mode != TPACPI_FAN_WR_NONE) { 8806 - if (tp_features.second_fan) { 8807 - /* attach second fan tachometer */ 8808 - fan_attributes[ARRAY_SIZE(fan_attributes)-2] = 8809 - &dev_attr_fan2_input.attr; 8810 - } 8811 - rc = sysfs_create_group(&tpacpi_hwmon->kobj, 8812 - &fan_attr_group); 8813 - if (rc < 0) 8814 - return rc; 8878 + if (fan_status_access_mode == TPACPI_FAN_NONE && 8879 + fan_control_access_mode == TPACPI_FAN_WR_NONE) 8880 + return -ENODEV; 8815 8881 8816 - rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, 8817 - &driver_attr_fan_watchdog); 8818 - if (rc < 0) { 8819 - sysfs_remove_group(&tpacpi_hwmon->kobj, 8820 - &fan_attr_group); 8821 - return rc; 8822 - } 8823 - return 0; 8824 - } else 8825 - return 1; 8882 + return 0; 8826 8883 } 8827 8884 8828 8885 static void fan_exit(void) 8829 8886 { 8830 8887 vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_FAN, 8831 8888 "cancelling any pending fan watchdog tasks\n"); 8832 - 8833 - /* FIXME: can we really do this unconditionally? */ 8834 - sysfs_remove_group(&tpacpi_hwmon->kobj, &fan_attr_group); 8835 - driver_remove_file(&tpacpi_hwmon_pdriver.driver, 8836 - &driver_attr_fan_watchdog); 8837 8889 8838 8890 cancel_delayed_work(&fan_watchdog_task); 8839 8891 flush_workqueue(tpacpi_wq); ··· 9230 9326 #define SET_START "BCCS" 9231 9327 #define GET_STOP "BCSG" 9232 9328 #define SET_STOP "BCSS" 9329 + #define GET_DISCHARGE "BDSG" 9330 + #define SET_DISCHARGE "BDSS" 9331 + #define GET_INHIBIT "BICG" 9332 + #define SET_INHIBIT "BICS" 9233 9333 9234 9334 enum { 9235 9335 BAT_ANY = 0, ··· 9250 9342 /* This is used in the get/set helpers */ 9251 9343 THRESHOLD_START, 9252 9344 THRESHOLD_STOP, 9345 + FORCE_DISCHARGE, 9346 + INHIBIT_CHARGE, 9253 9347 }; 9254 9348 9255 9349 struct tpacpi_battery_data { ··· 9259 9349 int start_support; 9260 9350 int charge_stop; 9261 9351 int stop_support; 9352 + unsigned int charge_behaviours; 9262 9353 }; 9263 9354 9264 9355 struct tpacpi_battery_driver_data { ··· 9317 9406 if (*ret == 0) 9318 9407 *ret = 100; 9319 9408 return 0; 9409 + case FORCE_DISCHARGE: 9410 + if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_DISCHARGE, ret, battery)) 9411 + return -ENODEV; 9412 + /* The force discharge status is in bit 0 */ 9413 + *ret = *ret & 0x01; 9414 + return 0; 9415 + case INHIBIT_CHARGE: 9416 + if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_INHIBIT, ret, battery)) 9417 + return -ENODEV; 9418 + /* The inhibit charge status is in bit 0 */ 9419 + *ret = *ret & 0x01; 9420 + return 0; 9320 9421 default: 9321 9422 pr_crit("wrong parameter: %d", what); 9322 9423 return -EINVAL; ··· 9357 9434 return -ENODEV; 9358 9435 } 9359 9436 return 0; 9437 + case FORCE_DISCHARGE: 9438 + /* Force discharge is in bit 0, 9439 + * break on AC attach is in bit 1 (won't work on some ThinkPads), 9440 + * battery ID is in bits 8-9, 2 bits. 9441 + */ 9442 + if (ACPI_FAILURE(tpacpi_battery_acpi_eval(SET_DISCHARGE, &ret, param))) { 9443 + pr_err("failed to set force discharge on %d", battery); 9444 + return -ENODEV; 9445 + } 9446 + return 0; 9447 + case INHIBIT_CHARGE: 9448 + /* When setting inhibit charge, we set a default value of 9449 + * always breaking on AC detach and the effective time is set to 9450 + * be permanent. 9451 + * The battery ID is in bits 4-5, 2 bits, 9452 + * the effective time is in bits 8-23, 2 bytes. 9453 + * A time of FFFF indicates forever. 9454 + */ 9455 + param = value; 9456 + param |= battery << 4; 9457 + param |= 0xFFFF << 8; 9458 + if (ACPI_FAILURE(tpacpi_battery_acpi_eval(SET_INHIBIT, &ret, param))) { 9459 + pr_err("failed to set inhibit charge on %d", battery); 9460 + return -ENODEV; 9461 + } 9462 + return 0; 9360 9463 default: 9361 9464 pr_crit("wrong parameter: %d", what); 9362 9465 return -EINVAL; 9363 9466 } 9467 + } 9468 + 9469 + static int tpacpi_battery_set_validate(int what, int battery, int value) 9470 + { 9471 + int ret, v; 9472 + 9473 + ret = tpacpi_battery_set(what, battery, value); 9474 + if (ret < 0) 9475 + return ret; 9476 + 9477 + ret = tpacpi_battery_get(what, battery, &v); 9478 + if (ret < 0) 9479 + return ret; 9480 + 9481 + if (v == value) 9482 + return 0; 9483 + 9484 + msleep(500); 9485 + 9486 + ret = tpacpi_battery_get(what, battery, &v); 9487 + if (ret < 0) 9488 + return ret; 9489 + 9490 + if (v == value) 9491 + return 0; 9492 + 9493 + return -EIO; 9364 9494 } 9365 9495 9366 9496 static int tpacpi_battery_probe(int battery) ··· 9428 9452 * 2) Check for support 9429 9453 * 3) Get the current stop threshold 9430 9454 * 4) Check for support 9455 + * 5) Get the current force discharge status 9456 + * 6) Check for support 9457 + * 7) Get the current inhibit charge status 9458 + * 8) Check for support 9431 9459 */ 9432 9460 if (acpi_has_method(hkey_handle, GET_START)) { 9433 9461 if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, &ret, battery)) { ··· 9468 9488 return -ENODEV; 9469 9489 } 9470 9490 } 9471 - pr_info("battery %d registered (start %d, stop %d)", 9472 - battery, 9473 - battery_info.batteries[battery].charge_start, 9474 - battery_info.batteries[battery].charge_stop); 9491 + if (acpi_has_method(hkey_handle, GET_DISCHARGE)) { 9492 + if (ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_DISCHARGE, &ret, battery))) { 9493 + pr_err("Error probing battery discharge; %d\n", battery); 9494 + return -ENODEV; 9495 + } 9496 + /* Support is marked in bit 8 */ 9497 + if (ret & BIT(8)) 9498 + battery_info.batteries[battery].charge_behaviours |= 9499 + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE); 9500 + } 9501 + if (acpi_has_method(hkey_handle, GET_INHIBIT)) { 9502 + if (ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_INHIBIT, &ret, battery))) { 9503 + pr_err("Error probing battery inhibit charge; %d\n", battery); 9504 + return -ENODEV; 9505 + } 9506 + /* Support is marked in bit 5 */ 9507 + if (ret & BIT(5)) 9508 + battery_info.batteries[battery].charge_behaviours |= 9509 + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE); 9510 + } 9511 + 9512 + battery_info.batteries[battery].charge_behaviours |= 9513 + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO); 9514 + 9515 + pr_info("battery %d registered (start %d, stop %d, behaviours: 0x%x)\n", 9516 + battery, 9517 + battery_info.batteries[battery].charge_start, 9518 + battery_info.batteries[battery].charge_stop, 9519 + battery_info.batteries[battery].charge_behaviours); 9475 9520 9476 9521 return 0; 9477 9522 } ··· 9631 9626 return tpacpi_battery_show(THRESHOLD_STOP, device, buf); 9632 9627 } 9633 9628 9629 + static ssize_t charge_behaviour_show(struct device *dev, 9630 + struct device_attribute *attr, 9631 + char *buf) 9632 + { 9633 + enum power_supply_charge_behaviour active = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; 9634 + struct power_supply *supply = to_power_supply(dev); 9635 + unsigned int available; 9636 + int ret, battery; 9637 + 9638 + battery = tpacpi_battery_get_id(supply->desc->name); 9639 + available = battery_info.batteries[battery].charge_behaviours; 9640 + 9641 + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) { 9642 + if (tpacpi_battery_get(FORCE_DISCHARGE, battery, &ret)) 9643 + return -ENODEV; 9644 + if (ret) { 9645 + active = POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE; 9646 + goto out; 9647 + } 9648 + } 9649 + 9650 + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)) { 9651 + if (tpacpi_battery_get(INHIBIT_CHARGE, battery, &ret)) 9652 + return -ENODEV; 9653 + if (ret) { 9654 + active = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; 9655 + goto out; 9656 + } 9657 + } 9658 + 9659 + out: 9660 + return power_supply_charge_behaviour_show(dev, available, active, buf); 9661 + } 9662 + 9634 9663 static ssize_t charge_control_start_threshold_store(struct device *dev, 9635 9664 struct device_attribute *attr, 9636 9665 const char *buf, size_t count) ··· 9679 9640 return tpacpi_battery_store(THRESHOLD_STOP, dev, buf, count); 9680 9641 } 9681 9642 9643 + static ssize_t charge_behaviour_store(struct device *dev, 9644 + struct device_attribute *attr, 9645 + const char *buf, size_t count) 9646 + { 9647 + struct power_supply *supply = to_power_supply(dev); 9648 + int selected, battery, ret = 0; 9649 + unsigned int available; 9650 + 9651 + battery = tpacpi_battery_get_id(supply->desc->name); 9652 + available = battery_info.batteries[battery].charge_behaviours; 9653 + selected = power_supply_charge_behaviour_parse(available, buf); 9654 + 9655 + if (selected < 0) 9656 + return selected; 9657 + 9658 + switch (selected) { 9659 + case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: 9660 + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) 9661 + ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 0); 9662 + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)) 9663 + ret = min(ret, tpacpi_battery_set_validate(INHIBIT_CHARGE, battery, 0)); 9664 + if (ret < 0) 9665 + return ret; 9666 + break; 9667 + case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE: 9668 + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)) 9669 + ret = tpacpi_battery_set_validate(INHIBIT_CHARGE, battery, 0); 9670 + ret = min(ret, tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 1)); 9671 + if (ret < 0) 9672 + return ret; 9673 + break; 9674 + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: 9675 + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) 9676 + ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 0); 9677 + ret = min(ret, tpacpi_battery_set_validate(INHIBIT_CHARGE, battery, 1)); 9678 + if (ret < 0) 9679 + return ret; 9680 + break; 9681 + default: 9682 + dev_err(dev, "Unexpected charge behaviour: %d\n", selected); 9683 + return -EINVAL; 9684 + } 9685 + 9686 + return count; 9687 + } 9688 + 9682 9689 static DEVICE_ATTR_RW(charge_control_start_threshold); 9683 9690 static DEVICE_ATTR_RW(charge_control_end_threshold); 9691 + static DEVICE_ATTR_RW(charge_behaviour); 9684 9692 static struct device_attribute dev_attr_charge_start_threshold = __ATTR( 9685 9693 charge_start_threshold, 9686 9694 0644, ··· 9746 9660 &dev_attr_charge_control_end_threshold.attr, 9747 9661 &dev_attr_charge_start_threshold.attr, 9748 9662 &dev_attr_charge_stop_threshold.attr, 9663 + &dev_attr_charge_behaviour.attr, 9749 9664 NULL, 9750 9665 }; 9751 9666 ··· 9971 9884 return 0; 9972 9885 } 9973 9886 9974 - static int dytc_get_version(void) 9975 - { 9976 - int err, output; 9977 - 9978 - /* Check if we've been called before - and just return cached value */ 9979 - if (dytc_version) 9980 - return dytc_version; 9981 - 9982 - /* Otherwise query DYTC and extract version information */ 9983 - err = dytc_command(DYTC_CMD_QUERY, &output); 9984 - /* 9985 - * If support isn't available (ENODEV) then don't return an error 9986 - * and don't create the sysfs group 9987 - */ 9988 - if (err == -ENODEV) 9989 - return 0; 9990 - /* For all other errors we can flag the failure */ 9991 - if (err) 9992 - return err; 9993 - 9994 - /* Check DYTC is enabled and supports mode setting */ 9995 - if (output & BIT(DYTC_QUERY_ENABLE_BIT)) 9996 - dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF; 9997 - 9998 - return 0; 9999 - } 10000 - 10001 9887 static int lapsensor_get(bool *present, bool *state) 10002 9888 { 10003 9889 int output, err; ··· 10053 9993 } 10054 9994 static DEVICE_ATTR_RO(palmsensor); 10055 9995 9996 + static struct attribute *proxsensor_attributes[] = { 9997 + &dev_attr_dytc_lapmode.attr, 9998 + &dev_attr_palmsensor.attr, 9999 + NULL 10000 + }; 10001 + 10002 + static umode_t proxsensor_attr_is_visible(struct kobject *kobj, 10003 + struct attribute *attr, int n) 10004 + { 10005 + if (attr == &dev_attr_dytc_lapmode.attr) { 10006 + /* 10007 + * Platforms before DYTC version 5 claim to have a lap sensor, 10008 + * but it doesn't work, so we ignore them. 10009 + */ 10010 + if (!has_lapsensor || dytc_version < 5) 10011 + return 0; 10012 + } else if (attr == &dev_attr_palmsensor.attr) { 10013 + if (!has_palmsensor) 10014 + return 0; 10015 + } 10016 + 10017 + return attr->mode; 10018 + } 10019 + 10020 + static const struct attribute_group proxsensor_attr_group = { 10021 + .is_visible = proxsensor_attr_is_visible, 10022 + .attrs = proxsensor_attributes, 10023 + }; 10024 + 10056 10025 static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm) 10057 10026 { 10058 - int palm_err, lap_err, err; 10027 + int palm_err, lap_err; 10059 10028 10060 10029 palm_err = palmsensor_get(&has_palmsensor, &palm_state); 10061 10030 lap_err = lapsensor_get(&has_lapsensor, &lap_state); 10062 - /* 10063 - * If support isn't available (ENODEV) for both devices then quit, but 10064 - * don't return an error. 10065 - */ 10031 + /* If support isn't available for both devices return -ENODEV */ 10066 10032 if ((palm_err == -ENODEV) && (lap_err == -ENODEV)) 10067 - return 0; 10033 + return -ENODEV; 10068 10034 /* Otherwise, if there was an error return it */ 10069 10035 if (palm_err && (palm_err != -ENODEV)) 10070 10036 return palm_err; 10071 10037 if (lap_err && (lap_err != -ENODEV)) 10072 10038 return lap_err; 10073 10039 10074 - if (has_palmsensor) { 10075 - err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_palmsensor.attr); 10076 - if (err) 10077 - return err; 10078 - } 10079 - 10080 - /* Check if we know the DYTC version, if we don't then get it */ 10081 - if (!dytc_version) { 10082 - err = dytc_get_version(); 10083 - if (err) 10084 - return err; 10085 - } 10086 - /* 10087 - * Platforms before DYTC version 5 claim to have a lap sensor, but it doesn't work, so we 10088 - * ignore them 10089 - */ 10090 - if (has_lapsensor && (dytc_version >= 5)) { 10091 - err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_dytc_lapmode.attr); 10092 - if (err) 10093 - return err; 10094 - } 10095 10040 return 0; 10096 - } 10097 - 10098 - static void proxsensor_exit(void) 10099 - { 10100 - if (has_lapsensor) 10101 - sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_dytc_lapmode.attr); 10102 - if (has_palmsensor) 10103 - sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_palmsensor.attr); 10104 10041 } 10105 10042 10106 10043 static struct ibm_struct proxsensor_driver_data = { 10107 10044 .name = "proximity-sensor", 10108 - .exit = proxsensor_exit, 10109 10045 }; 10110 10046 10111 10047 /************************************************************************* ··· 10140 10084 10141 10085 #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1) 10142 10086 10143 - static bool dytc_profile_available; 10144 10087 static enum platform_profile_option dytc_current_profile; 10145 10088 static atomic_t dytc_ignore_event = ATOMIC_INIT(0); 10146 10089 static DEFINE_MUTEX(dytc_mutex); ··· 10243 10188 int output; 10244 10189 int err; 10245 10190 10246 - if (!dytc_profile_available) 10247 - return -ENODEV; 10248 - 10249 10191 err = mutex_lock_interruptible(&dytc_mutex); 10250 10192 if (err) 10251 10193 return err; ··· 10313 10261 set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices); 10314 10262 set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices); 10315 10263 10316 - dytc_profile_available = false; 10317 10264 err = dytc_command(DYTC_CMD_QUERY, &output); 10318 - /* 10319 - * If support isn't available (ENODEV) then don't return an error 10320 - * and don't create the sysfs group 10321 - */ 10322 - if (err == -ENODEV) 10323 - return 0; 10324 - /* For all other errors we can flag the failure */ 10325 10265 if (err) 10326 10266 return err; 10327 10267 10328 - /* Check if we know the DYTC version, if we don't then get it */ 10329 - if (!dytc_version) { 10330 - err = dytc_get_version(); 10331 - if (err) 10332 - return err; 10333 - } 10334 - /* Check DYTC is enabled and supports mode setting */ 10335 - if (dytc_version >= 5) { 10336 - dbg_printk(TPACPI_DBG_INIT, 10337 - "DYTC version %d: thermal mode available\n", dytc_version); 10338 - /* 10339 - * Check if MMC_GET functionality available 10340 - * Version > 6 and return success from MMC_GET command 10341 - */ 10342 - dytc_mmc_get_available = false; 10343 - if (dytc_version >= 6) { 10344 - err = dytc_command(DYTC_CMD_MMC_GET, &output); 10345 - if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS)) 10346 - dytc_mmc_get_available = true; 10347 - } 10348 - /* Create platform_profile structure and register */ 10349 - err = platform_profile_register(&dytc_profile); 10350 - /* 10351 - * If for some reason platform_profiles aren't enabled 10352 - * don't quit terminally. 10353 - */ 10354 - if (err) 10355 - return 0; 10268 + if (output & BIT(DYTC_QUERY_ENABLE_BIT)) 10269 + dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF; 10356 10270 10357 - dytc_profile_available = true; 10358 - /* Ensure initial values are correct */ 10359 - dytc_profile_refresh(); 10271 + /* Check DYTC is enabled and supports mode setting */ 10272 + if (dytc_version < 5) 10273 + return -ENODEV; 10274 + 10275 + dbg_printk(TPACPI_DBG_INIT, 10276 + "DYTC version %d: thermal mode available\n", dytc_version); 10277 + /* 10278 + * Check if MMC_GET functionality available 10279 + * Version > 6 and return success from MMC_GET command 10280 + */ 10281 + dytc_mmc_get_available = false; 10282 + if (dytc_version >= 6) { 10283 + err = dytc_command(DYTC_CMD_MMC_GET, &output); 10284 + if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS)) 10285 + dytc_mmc_get_available = true; 10360 10286 } 10287 + /* Create platform_profile structure and register */ 10288 + err = platform_profile_register(&dytc_profile); 10289 + /* 10290 + * If for some reason platform_profiles aren't enabled 10291 + * don't quit terminally. 10292 + */ 10293 + if (err) 10294 + return -ENODEV; 10295 + 10296 + /* Ensure initial values are correct */ 10297 + dytc_profile_refresh(); 10298 + 10361 10299 return 0; 10362 10300 } 10363 10301 10364 10302 static void dytc_profile_exit(void) 10365 10303 { 10366 - if (dytc_profile_available) { 10367 - dytc_profile_available = false; 10368 - platform_profile_remove(); 10369 - } 10304 + platform_profile_remove(); 10370 10305 } 10371 10306 10372 10307 static struct ibm_struct dytc_profile_driver_data = { ··· 10501 10462 NULL 10502 10463 }; 10503 10464 10465 + static umode_t kbdlang_attr_is_visible(struct kobject *kobj, 10466 + struct attribute *attr, int n) 10467 + { 10468 + return tp_features.kbd_lang ? attr->mode : 0; 10469 + } 10470 + 10504 10471 static const struct attribute_group kbdlang_attr_group = { 10472 + .is_visible = kbdlang_attr_is_visible, 10505 10473 .attrs = kbdlang_attributes, 10506 10474 }; 10507 10475 ··· 10517 10471 int err, output; 10518 10472 10519 10473 err = get_keyboard_lang(&output); 10520 - /* 10521 - * If support isn't available (ENODEV) then don't return an error 10522 - * just don't create the sysfs group. 10523 - */ 10524 - if (err == -ENODEV) 10525 - return 0; 10526 - 10527 - if (err) 10528 - return err; 10529 - 10530 - /* Platform supports this feature - create the sysfs file */ 10531 - return sysfs_create_group(&tpacpi_pdev->dev.kobj, &kbdlang_attr_group); 10532 - } 10533 - 10534 - static void kbdlang_exit(void) 10535 - { 10536 - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &kbdlang_attr_group); 10474 + tp_features.kbd_lang = !err; 10475 + return err; 10537 10476 } 10538 10477 10539 10478 static struct ibm_struct kbdlang_driver_data = { 10540 10479 .name = "kbdlang", 10541 - .exit = kbdlang_exit, 10542 10480 }; 10543 10481 10544 10482 /************************************************************************* ··· 10593 10563 } 10594 10564 static DEVICE_ATTR_RO(wwan_antenna_type); 10595 10565 10596 - static int tpacpi_dprc_init(struct ibm_init_struct *iibm) 10566 + static struct attribute *dprc_attributes[] = { 10567 + &dev_attr_wwan_antenna_type.attr, 10568 + NULL 10569 + }; 10570 + 10571 + static umode_t dprc_attr_is_visible(struct kobject *kobj, 10572 + struct attribute *attr, int n) 10597 10573 { 10598 - int wwanantenna_err, err; 10599 - 10600 - wwanantenna_err = get_wwan_antenna(&wwan_antennatype); 10601 - /* 10602 - * If support isn't available (ENODEV) then quit, but don't 10603 - * return an error. 10604 - */ 10605 - if (wwanantenna_err == -ENODEV) 10606 - return 0; 10607 - 10608 - /* if there was an error return it */ 10609 - if (wwanantenna_err && (wwanantenna_err != -ENODEV)) 10610 - return wwanantenna_err; 10611 - else if (!wwanantenna_err) 10612 - has_antennatype = true; 10613 - 10614 - if (has_antennatype) { 10615 - err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr); 10616 - if (err) 10617 - return err; 10618 - } 10619 - return 0; 10574 + return has_antennatype ? attr->mode : 0; 10620 10575 } 10621 10576 10622 - static void dprc_exit(void) 10577 + static const struct attribute_group dprc_attr_group = { 10578 + .is_visible = dprc_attr_is_visible, 10579 + .attrs = dprc_attributes, 10580 + }; 10581 + 10582 + static int tpacpi_dprc_init(struct ibm_init_struct *iibm) 10623 10583 { 10624 - if (has_antennatype) 10625 - sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr); 10584 + int err; 10585 + 10586 + err = get_wwan_antenna(&wwan_antennatype); 10587 + if (err) 10588 + return err; 10589 + 10590 + has_antennatype = true; 10591 + return 0; 10626 10592 } 10627 10593 10628 10594 static struct ibm_struct dprc_driver_data = { 10629 10595 .name = "dprc", 10630 - .exit = dprc_exit, 10596 + }; 10597 + 10598 + /* --------------------------------------------------------------------- */ 10599 + 10600 + static struct attribute *tpacpi_driver_attributes[] = { 10601 + &driver_attr_debug_level.attr, 10602 + &driver_attr_version.attr, 10603 + &driver_attr_interface_version.attr, 10604 + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 10605 + &driver_attr_wlsw_emulstate.attr, 10606 + &driver_attr_bluetooth_emulstate.attr, 10607 + &driver_attr_wwan_emulstate.attr, 10608 + &driver_attr_uwb_emulstate.attr, 10609 + #endif 10610 + NULL 10611 + }; 10612 + 10613 + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 10614 + static umode_t tpacpi_attr_is_visible(struct kobject *kobj, 10615 + struct attribute *attr, int n) 10616 + { 10617 + if (attr == &driver_attr_wlsw_emulstate.attr) { 10618 + if (!dbg_wlswemul) 10619 + return 0; 10620 + } else if (attr == &driver_attr_bluetooth_emulstate.attr) { 10621 + if (!dbg_bluetoothemul) 10622 + return 0; 10623 + } else if (attr == &driver_attr_wwan_emulstate.attr) { 10624 + if (!dbg_wwanemul) 10625 + return 0; 10626 + } else if (attr == &driver_attr_uwb_emulstate.attr) { 10627 + if (!dbg_uwbemul) 10628 + return 0; 10629 + } 10630 + 10631 + return attr->mode; 10632 + } 10633 + #endif 10634 + 10635 + static const struct attribute_group tpacpi_driver_attr_group = { 10636 + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 10637 + .is_visible = tpacpi_attr_is_visible, 10638 + #endif 10639 + .attrs = tpacpi_driver_attributes, 10640 + }; 10641 + 10642 + static const struct attribute_group *tpacpi_driver_groups[] = { 10643 + &tpacpi_driver_attr_group, 10644 + NULL, 10645 + }; 10646 + 10647 + static const struct attribute_group *tpacpi_groups[] = { 10648 + &adaptive_kbd_attr_group, 10649 + &hotkey_attr_group, 10650 + &bluetooth_attr_group, 10651 + &wan_attr_group, 10652 + &cmos_attr_group, 10653 + &proxsensor_attr_group, 10654 + &kbdlang_attr_group, 10655 + &dprc_attr_group, 10656 + NULL, 10657 + }; 10658 + 10659 + static const struct attribute_group *tpacpi_hwmon_groups[] = { 10660 + &thermal_attr_group, 10661 + &temp_label_attr_group, 10662 + &fan_attr_group, 10663 + NULL, 10664 + }; 10665 + 10666 + static const struct attribute_group *tpacpi_hwmon_driver_groups[] = { 10667 + &fan_driver_attr_group, 10668 + NULL, 10669 + }; 10670 + 10671 + /**************************************************************************** 10672 + **************************************************************************** 10673 + * 10674 + * Platform drivers 10675 + * 10676 + **************************************************************************** 10677 + ****************************************************************************/ 10678 + 10679 + static struct platform_driver tpacpi_pdriver = { 10680 + .driver = { 10681 + .name = TPACPI_DRVR_NAME, 10682 + .pm = &tpacpi_pm, 10683 + .groups = tpacpi_driver_groups, 10684 + .dev_groups = tpacpi_groups, 10685 + }, 10686 + .shutdown = tpacpi_shutdown_handler, 10687 + }; 10688 + 10689 + static struct platform_driver tpacpi_hwmon_pdriver = { 10690 + .driver = { 10691 + .name = TPACPI_HWMON_DRVR_NAME, 10692 + .groups = tpacpi_hwmon_driver_groups, 10693 + }, 10631 10694 }; 10632 10695 10633 10696 /**************************************************************************** ··· 10877 10754 10878 10755 if (iibm->init) { 10879 10756 ret = iibm->init(iibm); 10880 - if (ret > 0) 10881 - return 0; /* probe failed */ 10757 + if (ret > 0 || ret == -ENODEV) 10758 + return 0; /* subdriver functionality not available */ 10882 10759 if (ret) 10883 10760 return ret; 10884 10761 ··· 11257 11134 11258 11135 for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { 11259 11136 ibm = ibms_init[i].data; 11260 - WARN_ON(ibm == NULL); 11261 - 11262 11137 if (!ibm || !ibm->name) 11263 11138 continue; 11264 11139 ··· 11368 11247 11369 11248 tpacpi_lifecycle = TPACPI_LIFE_EXITING; 11370 11249 11250 + if (tpacpi_hwmon) 11251 + hwmon_device_unregister(tpacpi_hwmon); 11252 + if (tp_features.sensors_pdrv_registered) 11253 + platform_driver_unregister(&tpacpi_hwmon_pdriver); 11254 + if (tp_features.platform_drv_registered) 11255 + platform_driver_unregister(&tpacpi_pdriver); 11256 + 11371 11257 list_for_each_entry_safe_reverse(ibm, itmp, 11372 11258 &tpacpi_all_drivers, 11373 11259 all_drivers) { ··· 11391 11263 kfree(hotkey_keycode_map); 11392 11264 } 11393 11265 11394 - if (tpacpi_hwmon) 11395 - hwmon_device_unregister(tpacpi_hwmon); 11396 - 11397 11266 if (tpacpi_sensors_pdev) 11398 11267 platform_device_unregister(tpacpi_sensors_pdev); 11399 11268 if (tpacpi_pdev) 11400 11269 platform_device_unregister(tpacpi_pdev); 11401 - 11402 - if (tp_features.sensors_pdrv_attrs_registered) 11403 - tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); 11404 - if (tp_features.platform_drv_attrs_registered) 11405 - tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); 11406 - 11407 - if (tp_features.sensors_pdrv_registered) 11408 - platform_driver_unregister(&tpacpi_hwmon_pdriver); 11409 - 11410 - if (tp_features.platform_drv_registered) 11411 - platform_driver_unregister(&tpacpi_pdriver); 11412 - 11413 11270 if (proc_dir) 11414 11271 remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir); 11415 - 11416 11272 if (tpacpi_wq) 11417 11273 destroy_workqueue(tpacpi_wq); 11418 11274 ··· 11448 11336 return -ENODEV; 11449 11337 } 11450 11338 11451 - ret = platform_driver_register(&tpacpi_pdriver); 11452 - if (ret) { 11453 - pr_err("unable to register main platform driver\n"); 11454 - thinkpad_acpi_module_exit(); 11455 - return ret; 11456 - } 11457 - tp_features.platform_drv_registered = 1; 11458 - 11459 - ret = platform_driver_register(&tpacpi_hwmon_pdriver); 11460 - if (ret) { 11461 - pr_err("unable to register hwmon platform driver\n"); 11462 - thinkpad_acpi_module_exit(); 11463 - return ret; 11464 - } 11465 - tp_features.sensors_pdrv_registered = 1; 11466 - 11467 - ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); 11468 - if (!ret) { 11469 - tp_features.platform_drv_attrs_registered = 1; 11470 - ret = tpacpi_create_driver_attributes( 11471 - &tpacpi_hwmon_pdriver.driver); 11472 - } 11473 - if (ret) { 11474 - pr_err("unable to create sysfs driver attributes\n"); 11475 - thinkpad_acpi_module_exit(); 11476 - return ret; 11477 - } 11478 - tp_features.sensors_pdrv_attrs_registered = 1; 11479 - 11480 - 11481 11339 /* Device initialization */ 11482 11340 tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1, 11483 11341 NULL, 0); ··· 11468 11386 thinkpad_acpi_module_exit(); 11469 11387 return ret; 11470 11388 } 11471 - tp_features.sensors_pdev_attrs_registered = 1; 11472 - tpacpi_hwmon = hwmon_device_register_with_groups( 11473 - &tpacpi_sensors_pdev->dev, TPACPI_NAME, NULL, NULL); 11474 11389 11475 - if (IS_ERR(tpacpi_hwmon)) { 11476 - ret = PTR_ERR(tpacpi_hwmon); 11477 - tpacpi_hwmon = NULL; 11478 - pr_err("unable to register hwmon device\n"); 11479 - thinkpad_acpi_module_exit(); 11480 - return ret; 11481 - } 11482 11390 mutex_init(&tpacpi_inputdev_send_mutex); 11483 11391 tpacpi_inputdev = input_allocate_device(); 11484 11392 if (!tpacpi_inputdev) { ··· 11500 11428 } 11501 11429 11502 11430 tpacpi_lifecycle = TPACPI_LIFE_RUNNING; 11431 + 11432 + ret = platform_driver_register(&tpacpi_pdriver); 11433 + if (ret) { 11434 + pr_err("unable to register main platform driver\n"); 11435 + thinkpad_acpi_module_exit(); 11436 + return ret; 11437 + } 11438 + tp_features.platform_drv_registered = 1; 11439 + 11440 + ret = platform_driver_register(&tpacpi_hwmon_pdriver); 11441 + if (ret) { 11442 + pr_err("unable to register hwmon platform driver\n"); 11443 + thinkpad_acpi_module_exit(); 11444 + return ret; 11445 + } 11446 + tp_features.sensors_pdrv_registered = 1; 11447 + 11448 + tpacpi_hwmon = hwmon_device_register_with_groups( 11449 + &tpacpi_sensors_pdev->dev, TPACPI_NAME, NULL, tpacpi_hwmon_groups); 11450 + if (IS_ERR(tpacpi_hwmon)) { 11451 + ret = PTR_ERR(tpacpi_hwmon); 11452 + tpacpi_hwmon = NULL; 11453 + pr_err("unable to register hwmon device\n"); 11454 + thinkpad_acpi_module_exit(); 11455 + return ret; 11456 + } 11503 11457 11504 11458 ret = input_register_device(tpacpi_inputdev); 11505 11459 if (ret < 0) {
+13 -25
drivers/platform/x86/touchscreen_dmi.c
··· 107 107 PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi10plus.fw"), 108 108 PROPERTY_ENTRY_U32("silead,max-fingers", 10), 109 109 PROPERTY_ENTRY_BOOL("silead,home-button"), 110 + PROPERTY_ENTRY_BOOL("silead,pen-supported"), 111 + PROPERTY_ENTRY_U32("silead,pen-resolution-x", 8), 112 + PROPERTY_ENTRY_U32("silead,pen-resolution-y", 8), 110 113 { } 111 114 }; 112 115 ··· 127 124 .properties = chuwi_hi10_plus_props, 128 125 }; 129 126 127 + static const u32 chuwi_hi10_pro_efi_min_max[] = { 8, 1911, 8, 1271 }; 128 + 130 129 static const struct property_entry chuwi_hi10_pro_props[] = { 131 - PROPERTY_ENTRY_U32("touchscreen-min-x", 8), 132 - PROPERTY_ENTRY_U32("touchscreen-min-y", 8), 133 - PROPERTY_ENTRY_U32("touchscreen-size-x", 1912), 134 - PROPERTY_ENTRY_U32("touchscreen-size-y", 1272), 130 + PROPERTY_ENTRY_U32("touchscreen-min-x", 80), 131 + PROPERTY_ENTRY_U32("touchscreen-min-y", 26), 132 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1962), 133 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1254), 135 134 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 136 135 PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi10-pro.fw"), 136 + PROPERTY_ENTRY_U32_ARRAY("silead,efi-fw-min-max", chuwi_hi10_pro_efi_min_max), 137 137 PROPERTY_ENTRY_U32("silead,max-fingers", 10), 138 138 PROPERTY_ENTRY_BOOL("silead,home-button"), 139 + PROPERTY_ENTRY_BOOL("silead,pen-supported"), 140 + PROPERTY_ENTRY_U32("silead,pen-resolution-x", 8), 141 + PROPERTY_ENTRY_U32("silead,pen-resolution-y", 8), 139 142 { } 140 143 }; 141 144 ··· 359 350 static const struct ts_dmi_data gdix1001_01_upside_down_data = { 360 351 .acpi_name = "GDIX1001:01", 361 352 .properties = gdix1001_upside_down_props, 362 - }; 363 - 364 - static const struct property_entry glavey_tm800a550l_props[] = { 365 - PROPERTY_ENTRY_STRING("firmware-name", "gt912-glavey-tm800a550l.fw"), 366 - PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-glavey-tm800a550l.cfg"), 367 - PROPERTY_ENTRY_U32("goodix,main-clk", 54), 368 - { } 369 - }; 370 - 371 - static const struct ts_dmi_data glavey_tm800a550l_data = { 372 - .acpi_name = "GDIX1001:00", 373 - .properties = glavey_tm800a550l_props, 374 353 }; 375 354 376 355 static const struct property_entry gp_electronic_t701_props[] = { ··· 1135 1138 .matches = { 1136 1139 DMI_MATCH(DMI_SYS_VENDOR, "Estar"), 1137 1140 DMI_MATCH(DMI_PRODUCT_NAME, "eSTAR BEAUTY HD Intel Quad core"), 1138 - }, 1139 - }, 1140 - { /* Glavey TM800A550L */ 1141 - .driver_data = (void *)&glavey_tm800a550l_data, 1142 - .matches = { 1143 - DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 1144 - DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), 1145 - /* Above strings are too generic, also match on BIOS version */ 1146 - DMI_MATCH(DMI_BIOS_VERSION, "ZY-8-BI-PX4S70VTR400-X423B-005-D"), 1147 1141 }, 1148 1142 }, 1149 1143 {
+4 -2
drivers/platform/x86/uv_sysfs.c
··· 175 175 &cnode_attribute.attr, 176 176 NULL, 177 177 }; 178 + ATTRIBUTE_GROUPS(uv_hub); 178 179 179 180 static void hub_release(struct kobject *kobj) 180 181 { ··· 206 205 static struct kobj_type hub_attr_type = { 207 206 .release = hub_release, 208 207 .sysfs_ops = &hub_sysfs_ops, 209 - .default_attrs = uv_hub_attrs, 208 + .default_groups = uv_hub_groups, 210 209 }; 211 210 212 211 static int uv_hubs_init(void) ··· 328 327 &uv_port_conn_port_attribute.attr, 329 328 NULL, 330 329 }; 330 + ATTRIBUTE_GROUPS(uv_port); 331 331 332 332 static void uv_port_release(struct kobject *kobj) 333 333 { ··· 359 357 static struct kobj_type uv_port_attr_type = { 360 358 .release = uv_port_release, 361 359 .sysfs_ops = &uv_port_sysfs_ops, 362 - .default_attrs = uv_port_attrs, 360 + .default_groups = uv_port_groups, 363 361 }; 364 362 365 363 static int uv_ports_init(void)
+18 -9
drivers/platform/x86/wmi.c
··· 57 57 static_assert(sizeof(struct guid_block) == 20); 58 58 static_assert(__alignof__(struct guid_block) == 1); 59 59 60 + enum { /* wmi_block flags */ 61 + WMI_READ_TAKES_NO_ARGS, 62 + WMI_PROBED, 63 + }; 64 + 60 65 struct wmi_block { 61 66 struct wmi_device dev; 62 67 struct list_head list; ··· 72 67 wmi_notify_handler handler; 73 68 void *handler_data; 74 69 u64 req_buf_size; 75 - 76 - bool read_takes_no_args; 70 + unsigned long flags; 77 71 }; 78 72 79 73 ··· 371 367 wq_params[0].type = ACPI_TYPE_INTEGER; 372 368 wq_params[0].integer.value = instance; 373 369 374 - if (instance == 0 && wblock->read_takes_no_args) 370 + if (instance == 0 && test_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags)) 375 371 input.count = 0; 376 372 377 373 /* ··· 1009 1005 } 1010 1006 } 1011 1007 1008 + set_bit(WMI_PROBED, &wblock->flags); 1012 1009 return 0; 1013 1010 1014 1011 probe_misc_failure: ··· 1026 1021 { 1027 1022 struct wmi_block *wblock = dev_to_wblock(dev); 1028 1023 struct wmi_driver *wdriver = drv_to_wdrv(dev->driver); 1024 + 1025 + clear_bit(WMI_PROBED, &wblock->flags); 1029 1026 1030 1027 if (wdriver->filter_callback) { 1031 1028 misc_deregister(&wblock->char_dev); ··· 1120 1113 * laptops, WQxx may not be a method at all.) 1121 1114 */ 1122 1115 if (info->type != ACPI_TYPE_METHOD || info->param_count == 0) 1123 - wblock->read_takes_no_args = true; 1116 + set_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags); 1124 1117 1125 1118 kfree(info); 1126 1119 ··· 1326 1319 return; 1327 1320 1328 1321 /* If a driver is bound, then notify the driver. */ 1329 - if (wblock->dev.dev.driver) { 1322 + if (test_bit(WMI_PROBED, &wblock->flags) && wblock->dev.dev.driver) { 1330 1323 struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver); 1331 1324 struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL }; 1332 1325 acpi_status status; 1333 1326 1334 - status = get_event_data(wblock, &evdata); 1335 - if (ACPI_FAILURE(status)) { 1336 - dev_warn(&wblock->dev.dev, "failed to get event data\n"); 1337 - return; 1327 + if (!driver->no_notify_data) { 1328 + status = get_event_data(wblock, &evdata); 1329 + if (ACPI_FAILURE(status)) { 1330 + dev_warn(&wblock->dev.dev, "failed to get event data\n"); 1331 + return; 1332 + } 1338 1333 } 1339 1334 1340 1335 if (driver->notify)
+870
drivers/platform/x86/x86-android-tablets.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * DMI based code to deal with broken DSDTs on X86 tablets which ship with 4 + * Android as (part of) the factory image. The factory kernels shipped on these 5 + * devices typically have a bunch of things hardcoded, rather than specified 6 + * in their DSDT. 7 + * 8 + * Copyright (C) 2021 Hans de Goede <hdegoede@redhat.com> 9 + */ 10 + 11 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 + 13 + #include <linux/acpi.h> 14 + #include <linux/dmi.h> 15 + #include <linux/gpio/consumer.h> 16 + #include <linux/gpio/driver.h> 17 + #include <linux/gpio/machine.h> 18 + #include <linux/i2c.h> 19 + #include <linux/irq.h> 20 + #include <linux/irqdomain.h> 21 + #include <linux/module.h> 22 + #include <linux/mod_devicetable.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/power/bq24190_charger.h> 25 + #include <linux/serdev.h> 26 + #include <linux/string.h> 27 + /* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */ 28 + #include "../../gpio/gpiolib.h" 29 + 30 + /* 31 + * Helper code to get Linux IRQ numbers given a description of the IRQ source 32 + * (either IOAPIC index, or GPIO chip name + pin-number). 33 + */ 34 + enum x86_acpi_irq_type { 35 + X86_ACPI_IRQ_TYPE_NONE, 36 + X86_ACPI_IRQ_TYPE_APIC, 37 + X86_ACPI_IRQ_TYPE_GPIOINT, 38 + X86_ACPI_IRQ_TYPE_PMIC, 39 + }; 40 + 41 + struct x86_acpi_irq_data { 42 + char *chip; /* GPIO chip label (GPIOINT) or PMIC ACPI path (PMIC) */ 43 + enum x86_acpi_irq_type type; 44 + enum irq_domain_bus_token domain; 45 + int index; 46 + int trigger; /* ACPI_EDGE_SENSITIVE / ACPI_LEVEL_SENSITIVE */ 47 + int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */ 48 + }; 49 + 50 + static int x86_acpi_irq_helper_gpiochip_find(struct gpio_chip *gc, void *data) 51 + { 52 + return gc->label && !strcmp(gc->label, data); 53 + } 54 + 55 + static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data) 56 + { 57 + struct irq_fwspec fwspec = { }; 58 + struct irq_domain *domain; 59 + struct acpi_device *adev; 60 + struct gpio_desc *gpiod; 61 + struct gpio_chip *chip; 62 + unsigned int irq_type; 63 + acpi_handle handle; 64 + acpi_status status; 65 + int irq, ret; 66 + 67 + switch (data->type) { 68 + case X86_ACPI_IRQ_TYPE_APIC: 69 + irq = acpi_register_gsi(NULL, data->index, data->trigger, data->polarity); 70 + if (irq < 0) 71 + pr_err("error %d getting APIC IRQ %d\n", irq, data->index); 72 + 73 + return irq; 74 + case X86_ACPI_IRQ_TYPE_GPIOINT: 75 + /* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */ 76 + chip = gpiochip_find(data->chip, x86_acpi_irq_helper_gpiochip_find); 77 + if (!chip) { 78 + pr_err("error cannot find GPIO chip %s\n", data->chip); 79 + return -ENODEV; 80 + } 81 + 82 + gpiod = gpiochip_get_desc(chip, data->index); 83 + if (IS_ERR(gpiod)) { 84 + ret = PTR_ERR(gpiod); 85 + pr_err("error %d getting GPIO %s %d\n", ret, data->chip, data->index); 86 + return ret; 87 + } 88 + 89 + irq = gpiod_to_irq(gpiod); 90 + if (irq < 0) { 91 + pr_err("error %d getting IRQ %s %d\n", irq, data->chip, data->index); 92 + return irq; 93 + } 94 + 95 + irq_type = acpi_dev_get_irq_type(data->trigger, data->polarity); 96 + if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq)) 97 + irq_set_irq_type(irq, irq_type); 98 + 99 + return irq; 100 + case X86_ACPI_IRQ_TYPE_PMIC: 101 + status = acpi_get_handle(NULL, data->chip, &handle); 102 + if (ACPI_FAILURE(status)) { 103 + pr_err("error could not get %s handle\n", data->chip); 104 + return -ENODEV; 105 + } 106 + 107 + acpi_bus_get_device(handle, &adev); 108 + if (!adev) { 109 + pr_err("error could not get %s adev\n", data->chip); 110 + return -ENODEV; 111 + } 112 + 113 + fwspec.fwnode = acpi_fwnode_handle(adev); 114 + domain = irq_find_matching_fwspec(&fwspec, data->domain); 115 + if (!domain) { 116 + pr_err("error could not find IRQ domain for %s\n", data->chip); 117 + return -ENODEV; 118 + } 119 + 120 + return irq_create_mapping(domain, data->index); 121 + default: 122 + return 0; 123 + } 124 + } 125 + 126 + struct x86_i2c_client_info { 127 + struct i2c_board_info board_info; 128 + char *adapter_path; 129 + struct x86_acpi_irq_data irq_data; 130 + }; 131 + 132 + struct x86_serdev_info { 133 + const char *ctrl_hid; 134 + const char *ctrl_uid; 135 + const char *ctrl_devname; 136 + /* 137 + * ATM the serdev core only supports of or ACPI matching; and sofar all 138 + * Android x86 tablets DSDTs have usable serdev nodes, but sometimes 139 + * under the wrong controller. So we just tie the existing serdev ACPI 140 + * node to the right controller. 141 + */ 142 + const char *serdev_hid; 143 + }; 144 + 145 + struct x86_dev_info { 146 + const char * const *modules; 147 + struct gpiod_lookup_table **gpiod_lookup_tables; 148 + const struct x86_i2c_client_info *i2c_client_info; 149 + const struct platform_device_info *pdev_info; 150 + const struct x86_serdev_info *serdev_info; 151 + int i2c_client_count; 152 + int pdev_count; 153 + int serdev_count; 154 + }; 155 + 156 + /* Generic / shared bq24190 settings */ 157 + static const char * const bq24190_suppliers[] = { "tusb1210-psy" }; 158 + 159 + static const struct property_entry bq24190_props[] = { 160 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_suppliers), 161 + PROPERTY_ENTRY_BOOL("omit-battery-class"), 162 + PROPERTY_ENTRY_BOOL("disable-reset"), 163 + { } 164 + }; 165 + 166 + static const struct software_node bq24190_node = { 167 + .properties = bq24190_props, 168 + }; 169 + 170 + /* For enableing the bq24190 5V boost based on id-pin */ 171 + static struct regulator_consumer_supply intel_int3496_consumer = { 172 + .supply = "vbus", 173 + .dev_name = "intel-int3496", 174 + }; 175 + 176 + static const struct regulator_init_data bq24190_vbus_init_data = { 177 + .constraints = { 178 + .name = "bq24190_vbus", 179 + .valid_ops_mask = REGULATOR_CHANGE_STATUS, 180 + }, 181 + .consumer_supplies = &intel_int3496_consumer, 182 + .num_consumer_supplies = 1, 183 + }; 184 + 185 + static struct bq24190_platform_data bq24190_pdata = { 186 + .regulator_init_data = &bq24190_vbus_init_data, 187 + }; 188 + 189 + static const char * const bq24190_modules[] __initconst = { 190 + "crystal_cove_charger", /* For the bq24190 IRQ */ 191 + "bq24190_charger", /* For the Vbus regulator for intel-int3496 */ 192 + NULL 193 + }; 194 + 195 + /* Generic pdevs array and gpio-lookups for micro USB ID pin handling */ 196 + static const struct platform_device_info int3496_pdevs[] __initconst = { 197 + { 198 + /* For micro USB ID pin handling */ 199 + .name = "intel-int3496", 200 + .id = PLATFORM_DEVID_NONE, 201 + }, 202 + }; 203 + 204 + static struct gpiod_lookup_table int3496_gpo2_pin22_gpios = { 205 + .dev_id = "intel-int3496", 206 + .table = { 207 + GPIO_LOOKUP("INT33FC:02", 22, "id", GPIO_ACTIVE_HIGH), 208 + { } 209 + }, 210 + }; 211 + 212 + /* Asus ME176C tablets have an Android factory img with everything hardcoded */ 213 + static const char * const asus_me176c_accel_mount_matrix[] = { 214 + "-1", "0", "0", 215 + "0", "1", "0", 216 + "0", "0", "1" 217 + }; 218 + 219 + static const struct property_entry asus_me176c_accel_props[] = { 220 + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", asus_me176c_accel_mount_matrix), 221 + { } 222 + }; 223 + 224 + static const struct software_node asus_me176c_accel_node = { 225 + .properties = asus_me176c_accel_props, 226 + }; 227 + 228 + static const struct x86_i2c_client_info asus_me176c_i2c_clients[] __initconst = { 229 + { 230 + /* bq24190 battery charger */ 231 + .board_info = { 232 + .type = "bq24190", 233 + .addr = 0x6b, 234 + .dev_name = "bq24190", 235 + .swnode = &bq24190_node, 236 + .platform_data = &bq24190_pdata, 237 + }, 238 + .adapter_path = "\\_SB_.I2C1", 239 + .irq_data = { 240 + .type = X86_ACPI_IRQ_TYPE_PMIC, 241 + .chip = "\\_SB_.I2C7.PMIC", 242 + .domain = DOMAIN_BUS_WAKEUP, 243 + .index = 0, 244 + }, 245 + }, { 246 + /* ug3105 battery monitor */ 247 + .board_info = { 248 + .type = "ug3105", 249 + .addr = 0x70, 250 + .dev_name = "ug3105", 251 + }, 252 + .adapter_path = "\\_SB_.I2C1", 253 + }, { 254 + /* ak09911 compass */ 255 + .board_info = { 256 + .type = "ak09911", 257 + .addr = 0x0c, 258 + .dev_name = "ak09911", 259 + }, 260 + .adapter_path = "\\_SB_.I2C5", 261 + }, { 262 + /* kxtj21009 accel */ 263 + .board_info = { 264 + .type = "kxtj21009", 265 + .addr = 0x0f, 266 + .dev_name = "kxtj21009", 267 + .swnode = &asus_me176c_accel_node, 268 + }, 269 + .adapter_path = "\\_SB_.I2C5", 270 + }, { 271 + /* goodix touchscreen */ 272 + .board_info = { 273 + .type = "GDIX1001:00", 274 + .addr = 0x14, 275 + .dev_name = "goodix_ts", 276 + }, 277 + .adapter_path = "\\_SB_.I2C6", 278 + .irq_data = { 279 + .type = X86_ACPI_IRQ_TYPE_APIC, 280 + .index = 0x45, 281 + .trigger = ACPI_EDGE_SENSITIVE, 282 + .polarity = ACPI_ACTIVE_LOW, 283 + }, 284 + }, 285 + }; 286 + 287 + static const struct x86_serdev_info asus_me176c_serdevs[] __initconst = { 288 + { 289 + .ctrl_hid = "80860F0A", 290 + .ctrl_uid = "2", 291 + .ctrl_devname = "serial0", 292 + .serdev_hid = "BCM2E3A", 293 + }, 294 + }; 295 + 296 + static struct gpiod_lookup_table asus_me176c_goodix_gpios = { 297 + .dev_id = "i2c-goodix_ts", 298 + .table = { 299 + GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_HIGH), 300 + GPIO_LOOKUP("INT33FC:02", 28, "irq", GPIO_ACTIVE_HIGH), 301 + { } 302 + }, 303 + }; 304 + 305 + static struct gpiod_lookup_table *asus_me176c_gpios[] = { 306 + &int3496_gpo2_pin22_gpios, 307 + &asus_me176c_goodix_gpios, 308 + NULL 309 + }; 310 + 311 + static const struct x86_dev_info asus_me176c_info __initconst = { 312 + .i2c_client_info = asus_me176c_i2c_clients, 313 + .i2c_client_count = ARRAY_SIZE(asus_me176c_i2c_clients), 314 + .pdev_info = int3496_pdevs, 315 + .pdev_count = ARRAY_SIZE(int3496_pdevs), 316 + .serdev_info = asus_me176c_serdevs, 317 + .serdev_count = ARRAY_SIZE(asus_me176c_serdevs), 318 + .gpiod_lookup_tables = asus_me176c_gpios, 319 + .modules = bq24190_modules, 320 + }; 321 + 322 + /* Asus TF103C tablets have an Android factory img with everything hardcoded */ 323 + static const char * const asus_tf103c_accel_mount_matrix[] = { 324 + "0", "-1", "0", 325 + "-1", "0", "0", 326 + "0", "0", "1" 327 + }; 328 + 329 + static const struct property_entry asus_tf103c_accel_props[] = { 330 + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", asus_tf103c_accel_mount_matrix), 331 + { } 332 + }; 333 + 334 + static const struct software_node asus_tf103c_accel_node = { 335 + .properties = asus_tf103c_accel_props, 336 + }; 337 + 338 + static const struct property_entry asus_tf103c_touchscreen_props[] = { 339 + PROPERTY_ENTRY_STRING("compatible", "atmel,atmel_mxt_ts"), 340 + { } 341 + }; 342 + 343 + static const struct software_node asus_tf103c_touchscreen_node = { 344 + .properties = asus_tf103c_touchscreen_props, 345 + }; 346 + 347 + static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst = { 348 + { 349 + /* bq24190 battery charger */ 350 + .board_info = { 351 + .type = "bq24190", 352 + .addr = 0x6b, 353 + .dev_name = "bq24190", 354 + .swnode = &bq24190_node, 355 + .platform_data = &bq24190_pdata, 356 + }, 357 + .adapter_path = "\\_SB_.I2C1", 358 + .irq_data = { 359 + .type = X86_ACPI_IRQ_TYPE_PMIC, 360 + .chip = "\\_SB_.I2C7.PMIC", 361 + .domain = DOMAIN_BUS_WAKEUP, 362 + .index = 0, 363 + }, 364 + }, { 365 + /* ug3105 battery monitor */ 366 + .board_info = { 367 + .type = "ug3105", 368 + .addr = 0x70, 369 + .dev_name = "ug3105", 370 + }, 371 + .adapter_path = "\\_SB_.I2C1", 372 + }, { 373 + /* ak09911 compass */ 374 + .board_info = { 375 + .type = "ak09911", 376 + .addr = 0x0c, 377 + .dev_name = "ak09911", 378 + }, 379 + .adapter_path = "\\_SB_.I2C5", 380 + }, { 381 + /* kxtj21009 accel */ 382 + .board_info = { 383 + .type = "kxtj21009", 384 + .addr = 0x0f, 385 + .dev_name = "kxtj21009", 386 + .swnode = &asus_tf103c_accel_node, 387 + }, 388 + .adapter_path = "\\_SB_.I2C5", 389 + }, { 390 + /* atmel touchscreen */ 391 + .board_info = { 392 + .type = "atmel_mxt_ts", 393 + .addr = 0x4a, 394 + .dev_name = "atmel_mxt_ts", 395 + .swnode = &asus_tf103c_touchscreen_node, 396 + }, 397 + .adapter_path = "\\_SB_.I2C6", 398 + .irq_data = { 399 + .type = X86_ACPI_IRQ_TYPE_GPIOINT, 400 + .chip = "INT33FC:02", 401 + .index = 28, 402 + .trigger = ACPI_EDGE_SENSITIVE, 403 + .polarity = ACPI_ACTIVE_LOW, 404 + }, 405 + }, 406 + }; 407 + 408 + static struct gpiod_lookup_table *asus_tf103c_gpios[] = { 409 + &int3496_gpo2_pin22_gpios, 410 + NULL 411 + }; 412 + 413 + static const struct x86_dev_info asus_tf103c_info __initconst = { 414 + .i2c_client_info = asus_tf103c_i2c_clients, 415 + .i2c_client_count = ARRAY_SIZE(asus_tf103c_i2c_clients), 416 + .pdev_info = int3496_pdevs, 417 + .pdev_count = ARRAY_SIZE(int3496_pdevs), 418 + .gpiod_lookup_tables = asus_tf103c_gpios, 419 + .modules = bq24190_modules, 420 + }; 421 + 422 + /* 423 + * When booted with the BIOS set to Android mode the Chuwi Hi8 (CWI509) DSDT 424 + * contains a whole bunch of bogus ACPI I2C devices and is missing entries 425 + * for the touchscreen and the accelerometer. 426 + */ 427 + static const struct property_entry chuwi_hi8_gsl1680_props[] = { 428 + PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), 429 + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), 430 + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 431 + PROPERTY_ENTRY_BOOL("silead,home-button"), 432 + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"), 433 + { } 434 + }; 435 + 436 + static const struct software_node chuwi_hi8_gsl1680_node = { 437 + .properties = chuwi_hi8_gsl1680_props, 438 + }; 439 + 440 + static const char * const chuwi_hi8_mount_matrix[] = { 441 + "1", "0", "0", 442 + "0", "-1", "0", 443 + "0", "0", "1" 444 + }; 445 + 446 + static const struct property_entry chuwi_hi8_bma250e_props[] = { 447 + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", chuwi_hi8_mount_matrix), 448 + { } 449 + }; 450 + 451 + static const struct software_node chuwi_hi8_bma250e_node = { 452 + .properties = chuwi_hi8_bma250e_props, 453 + }; 454 + 455 + static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = { 456 + { 457 + /* Silead touchscreen */ 458 + .board_info = { 459 + .type = "gsl1680", 460 + .addr = 0x40, 461 + .swnode = &chuwi_hi8_gsl1680_node, 462 + }, 463 + .adapter_path = "\\_SB_.I2C4", 464 + .irq_data = { 465 + .type = X86_ACPI_IRQ_TYPE_APIC, 466 + .index = 0x44, 467 + .trigger = ACPI_EDGE_SENSITIVE, 468 + .polarity = ACPI_ACTIVE_HIGH, 469 + }, 470 + }, { 471 + /* BMA250E accelerometer */ 472 + .board_info = { 473 + .type = "bma250e", 474 + .addr = 0x18, 475 + .swnode = &chuwi_hi8_bma250e_node, 476 + }, 477 + .adapter_path = "\\_SB_.I2C3", 478 + .irq_data = { 479 + .type = X86_ACPI_IRQ_TYPE_GPIOINT, 480 + .chip = "INT33FC:02", 481 + .index = 23, 482 + .trigger = ACPI_LEVEL_SENSITIVE, 483 + .polarity = ACPI_ACTIVE_HIGH, 484 + }, 485 + }, 486 + }; 487 + 488 + static const struct x86_dev_info chuwi_hi8_info __initconst = { 489 + .i2c_client_info = chuwi_hi8_i2c_clients, 490 + .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients), 491 + }; 492 + 493 + /* 494 + * Whitelabel (sold as various brands) TM800A550L tablets. 495 + * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices 496 + * (removed through acpi_quirk_skip_i2c_client_enumeration()) and 497 + * the touchscreen fwnode has the wrong GPIOs. 498 + */ 499 + static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = { 500 + "-1", "0", "0", 501 + "0", "1", "0", 502 + "0", "0", "1" 503 + }; 504 + 505 + static const struct property_entry whitelabel_tm800a550l_accel_props[] = { 506 + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", whitelabel_tm800a550l_accel_mount_matrix), 507 + { } 508 + }; 509 + 510 + static const struct software_node whitelabel_tm800a550l_accel_node = { 511 + .properties = whitelabel_tm800a550l_accel_props, 512 + }; 513 + 514 + static const struct property_entry whitelabel_tm800a550l_goodix_props[] = { 515 + PROPERTY_ENTRY_STRING("firmware-name", "gt912-tm800a550l.fw"), 516 + PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-tm800a550l.cfg"), 517 + PROPERTY_ENTRY_U32("goodix,main-clk", 54), 518 + { } 519 + }; 520 + 521 + static const struct software_node whitelabel_tm800a550l_goodix_node = { 522 + .properties = whitelabel_tm800a550l_goodix_props, 523 + }; 524 + 525 + static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __initconst = { 526 + { 527 + /* goodix touchscreen */ 528 + .board_info = { 529 + .type = "GDIX1001:00", 530 + .addr = 0x14, 531 + .dev_name = "goodix_ts", 532 + .swnode = &whitelabel_tm800a550l_goodix_node, 533 + }, 534 + .adapter_path = "\\_SB_.I2C2", 535 + .irq_data = { 536 + .type = X86_ACPI_IRQ_TYPE_APIC, 537 + .index = 0x44, 538 + .trigger = ACPI_EDGE_SENSITIVE, 539 + .polarity = ACPI_ACTIVE_HIGH, 540 + }, 541 + }, { 542 + /* kxcj91008 accel */ 543 + .board_info = { 544 + .type = "kxcj91008", 545 + .addr = 0x0f, 546 + .dev_name = "kxcj91008", 547 + .swnode = &whitelabel_tm800a550l_accel_node, 548 + }, 549 + .adapter_path = "\\_SB_.I2C3", 550 + }, 551 + }; 552 + 553 + static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = { 554 + .dev_id = "i2c-goodix_ts", 555 + .table = { 556 + GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH), 557 + GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH), 558 + { } 559 + }, 560 + }; 561 + 562 + static struct gpiod_lookup_table *whitelabel_tm800a550l_gpios[] = { 563 + &whitelabel_tm800a550l_goodix_gpios, 564 + NULL 565 + }; 566 + 567 + static const struct x86_dev_info whitelabel_tm800a550l_info __initconst = { 568 + .i2c_client_info = whitelabel_tm800a550l_i2c_clients, 569 + .i2c_client_count = ARRAY_SIZE(whitelabel_tm800a550l_i2c_clients), 570 + .gpiod_lookup_tables = whitelabel_tm800a550l_gpios, 571 + }; 572 + 573 + /* 574 + * If the EFI bootloader is not Xiaomi's own signed Android loader, then the 575 + * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing 576 + * a bunch of devices to be hidden. 577 + * 578 + * This takes care of instantiating the hidden devices manually. 579 + */ 580 + static const char * const bq27520_suppliers[] = { "bq25890-charger" }; 581 + 582 + static const struct property_entry bq27520_props[] = { 583 + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq27520_suppliers), 584 + { } 585 + }; 586 + 587 + static const struct software_node bq27520_node = { 588 + .properties = bq27520_props, 589 + }; 590 + 591 + static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = { 592 + { 593 + /* BQ27520 fuel-gauge */ 594 + .board_info = { 595 + .type = "bq27520", 596 + .addr = 0x55, 597 + .dev_name = "bq27520", 598 + .swnode = &bq27520_node, 599 + }, 600 + .adapter_path = "\\_SB_.PCI0.I2C1", 601 + }, { 602 + /* KTD2026 RGB notification LED controller */ 603 + .board_info = { 604 + .type = "ktd2026", 605 + .addr = 0x30, 606 + .dev_name = "ktd2026", 607 + }, 608 + .adapter_path = "\\_SB_.PCI0.I2C3", 609 + }, 610 + }; 611 + 612 + static const struct x86_dev_info xiaomi_mipad2_info __initconst = { 613 + .i2c_client_info = xiaomi_mipad2_i2c_clients, 614 + .i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients), 615 + }; 616 + 617 + static const struct dmi_system_id x86_android_tablet_ids[] __initconst = { 618 + { 619 + /* Asus MeMO Pad 7 ME176C */ 620 + .matches = { 621 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 622 + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), 623 + }, 624 + .driver_data = (void *)&asus_me176c_info, 625 + }, 626 + { 627 + /* Asus TF103C */ 628 + .matches = { 629 + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 630 + DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), 631 + }, 632 + .driver_data = (void *)&asus_tf103c_info, 633 + }, 634 + { 635 + /* Chuwi Hi8 (CWI509) */ 636 + .matches = { 637 + DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), 638 + DMI_MATCH(DMI_BOARD_NAME, "BYT-PA03C"), 639 + DMI_MATCH(DMI_SYS_VENDOR, "ilife"), 640 + DMI_MATCH(DMI_PRODUCT_NAME, "S806"), 641 + }, 642 + .driver_data = (void *)&chuwi_hi8_info, 643 + }, 644 + { 645 + /* Whitelabel (sold as various brands) TM800A550L */ 646 + .matches = { 647 + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 648 + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), 649 + /* Above strings are too generic, also match on BIOS version */ 650 + DMI_MATCH(DMI_BIOS_VERSION, "ZY-8-BI-PX4S70VTR400-X423B-005-D"), 651 + }, 652 + .driver_data = (void *)&whitelabel_tm800a550l_info, 653 + }, 654 + { 655 + /* Xiaomi Mi Pad 2 */ 656 + .matches = { 657 + DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"), 658 + DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), 659 + }, 660 + .driver_data = (void *)&xiaomi_mipad2_info, 661 + }, 662 + { } 663 + }; 664 + MODULE_DEVICE_TABLE(dmi, x86_android_tablet_ids); 665 + 666 + static int i2c_client_count; 667 + static int pdev_count; 668 + static int serdev_count; 669 + static struct i2c_client **i2c_clients; 670 + static struct platform_device **pdevs; 671 + static struct serdev_device **serdevs; 672 + static struct gpiod_lookup_table **gpiod_lookup_tables; 673 + 674 + static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info, 675 + int idx) 676 + { 677 + const struct x86_i2c_client_info *client_info = &dev_info->i2c_client_info[idx]; 678 + struct i2c_board_info board_info = client_info->board_info; 679 + struct i2c_adapter *adap; 680 + acpi_handle handle; 681 + acpi_status status; 682 + 683 + board_info.irq = x86_acpi_irq_helper_get(&client_info->irq_data); 684 + if (board_info.irq < 0) 685 + return board_info.irq; 686 + 687 + status = acpi_get_handle(NULL, client_info->adapter_path, &handle); 688 + if (ACPI_FAILURE(status)) { 689 + pr_err("Error could not get %s handle\n", client_info->adapter_path); 690 + return -ENODEV; 691 + } 692 + 693 + adap = i2c_acpi_find_adapter_by_handle(handle); 694 + if (!adap) { 695 + pr_err("error could not get %s adapter\n", client_info->adapter_path); 696 + return -ENODEV; 697 + } 698 + 699 + i2c_clients[idx] = i2c_new_client_device(adap, &board_info); 700 + put_device(&adap->dev); 701 + if (IS_ERR(i2c_clients[idx])) 702 + return dev_err_probe(&adap->dev, PTR_ERR(i2c_clients[idx]), 703 + "creating I2C-client %d\n", idx); 704 + 705 + return 0; 706 + } 707 + 708 + static __init int x86_instantiate_serdev(const struct x86_serdev_info *info, int idx) 709 + { 710 + struct acpi_device *ctrl_adev, *serdev_adev; 711 + struct serdev_device *serdev; 712 + struct device *ctrl_dev; 713 + int ret = -ENODEV; 714 + 715 + ctrl_adev = acpi_dev_get_first_match_dev(info->ctrl_hid, info->ctrl_uid, -1); 716 + if (!ctrl_adev) { 717 + pr_err("error could not get %s/%s ctrl adev\n", 718 + info->ctrl_hid, info->ctrl_uid); 719 + return -ENODEV; 720 + } 721 + 722 + serdev_adev = acpi_dev_get_first_match_dev(info->serdev_hid, NULL, -1); 723 + if (!serdev_adev) { 724 + pr_err("error could not get %s serdev adev\n", info->serdev_hid); 725 + goto put_ctrl_adev; 726 + } 727 + 728 + /* get_first_physical_node() returns a weak ref, no need to put() it */ 729 + ctrl_dev = acpi_get_first_physical_node(ctrl_adev); 730 + if (!ctrl_dev) { 731 + pr_err("error could not get %s/%s ctrl physical dev\n", 732 + info->ctrl_hid, info->ctrl_uid); 733 + goto put_serdev_adev; 734 + } 735 + 736 + /* ctrl_dev now points to the controller's parent, get the controller */ 737 + ctrl_dev = device_find_child_by_name(ctrl_dev, info->ctrl_devname); 738 + if (!ctrl_dev) { 739 + pr_err("error could not get %s/%s %s ctrl dev\n", 740 + info->ctrl_hid, info->ctrl_uid, info->ctrl_devname); 741 + goto put_serdev_adev; 742 + } 743 + 744 + serdev = serdev_device_alloc(to_serdev_controller(ctrl_dev)); 745 + if (!serdev) { 746 + ret = -ENOMEM; 747 + goto put_serdev_adev; 748 + } 749 + 750 + ACPI_COMPANION_SET(&serdev->dev, serdev_adev); 751 + acpi_device_set_enumerated(serdev_adev); 752 + 753 + ret = serdev_device_add(serdev); 754 + if (ret) { 755 + dev_err(&serdev->dev, "error %d adding serdev\n", ret); 756 + serdev_device_put(serdev); 757 + goto put_serdev_adev; 758 + } 759 + 760 + serdevs[idx] = serdev; 761 + 762 + put_serdev_adev: 763 + acpi_dev_put(serdev_adev); 764 + put_ctrl_adev: 765 + acpi_dev_put(ctrl_adev); 766 + return ret; 767 + } 768 + 769 + static void x86_android_tablet_cleanup(void) 770 + { 771 + int i; 772 + 773 + for (i = 0; i < serdev_count; i++) { 774 + if (serdevs[i]) 775 + serdev_device_remove(serdevs[i]); 776 + } 777 + 778 + kfree(serdevs); 779 + 780 + for (i = 0; i < pdev_count; i++) 781 + platform_device_unregister(pdevs[i]); 782 + 783 + kfree(pdevs); 784 + 785 + for (i = 0; i < i2c_client_count; i++) 786 + i2c_unregister_device(i2c_clients[i]); 787 + 788 + kfree(i2c_clients); 789 + 790 + for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) 791 + gpiod_remove_lookup_table(gpiod_lookup_tables[i]); 792 + } 793 + 794 + static __init int x86_android_tablet_init(void) 795 + { 796 + const struct x86_dev_info *dev_info; 797 + const struct dmi_system_id *id; 798 + int i, ret = 0; 799 + 800 + id = dmi_first_match(x86_android_tablet_ids); 801 + if (!id) 802 + return -ENODEV; 803 + 804 + dev_info = id->driver_data; 805 + 806 + /* 807 + * Since this runs from module_init() it cannot use -EPROBE_DEFER, 808 + * instead pre-load any modules which are listed as requirements. 809 + */ 810 + for (i = 0; dev_info->modules && dev_info->modules[i]; i++) 811 + request_module(dev_info->modules[i]); 812 + 813 + gpiod_lookup_tables = dev_info->gpiod_lookup_tables; 814 + for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) 815 + gpiod_add_lookup_table(gpiod_lookup_tables[i]); 816 + 817 + i2c_clients = kcalloc(dev_info->i2c_client_count, sizeof(*i2c_clients), GFP_KERNEL); 818 + if (!i2c_clients) { 819 + x86_android_tablet_cleanup(); 820 + return -ENOMEM; 821 + } 822 + 823 + i2c_client_count = dev_info->i2c_client_count; 824 + for (i = 0; i < i2c_client_count; i++) { 825 + ret = x86_instantiate_i2c_client(dev_info, i); 826 + if (ret < 0) { 827 + x86_android_tablet_cleanup(); 828 + return ret; 829 + } 830 + } 831 + 832 + pdevs = kcalloc(dev_info->pdev_count, sizeof(*pdevs), GFP_KERNEL); 833 + if (!pdevs) { 834 + x86_android_tablet_cleanup(); 835 + return -ENOMEM; 836 + } 837 + 838 + pdev_count = dev_info->pdev_count; 839 + for (i = 0; i < pdev_count; i++) { 840 + pdevs[i] = platform_device_register_full(&dev_info->pdev_info[i]); 841 + if (IS_ERR(pdevs[i])) { 842 + x86_android_tablet_cleanup(); 843 + return PTR_ERR(pdevs[i]); 844 + } 845 + } 846 + 847 + serdevs = kcalloc(dev_info->serdev_count, sizeof(*serdevs), GFP_KERNEL); 848 + if (!serdevs) { 849 + x86_android_tablet_cleanup(); 850 + return -ENOMEM; 851 + } 852 + 853 + serdev_count = dev_info->serdev_count; 854 + for (i = 0; i < serdev_count; i++) { 855 + ret = x86_instantiate_serdev(&dev_info->serdev_info[i], i); 856 + if (ret < 0) { 857 + x86_android_tablet_cleanup(); 858 + return ret; 859 + } 860 + } 861 + 862 + return 0; 863 + } 864 + 865 + module_init(x86_android_tablet_init); 866 + module_exit(x86_android_tablet_cleanup); 867 + 868 + MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com"); 869 + MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver"); 870 + MODULE_LICENSE("GPL");
+56
drivers/power/supply/power_supply_sysfs.c
··· 134 134 [POWER_SUPPLY_SCOPE_DEVICE] = "Device", 135 135 }; 136 136 137 + static const char * const POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[] = { 138 + [POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO] = "auto", 139 + [POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE] = "inhibit-charge", 140 + [POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE] = "force-discharge", 141 + }; 142 + 137 143 static struct power_supply_attr power_supply_attrs[] = { 138 144 /* Properties of type `int' */ 139 145 POWER_SUPPLY_ENUM_ATTR(STATUS), ··· 179 173 POWER_SUPPLY_ATTR(CHARGE_CONTROL_LIMIT_MAX), 180 174 POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD), 181 175 POWER_SUPPLY_ATTR(CHARGE_CONTROL_END_THRESHOLD), 176 + POWER_SUPPLY_ENUM_ATTR(CHARGE_BEHAVIOUR), 182 177 POWER_SUPPLY_ATTR(INPUT_CURRENT_LIMIT), 183 178 POWER_SUPPLY_ATTR(INPUT_VOLTAGE_LIMIT), 184 179 POWER_SUPPLY_ATTR(INPUT_POWER_LIMIT), ··· 492 485 493 486 return ret; 494 487 } 488 + 489 + ssize_t power_supply_charge_behaviour_show(struct device *dev, 490 + unsigned int available_behaviours, 491 + enum power_supply_charge_behaviour current_behaviour, 492 + char *buf) 493 + { 494 + bool match = false, available, active; 495 + ssize_t count = 0; 496 + int i; 497 + 498 + for (i = 0; i < ARRAY_SIZE(POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT); i++) { 499 + available = available_behaviours & BIT(i); 500 + active = i == current_behaviour; 501 + 502 + if (available && active) { 503 + count += sysfs_emit_at(buf, count, "[%s] ", 504 + POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[i]); 505 + match = true; 506 + } else if (available) { 507 + count += sysfs_emit_at(buf, count, "%s ", 508 + POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[i]); 509 + } 510 + } 511 + 512 + if (!match) { 513 + dev_warn(dev, "driver reporting unsupported charge behaviour\n"); 514 + return -EINVAL; 515 + } 516 + 517 + if (count) 518 + buf[count - 1] = '\n'; 519 + 520 + return count; 521 + } 522 + EXPORT_SYMBOL_GPL(power_supply_charge_behaviour_show); 523 + 524 + int power_supply_charge_behaviour_parse(unsigned int available_behaviours, const char *buf) 525 + { 526 + int i = sysfs_match_string(POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT, buf); 527 + 528 + if (i < 0) 529 + return i; 530 + 531 + if (available_behaviours & BIT(i)) 532 + return i; 533 + 534 + return -EINVAL; 535 + } 536 + EXPORT_SYMBOL_GPL(power_supply_charge_behaviour_parse);
+11
drivers/watchdog/Kconfig
··· 1589 1589 To compile this driver as a module, choose M here: the module will be 1590 1590 called nic7018_wdt. 1591 1591 1592 + config SIEMENS_SIMATIC_IPC_WDT 1593 + tristate "Siemens Simatic IPC Watchdog" 1594 + depends on SIEMENS_SIMATIC_IPC 1595 + select WATCHDOG_CORE 1596 + help 1597 + This driver adds support for several watchdogs found in Industrial 1598 + PCs from Siemens. 1599 + 1600 + To compile this driver as a module, choose M here: the module will be 1601 + called simatic-ipc-wdt. 1602 + 1592 1603 # M68K Architecture 1593 1604 1594 1605 config M54xx_WATCHDOG
+1
drivers/watchdog/Makefile
··· 143 143 obj-$(CONFIG_NIC7018_WDT) += nic7018_wdt.o 144 144 obj-$(CONFIG_MLX_WDT) += mlx_wdt.o 145 145 obj-$(CONFIG_KEEMBAY_WATCHDOG) += keembay_wdt.o 146 + obj-$(CONFIG_SIEMENS_SIMATIC_IPC_WDT) += simatic-ipc-wdt.o 146 147 147 148 # M68K Architecture 148 149 obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o
+228
drivers/watchdog/simatic-ipc-wdt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for Watchdogs 4 + * 5 + * Copyright (c) Siemens AG, 2020-2021 6 + * 7 + * Authors: 8 + * Gerd Haeussler <gerd.haeussler.ext@siemens.com> 9 + */ 10 + 11 + #include <linux/device.h> 12 + #include <linux/errno.h> 13 + #include <linux/init.h> 14 + #include <linux/io.h> 15 + #include <linux/ioport.h> 16 + #include <linux/kernel.h> 17 + #include <linux/module.h> 18 + #include <linux/pci.h> 19 + #include <linux/platform_data/x86/simatic-ipc-base.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/sizes.h> 22 + #include <linux/util_macros.h> 23 + #include <linux/watchdog.h> 24 + 25 + #define WD_ENABLE_IOADR 0x62 26 + #define WD_TRIGGER_IOADR 0x66 27 + #define GPIO_COMMUNITY0_PORT_ID 0xaf 28 + #define PAD_CFG_DW0_GPP_A_23 0x4b8 29 + #define SAFE_EN_N_427E 0x01 30 + #define SAFE_EN_N_227E 0x04 31 + #define WD_ENABLED 0x01 32 + #define WD_TRIGGERED 0x80 33 + #define WD_MACROMODE 0x02 34 + 35 + #define TIMEOUT_MIN 2 36 + #define TIMEOUT_DEF 64 37 + #define TIMEOUT_MAX 64 38 + 39 + #define GP_STATUS_REG_227E 0x404D /* IO PORT for SAFE_EN_N on 227E */ 40 + 41 + static bool nowayout = WATCHDOG_NOWAYOUT; 42 + module_param(nowayout, bool, 0000); 43 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 44 + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 45 + 46 + static struct resource gp_status_reg_227e_res = 47 + DEFINE_RES_IO_NAMED(GP_STATUS_REG_227E, SZ_1, KBUILD_MODNAME); 48 + 49 + static struct resource io_resource_enable = 50 + DEFINE_RES_IO_NAMED(WD_ENABLE_IOADR, SZ_1, 51 + KBUILD_MODNAME " WD_ENABLE_IOADR"); 52 + 53 + static struct resource io_resource_trigger = 54 + DEFINE_RES_IO_NAMED(WD_TRIGGER_IOADR, SZ_1, 55 + KBUILD_MODNAME " WD_TRIGGER_IOADR"); 56 + 57 + /* the actual start will be discovered with pci, 0 is a placeholder */ 58 + static struct resource mem_resource = 59 + DEFINE_RES_MEM_NAMED(0, SZ_4, "WD_RESET_BASE_ADR"); 60 + 61 + static u32 wd_timeout_table[] = {2, 4, 6, 8, 16, 32, 48, 64 }; 62 + static void __iomem *wd_reset_base_addr; 63 + 64 + static int wd_start(struct watchdog_device *wdd) 65 + { 66 + outb(inb(WD_ENABLE_IOADR) | WD_ENABLED, WD_ENABLE_IOADR); 67 + return 0; 68 + } 69 + 70 + static int wd_stop(struct watchdog_device *wdd) 71 + { 72 + outb(inb(WD_ENABLE_IOADR) & ~WD_ENABLED, WD_ENABLE_IOADR); 73 + return 0; 74 + } 75 + 76 + static int wd_ping(struct watchdog_device *wdd) 77 + { 78 + inb(WD_TRIGGER_IOADR); 79 + return 0; 80 + } 81 + 82 + static int wd_set_timeout(struct watchdog_device *wdd, unsigned int t) 83 + { 84 + int timeout_idx = find_closest(t, wd_timeout_table, 85 + ARRAY_SIZE(wd_timeout_table)); 86 + 87 + outb((inb(WD_ENABLE_IOADR) & 0xc7) | timeout_idx << 3, WD_ENABLE_IOADR); 88 + wdd->timeout = wd_timeout_table[timeout_idx]; 89 + return 0; 90 + } 91 + 92 + static const struct watchdog_info wdt_ident = { 93 + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | 94 + WDIOF_SETTIMEOUT, 95 + .identity = KBUILD_MODNAME, 96 + }; 97 + 98 + static const struct watchdog_ops wdt_ops = { 99 + .owner = THIS_MODULE, 100 + .start = wd_start, 101 + .stop = wd_stop, 102 + .ping = wd_ping, 103 + .set_timeout = wd_set_timeout, 104 + }; 105 + 106 + static void wd_secondary_enable(u32 wdtmode) 107 + { 108 + u16 resetbit; 109 + 110 + /* set safe_en_n so we are not just WDIOF_ALARMONLY */ 111 + if (wdtmode == SIMATIC_IPC_DEVICE_227E) { 112 + /* enable SAFE_EN_N on GP_STATUS_REG_227E */ 113 + resetbit = inb(GP_STATUS_REG_227E); 114 + outb(resetbit & ~SAFE_EN_N_227E, GP_STATUS_REG_227E); 115 + } else { 116 + /* enable SAFE_EN_N on PCH D1600 */ 117 + resetbit = ioread16(wd_reset_base_addr); 118 + iowrite16(resetbit & ~SAFE_EN_N_427E, wd_reset_base_addr); 119 + } 120 + } 121 + 122 + static int wd_setup(u32 wdtmode) 123 + { 124 + unsigned int bootstatus = 0; 125 + int timeout_idx; 126 + 127 + timeout_idx = find_closest(TIMEOUT_DEF, wd_timeout_table, 128 + ARRAY_SIZE(wd_timeout_table)); 129 + 130 + if (inb(WD_ENABLE_IOADR) & WD_TRIGGERED) 131 + bootstatus |= WDIOF_CARDRESET; 132 + 133 + /* reset alarm bit, set macro mode, and set timeout */ 134 + outb(WD_TRIGGERED | WD_MACROMODE | timeout_idx << 3, WD_ENABLE_IOADR); 135 + 136 + wd_secondary_enable(wdtmode); 137 + 138 + return bootstatus; 139 + } 140 + 141 + static struct watchdog_device wdd_data = { 142 + .info = &wdt_ident, 143 + .ops = &wdt_ops, 144 + .min_timeout = TIMEOUT_MIN, 145 + .max_timeout = TIMEOUT_MAX 146 + }; 147 + 148 + static int simatic_ipc_wdt_probe(struct platform_device *pdev) 149 + { 150 + struct simatic_ipc_platform *plat = pdev->dev.platform_data; 151 + struct device *dev = &pdev->dev; 152 + struct resource *res; 153 + 154 + switch (plat->devmode) { 155 + case SIMATIC_IPC_DEVICE_227E: 156 + if (!devm_request_region(dev, gp_status_reg_227e_res.start, 157 + resource_size(&gp_status_reg_227e_res), 158 + KBUILD_MODNAME)) { 159 + dev_err(dev, 160 + "Unable to register IO resource at %pR\n", 161 + &gp_status_reg_227e_res); 162 + return -EBUSY; 163 + } 164 + fallthrough; 165 + case SIMATIC_IPC_DEVICE_427E: 166 + wdd_data.parent = dev; 167 + break; 168 + default: 169 + return -EINVAL; 170 + } 171 + 172 + if (!devm_request_region(dev, io_resource_enable.start, 173 + resource_size(&io_resource_enable), 174 + io_resource_enable.name)) { 175 + dev_err(dev, 176 + "Unable to register IO resource at %#x\n", 177 + WD_ENABLE_IOADR); 178 + return -EBUSY; 179 + } 180 + 181 + if (!devm_request_region(dev, io_resource_trigger.start, 182 + resource_size(&io_resource_trigger), 183 + io_resource_trigger.name)) { 184 + dev_err(dev, 185 + "Unable to register IO resource at %#x\n", 186 + WD_TRIGGER_IOADR); 187 + return -EBUSY; 188 + } 189 + 190 + if (plat->devmode == SIMATIC_IPC_DEVICE_427E) { 191 + res = &mem_resource; 192 + 193 + /* get GPIO base from PCI */ 194 + res->start = simatic_ipc_get_membase0(PCI_DEVFN(0x1f, 1)); 195 + if (res->start == 0) 196 + return -ENODEV; 197 + 198 + /* do the final address calculation */ 199 + res->start = res->start + (GPIO_COMMUNITY0_PORT_ID << 16) + 200 + PAD_CFG_DW0_GPP_A_23; 201 + res->end += res->start; 202 + 203 + wd_reset_base_addr = devm_ioremap_resource(dev, res); 204 + if (IS_ERR(wd_reset_base_addr)) 205 + return PTR_ERR(wd_reset_base_addr); 206 + } 207 + 208 + wdd_data.bootstatus = wd_setup(plat->devmode); 209 + if (wdd_data.bootstatus) 210 + dev_warn(dev, "last reboot caused by watchdog reset\n"); 211 + 212 + watchdog_set_nowayout(&wdd_data, nowayout); 213 + watchdog_stop_on_reboot(&wdd_data); 214 + return devm_watchdog_register_device(dev, &wdd_data); 215 + } 216 + 217 + static struct platform_driver simatic_ipc_wdt_driver = { 218 + .probe = simatic_ipc_wdt_probe, 219 + .driver = { 220 + .name = KBUILD_MODNAME, 221 + }, 222 + }; 223 + 224 + module_platform_driver(simatic_ipc_wdt_driver); 225 + 226 + MODULE_LICENSE("GPL v2"); 227 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 228 + MODULE_AUTHOR("Gerd Haeussler <gerd.haeussler.ext@siemens.com>");
+2
include/linux/platform_data/x86/asus-wmi.h
··· 77 77 #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 78 78 #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */ 79 79 #define ASUS_WMI_DEVID_CPU_FAN_CTRL 0x00110013 80 + #define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024 81 + #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025 80 82 81 83 /* Power */ 82 84 #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
+29
include/linux/platform_data/x86/simatic-ipc-base.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Siemens SIMATIC IPC drivers 4 + * 5 + * Copyright (c) Siemens AG, 2018-2021 6 + * 7 + * Authors: 8 + * Henning Schild <henning.schild@siemens.com> 9 + * Gerd Haeussler <gerd.haeussler.ext@siemens.com> 10 + */ 11 + 12 + #ifndef __PLATFORM_DATA_X86_SIMATIC_IPC_BASE_H 13 + #define __PLATFORM_DATA_X86_SIMATIC_IPC_BASE_H 14 + 15 + #include <linux/types.h> 16 + 17 + #define SIMATIC_IPC_DEVICE_NONE 0 18 + #define SIMATIC_IPC_DEVICE_227D 1 19 + #define SIMATIC_IPC_DEVICE_427E 2 20 + #define SIMATIC_IPC_DEVICE_127E 3 21 + #define SIMATIC_IPC_DEVICE_227E 4 22 + 23 + struct simatic_ipc_platform { 24 + u8 devmode; 25 + }; 26 + 27 + u32 simatic_ipc_get_membase0(unsigned int p2sb); 28 + 29 + #endif /* __PLATFORM_DATA_X86_SIMATIC_IPC_BASE_H */
+72
include/linux/platform_data/x86/simatic-ipc.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Siemens SIMATIC IPC drivers 4 + * 5 + * Copyright (c) Siemens AG, 2018-2021 6 + * 7 + * Authors: 8 + * Henning Schild <henning.schild@siemens.com> 9 + * Gerd Haeussler <gerd.haeussler.ext@siemens.com> 10 + */ 11 + 12 + #ifndef __PLATFORM_DATA_X86_SIMATIC_IPC_H 13 + #define __PLATFORM_DATA_X86_SIMATIC_IPC_H 14 + 15 + #include <linux/dmi.h> 16 + #include <linux/platform_data/x86/simatic-ipc-base.h> 17 + 18 + #define SIMATIC_IPC_DMI_ENTRY_OEM 129 19 + /* binary type */ 20 + #define SIMATIC_IPC_DMI_TYPE 0xff 21 + #define SIMATIC_IPC_DMI_GROUP 0x05 22 + #define SIMATIC_IPC_DMI_ENTRY 0x02 23 + #define SIMATIC_IPC_DMI_TID 0x02 24 + 25 + enum simatic_ipc_station_ids { 26 + SIMATIC_IPC_INVALID_STATION_ID = 0, 27 + SIMATIC_IPC_IPC227D = 0x00000501, 28 + SIMATIC_IPC_IPC427D = 0x00000701, 29 + SIMATIC_IPC_IPC227E = 0x00000901, 30 + SIMATIC_IPC_IPC277E = 0x00000902, 31 + SIMATIC_IPC_IPC427E = 0x00000A01, 32 + SIMATIC_IPC_IPC477E = 0x00000A02, 33 + SIMATIC_IPC_IPC127E = 0x00000D01, 34 + }; 35 + 36 + static inline u32 simatic_ipc_get_station_id(u8 *data, int max_len) 37 + { 38 + struct { 39 + u8 type; /* type (0xff = binary) */ 40 + u8 len; /* len of data entry */ 41 + u8 group; 42 + u8 entry; 43 + u8 tid; 44 + __le32 station_id; /* station id (LE) */ 45 + } __packed * data_entry = (void *)data + sizeof(struct dmi_header); 46 + 47 + while ((u8 *)data_entry < data + max_len) { 48 + if (data_entry->type == SIMATIC_IPC_DMI_TYPE && 49 + data_entry->len == sizeof(*data_entry) && 50 + data_entry->group == SIMATIC_IPC_DMI_GROUP && 51 + data_entry->entry == SIMATIC_IPC_DMI_ENTRY && 52 + data_entry->tid == SIMATIC_IPC_DMI_TID) { 53 + return le32_to_cpu(data_entry->station_id); 54 + } 55 + data_entry = (void *)((u8 *)(data_entry) + data_entry->len); 56 + } 57 + 58 + return SIMATIC_IPC_INVALID_STATION_ID; 59 + } 60 + 61 + static inline void 62 + simatic_ipc_find_dmi_entry_helper(const struct dmi_header *dh, void *_data) 63 + { 64 + u32 *id = _data; 65 + 66 + if (dh->type != SIMATIC_IPC_DMI_ENTRY_OEM) 67 + return; 68 + 69 + *id = simatic_ipc_get_station_id((u8 *)dh, dh->length); 70 + } 71 + 72 + #endif /* __PLATFORM_DATA_X86_SIMATIC_IPC_H */
+31
include/linux/power_supply.h
··· 133 133 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, 134 134 POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, /* in percents! */ 135 135 POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, /* in percents! */ 136 + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, 136 137 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, 137 138 POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, 138 139 POWER_SUPPLY_PROP_INPUT_POWER_LIMIT, ··· 202 201 POWER_SUPPLY_USB_TYPE_PD_DRP, /* PD Dual Role Port */ 203 202 POWER_SUPPLY_USB_TYPE_PD_PPS, /* PD Programmable Power Supply */ 204 203 POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID, /* Apple Charging Method */ 204 + }; 205 + 206 + enum power_supply_charge_behaviour { 207 + POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO = 0, 208 + POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE, 209 + POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE, 205 210 }; 206 211 207 212 enum power_supply_notifier_events { ··· 714 707 715 708 static inline 716 709 void power_supply_remove_hwmon_sysfs(struct power_supply *psy) {} 710 + #endif 711 + 712 + #ifdef CONFIG_SYSFS 713 + ssize_t power_supply_charge_behaviour_show(struct device *dev, 714 + unsigned int available_behaviours, 715 + enum power_supply_charge_behaviour behaviour, 716 + char *buf); 717 + 718 + int power_supply_charge_behaviour_parse(unsigned int available_behaviours, const char *buf); 719 + #else 720 + static inline 721 + ssize_t power_supply_charge_behaviour_show(struct device *dev, 722 + unsigned int available_behaviours, 723 + enum power_supply_charge_behaviour behaviour, 724 + char *buf) 725 + { 726 + return -EOPNOTSUPP; 727 + } 728 + 729 + static inline int power_supply_charge_behaviour_parse(unsigned int available_behaviours, 730 + const char *buf) 731 + { 732 + return -EOPNOTSUPP; 733 + } 717 734 #endif 718 735 719 736 #endif /* __LINUX_POWER_SUPPLY_H__ */
+9
include/linux/surface_aggregator/device.h
··· 319 319 ssam_device_driver_unregister) 320 320 321 321 322 + /* -- Helpers for controller and hub devices. ------------------------------- */ 323 + 324 + #ifdef CONFIG_SURFACE_AGGREGATOR_BUS 325 + void ssam_remove_clients(struct device *dev); 326 + #else /* CONFIG_SURFACE_AGGREGATOR_BUS */ 327 + static inline void ssam_remove_clients(struct device *dev) {} 328 + #endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ 329 + 330 + 322 331 /* -- Helpers for client-device requests. ----------------------------------- */ 323 332 324 333 /**
+1
include/linux/wmi.h
··· 35 35 struct wmi_driver { 36 36 struct device_driver driver; 37 37 const struct wmi_device_id *id_table; 38 + bool no_notify_data; 38 39 39 40 int (*probe)(struct wmi_device *wdev, const void *context); 40 41 void (*remove)(struct wmi_device *wdev);
+3 -1
tools/power/x86/intel-speed-select/isst-config.c
··· 15 15 int arg; 16 16 }; 17 17 18 - static const char *version_str = "v1.10"; 18 + static const char *version_str = "v1.11"; 19 19 static const int supported_api_ver = 1; 20 20 static struct isst_if_platform_info isst_platform_info; 21 21 static char *progname; ··· 1599 1599 die_id != get_physical_die_id(i)) 1600 1600 continue; 1601 1601 1602 + adjust_scaling_max_from_base_freq(i); 1602 1603 set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0); 1603 1604 adjust_scaling_min_from_base_freq(i); 1604 1605 } ··· 1616 1615 die_id != get_physical_die_id(i)) 1617 1616 continue; 1618 1617 1618 + adjust_scaling_max_from_base_freq(i); 1619 1619 set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0); 1620 1620 } 1621 1621 }