summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2017-02-17 13:37:51 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2017-02-17 13:37:51 +1100
commit649f37301c40779563d65f1c9b71d1ab4ffa0973 (patch)
tree41b039fbc3eec1b13b11ff707eabdf94a88896e5
parenta0acfdf96b1452ed93ee6587613f376234437b2e (diff)
parentb193d56a3561e7900a8a56b26d5d81017c473248 (diff)
Merge remote-tracking branch 'drivers-x86/for-next'
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/platform/x86/Kconfig31
-rw-r--r--drivers/platform/x86/Makefile2
-rw-r--r--drivers/platform/x86/acer-wmi.c22
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c220
-rw-r--r--drivers/platform/x86/hp_accel.c1
-rw-r--r--drivers/platform/x86/intel_mid_powerbtn.c187
-rw-r--r--drivers/platform/x86/intel_mid_thermal.c2
-rw-r--r--drivers/platform/x86/intel_pmc_core.c6
-rw-r--r--drivers/platform/x86/intel_pmc_ipc.c2
-rw-r--r--drivers/platform/x86/intel_turbo_max_3.c152
-rw-r--r--drivers/platform/x86/mlx-platform.c84
-rw-r--r--drivers/platform/x86/silead_dmi.c136
13 files changed, 648 insertions, 205 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index df1d24bfb3db..0e3e2dbc667c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11408,6 +11408,14 @@ F: drivers/media/usb/siano/
F: drivers/media/usb/siano/
F: drivers/media/mmc/siano/
+SILEAD TOUCHSCREEN DRIVER
+M: Hans de Goede <hdegoede@redhat.com>
+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
+
SIMPLEFB FB DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-fbdev@vger.kernel.org
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index a9e9c91cf4d4..4bc88eb52712 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -92,9 +92,8 @@ config ASUS_LAPTOP
If you have an ACPI-compatible ASUS laptop, say Y or M here.
config DELL_SMBIOS
- tristate "Dell SMBIOS Support"
- depends on DCDBAS
- default n
+ tristate
+ select DCDBAS
---help---
This module provides common functions for kernel modules using
Dell SMBIOS.
@@ -103,16 +102,15 @@ config DELL_SMBIOS
config DELL_LAPTOP
tristate "Dell Laptop Extras"
- depends on DELL_SMBIOS
depends on DMI
depends on BACKLIGHT_CLASS_DEVICE
depends on ACPI_VIDEO || ACPI_VIDEO = n
depends on RFKILL || RFKILL = n
depends on SERIO_I8042
+ select DELL_SMBIOS
select POWER_SUPPLY
select LEDS_CLASS
select NEW_LEDS
- default n
---help---
This driver adds support for rfkill and backlight control to Dell
laptops (except for some models covered by the Compal driver).
@@ -123,7 +121,7 @@ config DELL_WMI
depends on DMI
depends on INPUT
depends on ACPI_VIDEO || ACPI_VIDEO = n
- depends on DELL_SMBIOS
+ select DELL_SMBIOS
select INPUT_SPARSEKMAP
---help---
Say Y here if you want to support WMI-based hotkeys on Dell laptops.
@@ -1069,6 +1067,27 @@ config MLX_CPLD_PLATFORM
This driver handles hot-plug events for the power suppliers, power
cables and fans on the wide range Mellanox IB and Ethernet systems.
+config INTEL_TURBO_MAX_3
+ bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
+ depends on X86_64 && SCHED_MC_PRIO
+ ---help---
+ This driver reads maximum performance ratio of each CPU and set up
+ the scheduler priority metrics. In this way scheduler can prefer
+ CPU with higher performance to schedule tasks.
+ 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"
+ depends on ACPI && DMI && I2C=y && INPUT
+ ---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.
+
endif # X86_PLATFORM_DEVICES
config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index cf9fc3e930c7..299d0f9e40f7 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -65,6 +65,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_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
@@ -76,3 +77,4 @@ obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o
+obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index a66192f692e3..c29b9b611ab2 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -1846,11 +1846,24 @@ static int __init acer_wmi_enable_lm(void)
return status;
}
+#define ACER_WMID_ACCEL_HID "BST0001"
+
static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
void *ctx, void **retval)
{
+ struct acpi_device *dev;
+
+ if (!strcmp(ctx, "SENR")) {
+ if (acpi_bus_get_device(ah, &dev))
+ return AE_OK;
+ if (!strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev)))
+ return AE_OK;
+ } else
+ return AE_OK;
+
*(acpi_handle *)retval = ah;
- return AE_OK;
+
+ return AE_CTRL_TERMINATE;
}
static int __init acer_wmi_get_handle(const char *name, const char *prop,
@@ -1877,7 +1890,7 @@ static int __init acer_wmi_accel_setup(void)
{
int err;
- err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle);
+ err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle);
if (err)
return err;
@@ -2233,10 +2246,11 @@ static int __init acer_wmi_init(void)
err = acer_wmi_input_setup();
if (err)
return err;
+ err = acer_wmi_accel_setup();
+ if (err)
+ return err;
}
- acer_wmi_accel_setup();
-
err = platform_driver_register(&acer_platform_driver);
if (err) {
pr_err("Unable to register platform driver\n");
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 82d67715ce76..2b218b1d13e5 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -202,6 +202,7 @@ static int radio_led_set(struct led_classdev *cdev,
static struct led_classdev radio_led = {
.name = "fujitsu::radio_led",
+ .default_trigger = "rfkill-any",
.brightness_get = radio_led_get,
.brightness_set_blocking = radio_led_set
};
@@ -270,15 +271,20 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
static int logolamp_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
- if (brightness >= LED_FULL) {
- call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
- return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON);
- } else if (brightness >= LED_HALF) {
- call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
- return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF);
- } else {
- return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF);
- }
+ int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
+ int ret;
+
+ if (brightness < LED_HALF)
+ poweron = FUNC_LED_OFF;
+
+ if (brightness < LED_FULL)
+ always = FUNC_LED_OFF;
+
+ ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
+ if (ret < 0)
+ return ret;
+
+ return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
}
static int kblamps_set(struct led_classdev *cdev,
@@ -313,17 +319,17 @@ static int eco_led_set(struct led_classdev *cdev,
static enum led_brightness logolamp_get(struct led_classdev *cdev)
{
- enum led_brightness brightness = LED_OFF;
- int poweron, always;
-
- poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
- if (poweron == FUNC_LED_ON) {
- brightness = LED_HALF;
- always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
- if (always == FUNC_LED_ON)
- brightness = LED_FULL;
- }
- return brightness;
+ int ret;
+
+ ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
+ if (ret == FUNC_LED_ON)
+ return LED_FULL;
+
+ ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
+ if (ret == FUNC_LED_ON)
+ return LED_HALF;
+
+ return LED_OFF;
}
static enum led_brightness kblamps_get(struct led_classdev *cdev)
@@ -1029,107 +1035,117 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device)
return 0;
}
+static void acpi_fujitsu_hotkey_press(int keycode)
+{
+ struct input_dev *input = fujitsu_hotkey->input;
+ int status;
+
+ status = kfifo_in_locked(&fujitsu_hotkey->fifo,
+ (unsigned char *)&keycode, sizeof(keycode),
+ &fujitsu_hotkey->fifo_lock);
+ if (status != sizeof(keycode)) {
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "Could not push keycode [0x%x]\n", keycode);
+ return;
+ }
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "Push keycode into ringbuffer [%d]\n", keycode);
+}
+
+static void acpi_fujitsu_hotkey_release(void)
+{
+ struct input_dev *input = fujitsu_hotkey->input;
+ int keycode, status;
+
+ while (true) {
+ status = kfifo_out_locked(&fujitsu_hotkey->fifo,
+ (unsigned char *)&keycode,
+ sizeof(keycode),
+ &fujitsu_hotkey->fifo_lock);
+ if (status != sizeof(keycode))
+ return;
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "Pop keycode from ringbuffer [%d]\n", keycode);
+ }
+}
+
static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
{
struct input_dev *input;
- int keycode, keycode_r;
+ int keycode;
unsigned int irb = 1;
- int i, status;
+ int i;
input = fujitsu_hotkey->input;
+ if (event != ACPI_FUJITSU_NOTIFY_CODE1) {
+ keycode = KEY_UNKNOWN;
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "Unsupported event [0x%x]\n", event);
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+ return;
+ }
+
if (fujitsu_hotkey->rfkill_supported)
fujitsu_hotkey->rfkill_state =
call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
- switch (event) {
- case ACPI_FUJITSU_NOTIFY_CODE1:
- i = 0;
- while ((irb =
- call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
- && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
- switch (irb & 0x4ff) {
- case KEY1_CODE:
- keycode = fujitsu->keycode1;
- break;
- case KEY2_CODE:
- keycode = fujitsu->keycode2;
- break;
- case KEY3_CODE:
- keycode = fujitsu->keycode3;
- break;
- case KEY4_CODE:
- keycode = fujitsu->keycode4;
- break;
- case KEY5_CODE:
- keycode = fujitsu->keycode5;
- break;
- case 0:
- keycode = 0;
- break;
- default:
- vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Unknown GIRB result [%x]\n", irb);
- keycode = -1;
- break;
- }
- if (keycode > 0) {
- vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "Push keycode into ringbuffer [%d]\n",
- keycode);
- status = kfifo_in_locked(&fujitsu_hotkey->fifo,
- (unsigned char *)&keycode,
- sizeof(keycode),
- &fujitsu_hotkey->fifo_lock);
- if (status != sizeof(keycode)) {
- vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Could not push keycode [0x%x]\n",
- keycode);
- } else {
- input_report_key(input, keycode, 1);
- input_sync(input);
- }
- } else if (keycode == 0) {
- while ((status =
- kfifo_out_locked(
- &fujitsu_hotkey->fifo,
- (unsigned char *) &keycode_r,
- sizeof(keycode_r),
- &fujitsu_hotkey->fifo_lock))
- == sizeof(keycode_r)) {
- input_report_key(input, keycode_r, 0);
- input_sync(input);
- vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "Pop keycode from ringbuffer [%d]\n",
- keycode_r);
- }
- }
+ i = 0;
+ while ((irb =
+ call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
+ && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
+ switch (irb & 0x4ff) {
+ case KEY1_CODE:
+ keycode = fujitsu->keycode1;
+ break;
+ case KEY2_CODE:
+ keycode = fujitsu->keycode2;
+ break;
+ case KEY3_CODE:
+ keycode = fujitsu->keycode3;
+ break;
+ case KEY4_CODE:
+ keycode = fujitsu->keycode4;
+ break;
+ case KEY5_CODE:
+ keycode = fujitsu->keycode5;
+ break;
+ case 0:
+ keycode = 0;
+ break;
+ default:
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "Unknown GIRB result [%x]\n", irb);
+ keycode = -1;
+ break;
}
- /* On some models (first seen on the Skylake-based Lifebook
- * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is
- * handled in software; its state is queried using FUNC_RFKILL
- */
- if ((fujitsu_hotkey->rfkill_supported & BIT(26)) &&
- (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) {
- keycode = KEY_TOUCHPAD_TOGGLE;
- input_report_key(input, keycode, 1);
- input_sync(input);
- input_report_key(input, keycode, 0);
- input_sync(input);
- }
+ if (keycode > 0)
+ acpi_fujitsu_hotkey_press(keycode);
+ else if (keycode == 0)
+ acpi_fujitsu_hotkey_release();
+ }
- break;
- default:
- keycode = KEY_UNKNOWN;
- vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Unsupported event [0x%x]\n", event);
+ /* On some models (first seen on the Skylake-based Lifebook
+ * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is
+ * handled in software; its state is queried using FUNC_RFKILL
+ */
+ if ((fujitsu_hotkey->rfkill_supported & BIT(26)) &&
+ (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) {
+ keycode = KEY_TOUCHPAD_TOGGLE;
input_report_key(input, keycode, 1);
input_sync(input);
input_report_key(input, keycode, 0);
input_sync(input);
- break;
}
+
}
/* Initialization */
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
index 09356684c32f..493d8910a74e 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp_accel.c
@@ -251,6 +251,7 @@ static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap),
AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted),
AXIS_DMI_MATCH("HPZBook15", "HP ZBook 15", x_inverted),
+ AXIS_DMI_MATCH("HPZBook17", "HP ZBook 17", xy_swap_yz_inverted),
{ NULL, }
/* Laptop models without axis info (yet):
* "NC6910" "HP Compaq 6910"
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c
index 361770568ad0..871cfa682519 100644
--- a/drivers/platform/x86/intel_mid_powerbtn.c
+++ b/drivers/platform/x86/intel_mid_powerbtn.c
@@ -1,7 +1,10 @@
/*
- * Power button driver for Medfield.
+ * Power button driver for Intel MID platforms.
*
- * Copyright (C) 2010 Intel Corp
+ * Copyright (C) 2010,2017 Intel Corp
+ *
+ * Author: Hong Liu <hong.liu@intel.com>
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -11,20 +14,20 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
#include <linux/input.h>
+#include <linux/interrupt.h>
#include <linux/mfd/intel_msic.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
+#include <linux/slab.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+#include <asm/intel_scu_ipc.h>
#define DRIVER_NAME "msic_power_btn"
@@ -36,37 +39,113 @@
*/
#define MSIC_PWRBTNM (1 << 0)
-static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
+/* Intel Tangier */
+#define BCOVE_PB_LEVEL (1 << 4) /* 1 - release, 0 - press */
+
+/* Basin Cove PMIC */
+#define BCOVE_PBIRQ 0x02
+#define BCOVE_IRQLVL1MSK 0x0c
+#define BCOVE_PBIRQMASK 0x0d
+#define BCOVE_PBSTATUS 0x27
+
+struct mid_pb_ddata {
+ struct device *dev;
+ int irq;
+ struct input_dev *input;
+ unsigned short mirqlvl1_addr;
+ unsigned short pbstat_addr;
+ u8 pbstat_mask;
+ int (*setup)(struct mid_pb_ddata *ddata);
+};
+
+static int mid_pbstat(struct mid_pb_ddata *ddata, int *value)
{
- struct input_dev *input = dev_id;
+ struct input_dev *input = ddata->input;
int ret;
u8 pbstat;
- ret = intel_msic_reg_read(INTEL_MSIC_PBSTATUS, &pbstat);
+ ret = intel_scu_ipc_ioread8(ddata->pbstat_addr, &pbstat);
+ if (ret)
+ return ret;
+
dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat);
+ *value = !(pbstat & ddata->pbstat_mask);
+ return 0;
+}
+
+static int mid_irq_ack(struct mid_pb_ddata *ddata)
+{
+ return intel_scu_ipc_update_register(ddata->mirqlvl1_addr, 0, MSIC_PWRBTNM);
+}
+
+static int mrfld_setup(struct mid_pb_ddata *ddata)
+{
+ /* Unmask the PBIRQ and MPBIRQ on Tangier */
+ intel_scu_ipc_update_register(BCOVE_PBIRQ, 0, MSIC_PWRBTNM);
+ intel_scu_ipc_update_register(BCOVE_PBIRQMASK, 0, MSIC_PWRBTNM);
+
+ return 0;
+}
+
+static irqreturn_t mid_pb_isr(int irq, void *dev_id)
+{
+ struct mid_pb_ddata *ddata = dev_id;
+ struct input_dev *input = ddata->input;
+ int value = 0;
+ int ret;
+
+ ret = mid_pbstat(ddata, &value);
if (ret < 0) {
- dev_err(input->dev.parent, "Read error %d while reading"
- " MSIC_PB_STATUS\n", ret);
+ dev_err(input->dev.parent,
+ "Read error %d while reading MSIC_PB_STATUS\n", ret);
} else {
- input_event(input, EV_KEY, KEY_POWER,
- !(pbstat & MSIC_PB_LEVEL));
+ input_event(input, EV_KEY, KEY_POWER, value);
input_sync(input);
}
+ mid_irq_ack(ddata);
return IRQ_HANDLED;
}
-static int mfld_pb_probe(struct platform_device *pdev)
+static struct mid_pb_ddata mfld_ddata = {
+ .mirqlvl1_addr = INTEL_MSIC_IRQLVL1MSK,
+ .pbstat_addr = INTEL_MSIC_PBSTATUS,
+ .pbstat_mask = MSIC_PB_LEVEL,
+};
+
+static struct mid_pb_ddata mrfld_ddata = {
+ .mirqlvl1_addr = BCOVE_IRQLVL1MSK,
+ .pbstat_addr = BCOVE_PBSTATUS,
+ .pbstat_mask = BCOVE_PB_LEVEL,
+ .setup = mrfld_setup,
+};
+
+#define ICPU(model, ddata) \
+ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (kernel_ulong_t)&ddata }
+
+static const struct x86_cpu_id mid_pb_cpu_ids[] = {
+ ICPU(INTEL_FAM6_ATOM_PENWELL, mfld_ddata),
+ ICPU(INTEL_FAM6_ATOM_MERRIFIELD, mrfld_ddata),
+ {}
+};
+
+static int mid_pb_probe(struct platform_device *pdev)
{
+ const struct x86_cpu_id *id;
+ struct mid_pb_ddata *ddata;
struct input_dev *input;
int irq = platform_get_irq(pdev, 0);
int error;
+ id = x86_match_cpu(mid_pb_cpu_ids);
+ if (!id)
+ return -ENODEV;
+
if (irq < 0)
return -EINVAL;
- input = input_allocate_device();
+ input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
@@ -77,25 +156,36 @@ static int mfld_pb_probe(struct platform_device *pdev)
input_set_capability(input, EV_KEY, KEY_POWER);
- error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_ONESHOT,
- DRIVER_NAME, input);
- if (error) {
- dev_err(&pdev->dev, "Unable to request irq %d for mfld power"
- "button\n", irq);
- goto err_free_input;
+ ddata = (struct mid_pb_ddata *)id->driver_data;
+ if (!ddata)
+ return -ENODATA;
+
+ ddata->dev = &pdev->dev;
+ ddata->irq = irq;
+ ddata->input = input;
+
+ if (ddata->setup) {
+ error = ddata->setup(ddata);
+ if (error)
+ return error;
}
- device_init_wakeup(&pdev->dev, true);
- dev_pm_set_wake_irq(&pdev->dev, irq);
+ error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mid_pb_isr,
+ IRQF_ONESHOT, DRIVER_NAME, ddata);
+ if (error) {
+ dev_err(&pdev->dev,
+ "Unable to request irq %d for MID power button\n", irq);
+ return error;
+ }
error = input_register_device(input);
if (error) {
- dev_err(&pdev->dev, "Unable to register input dev, error "
- "%d\n", error);
- goto err_free_irq;
+ dev_err(&pdev->dev,
+ "Unable to register input dev, error %d\n", error);
+ return error;
}
- platform_set_drvdata(pdev, input);
+ platform_set_drvdata(pdev, ddata);
/*
* SCU firmware might send power button interrupts to IA core before
@@ -107,46 +197,39 @@ static int mfld_pb_probe(struct platform_device *pdev)
* initialization. The race happens rarely. So we needn't worry
* about it.
*/
- error = intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM);
+ error = mid_irq_ack(ddata);
if (error) {
- dev_err(&pdev->dev, "Unable to clear power button interrupt, "
- "error: %d\n", error);
- goto err_free_irq;
+ dev_err(&pdev->dev,
+ "Unable to clear power button interrupt, error: %d\n",
+ error);
+ return error;
}
- return 0;
+ device_init_wakeup(&pdev->dev, true);
+ dev_pm_set_wake_irq(&pdev->dev, irq);
-err_free_irq:
- free_irq(irq, input);
-err_free_input:
- input_free_device(input);
- return error;
+ return 0;
}
-static int mfld_pb_remove(struct platform_device *pdev)
+static int mid_pb_remove(struct platform_device *pdev)
{
- struct input_dev *input = platform_get_drvdata(pdev);
- int irq = platform_get_irq(pdev, 0);
-
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
- free_irq(irq, input);
- input_unregister_device(input);
return 0;
}
-static struct platform_driver mfld_pb_driver = {
+static struct platform_driver mid_pb_driver = {
.driver = {
.name = DRIVER_NAME,
},
- .probe = mfld_pb_probe,
- .remove = mfld_pb_remove,
+ .probe = mid_pb_probe,
+ .remove = mid_pb_remove,
};
-module_platform_driver(mfld_pb_driver);
+module_platform_driver(mid_pb_driver);
MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
-MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
+MODULE_DESCRIPTION("Intel MID Power Button Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index 0df3c9d37509..008a76903cbf 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -549,9 +549,9 @@ static int mid_thermal_remove(struct platform_device *pdev)
static const struct platform_device_id therm_id_table[] = {
{ DRIVER_NAME, 1 },
- { "msic_thermal", 1 },
{ }
};
+MODULE_DEVICE_TABLE(platform, therm_id_table);
static struct platform_driver mid_thermal_driver = {
.driver = {
diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index b130b8c9b9d7..914bcd2edbde 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -188,8 +188,7 @@ static int pmc_core_check_read_lock_bit(void)
u32 value;
value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_CFG_OFFSET);
- return test_bit(SPT_PMC_READ_DISABLE_BIT,
- (unsigned long *)&value);
+ return value & BIT(SPT_PMC_READ_DISABLE_BIT);
}
#if IS_ENABLED(CONFIG_DEBUG_FS)
@@ -238,8 +237,7 @@ static int pmc_core_mtpmc_link_status(void)
u32 value;
value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_STS_OFFSET);
- return test_bit(SPT_PMC_MSG_FULL_STS_BIT,
- (unsigned long *)&value);
+ return value & BIT(SPT_PMC_MSG_FULL_STS_BIT);
}
static int pmc_core_send_msg(u32 *addr_xram)
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index 0bf51d574fa9..59a86121105b 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -97,8 +97,6 @@
#define TCO_PMC_OFFSET 0x8
#define TCO_PMC_SIZE 0x4
-static const int iTCO_version = 3;
-
static struct intel_pmc_ipc_dev {
struct device *dev;
void __iomem *ipc_base;
diff --git a/drivers/platform/x86/intel_turbo_max_3.c b/drivers/platform/x86/intel_turbo_max_3.c
new file mode 100644
index 000000000000..0103f5b32e34
--- /dev/null
+++ b/drivers/platform/x86/intel_turbo_max_3.c
@@ -0,0 +1,152 @@
+/*
+ * Intel Turbo Boost Max Technology 3.0 legacy (non HWP) enumeration driver
+ * Copyright (c) 2017, Intel Corporation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cpuhotplug.h>
+#include <linux/cpufeature.h>
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
+#define MSR_OC_MAILBOX 0x150
+#define MSR_OC_MAILBOX_CMD_OFFSET 32
+#define MSR_OC_MAILBOX_RSP_OFFSET 32
+#define MSR_OC_MAILBOX_BUSY_BIT 63
+#define OC_MAILBOX_FC_CONTROL_CMD 0x1C
+
+/*
+ * Typical latency to get mail box response is ~3us, It takes +3 us to
+ * process reading mailbox after issuing mailbox write on a Broadwell 3.4 GHz
+ * system. So for most of the time, the first mailbox read should have the
+ * response, but to avoid some boundary cases retry twice.
+ */
+#define OC_MAILBOX_RETRY_COUNT 2
+
+static int get_oc_core_priority(unsigned int cpu)
+{
+ u64 value, cmd = OC_MAILBOX_FC_CONTROL_CMD;
+ int ret, i;
+
+ /* Issue favored core read command */
+ value = cmd << MSR_OC_MAILBOX_CMD_OFFSET;
+ /* Set the busy bit to indicate OS is trying to issue command */
+ value |= BIT_ULL(MSR_OC_MAILBOX_BUSY_BIT);
+ ret = wrmsrl_safe(MSR_OC_MAILBOX, value);
+ if (ret) {
+ pr_debug("cpu %d OC mailbox write failed\n", cpu);
+ return ret;
+ }
+
+ for (i = 0; i < OC_MAILBOX_RETRY_COUNT; ++i) {
+ ret = rdmsrl_safe(MSR_OC_MAILBOX, &value);
+ if (ret) {
+ pr_debug("cpu %d OC mailbox read failed\n", cpu);
+ break;
+ }
+
+ if (value & BIT_ULL(MSR_OC_MAILBOX_BUSY_BIT)) {
+ pr_debug("cpu %d OC mailbox still processing\n", cpu);
+ ret = -EBUSY;
+ continue;
+ }
+
+ if ((value >> MSR_OC_MAILBOX_RSP_OFFSET) & 0xff) {
+ pr_debug("cpu %d OC mailbox cmd failed\n", cpu);
+ ret = -ENXIO;
+ break;
+ }
+
+ ret = value & 0xff;
+ pr_debug("cpu %d max_ratio %d\n", cpu, ret);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * The work item is needed to avoid CPU hotplug locking issues. The function
+ * itmt_legacy_set_priority() is called from CPU online callback, so can't
+ * call sched_set_itmt_support() from there as this function will aquire
+ * hotplug locks in its path.
+ */
+static void itmt_legacy_work_fn(struct work_struct *work)
+{
+ sched_set_itmt_support();
+}
+
+static DECLARE_WORK(sched_itmt_work, itmt_legacy_work_fn);
+
+static int itmt_legacy_cpu_online(unsigned int cpu)
+{
+ static u32 max_highest_perf = 0, min_highest_perf = U32_MAX;
+ int priority;
+
+ priority = get_oc_core_priority(cpu);
+ if (priority < 0)
+ return 0;
+
+ sched_set_itmt_core_prio(priority, cpu);
+
+ /* Enable ITMT feature when a core with different priority is found */
+ if (max_highest_perf <= min_highest_perf) {
+ if (priority > max_highest_perf)
+ max_highest_perf = priority;
+
+ if (priority < min_highest_perf)
+ min_highest_perf = priority;
+
+ if (max_highest_perf > min_highest_perf)
+ schedule_work(&sched_itmt_work);
+ }
+
+ return 0;
+}
+
+#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
+
+static const struct x86_cpu_id itmt_legacy_cpu_ids[] = {
+ ICPU(INTEL_FAM6_BROADWELL_X),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, itmt_legacy_cpu_ids);
+
+static int __init itmt_legacy_init(void)
+{
+ const struct x86_cpu_id *id;
+ int ret;
+
+ id = x86_match_cpu(itmt_legacy_cpu_ids);
+ if (!id)
+ return -ENODEV;
+
+ if (boot_cpu_has(X86_FEATURE_HWP))
+ return -ENODEV;
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+ "platform/x86/turbo_max_3:online",
+ itmt_legacy_cpu_online, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+late_initcall(itmt_legacy_init)
+
+MODULE_DESCRIPTION("Intel Turbo Boost Max 3.0 enumeration driver");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 25f15df5c2d7..8f98c211b440 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -45,6 +45,10 @@
/* LPC bus IO offsets */
#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
+#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a
+#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558
+#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564
+#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588
#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
@@ -56,6 +60,17 @@
MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
MLXPLAT_CPLD_LPC_PIO_OFFSET)
+/* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */
+#define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08
+#define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08
+#define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40
+#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \
+ MLXPLAT_CPLD_AGGR_FAN_MASK_DEF)
+#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04
+#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
+#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
+#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
+
/* Start channel numbers */
#define MLXPLAT_CPLD_CH1 2
#define MLXPLAT_CPLD_CH2 10
@@ -123,7 +138,7 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
};
/* Platform hotplug devices */
-static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = {
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = {
{
.brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
.bus = 10,
@@ -134,7 +149,7 @@ static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = {
},
};
-static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = {
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = {
{
.brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
.bus = 10,
@@ -145,7 +160,7 @@ static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = {
},
};
-static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = {
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = {
{
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
.bus = 11,
@@ -166,38 +181,38 @@ static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = {
/* Platform hotplug default data */
static
-struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_default_data = {
- .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
- .top_aggr_mask = 0x48,
- .top_aggr_psu_mask = 0x08,
- .psu_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x58),
- .psu_mask = 0x03,
- .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_psu),
- .psu = mlxplat_mlxcpld_hotplug_psu,
- .top_aggr_pwr_mask = 0x08,
- .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
- .pwr_mask = 0x03,
- .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
- .pwr = mlxplat_mlxcpld_hotplug_pwr,
- .top_aggr_fan_mask = 0x40,
- .fan_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x88),
- .fan_mask = 0x0f,
- .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_fan),
- .fan = mlxplat_mlxcpld_hotplug_fan,
+struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = {
+ .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
+ .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
+ .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
+ .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR,
+ .psu_mask = MLXPLAT_CPLD_PSU_MASK,
+ .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
+ .psu = mlxplat_mlxcpld_psu,
+ .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
+ .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
+ .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
+ .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
+ .pwr = mlxplat_mlxcpld_pwr,
+ .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
+ .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR,
+ .fan_mask = MLXPLAT_CPLD_FAN_MASK,
+ .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
+ .fan = mlxplat_mlxcpld_fan,
};
/* Platform hotplug MSN21xx system family data */
static
-struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_msn21xx_data = {
- .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
- .top_aggr_mask = 0x04,
- .top_aggr_pwr_mask = 0x04,
- .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
- .pwr_mask = 0x03,
- .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
+struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
+ .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
+ .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
+ .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
+ .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
+ .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
+ .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
};
-static struct resource mlxplat_mlxcpld_hotplug_resources[] = {
+static struct resource mlxplat_mlxcpld_resources[] = {
[0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
};
@@ -213,7 +228,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_default_channels[i]);
}
- mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_default_data;
+ mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
return 1;
};
@@ -227,7 +242,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_msn21xx_channels);
}
- mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_msn21xx_data;
+ mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
return 1;
};
@@ -314,9 +329,10 @@ static int __init mlxplat_init(void)
}
priv->pdev_hotplug = platform_device_register_resndata(
- &mlxplat_dev->dev, "mlxcpld-hotplug", -1,
- mlxplat_mlxcpld_hotplug_resources,
- ARRAY_SIZE(mlxplat_mlxcpld_hotplug_resources),
+ &mlxplat_dev->dev, "mlxcpld-hotplug",
+ PLATFORM_DEVID_NONE,
+ mlxplat_mlxcpld_resources,
+ ARRAY_SIZE(mlxplat_mlxcpld_resources),
mlxplat_hotplug, sizeof(*mlxplat_hotplug));
if (IS_ERR(priv->pdev_hotplug)) {
err = PTR_ERR(priv->pdev_hotplug);
diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c
new file mode 100644
index 000000000000..02e11fdbf375
--- /dev/null
+++ b/drivers/platform/x86/silead_dmi.c
@@ -0,0 +1,136 @@
+/*
+ * Silead touchscreen driver DMI based configuration code
+ *
+ * Copyright (c) 2017 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Red Hat authors:
+ * Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/notifier.h>
+#include <linux/property.h>
+#include <linux/string.h>
+
+struct silead_ts_dmi_data {
+ const char *acpi_name;
+ struct property_entry *properties;
+};
+
+static struct property_entry cube_iwork8_air_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1660),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 900),
+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ { }
+};
+
+static const struct silead_ts_dmi_data cube_iwork8_air_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = cube_iwork8_air_props,
+};
+
+static struct property_entry jumper_ezpad_mini3_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1700),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1150),
+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-jumper-ezpad-mini3.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ { }
+};
+
+static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = jumper_ezpad_mini3_props,
+};
+
+static const struct dmi_system_id silead_ts_dmi_table[] = {
+ {
+ /* CUBE iwork8 Air */
+ .driver_data = (void *)&cube_iwork8_air_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "cube"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "i1-TF"),
+ DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
+ },
+ },
+ {
+ /* Jumper EZpad mini3 */
+ .driver_data = (void *)&jumper_ezpad_mini3_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+ /* jumperx.T87.KFBNEEA02 with the version-nr dropped */
+ DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"),
+ },
+ },
+ { },
+};
+
+static void silead_ts_dmi_add_props(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ const struct dmi_system_id *dmi_id;
+ const struct silead_ts_dmi_data *ts_data;
+ int error;
+
+ dmi_id = dmi_first_match(silead_ts_dmi_table);
+ if (!dmi_id)
+ return;
+
+ ts_data = dmi_id->driver_data;
+ if (has_acpi_companion(dev) &&
+ !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) {
+ error = device_add_properties(dev, ts_data->properties);
+ if (error)
+ dev_err(dev, "failed to add properties: %d\n", error);
+ }
+}
+
+static int silead_ts_dmi_notifier_call(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ silead_ts_dmi_add_props(dev);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct notifier_block silead_ts_dmi_notifier = {
+ .notifier_call = silead_ts_dmi_notifier_call,
+};
+
+static int __init silead_ts_dmi_init(void)
+{
+ int error;
+
+ error = bus_register_notifier(&i2c_bus_type, &silead_ts_dmi_notifier);
+ if (error)
+ pr_err("%s: failed to register i2c bus notifier: %d\n",
+ __func__, error);
+
+ return error;
+}
+
+/*
+ * We are registering out notifier after i2c core is initialized and i2c bus
+ * itself is ready (which happens at postcore initcall level), but before
+ * ACPI starts enumerating devices (at subsys initcall level).
+ */
+arch_initcall(silead_ts_dmi_init);