Skip to content

Commit 7710082

Browse files
fougestephanosio
authored andcommitted
drivers: i2c: stm32: PM device support
Clock and pins used by the I2C device are suspended when power manager requires it. Do not compile function i2c_stm32_suspend when PM_DEVICE isn't enabled as it is left unused and will make the compiler throw a warning. Signed-off-by: Cyril Fougeray <[email protected]>
1 parent 51fa86b commit 7710082

File tree

1 file changed

+90
-13
lines changed

1 file changed

+90
-13
lines changed

drivers/i2c/i2c_ll_stm32.c

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
99
#include <zephyr/drivers/clock_control.h>
10+
#include <zephyr/pm/device.h>
1011
#include <zephyr/sys/util.h>
1112
#include <zephyr/kernel.h>
1213
#include <soc.h>
@@ -65,9 +66,13 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config)
6566
data->dev_config = config;
6667

6768
k_sem_take(&data->bus_mutex, K_FOREVER);
69+
pm_device_busy_set(dev);
70+
6871
LL_I2C_Disable(i2c);
6972
LL_I2C_SetMode(i2c, LL_I2C_MODE_I2C);
7073
ret = stm32_i2c_configure_timing(dev, clock);
74+
75+
pm_device_busy_clear(dev);
7176
k_sem_give(&data->bus_mutex);
7277

7378
return ret;
@@ -179,6 +184,9 @@ static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg,
179184
/* Send out messages */
180185
k_sem_take(&data->bus_mutex, K_FOREVER);
181186

187+
/* Prevent driver from being suspended by PM until I2C transaction is complete */
188+
pm_device_busy_set(dev);
189+
182190
current = msg;
183191

184192
while (num_msgs > 0) {
@@ -196,6 +204,8 @@ static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg,
196204
num_msgs--;
197205
}
198206

207+
pm_device_busy_clear(dev);
208+
199209
k_sem_give(&data->bus_mutex);
200210
return ret;
201211
}
@@ -209,6 +219,59 @@ static const struct i2c_driver_api api_funcs = {
209219
#endif
210220
};
211221

222+
#ifdef CONFIG_PM_DEVICE
223+
224+
static int i2c_stm32_suspend(const struct device *dev)
225+
{
226+
int ret;
227+
const struct i2c_stm32_config *cfg = dev->config;
228+
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
229+
230+
/* Disable device clock. */
231+
ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
232+
if (ret < 0) {
233+
LOG_ERR("failure disabling I2C clock");
234+
return ret;
235+
}
236+
237+
/* Move pins to sleep state */
238+
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_SLEEP);
239+
if (ret == -ENOENT) {
240+
/* Warn but don't block suspend */
241+
LOG_WRN("I2C pinctrl sleep state not available ");
242+
} else if (ret < 0) {
243+
return ret;
244+
}
245+
246+
return 0;
247+
}
248+
249+
#endif
250+
251+
static int i2c_stm32_activate(const struct device *dev)
252+
{
253+
int ret;
254+
const struct i2c_stm32_config *cfg = dev->config;
255+
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
256+
257+
/* Move pins to active/default state */
258+
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
259+
if (ret < 0) {
260+
LOG_ERR("I2C pinctrl setup failed (%d)", ret);
261+
return ret;
262+
}
263+
264+
/* Enable device clock. */
265+
if (clock_control_on(clk,
266+
(clock_control_subsys_t *) &cfg->pclken[0]) != 0) {
267+
LOG_ERR("i2c: failure enabling clock");
268+
return -EIO;
269+
}
270+
271+
return 0;
272+
}
273+
274+
212275
static int i2c_stm32_init(const struct device *dev)
213276
{
214277
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
@@ -221,13 +284,6 @@ static int i2c_stm32_init(const struct device *dev)
221284
cfg->irq_config_func(dev);
222285
#endif
223286

224-
/* Configure dt provided device signals when available */
225-
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
226-
if (ret < 0) {
227-
LOG_ERR("I2C pinctrl setup failed (%d)", ret);
228-
return ret;
229-
}
230-
231287
/*
232288
* initialize mutex used when multiple transfers
233289
* are taking place to guarantee that each one is
@@ -240,11 +296,7 @@ static int i2c_stm32_init(const struct device *dev)
240296
return -ENODEV;
241297
}
242298

243-
if (clock_control_on(clk,
244-
(clock_control_subsys_t *) &cfg->pclken[0]) != 0) {
245-
LOG_ERR("i2c: failure enabling clock");
246-
return -EIO;
247-
}
299+
i2c_stm32_activate(dev);
248300

249301
if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
250302
/* Enable I2C clock source */
@@ -279,6 +331,28 @@ static int i2c_stm32_init(const struct device *dev)
279331
return 0;
280332
}
281333

334+
#ifdef CONFIG_PM_DEVICE
335+
336+
static int i2c_stm32_pm_action(const struct device *dev, enum pm_device_action action)
337+
{
338+
int err;
339+
340+
switch (action) {
341+
case PM_DEVICE_ACTION_RESUME:
342+
err = i2c_stm32_activate(dev);
343+
break;
344+
case PM_DEVICE_ACTION_SUSPEND:
345+
err = i2c_stm32_suspend(dev);
346+
break;
347+
default:
348+
return -ENOTSUP;
349+
}
350+
351+
return err;
352+
}
353+
354+
#endif
355+
282356
/* Macros for I2C instance declaration */
283357

284358
#ifdef CONFIG_I2C_STM32_INTERRUPT
@@ -360,8 +434,11 @@ static const struct i2c_stm32_config i2c_stm32_cfg_##index = { \
360434
\
361435
static struct i2c_stm32_data i2c_stm32_dev_data_##index; \
362436
\
437+
PM_DEVICE_DT_INST_DEFINE(index, i2c_stm32_pm_action); \
438+
\
363439
I2C_DEVICE_DT_INST_DEFINE(index, i2c_stm32_init, \
364-
NULL, &i2c_stm32_dev_data_##index, \
440+
PM_DEVICE_DT_INST_GET(index), \
441+
&i2c_stm32_dev_data_##index, \
365442
&i2c_stm32_cfg_##index, \
366443
POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \
367444
&api_funcs); \

0 commit comments

Comments
 (0)