12
12
#include <zephyr/drivers/uart.h>
13
13
#include <zephyr/drivers/pinctrl.h>
14
14
#include <zephyr/irq.h>
15
+ #include <zephyr/pm/device.h>
16
+ #include <zephyr/pm/device_runtime.h>
17
+ #include <zephyr/pm/policy.h>
18
+ #include <zephyr/sys/atomic.h>
15
19
16
20
#include <errno.h>
17
21
@@ -52,6 +56,12 @@ struct uart_cc23x0_config {
52
56
#endif
53
57
};
54
58
59
+ enum uart_cc23x0_pm_locks {
60
+ UART_CC23X0_PM_LOCK_TX ,
61
+ UART_CC23X0_PM_LOCK_RX ,
62
+ UART_CC23X0_PM_LOCK_COUNT ,
63
+ };
64
+
55
65
struct uart_cc23x0_data {
56
66
struct uart_config uart_config ;
57
67
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
@@ -74,8 +84,33 @@ struct uart_cc23x0_data {
74
84
uint8_t * rx_next_buf ;
75
85
size_t rx_next_len ;
76
86
#endif /* CONFIG_UART_CC23X0_DMA_DRIVEN */
87
+ #ifdef CONFIG_PM
88
+ ATOMIC_DEFINE (pm_lock , UART_CC23X0_PM_LOCK_COUNT );
89
+ #endif
77
90
};
78
91
92
+ static inline void uart_cc23x0_pm_policy_state_lock_get (struct uart_cc23x0_data * data ,
93
+ enum uart_cc23x0_pm_locks pm_lock_type )
94
+ {
95
+ #ifdef CONFIG_PM_DEVICE
96
+ if (!atomic_test_and_set_bit (data -> pm_lock , pm_lock_type )) {
97
+ pm_policy_state_lock_get (PM_STATE_RUNTIME_IDLE , PM_ALL_SUBSTATES );
98
+ pm_policy_state_lock_get (PM_STATE_STANDBY , PM_ALL_SUBSTATES );
99
+ }
100
+ #endif
101
+ }
102
+
103
+ static inline void uart_cc23x0_pm_policy_state_lock_put (struct uart_cc23x0_data * data ,
104
+ enum uart_cc23x0_pm_locks pm_lock_type )
105
+ {
106
+ #ifdef CONFIG_PM_DEVICE
107
+ if (atomic_test_and_clear_bit (data -> pm_lock , pm_lock_type )) {
108
+ pm_policy_state_lock_put (PM_STATE_STANDBY , PM_ALL_SUBSTATES );
109
+ pm_policy_state_lock_put (PM_STATE_RUNTIME_IDLE , PM_ALL_SUBSTATES );
110
+ }
111
+ #endif
112
+ }
113
+
79
114
static int uart_cc23x0_poll_in (const struct device * dev , unsigned char * c )
80
115
{
81
116
const struct uart_cc23x0_config * config = dev -> config ;
@@ -94,6 +129,14 @@ static void uart_cc23x0_poll_out(const struct device *dev, unsigned char c)
94
129
const struct uart_cc23x0_config * config = dev -> config ;
95
130
96
131
UARTPutChar (config -> reg , c );
132
+
133
+ #ifdef CONFIG_PM_DEVICE
134
+ /* Wait for character to be transmitted to ensure CPU
135
+ * does not enter standby when UART is busy
136
+ */
137
+ while (UARTBusy (config -> reg )) {
138
+ }
139
+ #endif
97
140
}
98
141
99
142
static int uart_cc23x0_err_check (const struct device * dev )
@@ -254,6 +297,11 @@ static void uart_cc23x0_irq_tx_enable(const struct device *dev)
254
297
{
255
298
const struct uart_cc23x0_config * config = dev -> config ;
256
299
300
+ /* When TX IRQ is enabled, it is implicit that we are expecting to transmit
301
+ * using the UART, hence we should no longer go into standby
302
+ */
303
+ uart_cc23x0_pm_policy_state_lock_get (dev -> data , UART_CC23X0_PM_LOCK_TX );
304
+
257
305
UARTEnableInt (config -> reg , UART_INT_TX );
258
306
}
259
307
@@ -262,6 +310,8 @@ static void uart_cc23x0_irq_tx_disable(const struct device *dev)
262
310
const struct uart_cc23x0_config * config = dev -> config ;
263
311
264
312
UARTDisableInt (config -> reg , UART_INT_TX );
313
+
314
+ uart_cc23x0_pm_policy_state_lock_put (dev -> data , UART_CC23X0_PM_LOCK_TX );
265
315
}
266
316
267
317
static int uart_cc23x0_irq_tx_ready (const struct device * dev )
@@ -275,6 +325,11 @@ static void uart_cc23x0_irq_rx_enable(const struct device *dev)
275
325
{
276
326
const struct uart_cc23x0_config * config = dev -> config ;
277
327
328
+ /* When RX IRQ is enabled, it is implicit that we are expecting to receive
329
+ * from the UART, hence we can no longer go into standby
330
+ */
331
+ uart_cc23x0_pm_policy_state_lock_get (dev -> data , UART_CC23X0_PM_LOCK_RX );
332
+
278
333
/* Trigger the ISR on both RX and Receive Timeout. This is to allow
279
334
* the use of the hardware FIFOs for more efficient operation
280
335
*/
@@ -286,6 +341,8 @@ static void uart_cc23x0_irq_rx_disable(const struct device *dev)
286
341
const struct uart_cc23x0_config * config = dev -> config ;
287
342
288
343
UARTDisableInt (config -> reg , UART_INT_RX | UART_INT_RT );
344
+
345
+ uart_cc23x0_pm_policy_state_lock_put (dev -> data , UART_CC23X0_PM_LOCK_RX );
289
346
}
290
347
291
348
static int uart_cc23x0_irq_tx_complete (const struct device * dev )
@@ -401,6 +458,12 @@ static int uart_cc23x0_async_tx(const struct device *dev, const uint8_t *buf, si
401
458
402
459
irq_unlock (key );
403
460
461
+ /* Resume DMA (TX) */
462
+ ret = pm_device_runtime_get (config -> dma_dev );
463
+ if (ret ) {
464
+ return ret ;
465
+ }
466
+
404
467
ret = dma_config (config -> dma_dev , config -> dma_channel_tx , & dma_cfg_tx );
405
468
if (ret ) {
406
469
return ret ;
@@ -420,6 +483,9 @@ static int uart_cc23x0_async_tx(const struct device *dev, const uint8_t *buf, si
420
483
return ret ;
421
484
}
422
485
486
+ /* Lock PM */
487
+ uart_cc23x0_pm_policy_state_lock_get (data , UART_CC23X0_PM_LOCK_TX );
488
+
423
489
/* Enable DMA trigger to start the transfer */
424
490
UARTEnableDMA (config -> reg , UART_DMA_TX );
425
491
@@ -433,6 +499,7 @@ static int uart_cc23x0_tx_halt(struct uart_cc23x0_data *data)
433
499
struct uart_event evt ;
434
500
size_t total_len ;
435
501
unsigned int key ;
502
+ int ret ;
436
503
437
504
key = irq_lock ();
438
505
@@ -457,6 +524,15 @@ static int uart_cc23x0_tx_halt(struct uart_cc23x0_data *data)
457
524
if (data -> async_callback ) {
458
525
data -> async_callback (data -> dev , & evt , data -> async_user_data );
459
526
}
527
+
528
+ /* Unlock PM */
529
+ uart_cc23x0_pm_policy_state_lock_put (data , UART_CC23X0_PM_LOCK_TX );
530
+
531
+ /* Suspend DMA (TX) */
532
+ ret = pm_device_runtime_put (config -> dma_dev );
533
+ if (ret ) {
534
+ return ret ;
535
+ }
460
536
} else {
461
537
return - EINVAL ;
462
538
}
@@ -522,6 +598,12 @@ static int uart_cc23x0_async_rx_enable(const struct device *dev, uint8_t *buf, s
522
598
goto unlock ;
523
599
}
524
600
601
+ /* Resume DMA (RX) */
602
+ ret = pm_device_runtime_get (config -> dma_dev );
603
+ if (ret ) {
604
+ goto unlock ;
605
+ }
606
+
525
607
ret = dma_config (config -> dma_dev , config -> dma_channel_rx , & dma_cfg_rx );
526
608
if (ret ) {
527
609
goto unlock ;
@@ -536,6 +618,9 @@ static int uart_cc23x0_async_rx_enable(const struct device *dev, uint8_t *buf, s
536
618
goto unlock ;
537
619
}
538
620
621
+ /* Lock PM */
622
+ uart_cc23x0_pm_policy_state_lock_get (data , UART_CC23X0_PM_LOCK_RX );
623
+
539
624
/* Enable DMA trigger to start the transfer */
540
625
UARTEnableDMA (config -> reg , UART_DMA_RX );
541
626
@@ -621,13 +706,22 @@ static int uart_cc23x0_async_rx_disable(const struct device *dev)
621
706
622
707
dma_stop (config -> dma_dev , config -> dma_channel_rx );
623
708
709
+ /* Unlock PM */
710
+ uart_cc23x0_pm_policy_state_lock_put (data , UART_CC23X0_PM_LOCK_RX );
711
+
624
712
if (dma_get_status (config -> dma_dev , config -> dma_channel_rx , & status ) == 0 &&
625
713
status .pending_length ) {
626
714
rx_processed = data -> rx_len - status .pending_length ;
627
715
628
716
uart_cc23x0_notify_rx_processed (data , rx_processed );
629
717
}
630
718
719
+ /* Suspend DMA (RX) */
720
+ ret = pm_device_runtime_put (config -> dma_dev );
721
+ if (ret ) {
722
+ goto unlock ;
723
+ }
724
+
631
725
if (data -> async_callback ) {
632
726
evt .type = UART_RX_BUF_RELEASED ;
633
727
evt .data .rx_buf .buf = data -> rx_buf ;
@@ -704,6 +798,12 @@ static void uart_cc23x0_isr(const struct device *dev)
704
798
data -> tx_buf = NULL ;
705
799
data -> tx_len = 0 ;
706
800
801
+ /* Unlock PM */
802
+ uart_cc23x0_pm_policy_state_lock_put (data , UART_CC23X0_PM_LOCK_TX );
803
+
804
+ /* Suspend DMA (TX) */
805
+ pm_device_runtime_put (config -> dma_dev );
806
+
707
807
irq_unlock (key );
708
808
709
809
UARTClearInt (config -> reg , UART_INT_TXDMADONE );
@@ -731,6 +831,12 @@ static void uart_cc23x0_isr(const struct device *dev)
731
831
732
832
data -> async_callback (dev , & evt , data -> async_user_data );
733
833
}
834
+
835
+ /* Unlock PM */
836
+ uart_cc23x0_pm_policy_state_lock_put (data , UART_CC23X0_PM_LOCK_RX );
837
+
838
+ /* Suspend DMA (RX) */
839
+ pm_device_runtime_put (config -> dma_dev );
734
840
} else {
735
841
/* Otherwise, load next buffer and start the transfer */
736
842
data -> rx_buf = data -> rx_next_buf ;
@@ -798,8 +904,6 @@ static DEVICE_API(uart, uart_cc23x0_driver_api) = {
798
904
799
905
#if CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_CC23X0_DMA_DRIVEN
800
906
#define UART_CC23X0_IRQ_CFG (n ) \
801
- const struct uart_cc23x0_config *config = dev->config; \
802
- \
803
907
do { \
804
908
UARTClearInt(config->reg, UART_INT_RX); \
805
909
UARTClearInt(config->reg, UART_INT_RT); \
@@ -832,57 +936,91 @@ static DEVICE_API(uart, uart_cc23x0_driver_api) = {
832
936
833
937
static int uart_cc23x0_init_common (const struct device * dev )
834
938
{
939
+ #ifdef CONFIG_UART_CC23X0_DMA_DRIVEN
835
940
const struct uart_cc23x0_config * config = dev -> config ;
836
- struct uart_cc23x0_data * data = dev -> data ;
837
941
int ret ;
942
+ #endif
943
+ struct uart_cc23x0_data * data = dev -> data ;
838
944
839
945
CLKCTLEnable (CLKCTL_BASE , CLKCTL_UART0 );
840
946
841
- ret = pinctrl_apply_state (config -> pcfg , PINCTRL_STATE_DEFAULT );
842
- if (ret < 0 ) {
843
- return ret ;
844
- }
845
-
846
947
#ifdef CONFIG_UART_CC23X0_DMA_DRIVEN
847
948
if (!device_is_ready (config -> dma_dev )) {
848
949
return - ENODEV ;
849
950
}
850
951
952
+ ret = pm_device_runtime_enable (config -> dma_dev );
953
+ if (ret ) {
954
+ return ret ;
955
+ }
956
+
851
957
UARTEnableInt (config -> reg , UART_INT_TXDMADONE | UART_INT_RXDMADONE );
852
958
853
959
k_work_init_delayable (& data -> tx_timeout_work , uart_cc23x0_async_tx_timeout );
854
960
855
961
data -> dev = dev ;
856
962
#endif
857
963
964
+ #ifdef CONFIG_PM_DEVICE
965
+ atomic_clear_bit (data -> pm_lock , UART_CC23X0_PM_LOCK_RX );
966
+ atomic_clear_bit (data -> pm_lock , UART_CC23X0_PM_LOCK_TX );
967
+ #endif
968
+
858
969
/* Configure and enable UART */
859
970
return uart_cc23x0_configure (dev , & data -> uart_config );
860
971
}
861
972
973
+ #ifdef CONFIG_PM_DEVICE
974
+
975
+ static int uart_cc23x0_pm_action (const struct device * dev , enum pm_device_action action )
976
+ {
977
+ const struct uart_cc23x0_config * config = dev -> config ;
978
+
979
+ switch (action ) {
980
+ case PM_DEVICE_ACTION_SUSPEND :
981
+ UARTDisable (config -> reg );
982
+ CLKCTLDisable (CLKCTL_BASE , CLKCTL_UART0 );
983
+ return 0 ;
984
+ case PM_DEVICE_ACTION_RESUME :
985
+ return uart_cc23x0_init_common (dev );
986
+ default :
987
+ return - ENOTSUP ;
988
+ }
989
+ }
990
+
991
+ #endif /* CONFIG_PM_DEVICE */
992
+
862
993
#define UART_CC23X0_DEVICE_DEFINE (n ) \
863
994
\
864
- DEVICE_DT_INST_DEFINE(n, uart_cc23x0_init_##n, NULL, &uart_cc23x0_data_##n, \
865
- &uart_cc23x0_config_ ##n, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
866
- &uart_cc23x0_driver_api)
995
+ DEVICE_DT_INST_DEFINE(n, uart_cc23x0_init_##n, PM_DEVICE_DT_INST_GET(n), \
996
+ &uart_cc23x0_data_ ##n, &uart_cc23x0_config_##n, \
997
+ PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_cc23x0_driver_api)
867
998
868
999
#define UART_CC23X0_INIT_FUNC (n ) \
869
1000
static int uart_cc23x0_init_##n(const struct device *dev) \
870
1001
{ \
1002
+ const struct uart_cc23x0_config *config = dev->config; \
871
1003
int ret; \
872
1004
\
1005
+ ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); \
1006
+ if (ret) { \
1007
+ return ret; \
1008
+ } \
1009
+ \
873
1010
ret = uart_cc23x0_init_common(dev); \
874
- if (ret < 0 ) { \
1011
+ if (ret) { \
875
1012
return ret; \
876
1013
} \
877
1014
\
878
1015
/* Enable interrupts */ \
879
1016
UART_CC23X0_IRQ_CFG (n ); \
880
1017
\
881
- return ret ; \
1018
+ return 0 ; \
882
1019
}
883
1020
884
1021
#define UART_CC23X0_INIT (n ) \
885
1022
PINCTRL_DT_INST_DEFINE(n); \
1023
+ PM_DEVICE_DT_INST_DEFINE(n, uart_cc23x0_pm_action); \
886
1024
UART_CC23X0_INIT_FUNC(n); \
887
1025
\
888
1026
static struct uart_cc23x0_config uart_cc23x0_config_##n = { \
0 commit comments