Skip to content

Commit 146ddc5

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 146ddc5

File tree

5 files changed

+130
-7
lines changed

5 files changed

+130
-7
lines changed

drivers/usb/udc/udc_mcux_ehci.c

Lines changed: 105 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,19 @@ 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+
730+
udc_mcux_change_state(dev, 1, priv->vbus_present);
731+
679732
return udc_mcux_control(dev, kUSB_DeviceControlRun, NULL);
680733
}
681734

682735
static int udc_mcux_disable(const struct device *dev)
683736
{
737+
struct udc_mcux_data *priv = udc_get_private(dev);
738+
739+
udc_mcux_change_state(dev, 0, priv->vbus_present);
740+
684741
return udc_mcux_control(dev, kUSB_DeviceControlStop, NULL);
685742
}
686743

@@ -759,7 +816,9 @@ static inline void udc_mcux_get_hal_driver_id(struct udc_mcux_data *priv,
759816
}
760817
}
761818

762-
static int udc_mcux_driver_preinit(const struct device *dev)
819+
820+
821+
static int udc_mcux_init_common(const struct device *dev)
763822
{
764823
const struct udc_mcux_config *config = dev->config;
765824
struct udc_data *data = dev->data;
@@ -771,9 +830,6 @@ static int udc_mcux_driver_preinit(const struct device *dev)
771830
return -ENOMEM;
772831
}
773832

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

778834
for (int i = 0; i < config->num_of_eps; i++) {
779835
config->ep_cfg_out[i].caps.out = 1;
@@ -823,11 +879,52 @@ static int udc_mcux_driver_preinit(const struct device *dev)
823879
data->caps.hs = true;
824880
priv->dev = dev;
825881

882+
826883
pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
827884

828885
return 0;
829886
}
830887

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+
831928
static const struct udc_api udc_mcux_api = {
832929
.device_speed = udc_mcux_device_speed,
833930
.ep_enqueue = udc_mcux_ep_enqueue,
@@ -913,7 +1010,8 @@ static usb_phy_config_struct_t phy_config_##n = { \
9131010
.priv = &priv_data_##n, \
9141011
}; \
9151012
\
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), \
9171015
&udc_data_##n, &priv_config_##n, \
9181016
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
9191017
&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)