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

leds: leds-lp50xx: Enable chip before any communication

If a GPIO is used to control the chip's enable pin, it needs to be pulled
high before any i2c communication is attempted.

Currently, the enable GPIO handling is not correct.

Assume the enable GPIO is low when the probe function is entered. In this
case the device is in SHUTDOWN mode and does not react to i2c commands.

During probe the following sequence happens:
1. The call to lp50xx_reset() on line 548 has no effect as i2c is not
possible yet.
2. Then - on line 552 - lp50xx_enable_disable() is called. As
"priv->enable_gpio“ has not yet been initialized, setting the GPIO has
no effect. Also the i2c enable command is not executed as the device
is still in SHUTDOWN.
3. On line 556 the call to lp50xx_probe_dt() finally parses the rest of
the DT and the configured priv->enable_gpio is set up.

As a result the device is still in SHUTDOWN mode and not ready for
operation.

Split lp50xx_enable_disable() into distinct enable and disable functions
to enforce correct ordering between enable_gpio manipulations and i2c
commands.
Read enable_gpio configuration from DT before attempting to manipulate
enable_gpio.
Add delays to observe correct wait timing after manipulating enable_gpio
and before any i2c communication.

Cc: stable@vger.kernel.org
Fixes: 242b81170fb8 ("leds: lp50xx: Add the LP50XX family of the RGB LED driver")
Signed-off-by: Christian Hitz <christian.hitz@bbv.ch>
Link: https://patch.msgid.link/20251028155141.1603193-1-christian@klarinett.li
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Christian Hitz and committed by
Lee Jones
43495961 ea1c4c7e

+40 -15
+40 -15
drivers/leds/leds-lp50xx.c
··· 50 50 51 51 #define LP50XX_SW_RESET 0xff 52 52 #define LP50XX_CHIP_EN BIT(6) 53 + #define LP50XX_CHIP_DISABLE 0x00 54 + #define LP50XX_START_TIME_US 500 55 + #define LP50XX_RESET_TIME_US 3 56 + 57 + #define LP50XX_EN_GPIO_LOW 0 58 + #define LP50XX_EN_GPIO_HIGH 1 53 59 54 60 /* There are 3 LED outputs per bank */ 55 61 #define LP50XX_LEDS_PER_MODULE 3 ··· 375 369 return regmap_write(priv->regmap, priv->chip_info->reset_reg, LP50XX_SW_RESET); 376 370 } 377 371 378 - static int lp50xx_enable_disable(struct lp50xx *priv, int enable_disable) 372 + static int lp50xx_enable(struct lp50xx *priv) 379 373 { 380 374 int ret; 381 375 382 - ret = gpiod_direction_output(priv->enable_gpio, enable_disable); 376 + if (priv->enable_gpio) { 377 + ret = gpiod_direction_output(priv->enable_gpio, LP50XX_EN_GPIO_HIGH); 378 + if (ret) 379 + return ret; 380 + 381 + udelay(LP50XX_START_TIME_US); 382 + } 383 + 384 + ret = lp50xx_reset(priv); 383 385 if (ret) 384 386 return ret; 385 387 386 - if (enable_disable) 387 - return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN); 388 - else 389 - return regmap_write(priv->regmap, LP50XX_DEV_CFG0, 0); 388 + return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN); 389 + } 390 390 391 + static int lp50xx_disable(struct lp50xx *priv) 392 + { 393 + int ret; 394 + 395 + ret = regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_DISABLE); 396 + if (ret) 397 + return ret; 398 + 399 + if (priv->enable_gpio) { 400 + ret = gpiod_direction_output(priv->enable_gpio, LP50XX_EN_GPIO_LOW); 401 + if (ret) 402 + return ret; 403 + 404 + udelay(LP50XX_RESET_TIME_US); 405 + } 406 + 407 + return 0; 391 408 } 392 409 393 410 static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv, ··· 473 444 if (IS_ERR(priv->enable_gpio)) 474 445 return dev_err_probe(priv->dev, PTR_ERR(priv->enable_gpio), 475 446 "Failed to get enable GPIO\n"); 447 + 448 + ret = lp50xx_enable(priv); 449 + if (ret) 450 + return ret; 476 451 477 452 priv->regulator = devm_regulator_get(priv->dev, "vled"); 478 453 if (IS_ERR(priv->regulator)) ··· 578 545 return ret; 579 546 } 580 547 581 - ret = lp50xx_reset(led); 582 - if (ret) 583 - return ret; 584 - 585 - ret = lp50xx_enable_disable(led, 1); 586 - if (ret) 587 - return ret; 588 - 589 548 return lp50xx_probe_dt(led); 590 549 } 591 550 ··· 586 561 struct lp50xx *led = i2c_get_clientdata(client); 587 562 int ret; 588 563 589 - ret = lp50xx_enable_disable(led, 0); 564 + ret = lp50xx_disable(led); 590 565 if (ret) 591 566 dev_err(led->dev, "Failed to disable chip\n"); 592 567