@@ -831,6 +831,12 @@ static hcd_port_event_t _intr_hdlr_hprt(port_t *port, usb_dwc_hal_port_event_t h
831831 port -> flags .conn_dev_ena = 0 ;
832832 break ;
833833 }
834+ case USB_DWC_HAL_PORT_EVENT_REMOTE_WAKEUP : {
835+ esp_rom_printf ("WAKE\n" );
836+ //port->state = HCD_PORT_STATE_ENABLED;
837+ port_event = HCD_PORT_EVENT_REMOTE_WAKEUP ;
838+ break ;
839+ }
834840 default : {
835841 abort ();
836842 break ;
@@ -1217,6 +1223,34 @@ static inline bool _is_fifo_config_by_bias(const usb_dwc_hal_fifo_config_t *cfg)
12171223 cfg -> ptx_fifo_lines == 0 );
12181224}
12191225
1226+ /**
1227+ * @brief Gate internal clock
1228+ *
1229+ * @param[in] port Pointer to the port object
1230+ * @param[in] enable enable/disable internal clock gating
1231+ * @return True internal clk successfully gated/un-gated
1232+ * @return False internal clk not gated/un-gated
1233+ */
1234+ static inline bool _internal_clk_gate (port_t * port , bool enable )
1235+ {
1236+ // Stop PHY Clock and gate HCLK
1237+ usb_dwc_hal_pwr_clk_internal_clock_gate (port -> hal , enable );
1238+
1239+ // Wait 10 PHY clock cycles, PHY Clock is 30MHz when using 16bit interface, 60MHz when 8bit interface
1240+ // which makes 33.3 nS. Busy wait for 1uS just to be sure
1241+ esp_rom_delay_us (1 );
1242+
1243+ const bool phy_clk_stopped = usb_dwc_hal_pwr_clk_check_phy_clk_stopped (port -> hal );
1244+ const bool hclk_gated = usb_dwc_hal_pwr_clk_check_hclk_gated (port -> hal );
1245+
1246+ // enable == phy_clk_stopped == hclk_gated
1247+ // When gating the clock, all 3 variables must be 1. When un-gating, all 3 must be 0.
1248+ if ((enable == phy_clk_stopped ) && (enable == hclk_gated )) {
1249+ return true;
1250+ }
1251+ return false;
1252+ }
1253+
12201254// ---------------------- Commands -------------------------
12211255
12221256static esp_err_t _port_cmd_power_on (port_t * port )
@@ -1227,6 +1261,7 @@ static esp_err_t _port_cmd_power_on(port_t *port)
12271261 port -> state = HCD_PORT_STATE_DISCONNECTED ;
12281262 usb_dwc_hal_port_init (port -> hal );
12291263 usb_dwc_hal_port_toggle_power (port -> hal , true);
1264+ //_internal_clk_gate(port, false); // Un-gate the phy clock TODO: Test this
12301265 ret = ESP_OK ;
12311266 } else {
12321267 ret = ESP_ERR_INVALID_STATE ;
@@ -1240,6 +1275,7 @@ static esp_err_t _port_cmd_power_off(port_t *port)
12401275 // Port can only be unpowered if already powered
12411276 if (port -> state != HCD_PORT_STATE_NOT_POWERED ) {
12421277 port -> state = HCD_PORT_STATE_NOT_POWERED ;
1278+ //_internal_clk_gate(port, false); // Un-gate the phy clock TODO: Test this
12431279 usb_dwc_hal_port_deinit (port -> hal );
12441280 usb_dwc_hal_port_toggle_power (port -> hal , false);
12451281 // If a device is currently connected, this should trigger a disconnect event
@@ -1255,7 +1291,8 @@ static esp_err_t _port_cmd_reset(port_t *port)
12551291 esp_err_t ret ;
12561292
12571293 // Port can only a reset when it is in the enabled or disabled (in the case of a new connection)states.
1258- if (port -> state != HCD_PORT_STATE_ENABLED && port -> state != HCD_PORT_STATE_DISABLED ) {
1294+ // Or suspended, to exit suspended state through host initiated reset
1295+ if (port -> state != HCD_PORT_STATE_ENABLED && port -> state != HCD_PORT_STATE_DISABLED && port -> state != HCD_PORT_STATE_SUSPENDED ) {
12591296 ret = ESP_ERR_INVALID_STATE ;
12601297 goto exit ;
12611298 }
@@ -1264,6 +1301,10 @@ static esp_err_t _port_cmd_reset(port_t *port)
12641301 ret = ESP_ERR_INVALID_STATE ;
12651302 goto exit ;
12661303 }
1304+ // If resetting from suspended state, we must un-gate the internal clock
1305+ if (port -> state == HCD_PORT_STATE_SUSPENDED ) {
1306+ _internal_clk_gate (port , false);
1307+ }
12671308 /*
12681309 Proceed to resetting the bus
12691310 - Update the port's state variable
@@ -1320,6 +1361,21 @@ static esp_err_t _port_cmd_reset(port_t *port)
13201361 return ret ;
13211362}
13221363
1364+ /**
1365+ * @brief Suspend the root port
1366+ *
1367+ * This sequence equals to a sequence from the DesignWare Cores USB 2.0 Programming Guide version 4.00a
1368+ * 14.2.3.3 External HCLK Gating When the Host Core is in Partial Power Down Mode
1369+ * Sequence Entering suspend state
1370+ *
1371+ * @param[in] port Pointer to the port object
1372+ * @return:
1373+ * - ESP_ERR_INVALID_STATE Port is not in a correct state to be suspended, or pipe(s) routed through this port is not halted
1374+ * - ESP_ERR_INVALID_RESPONSE Port state unexpectedly changed (for example: device was disconnected)
1375+ * - ESP_ERR_NOT_FINISHED Port did not finish the suspending sequence and is not in the suspended state
1376+ * - ESP_ERR_NOT_ALLOWED PHY clk was not suspended
1377+ * - ESP_OK Root port suspended
1378+ */
13231379static esp_err_t _port_cmd_bus_suspend (port_t * port )
13241380{
13251381 esp_err_t ret ;
@@ -1353,13 +1409,34 @@ static esp_err_t _port_cmd_bus_suspend(port_t *port)
13531409 goto exit ;
13541410 }
13551411
1412+ if (! _internal_clk_gate (port , true)) {
1413+ ret = ESP_ERR_NOT_ALLOWED ;
1414+ goto exit ;
1415+ }
1416+
13561417 port -> state = HCD_PORT_STATE_SUSPENDED ;
13571418 ret = ESP_OK ;
13581419
13591420exit :
13601421 return ret ;
13611422}
13621423
1424+ /**
1425+ * @brief Resume the root port
1426+ *
1427+ * This sequence equals to a sequence from the DesignWare Cores USB 2.0 Programming Guide version 4.00a
1428+ * 14.2.3.3 External HCLK Gating When the Host Core is in Partial Power Down Mode
1429+ * Sequence Exiting Suspend State Through Host Initiated Resume
1430+ * Exiting Suspend State Through Device Initiated Remote Wakeup
1431+ *
1432+ * @note this sequence is used for both resume scenarios: the host initiated and the device initiated (remote wakeup) resume
1433+ * @param[in] port Pointer to the port object
1434+ * @return:
1435+ * - ESP_ERR_INVALID_STATE Port is not in a correct state to be resumed
1436+ * - ESP_ERR_NOT_ALLOWED PHY clk was not resumed
1437+ * - ESP_ERR_INVALID_RESPONSE Port state unexpectedly changed (for example: device was disconnected)
1438+ * - ESP_OK Root port resumed
1439+ */
13631440static esp_err_t _port_cmd_bus_resume (port_t * port )
13641441{
13651442 esp_err_t ret ;
@@ -1368,6 +1445,12 @@ static esp_err_t _port_cmd_bus_resume(port_t *port)
13681445 ret = ESP_ERR_INVALID_STATE ;
13691446 goto exit ;
13701447 }
1448+
1449+ if (!_internal_clk_gate (port , false)) {
1450+ ret = ESP_ERR_NOT_ALLOWED ;
1451+ goto exit ;
1452+ }
1453+
13711454 // Put and hold the bus in the K state.
13721455 usb_dwc_hal_port_toggle_resume (port -> hal , true);
13731456 port -> state = HCD_PORT_STATE_RESUMING ;
@@ -1485,6 +1568,7 @@ esp_err_t hcd_port_deinit(hcd_port_handle_t port_hdl)
14851568 return ESP_OK ;
14861569}
14871570
1571+
14881572esp_err_t hcd_port_command (hcd_port_handle_t port_hdl , hcd_port_cmd_t command )
14891573{
14901574 esp_err_t ret = ESP_ERR_INVALID_STATE ;
0 commit comments