drivers: gpio: smartbond: Add GPIO latching for PM

This adds automatic GPIO latching before going to extended sleep and
restoring state after wakeup.

Mode and state for each pin is stored, then ports are latched to retain
state when PD_COM is disabled during sleep. On wakeup mode and state for
each pin is restored and ports are unlatched to make it work again.

Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
Signed-off-by: Jerzy Kasenberg <jerzy.kasenberg@codecoup.pl>
This commit is contained in:
Andrzej Kaczmarek 2023-06-14 14:06:15 +02:00 committed by Carles Cufí
parent 80c5f72fe2
commit 422092f2d3
3 changed files with 105 additions and 8 deletions

View file

@ -5,5 +5,6 @@ config GPIO_SMARTBOND
bool "Renesas SmartBond(tm) GPIO driver" bool "Renesas SmartBond(tm) GPIO driver"
default y default y
depends on DT_HAS_RENESAS_SMARTBOND_GPIO_ENABLED depends on DT_HAS_RENESAS_SMARTBOND_GPIO_ENABLED
select PM_DEVICE if PM
help help
Enable GPIO driver for Renesas SmartBond(tm) MCU family. Enable GPIO driver for Renesas SmartBond(tm) MCU family.

View file

@ -11,9 +11,11 @@
#include <stdint.h> #include <stdint.h>
#include <zephyr/drivers/gpio.h> #include <zephyr/drivers/gpio.h>
#include <zephyr/irq.h> #include <zephyr/irq.h>
#include <zephyr/pm/device.h>
#include <DA1469xAB.h> #include <DA1469xAB.h>
#include <da1469x_pdc.h> #include <da1469x_pdc.h>
#include <da1469x_pd.h>
#define GPIO_MODE_RESET 0x200 #define GPIO_MODE_RESET 0x200
@ -60,6 +62,14 @@ struct gpio_smartbond_data {
/* Pins that are configured for both edges (handled by software) */ /* Pins that are configured for both edges (handled by software) */
gpio_port_pins_t both_edges_pins; gpio_port_pins_t both_edges_pins;
sys_slist_t callbacks; sys_slist_t callbacks;
#if CONFIG_PM_DEVICE
/*
* Saved state consist of:
* 1 word for GPIO output port state
* GPIOx_NGPIOS words for each pin mode
*/
uint32_t *gpio_saved_state;
#endif
}; };
struct gpio_smartbond_config { struct gpio_smartbond_config {
@ -71,6 +81,9 @@ struct gpio_smartbond_config {
volatile struct gpio_smartbond_wkup_regs *wkup_regs; volatile struct gpio_smartbond_wkup_regs *wkup_regs;
/* Value of TRIG_SELECT for PDC_CTRLx_REG entry */ /* Value of TRIG_SELECT for PDC_CTRLx_REG entry */
uint8_t wkup_trig_select; uint8_t wkup_trig_select;
#if CONFIG_PM_DEVICE
uint8_t ngpios;
#endif
}; };
static void gpio_smartbond_wkup_init(void) static void gpio_smartbond_wkup_init(void)
@ -292,6 +305,78 @@ static void gpio_smartbond_isr(const struct device *dev)
gpio_fire_callbacks(&data->callbacks, dev, stat); gpio_fire_callbacks(&data->callbacks, dev, stat);
} }
#ifdef CONFIG_PM_DEVICE
static void gpio_latch_inst(mem_addr_t data_reg, mem_addr_t mode_reg, mem_addr_t latch_reg,
uint8_t ngpios, uint32_t *data, uint32_t *mode)
{
uint8_t idx;
*data = sys_read32(data_reg);
for (idx = 0; idx < ngpios; idx++, mode_reg += 4) {
mode[idx] = sys_read32(mode_reg);
}
sys_write32(BIT_MASK(ngpios), latch_reg);
}
static void gpio_unlatch_inst(mem_addr_t data_reg, mem_addr_t mode_reg, mem_addr_t latch_reg,
uint8_t ngpios, uint32_t data, uint32_t *mode)
{
uint8_t idx;
sys_write32(data, data_reg);
for (idx = 0; idx < ngpios; idx++, mode_reg += 4) {
sys_write32(mode[idx], mode_reg);
}
sys_write32(BIT_MASK(ngpios), latch_reg);
}
static void gpio_latch(const struct device *dev)
{
const struct gpio_smartbond_config *config = dev->config;
const struct gpio_smartbond_data *data = dev->data;
gpio_latch_inst((mem_addr_t)&config->data_regs->data,
(mem_addr_t)config->mode_regs,
(mem_addr_t)&config->latch_regs->reset,
config->ngpios, data->gpio_saved_state, data->gpio_saved_state + 1);
}
static void gpio_unlatch(const struct device *dev)
{
const struct gpio_smartbond_config *config = dev->config;
const struct gpio_smartbond_data *data = dev->data;
gpio_unlatch_inst((mem_addr_t)&config->data_regs->data,
(mem_addr_t)config->mode_regs,
(mem_addr_t)&config->latch_regs->set,
config->ngpios, data->gpio_saved_state[0], data->gpio_saved_state + 1);
}
static int gpio_smartbond_pm_action(const struct device *dev,
enum pm_device_action action)
{
int ret = 0;
switch (action) {
case PM_DEVICE_ACTION_RESUME:
da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
gpio_unlatch(dev);
break;
case PM_DEVICE_ACTION_SUSPEND:
gpio_latch(dev);
da1469x_pd_release(MCU_PD_DOMAIN_COM);
break;
default:
ret = -ENOTSUP;
}
return ret;
}
#endif /* CONFIG_PM_DEVICE */
/* GPIO driver registration */ /* GPIO driver registration */
static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = { static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = {
.pin_configure = gpio_smartbond_pin_configure, .pin_configure = gpio_smartbond_pin_configure,
@ -304,8 +389,15 @@ static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = {
.manage_callback = gpio_smartbond_manage_callback, .manage_callback = gpio_smartbond_manage_callback,
}; };
#define GPIO_SAVED_STATE(id) gpio_smartbond_saved_state_##id
#define GPIO_PM_DEVICE_CFG(fld, val) \
COND_CODE_1(CONFIG_PM_DEVICE, (fld = val,), ())
#define GPIO_PM_DEVICE_STATE(id, ngpios) \
COND_CODE_1(CONFIG_PM_DEVICE, (static uint32_t GPIO_SAVED_STATE(id)[1 + ngpios];), ())
#define GPIO_SMARTBOND_DEVICE(id) \ #define GPIO_SMARTBOND_DEVICE(id) \
static const struct gpio_smartbond_config gpio_smartbond_p##id##_config = { \ GPIO_PM_DEVICE_STATE(id, DT_INST_PROP(id, ngpios)) \
static const struct gpio_smartbond_config gpio_smartbond_config_##id = { \
.common = { \ .common = { \
.port_pin_mask = \ .port_pin_mask = \
GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \ GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
@ -318,12 +410,16 @@ static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = {
.wkup_regs = (volatile struct gpio_smartbond_wkup_regs *) \ .wkup_regs = (volatile struct gpio_smartbond_wkup_regs *) \
DT_INST_REG_ADDR_BY_NAME(id, wkup), \ DT_INST_REG_ADDR_BY_NAME(id, wkup), \
.wkup_trig_select = id, \ .wkup_trig_select = id, \
GPIO_PM_DEVICE_CFG(.ngpios, DT_INST_PROP(id, ngpios)) \
}; \ }; \
\ \
static struct gpio_smartbond_data gpio_smartbond_p##id##_data; \ static struct gpio_smartbond_data gpio_smartbond_data_##id = { \
GPIO_PM_DEVICE_CFG(.gpio_saved_state, GPIO_SAVED_STATE(id)) \
}; \
\ \
static int gpio_smartbond_##id##_init(const struct device *dev) \ static int gpio_smartbond_init_##id(const struct device *dev) \
{ \ { \
da1469x_pd_acquire(MCU_PD_DOMAIN_COM); \
gpio_smartbond_wkup_init(); \ gpio_smartbond_wkup_init(); \
IRQ_CONNECT(DT_INST_IRQN(id), \ IRQ_CONNECT(DT_INST_IRQN(id), \
DT_INST_IRQ(id, priority), \ DT_INST_IRQ(id, priority), \
@ -333,10 +429,11 @@ static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = {
return 0; \ return 0; \
} \ } \
\ \
DEVICE_DT_INST_DEFINE(id, gpio_smartbond_##id##_init, \ PM_DEVICE_DEFINE(id, gpio_smartbond_pm_action); \
NULL, \ DEVICE_DT_INST_DEFINE(id, gpio_smartbond_init_##id, \
&gpio_smartbond_p##id##_data, \ PM_DEVICE_GET(id), \
&gpio_smartbond_p##id##_config, \ &gpio_smartbond_data_##id, \
&gpio_smartbond_config_##id, \
PRE_KERNEL_1, \ PRE_KERNEL_1, \
CONFIG_GPIO_INIT_PRIORITY, \ CONFIG_GPIO_INIT_PRIORITY, \
&gpio_smartbond_drv_api_funcs); &gpio_smartbond_drv_api_funcs);

View file

@ -175,7 +175,6 @@ static int renesas_da1469x_init(void)
da1469x_pd_init(); da1469x_pd_init();
da1469x_pd_acquire(MCU_PD_DOMAIN_SYS); da1469x_pd_acquire(MCU_PD_DOMAIN_SYS);
da1469x_pd_acquire(MCU_PD_DOMAIN_TIM); da1469x_pd_acquire(MCU_PD_DOMAIN_TIM);
da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
return 0; return 0;
} }