drivers: spi: Add power management Smartbond SPI
Code adds pm action function that stores SPI configuration before PD_COM is allowed to be turned off. PM_DEVICE_RUNTIME scheme is also supported Signed-off-by: Jerzy Kasenberg <jerzy.kasenberg@codecoup.pl>
This commit is contained in:
parent
2f272b2d79
commit
71ed2e4b02
5 changed files with 151 additions and 7 deletions
|
@ -52,6 +52,14 @@
|
|||
};
|
||||
};
|
||||
|
||||
/omit-if-no-ref/ spi_sleep: spi_sleep {
|
||||
group1 {
|
||||
pinmux = <SMARTBOND_PINMUX(GPIO, 0, 21)>,
|
||||
<SMARTBOND_PINMUX(GPIO, 0, 24)>,
|
||||
<SMARTBOND_PINMUX(GPIO, 0, 26)>;
|
||||
};
|
||||
};
|
||||
|
||||
spi_controller: spi_controller {
|
||||
group1 {
|
||||
pinmux = < SMARTBOND_PINMUX(SPI_CLK, 0, 21) >,
|
||||
|
@ -64,6 +72,14 @@
|
|||
};
|
||||
};
|
||||
|
||||
/omit-if-no-ref/ spi2_sleep: spi2_sleep {
|
||||
group1 {
|
||||
pinmux = <SMARTBOND_PINMUX(GPIO, 1, 3)>,
|
||||
<SMARTBOND_PINMUX(GPIO, 1, 4)>,
|
||||
<SMARTBOND_PINMUX(GPIO, 1, 5)>;
|
||||
};
|
||||
};
|
||||
|
||||
spi2_controller: spi2_controller {
|
||||
group1 {
|
||||
pinmux = < SMARTBOND_PINMUX(SPI2_CLK, 1, 3) >,
|
||||
|
|
|
@ -201,13 +201,15 @@ zephyr_udc0: &usbd {
|
|||
&spi {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&spi_controller>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-1 = <&spi_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
||||
|
||||
&spi2 {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&spi2_controller>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-1 = <&spi2_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
||||
|
||||
mikrobus_1_i2c: &i2c {};
|
||||
|
|
|
@ -79,6 +79,14 @@
|
|||
};
|
||||
};
|
||||
|
||||
/omit-if-no-ref/ spi_sleep: spi_sleep {
|
||||
group1 {
|
||||
pinmux = <SMARTBOND_PINMUX(GPIO, 0, 21)>,
|
||||
<SMARTBOND_PINMUX(GPIO, 0, 24)>,
|
||||
<SMARTBOND_PINMUX(GPIO, 0, 26)>;
|
||||
};
|
||||
};
|
||||
|
||||
spi_controller: spi_controller {
|
||||
group1 {
|
||||
pinmux = <SMARTBOND_PINMUX(SPI_CLK, 0, 21)>,
|
||||
|
@ -91,6 +99,14 @@
|
|||
};
|
||||
};
|
||||
|
||||
/omit-if-no-ref/ spi2_sleep: spi2_sleep {
|
||||
group1 {
|
||||
pinmux = <SMARTBOND_PINMUX(GPIO, 1, 3)>,
|
||||
<SMARTBOND_PINMUX(GPIO, 1, 4)>,
|
||||
<SMARTBOND_PINMUX(GPIO, 1, 5)>;
|
||||
};
|
||||
};
|
||||
|
||||
spi2_controller: spi2_controller {
|
||||
group1 {
|
||||
pinmux = < SMARTBOND_PINMUX(SPI2_CLK, 1, 3) >,
|
||||
|
|
|
@ -167,11 +167,13 @@ zephyr_udc0: &usbd {
|
|||
&spi {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&spi_controller>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-1 = <&spi_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
||||
|
||||
&spi2 {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&spi2_controller>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-1 = <&spi2_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
||||
|
|
|
@ -15,8 +15,12 @@ LOG_MODULE_REGISTER(spi_smartbond);
|
|||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
#include <zephyr/pm/policy.h>
|
||||
#include <zephyr/pm/device_runtime.h>
|
||||
|
||||
#include <DA1469xAB.h>
|
||||
#include <da1469x_pd.h>
|
||||
|
||||
#define DIVN_CLK 32000000 /* divN_clk 32MHz */
|
||||
#define SCLK_FREQ_2MHZ (DIVN_CLK / 14) /* 2.285714MHz*/
|
||||
|
@ -33,6 +37,10 @@ struct spi_smartbond_cfg {
|
|||
struct spi_smartbond_data {
|
||||
struct spi_context ctx;
|
||||
uint8_t dfs;
|
||||
#if defined(CONFIG_PM_DEVICE)
|
||||
ATOMIC_DEFINE(pm_policy_state_flag, 1);
|
||||
uint32_t spi_ctrl_reg;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline void spi_smartbond_enable(const struct spi_smartbond_cfg *cfg, bool enable)
|
||||
|
@ -106,6 +114,31 @@ static inline int spi_smartbond_set_word_size(const struct spi_smartbond_cfg *cf
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void spi_smartbond_pm_policy_state_lock_get(struct spi_smartbond_data *data)
|
||||
{
|
||||
#if defined(CONFIG_PM_DEVICE)
|
||||
if (atomic_test_and_set_bit(data->pm_policy_state_flag, 0) == 0) {
|
||||
/*
|
||||
* Prevent the SoC from entering the normal sleep state as PDC does not support
|
||||
* waking up the application core following SPI events.
|
||||
*/
|
||||
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void spi_smartbond_pm_policy_state_lock_put(struct spi_smartbond_data *data)
|
||||
{
|
||||
#if defined(CONFIG_PM_DEVICE)
|
||||
if (atomic_test_and_clear_bit(data->pm_policy_state_flag, 0) == 1) {
|
||||
/*
|
||||
* Allow the SoC to enter the normal sleep state once SPI transactions are done.
|
||||
*/
|
||||
pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int spi_smartbond_configure(const struct spi_smartbond_cfg *cfg,
|
||||
struct spi_smartbond_data *data,
|
||||
const struct spi_config *spi_cfg)
|
||||
|
@ -113,6 +146,9 @@ static int spi_smartbond_configure(const struct spi_smartbond_cfg *cfg,
|
|||
int rc;
|
||||
|
||||
if (spi_context_configured(&data->ctx, spi_cfg)) {
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
spi_smartbond_enable(cfg, true);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -182,6 +218,8 @@ static int spi_smartbond_transceive(const struct device *dev, const struct spi_c
|
|||
uint32_t bitmask;
|
||||
int rc;
|
||||
|
||||
spi_smartbond_pm_policy_state_lock_get(data);
|
||||
|
||||
spi_context_lock(&data->ctx, false, NULL, NULL, spi_cfg);
|
||||
rc = spi_smartbond_configure(cfg, data, spi_cfg);
|
||||
if (rc == 0) {
|
||||
|
@ -211,6 +249,8 @@ static int spi_smartbond_transceive(const struct device *dev, const struct spi_c
|
|||
spi_context_cs_control(ctx, false);
|
||||
spi_context_release(&data->ctx, rc);
|
||||
|
||||
spi_smartbond_pm_policy_state_lock_put(data);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#ifdef CONFIG_SPI_ASYNC
|
||||
|
@ -247,7 +287,7 @@ static const struct spi_driver_api spi_smartbond_driver_api = {
|
|||
.release = spi_smartbond_release,
|
||||
};
|
||||
|
||||
static int spi_smartbond_init(const struct device *dev)
|
||||
static int spi_smartbond_resume(const struct device *dev)
|
||||
{
|
||||
const struct spi_smartbond_cfg *cfg = dev->config;
|
||||
struct spi_smartbond_data *data = dev->data;
|
||||
|
@ -273,6 +313,69 @@ static int spi_smartbond_init(const struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM_DEVICE)
|
||||
static int spi_smartbond_suspend(const struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
const struct spi_smartbond_cfg *config = dev->config;
|
||||
struct spi_smartbond_data *data = dev->data;
|
||||
|
||||
data->spi_ctrl_reg = config->regs->SPI_CTRL_REG;
|
||||
/* Disable the SPI digital block */
|
||||
config->regs->SPI_CTRL_REG &= ~SPI_SPI_CTRL_REG_SPI_EN_CTRL_Msk;
|
||||
/* Gate SPI clocking */
|
||||
CRG_COM->RESET_CLK_COM_REG = config->periph_clock_config;
|
||||
|
||||
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
|
||||
if (ret < 0) {
|
||||
LOG_WRN("Failed to configure the SPI pins to inactive state");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_smartbond_pm_action(const struct device *dev,
|
||||
enum pm_device_action action)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (action) {
|
||||
case PM_DEVICE_ACTION_RESUME:
|
||||
da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
|
||||
ret = spi_smartbond_resume(dev);
|
||||
break;
|
||||
case PM_DEVICE_ACTION_SUSPEND:
|
||||
ret = spi_smartbond_suspend(dev);
|
||||
da1469x_pd_release(MCU_PD_DOMAIN_COM);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOTSUP;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int spi_smartbond_init(const struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct spi_smartbond_data *data = dev->data;
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE_RUNTIME
|
||||
/* Make sure device state is marked as suspended */
|
||||
pm_device_init_suspended(dev);
|
||||
|
||||
ret = pm_device_runtime_enable(dev);
|
||||
|
||||
#else
|
||||
da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
|
||||
ret = spi_smartbond_resume(dev);
|
||||
#endif
|
||||
spi_context_unlock_unconditionally(&data->ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define SPI_SMARTBOND_DEVICE(id) \
|
||||
PINCTRL_DT_INST_DEFINE(id); \
|
||||
static const struct spi_smartbond_cfg spi_smartbond_##id##_cfg = { \
|
||||
|
@ -284,8 +387,13 @@ static int spi_smartbond_init(const struct device *dev)
|
|||
SPI_CONTEXT_INIT_LOCK(spi_smartbond_##id##_data, ctx), \
|
||||
SPI_CONTEXT_INIT_SYNC(spi_smartbond_##id##_data, ctx), \
|
||||
SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(id), ctx)}; \
|
||||
DEVICE_DT_INST_DEFINE(id, spi_smartbond_init, NULL, &spi_smartbond_##id##_data, \
|
||||
&spi_smartbond_##id##_cfg, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
|
||||
PM_DEVICE_DT_INST_DEFINE(id, spi_smartbond_pm_action); \
|
||||
DEVICE_DT_INST_DEFINE(id, \
|
||||
spi_smartbond_init, \
|
||||
PM_DEVICE_DT_INST_GET(id), \
|
||||
&spi_smartbond_##id##_data, \
|
||||
&spi_smartbond_##id##_cfg, \
|
||||
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
|
||||
&spi_smartbond_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SPI_SMARTBOND_DEVICE)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue