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 <james.goppert@gmail.com>
Signed-off-by: Benjamin Perseghetti <bperseghetti@rudislabs.com>
This commit is contained in:
Benjamin Perseghetti 2024-05-10 19:12:15 -04:00 committed by Alberto Escolar
commit daaf06db94

View file

@ -12,6 +12,7 @@
#include <soc.h>
#include <fsl_pwm.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
@ -35,9 +36,10 @@ struct pwm_mcux_config {
struct pwm_mcux_data {
uint32_t period_cycles[CHANNEL_COUNT];
pwm_signal_param_t channel[CHANNEL_COUNT];
struct k_mutex lock;
};
static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel,
static int mcux_pwm_set_cycles_internal(const struct device *dev, uint32_t channel,
uint32_t period_cycles, uint32_t pulse_cycles,
pwm_flags_t flags)
{
@ -45,24 +47,6 @@ static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel,
struct pwm_mcux_data *data = dev->data;
pwm_level_select_t level;
if (channel >= CHANNEL_COUNT) {
LOG_ERR("Invalid channel");
return -EINVAL;
}
if (period_cycles == 0) {
LOG_ERR("Channel can not be set to inactive level");
return -ENOTSUP;
}
if (period_cycles > UINT16_MAX) {
/* 16-bit resolution */
LOG_ERR("Too long period (%u), adjust pwm prescaler!",
period_cycles);
/* TODO: dynamically adjust prescaler */
return -EINVAL;
}
if (flags & PWM_POLARITY_INVERTED) {
level = kPWM_LowTrue;
} else {
@ -158,6 +142,36 @@ static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel,
return 0;
}
static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel,
uint32_t period_cycles, uint32_t pulse_cycles,
pwm_flags_t flags)
{
struct pwm_mcux_data *data = dev->data;
int result;
if (channel >= CHANNEL_COUNT) {
LOG_ERR("Invalid channel");
return -EINVAL;
}
if (period_cycles == 0) {
LOG_ERR("Channel can not be set to inactive level");
return -ENOTSUP;
}
if (period_cycles > UINT16_MAX) {
/* 16-bit resolution */
LOG_ERR("Too long period (%u), adjust pwm prescaler!",
period_cycles);
/* TODO: dynamically adjust prescaler */
return -EINVAL;
}
k_mutex_lock(&data->lock, K_FOREVER);
result = mcux_pwm_set_cycles_internal(dev, channel, period_cycles, pulse_cycles, flags);
k_mutex_unlock(&data->lock);
return result;
}
static int mcux_pwm_get_cycles_per_sec(const struct device *dev,
uint32_t channel, uint64_t *cycles)
{
@ -181,6 +195,8 @@ static int pwm_mcux_init(const struct device *dev)
status_t status;
int i, err;
k_mutex_init(&data->lock);
if (!device_is_ready(config->clock_dev)) {
LOG_ERR("clock control device not ready");
return -ENODEV;