pinebuds/platform/drivers/ana/best2300p/usbphy_best2300p.c

411 lines
9.7 KiB
C

/***************************************************************************
*
* 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