Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

backlight: lp855x: Add support ACPI enumeration

The Xiaomi Mi Pad 2 tablet uses an ACPI enumerated LP8556 backlight
controller for its LCD-panel, with a Xiaomi specific ACPI HID of
"XMCC0001", add support for this.

Note the new "if (id)" check also fixes a NULL pointer deref when a user
tries to manually bind the driver from sysfs.

When CONFIG_ACPI is disabled acpi_match_device() will always return NULL,
so the lp855x_parse_acpi() call will get optimized away.

Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Link: https://lore.kernel.org/r/20211102225504.18920-3-hdegoede@redhat.com

authored by

Hans de Goede and committed by
Lee Jones
6202b5de 92add941

+61 -12
+61 -12
drivers/video/backlight/lp855x_bl.c
··· 5 5 * Copyright (C) 2011 Texas Instruments 6 6 */ 7 7 8 + #include <linux/acpi.h> 8 9 #include <linux/module.h> 9 10 #include <linux/slab.h> 10 11 #include <linux/i2c.h> ··· 331 330 { 332 331 struct device *dev = lp->dev; 333 332 struct device_node *node = dev->of_node; 334 - struct lp855x_platform_data *pdata; 333 + struct lp855x_platform_data *pdata = lp->pdata; 335 334 int rom_length; 336 335 337 336 if (!node) { 338 337 dev_err(dev, "no platform data\n"); 339 338 return -EINVAL; 340 339 } 341 - 342 - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 343 - if (!pdata) 344 - return -ENOMEM; 345 340 346 341 of_property_read_string(node, "bl-name", &pdata->name); 347 342 of_property_read_u8(node, "dev-ctrl", &pdata->device_control); ··· 365 368 pdata->rom_data = &rom[0]; 366 369 } 367 370 368 - lp->pdata = pdata; 369 - 370 371 return 0; 371 372 } 372 373 #else ··· 374 379 } 375 380 #endif 376 381 382 + static int lp855x_parse_acpi(struct lp855x *lp) 383 + { 384 + int ret; 385 + 386 + /* 387 + * On ACPI the device has already been initialized by the firmware 388 + * and is in register mode, so we can read back the settings from 389 + * the registers. 390 + */ 391 + ret = i2c_smbus_read_byte_data(lp->client, lp->cfg->reg_brightness); 392 + if (ret < 0) 393 + return ret; 394 + 395 + lp->pdata->initial_brightness = ret; 396 + 397 + ret = i2c_smbus_read_byte_data(lp->client, lp->cfg->reg_devicectrl); 398 + if (ret < 0) 399 + return ret; 400 + 401 + lp->pdata->device_control = ret; 402 + return 0; 403 + } 404 + 377 405 static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) 378 406 { 407 + const struct acpi_device_id *acpi_id = NULL; 379 408 struct device *dev = &cl->dev; 380 409 struct lp855x *lp; 381 410 int ret; ··· 413 394 414 395 lp->client = cl; 415 396 lp->dev = dev; 416 - lp->chipname = id->name; 417 - lp->chip_id = id->driver_data; 418 397 lp->pdata = dev_get_platdata(dev); 398 + 399 + if (id) { 400 + lp->chipname = id->name; 401 + lp->chip_id = id->driver_data; 402 + } else { 403 + acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); 404 + if (!acpi_id) 405 + return -ENODEV; 406 + 407 + lp->chipname = acpi_id->id; 408 + lp->chip_id = acpi_id->driver_data; 409 + } 419 410 420 411 switch (lp->chip_id) { 421 412 case LP8550: ··· 444 415 } 445 416 446 417 if (!lp->pdata) { 447 - ret = lp855x_parse_dt(lp); 448 - if (ret < 0) 449 - return ret; 418 + lp->pdata = devm_kzalloc(dev, sizeof(*lp->pdata), GFP_KERNEL); 419 + if (!lp->pdata) 420 + return -ENOMEM; 421 + 422 + if (id) { 423 + ret = lp855x_parse_dt(lp); 424 + if (ret < 0) 425 + return ret; 426 + } else { 427 + ret = lp855x_parse_acpi(lp); 428 + if (ret < 0) 429 + return ret; 430 + } 450 431 } 451 432 452 433 if (lp->pdata->period_ns > 0) ··· 576 537 }; 577 538 MODULE_DEVICE_TABLE(i2c, lp855x_ids); 578 539 540 + #ifdef CONFIG_ACPI 541 + static const struct acpi_device_id lp855x_acpi_match[] = { 542 + /* Xiaomi specific HID used for the LP8556 on the Mi Pad 2 */ 543 + { "XMCC0001", LP8556 }, 544 + { } 545 + }; 546 + MODULE_DEVICE_TABLE(acpi, lp855x_acpi_match); 547 + #endif 548 + 579 549 static struct i2c_driver lp855x_driver = { 580 550 .driver = { 581 551 .name = "lp855x", 582 552 .of_match_table = of_match_ptr(lp855x_dt_ids), 553 + .acpi_match_table = ACPI_PTR(lp855x_acpi_match), 583 554 }, 584 555 .probe = lp855x_probe, 585 556 .remove = lp855x_remove,