mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-11 08:50:20 +08:00
Merge tag 'platform-drivers-x86-v5.2-1' of git://git.infradead.org/linux-platform-drivers-x86
Pull x86 platform driver updates from Andy Shevchenko:
"Gathered pile of patches for Platform Drivers x86. No surprises and no
merge conflicts. Business as usual.
Summary:
- New driver of power button for Basin Cove PMIC.
- ASUS WMI driver has got a Fn lock mode switch support.
- Resolve a never end story with non working Wi-Fi on newer Lenovo
Ideapad computers. Now the black list is replaced with white list.
- New facility to debug S0ix failures on Intel Atom platforms. The
Intel PMC and accompanying drivers are cleaned up.
- Mellanox got a new TmFifo driver. Besides tachometer sensor and
watchdog are enabled on Mellanox platforms.
- The information of embedded controller is now recognized on new
Thinkpads. Bluetooth driver on Thinkpads is blacklisted for some
models.
- Touchscreen DMI driver extended to support 'jumper ezpad 6 pro b'
and Myria MY8307 2-in-1.
- Additionally few small fixes here and there for WMI and ACPI laptop
drivers.
- The following is an automated git shortlog grouped by driver:
- alienware-wmi:
- printing the wrong error code
- fix kfree on potentially uninitialized pointer
- asus-wmi:
- Add fn-lock mode switch support
- dell-laptop:
- fix rfkill functionality
- dell-rbtn:
- Add missing #include
- ideapad-laptop:
- Remove no_hw_rfkill_list
- intel_pmc_core:
- Allow to dump debug registers on S0ix failure
- Convert to a platform_driver
- Mark local function static
- intel_pmc_ipc:
- Don't map non-used optional resources
- Apply same width for offset definitions
- Use BIT() macro
- adding error handling
- intel_punit_ipc:
- Revert "Fix resource ioremap warning"
- mlx-platform:
- Add mlx-wdt platform driver activation
- Add support for tachometer speed register
- Add TmFifo driver for Mellanox BlueField Soc
- sony-laptop:
- Fix unintentional fall-through
- thinkpad_acpi:
- cleanup for Thinkpad ACPI led
- Mark expected switch fall-throughs
- fix spelling mistake "capabilites" -> "capabilities"
- Read EC information on newer models
- Disable Bluetooth for some machines
- touchscreen_dmi:
- Add info for 'jumper ezpad 6 pro b' touchscreen
- Add info for Myria MY8307 2-in-1"
* tag 'platform-drivers-x86-v5.2-1' of git://git.infradead.org/linux-platform-drivers-x86: (26 commits)
platform/x86: Add support for Basin Cove power button
platform/x86: asus-wmi: Add fn-lock mode switch support
platform/x86: ideapad-laptop: Remove no_hw_rfkill_list
platform/x86: touchscreen_dmi: Add info for 'jumper ezpad 6 pro b' touchscreen
platform/x86: thinkpad_acpi: cleanup for Thinkpad ACPI led
platform/x86: thinkpad_acpi: Mark expected switch fall-throughs
platform/x86: sony-laptop: Fix unintentional fall-through
platform/x86: alienware-wmi: printing the wrong error code
platform/x86: intel_pmc_core: Allow to dump debug registers on S0ix failure
platform/x86: intel_pmc_core: Convert to a platform_driver
platform/x86: mlx-platform: Add mlx-wdt platform driver activation
platform/x86: mlx-platform: Add support for tachometer speed register
platform/mellanox: Add TmFifo driver for Mellanox BlueField Soc
platform/x86: thinkpad_acpi: fix spelling mistake "capabilites" -> "capabilities"
platform/x86: intel_punit_ipc: Revert "Fix resource ioremap warning"
platform/x86: intel_pmc_ipc: Don't map non-used optional resources
platform/x86: intel_pmc_ipc: Apply same width for offset definitions
platform/x86: intel_pmc_ipc: Use BIT() macro
platform/x86: alienware-wmi: fix kfree on potentially uninitialized pointer
platform/x86: dell-laptop: fix rfkill functionality
...
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
menuconfig MELLANOX_PLATFORM
|
||||
bool "Platform support for Mellanox hardware"
|
||||
depends on X86 || ARM || COMPILE_TEST
|
||||
depends on X86 || ARM || ARM64 || COMPILE_TEST
|
||||
---help---
|
||||
Say Y here to get to see options for platform support for
|
||||
Mellanox systems. This option alone does not add any kernel code.
|
||||
@@ -34,4 +34,14 @@ config MLXREG_IO
|
||||
to system resets operation, system reset causes monitoring and some
|
||||
kinds of mux selection.
|
||||
|
||||
config MLXBF_TMFIFO
|
||||
tristate "Mellanox BlueField SoC TmFifo platform driver"
|
||||
depends on ARM64
|
||||
depends on ACPI
|
||||
depends on VIRTIO_CONSOLE && VIRTIO_NET
|
||||
help
|
||||
Say y here to enable TmFifo support. The TmFifo driver provides
|
||||
platform driver support for the TmFifo which supports console
|
||||
and networking based on the virtio framework.
|
||||
|
||||
endif # MELLANOX_PLATFORM
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
# Makefile for linux/drivers/platform/mellanox
|
||||
# Mellanox Platform-Specific Drivers
|
||||
#
|
||||
obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o
|
||||
obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
|
||||
obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
|
||||
|
||||
63
drivers/platform/mellanox/mlxbf-tmfifo-regs.h
Normal file
63
drivers/platform/mellanox/mlxbf-tmfifo-regs.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019, Mellanox Technologies. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __MLXBF_TMFIFO_REGS_H__
|
||||
#define __MLXBF_TMFIFO_REGS_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/bits.h>
|
||||
|
||||
#define MLXBF_TMFIFO_TX_DATA 0x00
|
||||
#define MLXBF_TMFIFO_TX_STS 0x08
|
||||
#define MLXBF_TMFIFO_TX_STS__LENGTH 0x0001
|
||||
#define MLXBF_TMFIFO_TX_STS__COUNT_SHIFT 0
|
||||
#define MLXBF_TMFIFO_TX_STS__COUNT_WIDTH 9
|
||||
#define MLXBF_TMFIFO_TX_STS__COUNT_RESET_VAL 0
|
||||
#define MLXBF_TMFIFO_TX_STS__COUNT_RMASK GENMASK_ULL(8, 0)
|
||||
#define MLXBF_TMFIFO_TX_STS__COUNT_MASK GENMASK_ULL(8, 0)
|
||||
#define MLXBF_TMFIFO_TX_CTL 0x10
|
||||
#define MLXBF_TMFIFO_TX_CTL__LENGTH 0x0001
|
||||
#define MLXBF_TMFIFO_TX_CTL__LWM_SHIFT 0
|
||||
#define MLXBF_TMFIFO_TX_CTL__LWM_WIDTH 8
|
||||
#define MLXBF_TMFIFO_TX_CTL__LWM_RESET_VAL 128
|
||||
#define MLXBF_TMFIFO_TX_CTL__LWM_RMASK GENMASK_ULL(7, 0)
|
||||
#define MLXBF_TMFIFO_TX_CTL__LWM_MASK GENMASK_ULL(7, 0)
|
||||
#define MLXBF_TMFIFO_TX_CTL__HWM_SHIFT 8
|
||||
#define MLXBF_TMFIFO_TX_CTL__HWM_WIDTH 8
|
||||
#define MLXBF_TMFIFO_TX_CTL__HWM_RESET_VAL 128
|
||||
#define MLXBF_TMFIFO_TX_CTL__HWM_RMASK GENMASK_ULL(7, 0)
|
||||
#define MLXBF_TMFIFO_TX_CTL__HWM_MASK GENMASK_ULL(15, 8)
|
||||
#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_SHIFT 32
|
||||
#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_WIDTH 9
|
||||
#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_RESET_VAL 256
|
||||
#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0)
|
||||
#define MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32)
|
||||
#define MLXBF_TMFIFO_RX_DATA 0x00
|
||||
#define MLXBF_TMFIFO_RX_STS 0x08
|
||||
#define MLXBF_TMFIFO_RX_STS__LENGTH 0x0001
|
||||
#define MLXBF_TMFIFO_RX_STS__COUNT_SHIFT 0
|
||||
#define MLXBF_TMFIFO_RX_STS__COUNT_WIDTH 9
|
||||
#define MLXBF_TMFIFO_RX_STS__COUNT_RESET_VAL 0
|
||||
#define MLXBF_TMFIFO_RX_STS__COUNT_RMASK GENMASK_ULL(8, 0)
|
||||
#define MLXBF_TMFIFO_RX_STS__COUNT_MASK GENMASK_ULL(8, 0)
|
||||
#define MLXBF_TMFIFO_RX_CTL 0x10
|
||||
#define MLXBF_TMFIFO_RX_CTL__LENGTH 0x0001
|
||||
#define MLXBF_TMFIFO_RX_CTL__LWM_SHIFT 0
|
||||
#define MLXBF_TMFIFO_RX_CTL__LWM_WIDTH 8
|
||||
#define MLXBF_TMFIFO_RX_CTL__LWM_RESET_VAL 128
|
||||
#define MLXBF_TMFIFO_RX_CTL__LWM_RMASK GENMASK_ULL(7, 0)
|
||||
#define MLXBF_TMFIFO_RX_CTL__LWM_MASK GENMASK_ULL(7, 0)
|
||||
#define MLXBF_TMFIFO_RX_CTL__HWM_SHIFT 8
|
||||
#define MLXBF_TMFIFO_RX_CTL__HWM_WIDTH 8
|
||||
#define MLXBF_TMFIFO_RX_CTL__HWM_RESET_VAL 128
|
||||
#define MLXBF_TMFIFO_RX_CTL__HWM_RMASK GENMASK_ULL(7, 0)
|
||||
#define MLXBF_TMFIFO_RX_CTL__HWM_MASK GENMASK_ULL(15, 8)
|
||||
#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_SHIFT 32
|
||||
#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_WIDTH 9
|
||||
#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RESET_VAL 256
|
||||
#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0)
|
||||
#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32)
|
||||
|
||||
#endif /* !defined(__MLXBF_TMFIFO_REGS_H__) */
|
||||
1281
drivers/platform/mellanox/mlxbf-tmfifo.c
Normal file
1281
drivers/platform/mellanox/mlxbf-tmfifo.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1263,6 +1263,17 @@ config INTEL_CHTDC_TI_PWRBTN
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called intel_chtdc_ti_pwrbtn.
|
||||
|
||||
config INTEL_MRFLD_PWRBTN
|
||||
tristate "Intel Merrifield Basin Cove power button driver"
|
||||
depends on INTEL_SOC_PMIC_MRFLD
|
||||
depends on INPUT
|
||||
---help---
|
||||
This option adds a power button driver for Basin Cove PMIC
|
||||
on Intel Merrifield devices.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called intel_mrfld_pwrbtn.
|
||||
|
||||
config I2C_MULTI_INSTANTIATE
|
||||
tristate "I2C multi instantiate pseudo device driver"
|
||||
depends on I2C && ACPI
|
||||
|
||||
@@ -94,6 +94,7 @@ obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
|
||||
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
|
||||
obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
|
||||
obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
|
||||
obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o
|
||||
obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o
|
||||
obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
|
||||
obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o
|
||||
|
||||
@@ -522,23 +522,22 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args,
|
||||
|
||||
input.length = (acpi_size) sizeof(*in_args);
|
||||
input.pointer = in_args;
|
||||
if (out_data != NULL) {
|
||||
if (out_data) {
|
||||
output.length = ACPI_ALLOCATE_BUFFER;
|
||||
output.pointer = NULL;
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
|
||||
command, &input, &output);
|
||||
} else
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
obj = (union acpi_object *)output.pointer;
|
||||
if (obj && obj->type == ACPI_TYPE_INTEGER)
|
||||
*out_data = (u32)obj->integer.value;
|
||||
}
|
||||
kfree(output.pointer);
|
||||
} else {
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
|
||||
command, &input, NULL);
|
||||
|
||||
if (ACPI_SUCCESS(status) && out_data != NULL) {
|
||||
obj = (union acpi_object *)output.pointer;
|
||||
if (obj && obj->type == ACPI_TYPE_INTEGER)
|
||||
*out_data = (u32) obj->integer.value;
|
||||
}
|
||||
kfree(output.pointer);
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -588,7 +587,7 @@ static ssize_t show_hdmi_source(struct device *dev,
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"input [gpu] unknown\n");
|
||||
}
|
||||
pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data);
|
||||
pr_err("alienware-wmi: unknown HDMI source status: %u\n", status);
|
||||
return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -66,10 +66,13 @@ MODULE_LICENSE("GPL");
|
||||
#define NOTIFY_BRNUP_MAX 0x1f
|
||||
#define NOTIFY_BRNDOWN_MIN 0x20
|
||||
#define NOTIFY_BRNDOWN_MAX 0x2e
|
||||
#define NOTIFY_FNLOCK_TOGGLE 0x4e
|
||||
#define NOTIFY_KBD_BRTUP 0xc4
|
||||
#define NOTIFY_KBD_BRTDWN 0xc5
|
||||
#define NOTIFY_KBD_BRTTOGGLE 0xc7
|
||||
|
||||
#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
|
||||
|
||||
#define ASUS_FAN_DESC "cpu_fan"
|
||||
#define ASUS_FAN_MFUN 0x13
|
||||
#define ASUS_FAN_SFUN_READ 0x06
|
||||
@@ -177,6 +180,8 @@ struct asus_wmi {
|
||||
struct workqueue_struct *hotplug_workqueue;
|
||||
struct work_struct hotplug_work;
|
||||
|
||||
bool fnlock_locked;
|
||||
|
||||
struct asus_wmi_debug debug;
|
||||
|
||||
struct asus_wmi_driver *driver;
|
||||
@@ -1619,6 +1624,23 @@ static int is_display_toggle(int code)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus)
|
||||
{
|
||||
u32 result;
|
||||
|
||||
asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FNLOCK, &result);
|
||||
|
||||
return (result & ASUS_WMI_DSTS_PRESENCE_BIT) &&
|
||||
!(result & ASUS_WMI_FNLOCK_BIOS_DISABLED);
|
||||
}
|
||||
|
||||
static void asus_wmi_fnlock_update(struct asus_wmi *asus)
|
||||
{
|
||||
int mode = asus->fnlock_locked;
|
||||
|
||||
asus_wmi_set_devstate(ASUS_WMI_DEVID_FNLOCK, mode, NULL);
|
||||
}
|
||||
|
||||
static void asus_wmi_notify(u32 value, void *context)
|
||||
{
|
||||
struct asus_wmi *asus = context;
|
||||
@@ -1680,6 +1702,12 @@ static void asus_wmi_notify(u32 value, void *context)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (code == NOTIFY_FNLOCK_TOGGLE) {
|
||||
asus->fnlock_locked = !asus->fnlock_locked;
|
||||
asus_wmi_fnlock_update(asus);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (is_display_toggle(code) &&
|
||||
asus->driver->quirks->no_display_toggle)
|
||||
goto exit;
|
||||
@@ -2134,6 +2162,11 @@ static int asus_wmi_add(struct platform_device *pdev)
|
||||
} else
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
|
||||
|
||||
if (asus_wmi_has_fnlock_key(asus)) {
|
||||
asus->fnlock_locked = true;
|
||||
asus_wmi_fnlock_update(asus);
|
||||
}
|
||||
|
||||
status = wmi_install_notify_handler(asus->driver->event_guid,
|
||||
asus_wmi_notify, asus);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@@ -2213,6 +2246,8 @@ static int asus_hotk_resume(struct device *device)
|
||||
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
|
||||
kbd_led_update(asus);
|
||||
|
||||
if (asus_wmi_has_fnlock_key(asus))
|
||||
asus_wmi_fnlock_update(asus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2249,6 +2284,8 @@ static int asus_hotk_restore(struct device *device)
|
||||
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
|
||||
kbd_led_update(asus);
|
||||
|
||||
if (asus_wmi_has_fnlock_key(asus))
|
||||
asus_wmi_fnlock_update(asus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -531,7 +531,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data)
|
||||
return;
|
||||
}
|
||||
|
||||
dell_fill_request(&buffer, 0, 0x2, 0, 0);
|
||||
dell_fill_request(&buffer, 0x2, 0, 0, 0);
|
||||
ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
|
||||
hwswitch = buffer.output[1];
|
||||
|
||||
@@ -562,7 +562,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data)
|
||||
return ret;
|
||||
status = buffer.output[1];
|
||||
|
||||
dell_fill_request(&buffer, 0, 0x2, 0, 0);
|
||||
dell_fill_request(&buffer, 0x2, 0, 0, 0);
|
||||
hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
|
||||
if (hwswitch_ret)
|
||||
return hwswitch_ret;
|
||||
@@ -647,7 +647,7 @@ static void dell_update_rfkill(struct work_struct *ignored)
|
||||
if (ret != 0)
|
||||
return;
|
||||
|
||||
dell_fill_request(&buffer, 0, 0x2, 0, 0);
|
||||
dell_fill_request(&buffer, 0x2, 0, 0, 0);
|
||||
ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
|
||||
|
||||
if (ret == 0 && (status & BIT(0)))
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "dell-rbtn.h"
|
||||
|
||||
enum rbtn_type {
|
||||
RBTN_UNKNOWN,
|
||||
RBTN_TOGGLE,
|
||||
|
||||
@@ -980,312 +980,21 @@ static void ideapad_wmi_notify(u32 value, void *context)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF
|
||||
* always results in 0 on these models, causing ideapad_laptop to wrongly
|
||||
* report all radios as hardware-blocked.
|
||||
* Some ideapads have a hardware rfkill switch, but most do not have one.
|
||||
* Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill,
|
||||
* switch causing ideapad_laptop to wrongly report all radios as hw-blocked.
|
||||
* There used to be a long list of DMI ids for models without a hw rfkill
|
||||
* switch here, but that resulted in playing whack a mole.
|
||||
* More importantly wrongly reporting the wifi radio as hw-blocked, results in
|
||||
* non working wifi. Whereas not reporting it hw-blocked, when it actually is
|
||||
* hw-blocked results in an empty SSID list, which is a much more benign
|
||||
* failure mode.
|
||||
* So the default now is the much safer option of assuming there is no
|
||||
* hardware rfkill switch. This default also actually matches most hardware,
|
||||
* since having a hw rfkill switch is quite rare on modern hardware, so this
|
||||
* also leads to a much shorter list.
|
||||
*/
|
||||
static const struct dmi_system_id no_hw_rfkill_list[] = {
|
||||
{
|
||||
.ident = "Lenovo RESCUER R720-15IKBN",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo R720-15IKBN"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo G40-30",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G40-30"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo G50-30",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo V310-14IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo V310-14ISK",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14ISK"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo V310-15IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo V310-15ISK",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15ISK"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo V510-15IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V510-15IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad 300-15IBR",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IBR"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad 300-15IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad 300S-11IBR",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300S-11BR"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad 310-15ABR",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ABR"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad 310-15IAP",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IAP"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad 310-15IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad 310-15ISK",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ISK"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad 330-15ICH",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 330-15ICH"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad 530S-14ARR",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 530S-14ARR"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad S130-14IGM",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad S130-14IGM"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad Y700-14ISK",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-14ISK"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad Y700-15ACZ",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ACZ"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad Y700-15ISK",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ISK"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad Y700 Touch-15ISK",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700 Touch-15ISK"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad Y700-17ISK",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo ideapad MIIX 720-12IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "MIIX 720-12IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Legion Y520-15IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Y520-15IKBM",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBM"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Legion Y530-15ICH",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion Y530-15ICH"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Legion Y530-15ICH-1060",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion Y530-15ICH-1060"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Legion Y720-15IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Legion Y720-15IKBN",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBN"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Y720-15IKBM",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBM"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Yoga 2 11 / 13 / Pro",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Yoga 2 11 / 13 / Pro",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Yoga2"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Yoga 2 13",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Yoga 2 13"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Yoga 3 1170 / 1470",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 3"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Yoga 3 Pro 1370",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Yoga 700",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 700"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Yoga 900",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 900"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Yoga 900",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "VIUU4"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo YOGA 910-13IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 910-13IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo YOGA 920-13IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920-13IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo YOGA C930-13IKB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA C930-13IKB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Lenovo Zhaoyang E42-80",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ZHAOYANG E42-80"),
|
||||
},
|
||||
},
|
||||
static const struct dmi_system_id hw_rfkill_list[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -1311,7 +1020,7 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
||||
priv->cfg = cfg;
|
||||
priv->adev = adev;
|
||||
priv->platform_device = pdev;
|
||||
priv->has_hw_rfkill_switch = !dmi_check_system(no_hw_rfkill_list);
|
||||
priv->has_hw_rfkill_switch = dmi_check_system(hw_rfkill_list);
|
||||
|
||||
ret = ideapad_sysfs_init(priv);
|
||||
if (ret)
|
||||
|
||||
107
drivers/platform/x86/intel_mrfld_pwrbtn.c
Normal file
107
drivers/platform/x86/intel_mrfld_pwrbtn.c
Normal file
@@ -0,0 +1,107 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Power-button driver for Basin Cove PMIC
|
||||
*
|
||||
* Copyright (c) 2019, Intel Corporation.
|
||||
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mfd/intel_soc_pmic.h>
|
||||
#include <linux/mfd/intel_soc_pmic_mrfld.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define BCOVE_PBSTATUS 0x27
|
||||
#define BCOVE_PBSTATUS_PBLVL BIT(4) /* 1 - release, 0 - press */
|
||||
|
||||
static irqreturn_t mrfld_pwrbtn_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct input_dev *input = dev_id;
|
||||
struct device *dev = input->dev.parent;
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
unsigned int state;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, BCOVE_PBSTATUS, &state);
|
||||
if (ret)
|
||||
return IRQ_NONE;
|
||||
|
||||
dev_dbg(dev, "PBSTATUS=0x%x\n", state);
|
||||
input_report_key(input, KEY_POWER, !(state & BCOVE_PBSTATUS_PBLVL));
|
||||
input_sync(input);
|
||||
|
||||
regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_PWRBTN, 0);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mrfld_pwrbtn_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
|
||||
struct input_dev *input;
|
||||
int irq, ret;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
input = devm_input_allocate_device(dev);
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
input->name = pdev->name;
|
||||
input->phys = "power-button/input0";
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->dev.parent = dev;
|
||||
input_set_capability(input, EV_KEY, KEY_POWER);
|
||||
ret = input_register_device(input);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_set_drvdata(dev, pmic->regmap);
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_pwrbtn_interrupt,
|
||||
IRQF_ONESHOT | IRQF_SHARED, pdev->name,
|
||||
input);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_update_bits(pmic->regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_PWRBTN, 0);
|
||||
regmap_update_bits(pmic->regmap, BCOVE_MPBIRQ, BCOVE_PBIRQ_PBTN, 0);
|
||||
|
||||
device_init_wakeup(dev, true);
|
||||
dev_pm_set_wake_irq(dev, irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mrfld_pwrbtn_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
dev_pm_clear_wake_irq(dev);
|
||||
device_init_wakeup(dev, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id mrfld_pwrbtn_id_table[] = {
|
||||
{ .name = "mrfld_bcove_pwrbtn" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mrfld_pwrbtn_id_table);
|
||||
|
||||
static struct platform_driver mrfld_pwrbtn_driver = {
|
||||
.driver = {
|
||||
.name = "mrfld_bcove_pwrbtn",
|
||||
},
|
||||
.probe = mrfld_pwrbtn_probe,
|
||||
.remove = mrfld_pwrbtn_remove,
|
||||
.id_table = mrfld_pwrbtn_id_table,
|
||||
};
|
||||
module_platform_driver(mrfld_pwrbtn_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Power-button driver for Basin Cove PMIC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/cpu_device_id.h>
|
||||
@@ -828,7 +830,7 @@ static const struct pci_device_id pmc_pci_ids[] = {
|
||||
* the platform BIOS enforces 24Mhx Crystal to shutdown
|
||||
* before PMC can assert SLP_S0#.
|
||||
*/
|
||||
int quirk_xtal_ignore(const struct dmi_system_id *id)
|
||||
static int quirk_xtal_ignore(const struct dmi_system_id *id)
|
||||
{
|
||||
struct pmc_dev *pmcdev = &pmc;
|
||||
u32 value;
|
||||
@@ -854,13 +856,17 @@ static const struct dmi_system_id pmc_core_dmi_table[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static int __init pmc_core_probe(void)
|
||||
static int pmc_core_probe(struct platform_device *pdev)
|
||||
{
|
||||
static bool device_initialized;
|
||||
struct pmc_dev *pmcdev = &pmc;
|
||||
const struct x86_cpu_id *cpu_id;
|
||||
u64 slp_s0_addr;
|
||||
int err;
|
||||
|
||||
if (device_initialized)
|
||||
return -ENODEV;
|
||||
|
||||
cpu_id = x86_match_cpu(intel_pmc_core_ids);
|
||||
if (!cpu_id)
|
||||
return -ENODEV;
|
||||
@@ -886,30 +892,178 @@ static int __init pmc_core_probe(void)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&pmcdev->lock);
|
||||
platform_set_drvdata(pdev, pmcdev);
|
||||
pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
|
||||
dmi_check_system(pmc_core_dmi_table);
|
||||
|
||||
err = pmc_core_dbgfs_register(pmcdev);
|
||||
if (err < 0) {
|
||||
pr_warn(" debugfs register failed.\n");
|
||||
dev_warn(&pdev->dev, "debugfs register failed.\n");
|
||||
iounmap(pmcdev->regbase);
|
||||
return err;
|
||||
}
|
||||
|
||||
dmi_check_system(pmc_core_dmi_table);
|
||||
pr_info(" initialized\n");
|
||||
device_initialized = true;
|
||||
dev_info(&pdev->dev, " initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(pmc_core_probe)
|
||||
|
||||
static void __exit pmc_core_remove(void)
|
||||
static int pmc_core_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pmc_dev *pmcdev = &pmc;
|
||||
struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
|
||||
|
||||
pmc_core_dbgfs_unregister(pmcdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
mutex_destroy(&pmcdev->lock);
|
||||
iounmap(pmcdev->regbase);
|
||||
return 0;
|
||||
}
|
||||
module_exit(pmc_core_remove)
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static bool warn_on_s0ix_failures;
|
||||
module_param(warn_on_s0ix_failures, bool, 0644);
|
||||
MODULE_PARM_DESC(warn_on_s0ix_failures, "Check and warn for S0ix failures");
|
||||
|
||||
static int pmc_core_suspend(struct device *dev)
|
||||
{
|
||||
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
|
||||
|
||||
pmcdev->check_counters = false;
|
||||
|
||||
/* No warnings on S0ix failures */
|
||||
if (!warn_on_s0ix_failures)
|
||||
return 0;
|
||||
|
||||
/* Check if the syspend will actually use S0ix */
|
||||
if (pm_suspend_via_firmware())
|
||||
return 0;
|
||||
|
||||
/* Save PC10 residency for checking later */
|
||||
if (rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pmcdev->pc10_counter))
|
||||
return -EIO;
|
||||
|
||||
/* Save S0ix residency for checking later */
|
||||
if (pmc_core_dev_state_get(pmcdev, &pmcdev->s0ix_counter))
|
||||
return -EIO;
|
||||
|
||||
pmcdev->check_counters = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool pmc_core_is_pc10_failed(struct pmc_dev *pmcdev)
|
||||
{
|
||||
u64 pc10_counter;
|
||||
|
||||
if (rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pc10_counter))
|
||||
return false;
|
||||
|
||||
if (pc10_counter == pmcdev->pc10_counter)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool pmc_core_is_s0ix_failed(struct pmc_dev *pmcdev)
|
||||
{
|
||||
u64 s0ix_counter;
|
||||
|
||||
if (pmc_core_dev_state_get(pmcdev, &s0ix_counter))
|
||||
return false;
|
||||
|
||||
if (s0ix_counter == pmcdev->s0ix_counter)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int pmc_core_resume(struct device *dev)
|
||||
{
|
||||
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
|
||||
const struct pmc_bit_map **maps = pmcdev->map->slps0_dbg_maps;
|
||||
int offset = pmcdev->map->slps0_dbg_offset;
|
||||
const struct pmc_bit_map *map;
|
||||
u32 data;
|
||||
|
||||
if (!pmcdev->check_counters)
|
||||
return 0;
|
||||
|
||||
if (!pmc_core_is_s0ix_failed(pmcdev))
|
||||
return 0;
|
||||
|
||||
if (pmc_core_is_pc10_failed(pmcdev)) {
|
||||
/* S0ix failed because of PC10 entry failure */
|
||||
dev_info(dev, "CPU did not enter PC10!!! (PC10 cnt=0x%llx)\n",
|
||||
pmcdev->pc10_counter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The real interesting case - S0ix failed - lets ask PMC why. */
|
||||
dev_warn(dev, "CPU did not enter SLP_S0!!! (S0ix cnt=%llu)\n",
|
||||
pmcdev->s0ix_counter);
|
||||
while (*maps) {
|
||||
map = *maps;
|
||||
data = pmc_core_reg_read(pmcdev, offset);
|
||||
offset += 4;
|
||||
while (map->name) {
|
||||
dev_dbg(dev, "SLP_S0_DBG: %-32s\tState: %s\n",
|
||||
map->name,
|
||||
data & map->bit_mask ? "Yes" : "No");
|
||||
map++;
|
||||
}
|
||||
maps++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops pmc_core_pm_ops = {
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(pmc_core_suspend, pmc_core_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver pmc_core_driver = {
|
||||
.driver = {
|
||||
.name = "intel_pmc_core",
|
||||
.pm = &pmc_core_pm_ops,
|
||||
},
|
||||
.probe = pmc_core_probe,
|
||||
.remove = pmc_core_remove,
|
||||
};
|
||||
|
||||
static struct platform_device pmc_core_device = {
|
||||
.name = "intel_pmc_core",
|
||||
};
|
||||
|
||||
static int __init pmc_core_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!x86_match_cpu(intel_pmc_core_ids))
|
||||
return -ENODEV;
|
||||
|
||||
ret = platform_driver_register(&pmc_core_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_device_register(&pmc_core_device);
|
||||
if (ret) {
|
||||
platform_driver_unregister(&pmc_core_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit pmc_core_exit(void)
|
||||
{
|
||||
platform_device_unregister(&pmc_core_device);
|
||||
platform_driver_unregister(&pmc_core_driver);
|
||||
}
|
||||
|
||||
module_init(pmc_core_init)
|
||||
module_exit(pmc_core_exit)
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Intel PMC Core Driver");
|
||||
|
||||
@@ -241,6 +241,9 @@ struct pmc_reg_map {
|
||||
* @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
|
||||
* used to read MPHY PG and PLL status are available
|
||||
* @mutex_lock: mutex to complete one transcation
|
||||
* @check_counters: On resume, check if counters are getting incremented
|
||||
* @pc10_counter: PC10 residency counter
|
||||
* @s0ix_counter: S0ix residency (step adjusted)
|
||||
*
|
||||
* pmc_dev contains info about power management controller device.
|
||||
*/
|
||||
@@ -253,6 +256,10 @@ struct pmc_dev {
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
int pmc_xram_read_bit;
|
||||
struct mutex lock; /* generic mutex lock for PMC Core */
|
||||
|
||||
bool check_counters; /* Check for counter increments on resume */
|
||||
u64 pc10_counter;
|
||||
u64 s0ix_counter;
|
||||
};
|
||||
|
||||
#endif /* PMC_CORE_H */
|
||||
|
||||
@@ -40,14 +40,14 @@
|
||||
* The ARC handles the interrupt and services it, writing optional data to
|
||||
* the IPC1 registers, updates the IPC_STS response register with the status.
|
||||
*/
|
||||
#define IPC_CMD 0x0
|
||||
#define IPC_CMD_MSI 0x100
|
||||
#define IPC_CMD 0x00
|
||||
#define IPC_CMD_MSI BIT(8)
|
||||
#define IPC_CMD_SIZE 16
|
||||
#define IPC_CMD_SUBCMD 12
|
||||
#define IPC_STATUS 0x04
|
||||
#define IPC_STATUS_IRQ 0x4
|
||||
#define IPC_STATUS_ERR 0x2
|
||||
#define IPC_STATUS_BUSY 0x1
|
||||
#define IPC_STATUS_IRQ BIT(2)
|
||||
#define IPC_STATUS_ERR BIT(1)
|
||||
#define IPC_STATUS_BUSY BIT(0)
|
||||
#define IPC_SPTR 0x08
|
||||
#define IPC_DPTR 0x0C
|
||||
#define IPC_WRITE_BUFFER 0x80
|
||||
@@ -101,13 +101,13 @@
|
||||
#define TELEM_SSRAM_SIZE 240
|
||||
#define TELEM_PMC_SSRAM_OFFSET 0x1B00
|
||||
#define TELEM_PUNIT_SSRAM_OFFSET 0x1A00
|
||||
#define TCO_PMC_OFFSET 0x8
|
||||
#define TCO_PMC_SIZE 0x4
|
||||
#define TCO_PMC_OFFSET 0x08
|
||||
#define TCO_PMC_SIZE 0x04
|
||||
|
||||
/* PMC register bit definitions */
|
||||
|
||||
/* PMC_CFG_REG bit masks */
|
||||
#define PMC_CFG_NO_REBOOT_MASK (1 << 4)
|
||||
#define PMC_CFG_NO_REBOOT_MASK BIT_MASK(4)
|
||||
#define PMC_CFG_NO_REBOOT_EN (1 << 4)
|
||||
#define PMC_CFG_NO_REBOOT_DIS (0 << 4)
|
||||
|
||||
@@ -131,6 +131,7 @@ static struct intel_pmc_ipc_dev {
|
||||
|
||||
/* punit */
|
||||
struct platform_device *punit_dev;
|
||||
unsigned int punit_res_count;
|
||||
|
||||
/* Telemetry */
|
||||
resource_size_t telem_pmc_ssram_base;
|
||||
@@ -682,7 +683,7 @@ static int ipc_create_punit_device(void)
|
||||
.name = PUNIT_DEVICE_NAME,
|
||||
.id = -1,
|
||||
.res = punit_res_array,
|
||||
.num_res = ARRAY_SIZE(punit_res_array),
|
||||
.num_res = ipcdev.punit_res_count,
|
||||
};
|
||||
|
||||
pdev = platform_device_register_full(&pdevinfo);
|
||||
@@ -771,13 +772,17 @@ static int ipc_create_pmc_devices(void)
|
||||
if (ret) {
|
||||
dev_err(ipcdev.dev, "Failed to add punit platform device\n");
|
||||
platform_device_unregister(ipcdev.tco_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ipcdev.telem_res_inval) {
|
||||
ret = ipc_create_telemetry_device();
|
||||
if (ret)
|
||||
if (ret) {
|
||||
dev_warn(ipcdev.dev,
|
||||
"Failed to add telemetry platform device\n");
|
||||
platform_device_unregister(ipcdev.punit_dev);
|
||||
platform_device_unregister(ipcdev.tco_dev);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -785,7 +790,7 @@ static int ipc_create_pmc_devices(void)
|
||||
|
||||
static int ipc_plat_get_res(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res, *punit_res;
|
||||
struct resource *res, *punit_res = punit_res_array;
|
||||
void __iomem *addr;
|
||||
int size;
|
||||
|
||||
@@ -800,7 +805,8 @@ static int ipc_plat_get_res(struct platform_device *pdev)
|
||||
ipcdev.acpi_io_size = size;
|
||||
dev_info(&pdev->dev, "io res: %pR\n", res);
|
||||
|
||||
punit_res = punit_res_array;
|
||||
ipcdev.punit_res_count = 0;
|
||||
|
||||
/* This is index 0 to cover BIOS data register */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM,
|
||||
PLAT_RESOURCE_BIOS_DATA_INDEX);
|
||||
@@ -808,7 +814,7 @@ static int ipc_plat_get_res(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
*punit_res = *res;
|
||||
punit_res[ipcdev.punit_res_count++] = *res;
|
||||
dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
|
||||
|
||||
/* This is index 1 to cover BIOS interface register */
|
||||
@@ -818,42 +824,38 @@ static int ipc_plat_get_res(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
*++punit_res = *res;
|
||||
punit_res[ipcdev.punit_res_count++] = *res;
|
||||
dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
|
||||
|
||||
/* This is index 2 to cover ISP data register, optional */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM,
|
||||
PLAT_RESOURCE_ISP_DATA_INDEX);
|
||||
++punit_res;
|
||||
if (res) {
|
||||
*punit_res = *res;
|
||||
punit_res[ipcdev.punit_res_count++] = *res;
|
||||
dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
|
||||
}
|
||||
|
||||
/* This is index 3 to cover ISP interface register, optional */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM,
|
||||
PLAT_RESOURCE_ISP_IFACE_INDEX);
|
||||
++punit_res;
|
||||
if (res) {
|
||||
*punit_res = *res;
|
||||
punit_res[ipcdev.punit_res_count++] = *res;
|
||||
dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
|
||||
}
|
||||
|
||||
/* This is index 4 to cover GTD data register, optional */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM,
|
||||
PLAT_RESOURCE_GTD_DATA_INDEX);
|
||||
++punit_res;
|
||||
if (res) {
|
||||
*punit_res = *res;
|
||||
punit_res[ipcdev.punit_res_count++] = *res;
|
||||
dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
|
||||
}
|
||||
|
||||
/* This is index 5 to cover GTD interface register, optional */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM,
|
||||
PLAT_RESOURCE_GTD_IFACE_INDEX);
|
||||
++punit_res;
|
||||
if (res) {
|
||||
*punit_res = *res;
|
||||
punit_res[ipcdev.punit_res_count++] = *res;
|
||||
dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);
|
||||
}
|
||||
|
||||
|
||||
@@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
|
||||
* - GTDRIVER_IPC BASE_IFACE
|
||||
*/
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
|
||||
if (res && resource_size(res) > 1) {
|
||||
if (res) {
|
||||
addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (!IS_ERR(addr))
|
||||
punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
|
||||
if (res && resource_size(res) > 1) {
|
||||
if (res) {
|
||||
addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (!IS_ERR(addr))
|
||||
punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
|
||||
if (res && resource_size(res) > 1) {
|
||||
if (res) {
|
||||
addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (!IS_ERR(addr))
|
||||
punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
|
||||
if (res && resource_size(res) > 1) {
|
||||
if (res) {
|
||||
addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (!IS_ERR(addr))
|
||||
punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
|
||||
|
||||
@@ -56,6 +56,16 @@
|
||||
#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
|
||||
#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
|
||||
#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET 0xcb
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET 0xcd
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET 0xce
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET 0xcf
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2
|
||||
#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3
|
||||
#define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3
|
||||
#define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4
|
||||
#define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5
|
||||
@@ -72,6 +82,7 @@
|
||||
#define MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET 0xf5
|
||||
#define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET 0xf6
|
||||
#define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf7
|
||||
#define MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET 0xf8
|
||||
#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
|
||||
#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
|
||||
#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
|
||||
@@ -128,6 +139,18 @@
|
||||
#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
|
||||
#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
|
||||
|
||||
/* Masks and default values for watchdogs */
|
||||
#define MLXPLAT_CPLD_WD1_CLEAR_MASK GENMASK(7, 1)
|
||||
#define MLXPLAT_CPLD_WD2_CLEAR_MASK (GENMASK(7, 0) & ~BIT(1))
|
||||
|
||||
#define MLXPLAT_CPLD_WD_TYPE1_TO_MASK GENMASK(7, 4)
|
||||
#define MLXPLAT_CPLD_WD_TYPE2_TO_MASK 0
|
||||
#define MLXPLAT_CPLD_WD_RESET_ACT_MASK GENMASK(7, 1)
|
||||
#define MLXPLAT_CPLD_WD_FAN_ACT_MASK (GENMASK(7, 0) & ~BIT(4))
|
||||
#define MLXPLAT_CPLD_WD_COUNT_ACT_MASK (GENMASK(7, 0) & ~BIT(7))
|
||||
#define MLXPLAT_CPLD_WD_DFLT_TIMEOUT 30
|
||||
#define MLXPLAT_CPLD_WD_MAX_DEVS 2
|
||||
|
||||
/* mlxplat_priv - platform private data
|
||||
* @pdev_i2c - i2c controller platform device
|
||||
* @pdev_mux - array of mux platform devices
|
||||
@@ -135,6 +158,7 @@
|
||||
* @pdev_led - led platform devices
|
||||
* @pdev_io_regs - register access platform devices
|
||||
* @pdev_fan - FAN platform devices
|
||||
* @pdev_wd - array of watchdog platform devices
|
||||
*/
|
||||
struct mlxplat_priv {
|
||||
struct platform_device *pdev_i2c;
|
||||
@@ -143,6 +167,7 @@ struct mlxplat_priv {
|
||||
struct platform_device *pdev_led;
|
||||
struct platform_device *pdev_io_regs;
|
||||
struct platform_device *pdev_fan;
|
||||
struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS];
|
||||
};
|
||||
|
||||
/* Regions for LPC I2C controller and LPC base register space */
|
||||
@@ -1339,6 +1364,10 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
|
||||
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET,
|
||||
.bit = BIT(3),
|
||||
},
|
||||
{
|
||||
.label = "conf",
|
||||
.capability = MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mlxreg_core_platform_data mlxplat_default_fan_data = {
|
||||
@@ -1346,6 +1375,148 @@ static struct mlxreg_core_platform_data mlxplat_default_fan_data = {
|
||||
.counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data),
|
||||
};
|
||||
|
||||
/* Watchdog type1: hardware implementation version1
|
||||
* (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140 systems).
|
||||
*/
|
||||
static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type1[] = {
|
||||
{
|
||||
.label = "action",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK,
|
||||
.bit = 0,
|
||||
},
|
||||
{
|
||||
.label = "timeout",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK,
|
||||
.health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
|
||||
},
|
||||
{
|
||||
.label = "ping",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD1_CLEAR_MASK,
|
||||
.bit = 0,
|
||||
},
|
||||
{
|
||||
.label = "reset",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
|
||||
.mask = GENMASK(7, 0) & ~BIT(6),
|
||||
.bit = 6,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type1[] = {
|
||||
{
|
||||
.label = "action",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK,
|
||||
.bit = 4,
|
||||
},
|
||||
{
|
||||
.label = "timeout",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK,
|
||||
.health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
|
||||
},
|
||||
{
|
||||
.label = "ping",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD1_CLEAR_MASK,
|
||||
.bit = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type1[] = {
|
||||
{
|
||||
.data = mlxplat_mlxcpld_wd_main_regs_type1,
|
||||
.counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type1),
|
||||
.version = MLX_WDT_TYPE1,
|
||||
.identity = "mlx-wdt-main",
|
||||
},
|
||||
{
|
||||
.data = mlxplat_mlxcpld_wd_aux_regs_type1,
|
||||
.counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type1),
|
||||
.version = MLX_WDT_TYPE1,
|
||||
.identity = "mlx-wdt-aux",
|
||||
},
|
||||
};
|
||||
|
||||
/* Watchdog type2: hardware implementation version 2
|
||||
* (all systems except (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140).
|
||||
*/
|
||||
static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type2[] = {
|
||||
{
|
||||
.label = "action",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK,
|
||||
.bit = 0,
|
||||
},
|
||||
{
|
||||
.label = "timeout",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
|
||||
.health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
|
||||
},
|
||||
{
|
||||
.label = "timeleft",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
|
||||
},
|
||||
{
|
||||
.label = "ping",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK,
|
||||
.bit = 0,
|
||||
},
|
||||
{
|
||||
.label = "reset",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
|
||||
.mask = GENMASK(7, 0) & ~BIT(6),
|
||||
.bit = 6,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type2[] = {
|
||||
{
|
||||
.label = "action",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK,
|
||||
.bit = 4,
|
||||
},
|
||||
{
|
||||
.label = "timeout",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
|
||||
.health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT,
|
||||
},
|
||||
{
|
||||
.label = "timeleft",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK,
|
||||
},
|
||||
{
|
||||
.label = "ping",
|
||||
.reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET,
|
||||
.mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK,
|
||||
.bit = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type2[] = {
|
||||
{
|
||||
.data = mlxplat_mlxcpld_wd_main_regs_type2,
|
||||
.counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type2),
|
||||
.version = MLX_WDT_TYPE2,
|
||||
.identity = "mlx-wdt-main",
|
||||
},
|
||||
{
|
||||
.data = mlxplat_mlxcpld_wd_aux_regs_type2,
|
||||
.counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type2),
|
||||
.version = MLX_WDT_TYPE2,
|
||||
.identity = "mlx-wdt-aux",
|
||||
},
|
||||
};
|
||||
|
||||
static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
@@ -1368,6 +1539,14 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
|
||||
case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET:
|
||||
return true;
|
||||
@@ -1411,6 +1590,16 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:
|
||||
@@ -1428,6 +1617,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1467,6 +1657,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:
|
||||
@@ -1484,6 +1678,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET:
|
||||
case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1493,6 +1688,7 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = {
|
||||
{ MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 },
|
||||
{ MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 },
|
||||
{ MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 },
|
||||
{ MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 },
|
||||
};
|
||||
|
||||
struct mlxplat_mlxcpld_regmap_context {
|
||||
@@ -1542,6 +1738,8 @@ static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
|
||||
static struct mlxreg_core_platform_data *mlxplat_led;
|
||||
static struct mlxreg_core_platform_data *mlxplat_regs_io;
|
||||
static struct mlxreg_core_platform_data *mlxplat_fan;
|
||||
static struct mlxreg_core_platform_data
|
||||
*mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS];
|
||||
|
||||
static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
|
||||
{
|
||||
@@ -1557,6 +1755,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
|
||||
mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||||
mlxplat_led = &mlxplat_default_led_data;
|
||||
mlxplat_regs_io = &mlxplat_default_regs_io_data;
|
||||
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
|
||||
|
||||
return 1;
|
||||
};
|
||||
@@ -1575,6 +1774,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
|
||||
mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||||
mlxplat_led = &mlxplat_msn21xx_led_data;
|
||||
mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
|
||||
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
|
||||
|
||||
return 1;
|
||||
};
|
||||
@@ -1593,6 +1793,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
|
||||
mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||||
mlxplat_led = &mlxplat_default_led_data;
|
||||
mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
|
||||
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
|
||||
|
||||
return 1;
|
||||
};
|
||||
@@ -1611,6 +1812,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
|
||||
mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
|
||||
mlxplat_led = &mlxplat_msn21xx_led_data;
|
||||
mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
|
||||
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
|
||||
|
||||
return 1;
|
||||
};
|
||||
@@ -1630,6 +1832,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
|
||||
mlxplat_led = &mlxplat_default_ng_led_data;
|
||||
mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;
|
||||
mlxplat_fan = &mlxplat_default_fan_data;
|
||||
for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++)
|
||||
mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i];
|
||||
|
||||
return 1;
|
||||
};
|
||||
@@ -1912,15 +2116,33 @@ static int __init mlxplat_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Add WD drivers. */
|
||||
for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) {
|
||||
if (mlxplat_wd_data[j]) {
|
||||
mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap;
|
||||
priv->pdev_wd[j] = platform_device_register_resndata(
|
||||
&mlxplat_dev->dev, "mlx-wdt",
|
||||
j, NULL, 0,
|
||||
mlxplat_wd_data[j],
|
||||
sizeof(*mlxplat_wd_data[j]));
|
||||
if (IS_ERR(priv->pdev_wd[j])) {
|
||||
err = PTR_ERR(priv->pdev_wd[j]);
|
||||
goto fail_platform_wd_register;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sync registers with hardware. */
|
||||
regcache_mark_dirty(mlxplat_hotplug->regmap);
|
||||
err = regcache_sync(mlxplat_hotplug->regmap);
|
||||
if (err)
|
||||
goto fail_platform_fan_register;
|
||||
goto fail_platform_wd_register;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_platform_fan_register:
|
||||
fail_platform_wd_register:
|
||||
while (--j >= 0)
|
||||
platform_device_unregister(priv->pdev_wd[j]);
|
||||
if (mlxplat_fan)
|
||||
platform_device_unregister(priv->pdev_fan);
|
||||
fail_platform_io_regs_register:
|
||||
@@ -1946,6 +2168,8 @@ static void __exit mlxplat_exit(void)
|
||||
struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
|
||||
int i;
|
||||
|
||||
for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--)
|
||||
platform_device_unregister(priv->pdev_wd[i]);
|
||||
if (priv->pdev_fan)
|
||||
platform_device_unregister(priv->pdev_fan);
|
||||
if (priv->pdev_io_regs)
|
||||
|
||||
@@ -4424,14 +4424,16 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
default:
|
||||
dprintk("Resource %d isn't an IRQ nor an IO port\n",
|
||||
resource->type);
|
||||
|
||||
case ACPI_RESOURCE_TYPE_END_TAG:
|
||||
return AE_OK;
|
||||
|
||||
default:
|
||||
dprintk("Resource %d isn't an IRQ nor an IO port\n",
|
||||
resource->type);
|
||||
return AE_CTRL_TERMINATE;
|
||||
|
||||
}
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
|
||||
static int sony_pic_possible_resources(struct acpi_device *device)
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
@@ -4212,7 +4212,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
|
||||
known_ev = true;
|
||||
break;
|
||||
}
|
||||
/* fallthrough to default */
|
||||
/* fallthrough - to default */
|
||||
default:
|
||||
known_ev = false;
|
||||
}
|
||||
@@ -4501,6 +4501,74 @@ static void bluetooth_exit(void)
|
||||
bluetooth_shutdown();
|
||||
}
|
||||
|
||||
static const struct dmi_system_id bt_fwbug_list[] __initconst = {
|
||||
{
|
||||
.ident = "ThinkPad E485",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "20KU"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "ThinkPad E585",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "20KV"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "ThinkPad A285 - 20MW",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "20MW"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "ThinkPad A285 - 20MX",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "20MX"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "ThinkPad A485 - 20MU",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "20MU"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "ThinkPad A485 - 20MV",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "20MV"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct pci_device_id fwbug_cards_ids[] __initconst = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24F3) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24FD) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2526) },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
static int __init have_bt_fwbug(void)
|
||||
{
|
||||
/*
|
||||
* Some AMD based ThinkPads have a firmware bug that calling
|
||||
* "GBDC" will cause bluetooth on Intel wireless cards blocked
|
||||
*/
|
||||
if (dmi_check_system(bt_fwbug_list) && pci_dev_present(fwbug_cards_ids)) {
|
||||
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
|
||||
FW_BUG "disable bluetooth subdriver for Intel cards\n");
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init bluetooth_init(struct ibm_init_struct *iibm)
|
||||
{
|
||||
int res;
|
||||
@@ -4513,7 +4581,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
|
||||
|
||||
/* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
|
||||
G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
|
||||
tp_features.bluetooth = hkey_handle &&
|
||||
tp_features.bluetooth = !have_bt_fwbug() && hkey_handle &&
|
||||
acpi_evalf(hkey_handle, &status, "GBDC", "qd");
|
||||
|
||||
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
|
||||
@@ -5808,7 +5876,7 @@ static int led_set_status(const unsigned int led,
|
||||
return -EPERM;
|
||||
if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
|
||||
(1 << led), led_sled_arg1[ledstatus]))
|
||||
rc = -EIO;
|
||||
return -EIO;
|
||||
break;
|
||||
case TPACPI_LED_OLD:
|
||||
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
|
||||
@@ -5832,10 +5900,10 @@ static int led_set_status(const unsigned int led,
|
||||
return -EPERM;
|
||||
if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
|
||||
led, led_led_arg1[ledstatus]))
|
||||
rc = -EIO;
|
||||
return -EIO;
|
||||
break;
|
||||
default:
|
||||
rc = -ENXIO;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
@@ -6249,8 +6317,8 @@ static int thermal_get_sensor(int idx, s32 *value)
|
||||
t = TP_EC_THERMAL_TMP8;
|
||||
idx -= 8;
|
||||
}
|
||||
/* fallthrough */
|
||||
#endif
|
||||
/* fallthrough */
|
||||
case TPACPI_THERMAL_TPEC_8:
|
||||
if (idx <= 7) {
|
||||
if (!acpi_ec_read(t + idx, &tmp))
|
||||
@@ -9890,6 +9958,37 @@ invalid:
|
||||
return '\0';
|
||||
}
|
||||
|
||||
static void find_new_ec_fwstr(const struct dmi_header *dm, void *private)
|
||||
{
|
||||
char *ec_fw_string = (char *) private;
|
||||
const char *dmi_data = (const char *)dm;
|
||||
/*
|
||||
* ThinkPad Embedded Controller Program Table on newer models
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* ----------------------------------------------------
|
||||
* 0x00 | Type | BYTE | 0x8C
|
||||
* 0x01 | Length | BYTE |
|
||||
* 0x02 | Handle | WORD | Varies
|
||||
* 0x04 | Signature | BYTEx6 | ASCII for "LENOVO"
|
||||
* 0x0A | OEM struct offset | BYTE | 0x0B
|
||||
* 0x0B | OEM struct number | BYTE | 0x07, for this structure
|
||||
* 0x0C | OEM struct revision | BYTE | 0x01, for this format
|
||||
* 0x0D | ECP version ID | STR ID |
|
||||
* 0x0E | ECP release date | STR ID |
|
||||
*/
|
||||
|
||||
/* Return if data structure not match */
|
||||
if (dm->type != 140 || dm->length < 0x0F ||
|
||||
memcmp(dmi_data + 4, "LENOVO", 6) != 0 ||
|
||||
dmi_data[0x0A] != 0x0B || dmi_data[0x0B] != 0x07 ||
|
||||
dmi_data[0x0C] != 0x01)
|
||||
return;
|
||||
|
||||
/* fwstr is the first 8byte string */
|
||||
strncpy(ec_fw_string, dmi_data + 0x0F, 8);
|
||||
}
|
||||
|
||||
/* returns 0 - probe ok, or < 0 - probe error.
|
||||
* Probe ok doesn't mean thinkpad found.
|
||||
* On error, kfree() cleanup on tp->* is not performed, caller must do it */
|
||||
@@ -9897,7 +9996,7 @@ static int __must_check __init get_thinkpad_model_data(
|
||||
struct thinkpad_id_data *tp)
|
||||
{
|
||||
const struct dmi_device *dev = NULL;
|
||||
char ec_fw_string[18];
|
||||
char ec_fw_string[18] = {0};
|
||||
char const *s;
|
||||
char t;
|
||||
|
||||
@@ -9937,23 +10036,28 @@ static int __must_check __init get_thinkpad_model_data(
|
||||
ec_fw_string) == 1) {
|
||||
ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
|
||||
ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
|
||||
|
||||
tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
|
||||
if (!tp->ec_version_str)
|
||||
return -ENOMEM;
|
||||
|
||||
t = tpacpi_parse_fw_id(ec_fw_string,
|
||||
&tp->ec_model, &tp->ec_release);
|
||||
if (t != 'H') {
|
||||
pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
|
||||
ec_fw_string);
|
||||
pr_notice("please report this to %s\n",
|
||||
TPACPI_MAIL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Newer ThinkPads have different EC program info table */
|
||||
if (!ec_fw_string[0])
|
||||
dmi_walk(find_new_ec_fwstr, &ec_fw_string);
|
||||
|
||||
if (ec_fw_string[0]) {
|
||||
tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
|
||||
if (!tp->ec_version_str)
|
||||
return -ENOMEM;
|
||||
|
||||
t = tpacpi_parse_fw_id(ec_fw_string,
|
||||
&tp->ec_model, &tp->ec_release);
|
||||
if (t != 'H') {
|
||||
pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
|
||||
ec_fw_string);
|
||||
pr_notice("please report this to %s\n", TPACPI_MAIL);
|
||||
}
|
||||
}
|
||||
|
||||
s = dmi_get_system_info(DMI_PRODUCT_VERSION);
|
||||
if (s && !(strncasecmp(s, "ThinkPad", 8) && strncasecmp(s, "Lenovo", 6))) {
|
||||
tp->model_str = kstrdup(s, GFP_KERNEL);
|
||||
@@ -10165,7 +10269,7 @@ MODULE_PARM_DESC(volume_mode,
|
||||
|
||||
module_param_named(volume_capabilities, volume_capabilities, uint, 0444);
|
||||
MODULE_PARM_DESC(volume_capabilities,
|
||||
"Selects the mixer capabilites: 0=auto, 1=volume and mute, 2=mute only");
|
||||
"Selects the mixer capabilities: 0=auto, 1=volume and mute, 2=mute only");
|
||||
|
||||
module_param_named(volume_control, volume_control_allowed, bool, 0444);
|
||||
MODULE_PARM_DESC(volume_control,
|
||||
|
||||
@@ -249,6 +249,21 @@ static const struct ts_dmi_data jumper_ezpad_6_pro_data = {
|
||||
.properties = jumper_ezpad_6_pro_props,
|
||||
};
|
||||
|
||||
static const struct property_entry jumper_ezpad_6_pro_b_props[] = {
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
|
||||
PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-pro-b.fw"),
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
|
||||
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
|
||||
PROPERTY_ENTRY_BOOL("silead,home-button"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct ts_dmi_data jumper_ezpad_6_pro_b_data = {
|
||||
.acpi_name = "MSSL1680:00",
|
||||
.properties = jumper_ezpad_6_pro_b_props,
|
||||
};
|
||||
|
||||
static const struct property_entry jumper_ezpad_mini3_props[] = {
|
||||
PROPERTY_ENTRY_U32("touchscreen-min-x", 23),
|
||||
PROPERTY_ENTRY_U32("touchscreen-min-y", 16),
|
||||
@@ -265,6 +280,23 @@ static const struct ts_dmi_data jumper_ezpad_mini3_data = {
|
||||
.properties = jumper_ezpad_mini3_props,
|
||||
};
|
||||
|
||||
static const struct property_entry myria_my8307_props[] = {
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-x", 1720),
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
|
||||
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-myria-my8307.fw"),
|
||||
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
|
||||
PROPERTY_ENTRY_BOOL("silead,home-button"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct ts_dmi_data myria_my8307_data = {
|
||||
.acpi_name = "MSSL1680:00",
|
||||
.properties = myria_my8307_props,
|
||||
};
|
||||
|
||||
static const struct property_entry onda_obook_20_plus_props[] = {
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
|
||||
@@ -673,6 +705,17 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
|
||||
DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Jumper EZpad 6 Pro B */
|
||||
.driver_data = (void *)&jumper_ezpad_6_pro_b_data,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Jumper"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"),
|
||||
DMI_MATCH(DMI_BIOS_VERSION, "5.12"),
|
||||
/* Above matches are too generic, add bios-date match */
|
||||
DMI_MATCH(DMI_BIOS_DATE, "04/24/2018"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Jumper EZpad mini3 */
|
||||
.driver_data = (void *)&jumper_ezpad_mini3_data,
|
||||
@@ -690,6 +733,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Myria MY8307 */
|
||||
.driver_data = (void *)&myria_my8307_data,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Complet Electro Serv"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MY8307"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Onda oBook 20 Plus */
|
||||
.driver_data = (void *)&onda_obook_20_plus_data,
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
/* Input */
|
||||
#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
|
||||
#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
|
||||
#define ASUS_WMI_DEVID_FNLOCK 0x00100023
|
||||
|
||||
/* Fan, Thermal */
|
||||
#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
|
||||
|
||||
Reference in New Issue
Block a user