Files
android/drivers/misc/mediatek/mu3d/drv/mtk_usb.c
T
threeeye bc1d038eac REVVL 6 Pro kernel bring-up: full working tree snapshot (2026-09-12)
Squashed backup commit (no shallow-clone history issues) of
xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream
commit 9eece662e) plus all fixes applied to get everpal_defconfig building
clean against a modern (GCC 15.2.0) toolchain -- see the previous commit
message on the lineage-23.2 branch (also in this repo history is not
available here since this is a squashed snapshot; full incremental history
lives in the local DL380 checkout and the upstream GitHub remote).

Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
2026-09-12 13:36:46 +00:00

932 lines
23 KiB
C

/*
* Copyright (C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
#include <linux/usb/gadget.h>
/*#include "mach/emi_mpu.h"*/
#include "mu3d_hal_osal.h"
#include "musb_core.h"
#if defined(CONFIG_MTK_UART_USB_SWITCH) || defined(CONFIG_MTK_SIB_USB_SWITCH)
#include "mtk-phy-asic.h"
/*#include <mach/mt_typedefs.h>*/
#endif
#ifdef CONFIG_PHY_MTK_SSUSB
#include "mtk-ssusb-hal.h"
#endif
unsigned int cable_mode = CABLE_MODE_NORMAL;
#ifdef CONFIG_MTK_UART_USB_SWITCH
u32 port_mode = PORT_MODE_USB;
u32 sw_tx;
u32 sw_rx;
u32 sw_uart_path;
#endif
/* ================================ */
/* connect and disconnect functions */
/* ================================ */
bool mt_usb_is_device(void)
{
#if !defined(CONFIG_FPGA_EARLY_PORTING) && defined(CONFIG_USB_XHCI_MTK)
bool tmp = mtk_is_host_mode();
os_printk(K_DEBUG, "%s mode\n", tmp ? "HOST" : "DEV");
return !tmp;
#else
return true;
#endif
}
enum status { INIT, ON, OFF };
#ifdef CONFIG_USBIF_COMPLIANCE
static enum status connection_work_dev_status = INIT;
void init_connection_work(void)
{
connection_work_dev_status = INIT;
}
#endif
#ifndef CONFIG_USBIF_COMPLIANCE
struct timespec connect_timestamp = { 0, 0 };
void set_connect_timestamp(void)
{
connect_timestamp = current_kernel_time();
pr_debug("set timestamp = %llu\n", timespec_to_ns(&connect_timestamp));
}
void clr_connect_timestamp(void)
{
connect_timestamp.tv_sec = 0;
connect_timestamp.tv_nsec = 0;
pr_debug("clr timestamp = %llu\n", timespec_to_ns(&connect_timestamp));
}
struct timespec get_connect_timestamp(void)
{
pr_debug("get timestamp = %llu\n", timespec_to_ns(&connect_timestamp));
return connect_timestamp;
}
#endif
static bool __usb_cable_connected(int ops);
void connection_work(struct work_struct *data)
{
struct musb *musb = _mu3d_musb;
#ifndef CONFIG_USBIF_COMPLIANCE
static enum status connection_work_dev_status = INIT;
#endif
bool is_usb_cable;
struct mt_usb_work *work =
container_of(data, struct mt_usb_work, dwork.work);
/* delay 100ms if user space is not ready to set usb function */
if (!is_usb_rdy()) {
static DEFINE_RATELIMIT_STATE(ratelimit, 1 * HZ, 5);
int delay = 50;
if (__ratelimit(&ratelimit))
os_printk(K_INFO, "%s, !is_usb_rdy, delay %d ms\n", __func__, delay);
/* to DISCONNECT stage to avoid stage transition while usb is ready */
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (in_uart_mode) {
os_printk(K_INFO, "%s, Uart mode. directly return\n", __func__);
goto exit;
}
#endif
#ifndef CONFIG_FPGA_EARLY_PORTING
if (!mt_usb_is_device()) {
os_printk(K_INFO, "%s, Host mode. directly return\n", __func__);
goto exit;
}
#endif
if (connection_work_dev_status != OFF) {
connection_work_dev_status = OFF;
#ifndef CONFIG_USBIF_COMPLIANCE
clr_connect_timestamp();
#endif
/*FIXME: we should use usb_gadget_disconnect() & usb_udc_stop(). like usb_udc_softconn_store().
* But have no time to think how to handle. However i think it is the correct way.
*/
musb_stop(musb);
if (musb->usb_wakelock.active)
__pm_relax(&musb->usb_wakelock);
#ifdef VCORE_OPS_DEV
vcore_op(0);
#endif
os_printk(K_INFO, "%s ----Disconnect----\n", __func__);
}
queue_delayed_work(musb->st_wq, &work->dwork,
msecs_to_jiffies(delay));
return;
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (!usb_phy_check_in_uart_mode()) {
#endif
#ifndef CONFIG_FPGA_EARLY_PORTING
if (!mt_usb_is_device()) {
connection_work_dev_status = OFF;
#ifdef CONFIG_PHY_MTK_SSUSB
if (musb->is_clk_on)
phy_power_off(musb->mtk_phy);
#else
usb_fake_powerdown(musb->is_clk_on);
#endif
musb->is_clk_on = 0;
os_printk(K_INFO, "%s, Host mode. directly return\n", __func__);
goto exit;
}
#endif
is_usb_cable = __usb_cable_connected(work->ops);
os_printk(K_INFO, "%s musb %s, cable %s\n", __func__,
((connection_work_dev_status ==
0) ? "INIT" : ((connection_work_dev_status == 1) ? "ON" : "OFF")),
(is_usb_cable ? "IN" : "OUT"));
if ((is_usb_cable == true) && (connection_work_dev_status != ON)) {
connection_work_dev_status = ON;
#ifndef CONFIG_USBIF_COMPLIANCE
set_connect_timestamp();
#endif
if (!musb->usb_wakelock.active)
__pm_stay_awake(&musb->usb_wakelock);
/* FIXME: Should use usb_udc_start() & usb_gadget_connect(), like usb_udc_softconn_store().
* But have no time to think how to handle. However i think it is the correct way.
*/
#ifdef VCORE_OPS_DEV
vcore_op(1);
#endif
musb_start(musb);
os_printk(K_INFO, "%s ----Connect----\n", __func__);
} else if ((is_usb_cable == false) && (connection_work_dev_status != OFF)) {
connection_work_dev_status = OFF;
#ifndef CONFIG_USBIF_COMPLIANCE
clr_connect_timestamp();
#endif
/*FIXME: we should use usb_gadget_disconnect() & usb_udc_stop(). like usb_udc_softconn_store().
* But have no time to think how to handle. However i think it is the correct way.
*/
musb_stop(musb);
if (musb->usb_wakelock.active)
__pm_relax(&musb->usb_wakelock);
#ifdef VCORE_OPS_DEV
vcore_op(0);
#endif
os_printk(K_INFO, "%s ----Disconnect----\n", __func__);
} else {
/* This if-elseif is to set wakelock when booting with USB cable.
* Because battery driver does _NOT_ notify at this codition.
*/
/* if( (is_usb_cable == true) && !wake_lock_active(&musb->usb_wakelock)) { */
/* os_printk(K_INFO, "%s Boot wakelock\n", __func__); */
/* __pm_stay_awake(&musb->usb_wakelock); */
/* } else if( (is_usb_cable == false) && wake_lock_active(&musb->usb_wakelock)) { */
/* os_printk(K_INFO, "%s Boot unwakelock\n", __func__); */
/* __pm_relax(&musb->usb_wakelock); */
/* } */
os_printk(K_INFO, "%s ----directly return----\n", __func__);
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
} else {
#if 0
usb_fake_powerdown(musb->is_clk_on);
musb->is_clk_on = 0;
#else
os_printk(K_INFO, "%s, in UART MODE!!!\n", __func__);
#endif
}
#endif
#ifndef CONFIG_FPGA_EARLY_PORTING
exit:
#endif
/* free mt_usb_work */
kfree(work);
}
bool mt_usb_is_ready(void)
{
os_printk(K_INFO, "USB is ready or not\n");
#ifdef NEVER
if (!mtk_musb || !mtk_musb->is_ready)
return false;
else
return true;
#endif /* NEVER */
return true;
}
static void issue_connection_work(int ops)
{
struct mt_usb_work *work;
if (!_mu3d_musb) {
os_printk(K_INFO, "_mu3d_musb = NULL\n");
return;
}
/* create and prepare worker */
work = kzalloc(sizeof(struct mt_usb_work), GFP_ATOMIC);
if (!work)
return;
work->ops = ops;
INIT_DELAYED_WORK(&work->dwork, connection_work);
/* issue connection work */
os_printk(K_INFO, "issue work, ops<%d>\n", ops);
queue_delayed_work(_mu3d_musb->st_wq, &work->dwork, 0);
}
void mt_usb_connect(void)
{
os_printk(K_INFO, "%s\n", __func__);
issue_connection_work(CONNECTION_OPS_CONN);
}
void mt_usb_disconnect(void)
{
os_printk(K_INFO, "%s\n", __func__);
issue_connection_work(CONNECTION_OPS_DISC);
}
void mt_usb_reconnect(void)
{
os_printk(K_INFO, "%s\n", __func__);
issue_connection_work(CONNECTION_OPS_CHECK);
}
/* build time force on */
#if defined(CONFIG_FPGA_EARLY_PORTING)
#define BYPASS_PMIC_LINKAGE
#endif
/* to avoid build error due to PMIC module not ready */
#ifndef CONFIG_MTK_CHARGER
#define BYPASS_PMIC_LINKAGE
#endif
static enum charger_type mu3d_hal_get_charger_type(void)
{
enum charger_type chg_type;
#ifdef BYPASS_PMIC_LINKAGE
os_printk(K_INFO, "force on");
chg_type = STANDARD_HOST;
#else
chg_type = mt_get_charger_type();
#endif
return chg_type;
}
static bool mu3d_hal_is_vbus_exist(void)
{
bool vbus_exist;
#ifdef BYPASS_PMIC_LINKAGE
os_printk(K_INFO, "force on");
vbus_exist = true;
#else
#ifdef CONFIG_POWER_EXT
vbus_exist = upmu_get_rgs_chrdet();
#else
vbus_exist = upmu_is_chr_det();
#endif
#endif
return vbus_exist;
}
static struct delayed_work disconnect_check_work;
static bool mu3d_hal_is_vbus_exist(void);
void do_disconnect_check_work(struct work_struct *data)
{
bool vbus_exist = false;
unsigned long flags = 0;
struct musb *musb = _mu3d_musb;
msleep(200);
vbus_exist = mu3d_hal_is_vbus_exist();
os_printk(K_INFO, "vbus_exist:<%d>\n", vbus_exist);
if (vbus_exist)
return;
spin_lock_irqsave(&musb->lock, flags);
os_printk(K_INFO, "speed <%d>\n", musb->g.speed);
/* notify gadget driver, g.speed judge is very important */
if (!musb->is_host && musb->g.speed != USB_SPEED_UNKNOWN) {
os_printk(K_INFO, "musb->gadget_driver:%p\n", musb->gadget_driver);
if (musb->gadget_driver && musb->gadget_driver->disconnect) {
os_printk(K_INFO, "musb->gadget_driver->disconnect:%p\n", musb->gadget_driver->disconnect);
/* align musb_g_disconnect */
spin_unlock(&musb->lock);
musb->gadget_driver->disconnect(&musb->g);
spin_lock(&musb->lock);
}
musb->g.speed = USB_SPEED_UNKNOWN;
}
os_printk(K_INFO, "speed <%d>\n", musb->g.speed);
spin_unlock_irqrestore(&musb->lock, flags);
}
void trigger_disconnect_check_work(void)
{
static int inited;
if (!mu3d_force_on)
return;
if (!inited) {
INIT_DELAYED_WORK(&disconnect_check_work, do_disconnect_check_work);
inited = 1;
}
queue_delayed_work(_mu3d_musb->st_wq, &disconnect_check_work, 0);
}
static int mu3d_test_connect;
static struct delayed_work mu3d_test_connect_work;
#define TEST_CONNECT_BASE_MS 3000
#define TEST_CONNECT_BIAS_MS 5000
static void do_mu3d_test_connect_work(struct work_struct *work)
{
static ktime_t ktime;
static unsigned long int ktime_us;
unsigned int delay_time_ms;
static bool test_connected;
if (!mu3d_test_connect) {
test_connected = false;
os_printk(K_INFO, "%s, test done, trigger connect\n", __func__);
mt_usb_connect();
return;
}
if (test_connected)
mt_usb_connect();
else
mt_usb_disconnect();
ktime = ktime_get();
ktime_us = ktime_to_us(ktime);
delay_time_ms = TEST_CONNECT_BASE_MS + (ktime_us % TEST_CONNECT_BIAS_MS);
os_printk(K_INFO, "%s, work after %d ms\n", __func__, delay_time_ms);
schedule_delayed_work(&mu3d_test_connect_work, msecs_to_jiffies(delay_time_ms));
test_connected = !test_connected;
}
void mt_usb_connect_test(int start)
{
static struct wakeup_source device_test_wakelock;
static int wake_lock_inited;
if (!wake_lock_inited) {
os_printk(K_WARNIN, "%s wake_lock_init\n", __func__);
wakeup_source_init(&device_test_wakelock, "device.test.lock");
wake_lock_inited = 1;
}
if (start) {
__pm_stay_awake(&device_test_wakelock);
mu3d_test_connect = 1;
INIT_DELAYED_WORK(&mu3d_test_connect_work, do_mu3d_test_connect_work);
schedule_delayed_work(&mu3d_test_connect_work, 0);
} else {
mu3d_test_connect = 0;
__pm_relax(&device_test_wakelock);
}
}
bool usb_cable_connected(void)
{
return __usb_cable_connected(CONNECTION_OPS_CHECK);
}
static bool __usb_cable_connected(int ops)
{
enum charger_type chg_type = CHARGER_UNKNOWN;
bool connected = false, vbus_exist = false;
if (mu3d_force_on) {
/* FORCE USB ON */
chg_type = _mu3d_musb->charger_mode = STANDARD_HOST;
vbus_exist = true;
connected = true;
os_printk(K_INFO, "%s type force to STANDARD_HOST\n", __func__);
} else {
/* TYPE CHECK*/
chg_type = _mu3d_musb->charger_mode = mu3d_hal_get_charger_type();
if (fake_CDP && chg_type == STANDARD_HOST) {
os_printk(K_INFO, "%s, fake to type 2\n", __func__);
chg_type = CHARGING_HOST;
}
if (chg_type == STANDARD_HOST || chg_type == CHARGING_HOST)
connected = true;
/* connected according to CONNECTION_OPS */
if (ops != CONNECTION_OPS_CHECK)
connected = CONNECTION_OPS_CONN ? true : false;
/* VBUS CHECK to avoid type miss-judge */
vbus_exist = mu3d_hal_is_vbus_exist();
os_printk(K_INFO, "%s vbus_exist=%d type=%d ops=%d\n",
__func__, vbus_exist, chg_type, ops);
if (!vbus_exist)
connected = false;
}
/* CMODE CHECK */
if (cable_mode == CABLE_MODE_CHRG_ONLY || (cable_mode == CABLE_MODE_HOST_ONLY && chg_type != CHARGING_HOST))
connected = false;
os_printk(K_INFO, "%s, connected:%d, cable_mode:%d\n", __func__, connected, cable_mode);
return connected;
}
EXPORT_SYMBOL_GPL(usb_cable_connected);
#ifdef NEVER
void musb_platform_reset(struct musb *musb)
{
u16 swrst = 0;
void __iomem *mbase = musb->mregs;
swrst = musb_readw(mbase, MUSB_SWRST);
swrst |= (MUSB_SWRST_DISUSBRESET | MUSB_SWRST_SWRST);
musb_writew(mbase, MUSB_SWRST, swrst);
}
#endif /* NEVER */
void musb_sync_with_bat(struct musb *musb, int usb_state)
{
os_printk(K_DEBUG, "musb_sync_with_bat\n");
#ifndef CONFIG_FPGA_EARLY_PORTING
#if defined(CONFIG_MTK_CHARGER)
BATTERY_SetUSBState(usb_state);
wake_up_bat();
#endif
#endif
}
EXPORT_SYMBOL_GPL(musb_sync_with_bat);
/*--FOR INSTANT POWER ON USAGE--------------------------------------------------*/
static inline struct musb *dev_to_musb(struct device *dev)
{
return dev_get_drvdata(dev);
}
const char *const usb_mode_str[CABLE_MODE_MAX] = { "CHRG_ONLY", "NORMAL", "HOST_ONLY" };
ssize_t musb_cmode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
if (!dev) {
os_printk(K_ERR, "dev is null!!\n");
return 0;
}
return sprintf(buf, "%d\n", cable_mode);
}
ssize_t musb_cmode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int cmode;
struct musb *musb;
if (!dev) {
os_printk(K_ERR, "dev is null!!\n");
return count;
}
musb = dev_to_musb(dev);
if (sscanf(buf, "%ud", &cmode) == 1) {
os_printk(K_INFO, "%s %s --> %s\n", __func__, usb_mode_str[cable_mode],
usb_mode_str[cmode]);
if (cmode >= CABLE_MODE_MAX)
cmode = CABLE_MODE_NORMAL;
if (cable_mode != cmode) {
cable_mode = cmode;
if (_mu3d_musb) {
if (down_interruptible(&_mu3d_musb->musb_lock))
os_printk(K_INFO, "%s: busy, Couldn't get musb_lock\n", __func__);
}
if (cmode == CABLE_MODE_CHRG_ONLY) {
if (musb) {
musb->usb_mode = CABLE_MODE_CHRG_ONLY;
mt_usb_reconnect();
}
} else if (cmode == CABLE_MODE_HOST_ONLY) {
if (musb) {
musb->usb_mode = CABLE_MODE_HOST_ONLY;
mt_usb_reconnect();
}
} else {
if (musb) {
musb->usb_mode = CABLE_MODE_NORMAL;
mt_usb_reconnect();
}
}
/* let work do it's job */
msleep(50);
if (_mu3d_musb)
up(&_mu3d_musb->musb_lock);
}
}
return count;
}
static bool saving_mode;
ssize_t musb_saving_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
if (!dev) {
pr_info("dev is null!!\n");
return 0;
}
return scnprintf(buf, PAGE_SIZE, "%d\n", saving_mode);
}
ssize_t musb_saving_mode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int saving;
long tmp_val;
if (!dev) {
pr_info("dev is null!!\n");
return count;
/* } else if (1 == sscanf(buf, "%d", &saving)) { */
} else if (kstrtol(buf, 10, &tmp_val) == 0) {
saving = tmp_val;
pr_info("old=%d new=%d\n", saving, saving_mode);
if (saving_mode == (!saving))
saving_mode = !saving_mode;
}
return count;
}
bool is_saving_mode(void)
{
pr_info("saving_mode : %d\n", saving_mode);
return saving_mode;
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
ssize_t musb_portmode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
if (!dev) {
pr_debug("dev is null!!\n");
return 0;
}
if (usb_phy_check_in_uart_mode())
port_mode = PORT_MODE_UART;
else
port_mode = PORT_MODE_USB;
if (port_mode == PORT_MODE_USB)
pr_debug("\nUSB Port mode -> USB\n");
else if (port_mode == PORT_MODE_UART)
pr_debug("\nUSB Port mode -> UART\n");
uart_usb_switch_dump_register();
return scnprintf(buf, PAGE_SIZE, "%d\n", port_mode);
}
ssize_t musb_portmode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int portmode;
if (!dev) {
pr_debug("dev is null!!\n");
return count;
} else if (sscanf(buf, "%ud", &portmode) == 1) {
pr_debug("\nUSB Port mode: current => %d (port_mode), change to => %d (portmode)\n",
port_mode, portmode);
if (portmode >= PORT_MODE_MAX)
portmode = PORT_MODE_USB;
if (port_mode != portmode) {
if (portmode == PORT_MODE_USB) { /* Changing to USB Mode */
pr_debug("USB Port mode -> USB\n");
usb_phy_switch_to_usb();
} else if (portmode == PORT_MODE_UART) { /* Changing to UART Mode */
pr_debug("USB Port mode -> UART\n");
usb_phy_switch_to_uart();
}
uart_usb_switch_dump_register();
port_mode = portmode;
}
}
return count;
}
ssize_t musb_tx_show(struct device *dev, struct device_attribute *attr, char *buf)
{
#ifdef CONFIG_PHY_MTK_SSUSB
struct musb *musb;
u32 value;
#endif
u8 var;
u8 var2;
if (!dev) {
pr_debug("dev is null!!\n");
return 0;
}
#ifdef CONFIG_PHY_MTK_SSUSB
musb = dev_to_musb(dev);
value = usb_mtkphy_io_read(musb->mtk_phy, 1, 0x6C);
var = value >> 16;
#else
var = U3PhyReadReg8((u3phy_addr_t) (U3D_U2PHYDTM1 + 0x2));
#endif
var2 = (var >> 3) & ~0xFE;
pr_debug("[MUSB]addr: 0x6E (TX), value: %x - %x\n", var, var2);
sw_tx = var;
return scnprintf(buf, PAGE_SIZE, "%x\n", var2);
}
ssize_t musb_tx_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int val;
#ifdef CONFIG_PHY_MTK_SSUSB
struct musb *musb;
u32 value;
#endif
u8 var;
u8 var2;
if (!dev) {
pr_debug("dev is null!!\n");
return count;
} else if (sscanf(buf, "%ud", &val) == 1) {
pr_debug("\n Write TX : %d\n", val);
#ifdef CONFIG_FPGA_EARLY_PORTING
var = USB_PHY_Read_Register8(U3D_U2PHYDTM1 + 0x2);
#else
#ifdef CONFIG_PHY_MTK_SSUSB
musb = dev_to_musb(dev);
value = usb_mtkphy_io_read(musb->mtk_phy, 1, 0x6C);
var = value >> 16;
#else
var = U3PhyReadReg8((u3phy_addr_t) (U3D_U2PHYDTM1 + 0x2));
#endif
#endif
if (val == 0)
var2 = var & ~(1 << 3);
else
var2 = var | (1 << 3);
#ifdef CONFIG_FPGA_EARLY_PORTING
USB_PHY_Write_Register8(var2, U3D_U2PHYDTM1 + 0x2);
var = USB_PHY_Read_Register8(U3D_U2PHYDTM1 + 0x2);
#else
/* U3PhyWriteField32(U3D_USBPHYDTM1+0x2,
* E60802_RG_USB20_BC11_SW_EN_OFST, E60802_RG_USB20_BC11_SW_EN, 0);
*/
/* Jeremy TODO 0320 */
#ifdef CONFIG_PHY_MTK_SSUSB
musb = dev_to_musb(dev);
value = usb_mtkphy_io_read(musb->mtk_phy, 1, 0x6C);
var = value >> 16;
#else
var = U3PhyReadReg8((u3phy_addr_t) (U3D_U2PHYDTM1 + 0x2));
#endif
#endif
var2 = (var >> 3) & ~0xFE;
pr_debug
("[MUSB]addr: U3D_U2PHYDTM1 (0x6E) TX [AFTER WRITE], value after: %x - %x\n",
var, var2);
sw_tx = var;
}
return count;
}
ssize_t musb_rx_show(struct device *dev, struct device_attribute *attr, char *buf)
{
#ifdef CONFIG_PHY_MTK_SSUSB
struct musb *musb;
u32 value;
#endif
u8 var;
u8 var2;
if (!dev) {
pr_debug("dev is null!!\n");
return 0;
}
#ifdef CONFIG_FPGA_EARLY_PORTING
var = USB_PHY_Read_Register8(U3D_U2PHYDMON1 + 0x3);
#else
#ifdef CONFIG_PHY_MTK_SSUSB
musb = dev_to_musb(dev);
value = usb_mtkphy_io_read(musb->mtk_phy, 1, 0x74);
var = value >> 24;
#else
var = U3PhyReadReg8((u3phy_addr_t) (U3D_U2PHYDMON1 + 0x3));
#endif
#endif
var2 = (var >> 7) & ~0xFE;
pr_debug("[MUSB]addr: U3D_U2PHYDMON1 (0x77) (RX), value: %x - %x\n", var, var2);
sw_rx = var;
return scnprintf(buf, PAGE_SIZE, "%x\n", var2);
}
ssize_t musb_uart_path_show(struct device *dev, struct device_attribute *attr, char *buf)
{
u32 var = 0;
if (!dev) {
pr_debug("dev is null!!\n");
return 0;
}
#ifdef CONFIG_PHY_MTK_SSUSB
var = usb_phy_get_uart_path();
#else
var = DRV_Reg32(ap_uart0_base + 0x600);
#endif
pr_debug("[MUSB]addr: (GPIO Misc) 0x600, value: %x\n\n", var);
sw_uart_path = var;
return scnprintf(buf, PAGE_SIZE, "%x\n", var);
}
#endif
#ifdef CONFIG_MTK_SIB_USB_SWITCH
ssize_t musb_sib_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int ret;
if (!dev) {
pr_debug("dev is null!!\n");
return 0;
}
ret = usb_phy_sib_enable_switch_status();
return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
}
ssize_t musb_sib_enable_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int mode;
if (!dev) {
pr_debug("dev is null!!\n");
return count;
} else if (!kstrtouint(buf, 0, &mode)) {
pr_debug("USB sib_enable: %d\n", mode);
usb_phy_sib_enable_switch(mode);
}
return count;
}
#endif
#ifdef NEVER
#ifdef CONFIG_FPGA_EARLY_PORTING
static struct i2c_client *usb_i2c_client;
static const struct i2c_device_id usb_i2c_id[] = { {"mtk-usb", 0}, {} };
static struct i2c_board_info usb_i2c_dev __initdata = { I2C_BOARD_INFO("mtk-usb", 0x60) };
void USB_PHY_Write_Register8(UINT8 var, UINT8 addr)
{
char buffer[2];
buffer[0] = addr;
buffer[1] = var;
i2c_master_send(usb_i2c_client, &buffer, 2);
}
UINT8 USB_PHY_Read_Register8(UINT8 addr)
{
UINT8 var;
i2c_master_send(usb_i2c_client, &addr, 1);
i2c_master_recv(usb_i2c_client, &var, 1);
return var;
}
static int usb_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
pr_debug("[MUSB]usb_i2c_probe, start\n");
usb_i2c_client = client;
/* disable usb mac suspend */
DRV_WriteReg8(USB_SIF_BASE + 0x86a, 0x00);
/* usb phy initial sequence */
USB_PHY_Write_Register8(0x00, 0xFF);
USB_PHY_Write_Register8(0x04, 0x61);
USB_PHY_Write_Register8(0x00, 0x68);
USB_PHY_Write_Register8(0x00, 0x6a);
USB_PHY_Write_Register8(0x6e, 0x00);
USB_PHY_Write_Register8(0x0c, 0x1b);
USB_PHY_Write_Register8(0x44, 0x08);
USB_PHY_Write_Register8(0x55, 0x11);
USB_PHY_Write_Register8(0x68, 0x1a);
pr_debug("[MUSB]addr: 0xFF, value: %x\n", USB_PHY_Read_Register8(0xFF));
pr_debug("[MUSB]addr: 0x61, value: %x\n", USB_PHY_Read_Register8(0x61));
pr_debug("[MUSB]addr: 0x68, value: %x\n", USB_PHY_Read_Register8(0x68));
pr_debug("[MUSB]addr: 0x6a, value: %x\n", USB_PHY_Read_Register8(0x6a));
pr_debug("[MUSB]addr: 0x00, value: %x\n", USB_PHY_Read_Register8(0x00));
pr_debug("[MUSB]addr: 0x1b, value: %x\n", USB_PHY_Read_Register8(0x1b));
pr_debug("[MUSB]addr: 0x08, value: %x\n", USB_PHY_Read_Register8(0x08));
pr_debug("[MUSB]addr: 0x11, value: %x\n", USB_PHY_Read_Register8(0x11));
pr_debug("[MUSB]addr: 0x1a, value: %x\n", USB_PHY_Read_Register8(0x1a));
pr_debug("[MUSB]usb_i2c_probe, end\n");
return 0;
}
static int usb_i2c_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)
{
strcpy(info->type, "mtk-usb");
return 0;
}
static int usb_i2c_remove(struct i2c_client *client)
{
return 0;
}
struct i2c_driver usb_i2c_driver = {
.probe = usb_i2c_probe,
.remove = usb_i2c_remove,
.detect = usb_i2c_detect,
.driver = {
.name = "mtk-usb",
},
.id_table = usb_i2c_id,
};
int add_usb_i2c_driver(void)
{
int ret = 0;
i2c_register_board_info(0, &usb_i2c_dev, 1);
if (i2c_add_driver(&usb_i2c_driver) != 0) {
pr_debug("[MUSB]usb_i2c_driver initialization failed!!\n");
ret = -1;
} else
pr_debug("[MUSB]usb_i2c_driver initialization succeed!!\n");
return ret;
}
#endif /* End of CONFIG_FPGA_EARLY_PORTING */
#endif /* NEVER */