Commit cbd7b8a7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v4.16-1' of git://git.infradead.org/linux-platform-drivers-x86

Pull x86 platform-driver updates from Darren Hart:
 "New model support added for Dell, Ideapad, Acer, Asus, Thinkpad, and
  GPD laptops. Improvements to the common intel-vbtn driver, including
  tablet mode, rotate, and front button support. Intel CPU support added
  for Cannonlake and platform support for Dollar Cove power button.

  Overhaul of the mellanox platform driver, creating a new
  platform/mellanox directory for the newly multi-architecture regmap
  interface.

  Significant Intel PMC update with CannonLake support, Coffeelake
  update, CPUID enumeration, module support, new read64 API, refactoring
  and cleanups.

  Revert the apple-gmux iGP IO lock, addressing reported issues with
  non-binary drivers, leaving Nvidia binary driver users to comment out
  conflicting code.

  Miscellaneous fixes and cleanups"

* tag 'platform-drivers-x86-v4.16-1' of git://git.infradead.org/linux-platform-drivers-x86: (81 commits)
  platform/x86: mlx-platform: Fix an ERR_PTR vs NULL issue
  platform/x86: intel_pmc_core: Special case for Coffeelake
  platform/x86: intel_pmc_core: Add CannonLake PCH support
  x86/cpu: Add Cannonlake to Intel family
  platform/x86: intel_pmc_core: Read base address from LPIT
  ACPI / LPIT: Export lpit_read_residency_count_address()
  platform/x86: intel-vbtn: Replace License by SDPX identifier
  platform/x86: intel-vbtn: Remove redundant inclusions
  platform/x86: intel-vbtn: Support tablet mode switch
  platform/x86: dell-laptop: Allocate buffer on heap rather than globally
  platform/x86: intel_pmc_core: Remove unused header file
  platform/x86: mlx-platform: Add hotplug device unregister to error path
  platform/x86: mlx-platform: fix module aliases
  platform/mellanox: mlxreg-hotplug: Add check for negative adapter number
  platform/x86: mlx-platform: Add IO access verification callbacks
  platform/x86: mlx-platform: Document pdev_hotplug field
  platform/x86: mlx-platform: Allow compilation for 32 bit arch
  platform/mellanox: mlxreg-hotplug: Enable building for ARM
  platform/mellanox: mlxreg-hotplug: Modify to use a regmap interface
  platform/mellanox: Group create/destroy with attribute functions
  ...
parents 3f551e3c 8a0f5b6f
......@@ -3,7 +3,7 @@ Date: January 1, 2010
KernelVersion: 2.6.33
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Description: Some Samsung laptops have different "performance levels"
that are can be modified by a function key, and by this
that can be modified by a function key, and by this
sysfs file. These values don't always make a whole lot
of sense, but some users like to modify them to keep
their fans quiet at all costs. Reading from this file
......
......@@ -6001,6 +6001,12 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/goodix.c
GPD POCKET FAN DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/gpd-pocket-fan.c
GPIO ACPI SUPPORT
M: Mika Westerberg <mika.westerberg@linux.intel.com>
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
......@@ -8939,12 +8945,13 @@ W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/mellanox/mlxfw/
MELLANOX MLX CPLD HOTPLUG DRIVER
MELLANOX HARDWARE PLATFORM SUPPORT
M: Andy Shevchenko <andy@infradead.org>
M: Darren Hart <dvhart@infradead.org>
M: Vadim Pasternak <vadimp@mellanox.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/mlxcpld-hotplug.c
F: include/linux/platform_data/mlxcpld-hotplug.h
F: drivers/platform/mellanox/
MELLANOX MLX4 core VPI driver
M: Tariq Toukan <tariqt@mellanox.com>
......@@ -15134,7 +15141,7 @@ X86 PLATFORM DRIVERS
M: Darren Hart <dvhart@infradead.org>
M: Andy Shevchenko <andy@infradead.org>
L: platform-driver-x86@vger.kernel.org
T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git
T: git git://git.infradead.org/linux-platform-drivers-x86.git
S: Maintained
F: drivers/platform/x86/
F: drivers/platform/olpc/
......
......@@ -10,6 +10,10 @@
*
* Things ending in "2" are usually because we have no better
* name for them. There's no processor called "SILVERMONT2".
*
* While adding a new CPUID for a new microarchitecture, add a new
* group to keep logically sorted out in chronological order. Within
* that group keep the CPUID for the variants sorted by model number.
*/
#define INTEL_FAM6_CORE_YONAH 0x0E
......@@ -49,6 +53,8 @@
#define INTEL_FAM6_KABYLAKE_MOBILE 0x8E
#define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E
#define INTEL_FAM6_CANNONLAKE_MOBILE 0x66
/* "Small Core" Processors (Atom) */
#define INTEL_FAM6_ATOM_PINEVIEW 0x1C
......
......@@ -38,6 +38,7 @@ int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
u32 *out, u32 outlen);
int intel_pmc_s0ix_counter_read(u64 *data);
int intel_pmc_gcr_read(u32 offset, u32 *data);
int intel_pmc_gcr_read64(u32 offset, u64 *data);
int intel_pmc_gcr_write(u32 offset, u32 data);
int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val);
......@@ -70,6 +71,11 @@ static inline int intel_pmc_gcr_read(u32 offset, u32 *data)
return -EINVAL;
}
static inline int intel_pmc_gcr_read64(u32 offset, u64 *data)
{
return -EINVAL;
}
static inline int intel_pmc_gcr_write(u32 offset, u32 data)
{
return -EINVAL;
......
/*
* Intel Core SoC Power Management Controller Header File
*
* Copyright (c) 2016, Intel Corporation.
* All Rights Reserved.
*
* Authors: Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com>
* Vishwanath Somayaji <vishwanath.somayaji@intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef _ASM_PMC_CORE_H
#define _ASM_PMC_CORE_H
/* API to read SLP_S0_RESIDENCY counter */
int intel_pmc_slp_s0_counter_read(u32 *data);
#endif /* _ASM_PMC_CORE_H */
......@@ -100,6 +100,7 @@ int lpit_read_residency_count_address(u64 *address)
return 0;
}
EXPORT_SYMBOL_GPL(lpit_read_residency_count_address);
static void lpit_update_residency(struct lpit_residency_info *info,
struct acpi_lpit_native *lpit_native)
......
......@@ -8,3 +8,5 @@ endif
source "drivers/platform/goldfish/Kconfig"
source "drivers/platform/chrome/Kconfig"
source "drivers/platform/mellanox/Kconfig"
......@@ -4,6 +4,7 @@
#
obj-$(CONFIG_X86) += x86/
obj-$(CONFIG_MELLANOX_PLATFORM) += mellanox/
obj-$(CONFIG_MIPS) += mips/
obj-$(CONFIG_OLPC) += olpc/
obj-$(CONFIG_GOLDFISH) += goldfish/
......
# SPDX-License-Identifier: GPL-2.0
#
# Platform support for Mellanox hardware
#
menuconfig MELLANOX_PLATFORM
bool "Platform support for Mellanox hardware"
depends on X86 || ARM || 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.
If you say N, all options in this submenu will be skipped and disabled.
if MELLANOX_PLATFORM
config MLXREG_HOTPLUG
tristate "Mellanox platform hotplug driver support"
depends on REGMAP
depends on HWMON
depends on I2C
---help---
This driver handles hot-plug events for the power suppliers, power
cables and fans on the wide range Mellanox IB and Ethernet systems.
endif # MELLANOX_PLATFORM
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for linux/drivers/platform/mellanox
# Mellanox Platform-Specific Drivers
#
obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
......@@ -36,6 +36,20 @@ config ACER_WMI
If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
here.
config ACER_WIRELESS
tristate "Acer Wireless Radio Control Driver"
depends on ACPI
depends on INPUT
---help---
The Acer Wireless Radio Control handles the airplane mode hotkey
present on new Acer laptops.
Say Y or M here if you have an Acer notebook with an airplane mode
hotkey.
If you choose to compile this driver as a module the module will be
called acer-wireless.
config ACERHDF
tristate "Acer Aspire One temperature and fan driver"
depends on ACPI && THERMAL
......@@ -244,6 +258,18 @@ config AMILO_RFKILL
This is a driver for enabling wifi on some Fujitsu-Siemens Amilo
laptops.
config GPD_POCKET_FAN
tristate "GPD Pocket Fan Controller support"
depends on ACPI
depends on THERMAL
---help---
Driver for the GPD Pocket vendor specific FAN02501 ACPI device
which controls the fan speed on the GPD Pocket.
Without this driver the fan on the Pocket will stay off independent
of the CPU temperature. Say Y or M if the kernel may be used on a
GPD pocket.
config TC1100_WMI
tristate "HP Compaq TC1100 Tablet WMI Extras"
depends on !X86_64
......@@ -812,9 +838,8 @@ config TOSHIBA_WMI
config ACPI_CMPC
tristate "CMPC Laptop Extras"
depends on ACPI
depends on ACPI && INPUT
depends on RFKILL || RFKILL=n
select INPUT
select BACKLIGHT_CLASS_DEVICE
help
Support for Intel Classmate PC ACPI devices, including some
......@@ -949,7 +974,7 @@ config INTEL_IMR
If you are running on a Galileo/Quark say Y here.
config INTEL_PMC_CORE
bool "Intel PMC Core driver"
tristate "Intel PMC Core driver"
depends on PCI
---help---
The Intel Platform Controller Hub for Intel Core SoCs provides access
......@@ -958,7 +983,10 @@ config INTEL_PMC_CORE
exposed by the Power Management Controller.
Supported features:
- SLP_S0_RESIDENCY counter.
- SLP_S0_RESIDENCY counter
- PCH IP Power Gating status
- LTR Ignore
- MPHY/PLL gating status (Sunrisepoint PCH only)
config IBM_RTL
tristate "Device driver to enable PRTL support"
......@@ -1131,7 +1159,6 @@ config INTEL_TELEMETRY
config MLX_PLATFORM
tristate "Mellanox Technologies platform support"
depends on X86_64
---help---
This option enables system support for the Mellanox Technologies
platform. The Mellanox systems provide data center networking
......@@ -1141,14 +1168,6 @@ config MLX_PLATFORM
If you have a Mellanox system, say Y or M here.
config MLX_CPLD_PLATFORM
tristate "Mellanox platform hotplug driver support"
select HWMON
select I2C
---help---
This driver handles hot-plug events for the power suppliers, power
cables and fans on the wide range Mellanox IB and Ethernet systems.
config INTEL_TURBO_MAX_3
bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
depends on X86_64 && SCHED_MC_PRIO
......@@ -1170,6 +1189,17 @@ config SILEAD_DMI
with the OS-image for the device. This option supplies the missing
information. Enable this for x86 tablets with Silead touchscreens.
config INTEL_CHTDC_TI_PWRBTN
tristate "Intel Cherry Trail Dollar Cove TI power button driver"
depends on INTEL_SOC_PMIC_CHTDC_TI
depends on INPUT
---help---
This option adds a power button driver driver for Dollar Cove TI
PMIC on Intel Cherry Trail devices.
To compile this driver as a module, choose M here: the module
will be called intel_chtdc_ti_pwrbtn.
endif # X86_PLATFORM_DEVICES
config PMC_ATOM
......
......@@ -23,11 +23,13 @@ obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ACER_WIRELESS) += acer-wireless.o
obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o
obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o
......@@ -86,5 +88,5 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o
obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
/*
* Acer Wireless Radio Control Driver
*
* Copyright (C) 2017 Endless Mobile, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/acpi.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci_ids.h>
#include <linux/types.h>
static const struct acpi_device_id acer_wireless_acpi_ids[] = {
{"10251229", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, acer_wireless_acpi_ids);
static void acer_wireless_notify(struct acpi_device *adev, u32 event)
{
struct input_dev *idev = acpi_driver_data(adev);
dev_dbg(&adev->dev, "event=%#x\n", event);
if (event != 0x80) {
dev_notice(&adev->dev, "Unknown SMKB event: %#x\n", event);
return;
}
input_report_key(idev, KEY_RFKILL, 1);
input_report_key(idev, KEY_RFKILL, 0);
input_sync(idev);
}
static int acer_wireless_add(struct acpi_device *adev)
{
struct input_dev *idev;
idev = devm_input_allocate_device(&adev->dev);
if (!idev)
return -ENOMEM;
adev->driver_data = idev;
idev->name = "Acer Wireless Radio Control";
idev->phys = "acer-wireless/input0";
idev->id.bustype = BUS_HOST;
idev->id.vendor = PCI_VENDOR_ID_AI;
idev->id.product = 0x1229;
set_bit(EV_KEY, idev->evbit);
set_bit(KEY_RFKILL, idev->keybit);
return input_register_device(idev);
}
static struct acpi_driver acer_wireless_driver = {
.name = "Acer Wireless Radio Control Driver",
.class = "hotkey",
.ids = acer_wireless_acpi_ids,
.ops = {
.add = acer_wireless_add,
.notify = acer_wireless_notify,
},
};
module_acpi_driver(acer_wireless_driver);
MODULE_DESCRIPTION("Acer Wireless Radio Control Driver");
MODULE_AUTHOR("Chris Chiu <chiu@gmail.com>");
MODULE_LICENSE("GPL v2");
......@@ -68,6 +68,14 @@ struct quirk_entry {
static struct quirk_entry *quirks;
static struct quirk_entry quirk_inspiron5675 = {
.num_zones = 2,
.hdmi_mux = 0,
.amplifier = 0,
.deepslp = 0,
};
static struct quirk_entry quirk_unknown = {
.num_zones = 2,
.hdmi_mux = 0,
......@@ -171,6 +179,15 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
},
.driver_data = &quirk_asm201,
},
{
.callback = dmi_matched,
.ident = "Dell Inc. Inspiron 5675",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"),
},
.driver_data = &quirk_inspiron5675,
},
{}
};
......
......@@ -24,7 +24,6 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/vga_switcheroo.h>
#include <linux/vgaarb.h>
#include <acpi/video.h>
#include <asm/io.h>
......@@ -54,7 +53,6 @@ struct apple_gmux_data {
bool indexed;
struct mutex index_lock;
struct pci_dev *pdev;
struct backlight_device *bdev;
/* switcheroo data */
......@@ -599,23 +597,6 @@ static int gmux_resume(struct device *dev)
return 0;
}
static struct pci_dev *gmux_get_io_pdev(void)
{
struct pci_dev *pdev = NULL;
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) {
u16 cmd;
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_IO))
continue;
return pdev;
}
return NULL;
}
static int is_thunderbolt(struct device *dev, void *data)
{
return to_pci_dev(dev)->is_thunderbolt;
......@@ -631,7 +612,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
int ret = -ENXIO;
acpi_status status;
unsigned long long gpe;
struct pci_dev *pdev = NULL;
if (apple_gmux_data)
return -EBUSY;
......@@ -682,7 +662,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
ver_minor = (version >> 16) & 0xff;
ver_release = (version >> 8) & 0xff;
} else {
pr_info("gmux device not present or IO disabled\n");
pr_info("gmux device not present\n");
ret = -ENODEV;
goto err_release;
}
......@@ -690,23 +670,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
ver_release, (gmux_data->indexed ? "indexed" : "classic"));
/*
* Apple systems with gmux are EFI based and normally don't use
* VGA. In addition changing IO+MEM ownership between IGP and dGPU
* disables IO/MEM used for backlight control on some systems.
* Lock IO+MEM to GPU with active IO to prevent switch.
*/
pdev = gmux_get_io_pdev();
if (pdev && vga_tryget(pdev,
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) {
pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n",
pci_name(pdev));
ret = -EBUSY;
goto err_release;
} else if (pdev)
pr_info("locked IO for PCI:%s\n", pci_name(pdev));
gmux_data->pdev = pdev;
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_PLATFORM;
props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
......@@ -822,10 +785,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
err_notify:
backlight_device_unregister(bdev);
err_release:
if (gmux_data->pdev)
vga_put(gmux_data->pdev,
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
pci_dev_put(pdev);
release_region(gmux_data->iostart, gmux_data->iolen);
err_free:
kfree(gmux_data);
......@@ -845,11 +804,6 @@ static void gmux_remove(struct pnp_dev *pnp)
&gmux_notify_handler);
}
if (gmux_data->pdev) {
vga_put(gmux_data->pdev,
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
pci_dev_put(gmux_data->pdev);
}
backlight_device_unregister(gmux_data->bdev);
release_region(gmux_data->iostart, gmux_data->iolen);
......
......@@ -111,7 +111,7 @@ static struct quirk_entry quirk_asus_x550lb = {
.xusb2pr = 0x01D9,
};
static struct quirk_entry quirk_asus_ux330uak = {
static struct quirk_entry quirk_asus_forceals = {
.wmi_force_als_set = true,
};
......@@ -387,7 +387,7 @@ static const struct dmi_system_id asus_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"),
},
.driver_data = &quirk_asus_ux330uak,
.driver_data = &quirk_asus_forceals,
},
{
.callback = dmi_matched,
......@@ -398,6 +398,15 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_x550lb,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. UX430UQ",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ"),
},
.driver_data = &quirk_asus_forceals,
},
{},
};
......
This diff is collapsed.
......@@ -65,10 +65,10 @@ static struct smbios_call call_whitelist[] = {
/* calls that are explicitly blacklisted */
static struct smbios_call call_blacklist[] = {
{0x0000, 01, 07}, /* manufacturing use */
{0x0000, 06, 05}, /* manufacturing use */
{0x0000, 11, 03}, /* write once */
{0x0000, 11, 07}, /* write once */
{0x0000, 1, 7}, /* manufacturing use */
{0x0000, 6, 5}, /* manufacturing use */
{0x0000, 11, 3}, /* write once */
{0x0000, 11, 7}, /* write once */
{0x0000, 11, 11}, /* write once */
{0x0000, 19, -1}, /* diagnostics */
/* handled by kernel: dell-laptop */
......
......@@ -261,6 +261,9 @@ static const u16 bios_to_linux_keycode[256] = {
* override them.
*/
static const struct key_entry dell_wmi_keymap_type_0010[] = {
/* Mic mute */
{ KE_KEY, 0x150, { KEY_MICMUTE } },
/* Fn-lock */
{ KE_IGNORE, 0x151, { KEY_RESERVED } },
......
// SPDX-License-Identifier: GPL-2.0+
/*
* GPD Pocket fan controller driver
*
* Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/thermal.h>
#include <linux/workqueue.h>
#define MAX_SPEED 3
static int temp_limits[3] = { 55000, 60000, 65000 };
module_param_array(temp_limits, int, NULL, 0444);
MODULE_PARM_DESC(temp_limits,
"Milli-celcius values above which the fan speed increases");
static int hysteresis = 3000;
module_param(hysteresis, int, 0444);
MODULE_PARM_DESC(hysteresis,
"Hysteresis in milli-celcius before lowering the fan speed");
static int speed_on_ac = 2;
module_param(speed_on_ac, int, 0444);
MODULE_PARM_DESC(speed_on_ac,
"minimum fan speed to allow when system is powered by AC");
struct gpd_pocket_fan_data {
struct device *dev;
struct thermal_zone_device *dts0;
struct thermal_zone_device *dts1;
struct gpio_desc *gpio0;
struct gpio_desc *gpio1;
struct delayed_work work;
int last_speed;
};
static void gpd_pocket_fan_set_speed(struct gpd_pocket_fan_data *fan, int speed)
{
if (speed == fan->last_speed)
return;
gpiod_direction_output(fan->gpio0, !!(speed & 1));
gpiod_direction_output(fan->gpio1, !!(speed & 2));
fan->last_speed = speed;
}
static int gpd_pocket_fan_min_speed(void)
{
if (power_supply_is_system_supplied())
return speed_on_ac;
else
return 0;
}
static void gpd_pocket_fan_worker(struct work_struct *work)
{
struct gpd_pocket_fan_data *fan =
container_of(work, struct gpd_pocket_fan_data, work.work);
int t0, t1, temp, speed, min_speed, i;
if (thermal_zone_get_temp(fan->dts0, &t0) ||
thermal_zone_get_temp(fan->dts1, &t1)) {
dev_warn(fan->dev, "Error getting temperature\n");
speed = MAX_SPEED;
goto set_speed;
}
temp = max(t0, t1);
speed = fan->last_speed;
min_speed = gpd_pocket_fan_min_speed();
/* Determine minimum speed */
for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) {
if (temp < temp_limits[i])
break;
}
if (speed < i)
speed = i;
/* Use hysteresis before lowering speed again */
for (i = min_speed; i < ARRAY_SIZE(temp_limits); i++) {
if (temp <= (temp_limits[i] - hysteresis))
break;
}
if (speed > i)
speed = i;
if (fan->last_speed <= 0 && speed)
speed = MAX_SPEED; /* kick start motor */
set_speed:
gpd_pocket_fan_set_speed(fan, speed);
/* When mostly idle (low temp/speed), slow down the poll interval. */
queue_delayed_work(system_wq, &fan->work,
msecs_to_jiffies(4000 / (speed + 1)));
}
static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data *fan)
{
fan->last_speed = -1;
mod_delayed_work(system_wq, &fan->work, 0);
}
static int gpd_pocket_fan_probe(struct platform_device *pdev)
{
struct gpd_pocket_fan_data *fan;
int i;
for (i = 0; i < ARRAY_SIZE(temp_limits); i++) {
if (temp_limits[i] < 40000 || temp_limits[i] > 70000) {
dev_err(&pdev->dev, "Invalid temp-limit %d (must be between 40000 and 70000)\n",
temp_limits[i]);
return -EINVAL;
}
}
if (hysteresis < 1000 || hysteresis > 10000) {
dev_err(&pdev->dev, "Invalid hysteresis %d (must be between 1000 and 10000)\n",
hysteresis);
return -EINVAL;
}
if (speed_on_ac < 0 || speed_on_ac > MAX_SPEED) {
dev_err(&pdev->dev, "Invalid speed_on_ac %d (must be between 0 and 3)\n",
speed_on_ac);
return -EINVAL;
}
fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
if (!fan)
return -ENOMEM;
fan->dev = &pdev->dev;
INIT_DELAYED_WORK(&fan->work, gpd_pocket_fan_worker);
/* Note this returns a "weak" reference which we don't need to free */
fan->dts0 = thermal_zone_get_zone_by_name("soc_dts0");
if (IS_ERR(fan->dts0))
return -EPROBE_DEFER;
fan->dts1 = thermal_zone_get_zone_by_name("soc_dts1");
if (IS_ERR(fan->dts1))
return -EPROBE_DEFER;
fan->gpio0 = devm_gpiod_get_index(fan->dev, NULL, 0, GPIOD_ASIS);
if (IS_ERR(fan->gpio0))
return PTR_ERR(fan->gpio0);
fan->gpio1 = devm_gpiod_get_index(fan->dev, NULL, 1, GPIOD_ASIS);
if (IS_ERR(fan->gpio1))
return PTR_ERR(fan->gpio1);
gpd_pocket_fan_force_update(fan);
platform_set_drvdata(pdev, fan);
return 0;
}
static int gpd_pocket_fan_remove(struct platform_device *pdev)
{
struct gpd_pocket_fan_data *fan = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&fan->work);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int gpd_pocket_fan_suspend(struct device *dev)
{
struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev);
cancel_delayed_work_sync(&fan->work);
gpd_pocket_fan_set_speed(fan, gpd_pocket_fan_min_speed());
return 0;
}
static int gpd_pocket_fan_resume(struct device *dev)
{
struct gpd_pocket_fan_data *fan = dev_get_drvdata(dev);
gpd_pocket_fan_force_update(fan);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(gpd_pocket_fan_pm_ops,
gpd_pocket_fan_suspend,
gpd_pocket_fan_resume);
static struct acpi_device_id gpd_pocket_fan_acpi_match[] = {
{ "FAN02501" },
{},
};
MODULE_DEVICE_TABLE(acpi, gpd_pocket_fan_acpi_match);
static struct platform_driver gpd_pocket_fan_driver = {
.probe = gpd_pocket_fan_probe,
.remove = gpd_pocket_fan_remove,
.driver = {
.name = "gpd_pocket_fan",
.acpi_match_table = gpd_pocket_fan_acpi_match,
.pm = &gpd_pocket_fan_pm_ops,
},
};
module_platform_driver(gpd_pocket_fan_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
MODULE_DESCRIPTION("GPD pocket fan driver");
MODULE_LICENSE("GPL");
......@@ -124,10 +124,10 @@ static int read_method_int(acpi_handle handle, const char *method, int *val)
if (ACPI_FAILURE(status)) {
*val = -1;
return -1;
} else {
}
*val = result;
return 0;
}
}
static int method_gbmd(acpi_handle handle, unsigned long *ret)
......@@ -164,10 +164,10 @@ static int method_vpcr(acpi_handle handle, int cmd, int *ret)
if (ACPI_FAILURE(status)) {
*ret = -1;
return -1;
} else {
}
*ret = result;
return 0;
}
}
static int method_vpcw(acpi_handle handle, int cmd, int data)
......@@ -231,7 +231,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
if (val == 0)
return 0;
}
pr_err("timeout in write_ec_cmd\n");
pr_err("timeout in %s\n", __func__);
return -1;
}
......@@ -963,6 +963,13 @@ static void ideapad_wmi_notify(u32 value, void *context)
* report all radios as hardware-blocked.
*/
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_BOARD_NAME, "80WW"),
},
},
{
.ident = "Lenovo G40-30",
.matches = {
......@@ -1103,6 +1110,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"),
},
},
{
.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 = {
......
......@@ -25,6 +25,7 @@
#include <linux/acpi.h>
#include <linux/suspend.h>
#include <acpi/acpi_bus.h>
#include <linux/dmi.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex Hung");
......@@ -73,6 +74,24 @@ static const struct key_entry intel_array_keymap[] = {
{ KE_END },
};
static const struct dmi_system_id button_array_table[] = {
{
.ident = "Wacom MobileStudio Pro 13",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 13"),
},
},
{
.ident = "Wacom MobileStudio Pro 16",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Wacom Co.,Ltd"),
DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 16"),
},
},
{ }
};
struct intel_hid_priv {
struct input_dev *input_dev;
struct input_dev *array;
......@@ -263,10 +282,27 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
ev_index);
}
static bool button_array_present(struct platform_device *device)
{
acpi_handle handle = ACPI_HANDLE(&device->dev);
unsigned long long event_cap;
acpi_status status;
bool supported = false;
status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap);
if (ACPI_SUCCESS(status) && (event_cap & 0x20000))
supported = true;
if (dmi_check_system(button_array_table))
supported = true;
return supported;
}
static int intel_hid_probe(struct platform_device *device)
{
acpi_handle handle = ACPI_HANDLE(&device->dev);
unsigned long long event_cap, mode;
unsigned long long mode;
struct intel_hid_priv *priv;
acpi_status status;
int err;
......@@ -299,8 +335,7 @@ static int intel_hid_probe(struct platform_device *device)
}
/* Setup 5 button array */
status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap);
if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) {
if (button_array_present(device)) {
dev_info(&device->dev, "platform supports 5 button array\n");
err = intel_button_array_input_setup(device);
if (err)
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Intel Virtual Button driver for Windows 8.1+
*
* Copyright (C) 2016 AceLan Kao <acelan.kao@canonical.com>
* Copyright (C) 2016 Alex Hung <alex.hung@canonical.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/acpi.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/input/sparse-keymap.h>
#include <linux/acpi.h>
#include <linux/suspend.h>
#include <acpi/acpi_bus.h>
/* When NOT in tablet mode, VGBS returns with the flag 0x40 */
#define TABLET_MODE_FLAG 0x40
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AceLan Kao");
......@@ -38,10 +29,16 @@ static const struct acpi_device_id intel_vbtn_ids[] = {
static const struct key_entry intel_vbtn_keymap[] = {
{ KE_KEY, 0xC0, { KEY_POWER } }, /* power key press */
{ KE_IGNORE, 0xC1, { KEY_POWER } }, /* power key release */
{ KE_KEY, 0xC2, { KEY_LEFTMETA } }, /* 'Windows' key press */
{ KE_KEY, 0xC3, { KEY_LEFTMETA } }, /* 'Windows' key release */
{ KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */
{ KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */
{ KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */
{ KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */
{ KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key press */
{ KE_KEY, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key release */
{ KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */
{ KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */
{ KE_END },
};
......@@ -74,20 +71,35 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
{
struct platform_device *device = context;
struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
unsigned int val = !(event & 1); /* Even=press, Odd=release */
const struct key_entry *ke_rel;
bool autorelease;
if (priv->wakeup_mode) {
if (sparse_keymap_entry_from_scancode(priv->input_dev, event)) {
pm_wakeup_hard_event(&device->dev);
return;
}
} else if (sparse_keymap_report_event(priv->input_dev, event, 1, true)) {
return;
goto out_unknown;
}
/*
* Even press events are autorelease if there is no corresponding odd
* release event, or if the odd event is KE_IGNORE.
*/
ke_rel = sparse_keymap_entry_from_scancode(priv->input_dev, event | 1);
autorelease = val && (!ke_rel || ke_rel->type == KE_IGNORE);
if (sparse_keymap_report_event(priv->input_dev, event, val, autorelease))
return;
out_unknown:
dev_dbg(&device->dev, "unknown event index 0x%x\n", event);
}
static int intel_vbtn_probe(struct platform_device *device)
{
struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_handle handle = ACPI_HANDLE(&device->dev);
struct intel_vbtn_priv *priv;
acpi_status status;
......@@ -110,6 +122,23 @@ static int intel_vbtn_probe(struct platform_device *device)
return err;
}
/*
* VGBS being present and returning something means we have
* a tablet mode switch.
*/
status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output);
if (ACPI_SUCCESS(status)) {
union acpi_object *obj = vgbs_output.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER) {
int m = !(obj->integer.value & TABLET_MODE_FLAG);
input_report_switch(priv->input_dev, SW_TABLET_MODE, m);
}
}
kfree(vgbs_output.pointer);
status = acpi_install_notify_handler(handle,
ACPI_DEVICE_NOTIFY,
notify_handler,
......
/*
* Power-button driver for Dollar Cove TI PMIC
* Copyright (C) 2014 Intel Corp
* Copyright (c) 2017 Takashi Iwai <tiwai@suse.de>
*/
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/slab.h>
#define CHTDC_TI_SIRQ_REG 0x3
#define SIRQ_PWRBTN_REL BIT(0)
static irqreturn_t chtdc_ti_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);
int state;
if (!regmap_read(regmap, CHTDC_TI_SIRQ_REG, &state)) {
dev_dbg(dev, "SIRQ_REG=0x%x\n", state);
input_report_key(input, KEY_POWER, !(state & SIRQ_PWRBTN_REL));
input_sync(input);
}
return IRQ_HANDLED;
}
static int chtdc_ti_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, err;
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_set_capability(input, EV_KEY, KEY_POWER);
err = input_register_device(input);
if (err)
return err;
dev_set_drvdata(dev, pmic->regmap);
err = devm_request_threaded_irq(dev, irq, NULL,
chtdc_ti_pwrbtn_interrupt,
0, KBUILD_MODNAME, input);
if (err)
return err;
device_init_wakeup(dev, true);
dev_pm_set_wake_irq(dev, irq);
return 0;
}
static int chtdc_ti_pwrbtn_remove(struct platform_device *pdev)
{
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
return 0;
}
static const struct platform_device_id chtdc_ti_pwrbtn_id_table[] = {
{ .name = "chtdc_ti_pwrbtn" },
{},
};
MODULE_DEVICE_TABLE(platform, chtdc_ti_pwrbtn_id_table);
static struct platform_driver chtdc_ti_pwrbtn_driver = {
.driver = {
.name = KBUILD_MODNAME,
},
.probe = chtdc_ti_pwrbtn_probe,
.remove = chtdc_ti_pwrbtn_remove,
.id_table = chtdc_ti_pwrbtn_id_table,
};
module_platform_driver(chtdc_ti_pwrbtn_driver);
MODULE_DESCRIPTION("Power-button driver for Dollar Cove TI PMIC");
MODULE_LICENSE("GPL v2");
......@@ -180,7 +180,7 @@ static int int0002_probe(struct platform_device *pdev)
* to gpiochip_set_chained_irqchip, because the irq is shared.
*/
ret = devm_request_irq(dev, irq, int0002_irq,
IRQF_SHARED | IRQF_NO_THREAD, "INT0002", chip);
IRQF_SHARED, "INT0002", chip);
if (ret) {
dev_err(dev, "Error requesting IRQ %d: %d\n", irq, ret);
return ret;
......
......@@ -18,20 +18,24 @@
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/uaccess.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/pmc_core.h>
#include "intel_pmc_core.h"
#define ICPU(model, data) \
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (kernel_ulong_t)data }
static struct pmc_dev pmc;
static const struct pmc_bit_map spt_pll_map[] = {
......@@ -119,10 +123,88 @@ static const struct pmc_reg_map spt_reg_map = {
.pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT,
};
static const struct pci_device_id pmc_pci_ids[] = {
{ PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID),
(kernel_ulong_t)&spt_reg_map },
{ 0, },
/* Cannonlake: PGD PFET Enable Ack Status Register(s) bitmap */
static const struct pmc_bit_map cnp_pfear_map[] = {
{"PMC", BIT(0)},
{"OPI-DMI", BIT(1)},
{"SPI/eSPI", BIT(2)},
{"XHCI", BIT(3)},
{"SPA", BIT(4)},
{"SPB", BIT(5)},
{"SPC", BIT(6)},
{"GBE", BIT(7)},
{"SATA", BIT(0)},
{"HDA_PGD0", BIT(1)},
{"HDA_PGD1", BIT(2)},
{"HDA_PGD2", BIT(3)},
{"HDA_PGD3", BIT(4)},
{"SPD", BIT(5)},
{"LPSS", BIT(6)},
{"LPC", BIT(7)},
{"SMB", BIT(0)},
{"ISH", BIT(1)},
{"P2SB", BIT(2)},
{"NPK_VNN", BIT(3)},
{"SDX", BIT(4)},
{"SPE", BIT(5)},
{"Fuse", BIT(6)},
{"Res_23", BIT(7)},
{"CSME_FSC", BIT(0)},
{"USB3_OTG", BIT(1)},
{"EXI", BIT(2)},
{"CSE", BIT(3)},
{"csme_kvm", BIT(4)},
{"csme_pmt", BIT(5)},
{"csme_clink", BIT(6)},
{"csme_ptio", BIT(7)},
{"csme_usbr", BIT(0)},
{"csme_susram", BIT(1)},
{"csme_smt1", BIT(2)},
{"CSME_SMT4", BIT(3)},
{"csme_sms2", BIT(4)},
{"csme_sms1", BIT(5)},
{"csme_rtc", BIT(6)},
{"csme_psf", BIT(7)},
{"SBR0", BIT(0)},
{"SBR1", BIT(1)},
{"SBR2", BIT(2)},
{"SBR3", BIT(3)},
{"SBR4", BIT(4)},
{"SBR5", BIT(5)},
{"CSME_PECI", BIT(6)},
{"PSF1", BIT(7)},
{"PSF2", BIT(0)},
{"PSF3", BIT(1)},
{"PSF4", BIT(2)},
{"CNVI", BIT(3)},
{"UFS0", BIT(4)},
{"EMMC", BIT(5)},
{"Res_6", BIT(6)},
{"SBR6", BIT(7)},
{"SBR7", BIT(0)},
{"NPK_AON", BIT(1)},
{"HDA_PGD4", BIT(2)},
{"HDA_PGD5", BIT(3)},
{"HDA_PGD6", BIT(4)},
{}
};
static const struct pmc_reg_map cnp_reg_map = {
.pfear_sts = cnp_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
.ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
.regmap_length = CNP_PMC_MMIO_REG_LEN,
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
.ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
};
static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset)
......@@ -146,37 +228,6 @@ static inline u32 pmc_core_adjust_slp_s0_step(u32 value)
return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP;
}
/**
* intel_pmc_slp_s0_counter_read() - Read SLP_S0 residency.
* @data: Out param that contains current SLP_S0 count.
*
* This API currently supports Intel Skylake SoC and Sunrise
* Point Platform Controller Hub. Future platform support
* should be added for platforms that support low power modes
* beyond Package C10 state.
*
* SLP_S0_RESIDENCY counter counts in 100 us granularity per
* step hence function populates the multiplied value in out
* parameter @data.
*
* Return: an error code or 0 on success.
*/
int intel_pmc_slp_s0_counter_read(u32 *data)
{
struct pmc_dev *pmcdev = &pmc;
const struct pmc_reg_map *map = pmcdev->map;
u32 value;
if (!pmcdev->has_slp_s0_res)
return -EACCES;
value = pmc_core_reg_read(pmcdev, map->slp_s0_offset);
*data = pmc_core_adjust_slp_s0_step(value);
return 0;
}
EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read);
static int pmc_core_dev_state_get(void *data, u64 *val)
{
struct pmc_dev *pmcdev = data;
......@@ -437,47 +488,33 @@ static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
{
struct dentry *dir, *file;
struct dentry *dir;
dir = debugfs_create_dir("pmc_core", NULL);
if (!dir)
return -ENOMEM;
pmcdev->dbgfs_dir = dir;
file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO,
dir, pmcdev, &pmc_core_dev_state);
if (!file)
goto err;
file = debugfs_create_file("pch_ip_power_gating_status",
S_IFREG | S_IRUGO, dir, pmcdev,
debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev,
&pmc_core_dev_state);
debugfs_create_file("pch_ip_power_gating_status", 0444, dir, pmcdev,
&pmc_core_ppfear_ops);
if (!file)
goto err;
file = debugfs_create_file("mphy_core_lanes_power_gating_status",
S_IFREG | S_IRUGO, dir, pmcdev,
&pmc_core_mphy_pg_ops);
if (!file)
goto err;
debugfs_create_file("ltr_ignore", 0644, dir, pmcdev,
&pmc_core_ltr_ignore_ops);
file = debugfs_create_file("pll_status",
S_IFREG | S_IRUGO, dir, pmcdev,
if (pmcdev->map->pll_sts)
debugfs_create_file("pll_status", 0444, dir, pmcdev,
&pmc_core_pll_ops);
if (!file)
goto err;
file = debugfs_create_file("ltr_ignore",
S_IFREG | S_IRUGO, dir, pmcdev,
&pmc_core_ltr_ignore_ops);
if (!file)
goto err;
if (pmcdev->map->mphy_sts)
debugfs_create_file("mphy_core_lanes_power_gating_status",
0444, dir, pmcdev,
&pmc_core_mphy_pg_ops);
return 0;
err:
pmc_core_dbgfs_unregister(pmcdev);
return -ENODEV;
}
#else
static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
......@@ -491,71 +528,76 @@ static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
#endif /* CONFIG_DEBUG_FS */
static const struct x86_cpu_id intel_pmc_core_ids[] = {
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT,
(kernel_ulong_t)NULL},
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT,
(kernel_ulong_t)NULL},
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_MOBILE, X86_FEATURE_MWAIT,
(kernel_ulong_t)NULL},
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_DESKTOP, X86_FEATURE_MWAIT,
(kernel_ulong_t)NULL},
ICPU(INTEL_FAM6_SKYLAKE_MOBILE, &spt_reg_map),
ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, &spt_reg_map),
ICPU(INTEL_FAM6_KABYLAKE_MOBILE, &spt_reg_map),
ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, &spt_reg_map),
ICPU(INTEL_FAM6_CANNONLAKE_MOBILE, &cnp_reg_map),
{}
};
static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id)
MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids);
static const struct pci_device_id pmc_pci_ids[] = {
{ PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), 0},
{ 0, },
};
static int __init pmc_core_probe(void)
{
struct device *ptr_dev = &dev->dev;
struct pmc_dev *pmcdev = &pmc;
const struct x86_cpu_id *cpu_id;
const struct pmc_reg_map *map = (struct pmc_reg_map *)id->driver_data;
u64 slp_s0_addr;
int err;
cpu_id = x86_match_cpu(intel_pmc_core_ids);
if (!cpu_id) {
dev_dbg(&dev->dev, "PMC Core: cpuid mismatch.\n");
return -EINVAL;
}
if (!cpu_id)
return -ENODEV;
err = pcim_enable_device(dev);
if (err < 0) {
dev_dbg(&dev->dev, "PMC Core: failed to enable Power Management Controller.\n");
return err;
}
pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data;
err = pci_read_config_dword(dev,
SPT_PMC_BASE_ADDR_OFFSET,
&pmcdev->base_addr);
if (err < 0) {
dev_dbg(&dev->dev, "PMC Core: failed to read PCI config space.\n");
return err;
}
pmcdev->base_addr &= PMC_BASE_ADDR_MASK;
dev_dbg(&dev->dev, "PMC Core: PWRMBASE is %#x\n", pmcdev->base_addr);
pmcdev->regbase = devm_ioremap_nocache(ptr_dev,
pmcdev->base_addr,
SPT_PMC_MMIO_REG_LEN);
if (!pmcdev->regbase) {
dev_dbg(&dev->dev, "PMC Core: ioremap failed.\n");
/*
* Coffeelake has CPU ID of Kabylake and Cannonlake PCH. So here
* Sunrisepoint PCH regmap can't be used. Use Cannonlake PCH regmap
* in this case.
*/
if (!pci_dev_present(pmc_pci_ids))
pmcdev->map = &cnp_reg_map;
if (lpit_read_residency_count_address(&slp_s0_addr))
pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT;
else
pmcdev->base_addr = slp_s0_addr - pmcdev->map->slp_s0_offset;
pmcdev->regbase = ioremap(pmcdev->base_addr,
pmcdev->map->regmap_length);
if (!pmcdev->regbase)
return -ENOMEM;
}
mutex_init(&pmcdev->lock);
pmcdev->map = map;
pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
err = pmc_core_dbgfs_register(pmcdev);
if (err < 0)
dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n");
if (err < 0) {
pr_warn(" debugfs register failed.\n");
iounmap(pmcdev->regbase);
return err;
}
pmc.has_slp_s0_res = true;
pr_info(" initialized\n");
return 0;
}
module_init(pmc_core_probe)
static struct pci_driver intel_pmc_core_driver = {
.name = "intel_pmc_core",
.id_table = pmc_pci_ids,
.probe = pmc_core_probe,
};
static void __exit pmc_core_remove(void)
{
struct pmc_dev *pmcdev = &pmc;
pmc_core_dbgfs_unregister(pmcdev);
mutex_destroy(&pmcdev->lock);
iounmap(pmcdev->regbase);
}
module_exit(pmc_core_remove)
builtin_pci_driver(intel_pmc_core_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel PMC Core Driver");
......@@ -21,9 +21,10 @@
#ifndef PMC_CORE_H
#define PMC_CORE_H
#define PMC_BASE_ADDR_DEFAULT 0xFE000000
/* Sunrise Point Power Management Controller PCI Device ID */
#define SPT_PMC_PCI_DEVICE_ID 0x9d21
#define SPT_PMC_BASE_ADDR_OFFSET 0x48
#define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c
#define SPT_PMC_PM_CFG_OFFSET 0x18
......@@ -122,6 +123,17 @@ enum ppfear_regs {
#define SPT_PMC_BIT_MPHY_CMN_LANE2 BIT(2)
#define SPT_PMC_BIT_MPHY_CMN_LANE3 BIT(3)
/* Cannonlake Power Management Controller register offsets */
#define CNP_PMC_SLP_S0_RES_COUNTER_OFFSET 0x193C
#define CNP_PMC_LTR_IGNORE_OFFSET 0x1B0C
#define CNP_PMC_PM_CFG_OFFSET 0x1818
/* Cannonlake: PGD PFET Enable Ack Status Register(s) start */
#define CNP_PMC_HOST_PPFEAR0A 0x1D90
#define CNP_PMC_MMIO_REG_LEN 0x2000
#define CNP_PPFEAR_NUM_ENTRIES 8
#define CNP_PMC_READ_DISABLE_BIT 22
struct pmc_bit_map {
const char *name;
u32 bit_mask;
......@@ -135,7 +147,6 @@ struct pmc_bit_map {
* @pll_sts: Maps name of PLL to corresponding bit status
* @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency
* @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit
* @base_address: Base address of PWRMBASE defined in BIOS writer guide
* @regmap_length: Length of memory to map from PWRMBASE address to access
* @ppfear0_offset: PWRMBASE offset to to read PPFEAR*
* @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from
......@@ -152,7 +163,6 @@ struct pmc_reg_map {
const struct pmc_bit_map *pll_sts;
const u32 slp_s0_offset;
const u32 ltr_ignore_offset;
const u32 base_address;
const int regmap_length;
const u32 ppfear0_offset;
const int ppfear_buckets;
......@@ -162,12 +172,14 @@ struct pmc_reg_map {
/**
* struct pmc_dev - pmc device structure
* @base_addr: comtains pmc base address
* @base_addr: contains pmc base address
* @regbase: pointer to io-remapped memory location
* @dbgfs_dir: path to debug fs interface
* @feature_available: flag to indicate whether
* the feature is available
* on a particular platform or not.
* @map: pointer to pmc_reg_map struct that contains platform
* specific attributes
* @dbgfs_dir: path to debugfs interface
* @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
*
* pmc_dev contains info about power management controller device.
*/
......@@ -178,7 +190,6 @@ struct pmc_dev {
#if IS_ENABLED(CONFIG_DEBUG_FS)
struct dentry *dbgfs_dir;
#endif /* CONFIG_DEBUG_FS */
bool has_slp_s0_res;
int pmc_xram_read_bit;
struct mutex lock; /* generic mutex lock for PMC Core */
};
......
......@@ -215,11 +215,11 @@ static inline int is_gcr_valid(u32 offset)
}
/**
* intel_pmc_gcr_read() - Read PMC GCR register
* intel_pmc_gcr_read() - Read a 32-bit PMC GCR register
* @offset: offset of GCR register from GCR address base
* @data: data pointer for storing the register output
*
* Reads the PMC GCR register of given offset.
* Reads the 32-bit PMC GCR register at given offset.
*
* Return: negative value on error or 0 on success.
*/
......@@ -243,6 +243,35 @@ int intel_pmc_gcr_read(u32 offset, u32 *data)
}
EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
/**
* intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register
* @offset: offset of GCR register from GCR address base
* @data: data pointer for storing the register output
*
* Reads the 64-bit PMC GCR register at given offset.
*
* Return: negative value on error or 0 on success.
*/
int intel_pmc_gcr_read64(u32 offset, u64 *data)
{
int ret;
spin_lock(&ipcdev.gcr_lock);
ret = is_gcr_valid(offset);
if (ret < 0) {
spin_unlock(&ipcdev.gcr_lock);
return ret;
}
*data = readq(ipcdev.gcr_mem_base + offset);
spin_unlock(&ipcdev.gcr_lock);
return 0;
}
EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64);
/**
* intel_pmc_gcr_write() - Write PMC GCR register
* @offset: offset of GCR register from GCR address base
......
......@@ -23,7 +23,6 @@
*/
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/seq_file.h>
......@@ -32,7 +31,6 @@
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/intel_pmc_ipc.h>
#include <asm/intel_punit_ipc.h>
#include <asm/intel_telemetry.h>
#define DRIVER_NAME "telemetry_soc_debugfs"
......@@ -98,10 +96,6 @@ static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp;
static u64 suspend_shlw_res_temp, suspend_deep_res_temp;
struct telemetry_susp_stats {
u32 shlw_swake_ctr;
u32 deep_swake_ctr;
u64 shlw_swake_res;
u64 deep_swake_res;
u32 shlw_ctr;
u32 deep_ctr;
u64 shlw_res;
......@@ -250,7 +244,6 @@ static struct telem_ioss_pg_info telem_apl_ioss_pg_data[] = {
{"PRTC", 25},
};
struct telemetry_debugfs_conf {
struct telemetry_susp_stats suspend_stats;
struct dentry *telemetry_dbg_dir;
......@@ -385,7 +378,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused)
TELEM_APL_MASK_PCS_STATE;
}
TELEM_CHECK_AND_PARSE_EVTS(conf->pss_idle_id,
conf->pss_idle_evts - 1,
pss_idle, evtlog[index].telem_evtlog,
......@@ -405,7 +397,6 @@ static int telem_pss_states_show(struct seq_file *s, void *unused)
conf->pcs_s0ix_blkd_data,
TELEM_MASK_BYTE);
TELEM_CHECK_AND_PARSE_EVTS(conf->pss_wakeup_id,
conf->pss_wakeup_evts,
pss_s0ix_wakeup,
......@@ -498,7 +489,6 @@ static const struct file_operations telem_pss_ops = {
.release = single_release,
};
static int telem_ioss_states_show(struct seq_file *s, void *unused)
{
struct telemetry_evtlog evtlog[TELEM_MAX_OS_ALLOCATED_EVENTS];
......@@ -598,19 +588,15 @@ static int telem_soc_states_show(struct seq_file *s, void *unused)
seq_printf(s, "S0IX Shallow\t\t\t %10u\t %10llu\n",
s0ix_shlw_ctr -
conf->suspend_stats.shlw_ctr -
conf->suspend_stats.shlw_swake_ctr,
conf->suspend_stats.shlw_ctr,
(u64)((s0ix_shlw_res -
conf->suspend_stats.shlw_res -
conf->suspend_stats.shlw_swake_res)*10/192));
conf->suspend_stats.shlw_res)*10/192));
seq_printf(s, "S0IX Deep\t\t\t %10u\t %10llu\n",
s0ix_deep_ctr -
conf->suspend_stats.deep_ctr -
conf->suspend_stats.deep_swake_ctr,
conf->suspend_stats.deep_ctr,
(u64)((s0ix_deep_res -
conf->suspend_stats.deep_res -
conf->suspend_stats.deep_swake_res)*10/192));
conf->suspend_stats.deep_res)*10/192));
seq_printf(s, "Suspend(With S0ixShallow)\t %10u\t %10llu\n",
conf->suspend_stats.shlw_ctr,
......@@ -620,13 +606,7 @@ static int telem_soc_states_show(struct seq_file *s, void *unused)
conf->suspend_stats.deep_ctr,
(u64)(conf->suspend_stats.deep_res*10)/192);
seq_printf(s, "Suspend(With Shallow-Wakes)\t %10u\t %10llu\n",
conf->suspend_stats.shlw_swake_ctr +
conf->suspend_stats.deep_swake_ctr,
(u64)((conf->suspend_stats.shlw_swake_res +
conf->suspend_stats.deep_swake_res)*10/192));
seq_printf(s, "S0IX+Suspend Total\t\t %10u\t %10llu\n", s0ix_total_ctr,
seq_printf(s, "TOTAL S0IX\t\t\t %10u\t %10llu\n", s0ix_total_ctr,
(u64)(s0ix_total_res*10/192));
seq_puts(s, "\n-------------------------------------------------\n");
seq_puts(s, "\t\tDEVICE STATES\n");
......@@ -772,7 +752,6 @@ static const struct file_operations telem_pss_trc_verb_ops = {
.release = single_release,
};
static int telem_ioss_trc_verb_show(struct seq_file *s, void *unused)
{
u32 verbosity;
......@@ -890,28 +869,45 @@ static int pm_suspend_exit_cb(void)
goto out;
}
/*
* Due to some design limitations in the firmware, sometimes the
* counters do not get updated by the time we reach here. As a
* workaround, we try to see if this was a genuine case of sleep
* failure or not by cross-checking from PMC GCR registers directly.
*/
if (suspend_shlw_ctr_exit == suspend_shlw_ctr_temp &&
suspend_deep_ctr_exit == suspend_deep_ctr_temp) {
ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_SHLW_S0IX_REG,
&suspend_shlw_res_exit);
if (ret < 0)
goto out;
ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_DEEP_S0IX_REG,
&suspend_deep_res_exit);
if (ret < 0)
goto out;
if (suspend_shlw_res_exit > suspend_shlw_res_temp)
suspend_shlw_ctr_exit++;
if (suspend_deep_res_exit > suspend_deep_res_temp)
suspend_deep_ctr_exit++;
}
suspend_shlw_ctr_exit -= suspend_shlw_ctr_temp;
suspend_deep_ctr_exit -= suspend_deep_ctr_temp;
suspend_shlw_res_exit -= suspend_shlw_res_temp;
suspend_deep_res_exit -= suspend_deep_res_temp;
if (suspend_shlw_ctr_exit == 1) {
if (suspend_shlw_ctr_exit != 0) {
conf->suspend_stats.shlw_ctr +=
suspend_shlw_ctr_exit;
conf->suspend_stats.shlw_res +=
suspend_shlw_res_exit;
}
/* Shallow Wakes Case */
else if (suspend_shlw_ctr_exit > 1) {
conf->suspend_stats.shlw_swake_ctr +=
suspend_shlw_ctr_exit;
conf->suspend_stats.shlw_swake_res +=
suspend_shlw_res_exit;
}
if (suspend_deep_ctr_exit == 1) {
if (suspend_deep_ctr_exit != 0) {
conf->suspend_stats.deep_ctr +=
suspend_deep_ctr_exit;
......@@ -919,15 +915,6 @@ static int pm_suspend_exit_cb(void)
suspend_deep_res_exit;
}
/* Shallow Wakes Case */
else if (suspend_deep_ctr_exit > 1) {
conf->suspend_stats.deep_swake_ctr +=
suspend_deep_ctr_exit;
conf->suspend_stats.deep_swake_res +=
suspend_deep_res_exit;
}
out:
suspend_prep_ok = 0;
return NOTIFY_OK;
......
This diff is collapsed.
......@@ -208,6 +208,20 @@ static const struct pmc_data cht_data = {
.clks = cht_clks,
};
#define DEFINE_SHOW_ATTRIBUTE(__name) \
static int __name ## _open(struct inode *inode, struct file *file) \
{ \
return single_open(file, __name ## _show, inode->i_private); \
} \
\
static const struct file_operations __name ## _fops = { \
.owner = THIS_MODULE, \
.open = __name ## _open, \
.read = seq_read, \
.llseek = seq_lseek, \
.release = single_release, \
}
static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset)
{
return readl(pmc->regmap + reg_offset);
......@@ -309,17 +323,7 @@ static int pmc_dev_state_show(struct seq_file *s, void *unused)
return 0;
}
static int pmc_dev_state_open(struct inode *inode, struct file *file)
{
return single_open(file, pmc_dev_state_show, inode->i_private);
}
static const struct file_operations pmc_dev_state_ops = {
.open = pmc_dev_state_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(pmc_dev_state);
static int pmc_pss_state_show(struct seq_file *s, void *unused)
{
......@@ -336,17 +340,7 @@ static int pmc_pss_state_show(struct seq_file *s, void *unused)
return 0;
}
static int pmc_pss_state_open(struct inode *inode, struct file *file)
{
return single_open(file, pmc_pss_state_show, inode->i_private);
}
static const struct file_operations pmc_pss_state_ops = {
.open = pmc_pss_state_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(pmc_pss_state);
static int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
{
......@@ -367,17 +361,7 @@ static int pmc_sleep_tmr_show(struct seq_file *s, void *unused)
return 0;
}
static int pmc_sleep_tmr_open(struct inode *inode, struct file *file)
{
return single_open(file, pmc_sleep_tmr_show, inode->i_private);
}
static const struct file_operations pmc_sleep_tmr_ops = {
.open = pmc_sleep_tmr_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr);
static void pmc_dbgfs_unregister(struct pmc_dev *pmc)
{
......@@ -395,17 +379,17 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc)
pmc->dbgfs_dir = dir;
f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO,
dir, pmc, &pmc_dev_state_ops);
dir, pmc, &pmc_dev_state_fops);
if (!f)
goto err;
f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO,
dir, pmc, &pmc_pss_state_ops);
dir, pmc, &pmc_pss_state_fops);
if (!f)
goto err;
f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO,
dir, pmc, &pmc_sleep_tmr_ops);
dir, pmc, &pmc_sleep_tmr_fops);
if (!f)
goto err;
......
......@@ -67,6 +67,21 @@ static const struct silead_ts_dmi_data dexp_ursus_7w_data = {
.properties = dexp_ursus_7w_props,
};
static const struct property_entry surftab_twin_10_1_st10432_8_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1900),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl3670-surftab-twin-10-1-st10432-8.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
{ }
};
static const struct silead_ts_dmi_data surftab_twin_10_1_st10432_8_data = {
.acpi_name = "MSSL1680:00",
.properties = surftab_twin_10_1_st10432_8_props,
};
static const struct property_entry surftab_wintron70_st70416_6_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 884),
PROPERTY_ENTRY_U32("touchscreen-size-y", 632),
......@@ -171,6 +186,97 @@ static const struct silead_ts_dmi_data digma_citi_e200_data = {
.properties = digma_citi_e200_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),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-obook-20-plus.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
};
static const struct silead_ts_dmi_data onda_obook_20_plus_data = {
.acpi_name = "MSSL1680:00",
.properties = onda_obook_20_plus_props,
};
static const struct property_entry chuwi_hi8_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_BOOL("silead,home-button"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"),
{ }
};
static const struct silead_ts_dmi_data chuwi_hi8_data = {
.acpi_name = "MSSL0001:00",
.properties = chuwi_hi8_props,
};
static const struct property_entry chuwi_vi8_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1724),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-chuwi-vi8.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
};
static const struct silead_ts_dmi_data chuwi_vi8_data = {
.acpi_name = "MSSL1680:00",
.properties = chuwi_vi8_props,
};
static const struct property_entry trekstor_primebook_c13_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 2624),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1920),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1680-trekstor-primebook-c13.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
};
static const struct silead_ts_dmi_data trekstor_primebook_c13_data = {
.acpi_name = "MSSL1680:00",
.properties = trekstor_primebook_c13_props,
};
static const struct property_entry teclast_x98plus2_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 2048),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl1686-teclast_x98plus2.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
{ }
};
static const struct silead_ts_dmi_data teclast_x98plus2_data = {
.acpi_name = "MSSL1680:00",
.properties = teclast_x98plus2_props,
};
static const struct property_entry teclast_x3_plus_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-teclast-x3-plus.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
};
static const struct silead_ts_dmi_data teclast_x3_plus_data = {
.acpi_name = "MSSL1680:00",
.properties = teclast_x3_plus_props,
};
static const struct dmi_system_id silead_ts_dmi_table[] = {
{
/* CUBE iwork8 Air */
......@@ -198,6 +304,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "7W"),
},
},
{
/* TrekStor SurfTab twin 10.1 ST10432-8 */
.driver_data = (void *)&surftab_twin_10_1_st10432_8_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"),
DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab twin 10.1"),
},
},
{
/* Trekstor Surftab Wintron 7.0 ST70416-6 */
.driver_data = (void *)&surftab_wintron70_st70416_6_data,
......@@ -208,6 +322,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"),
},
},
{
/* Trekstor Surftab Wintron 7.0 ST70416-6, newer BIOS */
.driver_data = (void *)&surftab_wintron70_st70416_6_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"),
DMI_MATCH(DMI_PRODUCT_NAME,
"SurfTab wintron 7.0 ST70416-6"),
/* Exact match, different versions need different fw */
DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"),
},
},
{
/* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */
.driver_data = (void *)&surftab_wintron70_st70416_6_data,
......@@ -271,6 +396,56 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
},
},
{
/* Onda oBook 20 Plus */
.driver_data = (void *)&onda_obook_20_plus_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ONDA"),
DMI_MATCH(DMI_PRODUCT_NAME, "OBOOK 20 PLUS"),
},
},
{
/* Chuwi Hi8 */
.driver_data = (void *)&chuwi_hi8_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ilife"),
DMI_MATCH(DMI_PRODUCT_NAME, "S806"),
},
},
{
/* Chuwi Vi8 (CWI506) */
.driver_data = (void *)&chuwi_vi8_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
DMI_MATCH(DMI_PRODUCT_NAME, "i86"),
DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"),
},
},
{
/* Trekstor Primebook C13 */
.driver_data = (void *)&trekstor_primebook_c13_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),
},
},
{
/* Teclast X98 Plus II */
.driver_data = (void *)&teclast_x98plus2_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"),
},
},
{
/* Teclast X3 Plus */
.driver_data = (void *)&teclast_x3_plus_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
DMI_MATCH(DMI_PRODUCT_NAME, "X3 Plus"),
DMI_MATCH(DMI_BOARD_NAME, "X3 Plus"),
},
},
{ },
};
......
......@@ -214,6 +214,10 @@ enum tpacpi_hkey_event_t {
/* AC-related events */
TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */
/* Further user-interface events */
TP_HKEY_EV_PALM_DETECTED = 0x60b0, /* palm hoveres keyboard */
TP_HKEY_EV_PALM_UNDETECTED = 0x60b1, /* palm removed */
/* Misc */
TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */
};
......@@ -2113,12 +2117,10 @@ static int hotkey_gmms_get_tablet_mode(int s, int *has_tablet_mode)
TP_ACPI_MULTI_MODE_FLAT;
break;
case 4:
valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
TP_ACPI_MULTI_MODE_TABLET |
TP_ACPI_MULTI_MODE_STAND |
TP_ACPI_MULTI_MODE_TENT;
break;
case 5:
/* In mode 4, FLAT is not specified as a valid mode. However,
* it can be seen at least on the X1 Yoga 2nd Generation.
*/
valid_modes = TP_ACPI_MULTI_MODE_LAPTOP |
TP_ACPI_MULTI_MODE_FLAT |
TP_ACPI_MULTI_MODE_TABLET |
......@@ -4079,6 +4081,12 @@ static bool hotkey_notify_6xxx(const u32 hkey,
*send_acpi_ev = false;
break;
case TP_HKEY_EV_PALM_DETECTED:
case TP_HKEY_EV_PALM_UNDETECTED:
/* palm detected hovering the keyboard, forward to user-space
* via netlink for consumption */
return true;
default:
pr_warn("unknown possible thermal alarm or keyboard event received\n");
known = false;
......
/*
* include/linux/platform_data/mlxcpld-hotplug.h
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
* Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
......@@ -32,68 +31,114 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H
#define __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H
#ifndef __LINUX_PLATFORM_DATA_MLXREG_H
#define __LINUX_PLATFORM_DATA_MLXREG_H
#define MLXREG_CORE_LABEL_MAX_SIZE 32
/**
* struct mlxcpld_hotplug_device - I2C device data:
* struct mlxreg_hotplug_device - I2C device data:
*
* @adapter: I2C device adapter;
* @client: I2C device client;
* @brdinfo: device board information;
* @bus: I2C bus, where device is attached;
* @nr: I2C device adapter number, to which device is to be attached;
*
* Structure represents I2C hotplug device static data (board topology) and
* dynamic data (related kernel objects handles).
*/
struct mlxcpld_hotplug_device {
struct mlxreg_hotplug_device {
struct i2c_adapter *adapter;
struct i2c_client *client;
struct i2c_board_info brdinfo;
u16 bus;
struct i2c_board_info *brdinfo;
int nr;
};
/**
* struct mlxreg_core_data - attributes control data:
*
* @label: attribute label;
* @label: attribute register offset;
* @reg: attribute register;
* @mask: attribute access mask;
* @mode: access mode;
* @bit: attribute effective bit;
* @np - pointer to node platform associated with attribute;
* @hpdev - hotplug device data;
* @health_cntr: dynamic device health indication counter;
* @attached: true if device has been attached after good health indication;
*/
struct mlxreg_core_data {
char label[MLXREG_CORE_LABEL_MAX_SIZE];
u32 reg;
u32 mask;
u32 bit;
umode_t mode;
struct device_node *np;
struct mlxreg_hotplug_device hpdev;
u8 health_cntr;
bool attached;
};
/**
* struct mlxreg_core_item - same type components controlled by the driver:
*
* @data: component data;
* @aggr_mask: group aggregation mask;
* @reg: group interrupt status register;
* @mask: group interrupt mask;
* @cache: last status value for elements fro the same group;
* @count: number of available elements in the group;
* @ind: element's index inside the group;
* @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;
* @health: true if device has health indication, false in other case;
*/
struct mlxreg_core_item {
struct mlxreg_core_data *data;
u32 aggr_mask;
u32 reg;
u32 mask;
u32 cache;
u8 count;
u8 ind;
u8 inversed;
u8 health;
};
/**
* struct mlxreg_core_platform_data - platform data:
*
* @led_data: led private data;
* @regmap: register map of parent device;
* @counter: number of led instances;
*/
struct mlxreg_core_platform_data {
struct mlxreg_core_data *data;
void *regmap;
int counter;
};
/**
* struct mlxcpld_hotplug_platform_data - device platform data:
* @top_aggr_offset: offset of top aggregation interrupt register;
* @top_aggr_mask: top aggregation interrupt common mask;
* @top_aggr_psu_mask: top aggregation interrupt PSU mask;
* @psu_reg_offset: offset of PSU interrupt register;
* @psu_mask: PSU interrupt mask;
* @psu_count: number of equipped replaceable PSUs;
* @psu: pointer to PSU devices data array;
* @top_aggr_pwr_mask: top aggregation interrupt power mask;
* @pwr_reg_offset: offset of power interrupt register
* @pwr_mask: power interrupt mask;
* @pwr_count: number of power sources;
* @pwr: pointer to power devices data array;
* @top_aggr_fan_mask: top aggregation interrupt FAN mask;
* @fan_reg_offset: offset of FAN interrupt register;
* @fan_mask: FAN interrupt mask;
* @fan_count: number of equipped replaceable FANs;
* @fan: pointer to FAN devices data array;
* struct mlxreg_core_hotplug_platform_data - hotplug platform data:
*
* Structure represents board platform data, related to system hotplug events,
* like FAN, PSU, power cable insertion and removing. This data provides the
* number of hot-pluggable devices and hardware description for event handling.
* @items: same type components with the hotplug capability;
* @irq: platform interrupt number;
* @regmap: register map of parent device;
* @counter: number of the components with the hotplug capability;
* @cell: location of top aggregation interrupt register;
* @mask: top aggregation interrupt common mask;
* @cell_low: location of low aggregation interrupt register;
* @mask_low: low aggregation interrupt common mask;
*/
struct mlxcpld_hotplug_platform_data {
u16 top_aggr_offset;
u8 top_aggr_mask;
u8 top_aggr_psu_mask;
u16 psu_reg_offset;
u8 psu_mask;
u8 psu_count;
struct mlxcpld_hotplug_device *psu;
u8 top_aggr_pwr_mask;
u16 pwr_reg_offset;
u8 pwr_mask;
u8 pwr_count;
struct mlxcpld_hotplug_device *pwr;
u8 top_aggr_fan_mask;
u16 fan_reg_offset;
u8 fan_mask;
u8 fan_count;
struct mlxcpld_hotplug_device *fan;
struct mlxreg_core_hotplug_platform_data {
struct mlxreg_core_item *items;
int irq;
void *regmap;
int counter;
u32 cell;
u32 mask;
u32 cell_low;
u32 mask_low;
};
#endif /* __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H */
#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
......@@ -594,6 +594,7 @@
#define BTN_DPAD_RIGHT 0x223
#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
......
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