diff --git a/MAINTAINERS b/MAINTAINERS index 5f10c28b2e15..88cbc17d71c8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11271,6 +11271,14 @@ F: drivers/media/usb/siano/ F: drivers/media/usb/siano/ F: drivers/media/mmc/siano/ +SILEAD TOUCHSCREEN DRIVER +M: Hans de Goede +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 L: linux-fbdev@vger.kernel.org diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index d9748a881798..cfa842daa270 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1084,4 +1084,15 @@ 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" + depends on ACPI && DMI && I2C && 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 diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index cde7b4fdf5d6..b689be13ade0 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -66,6 +66,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 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +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);