Skip to content

Commit

Permalink
[nrf fromlist] drivers: serial: nrfx_uarte: Add workaround for BAUDRA…
Browse files Browse the repository at this point in the history
…TE register

On uart120 BAUDRATE register is not retained when ENABLE=0 and
because of that BAUDRATE must be set after enabling. Add workaround
to the driver.

Upstream PR: zephyrproject-rtos/zephyr#75462

Signed-off-by: Krzysztof Chruściński <[email protected]>
  • Loading branch information
nordic-krch committed Oct 11, 2024
1 parent f014711 commit dbcbd87
Showing 1 changed file with 37 additions and 2 deletions.
39 changes: 37 additions & 2 deletions drivers/serial/uart_nrfx_uarte.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, 0);
#define UARTE_ANY_CACHE 1
#endif

#ifdef UARTE_ANY_CACHE
/* uart120 instance does not retain BAUDRATE register when ENABLE=0. When this instance
* is used then baudrate must be set after enabling the peripheral and not before.
* This approach works for all instances so can be generally applied when uart120 is used.
* It is not default for all because it costs some resources. Since currently only uart120
* needs cache, that is used to determine if workaround shall be applied.
*/
#define UARTE_BAUDRATE_RETENTION_WORKAROUND 1
#endif

/*
* RX timeout is divided into time slabs, this define tells how many divisions
* should be made. More divisions - higher timeout accuracy and processor usage.
Expand Down Expand Up @@ -187,6 +197,9 @@ struct uarte_nrfx_int_driven {
struct uarte_nrfx_data {
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
struct uart_config uart_config;
#ifdef UARTE_BAUDRATE_RETENTION_WORKAROUND
nrf_uarte_baudrate_t nrf_baudrate;
#endif
#endif
#ifdef UARTE_INTERRUPT_DRIVEN
struct uarte_nrfx_int_driven *int_driven;
Expand Down Expand Up @@ -387,7 +400,6 @@ static int baudrate_set(const struct device *dev, uint32_t baudrate)
const struct uarte_nrfx_config *config = dev->config;
/* calculated baudrate divisor */
nrf_uarte_baudrate_t nrf_baudrate = NRF_BAUDRATE(baudrate);
NRF_UARTE_Type *uarte = get_uarte_instance(dev);

if (nrf_baudrate == 0) {
return -EINVAL;
Expand All @@ -398,7 +410,15 @@ static int baudrate_set(const struct device *dev, uint32_t baudrate)
nrf_baudrate /= config->clock_freq / NRF_UARTE_BASE_FREQUENCY_16MHZ;
}

#ifdef UARTE_BAUDRATE_RETENTION_WORKAROUND
struct uarte_nrfx_data *data = dev->data;

data->nrf_baudrate = nrf_baudrate;
#else
NRF_UARTE_Type *uarte = get_uarte_instance(dev);

nrf_uarte_baudrate_set(uarte, nrf_baudrate);
#endif

return 0;
}
Expand Down Expand Up @@ -582,6 +602,13 @@ static void uarte_enable(const struct device *dev, uint32_t act_mask, uint32_t s
}
#endif
nrf_uarte_enable(get_uarte_instance(dev));
#if UARTE_BAUDRATE_RETENTION_WORKAROUND
nrf_uarte_baudrate_t baudrate = COND_CODE_1(CONFIG_UART_USE_RUNTIME_CONFIGURE,
(data->nrf_baudrate),
(((const struct uarte_nrfx_config *)dev->config)->nrf_baudrate));

nrf_uarte_baudrate_set(get_uarte_instance(dev), baudrate);
#endif
}

/* At this point we should have irq locked and any previous transfer completed.
Expand Down Expand Up @@ -2140,12 +2167,19 @@ static int uarte_nrfx_pm_action(const struct device *dev,

switch (action) {
case PM_DEVICE_ACTION_RESUME:
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
{
ret = pins_state_change(dev, true);
if (ret < 0) {
return ret;
}

nrf_uarte_enable(uarte);
#if UARTE_BAUDRATE_RETENTION_WORKAROUND
nrf_uarte_baudrate_t baudrate = COND_CODE_1(CONFIG_UART_USE_RUNTIME_CONFIGURE,
(data->nrf_baudrate), (cfg->nrf_baudrate));

nrf_uarte_baudrate_set(get_uarte_instance(dev), baudrate);
#endif

#ifdef UARTE_ANY_ASYNC
if (data->async) {
Expand All @@ -2169,6 +2203,7 @@ static int uarte_nrfx_pm_action(const struct device *dev,
#endif
}
break;
}
case PM_DEVICE_ACTION_SUSPEND:
/* Disabling UART requires stopping RX, but stop RX event is
* only sent after each RX if async UART API is used.
Expand Down

0 comments on commit dbcbd87

Please sign in to comment.