|
22 | 22 | #include <DA1469xAB.h> |
23 | 23 | #include <soc.h> |
24 | 24 | #include <da1469x_clock.h> |
| 25 | +#include <da1469x_pd.h> |
25 | 26 |
|
26 | 27 | #include <zephyr/logging/log.h> |
27 | 28 | #include <zephyr/drivers/gpio.h> |
| 29 | +#include <zephyr/drivers/clock_control/smartbond_clock_control.h> |
| 30 | +#include <zephyr/pm/policy.h> |
28 | 31 |
|
29 | 32 | LOG_MODULE_REGISTER(usb_dc_smartbond, CONFIG_USB_DRIVER_LOG_LEVEL); |
30 | 33 |
|
@@ -128,6 +131,7 @@ struct smartbond_ep_state { |
128 | 131 | struct usb_dc_state { |
129 | 132 | bool vbus_present; |
130 | 133 | bool attached; |
| 134 | + atomic_t clk_requested; |
131 | 135 | uint8_t nfsr; |
132 | 136 | usb_dc_status_callback status_cb; |
133 | 137 | struct smartbond_ep_state ep_state[2][4]; |
@@ -684,6 +688,7 @@ static uint32_t check_reset_end(uint32_t alt_ev) |
684 | 688 | } |
685 | 689 | LOG_INF("Set operational %02x", USB->USB_MAMSK_REG); |
686 | 690 | set_nfsr(NFSR_NODE_OPERATIONAL); |
| 691 | + dev_state.status_cb(USB_DC_CONNECTED, NULL); |
687 | 692 | } |
688 | 693 | } |
689 | 694 | return alt_ev; |
@@ -723,11 +728,30 @@ static void handle_bus_reset(void) |
723 | 728 | check_reset_end(alt_ev); |
724 | 729 | } |
725 | 730 |
|
| 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 | + |
726 | 747 | static void handle_alt_ev(void) |
727 | 748 | { |
728 | 749 | struct smartbond_ep_state *ep_state; |
729 | 750 | uint32_t alt_ev = USB->USB_ALTEV_REG; |
730 | 751 |
|
| 752 | + if (USB->USB_NFSR_REG == NFSR_NODE_SUSPEND) { |
| 753 | + usb_clock_on(); |
| 754 | + } |
731 | 755 | alt_ev = check_reset_end(alt_ev); |
732 | 756 | if (GET_BIT(alt_ev, USB_USB_ALTEV_REG_USB_RESET) && |
733 | 757 | dev_state.nfsr != NFSR_NODE_RESET) { |
@@ -755,6 +779,7 @@ static void handle_alt_ev(void) |
755 | 779 | USB->USB_ALTMSK_REG = |
756 | 780 | USB_USB_ALTMSK_REG_USB_M_RESET_Msk | |
757 | 781 | USB_USB_ALTMSK_REG_USB_M_RESUME_Msk; |
| 782 | + usb_clock_off(); |
758 | 783 | dev_state.status_cb(USB_DC_SUSPEND, NULL); |
759 | 784 | } |
760 | 785 | } |
@@ -892,34 +917,76 @@ static void usb_dc_smartbond_isr(void) |
892 | 917 | } |
893 | 918 | } |
894 | 919 |
|
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) |
896 | 929 | { |
897 | | - if (dev_state.vbus_present == present) { |
| 930 | + if (dev_state.attached == attached && dev_state.vbus_present == vbus_present) { |
898 | 931 | return; |
899 | 932 | } |
900 | 933 |
|
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 |
907 | 940 | */ |
| 941 | + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); |
| 942 | + usb_clock_on(); |
908 | 943 | 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; |
910 | 970 | USB->USB_MCTRL_REG = 0; |
| 971 | + usb_clock_off(); |
911 | 972 | 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; |
913 | 979 | } |
914 | 980 | } |
915 | 981 |
|
916 | 982 | static void usb_dc_smartbond_vbus_isr(void) |
917 | 983 | { |
918 | | - bool vbus_present = |
919 | | - (CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_VBUS_AVAILABLE_Msk) != 0; |
| 984 | + LOG_DBG("VBUS_ISR"); |
920 | 985 |
|
921 | 986 | 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); |
923 | 990 | } |
924 | 991 |
|
925 | 992 | static int usb_init(void) |
@@ -1255,40 +1322,18 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const ep_cfg) |
1255 | 1322 |
|
1256 | 1323 | int usb_dc_detach(void) |
1257 | 1324 | { |
1258 | | - LOG_DBG(""); |
| 1325 | + LOG_DBG("Detach"); |
1259 | 1326 |
|
1260 | | - REG_CLR_BIT(USB_MCTRL_REG, USB_NAT); |
1261 | | - |
1262 | | - dev_state.attached = false; |
| 1327 | + usb_change_state(false, dev_state.vbus_present); |
1263 | 1328 |
|
1264 | 1329 | return 0; |
1265 | 1330 | } |
1266 | 1331 |
|
1267 | 1332 | int usb_dc_attach(void) |
1268 | 1333 | { |
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"); |
1276 | 1335 |
|
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); |
1292 | 1337 |
|
1293 | 1338 | return 0; |
1294 | 1339 | } |
|
0 commit comments