Commit 09a0bd07 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull x86 platform driver updates from Andy Shevchenko:

 - ASUS WMI driver honors BAT1 name of the battery (quite a few new
   laptops are using it)

 - Dell WMI driver supports new key codes and backlight events

 - ThinkPad ACPI driver now may use standard charge threshold interface,
   it also has been updated to provide Laptop or Desktop mode to the
   user

 - Intel Speed Select Technology gained support on Sapphire Rapids
   platform

 - Regular update of Speed Select Technology tools

 - Mellanox has been updated to support complex attributes

 - PMC core driver has been fixed to show correct names for LPM0
   register

 - HTTP links were replaced by HTTPS ones where it applies

 - Miscellaneous fixes and cleanups here and there

* tag 'platform-drivers-x86-v5.9-1' of git://git.infradead.org/linux-platform-drivers-x86: (42 commits)
  platform/x86: asus-nb-wmi: Drop duplicate DMI quirk structures
  platform/x86: thinkpad_acpi: Make some symbols static
  platform/x86: thinkpad_acpi: add documentation for battery charge control
  platform/x86: thinkpad_acpi: use standard charge control attribute names
  platform/x86: thinkpad_acpi: remove unused defines
  platform/x86: ISST: drop a duplicated word in isst_if.h
  tools/power/x86/intel-speed-select: Update version for v5.9
  tools/power/x86/intel-speed-select: Add retries for mail box commands
  tools/power/x86/intel-speed-select: Add option to delay mbox commands
  tools/power/x86/intel-speed-select: Ignore -o option processing on error
  tools/power/x86/intel-speed-select: Change path for caching topology info
  platform/x86: acerhdf: Replace HTTP links with HTTPS ones
  platform/x86: apple-gmux: Replace HTTP links with HTTPS ones
  platform/x86: pcengines-apuv2: revert wiring up simswitch GPIO as LED
  platform/x86: mlx-platform: Extend FAN platform data description
  platform_data/mlxreg: Add presence register field for FAN devices
  Documentation/ABI: Add new attribute for mlxreg-io sysfs interfaces
  platform/mellanox: mlxreg-io: Add support for complex attributes
  platform/x86: mlx-platform: Add more definitions for system attributes
  platform_data/mlxreg: Add support for complex attributes
  ...
parents e53bc3ff 67186653
......@@ -206,3 +206,20 @@ Description: This file exposes the firmware version of burnable voltage
regulator devices.
The file is read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld1_pn
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld2_pn
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld3_pn
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld4_pn
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld1_version_min
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld2_version_min
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld3_version_min
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld4_version_min
Date: July 2020
KernelVersion: 5.9
Contact: Vadim Pasternak <vadimpmellanox.com>
Description: These files show with which CPLD part numbers and minor
versions have been burned CPLD devices equipped on a
system.
The files are read only.
......@@ -50,6 +50,7 @@ detailed description):
- WAN enable and disable
- UWB enable and disable
- LCD Shadow (PrivacyGuard) enable and disable
- Lap mode sensor
A compatibility table by model and feature is maintained on the web
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
......@@ -1432,6 +1433,20 @@ The first command ensures the best viewing angle and the latter one turns
on the feature, restricting the viewing angles.
DYTC Lapmode sensor
------------------
sysfs: dytc_lapmode
Newer thinkpads and mobile workstations have the ability to determine if
the device is in deskmode or lapmode. This feature is used by user space
to decide if WWAN transmission can be increased to maximum power and is
also useful for understanding the different thermal modes available as
they differ between desk and lap mode.
The property is read-only. If the platform doesn't have support the sysfs
class is not created.
EXPERIMENTAL: UWB
-----------------
......@@ -1470,6 +1485,23 @@ For more details about which buttons will appear depending on the mode, please
review the laptop's user guide:
http://www.lenovo.com/shop/americas/content/user_guides/x1carbon_2_ug_en.pdf
Battery charge control
----------------------
sysfs attributes:
/sys/class/power_supply/BAT*/charge_control_{start,end}_threshold
These two attributes are created for those batteries that are supported by the
driver. They enable the user to control the battery charge thresholds of the
given battery. Both values may be read and set. `charge_control_start_threshold`
accepts an integer between 0 and 99 (inclusive); this value represents a battery
percentage level, below which charging will begin. `charge_control_end_threshold`
accepts an integer between 1 and 100 (inclusive); this value represents a battery
percentage level, above which charging will stop.
The exact semantics of the attributes may be found in
Documentation/ABI/testing/sysfs-class-power.
Multiple Commands, Module Parameters
------------------------------------
......
......@@ -8610,6 +8610,12 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/intel_atomisp2_pm.c
INTEL ATOMISP2 LED DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/intel_atomisp2_led.c
INTEL BROXTON PMC DRIVER
M: Mika Westerberg <mika.westerberg@linux.intel.com>
M: Zha Qipeng <qipeng.zha@intel.com>
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved.
* Copyright (c) 2016-2018 Vadim Pasternak <vadimp@mellanox.com>
* Mellanox hotplug driver
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* Copyright (C) 2016-2020 Mellanox Technologies
*/
#include <linux/bitops.h>
......@@ -42,6 +16,7 @@
#include <linux/platform_data/mlxreg.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/string_helpers.h>
#include <linux/regmap.h>
#include <linux/workqueue.h>
......@@ -97,6 +72,23 @@ struct mlxreg_hotplug_priv_data {
u8 not_asserted;
};
/* Environment variables array for udev. */
static char *mlxreg_hotplug_udev_envp[] = { NULL, NULL };
static int
mlxreg_hotplug_udev_event_send(struct kobject *kobj,
struct mlxreg_core_data *data, bool action)
{
char event_str[MLXREG_CORE_LABEL_MAX_SIZE + 2];
char label[MLXREG_CORE_LABEL_MAX_SIZE] = { 0 };
mlxreg_hotplug_udev_envp[0] = event_str;
string_upper(label, data->label);
snprintf(event_str, MLXREG_CORE_LABEL_MAX_SIZE, "%s=%d", label, !!action);
return kobject_uevent_env(kobj, KOBJ_CHANGE, mlxreg_hotplug_udev_envp);
}
static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
struct mlxreg_core_data *data)
{
......@@ -104,7 +96,7 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
struct i2c_client *client;
/* Notify user by sending hwmon uevent. */
kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, true);
/*
* Return if adapter number is negative. It could be in case hotplug
......@@ -144,7 +136,7 @@ mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
struct mlxreg_core_data *data)
{
/* Notify user by sending hwmon uevent. */
kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false);
if (data->hpdev.client) {
i2c_unregister_device(data->hpdev.client);
......@@ -199,17 +191,49 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
struct mlxreg_core_hotplug_platform_data *pdata;
struct mlxreg_core_item *item;
struct mlxreg_core_data *data;
int num_attrs = 0, id = 0, i, j;
unsigned long mask;
u32 regval;
int num_attrs = 0, id = 0, i, j, k, ret;
pdata = dev_get_platdata(&priv->pdev->dev);
item = pdata->items;
/* Go over all kinds of items - psu, pwr, fan. */
for (i = 0; i < pdata->counter; i++, item++) {
num_attrs += item->count;
if (item->capability) {
/*
* Read group capability register to get actual number
* of interrupt capable components and set group mask
* accordingly.
*/
ret = regmap_read(priv->regmap, item->capability,
&regval);
if (ret)
return ret;
item->mask = GENMASK((regval & item->mask) - 1, 0);
}
data = item->data;
/* Go over all units within the item. */
for (j = 0; j < item->count; j++, data++, id++) {
/* Go over all unmasked units within item. */
mask = item->mask;
k = 0;
for_each_set_bit(j, &mask, item->count) {
if (data->capability) {
/*
* Read capability register and skip non
* relevant attributes.
*/
ret = regmap_read(priv->regmap,
data->capability, &regval);
if (ret)
return ret;
if (!(regval & data->bit)) {
data++;
continue;
}
}
PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
GFP_KERNEL,
......@@ -227,9 +251,13 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
PRIV_DEV_ATTR(id).dev_attr.show =
mlxreg_hotplug_attr_show;
PRIV_DEV_ATTR(id).nr = i;
PRIV_DEV_ATTR(id).index = j;
PRIV_DEV_ATTR(id).index = k;
sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
data++;
id++;
k++;
}
num_attrs += k;
}
priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
......@@ -507,20 +535,6 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
item = pdata->items;
for (i = 0; i < pdata->counter; i++, item++) {
if (item->capability) {
/*
* Read group capability register to get actual number
* of interrupt capable components and set group mask
* accordingly.
*/
ret = regmap_read(priv->regmap, item->capability,
&regval);
if (ret)
goto out;
item->mask = GENMASK((regval & item->mask) - 1, 0);
}
/* Clear group presense event. */
ret = regmap_write(priv->regmap, item->reg +
MLXREG_HOTPLUG_EVENT_OFF, 0);
......
......@@ -30,6 +30,7 @@
* @mlxreg_io_dev_attr: sysfs sensor device attribute array;
* @group: sysfs attribute group;
* @groups: list of sysfs attribute group for hwmon registration;
* @regsize: size of a register value;
*/
struct mlxreg_io_priv_data {
struct platform_device *pdev;
......@@ -39,27 +40,30 @@ struct mlxreg_io_priv_data {
struct sensor_device_attribute mlxreg_io_dev_attr[MLXREG_IO_ATT_NUM];
struct attribute_group group;
const struct attribute_group *groups[2];
int regsize;
};
static int
mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val,
bool rw_flag, u32 *regval)
bool rw_flag, int regsize, u32 *regval)
{
int ret;
int i, val, ret;
ret = regmap_read(regmap, data->reg, regval);
if (ret)
goto access_error;
/*
* There are three kinds of attributes: single bit, full register's
* bits and bit sequence. For the first kind field mask indicates which
* bits are not related and field bit is set zero. For the second kind
* field mask is set to zero and field bit is set with all bits one.
* No special handling for such kind of attributes - pass value as is.
* For the third kind, field mask indicates which bits are related and
* field bit is set to the first bit number (from 1 to 32) is the bit
* sequence.
* There are four kinds of attributes: single bit, full register's
* bits, bit sequence, bits in few registers For the first kind field
* mask indicates which bits are not related and field bit is set zero.
* For the second kind field mask is set to zero and field bit is set
* with all bits one. No special handling for such kind of attributes -
* pass value as is. For the third kind, the field mask indicates which
* bits are related and the field bit is set to the first bit number
* (from 1 to 32) is the bit sequence. For the fourth kind - the number
* of registers which should be read for getting an attribute are
* specified through 'data->regnum' field.
*/
if (!data->bit) {
/* Single bit. */
......@@ -83,6 +87,19 @@ mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val,
/* Clear relevant bits and set them to new value. */
*regval = (*regval & ~data->mask) | in_val;
}
} else {
/*
* Some attributes could occupied few registers in case regmap
* bit size is 8 or 16. Compose such attributes from 'regnum'
* registers. Such attributes contain read-only data.
*/
for (i = 1; i < data->regnum; i++) {
ret = regmap_read(regmap, data->reg + i, &val);
if (ret)
goto access_error;
*regval |= rol32(val, regsize * i);
}
}
access_error:
......@@ -99,7 +116,8 @@ mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr,
u32 regval = 0;
int ret;
ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, &regval);
ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true,
priv->regsize, &regval);
if (ret)
goto access_error;
......@@ -128,7 +146,7 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr,
return ret;
ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false,
&regval);
priv->regsize, &regval);
if (ret)
goto access_error;
......@@ -207,6 +225,9 @@ static int mlxreg_io_probe(struct platform_device *pdev)
}
priv->pdev = pdev;
priv->regsize = regmap_get_val_bytes(priv->pdata->regmap);
if (priv->regsize < 0)
return priv->regsize;
err = mlxreg_io_attr_init(priv);
if (err) {
......
......@@ -140,7 +140,7 @@ config ACERHDF
in the same node directory will tell you if it is "acerhdf".
For more information about this driver see
<http://piie.net/files/acerhdf_README.txt>
<https://piie.net/files/acerhdf_README.txt>
If you have an Acer Aspire One netbook, say Y or M
here.
......@@ -748,6 +748,27 @@ config THINKPAD_ACPI_HOTKEY_POLL
If you are not sure, say Y here. The driver enables polling only if
it is strictly necessary to do so.
config INTEL_ATOMISP2_LED
tristate "Intel AtomISP2 camera LED driver"
depends on GPIOLIB && LEDS_GPIO
help
Many Bay Trail and Cherry Trail devices come with a camera attached
to Intel's Image Signal Processor. Linux currently does not have a
driver for these, so they do not work as a camera. Some of these
camera's have a LED which is controlled through a GPIO.
Some of these devices have a firmware issue where the LED gets turned
on at boot. This driver will turn the LED off at boot and also allows
controlling the LED (repurposing it) through the sysfs LED interface.
Which GPIO is attached to the LED is usually not described in the
ACPI tables, so this driver contains per-system info about the GPIO
inside the driver, this means that this driver only works on systems
the driver knows about.
To compile this driver as a module, choose M here: the module
will be called intel_atomisp2_led.
config INTEL_ATOMISP2_PM
tristate "Intel AtomISP2 dummy / power-management driver"
depends on PCI && IOSF_MBI && PM
......
......@@ -69,6 +69,7 @@ obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
# Intel
obj-$(CONFIG_INTEL_ATOMISP2_LED) += intel_atomisp2_led.o
obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o
intel_cht_int33fe-objs := intel_cht_int33fe_common.o \
......
......@@ -5,7 +5,7 @@
* as soon as the upper/lower threshold is reached.
*
* (C) 2009 - Peter Kaestle peter (a) piie.net
* http://piie.net
* https://piie.net
* 2009 Borislav Petkov bp (a) alien8.de
*
* Inspired by and many thanks to:
......
......@@ -277,8 +277,8 @@ static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
* MBP5 2008/09 uses a `TI LP8543`_ backlight driver. All newer models
* use a `TI LP8545`_.
*
* .. _TI LP8543: http://www.ti.com/lit/ds/symlink/lp8543.pdf
* .. _TI LP8545: http://www.ti.com/lit/ds/symlink/lp8545.pdf
* .. _TI LP8543: https://www.ti.com/lit/ds/symlink/lp8543.pdf
* .. _TI LP8545: https://www.ti.com/lit/ds/symlink/lp8545.pdf
*/
static int gmux_get_brightness(struct backlight_device *bd)
......@@ -373,14 +373,14 @@ static const struct backlight_ops gmux_bl_ops = {
* switch the panel and the external DP connector and allocates a framebuffer
* for the selected GPU.
*
* .. _US 8,687,007 B2: http://pimg-fpiw.uspto.gov/fdd/07/870/086/0.pdf
* .. _NXP CBTL06141: http://www.nxp.com/documents/data_sheet/CBTL06141.pdf
* .. _NXP CBTL06142: http://www.nxp.com/documents/data_sheet/CBTL06141.pdf
* .. _TI HD3SS212: http://www.ti.com/lit/ds/symlink/hd3ss212.pdf
* .. _US 8,687,007 B2: https://pimg-fpiw.uspto.gov/fdd/07/870/086/0.pdf
* .. _NXP CBTL06141: https://www.nxp.com/documents/data_sheet/CBTL06141.pdf
* .. _NXP CBTL06142: https://www.nxp.com/documents/data_sheet/CBTL06141.pdf
* .. _TI HD3SS212: https://www.ti.com/lit/ds/symlink/hd3ss212.pdf
* .. _Pericom PI3VDP12412: https://www.pericom.com/assets/Datasheets/PI3VDP12412.pdf
* .. _TI SN74LV4066A: http://www.ti.com/lit/ds/symlink/sn74lv4066a.pdf
* .. _TI SN74LV4066A: https://www.ti.com/lit/ds/symlink/sn74lv4066a.pdf
* .. _NXP CBTL03062: http://pdf.datasheetarchive.com/indexerfiles/Datasheets-SW16/DSASW00308511.pdf
* .. _TI TS3DS10224: http://www.ti.com/lit/ds/symlink/ts3ds10224.pdf
* .. _TI TS3DS10224: https://www.ti.com/lit/ds/symlink/ts3ds10224.pdf
*/
static void gmux_read_switch_state(struct apple_gmux_data *gmux_data)
......
......@@ -110,6 +110,11 @@ static struct quirk_entry quirk_asus_forceals = {
.wmi_force_als_set = true,
};
static struct quirk_entry quirk_asus_vendor_backlight = {
.wmi_backlight_power = true,
.wmi_backlight_set_devstate = true,
};
static int dmi_matched(const struct dmi_system_id *dmi)
{
pr_info("Identified laptop model '%s'\n", dmi->ident);
......@@ -411,6 +416,78 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_forceals,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. GA401IH",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA401IH"),
},
.driver_data = &quirk_asus_vendor_backlight,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. GA401II",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA401II"),
},
.driver_data = &quirk_asus_vendor_backlight,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. GA401IU",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA401IU"),
},
.driver_data = &quirk_asus_vendor_backlight,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. GA401IV",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA401IV"),
},
.driver_data = &quirk_asus_vendor_backlight,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. GA401IVC",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA401IVC"),
},
.driver_data = &quirk_asus_vendor_backlight,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. GA502II",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA502II"),
},
.driver_data = &quirk_asus_vendor_backlight,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. GA502IU",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA502IU"),
},
.driver_data = &quirk_asus_vendor_backlight,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. GA502IV",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GA502IV"),
},
.driver_data = &quirk_asus_vendor_backlight,
},
{},
};
......
......@@ -255,6 +255,10 @@ static const struct key_entry dell_wmi_keymap_type_0010[] = {
/* Keyboard backlight change notification */
{ KE_IGNORE, 0x3f, { KEY_RESERVED } },
/* Backlight brightness level */
{ KE_KEY, 0x57, { KEY_BRIGHTNESSDOWN } },
{ KE_KEY, 0x58, { KEY_BRIGHTNESSUP } },
/* Mic mute */
{ KE_KEY, 0x150, { KEY_MICMUTE } },
......@@ -330,6 +334,15 @@ static const struct key_entry dell_wmi_keymap_type_0011[] = {
{ KE_IGNORE, KBD_LED_AUTO_100_TOKEN, { KEY_RESERVED } },
};
/*
* Keymap for WMI events of type 0x0012
* They are events with extended data
*/
static const struct key_entry dell_wmi_keymap_type_0012[] = {
/* Fn-lock button pressed */
{ KE_IGNORE, 0xe035, { KEY_RESERVED } },
};
static void dell_wmi_process_key(struct wmi_device *wdev, int type, int code)
{
struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
......@@ -414,10 +427,11 @@ static void dell_wmi_notify(struct wmi_device *wdev,
switch (buffer_entry[1]) {
case 0x0000: /* One key pressed or event occurred */
case 0x0012: /* Event with extended data occurred */
if (len > 2)
dell_wmi_process_key(wdev, 0x0000,
dell_wmi_process_key(wdev, buffer_entry[1],
buffer_entry[2]);
/* Other entries could contain additional information */
/* Extended data is currently ignored */
break;
case 0x0010: /* Sequence of keys pressed */
case 0x0011: /* Sequence of events occurred */
......@@ -492,7 +506,7 @@ static void handle_dmi_entry(const struct dmi_header *dm, void *opaque)
u16 keycode = (bios_entry->keycode <
ARRAY_SIZE(bios_to_linux_keycode)) ?
bios_to_linux_keycode[bios_entry->keycode] :
KEY_RESERVED;
(bios_entry->keycode == 0xffff ? KEY_UNKNOWN : KEY_RESERVED);
/*
* Log if we find an entry in the DMI table that we don't
......@@ -552,6 +566,7 @@ static int dell_wmi_input_setup(struct wmi_device *wdev)
ARRAY_SIZE(dell_wmi_keymap_type_0000) +
ARRAY_SIZE(dell_wmi_keymap_type_0010) +
ARRAY_SIZE(dell_wmi_keymap_type_0011) +
ARRAY_SIZE(dell_wmi_keymap_type_0012) +
1,
sizeof(struct key_entry), GFP_KERNEL);
if (!keymap) {
......@@ -596,6 +611,13 @@ static int dell_wmi_input_setup(struct wmi_device *wdev)
pos++;
}
/* Append table with events of type 0x0012 */
for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
keymap[pos] = dell_wmi_keymap_type_0012[i];
keymap[pos].code |= (0x0012 << 16);
pos++;
}
/*
* Now append also table with "legacy" events of type 0x0000. Some of
* them are reported also on laptops which have scancodes in DMI.
......
......@@ -571,7 +571,7 @@ check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
if (acpi_match_device_ids(dev, ids) == 0)
if (acpi_create_platform_device(dev, NULL))
if (!IS_ERR_OR_NULL(acpi_create_platform_device(dev, NULL)))
dev_info(&dev->dev,
"intel-hid: created platform device\n");
......
......@@ -299,7 +299,7 @@ check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
if (acpi_match_device_ids(dev, ids) == 0)
if (acpi_create_platform_device(dev, NULL))
if (!IS_ERR_OR_NULL(acpi_create_platform_device(dev, NULL)))
dev_info(&dev->dev,
"intel-vbtn: created platform device\n");
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for controlling LEDs for cameras connected to the Intel atomisp2
* The main purpose of this driver is to turn off LEDs which are on at boot.
*
* Copyright (C) 2020 Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/dmi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
/* This must be leds-gpio as the leds-gpio driver binds to the name */
#define DEV_NAME "leds-gpio"
static const struct gpio_led atomisp2_leds[] = {
{
.name = "atomisp2::camera",
.default_state = LEDS_GPIO_DEFSTATE_OFF,
},
};
static const struct gpio_led_platform_data atomisp2_leds_pdata = {
.num_leds = ARRAY_SIZE(atomisp2_leds),
.leds = atomisp2_leds,
};
static struct gpiod_lookup_table asus_t100ta_lookup = {
.dev_id = DEV_NAME,
.table = {
GPIO_LOOKUP_IDX("INT33FC:02", 8, NULL, 0, GPIO_ACTIVE_HIGH),
{ }
}
};
static struct gpiod_lookup_table asus_t100chi_lookup = {
.dev_id = DEV_NAME,
.table = {
GPIO_LOOKUP_IDX("INT33FC:01", 24, NULL, 0, GPIO_ACTIVE_HIGH),
{ }
}
};
static const struct dmi_system_id atomisp2_led_systems[] __initconst = {
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
},
.driver_data = &asus_t100ta_lookup,
},
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T200TA"),
},
.driver_data = &asus_t100ta_lookup,
},
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100CHI"),
},
.driver_data = &asus_t100chi_lookup,
},
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(dmi, atomisp2_led_systems);
static struct gpiod_lookup_table *gpio_lookup;
static struct platform_device *pdev;
static int __init atomisp2_led_init(void)
{
const struct dmi_system_id *system;
system = dmi_first_match(atomisp2_led_systems);
if (!system)
return -ENODEV;
gpio_lookup = system->driver_data;
gpiod_add_lookup_table(gpio_lookup);
pdev = platform_device_register_resndata(NULL,
DEV_NAME, PLATFORM_DEVID_NONE,
NULL, 0, &atomisp2_leds_pdata,
sizeof(atomisp2_leds_pdata));
if (IS_ERR(pdev))
gpiod_remove_lookup_table(gpio_lookup);
return PTR_ERR_OR_ZERO(pdev);
}
static void __exit atomisp2_led_cleanup(void)
{
platform_device_unregister(pdev);
gpiod_remove_lookup_table(gpio_lookup);
}
module_init(atomisp2_led_init);
module_exit(atomisp2_led_cleanup);
/*
* The ACPI INIT method from Asus WMI's code on the T100TA and T200TA turns the
* LED on (without the WMI interface allowing further control over the LED).
* Ensure we are loaded after asus-nb-wmi so that we turn the LED off again.
*/
MODULE_SOFTDEP("pre: asus_nb_wmi");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
MODULE_DESCRIPTION("Intel atomisp2 camera LED driver");
MODULE_LICENSE("GPL");
......@@ -29,18 +29,16 @@ static int cht_int33fe_i2c_res_filter(struct acpi_resource *ares, void *data)
static int cht_int33fe_count_i2c_clients(struct device *dev)
{
struct acpi_device *adev;
struct acpi_device *adev = ACPI_COMPANION(dev);
LIST_HEAD(resource_list);
int count = 0;
int ret;
adev = ACPI_COMPANION(dev);
if (!adev)
return -EINVAL;
acpi_dev_get_resources(adev, &resource_list,
cht_int33fe_i2c_res_filter, &count);
ret = acpi_dev_get_resources(adev, &resource_list,
cht_int33fe_i2c_res_filter, &count);
acpi_dev_free_resource_list(&resource_list);
if (ret < 0)
return ret;
return count;
}
......
......@@ -415,7 +415,7 @@ static const struct pmc_bit_map tgl_lpm0_map[] = {
{"PCIe_Gen3PLL_OFF_STS", BIT(20)},
{"OPIOPLL_OFF_STS", BIT(21)},
{"OCPLL_OFF_STS", BIT(22)},
{"AudioPLL_OFF_STS", BIT(23)},
{"MainPLL_OFF_STS", BIT(23)},
{"MIPIPLL_OFF_STS", BIT(24)},
{"Fast_XTAL_Osc_OFF_STS", BIT(25)},
{"AC_Ring_Osc_OFF_STS", BIT(26)},
......@@ -795,7 +795,7 @@ static int pmc_core_mphy_pg_show(struct seq_file *s, void *unused)
msleep(10);
val_high = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET);
for (index = 0; map[index].name && index < 8; index++) {
for (index = 0; index < 8 && map[index].name; index++) {
seq_printf(s, "%-32s\tState: %s\n",
map[index].name,
map[index].bit_mask & val_low ? "Not power gated" :
......
......@@ -26,6 +26,10 @@
#define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET 0x01
#define MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET 0x02
#define MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET 0x03
#define MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET 0x04
#define MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET 0x06
#define MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET 0x08
#define MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET 0x0a
#define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d
#define MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET 0x1e
#define MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET 0x1f
......@@ -72,6 +76,10 @@
#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1
#define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2
#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3
#define MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET 0xde
#define MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET 0xdf
#define MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET 0xe0
#define MLXPLAT_CPLD_LPC_REG_CPLD4_MVER_OFFSET 0xe1
#define MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET 0xe2
#define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3
#define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4
......@@ -1303,6 +1311,32 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = {
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "cpld1_pn",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET,
.bit = GENMASK(15, 0),
.mode = 0444,
.regnum = 2,
},
{
.label = "cpld2_pn",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET,
.bit = GENMASK(15, 0),
.mode = 0444,
.regnum = 2,
},
{
.label = "cpld1_version_min",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "cpld2_version_min",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "reset_long_pb",
.reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
......@@ -1409,6 +1443,32 @@ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = {
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "cpld1_pn",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET,
.bit = GENMASK(15, 0),
.mode = 0444,
.regnum = 2,
},
{
.label = "cpld2_pn",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET,
.bit = GENMASK(15, 0),
.mode = 0444,
.regnum = 2,
},
{
.label = "cpld1_version_min",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "cpld2_version_min",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "reset_long_pb",
.reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
......@@ -1527,6 +1587,58 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "cpld1_pn",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET,
.bit = GENMASK(15, 0),
.mode = 0444,
.regnum = 2,
},
{
.label = "cpld2_pn",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET,
.bit = GENMASK(15, 0),
.mode = 0444,
.regnum = 2,
},
{
.label = "cpld3_pn",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET,
.bit = GENMASK(15, 0),
.mode = 0444,
.regnum = 2,
},
{
.label = "cpld4_pn",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET,
.bit = GENMASK(15, 0),
.mode = 0444,
.regnum = 2,
},
{
.label = "cpld1_version_min",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "cpld2_version_min",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "cpld3_version_min",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "cpld4_version_min",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD4_MVER_OFFSET,
.bit = GENMASK(7, 0),
.mode = 0444,
},
{
.label = "reset_long_pb",
.reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
......@@ -1728,6 +1840,8 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET,
.bit = BIT(0),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho2",
......@@ -1735,6 +1849,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET,
.bit = BIT(1),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho3",
......@@ -1742,6 +1857,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET,
.bit = BIT(2),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho4",
......@@ -1749,6 +1865,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET,
.bit = BIT(3),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho5",
......@@ -1756,6 +1873,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET,
.bit = BIT(4),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho6",
......@@ -1763,6 +1881,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET,
.bit = BIT(5),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho7",
......@@ -1770,6 +1889,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET,
.bit = BIT(6),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho8",
......@@ -1777,6 +1897,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET,
.bit = BIT(7),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho9",
......@@ -1784,6 +1905,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET,
.bit = BIT(0),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho10",
......@@ -1791,6 +1913,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET,
.bit = BIT(1),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho11",
......@@ -1798,6 +1921,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET,
.bit = BIT(2),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "tacho12",
......@@ -1805,6 +1929,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = {
.mask = GENMASK(7, 0),
.capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET,
.bit = BIT(3),
.reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
},
{
.label = "conf",
......@@ -2006,6 +2131,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET:
case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET:
......@@ -2051,6 +2180,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD4_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:
......@@ -2085,6 +2218,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET:
case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET:
......@@ -2122,6 +2259,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD4_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET:
......
......@@ -78,7 +78,6 @@ static const struct gpio_led apu2_leds[] = {
{ .name = "apu:green:1" },
{ .name = "apu:green:2" },
{ .name = "apu:green:3" },
{ .name = "apu:simswap" },
};
static const struct gpio_led_platform_data apu2_leds_pdata = {
......@@ -95,8 +94,6 @@ static struct gpiod_lookup_table gpios_led_table = {
NULL, 1, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_LED3,
NULL, 2, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX(AMD_FCH_GPIO_DRIVER_NAME, APU2_GPIO_LINE_SIMSWAP,
NULL, 3, GPIO_ACTIVE_LOW),
}
};
......
......@@ -103,12 +103,12 @@ static enum led_brightness ap_led_get(struct led_classdev *led)
}
// Set the airplane mode LED brightness
static void ap_led_set(struct led_classdev *led, enum led_brightness value)
static int ap_led_set(struct led_classdev *led, enum led_brightness value)
{
struct system76_data *data;
data = container_of(led, struct system76_data, ap_led);
system76_set(data, "SAPL", value == LED_OFF ? 0 : 1);
return system76_set(data, "SAPL", value == LED_OFF ? 0 : 1);
}
// Get the last set keyboard LED brightness
......@@ -121,13 +121,13 @@ static enum led_brightness kb_led_get(struct led_classdev *led)
}
// Set the keyboard LED brightness
static void kb_led_set(struct led_classdev *led, enum led_brightness value)
static int kb_led_set(struct led_classdev *led, enum led_brightness value)
{
struct system76_data *data;
data = container_of(led, struct system76_data, kb_led);
data->kb_brightness = value;
system76_set(data, "SKBL", (int)data->kb_brightness);
return system76_set(data, "SKBL", (int)data->kb_brightness);
}
// Get the last set keyboard LED color
......@@ -313,7 +313,7 @@ static int system76_add(struct acpi_device *acpi_dev)
data->ap_led.name = "system76_acpi::airplane";
data->ap_led.flags = LED_CORE_SUSPENDRESUME;
data->ap_led.brightness_get = ap_led_get;
data->ap_led.brightness_set = ap_led_set;
data->ap_led.brightness_set_blocking = ap_led_set;
data->ap_led.max_brightness = 1;
data->ap_led.default_trigger = "rfkill-none";
err = devm_led_classdev_register(&acpi_dev->dev, &data->ap_led);
......@@ -323,7 +323,7 @@ static int system76_add(struct acpi_device *acpi_dev)
data->kb_led.name = "system76_acpi::kbd_backlight";
data->kb_led.flags = LED_BRIGHT_HW_CHANGED | LED_CORE_SUSPENDRESUME;
data->kb_led.brightness_get = kb_led_get;
data->kb_led.brightness_set = kb_led_set;
data->kb_led.brightness_set_blocking = kb_led_set;
if (acpi_has_method(acpi_device_handle(data->acpi_dev), "SKBC")) {
data->kb_led.max_brightness = 255;
data->kb_toggle_brightness = 72;
......
......@@ -4030,8 +4030,8 @@ static bool hotkey_notify_6xxx(const u32 hkey,
return true;
case TP_HKEY_EV_THM_CSM_COMPLETED:
pr_debug("EC reports: Thermal Control Command set completed (DYTC)\n");
/* recommended action: do nothing, we don't have
* Lenovo ATM information */
/* Thermal event - pass on to event handler */
tpacpi_driver_event(hkey);
return true;
case TP_HKEY_EV_THM_TRANSFM_CHANGED:
pr_debug("EC reports: Thermal Transformation changed (GMTS)\n");
......@@ -6963,10 +6963,13 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
pr_warn("Cannot enable backlight brightness support, ACPI is already handling it. Refer to the acpi_backlight kernel parameter.\n");
return 1;
}
} else if (tp_features.bright_acpimode && brightness_enable > 1) {
pr_notice("Standard ACPI backlight interface not available, thinkpad_acpi native brightness control enabled\n");
} else if (!tp_features.bright_acpimode) {
pr_notice("ACPI backlight interface not available\n");
return 1;
}
pr_notice("ACPI native brightness control enabled\n");
/*
* Check for module parameter bogosity, note that we
* init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be
......@@ -7965,7 +7968,7 @@ static struct ibm_struct volume_driver_data = {
* does so, its initial value is meaningless (0x07).
*
* For firmware bugs, refer to:
* http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
* https://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
*
* ----
*
......@@ -7990,7 +7993,7 @@ static struct ibm_struct volume_driver_data = {
* mode.
*
* For firmware bugs, refer to:
* http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
* https://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
*
* ----
*
......@@ -9315,9 +9318,6 @@ static struct ibm_struct mute_led_driver_data = {
#define GET_STOP "BCSG"
#define SET_STOP "BCSS"
#define START_ATTR "charge_start_threshold"
#define STOP_ATTR "charge_stop_threshold"
enum {
BAT_ANY = 0,
BAT_PRIMARY = 1,
......@@ -9603,38 +9603,52 @@ static ssize_t tpacpi_battery_show(int what,
return sprintf(buf, "%d\n", ret);
}
static ssize_t charge_start_threshold_show(struct device *device,
static ssize_t charge_control_start_threshold_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
return tpacpi_battery_show(THRESHOLD_START, device, buf);
}
static ssize_t charge_stop_threshold_show(struct device *device,
static ssize_t charge_control_end_threshold_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
return tpacpi_battery_show(THRESHOLD_STOP, device, buf);
}
static ssize_t charge_start_threshold_store(struct device *dev,
static ssize_t charge_control_start_threshold_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return tpacpi_battery_store(THRESHOLD_START, dev, buf, count);
}
static ssize_t charge_stop_threshold_store(struct device *dev,
static ssize_t charge_control_end_threshold_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return tpacpi_battery_store(THRESHOLD_STOP, dev, buf, count);
}
static DEVICE_ATTR_RW(charge_start_threshold);
static DEVICE_ATTR_RW(charge_stop_threshold);
static DEVICE_ATTR_RW(charge_control_start_threshold);
static DEVICE_ATTR_RW(charge_control_end_threshold);
static struct device_attribute dev_attr_charge_start_threshold = __ATTR(
charge_start_threshold,
0644,
charge_control_start_threshold_show,
charge_control_start_threshold_store
);
static struct device_attribute dev_attr_charge_stop_threshold = __ATTR(
charge_stop_threshold,
0644,
charge_control_end_threshold_show,
charge_control_end_threshold_store
);
static struct attribute *tpacpi_battery_attrs[] = {
&dev_attr_charge_control_start_threshold.attr,
&dev_attr_charge_control_end_threshold.attr,
&dev_attr_charge_start_threshold.attr,
&dev_attr_charge_stop_threshold.attr,
NULL,
......@@ -9803,6 +9817,105 @@ static struct ibm_struct lcdshadow_driver_data = {
.write = lcdshadow_write,
};
/*************************************************************************
* DYTC subdriver, for the Lenovo lapmode feature
*/
#define DYTC_CMD_GET 2 /* To get current IC function and mode */
#define DYTC_GET_LAPMODE_BIT 17 /* Set when in lapmode */
static bool dytc_lapmode;
static void dytc_lapmode_notify_change(void)
{
sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "dytc_lapmode");
}
static int dytc_command(int command, int *output)
{
acpi_handle dytc_handle;
if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "DYTC", &dytc_handle))) {
/* Platform doesn't support DYTC */
return -ENODEV;
}
if (!acpi_evalf(dytc_handle, output, NULL, "dd", command))
return -EIO;
return 0;
}
static int dytc_lapmode_get(bool *state)
{
int output, err;
err = dytc_command(DYTC_CMD_GET, &output);
if (err)
return err;
*state = output & BIT(DYTC_GET_LAPMODE_BIT) ? true : false;
return 0;
}
static void dytc_lapmode_refresh(void)
{
bool new_state;
int err;
err = dytc_lapmode_get(&new_state);
if (err || (new_state == dytc_lapmode))
return;
dytc_lapmode = new_state;
dytc_lapmode_notify_change();
}
/* sysfs lapmode entry */
static ssize_t dytc_lapmode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", dytc_lapmode);
}
static DEVICE_ATTR_RO(dytc_lapmode);
static struct attribute *dytc_attributes[] = {
&dev_attr_dytc_lapmode.attr,
NULL,
};
static const struct attribute_group dytc_attr_group = {
.attrs = dytc_attributes,
};
static int tpacpi_dytc_init(struct ibm_init_struct *iibm)
{
int err;
err = dytc_lapmode_get(&dytc_lapmode);
/* If support isn't available (ENODEV) then don't return an error
* but just don't create the sysfs group
*/
if (err == -ENODEV)
return 0;
/* For all other errors we can flag the failure */
if (err)
return err;
/* Platform supports this feature - create the group */
err = sysfs_create_group(&tpacpi_pdev->dev.kobj, &dytc_attr_group);
return err;
}
static void dytc_exit(void)
{
sysfs_remove_group(&tpacpi_pdev->dev.kobj, &dytc_attr_group);
}
static struct ibm_struct dytc_driver_data = {
.name = "dytc",
.exit = dytc_exit,
};
/****************************************************************************
****************************************************************************
*
......@@ -9850,6 +9963,10 @@ static void tpacpi_driver_event(const unsigned int hkey_event)
mutex_unlock(&kbdlight_mutex);
}
if (hkey_event == TP_HKEY_EV_THM_CSM_COMPLETED)
dytc_lapmode_refresh();
}
static void hotkey_driver_event(const unsigned int scancode)
......@@ -10102,7 +10219,7 @@ static int __must_check __init get_thinkpad_model_data(
* X32 or newer, all Z series; Some models must have an
* up-to-date BIOS or they will not be detected.
*
* See http://thinkwiki.org/wiki/List_of_DMI_IDs
* See https://thinkwiki.org/wiki/List_of_DMI_IDs
*/
while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
if (sscanf(dev->name,
......@@ -10288,6 +10405,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = tpacpi_lcdshadow_init,
.data = &lcdshadow_driver_data,
},
{
.init = tpacpi_dytc_init,
.data = &dytc_driver_data,
},
};
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
......@@ -10621,8 +10742,8 @@ MODULE_DEVICE_TABLE(acpi, ibm_htk_device_ids);
/*
* DMI matching for module autoloading
*
* See http://thinkwiki.org/wiki/List_of_DMI_IDs
* See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
* See https://thinkwiki.org/wiki/List_of_DMI_IDs
* See https://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
*
* Only models listed in thinkwiki will be supported, so add yours
* if it is not there yet.
......
......@@ -75,11 +75,13 @@ struct mlxreg_hotplug_device {
* @mask: attribute access mask;
* @bit: attribute effective bit;
* @capability: attribute capability register;
* @reg_prsnt: attribute presence register;
* @mode: access mode;
* @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;
* @regnum: number of registers occupied by multi-register attribute;
*/
struct mlxreg_core_data {
char label[MLXREG_CORE_LABEL_MAX_SIZE];
......@@ -87,11 +89,13 @@ struct mlxreg_core_data {
u32 mask;
u32 bit;
u32 capability;
u32 reg_prsnt;
umode_t mode;
struct device_node *np;
struct mlxreg_hotplug_device hpdev;
u8 health_cntr;
bool attached;
u8 regnum;
};
/**
......
......@@ -2,6 +2,7 @@
#ifndef _LINUX_STRING_HELPERS_H_
#define _LINUX_STRING_HELPERS_H_
#include <linux/ctype.h>
#include <linux/types.h>
struct file;
......@@ -75,6 +76,20 @@ static inline int string_escape_str_any_np(const char *src, char *dst,
return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, only);
}
static inline void string_upper(char *dst, const char *src)
{
do {
*dst++ = toupper(*src);
} while (*src++);
}
static inline void string_lower(char *dst, const char *src)
{
do {
*dst++ = tolower(*src);
} while (*src++);
}
char *kstrdup_quotable(const char *src, gfp_t gfp);
char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp);
char *kstrdup_quotable_file(struct file *file, gfp_t gfp);
......
......@@ -69,7 +69,7 @@ struct isst_if_cpu_maps {
* @logical_cpu: Logical CPU number to get target PCI device.
* @reg: PUNIT register offset
* @value: For write operation value to write and for
* for read placeholder read value
* read placeholder read value
*
* Structure to specify read/write data to PUNIT registers.
*/
......
......@@ -238,6 +238,28 @@ static const struct test_string_2 escape1[] __initconst = {{
/* terminator */
}};
static const struct test_string strings_upper[] __initconst = {
{
.in = "abcdefgh1234567890test",
.out = "ABCDEFGH1234567890TEST",
},
{
.in = "abCdeFgH1234567890TesT",
.out = "ABCDEFGH1234567890TEST",
},
};
static const struct test_string strings_lower[] __initconst = {
{
.in = "ABCDEFGH1234567890TEST",
.out = "abcdefgh1234567890test",
},
{
.in = "abCdeFgH1234567890TesT",
.out = "abcdefgh1234567890test",
},
};
static __init const char *test_string_find_match(const struct test_string_2 *s2,
unsigned int flags)
{
......@@ -390,6 +412,48 @@ static __init void test_string_get_size(void)
test_string_get_size_one(4096, U64_MAX, "75.6 ZB", "64.0 ZiB");
}
static void __init test_string_upper_lower(void)
{
char *dst;
int i;
for (i = 0; i < ARRAY_SIZE(strings_upper); i++) {
const char *s = strings_upper[i].in;
int len = strlen(strings_upper[i].in) + 1;
dst = kmalloc(len, GFP_KERNEL);
if (!dst)
return;
string_upper(dst, s);
if (memcmp(dst, strings_upper[i].out, len)) {
pr_warn("Test 'string_upper' failed : expected %s, got %s!\n",
strings_upper[i].out, dst);
kfree(dst);
return;
}
kfree(dst);
}
for (i = 0; i < ARRAY_SIZE(strings_lower); i++) {
const char *s = strings_lower[i].in;
int len = strlen(strings_lower[i].in) + 1;
dst = kmalloc(len, GFP_KERNEL);
if (!dst)
return;
string_lower(dst, s);
if (memcmp(dst, strings_lower[i].out, len)) {
pr_warn("Test 'string_lower failed : : expected %s, got %s!\n",
strings_lower[i].out, dst);
kfree(dst);
return;
}
kfree(dst);
}
}
static int __init test_string_helpers_init(void)
{
unsigned int i;
......@@ -411,6 +475,9 @@ static int __init test_string_helpers_init(void)
/* Test string_get_size() */
test_string_get_size();
/* Test string upper(), string_lower() */
test_string_upper_lower();
return -EINVAL;
}
module_init(test_string_helpers_init);
......
......@@ -15,7 +15,7 @@ struct process_cmd_struct {
int arg;
};
static const char *version_str = "v1.4";
static const char *version_str = "v1.5";
static const int supported_api_ver = 1;
static struct isst_if_platform_info isst_platform_info;
static char *progname;
......@@ -44,6 +44,9 @@ static int force_online_offline;
static int auto_mode;
static int fact_enable_fail;
static int mbox_delay;
static int mbox_retries = 3;
/* clos related */
static int current_clos = -1;
static int clos_epp = -1;
......@@ -198,7 +201,7 @@ int out_format_is_json(void)
static int get_stored_topology_info(int cpu, int *core_id, int *pkg_id, int *die_id)
{
const char *pathname = "/tmp/isst_cpu_topology.dat";
const char *pathname = "/var/run/isst_cpu_topology.dat";
struct cpu_topology cpu_top;
FILE *fp;
int ret;
......@@ -230,7 +233,7 @@ static int get_stored_topology_info(int cpu, int *core_id, int *pkg_id, int *die
static void store_cpu_topology(void)
{
const char *pathname = "/tmp/isst_cpu_topology.dat";
const char *pathname = "/var/run/isst_cpu_topology.dat";
FILE *fp;
int i;
......@@ -247,6 +250,8 @@ static void store_cpu_topology(void)
return;
}
fprintf(stderr, "Caching topology information\n");
for (i = 0; i < topo_max_cpus; ++i) {
struct cpu_topology cpu_top;
......@@ -734,7 +739,7 @@ int isst_send_mbox_command(unsigned int cpu, unsigned char command,
unsigned int req_data, unsigned int *resp)
{
const char *pathname = "/dev/isst_interface";
int fd;
int fd, retry;
struct isst_if_mbox_cmds mbox_cmds = { 0 };
debug_printf(
......@@ -786,29 +791,42 @@ int isst_send_mbox_command(unsigned int cpu, unsigned char command,
mbox_cmds.mbox_cmd[0].parameter = parameter;
mbox_cmds.mbox_cmd[0].req_data = req_data;
if (mbox_delay)
usleep(mbox_delay * 1000);
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed", pathname);
if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) {
if (errno == ENOTTY) {
perror("ISST_IF_MBOX_COMMAND\n");
fprintf(stderr, "Check presence of kernel modules: isst_if_mbox_pci or isst_if_mbox_msr\n");
exit(0);
retry = mbox_retries;
do {
if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) {
if (errno == ENOTTY) {
perror("ISST_IF_MBOX_COMMAND\n");
fprintf(stderr, "Check presence of kernel modules: isst_if_mbox_pci or isst_if_mbox_msr\n");
exit(0);
}
debug_printf(
"Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x errorno:%d\n",
cpu, command, sub_command, parameter, req_data, errno);
--retry;
} else {
*resp = mbox_cmds.mbox_cmd[0].resp_data;
debug_printf(
"mbox_cmd response: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x resp:%x\n",
cpu, command, sub_command, parameter, req_data, *resp);
break;
}
debug_printf(
"Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x errorno:%d\n",
cpu, command, sub_command, parameter, req_data, errno);
return -1;
} else {
*resp = mbox_cmds.mbox_cmd[0].resp_data;
debug_printf(
"mbox_cmd response: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x resp:%x\n",
cpu, command, sub_command, parameter, req_data, *resp);
}
} while (retry);
close(fd);
if (!retry) {
debug_printf("Failed mbox command even after retries\n");
return -1;
}
return 0;
}
......@@ -1245,7 +1263,11 @@ static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
fprintf(stderr, "Option is set to online/offline\n");
ctdp_level.core_cpumask_size =
alloc_cpu_set(&ctdp_level.core_cpumask);
isst_get_coremask_info(cpu, tdp_level, &ctdp_level);
ret = isst_get_coremask_info(cpu, tdp_level, &ctdp_level);
if (ret) {
isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0);
return;
}
if (ctdp_level.cpu_count) {
int i, max_cpus = get_topo_max_cpus();
for (i = 0; i < max_cpus; ++i) {
......@@ -2593,6 +2615,8 @@ static void usage(void)
printf("\t[-i|--info] : Print platform information\n");
printf("\t[-o|--out] : Output file\n");
printf("\t\t\tDefault : stderr\n");
printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n");
printf("\t[-r|--retry] : Retry count for mail box commands on failure, default 3\n");
printf("\t[-v|--version] : Print version\n");
printf("\nResult format\n");
......@@ -2624,6 +2648,7 @@ static void print_version(void)
static void cmdline(int argc, char **argv)
{
const char *pathname = "/dev/isst_interface";
char *ptr;
FILE *fp;
int opt;
int option_index = 0;
......@@ -2635,7 +2660,9 @@ static void cmdline(int argc, char **argv)
{ "format", required_argument, 0, 'f' },
{ "help", no_argument, 0, 'h' },
{ "info", no_argument, 0, 'i' },
{ "pause", required_argument, 0, 'p' },
{ "out", required_argument, 0, 'o' },
{ "retry", required_argument, 0, 'r' },
{ "version", no_argument, 0, 'v' },
{ 0, 0, 0, 0 }
};
......@@ -2688,6 +2715,20 @@ static void cmdline(int argc, char **argv)
fclose(outf);
outf = fopen_or_exit(optarg, "w");
break;
case 'p':
ret = strtol(optarg, &ptr, 10);
if (!ret)
fprintf(stderr, "Invalid pause interval, ignore\n");
else
mbox_delay = ret;
break;
case 'r':
ret = strtol(optarg, &ptr, 10);
if (!ret)
fprintf(stderr, "Invalid retry count, ignore\n");
else
mbox_retries = ret;
break;
case 'v':
print_version();
break;
......
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