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(&register_otg_work, do_register_otg_work);
	queue_delayed_work(mtk_musb->st_wq, &register_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,<musb_disable_q_all 333>, 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
  • 1
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MTK OTG(On-The-Go)识别流程是指在MTK芯片手机上,如何实现对外部设备的识别和连接。OTG功能允许手机直接连接其他USB设备,这样可以实现数据传输和设备控制。 MTK OTG识别流程如下: 1. 初始化:手机USB OTG适配器后,系统会先进行初始化,确认OTG功能是否可用。 2. 检测外部设备:系统会检测入的设备类型,并判断其是否是支持的OTG设备。 3. 供电设置:如果外部设备支持OTG,则系统会设置合适的供电模式,以确保设备可以正常工作。 4. 设备驱动加载:系统会根据外部设备的类型,加载相应的设备驱动。 5. 设备识别:系统会通过设备驱动识别外部设备,并获取设备的一些基本信息,如设备ID、制造商等。 6. 连接确认:系统会确认设备是否可正常连接,以及支持的功能和参数。 7. 用户确认:如果设备需要用户交互或权限确认,系统会提示用户是否接受连接。 8. 数据传输:如果连接成功,系统可以通过OTG接口与外部设备进行数据传输和交互。 9. 断开连接:当外部设备拔出时,系统会断开与设备的连接,并释放相应的资源。 总的来说,MTK OTG识别流程是通过系统的初始化、设备检测、供电设置、驱动加载、设备识别、连接确认、用户确认、数据传输和断开连接等一系列步骤来实现对外部设备的识别和连接。这样手机可以方便地连接各种类型的外部设备,提供更多的功能和扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值