* [PATCH v2 0/2] regulator: fp9931: fix voltage mapping and runtime PM issues @ 2026-07-24 10:34 robby.cai 2026-07-24 10:34 ` [PATCH v2 1/2] regulator: fp9931: Fix VPOS/VNEG voltage selector table robby.cai 2026-07-24 10:34 ` [PATCH v2 2/2] regulator: fp9931: Fix Runtime PM usage count underflow in v3p3 ops robby.cai 0 siblings, 2 replies; 5+ messages in thread From: robby.cai @ 2026-07-24 10:34 UTC (permalink / raw) To: lgirdwood, broonie, andreas; +Cc: linux-kernel, imx From: Robby Cai <robby.cai@nxp.com> This series fixes two issues in the FP9931/JD9930 regulator driver. Patch 1 fixes errors in the VPOS/VNEG voltage selector table, correcting an off-by-one entry and extending the table to cover the full selector range defined by the datasheet [1]. Patch 2 fixes a Runtime PM reference counting bug in the V3P3 regulator callbacks that can lead to "Runtime PM usage count underflow!" warnings. [1] https://www.fitipower.com/dl/file/flXa6hIchVeu0W3K (Datasheet, p.13) Thanks, Robby --- Changes in v2: - [1/2] Extend VPOSNEG_table[] to cover selectors 0x29-0x3f as defined by the datasheet and reformat the table for readability. - [2/2] Refine commit message; no code change. Link to v1: https://lore.kernel.org/imx/20260721095959.1855436-1-robby.cai@oss.nxp.com/ --- Robby Cai (2): regulator: fp9931: Fix VPOS/VNEG voltage selector table regulator: fp9931: Fix Runtime PM usage count underflow in v3p3 ops drivers/regulator/fp9931.c | 61 +++++++++++--------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) -- 2.50.1 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] regulator: fp9931: Fix VPOS/VNEG voltage selector table 2026-07-24 10:34 [PATCH v2 0/2] regulator: fp9931: fix voltage mapping and runtime PM issues robby.cai @ 2026-07-24 10:34 ` robby.cai 2026-07-24 10:41 ` sashiko-bot 2026-07-24 10:34 ` [PATCH v2 2/2] regulator: fp9931: Fix Runtime PM usage count underflow in v3p3 ops robby.cai 1 sibling, 1 reply; 5+ messages in thread From: robby.cai @ 2026-07-24 10:34 UTC (permalink / raw) To: lgirdwood, broonie, andreas; +Cc: linux-kernel, imx From: Robby Cai <robby.cai@nxp.com> The VPOSNEG_table[] mapping does not match the FP9931 datasheet. The datasheet defines the VPOS/VNEG voltage mapping as: 00h-04h -> 7.04V (-7.04V) 05h -> 7.26V (-7.26V) 06h -> 7.49V (-7.49V) ... 28h-3Fh -> 15.06V (-15.06V) However, VPOSNEG_table[] has two issues: 1. Selector 0x00~0x04 should all map to 7.04V (5 entries), but the table has 6 entries of 7.04V, causing all subsequent entries to be shifted by one position. 2. Selectors 0x29~0x3F should all clamp to 15.06V (23 entries), but the table has only 41 entries. Any selector value above 0x28 would result in an out-of-bounds table access. Fix both issues by removing the duplicate 7.04V entry and appending the missing 23 clamped 15.06V entries, bringing the table to the correct size of 64 entries (0x00~0x3F). Fixes: 12d821bd13d4 ("regulator: Add FP9931/JD9930 driver") Signed-off-by: Robby Cai <robby.cai@nxp.com> --- drivers/regulator/fp9931.c | 54 +++++++++----------------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c index 002b41f53eff..ff743a8b0dfe 100644 --- a/drivers/regulator/fp9931.c +++ b/drivers/regulator/fp9931.c @@ -37,48 +37,18 @@ struct fp9931_data { }; static const unsigned int VPOSNEG_table[] = { - 7040000, - 7040000, - 7040000, - 7040000, - 7040000, - 7040000, - 7260000, - 7490000, - 7710000, - 7930000, - 8150000, - 8380000, - 8600000, - 8820000, - 9040000, - 9270000, - 9490000, - 9710000, - 9940000, - 10160000, - 10380000, - 10600000, - 10830000, - 11050000, - 11270000, - 11490000, - 11720000, - 11940000, - 12160000, - 12380000, - 12610000, - 12830000, - 13050000, - 13280000, - 13500000, - 13720000, - 13940000, - 14170000, - 14390000, - 14610000, - 14830000, - 15060000, + 7040000, 7040000, 7040000, 7040000, 7040000, /* 00h-04h */ + 7260000, 7490000, 7710000, 7930000, 8150000, 8380000, /* 05h-0Ah */ + 8600000, 8820000, 9040000, 9270000, 9490000, 9710000, /* 0Bh-10h */ + 9940000, 10160000, 10380000, 10600000, 10830000, 11050000, /* 11h-16h */ + 11270000, 11490000, 11720000, 11940000, 12160000, 12380000, /* 17h-1Ch */ + 12610000, 12830000, 13050000, 13280000, 13500000, 13720000, /* 1Dh-22h */ + 13940000, 14170000, 14390000, 14610000, 14830000, 15060000, /* 23h-28h */ + /* 29h-3Fh: clamped to 15.06V per datasheet */ + 15060000, 15060000, 15060000, 15060000, 15060000, 15060000, + 15060000, 15060000, 15060000, 15060000, 15060000, 15060000, + 15060000, 15060000, 15060000, 15060000, 15060000, 15060000, + 15060000, 15060000, 15060000, 15060000, 15060000, }; static const struct hwmon_channel_info *fp9931_info[] = { -- 2.50.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/2] regulator: fp9931: Fix VPOS/VNEG voltage selector table 2026-07-24 10:34 ` [PATCH v2 1/2] regulator: fp9931: Fix VPOS/VNEG voltage selector table robby.cai @ 2026-07-24 10:41 ` sashiko-bot 0 siblings, 0 replies; 5+ messages in thread From: sashiko-bot @ 2026-07-24 10:41 UTC (permalink / raw) To: robby.cai; +Cc: Frank.Li, imx Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: New issues: - [Medium] The commit message makes technically inaccurate claims about the VPOSNEG_table size and an out-of-bounds access. Pre-existing issues: - [High] The vcom regulator is configured with n_voltages = 255 but its vsel_mask is 0xFF, preventing the maximum voltage level from being reached. - [High] fp9931_set_enable() leaves en_gpio asserted when wait_for_completion_timeout() fails. - [High] Incomplete error handling in fp9931_runtime_resume() leaks physical regulator enable and GPIO state on regcache_sync failure. -- --- Patch [1]: [PATCH v2 1/2] regulator: fp9931: Fix VPOS/VNEG voltage selector table --- commit 96adb91729b2025db8107f97477744ebe2be390d Author: Robby Cai <robby.cai@nxp.com> regulator: fp9931: Fix VPOS/VNEG voltage selector table This commit fixes the VPOSNEG_table voltage mapping in the FP9931 regulator driver. It removes a duplicate entry for 7.04V and appends missing entries to properly clamp higher selectors to 15.06V, matching the datasheet specifications. > 2. Selectors 0x29~0x3F should all clamp to 15.06V (23 entries), but > the table has only 41 entries. Any selector value above 0x28 > would result in an out-of-bounds table access. [Severity: Medium] Are these claims accurate? The original table had 42 entries, not 41 (six 7.04V entries plus 36 other entries). Also, an out-of-bounds array access is not possible here since the regulator core bounds-checks the requested selector against n_voltages (which was correctly set to ARRAY_SIZE(VPOSNEG_table)). While reviewing this patch, I noticed a few pre-existing issues in the same file: drivers/regulator/fp9931.c:fp9931_runtime_resume() { ... > if (data->en_ts_gpio) { > gpiod_set_value_cansleep(data->en_ts_gpio, 1); > /* wait for one ADC conversion to have sane temperature */ > usleep_range(10000, 15000); > } > > ret = regcache_sync(data->regmap); > > return ret; > } [Severity: High] This isn't a bug introduced by this patch, but could this leak resources if regcache_sync() fails? It returns early without disabling data->vin_reg or clearing data->en_ts_gpio. This leaves the hardware perpetually on since the PM core will keep the device in RPM_SUSPENDED without calling runtime_suspend(). drivers/regulator/fp9931.c:fp9931_set_enable() { ... > wait_for_completion_timeout(&data->pgood_completion, > msecs_to_jiffies(PGOOD_TIMEOUT_MSECS)); > dev_dbg(data->dev, "turned on"); > if (gpiod_get_value_cansleep(data->pgood_gpio) != 1) { > pm_runtime_put_autosuspend(data->dev); > return -ETIMEDOUT; > } > > return 0; > } [Severity: High] This is a pre-existing issue, but might this timeout path leave en_gpio asserted? If the enable operation times out, it returns -ETIMEDOUT but leaves data->en_gpio set to 1. Since the regulator framework assumes the device is disabled, it will not issue a disable() call, which might leave the physical pin asserted indefinitely. drivers/regulator/fp9931.c:regulators ... > { > .name = "vcom", > .of_match = of_match_ptr("vcom"), > .regulators_node = of_match_ptr("regulators"), > .id = 2, > .ops = &fp9931_vcom_ops, > .type = REGULATOR_VOLTAGE, > .owner = THIS_MODULE, > .n_voltages = 255, > .min_uV = 0, > .uV_step = 5000000 / 255, > .vsel_reg = FP9931_REG_VCOM_SETTING, > .vsel_mask = 0xFF > }, [Severity: High] This isn't a bug introduced by this patch, but does the n_voltages value prevent the maximum voltage level from being reached? By setting n_voltages to 255 instead of 256 for an 8-bit vsel_mask (0xFF), the valid selectors are restricted to 0..254. The maximum selector 0xFF (255) would be rejected by the regulator core, meaning the maximum intended voltage cannot be set. -- Sashiko AI review · https://sashiko.dev/#/patchset/20260724103441.800522-1-robby.cai@oss.nxp.com?part=1 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] regulator: fp9931: Fix Runtime PM usage count underflow in v3p3 ops 2026-07-24 10:34 [PATCH v2 0/2] regulator: fp9931: fix voltage mapping and runtime PM issues robby.cai 2026-07-24 10:34 ` [PATCH v2 1/2] regulator: fp9931: Fix VPOS/VNEG voltage selector table robby.cai @ 2026-07-24 10:34 ` robby.cai 2026-07-24 10:41 ` sashiko-bot 1 sibling, 1 reply; 5+ messages in thread From: robby.cai @ 2026-07-24 10:34 UTC (permalink / raw) To: lgirdwood, broonie, andreas; +Cc: linux-kernel, imx From: Robby Cai <robby.cai@nxp.com> The fp9931_v3p3_enable() callback acquires a Runtime PM reference which remains held until fp9931_v3p3_disable() releases it. Device-level Runtime PM lifetime is also managed through the shared VCOM enable path: fp9931_set_enable() acquires a reference and fp9931_clear_enable() releases it. As a result, the Runtime PM usage count may already have reached 0 before fp9931_v3p3_disable() is invoked. In that case, fp9931_v3p3_disable() calls pm_runtime_put_autosuspend() on an already-zero count, triggering: fp9931 1-0018: Runtime PM usage count underflow! Holding a Runtime PM reference across the V3P3 regulator lifetime is unnecessary. V3P3 only needs the device to be runtime-active for the duration of the register access. Fix this by scoping the Runtime PM reference lifetime to the register access itself, pairing pm_runtime_resume_and_get() and pm_runtime_put_autosuspend() within each callback. Fixes: 12d821bd13d4 ("regulator: Add FP9931/JD9930 driver") Signed-off-by: Robby Cai <robby.cai@nxp.com> --- drivers/regulator/fp9931.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c index ff743a8b0dfe..0d926546221a 100644 --- a/drivers/regulator/fp9931.c +++ b/drivers/regulator/fp9931.c @@ -214,8 +214,7 @@ static int fp9931_v3p3_enable(struct regulator_dev *rdev) return ret; ret = regulator_enable_regmap(rdev); - if (ret < 0) - pm_runtime_put_autosuspend(data->dev); + pm_runtime_put_autosuspend(data->dev); return ret; } @@ -225,6 +224,10 @@ static int fp9931_v3p3_disable(struct regulator_dev *rdev) struct fp9931_data *data = rdev_get_drvdata(rdev); int ret; + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + ret = regulator_disable_regmap(rdev); pm_runtime_put_autosuspend(data->dev); -- 2.50.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/2] regulator: fp9931: Fix Runtime PM usage count underflow in v3p3 ops 2026-07-24 10:34 ` [PATCH v2 2/2] regulator: fp9931: Fix Runtime PM usage count underflow in v3p3 ops robby.cai @ 2026-07-24 10:41 ` sashiko-bot 0 siblings, 0 replies; 5+ messages in thread From: sashiko-bot @ 2026-07-24 10:41 UTC (permalink / raw) To: robby.cai; +Cc: Frank.Li, imx Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] Dropping the runtime PM reference in fp9931_v3p3_enable() allows the PMIC to auto-suspend, physically powering off the active V3P3 regulator and violating framework guarantees. - [High] Disabling the V3P3 regulator while the PMIC is runtime-suspended causes a spurious 3.3V power-on glitch. -- --- Patch [2]: [PATCH v2 2/2] regulator: fp9931: Fix Runtime PM usage count underflow in v3p3 ops --- commit 195ff0977cf3484ecb06ab9189df30e12979d50c Author: Robby Cai <robby.cai@nxp.com> regulator: fp9931: Fix Runtime PM usage count underflow in v3p3 ops This commit scopes the Runtime PM reference lifetime to the register access itself in the v3p3 enable and disable callbacks. It pairs pm_runtime_resume_and_get() and pm_runtime_put_autosuspend() within each function to fix a usage count underflow issue. > diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c > index ff743a8b0dfe8..0d926546221a6 100644 > --- a/drivers/regulator/fp9931.c > +++ b/drivers/regulator/fp9931.c [ ... ] > @@ -214,8 +214,7 @@ static int fp9931_v3p3_enable(struct regulator_dev *rdev) > return ret; > > ret = regulator_enable_regmap(rdev); > - if (ret < 0) > - pm_runtime_put_autosuspend(data->dev); > + pm_runtime_put_autosuspend(data->dev); [Severity: High] Does dropping the runtime PM reference here allow the PMIC to auto-suspend while the V3P3 regulator is still logically enabled by consumers? If a consumer enables V3P3, fp9931_v3p3_enable() will acquire and then unconditionally release the reference after setting the register. When the PMIC subsequently auto-suspends, fp9931_runtime_suspend() could disable the main vin_reg power supply, causing the V3P3 output to physically power down and break framework guarantees. > > return ret; > } > @@ -225,6 +224,10 @@ static int fp9931_v3p3_disable(struct regulator_dev *rdev) > struct fp9931_data *data = rdev_get_drvdata(rdev); > int ret; > > + ret = pm_runtime_resume_and_get(data->dev); > + if (ret < 0) > + return ret; > + > ret = regulator_disable_regmap(rdev); [Severity: High] Can this resume trigger a spurious 3.3V power-on glitch if the device was already suspended? Since the device can now auto-suspend while V3P3 is logically enabled, calling regulator_disable() could trigger fp9931_v3p3_disable() while the device is suspended. In this state, pm_runtime_resume_and_get() wakes the device and invokes fp9931_runtime_resume(), which calls regcache_sync(). Because the regcache still contains the 'enabled' state for V3P3, wouldn't regcache_sync() write that state to hardware, physically turning V3P3 ON just before regulator_disable_regmap() clears the bit and turns it OFF? > pm_runtime_put_autosuspend(data->dev); > -- Sashiko AI review · https://sashiko.dev/#/patchset/20260724103441.800522-1-robby.cai@oss.nxp.com?part=2 ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-24 10:41 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-24 10:34 [PATCH v2 0/2] regulator: fp9931: fix voltage mapping and runtime PM issues robby.cai 2026-07-24 10:34 ` [PATCH v2 1/2] regulator: fp9931: Fix VPOS/VNEG voltage selector table robby.cai 2026-07-24 10:41 ` sashiko-bot 2026-07-24 10:34 ` [PATCH v2 2/2] regulator: fp9931: Fix Runtime PM usage count underflow in v3p3 ops robby.cai 2026-07-24 10:41 ` sashiko-bot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox