platform-drivers-x86 for v5.2-1

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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEqaflIX74DDDzMJJtb7wzTHR8rCgFAlzVl80ACgkQb7wzTHR8
 rCjhGQ/8CqTADSP1VDKUQqlJ0uqGTZbxcxNHxR3bGA/g7mGCjpQ6jbW3yWK8f2cO
 YJZl8j3PriaJwsO2JzhgVnVhyaL505nwSA2TCEgD7RciuQCvx8GKZemPmbd0FwUf
 /28McB5zpcvCWoZWaS4kdMCNKVSpY08VKekuchO6ofaqiikq2JgxKtXwsoRhx5hm
 AAX8e8+A18CJj7xpj3IdiVEujfbZy9Gjpakj3L9lOPsYwA4DLPoJ3YvjkmHmsZwd
 KsDcd8Er8oxa1LVg1fTnBMe7R3iDkiuNGiYOZpRqdGLynZw/NS5VSCCj+zcQZ4Ia
 W7mmksce8DGnSmgwVBOJd/Uo+qdcBmqCe6zkuePLeR5k0zu3yHzsFXcEfQiONm08
 FtGUc3WOqyl4I4X4gcIOFRDWW6XTjVTENVc4kuX9BCFDyGiYr7z1YQzf2GNB8x1m
 FLfSC7cWZeHzSatWbIDd6l2TU7CptusRfsZdVBNaKwLHKgf2A5rogngOYCZud5oY
 yVxoeajFskXU0LgHRQU88t/jw+RehYKNZ6r8CRHp+toWotVcu6ZGEnDEpa0acSWL
 upyV1/tTexo7jsghNEwrSqa14l7K/3RC+1l8pjQCVV+ltUzkDqLQZoEovtmv9CEE
 b5TKAfoqlc3a6YEtJuvMfHwsq8x2rEQ3XiB+HogDljnnzN0Ojzc=
 =5b//
 -----END PGP SIGNATURE-----

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:
Linus Torvalds 2019-05-10 13:03:47 -04:00
commit 7817ffd20a
21 changed files with 2149 additions and 383 deletions

View File

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

View File

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

View 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__) */

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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)))

View File

@ -18,6 +18,8 @@
#include <linux/rfkill.h>
#include <linux/input.h>
#include "dell-rbtn.h"
enum rbtn_type {
RBTN_UNKNOWN,
RBTN_TOGGLE,

View File

@ -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)

View 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");

View File

@ -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");

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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,

View File

@ -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,

View File

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