kernel_samsung_a34x-permissive/drivers/misc/mediatek/usb20/mt6833/usb20_phy.c
2024-04-28 15:51:13 +02:00

906 lines
21 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifdef CONFIG_MTK_CLKMGR
#include <mach/mt_clkmgr.h>
#else
#include <linux/clk.h>
#endif
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <mtk_musb.h>
#include <musb_core.h>
#include "usb20.h"
#include "mtk_devinfo.h"
#include <linux/phy/phy.h>
#ifdef CONFIG_OF
#include <linux/of_address.h>
#endif
#ifdef CONFIG_MTK_AEE_FEATURE
#include <mt-plat/aee.h>
#endif
#include <mt-plat/mtk_boot_common.h>
#define FRA (48)
#define PARA (28)
#ifdef CONFIG_OF
extern struct musb *mtk_musb;
#ifdef USB2_PHY_V2
#define USB_PHY_OFFSET 0x300
#else
#define USB_PHY_OFFSET 0x800
#endif
#define USBPHY_READ8(offset) \
readb((void __iomem *)\
(((unsigned long)\
mtk_musb->xceiv->io_priv)+USB_PHY_OFFSET+offset))
#define USBPHY_WRITE8(offset, value) writeb(value, (void __iomem *)\
(((unsigned long)mtk_musb->xceiv->io_priv)+USB_PHY_OFFSET+offset))
#define USBPHY_SET8(offset, mask) \
USBPHY_WRITE8(offset, (USBPHY_READ8(offset)) | (mask))
#define USBPHY_CLR8(offset, mask) \
USBPHY_WRITE8(offset, (USBPHY_READ8(offset)) & (~(mask)))
#define USBPHY_READ32(offset) \
readl((void __iomem *)(((unsigned long)\
mtk_musb->xceiv->io_priv)+USB_PHY_OFFSET+offset))
#define USBPHY_WRITE32(offset, value) \
writel(value, (void __iomem *)\
(((unsigned long)mtk_musb->xceiv->io_priv)+USB_PHY_OFFSET+offset))
#define USBPHY_SET32(offset, mask) \
USBPHY_WRITE32(offset, (USBPHY_READ32(offset)) | (mask))
#define USBPHY_CLR32(offset, mask) \
USBPHY_WRITE32(offset, (USBPHY_READ32(offset)) & (~(mask)))
#ifdef MTK_UART_USB_SWITCH
#define UART2_BASE 0x11003000
#endif
#else
#include <mach/mt_reg_base.h>
#define USBPHY_READ8(offset) \
readb((void __iomem *)(USB_SIF_BASE+USB_PHY_OFFSET+offset))
#define USBPHY_WRITE8(offset, value) \
writeb(value, (void __iomem *)(USB_SIF_BASE+USB_PHY_OFFSET+offset))
#define USBPHY_SET8(offset, mask) \
USBPHY_WRITE8(offset, (USBPHY_READ8(offset)) | (mask))
#define USBPHY_CLR8(offset, mask) \
USBPHY_WRITE8(offset, (USBPHY_READ8(offset)) & (~mask))
#define USBPHY_READ32(offset) \
readl((void __iomem *)(USB_SIF_BASE+USB_PHY_OFFSET+offset))
#define USBPHY_WRITE32(offset, value) \
writel(value, (void __iomem *)(USB_SIF_BASE+USB_PHY_OFFSET+offset))
#define USBPHY_SET32(offset, mask) \
USBPHY_WRITE32(offset, (USBPHY_READ32(offset)) | (mask))
#define USBPHY_CLR32(offset, mask) \
USBPHY_WRITE32(offset, (USBPHY_READ32(offset)) & (~mask))
#endif
#ifdef FPGA_PLATFORM
bool usb_enable_clock(bool enable)
{
return true;
}
bool usb_prepare_clock(bool enable)
{
return true;
}
void usb_prepare_enable_clock(bool enable)
{
}
void usb_phy_poweron(void)
{
}
void usb_phy_savecurrent(void)
{
}
void usb_phy_recover(void)
{
}
/* BC1.2 */
void Charger_Detect_Init(void)
{
}
void Charger_Detect_Release(void)
{
}
void usb_phy_context_save(void)
{
}
void usb_phy_context_restore(void)
{
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
bool usb_phy_check_in_uart_mode(void)
{
return false;
}
void usb_phy_switch_to_uart(void)
{
}
void usb_phy_switch_to_usb(void)
{
}
#endif
#else
#include <linux/of_irq.h>
#include <linux/of_address.h>
#define VAL_MAX_WIDTH_2 0x3
#define VAL_MAX_WIDTH_3 0x7
#define OFFSET_RG_USB20_VRT_VREF_SEL 0x4
#define SHFT_RG_USB20_VRT_VREF_SEL 12
#define OFFSET_RG_USB20_TERM_VREF_SEL 0x4
#define SHFT_RG_USB20_TERM_VREF_SEL 8
#define OFFSET_RG_USB20_PHY_REV6 0x18
#define SHFT_RG_USB20_PHY_REV6 30
void usb_phy_tuning(void)
{
static bool inited;
static s32 u2_vrt_ref, u2_term_ref, u2_enhance;
struct device_node *of_node;
if (!inited) {
/* apply default value */
u2_vrt_ref = 5;
u2_term_ref = 5;
u2_enhance = 1;
of_node = of_find_compatible_node(NULL,
NULL, "mediatek,phy_tuning");
if (of_node) {
/* value won't be updated if property not being found */
of_property_read_u32(of_node,
"u2_vrt_ref", (u32 *) &u2_vrt_ref);
of_property_read_u32(of_node,
"u2_term_ref", (u32 *) &u2_term_ref);
of_property_read_u32(of_node,
"u2_enhance", (u32 *) &u2_enhance);
}
inited = true;
}
if (u2_vrt_ref != -1) {
if (u2_vrt_ref <= VAL_MAX_WIDTH_3) {
USBPHY_CLR32(OFFSET_RG_USB20_VRT_VREF_SEL,
VAL_MAX_WIDTH_3 << SHFT_RG_USB20_VRT_VREF_SEL);
USBPHY_SET32(OFFSET_RG_USB20_VRT_VREF_SEL,
u2_vrt_ref << SHFT_RG_USB20_VRT_VREF_SEL);
}
}
if (u2_term_ref != -1) {
if (u2_term_ref <= VAL_MAX_WIDTH_3) {
USBPHY_CLR32(OFFSET_RG_USB20_TERM_VREF_SEL,
VAL_MAX_WIDTH_3 << SHFT_RG_USB20_TERM_VREF_SEL);
USBPHY_SET32(OFFSET_RG_USB20_TERM_VREF_SEL,
u2_term_ref << SHFT_RG_USB20_TERM_VREF_SEL);
}
}
if (u2_enhance != -1) {
if (u2_enhance <= VAL_MAX_WIDTH_2) {
USBPHY_CLR32(OFFSET_RG_USB20_PHY_REV6,
VAL_MAX_WIDTH_2 << SHFT_RG_USB20_PHY_REV6);
USBPHY_SET32(OFFSET_RG_USB20_PHY_REV6,
u2_enhance<<SHFT_RG_USB20_PHY_REV6);
}
}
}
#ifdef CONFIG_MTK_USB2JTAG_SUPPORT
int usb2jtag_usb_init(void)
{
struct device_node *node = NULL;
void __iomem *usb_phy_base, usb_sif_base;
u32 temp;
node = of_find_compatible_node(NULL, NULL, "mediatek,mt6833-usb20");
if (!node) {
pr_err("[USB2JTAG] map node @ mediatek,USB0 failed\n");
return -1;
}
usb_phy_base = of_iomap(node, 1);
if (!usb_phy_base) {
pr_err("[USB2JTAG] iomap usb_phy_base failed\n");
return -1;
}
usb_sif_base = usb_phy_base + USB_PHY_OFFSET;
/* rg_usb20_gpio_ctl: bit[9] = 1 */
temp = readl(usb_sif_base + 0x20);
writel(temp | (1 << 9), usb_sif_base + 0x20);
/* RG_USB20_BGR_EN: bit[0] = 1 */
temp = readl(usb_sif_base);
writel(temp | (1 << 0), usb_sif_base);
/* RG_USB20_BC11_SW_EN: bit[23] = 0 */
temp = readl(usb_sif_base + 0x18);
writel(temp & ~(1 << 23), usb_sif_base + 0x18);
/* wait stable */
mdelay(1);
iounmap(usb_phy_base);
return 0;
}
#endif
#ifdef CONFIG_MTK_UART_USB_SWITCH
bool in_uart_mode;
#endif
void usb_prepare_enable_clock(bool enable)
{
if (enable) {
usb_prepare_clock(true);
usb_enable_clock(true);
} else {
usb_enable_clock(false);
usb_prepare_clock(false);
}
}
DEFINE_MUTEX(prepare_lock);
static atomic_t clk_prepare_cnt = ATOMIC_INIT(0);
bool usb_prepare_clock(bool enable)
{
int before_cnt = atomic_read(&clk_prepare_cnt);
mutex_lock(&prepare_lock);
if (IS_ERR_OR_NULL(musb_clk) ||
IS_ERR_OR_NULL(musb_ref_clk) ||
IS_ERR_OR_NULL(musb_clk_top_sel) ||
IS_ERR_OR_NULL(musb_clk_univpll5_d4)) {
DBG(0, "clk not ready\n");
mutex_unlock(&prepare_lock);
return 0;
}
if (enable) {
if (clk_prepare(musb_clk_top_sel)) {
DBG(0, "musb_clk_top_sel prepare fail\n");
} else {
if (clk_set_parent(musb_clk_top_sel,
musb_clk_univpll5_d4))
DBG(0, "musb_clk_top_sel set_parent fail\n");
}
if (clk_prepare(musb_clk))
DBG(0, "musb_clk prepare fail\n");
if (clk_prepare(musb_ref_clk))
DBG(0, "musb_ref_clk prepare fail\n");
atomic_inc(&clk_prepare_cnt);
} else {
clk_unprepare(musb_clk_top_sel);
clk_unprepare(musb_ref_clk);
clk_unprepare(musb_clk);
atomic_dec(&clk_prepare_cnt);
}
mutex_unlock(&prepare_lock);
DBG(1, "enable(%d), usb prepare_cnt, before(%d), after(%d)\n",
enable, before_cnt, atomic_read(&clk_prepare_cnt));
#ifdef CONFIG_MTK_AEE_FEATURE
if (atomic_read(&clk_prepare_cnt) < 0)
aee_kernel_warning("usb20", "usb clock prepare_cnt error\n");
#endif
return 1;
}
EXPORT_SYMBOL(usb_prepare_clock);
static DEFINE_SPINLOCK(musb_reg_clock_lock);
bool usb_enable_clock(bool enable)
{
static int count;
static int real_enable = 0, real_disable;
static int virt_enable = 0, virt_disable;
unsigned long flags;
DBG(1, "enable(%d),count(%d),<%d,%d,%d,%d>\n",
enable, count, virt_enable, virt_disable,
real_enable, real_disable);
spin_lock_irqsave(&musb_reg_clock_lock, flags);
if (unlikely(atomic_read(&clk_prepare_cnt) <= 0)) {
DBG_LIMIT(1, "clock not prepare");
goto exit;
}
if (enable && count == 0) {
if (clk_enable(musb_clk_top_sel)) {
DBG(0, "musb_clk_top_sel enable fail\n");
goto exit;
}
if (clk_enable(musb_clk)) {
DBG(0, "musb_clk enable fail\n");
clk_disable(musb_clk_top_sel);
goto exit;
}
if (clk_enable(musb_ref_clk)) {
DBG(0, "musb_ref_clk enable fail\n");
clk_disable(musb_clk);
clk_disable(musb_clk_top_sel);
goto exit;
}
usb_hal_dpidle_request(USB_DPIDLE_FORBIDDEN);
real_enable++;
} else if (!enable && count == 1) {
clk_disable(musb_clk);
clk_disable(musb_ref_clk);
clk_disable(musb_clk_top_sel);
usb_hal_dpidle_request(USB_DPIDLE_ALLOWED);
real_disable++;
}
if (enable)
count++;
else
count = (count == 0) ? 0 : (count - 1);
exit:
if (enable)
virt_enable++;
else
virt_disable++;
spin_unlock_irqrestore(&musb_reg_clock_lock, flags);
DBG(1, "enable(%d),count(%d), <%d,%d,%d,%d>\n",
enable, count, virt_enable, virt_disable,
real_enable, real_disable);
return 1;
}
EXPORT_SYMBOL(usb_enable_clock);
#ifdef CONFIG_MTK_UART_USB_SWITCH
bool usb_phy_check_in_uart_mode(void)
{
u32 usb_port_mode;
usb_enable_clock(true);
udelay(50);
usb_port_mode = USBPHY_READ32(0x68);
usb_enable_clock(false);
if (((usb_port_mode >> 30) & 0x3) == 1) {
DBG(0, "%s:%d - IN UART MODE : 0x%x\n",
__func__, __LINE__, usb_port_mode);
in_uart_mode = true;
} else {
DBG(0, "%s:%d - NOT IN UART MODE : 0x%x\n",
__func__, __LINE__, usb_port_mode);
in_uart_mode = false;
}
return in_uart_mode;
}
void usb_phy_switch_to_uart(void)
{
unsigned int val = 0;
if (usb_phy_check_in_uart_mode()) {
DBG(0, "Already in UART mode.\n");
return;
}
udelay(50);
/* RG_USB20_BC11_SW_EN 0x11F4_0818[23] = 1'b0 */
USBPHY_CLR32(0x18, (0x1 << 23));
/* Set RG_SUSPENDM 0x11F4_0868[3] to 1 */
USBPHY_SET32(0x68, (0x1 << 3));
/* force suspendm 0x11F4_0868[18] = 1 */
USBPHY_SET32(0x68, (0x1 << 18));
/* Set rg_uart_mode 0x11F4_0868[31:30] to 2'b01 */
USBPHY_CLR32(0x68, (0x3 << 30));
USBPHY_SET32(0x68, (0x1 << 30));
/* force_uart_i 0x11F4_0868[29] = 0*/
USBPHY_CLR32(0x68, (0x1 << 29));
/* force_uart_bias_en 0x11F4_0868[28] = 1 */
USBPHY_SET32(0x68, (0x1 << 28));
/* force_uart_tx_oe 0x11F4_0868[27] = 1 */
USBPHY_SET32(0x68, (0x1 << 27));
/* force_uart_en 0x11F4_0868[26] = 1 */
USBPHY_SET32(0x68, (0x1 << 26));
/* RG_UART_BIAS_EN 0x11F4_086c[18] = 1 */
USBPHY_SET32(0x6C, (0x1 << 18));
/* RG_UART_TX_OE 0x11F4_086c[17] = 1 */
USBPHY_SET32(0x6C, (0x1 << 17));
/* Set RG_UART_EN to 1 */
USBPHY_SET32(0x6C, (0x1 << 16));
/* Set RG_USB20_DM_100K_EN to 1 */
USBPHY_SET32(0x20, (0x1 << 17));
/* RG_DPPULLDOWN, 1'b0, RG_DMPULLDOWN, 1'b0 */
USBPHY_CLR32(0x68, ((0x1 << 6) | (0x1 << 7)));
/* GPIO Selection */
val = readl(ap_gpio_base);
writel(val & (~(GPIO_SEL_MASK)), ap_gpio_base);
val = readl(ap_gpio_base);
writel(val | (GPIO_SEL_UART0), ap_gpio_base);
in_uart_mode = true;
}
void usb_phy_switch_to_usb(void)
{
unsigned int val = 0;
/* GPIO Selection */
val = readl(ap_gpio_base);
writel(val & (~(GPIO_SEL_MASK)), ap_gpio_base);
/* clear force_uart_en */
USBPHY_CLR32(0x68, (0x1 << 26));
/* Set rg_uart_mode 0x11F4_0868[31:30] to 2'b00 */
USBPHY_CLR32(0x68, (0x3 << 30));
in_uart_mode = false;
usb_phy_poweron();
}
#endif
void set_usb_phy_mode(int mode)
{
switch (mode) {
case PHY_MODE_USB_DEVICE:
/* VBUSVALID=1, AVALID=1, BVALID=1, SESSEND=0, IDDIG=1, IDPULLUP=1 */
USBPHY_CLR32(0x6C, (0x10<<0));
USBPHY_SET32(0x6C, (0x2F<<0));
USBPHY_SET32(0x6C, (0x3F<<8));
break;
case PHY_MODE_USB_HOST:
/* VBUSVALID=1, AVALID=1, BVALID=1, SESSEND=0, IDDIG=0, IDPULLUP=1 */
USBPHY_CLR32(0x6c, (0x12<<0));
USBPHY_SET32(0x6c, (0x2d<<0));
USBPHY_SET32(0x6c, (0x3f<<8));
break;
case PHY_MODE_INVALID:
/* VBUSVALID=0, AVALID=0, BVALID=0, SESSEND=1, IDDIG=0, IDPULLUP=1 */
USBPHY_SET32(0x6c, (0x11<<0));
USBPHY_CLR32(0x6c, (0x2e<<0));
USBPHY_SET32(0x6c, (0x3f<<8));
break;
default:
DBG(0, "mode error %d\n", mode);
}
DBG(0, "force PHY to mode %d, 0x6c=%x\n", mode, USBPHY_READ32(0x6c));
}
void usb_rev6_setting(int value)
{
static int direct_return;
if (direct_return)
return;
/* RG_USB20_PHY_REV[7:0] = 8'b01000000 */
USBPHY_CLR32(0x18, (0xFF << 24));
if (value)
USBPHY_SET32(0x18, (value << 24));
else
direct_return = 1;
}
/* M17_USB_PWR Sequence 20160603.xls */
void usb_phy_poweron(void)
{
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (in_uart_mode) {
DBG(0, "At UART mode. No %s\n", __func__);
return;
}
#endif
/* wait 50 usec for PHY3.3v/1.8v stable. */
udelay(50);
/* RG_USB20_PLL_PREDIV[1:0]=2'b00 */
USBPHY_CLR32(0x00, (0x3 << 6));
/* RG_USB20_PLL_FBDIV[21:0]=22'd1814843 */
USBPHY_CLR32(0x30, (0x3fffff << 0));
USBPHY_SET32(0x30, (0x1bb13b << 0));
/* RG_USB20_PLL_FRA_EN=1'b1 */
USBPHY_SET32(0x44, (0x1 << 3));
/* RG_USB20_PLL_ REFCLK_SEL=1'b1 */
USBPHY_SET32(0x44, (0x1 << 5));
/* RG_USB20_PLL_BW[2:0]=3'b011 */
USBPHY_CLR32(0x08, (0x7 << 19));
USBPHY_SET32(0x08, (0x3 << 19));
/*
* force_uart_en 1'b0 0x68 26
* RG_UART_EN 1'b0 0x6c 16
* rg_usb20_gpio_ctl 1'b0 0x20 09
* usb20_gpio_mode 1'b0 0x20 08
* RG_USB20_BC11_SW_EN 1'b0 0x18 23
* rg_usb20_dp_100k_mode 1'b1 0x20 18
* USB20_DP_100K_EN 1'b0 0x20 16
* RG_USB20_DM_100K_EN 1'b0 0x20 17
* RG_USB20_OTG_VBUSCMP_EN 1'b1 0x18 20
* force_suspendm 1'b0 0x68 18
*/
/* force_uart_en, 1'b0 */
USBPHY_CLR32(0x68, (0x1 << 26));
/* RG_UART_EN, 1'b0 */
USBPHY_CLR32(0x6c, (0x1 << 16));
/* rg_usb20_gpio_ctl, 1'b0, usb20_gpio_mode, 1'b0 */
USBPHY_CLR32(0x20, ((0x1 << 9) | (0x1 << 8)));
/* RG_USB20_BC11_SW_EN, 1'b0 */
USBPHY_CLR32(0x18, (0x1 << 23));
/* rg_usb20_dp_100k_mode, 1'b1 */
USBPHY_SET32(0x20, (0x1 << 18));
/* USB20_DP_100K_EN 1'b0, RG_USB20_DM_100K_EN, 1'b0 */
USBPHY_CLR32(0x20, ((0x1 << 16) | (0x1 << 17)));
/* RG_USB20_OTG_VBUSCMP_EN, 1'b1 */
USBPHY_SET32(0x18, (0x1 << 20));
/* force_suspendm, 1'b0 */
USBPHY_CLR32(0x68, (0x1 << 18));
/* RG_USB20_PHY_REV[7:0] = 8'b01000000 */
USBPHY_CLR32(0x18, (0xFF << 24));
USBPHY_SET32(0x18, (0x40 << 24));
/* wait for 800 usec. */
udelay(800);
DBG(0, "usb power on success\n");
}
/* M17_USB_PWR Sequence 20160603.xls */
void usb_phy_savecurrent_internal(void)
{
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (in_uart_mode) {
DBG(0, "At UART mode. No %s\n", __func__);
return;
}
#endif
/*
* force_uart_en 1'b0 0x68 26
* RG_UART_EN 1'b0 0x6c 16
* rg_usb20_gpio_ctl 1'b0 0x20 09
* usb20_gpio_mode 1'b0 0x20 08
* RG_USB20_BC11_SW_EN 1'b0 0x18 23
* RG_USB20_OTG_VBUSCMP_EN 1'b0 0x18 20
* RG_SUSPENDM 1'b1 0x68 03
* force_suspendm 1'b1 0x68 18
* RG_DPPULLDOWN 1'b1 0x68 06
* RG_DMPULLDOWN 1'b1 0x68 07
* RG_XCVRSEL[1:0] 2'b01 0x68 [04-05]
* RG_TERMSEL 1'b1 0x68 02
* RG_DATAIN[3:0] 4'b0000 0x68 [10-13]
* force_dp_pulldown 1'b1 0x68 20
* force_dm_pulldown 1'b1 0x68 21
* force_xcversel 1'b1 0x68 19
* force_termsel 1'b1 0x68 17
* force_datain 1'b1 0x68 23
* RG_SUSPENDM 1'b0 0x68 03
*/
/* force_uart_en, 1'b0 */
USBPHY_CLR32(0x68, (0x1 << 26));
/* RG_UART_EN, 1'b0 */
USBPHY_CLR32(0x6c, (0x1 << 16));
/* rg_usb20_gpio_ctl, 1'b0, usb20_gpio_mode, 1'b0 */
USBPHY_CLR32(0x20, (0x1 << 9));
USBPHY_CLR32(0x20, (0x1 << 8));
/* RG_USB20_BC11_SW_EN, 1'b0 */
USBPHY_CLR32(0x18, (0x1 << 23));
/* RG_USB20_OTG_VBUSCMP_EN, 1'b0 */
USBPHY_CLR32(0x18, (0x1 << 20));
/* RG_SUSPENDM, 1'b1 */
USBPHY_SET32(0x68, (0x1 << 3));
/* force_suspendm, 1'b1 */
USBPHY_SET32(0x68, (0x1 << 18));
/* RG_DPPULLDOWN, 1'b1, RG_DMPULLDOWN, 1'b1 */
USBPHY_SET32(0x68, ((0x1 << 6) | (0x1 << 7)));
/* RG_XCVRSEL[1:0], 2'b01. */
USBPHY_CLR32(0x68, (0x3 << 4));
USBPHY_SET32(0x68, (0x1 << 4));
/* RG_TERMSEL, 1'b1 */
USBPHY_SET32(0x68, (0x1 << 2));
/* RG_DATAIN[3:0], 4'b0000 */
USBPHY_CLR32(0x68, (0xF << 10));
/* force_dp_pulldown, 1'b1, force_dm_pulldown, 1'b1,
* force_xcversel, 1'b1, force_termsel, 1'b1, force_datain, 1'b1
*/
USBPHY_SET32(0x68, ((0x1 << 20) | (0x1 << 21) |
(0x1 << 19) | (0x1 << 17) | (0x1 << 23)));
udelay(800);
/* RG_SUSPENDM, 1'b0 */
USBPHY_CLR32(0x68, (0x1 << 3));
udelay(1);
set_usb_phy_mode(PHY_MODE_INVALID);
}
void usb_phy_savecurrent(void)
{
usb_phy_savecurrent_internal();
DBG(0, "usb save current success\n");
}
EXPORT_SYMBOL(usb_phy_savecurrent);
/* M17_USB_PWR Sequence 20160603.xls */
void usb_phy_recover(void)
{
unsigned int efuse_val = 0;
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (in_uart_mode) {
DBG(0, "At UART mode. No %s\n", __func__);
return;
}
#endif
/* wait 50 usec. */
udelay(50);
/* RG_USB20_PLL_PREDIV[1:0]=2'b00 */
USBPHY_CLR32(0x00, (0x3 << 6));
/* RG_USB20_PLL_FBDIV[21:0]=22'd1814843 */
USBPHY_CLR32(0x30, (0x3fffff << 0));
USBPHY_SET32(0x30, (0x1bb13b << 0));
/* RG_USB20_PLL_FRA_EN=1'b1 */
USBPHY_SET32(0x44, (0x1 << 3));
/* RG_USB20_PLL_ REFCLK_SEL=1'b1 */
USBPHY_SET32(0x44, (0x1 << 5));
/* RG_USB20_PLL_BW[2:0]=3'b011 */
USBPHY_CLR32(0x08, (0x7 << 19));
USBPHY_SET32(0x08, (0x3 << 19));
/*
* 04.force_uart_en 1'b0 0x68 26
* 04.RG_UART_EN 1'b0 0x6C 16
* 04.rg_usb20_gpio_ctl 1'b0 0x20 09
* 04.usb20_gpio_mode 1'b0 0x20 08
* 05.force_suspendm 1'b0 0x68 18
* 06.RG_DPPULLDOWN 1'b0 0x68 06
* 07.RG_DMPULLDOWN 1'b0 0x68 07
* 08.RG_XCVRSEL[1:0] 2'b00 0x68 [04:05]
* 09.RG_TERMSEL 1'b0 0x68 02
* 10.RG_DATAIN[3:0] 4'b0000 0x68 [10:13]
* 11.force_dp_pulldown 1'b0 0x68 20
* 12.force_dm_pulldown 1'b0 0x68 21
* 13.force_xcversel 1'b0 0x68 19
* 14.force_termsel 1'b0 0x68 17
* 15.force_datain 1'b0 0x68 23
* 16.RG_USB20_BC11_SW_EN 1'b0 0x18 23
* 17.RG_USB20_OTG_VBUSCMP_EN 1'b1 0x18 20
*/
/* clean PUPD_BIST_EN */
/* PUPD_BIST_EN = 1'b0 */
/* PMIC will use it to detect charger type */
/* NEED?? USBPHY_CLR8(0x1d, 0x10);*/
USBPHY_CLR32(0x1c, (0x1 << 12));
/* force_uart_en, 1'b0 */
USBPHY_CLR32(0x68, (0x1 << 26));
/* RG_UART_EN, 1'b0 */
USBPHY_CLR32(0x6C, (0x1 << 16));
/* rg_usb20_gpio_ctl, 1'b0, usb20_gpio_mode, 1'b0 */
USBPHY_CLR32(0x20, (0x1 << 9));
USBPHY_CLR32(0x20, (0x1 << 8));
/* force_suspendm, 1'b0 */
USBPHY_CLR32(0x68, (0x1 << 18));
/* RG_DPPULLDOWN, 1'b0, RG_DMPULLDOWN, 1'b0 */
USBPHY_CLR32(0x68, ((0x1 << 6) | (0x1 << 7)));
/* RG_XCVRSEL[1:0], 2'b00. */
USBPHY_CLR32(0x68, (0x3 << 4));
/* RG_TERMSEL, 1'b0 */
USBPHY_CLR32(0x68, (0x1 << 2));
/* RG_DATAIN[3:0], 4'b0000 */
USBPHY_CLR32(0x68, (0xF << 10));
/* force_dp_pulldown, 1'b0, force_dm_pulldown, 1'b0,
* force_xcversel, 1'b0, force_termsel, 1'b0, force_datain, 1'b0
*/
USBPHY_CLR32(0x68, ((0x1 << 20) | (0x1 << 21) |
(0x1 << 19) | (0x1 << 17) | (0x1 << 23)));
/* RG_USB20_BC11_SW_EN, 1'b0 */
USBPHY_CLR32(0x18, (0x1 << 23));
/* RG_USB20_OTG_VBUSCMP_EN, 1'b1 */
USBPHY_SET32(0x18, (0x1 << 20));
/* RG_USB20_PHY_REV[7:0] = 8'b01000000 */
usb_rev6_setting(0x40);
/* wait 800 usec. */
udelay(800);
/* force enter device mode */
set_usb_phy_mode(PHY_DEV_ACTIVE);
/* M_ANALOG8[4:0] => RG_USB20_INTR_CAL[4:0] */
efuse_val = (get_devinfo_with_index(107) & (0x1f<<0)) >> 0;
if (efuse_val) {
DBG(0, "apply efuse setting, RG_USB20_INTR_CAL=0x%x\n",
efuse_val);
USBPHY_CLR32(0x04, (0x1F<<19));
USBPHY_SET32(0x04, (efuse_val<<19));
}
/* RG_USB20_DISCTH[7:4], 4'b0111 for 700 mV */
USBPHY_CLR32(0x18, (0xf0<<0));
USBPHY_SET32(0x18, (0x70<<0));
USBPHY_SET32(0x18, (0x1<<28));
USBPHY_CLR32(0x18, (0xf<<0));
USBPHY_SET32(0x18, (0x5<<0));
usb_phy_tuning();
DBG(0, "usb recovery success\n");
}
EXPORT_SYMBOL(usb_phy_recover);
/* BC1.2 */
void Charger_Detect_Init(void)
{
#if 0
if ((get_boot_mode() == META_BOOT) ||
(get_boot_mode() == ADVMETA_BOOT) ||
!mtk_musb) {
DBG(0, "%s Skip, musb<%p>\n",
__func__, mtk_musb);
return;
}
#endif
usb_prepare_enable_clock(true);
/* wait 50 usec. */
udelay(50);
/* RG_USB20_BC11_SW_EN = 1'b1 */
USBPHY_SET32(0x18, (0x1 << 23));
usb_prepare_enable_clock(false);
DBG(0, "%s\n", __func__);
}
EXPORT_SYMBOL(Charger_Detect_Init);
void Charger_Detect_Release(void)
{
#if 0
if ((get_boot_mode() == META_BOOT) ||
(get_boot_mode() == ADVMETA_BOOT) ||
!mtk_musb) {
DBG(0, "%s Skip, musb<%p>\n",
__func__, mtk_musb);
return;
}
#endif
usb_prepare_enable_clock(true);
/* RG_USB20_BC11_SW_EN = 1'b0 */
USBPHY_CLR32(0x18, (0x1 << 23));
udelay(1);
usb_prepare_enable_clock(false);
DBG(0, "%s\n", __func__);
}
EXPORT_SYMBOL(Charger_Detect_Release);
void usb_phy_context_save(void)
{
#ifdef CONFIG_MTK_UART_USB_SWITCH
in_uart_mode = usb_phy_check_in_uart_mode();
#endif
}
void usb_phy_context_restore(void)
{
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (in_uart_mode)
usb_phy_switch_to_uart();
#endif
}
void usb_dpdm_pulldown(bool enable)
{
DBG(0, "%s: enable=%d\n", __func__, enable);
usb_prepare_enable_clock(true);
/* wait 50 usec. */
udelay(50);
if (enable) {
/* RG_DPPULLDOWN, 1'b1, RG_DMPULLDOWN, 1'b1 */
USBPHY_SET32(0x68, (0x1 << 6) | (0x1 << 7));
/* RG_USB20_PHY_REV */
USBPHY_CLR32(0x18, (0x2 << 24));
} else {
/* RG_DPPULLDOWN, 1'b0, RG_DMPULLDOWN, 1'b0 */
USBPHY_CLR32(0x68, (0x1 << 6) | (0x1 << 7));
/* RG_USB20_PHY_REV */
USBPHY_SET32(0x18, (0x2 << 24));
}
usb_prepare_enable_clock(false);
DBG(0, "%s\n", __func__);
}
#endif