Skip to content

Commit 4e46e52

Browse files
committed
drivers: usb: udc: Enabling PM to udc_mcux_ehci
Enables PM support for USB devices that use udc_mcux_ehci. Signed-off-by: Emilio Benavente <emilio.benavente@nxp.com>
1 parent af46f62 commit 4e46e52

File tree

5 files changed

+127
-7
lines changed

5 files changed

+127
-7
lines changed

drivers/usb/udc/udc_mcux_ehci.c

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "usb_phy.h"
2424

2525
#include <zephyr/logging/log.h>
26+
#include <zephyr/pm/device.h>
27+
#include <zephyr/pm/policy.h>
2628
LOG_MODULE_REGISTER(udc_mcux, CONFIG_UDC_DRIVER_LOG_LEVEL);
2729

2830
/*
@@ -34,6 +36,7 @@ LOG_MODULE_REGISTER(udc_mcux, CONFIG_UDC_DRIVER_LOG_LEVEL);
3436

3537
#define PRV_DATA_HANDLE(_handle) CONTAINER_OF(_handle, struct udc_mcux_data, mcux_device)
3638

39+
3740
struct udc_mcux_config {
3841
const usb_device_controller_interface_struct_t *mcux_if;
3942
void (*irq_enable_func)(const struct device *dev);
@@ -51,6 +54,8 @@ struct udc_mcux_data {
5154
usb_device_struct_t mcux_device;
5255
struct k_work work;
5356
struct k_fifo fifo;
57+
bool enabled;
58+
bool vbus_present;
5459
uint8_t controller_id; /* 0xFF is invalid value */
5560
};
5661

@@ -92,6 +97,50 @@ static int udc_mcux_control(const struct device *dev, usb_device_control_type_t
9297
return 0;
9398
}
9499

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+
95144
/* If ep is busy, return busy. Otherwise feed the buf to controller */
96145
static int udc_mcux_ep_feed(const struct device *dev,
97146
struct udc_ep_config *const cfg,
@@ -525,10 +574,10 @@ usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg)
525574
case kUSB_DeviceNotifyLPMSleep:
526575
break;
527576
case kUSB_DeviceNotifyDetach:
528-
udc_submit_event(dev, UDC_EVT_VBUS_REMOVED, 0);
577+
udc_mcux_change_state(dev, priv->enabled, 0);
529578
break;
530579
case kUSB_DeviceNotifyAttach:
531-
udc_submit_event(dev, UDC_EVT_VBUS_READY, 0);
580+
udc_mcux_change_state(dev, priv->enabled, 1);
532581
break;
533582
case kUSB_DeviceNotifySOF:
534583
udc_submit_event(dev, UDC_EVT_SOF, 0);
@@ -676,11 +725,17 @@ static int udc_mcux_set_address(const struct device *dev, const uint8_t addr)
676725

677726
static int udc_mcux_enable(const struct device *dev)
678727
{
728+
struct udc_mcux_data *priv = udc_get_private(dev);
729+
udc_mcux_change_state(dev, 1, priv->vbus_present);
730+
679731
return udc_mcux_control(dev, kUSB_DeviceControlRun, NULL);
680732
}
681733

682734
static int udc_mcux_disable(const struct device *dev)
683735
{
736+
struct udc_mcux_data *priv = udc_get_private(dev);
737+
udc_mcux_change_state(dev, 0, priv->vbus_present);
738+
684739
return udc_mcux_control(dev, kUSB_DeviceControlStop, NULL);
685740
}
686741

@@ -759,7 +814,9 @@ static inline void udc_mcux_get_hal_driver_id(struct udc_mcux_data *priv,
759814
}
760815
}
761816

762-
static int udc_mcux_driver_preinit(const struct device *dev)
817+
818+
819+
static int udc_mcux_init_common(const struct device *dev)
763820
{
764821
const struct udc_mcux_config *config = dev->config;
765822
struct udc_data *data = dev->data;
@@ -771,9 +828,6 @@ static int udc_mcux_driver_preinit(const struct device *dev)
771828
return -ENOMEM;
772829
}
773830

774-
k_mutex_init(&data->mutex);
775-
k_fifo_init(&priv->fifo);
776-
k_work_init(&priv->work, udc_mcux_work_handler);
777831

778832
for (int i = 0; i < config->num_of_eps; i++) {
779833
config->ep_cfg_out[i].caps.out = 1;
@@ -823,11 +877,51 @@ static int udc_mcux_driver_preinit(const struct device *dev)
823877
data->caps.hs = true;
824878
priv->dev = dev;
825879

880+
826881
pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
827882

828883
return 0;
829884
}
830885

886+
static int udc_mcux_driver_preinit(const struct device *dev)
887+
{
888+
const struct udc_mcux_config *config = dev->config;
889+
struct udc_data *data = dev->data;
890+
struct udc_mcux_data *priv = data->priv;
891+
892+
udc_mcux_get_hal_driver_id(priv, config);
893+
if (priv->controller_id == 0xFFu) {
894+
return -ENOMEM;
895+
}
896+
897+
k_mutex_init(&data->mutex);
898+
k_fifo_init(&priv->fifo);
899+
k_work_init(&priv->work, udc_mcux_work_handler);
900+
return udc_mcux_init_common(dev);
901+
}
902+
903+
#ifdef CONFIG_PM
904+
static int udc_mcux_pm_action(const struct device *dev, enum pm_device_action action)
905+
{
906+
struct udc_mcux_data *priv = udc_get_private(dev);
907+
switch (action) {
908+
case PM_DEVICE_ACTION_RESUME:
909+
case PM_DEVICE_ACTION_SUSPEND:
910+
case PM_DEVICE_ACTION_TURN_OFF:
911+
break;
912+
case PM_DEVICE_ACTION_TURN_ON:
913+
udc_mcux_init_common(dev);
914+
if(priv->enabled) {
915+
udc_mcux_control(dev, kUSB_DeviceControlRun, NULL);
916+
}
917+
break;
918+
default:
919+
return -ENOTSUP;
920+
}
921+
return 0;
922+
}
923+
#endif /* CONFIG_PM */
924+
831925
static const struct udc_api udc_mcux_api = {
832926
.device_speed = udc_mcux_device_speed,
833927
.ep_enqueue = udc_mcux_ep_enqueue,
@@ -913,7 +1007,8 @@ static usb_phy_config_struct_t phy_config_##n = { \
9131007
.priv = &priv_data_##n, \
9141008
}; \
9151009
\
916-
DEVICE_DT_INST_DEFINE(n, udc_mcux_driver_preinit, NULL, \
1010+
PM_DEVICE_DT_INST_DEFINE(n, udc_mcux_pm_action); \
1011+
DEVICE_DT_INST_DEFINE(n, udc_mcux_driver_preinit, PM_DEVICE_DT_INST_GET(n), \
9171012
&udc_data_##n, &priv_config_##n, \
9181013
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
9191014
&udc_mcux_api);

dts/arm/nxp/nxp_rw6xx_common.dtsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@
238238
interrupt-names = "usb_otg";
239239
num-bidir-endpoints = <8>;
240240
power-domains = <&power_mode3_domain>;
241+
zephyr,disabling-power-states = <&suspend &standby>;
241242
status = "disabled";
242243
};
243244

modules/hal_nxp/mcux/mcux-sdk-ng/middleware/usb_device_config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ BUILD_ASSERT(NUM_INSTS <= 1, "Only one USB device supported");
114114
*/
115115
#define USB_DEVICE_CONFIG_SOF_NOTIFICATIONS (1U)
116116

117+
#define USB_DEVICE_CONFIG_DETACH_ENABLE (1U)
118+
117119
#endif
118120

119121
#endif /* __USB_DEVICE_CONFIG_H__ */
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
chosen {
9+
zephyr,console = &cdc_acm_uart0;
10+
};
11+
};
12+
13+
&zephyr_udc0 {
14+
cdc_acm_uart0: cdc_acm_uart0 {
15+
compatible = "zephyr,cdc-acm-uart";
16+
};
17+
};

soc/nxp/rw/power.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919

2020
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
2121

22+
#if CONFIG_PM && CONFIG_UDC_NXP_EHCI && DT_NODE_HAS_STATUS(DT_NODELABEL(standby),okay)
23+
#error "UDC EHCI CURRENTLY DOES NOT SUPPORT STANDBY MODE"
24+
#endif
25+
26+
2227
/* Active mode */
2328
#define POWER_MODE0 0
2429
/* Idle mode */

0 commit comments

Comments
 (0)