Skip to content

Commit 59c94db

Browse files
ananglkartben
authored andcommitted
drivers: spi_nrfx_spim: Add clock requests for fast SPIM instances
Fast SPIM instances (SPIM120 and SPIM121) for correct operation require the highest frequency from the global HSFLL. This commit adds needed clock controller requests to the driver. When the runtime device power management is enabled, the frequency is requested as long as the SPIM is resumed, otherwise it is requested for the duration of transfers. This commit also adds a missing call to `pm_device_runtime_put()` when SPIM reconfiguration fails. Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
1 parent b7c8558 commit 59c94db

File tree

1 file changed

+105
-3
lines changed

1 file changed

+105
-3
lines changed

drivers/spi/spi_nrfx_spim.c

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <zephyr/cache.h>
1010
#include <zephyr/pm/device.h>
1111
#include <zephyr/pm/device_runtime.h>
12+
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
1213
#include <zephyr/drivers/pinctrl.h>
1314
#include <zephyr/mem_mgmt/mem_attr.h>
1415
#include <soc.h>
@@ -42,6 +43,16 @@ LOG_MODULE_REGISTER(spi_nrfx_spim, CONFIG_SPI_LOG_LEVEL);
4243
#define SPI_BUFFER_IN_RAM 1
4344
#endif
4445

46+
#if defined(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL) && \
47+
(defined(CONFIG_HAS_HW_NRF_SPIM120) || \
48+
defined(CONFIG_HAS_HW_NRF_SPIM121))
49+
#define SPIM_REQUESTS_CLOCK(idx) UTIL_OR(IS_EQ(idx, 120), \
50+
IS_EQ(idx, 121))
51+
#define USE_CLOCK_REQUESTS 1
52+
#else
53+
#define SPIM_REQUESTS_CLOCK(idx) 0
54+
#endif
55+
4556
struct spi_nrfx_data {
4657
struct spi_context ctx;
4758
const struct device *dev;
@@ -57,6 +68,9 @@ struct spi_nrfx_data {
5768
uint8_t ppi_ch;
5869
uint8_t gpiote_ch;
5970
#endif
71+
#ifdef USE_CLOCK_REQUESTS
72+
bool clock_requested;
73+
#endif
6074
};
6175

6276
struct spi_nrfx_config {
@@ -74,10 +88,59 @@ struct spi_nrfx_config {
7488
#ifdef CONFIG_DCACHE
7589
uint32_t mem_attr;
7690
#endif
91+
#ifdef USE_CLOCK_REQUESTS
92+
const struct device *clk_dev;
93+
struct nrf_clock_spec clk_spec;
94+
#endif
7795
};
7896

7997
static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context);
8098

99+
static inline int request_clock(const struct device *dev)
100+
{
101+
#ifdef USE_CLOCK_REQUESTS
102+
struct spi_nrfx_data *dev_data = dev->data;
103+
const struct spi_nrfx_config *dev_config = dev->config;
104+
int error;
105+
106+
if (!dev_config->clk_dev) {
107+
return 0;
108+
}
109+
110+
error = nrf_clock_control_request_sync(
111+
dev_config->clk_dev, &dev_config->clk_spec,
112+
K_MSEC(CONFIG_SPI_COMPLETION_TIMEOUT_TOLERANCE));
113+
if (error < 0) {
114+
LOG_ERR("Failed to request clock: %d", error);
115+
return error;
116+
}
117+
118+
dev_data->clock_requested = true;
119+
#else
120+
ARG_UNUSED(dev);
121+
#endif
122+
123+
return 0;
124+
}
125+
126+
static inline void release_clock(const struct device *dev)
127+
{
128+
#ifdef USE_CLOCK_REQUESTS
129+
struct spi_nrfx_data *dev_data = dev->data;
130+
const struct spi_nrfx_config *dev_config = dev->config;
131+
132+
if (!dev_data->clock_requested) {
133+
return;
134+
}
135+
136+
dev_data->clock_requested = false;
137+
138+
nrf_clock_control_release(dev_config->clk_dev, &dev_config->clk_spec);
139+
#else
140+
ARG_UNUSED(dev);
141+
#endif
142+
}
143+
81144
static inline void finalize_spi_transaction(const struct device *dev, bool deactivate_cs)
82145
{
83146
struct spi_nrfx_data *dev_data = dev->data;
@@ -92,6 +155,10 @@ static inline void finalize_spi_transaction(const struct device *dev, bool deact
92155
nrfy_spim_disable(reg);
93156
}
94157

158+
if (!IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
159+
release_clock(dev);
160+
}
161+
95162
pm_device_runtime_put_async(dev, K_NO_WAIT);
96163
}
97164

@@ -467,6 +534,11 @@ static int transceive(const struct device *dev,
467534
spi_context_lock(&dev_data->ctx, asynchronous, cb, userdata, spi_cfg);
468535

469536
error = configure(dev, spi_cfg);
537+
538+
if (error == 0 && !IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
539+
error = request_clock(dev);
540+
}
541+
470542
if (error == 0) {
471543
dev_data->busy = true;
472544

@@ -518,6 +590,8 @@ static int transceive(const struct device *dev,
518590
} else if (error) {
519591
finalize_spi_transaction(dev, true);
520592
}
593+
} else {
594+
pm_device_runtime_put(dev);
521595
}
522596

523597
spi_context_release(&dev_data->ctx, error);
@@ -575,7 +649,7 @@ static DEVICE_API(spi, spi_nrfx_driver_api) = {
575649
.release = spi_nrfx_release,
576650
};
577651

578-
static void spim_resume(const struct device *dev)
652+
static int spim_resume(const struct device *dev)
579653
{
580654
const struct spi_nrfx_config *dev_config = dev->config;
581655

@@ -587,6 +661,8 @@ static void spim_resume(const struct device *dev)
587661
#ifdef CONFIG_SOC_NRF54H20_GPD
588662
nrf_gpd_retain_pins_set(dev_config->pcfg, false);
589663
#endif
664+
665+
return IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) ? request_clock(dev) : 0;
590666
}
591667

592668
static void spim_suspend(const struct device *dev)
@@ -599,6 +675,10 @@ static void spim_suspend(const struct device *dev)
599675
dev_data->initialized = false;
600676
}
601677

678+
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
679+
release_clock(dev);
680+
}
681+
602682
#ifdef CONFIG_SOC_NRF54H20_GPD
603683
nrf_gpd_retain_pins_set(dev_config->pcfg, true);
604684
#endif
@@ -609,7 +689,7 @@ static void spim_suspend(const struct device *dev)
609689
static int spim_nrfx_pm_action(const struct device *dev, enum pm_device_action action)
610690
{
611691
if (action == PM_DEVICE_ACTION_RESUME) {
612-
spim_resume(dev);
692+
return spim_resume(dev);
613693
} else if (IS_ENABLED(CONFIG_PM_DEVICE) && (action == PM_DEVICE_ACTION_SUSPEND)) {
614694
spim_suspend(dev);
615695
} else {
@@ -685,6 +765,21 @@ static int spi_nrfx_init(const struct device *dev)
685765
(0))), \
686766
(0))
687767

768+
/* Fast instances depend on the global HSFLL clock controller (as they need
769+
* to request the highest frequency from it to operate correctly), so they
770+
* must be initialized after that controller driver, hence the default SPI
771+
* initialization priority may be too early for them.
772+
*/
773+
#if defined(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY) && \
774+
CONFIG_SPI_INIT_PRIORITY < CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY
775+
#define SPIM_INIT_PRIORITY(idx) \
776+
COND_CODE_1(SPIM_REQUESTS_CLOCK(idx), \
777+
(UTIL_INC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY)), \
778+
(CONFIG_SPI_INIT_PRIORITY))
779+
#else
780+
#define SPIM_INIT_PRIORITY(idx) CONFIG_SPI_INIT_PRIORITY
781+
#endif
782+
688783
#define SPI_NRFX_SPIM_DEFINE(idx) \
689784
NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(SPIM(idx)); \
690785
static void irq_connect##idx(void) \
@@ -735,6 +830,13 @@ static int spi_nrfx_init(const struct device *dev)
735830
.wake_gpiote = WAKE_GPIOTE_INSTANCE(SPIM(idx)), \
736831
IF_ENABLED(CONFIG_DCACHE, \
737832
(.mem_attr = SPIM_GET_MEM_ATTR(idx),)) \
833+
IF_ENABLED(USE_CLOCK_REQUESTS, \
834+
(.clk_dev = SPIM_REQUESTS_CLOCK(idx) \
835+
? DEVICE_DT_GET(DT_CLOCKS_CTLR(SPIM(idx))) \
836+
: NULL, \
837+
.clk_spec = { \
838+
.frequency = NRF_CLOCK_CONTROL_FREQUENCY_MAX, \
839+
},)) \
738840
}; \
739841
BUILD_ASSERT(!SPIM_HAS_PROP(idx, wake_gpios) || \
740842
!(DT_GPIO_FLAGS(SPIM(idx), wake_gpios) & GPIO_ACTIVE_LOW),\
@@ -745,7 +847,7 @@ static int spi_nrfx_init(const struct device *dev)
745847
PM_DEVICE_DT_GET(SPIM(idx)), \
746848
&spi_##idx##_data, \
747849
&spi_##idx##z_config, \
748-
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
850+
POST_KERNEL, SPIM_INIT_PRIORITY(idx), \
749851
&spi_nrfx_driver_api)
750852

751853
#define SPIM_MEMORY_SECTION(idx) \

0 commit comments

Comments
 (0)