Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Renesas SmartBond(tm) power management #61857

Merged
merged 7 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/gpio/Kconfig.smartbond
Original file line number Diff line number Diff line change
Expand Up @@ -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.
111 changes: 104 additions & 7 deletions drivers/gpio/gpio_smartbond.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 {
Expand All @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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), \
Expand All @@ -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), \
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions drivers/regulator/Kconfig.da1469x
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
config REGULATOR_DA1469X
bool "DA1469X regulators driver"
default y
select PM_DEVICE if PM
depends on DT_HAS_RENESAS_SMARTBOND_REGULATOR_ENABLED
help
Enable support for the Smartbond DA1469x regulators.
Expand Down
59 changes: 57 additions & 2 deletions drivers/regulator/regulator_da1469x.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <zephyr/drivers/regulator.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/linear_range.h>
#include <zephyr/pm/pm.h>
#include <zephyr/pm/device.h>
#include <DA1469xAB.h>

LOG_MODULE_REGISTER(regulator_da1469x, CONFIG_REGULATOR_LOG_LEVEL);
Expand Down Expand Up @@ -77,6 +79,16 @@ enum da1469x_rail {
V30,
};

struct dcdc_regs {
uint32_t v18;
uint32_t v18p;
uint32_t vdd;
uint32_t v14;
uint32_t ctrl1;
};

static struct dcdc_regs dcdc_state;

struct regulator_da1469x_desc {
const struct linear_range *voltage_ranges;
const struct linear_range *current_ranges;
Expand All @@ -85,6 +97,7 @@ struct regulator_da1469x_desc {
uint32_t enable_mask;
uint32_t voltage_idx_mask;
volatile uint32_t *dcdc_register;
uint32_t *dcdc_register_shadow;
};

static const struct regulator_da1469x_desc vdd_desc = {
Expand All @@ -94,6 +107,7 @@ static const struct regulator_da1469x_desc vdd_desc = {
.enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_CORE_ENABLE_Msk,
.voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_LEVEL_Msk,
.dcdc_register = &DCDC->DCDC_VDD_REG,
.dcdc_register_shadow = &dcdc_state.vdd,
};

static const struct regulator_da1469x_desc vdd_sleep_desc = {
Expand All @@ -117,6 +131,7 @@ static const struct regulator_da1469x_desc v14_desc = {
.enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk,
.voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V14_LEVEL_Msk,
.dcdc_register = &DCDC->DCDC_V14_REG,
.dcdc_register_shadow = &dcdc_state.v14,
};

static const struct regulator_da1469x_desc v18_desc = {
Expand All @@ -127,6 +142,7 @@ static const struct regulator_da1469x_desc v18_desc = {
CRG_TOP_POWER_CTRL_REG_LDO_1V8_RET_ENABLE_SLEEP_Msk,
.voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V18_LEVEL_Msk,
.dcdc_register = &DCDC->DCDC_V18_REG,
.dcdc_register_shadow = &dcdc_state.v18,
};

static const struct regulator_da1469x_desc v18p_desc = {
Expand All @@ -137,6 +153,7 @@ static const struct regulator_da1469x_desc v18p_desc = {
CRG_TOP_POWER_CTRL_REG_LDO_1V8P_RET_ENABLE_SLEEP_Msk,
.voltage_idx_mask = 0,
.dcdc_register = &DCDC->DCDC_V18P_REG,
.dcdc_register_shadow = &dcdc_state.v18p,
};

static const struct regulator_da1469x_desc v30_desc = {
Expand Down Expand Up @@ -183,6 +200,7 @@ static int regulator_da1469x_enable(const struct device *dev)
~(DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_HV_Msk |
DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_LV_Msk);
reg_val |= config->dcdc_bits;
*config->desc->dcdc_register_shadow = reg_val;
*config->desc->dcdc_register = reg_val;
}

Expand All @@ -196,6 +214,7 @@ static int regulator_da1469x_enable(const struct device *dev)
(CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_COMP_VBAT_HIGH_Msk) &&
config->dcdc_bits & DCDC_REQUESTED) {
DCDC->DCDC_CTRL1_REG |= DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk;
dcdc_state.ctrl1 = DCDC->DCDC_CTRL1_REG;
}

return 0;
Expand All @@ -214,6 +233,7 @@ static int regulator_da1469x_disable(const struct device *dev)
reg_val = *config->desc->dcdc_register &
~(DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_HV_Msk |
DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_LV_Msk);
*config->desc->dcdc_register_shadow = reg_val;
*config->desc->dcdc_register = reg_val;
}

Expand All @@ -224,6 +244,7 @@ static int regulator_da1469x_disable(const struct device *dev)
(DCDC->DCDC_V18_REG & DCDC_REQUESTED) == 0 &&
(DCDC->DCDC_V18P_REG & DCDC_REQUESTED) == 0) {
DCDC->DCDC_CTRL1_REG &= ~DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk;
dcdc_state.ctrl1 = DCDC->DCDC_CTRL1_REG;
}

return 0;
Expand Down Expand Up @@ -321,7 +342,7 @@ static int regulator_da1469x_set_current_limit(const struct device *dev,
reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk, idx);
reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_LV_Msk, idx);
reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MIN_Msk, idx);

*config->desc->dcdc_register_shadow = reg_val;
*config->desc->dcdc_register = reg_val;

return ret;
Expand Down Expand Up @@ -369,6 +390,37 @@ static int regulator_da1469x_init(const struct device *dev)
return regulator_common_init(dev, 0);
}

#if IS_ENABLED(CONFIG_PM_DEVICE)
static int regulator_da1469x_pm_action(const struct device *dev,
enum pm_device_action action)
{
const struct regulator_da1469x_config *config = dev->config;
int ret = 0;

switch (action) {
case PM_DEVICE_ACTION_RESUME:
if (config->desc->dcdc_register) {
*config->desc->dcdc_register = *config->desc->dcdc_register_shadow;
if ((CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_COMP_VBAT_HIGH_Msk) &&
(*config->desc->dcdc_register_shadow & DCDC_REQUESTED)) {
DCDC->DCDC_CTRL1_REG = dcdc_state.ctrl1;
}
}
break;
case PM_DEVICE_ACTION_SUSPEND:
/*
* Shadow register is saved on each regulator API call, there is no need
* to save it here.
*/
break;
default:
ret = -ENOTSUP;
}

return ret;
}
#endif
Comment on lines +393 to +422
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you really need this if notifier bit is in place?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this removed?


#define REGULATOR_DA1469X_DEFINE(node, id, rail_id) \
static struct regulator_da1469x_data data_##id; \
\
Expand All @@ -392,7 +444,10 @@ static int regulator_da1469x_init(const struct device *dev)
(DT_PROP(node, renesas_regulator_dcdc_vbat_low) * \
DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_LV_Msk) \
}; \
DEVICE_DT_DEFINE(node, regulator_da1469x_init, NULL, &data_##id, \
PM_DEVICE_DT_DEFINE(node, regulator_da1469x_pm_action); \
DEVICE_DT_DEFINE(node, regulator_da1469x_init, \
PM_DEVICE_DT_GET(node), \
&data_##id, \
&config_##id, PRE_KERNEL_1, \
CONFIG_REGULATOR_DA1469X_INIT_PRIORITY, \
&regulator_da1469x_api);
Expand Down
1 change: 1 addition & 0 deletions drivers/timer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ zephyr_library_sources_ifdef(CONFIG_SAM0_RTC_TIMER sam0_rtc_timer.c)
zephyr_library_sources_ifdef(CONFIG_STM32_LPTIM_TIMER stm32_lptim_timer.c)
zephyr_library_sources_ifdef(CONFIG_XLNX_PSTTC_TIMER xlnx_psttc_timer.c)
zephyr_library_sources_ifdef(CONFIG_XTENSA_TIMER xtensa_sys_timer.c)
zephyr_library_sources_ifdef(CONFIG_SMARTBOND_TIMER smartbond_timer.c)
1 change: 1 addition & 0 deletions drivers/timer/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ source "drivers/timer/Kconfig.rcar_cmt"
source "drivers/timer/Kconfig.riscv_machine"
source "drivers/timer/Kconfig.rv32m1_lptmr"
source "drivers/timer/Kconfig.sam0_rtc"
source "drivers/timer/Kconfig.smartbond"
source "drivers/timer/Kconfig.stm32_lptim"
source "drivers/timer/Kconfig.xlnx_psttc"
source "drivers/timer/Kconfig.xtensa"
Expand Down
13 changes: 13 additions & 0 deletions drivers/timer/Kconfig.smartbond
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2023 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0

config SMARTBOND_TIMER
bool "Renesas SmartBond(tm) timer"
default y
depends on SOC_FAMILY_RENESAS_SMARTBOND
depends on CLOCK_CONTROL
depends on !$(dt_nodelabel_enabled,timer2)
select TICKLESS_CAPABLE
help
This module implements a kernel device driver for the TIMER2 timer
and provides the standard "system clock driver" interfaces.
Loading
Loading