e105396398
I2C bus has both i2c clients and adapter devices, so we must be careful in
notifier code and verify that we are actually dealing with an i2c client
before using it as such.
Fixes: cef9dd85ac
("platform/x86: add support for devices with Silead...")
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
[andy: simplified silead_ts_dmi_add_props() change]
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
161 lines
4.2 KiB
C
161 lines
4.2 KiB
C
/*
|
|
* 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;
|
|
const struct property_entry *properties;
|
|
};
|
|
|
|
static const 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 const 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 property_entry dexp_ursus_7w_props[] = {
|
|
PROPERTY_ENTRY_U32("touchscreen-size-x", 890),
|
|
PROPERTY_ENTRY_U32("touchscreen-size-y", 630),
|
|
PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"),
|
|
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
|
|
{ }
|
|
};
|
|
|
|
static const struct silead_ts_dmi_data dexp_ursus_7w_data = {
|
|
.acpi_name = "MSSL1680:00",
|
|
.properties = dexp_ursus_7w_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"),
|
|
},
|
|
},
|
|
{
|
|
/* DEXP Ursus 7W */
|
|
.driver_data = (void *)&dexp_ursus_7w_data,
|
|
.matches = {
|
|
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "7W"),
|
|
},
|
|
},
|
|
{ },
|
|
};
|
|
|
|
static void silead_ts_dmi_add_props(struct i2c_client *client)
|
|
{
|
|
struct device *dev = &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;
|
|
struct i2c_client *client;
|
|
|
|
switch (action) {
|
|
case BUS_NOTIFY_ADD_DEVICE:
|
|
client = i2c_verify_client(dev);
|
|
if (client)
|
|
silead_ts_dmi_add_props(client);
|
|
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);
|