Commit 7574c0db authored by Hans de Goede's avatar Hans de Goede Committed by Wolfram Sang

i2c: acpi: Force bus speed to 400KHz if a Silead touchscreen is present

Many cheap devices use Silead touchscreen controllers. Testing has shown
repeatedly that these touchscreen controllers work fine at 400KHz, but for
unknown reasons do not work properly at 100KHz. This has been seen on
both ARM and x86 devices using totally different i2c controllers.

On some devices the ACPI tables list another device at the same I2C-bus
as only being capable of 100KHz, testing has shown that these other
devices work fine at 400KHz (as can be expected of any recent I2C hw).

This commit makes i2c_acpi_find_bus_speed() always return 400KHz if a
Silead touchscreen controller is present, fixing the touchscreen not
working on devices which ACPI tables' wrongly list another device on the
same bus as only being capable of 100KHz.

Specifically this fixes the touchscreen on the Jumper EZpad 6 m4 not
working.
Reported-by: default avataryouling 257 <youling257@gmail.com>
Tested-by: default avataryouling 257 <youling257@gmail.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Reviewed-by: default avatarJarkko Nikula <jarkko.nikula@linux.intel.com>
Acked-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
[wsa: rewording warning a little]
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
Cc: stable@kernel.org
parent 31f4f5b4
...@@ -39,6 +39,7 @@ struct i2c_acpi_lookup { ...@@ -39,6 +39,7 @@ struct i2c_acpi_lookup {
int index; int index;
u32 speed; u32 speed;
u32 min_speed; u32 min_speed;
u32 force_speed;
}; };
/** /**
...@@ -285,6 +286,19 @@ i2c_acpi_match_device(const struct acpi_device_id *matches, ...@@ -285,6 +286,19 @@ i2c_acpi_match_device(const struct acpi_device_id *matches,
return acpi_match_device(matches, &client->dev); return acpi_match_device(matches, &client->dev);
} }
static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = {
/*
* These Silead touchscreen controllers only work at 400KHz, for
* some reason they do not work at 100KHz. On some devices the ACPI
* tables list another device at their bus as only being capable
* of 100KHz, testing has shown that these other devices work fine
* at 400KHz (as can be expected of any recent i2c hw) so we force
* the speed of the bus to 400 KHz if a Silead device is present.
*/
{ "MSSL1680", 0 },
{}
};
static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level, static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level,
void *data, void **return_value) void *data, void **return_value)
{ {
...@@ -303,6 +317,9 @@ static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level, ...@@ -303,6 +317,9 @@ static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level,
if (lookup->speed <= lookup->min_speed) if (lookup->speed <= lookup->min_speed)
lookup->min_speed = lookup->speed; lookup->min_speed = lookup->speed;
if (acpi_match_device_ids(adev, i2c_acpi_force_400khz_device_ids) == 0)
lookup->force_speed = 400000;
return AE_OK; return AE_OK;
} }
...@@ -340,7 +357,16 @@ u32 i2c_acpi_find_bus_speed(struct device *dev) ...@@ -340,7 +357,16 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
return 0; return 0;
} }
return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0; if (lookup.force_speed) {
if (lookup.force_speed != lookup.min_speed)
dev_warn(dev, FW_BUG "DSDT uses known not-working I2C bus speed %d, forcing it to %d\n",
lookup.min_speed, lookup.force_speed);
return lookup.force_speed;
} else if (lookup.min_speed != UINT_MAX) {
return lookup.min_speed;
} else {
return 0;
}
} }
EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed);
......
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