summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/stable/sysfs-driver-mlxreg-io78
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/platform/mellanox/Kconfig11
-rw-r--r--drivers/platform/mellanox/Makefile1
-rw-r--r--drivers/platform/mellanox/mlxreg-hotplug.c60
-rw-r--r--drivers/platform/mellanox/mlxreg-io.c245
-rw-r--r--drivers/platform/x86/Kconfig16
-rw-r--r--drivers/platform/x86/Makefile2
-rw-r--r--drivers/platform/x86/acer-wmi.c7
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c1
-rw-r--r--drivers/platform/x86/asus-wireless.c24
-rw-r--r--drivers/platform/x86/asus-wmi.c34
-rw-r--r--drivers/platform/x86/dell-smbios-base.c35
-rw-r--r--drivers/platform/x86/dell-smbios-smm.c4
-rw-r--r--drivers/platform/x86/dell-smbios-wmi.c2
-rw-r--r--drivers/platform/x86/ideapad-laptop.c18
-rw-r--r--drivers/platform/x86/intel-hid.c178
-rw-r--r--drivers/platform/x86/intel-vbtn.c5
-rw-r--r--drivers/platform/x86/intel_ips.c5
-rw-r--r--drivers/platform/x86/intel_pmc_core.c120
-rw-r--r--drivers/platform/x86/intel_pmc_core.h6
-rw-r--r--drivers/platform/x86/intel_punit_ipc.c1
-rw-r--r--drivers/platform/x86/mlx-platform.c486
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c135
-rw-r--r--drivers/platform/x86/toshiba_acpi.c33
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c (renamed from drivers/platform/x86/silead_dmi.c)639
-rw-r--r--drivers/platform/x86/wmi.c9
27 files changed, 1738 insertions, 419 deletions
diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io
new file mode 100644
index 000000000000..d9d117d457e1
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io
@@ -0,0 +1,78 @@
+What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
+ asic_health
+
+Date: June 2018
+KernelVersion: 4.19
+Contact: Vadim Pasternak <vadimpmellanox.com>
+Description: This file shows ASIC health status. The possible values are:
+ 0 - health failed, 2 - health OK, 3 - ASIC in booting state.
+
+ The files are read only.
+
+What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
+ cpld1_version
+ cpld2_version
+
+Date: June 2018
+KernelVersion: 4.19
+Contact: Vadim Pasternak <vadimpmellanox.com>
+Description: These files show with which CPLD versions have been burned
+ on carrier and switch boards.
+
+ The files are read only.
+
+What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/select_iio
+Date: June 2018
+KernelVersion: 4.19
+Contact: Vadim Pasternak <vadimpmellanox.com>
+Description: This file allows iio devices selection.
+
+ Attribute select_iio can be written with 0 or with 1. It
+ selects which one of iio devices can be accessed.
+
+ The file is read/write.
+
+What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/psu1_on
+ /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/psu2_on
+ /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pwr_cycle
+ /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pwr_down
+Date: June 2018
+KernelVersion: 4.19
+Contact: Vadim Pasternak <vadimpmellanox.com>
+Description: These files allow asserting system power cycling, switching
+ power supply units on and off and system's main power domain
+ shutdown.
+ Expected behavior:
+ When pwr_cycle is written 1: auxiliary power domain will go
+ down and after short period (about 1 second) up.
+ When psu1_on or psu2_on is written 1, related unit will be
+ disconnected from the power source, when written 0 - connected.
+ If both are written 1 - power supplies main power domain will
+ go down.
+ When pwr_down is written 1, system's main power domain will go
+ down.
+
+ The files are write only.
+
+What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
+ reset_aux_pwr_or_ref
+ reset_asic_thermal
+ reset_hotswap_or_halt
+ reset_hotswap_or_wd
+ reset_fw_reset
+ reset_long_pb
+ reset_main_pwr_fail
+ reset_short_pb
+ reset_sw_reset
+Date: June 2018
+KernelVersion: 4.19
+Contact: Vadim Pasternak <vadimpmellanox.com>
+Description: These files show the system reset cause, as following: power
+ auxiliary outage or power refresh, ASIC thermal shutdown, halt,
+ hotswap, watchdog, firmware reset, long press power button,
+ short press power button, software reset. Value 1 in file means
+ this is reset cause, 0 - otherwise. Only one of the above
+ causes could be 1 at the same time, representing only last
+ reset cause.
+
+ The files are read only.
diff --git a/MAINTAINERS b/MAINTAINERS
index 24b200d91b30..efb08d70cc28 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13207,7 +13207,7 @@ L: linux-input@vger.kernel.org
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/silead.c
-F: drivers/platform/x86/silead_dmi.c
+F: drivers/platform/x86/touchscreen_dmi.c
SILICON MOTION SM712 FRAME BUFFER DRIVER
M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
index 591bccdeaff9..cd8a90846063 100644
--- a/drivers/platform/mellanox/Kconfig
+++ b/drivers/platform/mellanox/Kconfig
@@ -23,4 +23,15 @@ config MLXREG_HOTPLUG
This driver handles hot-plug events for the power suppliers, power
cables and fans on the wide range Mellanox IB and Ethernet systems.
+config MLXREG_IO
+ tristate "Mellanox platform register access driver support"
+ depends on REGMAP
+ depends on HWMON
+ help
+ This driver allows access to Mellanox programmable device register
+ space through sysfs interface. The sets of registers for sysfs access
+ are defined per system type bases and include the registers related
+ to system resets operation, system reset causes monitoring and some
+ kinds of mux selection.
+
endif # MELLANOX_PLATFORM
diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile
index 7c8385e497a8..57074d9c722c 100644
--- a/drivers/platform/mellanox/Makefile
+++ b/drivers/platform/mellanox/Makefile
@@ -4,3 +4,4 @@
# Mellanox Platform-Specific Drivers
#
obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
+obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index ac97aa020db3..b6d44550d98c 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -50,9 +50,8 @@
#define MLXREG_HOTPLUG_MASK_OFF 2
#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1
-/* ASIC health parameters. */
-#define MLXREG_HOTPLUG_HEALTH_MASK 0x02
-#define MLXREG_HOTPLUG_RST_CNTR 3
+/* ASIC good health mask. */
+#define MLXREG_HOTPLUG_GOOD_HEALTH_MASK 0x02
#define MLXREG_HOTPLUG_ATTRS_MAX 24
#define MLXREG_HOTPLUG_NOT_ASSERT 3
@@ -103,6 +102,9 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
{
struct mlxreg_core_hotplug_platform_data *pdata;
+ /* Notify user by sending hwmon uevent. */
+ kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
+
/*
* Return if adapter number is negative. It could be in case hotplug
* event is not associated with hotplug device.
@@ -134,8 +136,13 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
return 0;
}
-static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data)
+static void
+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);
+
if (data->hpdev.client) {
i2c_unregister_device(data->hpdev.client);
data->hpdev.client = NULL;
@@ -278,14 +285,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(data);
+ mlxreg_hotplug_device_destroy(priv, data);
else
mlxreg_hotplug_device_create(priv, data);
} else {
if (item->inversed)
mlxreg_hotplug_device_create(priv, data);
else
- mlxreg_hotplug_device_destroy(data);
+ mlxreg_hotplug_device_destroy(priv, data);
}
}
@@ -325,21 +332,40 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
goto out;
regval &= data->mask;
- item->cache = regval;
- if (regval == MLXREG_HOTPLUG_HEALTH_MASK) {
- if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) ||
- !priv->after_probe) {
+
+ if (item->cache == regval)
+ goto ack_event;
+
+ /*
+ * ASIC health indication is provided through two bits. Bits
+ * value 0x2 indicates that ASIC reached the good health, value
+ * 0x0 indicates ASIC the bad health or dormant state and value
+ * 0x3 indicates the booting state. During ASIC reset it should
+ * pass the following states: dormant -> booting -> good.
+ */
+ if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) {
+ if (!data->attached) {
+ /*
+ * ASIC is in steady state. Connect associated
+ * device, if configured.
+ */
mlxreg_hotplug_device_create(priv, data);
data->attached = true;
}
} else {
if (data->attached) {
- mlxreg_hotplug_device_destroy(data);
+ /*
+ * ASIC health is failed after ASIC has been
+ * in steady state. Disconnect associated
+ * device, if it has been connected.
+ */
+ mlxreg_hotplug_device_destroy(priv, data);
data->attached = false;
data->health_cntr = 0;
}
}
-
+ item->cache = regval;
+ack_event:
/* Acknowledge event. */
ret = regmap_write(priv->regmap, data->reg +
MLXREG_HOTPLUG_EVENT_OFF, 0);
@@ -551,7 +577,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(data);
+ mlxreg_hotplug_device_destroy(priv, data);
}
}
@@ -616,10 +642,6 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
disable_irq(priv->irq);
spin_lock_init(&priv->lock);
INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
- /* Perform initial interrupts setup. */
- mlxreg_hotplug_set_irq(priv);
-
- priv->after_probe = true;
dev_set_drvdata(&pdev->dev, priv);
err = mlxreg_hotplug_attr_init(priv);
@@ -637,6 +659,10 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
return PTR_ERR(priv->hwmon);
}
+ /* Perform initial interrupts setup. */
+ mlxreg_hotplug_set_irq(priv);
+ priv->after_probe = true;
+
return 0;
}
diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c
new file mode 100644
index 000000000000..acfaf64ffde6
--- /dev/null
+++ b/drivers/platform/mellanox/mlxreg-io.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Mellanox register access driver
+ *
+ * Copyright (C) 2018 Mellanox Technologies
+ * Copyright (C) 2018 Vadim Pasternak <vadimp@mellanox.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/mlxreg.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* Attribute parameters. */
+#define MLXREG_IO_ATT_SIZE 10
+#define MLXREG_IO_ATT_NUM 48
+
+/**
+ * struct mlxreg_io_priv_data - driver's private data:
+ *
+ * @pdev: platform device;
+ * @pdata: platform data;
+ * @hwmon: hwmon device;
+ * @mlxreg_io_attr: sysfs attributes array;
+ * @mlxreg_io_dev_attr: sysfs sensor device attribute array;
+ * @group: sysfs attribute group;
+ * @groups: list of sysfs attribute group for hwmon registration;
+ */
+struct mlxreg_io_priv_data {
+ struct platform_device *pdev;
+ struct mlxreg_core_platform_data *pdata;
+ struct device *hwmon;
+ struct attribute *mlxreg_io_attr[MLXREG_IO_ATT_NUM + 1];
+ struct sensor_device_attribute mlxreg_io_dev_attr[MLXREG_IO_ATT_NUM];
+ struct attribute_group group;
+ const struct attribute_group *groups[2];
+};
+
+static int
+mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val,
+ bool rw_flag, u32 *regval)
+{
+ int 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.
+ */
+ if (!data->bit) {
+ /* Single bit. */
+ if (rw_flag) {
+ /* For show: expose effective bit value as 0 or 1. */
+ *regval = !!(*regval & ~data->mask);
+ } else {
+ /* For store: set effective bit value. */
+ *regval &= data->mask;
+ if (in_val)
+ *regval |= ~data->mask;
+ }
+ } else if (data->mask) {
+ /* Bit sequence. */
+ if (rw_flag) {
+ /* For show: mask and shift right. */
+ *regval = ror32(*regval & data->mask, (data->bit - 1));
+ } else {
+ /* For store: shift to the position and mask. */
+ in_val = rol32(in_val, data->bit - 1) & data->mask;
+ /* Clear relevant bits and set them to new value. */
+ *regval = (*regval & ~data->mask) | in_val;
+ }
+ }
+
+access_error:
+ return ret;
+}
+
+static ssize_t
+mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ struct mlxreg_core_data *data = priv->pdata->data + index;
+ u32 regval = 0;
+ int ret;
+
+ ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, &regval);
+ if (ret)
+ goto access_error;
+
+ return sprintf(buf, "%u\n", regval);
+
+access_error:
+ return ret;
+}
+
+static ssize_t
+mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ struct mlxreg_core_data *data = priv->pdata->data + index;
+ u32 input_val, regval;
+ int ret;
+
+ if (len > MLXREG_IO_ATT_SIZE)
+ return -EINVAL;
+
+ /* Convert buffer to input value. */
+ ret = kstrtou32(buf, len, &input_val);
+ if (ret)
+ return ret;
+
+ ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false,
+ &regval);
+ if (ret)
+ goto access_error;
+
+ ret = regmap_write(priv->pdata->regmap, data->reg, regval);
+ if (ret)
+ goto access_error;
+
+ return len;
+
+access_error:
+ dev_err(&priv->pdev->dev, "Bus access error\n");
+ return ret;
+}
+
+static struct device_attribute mlxreg_io_devattr_rw = {
+ .show = mlxreg_io_attr_show,
+ .store = mlxreg_io_attr_store,
+};
+
+static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv)
+{
+ int i;
+
+ priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
+ priv->pdata->counter,
+ sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!priv->group.attrs)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->pdata->counter; i++) {
+ priv->mlxreg_io_attr[i] =
+ &priv->mlxreg_io_dev_attr[i].dev_attr.attr;
+ memcpy(&priv->mlxreg_io_dev_attr[i].dev_attr,
+ &mlxreg_io_devattr_rw, sizeof(struct device_attribute));
+
+ /* Set attribute name as a label. */
+ priv->mlxreg_io_attr[i]->name =
+ devm_kasprintf(&priv->pdev->dev, GFP_KERNEL,
+ priv->pdata->data[i].label);
+
+ if (!priv->mlxreg_io_attr[i]->name) {
+ dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n",
+ i + 1);
+ return -ENOMEM;
+ }
+
+ priv->mlxreg_io_dev_attr[i].dev_attr.attr.mode =
+ priv->pdata->data[i].mode;
+ priv->mlxreg_io_dev_attr[i].dev_attr.attr.name =
+ priv->mlxreg_io_attr[i]->name;
+ priv->mlxreg_io_dev_attr[i].index = i;
+ sysfs_attr_init(&priv->mlxreg_io_dev_attr[i].dev_attr.attr);
+ }
+
+ priv->group.attrs = priv->mlxreg_io_attr;
+ priv->groups[0] = &priv->group;
+ priv->groups[1] = NULL;
+
+ return 0;
+}
+
+static int mlxreg_io_probe(struct platform_device *pdev)
+{
+ struct mlxreg_io_priv_data *priv;
+ int err;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->pdata = dev_get_platdata(&pdev->dev);
+ if (!priv->pdata) {
+ dev_err(&pdev->dev, "Failed to get platform data.\n");
+ return -EINVAL;
+ }
+
+ priv->pdev = pdev;
+
+ err = mlxreg_io_attr_init(priv);
+ if (err) {
+ dev_err(&priv->pdev->dev, "Failed to allocate attributes: %d\n",
+ err);
+ return err;
+ }
+
+ priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
+ "mlxreg_io",
+ priv,
+ priv->groups);
+ if (IS_ERR(priv->hwmon)) {
+ dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
+ PTR_ERR(priv->hwmon));
+ return PTR_ERR(priv->hwmon);
+ }
+
+ dev_set_drvdata(&pdev->dev, priv);
+
+ return 0;
+}
+
+static struct platform_driver mlxreg_io_driver = {
+ .driver = {
+ .name = "mlxreg-io",
+ },
+ .probe = mlxreg_io_probe,
+};
+
+module_platform_driver(mlxreg_io_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox regmap I/O access driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mlxreg-io");
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 107d336453b2..0c1aa6c314f5 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1196,16 +1196,16 @@ config INTEL_TURBO_MAX_3
This driver is only required when the system is not using Hardware
P-States (HWP). In HWP mode, priority can be read from ACPI tables.
-config SILEAD_DMI
- bool "Tablets with Silead touchscreens"
+config TOUCHSCREEN_DMI
+ bool "DMI based touchscreen configuration info"
depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD
---help---
- Certain ACPI based tablets with Silead touchscreens do not have
- enough data in ACPI tables for the touchscreen driver to handle
- the touchscreen properly, as OEMs expected the data to be baked
- into the tablet model specific version of the driver shipped
- with the OS-image for the device. This option supplies the missing
- information. Enable this for x86 tablets with Silead touchscreens.
+ Certain ACPI based tablets with e.g. Silead or Chipone touchscreens
+ do not have enough data in ACPI tables for the touchscreen driver to
+ handle the touchscreen properly, as OEMs expect the data to be baked
+ into the tablet model specific version of the driver shipped with the
+ the OS-image for the device. This option supplies the missing info.
+ Enable this for x86 tablets with Silead or Chipone touchscreens.
config INTEL_CHTDC_TI_PWRBTN
tristate "Intel Cherry Trail Dollar Cove TI power button driver"
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 50dc8f280914..e6d1becf81ce 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -78,7 +78,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
-obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o
+obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o
obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 8952173dd380..fcfeadd1301f 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -672,10 +672,7 @@ static void __init find_quirks(void)
static bool has_cap(u32 cap)
{
- if ((interface->capability & cap) != 0)
- return 1;
-
- return 0;
+ return interface->capability & cap;
}
/*
@@ -2216,7 +2213,7 @@ static int __init acer_wmi_init(void)
if (wmi_has_guid(AMW0_GUID1) &&
!dmi_check_system(amw0_whitelist) &&
quirks == &quirk_unknown) {
- pr_err("Unsupported machine has AMW0_GUID1, unable to load\n");
+ pr_debug("Unsupported machine has AMW0_GUID1, unable to load\n");
return -ENODEV;
}
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index 136ff2b4cce5..db2af09067db 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -496,6 +496,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
{ KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
{ KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */
+ { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */
{ KE_END, 0},
};
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
index 6afd011de9e5..7458f7602d5e 100644
--- a/drivers/platform/x86/asus-wireless.c
+++ b/drivers/platform/x86/asus-wireless.c
@@ -52,13 +52,12 @@ static const struct acpi_device_id device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, device_ids);
-static u64 asus_wireless_method(acpi_handle handle, const char *method,
- int param)
+static acpi_status asus_wireless_method(acpi_handle handle, const char *method,
+ int param, u64 *ret)
{
struct acpi_object_list p;
union acpi_object obj;
acpi_status s;
- u64 ret;
acpi_handle_debug(handle, "Evaluating method %s, parameter %#x\n",
method, param);
@@ -67,24 +66,27 @@ static u64 asus_wireless_method(acpi_handle handle, const char *method,
p.count = 1;
p.pointer = &obj;
- s = acpi_evaluate_integer(handle, (acpi_string) method, &p, &ret);
+ s = acpi_evaluate_integer(handle, (acpi_string) method, &p, ret);
if (ACPI_FAILURE(s))
acpi_handle_err(handle,
"Failed to eval method %s, param %#x (%d)\n",
method, param, s);
- acpi_handle_debug(handle, "%s returned %#llx\n", method, ret);
- return ret;
+ else
+ acpi_handle_debug(handle, "%s returned %#llx\n", method, *ret);
+
+ return s;
}
static enum led_brightness led_state_get(struct led_classdev *led)
{
struct asus_wireless_data *data;
- int s;
+ acpi_status s;
+ u64 ret;
data = container_of(led, struct asus_wireless_data, led);
s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
- data->hswc_params->status);
- if (s == data->hswc_params->on)
+ data->hswc_params->status, &ret);
+ if (ACPI_SUCCESS(s) && ret == data->hswc_params->on)
return LED_FULL;
return LED_OFF;
}
@@ -92,10 +94,11 @@ static enum led_brightness led_state_get(struct led_classdev *led)
static void led_state_update(struct work_struct *work)
{
struct asus_wireless_data *data;
+ u64 ret;
data = container_of(work, struct asus_wireless_data, led_work);
asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
- data->led_state);
+ data->led_state, &ret);
}
static void led_state_set(struct led_classdev *led, enum led_brightness value)
@@ -167,6 +170,7 @@ static int asus_wireless_add(struct acpi_device *adev)
data->led.brightness_get = led_state_get;
data->led.flags = LED_CORE_SUSPENDRESUME;
data->led.max_brightness = 1;
+ data->led.default_trigger = "rfkill-none";
err = devm_led_classdev_register(&adev->dev, &data->led);
if (err)
destroy_workqueue(data->wq);
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index d67f32a29bb4..2d6e272315a8 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -67,6 +67,7 @@ MODULE_LICENSE("GPL");
#define NOTIFY_BRNDOWN_MAX 0x2e
#define NOTIFY_KBD_BRTUP 0xc4
#define NOTIFY_KBD_BRTDWN 0xc5
+#define NOTIFY_KBD_BRTTOGGLE 0xc7
/* WMI Methods */
#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
@@ -470,6 +471,7 @@ static void kbd_led_update(struct work_struct *work)
ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F);
asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL);
+ led_classdev_notify_brightness_hw_changed(&asus->kbd_led, asus->kbd_led_wk);
}
static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
@@ -500,15 +502,16 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
return retval;
}
-static void kbd_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
+static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
{
struct asus_wmi *asus;
+ int max_level;
asus = container_of(led_cdev, struct asus_wmi, kbd_led);
+ max_level = asus->kbd_led.max_brightness;
- if (value > asus->kbd_led.max_brightness)
- value = asus->kbd_led.max_brightness;
+ if (value > max_level)
+ value = max_level;
else if (value < 0)
value = 0;
@@ -516,6 +519,12 @@ static void kbd_led_set(struct led_classdev *led_cdev,
queue_work(asus->led_workqueue, &asus->kbd_led_work);
}
+static void kbd_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ do_kbd_led_set(led_cdev, value);
+}
+
static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
{
struct asus_wmi *asus;
@@ -666,6 +675,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
asus->kbd_led_wk = led_val;
asus->kbd_led.name = "asus::kbd_backlight";
+ asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
asus->kbd_led.brightness_set = kbd_led_set;
asus->kbd_led.brightness_get = kbd_led_get;
asus->kbd_led.max_brightness = 3;
@@ -1754,6 +1764,22 @@ static void asus_wmi_notify(u32 value, void *context)
}
}
+ if (code == NOTIFY_KBD_BRTUP) {
+ do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1);
+ goto exit;
+ }
+ if (code == NOTIFY_KBD_BRTDWN) {
+ do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk - 1);
+ goto exit;
+ }
+ if (code == NOTIFY_KBD_BRTTOGGLE) {
+ if (asus->kbd_led_wk == asus->kbd_led.max_brightness)
+ do_kbd_led_set(&asus->kbd_led, 0);
+ else
+ do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1);
+ goto exit;
+ }
+
if (is_display_toggle(code) &&
asus->driver->quirks->no_display_toggle)
goto exit;
diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c
index 9dc282ed5a9e..0537d44d45a6 100644
--- a/drivers/platform/x86/dell-smbios-base.c
+++ b/drivers/platform/x86/dell-smbios-base.c
@@ -212,6 +212,12 @@ int dell_smbios_call_filter(struct device *d,
if ((buffer->cmd_class == CLASS_TOKEN_READ ||
buffer->cmd_class == CLASS_TOKEN_WRITE) &&
buffer->cmd_select < 3) {
+ /* tokens enabled ? */
+ if (!da_tokens) {
+ dev_dbg(d, "no token support on this system\n");
+ return -EINVAL;
+ }
+
/* find the matching token ID */
for (i = 0; i < da_num_tokens; i++) {
if (da_tokens[i].location != buffer->input[0])
@@ -315,6 +321,9 @@ struct calling_interface_token *dell_smbios_find_token(int tokenid)
{
int i;
+ if (!da_tokens)
+ return NULL;
+
for (i = 0; i < da_num_tokens; i++) {
if (da_tokens[i].tokenID == tokenid)
return &da_tokens[i];
@@ -565,11 +574,6 @@ static int __init dell_smbios_init(void)
dmi_walk(find_tokens, NULL);
- if (!da_tokens) {
- pr_info("Unable to find dmi tokens\n");
- return -ENODEV;
- }
-
ret = platform_driver_register(&platform_driver);
if (ret)
goto fail_platform_driver;
@@ -583,13 +587,6 @@ static int __init dell_smbios_init(void)
if (ret)
goto fail_platform_device_add;
- /* duplicate tokens will cause problems building sysfs files */
- zero_duplicates(&platform_device->dev);
-
- ret = build_tokens_sysfs(platform_device);
- if (ret)
- goto fail_create_group;
-
/* register backends */
wmi = init_dell_smbios_wmi();
if (wmi)
@@ -600,7 +597,16 @@ static int __init dell_smbios_init(void)
if (wmi && smm) {
pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n",
wmi, smm);
- goto fail_sysfs;
+ goto fail_create_group;
+ }
+
+ if (da_tokens) {
+ /* duplicate tokens will cause problems building sysfs files */
+ zero_duplicates(&platform_device->dev);
+
+ ret = build_tokens_sysfs(platform_device);
+ if (ret)
+ goto fail_sysfs;
}
return 0;
@@ -628,7 +634,8 @@ static void __exit dell_smbios_exit(void)
exit_dell_smbios_smm();
mutex_lock(&smbios_mutex);
if (platform_device) {
- free_group(platform_device);
+ if (da_tokens)
+ free_group(platform_device);
platform_device_unregister(platform_device);
platform_driver_unregister(&platform_driver);
}
diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c
index e9e9da556318..97a90bebc360 100644
--- a/drivers