Skip to content

Commit f500ca1

Browse files
committed
[nrf fromtree] drivers: serial: nrfx_uarte: Fix low power mode for interrupt driven API
Low power mode for non-asynchronous API case is only available when RX is not used (RX pin is not defined). In that case TX starting function was using uarte_enable_locked() which tracks if UARTE is used by TX or RX and TXSTOPPED interrupt was disabling UARTE unconditionally. Because of that following attempt to TX start was assuming that UARTE is already enabled when it was disabled. Fixing it by using uarte_disable_locked function in TXSTOPPED handling. Code reordering was required to make uarte_disable_locked() available earlier. Signed-off-by: Krzysztof Chruściński <[email protected]> (cherry picked from commit 1952679)
1 parent d0bef36 commit f500ca1

File tree

2 files changed

+51
-48
lines changed

2 files changed

+51
-48
lines changed

drivers/serial/uart_nrfx_uarte.c

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,13 @@ struct uarte_nrfx_config {
333333
uint8_t *poll_in_byte;
334334
};
335335

336+
/* Using Macro instead of static inline function to handle NO_OPTIMIZATIONS case
337+
* where static inline fails on linking.
338+
*/
339+
#define HW_RX_COUNTING_ENABLED(config) \
340+
(IS_ENABLED(UARTE_ANY_HW_ASYNC) ? \
341+
(config->flags & UARTE_CFG_FLAG_HW_BYTE_COUNTING) : false)
342+
336343
static inline NRF_UARTE_Type *get_uarte_instance(const struct device *dev)
337344
{
338345
const struct uarte_nrfx_config *config = dev->config;
@@ -355,6 +362,44 @@ static void endtx_isr(const struct device *dev)
355362

356363
}
357364

365+
/** @brief Disable UARTE peripheral is not used by RX or TX.
366+
*
367+
* It must be called with interrupts locked so that deciding if no direction is
368+
* using the UARTE is atomically performed with UARTE peripheral disabling. Otherwise
369+
* it would be possible that after clearing flags we get preempted and UARTE is
370+
* enabled from the higher priority context and when we come back UARTE is disabled
371+
* here.
372+
* @param dev Device.
373+
* @param dis_mask Mask of direction (RX or TX) which now longer uses the UARTE instance.
374+
*/
375+
static void uarte_disable_locked(const struct device *dev, uint32_t dis_mask)
376+
{
377+
struct uarte_nrfx_data *data = dev->data;
378+
379+
data->flags &= ~dis_mask;
380+
if (data->flags & UARTE_FLAG_LOW_POWER) {
381+
return;
382+
}
383+
384+
#if defined(UARTE_ANY_ASYNC) && !defined(CONFIG_UART_NRFX_UARTE_ENHANCED_RX)
385+
const struct uarte_nrfx_config *config = dev->config;
386+
387+
if (data->async && HW_RX_COUNTING_ENABLED(config)) {
388+
nrfx_timer_disable(&config->timer);
389+
/* Timer/counter value is reset when disabled. */
390+
data->async->rx.total_byte_cnt = 0;
391+
data->async->rx.total_user_byte_cnt = 0;
392+
}
393+
#endif
394+
395+
#ifdef CONFIG_SOC_NRF54H20_GPD
396+
const struct uarte_nrfx_config *cfg = dev->config;
397+
398+
nrf_gpd_retain_pins_set(cfg->pcfg, true);
399+
#endif
400+
nrf_uarte_disable(get_uarte_instance(dev));
401+
}
402+
358403
#ifdef UARTE_ANY_NONE_ASYNC
359404
/**
360405
* @brief Interrupt service routine.
@@ -390,7 +435,7 @@ static void uarte_nrfx_isr_int(const void *arg)
390435
pm_device_runtime_put_async(dev, K_NO_WAIT);
391436
}
392437
} else {
393-
nrf_uarte_disable(uarte);
438+
uarte_disable_locked(dev, UARTE_FLAG_LOW_POWER_TX);
394439
}
395440
#ifdef UARTE_INTERRUPT_DRIVEN
396441
if (!data->int_driven)
@@ -610,13 +655,6 @@ static int wait_tx_ready(const struct device *dev)
610655
return key;
611656
}
612657

613-
/* Using Macro instead of static inline function to handle NO_OPTIMIZATIONS case
614-
* where static inline fails on linking.
615-
*/
616-
#define HW_RX_COUNTING_ENABLED(config) \
617-
(IS_ENABLED(UARTE_ANY_HW_ASYNC) ? \
618-
(config->flags & UARTE_CFG_FLAG_HW_BYTE_COUNTING) : false)
619-
620658
static void uarte_periph_enable(const struct device *dev)
621659
{
622660
NRF_UARTE_Type *uarte = get_uarte_instance(dev);
@@ -719,44 +757,6 @@ static void tx_start(const struct device *dev, const uint8_t *buf, size_t len)
719757
}
720758

721759
#if defined(UARTE_ANY_ASYNC)
722-
/** @brief Disable UARTE peripheral is not used by RX or TX.
723-
*
724-
* It must be called with interrupts locked so that deciding if no direction is
725-
* using the UARTE is atomically performed with UARTE peripheral disabling. Otherwise
726-
* it would be possible that after clearing flags we get preempted and UARTE is
727-
* enabled from the higher priority context and when we come back UARTE is disabled
728-
* here.
729-
* @param dev Device.
730-
* @param dis_mask Mask of direction (RX or TX) which now longer uses the UARTE instance.
731-
*/
732-
static void uarte_disable_locked(const struct device *dev, uint32_t dis_mask)
733-
{
734-
struct uarte_nrfx_data *data = dev->data;
735-
736-
data->flags &= ~dis_mask;
737-
if (data->flags & UARTE_FLAG_LOW_POWER) {
738-
return;
739-
}
740-
741-
#if !defined(CONFIG_UART_NRFX_UARTE_ENHANCED_RX)
742-
const struct uarte_nrfx_config *config = dev->config;
743-
744-
if (data->async && HW_RX_COUNTING_ENABLED(config)) {
745-
nrfx_timer_disable(&config->timer);
746-
/* Timer/counter value is reset when disabled. */
747-
data->async->rx.total_byte_cnt = 0;
748-
data->async->rx.total_user_byte_cnt = 0;
749-
}
750-
#endif
751-
752-
#ifdef CONFIG_SOC_NRF54H20_GPD
753-
const struct uarte_nrfx_config *cfg = dev->config;
754-
755-
nrf_gpd_retain_pins_set(cfg->pcfg, true);
756-
#endif
757-
nrf_uarte_disable(get_uarte_instance(dev));
758-
}
759-
760760
static void rx_timeout(struct k_timer *timer);
761761
static void tx_timeout(struct k_timer *timer);
762762

samples/subsys/shell/shell_module/src/main.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,17 +427,20 @@ SHELL_SUBCMD_ADD((section_cmd), cmd1, &sub_section_cmd1, "help for cmd1", cmd1_h
427427
SHELL_CMD_REGISTER(section_cmd, &sub_section_cmd,
428428
"Demo command using section for subcommand registration", NULL);
429429

430+
#include <zephyr/pm/device.h>
431+
#include <zephyr/pm/device_runtime.h>
430432
int main(void)
431433
{
432434
if (IS_ENABLED(CONFIG_SHELL_START_OBSCURED)) {
433435
login_init();
434436
}
435437

436-
#if DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_shell_uart), zephyr_cdc_acm_uart)
437438
const struct device *dev;
439+
dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart));
440+
pm_device_runtime_get(dev);
441+
#if DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_shell_uart), zephyr_cdc_acm_uart)
438442
uint32_t dtr = 0;
439443

440-
dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart));
441444
if (!device_is_ready(dev) || usb_enable(NULL)) {
442445
return 0;
443446
}

0 commit comments

Comments
 (0)