Skip to content

Commit daaf06d

Browse files
bperseghettijgoppert
authored andcommitted
drivers: pwm: pwm_mcux: make thread safe with mutex.
Fixes a bug where more than one thread trying to access different PWM devices can cause erroneous behavior. Co-authored-by: James Goppert <[email protected]> Signed-off-by: Benjamin Perseghetti <[email protected]>
1 parent c9649bd commit daaf06d

File tree

1 file changed

+35
-19
lines changed

1 file changed

+35
-19
lines changed

drivers/pwm/pwm_mcux.c

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <soc.h>
1313
#include <fsl_pwm.h>
1414
#include <zephyr/drivers/pinctrl.h>
15+
#include <zephyr/kernel.h>
1516

1617
#include <zephyr/logging/log.h>
1718

@@ -35,34 +36,17 @@ struct pwm_mcux_config {
3536
struct pwm_mcux_data {
3637
uint32_t period_cycles[CHANNEL_COUNT];
3738
pwm_signal_param_t channel[CHANNEL_COUNT];
39+
struct k_mutex lock;
3840
};
3941

40-
static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel,
42+
static int mcux_pwm_set_cycles_internal(const struct device *dev, uint32_t channel,
4143
uint32_t period_cycles, uint32_t pulse_cycles,
4244
pwm_flags_t flags)
4345
{
4446
const struct pwm_mcux_config *config = dev->config;
4547
struct pwm_mcux_data *data = dev->data;
4648
pwm_level_select_t level;
4749

48-
if (channel >= CHANNEL_COUNT) {
49-
LOG_ERR("Invalid channel");
50-
return -EINVAL;
51-
}
52-
53-
if (period_cycles == 0) {
54-
LOG_ERR("Channel can not be set to inactive level");
55-
return -ENOTSUP;
56-
}
57-
58-
if (period_cycles > UINT16_MAX) {
59-
/* 16-bit resolution */
60-
LOG_ERR("Too long period (%u), adjust pwm prescaler!",
61-
period_cycles);
62-
/* TODO: dynamically adjust prescaler */
63-
return -EINVAL;
64-
}
65-
6650
if (flags & PWM_POLARITY_INVERTED) {
6751
level = kPWM_LowTrue;
6852
} else {
@@ -158,6 +142,36 @@ static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel,
158142
return 0;
159143
}
160144

145+
static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel,
146+
uint32_t period_cycles, uint32_t pulse_cycles,
147+
pwm_flags_t flags)
148+
{
149+
struct pwm_mcux_data *data = dev->data;
150+
int result;
151+
152+
if (channel >= CHANNEL_COUNT) {
153+
LOG_ERR("Invalid channel");
154+
return -EINVAL;
155+
}
156+
157+
if (period_cycles == 0) {
158+
LOG_ERR("Channel can not be set to inactive level");
159+
return -ENOTSUP;
160+
}
161+
162+
if (period_cycles > UINT16_MAX) {
163+
/* 16-bit resolution */
164+
LOG_ERR("Too long period (%u), adjust pwm prescaler!",
165+
period_cycles);
166+
/* TODO: dynamically adjust prescaler */
167+
return -EINVAL;
168+
}
169+
k_mutex_lock(&data->lock, K_FOREVER);
170+
result = mcux_pwm_set_cycles_internal(dev, channel, period_cycles, pulse_cycles, flags);
171+
k_mutex_unlock(&data->lock);
172+
return result;
173+
}
174+
161175
static int mcux_pwm_get_cycles_per_sec(const struct device *dev,
162176
uint32_t channel, uint64_t *cycles)
163177
{
@@ -181,6 +195,8 @@ static int pwm_mcux_init(const struct device *dev)
181195
status_t status;
182196
int i, err;
183197

198+
k_mutex_init(&data->lock);
199+
184200
if (!device_is_ready(config->clock_dev)) {
185201
LOG_ERR("clock control device not ready");
186202
return -ENODEV;

0 commit comments

Comments
 (0)