Skip to content

Commit 4349596

Browse files
chhitzlag-linaro
authored andcommitted
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: 242b811 ("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>
1 parent ea1c4c7 commit 4349596

1 file changed

Lines changed: 40 additions & 15 deletions

File tree

drivers/leds/leds-lp50xx.c

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@
5050

5151
#define LP50XX_SW_RESET 0xff
5252
#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
5359

5460
/* There are 3 LED outputs per bank */
5561
#define LP50XX_LEDS_PER_MODULE 3
@@ -369,19 +375,42 @@ static int lp50xx_reset(struct lp50xx *priv)
369375
return regmap_write(priv->regmap, priv->chip_info->reset_reg, LP50XX_SW_RESET);
370376
}
371377

372-
static int lp50xx_enable_disable(struct lp50xx *priv, int enable_disable)
378+
static int lp50xx_enable(struct lp50xx *priv)
373379
{
374380
int ret;
375381

376-
ret = gpiod_direction_output(priv->enable_gpio, enable_disable);
382+
if (priv->enable_gpio) {
383+
ret = gpiod_direction_output(priv->enable_gpio, LP50XX_EN_GPIO_HIGH);
384+
if (ret)
385+
return ret;
386+
387+
udelay(LP50XX_START_TIME_US);
388+
}
389+
390+
ret = lp50xx_reset(priv);
377391
if (ret)
378392
return ret;
379393

380-
if (enable_disable)
381-
return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN);
382-
else
383-
return regmap_write(priv->regmap, LP50XX_DEV_CFG0, 0);
394+
return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN);
395+
}
384396

397+
static int lp50xx_disable(struct lp50xx *priv)
398+
{
399+
int ret;
400+
401+
ret = regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_DISABLE);
402+
if (ret)
403+
return ret;
404+
405+
if (priv->enable_gpio) {
406+
ret = gpiod_direction_output(priv->enable_gpio, LP50XX_EN_GPIO_LOW);
407+
if (ret)
408+
return ret;
409+
410+
udelay(LP50XX_RESET_TIME_US);
411+
}
412+
413+
return 0;
385414
}
386415

387416
static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv,
@@ -445,6 +474,10 @@ static int lp50xx_probe_dt(struct lp50xx *priv)
445474
return dev_err_probe(priv->dev, PTR_ERR(priv->enable_gpio),
446475
"Failed to get enable GPIO\n");
447476

477+
ret = lp50xx_enable(priv);
478+
if (ret)
479+
return ret;
480+
448481
priv->regulator = devm_regulator_get(priv->dev, "vled");
449482
if (IS_ERR(priv->regulator))
450483
priv->regulator = NULL;
@@ -545,14 +578,6 @@ static int lp50xx_probe(struct i2c_client *client)
545578
return ret;
546579
}
547580

548-
ret = lp50xx_reset(led);
549-
if (ret)
550-
return ret;
551-
552-
ret = lp50xx_enable_disable(led, 1);
553-
if (ret)
554-
return ret;
555-
556581
return lp50xx_probe_dt(led);
557582
}
558583

@@ -561,7 +586,7 @@ static void lp50xx_remove(struct i2c_client *client)
561586
struct lp50xx *led = i2c_get_clientdata(client);
562587
int ret;
563588

564-
ret = lp50xx_enable_disable(led, 0);
589+
ret = lp50xx_disable(led);
565590
if (ret)
566591
dev_err(led->dev, "Failed to disable chip\n");
567592

0 commit comments

Comments
 (0)