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 {
|
spi_controller: spi_controller {
|
||||||
group1 {
|
group1 {
|
||||||
pinmux = < SMARTBOND_PINMUX(SPI_CLK, 0, 21) >,
|
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 {
|
spi2_controller: spi2_controller {
|
||||||
group1 {
|
group1 {
|
||||||
pinmux = < SMARTBOND_PINMUX(SPI2_CLK, 1, 3) >,
|
pinmux = < SMARTBOND_PINMUX(SPI2_CLK, 1, 3) >,
|
||||||
|
|
|
@ -201,13 +201,15 @@ zephyr_udc0: &usbd {
|
||||||
&spi {
|
&spi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
pinctrl-0 = <&spi_controller>;
|
pinctrl-0 = <&spi_controller>;
|
||||||
pinctrl-names = "default";
|
pinctrl-1 = <&spi_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
};
|
};
|
||||||
|
|
||||||
&spi2 {
|
&spi2 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
pinctrl-0 = <&spi2_controller>;
|
pinctrl-0 = <&spi2_controller>;
|
||||||
pinctrl-names = "default";
|
pinctrl-1 = <&spi2_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
};
|
};
|
||||||
|
|
||||||
mikrobus_1_i2c: &i2c {};
|
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 {
|
spi_controller: spi_controller {
|
||||||
group1 {
|
group1 {
|
||||||
pinmux = <SMARTBOND_PINMUX(SPI_CLK, 0, 21)>,
|
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 {
|
spi2_controller: spi2_controller {
|
||||||
group1 {
|
group1 {
|
||||||
pinmux = < SMARTBOND_PINMUX(SPI2_CLK, 1, 3) >,
|
pinmux = < SMARTBOND_PINMUX(SPI2_CLK, 1, 3) >,
|
||||||
|
|
|
@ -167,11 +167,13 @@ zephyr_udc0: &usbd {
|
||||||
&spi {
|
&spi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
pinctrl-0 = <&spi_controller>;
|
pinctrl-0 = <&spi_controller>;
|
||||||
pinctrl-names = "default";
|
pinctrl-1 = <&spi_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
};
|
};
|
||||||
|
|
||||||
&spi2 {
|
&spi2 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
pinctrl-0 = <&spi2_controller>;
|
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/gpio.h>
|
||||||
#include <zephyr/drivers/pinctrl.h>
|
#include <zephyr/drivers/pinctrl.h>
|
||||||
#include <zephyr/drivers/spi.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 <DA1469xAB.h>
|
||||||
|
#include <da1469x_pd.h>
|
||||||
|
|
||||||
#define DIVN_CLK 32000000 /* divN_clk 32MHz */
|
#define DIVN_CLK 32000000 /* divN_clk 32MHz */
|
||||||
#define SCLK_FREQ_2MHZ (DIVN_CLK / 14) /* 2.285714MHz*/
|
#define SCLK_FREQ_2MHZ (DIVN_CLK / 14) /* 2.285714MHz*/
|
||||||
|
@ -33,6 +37,10 @@ struct spi_smartbond_cfg {
|
||||||
struct spi_smartbond_data {
|
struct spi_smartbond_data {
|
||||||
struct spi_context ctx;
|
struct spi_context ctx;
|
||||||
uint8_t dfs;
|
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)
|
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;
|
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,
|
static int spi_smartbond_configure(const struct spi_smartbond_cfg *cfg,
|
||||||
struct spi_smartbond_data *data,
|
struct spi_smartbond_data *data,
|
||||||
const struct spi_config *spi_cfg)
|
const struct spi_config *spi_cfg)
|
||||||
|
@ -113,6 +146,9 @@ static int spi_smartbond_configure(const struct spi_smartbond_cfg *cfg,
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (spi_context_configured(&data->ctx, spi_cfg)) {
|
if (spi_context_configured(&data->ctx, spi_cfg)) {
|
||||||
|
#ifdef CONFIG_PM_DEVICE
|
||||||
|
spi_smartbond_enable(cfg, true);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,6 +218,8 @@ static int spi_smartbond_transceive(const struct device *dev, const struct spi_c
|
||||||
uint32_t bitmask;
|
uint32_t bitmask;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
spi_smartbond_pm_policy_state_lock_get(data);
|
||||||
|
|
||||||
spi_context_lock(&data->ctx, false, NULL, NULL, spi_cfg);
|
spi_context_lock(&data->ctx, false, NULL, NULL, spi_cfg);
|
||||||
rc = spi_smartbond_configure(cfg, data, spi_cfg);
|
rc = spi_smartbond_configure(cfg, data, spi_cfg);
|
||||||
if (rc == 0) {
|
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_cs_control(ctx, false);
|
||||||
spi_context_release(&data->ctx, rc);
|
spi_context_release(&data->ctx, rc);
|
||||||
|
|
||||||
|
spi_smartbond_pm_policy_state_lock_put(data);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_SPI_ASYNC
|
#ifdef CONFIG_SPI_ASYNC
|
||||||
|
@ -247,7 +287,7 @@ static const struct spi_driver_api spi_smartbond_driver_api = {
|
||||||
.release = spi_smartbond_release,
|
.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;
|
const struct spi_smartbond_cfg *cfg = dev->config;
|
||||||
struct spi_smartbond_data *data = dev->data;
|
struct spi_smartbond_data *data = dev->data;
|
||||||
|
@ -273,6 +313,69 @@ static int spi_smartbond_init(const struct device *dev)
|
||||||
return 0;
|
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) \
|
#define SPI_SMARTBOND_DEVICE(id) \
|
||||||
PINCTRL_DT_INST_DEFINE(id); \
|
PINCTRL_DT_INST_DEFINE(id); \
|
||||||
static const struct spi_smartbond_cfg spi_smartbond_##id##_cfg = { \
|
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_LOCK(spi_smartbond_##id##_data, ctx), \
|
||||||
SPI_CONTEXT_INIT_SYNC(spi_smartbond_##id##_data, ctx), \
|
SPI_CONTEXT_INIT_SYNC(spi_smartbond_##id##_data, ctx), \
|
||||||
SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(id), ctx)}; \
|
SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(id), ctx)}; \
|
||||||
DEVICE_DT_INST_DEFINE(id, spi_smartbond_init, NULL, &spi_smartbond_##id##_data, \
|
PM_DEVICE_DT_INST_DEFINE(id, spi_smartbond_pm_action); \
|
||||||
&spi_smartbond_##id##_cfg, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
|
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);
|
&spi_smartbond_driver_api);
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(SPI_SMARTBOND_DEVICE)
|
DT_INST_FOREACH_STATUS_OKAY(SPI_SMARTBOND_DEVICE)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue