All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Paul Louvel" <paul.louvel@bootlin.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH 5/5] regulator: Add TI LM51772 support
Date: Wed, 21 Oct 2026 10:56:58 +0000	[thread overview]
Message-ID: <sashiko-outbox-180131@kernel.org> (raw)
In-Reply-To: <20261021-paul-lm51772-v1-5-25f0ffbffa8d@bootlin.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] regulator: lm51772: wrong register for CONV_EN in lm51772_set_conv_en()
- [High] regulator: lm51772: cached CLEAR_FAULTS read in lm51772_irq_renable()
- [High] regulator: lm51772: OVP lowered before VOUT in lm51772_regulator_set_voltage_sel()
- [Medium] regulator: lm51772: multi-bit mask passed to regulator_err2notif()
- [Medium] regulator: lm51772: plain 64-bit division in lm51772_regulator_set_current_limit()
- [Medium] regulator: lm51772: min_uA ignored in lm51772_regulator_set_current_limit()
--

commit a4b40e7b6b6cb8eaba3df00e481d736c9bbb846f
Author: Paul Louvel <paul.louvel@bootlin.com>

regulator: Add TI LM51772 support

This commit adds an I2C regulator driver for the TI LM51772 buck-boost
controller, supporting a configurable buck-boost output and a fixed 5 V LDO
output with voltage setting, current limiting, and fault reporting.

> diff --git a/drivers/regulator/lm51772-regulator.c b/drivers/regulator/lm51772-regulator.c
> new file mode 100644
> index 0000000000000..b5259f2772433
> --- /dev/null
> +++ b/drivers/regulator/lm51772-regulator.c
> @@ -0,0 +1,826 @@

[ ... ]

> +/* MFR_SPECIFIC_D0 bits */
> +#define LM51772_EN_VCC1				BIT(5)
> +
> +/* MFR_SPECIFIC_D1 bits */
> +#define LM51772_EN_THER_WARN			BIT(7)
> +#define LM51772_THW_THRESHOLD_MASK		GENMASK(6, 5)
> +#define LM51772_EN_NINT				BIT(4)
> +#define LM51772_CONV_EN				BIT(0)

[ ... ]

> +static int lm51772_set_conv_en(struct regmap *regmap, bool enable)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(regmap, LM51772_REG_USB_PD_CONTROL_0,
> +				 LM51772_CONV_EN2,
> +				 FIELD_PREP(LM51772_CONV_EN2, enable));
> +	if (ret)
> +		return ret;
> +
> +	return regmap_update_bits(regmap, LM51772_REG_MFR_SPECIFIC_D0,
> +				  LM51772_CONV_EN,
> +				  FIELD_PREP(LM51772_CONV_EN, enable));
> +}
> +
> +static int lm51772_get_conv_en(struct regmap *regmap)
> +{
> +	unsigned int pd_ctrl, cfg0;
> +	int ret;
> +
> +	ret = regmap_read(regmap, LM51772_REG_USB_PD_CONTROL_0, &pd_ctrl);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_read(regmap, LM51772_REG_MFR_SPECIFIC_D0, &cfg0);
> +	if (ret)
> +		return ret;
> +
> +	return FIELD_GET(LM51772_CONV_EN2, pd_ctrl) || FIELD_GET(LM51772_CONV_EN, cfg0);
> +}

[Severity: High]
Should lm51772_set_conv_en() and lm51772_get_conv_en() access
LM51772_REG_MFR_SPECIFIC_D1 instead of LM51772_REG_MFR_SPECIFIC_D0 for
LM51772_CONV_EN?

LM51772_CONV_EN is defined under the MFR_SPECIFIC_D1 bit definitions, and in
lm51772_reg_defaults, LM51772_REG_MFR_SPECIFIC_D1 has a default value of
0x09 (bit 0 set) while LM51772_REG_MFR_SPECIFIC_D0 defaults to 0x32 (bit 0
clear).

When lm51772_regulator_enable(), lm51772_regulator_disable(), or
lm51772_regulator_is_enabled() is called on the vout regulator, updating and
reading LM51772_REG_MFR_SPECIFIC_D0 leaves LM51772_CONV_EN set in
LM51772_REG_MFR_SPECIFIC_D1, preventing the converter from being disabled in
hardware while modifying bit 0 of LM51772_REG_MFR_SPECIFIC_D0.

[ ... ]

> +static int lm51772_set_ov(struct regulator_dev *rdev, int lim_uV)
> +{
> +	static const struct linear_range ovp_ranges[] = {
> +		LINEAR_RANGE(4000000, 0, 0x17, 500000),
> +		LINEAR_RANGE(16000000, 0x18, 0x3f, 1000000),
> +	};
> +	struct regmap *regmap = rdev_get_regmap(rdev);
> +	struct device *dev = rdev_get_dev(rdev);
> +	unsigned int selector;
> +	bool found;
> +	int ret;
> +
> +	ret = linear_range_get_selector_low_array(ovp_ranges, ARRAY_SIZE(ovp_ranges), lim_uV,
> +						  &selector, &found);
> +	if (ret || !found)
> +		return -EINVAL;
> +
> +	dev_dbg(dev, "OVP set to %d uV (selector 0x%02x)\n", lim_uV, selector);
> +
> +	return regmap_write(regmap, LM51772_REG_MFR_SPECIFIC_D5, selector);
> +}
> +
> +static int lm51772_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
> +{
> +	const struct lm51772_priv *priv = rdev_get_drvdata(rdev);
> +	int ret;
> +
> +	/*
> +	 * The LM51772 uses hardcoded OVP thresholds. Update the OVP threshold
> +	 * to match the new voltage.
> +	 */
> +	if (priv->ovp_thres) {
> +		ret = regulator_list_voltage_pickable_linear_range(rdev, selector);
> +		if (ret < 0)
> +			return ret;
> +
> +		ret = lm51772_set_ov(rdev, ret + priv->ovp_thres);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return regulator_set_voltage_sel_pickable_regmap(rdev, selector);
> +}

[Severity: High]
When decreasing the output voltage in lm51772_regulator_set_voltage_sel()
while priv->ovp_thres is set, can calling lm51772_set_ov() before
regulator_set_voltage_sel_pickable_regmap() trip a false over-voltage
protection fault because VOUT is still at the higher voltage when the lower
OVP threshold is written to LM51772_REG_MFR_SPECIFIC_D5?

Also, in lm51772_set_ov(), ovp_ranges[0] ends at 15500000 uV (selector 0x17)
and ovp_ranges[1] starts at 16000000 uV (selector 0x18), up to 55000000 uV
(selector 0x3f). If ret + priv->ovp_thres falls between 15500001 uV and
15999999 uV, or exceeds 55000000 uV, linear_range_get_selector_low_array()
sets found to false and lm51772_set_ov() returns -EINVAL, causing the
voltage change to fail.

[ ... ]

> +static int lm51772_regulator_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA)
> +{
> +	struct lm51772_priv *priv = rdev_get_drvdata(rdev);
> +	u64 voltage_uV = ((u64)priv->sense_res_milliohms * max_uA) / 1000;
> +	struct regmap *regmap = rdev_get_regmap(rdev);
> +	u8 ilim_reg;
> +
> +	if (priv->iset_pin)
> +		return -EOPNOTSUPP;
> +
> +	if (voltage_uV < LM51772_ILIM_THR_MIN_UV || voltage_uV > LM51772_ILIM_THR_MAX_UV)
> +		return -EINVAL;
> +
> +	ilim_reg = voltage_uV / LM51772_ILIM_THR_STEP_UV;

[Severity: Medium]
Will dividing u64 values with the plain / operator in
lm51772_regulator_set_current_limit() cause a link failure (__udivdi3 /
__aeabi_uldivmod undefined) when building on 32-bit architectures? Should
this use div_u64() instead?

[Severity: Medium]
What happens in lm51772_regulator_set_current_limit() if the truncated
register value ilim_reg corresponds to a current limit strictly below
min_uA? Because min_uA is not checked, can this program a hardware current
limit lower than the minimum requested by the caller instead of returning
-EINVAL?

> +
> +	dev_dbg(rdev_get_dev(rdev),
> +		"set current limit: %d uA (ilim_reg 0x%02x, sense_res %d mOhm)\n", max_uA, ilim_reg,
> +		priv->sense_res_milliohms);
> +
> +	return regmap_write(regmap, LM51772_REG_ILIM_THRESHOLD, ilim_reg);
> +}

[ ... ]

> +static int lm51772_irq_map_event(int irq, struct regulator_irq_data *rid,
> +			     unsigned long *dev_mask)
> +{
> +	struct regmap *regmap = rid->data;
> +	unsigned int reg, errors;
> +	int ret;
> +
> +	ret = regmap_read(regmap, LM51772_REG_STATUS_BYTE, &reg);
> +	if (ret)
> +		return REGULATOR_FAILED_RETRY;
> +
> +	errors = lm51772_status2err(reg);
> +
> +	for (size_t i = 0; i < rid->num_states; i++) {
> +		rid->states[i].errors = errors & rid->states[i].possible_errs;
> +		rid->states[i].notifs = regulator_err2notif(rid->states[i].errors);

[Severity: Medium]
In lm51772_irq_map_event(), what happens when more than one fault bit is set
in LM51772_REG_STATUS_BYTE at the same time?

lm51772_status2err() ORs multiple REGULATOR_ERROR_* flags together, so
rid->states[i].errors can have multiple bits set. However,
regulator_err2notif() in include/linux/regulator/driver.h is a switch
statement over single-bit REGULATOR_ERROR_* constants and returns 0 when
passed a multi-bit mask, which drops the corresponding REGULATOR_EVENT_*
notifications.

> +
> +		if (reg & LM51772_STAT_OFF)
> +			rid->states[i].notifs |= REGULATOR_EVENT_DISABLE;
> +
> +		if (rid->states[i].errors || rid->states[i].notifs & REGULATOR_EVENT_DISABLE)
> +			*dev_mask |= BIT(i);
> +	}
> +
> +	rid->opaque = reg;
> +
> +	return 0;
> +}
> +
> +static int lm51772_irq_renable(struct regulator_irq_data *rid)
> +{
> +	struct regmap *regmap = rid->data;
> +	unsigned int reg;
> +	int ret;
> +
> +	ret = regmap_read(regmap, LM51772_REG_STATUS_BYTE, &reg);
> +	if (ret)
> +		return REGULATOR_FAILED_RETRY;
> +
> +	if (rid->opaque && rid->opaque == reg) {
> +		ret = regmap_read(regmap, LM51772_REG_CLEAR_FAULTS, &reg);
> +		if (ret)
> +			return REGULATOR_FAILED_RETRY;
> +
> +		return REGULATOR_ERROR_ON;
> +	}
> +
> +	rid->opaque = 0;
> +
> +	return REGULATOR_ERROR_CLEARED;
> +}

[ ... ]

> +static const struct regmap_range lm51772_volatile_ranges[] = {
> +	regmap_reg_range(LM51772_REG_PD_STATUS_0, LM51772_REG_PD_STATUS_0),
> +	regmap_reg_range(LM51772_REG_STATUS_BYTE, LM51772_REG_STATUS_BYTE)
> +};
> +
> +static const struct regmap_access_table lm51772_volatile_table = {
> +	.yes_ranges = lm51772_volatile_ranges,
> +	.n_yes_ranges = ARRAY_SIZE(lm51772_volatile_ranges)
> +};
> +
> +static const struct reg_default lm51772_reg_defaults[] = {
> +	{ LM51772_REG_CLEAR_FAULTS, 0x00 },	{ LM51772_REG_ILIM_THRESHOLD, 0x64 },

[Severity: High]
Does regmap_read(regmap, LM51772_REG_CLEAR_FAULTS, &reg) in
lm51772_irq_renable() actually reach the hardware over I2C?

Because lm51772_regmap_config enables REGCACHE_MAPLE, seeds
LM51772_REG_CLEAR_FAULTS in lm51772_reg_defaults, and omits
LM51772_REG_CLEAR_FAULTS from lm51772_volatile_ranges, regmap_read() returns
the cached 0x00 value without performing an I2C bus transaction. As a
result, latched faults in LM51772_REG_STATUS_BYTE are never cleared and
lm51772_irq_renable() will keep returning REGULATOR_ERROR_ON.

Also, in lm51772_irq_renable(), if an additional fault bit becomes set in
LM51772_REG_STATUS_BYTE so that reg is non-zero but no longer equal to
rid->opaque, won't the (rid->opaque && rid->opaque == reg) check evaluate to
false and return REGULATOR_ERROR_CLEARED while faults are still active?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261021-paul-lm51772-v1-0-25f0ffbffa8d@bootlin.com?part=5

  reply	other threads:[~2026-10-21 10:56 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-21 10:27 [PATCH 0/5] Add TI LM51772 buck-boost voltage regulator Paul Louvel
2026-10-21 10:27 ` [PATCH 1/5] regulator: dt-bindings: Add regulator-boot-force-off property Paul Louvel
2026-10-21 17:01   ` Conor Dooley
2026-10-21 17:11     ` Paul Louvel
2026-10-22  7:08       ` Krzysztof Kozlowski
2026-10-22 12:22       ` Mark Brown
2026-10-22 12:39         ` Paul Louvel
2026-10-21 10:27 ` [PATCH 2/5] regulator: dt-bindings: Add TI LM51772 support Paul Louvel
2026-10-21 10:44   ` sashiko-bot
2026-10-21 10:27 ` [PATCH 3/5] regulator: core: Add mechanism to force disable a regulator at boot Paul Louvel
2026-10-21 10:46   ` sashiko-bot
2026-10-21 15:17     ` Paul Louvel
2026-10-22 13:48   ` Mark Brown
2026-10-21 10:27 ` [PATCH 4/5] regulator: Support regulators where the voltage selector spans two registers Paul Louvel
2026-10-21 10:45   ` sashiko-bot
2026-10-21 15:10     ` Paul Louvel
2026-10-22 17:21   ` Mark Brown
2026-10-23 10:02     ` Paul Louvel
2026-10-21 10:27 ` [PATCH 5/5] regulator: Add TI LM51772 support Paul Louvel
2026-10-21 10:56   ` sashiko-bot [this message]
2026-10-21 15:14     ` Paul Louvel
2026-10-21 15:10   ` Uwe Kleine-König
2026-10-22 17:34   ` Mark Brown
2026-10-23  7:24     ` Paul Louvel
2026-10-24 19:28   ` kernel test robot
2026-10-22 13:42 ` [PATCH 0/5] Add TI LM51772 buck-boost voltage regulator Mark Brown
2026-10-23 10:31   ` Paul Louvel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-180131@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=paul.louvel@bootlin.com \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.