7、插otg的识别过程

🏰 365bet现场走地盘 📅 2025-08-24 01:32:36 👤 admin 👁️ 7989 👑 777
7、插otg的识别过程

原理分析:OTG的识别主要靠的是ID引脚,当OTG设备插入机器时,会自动将usb的ID pin引脚拉低,从而会触发中断,进而识别出有OTG设备插入。

补充1:

usb id pin一般为1.8v,默认可以连接电脑usb或adb,即机器默认做从设备device。

而usb id pin拉低到0v后,将触发usb切换为host模式,即可以连接otg设备。

过程分析:

在usb20_host.c文件里面

mt_usb_otg_init函数中

void mt_usb_otg_init(struct musb *musb)

{

/* BYPASS OTG function in special mode */

if (get_boot_mode() == META_BOOT

|| get_boot_mode() == KERNEL_POWER_OFF_CHARGING_BOOT

|| get_boot_mode() == LOW_POWER_OFF_CHARGING_BOOT

) {

DBG(0, "in special mode %d\n", get_boot_mode());

return;

}

/* test */

INIT_DELAYED_WORK(&host_plug_test_work, do_host_plug_test_work); // host热拔插测试work

ktime_start = ktime_get();

INIT_DELAYED_WORK(&musb->host_work, musb_host_work); // 初始化了一个延时工作work

/* CONNECTION MANAGEMENT*/

#ifdef CONFIG_USB_C_SWITCH

DBG(0, "host controlled by TYPEC\n");

typec_control = 1;

#ifdef CONFIG_TCPC_CLASS

mutex_init(&tcpc_otg_lock);

mutex_init(&tcpc_otg_pwr_lock);

otg_tcpc_workq = create_singlethread_workqueue("tcpc_otg_workq");

otg_tcpc_power_workq = create_singlethread_workqueue("tcpc_otg_power_workq");

INIT_WORK(&tcpc_otg_power_work, tcpc_otg_power_work_call);

INIT_WORK(&tcpc_otg_work, tcpc_otg_work_call);

INIT_DELAYED_WORK(®ister_otg_work, do_register_otg_work);

queue_delayed_work(mtk_musb->st_wq, ®ister_otg_work, 0);

vbus_control = 0;

#else

typec_host_driver.priv_data = NULL;

register_typec_switch_callback(&typec_host_driver);

vbus_control = 0;

#endif

#else

DBG(0, "host controlled by IDDIG\n");

iddig_int_init(); // 初始化了iddig引脚

vbus_control = 1;

#endif

/* EP table */

musb->fifo_cfg_host = fifo_cfg_host;

musb->fifo_cfg_host_size = ARRAY_SIZE(fifo_cfg_host);

/*

* otg_state.name = "otg_state";

* otg_state.index = 0;

* otg_state.state = 0;

*

* if (switch_dev_register(&otg_state))

* pr_notice("switch_dev_register fail\n");

* else

* pr_debug("switch_dev register success\n");

*/

先看 iddig_int_init 函数

static int iddig_int_init(void)

{

int ret = 0;

ret = platform_driver_register(&otg_iddig_driver); // 平台设备注册了一个otg的driver

if (ret)

DBG(0, "ret:%d\n", ret);

return 0;

}

继续看下 otg_iddig_driver

static const struct of_device_id otg_iddig_of_match[] = {

{.compatible = "mediatek,usb_iddig_bi_eint"}, // 匹配的名字

{},

};

static int otg_iddig_probe(struct platform_device *pdev)

{

int ret;

struct device *dev = &pdev->dev;

struct device_node *node = dev->of_node;

iddig_eint_num = irq_of_parse_and_map(node, 0); // 解析dts里面的中断引脚

DBG(0, "iddig_eint_num<%d>\n", iddig_eint_num);

if (iddig_eint_num < 0)

return -ENODEV;

ret = request_irq(iddig_eint_num, mt_usb_ext_iddig_int, IRQF_TRIGGER_LOW, "USB_IDDIG", NULL);// 申请idd中断 低电平触发

if (ret) {

DBG(0, "request EINT <%d> fail, ret<%d>\n", iddig_eint_num, ret);

return ret;

}

return 0;

}

static struct platform_driver otg_iddig_driver = {

.probe = otg_iddig_probe,

/* .remove = otg_iddig_remove, */

/* .shutdown = otg_iddig_shutdown, */

.driver = {

.name = "otg_iddig",

.owner = THIS_MODULE,

.of_match_table = of_match_ptr(otg_iddig_of_match),

},

};

dts文件里面的内容

otg_iddig: otg_iddig {

compatible = "mediatek,usb_iddig_bi_eint";

};

&otg_iddig {

interrupt-parent = <&pio>;

interrupts = <16 IRQ_TYPE_EDGE_FALLING 16 0>; // 上面的中断其实就是解析这里的16,gpio16

status = "okay";

};

我们看下最重要的中断函数 mt_usb_ext_iddig_int

static irqreturn_t mt_usb_ext_iddig_int(int irq, void *dev_id)

{

iddig_cnt++;

iddig_req_host = !iddig_req_host;

DBG(0, "id pin assert, %s\n", iddig_req_host ? "connect" : "disconnect");

queue_delayed_work(mtk_musb->st_wq, &mtk_musb->host_work, msecs_to_jiffies(sw_deboun_time)); // 调度了延时工作work

disable_irq_nosync(iddig_eint_num);

return IRQ_HANDLED;

}

其实OTG触发中断后就只做了一件事就是调度上面的延时work,下面我们分析一下这个延时work

INIT_DELAYED_WORK(&musb->host_work, musb_host_work); // host干活函数

#define ID_PIN_WORK_RECHECK_TIME 30 /* 30 ms */

#define ID_PIN_WORK_BLOCK_TIMEOUT 30000 /* 30000 ms */

static void musb_host_work(struct work_struct *data) // host延时work

{

u8 devctl = 0;

unsigned long flags;

static int inited, timeout; /* default to 0 */

static s64 diff_time;

int host_mode;

int usb_clk_state = NO_CHANGE;

/* kernel_init_done should be set in early-init stage through init.$platform.usb.rc */

if (!inited && !kernel_init_done && !mtk_musb->is_ready && !timeout) {

ktime_end = ktime_get();

diff_time = ktime_to_ms(ktime_sub(ktime_end, ktime_start));

DBG_LIMIT(3, "init_done:%d, is_ready:%d, inited:%d, TO:%d, diff:%lld",

kernel_init_done, mtk_musb->is_ready, inited, timeout,

diff_time);

if (diff_time > ID_PIN_WORK_BLOCK_TIMEOUT) {

DBG(0, "diff_time:%lld\n", diff_time);

timeout = 1;

}

queue_delayed_work(mtk_musb->st_wq, &mtk_musb->host_work, msecs_to_jiffies(ID_PIN_WORK_RECHECK_TIME));

return;

} else if (!inited) {

DBG(0, "PASS, init_done:%d, is_ready:%d, inited:%d, TO:%d\n",

kernel_init_done, mtk_musb->is_ready, inited, timeout);

}

inited = 1;

/* always prepare clock and check if need to unprepater later */

/* clk_prepare_cnt +1 here */

usb_prepare_clock(true); // 准备usb clk

spin_lock_irqsave(&mtk_musb->lock, flags);

musb_generic_disable(mtk_musb);

spin_unlock_irqrestore(&mtk_musb->lock, flags);

down(&mtk_musb->musb_lock);

DBG(0, "work start, is_host=%d\n", mtk_musb->is_host);

if (mtk_musb->in_ipo_off) {

DBG(0, "do nothing due to in_ipo_off\n");

goto out;

}

/* flip */

if (host_plug_test_triggered)

host_mode = !mtk_musb->is_host;

else

host_mode = musb_is_host(); // 获取usb模式

DBG(0, "musb is as %s\n", host_mode?"host":"device");

/*switch_set_state((struct switch_dev *)&otg_state, host_mode);*/

if (host_mode) { // 如果是host模式,如果插otg就是跑这里

/* switch to HOST state before turn on VBUS */

MUSB_HST_MODE(mtk_musb);

/* to make sure all event clear */

msleep(32);

#ifdef CONFIG_MTK_UAC_POWER_SAVING

if (!usb_on_sram) {

int ret;

ret = gpd_switch_to_sram(mtk_musb->controller);

DBG(0, "gpd_switch_to_sram, ret<%d>\n", ret);

if (ret == 0)

usb_on_sram = 1;

}

#endif

/* setup fifo for host mode */

ep_config_from_table_for_host(mtk_musb);

__pm_stay_awake(&mtk_musb->usb_lock);

/* this make PHY operation workable */

musb_platform_enable(mtk_musb);

/* for no VBUS sensing IP*/

#if 1

/* wait VBUS ready */

msleep(100);

/* clear session*/

devctl = musb_readb(mtk_musb->mregs, MUSB_DEVCTL);

musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, (devctl&(~MUSB_DEVCTL_SESSION)));

set_usb_phy_mode(PHY_IDLE_MODE); // 设置usb phy模式

/* wait */

mdelay(5);

/* restart session */

devctl = musb_readb(mtk_musb->mregs, MUSB_DEVCTL);

musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, (devctl | MUSB_DEVCTL_SESSION));

set_usb_phy_mode(PHY_HOST_ACTIVE);

#endif

musb_start(mtk_musb); // 开始

if (!typec_control && !host_plug_test_triggered)

switch_int_to_device(mtk_musb);

/* for some signal issue */

mdelay(5);

mt_usb_set_vbus(mtk_musb, 1); // 设置vbus电源

if (check_vbus() < 0)

DBG(0, "check vbus fail\n");

if (host_plug_test_enable && !host_plug_test_triggered)

queue_delayed_work(mtk_musb->st_wq, &host_plug_test_work, 0);

usb_clk_state = OFF_TO_ON;

} else { // 如果是device模式

/* for device no disconnect interrupt */

spin_lock_irqsave(&mtk_musb->lock, flags);

if (mtk_musb->is_active) {

DBG(0, "for not receiving disconnect interrupt\n");

usb_hcd_resume_root_hub(musb_to_hcd(mtk_musb));

musb_root_disconnect(mtk_musb);

}

spin_unlock_irqrestore(&mtk_musb->lock, flags);

DBG(1, "devctl is %x\n", musb_readb(mtk_musb->mregs, MUSB_DEVCTL));

musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0);

if (mtk_musb->usb_lock.active)

__pm_relax(&mtk_musb->usb_lock);

mt_usb_set_vbus(mtk_musb, 0);

/* for no VBUS sensing IP */

#if 1

set_usb_phy_mode(PHY_IDLE_MODE);

#endif

musb_stop(mtk_musb);

if (!typec_control && !host_plug_test_triggered)

switch_int_to_host(mtk_musb);

#ifdef CONFIG_MTK_UAC_POWER_SAVING

if (usb_on_sram) {

gpd_switch_to_dram(mtk_musb->controller);

usb_on_sram = 0;

}

#endif

/* to make sure all event clear */

msleep(32);

mtk_musb->xceiv->otg->state = OTG_STATE_B_IDLE;

/* switch to DEV state after turn off VBUS */

MUSB_DEV_MODE(mtk_musb);

usb_clk_state = ON_TO_OFF;

}

out:

DBG(0, "work end, is_host=%d\n", mtk_musb->is_host);

up(&mtk_musb->musb_lock);

if (usb_clk_state == ON_TO_OFF) {

/* clock on -> of: clk_prepare_cnt -2 */

usb_prepare_clock(false);

usb_prepare_clock(false);

} else if (usb_clk_state == NO_CHANGE) {

/* clock no change : clk_prepare_cnt -1 */

usb_prepare_clock(false);

}

}

执行到此,host模式便已经切换ok了,这是otg设备也已经可以识别到了。

下面是插入U盘时的串口log:

[ 243.735713] <0>-(0)[0:swapper/0][MUSB]mt_usb_ext_iddig_int 730: id pin assert, connect USB插入打印

[ 244.146373] <0>.(0)[973:kworker/u8:12][MUSB]musb_host_work 584: PASS, init_done:1, is_ready:1, inited:0, TO:0

[ 244.151959] <0>.(0)[973:kworker/u8:12][MUSB]musb_host_work 598: work start, is_host=0

[ 244.152940] <0>.(0)[973:kworker/u8:12][MUSB]musb_host_work 612: musb is as host

[ 244.193172] <0>.(0)[973:kworker/u8:12][MUSB]mt_usb_enable 298: begin <0,0>,<2,1,1,1>

[ 244.205044] <0>.(0)[973:kworker/u8:12][MUSB]set_usb_phy_mode 437: force PHY to mode 1, 0x6c=3f2f

[ 244.206147] <0>.(0)[973:kworker/u8:12][MUSB]hs_slew_rate_cal 302: [USBPHY]slew calibration:FM_OUT =321,x=4287,value=4

[ 244.207481] <0>.(0)[973:kworker/u8:12][MUSB]usb_phy_recover 685: skip efuse setting temporary, RG_USB20_INTR_CAL=0x19

[ 244.208796] <0>.(0)[973:kworker/u8:12][MUSB]usb_phy_recover 694: usb recovery success

[ 244.209783] <0>.(0)[973:kworker/u8:12][MUSB]mt_usb_enable 327: end, <2,1,2,1>

[ 244.316384] <0>.(0)[973:kworker/u8:12][MUSB]set_usb_phy_mode 437: force PHY to mode 0, 0x6c=3f11

[ 244.322493] <0>.(0)[973:kworker/u8:12][MUSB]set_usb_phy_mode 437: force PHY to mode 2, 0x6c=3f2d

[ 244.323594] <0>.(0)[973:kworker/u8:12][MUSB]musb_start 1346: start, is_host=1 is_active=0

[ 244.324607] <0>.(0)[973:kworker/u8:12][MUSB]mt_usb_enable 298: begin <1,1>,<3,1,2,1>

[ 244.325575] <0>.(0)[973:kworker/u8:12][MUSB]musb_start 1391: set ignore babble MUSB_ULPI_REG_DATA=88

[ 244.326722] <0>.(0)[973:kworker/u8:12][MUSB]musb_start 1399: add softconn

[ 244.327616] <0>.(0)[28:kworker/0:1]musb-hdrc musb-hdrc: prop=1, power=1, is_host=1

[ 244.328559] <0>.(0)[28:kworker/0:1]musb-hdrc musb-hdrc: prop=2, power=1, is_host=1

[ 244.329499] <0>.(0)[28:kworker/0:1]musb-hdrc musb-hdrc: prop=3, power=1, is_host=1

[ 244.330624] <0>.(0)[973:kworker/u8:12][MUSB]switch_int_to_device 389: switch_int_to_device is done

[ 244.333642] <1>.(1)[1052:usb@1.1-service]musb-hdrc musb-hdrc: prop=2, power=1, is_host=1

[ 244.334883] <1>.(1)[1052:usb@1.1-service]musb-hdrc musb-hdrc: prop=3, power=1, is_host=1

[ 244.335993] <1>.(1)[1052:usb@1.1-service]musb-hdrc musb-hdrc: prop=1, power=1, is_host=1

[ 244.336747] <0>.(0)[973:kworker/u8:12][MUSB]mt_usb_set_vbus 175: is_on<1>, control<1>

[ 244.337984] <0>.(0)[973:kworker/u8:12][MUSB]vbus_init 117: +++

[ 244.338726] <0>.(0)[973:kworker/u8:12][MUSB]vbus_init 125: ---

[ 244.339452] <0>.(0)[973:kworker/u8:12][MUSB]_set_vbus 147: op<1>, status<0>

[ 244.340902] <0>-(0)[973:kworker/u8:12]alarmtimer_enqueue, 838546272379

[ 244.342056] <0>.(0)[973:kworker/u8:12]mt635x-auxadc mt635x-auxadc: name:VCDT, channel=2, adc_out=0x346, adc_result=368

[ 244.343412] <0>.(0)[973:kworker/u8:12][MUSB]check_vbus 537: vbus=3481

[ 244.450086] <0>.(0)[973:kworker/u8:12]mt635x-auxadc mt635x-auxadc: name:VCDT, channel=2, adc_out=0x4a0, adc_result=520

[ 244.451428] <0>.(0)[973:kworker/u8:12][MUSB]check_vbus 537: vbus=4920

[ 244.452225] <0>.(0)[973:kworker/u8:12][MUSB]musb_host_work 712: work end, is_host=1

[ 244.483017] <1>.(1)[81:irq/220-mt6358-]mt6358-pmic 1000d000.pwrap:mt6357-pmic: Reg[0x91a]=0x40,name=chrdet_edge,hwirq=54,type=4

[ 244.484485] <1>.(1)[81:irq/220-mt6358-][MUSB]usb20_check_vbus_on 135: vbus_on<1>

[ 244.485398] <1>.(1)[81:irq/220-mt6358-]charger type: UNKNOWN, Now is usb host mode. Skip detection

[ 244.613519] <0>-(0)[0:swapper/0][MUSB]musb_stage0_irq 1072: MUSB_INTR_CONNECT (b_idle)

[ 244.614515] <0>-(0)[0:swapper/0]QMU_WARN,, disable_q_all

[ 244.615480] <0>-(0)[0:swapper/0][MUSB]musb_stage0_irq 1155: CONNECT (a_host) devctl 5d

[ 244.616551] <0>-(0)[28:kworker/0:1][MUSB]musb_hub_control 370: port status 00010101,devctl=0x5d

[ 244.723052] <0>-(0)[28:kworker/0:1][MUSB]musb_hub_control 370: port status 00000101,devctl=0x5d

[ 244.724216] <0>-(0)[28:kworker/0:1][MUSB]musb_port_reset 129: force musb_platform_reset

[ 244.792968] <0>-(0)[28:kworker/0:1][MUSB]musb_hub_control 370: port status 00120503,devctl=0x5d

[ 244.849662] <0>.(0)[28:kworker/0:1]usb 1-1: new high-speed USB device number 2 using musb-hdrc

[ 244.851582] <0>-(0)[28:kworker/0:1][MUSB]musb_port_reset 129: force musb_platform_reset

[ 244.885206] <2>.(2)[0:swapper/2][mcdi]mcdi cpu: 48, 35, 24, 10, cluster : 20, pause = 62, multi core = 33, latency = 0, residency = 2, last core = 97, avail cpu = 000f, cluster = 0001, enabled = 1, max_s_state = 5, system_idle_hint = 00000000

[ 244.919727] <0>-(0)[28:kworker/0:1][MUSB]musb_hub_control 370: port status 00120503,devctl=0x5d

[ 244.997176] <0>.(0)[28:kworker/0:1]usb-storage 1-1:1.0: USB Mass Storage device detected

[ 244.999402] <0>.(0)[28:kworker/0:1]scsi host0: usb-storage 1-1:1.0

[ 245.001076] <0>-(0)[28:kworker/0:1][MUSB]musb_hub_control 370: port status 00020503,devctl=0x5d

皇家推荐

如何在PSN港服注册及科学上网的详细指南
365bet现场走地盘

如何在PSN港服注册及科学上网的详细指南

📅 08-14 👁️ 6573
Visual Basic中有哪些常用的GUI控件?
365bet现场走地盘

Visual Basic中有哪些常用的GUI控件?

📅 07-23 👁️ 4067
c语言中出现void错误,关于C语言问题
日博best365

c语言中出现void错误,关于C语言问题

📅 07-10 👁️ 4060
2024正规手游折扣平台排行榜 靠谱的折扣手游平台app榜单
阿里巴巴国际如何设置客服(阿里巴巴国际如何设置客服人员)
GTA5车转向灯哪个按键 GTA5车转向灯使用教程
365bet现场走地盘

GTA5车转向灯哪个按键 GTA5车转向灯使用教程

📅 07-06 👁️ 3967