Skip to content

Commit 18a7603

Browse files
kasjernashif
authored andcommitted
drivers: usb_device: smartbond: Add power management
Add support for automatic control of PLL for USB subsystem. This utilized virtual USB clock present in clock control. USB driver enables PLL when device is attached or USB sends resume signaling. PLL can be turned off (if application does not requested it) when device is detached (application request) or USB host sends suspend request. When VBUS is not present or application did not started USB yet PD_DOMAIN_SYS is also not acquired that allows for deep sleep. When USB is active deep sleep will never be activated. Signed-off-by: Jerzy Kasenberg <[email protected]>
1 parent 16c0cec commit 18a7603

File tree

1 file changed

+84
-39
lines changed

1 file changed

+84
-39
lines changed

drivers/usb/device/usb_dc_smartbond.c

Lines changed: 84 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@
2222
#include <DA1469xAB.h>
2323
#include <soc.h>
2424
#include <da1469x_clock.h>
25+
#include <da1469x_pd.h>
2526

2627
#include <zephyr/logging/log.h>
2728
#include <zephyr/drivers/gpio.h>
29+
#include <zephyr/drivers/clock_control/smartbond_clock_control.h>
30+
#include <zephyr/pm/policy.h>
2831

2932
LOG_MODULE_REGISTER(usb_dc_smartbond, CONFIG_USB_DRIVER_LOG_LEVEL);
3033

@@ -128,6 +131,7 @@ struct smartbond_ep_state {
128131
struct usb_dc_state {
129132
bool vbus_present;
130133
bool attached;
134+
atomic_t clk_requested;
131135
uint8_t nfsr;
132136
usb_dc_status_callback status_cb;
133137
struct smartbond_ep_state ep_state[2][4];
@@ -684,6 +688,7 @@ static uint32_t check_reset_end(uint32_t alt_ev)
684688
}
685689
LOG_INF("Set operational %02x", USB->USB_MAMSK_REG);
686690
set_nfsr(NFSR_NODE_OPERATIONAL);
691+
dev_state.status_cb(USB_DC_CONNECTED, NULL);
687692
}
688693
}
689694
return alt_ev;
@@ -723,11 +728,30 @@ static void handle_bus_reset(void)
723728
check_reset_end(alt_ev);
724729
}
725730

731+
static void usb_clock_on(void)
732+
{
733+
if (atomic_cas(&dev_state.clk_requested, 0, 1)) {
734+
clock_control_on(DEVICE_DT_GET(DT_NODELABEL(osc)),
735+
(clock_control_subsys_rate_t)SMARTBOND_CLK_USB);
736+
}
737+
}
738+
739+
static void usb_clock_off(void)
740+
{
741+
if (atomic_cas(&dev_state.clk_requested, 1, 0)) {
742+
clock_control_off(DEVICE_DT_GET(DT_NODELABEL(osc)),
743+
(clock_control_subsys_rate_t)SMARTBOND_CLK_USB);
744+
}
745+
}
746+
726747
static void handle_alt_ev(void)
727748
{
728749
struct smartbond_ep_state *ep_state;
729750
uint32_t alt_ev = USB->USB_ALTEV_REG;
730751

752+
if (USB->USB_NFSR_REG == NFSR_NODE_SUSPEND) {
753+
usb_clock_on();
754+
}
731755
alt_ev = check_reset_end(alt_ev);
732756
if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESET) &&
733757
dev_state.nfsr != NFSR_NODE_RESET) {
@@ -755,6 +779,7 @@ static void handle_alt_ev(void)
755779
USB->USB_ALTMSK_REG =
756780
USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
757781
USB_USB_ALTMSK_REG_USB_M_RESUME_Msk;
782+
usb_clock_off();
758783
dev_state.status_cb(USB_DC_SUSPEND, NULL);
759784
}
760785
}
@@ -892,34 +917,76 @@ static void usb_dc_smartbond_isr(void)
892917
}
893918
}
894919

895-
static void usb_dc_smartbond_vbus_changed(bool present)
920+
/**
921+
* USB functionality can be disabled from HOST and DEVICE side.
922+
* Host side is indicated by VBUS line.
923+
* Device side is decided by pair of calls usb_dc_attach()/usb_dc_detach,
924+
* USB will only work when application calls usb_dc_attach() and VBUS is present.
925+
* When both conditions are not met USB clock (PLL) is released, and peripheral
926+
* remain in reset state.
927+
*/
928+
static void usb_change_state(bool attached, bool vbus_present)
896929
{
897-
if (dev_state.vbus_present == present) {
930+
if (dev_state.attached == attached && dev_state.vbus_present == vbus_present) {
898931
return;
899932
}
900933

901-
dev_state.vbus_present = present;
902-
903-
if (present) {
904-
/* TODO: Add PD acquire when available */
905-
/* If power event happened before USB started, delay dcd_connect
906-
* until dcd_init is called.
934+
if (attached && vbus_present) {
935+
dev_state.attached = true;
936+
dev_state.vbus_present = true;
937+
/*
938+
* Prevent transition to standby, this greatly reduces
939+
* IRQ response time
907940
*/
941+
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
942+
usb_clock_on();
908943
dev_state.status_cb(USB_DC_CONNECTED, NULL);
909-
} else {
944+
USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk;
945+
USB->USB_NFSR_REG = 0;
946+
USB->USB_FAR_REG = 0x80;
947+
USB->USB_TXMSK_REG = 0;
948+
USB->USB_RXMSK_REG = 0;
949+
950+
USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
951+
USB_USB_MAMSK_REG_USB_M_ALT_Msk |
952+
USB_USB_MAMSK_REG_USB_M_WARN_Msk;
953+
USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
954+
USB_USB_ALTEV_REG_USB_SD3_Msk;
955+
956+
USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk |
957+
USB_USB_MCTRL_REG_USB_NAT_Msk;
958+
959+
/* Select chosen DMA to be triggered by USB. */
960+
DMA->DMA_REQ_MUX_REG =
961+
(DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) |
962+
DA146XX_DMA_USB_MUX;
963+
} else if (dev_state.attached && dev_state.vbus_present) {
964+
/*
965+
* USB was previously in use now either VBUS is gone or application
966+
* requested detach, put it down
967+
*/
968+
dev_state.attached = attached;
969+
dev_state.vbus_present = vbus_present;
910970
USB->USB_MCTRL_REG = 0;
971+
usb_clock_off();
911972
dev_state.status_cb(USB_DC_DISCONNECTED, NULL);
912-
/* TODO: Add PD release when available */
973+
/* Allow standby USB not in use or not connected */
974+
pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
975+
} else {
976+
/* USB still not activated, keep track of what's on and off */
977+
dev_state.attached = attached;
978+
dev_state.vbus_present = vbus_present;
913979
}
914980
}
915981

916982
static void usb_dc_smartbond_vbus_isr(void)
917983
{
918-
bool vbus_present =
919-
(CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_VBUS_AVAILABLE_Msk) != 0;
984+
LOG_DBG("VBUS_ISR");
920985

921986
CRG_TOP->VBUS_IRQ_CLEAR_REG = 1;
922-
usb_dc_smartbond_vbus_changed(vbus_present);
987+
usb_change_state(dev_state.attached,
988+
(CRG_TOP->ANA_STATUS_REG &
989+
CRG_TOP_ANA_STATUS_REG_VBUS_AVAILABLE_Msk) != 0);
923990
}
924991

925992
static int usb_init(void)
@@ -1255,40 +1322,18 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const ep_cfg)
12551322

12561323
int usb_dc_detach(void)
12571324
{
1258-
LOG_DBG("");
1325+
LOG_DBG("Detach");
12591326

1260-
REG_CLR_BIT(USB_MCTRL_REG, USB_NAT);
1261-
1262-
dev_state.attached = false;
1327+
usb_change_state(false, dev_state.vbus_present);
12631328

12641329
return 0;
12651330
}
12661331

12671332
int usb_dc_attach(void)
12681333
{
1269-
LOG_DBG("");
1270-
if (GET_BIT(USB->USB_MCTRL_REG, USB_USB_MCTRL_REG_USB_NAT) == 0) {
1271-
USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk;
1272-
USB->USB_NFSR_REG = 0;
1273-
USB->USB_FAR_REG = 0x80;
1274-
USB->USB_TXMSK_REG = 0;
1275-
USB->USB_RXMSK_REG = 0;
1334+
LOG_INF("Attach");
12761335

1277-
USB->USB_MAMSK_REG = USB_USB_MAMSK_REG_USB_M_INTR_Msk |
1278-
USB_USB_MAMSK_REG_USB_M_ALT_Msk |
1279-
USB_USB_MAMSK_REG_USB_M_WARN_Msk;
1280-
USB->USB_ALTMSK_REG = USB_USB_ALTMSK_REG_USB_M_RESET_Msk |
1281-
USB_USB_ALTEV_REG_USB_SD3_Msk;
1282-
1283-
USB->USB_MCTRL_REG = USB_USB_MCTRL_REG_USBEN_Msk |
1284-
USB_USB_MCTRL_REG_USB_NAT_Msk;
1285-
1286-
/* Select chosen DMA to be triggered by USB. */
1287-
DMA->DMA_REQ_MUX_REG =
1288-
(DMA->DMA_REQ_MUX_REG & ~DA146XX_DMA_USB_MUX_MASK) |
1289-
DA146XX_DMA_USB_MUX;
1290-
}
1291-
dev_state.attached = true;
1336+
usb_change_state(true, dev_state.vbus_present);
12921337

12931338
return 0;
12941339
}

0 commit comments

Comments
 (0)