Skip to content

Commit

Permalink
[nrf fromlist] drivers: pwm: nrfx: add global hsfll request for fast PWM
Browse files Browse the repository at this point in the history
Added clock control api for global hsfll used in fast PWM120 driver.

Upstream PR #: 82133

Signed-off-by: Michał Stasiak <[email protected]>
  • Loading branch information
mstasiaknordic committed Jan 13, 2025
1 parent 9023a99 commit 3d97669
Showing 1 changed file with 85 additions and 8 deletions.
93 changes: 85 additions & 8 deletions drivers/pwm/pwm_nrfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <zephyr/linker/devicetree_regions.h>
#include <zephyr/cache.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#ifdef CONFIG_SOC_NRF54H20_GPD
#include <nrf/gpd.h>
#endif
Expand All @@ -35,6 +36,21 @@ LOG_MODULE_REGISTER(pwm_nrfx, CONFIG_PWM_LOG_LEVEL);
#define ANOMALY_109_EGU_IRQ_CONNECT(idx)
#endif

#define PWM(dev_idx) DT_NODELABEL(pwm##dev_idx)
#define PWM_PROP(dev_idx, prop) DT_PROP(PWM(dev_idx), prop)
#define PWM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(PWM(idx), prop)

#define PWM_NRFX_IS_FAST(unused, prefix, idx, _) \
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(PWM(idx)), \
(COND_CODE_1(PWM_HAS_PROP(idx, power_domains), \
(IS_EQ(DT_PHA(PWM(idx), power_domains, id), NRF_GPD_FAST_ACTIVE1)), \
(0))), (0))

#if (NRFX_FOREACH_PRESENT(PWM, PWM_NRFX_IS_FAST, (||), (0))) && \
CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL

Check notice on line 50 in drivers/pwm/pwm_nrfx.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/pwm/pwm_nrfx.c:50 -#if (NRFX_FOREACH_PRESENT(PWM, PWM_NRFX_IS_FAST, (||), (0))) && \ +#if (NRFX_FOREACH_PRESENT(PWM, PWM_NRFX_IS_FAST, (||), (0))) && \
#define PWM_NRFX_USE_CLOCK_CONTROL 1
#endif

#define PWM_NRFX_CH_POLARITY_MASK BIT(15)
#define PWM_NRFX_CH_COMPARE_MASK BIT_MASK(15)
#define PWM_NRFX_CH_VALUE(compare_value, inverted) \
Expand All @@ -49,6 +65,10 @@ struct pwm_nrfx_config {
#ifdef CONFIG_DCACHE
uint32_t mem_attr;
#endif
#ifdef PWM_NRFX_USE_CLOCK_CONTROL
const struct device *clk_dev;
struct nrf_clock_spec clk_spec;
#endif
};

struct pwm_nrfx_data {
Expand All @@ -57,6 +77,9 @@ struct pwm_nrfx_data {
uint8_t pwm_needed;
uint8_t prescaler;
bool stop_requested;
#ifdef PWM_NRFX_USE_CLOCK_CONTROL
bool clock_requested;
#endif
};
/* Ensure the pwm_needed bit mask can accommodate all available channels. */
#if (NRF_PWM_CHANNEL_COUNT > 8)
Expand Down Expand Up @@ -229,6 +252,18 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel,
* ensure it is stopped before starting the next playback.
*/
nrfx_pwm_stop(&config->pwm, false);
#if PWM_NRFX_USE_CLOCK_CONTROL
if (data->clock_requested && config->clk_dev) {
int ret = nrf_clock_control_release(config->clk_dev, &config->clk_spec);

if (ret < 0) {
LOG_ERR("Global HSFLL release failed: %d", ret);
return ret;
}

data->clock_requested = false;
}
#endif
data->stop_requested = true;
} else {
if (data->stop_requested) {
Expand All @@ -248,6 +283,20 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel,
* until another playback is requested (new values will be
* loaded then) or the PWM peripheral is stopped.
*/
#if PWM_NRFX_USE_CLOCK_CONTROL
if (!data->clock_requested && config->clk_dev) {
int ret = nrf_clock_control_request_sync(config->clk_dev,
&config->clk_spec,
K_FOREVER);

Check notice on line 290 in drivers/pwm/pwm_nrfx.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/pwm/pwm_nrfx.c:290 - int ret = nrf_clock_control_request_sync(config->clk_dev, - &config->clk_spec, + int ret = nrf_clock_control_request_sync(config->clk_dev, &config->clk_spec,

if (ret < 0) {
LOG_ERR("Global HSFLL request failed: %d", ret);
return ret;
}

data->clock_requested = true;
}
#endif
nrfx_pwm_simple_playback(&config->pwm, &config->seq, 1,
NRFX_PWM_FLAG_NO_EVT_FINISHED);
}
Expand All @@ -270,7 +319,7 @@ static const struct pwm_driver_api pwm_nrfx_drv_api_funcs = {
.get_cycles_per_sec = pwm_nrfx_get_cycles_per_sec,
};

static void pwm_resume(const struct device *dev)
static int pwm_resume(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;
uint8_t initially_inverted = 0;
Expand Down Expand Up @@ -299,13 +348,29 @@ static void pwm_resume(const struct device *dev)

seq_values_ptr_get(dev)[i] = PWM_NRFX_CH_VALUE(0, inverted);
}

return 0;
}

static void pwm_suspend(const struct device *dev)
static int pwm_suspend(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;

nrfx_pwm_stop(&config->pwm, false);
#if PWM_NRFX_USE_CLOCK_CONTROL
struct pwm_nrfx_data *data = dev->data;

if (data->clock_requested) {
int ret = nrf_clock_control_release(config->clk_dev, &config->clk_spec);

if (ret < 0) {
LOG_ERR("Global HSFLL release failed: %d", ret);
return ret;
}

data->clock_requested = false;
}
#endif
while (!nrfx_pwm_stopped_check(&config->pwm)) {
}

Expand All @@ -315,15 +380,17 @@ static void pwm_suspend(const struct device *dev)

memset(dev->data, 0, sizeof(struct pwm_nrfx_data));
(void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);

return 0;
}

static int pwm_nrfx_pm_action(const struct device *dev,
enum pm_device_action action)
{
if (action == PM_DEVICE_ACTION_RESUME) {
pwm_resume(dev);
return pwm_resume(dev);
} else if (IS_ENABLED(CONFIG_PM_DEVICE) && (action == PM_DEVICE_ACTION_SUSPEND)) {
pwm_suspend(dev);
return pwm_suspend(dev);
} else {
return -ENOTSUP;
}
Expand Down Expand Up @@ -351,9 +418,6 @@ static int pwm_nrfx_init(const struct device *dev)
return pm_device_driver_init(dev, pwm_nrfx_pm_action);
}

#define PWM(dev_idx) DT_NODELABEL(pwm##dev_idx)
#define PWM_PROP(dev_idx, prop) DT_PROP(PWM(dev_idx), prop)
#define PWM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(PWM(idx), prop)
#define PWM_MEM_REGION(idx) DT_PHANDLE(PWM(idx), memory_regions)

#define PWM_MEMORY_SECTION(idx) \
Expand All @@ -366,6 +430,11 @@ static int pwm_nrfx_init(const struct device *dev)
COND_CODE_1(PWM_HAS_PROP(idx, memory_regions), \
(DT_PROP_OR(PWM_MEM_REGION(idx), zephyr_memory_attr, 0)), (0))

#define PWM_INIT_PRIORITY(idx) \
COND_CODE_1(PWM_NRFX_IS_FAST(_, /*empty*/, idx, _), \
(UTIL_INC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY)), \
(CONFIG_PWM_INIT_PRIORITY))

#define PWM_NRFX_DEVICE(idx) \
NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(PWM(idx)); \
static struct pwm_nrfx_data pwm_nrfx_##idx##_data; \
Expand Down Expand Up @@ -393,6 +462,14 @@ static int pwm_nrfx_init(const struct device *dev)
(16ul * 1000ul * 1000ul)), \
IF_ENABLED(CONFIG_DCACHE, \
(.mem_attr = PWM_GET_MEM_ATTR(idx),)) \
IF_ENABLED(PWM_NRFX_USE_CLOCK_CONTROL, \
(.clk_dev = PWM_NRFX_IS_FAST(_, /*empty*/, idx, _) \
? DEVICE_DT_GET(DT_CLOCKS_CTLR(PWM(idx))) \
: NULL, \
.clk_spec = { \
.frequency = \
NRF_PERIPH_GET_FREQUENCY(PWM(idx)), \
},)) \
}; \
static int pwm_nrfx_init##idx(const struct device *dev) \
{ \
Expand All @@ -405,7 +482,7 @@ static int pwm_nrfx_init(const struct device *dev)
pwm_nrfx_init##idx, PM_DEVICE_DT_GET(PWM(idx)), \
&pwm_nrfx_##idx##_data, \
&pwm_nrfx_##idx##_config, \
POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, \
POST_KERNEL, PWM_INIT_PRIORITY(idx), \
&pwm_nrfx_drv_api_funcs)

Check notice on line 487 in drivers/pwm/pwm_nrfx.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/pwm/pwm_nrfx.c:487 -#define PWM_INIT_PRIORITY(idx) \ - COND_CODE_1(PWM_NRFX_IS_FAST(_, /*empty*/, idx, _), \ - (UTIL_INC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY)), \ +#define PWM_INIT_PRIORITY(idx) \ + COND_CODE_1(PWM_NRFX_IS_FAST(_, /*empty*/, idx, _), \ + (UTIL_INC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY)), \ (CONFIG_PWM_INIT_PRIORITY)) -#define PWM_NRFX_DEVICE(idx) \ - NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(PWM(idx)); \ - static struct pwm_nrfx_data pwm_nrfx_##idx##_data; \ - static uint16_t pwm_##idx##_seq_values[NRF_PWM_CHANNEL_COUNT] \ - PWM_MEMORY_SECTION(idx); \ - PINCTRL_DT_DEFINE(PWM(idx)); \ - static const struct pwm_nrfx_config pwm_nrfx_##idx##_config = { \ - .pwm = NRFX_PWM_INSTANCE(idx), \ - .initial_config = { \ - .skip_gpio_cfg = true, \ - .skip_psel_cfg = true, \ - .base_clock = NRF_PWM_CLK_1MHz, \ - .count_mode = (PWM_PROP(idx, center_aligned) \ - ? NRF_PWM_MODE_UP_AND_DOWN \ - : NRF_PWM_MODE_UP), \ - .top_value = 1000, \ - .load_mode = NRF_PWM_LOAD_INDIVIDUAL, \ - .step_mode = NRF_PWM_STEP_TRIGGERED, \ - }, \ - .seq.values.p_raw = pwm_##idx##_seq_values, \ - .seq.length = NRF_PWM_CHANNEL_COUNT, \ - .pcfg = PINCTRL_DT_DEV_CONFIG_GET(PWM(idx)), \ - .clock_freq = COND_CODE_1(DT_CLOCKS_HAS_IDX(PWM(idx), 0), \ - (DT_PROP(DT_CLOCKS_CTLR(PWM(idx)), clock_frequency)), \ - (16ul * 1000ul * 1000ul)), \ - IF_ENABLED(CONFIG_DCACHE, \ - (.mem_attr = PWM_GET_MEM_ATTR(idx),)) \ - IF_ENABLED(PWM_NRFX_USE_CLOCK_CONTROL, \ - (.clk_dev = PWM_NRFX_IS_FAST(_, /*empty*/, idx, _) \ - ? DEVICE_DT_GET(DT_CLOCKS_CTLR(PWM(idx))) \ - : NULL, \ - .clk_spec = { \ - .frequency = \ - NRF_PERIPH_GET_FREQUENCY(PWM(idx)), \ - },)) \ - }; \ - static int pwm_nrfx_init##idx(const struct device *dev) \ - { \ - IRQ_CONNECT(DT_IRQN(PWM(idx)), DT_IRQ(PWM(idx), priority), \ - nrfx_isr, nrfx_pwm_##idx##_irq_handler, 0); \ - return pwm_nrfx_init(dev); \ - }; \ - PM_DEVICE_DT_DEFINE(PWM(idx), pwm_nrfx_pm_action); \ - DEVICE_DT_DEFINE(PWM(idx), \ - pwm_nrfx_init##idx, PM_DEVICE_DT_GET(PWM(idx)), \ - &pwm_nrfx_##idx##_data, \ - &pwm_nrfx_##idx##_config, \ - POST_KERNEL, PWM_INIT_PRIORITY(idx), \ - &pwm_nrfx_drv_api_funcs) +#define PWM_NRFX_DEVICE(idx) \ + NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(PWM(idx)); \ + static struct pwm_nrfx_data pwm_nrfx_##idx##_data; \ + static uint16_t pwm_##idx##_seq_values[NRF_PWM_CHANNEL_COUNT] PWM_MEMORY_SECTION(idx); \ + PINCTRL_DT_DEFINE(PWM(idx)); \ + static const struct pwm_nrfx_config pwm_nrfx_##idx##_config = { \ + .pwm = NRFX_PWM_INSTANCE(idx), \ + .initial_config = \ + { \ + .skip_gpio_cfg = true, \ + .skip_psel_cfg = true, \ + .base_clock = NRF_PWM_CLK_1MHz, \ + .count_mode = \ + (PWM_PROP(idx, center_aligned) ? NRF_PWM_MODE_UP_AND_DOWN \ + : NRF_PWM_MODE_UP), \ + .top_value = 1000,
#define COND_PWM_NRFX_DEVICE(unused, prefix, i, _) \
Expand Down

0 comments on commit 3d97669

Please sign in to comment.