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:
parent
80c5f72fe2
commit
422092f2d3
|
@ -5,5 +5,6 @@ config GPIO_SMARTBOND
|
|||
bool "Renesas SmartBond(tm) GPIO driver"
|
||||
default y
|
||||
depends on DT_HAS_RENESAS_SMARTBOND_GPIO_ENABLED
|
||||
select PM_DEVICE if PM
|
||||
help
|
||||
Enable GPIO driver for Renesas SmartBond(tm) MCU family.
|
||||
|
|
|
@ -11,9 +11,11 @@
|
|||
#include <stdint.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/irq.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
|
||||
#include <DA1469xAB.h>
|
||||
#include <da1469x_pdc.h>
|
||||
#include <da1469x_pd.h>
|
||||
|
||||
#define GPIO_MODE_RESET 0x200
|
||||
|
||||
|
@ -60,6 +62,14 @@ struct gpio_smartbond_data {
|
|||
/* Pins that are configured for both edges (handled by software) */
|
||||
gpio_port_pins_t both_edges_pins;
|
||||
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 {
|
||||
|
@ -71,6 +81,9 @@ struct gpio_smartbond_config {
|
|||
volatile struct gpio_smartbond_wkup_regs *wkup_regs;
|
||||
/* Value of TRIG_SELECT for PDC_CTRLx_REG entry */
|
||||
uint8_t wkup_trig_select;
|
||||
#if CONFIG_PM_DEVICE
|
||||
uint8_t ngpios;
|
||||
#endif
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#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 */
|
||||
static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = {
|
||||
.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,
|
||||
};
|
||||
|
||||
#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) \
|
||||
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 = { \
|
||||
.port_pin_mask = \
|
||||
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 *) \
|
||||
DT_INST_REG_ADDR_BY_NAME(id, wkup), \
|
||||
.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(); \
|
||||
IRQ_CONNECT(DT_INST_IRQN(id), \
|
||||
DT_INST_IRQ(id, priority), \
|
||||
|
@ -333,10 +429,11 @@ static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = {
|
|||
return 0; \
|
||||
} \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(id, gpio_smartbond_##id##_init, \
|
||||
NULL, \
|
||||
&gpio_smartbond_p##id##_data, \
|
||||
&gpio_smartbond_p##id##_config, \
|
||||
PM_DEVICE_DEFINE(id, gpio_smartbond_pm_action); \
|
||||
DEVICE_DT_INST_DEFINE(id, gpio_smartbond_init_##id, \
|
||||
PM_DEVICE_GET(id), \
|
||||
&gpio_smartbond_data_##id, \
|
||||
&gpio_smartbond_config_##id, \
|
||||
PRE_KERNEL_1, \
|
||||
CONFIG_GPIO_INIT_PRIORITY, \
|
||||
&gpio_smartbond_drv_api_funcs);
|
||||
|
|
|
@ -175,7 +175,6 @@ static int renesas_da1469x_init(void)
|
|||
da1469x_pd_init();
|
||||
da1469x_pd_acquire(MCU_PD_DOMAIN_SYS);
|
||||
da1469x_pd_acquire(MCU_PD_DOMAIN_TIM);
|
||||
da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue