23
23
#include "usb_phy.h"
24
24
25
25
#include <zephyr/logging/log.h>
26
+ #include <zephyr/pm/device.h>
27
+ #include <zephyr/pm/policy.h>
26
28
LOG_MODULE_REGISTER (udc_mcux , CONFIG_UDC_DRIVER_LOG_LEVEL );
27
29
28
30
/*
@@ -34,6 +36,7 @@ LOG_MODULE_REGISTER(udc_mcux, CONFIG_UDC_DRIVER_LOG_LEVEL);
34
36
35
37
#define PRV_DATA_HANDLE (_handle ) CONTAINER_OF(_handle, struct udc_mcux_data, mcux_device)
36
38
39
+
37
40
struct udc_mcux_config {
38
41
const usb_device_controller_interface_struct_t * mcux_if ;
39
42
void (* irq_enable_func )(const struct device * dev );
@@ -51,6 +54,8 @@ struct udc_mcux_data {
51
54
usb_device_struct_t mcux_device ;
52
55
struct k_work work ;
53
56
struct k_fifo fifo ;
57
+ bool enabled ;
58
+ bool vbus_present ;
54
59
uint8_t controller_id ; /* 0xFF is invalid value */
55
60
};
56
61
@@ -92,6 +97,50 @@ static int udc_mcux_control(const struct device *dev, usb_device_control_type_t
92
97
return 0 ;
93
98
}
94
99
100
+ /* Helper function to keep track of the activity state for the udc */
101
+ static void udc_mcux_change_state (const struct device * dev , bool enabled , bool vbus_present )
102
+ {
103
+ struct udc_mcux_data * data = udc_get_private (dev );
104
+
105
+ if (data -> enabled == enabled && data -> vbus_present == vbus_present ) {
106
+ return ;
107
+ }
108
+
109
+ if (vbus_present != data -> vbus_present && enabled ) {
110
+ udc_submit_event (data -> dev ,
111
+ vbus_present ? UDC_EVT_VBUS_READY : UDC_EVT_VBUS_REMOVED , 0 );
112
+ }
113
+ if (enabled && vbus_present ) {
114
+ data -> enabled = true;
115
+ data -> vbus_present = true;
116
+
117
+ /*
118
+ * Block PM when usb is active.
119
+ */
120
+ #if defined(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS )
121
+ pm_policy_device_power_lock_get (dev );
122
+ #endif
123
+ } else if (data -> enabled && data -> vbus_present ) {
124
+ /*
125
+ * USB was previously busy, but now has either lost
126
+ * VBUS signal or application has disabled udc.
127
+ */
128
+ data -> enabled = enabled ;
129
+ data -> vbus_present = vbus_present ;
130
+
131
+ /*
132
+ * UDC will now unblock PM
133
+ */
134
+ #if defined(CONFIG_PM_POLICY_DEVICE_CONSTRAINTS )
135
+ pm_policy_device_power_lock_put (dev );
136
+ #endif
137
+ } else {
138
+ /* USB still not activated, keep track of what's on and off */
139
+ data -> enabled = enabled ;
140
+ data -> vbus_present = vbus_present ;
141
+ }
142
+ }
143
+
95
144
/* If ep is busy, return busy. Otherwise feed the buf to controller */
96
145
static int udc_mcux_ep_feed (const struct device * dev ,
97
146
struct udc_ep_config * const cfg ,
@@ -525,10 +574,10 @@ usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg)
525
574
case kUSB_DeviceNotifyLPMSleep :
526
575
break ;
527
576
case kUSB_DeviceNotifyDetach :
528
- udc_submit_event (dev , UDC_EVT_VBUS_REMOVED , 0 );
577
+ udc_mcux_change_state (dev , priv -> enabled , 0 );
529
578
break ;
530
579
case kUSB_DeviceNotifyAttach :
531
- udc_submit_event (dev , UDC_EVT_VBUS_READY , 0 );
580
+ udc_mcux_change_state (dev , priv -> enabled , 1 );
532
581
break ;
533
582
case kUSB_DeviceNotifySOF :
534
583
udc_submit_event (dev , UDC_EVT_SOF , 0 );
@@ -676,11 +725,19 @@ static int udc_mcux_set_address(const struct device *dev, const uint8_t addr)
676
725
677
726
static int udc_mcux_enable (const struct device * dev )
678
727
{
728
+ struct udc_mcux_data * priv = udc_get_private (dev );
729
+
730
+ udc_mcux_change_state (dev , 1 , priv -> vbus_present );
731
+
679
732
return udc_mcux_control (dev , kUSB_DeviceControlRun , NULL );
680
733
}
681
734
682
735
static int udc_mcux_disable (const struct device * dev )
683
736
{
737
+ struct udc_mcux_data * priv = udc_get_private (dev );
738
+
739
+ udc_mcux_change_state (dev , 0 , priv -> vbus_present );
740
+
684
741
return udc_mcux_control (dev , kUSB_DeviceControlStop , NULL );
685
742
}
686
743
@@ -759,7 +816,9 @@ static inline void udc_mcux_get_hal_driver_id(struct udc_mcux_data *priv,
759
816
}
760
817
}
761
818
762
- static int udc_mcux_driver_preinit (const struct device * dev )
819
+
820
+
821
+ static int udc_mcux_init_common (const struct device * dev )
763
822
{
764
823
const struct udc_mcux_config * config = dev -> config ;
765
824
struct udc_data * data = dev -> data ;
@@ -771,9 +830,6 @@ static int udc_mcux_driver_preinit(const struct device *dev)
771
830
return - ENOMEM ;
772
831
}
773
832
774
- k_mutex_init (& data -> mutex );
775
- k_fifo_init (& priv -> fifo );
776
- k_work_init (& priv -> work , udc_mcux_work_handler );
777
833
778
834
for (int i = 0 ; i < config -> num_of_eps ; i ++ ) {
779
835
config -> ep_cfg_out [i ].caps .out = 1 ;
@@ -823,11 +879,52 @@ static int udc_mcux_driver_preinit(const struct device *dev)
823
879
data -> caps .hs = true;
824
880
priv -> dev = dev ;
825
881
882
+
826
883
pinctrl_apply_state (config -> pincfg , PINCTRL_STATE_DEFAULT );
827
884
828
885
return 0 ;
829
886
}
830
887
888
+ static int udc_mcux_driver_preinit (const struct device * dev )
889
+ {
890
+ const struct udc_mcux_config * config = dev -> config ;
891
+ struct udc_data * data = dev -> data ;
892
+ struct udc_mcux_data * priv = data -> priv ;
893
+
894
+ udc_mcux_get_hal_driver_id (priv , config );
895
+ if (priv -> controller_id == 0xFFu ) {
896
+ return - ENOMEM ;
897
+ }
898
+
899
+ k_mutex_init (& data -> mutex );
900
+ k_fifo_init (& priv -> fifo );
901
+ k_work_init (& priv -> work , udc_mcux_work_handler );
902
+ return udc_mcux_init_common (dev );
903
+ }
904
+
905
+ #ifdef CONFIG_PM
906
+ static int udc_mcux_pm_action (const struct device * dev , enum pm_device_action action )
907
+ {
908
+ struct udc_mcux_data * priv = udc_get_private (dev );
909
+
910
+ switch (action ) {
911
+ case PM_DEVICE_ACTION_RESUME :
912
+ case PM_DEVICE_ACTION_SUSPEND :
913
+ case PM_DEVICE_ACTION_TURN_OFF :
914
+ break ;
915
+ case PM_DEVICE_ACTION_TURN_ON :
916
+ udc_mcux_init_common (dev );
917
+ if (priv -> enabled ) {
918
+ udc_mcux_control (dev , kUSB_DeviceControlRun , NULL );
919
+ }
920
+ break ;
921
+ default :
922
+ return - ENOTSUP ;
923
+ }
924
+ return 0 ;
925
+ }
926
+ #endif /* CONFIG_PM */
927
+
831
928
static const struct udc_api udc_mcux_api = {
832
929
.device_speed = udc_mcux_device_speed ,
833
930
.ep_enqueue = udc_mcux_ep_enqueue ,
@@ -913,7 +1010,8 @@ static usb_phy_config_struct_t phy_config_##n = { \
913
1010
.priv = &priv_data_##n, \
914
1011
}; \
915
1012
\
916
- DEVICE_DT_INST_DEFINE(n, udc_mcux_driver_preinit, NULL, \
1013
+ PM_DEVICE_DT_INST_DEFINE(n, udc_mcux_pm_action); \
1014
+ DEVICE_DT_INST_DEFINE(n, udc_mcux_driver_preinit, PM_DEVICE_DT_INST_GET(n), \
917
1015
&udc_data_##n, &priv_config_##n, \
918
1016
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
919
1017
&udc_mcux_api);
0 commit comments