From e7a075f4606e410ab3d0aae1152280029aba8ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 20 Apr 2022 09:00:00 +0200 Subject: [PATCH] drivers: pwm_nrfx: Add support for PWM_POLARITY_INVERTED flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for inverting of PWM channel outputs in the pwm_nrfx driver by properly handling the `PWM_POLARITY_INVERTED` flag. The dts properties that were used so far for inverting of the outputs ("nordic,invert" and "chX-inverted") are kept as they are needed for setting of the initial polarity, i.e. for setting the inactive state of the outputs before any PWM signal generation is requested for them. Signed-off-by: Andrzej Głąbek --- drivers/pwm/pwm_nrfx.c | 81 ++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/drivers/pwm/pwm_nrfx.c b/drivers/pwm/pwm_nrfx.c index 43dce2e6452..522e9c8f90e 100644 --- a/drivers/pwm/pwm_nrfx.c +++ b/drivers/pwm/pwm_nrfx.c @@ -34,7 +34,7 @@ struct pwm_nrfx_data { uint16_t current[NRF_PWM_CHANNEL_COUNT]; uint16_t countertop; uint8_t prescaler; - uint8_t inverted_channels; + uint8_t initially_inverted; }; @@ -112,6 +112,15 @@ static bool any_other_channel_is_active(uint8_t channel, return false; } +static bool channel_psel_get(uint32_t channel, uint32_t *psel, + const struct pwm_nrfx_config *config) +{ + *psel = nrf_pwm_pin_get(config->pwm.p_registers, channel); + + return (((*psel & PWM_PSEL_OUT_CONNECT_Msk) >> PWM_PSEL_OUT_CONNECT_Pos) + == PWM_PSEL_OUT_CONNECT_Connected); +} + static int pwm_nrfx_pin_set(const struct device *dev, uint32_t pwm, uint32_t period_cycles, uint32_t pulse_cycles, pwm_flags_t flags) @@ -124,13 +133,9 @@ static int pwm_nrfx_pin_set(const struct device *dev, uint32_t pwm, const struct pwm_nrfx_config *config = dev->config; struct pwm_nrfx_data *data = dev->data; uint8_t channel = pwm; + bool inverted = (flags & PWM_POLARITY_INVERTED); bool was_stopped; - if (flags) { - /* PWM polarity not supported (yet?) */ - return -ENOTSUP; - } - if (channel >= NRF_PWM_CHANNEL_COUNT) { LOG_ERR("Invalid channel: %u.", channel); return -EINVAL; @@ -156,8 +161,7 @@ static int pwm_nrfx_pin_set(const struct device *dev, uint32_t pwm, /* Check if period_cycles is either matching currently used, or * possible to use with our prescaler options. * Don't do anything if the period length happens to be zero. - * In such case, pulse cycles will be right below limited to 0 - * and this will result in making the channel inactive. + * In such case, the channel is treated as inactive. */ if (period_cycles != 0 && period_cycles != data->period_cycles) { int ret = pwm_period_check_and_set(config, data, channel, @@ -167,10 +171,8 @@ static int pwm_nrfx_pin_set(const struct device *dev, uint32_t pwm, } } - /* Store new pulse value bit[14:0], and polarity bit[15] for channel. */ - data->current[channel] = ( - (data->current[channel] & PWM_NRFX_CH_POLARITY_MASK) - | (pulse_cycles >> data->prescaler)); + data->current[channel] = + PWM_NRFX_CH_VALUE(pulse_cycles >> data->prescaler, inverted); LOG_DBG("channel %u, pulse %u, period %u, prescaler: %u.", channel, pulse_cycles, period_cycles, data->prescaler); @@ -182,27 +184,22 @@ static int pwm_nrfx_pin_set(const struct device *dev, uint32_t pwm, * is disabled after all channels appear to be inactive. */ if (!pwm_channel_is_active(channel, data)) { - /* If pulse 0% and pin not inverted, set LOW. - * If pulse 100% and pin inverted, set LOW. - * If pulse 0% and pin inverted, set HIGH. - * If pulse 100% and pin not inverted, set HIGH. - */ - bool channel_inverted_state = - data->inverted_channels & BIT(channel); + uint32_t psel; - bool pulse_0_and_not_inverted = - (pulse_cycles == 0U) - && !channel_inverted_state; - bool pulse_100_and_inverted = - (pulse_cycles == period_cycles) - && channel_inverted_state; - uint32_t psel = - nrf_pwm_pin_get(config->pwm.p_registers, channel); + if (channel_psel_get(channel, &psel, config)) { + /* If pulse 0% and pin not inverted, set LOW. + * If pulse 100% and pin inverted, set LOW. + * If pulse 0% and pin inverted, set HIGH. + * If pulse 100% and pin not inverted, set HIGH. + */ + bool pulse_0_and_not_inverted = + (pulse_cycles == 0U) && !inverted; + bool pulse_100_and_inverted = + (pulse_cycles == period_cycles) && inverted; + uint32_t value = (pulse_0_and_not_inverted || + pulse_100_and_inverted) ? 0 : 1; - if (pulse_0_and_not_inverted || pulse_100_and_inverted) { - nrf_gpio_pin_clear(psel); - } else { - nrf_gpio_pin_set(psel); + nrf_gpio_pin_write(psel, value); } if (!any_other_channel_is_active(channel, data)) { @@ -259,23 +256,23 @@ static int pwm_nrfx_init(const struct device *dev) return ret; } - data->inverted_channels = 0; + data->initially_inverted = 0; for (size_t i = 0; i < ARRAY_SIZE(data->current); i++) { - uint32_t psel = nrf_pwm_pin_get(config->pwm.p_registers, i); - /* 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). - */ - if (((psel & PWM_PSEL_OUT_CONNECT_Msk) >> PWM_PSEL_OUT_CONNECT_Pos) - == PWM_PSEL_OUT_CONNECT_Connected) { - data->inverted_channels |= + uint32_t psel; + + if (channel_psel_get(i, &psel, config)) { + /* 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). + */ + data->initially_inverted |= nrf_gpio_pin_out_read(psel) ? BIT(i) : 0; } } #endif for (size_t i = 0; i < ARRAY_SIZE(data->current); i++) { - bool inverted = data->inverted_channels & BIT(i); + bool inverted = data->initially_inverted & BIT(i); data->current[i] = PWM_NRFX_CH_VALUE(0, inverted); } @@ -362,7 +359,7 @@ static int pwm_nrfx_pm_action(const struct device *dev, ch0_pin, ch1_pin, ch2_pin, ch3_pin); \ static struct pwm_nrfx_data pwm_nrfx_##idx##_data = { \ COND_CODE_1(CONFIG_PINCTRL, (), \ - (.inverted_channels = \ + (.initially_inverted = \ (PWM_CH_INVERTED(idx, 0) ? BIT(0) : 0) | \ (PWM_CH_INVERTED(idx, 1) ? BIT(1) : 0) | \ (PWM_CH_INVERTED(idx, 2) ? BIT(2) : 0) | \