Skip to content

Commit 6b27354

Browse files
committed
Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c fixes from Wolfram Sang: "An I2C core fix to prevent a use-after-free in a rare error path, and an I2C ACPI addition to work around broken HW/firmware related to touchscreens" * 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: i2c: core: fix use after free in of_i2c_notify i2c: acpi: Force bus speed to 400KHz if a Silead touchscreen is present
2 parents 1d4c79e + a4c2fec commit 6b27354

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

drivers/i2c/i2c-core-acpi.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct i2c_acpi_lookup {
3939
int index;
4040
u32 speed;
4141
u32 min_speed;
42+
u32 force_speed;
4243
};
4344

4445
/**
@@ -285,6 +286,19 @@ i2c_acpi_match_device(const struct acpi_device_id *matches,
285286
return acpi_match_device(matches, &client->dev);
286287
}
287288

289+
static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = {
290+
/*
291+
* These Silead touchscreen controllers only work at 400KHz, for
292+
* some reason they do not work at 100KHz. On some devices the ACPI
293+
* tables list another device at their bus as only being capable
294+
* of 100KHz, testing has shown that these other devices work fine
295+
* at 400KHz (as can be expected of any recent i2c hw) so we force
296+
* the speed of the bus to 400 KHz if a Silead device is present.
297+
*/
298+
{ "MSSL1680", 0 },
299+
{}
300+
};
301+
288302
static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level,
289303
void *data, void **return_value)
290304
{
@@ -303,6 +317,9 @@ static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level,
303317
if (lookup->speed <= lookup->min_speed)
304318
lookup->min_speed = lookup->speed;
305319

320+
if (acpi_match_device_ids(adev, i2c_acpi_force_400khz_device_ids) == 0)
321+
lookup->force_speed = 400000;
322+
306323
return AE_OK;
307324
}
308325

@@ -340,7 +357,16 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
340357
return 0;
341358
}
342359

343-
return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0;
360+
if (lookup.force_speed) {
361+
if (lookup.force_speed != lookup.min_speed)
362+
dev_warn(dev, FW_BUG "DSDT uses known not-working I2C bus speed %d, forcing it to %d\n",
363+
lookup.min_speed, lookup.force_speed);
364+
return lookup.force_speed;
365+
} else if (lookup.min_speed != UINT_MAX) {
366+
return lookup.min_speed;
367+
} else {
368+
return 0;
369+
}
344370
}
345371
EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed);
346372

drivers/i2c/i2c-core-of.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,14 +245,14 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
245245
}
246246

247247
client = of_i2c_register_device(adap, rd->dn);
248-
put_device(&adap->dev);
249-
250248
if (IS_ERR(client)) {
251249
dev_err(&adap->dev, "failed to create client for '%pOF'\n",
252250
rd->dn);
251+
put_device(&adap->dev);
253252
of_node_clear_flag(rd->dn, OF_POPULATED);
254253
return notifier_from_errno(PTR_ERR(client));
255254
}
255+
put_device(&adap->dev);
256256
break;
257257
case OF_RECONFIG_CHANGE_REMOVE:
258258
/* already depopulated? */

0 commit comments

Comments
 (0)