Skip to content

Commit 2a7a86f

Browse files
committed
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]>
1 parent 35bd19f commit 2a7a86f

File tree

1 file changed

+46
-46
lines changed

1 file changed

+46
-46
lines changed

drivers/serial/uart_nrfx_uarte.c

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,13 @@ struct uarte_nrfx_config {
340340
uint8_t *poll_in_byte;
341341
};
342342

343+
/* Using Macro instead of static inline function to handle NO_OPTIMIZATIONS case
344+
* where static inline fails on linking.
345+
*/
346+
#define HW_RX_COUNTING_ENABLED(config) \
347+
(IS_ENABLED(UARTE_ANY_HW_ASYNC) ? \
348+
(config->flags & UARTE_CFG_FLAG_HW_BYTE_COUNTING) : false)
349+
343350
static inline NRF_UARTE_Type *get_uarte_instance(const struct device *dev)
344351
{
345352
const struct uarte_nrfx_config *config = dev->config;
@@ -362,6 +369,44 @@ static void endtx_isr(const struct device *dev)
362369

363370
}
364371

372+
/** @brief Disable UARTE peripheral is not used by RX or TX.
373+
*
374+
* It must be called with interrupts locked so that deciding if no direction is
375+
* using the UARTE is atomically performed with UARTE peripheral disabling. Otherwise
376+
* it would be possible that after clearing flags we get preempted and UARTE is
377+
* enabled from the higher priority context and when we come back UARTE is disabled
378+
* here.
379+
* @param dev Device.
380+
* @param dis_mask Mask of direction (RX or TX) which now longer uses the UARTE instance.
381+
*/
382+
static void uarte_disable_locked(const struct device *dev, uint32_t dis_mask)
383+
{
384+
struct uarte_nrfx_data *data = dev->data;
385+
386+
data->flags &= ~dis_mask;
387+
if (data->flags & UARTE_FLAG_LOW_POWER) {
388+
return;
389+
}
390+
391+
#if defined(UARTE_ANY_ASYNC) && !defined(CONFIG_UART_NRFX_UARTE_ENHANCED_RX)
392+
const struct uarte_nrfx_config *config = dev->config;
393+
394+
if (data->async && HW_RX_COUNTING_ENABLED(config)) {
395+
nrfx_timer_disable(&config->timer);
396+
/* Timer/counter value is reset when disabled. */
397+
data->async->rx.total_byte_cnt = 0;
398+
data->async->rx.total_user_byte_cnt = 0;
399+
}
400+
#endif
401+
402+
#ifdef CONFIG_SOC_NRF54H20_GPD
403+
const struct uarte_nrfx_config *cfg = dev->config;
404+
405+
nrf_gpd_retain_pins_set(cfg->pcfg, true);
406+
#endif
407+
nrf_uarte_disable(get_uarte_instance(dev));
408+
}
409+
365410
#ifdef UARTE_ANY_NONE_ASYNC
366411
/**
367412
* @brief Interrupt service routine.
@@ -397,7 +442,7 @@ static void uarte_nrfx_isr_int(const void *arg)
397442
pm_device_runtime_put_async(dev, K_NO_WAIT);
398443
}
399444
} else {
400-
nrf_uarte_disable(uarte);
445+
uarte_disable_locked(dev, UARTE_FLAG_LOW_POWER_TX);
401446
}
402447
#ifdef UARTE_INTERRUPT_DRIVEN
403448
if (!data->int_driven)
@@ -617,13 +662,6 @@ static int wait_tx_ready(const struct device *dev)
617662
return key;
618663
}
619664

620-
/* Using Macro instead of static inline function to handle NO_OPTIMIZATIONS case
621-
* where static inline fails on linking.
622-
*/
623-
#define HW_RX_COUNTING_ENABLED(config) \
624-
(IS_ENABLED(UARTE_ANY_HW_ASYNC) ? \
625-
(config->flags & UARTE_CFG_FLAG_HW_BYTE_COUNTING) : false)
626-
627665
static void uarte_periph_enable(const struct device *dev)
628666
{
629667
NRF_UARTE_Type *uarte = get_uarte_instance(dev);
@@ -726,44 +764,6 @@ static void tx_start(const struct device *dev, const uint8_t *buf, size_t len)
726764
}
727765

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

0 commit comments

Comments
 (0)