Commit 90035c28 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v5.13-1' of...

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

Pull x86 platform driver updates freom Hans de Goede:

 - lots of Microsoft Surface work

 - platform-profile support for HP and Microsoft Surface devices

 - new WMI Gigabyte motherboard temperature monitoring driver

 - Intel PMC improvements for Tiger Lake and Alder Lake

 - misc bugfixes, improvements and quirk additions all over

* tag 'platform-drivers-x86-v5.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (87 commits)
  platform/x86: gigabyte-wmi: add support for B550M AORUS PRO-P
  platform/x86: intel_pmc_core: Uninitialized data in pmc_core_lpm_latch_mode_write()
  platform/x86: intel_pmc_core: add ACPI dependency
  platform/surface: aggregator: fix a bit test
  platform/x86: intel_pmc_core: Fix "unsigned 'ret' is never less than zero" smatch warning
  platform/x86: touchscreen_dmi: Add info for the Teclast Tbook 11 tablet
  platform/x86: intel_pmc_core: Add support for Alder Lake PCH-P
  platform/x86: intel_pmc_core: Add LTR registers for Tiger Lake
  platform/x86: intel_pmc_core: Add option to set/clear LPM mode
  platform/x86: intel_pmc_core: Add requirements file to debugfs
  platform/x86: intel_pmc_core: Get LPM requirements for Tiger Lake
  platform/x86: intel_pmc_core: Show LPM residency in microseconds
  platform/x86: intel_pmc_core: Handle sub-states generically
  platform/x86: intel_pmc_core: Remove global struct pmc_dev
  platform/x86: intel_pmc_core: Don't use global pmcdev in quirks
  platform/x86: intel_chtdc_ti_pwrbtn: Fix missing IRQF_ONESHOT as only threaded handler
  platform/x86: gigabyte-wmi: add X570 AORUS ELITE
  platform/x86: thinkpad_acpi: Add labels to the first 2 temperature sensors
  platform/x86: pmc_atom: Match all Beckhoff Automation baytrail boards with critclk_systems DMI table
  platform/x86: add Gigabyte WMI temperature driver
  ...
parents 81f20231 e7882cd7
What: /sys/devices/platform/<platform>/etr3
Date: Apr 2021
KernelVersion: 5.13
Contact: "Tomas Winkler" <tomas.winkler@intel.com>
Description:
The file exposes "Extended Test Mode Register 3" global
reset bits. The bits are used during an Intel platform
manufacturing process to indicate that consequent reset
of the platform is a "global reset". This type of reset
is required in order for manufacturing configurations
to take effect.
Display global reset setting bits for PMC.
* bit 31 - global reset is locked
* bit 20 - global reset is set
Writing bit 20 value to the etr3 will induce
a platform "global reset" upon consequent platform reset,
in case the register is not locked.
The "global reset bit" should be locked on a production
system and the file is in read-only mode.
......@@ -52,6 +52,7 @@ detailed description):
- LCD Shadow (PrivacyGuard) enable and disable
- Lap mode sensor
- Setting keyboard language
- WWAN Antenna type
A compatibility table by model and feature is maintained on the web
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
......@@ -1490,6 +1491,25 @@ fr(French), fr-ch(French(Switzerland)), hu(Hungarian), it(Italy), jp (Japan),
nl(Dutch), nn(Norway), pl(Polish), pt(portugese), sl(Slovenian), sv(Sweden),
tr(Turkey)
WWAN Antenna type
-----------------
sysfs: wwan_antenna_type
On some newer Thinkpads we need to set SAR value based on the antenna
type. This interface will be used by userspace to get the antenna type
and set the corresponding SAR value, as is required for FCC certification.
The available commands are::
cat /sys/devices/platform/thinkpad_acpi/wwan_antenna_type
Currently 2 antenna types are supported as mentioned below:
- type a
- type b
The property is read-only. If the platform doesn't have support the sysfs
class is not created.
Adaptive keyboard
-----------------
......
......@@ -248,7 +248,7 @@ This example defines a function
.. code-block:: c
int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);
static int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);
executing the specified request, with the controller passed in when calling
said function. In this example, the argument is provided via the ``arg``
......@@ -296,7 +296,7 @@ This invocation of the macro defines a function
.. code-block:: c
int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);
static int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);
executing the specified request, using the device IDs and controller given
in the client device. The full list of such macros for client devices is:
......
This diff is collapsed.
......@@ -11,6 +11,7 @@ This is the documentation for client drivers themselves. Refer to
:maxdepth: 1
cdev
dtx
san
.. only:: subproject and html
......
......@@ -327,6 +327,8 @@ Code Seq# Include File Comments
0xA4 00-1F uapi/asm/sgx.h <mailto:linux-sgx@vger.kernel.org>
0xA5 01 linux/surface_aggregator/cdev.h Microsoft Surface Platform System Aggregator
<mailto:luzmaximilian@gmail.com>
0xA5 20-2F linux/surface_aggregator/dtx.h Microsoft Surface DTX driver
<mailto:luzmaximilian@gmail.com>
0xAA 00-3F linux/uapi/linux/userfaultfd.h
0xAB 00-1F linux/nbd.h
0xAC 00-1F linux/raw.h
......
......@@ -573,6 +573,12 @@ S: Maintained
F: Documentation/scsi/advansys.rst
F: drivers/scsi/advansys.c
ADVANTECH SWBTN DRIVER
M: Andrea Ho <Andrea.Ho@advantech.com.tw>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/adv_swbutton.c
ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
M: Michael Hennerich <michael.hennerich@analog.com>
S: Supported
......@@ -697,6 +703,11 @@ S: Maintained
F: Documentation/i2c/busses/i2c-ali1563.rst
F: drivers/i2c/busses/i2c-ali1563.c
ALIENWARE WMI DRIVER
L: Dell.Client.Kernel@dell.com
S: Maintained
F: drivers/platform/x86/dell/alienware-wmi.c
ALL SENSORS DLH SERIES PRESSURE SENSORS DRIVER
M: Tomislav Denis <tomislav.denis@avl.com>
L: linux-iio@vger.kernel.org
......@@ -5043,19 +5054,19 @@ F: drivers/platform/x86/dell/dell_rbu.c
DELL SMBIOS DRIVER
M: Pali Rohár <pali@kernel.org>
M: Mario Limonciello <mario.limonciello@dell.com>
L: Dell.Client.Kernel@dell.com
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/dell/dell-smbios.*
DELL SMBIOS SMM DRIVER
M: Mario Limonciello <mario.limonciello@dell.com>
L: Dell.Client.Kernel@dell.com
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/dell/dell-smbios-smm.c
DELL SMBIOS WMI DRIVER
M: Mario Limonciello <mario.limonciello@dell.com>
L: Dell.Client.Kernel@dell.com
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/dell/dell-smbios-wmi.c
......@@ -5069,14 +5080,14 @@ F: Documentation/driver-api/dcdbas.rst
F: drivers/platform/x86/dell/dcdbas.*
DELL WMI DESCRIPTOR DRIVER
M: Mario Limonciello <mario.limonciello@dell.com>
L: Dell.Client.Kernel@dell.com
S: Maintained
F: drivers/platform/x86/dell/dell-wmi-descriptor.c
DELL WMI SYSMAN DRIVER
M: Divya Bharathi <divya.bharathi@dell.com>
M: Mario Limonciello <mario.limonciello@dell.com>
M: Prasanth Ksr <prasanth.ksr@dell.com>
L: Dell.Client.Kernel@dell.com
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-class-firmware-attributes
......@@ -7551,6 +7562,12 @@ F: Documentation/filesystems/gfs2*
F: fs/gfs2/
F: include/uapi/linux/gfs2_ondisk.h
GIGABYTE WMI DRIVER
M: Thomas Weißschuh <thomas@weissschuh.net>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/gigabyte-wmi.c
GNSS SUBSYSTEM
M: Johan Hovold <johan@kernel.org>
S: Maintained
......@@ -9141,6 +9158,7 @@ M: Rajneesh Bhardwaj <irenic.rajneesh@gmail.com>
M: David E Box <david.e.box@intel.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-platform-intel-pmc
F: drivers/platform/x86/intel_pmc_core*
INTEL PMIC GPIO DRIVERS
......@@ -9251,7 +9269,7 @@ W: https://slimbootloader.github.io/security/firmware-update.html
F: drivers/platform/x86/intel-wmi-sbl-fw-update.c
INTEL WMI THUNDERBOLT FORCE POWER DRIVER
M: Mario Limonciello <mario.limonciello@dell.com>
L: Dell.Client.Kernel@dell.com
S: Maintained
F: drivers/platform/x86/intel-wmi-thunderbolt.c
......@@ -11452,8 +11470,8 @@ Q: https://patchwork.kernel.org/project/netdevbpf/list/
F: drivers/net/ethernet/mellanox/mlxfw/
MELLANOX HARDWARE PLATFORM SUPPORT
M: Andy Shevchenko <andy@infradead.org>
M: Darren Hart <dvhart@infradead.org>
M: Hans de Goede <hdegoede@redhat.com>
M: Mark Gross <mgross@linux.intel.com>
M: Vadim Pasternak <vadimp@nvidia.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
......@@ -11876,6 +11894,14 @@ F: drivers/scsi/smartpqi/smartpqi*.[ch]
F: include/linux/cciss*.h
F: include/uapi/linux/cciss*.h
MICROSOFT SURFACE DTX DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: Documentation/driver-api/surface_aggregator/clients/dtx.rst
F: drivers/platform/surface/surface_dtx.c
F: include/uapi/linux/surface_aggregator/dtx.h
MICROSOFT SURFACE GPE LID SUPPORT DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: platform-driver-x86@vger.kernel.org
......@@ -11897,6 +11923,12 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/surface/surface_hotplug.c
MICROSOFT SURFACE PLATFORM PROFILE DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/surface/surface_platform_profile.c
MICROSOFT SURFACE PRO 3 BUTTON DRIVER
M: Chen Yu <yu.c.chen@intel.com>
L: platform-driver-x86@vger.kernel.org
......@@ -11912,6 +11944,7 @@ F: Documentation/driver-api/surface_aggregator/
F: drivers/platform/surface/aggregator/
F: drivers/platform/surface/surface_acpi_notify.c
F: drivers/platform/surface/surface_aggregator_cdev.c
F: drivers/platform/surface/surface_aggregator_registry.c
F: include/linux/surface_acpi_notify.h
F: include/linux/surface_aggregator/
F: include/uapi/linux/surface_aggregator/
......
......@@ -49,10 +49,14 @@ enum pmt_quirks {
/* Use shift instead of mask to read discovery table offset */
PMT_QUIRK_TABLE_SHIFT = BIT(2),
/* DVSEC not present (provided in driver data) */
PMT_QUIRK_NO_DVSEC = BIT(3),
};
struct pmt_platform_info {
unsigned long quirks;
struct intel_dvsec_header **capabilities;
};
static const struct pmt_platform_info tgl_info = {
......@@ -60,6 +64,26 @@ static const struct pmt_platform_info tgl_info = {
PMT_QUIRK_TABLE_SHIFT,
};
/* DG1 Platform with DVSEC quirk*/
static struct intel_dvsec_header dg1_telemetry = {
.length = 0x10,
.id = 2,
.num_entries = 1,
.entry_size = 3,
.tbir = 0,
.offset = 0x466000,
};
static struct intel_dvsec_header *dg1_capabilities[] = {
&dg1_telemetry,
NULL
};
static const struct pmt_platform_info dg1_info = {
.quirks = PMT_QUIRK_NO_DVSEC,
.capabilities = dg1_capabilities,
};
static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header,
unsigned long quirks)
{
......@@ -79,19 +103,18 @@ static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header,
case DVSEC_INTEL_ID_WATCHER:
if (quirks & PMT_QUIRK_NO_WATCHER) {
dev_info(dev, "Watcher not supported\n");
return 0;
return -EINVAL;
}
name = "pmt_watcher";
break;
case DVSEC_INTEL_ID_CRASHLOG:
if (quirks & PMT_QUIRK_NO_CRASHLOG) {
dev_info(dev, "Crashlog not supported\n");
return 0;
return -EINVAL;
}
name = "pmt_crashlog";
break;
default:
dev_err(dev, "Unrecognized PMT capability: %d\n", id);
return -EINVAL;
}
......@@ -148,6 +171,22 @@ static int pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (info)
quirks = info->quirks;
if (info && (info->quirks & PMT_QUIRK_NO_DVSEC)) {
struct intel_dvsec_header **header;
header = info->capabilities;
while (*header) {
ret = pmt_add_dev(pdev, *header, quirks);
if (ret)
dev_warn(&pdev->dev,
"Failed to add device for DVSEC id %d\n",
(*header)->id);
else
found_devices = true;
++header;
}
} else {
do {
struct intel_dvsec_header header;
u32 table;
......@@ -174,15 +213,12 @@ static int pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
ret = pmt_add_dev(pdev, &header, quirks);
if (ret) {
dev_warn(&pdev->dev,
"Failed to add device for DVSEC id %d\n",
header.id);
if (ret)
continue;
}
found_devices = true;
} while (true);
}
if (!found_devices)
return -ENODEV;
......@@ -200,10 +236,12 @@ static void pmt_pci_remove(struct pci_dev *pdev)
}
#define PCI_DEVICE_ID_INTEL_PMT_ADL 0x467d
#define PCI_DEVICE_ID_INTEL_PMT_DG1 0x490e
#define PCI_DEVICE_ID_INTEL_PMT_OOBMSM 0x09a7
#define PCI_DEVICE_ID_INTEL_PMT_TGL 0x9a0d
static const struct pci_device_id pmt_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, PMT_ADL, &tgl_info) },
{ PCI_DEVICE_DATA(INTEL, PMT_DG1, &dg1_info) },
{ PCI_DEVICE_DATA(INTEL, PMT_OOBMSM, NULL) },
{ PCI_DEVICE_DATA(INTEL, PMT_TGL, &tgl_info) },
{ }
......
......@@ -208,7 +208,7 @@ static ssize_t secure_boot_fuse_state_show(struct device *dev,
* 0011 = version 1, 0111 = version 2, 1111 = version 3). Upper 4 bits
* are a thermometer code indicating key programming has completed for
* key n (same encodings as the start bits). This allows for detection
* of an interruption in the progamming process which has left the key
* of an interruption in the programming process which has left the key
* partially programmed (and thus invalid). The process is to burn the
* eFuse for the new key start bit, burn the key eFuses, then burn the
* eFuse for the new key complete bit.
......
......@@ -683,13 +683,13 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
err = devm_request_irq(&pdev->dev, priv->irq,
mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
| IRQF_SHARED, "mlxreg-hotplug", priv);
| IRQF_SHARED | IRQF_NO_AUTOEN,
"mlxreg-hotplug", priv);
if (err) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
return err;
}
disable_irq(priv->irq);
spin_lock_init(&priv->lock);
INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
dev_set_drvdata(&pdev->dev, priv);
......
......@@ -77,6 +77,53 @@ config SURFACE_AGGREGATOR_CDEV
The provided interface is intended for debugging and development only,
and should not be used otherwise.
config SURFACE_AGGREGATOR_REGISTRY
tristate "Surface System Aggregator Module Device Registry"
depends on SURFACE_AGGREGATOR
depends on SURFACE_AGGREGATOR_BUS
help
Device-registry and device-hubs for Surface System Aggregator Module
(SSAM) devices.
Provides a module and driver which act as a device-registry for SSAM
client devices that cannot be detected automatically, e.g. via ACPI.
Such devices are instead provided via this registry and attached via
device hubs, also provided in this module.
Devices provided via this registry are:
- Platform profile (performance-/cooling-mode) device (5th- and later
generations).
- Battery/AC devices (7th-generation).
- HID input devices (7th-generation).
Select M (recommended) or Y here if you want support for the above
mentioned devices on the corresponding Surface models. Without this
module, the respective devices will not be instantiated and thus any
functionality provided by them will be missing, even when drivers for
these devices are present. In other words, this module only provides
the respective client devices. Drivers for these devices still need to
be selected via the other options.
config SURFACE_DTX
tristate "Surface DTX (Detachment System) Driver"
depends on SURFACE_AGGREGATOR
depends on INPUT
help
Driver for the Surface Book clipboard detachment system (DTX).
On the Surface Book series devices, the display part containing the
CPU (called the clipboard) can be detached from the base (containing a
battery, the keyboard, and, optionally, a discrete GPU) by (if
necessary) unlocking and opening the latch connecting both parts.
This driver provides a user-space interface that can influence the
behavior of this process, which includes the option to abort it in
case the base is still in use or speed it up in case it is not.
Note that this module can be built without support for the Surface
Aggregator Bus (i.e. CONFIG_SURFACE_AGGREGATOR_BUS=n). In that case,
some devices, specifically the Surface Book 3, will not be supported.
config SURFACE_GPE
tristate "Surface GPE/Lid Support Driver"
depends on DMI
......@@ -105,6 +152,28 @@ config SURFACE_HOTPLUG
Select M or Y here, if you want to (fully) support hot-plugging of
dGPU devices on the Surface Book 2 and/or 3 during D3cold.
config SURFACE_PLATFORM_PROFILE
tristate "Surface Platform Profile Driver"
depends on SURFACE_AGGREGATOR_REGISTRY
select ACPI_PLATFORM_PROFILE
help
Provides support for the ACPI platform profile on 5th- and later
generation Microsoft Surface devices.
More specifically, this driver provides ACPI platform profile support
on Microsoft Surface devices with a Surface System Aggregator Module
(SSAM) connected via the Surface Serial Hub (SSH / SAM-over-SSH). In
other words, this driver provides platform profile support on the
Surface Pro 5, Surface Book 2, Surface Laptop, Surface Laptop Go and
later. On those devices, the platform profile can significantly
influence cooling behavior, e.g. setting it to 'quiet' (default) or
'low-power' can significantly limit performance of the discrete GPU on
Surface Books, while in turn leading to lower power consumption and/or
less fan noise.
Select M or Y here, if you want to include ACPI platform profile
support on the above mentioned devices.
config SURFACE_PRO3_BUTTON
tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
depends on INPUT
......
......@@ -10,6 +10,9 @@ obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o
obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o
obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/
obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o
obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o
obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o
obj-$(CONFIG_SURFACE_PLATFORM_PROFILE) += surface_platform_profile.o
obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
......@@ -1040,7 +1040,7 @@ static int ssam_dsm_load_u32(acpi_handle handle, u64 funcs, u64 func, u32 *ret)
union acpi_object *obj;
u64 val;
if (!(funcs & BIT(func)))
if (!(funcs & BIT_ULL(func)))
return 0; /* Not supported, leave *ret at its default value */
obj = acpi_evaluate_dsm_typed(handle, &SSAM_SSH_DSM_GUID,
......@@ -1750,35 +1750,35 @@ EXPORT_SYMBOL_GPL(ssam_request_sync_with_buffer);
/* -- Internal SAM requests. ------------------------------------------------ */
static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, {
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.command_id = 0x13,
.instance_id = 0x00,
});
static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, {
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.command_id = 0x15,
.instance_id = 0x00,
});
static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, {
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.command_id = 0x16,
.instance_id = 0x00,
});
static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, {
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.command_id = 0x33,
.instance_id = 0x00,
});
static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, {
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.command_id = 0x34,
......@@ -2483,7 +2483,8 @@ int ssam_irq_setup(struct ssam_controller *ctrl)
* interrupt, and let the SAM resume callback during the controller
* resume process clear it.
*/
const int irqf = IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_RISING;
const int irqf = IRQF_SHARED | IRQF_ONESHOT |
IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN;
gpiod = gpiod_get(dev, "ssam_wakeup-int", GPIOD_ASIS);
if (IS_ERR(gpiod))
......@@ -2501,7 +2502,6 @@ int ssam_irq_setup(struct ssam_controller *ctrl)
return status;
ctrl->irq.num = irq;
disable_irq(ctrl->irq.num);
return 0;
}
......
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0+
/*
* Surface Platform Profile / Performance Mode driver for Surface System
* Aggregator Module (thermal subsystem).
*
* Copyright (C) 2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <asm/unaligned.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_profile.h>
#include <linux/types.h>
#include <linux/surface_aggregator/device.h>
enum ssam_tmp_profile {
SSAM_TMP_PROFILE_NORMAL = 1,
SSAM_TMP_PROFILE_BATTERY_SAVER = 2,
SSAM_TMP_PROFILE_BETTER_PERFORMANCE = 3,
SSAM_TMP_PROFILE_BEST_PERFORMANCE = 4,
};
struct ssam_tmp_profile_info {
__le32 profile;
__le16 unknown1;
__le16 unknown2;
} __packed;
struct ssam_tmp_profile_device {
struct ssam_device *sdev;
struct platform_profile_handler handler;
};
SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get, struct ssam_tmp_profile_info, {
.target_category = SSAM_SSH_TC_TMP,
.command_id = 0x02,
});
SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set, __le32, {
.target_category = SSAM_SSH_TC_TMP,
.command_id = 0x03,
});
static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile *p)
{
struct ssam_tmp_profile_info info;
int status;
status = ssam_retry(__ssam_tmp_profile_get, sdev, &info);
if (status < 0)
return status;
*p = le32_to_cpu(info.profile);
return 0;
}
static int ssam_tmp_profile_set(struct ssam_device *sdev, enum ssam_tmp_profile p)
{
__le32 profile_le = cpu_to_le32(p);
return ssam_retry(__ssam_tmp_profile_set, sdev, &profile_le);
}
static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p)
{
switch (p) {
case SSAM_TMP_PROFILE_NORMAL:
return PLATFORM_PROFILE_BALANCED;
case SSAM_TMP_PROFILE_BATTERY_SAVER:
return PLATFORM_PROFILE_LOW_POWER;
case SSAM_TMP_PROFILE_BETTER_PERFORMANCE:
return PLATFORM_PROFILE_BALANCED_PERFORMANCE;
case SSAM_TMP_PROFILE_BEST_PERFORMANCE:
return PLATFORM_PROFILE_PERFORMANCE;
default:
dev_err(&sdev->dev, "invalid performance profile: %d", p);
return -EINVAL;
}
}
static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profile_option p)
{
switch (p) {
case PLATFORM_PROFILE_LOW_POWER:
return SSAM_TMP_PROFILE_BATTERY_SAVER;
case PLATFORM_PROFILE_BALANCED:
return SSAM_TMP_PROFILE_NORMAL;
case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
return SSAM_TMP_PROFILE_BETTER_PERFORMANCE;
case PLATFORM_PROFILE_PERFORMANCE:
return SSAM_TMP_PROFILE_BEST_PERFORMANCE;
default:
/* This should have already been caught by platform_profile_store(). */
WARN(true, "unsupported platform profile");
return -EOPNOTSUPP;
}
}
static int ssam_platform_profile_get(struct platform_profile_handler *pprof,
enum platform_profile_option *profile)
{
struct ssam_tmp_profile_device *tpd;
enum ssam_tmp_profile tp;
int status;
tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
status = ssam_tmp_profile_get(tpd->sdev, &tp);
if (status)
return status;
status = convert_ssam_to_profile(tpd->sdev, tp);
if (status < 0)
return status;
*profile = status;
return 0;
}
static int ssam_platform_profile_set(struct platform_profile_handler *pprof,
enum platform_profile_option profile)
{
struct ssam_tmp_profile_device *tpd;
int tp;
tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
tp = convert_profile_to_ssam(tpd->sdev, profile);
if (tp < 0)
return tp;
return ssam_tmp_profile_set(tpd->sdev, tp);
}
static int surface_platform_profile_probe(struct ssam_device *sdev)
{
struct ssam_tmp_profile_device *tpd;
tpd = devm_kzalloc(&sdev->dev, sizeof(*tpd), GFP_KERNEL);
if (!tpd)
return -ENOMEM;
tpd->sdev = sdev;
tpd->handler.profile_get = ssam_platform_profile_get;
tpd->handler.profile_set = ssam_platform_profile_set;
set_bit(PLATFORM_PROFILE_LOW_POWER, tpd->handler.choices);
set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices);
set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices);
set_bit(PLATFORM_PROFILE_PERFORMANCE, tpd->handler.choices);
platform_profile_register(&tpd->handler);
return 0;
}
static void surface_platform_profile_remove(struct ssam_device *sdev)
{
platform_profile_remove();
}
static const struct ssam_device_id ssam_platform_profile_match[] = {
{ SSAM_SDEV(TMP, 0x01, 0x00, 0x01) },
{ },
};
MODULE_DEVICE_TABLE(ssam, ssam_platform_profile_match);
static struct ssam_device_driver surface_platform_profile = {
.probe = surface_platform_profile_probe,
.remove = surface_platform_profile_remove,
.match_table = ssam_platform_profile_match,
.driver = {
.name = "surface_platform_profile",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
module_ssam_device_driver(surface_platform_profile);
MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("Platform Profile Support for Surface System Aggregator Module");
MODULE_LICENSE("GPL");
......@@ -40,8 +40,6 @@ static const guid_t MSHW0040_DSM_UUID =
#define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN 0xc2
#define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN 0xc3
ACPI_MODULE_NAME("surface pro 3 button");
MODULE_AUTHOR("Chen Yu");
MODULE_DESCRIPTION("Surface Pro3 Button Driver");
MODULE_LICENSE("GPL v2");
......
......@@ -123,6 +123,17 @@ config XIAOMI_WMI
To compile this driver as a module, choose M here: the module will
be called xiaomi-wmi.
config GIGABYTE_WMI
tristate "Gigabyte WMI temperature driver"
depends on ACPI_WMI
depends on HWMON
help
Say Y here if you want to support WMI-based temperature reporting on
Gigabyte mainboards.
To compile this driver as a module, choose M here: the module will
be called gigabyte-wmi.
config ACERHDF
tristate "Acer Aspire One temperature and fan driver"
depends on ACPI && THERMAL
......@@ -193,6 +204,17 @@ config AMD_PMC
If you choose to compile this driver as a module the module will be
called amd-pmc.
config ADV_SWBUTTON
tristate "Advantech ACPI Software Button Driver"
depends on ACPI && INPUT
help
Say Y here to enable support for Advantech software defined
button feature. More information can be found at
<http://www.advantech.com.tw/products/>
To compile this driver as a module, choose M here. The module will
be called adv_swbutton.
config APPLE_GMUX
tristate "Apple Gmux Driver"
depends on ACPI && PCI
......@@ -410,6 +432,7 @@ config HP_WMI
depends on INPUT
depends on RFKILL || RFKILL = n
select INPUT_SPARSEKMAP
select ACPI_PLATFORM_PROFILE
help
Say Y here if you want to support WMI-based hotkeys on HP laptops and
to read data from WMI such as docking or ambient light sensor state.
......@@ -1171,6 +1194,7 @@ config INTEL_MRFLD_PWRBTN
config INTEL_PMC_CORE
tristate "Intel PMC Core driver"
depends on PCI
depends on ACPI
help
The Intel Platform Controller Hub for Intel Core SoCs provides access
to Power Management Controller registers via various interfaces. This
......@@ -1192,7 +1216,7 @@ config INTEL_PMT_CLASS
tristate
help
The Intel Platform Monitoring Technology (PMT) class driver provides
the basic sysfs interface and file hierarchy uses by PMT devices.
the basic sysfs interface and file hierarchy used by PMT devices.
For more information, see:
<file:Documentation/ABI/testing/sysfs-class-intel_pmt>
......
......@@ -15,6 +15,7 @@ obj-$(CONFIG_INTEL_WMI_THUNDERBOLT) += intel-wmi-thunderbolt.o
obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o
obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o
obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o
# Acer
obj-$(CONFIG_ACERHDF) += acerhdf.o
......@@ -24,6 +25,9 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o
# AMD
obj-$(CONFIG_AMD_PMC) += amd-pmc.o
# Advantech
obj-$(CONFIG_ADV_SWBUTTON) += adv_swbutton.o
# Apple
obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* adv_swbutton.c - Software Button Interface Driver.
*
* (C) Copyright 2020 Advantech Corporation, Inc
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#define ACPI_BUTTON_HID_SWBTN "AHC0310"
#define ACPI_BUTTON_NOTIFY_SWBTN_RELEASE 0x86
#define ACPI_BUTTON_NOTIFY_SWBTN_PRESSED 0x85
struct adv_swbutton {
struct input_dev *input;
char phys[32];
};
/*-------------------------------------------------------------------------
* Driver Interface
*--------------------------------------------------------------------------
*/
static void adv_swbutton_notify(acpi_handle handle, u32 event, void *context)
{
struct platform_device *device = context;
struct adv_swbutton *button = dev_get_drvdata(&device->dev);
switch (event) {
case ACPI_BUTTON_NOTIFY_SWBTN_RELEASE:
input_report_key(button->input, KEY_PROG1, 0);
input_sync(button->input);
break;
case ACPI_BUTTON_NOTIFY_SWBTN_PRESSED:
input_report_key(button->input, KEY_PROG1, 1);
input_sync(button->input);
break;
default:
dev_dbg(&device->dev, "Unsupported event [0x%x]\n", event);
}
}
static int adv_swbutton_probe(struct platform_device *device)
{
struct adv_swbutton *button;
struct input_dev *input;
acpi_handle handle = ACPI_HANDLE(&device->dev);
acpi_status status;
int error;
button = devm_kzalloc(&device->dev, sizeof(*button), GFP_KERNEL);
if (!button)
return -ENOMEM;
dev_set_drvdata(&device->dev, button);
input = devm_input_allocate_device(&device->dev);
if (!input)
return -ENOMEM;
button->input = input;
snprintf(button->phys, sizeof(button->phys), "%s/button/input0", ACPI_BUTTON_HID_SWBTN);
input->name = "Advantech Software Button";
input->phys = button->phys;
input->id.bustype = BUS_HOST;
input->dev.parent = &device->dev;
set_bit(EV_REP, input->evbit);
input_set_capability(input, EV_KEY, KEY_PROG1);
error = input_register_device(input);
if (error)
return error;
device_init_wakeup(&device->dev, true);
status = acpi_install_notify_handler(handle,
ACPI_DEVICE_NOTIFY,
adv_swbutton_notify,
device);
if (ACPI_FAILURE(status)) {
dev_err(&device->dev, "Error installing notify handler\n");
return -EIO;
}
return 0;
}
static int adv_swbutton_remove(struct platform_device *device)
{
acpi_handle handle = ACPI_HANDLE(&device->dev);
acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY,
adv_swbutton_notify);
return 0;
}
static const struct acpi_device_id button_device_ids[] = {
{ACPI_BUTTON_HID_SWBTN, 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, button_device_ids);
static struct platform_driver adv_swbutton_driver = {
.driver = {
.name = "adv_swbutton",
.acpi_match_table = button_device_ids,
},
.probe = adv_swbutton_probe,
.remove = adv_swbutton_remove,
};
module_platform_driver(adv_swbutton_driver);
MODULE_AUTHOR("Andrea Ho");
MODULE_DESCRIPTION("Advantech ACPI SW Button Driver");
MODULE_LICENSE("GPL v2");
......@@ -1569,7 +1569,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
struct attribute *attr,
int idx)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct asus_laptop *asus = dev_get_drvdata(dev);
acpi_handle handle = asus->handle;
bool supported;
......
......@@ -47,6 +47,9 @@ MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>, "
MODULE_DESCRIPTION("Asus Generic WMI Driver");
MODULE_LICENSE("GPL");
static bool fnlock_default = true;
module_param(fnlock_default, bool, 0444);
#define to_asus_wmi_driver(pdrv) \
(container_of((pdrv), struct asus_wmi_driver, platform_driver))
......@@ -2673,7 +2676,7 @@ static int asus_wmi_add(struct platform_device *pdev)
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
if (asus_wmi_has_fnlock_key(asus)) {
asus->fnlock_locked = true;
asus->fnlock_locked = fnlock_default;
asus_wmi_fnlock_update(asus);
}
......
......@@ -956,7 +956,7 @@ static int cmpc_ipml_add(struct acpi_device *acpi)
/*
* If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
* This is OK, however, since all other uses of the device will not
* derefence it.
* dereference it.
*/
if (ipml->rf) {
retval = rfkill_register(ipml->rf);
......
......@@ -2,7 +2,7 @@
/*
* Alienware AlienFX control
*
* Copyright (C) 2014 Dell Inc <mario_limonciello@dell.com>
* Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
......@@ -26,7 +26,7 @@
#define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B
#define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C
MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>");
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
MODULE_DESCRIPTION("Alienware special feature control");
MODULE_LICENSE("GPL");
MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID);
......
......@@ -647,6 +647,6 @@ module_exit(dell_smbios_exit);
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS");
MODULE_LICENSE("GPL");
......@@ -205,7 +205,7 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev, const void *context)
return ret;
}
static int dell_smbios_wmi_remove(struct wmi_device *wdev)
static void dell_smbios_wmi_remove(struct wmi_device *wdev)
{
struct wmi_smbios_priv *priv = dev_get_drvdata(&wdev->dev);
int count;
......@@ -218,7 +218,6 @@ static int dell_smbios_wmi_remove(struct wmi_device *wdev)
count = get_order(priv->req_buf_size);
free_pages((unsigned long)priv->buf, count);
mutex_unlock(&call_mutex);
return 0;
}
static const struct wmi_device_id dell_smbios_wmi_id_table[] = {
......
......@@ -174,14 +174,13 @@ static int dell_wmi_descriptor_probe(struct wmi_device *wdev,
return ret;
}
static int dell_wmi_descriptor_remove(struct wmi_device *wdev)
static void dell_wmi_descriptor_remove(struct wmi_device *wdev)
{
struct descriptor_priv *priv = dev_get_drvdata(&wdev->dev);
mutex_lock(&list_mutex);
list_del(&priv->list);
mutex_unlock(&list_mutex);
return 0;
}
static const struct wmi_device_id dell_wmi_descriptor_id_table[] = {
......@@ -201,6 +200,6 @@ static struct wmi_driver dell_wmi_descriptor_driver = {
module_wmi_driver(dell_wmi_descriptor_driver);
MODULE_DEVICE_TABLE(wmi, dell_wmi_descriptor_id_table);
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
MODULE_DESCRIPTION("Dell WMI descriptor driver");
MODULE_LICENSE("GPL");
......@@ -152,12 +152,11 @@ static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *co
return 0;
}
static int bios_attr_set_interface_remove(struct wmi_device *wdev)
static void bios_attr_set_interface_remove(struct wmi_device *wdev)
{
mutex_lock(&wmi_priv.mutex);
wmi_priv.bios_attr_wdev = NULL;
mutex_unlock(&wmi_priv.mutex);
return 0;
}
static const struct wmi_device_id bios_attr_set_interface_id_table[] = {
......
......@@ -119,12 +119,11 @@ static int bios_attr_pass_interface_probe(struct wmi_device *wdev, const void *c
return 0;
}
static int bios_attr_pass_interface_remove(struct wmi_device *wdev)
static void bios_attr_pass_interface_remove(struct wmi_device *wdev)
{
mutex_lock(&wmi_priv.mutex);
wmi_priv.password_attr_wdev = NULL;
mutex_unlock(&wmi_priv.mutex);
return 0;
}
static const struct wmi_device_id bios_attr_pass_interface_id_table[] = {
......
......@@ -399,6 +399,7 @@ static int init_bios_attributes(int attr_type, const char *guid)
union acpi_object *obj = NULL;
union acpi_object *elements;
struct kset *tmp_set;
int min_elements;
/* instance_id needs to be reset for each type GUID
* also, instance IDs are unique within GUID but not across
......@@ -409,14 +410,38 @@ static int init_bios_attributes(int attr_type, const char *guid)
retval = alloc_attributes_data(attr_type);
if (retval)
return retval;
switch (attr_type) {
case ENUM: min_elements = 8; break;
case INT: min_elements = 9; break;
case STR: min_elements = 8; break;
case PO: min_elements = 4; break;
default:
pr_err("Error: Unknown attr_type: %d\n", attr_type);
return -EINVAL;
}
/* need to use specific instance_id and guid combination to get right data */
obj = get_wmiobj_pointer(instance_id, guid);
if (!obj || obj->type != ACPI_TYPE_PACKAGE)
if (!obj)
return -ENODEV;
elements = obj->package.elements;
mutex_lock(&wmi_priv.mutex);
while (elements) {
while (obj) {
if (obj->type != ACPI_TYPE_PACKAGE) {
pr_err("Error: Expected ACPI-package type, got: %d\n", obj->type);
retval = -EIO;
goto err_attr_init;
}
if (obj->package.count < min_elements) {
pr_err("Error: ACPI-package does not have enough elements: %d < %d\n",
obj->package.count, min_elements);
goto nextobj;
}
elements = obj->package.elements;
/* sanity checking */
if (elements[ATTR_NAME].type != ACPI_TYPE_STRING) {
pr_debug("incorrect element type\n");
......@@ -481,7 +506,6 @@ static int init_bios_attributes(int attr_type, const char *guid)
kfree(obj);
instance_id++;
obj = get_wmiobj_pointer(instance_id, guid);
elements = obj ? obj->package.elements : NULL;
}
mutex_unlock(&wmi_priv.mutex);
......@@ -604,7 +628,7 @@ static void __exit sysman_exit(void)
module_init(sysman_init);
module_exit(sysman_exit);
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
MODULE_AUTHOR("Prasanth Ksr <prasanth.ksr@dell.com>");
MODULE_AUTHOR("Divya Bharathi <divya.bharathi@dell.com>");
MODULE_DESCRIPTION("Dell platform setting control interface");
......
......@@ -714,10 +714,9 @@ static int dell_wmi_probe(struct wmi_device *wdev, const void *context)
return dell_wmi_input_setup(wdev);
}
static int dell_wmi_remove(struct wmi_device *wdev)
static void dell_wmi_remove(struct wmi_device *wdev)
{
dell_wmi_input_destroy(wdev);
return 0;
}
static const struct wmi_device_id dell_wmi_id_table[] = {
{ .guid_string = DELL_EVENT_GUID },
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2021 Thomas Weißschuh <thomas@weissschuh.net>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/hwmon.h>
#include <linux/module.h>
#include <linux/wmi.h>
#define GIGABYTE_WMI_GUID "DEADBEEF-2001-0000-00A0-C90629100000"
#define NUM_TEMPERATURE_SENSORS 6
static bool force_load;
module_param(force_load, bool, 0444);
MODULE_PARM_DESC(force_load, "Force loading on unknown platform");
static u8 usable_sensors_mask;
enum gigabyte_wmi_commandtype {
GIGABYTE_WMI_BUILD_DATE_QUERY = 0x1,
GIGABYTE_WMI_MAINBOARD_TYPE_QUERY = 0x2,
GIGABYTE_WMI_FIRMWARE_VERSION_QUERY = 0x4,
GIGABYTE_WMI_MAINBOARD_NAME_QUERY = 0x5,
GIGABYTE_WMI_TEMPERATURE_QUERY = 0x125,
};
struct gigabyte_wmi_args {
u32 arg1;
};
static int gigabyte_wmi_perform_query(struct wmi_device *wdev,
enum gigabyte_wmi_commandtype command,
struct gigabyte_wmi_args *args, struct acpi_buffer *out)
{
const struct acpi_buffer in = {
.length = sizeof(*args),
.pointer = args,
};
acpi_status ret = wmidev_evaluate_method(wdev, 0x0, command, &in, out);
if (ACPI_FAILURE(ret))
return -EIO;
return 0;
}
static int gigabyte_wmi_query_integer(struct wmi_device *wdev,
enum gigabyte_wmi_commandtype command,
struct gigabyte_wmi_args *args, u64 *res)
{
union acpi_object *obj;
struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
int ret;
ret = gigabyte_wmi_perform_query(wdev, command, args, &result);
if (ret)
return ret;
obj = result.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER)
*res = obj->integer.value;
else
ret = -EIO;
kfree(result.pointer);
return ret;
}
static int gigabyte_wmi_temperature(struct wmi_device *wdev, u8 sensor, long *res)
{
struct gigabyte_wmi_args args = {
.arg1 = sensor,
};
u64 temp;
acpi_status ret;
ret = gigabyte_wmi_query_integer(wdev, GIGABYTE_WMI_TEMPERATURE_QUERY, &args, &temp);
if (ret == 0) {
if (temp == 0)
return -ENODEV;
*res = (s8)temp * 1000; // value is a signed 8-bit integer
}
return ret;
}
static int gigabyte_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct wmi_device *wdev = dev_get_drvdata(dev);
return gigabyte_wmi_temperature(wdev, channel, val);
}
static umode_t gigabyte_wmi_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
return usable_sensors_mask & BIT(channel) ? 0444 : 0;
}
static const struct hwmon_channel_info *gigabyte_wmi_hwmon_info[] = {
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT,
HWMON_T_INPUT,
HWMON_T_INPUT,
HWMON_T_INPUT,
HWMON_T_INPUT,
HWMON_T_INPUT),
NULL
};
static const struct hwmon_ops gigabyte_wmi_hwmon_ops = {
.read = gigabyte_wmi_hwmon_read,
.is_visible = gigabyte_wmi_hwmon_is_visible,
};
static const struct hwmon_chip_info gigabyte_wmi_hwmon_chip_info = {
.ops = &gigabyte_wmi_hwmon_ops,
.info = gigabyte_wmi_hwmon_info,
};
static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev)
{
int i;
long temp;
u8 r = 0;
for (i = 0; i < NUM_TEMPERATURE_SENSORS; i++) {
if (!gigabyte_wmi_temperature(wdev, i, &temp))
r |= BIT(i);
}
return r;
}
static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = {
{ .matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "B550 GAMING X V2"),
}},
{ .matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "B550M AORUS PRO-P"),
}},
{ .matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "B550M DS3H"),
}},
{ .matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Z390 I AORUS PRO WIFI-CF"),
}},
{ .matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X570 AORUS ELITE"),
}},
{ .matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "X570 I AORUS PRO WIFI"),
}},
{ }
};
static int gigabyte_wmi_probe(struct wmi_device *wdev, const void *context)
{
struct device *hwmon_dev;
if (!dmi_check_system(gigabyte_wmi_known_working_platforms)) {
if (!force_load)
return -ENODEV;
dev_warn(&wdev->dev, "Forcing load on unknown platform");
}
usable_sensors_mask = gigabyte_wmi_detect_sensor_usability(wdev);
if (!usable_sensors_mask) {
dev_info(&wdev->dev, "No temperature sensors usable");
return -ENODEV;
}
hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev, "gigabyte_wmi", wdev,
&gigabyte_wmi_hwmon_chip_info, NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct wmi_device_id gigabyte_wmi_id_table[] = {
{ GIGABYTE_WMI_GUID, NULL },
{ }
};
static struct wmi_driver gigabyte_wmi_driver = {
.driver = {
.name = "gigabyte-wmi",
},
.id_table = gigabyte_wmi_id_table,
.probe = gigabyte_wmi_probe,
};
module_wmi_driver(gigabyte_wmi_driver);
MODULE_DEVICE_TABLE(wmi, gigabyte_wmi_id_table);
MODULE_AUTHOR("Thomas Weißschuh <thomas@weissschuh.net>");
MODULE_DESCRIPTION("Gigabyte WMI temperature driver");
MODULE_LICENSE("GPL");
......@@ -21,6 +21,7 @@
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/platform_device.h>
#include <linux/platform_profile.h>
#include <linux/acpi.h>
#include <linux/rfkill.h>
#include <linux/string.h>
......@@ -85,7 +86,7 @@ enum hp_wmi_commandtype {
HPWMI_FEATURE2_QUERY = 0x0d,
HPWMI_WIRELESS2_QUERY = 0x1b,
HPWMI_POSTCODEERROR_QUERY = 0x2a,
HPWMI_THERMAL_POLICY_QUERY = 0x4c,
HPWMI_THERMAL_PROFILE_QUERY = 0x4c,
};
enum hp_wmi_command {
......@@ -119,6 +120,12 @@ enum hp_wireless2_bits {
HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD,
};
enum hp_thermal_profile {
HP_THERMAL_PROFILE_PERFORMANCE = 0x00,
HP_THERMAL_PROFILE_DEFAULT = 0x01,
HP_THERMAL_PROFILE_COOL = 0x02
};
#define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW)
#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
......@@ -159,6 +166,8 @@ static const struct key_entry hp_wmi_keymap[] = {
static struct input_dev *hp_wmi_input_dev;
static struct platform_device *hp_wmi_platform_dev;
static struct platform_profile_handler platform_profile_handler;
static bool platform_profile_support;
static struct rfkill *wifi_rfkill;
static struct rfkill *bluetooth_rfkill;
......@@ -869,23 +878,98 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
return err;
}
static int thermal_policy_setup(struct platform_device *device)
static int thermal_profile_get(void)
{
return hp_wmi_read_int(HPWMI_THERMAL_PROFILE_QUERY);
}
static int thermal_profile_set(int thermal_profile)
{
return hp_wmi_perform_query(HPWMI_THERMAL_PROFILE_QUERY, HPWMI_WRITE, &thermal_profile,
sizeof(thermal_profile), 0);
}
static int platform_profile_get(struct platform_profile_handler *pprof,
enum platform_profile_option *profile)
{
int tp;
tp = thermal_profile_get();
if (tp < 0)
return tp;
switch (tp) {
case HP_THERMAL_PROFILE_PERFORMANCE:
*profile = PLATFORM_PROFILE_PERFORMANCE;
break;
case HP_THERMAL_PROFILE_DEFAULT:
*profile = PLATFORM_PROFILE_BALANCED;
break;
case HP_THERMAL_PROFILE_COOL:
*profile = PLATFORM_PROFILE_COOL;
break;
default:
return -EINVAL;
}
return 0;
}
static int platform_profile_set(struct platform_profile_handler *pprof,
enum platform_profile_option profile)
{
int err, tp;
tp = hp_wmi_read_int(HPWMI_THERMAL_POLICY_QUERY);
switch (profile) {
case PLATFORM_PROFILE_PERFORMANCE:
tp = HP_THERMAL_PROFILE_PERFORMANCE;
break;
case PLATFORM_PROFILE_BALANCED:
tp = HP_THERMAL_PROFILE_DEFAULT;
break;
case PLATFORM_PROFILE_COOL:
tp = HP_THERMAL_PROFILE_COOL;
break;
default:
return -EOPNOTSUPP;
}
err = thermal_profile_set(tp);
if (err)
return err;
return 0;
}
static int thermal_profile_setup(void)
{
int err, tp;
tp = thermal_profile_get();
if (tp < 0)
return tp;
/*
* call thermal policy write command to ensure that the firmware correctly
* call thermal profile write command to ensure that the firmware correctly
* sets the OEM variables for the DPTF
*/
err = hp_wmi_perform_query(HPWMI_THERMAL_POLICY_QUERY, HPWMI_WRITE, &tp,
sizeof(tp), 0);
err = thermal_profile_set(tp);
if (err)
return err;
platform_profile_handler.profile_get = platform_profile_get,
platform_profile_handler.profile_set = platform_profile_set,
set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices);
set_bit(PLATFORM_PROFILE_BALANCED, platform_profile_handler.choices);
set_bit(PLATFORM_PROFILE_PERFORMANCE, platform_profile_handler.choices);
err = platform_profile_register(&platform_profile_handler);
if (err)
return err;
platform_profile_support = true;
return 0;
}
......@@ -900,7 +984,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
if (hp_wmi_rfkill_setup(device))
hp_wmi_rfkill2_setup(device);
thermal_policy_setup(device);
thermal_profile_setup();
return 0;
}
......@@ -927,6 +1011,9 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
rfkill_destroy(wwan_rfkill);
}
if (platform_profile_support)
platform_profile_remove();
return 0;
}
......
......@@ -63,9 +63,6 @@ static const struct key_entry intel_vbtn_switchmap[] = {
{ KE_END }
};
#define KEYMAP_LEN \
(ARRAY_SIZE(intel_vbtn_keymap) + ARRAY_SIZE(intel_vbtn_switchmap) + 1)
struct intel_vbtn_priv {
struct input_dev *buttons_dev;
struct input_dev *switches_dev;
......
......@@ -117,10 +117,9 @@ static int intel_wmi_sbl_fw_update_probe(struct wmi_device *wdev,
return 0;
}
static int intel_wmi_sbl_fw_update_remove(struct wmi_device *wdev)
static void intel_wmi_sbl_fw_update_remove(struct wmi_device *wdev)
{
dev_info(&wdev->dev, "Slim Bootloader signaling driver removed\n");
return 0;
}
static const struct wmi_device_id intel_wmi_sbl_id_table[] = {
......
......@@ -66,11 +66,10 @@ static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev,
return ret;
}
static int intel_wmi_thunderbolt_remove(struct wmi_device *wdev)
static void intel_wmi_thunderbolt_remove(struct wmi_device *wdev)
{
sysfs_remove_group(&wdev->dev.kobj, &tbt_attribute_group);
kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
return 0;
}
static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = {
......
......@@ -58,7 +58,7 @@ static int chtdc_ti_pwrbtn_probe(struct platform_device *pdev)
err = devm_request_threaded_irq(dev, irq, NULL,
chtdc_ti_pwrbtn_interrupt,
0, KBUILD_MODNAME, input);
IRQF_ONESHOT, KBUILD_MODNAME, input);
if (err)
return err;
......
This diff is collapsed.
......@@ -187,20 +187,38 @@ enum ppfear_regs {
#define ICL_PMC_LTR_WIGIG 0x1BFC
#define ICL_PMC_SLP_S0_RES_COUNTER_STEP 0x64
#define TGL_NUM_IP_IGN_ALLOWED 22
#define LPM_MAX_NUM_MODES 8
#define GET_X2_COUNTER(v) ((v) >> 1)
#define LPM_STS_LATCH_MODE BIT(31)
#define TGL_PMC_SLP_S0_RES_COUNTER_STEP 0x7A
#define TGL_PMC_LTR_THC0 0x1C04
#define TGL_PMC_LTR_THC1 0x1C08
#define TGL_NUM_IP_IGN_ALLOWED 23
#define TGL_PMC_LPM_RES_COUNTER_STEP_X2 61 /* 30.5us * 2 */
/*
* Tigerlake Power Management Controller register offsets
*/
#define TGL_LPM_STS_LATCH_EN_OFFSET 0x1C34
#define TGL_LPM_EN_OFFSET 0x1C78
#define TGL_LPM_RESIDENCY_OFFSET 0x1C80
/* Tigerlake Low Power Mode debug registers */
#define TGL_LPM_STATUS_OFFSET 0x1C3C
#define TGL_LPM_LIVE_STATUS_OFFSET 0x1C5C
#define TGL_LPM_PRI_OFFSET 0x1C7C
#define TGL_LPM_NUM_MAPS 6
/* Extended Test Mode Register 3 (CNL and later) */
#define ETR3_OFFSET 0x1048
#define ETR3_CF9GR BIT(20)
#define ETR3_CF9LOCK BIT(31)
/* Extended Test Mode Register LPM bits (TGL and later */
#define ETR3_CLEAR_LPM_EVENTS BIT(28)
const char *tgl_lpm_modes[] = {
const char *pmc_lpm_modes[] = {
"S0i2.0",
"S0i2.1",
"S0i2.2",
......@@ -258,11 +276,15 @@ struct pmc_reg_map {
const u32 ltr_ignore_max;
const u32 pm_vric1_offset;
/* Low Power Mode registers */
const char **lpm_modes;
const int lpm_num_maps;
const int lpm_res_counter_step_x2;
const u32 lpm_sts_latch_en_offset;
const u32 lpm_en_offset;
const u32 lpm_priority_offset;
const u32 lpm_residency_offset;
const u32 lpm_status_offset;
const u32 lpm_live_status_offset;
const u32 etr3_offset;
};
/**
......@@ -278,6 +300,9 @@ struct pmc_reg_map {
* @check_counters: On resume, check if counters are getting incremented
* @pc10_counter: PC10 residency counter
* @s0ix_counter: S0ix residency (step adjusted)
* @num_lpm_modes: Count of enabled modes
* @lpm_en_modes: Array of enabled modes from lowest to highest priority
* @lpm_req_regs: List of substate requirements
*
* pmc_dev contains info about power management controller device.
*/
......@@ -292,6 +317,28 @@ struct pmc_dev {
bool check_counters; /* Check for counter increments on resume */
u64 pc10_counter;
u64 s0ix_counter;
int num_lpm_modes;
int lpm_en_modes[LPM_MAX_NUM_MODES];
u32 *lpm_req_regs;
};
#define pmc_for_each_mode(i, mode, pmcdev) \
for (i = 0, mode = pmcdev->lpm_en_modes[i]; \
i < pmcdev->num_lpm_modes; \
i++, mode = pmcdev->lpm_en_modes[i])
#define DEFINE_PMC_CORE_ATTR_WRITE(__name) \
static int __name ## _open(struct inode *inode, struct file *file) \
{ \
return single_open(file, __name ## _show, inode->i_private); \
} \
\
static const struct file_operations __name ## _fops = { \
.owner = THIS_MODULE, \
.open = __name ## _open, \
.read = seq_read, \
.write = __name ## _write, \
.release = single_release, \
}
#endif /* PMC_CORE_H */
......@@ -19,6 +19,28 @@
#define PMT_XA_MAX INT_MAX
#define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX)
/*
* Early implementations of PMT on client platforms have some
* differences from the server platforms (which use the Out Of Band
* Management Services Module OOBMSM). This list tracks those
* platforms as needed to handle those differences. Newer client
* platforms are expected to be fully compatible with server.
*/
static const struct pci_device_id pmt_telem_early_client_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x467d) }, /* ADL */
{ PCI_VDEVICE(INTEL, 0x490e) }, /* DG1 */
{ PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */
{ }
};
bool intel_pmt_is_early_client_hw(struct device *dev)
{
struct pci_dev *parent = to_pci_dev(dev->parent);
return !!pci_match_id(pmt_telem_early_client_pci_ids, parent);
}
EXPORT_SYMBOL_GPL(intel_pmt_is_early_client_hw);
/*
* sysfs
*/
......@@ -147,6 +169,30 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,
* base address = end of discovery region + base offset
*/
entry->base_addr = disc_res->end + 1 + header->base_offset;
/*
* Some hardware use a different calculation for the base address
* when access_type == ACCESS_LOCAL. On the these systems
* ACCCESS_LOCAL refers to an address in the same BAR as the
* header but at a fixed offset. But as the header address was
* supplied to the driver, we don't know which BAR it was in.
* So search for the bar whose range includes the header address.
*/
if (intel_pmt_is_early_client_hw(dev)) {
int i;
entry->base_addr = 0;
for (i = 0; i < 6; i++)
if (disc_res->start >= pci_resource_start(pci_dev, i) &&
(disc_res->start <= pci_resource_end(pci_dev, i))) {
entry->base_addr = pci_resource_start(pci_dev, i) +
header->base_offset;
break;
}
if (!entry->base_addr)
return -EINVAL;
}
break;
case ACCESS_BARID:
/*
......
......@@ -44,6 +44,7 @@ struct intel_pmt_namespace {
struct device *dev);
};
bool intel_pmt_is_early_client_hw(struct device *dev);
int intel_pmt_dev_create(struct intel_pmt_entry *entry,
struct intel_pmt_namespace *ns,
struct platform_device *pdev, int idx);
......
......@@ -34,26 +34,6 @@ struct pmt_telem_priv {
struct intel_pmt_entry entry[];
};
/*
* Early implementations of PMT on client platforms have some
* differences from the server platforms (which use the Out Of Band
* Management Services Module OOBMSM). This list tracks those
* platforms as needed to handle those differences. Newer client
* platforms are expected to be fully compatible with server.
*/
static const struct pci_device_id pmt_telem_early_client_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */
{ PCI_VDEVICE(INTEL, 0x467d) }, /* ADL */
{ }
};
static bool intel_pmt_is_early_client_hw(struct device *dev)
{
struct pci_dev *parent = to_pci_dev(dev->parent);
return !!pci_match_id(pmt_telem_early_client_pci_ids, parent);
}
static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry,
struct device *dev)
{
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment