From 545c93b9b42b9360143de13a75357832ed9fb83d Mon Sep 17 00:00:00 2001 From: Franklin Cooper Jr Date: Mon, 28 Sep 2026 09:06:24 -0500 Subject: [PATCH 1/4] UPSTREAM-PEND: drivers: i2c: i2c_mspm0 - Acquire lock before checking va... PR: 122743 In the target_register and target_unregister functions is_target is checked before lock is taken. Correct this since this causes more of an issue when power management support is added. Signed-off-by: Franklin Cooper Jr --- drivers/i2c/i2c_mspm0.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c_mspm0.c b/drivers/i2c/i2c_mspm0.c index 7a221f4e90ad..70799e8f92f7 100644 --- a/drivers/i2c/i2c_mspm0.c +++ b/drivers/i2c/i2c_mspm0.c @@ -906,13 +906,14 @@ static int i2c_mspm0_target_register(const struct device *dev, struct i2c_target struct i2c_mspm0_data *data = dev->data; const mm_reg_t base = config->base; + k_sem_take(&data->i2c_lock, K_FOREVER); + /* Device is already registered as target */ if (data->is_target || data->target_config == cfg) { + k_sem_give(&data->i2c_lock); return -EBUSY; } - k_sem_take(&data->i2c_lock, K_FOREVER); - data->target_config = cfg; data->target_callbacks = cfg->callbacks; @@ -953,12 +954,13 @@ static int i2c_mspm0_target_unregister(const struct device *dev, struct i2c_targ struct i2c_mspm0_data *data = dev->data; const mm_reg_t base = config->base; + k_sem_take(&data->i2c_lock, K_FOREVER); + if (data->is_target == false) { + k_sem_give(&data->i2c_lock); return 0; } - k_sem_take(&data->i2c_lock, K_FOREVER); - data->target_config = NULL; data->is_target = false; From 462101eb196322f15022be1e782e81939fa71f36 Mon Sep 17 00:00:00 2001 From: Franklin Cooper Jr Date: Mon, 28 Sep 2026 15:24:51 -0500 Subject: [PATCH 2/4] UPSTREAM-PEND: drivers: i2c_mspm0 - Add PM device runtime support PR: 122743 Enable PM device runtime support for MSPM0 i2c driver. Signed-off-by: Franklin Cooper Jr --- drivers/i2c/i2c_mspm0.c | 82 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c_mspm0.c b/drivers/i2c/i2c_mspm0.c index 70799e8f92f7..a6ff19811355 100644 --- a/drivers/i2c/i2c_mspm0.c +++ b/drivers/i2c/i2c_mspm0.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "i2c-priv.h" @@ -406,6 +408,47 @@ static inline uint8_t i2c_receive_controller_data(mm_reg_t base) return (uint8_t)(sys_read32(base + I2C_REG_CRXDATA) & I2C_CRXDATA_VALUE_MASK); } +#if defined(CONFIG_PM_DEVICE) +static int i2c_mspm0_pm_action(const struct device *dev, enum pm_device_action action) +{ + int err; + const struct i2c_mspm0_config *config = dev->config; + const mm_reg_t base = config->base; + i2c_clock_config_t clock_config = config->clock_config; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + /* Set pins to active state */ + err = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT); + if (err < 0) { + return err; + } + + /* Restore the parent clock selection. */ + i2c_set_clock_config(base, &clock_config); + + break; + + case PM_DEVICE_ACTION_SUSPEND: + /* Move pins to sleep state */ + err = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_SLEEP); + if ((err < 0) && (err != -ENOENT)) { + return err; + } + + /* Unselect all parent clocks to gate the peripheral clock. */ + clock_config.clock_sel = 0; + i2c_set_clock_config(base, &clock_config); + + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif + /* Multi-byte FIFO operations */ static uint16_t i2c_fill_controller_tx_fifo(mm_reg_t base, const uint8_t *buffer, uint16_t count) { @@ -650,6 +693,11 @@ static int i2c_mspm0_configure(const struct device *dev, uint32_t dev_config) return -ENODEV; } + ret = pm_device_runtime_get(dev); + if (ret < 0) { + return ret; + } + k_sem_take(&data->i2c_lock, K_FOREVER); /* Config I2C speed */ @@ -721,6 +769,7 @@ static int i2c_mspm0_configure(const struct device *dev, uint32_t dev_config) sem_give: k_sem_give(&data->i2c_lock); + pm_device_runtime_put(dev); return ret; } @@ -767,7 +816,16 @@ static int i2c_mspm0_init(const struct device *dev) /* Enable interrupts */ config->irq_config_func(dev); +#ifdef CONFIG_PM_DEVICE + ret = i2c_mspm0_pm_action(dev, PM_DEVICE_ACTION_SUSPEND); + if (ret < 0) { + return ret; + } + + return pm_device_driver_init(dev, i2c_mspm0_pm_action); +#else return 0; +#endif } static int i2c_mspm0_get_config(const struct device *dev, uint32_t *dev_config) @@ -860,6 +918,11 @@ static int i2c_mspm0_transfer(const struct device *dev, struct i2c_msg *msgs, ui uint32_t dev_config; int ret; + ret = pm_device_runtime_get(dev); + if (ret < 0) { + return ret; + } + k_sem_take(&data->i2c_lock, K_FOREVER); data->msgs = msgs; @@ -896,6 +959,8 @@ static int i2c_mspm0_transfer(const struct device *dev, struct i2c_msg *msgs, ui } k_sem_give(&data->i2c_lock); + + pm_device_runtime_put(dev); return ret; } @@ -905,6 +970,7 @@ static int i2c_mspm0_target_register(const struct device *dev, struct i2c_target const struct i2c_mspm0_config *config = dev->config; struct i2c_mspm0_data *data = dev->data; const mm_reg_t base = config->base; + int ret; k_sem_take(&data->i2c_lock, K_FOREVER); @@ -914,6 +980,12 @@ static int i2c_mspm0_target_register(const struct device *dev, struct i2c_target return -EBUSY; } + ret = pm_device_runtime_get(dev); + if (ret < 0) { + k_sem_give(&data->i2c_lock); + return ret; + } + data->target_config = cfg; data->target_callbacks = cfg->callbacks; @@ -968,6 +1040,9 @@ static int i2c_mspm0_target_unregister(const struct device *dev, struct i2c_targ i2c_disable_interrupt(base, TI_MSPM0_TARGET_INTERRUPTS); k_sem_give(&data->i2c_lock); + + pm_device_runtime_put(dev); + return 0; } @@ -1324,8 +1399,9 @@ static DEVICE_API(i2c, i2c_mspm0_driver_api) = { .divide_ratio = I2C_CLKDIV_RATIO_DIVIDE_BY_1, \ }}; \ static struct i2c_mspm0_data i2c_mspm0_data_##index; \ - I2C_DEVICE_DT_INST_DEFINE(index, i2c_mspm0_init, NULL, &i2c_mspm0_data_##index, \ - &i2c_mspm0_cfg_##index, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ - &i2c_mspm0_driver_api); + PM_DEVICE_DT_INST_DEFINE(index, i2c_mspm0_pm_action); \ + I2C_DEVICE_DT_INST_DEFINE(index, i2c_mspm0_init, PM_DEVICE_DT_INST_GET(index), \ + &i2c_mspm0_data_##index, &i2c_mspm0_cfg_##index, POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, &i2c_mspm0_driver_api); DT_INST_FOREACH_STATUS_OKAY(MSP_I2C_INIT_FN) From 79307f053696843e0ce4dcab602ea493628f8da8 Mon Sep 17 00:00:00 2001 From: Franklin Cooper Jr Date: Tue, 29 Sep 2026 10:37:16 -0500 Subject: [PATCH 3/4] UPSTREAM-PEND: dts: arm: ti: mspm0: Specify disabling power states for I2C PR: 122743 Add disabling power states for i2c peripheral. These low power modes will disrupt i2c operations. This information came from the datasheets table called "Operating Modes". Signed-off-by: Franklin Cooper Jr --- dts/arm/ti/mspm0/g/mspm0g.dtsi | 1 + dts/arm/ti/mspm0/g/mspm0gx51x.dtsi | 1 + dts/arm/ti/mspm0/l/mspm0l13x3.dtsi | 1 + dts/arm/ti/mspm0/l/mspm0l13x4.dtsi | 1 + dts/arm/ti/mspm0/l/mspm0l13x5.dtsi | 1 + dts/arm/ti/mspm0/l/mspm0l13x6.dtsi | 1 + dts/arm/ti/mspm0/l/mspm0lx22x.dtsi | 2 ++ dts/arm/ti/mspm0/mspm0.dtsi | 1 + 8 files changed, 9 insertions(+) diff --git a/dts/arm/ti/mspm0/g/mspm0g.dtsi b/dts/arm/ti/mspm0/g/mspm0g.dtsi index 1fcf7d388074..9440e2371ad2 100644 --- a/dts/arm/ti/mspm0/g/mspm0g.dtsi +++ b/dts/arm/ti/mspm0/g/mspm0g.dtsi @@ -264,6 +264,7 @@ i2c1: i2c@400f2000 { compatible = "ti,mspm0-i2c"; + zephyr,disabling-power-states = <&stdby1>; clocks = <&ckm MSPM0_CLOCK_ULPCLK>; clock-frequency = ; #address-cells = <1>; diff --git a/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi b/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi index 45062c5b0ebd..172b89b79b0d 100644 --- a/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi +++ b/dts/arm/ti/mspm0/g/mspm0gx51x.dtsi @@ -112,6 +112,7 @@ i2c2: i2c@400f4000 { compatible = "ti,mspm0-i2c"; + zephyr,disabling-power-states = <&stdby1>; clocks = <&ckm MSPM0_CLOCK_ULPCLK>; clock-frequency = ; #address-cells = <1>; diff --git a/dts/arm/ti/mspm0/l/mspm0l13x3.dtsi b/dts/arm/ti/mspm0/l/mspm0l13x3.dtsi index ded72635e109..c587519f0518 100644 --- a/dts/arm/ti/mspm0/l/mspm0l13x3.dtsi +++ b/dts/arm/ti/mspm0/l/mspm0l13x3.dtsi @@ -20,6 +20,7 @@ i2c1: i2c@400f2000 { compatible = "ti,mspm0-i2c"; + zephyr,disabling-power-states = <&stdby1>; clocks = <&ckm MSPM0_CLOCK_ULPCLK>; clock-frequency = ; #address-cells = <1>; diff --git a/dts/arm/ti/mspm0/l/mspm0l13x4.dtsi b/dts/arm/ti/mspm0/l/mspm0l13x4.dtsi index 2a2a230b85b8..310270a07bc5 100644 --- a/dts/arm/ti/mspm0/l/mspm0l13x4.dtsi +++ b/dts/arm/ti/mspm0/l/mspm0l13x4.dtsi @@ -20,6 +20,7 @@ i2c1: i2c@400f2000 { compatible = "ti,mspm0-i2c"; + zephyr,disabling-power-states = <&stdby1>; clocks = <&ckm MSPM0_CLOCK_ULPCLK>; clock-frequency = ; #address-cells = <1>; diff --git a/dts/arm/ti/mspm0/l/mspm0l13x5.dtsi b/dts/arm/ti/mspm0/l/mspm0l13x5.dtsi index 041c34bafd42..4c94734ef305 100644 --- a/dts/arm/ti/mspm0/l/mspm0l13x5.dtsi +++ b/dts/arm/ti/mspm0/l/mspm0l13x5.dtsi @@ -20,6 +20,7 @@ i2c1: i2c@400f2000 { compatible = "ti,mspm0-i2c"; + zephyr,disabling-power-states = <&stdby1>; clocks = <&ckm MSPM0_CLOCK_ULPCLK>; clock-frequency = ; #address-cells = <1>; diff --git a/dts/arm/ti/mspm0/l/mspm0l13x6.dtsi b/dts/arm/ti/mspm0/l/mspm0l13x6.dtsi index aaefdadea015..6a971300242f 100644 --- a/dts/arm/ti/mspm0/l/mspm0l13x6.dtsi +++ b/dts/arm/ti/mspm0/l/mspm0l13x6.dtsi @@ -20,6 +20,7 @@ i2c1: i2c@400f2000 { compatible = "ti,mspm0-i2c"; + zephyr,disabling-power-states = <&stdby1>; clocks = <&ckm MSPM0_CLOCK_ULPCLK>; clock-frequency = ; #address-cells = <1>; diff --git a/dts/arm/ti/mspm0/l/mspm0lx22x.dtsi b/dts/arm/ti/mspm0/l/mspm0lx22x.dtsi index 6d8588597c54..3353991716d3 100644 --- a/dts/arm/ti/mspm0/l/mspm0lx22x.dtsi +++ b/dts/arm/ti/mspm0/l/mspm0lx22x.dtsi @@ -146,6 +146,7 @@ i2c1: i2c@400f2000 { compatible = "ti,mspm0-i2c"; + zephyr,disabling-power-states = <&stdby1>; clocks = <&ckm MSPM0_CLOCK_ULPCLK>; clock-frequency = ; #address-cells = <1>; @@ -157,6 +158,7 @@ i2c2: i2c@400f4000 { compatible = "ti,mspm0-i2c"; + zephyr,disabling-power-states = <&stdby1>; clocks = <&ckm MSPM0_CLOCK_ULPCLK>; clock-frequency = ; #address-cells = <1>; diff --git a/dts/arm/ti/mspm0/mspm0.dtsi b/dts/arm/ti/mspm0/mspm0.dtsi index c6568d08b642..aa402380616b 100644 --- a/dts/arm/ti/mspm0/mspm0.dtsi +++ b/dts/arm/ti/mspm0/mspm0.dtsi @@ -277,6 +277,7 @@ i2c0: i2c@400f0000 { compatible = "ti,mspm0-i2c"; + zephyr,disabling-power-states = <&stdby1>; clocks = <&ckm MSPM0_CLOCK_ULPCLK>; clock-frequency = ; #address-cells = <1>; From c918b91d26adc35e4990a93afada1fcc570eed02 Mon Sep 17 00:00:00 2001 From: Franklin Cooper Jr Date: Tue, 29 Sep 2026 14:12:39 -0500 Subject: [PATCH 4/4] UPSTREAM-PEND: drivers: i2c_mspm0 - Add policy locks PR: 122743 Add policy locks to prevent system from entering a low power mode that would disrupt i2c operations. Signed-off-by: Franklin Cooper Jr --- drivers/i2c/i2c_mspm0.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/i2c/i2c_mspm0.c b/drivers/i2c/i2c_mspm0.c index a6ff19811355..e34cca154475 100644 --- a/drivers/i2c/i2c_mspm0.c +++ b/drivers/i2c/i2c_mspm0.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "i2c-priv.h" @@ -924,6 +925,7 @@ static int i2c_mspm0_transfer(const struct device *dev, struct i2c_msg *msgs, ui } k_sem_take(&data->i2c_lock, K_FOREVER); + pm_policy_device_power_lock_get(dev); data->msgs = msgs; data->num_msgs = num_msgs; @@ -958,6 +960,7 @@ static int i2c_mspm0_transfer(const struct device *dev, struct i2c_msg *msgs, ui i2c_mspm0_configure(dev, dev_config); } + pm_policy_device_power_lock_put(dev); k_sem_give(&data->i2c_lock); pm_device_runtime_put(dev); @@ -986,6 +989,8 @@ static int i2c_mspm0_target_register(const struct device *dev, struct i2c_target return ret; } + pm_policy_device_power_lock_get(dev); + data->target_config = cfg; data->target_callbacks = cfg->callbacks; @@ -1039,6 +1044,7 @@ static int i2c_mspm0_target_unregister(const struct device *dev, struct i2c_targ i2c_disable_target(base); i2c_disable_interrupt(base, TI_MSPM0_TARGET_INTERRUPTS); + pm_policy_device_power_lock_put(dev); k_sem_give(&data->i2c_lock); pm_device_runtime_put(dev);