Skip to content

Commit 13de6e3

Browse files
erwangonashif
authored andcommitted
drivers/gpio: stm32: Enable PM_DEVICE services
Implement power mgmt hooks to support PM_DEVICE and PM_DEVICE_RUNTIME. In case of PM_DEVICE_RUNTIME, clock is requested for bank writes so it is requested before configuring and released only if pin is not configured as output. Signed-off-by: Erwan Gouriou <[email protected]>
1 parent c730603 commit 13de6e3

File tree

2 files changed

+112
-2
lines changed

2 files changed

+112
-2
lines changed

drivers/gpio/gpio_stm32.c

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <drivers/pinmux.h>
2323
#include <sys/util.h>
2424
#include <drivers/interrupt_controller/exti_stm32.h>
25+
#include <pm/device.h>
26+
#include <pm/device_runtime.h>
2527

2628
#include "stm32_hsem.h"
2729
#include "gpio_stm32.h"
@@ -238,7 +240,6 @@ int gpio_stm32_clock_request(const struct device *dev, bool on)
238240
if (on) {
239241
ret = clock_control_on(clk,
240242
(clock_control_subsys_t *)&cfg->pclken);
241-
242243
} else {
243244
ret = clock_control_off(clk,
244245
(clock_control_subsys_t *)&cfg->pclken);
@@ -463,6 +464,9 @@ static int gpio_stm32_port_toggle_bits(const struct device *dev,
463464
static int gpio_stm32_config(const struct device *dev,
464465
gpio_pin_t pin, gpio_flags_t flags)
465466
{
467+
#ifdef CONFIG_PM_DEVICE_RUNTIME
468+
struct gpio_stm32_data *data = dev->data;
469+
#endif /* CONFIG_PM_DEVICE_RUNTIME */
466470
int err = 0;
467471
int pincfg;
468472

@@ -474,6 +478,16 @@ static int gpio_stm32_config(const struct device *dev,
474478
goto exit;
475479
}
476480

481+
#ifdef CONFIG_PM_DEVICE_RUNTIME
482+
/* Enable device clock before configuration (requires bank writes) */
483+
if (data->power_state != PM_DEVICE_ACTIVE_STATE) {
484+
err = pm_device_get_sync(dev);
485+
if (err < 0) {
486+
return err;
487+
}
488+
}
489+
#endif /* CONFIG_PM_DEVICE_RUNTIME */
490+
477491
if ((flags & GPIO_OUTPUT) != 0) {
478492
if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
479493
gpio_stm32_port_set_bits_raw(dev, BIT(pin));
@@ -484,6 +498,17 @@ static int gpio_stm32_config(const struct device *dev,
484498

485499
gpio_stm32_configure(dev, pin, pincfg, 0);
486500

501+
/* Device released */
502+
#ifdef CONFIG_PM_DEVICE_RUNTIME
503+
/* Release clock only if configuration doesn't require bank writes */
504+
if ((flags & GPIO_OUTPUT) == 0) {
505+
err = pm_device_put(dev);
506+
if (err < 0) {
507+
return err;
508+
}
509+
}
510+
#endif /* CONFIG_PM_DEVICE_RUNTIME */
511+
487512
exit:
488513
return err;
489514
}
@@ -561,6 +586,69 @@ static const struct gpio_driver_api gpio_stm32_driver = {
561586
.manage_callback = gpio_stm32_manage_callback,
562587
};
563588

589+
#ifdef CONFIG_PM_DEVICE
590+
static uint32_t gpio_stm32_get_power_state(const struct device *dev)
591+
{
592+
struct gpio_stm32_data *data = dev->data;
593+
594+
return data->power_state;
595+
}
596+
597+
static int gpio_stm32_set_power_state(const struct device *dev,
598+
uint32_t new_state)
599+
{
600+
struct gpio_stm32_data *data = dev->data;
601+
int ret = 0;
602+
603+
if (new_state == PM_DEVICE_ACTIVE_STATE) {
604+
ret = gpio_stm32_clock_request(dev, true);
605+
} else if (new_state == PM_DEVICE_SUSPEND_STATE) {
606+
ret = gpio_stm32_clock_request(dev, false);
607+
} else if (new_state == PM_DEVICE_LOW_POWER_STATE) {
608+
ret = gpio_stm32_clock_request(dev, false);
609+
}
610+
611+
if (ret < 0) {
612+
return ret;
613+
}
614+
615+
data->power_state = new_state;
616+
617+
return 0;
618+
}
619+
620+
static int gpio_stm32_pm_device_ctrl(const struct device *dev,
621+
uint32_t ctrl_command,
622+
void *context, pm_device_cb cb, void *arg)
623+
{
624+
struct gpio_stm32_data *data = dev->data;
625+
uint32_t new_state;
626+
int ret = 0;
627+
628+
switch (ctrl_command) {
629+
case PM_DEVICE_STATE_SET:
630+
new_state = *((const uint32_t *)context);
631+
if (new_state != data->power_state) {
632+
ret = gpio_stm32_set_power_state(dev, new_state);
633+
}
634+
break;
635+
case PM_DEVICE_STATE_GET:
636+
*((uint32_t *)context) = gpio_stm32_get_power_state(dev);
637+
break;
638+
default:
639+
ret = -EINVAL;
640+
641+
}
642+
643+
if (cb) {
644+
cb(dev, ret, context, arg);
645+
}
646+
647+
return ret;
648+
}
649+
#endif /* CONFIG_PM_DEVICE */
650+
651+
564652
/**
565653
* @brief Initialize GPIO port
566654
*
@@ -577,7 +665,25 @@ static int gpio_stm32_init(const struct device *dev)
577665

578666
data->dev = dev;
579667

668+
#if defined(PWR_CR2_IOSV) && DT_NODE_HAS_STATUS(DT_NODELABEL(gpiog), okay)
669+
z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY);
670+
/* Port G[15:2] requires external power supply */
671+
/* Cf: L4/L5 RM, Chapter "Independent I/O supply rail" */
672+
LL_PWR_EnableVddIO2();
673+
z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
674+
#endif
675+
676+
#ifdef CONFIG_PM_DEVICE_RUNTIME
677+
data->power_state = PM_DEVICE_OFF_STATE;
678+
pm_device_enable(dev);
679+
680+
return 0;
681+
#else
682+
#ifdef CONFIG_PM_DEVICE
683+
data->power_state = PM_DEVICE_ACTIVE_STATE;
684+
#endif
580685
return gpio_stm32_clock_request(dev, true);
686+
#endif
581687
}
582688

583689
#define GPIO_DEVICE_INIT(__node, __suffix, __base_addr, __port, __cenr, __bus) \
@@ -592,7 +698,7 @@ static int gpio_stm32_init(const struct device *dev)
592698
static struct gpio_stm32_data gpio_stm32_data_## __suffix; \
593699
DEVICE_DT_DEFINE(__node, \
594700
gpio_stm32_init, \
595-
NULL, \
701+
gpio_stm32_pm_device_ctrl, \
596702
&gpio_stm32_data_## __suffix, \
597703
&gpio_stm32_cfg_## __suffix, \
598704
POST_KERNEL, \

drivers/gpio/gpio_stm32.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ struct gpio_stm32_data {
229229
const struct device *dev;
230230
/* user ISR cb */
231231
sys_slist_t cb;
232+
#ifdef CONFIG_PM_DEVICE
233+
/* device power state */
234+
uint32_t power_state;
235+
#endif
232236
};
233237

234238
/**

0 commit comments

Comments
 (0)