Commit 7817ffd2 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents cccd559e 6456fd73
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
menuconfig MELLANOX_PLATFORM menuconfig MELLANOX_PLATFORM
bool "Platform support for Mellanox hardware" bool "Platform support for Mellanox hardware"
depends on X86 || ARM || COMPILE_TEST depends on X86 || ARM || ARM64 || COMPILE_TEST
---help--- ---help---
Say Y here to get to see options for platform support for Say Y here to get to see options for platform support for
Mellanox systems. This option alone does not add any kernel code. Mellanox systems. This option alone does not add any kernel code.
...@@ -34,4 +34,14 @@ config MLXREG_IO ...@@ -34,4 +34,14 @@ config MLXREG_IO
to system resets operation, system reset causes monitoring and some to system resets operation, system reset causes monitoring and some
kinds of mux selection. 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 endif # MELLANOX_PLATFORM
...@@ -3,5 +3,6 @@ ...@@ -3,5 +3,6 @@
# Makefile for linux/drivers/platform/mellanox # Makefile for linux/drivers/platform/mellanox
# Mellanox Platform-Specific Drivers # Mellanox Platform-Specific Drivers
# #
obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o
obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
/* 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__) */
This diff is collapsed.
...@@ -1263,6 +1263,17 @@ config INTEL_CHTDC_TI_PWRBTN ...@@ -1263,6 +1263,17 @@ config INTEL_CHTDC_TI_PWRBTN
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called intel_chtdc_ti_pwrbtn. 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 config I2C_MULTI_INSTANTIATE
tristate "I2C multi instantiate pseudo device driver" tristate "I2C multi instantiate pseudo device driver"
depends on I2C && ACPI depends on I2C && ACPI
......
...@@ -94,6 +94,7 @@ obj-$(CONFIG_PMC_ATOM) += pmc_atom.o ...@@ -94,6 +94,7 @@ obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.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_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_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o
obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o
...@@ -522,23 +522,22 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, ...@@ -522,23 +522,22 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args,
input.length = (acpi_size) sizeof(*in_args); input.length = (acpi_size) sizeof(*in_args);
input.pointer = in_args; input.pointer = in_args;
if (out_data != NULL) { if (out_data) {
output.length = ACPI_ALLOCATE_BUFFER; output.length = ACPI_ALLOCATE_BUFFER;
output.pointer = NULL; output.pointer = NULL;
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
command, &input, &output); 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, status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
command, &input, NULL); 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; return status;
} }
/* /*
...@@ -588,7 +587,7 @@ static ssize_t show_hdmi_source(struct device *dev, ...@@ -588,7 +587,7 @@ static ssize_t show_hdmi_source(struct device *dev,
return scnprintf(buf, PAGE_SIZE, return scnprintf(buf, PAGE_SIZE,
"input [gpu] unknown\n"); "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"); return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
} }
......
...@@ -66,10 +66,13 @@ MODULE_LICENSE("GPL"); ...@@ -66,10 +66,13 @@ MODULE_LICENSE("GPL");
#define NOTIFY_BRNUP_MAX 0x1f #define NOTIFY_BRNUP_MAX 0x1f
#define NOTIFY_BRNDOWN_MIN 0x20 #define NOTIFY_BRNDOWN_MIN 0x20
#define NOTIFY_BRNDOWN_MAX 0x2e #define NOTIFY_BRNDOWN_MAX 0x2e
#define NOTIFY_FNLOCK_TOGGLE 0x4e
#define NOTIFY_KBD_BRTUP 0xc4 #define NOTIFY_KBD_BRTUP 0xc4
#define NOTIFY_KBD_BRTDWN 0xc5 #define NOTIFY_KBD_BRTDWN 0xc5
#define NOTIFY_KBD_BRTTOGGLE 0xc7 #define NOTIFY_KBD_BRTTOGGLE 0xc7
#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
#define ASUS_FAN_DESC "cpu_fan" #define ASUS_FAN_DESC "cpu_fan"
#define ASUS_FAN_MFUN 0x13 #define ASUS_FAN_MFUN 0x13
#define ASUS_FAN_SFUN_READ 0x06 #define ASUS_FAN_SFUN_READ 0x06
...@@ -177,6 +180,8 @@ struct asus_wmi { ...@@ -177,6 +180,8 @@ struct asus_wmi {
struct workqueue_struct *hotplug_workqueue; struct workqueue_struct *hotplug_workqueue;
struct work_struct hotplug_work; struct work_struct hotplug_work;
bool fnlock_locked;
struct asus_wmi_debug debug; struct asus_wmi_debug debug;
struct asus_wmi_driver *driver; struct asus_wmi_driver *driver;
...@@ -1619,6 +1624,23 @@ static int is_display_toggle(int code) ...@@ -1619,6 +1624,23 @@ static int is_display_toggle(int code)
return 0; 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) static void asus_wmi_notify(u32 value, void *context)
{ {
struct asus_wmi *asus = context; struct asus_wmi *asus = context;
...@@ -1680,6 +1702,12 @@ static void asus_wmi_notify(u32 value, void *context) ...@@ -1680,6 +1702,12 @@ static void asus_wmi_notify(u32 value, void *context)
goto exit; 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) && if (is_display_toggle(code) &&
asus->driver->quirks->no_display_toggle) asus->driver->quirks->no_display_toggle)
goto exit; goto exit;
...@@ -2134,6 +2162,11 @@ static int asus_wmi_add(struct platform_device *pdev) ...@@ -2134,6 +2162,11 @@ static int asus_wmi_add(struct platform_device *pdev)
} else } else
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL); 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, status = wmi_install_notify_handler(asus->driver->event_guid,
asus_wmi_notify, asus); asus_wmi_notify, asus);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
...@@ -2213,6 +2246,8 @@ static int asus_hotk_resume(struct device *device) ...@@ -2213,6 +2246,8 @@ static int asus_hotk_resume(struct device *device)
if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
kbd_led_update(asus); kbd_led_update(asus);
if (asus_wmi_has_fnlock_key(asus))
asus_wmi_fnlock_update(asus);
return 0; return 0;
} }
...@@ -2249,6 +2284,8 @@ static int asus_hotk_restore(struct device *device) ...@@ -2249,6 +2284,8 @@ static int asus_hotk_restore(struct device *device)
if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
kbd_led_update(asus); kbd_led_update(asus);
if (asus_wmi_has_fnlock_key(asus))
asus_wmi_fnlock_update(asus);
return 0; return 0;
} }
......
...@@ -531,7 +531,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) ...@@ -531,7 +531,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data)
return; 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); ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
hwswitch = buffer.output[1]; hwswitch = buffer.output[1];
...@@ -562,7 +562,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data) ...@@ -562,7 +562,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data)
return ret; return ret;
status = buffer.output[1]; 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); hwswitch_ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
if (hwswitch_ret) if (hwswitch_ret)
return hwswitch_ret; return hwswitch_ret;
...@@ -647,7 +647,7 @@ static void dell_update_rfkill(struct work_struct *ignored) ...@@ -647,7 +647,7 @@ static void dell_update_rfkill(struct work_struct *ignored)
if (ret != 0) if (ret != 0)
return; 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); ret = dell_send_request(&buffer, CLASS_INFO, SELECT_RFKILL);
if (ret == 0 && (status & BIT(0))) if (ret == 0 && (status & BIT(0)))
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <linux/rfkill.h> #include <linux/rfkill.h>
#include <linux/input.h> #include <linux/input.h>
#include "dell-rbtn.h"
enum rbtn_type { enum rbtn_type {
RBTN_UNKNOWN, RBTN_UNKNOWN,
RBTN_TOGGLE, RBTN_TOGGLE,
......
...@@ -980,312 +980,21 @@ static void ideapad_wmi_notify(u32 value, void *context) ...@@ -980,312 +980,21 @@ static void ideapad_wmi_notify(u32 value, void *context)
#endif #endif
/* /*
* Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF * Some ideapads have a hardware rfkill switch, but most do not have one.
* always results in 0 on these models, causing ideapad_laptop to wrongly * Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill,
* report all radios as hardware-blocked. * 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[] = { static const struct dmi_system_id 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"),
},
},
{} {}
}; };
...@@ -1311,7 +1020,7 @@ static int ideapad_acpi_add(struct platform_device *pdev) ...@@ -1311,7 +1020,7 @@ static int ideapad_acpi_add(struct platform_device *pdev)
priv->cfg = cfg; priv->cfg = cfg;
priv->adev = adev; priv->adev = adev;
priv->platform_device = pdev; 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); ret = ideapad_sysfs_init(priv);
if (ret) if (ret)
......
// 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 @@ ...@@ -19,6 +19,8 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/cpu_device_id.h> #include <asm/cpu_device_id.h>
...@@ -828,7 +830,7 @@ static const struct pci_device_id pmc_pci_ids[] = { ...@@ -828,7 +830,7 @@ static const struct pci_device_id pmc_pci_ids[] = {
* the platform BIOS enforces 24Mhx Crystal to shutdown * the platform BIOS enforces 24Mhx Crystal to shutdown
* before PMC can assert SLP_S0#. * 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; struct pmc_dev *pmcdev = &pmc;
u32 value; u32 value;
...@@ -854,13 +856,17 @@ static const struct dmi_system_id pmc_core_dmi_table[] = { ...@@ -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; struct pmc_dev *pmcdev = &pmc;
const struct x86_cpu_id *cpu_id; const struct x86_cpu_id *cpu_id;
u64 slp_s0_addr; u64 slp_s0_addr;
int err; int err;
if (device_initialized)
return -ENODEV;
cpu_id = x86_match_cpu(intel_pmc_core_ids); cpu_id = x86_match_cpu(intel_pmc_core_ids);
if (!cpu_id) if (!cpu_id)
return -ENODEV; return -ENODEV;
...@@ -886,30 +892,178 @@ static int __init pmc_core_probe(void) ...@@ -886,30 +892,178 @@ static int __init pmc_core_probe(void)
return -ENOMEM; return -ENOMEM;
mutex_init(&pmcdev->lock); mutex_init(&pmcdev->lock);
platform_set_drvdata(pdev, pmcdev);
pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(); pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
dmi_check_system(pmc_core_dmi_table);
err = pmc_core_dbgfs_register(pmcdev); err = pmc_core_dbgfs_register(pmcdev);
if (err < 0) { if (err < 0) {
pr_warn(" debugfs register failed.\n"); dev_warn(&pdev->dev, "debugfs register failed.\n");
iounmap(pmcdev->regbase); iounmap(pmcdev->regbase);
return err; return err;
} }
dmi_check_system(pmc_core_dmi_table); device_initialized = true;
pr_info(" initialized\n"); dev_info(&pdev->dev, " initialized\n");
return 0; 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); pmc_core_dbgfs_unregister(pmcdev);
platform_set_drvdata(pdev, NULL);
mutex_destroy(&pmcdev->lock); mutex_destroy(&pmcdev->lock);
iounmap(pmcdev->regbase); 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_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel PMC Core Driver"); MODULE_DESCRIPTION("Intel PMC Core Driver");
...@@ -241,6 +241,9 @@ struct pmc_reg_map { ...@@ -241,6 +241,9 @@ struct pmc_reg_map {
* @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
* used to read MPHY PG and PLL status are available * used to read MPHY PG and PLL status are available
* @mutex_lock: mutex to complete one transcation * @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. * pmc_dev contains info about power management controller device.
*/ */
...@@ -253,6 +256,10 @@ struct pmc_dev { ...@@ -253,6 +256,10 @@ struct pmc_dev {
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
int pmc_xram_read_bit; int pmc_xram_read_bit;
struct mutex lock; /* generic mutex lock for PMC Core */ 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 */ #endif /* PMC_CORE_H */
...@@ -40,14 +40,14 @@ ...@@ -40,14 +40,14 @@
* The ARC handles the interrupt and services it, writing optional data to * The ARC handles the interrupt and services it, writing optional data to
* the IPC1 registers, updates the IPC_STS response register with the status. * the IPC1 registers, updates the IPC_STS response register with the status.
*/ */
#define IPC_CMD 0x0 #define IPC_CMD 0x00
#define IPC_CMD_MSI 0x100 #define IPC_CMD_MSI BIT(8)
#define IPC_CMD_SIZE 16 #define IPC_CMD_SIZE 16
#define IPC_CMD_SUBCMD 12 #define IPC_CMD_SUBCMD 12
#define IPC_STATUS 0x04 #define IPC_STATUS 0x04
#define IPC_STATUS_IRQ 0x4 #define IPC_STATUS_IRQ BIT(2)
#define IPC_STATUS_ERR 0x2 #define IPC_STATUS_ERR BIT(1)
#define IPC_STATUS_BUSY 0x1 #define IPC_STATUS_BUSY BIT(0)
#define IPC_SPTR 0x08 #define IPC_SPTR 0x08
#define IPC_DPTR 0x0C #define IPC_DPTR 0x0C
#define IPC_WRITE_BUFFER 0x80 #define IPC_WRITE_BUFFER 0x80
...@@ -101,13 +101,13 @@ ...@@ -101,13 +101,13 @@
#define TELEM_SSRAM_SIZE 240 #define TELEM_SSRAM_SIZE 240
#define TELEM_PMC_SSRAM_OFFSET 0x1B00 #define TELEM_PMC_SSRAM_OFFSET 0x1B00
#define TELEM_PUNIT_SSRAM_OFFSET 0x1A00 #define TELEM_PUNIT_SSRAM_OFFSET 0x1A00
#define TCO_PMC_OFFSET 0x8 #define TCO_PMC_OFFSET 0x08
#define TCO_PMC_SIZE 0x4 #define TCO_PMC_SIZE 0x04
/* PMC register bit definitions */ /* PMC register bit definitions */
/* PMC_CFG_REG bit masks */ /* 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_EN (1 << 4)
#define PMC_CFG_NO_REBOOT_DIS (0 << 4) #define PMC_CFG_NO_REBOOT_DIS (0 << 4)
...@@ -131,6 +131,7 @@ static struct intel_pmc_ipc_dev { ...@@ -131,6 +131,7 @@ static struct intel_pmc_ipc_dev {
/* punit */ /* punit */
struct platform_device *punit_dev; struct platform_device *punit_dev;
unsigned int punit_res_count;
/* Telemetry */ /* Telemetry */
resource_size_t telem_pmc_ssram_base; resource_size_t telem_pmc_ssram_base;
...@@ -682,7 +683,7 @@ static int ipc_create_punit_device(void) ...@@ -682,7 +683,7 @@ static int ipc_create_punit_device(void)
.name = PUNIT_DEVICE_NAME, .name = PUNIT_DEVICE_NAME,
.id = -1, .id = -1,
.res = punit_res_array, .res = punit_res_array,
.num_res = ARRAY_SIZE(punit_res_array), .num_res = ipcdev.punit_res_count,
}; };
pdev = platform_device_register_full(&pdevinfo); pdev = platform_device_register_full(&pdevinfo);
...@@ -771,13 +772,17 @@ static int ipc_create_pmc_devices(void) ...@@ -771,13 +772,17 @@ static int ipc_create_pmc_devices(void)
if (ret) { if (ret) {
dev_err(ipcdev.dev, "Failed to add punit platform device\n"); dev_err(ipcdev.dev, "Failed to add punit platform device\n");
platform_device_unregister(ipcdev.tco_dev); platform_device_unregister(ipcdev.tco_dev);
return ret;
} }
if (!ipcdev.telem_res_inval) { if (!ipcdev.telem_res_inval) {
ret = ipc_create_telemetry_device(); ret = ipc_create_telemetry_device();
if (ret) if (ret) {
dev_warn(ipcdev.dev, dev_warn(ipcdev.dev,
"Failed to add telemetry platform device\n"); "Failed to add telemetry platform device\n");
platform_device_unregister(ipcdev.punit_dev);
platform_device_unregister(ipcdev.tco_dev);
}
} }
return ret; return ret;
...@@ -785,7 +790,7 @@ static int ipc_create_pmc_devices(void) ...@@ -785,7 +790,7 @@ static int ipc_create_pmc_devices(void)
static int ipc_plat_get_res(struct platform_device *pdev) 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; void __iomem *addr;
int size; int size;
...@@ -800,7 +805,8 @@ static int ipc_plat_get_res(struct platform_device *pdev) ...@@ -800,7 +805,8 @@ static int ipc_plat_get_res(struct platform_device *pdev)
ipcdev.acpi_io_size = size; ipcdev.acpi_io_size = size;
dev_info(&pdev->dev, "io res: %pR\n", res); 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 */ /* This is index 0 to cover BIOS data register */
res = platform_get_resource(pdev, IORESOURCE_MEM, res = platform_get_resource(pdev, IORESOURCE_MEM,
PLAT_RESOURCE_BIOS_DATA_INDEX); PLAT_RESOURCE_BIOS_DATA_INDEX);
...@@ -808,7 +814,7 @@ static int ipc_plat_get_res(struct platform_device *pdev) ...@@ -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"); dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
return -ENXIO; return -ENXIO;
} }
*punit_res = *res; punit_res[ipcdev.punit_res_count++] = *res;
dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res); dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
/* This is index 1 to cover BIOS interface register */ /* This is index 1 to cover BIOS interface register */
...@@ -818,42 +824,38 @@ static int ipc_plat_get_res(struct platform_device *pdev) ...@@ -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"); dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
return -ENXIO; return -ENXIO;
} }
*++punit_res = *res; punit_res[ipcdev.punit_res_count++] = *res;
dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res); dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
/* This is index 2 to cover ISP data register, optional */ /* This is index 2 to cover ISP data register, optional */
res = platform_get_resource(pdev, IORESOURCE_MEM, res = platform_get_resource(pdev, IORESOURCE_MEM,
PLAT_RESOURCE_ISP_DATA_INDEX); PLAT_RESOURCE_ISP_DATA_INDEX);
++punit_res;
if (res) { if (res) {
*punit_res = *res; punit_res[ipcdev.punit_res_count++] = *res;
dev_info(&pdev->dev, "punit ISP data res: %pR\n", res); dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
} }
/* This is index 3 to cover ISP interface register, optional */ /* This is index 3 to cover ISP interface register, optional */
res = platform_get_resource(pdev, IORESOURCE_MEM, res = platform_get_resource(pdev, IORESOURCE_MEM,
PLAT_RESOURCE_ISP_IFACE_INDEX); PLAT_RESOURCE_ISP_IFACE_INDEX);
++punit_res;
if (res) { if (res) {
*punit_res = *res; punit_res[ipcdev.punit_res_count++] = *res;
dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res); dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
} }
/* This is index 4 to cover GTD data register, optional */ /* This is index 4 to cover GTD data register, optional */
res = platform_get_resource(pdev, IORESOURCE_MEM, res = platform_get_resource(pdev, IORESOURCE_MEM,
PLAT_RESOURCE_GTD_DATA_INDEX); PLAT_RESOURCE_GTD_DATA_INDEX);
++punit_res;
if (res) { if (res) {
*punit_res = *res; punit_res[ipcdev.punit_res_count++] = *res;
dev_info(&pdev->dev, "punit GTD data res: %pR\n", res); dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
} }
/* This is index 5 to cover GTD interface register, optional */ /* This is index 5 to cover GTD interface register, optional */
res = platform_get_resource(pdev, IORESOURCE_MEM, res = platform_get_resource(pdev, IORESOURCE_MEM,
PLAT_RESOURCE_GTD_IFACE_INDEX); PLAT_RESOURCE_GTD_IFACE_INDEX);
++punit_res;
if (res) { if (res) {
*punit_res = *res; punit_res[ipcdev.punit_res_count++] = *res;
dev_info(&pdev->dev, "punit GTD interface res: %pR\n", 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) ...@@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
* - GTDRIVER_IPC BASE_IFACE * - GTDRIVER_IPC BASE_IFACE
*/ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 2); res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (res && resource_size(res) > 1) { if (res) {
addr = devm_ioremap_resource(&pdev->dev, res); addr = devm_ioremap_resource(&pdev->dev, res);
if (!IS_ERR(addr)) if (!IS_ERR(addr))
punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr; punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 3); res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
if (res && resource_size(res) > 1) { if (res) {
addr = devm_ioremap_resource(&pdev->dev, res); addr = devm_ioremap_resource(&pdev->dev, res);
if (!IS_ERR(addr)) if (!IS_ERR(addr))
punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr; punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 4); res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
if (res && resource_size(res) > 1) { if (res) {
addr = devm_ioremap_resource(&pdev->dev, res); addr = devm_ioremap_resource(&pdev->dev, res);
if (!IS_ERR(addr)) if (!IS_ERR(addr))
punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr; punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 5); res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
if (res && resource_size(res) > 1) { if (res) {
addr = devm_ioremap_resource(&pdev->dev, res); addr = devm_ioremap_resource(&pdev->dev, res);
if (!IS_ERR(addr)) if (!IS_ERR(addr))
punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr; punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
......
This diff is collapsed.
...@@ -4424,14 +4424,16 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) ...@@ -4424,14 +4424,16 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
} }
return AE_OK; return AE_OK;
} }
case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
default: default:
dprintk("Resource %d isn't an IRQ nor an IO port\n", dprintk("Resource %d isn't an IRQ nor an IO port\n",
resource->type); resource->type);
return AE_CTRL_TERMINATE;
case ACPI_RESOURCE_TYPE_END_TAG:
return AE_OK;
} }
return AE_CTRL_TERMINATE;
} }
static int sony_pic_possible_resources(struct acpi_device *device) static int sony_pic_possible_resources(struct acpi_device *device)
......
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/pci_ids.h> #include <linux/pci.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/control.h> #include <sound/control.h>
...@@ -4212,7 +4212,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) ...@@ -4212,7 +4212,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
known_ev = true; known_ev = true;
break; break;
} }
/* fallthrough to default */ /* fallthrough - to default */
default: default:
known_ev = false; known_ev = false;
} }
...@@ -4501,6 +4501,74 @@ static void bluetooth_exit(void) ...@@ -4501,6 +4501,74 @@ static void bluetooth_exit(void)
bluetooth_shutdown(); 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) static int __init bluetooth_init(struct ibm_init_struct *iibm)
{ {
int res; int res;
...@@ -4513,7 +4581,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) ...@@ -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, /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ 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"); acpi_evalf(hkey_handle, &status, "GBDC", "qd");
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL,
...@@ -5808,7 +5876,7 @@ static int led_set_status(const unsigned int led, ...@@ -5808,7 +5876,7 @@ static int led_set_status(const unsigned int led,
return -EPERM; return -EPERM;
if (!acpi_evalf(led_handle, NULL, NULL, "vdd", if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
(1 << led), led_sled_arg1[ledstatus])) (1 << led), led_sled_arg1[ledstatus]))
rc = -EIO; return -EIO;
break; break;
case TPACPI_LED_OLD: case TPACPI_LED_OLD:
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
...@@ -5832,10 +5900,10 @@ static int led_set_status(const unsigned int led, ...@@ -5832,10 +5900,10 @@ static int led_set_status(const unsigned int led,
return -EPERM; return -EPERM;
if (!acpi_evalf(led_handle, NULL, NULL, "vdd", if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
led, led_led_arg1[ledstatus])) led, led_led_arg1[ledstatus]))
rc = -EIO; return -EIO;
break; break;
default: default:
rc = -ENXIO; return -ENXIO;
} }
if (!rc) if (!rc)
...@@ -6249,8 +6317,8 @@ static int thermal_get_sensor(int idx, s32 *value) ...@@ -6249,8 +6317,8 @@ static int thermal_get_sensor(int idx, s32 *value)
t = TP_EC_THERMAL_TMP8; t = TP_EC_THERMAL_TMP8;
idx -= 8; idx -= 8;
} }
/* fallthrough */
#endif #endif
/* fallthrough */
case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_TPEC_8:
if (idx <= 7) { if (idx <= 7) {
if (!acpi_ec_read(t + idx, &tmp)) if (!acpi_ec_read(t + idx, &tmp))
...@@ -9890,6 +9958,37 @@ static char __init tpacpi_parse_fw_id(const char * const s, ...@@ -9890,6 +9958,37 @@ static char __init tpacpi_parse_fw_id(const char * const s,
return '\0'; 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. /* returns 0 - probe ok, or < 0 - probe error.
* Probe ok doesn't mean thinkpad found. * Probe ok doesn't mean thinkpad found.
* On error, kfree() cleanup on tp->* is not performed, caller must do it */ * 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( ...@@ -9897,7 +9996,7 @@ static int __must_check __init get_thinkpad_model_data(
struct thinkpad_id_data *tp) struct thinkpad_id_data *tp)
{ {
const struct dmi_device *dev = NULL; const struct dmi_device *dev = NULL;
char ec_fw_string[18]; char ec_fw_string[18] = {0};
char const *s; char const *s;
char t; char t;
...@@ -9937,20 +10036,25 @@ static int __must_check __init get_thinkpad_model_data( ...@@ -9937,20 +10036,25 @@ static int __must_check __init get_thinkpad_model_data(
ec_fw_string) == 1) { ec_fw_string) == 1) {
ec_fw_string[sizeof(ec_fw_string) - 1] = 0; ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
break;
}
}
tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); /* Newer ThinkPads have different EC program info table */
if (!tp->ec_version_str) if (!ec_fw_string[0])
return -ENOMEM; dmi_walk(find_new_ec_fwstr, &ec_fw_string);
t = tpacpi_parse_fw_id(ec_fw_string, if (ec_fw_string[0]) {
&tp->ec_model, &tp->ec_release); tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
if (t != 'H') { if (!tp->ec_version_str)
pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n", return -ENOMEM;
ec_fw_string);
pr_notice("please report this to %s\n", t = tpacpi_parse_fw_id(ec_fw_string,
TPACPI_MAIL); &tp->ec_model, &tp->ec_release);
} if (t != 'H') {
break; 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);
} }
} }
...@@ -10165,7 +10269,7 @@ MODULE_PARM_DESC(volume_mode, ...@@ -10165,7 +10269,7 @@ MODULE_PARM_DESC(volume_mode,
module_param_named(volume_capabilities, volume_capabilities, uint, 0444); module_param_named(volume_capabilities, volume_capabilities, uint, 0444);
MODULE_PARM_DESC(volume_capabilities, 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_param_named(volume_control, volume_control_allowed, bool, 0444);
MODULE_PARM_DESC(volume_control, MODULE_PARM_DESC(volume_control,
......
...@@ -249,6 +249,21 @@ static const struct ts_dmi_data jumper_ezpad_6_pro_data = { ...@@ -249,6 +249,21 @@ static const struct ts_dmi_data jumper_ezpad_6_pro_data = {
.properties = jumper_ezpad_6_pro_props, .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[] = { static const struct property_entry jumper_ezpad_mini3_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-x", 23), PROPERTY_ENTRY_U32("touchscreen-min-x", 23),
PROPERTY_ENTRY_U32("touchscreen-min-y", 16), PROPERTY_ENTRY_U32("touchscreen-min-y", 16),
...@@ -265,6 +280,23 @@ static const struct ts_dmi_data jumper_ezpad_mini3_data = { ...@@ -265,6 +280,23 @@ static const struct ts_dmi_data jumper_ezpad_mini3_data = {
.properties = jumper_ezpad_mini3_props, .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[] = { static const struct property_entry onda_obook_20_plus_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
...@@ -673,6 +705,17 @@ static const struct dmi_system_id touchscreen_dmi_table[] = { ...@@ -673,6 +705,17 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"), 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 */ /* Jumper EZpad mini3 */
.driver_data = (void *)&jumper_ezpad_mini3_data, .driver_data = (void *)&jumper_ezpad_mini3_data,
...@@ -690,6 +733,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = { ...@@ -690,6 +733,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"), 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 */ /* Onda oBook 20 Plus */
.driver_data = (void *)&onda_obook_20_plus_data, .driver_data = (void *)&onda_obook_20_plus_data,
......
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
/* Input */ /* Input */
#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
#define ASUS_WMI_DEVID_FNLOCK 0x00100023
/* Fan, Thermal */ /* Fan, Thermal */
#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
......
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