Commit 6ab1d483 authored by Linus Torvalds's avatar Linus Torvalds

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

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

Pull x86 platform driver updates from Hans de Goede:
 "Highlights:

   - AMD-PMC S0ix support fixes and improvements

   - HP-WMI support for Omen laptops

   - New nvidia-wmi-ec-backlight driver

   - New Intel ISH ECLITE driver

   - WMI core cleanups

   - Support for various new Melanox platforms

   - System76 Laptop support improvements

   - Surface Laptop Studio support and initial Surface Pro 8 support

   - Various other small fixes and hardware-id additions"

* tag 'platform-drivers-x86-v5.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (106 commits)
  platform/x86: system76_acpi: Fix input device error handling
  platform/x86: touchscreen_dmi: Add info for the Viglen Connect 10 tablet
  platform/surface: aggregator_registry: Add initial support for Surface Pro 8
  platform/x86: mlx-platform: Add support for new system SGN2410
  platform/x86: mlx-platform: Add BIOS attributes for CoffeeLake COMEx based systems
  platform/x86: mlx-platform: Extend FAN and LED configuration to support new MQM97xx systems
  platform/x86: asus-wmi: rename platform_profile_* function symbols
  platform/x86: hp-wmi: rename platform_profile_* function symbols
  platform/x86: amd-pmc: Drop check for valid alarm time
  platform/x86: amd-pmc: Downgrade dev_info message to dev_dbg
  platform/x86: amd-pmc: fix compilation without CONFIG_RTC_SYSTOHC_DEVICE
  platform/x86: system76_acpi: fix Kconfig dependencies
  platform/x86: barco-p50-gpio: use KEY_VENDOR for button instead of KEY_RESTART
  platform/x86: sony-laptop: replace snprintf in show functions with sysfs_emit
  platform/x86: lg-laptop: replace snprintf in show functions with sysfs_emit
  docs: ABI: fix documentation warning in sysfs-driver-mlxreg-io
  platform/x86: wmi: change notification handler type
  HID: surface-hid: Allow driver matching for target ID 1 devices
  HID: surface-hid: Use correct event registry for managing HID events
  platform/surface: aggregator_registry: Add support for Surface Laptop Studio
  ...
parents 56d33754 97ae4595
What: /sys/bus/wmi/devices/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_supported_type
Date: Apr 2021
KernelVersion: 5.13
Contact: "perry.yuan@dell.com>"
Contact: "<perry.yuan@dell.com>"
Description:
Display which dell hardware level privacy devices are supported
“Dell Privacy” is a set of HW, FW, and SW features to enhance
Dell’s commitment to platform privacy for MIC, Camera, and
ePrivacy screens.
The supported hardware privacy devices are:
Attributes:
Microphone Mute:
Attributes:
Microphone Mute:
Identifies the local microphone can be muted by hardware, no applications
is available to capture system mic sound
Camera Shutter:
Camera Shutter:
Identifies camera shutter controlled by hardware, which is a micromechanical
shutter assembly that is built onto the camera module to block capturing images
from outside the laptop
supported:
Values:
supported:
The privacy device is supported by this system
unsupported:
unsupported:
The privacy device is not supported on this system
For example to check which privacy devices are supported:
For example to check which privacy devices are supported::
# cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_supported_type
[Microphone Mute] [supported]
[Camera Shutter] [supported]
[ePrivacy Screen] [unsupported]
# cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_supported_type
[Microphone Mute] [supported]
[Camera Shutter] [supported]
[ePrivacy Screen] [unsupported]
What: /sys/bus/wmi/devices/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_current_state
Date: Apr 2021
KernelVersion: 5.13
Contact: "perry.yuan@dell.com>"
Contact: "<perry.yuan@dell.com>"
Description:
Allow user space to check current dell privacy device state.
Describes the Device State class exposed by BIOS which can be
consumed by various applications interested in knowing the Privacy
feature capabilities
Attributes:
muted:
Identifies the privacy device is turned off and cannot send stream to OS applications
unmuted:
Identifies the privacy device is turned on ,audio or camera driver can get
stream from mic and camera module to OS applications
Attributes:
Microphone:
Identifies the local microphone can be muted by hardware, no applications
is available to capture system mic sound
Camera Shutter:
Identifies camera shutter controlled by hardware, which is a micromechanical
shutter assembly that is built onto the camera module to block capturing images
from outside the laptop
Values:
muted:
Identifies the privacy device is turned off
and cannot send stream to OS applications
unmuted:
Identifies the privacy device is turned on,
audio or camera driver can get stream from mic
and camera module to OS applications
For example to check all supported current privacy device states:
For example to check all supported current privacy device states::
# cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_current_state
[Microphone] [unmuted]
[Camera Shutter] [unmuted]
# cat /sys/bus/wmi/drivers/dell-privacy/6932965F-1671-4CEB-B988-D3AB0A901919/dell_privacy_current_state
[Microphone] [unmuted]
[Camera Shutter] [unmuted]
......@@ -11,8 +11,10 @@ Description:
to take effect.
Display global reset setting bits for PMC.
* bit 31 - global reset is locked
* bit 20 - global reset is set
Writing bit 20 value to the etr3 will induce
a platform "global reset" upon consequent platform reset,
in case the register is not locked.
......
......@@ -3229,6 +3229,12 @@ F: drivers/video/backlight/
F: include/linux/backlight.h
F: include/linux/pwm_backlight.h
BARCO P50 GPIO DRIVER
M: Santosh Kumar Yadav <santoshkumar.yadav@barco.com>
M: Peter Korsgaard <peter.korsgaard@barco.com>
S: Maintained
F: drivers/platform/x86/barco-p50-gpio.c
BATMAN ADVANCED
M: Marek Lindner <mareklindner@neomailbox.ch>
M: Simon Wunderlich <sw@simonwunderlich.de>
......@@ -6725,7 +6731,7 @@ S: Supported
F: drivers/edac/dmc520_edac.c
EDAC-E752X
M: Mark Gross <mark.gross@intel.com>
M: Mark Gross <markgross@kernel.org>
L: linux-edac@vger.kernel.org
S: Maintained
F: drivers/edac/e752x_edac.c
......@@ -9537,6 +9543,12 @@ L: linux-crypto@vger.kernel.org
S: Maintained
F: drivers/crypto/ixp4xx_crypto.c
INTEL ISHTP ECLITE DRIVER
M: Sumesh K Naduvalath <sumesh.k.naduvalath@intel.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/intel/ishtp_eclite.c
INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
M: Krzysztof Halasa <khalasa@piap.pl>
S: Maintained
......@@ -12067,7 +12079,7 @@ F: drivers/net/ethernet/mellanox/mlxfw/
MELLANOX HARDWARE PLATFORM SUPPORT
M: Hans de Goede <hdegoede@redhat.com>
M: Mark Gross <mgross@linux.intel.com>
M: Mark Gross <markgross@kernel.org>
M: Vadim Pasternak <vadimp@nvidia.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
......@@ -12525,7 +12537,7 @@ F: drivers/platform/surface/surface_gpe.c
MICROSOFT SURFACE HARDWARE PLATFORM SUPPORT
M: Hans de Goede <hdegoede@redhat.com>
M: Mark Gross <mgross@linux.intel.com>
M: Mark Gross <markgross@kernel.org>
M: Maximilian Luz <luzmaximilian@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
......@@ -13479,6 +13491,12 @@ S: Maintained
F: drivers/video/fbdev/nvidia/
F: drivers/video/fbdev/riva/
NVIDIA WMI EC BACKLIGHT DRIVER
M: Daniel Dadap <ddadap@nvidia.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/nvidia-wmi-ec-backlight.c
NVM EXPRESS DRIVER
M: Keith Busch <kbusch@kernel.org>
M: Jens Axboe <axboe@fb.com>
......@@ -18561,7 +18579,7 @@ S: Supported
F: drivers/net/ethernet/tehuti/*
TELECOM CLOCK DRIVER FOR MCPL0010
M: Mark Gross <mark.gross@intel.com>
M: Mark Gross <markgross@kernel.org>
S: Supported
F: drivers/char/tlclk.c
......@@ -20480,7 +20498,7 @@ F: arch/x86/mm/
X86 PLATFORM DRIVERS
M: Hans de Goede <hdegoede@redhat.com>
M: Mark Gross <mgross@linux.intel.com>
M: Mark Gross <markgross@kernel.org>
L: platform-driver-x86@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
......
......@@ -209,7 +209,7 @@ static int surface_hid_probe(struct ssam_device *sdev)
shid->notif.base.priority = 1;
shid->notif.base.fn = ssam_hid_event_fn;
shid->notif.event.reg = SSAM_EVENT_REGISTRY_REG;
shid->notif.event.reg = SSAM_EVENT_REGISTRY_REG(sdev->uid.target);
shid->notif.event.id.target_category = sdev->uid.category;
shid->notif.event.id.instance = sdev->uid.instance;
shid->notif.event.mask = SSAM_EVENT_MASK_STRICT;
......@@ -230,7 +230,7 @@ static void surface_hid_remove(struct ssam_device *sdev)
}
static const struct ssam_device_id surface_hid_match[] = {
{ SSAM_SDEV(HID, 0x02, SSAM_ANY_IID, 0x00) },
{ SSAM_SDEV(HID, SSAM_ANY_TID, SSAM_ANY_IID, 0x00) },
{ },
};
MODULE_DEVICE_TABLE(ssam, surface_hid_match);
......
......@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/platform_data/x86/soc.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
......@@ -255,41 +256,24 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
return 0;
}
#ifdef CONFIG_ACPI
static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek,
struct platform_device *pdev)
static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek)
{
unsigned long long hrv = 0;
acpi_status status;
if (IS_ENABLED(CONFIG_INPUT_SOC_BUTTON_ARRAY) &&
axp20x_pek->axp20x->variant == AXP288_ID) {
status = acpi_evaluate_integer(ACPI_HANDLE(pdev->dev.parent),
"_HRV", NULL, &hrv);
if (ACPI_FAILURE(status))
dev_err(&pdev->dev, "Failed to get PMIC hardware revision\n");
/*
* On Cherry Trail platforms (hrv == 3), do not register the
* input device if there is an "INTCFD9" or "ACPI0011" gpio
* button ACPI device, as that handles the power button too,
* and otherwise we end up reporting all presses twice.
*/
if (hrv == 3 && (acpi_dev_present("INTCFD9", NULL, -1) ||
if (soc_intel_is_cht() &&
(acpi_dev_present("INTCFD9", NULL, -1) ||
acpi_dev_present("ACPI0011", NULL, -1)))
return false;
}
return true;
}
#else
static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek,
struct platform_device *pdev)
{
return true;
}
#endif
static int axp20x_pek_probe(struct platform_device *pdev)
{
......@@ -321,7 +305,7 @@ static int axp20x_pek_probe(struct platform_device *pdev)
axp20x_pek->irq_dbf = regmap_irq_get_virq(
axp20x_pek->axp20x->regmap_irqc, axp20x_pek->irq_dbf);
if (axp20x_pek_should_register_input(axp20x_pek, pdev)) {
if (axp20x_pek_should_register_input(axp20x_pek)) {
error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
if (error)
return error;
......
......@@ -34,6 +34,18 @@ config MLXREG_IO
to system resets operation, system reset causes monitoring and some
kinds of mux selection.
config MLXREG_LC
tristate "Mellanox line card platform driver support"
depends on REGMAP
depends on HWMON
depends on I2C
help
This driver provides support for the Mellanox MSN4800-XX line cards,
which are the part of MSN4800 Ethernet modular switch systems
providing a high performance switching solution for Enterprise Data
Centers (EDC) for building Ethernet based clusters, High-Performance
Computing (HPC) and embedded environments.
config MLXBF_TMFIFO
tristate "Mellanox BlueField SoC TmFifo platform driver"
depends on ARM64
......
......@@ -8,3 +8,4 @@ obj-$(CONFIG_MLXBF_PMC) += mlxbf-pmc.o
obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o
obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
obj-$(CONFIG_MLXREG_LC) += mlxreg-lc.o
......@@ -28,7 +28,7 @@
/* ASIC good health mask. */
#define MLXREG_HOTPLUG_GOOD_HEALTH_MASK 0x02
#define MLXREG_HOTPLUG_ATTRS_MAX 24
#define MLXREG_HOTPLUG_ATTRS_MAX 128
#define MLXREG_HOTPLUG_NOT_ASSERT 3
/**
......@@ -89,9 +89,20 @@ mlxreg_hotplug_udev_event_send(struct kobject *kobj,
return kobject_uevent_env(kobj, KOBJ_CHANGE, mlxreg_hotplug_udev_envp);
}
static void
mlxreg_hotplug_pdata_export(void *pdata, void *regmap)
{
struct mlxreg_core_hotplug_platform_data *dev_pdata = pdata;
/* Export regmap to underlying device. */
dev_pdata->regmap = regmap;
}
static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
struct mlxreg_core_data *data)
struct mlxreg_core_data *data,
enum mlxreg_hotplug_kind kind)
{
struct i2c_board_info *brdinfo = data->hpdev.brdinfo;
struct mlxreg_core_hotplug_platform_data *pdata;
struct i2c_client *client;
......@@ -106,46 +117,88 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
return 0;
pdata = dev_get_platdata(&priv->pdev->dev);
data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
pdata->shift_nr);
if (!data->hpdev.adapter) {
dev_err(priv->dev, "Failed to get adapter for bus %d\n",
data->hpdev.nr + pdata->shift_nr);
return -EFAULT;
}
switch (data->hpdev.action) {
case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
pdata->shift_nr);
if (!data->hpdev.adapter) {
dev_err(priv->dev, "Failed to get adapter for bus %d\n",
data->hpdev.nr + pdata->shift_nr);
return -EFAULT;
}
client = i2c_new_client_device(data->hpdev.adapter,
data->hpdev.brdinfo);
if (IS_ERR(client)) {
dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
data->hpdev.brdinfo->type, data->hpdev.nr +
pdata->shift_nr, data->hpdev.brdinfo->addr);
/* Export platform data to underlying device. */
if (brdinfo->platform_data)
mlxreg_hotplug_pdata_export(brdinfo->platform_data, pdata->regmap);
i2c_put_adapter(data->hpdev.adapter);
data->hpdev.adapter = NULL;
return PTR_ERR(client);
client = i2c_new_client_device(data->hpdev.adapter,
brdinfo);
if (IS_ERR(client)) {
dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
brdinfo->type, data->hpdev.nr +
pdata->shift_nr, brdinfo->addr);
i2c_put_adapter(data->hpdev.adapter);
data->hpdev.adapter = NULL;
return PTR_ERR(client);
}
data->hpdev.client = client;
break;
case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION:
/* Export platform data to underlying device. */
if (data->hpdev.brdinfo && data->hpdev.brdinfo->platform_data)
mlxreg_hotplug_pdata_export(data->hpdev.brdinfo->platform_data,
pdata->regmap);
/* Pass parent hotplug device handle to underlying device. */
data->notifier = data->hpdev.notifier;
data->hpdev.pdev = platform_device_register_resndata(&priv->pdev->dev,
brdinfo->type,
data->hpdev.nr,
NULL, 0, data,
sizeof(*data));
if (IS_ERR(data->hpdev.pdev))
return PTR_ERR(data->hpdev.pdev);
break;
default:
break;
}
data->hpdev.client = client;
if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
return data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 1);
return 0;
}
static void
mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
struct mlxreg_core_data *data)
struct mlxreg_core_data *data,
enum mlxreg_hotplug_kind kind)
{
/* Notify user by sending hwmon uevent. */
mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false);
if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 0);
switch (data->hpdev.action) {
case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
if (data->hpdev.client) {
i2c_unregister_device(data->hpdev.client);
data->hpdev.client = NULL;
}
if (data->hpdev.client) {
i2c_unregister_device(data->hpdev.client);
data->hpdev.client = NULL;
}
if (data->hpdev.adapter) {
i2c_put_adapter(data->hpdev.adapter);
data->hpdev.adapter = NULL;
if (data->hpdev.adapter) {
i2c_put_adapter(data->hpdev.adapter);
data->hpdev.adapter = NULL;
}
break;
case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION:
if (data->hpdev.pdev)
platform_device_unregister(data->hpdev.pdev);
break;
default:
break;
}
}
......@@ -317,14 +370,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
data = item->data + bit;
if (regval & BIT(bit)) {
if (item->inversed)
mlxreg_hotplug_device_destroy(priv, data);
mlxreg_hotplug_device_destroy(priv, data, item->kind);
else
mlxreg_hotplug_device_create(priv, data);
mlxreg_hotplug_device_create(priv, data, item->kind);
} else {
if (item->inversed)
mlxreg_hotplug_device_create(priv, data);
mlxreg_hotplug_device_create(priv, data, item->kind);
else
mlxreg_hotplug_device_destroy(priv, data);
mlxreg_hotplug_device_destroy(priv, data, item->kind);
}
}
......@@ -381,7 +434,7 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
* ASIC is in steady state. Connect associated
* device, if configured.
*/
mlxreg_hotplug_device_create(priv, data);
mlxreg_hotplug_device_create(priv, data, item->kind);
data->attached = true;
}
} else {
......@@ -391,7 +444,7 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
* in steady state. Disconnect associated
* device, if it has been connected.
*/
mlxreg_hotplug_device_destroy(priv, data);
mlxreg_hotplug_device_destroy(priv, data, item->kind);
data->attached = false;
data->health_cntr = 0;
}
......@@ -630,7 +683,7 @@ static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
/* Remove all the attached devices in group. */
count = item->count;
for (j = 0; j < count; j++, data++)
mlxreg_hotplug_device_destroy(priv, data);
mlxreg_hotplug_device_destroy(priv, data, item->kind);
}
}
......
......@@ -18,7 +18,7 @@
/* Attribute parameters. */
#define MLXREG_IO_ATT_SIZE 10
#define MLXREG_IO_ATT_NUM 48
#define MLXREG_IO_ATT_NUM 96
/**
* struct mlxreg_io_priv_data - driver's private data:
......
This diff is collapsed.
......@@ -139,13 +139,12 @@ static acpi_status s3_wmi_attach_spi_device(acpi_handle handle,
static int s3_wmi_check_platform_device(struct device *dev, void *data)
{
struct acpi_device *adev, *ts_adev = NULL;
acpi_handle handle;
struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_device *ts_adev = NULL;
acpi_status status;
/* ignore non ACPI devices */
handle = ACPI_HANDLE(dev);
if (!handle || acpi_bus_get_device(handle, &adev))
if (!adev)
return 0;
/* check for LID ACPI switch */
......@@ -159,7 +158,7 @@ static int s3_wmi_check_platform_device(struct device *dev, void *data)
strlen(SPI_CTL_OBJ_NAME)))
return 0;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, adev->handle, 1,
s3_wmi_attach_spi_device, NULL,
&ts_adev, NULL);
if (ACPI_FAILURE(status))
......
......@@ -159,12 +159,11 @@ mshw0011_notify(struct mshw0011_data *cdata, u8 arg1, u8 arg2,
unsigned int *ret_value)
{
union acpi_object *obj;
struct acpi_device *adev;
acpi_handle handle;
unsigned int i;
handle = ACPI_HANDLE(&cdata->adp1->dev);
if (!handle || acpi_bus_get_device(handle, &adev))
if (!handle)
return -ENODEV;
obj = acpi_evaluate_dsm_typed(handle, &mshw0011_guid, arg1, arg2, NULL,
......
......@@ -77,6 +77,42 @@ static const struct software_node ssam_node_bas_dtx = {
.parent = &ssam_node_root,
};
/* HID keyboard (TID1). */
static const struct software_node ssam_node_hid_tid1_keyboard = {
.name = "ssam:01:15:01:01:00",
.parent = &ssam_node_root,
};
/* HID pen stash (TID1; pen taken / stashed away evens). */
static const struct software_node ssam_node_hid_tid1_penstash = {
.name = "ssam:01:15:01:02:00",
.parent = &ssam_node_root,
};
/* HID touchpad (TID1). */
static const struct software_node ssam_node_hid_tid1_touchpad = {
.name = "ssam:01:15:01:03:00",
.parent = &ssam_node_root,
};
/* HID device instance 6 (TID1, unknown HID device). */
static const struct software_node ssam_node_hid_tid1_iid6 = {
.name = "ssam:01:15:01:06:00",
.parent = &ssam_node_root,
};
/* HID device instance 7 (TID1, unknown HID device). */
static const struct software_node ssam_node_hid_tid1_iid7 = {
.name = "ssam:01:15:01:07:00",
.parent = &ssam_node_root,
};
/* HID system controls (TID1). */
static const struct software_node ssam_node_hid_tid1_sysctrl = {
.name = "ssam:01:15:01:08:00",
.parent = &ssam_node_root,
};
/* HID keyboard. */
static const struct software_node ssam_node_hid_main_keyboard = {
.name = "ssam:01:15:02:01:00",
......@@ -159,6 +195,21 @@ static const struct software_node *ssam_node_group_sl3[] = {
NULL,
};
/* Devices for Surface Laptop Studio. */
static const struct software_node *ssam_node_group_sls[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
&ssam_node_hid_tid1_keyboard,
&ssam_node_hid_tid1_penstash,
&ssam_node_hid_tid1_touchpad,
&ssam_node_hid_tid1_iid6,
&ssam_node_hid_tid1_iid7,
&ssam_node_hid_tid1_sysctrl,
NULL,
};
/* Devices for Surface Laptop Go. */
static const struct software_node *ssam_node_group_slg1[] = {
&ssam_node_root,
......@@ -177,6 +228,15 @@ static const struct software_node *ssam_node_group_sp7[] = {
NULL,
};
static const struct software_node *ssam_node_group_sp8[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
/* TODO: Add support for keyboard cover. */
NULL,
};
/* -- Device registry helper functions. ------------------------------------- */
......@@ -483,6 +543,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Pro 7+ */
{ "MSHW0119", (unsigned long)ssam_node_group_sp7 },
/* Surface Pro 8 */
{ "MSHW0263", (unsigned long)ssam_node_group_sp8 },
/* Surface Book 2 */
{ "MSHW0107", (unsigned long)ssam_node_group_gen5 },
......@@ -507,6 +570,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Laptop Go 1 */
{ "MSHW0118", (unsigned long)ssam_node_group_slg1 },
/* Surface Laptop Studio */
{ "MSHW0123", (unsigned long)ssam_node_group_sls },
{ },
};
MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_match);
......
......@@ -26,6 +26,11 @@ static const struct property_entry lid_device_props_l17[] = {
{},
};
static const struct property_entry lid_device_props_l4B[] = {
PROPERTY_ENTRY_U32("gpe", 0x4B),
{},
};
static const struct property_entry lid_device_props_l4D[] = {
PROPERTY_ENTRY_U32("gpe", 0x4D),
{},
......@@ -158,6 +163,14 @@ static const struct dmi_system_id dmi_lid_device_table[] = {
},
.driver_data = (void *)lid_device_props_l4D,
},
{
.ident = "Surface Laptop Studio",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop Studio"),
},
.driver_data = (void *)lid_device_props_l4B,
},
{ }
};
......
......@@ -91,6 +91,21 @@ config PEAQ_WMI
help
Say Y here if you want to support WMI-based hotkeys on PEAQ 2-in-1s.
config NVIDIA_WMI_EC_BACKLIGHT
tristate "EC Backlight Driver for Hybrid Graphics Notebook Systems"
depends on ACPI_WMI
depends on BACKLIGHT_CLASS_DEVICE
help
This driver provides a sysfs backlight interface for notebook systems
which are equipped with NVIDIA hybrid graphics and drive LCD backlight
levels through the Embedded Controller (EC).
Say Y or M here if you want to control the backlight on a notebook
system with an EC-driven backlight.
If you choose to compile this driver as a module the module will be
called nvidia-wmi-ec-backlight.
config XIAOMI_WMI
tristate "Xiaomi WMI key driver"
depends on ACPI_WMI
......@@ -426,6 +441,7 @@ config HP_WMI
depends on RFKILL || RFKILL = n
select INPUT_SPARSEKMAP
select ACPI_PLATFORM_PROFILE
select HWMON
help
Say Y here if you want to support WMI-based hotkeys on HP laptops and
to read data from WMI such as docking or ambient light sensor state.
......@@ -713,6 +729,16 @@ config PCENGINES_APU2
To compile this driver as a module, choose M here: the module
will be called pcengines-apuv2.
config BARCO_P50_GPIO
tristate "Barco P50 GPIO driver for identify LED/button"
depends on GPIOLIB
help
This driver provides access to the GPIOs for the identify button
and led present on Barco P50 board.
To compile this driver as a module, choose M here: the module
will be called barco-p50-gpio.
config SAMSUNG_LAPTOP
tristate "Samsung Laptop driver"
depends on RFKILL || RFKILL = n
......@@ -905,6 +931,9 @@ config SONYPI_COMPAT
config SYSTEM76_ACPI
tristate "System76 ACPI Driver"
depends on ACPI
depends on ACPI_BATTERY
depends on HWMON
depends on INPUT
select NEW_LEDS
select LEDS_CLASS
select LEDS_TRIGGERS
......
......@@ -11,6 +11,7 @@ obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o
# WMI drivers
obj-$(CONFIG_HUAWEI_WMI) += huawei-wmi.o
obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
obj-$(CONFIG_NVIDIA_WMI_EC_BACKLIGHT) += nvidia-wmi-ec-backlight.o
obj-$(CONFIG_PEAQ_WMI) += peaq-wmi.o
obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o
obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o
......@@ -80,6 +81,9 @@ obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o
# PC Engines
obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o
# Barco
obj-$(CONFIG_BARCO_P50_GPIO) += barco-p50-gpio.o
# Samsung
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
......
......@@ -138,7 +138,7 @@ struct event_return_value {
u16 reserved1;
u8 kbd_dock_state;
u8 reserved2;
} __attribute__((packed));
} __packed;
/*
* GUID3 Get Device Status device flags
......@@ -172,33 +172,33 @@ struct func_input_params {
u8 app_status; /* Acer Device Status. LM, ePM, RF Button... */
u8 app_mask; /* Bit mask to app_status */
u8 reserved;
} __attribute__((packed));
} __packed;
struct func_return_value {
u8 error_code; /* Error Code */
u8 ec_return_value; /* EC Return Value */
u16 reserved;
} __attribute__((packed));
} __packed;
struct wmid3_gds_set_input_param { /* Set Device Status input parameter */
u8 function_num; /* Function Number */
u8 hotkey_number; /* Hotkey Number */
u16 devices; /* Set Device */
u8 volume_value; /* Volume Value */
} __attribute__((packed));
} __packed;
struct wmid3_gds_get_input_param { /* Get Device Status input parameter */
u8 function_num; /* Function Number */
u8 hotkey_number; /* Hotkey Number */
u16 devices; /* Get Device */
} __attribute__((packed));
} __packed;
struct wmid3_gds_return_value { /* Get Device Status return value*/
u8 error_code; /* Error Code */
u8 ec_return_value; /* EC Return Value */
u16 devices; /* Current Device Status */
u32 reserved;
} __attribute__((packed));
} __packed;
struct hotkey_function_type_aa {
u8 type;
......@@ -210,7 +210,7 @@ struct hotkey_function_type_aa {
u16 display_func_bitmap;
u16 others_func_bitmap;
u8 commun_fn_key_number;
} __attribute__((packed));
} __packed;
/*
* Interface capability flags
......
......@@ -17,9 +17,11 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/suspend.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
......@@ -29,6 +31,10 @@
#define AMD_PMC_REGISTER_RESPONSE 0x980
#define AMD_PMC_REGISTER_ARGUMENT 0x9BC
/* PMC Scratch Registers */
#define AMD_PMC_SCRATCH_REG_CZN 0x94
#define AMD_PMC_SCRATCH_REG_YC 0xD14
/* Base address of SMU for mapping physical address to virtual address */
#define AMD_PMC_SMU_INDEX_ADDRESS 0xB8
#define AMD_PMC_SMU_INDEX_DATA 0xBC
......@@ -110,6 +116,10 @@ struct amd_pmc_dev {
u32 base_addr;
u32 cpu_id;
u32 active_ips;
/* SMU version information */
u16 major;
u16 minor;
u16 rev;
struct device *dev;
struct mutex lock; /* generic mutex lock */
#if IS_ENABLED(CONFIG_DEBUG_FS)
......@@ -118,7 +128,7 @@ struct amd_pmc_dev {
};
static struct amd_pmc_dev pmc;
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret);
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret);
static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset)
{
......@@ -133,7 +143,7 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3
struct smu_metrics {
u32 table_version;
u32 hint_count;
u32 s0i3_cyclecount;
u32 s0i3_last_entry_status;
u32 timein_s0i2;
u64 timeentering_s0i3_lastcapture;
u64 timeentering_s0i3_totaltime;
......@@ -147,6 +157,49 @@ struct smu_metrics {
u64 timecondition_notmet_totaltime[SOC_SUBSYSTEM_IP_MAX];
} __packed;
static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
{
int rc;
u32 val;
rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, 1);
if (rc)
return rc;
dev->major = (val >> 16) & GENMASK(15, 0);
dev->minor = (val >> 8) & GENMASK(7, 0);
dev->rev = (val >> 0) & GENMASK(7, 0);
dev_dbg(dev->dev, "SMU version is %u.%u.%u\n", dev->major, dev->minor, dev->rev);
return 0;
}
static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev,
struct seq_file *s)
{
u32 val;
switch (pdev->cpu_id) {
case AMD_CPU_ID_CZN:
val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN);
break;
case AMD_CPU_ID_YC:
val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC);
break;
default:
return -EINVAL;
}
if (dev)
dev_dbg(pdev->dev, "SMU idlemask s0i3: 0x%x\n", val);
if (s)
seq_printf(s, "SMU idlemask : 0x%x\n", val);
return 0;
}
#ifdef CONFIG_DEBUG_FS
static int smu_fw_info_show(struct seq_file *s, void *unused)
{
......@@ -162,9 +215,12 @@ static int smu_fw_info_show(struct seq_file *s, void *unused)
seq_puts(s, "\n=== SMU Statistics ===\n");
seq_printf(s, "Table Version: %d\n", table.table_version);
seq_printf(s, "Hint Count: %d\n", table.hint_count);
seq_printf(s, "S0i3 Cycle Count: %d\n", table.s0i3_cyclecount);
seq_printf(s, "Last S0i3 Status: %s\n", table.s0i3_last_entry_status ? "Success" :
"Unknown/Fail");
seq_printf(s, "Time (in us) to S0i3: %lld\n", table.timeentering_s0i3_lastcapture);
seq_printf(s, "Time (in us) in S0i3: %lld\n", table.timein_s0i3_lastcapture);
seq_printf(s, "Time (in us) to resume from S0i3: %lld\n",
table.timeto_resume_to_os_lastcapture);
seq_puts(s, "\n=== Active time (in us) ===\n");
for (idx = 0 ; idx < SOC_SUBSYSTEM_IP_MAX ; idx++) {
......@@ -201,6 +257,23 @@ static int s0ix_stats_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(s0ix_stats);
static int amd_pmc_idlemask_show(struct seq_file *s, void *unused)
{
struct amd_pmc_dev *dev = s->private;
int rc;
if (dev->major > 56 || (dev->major >= 55 && dev->minor >= 37)) {
rc = amd_pmc_idlemask_read(dev, NULL, s);
if (rc)
return rc;
} else {
seq_puts(s, "Unsupported SMU version for Idlemask\n");
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(amd_pmc_idlemask);
static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
{
debugfs_remove_recursive(dev->dbgfs_dir);
......@@ -213,6 +286,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
&smu_fw_info_fops);
debugfs_create_file("s0ix_stats", 0644, dev->dbgfs_dir, dev,
&s0ix_stats_fops);
debugfs_create_file("amd_pmc_idlemask", 0644, dev->dbgfs_dir, dev,
&amd_pmc_idlemask_fops);
}
#else
static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
......@@ -264,7 +339,7 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value);
}
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret)
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret)
{
int rc;
u32 val;
......@@ -283,7 +358,7 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg
amd_pmc_reg_write(dev, AMD_PMC_REGISTER_RESPONSE, 0);
/* Write argument into response register */
amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, set);
amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, arg);
/* Write message ID to message ID register */
amd_pmc_reg_write(dev, AMD_PMC_REGISTER_MESSAGE, msg);
......@@ -339,18 +414,73 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
return -EINVAL;
}
static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
{
struct rtc_device *rtc_device;
time64_t then, now, duration;
struct rtc_wkalrm alarm;
struct rtc_time tm;
int rc;
if (pdev->major < 64 || (pdev->major == 64 && pdev->minor < 53))
return 0;
rtc_device = rtc_class_open("rtc0");
if (!rtc_device)
return 0;
rc = rtc_read_alarm(rtc_device, &alarm);
if (rc)
return rc;
if (!alarm.enabled) {
dev_dbg(pdev->dev, "alarm not enabled\n");
return 0;
}
rc = rtc_read_time(rtc_device, &tm);
if (rc)
return rc;
then = rtc_tm_to_time64(&alarm.time);
now = rtc_tm_to_time64(&tm);
duration = then-now;
/* in the past */
if (then < now)
return 0;
/* will be stored in upper 16 bits of s0i3 hint argument,
* so timer wakeup from s0i3 is limited to ~18 hours or less
*/
if (duration <= 4 || duration > U16_MAX)
return -EINVAL;
*arg |= (duration << 16);
rc = rtc_alarm_irq_enable(rtc_device, 0);
dev_dbg(pdev->dev, "wakeup timer programmed for %lld seconds\n", duration);
return rc;
}
static int __maybe_unused amd_pmc_suspend(struct device *dev)
{
struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
int rc;
u8 msg;
u32 arg = 1;
/* Reset and Start SMU logging - to monitor the s0i3 stats */
amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_RESET, 0);
amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_START, 0);
/* Activate CZN specific RTC functionality */
if (pdev->cpu_id == AMD_CPU_ID_CZN) {
rc = amd_pmc_verify_czn_rtc(pdev, &arg);
if (rc < 0)
return rc;
}
/* Dump the IdleMask before we send hint to SMU */
amd_pmc_idlemask_read(pdev, dev, NULL);
msg = amd_pmc_get_os_hint(pdev);
rc = amd_pmc_send_cmd(pdev, 1, NULL, msg, 0);
rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, 0);
if (rc)
dev_err(pdev->dev, "suspend failed\n");
......@@ -363,14 +493,17 @@ static int __maybe_unused amd_pmc_resume(struct device *dev)
int rc;
u8 msg;
/* Let SMU know that we are looking for stats */
amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0);
msg = amd_pmc_get_os_hint(pdev);
rc = amd_pmc_send_cmd(pdev, 0, NULL, msg, 0);
if (rc)
dev_err(pdev->dev, "resume failed\n");
/* Let SMU know that we are looking for stats */
amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0);
/* Dump the IdleMask to see the blockers */
amd_pmc_idlemask_read(pdev, dev, NULL);
return 0;
}
......@@ -457,6 +590,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
if (err)
dev_err(dev->dev, "SMU debugging info not supported on this platform\n");
amd_pmc_get_smu_version(dev);
platform_set_drvdata(pdev, dev);
amd_pmc_dbgfs_register(dev);
return 0;
......
......@@ -2169,8 +2169,8 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
static DEVICE_ATTR_RW(throttle_thermal_policy);
/* Platform profile ***********************************************************/
static int platform_profile_get(struct platform_profile_handler *pprof,
enum platform_profile_option *profile)
static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
enum platform_profile_option *profile)
{
struct asus_wmi *asus;
int tp;
......@@ -2196,8 +2196,8 @@ static int platform_profile_get(struct platform_profile_handler *pprof,
return 0;
}
static int platform_profile_set(struct platform_profile_handler *pprof,
enum platform_profile_option profile)
static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof,
enum platform_profile_option profile)
{
struct asus_wmi *asus;
int tp;
......@@ -2236,8 +2236,8 @@ static int platform_profile_setup(struct asus_wmi *asus)
dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n");
asus->platform_profile_handler.profile_get = platform_profile_get;
asus->platform_profile_handler.profile_set = platform_profile_set;
asus->platform_profile_handler.profile_get = asus_wmi_platform_profile_get;
asus->platform_profile_handler.profile_set = asus_wmi_platform_profile_set;
set_bit(PLATFORM_PROFILE_QUIET, asus->platform_profile_handler.choices);
set_bit(PLATFORM_PROFILE_BALANCED,
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Support for EC-connected GPIOs for identify
* LED/button on Barco P50 board
*
* Copyright (C) 2021 Barco NV
* Author: Santosh Kumar Yadav <santoshkumar.yadav@barco.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio_keys.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/input.h>
#define DRIVER_NAME "barco-p50-gpio"
/* GPIO lines */
#define P50_GPIO_LINE_LED 0
#define P50_GPIO_LINE_BTN 1
/* GPIO IO Ports */
#define P50_GPIO_IO_PORT_BASE 0x299
#define P50_PORT_DATA 0x00
#define P50_PORT_CMD 0x01
#define P50_STATUS_OBF 0x01 /* EC output buffer full */
#define P50_STATUS_IBF 0x02 /* EC input buffer full */
#define P50_CMD_READ 0xa0
#define P50_CMD_WRITE 0x50
/* EC mailbox registers */
#define P50_MBOX_REG_CMD 0x00
#define P50_MBOX_REG_STATUS 0x01
#define P50_MBOX_REG_PARAM 0x02
#define P50_MBOX_REG_DATA 0x03
#define P50_MBOX_CMD_READ_GPIO 0x11
#define P50_MBOX_CMD_WRITE_GPIO 0x12
#define P50_MBOX_CMD_CLEAR 0xff
#define P50_MBOX_STATUS_SUCCESS 0x01
#define P50_MBOX_PARAM_LED 0x12
#define P50_MBOX_PARAM_BTN 0x13
struct p50_gpio {
struct gpio_chip gc;
struct mutex lock;
unsigned long base;
struct platform_device *leds_pdev;
struct platform_device *keys_pdev;
};
static struct platform_device *gpio_pdev;
static int gpio_params[] = {
[P50_GPIO_LINE_LED] = P50_MBOX_PARAM_LED,
[P50_GPIO_LINE_BTN] = P50_MBOX_PARAM_BTN,
};
static const char * const gpio_names[] = {
[P50_GPIO_LINE_LED] = "identify-led",
[P50_GPIO_LINE_BTN] = "identify-button",
};
static struct gpiod_lookup_table p50_gpio_led_table = {
.dev_id = "leds-gpio",
.table = {
GPIO_LOOKUP_IDX(DRIVER_NAME, P50_GPIO_LINE_LED, NULL, 0, GPIO_ACTIVE_HIGH),
{}
}
};
/* GPIO LEDs */
static struct gpio_led leds[] = {
{ .name = "identify" }
};
static struct gpio_led_platform_data leds_pdata = {
.num_leds = ARRAY_SIZE(leds),
.leds = leds,
};
/* GPIO keyboard */
static struct gpio_keys_button buttons[] = {
{
.code = KEY_VENDOR,
.gpio = P50_GPIO_LINE_BTN,
.active_low = 1,
.type = EV_KEY,
.value = 1,
},
};
static struct gpio_keys_platform_data keys_pdata = {
.buttons = buttons,
.nbuttons = ARRAY_SIZE(buttons),
.poll_interval = 100,
.rep = 0,
.name = "identify",
};
/* low level access routines */
static int p50_wait_ec(struct p50_gpio *p50, int mask, int expected)
{
int i, val;
for (i = 0; i < 100; i++) {
val = inb(p50->base + P50_PORT_CMD) & mask;
if (val == expected)
return 0;
usleep_range(500, 2000);
}
dev_err(p50->gc.parent, "Timed out waiting for EC (0x%x)\n", val);
return -ETIMEDOUT;
}
static int p50_read_mbox_reg(struct p50_gpio *p50, int reg)
{
int ret;
ret = p50_wait_ec(p50, P50_STATUS_IBF, 0);
if (ret)
return ret;
/* clear output buffer flag, prevent unfinished commands */
inb(p50->base + P50_PORT_DATA);
/* cmd/address */
outb(P50_CMD_READ | reg, p50->base + P50_PORT_CMD);
ret = p50_wait_ec(p50, P50_STATUS_OBF, P50_STATUS_OBF);
if (ret)
return ret;
return inb(p50->base + P50_PORT_DATA);
}
static int p50_write_mbox_reg(struct p50_gpio *p50, int reg, int val)
{
int ret;
ret = p50_wait_ec(p50, P50_STATUS_IBF, 0);
if (ret)
return ret;
/* cmd/address */
outb(P50_CMD_WRITE | reg, p50->base + P50_PORT_CMD);
ret = p50_wait_ec(p50, P50_STATUS_IBF, 0);
if (ret)
return ret;
/* data */
outb(val, p50->base + P50_PORT_DATA);
return 0;
}
/* mbox routines */
static int p50_wait_mbox_idle(struct p50_gpio *p50)
{
int i, val;
for (i = 0; i < 1000; i++) {
val = p50_read_mbox_reg(p50, P50_MBOX_REG_CMD);
/* cmd is 0 when idle */
if (val <= 0)
return val;
usleep_range(500, 2000);
}
dev_err(p50->gc.parent, "Timed out waiting for EC mbox idle (CMD: 0x%x)\n", val);
return -ETIMEDOUT;
}
static int p50_send_mbox_cmd(struct p50_gpio *p50, int cmd, int param, int data)
{
int ret;
ret = p50_wait_mbox_idle(p50);
if (ret)
return ret;
ret = p50_write_mbox_reg(p50, P50_MBOX_REG_DATA, data);
if (ret)
return ret;
ret = p50_write_mbox_reg(p50, P50_MBOX_REG_PARAM, param);
if (ret)
return ret;
ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, cmd);
if (ret)
return ret;
ret = p50_wait_mbox_idle(p50);
if (ret)
return ret;
ret = p50_read_mbox_reg(p50, P50_MBOX_REG_STATUS);
if (ret < 0)
return ret;
if (ret == P50_MBOX_STATUS_SUCCESS)
return 0;
dev_err(p50->gc.parent, "Mbox command failed (CMD=0x%x STAT=0x%x PARAM=0x%x DATA=0x%x)\n",
cmd, ret, param, data);
return -EIO;
}
/* gpio routines */
static int p50_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
switch (offset) {
case P50_GPIO_LINE_BTN:
return GPIO_LINE_DIRECTION_IN;
case P50_GPIO_LINE_LED:
return GPIO_LINE_DIRECTION_OUT;
default:
return -EINVAL;
}
}
static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct p50_gpio *p50 = gpiochip_get_data(gc);
int ret;
mutex_lock(&p50->lock);
ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0);
if (ret == 0)
ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA);
mutex_unlock(&p50->lock);
return ret;
}
static void p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
{
struct p50_gpio *p50 = gpiochip_get_data(gc);
mutex_lock(&p50->lock);
p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO, gpio_params[offset], value);
mutex_unlock(&p50->lock);
}
static int p50_gpio_probe(struct platform_device *pdev)
{
struct p50_gpio *p50;
struct resource *res;
int ret;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res) {
dev_err(&pdev->dev, "Cannot get I/O ports\n");
return -ENODEV;
}
if (!devm_request_region(&pdev->dev, res->start, resource_size(res), pdev->name)) {
dev_err(&pdev->dev, "Unable to reserve I/O region\n");
return -EBUSY;
}
p50 = devm_kzalloc(&pdev->dev, sizeof(*p50), GFP_KERNEL);
if (!p50)
return -ENOMEM;
platform_set_drvdata(pdev, p50);
mutex_init(&p50->lock);
p50->base = res->start;
p50->gc.owner = THIS_MODULE;
p50->gc.parent = &pdev->dev;
p50->gc.label = dev_name(&pdev->dev);
p50->gc.ngpio = ARRAY_SIZE(gpio_names);
p50->gc.names = gpio_names;
p50->gc.can_sleep = true;
p50->gc.base = -1;
p50->gc.get_direction = p50_gpio_get_direction;
p50->gc.get = p50_gpio_get;
p50->gc.set = p50_gpio_set;
/* reset mbox */
ret = p50_wait_mbox_idle(p50);
if (ret)
return ret;
ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, P50_MBOX_CMD_CLEAR);
if (ret)
return ret;
ret = p50_wait_mbox_idle(p50);
if (ret)
return ret;
ret = devm_gpiochip_add_data(&pdev->dev, &p50->gc, p50);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip: %d\n", ret);
return ret;
}
gpiod_add_lookup_table(&p50_gpio_led_table);
p50->leds_pdev = platform_device_register_data(&pdev->dev,
"leds-gpio", PLATFORM_DEVID_NONE, &leds_pdata, sizeof(leds_pdata));
if (IS_ERR(p50->leds_pdev)) {
ret = PTR_ERR(p50->leds_pdev);
dev_err(&pdev->dev, "Could not register leds-gpio: %d\n", ret);
goto err_leds;
}
/* gpio-keys-polled uses old-style gpio interface, pass the right identifier */
buttons[0].gpio += p50->gc.base;
p50->keys_pdev =
platform_device_register_data(&pdev->dev, "gpio-keys-polled",
PLATFORM_DEVID_NONE,
&keys_pdata, sizeof(keys_pdata));
if (IS_ERR(p50->keys_pdev)) {
ret = PTR_ERR(p50->keys_pdev);
dev_err(&pdev->dev, "Could not register gpio-keys-polled: %d\n", ret);
goto err_keys;
}
return 0;
err_keys:
platform_device_unregister(p50->leds_pdev);
err_leds:
gpiod_remove_lookup_table(&p50_gpio_led_table);
return ret;
}
static int p50_gpio_remove(struct platform_device *pdev)
{
struct p50_gpio *p50 = platform_get_drvdata(pdev);
platform_device_unregister(p50->keys_pdev);
platform_device_unregister(p50->leds_pdev);
gpiod_remove_lookup_table(&p50_gpio_led_table);
return 0;
}
static struct platform_driver p50_gpio_driver = {
.driver = {
.name = DRIVER_NAME,
},
.probe = p50_gpio_probe,
.remove = p50_gpio_remove,
};
/* Board setup */
static const struct dmi_system_id dmi_ids[] __initconst = {
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Barco"),
DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "P50")
},
},
{}
};
MODULE_DEVICE_TABLE(dmi, dmi_ids);
static int __init p50_module_init(void)
{
struct resource res = DEFINE_RES_IO(P50_GPIO_IO_PORT_BASE, P50_PORT_CMD + 1);
if (!dmi_first_match(dmi_ids))
return -ENODEV;
platform_driver_register(&p50_gpio_driver);
gpio_pdev = platform_device_register_simple(DRIVER_NAME, PLATFORM_DEVID_NONE, &res, 1);
if (IS_ERR(gpio_pdev)) {
pr_err("failed registering %s: %ld\n", DRIVER_NAME, PTR_ERR(gpio_pdev));
platform_driver_unregister(&p50_gpio_driver);
return PTR_ERR(gpio_pdev);
}
return 0;
}
static void __exit p50_module_exit(void)
{
platform_device_unregister(gpio_pdev);
platform_driver_unregister(&p50_gpio_driver);
}
module_init(p50_module_init);
module_exit(p50_module_exit);
MODULE_AUTHOR("Santosh Kumar Yadav, Barco NV <santoshkumar.yadav@barco.com>");
MODULE_DESCRIPTION("Barco P50 identify GPIOs driver");
MODULE_LICENSE("GPL");
......@@ -40,6 +40,7 @@ static bool wmi_requires_smbios_request;
struct dell_wmi_priv {
struct input_dev *input_dev;
struct input_dev *tabletswitch_dev;
u32 interface_version;
};
......@@ -309,6 +310,9 @@ static const struct key_entry dell_wmi_keymap_type_0010[] = {
* Keymap for WMI events of type 0x0011
*/
static const struct key_entry dell_wmi_keymap_type_0011[] = {
/* Reflex keyboard switch on 2n1 devices */
{ KE_IGNORE, 0xe070, { KEY_RESERVED } },
/* Battery unplugged */
{ KE_IGNORE, 0xfff0, { KEY_RESERVED } },
......@@ -340,21 +344,55 @@ static const struct key_entry dell_wmi_keymap_type_0011[] = {
* They are events with extended data
*/
static const struct key_entry dell_wmi_keymap_type_0012[] = {
/* Ultra-performance mode switch request */
{ KE_IGNORE, 0x000d, { KEY_RESERVED } },
/* Fn-lock button pressed */
{ KE_IGNORE, 0xe035, { KEY_RESERVED } },
};
static void dell_wmi_process_key(struct wmi_device *wdev, int type, int code)
static void dell_wmi_switch_event(struct input_dev **subdev,
const char *devname,
int switchid,
int value)
{
if (!*subdev) {
struct input_dev *dev = input_allocate_device();
if (!dev) {
pr_warn("could not allocate device for %s\n", devname);
return;
}
__set_bit(EV_SW, (dev)->evbit);
__set_bit(switchid, (dev)->swbit);
(dev)->name = devname;
(dev)->id.bustype = BUS_HOST;
if (input_register_device(dev)) {
input_free_device(dev);
pr_warn("could not register device for %s\n", devname);
return;
}
*subdev = dev;
}
input_report_switch(*subdev, switchid, value);
input_sync(*subdev);
}
static int dell_wmi_process_key(struct wmi_device *wdev, int type, int code, u16 *buffer, int remaining)
{
struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
const struct key_entry *key;
int used = 0;
int value = 1;
key = sparse_keymap_entry_from_scancode(priv->input_dev,
(type << 16) | code);
if (!key) {
pr_info("Unknown key with type 0x%04x and code 0x%04x pressed\n",
type, code);
return;
return 0;
}
pr_debug("Key with type 0x%04x and code 0x%04x pressed\n", type, code);
......@@ -363,16 +401,27 @@ static void dell_wmi_process_key(struct wmi_device *wdev, int type, int code)
if ((key->keycode == KEY_BRIGHTNESSUP ||
key->keycode == KEY_BRIGHTNESSDOWN) &&
acpi_video_handles_brightness_key_presses())
return;
return 0;
if (type == 0x0000 && code == 0xe025 && !wmi_requires_smbios_request)
return;
return 0;
if (key->keycode == KEY_KBDILLUMTOGGLE)
if (key->keycode == KEY_KBDILLUMTOGGLE) {
dell_laptop_call_notifier(
DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED, NULL);
} else if (type == 0x0011 && code == 0xe070 && remaining > 0) {
dell_wmi_switch_event(&priv->tabletswitch_dev,
"Dell tablet mode switch",
SW_TABLET_MODE, !buffer[0]);
return 1;
} else if (type == 0x0012 && code == 0x000d && remaining > 0) {
value = (buffer[2] == 2);
used = 1;
}
sparse_keymap_report_entry(priv->input_dev, key, 1, true);
sparse_keymap_report_entry(priv->input_dev, key, value, true);
return used;
}
static void dell_wmi_notify(struct wmi_device *wdev,
......@@ -430,21 +479,26 @@ static void dell_wmi_notify(struct wmi_device *wdev,
case 0x0000: /* One key pressed or event occurred */
if (len > 2)
dell_wmi_process_key(wdev, buffer_entry[1],
buffer_entry[2]);
buffer_entry[2],
buffer_entry + 3,
len - 3);
/* Extended data is currently ignored */
break;
case 0x0010: /* Sequence of keys pressed */
case 0x0011: /* Sequence of events occurred */
for (i = 2; i < len; ++i)
dell_wmi_process_key(wdev, buffer_entry[1],
buffer_entry[i]);
i += dell_wmi_process_key(wdev, buffer_entry[1],
buffer_entry[i],
buffer_entry + i,
len - i - 1);
break;
case 0x0012:
if ((len > 4) && dell_privacy_process_event(buffer_entry[1], buffer_entry[3],
buffer_entry[4]))
/* dell_privacy_process_event has handled the event */;
else if (len > 2)
dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2]);
dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2],
buffer_entry + 3, len - 3);
break;
default: /* Unknown event */
pr_info("Unknown WMI event type 0x%x\n",
......@@ -661,6 +715,8 @@ static void dell_wmi_input_destroy(struct wmi_device *wdev)
struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
input_unregister_device(priv->input_dev);
if (priv->tabletswitch_dev)
input_unregister_device(priv->tabletswitch_dev);
}
/*
......
This diff is collapsed.
......@@ -868,6 +868,18 @@ static void dytc_profile_refresh(struct ideapad_private *priv)
}
}
static const struct dmi_system_id ideapad_dytc_v4_allow_table[] = {
{
/* Ideapad 5 Pro 16ACH6 */
.ident = "LENOVO 82L5",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "82L5")
}
},
{}
};
static int ideapad_dytc_profile_init(struct ideapad_private *priv)
{
int err, dytc_version;
......@@ -882,12 +894,21 @@ static int ideapad_dytc_profile_init(struct ideapad_private *priv)
return err;
/* Check DYTC is enabled and supports mode setting */
if (!test_bit(DYTC_QUERY_ENABLE_BIT, &output))
if (!test_bit(DYTC_QUERY_ENABLE_BIT, &output)) {
dev_info(&priv->platform_device->dev, "DYTC_QUERY_ENABLE_BIT returned false\n");
return -ENODEV;
}
dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF;
if (dytc_version < 5)
return -ENODEV;
if (dytc_version < 5) {
if (dytc_version < 4 || !dmi_check_system(ideapad_dytc_v4_allow_table)) {
dev_info(&priv->platform_device->dev,
"DYTC_VERSION is less than 4 or is not allowed: %d\n",
dytc_version);
return -ENODEV;
}
}
priv->dytc = kzalloc(sizeof(*priv->dytc), GFP_KERNEL);
if (!priv->dytc)
......@@ -1534,17 +1555,13 @@ static void ideapad_check_features(struct ideapad_private *priv)
static int ideapad_acpi_add(struct platform_device *pdev)
{
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
struct ideapad_private *priv;
struct acpi_device *adev;
acpi_status status;
unsigned long cfg;
int err, i;
err = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev);
if (err)
return -ENODEV;
if (eval_int(adev->handle, "_CFG", &cfg))
if (!adev || eval_int(adev->handle, "_CFG", &cfg))
return -ENODEV;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
......
......@@ -102,6 +102,22 @@ 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_ISHTP_ECLITE
tristate "Intel ISHTP eclite controller Driver"
depends on INTEL_ISH_HID
depends on ACPI
help
This driver is for accessing the PSE (Programmable Service Engine) -
an Embedded Controller like IP - using ISHTP (Integrated Sensor Hub
Transport Protocol) to get battery, thermal and UCSI (USB Type-C
Connector System Software Interface) related data from the platform.
Users who don't want to use discrete Embedded Controller on Intel's
Elkhartlake platform can leverage this integrated solution of
ECLite which is part of PSE subsystem.
To compile this driver as a module, choose M here: the module
will be called intel_ishtp_eclite.
config INTEL_MRFLD_PWRBTN
tristate "Intel Merrifield Basin Cove power button driver"
depends on INTEL_SOC_PMIC_MRFLD
......
......@@ -21,6 +21,7 @@ intel-vbtn-y := vbtn.o
obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o
# Intel miscellaneous drivers
obj-$(CONFIG_INTEL_ISHTP_ECLITE) += ishtp_eclite.o
intel_int0002_vgpio-y := int0002_vgpio.o
obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o
intel_oaktrail-y := oaktrail.o
......
......@@ -34,13 +34,11 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_data/x86/soc.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#define DRV_NAME "INT0002 Virtual GPIO"
/* For some reason the virtual GPIO pin tied to the GPE is numbered pin 2 */
......@@ -151,12 +149,6 @@ static struct irq_chip int0002_irqchip = {
.irq_set_wake = int0002_irq_set_wake,
};
static const struct x86_cpu_id int0002_cpu_ids[] = {
X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, NULL),
X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, NULL),
{}
};
static void int0002_init_irq_valid_mask(struct gpio_chip *chip,
unsigned long *valid_mask,
unsigned int ngpios)
......@@ -167,15 +159,13 @@ static void int0002_init_irq_valid_mask(struct gpio_chip *chip,
static int int0002_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct x86_cpu_id *cpu_id;
struct int0002_data *int0002;
struct gpio_irq_chip *girq;
struct gpio_chip *chip;
int irq, ret;
/* Menlow has a different INT0002 device? <sigh> */
cpu_id = x86_match_cpu(int0002_cpu_ids);
if (!cpu_id)
if (!soc_intel_is_byt() && !soc_intel_is_cht())
return -ENODEV;
irq = platform_get_irq(pdev, 0);
......
This diff is collapsed.
......@@ -60,7 +60,6 @@ MODULE_ALIAS("wmi:" WMI_EVENT_GUID2);
MODULE_ALIAS("wmi:" WMI_EVENT_GUID3);
MODULE_ALIAS("wmi:" WMI_METHOD_WMAB);
MODULE_ALIAS("wmi:" WMI_METHOD_WMBB);
MODULE_ALIAS("acpi*:LGEX0815:*");
static struct platform_device *pf_device;
static struct input_dev *wmi_input_dev;
......@@ -331,7 +330,7 @@ static ssize_t fan_mode_show(struct device *dev,
status = r->integer.value & 0x01;
kfree(r);
return snprintf(buffer, PAGE_SIZE, "%d\n", status);
return sysfs_emit(buffer, "%d\n", status);
}
static ssize_t usb_charge_store(struct device *dev,
......@@ -373,7 +372,7 @@ static ssize_t usb_charge_show(struct device *dev,
kfree(r);
return snprintf(buffer, PAGE_SIZE, "%d\n", status);
return sysfs_emit(buffer, "%d\n", status);
}
static ssize_t reader_mode_store(struct device *dev,
......@@ -415,7 +414,7 @@ static ssize_t reader_mode_show(struct device *dev,
kfree(r);
return snprintf(buffer, PAGE_SIZE, "%d\n", status);
return sysfs_emit(buffer, "%d\n", status);
}
static ssize_t fn_lock_store(struct device *dev,
......@@ -456,7 +455,7 @@ static ssize_t fn_lock_show(struct device *dev,
status = !!r->buffer.pointer[0];
kfree(r);
return snprintf(buffer, PAGE_SIZE, "%d\n", status);
return sysfs_emit(buffer, "%d\n", status);
}
static ssize_t battery_care_limit_store(struct device *dev,
......@@ -521,7 +520,7 @@ static ssize_t battery_care_limit_show(struct device *dev,
if (status != 80 && status != 100)
status = 0;
return snprintf(buffer, PAGE_SIZE, "%d\n", status);
return sysfs_emit(buffer, "%d\n", status);
}
static DEVICE_ATTR_RW(fan_mode);
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/acpi.h>
#include <linux/backlight.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/wmi.h>
/**
* enum wmi_brightness_method - WMI method IDs
* @WMI_BRIGHTNESS_METHOD_LEVEL: Get/Set EC brightness level status
* @WMI_BRIGHTNESS_METHOD_SOURCE: Get/Set EC Brightness Source
*/
enum wmi_brightness_method {
WMI_BRIGHTNESS_METHOD_LEVEL = 1,
WMI_BRIGHTNESS_METHOD_SOURCE = 2,
WMI_BRIGHTNESS_METHOD_MAX
};
/**
* enum wmi_brightness_mode - Operation mode for WMI-wrapped method
* @WMI_BRIGHTNESS_MODE_GET: Get the current brightness level/source.
* @WMI_BRIGHTNESS_MODE_SET: Set the brightness level.
* @WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL: Get the maximum brightness level. This
* is only valid when the WMI method is
* %WMI_BRIGHTNESS_METHOD_LEVEL.
*/
enum wmi_brightness_mode {
WMI_BRIGHTNESS_MODE_GET = 0,
WMI_BRIGHTNESS_MODE_SET = 1,
WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2,
WMI_BRIGHTNESS_MODE_MAX
};
/**
* enum wmi_brightness_source - Backlight brightness control source selection
* @WMI_BRIGHTNESS_SOURCE_GPU: Backlight brightness is controlled by the GPU.
* @WMI_BRIGHTNESS_SOURCE_EC: Backlight brightness is controlled by the
* system's Embedded Controller (EC).
* @WMI_BRIGHTNESS_SOURCE_AUX: Backlight brightness is controlled over the
* DisplayPort AUX channel.
*/
enum wmi_brightness_source {
WMI_BRIGHTNESS_SOURCE_GPU = 1,
WMI_BRIGHTNESS_SOURCE_EC = 2,
WMI_BRIGHTNESS_SOURCE_AUX = 3,
WMI_BRIGHTNESS_SOURCE_MAX
};
/**
* struct wmi_brightness_args - arguments for the WMI-wrapped ACPI method
* @mode: Pass in an &enum wmi_brightness_mode value to select between
* getting or setting a value.
* @val: In parameter for value to set when using %WMI_BRIGHTNESS_MODE_SET
* mode. Not used in conjunction with %WMI_BRIGHTNESS_MODE_GET or
* %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode.
* @ret: Out parameter returning retrieved value when operating in
* %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL
* mode. Not used in %WMI_BRIGHTNESS_MODE_SET mode.
* @ignored: Padding; not used. The ACPI method expects a 24 byte params struct.
*
* This is the parameters structure for the WmiBrightnessNotify ACPI method as
* wrapped by WMI. The value passed in to @val or returned by @ret will be a
* brightness value when the WMI method ID is %WMI_BRIGHTNESS_METHOD_LEVEL, or
* an &enum wmi_brightness_source value with %WMI_BRIGHTNESS_METHOD_SOURCE.
*/
struct wmi_brightness_args {
u32 mode;
u32 val;
u32 ret;
u32 ignored[3];
};
/**
* wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method
* @w: Pointer to the struct wmi_device identified by %WMI_BRIGHTNESS_GUID
* @id: The WMI method ID to call (e.g. %WMI_BRIGHTNESS_METHOD_LEVEL or
* %WMI_BRIGHTNESS_METHOD_SOURCE)
* @mode: The operation to perform on the method (e.g. %WMI_BRIGHTNESS_MODE_SET
* or %WMI_BRIGHTNESS_MODE_GET)
* @val: Pointer to a value passed in by the caller when @mode is
* %WMI_BRIGHTNESS_MODE_SET, or a value passed out to caller when @mode
* is %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL.
*
* Returns 0 on success, or a negative error number on failure.
*/
static int wmi_brightness_notify(struct wmi_device *w, enum wmi_brightness_method id, enum wmi_brightness_mode mode, u32 *val)
{
struct wmi_brightness_args args = {
.mode = mode,
.val = 0,
.ret = 0,
};
struct acpi_buffer buf = { (acpi_size)sizeof(args), &args };
acpi_status status;
if (id < WMI_BRIGHTNESS_METHOD_LEVEL ||
id >= WMI_BRIGHTNESS_METHOD_MAX ||
mode < WMI_BRIGHTNESS_MODE_GET || mode >= WMI_BRIGHTNESS_MODE_MAX)
return -EINVAL;
if (mode == WMI_BRIGHTNESS_MODE_SET)
args.val = *val;
status = wmidev_evaluate_method(w, 0, id, &buf, &buf);
if (ACPI_FAILURE(status)) {
dev_err(&w->dev, "EC backlight control failed: %s\n",
acpi_format_exception(status));
return -EIO;
}
if (mode != WMI_BRIGHTNESS_MODE_SET)
*val = args.ret;
return 0;
}
static int nvidia_wmi_ec_backlight_update_status(struct backlight_device *bd)
{
struct wmi_device *wdev = bl_get_data(bd);
return wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL,
WMI_BRIGHTNESS_MODE_SET,
&bd->props.brightness);
}
static int nvidia_wmi_ec_backlight_get_brightness(struct backlight_device *bd)
{
struct wmi_device *wdev = bl_get_data(bd);
u32 level;
int ret;
ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL,
WMI_BRIGHTNESS_MODE_GET, &level);
if (ret < 0)
return ret;
return level;
}
static const struct backlight_ops nvidia_wmi_ec_backlight_ops = {
.update_status = nvidia_wmi_ec_backlight_update_status,
.get_brightness = nvidia_wmi_ec_backlight_get_brightness,
};
static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ctx)
{
struct backlight_properties props = {};
struct backlight_device *bdev;
u32 source;
int ret;
ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_SOURCE,
WMI_BRIGHTNESS_MODE_GET, &source);
if (ret)
return ret;
/*
* This driver is only to be used when brightness control is handled
* by the EC; otherwise, the GPU driver(s) should control brightness.
*/
if (source != WMI_BRIGHTNESS_SOURCE_EC)
return -ENODEV;
/*
* Identify this backlight device as a firmware device so that it can
* be prioritized over any exposed GPU-driven raw device(s).
*/
props.type = BACKLIGHT_FIRMWARE;
ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL,
WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL,
&props.max_brightness);
if (ret)
return ret;
ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_LEVEL,
WMI_BRIGHTNESS_MODE_GET, &props.brightness);
if (ret)
return ret;
bdev = devm_backlight_device_register(&wdev->dev,
"nvidia_wmi_ec_backlight",
&wdev->dev, wdev,
&nvidia_wmi_ec_backlight_ops,
&props);
return PTR_ERR_OR_ZERO(bdev);
}
#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7"
static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table[] = {
{ .guid_string = WMI_BRIGHTNESS_GUID },
{ }
};
MODULE_DEVICE_TABLE(wmi, nvidia_wmi_ec_backlight_id_table);
static struct wmi_driver nvidia_wmi_ec_backlight_driver = {
.driver = {
.name = "nvidia-wmi-ec-backlight",
},
.probe = nvidia_wmi_ec_backlight_probe,
.id_table = nvidia_wmi_ec_backlight_id_table,
};
module_wmi_driver(nvidia_wmi_ec_backlight_driver);
MODULE_AUTHOR("Daniel Dadap <ddadap@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA WMI EC Backlight driver");
MODULE_LICENSE("GPL");
......@@ -470,7 +470,7 @@ static ssize_t numbatt_show(struct device *dev, struct device_attribute *attr,
if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
}
static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr,
......@@ -482,7 +482,7 @@ static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr,
if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
}
static ssize_t mute_show(struct device *dev, struct device_attribute *attr,
......@@ -494,7 +494,7 @@ static ssize_t mute_show(struct device *dev, struct device_attribute *attr,
if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_MUTE]);
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_MUTE]);
}
static ssize_t mute_store(struct device *dev, struct device_attribute *attr,
......@@ -524,7 +524,7 @@ static ssize_t sticky_key_show(struct device *dev, struct device_attribute *attr
if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sticky_key);
return sysfs_emit(buf, "%u\n", pcc->sticky_key);
}
static ssize_t sticky_key_store(struct device *dev, struct device_attribute *attr,
......@@ -566,7 +566,7 @@ static ssize_t eco_mode_show(struct device *dev, struct device_attribute *attr,
result = -EIO;
break;
}
return snprintf(buf, PAGE_SIZE, "%u\n", result);
return sysfs_emit(buf, "%u\n", result);
}
static ssize_t eco_mode_store(struct device *dev, struct device_attribute *attr,
......@@ -625,7 +625,7 @@ static ssize_t ac_brightness_show(struct device *dev, struct device_attribute *a
if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]);
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]);
}
static ssize_t ac_brightness_store(struct device *dev, struct device_attribute *attr,
......@@ -655,7 +655,7 @@ static ssize_t dc_brightness_show(struct device *dev, struct device_attribute *a
if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]);
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]);
}
static ssize_t dc_brightness_store(struct device *dev, struct device_attribute *attr,
......@@ -685,7 +685,7 @@ static ssize_t current_brightness_show(struct device *dev, struct device_attribu
if (!acpi_pcc_retrieve_biosdata(pcc))
return -EIO;
return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]);
return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]);
}
static ssize_t current_brightness_store(struct device *dev, struct device_attribute *attr,
......@@ -710,7 +710,7 @@ static ssize_t current_brightness_store(struct device *dev, struct device_attrib
static ssize_t cdpower_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", get_optd_power_state());
return sysfs_emit(buf, "%d\n", get_optd_power_state());
}
static ssize_t cdpower_store(struct device *dev, struct device_attribute *attr,
......
......@@ -964,7 +964,7 @@ static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *a
if (item->validate)
value = item->validate(SNC_VALIDATE_OUT, value);
return snprintf(buffer, PAGE_SIZE, "%d\n", value);
return sysfs_emit(buffer, "%d\n", value);
}
static ssize_t sony_nc_sysfs_store(struct device *dev,
......@@ -1811,9 +1811,7 @@ static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
struct device_attribute *attr, char *buffer)
{
ssize_t count = 0;
count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode);
return count;
return sysfs_emit(buffer, "%d\n", kbdbl_ctl->mode);
}
static int __sony_nc_kbd_backlight_timeout_set(u8 value)
......@@ -1855,9 +1853,7 @@ static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
struct device_attribute *attr, char *buffer)
{
ssize_t count = 0;
count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout);
return count;
return sysfs_emit(buffer, "%d\n", kbdbl_ctl->timeout);
}
static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
......@@ -2051,21 +2047,18 @@ static ssize_t sony_nc_battery_care_limit_show(struct device *dev,
break;
}
return snprintf(buffer, PAGE_SIZE, "%d\n", status);
return sysfs_emit(buffer, "%d\n", status);
}
static ssize_t sony_nc_battery_care_health_show(struct device *dev,
struct device_attribute *attr, char *buffer)
{
ssize_t count = 0;
unsigned int health;
if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health))
return -EIO;
count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff);
return count;
return sysfs_emit(buffer, "%d\n", health & 0xff);
}
static int sony_nc_battery_care_setup(struct platform_device *pd,
......@@ -2215,15 +2208,12 @@ static ssize_t sony_nc_thermal_mode_store(struct device *dev,
static ssize_t sony_nc_thermal_mode_show(struct device *dev,
struct device_attribute *attr, char *buffer)
{
ssize_t count = 0;
int mode = sony_nc_thermal_mode_get();
if (mode < 0)
return mode;
count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]);
return count;
return sysfs_emit(buffer, "%s\n", snc_thermal_profiles[mode]);
}
static int sony_nc_thermal_setup(struct platform_device *pd)
......@@ -2361,7 +2351,7 @@ static ssize_t sony_nc_lid_resume_show(struct device *dev,
while (pos < LID_RESUME_MAX) {
if (&lid_ctl->attrs[pos].attr == &attr->attr)
return snprintf(buffer, PAGE_SIZE, "%d\n",
return sysfs_emit(buffer, "%d\n",
(lid_ctl->status >> pos) & 0x01);
pos++;
}
......@@ -2493,7 +2483,7 @@ static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
if (pos < 0)
return pos;
return snprintf(buffer, PAGE_SIZE, "%s\n",
return sysfs_emit(buffer, "%s\n",
pos == SPEED ? "speed" :
pos == STAMINA ? "stamina" :
pos == AUTO ? "auto" : "unknown");
......@@ -2568,7 +2558,7 @@ static ssize_t sony_nc_highspeed_charging_show(struct device *dev,
if (sony_call_snc_handle(0x0131, 0x0100, &result))
return -EIO;
return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
return sysfs_emit(buffer, "%d\n", result & 0x01);
}
static int sony_nc_highspeed_charging_setup(struct platform_device *pd)
......@@ -2642,7 +2632,7 @@ static ssize_t sony_nc_lowbatt_show(struct device *dev,
if (sony_call_snc_handle(0x0121, 0x0200, &result))
return -EIO;
return snprintf(buffer, PAGE_SIZE, "%d\n", result & 1);
return sysfs_emit(buffer, "%d\n", result & 1);
}
static int sony_nc_lowbatt_setup(struct platform_device *pd)
......@@ -2708,7 +2698,7 @@ static ssize_t sony_nc_hsfan_show(struct device *dev,
if (sony_call_snc_handle(0x0149, 0x0100, &result))
return -EIO;
return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
return sysfs_emit(buffer, "%d\n", result & 0x01);
}
static ssize_t sony_nc_fanspeed_show(struct device *dev,
......@@ -2719,7 +2709,7 @@ static ssize_t sony_nc_fanspeed_show(struct device *dev,
if (sony_call_snc_handle(0x0149, 0x0300, &result))
return -EIO;
return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
return sysfs_emit(buffer, "%d\n", result & 0xff);
}
static int sony_nc_fanspeed_setup(struct platform_device *pd)
......@@ -2815,7 +2805,7 @@ static ssize_t sony_nc_usb_charge_show(struct device *dev,
if (sony_call_snc_handle(0x0155, 0x0000, &result))
return -EIO;
return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
return sysfs_emit(buffer, "%d\n", result & 0x01);
}
static int sony_nc_usb_charge_setup(struct platform_device *pd)
......@@ -2870,7 +2860,7 @@ static ssize_t sony_nc_panelid_show(struct device *dev,
if (sony_call_snc_handle(0x011D, 0x0000, &result))
return -EIO;
return snprintf(buffer, PAGE_SIZE, "%d\n", result);
return sysfs_emit(buffer, "%d\n", result);
}
static int sony_nc_panelid_setup(struct platform_device *pd)
......@@ -2998,7 +2988,7 @@ static ssize_t sony_nc_touchpad_show(struct device *dev,
if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result))
return -EINVAL;
return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01));
return sysfs_emit(buffer, "%d\n", !(result & 0x01));
}
static int sony_nc_touchpad_setup(struct platform_device *pd,
......@@ -3915,7 +3905,7 @@ static ssize_t sony_pic_wwanpower_show(struct device *dev,
{
ssize_t count;
mutex_lock(&spic_dev.lock);
count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
count = sysfs_emit(buffer, "%d\n", spic_dev.wwan_power);
mutex_unlock(&spic_dev.lock);
return count;
}
......@@ -3954,7 +3944,7 @@ static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
{
ssize_t count = 0;
mutex_lock(&spic_dev.lock);
count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
count = sysfs_emit(buffer, "%d\n", spic_dev.bluetooth_power);
mutex_unlock(&spic_dev.lock);
return count;
}
......@@ -3996,7 +3986,7 @@ static ssize_t sony_pic_fanspeed_show(struct device *dev,
if (sony_pic_get_fanspeed(&value))
return -EIO;
return snprintf(buffer, PAGE_SIZE, "%d\n", value);
return sysfs_emit(buffer, "%d\n", value);
}
#define SPIC_ATTR(_name, _mode) \
......
This diff is collapsed.
This diff is collapsed.
......@@ -938,6 +938,23 @@ static const struct ts_dmi_data trekstor_surftab_wintron70_data = {
.properties = trekstor_surftab_wintron70_props,
};
static const struct property_entry viglen_connect_10_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1890),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
PROPERTY_ENTRY_U32("touchscreen-fuzz-x", 6),
PROPERTY_ENTRY_U32("touchscreen-fuzz-y", 6),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-viglen-connect-10.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
};
static const struct ts_dmi_data viglen_connect_10_data = {
.acpi_name = "MSSL1680:00",
.properties = viglen_connect_10_props,
};
static const struct property_entry vinga_twizzle_j116_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1920),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
......@@ -1521,6 +1538,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "YOURBOOK C11B"),
},
},
{
/* Viglen Connect 10 */
.driver_data = (void *)&viglen_connect_10_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Viglen Ltd."),
DMI_MATCH(DMI_PRODUCT_NAME, "Connect 10'' Tablet PC"),
},
},
{
/* Vinga Twizzle J116 */
.driver_data = (void *)&vinga_twizzle_j116_data,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -792,8 +792,8 @@ enum ssam_event_mask {
#define SSAM_EVENT_REGISTRY_KIP \
SSAM_EVENT_REGISTRY(SSAM_SSH_TC_KIP, 0x02, 0x27, 0x28)
#define SSAM_EVENT_REGISTRY_REG \
SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, 0x02, 0x01, 0x02)
#define SSAM_EVENT_REGISTRY_REG(tid)\
SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, tid, 0x01, 0x02)
/**
* enum ssam_event_notifier_flags - Flags for event notifiers.
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment