/*************************************************************************** * * Copyright 2015-2019 BES. * All rights reserved. All unpublished rights reserved. * * No part of this work may be used or reproduced in any form or by any * means, or stored in a database or retrieval system, without prior written * permission of BES. * * Use of this work is governed by a license granted by BES. * This work contains confidential and proprietary information of * BES. which is protected by copyright, trade secret, * trademark and other intellectual property rights. * ****************************************************************************/ #include "usbphy.h" #include "cmsis_nvic.h" #include "hal_cmu.h" #include "hal_phyif.h" #include "hal_timer.h" #include "hal_trace.h" #include "pmu.h" #include CHIP_SPECIFIC_HDR(reg_usbphy) #ifdef CHIP_HAS_SPIPHY //#define USBPHY_SERIAL_ITF void usbphy_ldo_config(int enable) { int ret; uint16_t val; ret = hal_phyif_open(SPIPHY_USB_CS); if (ret) { hal_phyif_close(SPIPHY_USB_CS); return; } if (enable) { #ifdef USB_HIGH_SPEED // USB ldo voltage should match with vcore (now 0.9V) usbphy_write(0x61, 0x1118); #else usbphy_write(0x61, 0x1116); #endif usbphy_write(0x62, 0x2229); usbphy_write(0x63, 0x0D82); hal_sys_timer_delay(MS_TO_TICKS(1)); } else { usbphy_write(0x63, 0x0000); usbphy_write(0x62, 0x0000); usbphy_read(0x61, &val); val &= (0x1 << 8); usbphy_write(0x61, val); hal_sys_timer_delay(2); hal_phyif_close(SPIPHY_USB_CS); } } void usbphy_open(void) { unsigned short val_01, val; #ifdef USB_HIGH_SPEED usbphy_read(0x01, &val_01); val_01 &= ~((1 << 0) | (1 << 11)); usbphy_write(0x01, val_01); val_01 |= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 13); #ifdef USBPHY_SERIAL_ITF // cdr_clk polariy=1 val_01 |= (1 << 4); #else // cdr_clk polariy=0 val_01 &= ~(1 << 4); #endif usbphy_write(0x01, val_01); usbphy_read(0x02, &val); val = (val & ~(0x1F << 10)) | (0xC << 10); usbphy_write(0x02, val); usbphy_read(0x05, &val); val |= (1 << 8); usbphy_write(0x05, val); #ifdef USBPHY_SERIAL_ITF usbphy_write(0x06, 0x4EE9); #else usbphy_write(0x06, 0xCEE8); #endif usbphy_write(0x07, 0x9813); usbphy_read(0x08, &val); usbphy_write(0x08, val); usbphy_read(0x09, &val); usbphy_write(0x09, val); #ifdef USBPHY_SERIAL_ITF usbphy_write(0x0D, 0x2B1E); #else usbphy_write(0x0D, 0x2A1E); #endif // Disable force clocks, and disable hs son signal usbphy_write(0x22, 0x030F); // Ignore all UTMI errors usbphy_write(0x12, 0x0003); hal_sys_timer_delay(MS_TO_TICKS(1)); val_01 |= (1 << 0); usbphy_write(0x01, val_01); #ifdef USB_HS_LOOPBACK_TEST usbphy_read(0x0A, &val); val |= (1 << 3) | (1 << 4) | (1 << 6); usbphy_write(0x0A, val); usbphy_read(0x0B, &val); val &= ~((1 << 3) | (1 << 4) | (3 << 6)); usbphy_write(0x0B, val); usbphy_read(0x09, &val); usbphy_write(0x09, val); usbphy_read(0x06, &val); usbphy_write(0x06, val); hal_sys_timer_delay(MS_TO_TICKS(1)); #define LOOPBACK_PATTERN (*(volatile uint8_t *)0x20000004) LOOPBACK_PATTERN = 0; uint8_t pattern = LOOPBACK_PATTERN; // Set tx pattern usbphy_read(0x03, &val); val = (val & ~(0xFF << 8)) | (pattern << 8); usbphy_write(0x03, val); // Enable force clocks usbphy_read(0x22, &val); val |= (1 << 4) | (1 << 5) | (1 << 6); usbphy_write(0x22, val); // Enable tx usbphy_read(0x04, &val); val |= (1 << 1); usbphy_write(0x04, val); // Update tx pattern while (1) { if (pattern != LOOPBACK_PATTERN) { pattern = LOOPBACK_PATTERN; usbphy_read(0x03, &val); val = (val & ~(0xFF << 8)) | (pattern << 8); usbphy_write(0x03, val); } } #endif #else // !USB_HIGH_SPEED usbphy_read(0x01, &val_01); val_01 &= ~(1 << 0); usbphy_write(0x01, val_01); val_01 |= (1 << 3); usbphy_write(0x01, val_01); #ifdef USB_USE_USBPLL val_01 |= (1 << 2) | (1 << 12); usbphy_write(0x01, val_01); usbphy_read(0x33, &val); val |= (1 << 0); usbphy_write(0x33, val); #endif val = 0; usbphy_write(0x06, val); usbphy_read(0x07, &val); usbphy_write(0x07, val); val = 0; usbphy_write(0x08, val); val = 0; usbphy_write(0x09, val); val_01 |= (1 << 0); usbphy_write(0x01, val_01); #endif // USB_HIGH_SPEED } void usbphy_close(void) { } void usbphy_sleep(void) { uint16_t val; usbphy_read(0x01, &val); #ifdef USB_HIGH_SPEED val &= ~((1 << 1) | (1 << 2) | (1 << 3)); #elif defined(USB_USE_USBPLL) val &= ~((1 << 2) | (1 << 3)); #else val &= ~(1 << 3); #endif usbphy_write(0x01, val); #if !defined(USB_HIGH_SPEED) && defined(USB_USE_USBPLL) usbphy_read(0x33, &val); val &= ~(1 << 0); usbphy_write(0x33, val); #endif usbphy_write(0x62, 0x0000); usbphy_write(0x63, 0x0000); } void usbphy_wakeup(void) { uint16_t val; usbphy_write(0x62, 0x2229); usbphy_write(0x63, 0x0D82); #if !defined(USB_HIGH_SPEED) && defined(USB_USE_USBPLL) usbphy_read(0x33, &val); val |= (1 << 0); usbphy_write(0x33, val); #endif usbphy_read(0x01, &val); #ifdef USB_HIGH_SPEED val |= (1 << 1) | (1 << 2) | (1 << 3); #elif defined(USB_USE_USBPLL) val |= (1 << 2) | (1 << 3); #else val |= (1 << 3); #endif usbphy_write(0x01, val); } //============================================================================================ // USB Pin Status Check //============================================================================================ static enum PMU_USB_PIN_CHK_STATUS_T usb_pin_status; static PMU_USB_PIN_CHK_CALLBACK usb_pin_callback; static int pmu_usb_check_pin_status(enum PMU_USB_PIN_CHK_STATUS_T status) { int dp, dm; pmu_usb_get_pin_status(&dp, &dm); //TRACE(5,"[%X] %s: status=%d dp=%d dm=%d", hal_sys_timer_get(), __FUNCTION__, status, dp, dm); // HOST_RESUME: (resume) dp == 0 && dm == 1, (reset) dp == 0 && dm == 0 if ( (status == PMU_USB_PIN_CHK_DEV_CONN && (dp == 1 && dm == 0)) || (status == PMU_USB_PIN_CHK_DEV_DISCONN && (dp == 0 && dm == 0)) || (status == PMU_USB_PIN_CHK_HOST_RESUME && dp == 0) ) { return 1; } return 0; } static void pmu_usb_pin_irq_handler(void) { uint16_t val; uint32_t lock; //TRACE(2,"[%X] %s", hal_sys_timer_get(), __FUNCTION__); lock = int_lock(); usbphy_read(USBPHY_REG_1A, &val); val |= REG_1A_INTR_CLR; usbphy_write(USBPHY_REG_1A, val); int_unlock(lock); if (usb_pin_callback) { if (pmu_usb_check_pin_status(usb_pin_status)) { pmu_usb_disable_pin_status_check(); usb_pin_callback(usb_pin_status); } } } int pmu_usb_config_pin_status_check(enum PMU_USB_PIN_CHK_STATUS_T status, PMU_USB_PIN_CHK_CALLBACK callback, int enable) { uint16_t val; uint32_t lock; //TRACE(3,"[%X] %s: status=%d", hal_sys_timer_get(), __FUNCTION__, status); if (status >= PMU_USB_PIN_CHK_STATUS_QTY) { return 1; } NVIC_DisableIRQ(USB_PIN_IRQn); lock = int_lock(); usb_pin_status = status; usb_pin_callback = callback; usbphy_read(USBPHY_REG_1A, &val); // Mask the irq val &= ~REG_1A_USB_INSERT_INTR_MSK; // Config pin check val |= REG_1A_DEBOUNCE_EN | REG_1A_NOLS_MODE | REG_1A_USBINSERT_DET_EN; val &= ~(REG_1A_POL_USB_RX_DP | REG_1A_POL_USB_RX_DM); if (status == PMU_USB_PIN_CHK_DEV_CONN) { // Check dp 0->1, dm x->0 } else if (status == PMU_USB_PIN_CHK_DEV_DISCONN) { // Check dp 1->0, dm x->0 val |= REG_1A_POL_USB_RX_DP; } else if (status == PMU_USB_PIN_CHK_HOST_RESUME) { // Check dp 1->0, dm 0->1 (resume) or dm 0->0 (reset) val |= REG_1A_POL_USB_RX_DP; } if (status != PMU_USB_PIN_CHK_NONE && callback) { val |= REG_1A_USBINSERT_INTR_EN | REG_1A_USB_INSERT_INTR_MSK | REG_1A_INTR_CLR; } usbphy_write(USBPHY_REG_1A, val); int_unlock(lock); if (enable) { // Wait at least 10 cycles of 32K clock for the new status when signal checking polarity is changed hal_sys_timer_delay(5); pmu_usb_enable_pin_status_check(); } return 0; } void pmu_usb_enable_pin_status_check(void) { uint16_t val; uint32_t lock; if (usb_pin_status != PMU_USB_PIN_CHK_NONE && usb_pin_callback) { lock = int_lock(); usbphy_read(USBPHY_REG_1A, &val); val |= REG_1A_INTR_CLR; usbphy_write(USBPHY_REG_1A, val); int_unlock(lock); NVIC_ClearPendingIRQ(USB_PIN_IRQn); if (pmu_usb_check_pin_status(usb_pin_status)) { pmu_usb_disable_pin_status_check(); usb_pin_callback(usb_pin_status); return; } NVIC_SetVector(USB_PIN_IRQn, (uint32_t)pmu_usb_pin_irq_handler); NVIC_SetPriority(USB_PIN_IRQn, IRQ_PRIORITY_NORMAL); NVIC_EnableIRQ(USB_PIN_IRQn); } } void pmu_usb_disable_pin_status_check(void) { uint16_t val; uint32_t lock; NVIC_DisableIRQ(USB_PIN_IRQn); lock = int_lock(); usbphy_read(USBPHY_REG_1A, &val); val &= ~(REG_1A_USBINSERT_INTR_EN | REG_1A_USBINSERT_DET_EN); usbphy_write(USBPHY_REG_1A, val); int_unlock(lock); } void pmu_usb_get_pin_status(int *dp, int *dm) { uint16_t pol, val; usbphy_read(USBPHY_REG_1A, &pol); usbphy_read(USBPHY_REG_25, &val); *dp = (!(pol & REG_1A_POL_USB_RX_DP)) ^ (!(val & REG_25_USB_STATUS_RX_DP)); *dm = (!(pol & REG_1A_POL_USB_RX_DM)) ^ (!(val & REG_25_USB_STATUS_RX_DM)); } #endif