diff --git a/drivers/i2c/i2c_mspm0.c b/drivers/i2c/i2c_mspm0.c index 7a221f4e90ad..e34cca154475 100644 --- a/drivers/i2c/i2c_mspm0.c +++ b/drivers/i2c/i2c_mspm0.c @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include #include "i2c-priv.h" @@ -406,6 +409,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 +694,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 +770,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 +817,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,7 +919,13 @@ 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); + pm_policy_device_power_lock_get(dev); data->msgs = msgs; data->num_msgs = num_msgs; @@ -895,7 +960,10 @@ 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); return ret; } @@ -905,13 +973,23 @@ 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); /* 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); + ret = pm_device_runtime_get(dev); + if (ret < 0) { + k_sem_give(&data->i2c_lock); + return ret; + } + + pm_policy_device_power_lock_get(dev); data->target_config = cfg; data->target_callbacks = cfg->callbacks; @@ -953,19 +1031,24 @@ 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; 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); + return 0; } @@ -1322,8 +1405,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) 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>;