Skip to content
Draft
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
13 changes: 1 addition & 12 deletions drivers/pwm/Kconfig.nrfx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,7 @@ config PWM_NRFX
bool "nRF PWM nrfx driver"
default y
depends on DT_HAS_NORDIC_NRF_PWM_ENABLED
select NRFX_PWM0 if HAS_HW_NRF_PWM0
select NRFX_PWM1 if HAS_HW_NRF_PWM1
select NRFX_PWM2 if HAS_HW_NRF_PWM2
select NRFX_PWM3 if HAS_HW_NRF_PWM3
select NRFX_PWM20 if HAS_HW_NRF_PWM20
select NRFX_PWM21 if HAS_HW_NRF_PWM21
select NRFX_PWM22 if HAS_HW_NRF_PWM22
select NRFX_PWM120 if HAS_HW_NRF_PWM120
select NRFX_PWM130 if HAS_HW_NRF_PWM130
select NRFX_PWM131 if HAS_HW_NRF_PWM131
select NRFX_PWM132 if HAS_HW_NRF_PWM132
select NRFX_PWM133 if HAS_HW_NRF_PWM133
select NRFX_PWM
select PINCTRL
help
Enable support for nrfx Hardware PWM driver for nRF52 MCU series.
Expand Down
179 changes: 91 additions & 88 deletions drivers/pwm/pwm_nrfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT nordic_nrf_pwm

#include <nrfx_pwm.h>
#include <zephyr/drivers/pwm.h>
#include <zephyr/pm/device.h>
Expand Down Expand Up @@ -33,10 +36,7 @@
#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(idx) NRF_DT_IS_FAST(PWM(idx))
#define PWM_NRFX_IS_FAST(inst) NRF_DT_IS_FAST(DT_DRV_INST(inst))

#if NRF_DT_INST_ANY_IS_FAST
#define PWM_NRFX_FAST_PRESENT 1
Expand All @@ -57,7 +57,6 @@
(compare_value | (inverted ? 0 : PWM_NRFX_CH_POLARITY_MASK))

struct pwm_nrfx_config {
nrfx_pwm_t pwm;
nrfx_pwm_config_t initial_config;
nrf_pwm_sequence_t seq;
const struct pinctrl_dev_config *pcfg;
Expand All @@ -72,6 +71,7 @@
};

struct pwm_nrfx_data {
nrfx_pwm_t pwm;
uint32_t period_cycles;
/* Bit mask indicating channels that need the PWM generation. */
uint8_t pwm_needed;
Expand Down Expand Up @@ -145,11 +145,11 @@
data->period_cycles = period_cycles;
data->prescaler = prescaler;

nrf_pwm_configure(config->pwm.p_reg,
nrf_pwm_configure(data->pwm.p_reg,
data->prescaler,
config->initial_config.count_mode,
(uint16_t)countertop);
return true;

Check notice on line 152 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:152 - nrf_pwm_configure(data->pwm.p_reg, - data->prescaler, - config->initial_config.count_mode, - (uint16_t)countertop); + nrf_pwm_configure(data->pwm.p_reg, data->prescaler, + config->initial_config.count_mode, (uint16_t)countertop);
}

countertop >>= 1;
Expand All @@ -160,26 +160,25 @@
return false;
}

static bool channel_psel_get(uint32_t channel, uint32_t *psel,
const struct pwm_nrfx_config *config)
static bool channel_psel_get(uint32_t channel, uint32_t *psel, struct pwm_nrfx_data *data)
{
*psel = nrf_pwm_pin_get(config->pwm.p_reg, (uint8_t)channel);
*psel = nrf_pwm_pin_get(data->pwm.p_reg, (uint8_t)channel);

return (((*psel & PWM_PSEL_OUT_CONNECT_Msk) >> PWM_PSEL_OUT_CONNECT_Pos)
== PWM_PSEL_OUT_CONNECT_Connected);
}

static int stop_pwm(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;
struct pwm_nrfx_data *data = dev->data;

/* Don't wait here for the peripheral to actually stop. Instead,
* ensure it is stopped before starting the next playback.
*/
nrfx_pwm_stop(&config->pwm, false);
* ensure it is stopped before starting the next playback.
*/
nrfx_pwm_stop(&data->pwm, false);

Check notice on line 178 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:178 - * ensure it is stopped before starting the next playback. - */ + * ensure it is stopped before starting the next playback. + */

#if PWM_NRFX_USE_CLOCK_CONTROL
struct pwm_nrfx_data *data = dev->data;
const struct pwm_nrfx_config *config = dev->config;

if (data->clock_requested) {
int ret = nrf_clock_control_release(config->clk_dev, &config->clk_spec);
Expand Down Expand Up @@ -268,7 +267,7 @@
if (!needs_pwm) {
uint32_t psel;

if (channel_psel_get(channel, &psel, config)) {
if (channel_psel_get(channel, &psel, data)) {
uint32_t out_level = (pulse_cycles == 0) ? 0 : 1;

if (inverted) {
Expand Down Expand Up @@ -323,7 +322,7 @@
* and till that moment, it ignores any start requests,
* so ensure here that it is stopped.
*/
while (!nrfx_pwm_stopped_check(&config->pwm)) {
while (!nrfx_pwm_stopped_check(&data->pwm)) {
}
}

Expand All @@ -346,7 +345,7 @@
data->clock_requested = true;
}
#endif
nrfx_pwm_simple_playback(&config->pwm, &config->seq, 1,
nrfx_pwm_simple_playback(&data->pwm, &config->seq, 1,
NRFX_PWM_FLAG_NO_EVT_FINISHED);
}

Expand All @@ -371,14 +370,16 @@
static int pwm_resume(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;
struct pwm_nrfx_data *data = dev->data;

uint8_t initially_inverted = 0;

(void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);

for (size_t i = 0; i < NRF_PWM_CHANNEL_COUNT; i++) {
uint32_t psel;

if (channel_psel_get(i, &psel, config)) {
if (channel_psel_get(i, &psel, data)) {
/* Mark channels as inverted according to what initial
* state of their outputs has been set by pinctrl (high
* idle state means that the channel is inverted).
Expand All @@ -400,6 +401,7 @@
static int pwm_suspend(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;
struct pwm_nrfx_data *data = dev->data;

int ret = stop_pwm(dev);

Expand All @@ -408,7 +410,7 @@
return ret;
}

while (!nrfx_pwm_stopped_check(&config->pwm)) {
while (!nrfx_pwm_stopped_check(&data->pwm)) {
}

memset(dev->data, 0, sizeof(struct pwm_nrfx_data));
Expand All @@ -434,34 +436,36 @@
static int pwm_nrfx_init(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;
nrfx_err_t err;
struct pwm_nrfx_data *data = dev->data;

int err;

ANOMALY_109_EGU_IRQ_CONNECT(NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE);

if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
(void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
}

err = nrfx_pwm_init(&config->pwm, &config->initial_config, pwm_handler, dev->data);
if (err != NRFX_SUCCESS) {
err = nrfx_pwm_init(&data->pwm, &config->initial_config, pwm_handler, dev->data);
if (err < 0) {
LOG_ERR("Failed to initialize device: %s", dev->name);
return -EBUSY;
return err;
}

return pm_device_driver_init(dev, pwm_nrfx_pm_action);
}

#define PWM_MEM_REGION(idx) DT_PHANDLE(PWM(idx), memory_regions)
#define PWM_MEM_REGION(inst) DT_PHANDLE(DT_DRV_INST(inst), memory_regions)

#define PWM_MEMORY_SECTION(idx) \
COND_CODE_1(PWM_HAS_PROP(idx, memory_regions), \
#define PWM_MEMORY_SECTION(inst) \
COND_CODE_1(DT_NODE_HAS_PROP(inst, memory_regions), \
(__attribute__((__section__(LINKER_DT_NODE_REGION_NAME( \
PWM_MEM_REGION(idx)))))), \
PWM_MEM_REGION(inst)))))), \
())

#define PWM_GET_MEM_ATTR(idx) \
COND_CODE_1(PWM_HAS_PROP(idx, memory_regions), \
(DT_PROP_OR(PWM_MEM_REGION(idx), zephyr_memory_attr, 0)), (0))
#define PWM_GET_MEM_ATTR(inst) \
COND_CODE_1(DT_NODE_HAS_PROP(inst, memory_regions), \

Check notice on line 467 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:467 -#define PWM_MEM_REGION(inst) DT_PHANDLE(DT_DRV_INST(inst), memory_regions) - -#define PWM_MEMORY_SECTION(inst) \ +#define PWM_MEM_REGION(inst) DT_PHANDLE(DT_DRV_INST(inst), memory_regions) + +#define PWM_MEMORY_SECTION(inst) \ COND_CODE_1(DT_NODE_HAS_PROP(inst, memory_regions), \ (__attribute__((__section__(LINKER_DT_NODE_REGION_NAME( \ PWM_MEM_REGION(inst)))))), \ ()) -#define PWM_GET_MEM_ATTR(inst) \ +#define PWM_GET_MEM_ATTR(inst) \
(DT_PROP_OR(PWM_MEM_REGION(inst), zephyr_memory_attr, 0)), (0))

/* Fast instances depend on the global HSFLL clock controller (as they need
* to request the highest frequency from it to operate correctly), so they
Expand All @@ -470,66 +474,65 @@
*/
#if defined(CONFIG_CLOCK_CONTROL_NRF_HSFLL_GLOBAL_INIT_PRIORITY) && \
CONFIG_PWM_INIT_PRIORITY < CONFIG_CLOCK_CONTROL_NRF_HSFLL_GLOBAL_INIT_PRIORITY
#define PWM_INIT_PRIORITY(idx) \
COND_CODE_1(PWM_NRFX_IS_FAST(idx), \
#define PWM_INIT_PRIORITY(inst) \
COND_CODE_1(PWM_NRFX_IS_FAST(inst), \

Check notice on line 478 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:478 -#define PWM_INIT_PRIORITY(inst) \ +#define PWM_INIT_PRIORITY(inst) \
(UTIL_INC(CONFIG_CLOCK_CONTROL_NRF_HSFLL_GLOBAL_INIT_PRIORITY)), \
(CONFIG_PWM_INIT_PRIORITY))
#else
#define PWM_INIT_PRIORITY(idx) CONFIG_PWM_INIT_PRIORITY
#define PWM_INIT_PRIORITY(inst) CONFIG_PWM_INIT_PRIORITY
#endif

#define PWM_NRFX_DEVICE(idx) \
NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(PWM(idx)); \
NRF_DT_CHECK_NODE_HAS_REQUIRED_MEMORY_REGIONS(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(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 COND_PWM_NRFX_DEVICE(unused, prefix, i, _) \
IF_ENABLED(CONFIG_HAS_HW_NRF_PWM##prefix##i, (PWM_NRFX_DEVICE(prefix##i);))

NRFX_FOREACH_PRESENT(PWM, COND_PWM_NRFX_DEVICE, (), (), _)
#define PWM_NRFX_DEFINE(inst) \
NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(DT_DRV_INST(inst)); \
NRF_DT_CHECK_NODE_HAS_REQUIRED_MEMORY_REGIONS(DT_DRV_INST(inst)); \
static struct pwm_nrfx_data pwm_nrfx_##inst##_data = { \
.pwm = NRFX_PWM_INSTANCE(DT_INST_REG_ADDR(inst)), \
}; \
static uint16_t pwm_##inst##_seq_values[NRF_PWM_CHANNEL_COUNT] \
PWM_MEMORY_SECTION(inst); \
PINCTRL_DT_INST_DEFINE(inst); \
static const struct pwm_nrfx_config pwm_nrfx_##inst##_config = { \
.initial_config = { \
.skip_gpio_cfg = true, \
.skip_psel_cfg = true, \
.base_clock = NRF_PWM_CLK_1MHz, \
.count_mode = (DT_INST_PROP(inst, 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_##inst##_seq_values, \
.seq.length = NRF_PWM_CHANNEL_COUNT, \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
.clock_freq = COND_CODE_1(DT_INST_CLOCKS_HAS_IDX(inst, 0), \
(DT_PROP(DT_INST_CLOCKS_CTLR(inst), clock_frequency)), \
(16ul * 1000ul * 1000ul)), \
IF_ENABLED(CONFIG_DCACHE, \
(.mem_attr = PWM_GET_MEM_ATTR(inst),)) \
IF_ENABLED(PWM_NRFX_USE_CLOCK_CONTROL, \
(.clk_dev = PWM_NRFX_IS_FAST(inst) \
? DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)) \
: NULL, \
.clk_spec = { \
.frequency = \
NRF_PERIPH_GET_FREQUENCY(DT_DRV_INST(inst)), \
},)) \
}; \
static int pwm_nrfx_init##inst(const struct device *dev) \
{ \
IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), \
nrfx_pwm_irq_handler, &pwm_nrfx_##inst##_data.pwm, 0); \
return pwm_nrfx_init(dev); \
}; \
PM_DEVICE_DT_INST_DEFINE(inst, pwm_nrfx_pm_action); \
DEVICE_DT_INST_DEINIT_DEFINE(inst, \
pwm_nrfx_init##inst, NULL, \
PM_DEVICE_DT_INST_GET(inst), \
&pwm_nrfx_##inst##_data, \
&pwm_nrfx_##inst##_config, \
POST_KERNEL, PWM_INIT_PRIORITY(inst), \
&pwm_nrfx_drv_api_funcs)

Check notice on line 536 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:536 -#define PWM_NRFX_DEFINE(inst) \ - NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(DT_DRV_INST(inst)); \ - NRF_DT_CHECK_NODE_HAS_REQUIRED_MEMORY_REGIONS(DT_DRV_INST(inst)); \ - static struct pwm_nrfx_data pwm_nrfx_##inst##_data = { \ - .pwm = NRFX_PWM_INSTANCE(DT_INST_REG_ADDR(inst)), \ - }; \ - static uint16_t pwm_##inst##_seq_values[NRF_PWM_CHANNEL_COUNT] \ - PWM_MEMORY_SECTION(inst); \ - PINCTRL_DT_INST_DEFINE(inst); \ - static const struct pwm_nrfx_config pwm_nrfx_##inst##_config = { \ - .initial_config = { \ - .skip_gpio_cfg = true, \ - .skip_psel_cfg = true, \ - .base_clock = NRF_PWM_CLK_1MHz, \ - .count_mode = (DT_INST_PROP(inst, 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_##inst##_seq_values, \ - .seq.length = NRF_PWM_CHANNEL_COUNT, \ - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ +#define PWM_NRFX_DEFINE(inst) \ + NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(DT_DRV_INST(inst)); \ + NRF_DT_CHECK_NODE_HAS_REQUIRED_MEMORY_REGIONS(DT_DRV_INST(inst)); \ + static struct pwm_nrfx_data pwm_nrfx_##inst##_data = { \ + .pwm = NRFX_PWM_INSTANCE(DT_INST_REG_ADDR(inst)), \ + }; \ + static uint16_t pwm_##inst##_seq_values[NRF_PWM_CHANNEL_COUNT] PWM_MEMORY_SECTION(inst); \ + PINCTRL_DT_INST_DEFINE(inst); \ + static const struct pwm_nrfx_config pwm_nrfx_##inst##_config = { \ + .initial_config = \ + { \ + .skip_gpio_cfg = true, \ + .skip_psel_cfg = true, \ + .base_clock = NRF_PWM_CLK_1MHz, \ + .count_mode = (DT_INST_PROP(inst, 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_##inst##_seq_values, \ + .seq.length = NRF_PWM_CHANNEL_COUNT, \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ .clock_freq = COND_CODE_1(DT_INST_CLOCKS_HAS_IDX(inst, 0), \ (DT_PROP(DT_INST_CLOCKS_CTLR(inst), clock_frequency)), \ - (16ul * 1000ul * 1000ul)), \ - IF_ENABLED(CONFIG_DCACHE, \ - (.mem_attr = PWM_GET_MEM_ATTR(inst),)) \ - IF_ENABLED(PWM_NRFX_USE_CLOCK_CONTROL, \ + (16ul * 1000ul * 1000ul)), \ + IF_ENABLED(CONFIG_DCACHE, \ + (.mem_attr = PWM_GET_MEM_ATTR(inst),)) \ + IF_ENABLED(PWM_NRFX_USE_CLOCK_CONTROL, \ (.clk_dev = PWM_NRFX_IS_FAST(inst) \ ? DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)) \ : NULL, \ .clk_spec = { \ .frequency = \ NRF_PERIPH_GET_FREQUENCY(DT_DRV_INST(inst)), \ - },)) \ - };

DT_INST_FOREACH_STATUS_OKAY(PWM_NRFX_DEFINE)
Loading
Loading