1.硬件原理图
看下面的原理图
VCC_OTG_EN 引脚,这个脚主要是用来控制给外部OTG设备提供电源控制的。如果设备作为DEVICE设备,这时候VBUS的电是由外部提供的,比如通过USB线和电脑连接,这个时候,VBUS的电压是由电脑提供的。
如果设备作为HOST设备,比如连接U盘,我们需要给U盘提供VBUS电压,就需要控制VCC_OTG_EN引脚给VBUS提供电压。
USB_OTG_ID 脚
这个脚用来判断有OTG设备插入
VBUS电压检测,这个电路看不懂有什么作用,硬件设计预期是希望如果有外部的USB设备给设备供电,就切换模式,但是实际上,不管设备作为HOST还是DEVICE,这个电压会一直存在。所以总觉得这个设计有点问题。
ID脚电压,没有插入OTG设备的时候,电压是1.79v,插入OTG设备的时候,电压是 0V。
2.软件控制dts 部分
&usb0 { pinctrl-names = "iddig_irq_init", "drvvbus_init", "drvvbus_low", "drvvbus_high"; pinctrl-0 = <&usb0_iddig>; pinctrl-1 = <&usb0_drvvbus>; pinctrl-2 = <&usb0_drvvbus_low>; pinctrl-3 = <&usb0_drvvbus_high>; usb-power-supply = <&mt6392_vusb_reg>; drvvbus_gpio = <&pio 0 2>; iddig_gpio = <&pio 41 2>; status = "okay"; }; 774 /* USB GPIO start */ 775 usb0_drvvbus: drvvbus_init { 776 pins_cmd_dat { 777 pins = <MT8167_PIN_0_EINT0__FUNC_GPIO0>; 778 output-low; 779 }; 780 }; 781 782 usb0_drvvbus_high: drvvbus_high { 783 pins_cmd_dat { 784 pins = <MT8167_PIN_0_EINT0__FUNC_GPIO0>; 785 slew-rate = <1>; 786 output-high; 787 }; 788 }; 789 790 usb0_drvvbus_low: drvvbus_low { 791 pins_cmd_dat { 792 pins = <MT8167_PIN_0_EINT0__FUNC_GPIO0>; 793 slew-rate = <1>; 794 output-low; 795 }; 796 }; 797 usb0_iddig: iddig_irq_init { 798 pins_cmd_dat { 799 pins = <MT8167_PIN_41_KPROW1__FUNC_IDDIG>; 800 slew-rate = <0>; 801 bias-pull-up = <MTK_PUPD_SET_R1R0_01>; 802 }; 803 }; 804 /* USB GPIO end */
引脚初始化部分
void mt_usb_init_drvvbus(void) { #if (!(defined(SWITCH_CHARGER) || defined(FPGA_PLATFORM))) && !(defined(OTG_BOOST_BY_SWITCH_CHARGER)) #ifdef CONFIG_OF #if defined(CONFIG_MTK_LEGACY) mt_set_gpio_mode(drvvbus_pin, drvvbus_pin_mode);/*should set GPIO2 as gpio mode.*/ mt_set_gpio_dir(drvvbus_pin, GPIO_DIR_OUT); mt_get_gpio_pull_enable(drvvbus_pin); mt_set_gpio_pull_select(drvvbus_pin, GPIO_PULL_UP); #else int ret = 0; DBG(0, "****%s:%d Init Drive VBUS!!!!!\n", __func__, __LINE__); if (drvvbus_pin < 0) return; if (IS_ERR(pinctrl)) return; pinctrl_drvvbus = pinctrl_lookup_state(pinctrl, "drvvbus_init"); if (IS_ERR(pinctrl_drvvbus)) { ret = PTR_ERR(pinctrl_drvvbus); dev_err(mtk_musb->controller, "Cannot find usb pinctrl drvvbus\n"); } pinctrl_drvvbus_low = pinctrl_lookup_state(pinctrl, "drvvbus_low"); if (IS_ERR(pinctrl_drvvbus_low)) { ret = PTR_ERR(pinctrl_drvvbus_low); dev_err(mtk_musb->controller, "Cannot find usb pinctrl drvvbus_low\n"); } pinctrl_drvvbus_high = pinctrl_lookup_state(pinctrl, "drvvbus_high"); if (IS_ERR(pinctrl_drvvbus_high)) { ret = PTR_ERR(pinctrl_drvvbus_high); dev_err(mtk_musb->controller, "Cannot find usb pinctrl drvvbus_high\n"); } if (!IS_ERR(pinctrl_drvvbus)) { pinctrl_select_state(pinctrl, pinctrl_drvvbus); DBG(0, "****%s:%d end Init Drive VBUS KS!!!!!\n", __func__, __LINE__); } #endif #else mt_set_gpio_mode(GPIO_OTG_DRVVBUS_PIN, GPIO_OTG_DRVVBUS_PIN_M_GPIO);/*should set GPIO2 as gpio mode.*/ mt_set_gpio_dir(GPIO_OTG_DRVVBUS_PIN, GPIO_DIR_OUT); mt_get_gpio_pull_enable(GPIO_OTG_DRVVBUS_PIN); mt_set_gpio_pull_select(GPIO_OTG_DRVVBUS_PIN, GPIO_PULL_UP); #endif #endif }
ID 引脚初始化部分
static void otg_int_init(void) { #if CONFIG_OF #if defined(CONFIG_MTK_LEGACY) mt_set_gpio_mode(iddig_pin, GPIO_MODE_00); mt_set_gpio_dir(iddig_pin, GPIO_DIR_IN); mt_set_gpio_pull_enable(iddig_pin, GPIO_PULL_ENABLE); mt_set_gpio_pull_select(iddig_pin, GPIO_PULL_UP); mt_eint_set_sens(IDDIG_EINT_PIN, MT_LEVEL_SENSITIVE); mt_eint_set_hw_debounce(IDDIG_EINT_PIN, 64); mt_eint_registration(IDDIG_EINT_PIN, EINTF_TRIGGER_LOW, mt_usb_ext_iddig_int, FALSE); #else int ret = 0; DBG(0, "****%s:%d before Init IDDIG KS!!!!!\n", __func__, __LINE__); if (iddig_pin < 0) { DBG(0, "iddig_pin is invalid:%d\n", iddig_pin); return; } pinctrl_iddig = pinctrl_lookup_state(pinctrl, "iddig_irq_init"); if (IS_ERR(pinctrl_iddig)) { ret = PTR_ERR(pinctrl_iddig); DBG(0, "Cannot find usb pinctrl iddig_irq_init\n"); } if (IS_ERR(pinctrl) || IS_ERR(pinctrl_iddig)) { DBG(0, "pinctrl or pinctrl_iddig error\n"); return; } pinctrl_select_state(pinctrl, pinctrl_iddig); DBG(0, "usb iddig_pin %d\n", iddig_pin); #if 0 gpio_set_debounce(iddig_pin, 64000); DBG(0, "will call __gpio_to_irq\n"); #endif usb_iddig_number = __gpio_to_irq(iddig_pin); DBG(0, "usb usb_iddig_number %d\n", usb_iddig_number); ret = request_irq(usb_iddig_number, mt_usb_ext_iddig_int, IRQF_TRIGGER_LOW, "USB_IDDIG", NULL); if (ret > 0) DBG(0, "USB IDDIG IRQ LINE not available!!\n"); else DBG(0, "USB IDDIG IRQ LINE available!!\n"); irq_set_irq_wake(usb_iddig_number, 1); #endif #else u32 phy_id_pull = 0; phy_id_pull = __raw_readl(U2PHYDTM1); phy_id_pull |= ID_PULL_UP; __raw_writel(phy_id_pull, U2PHYDTM1); musb_writel(mtk_musb->mregs, USB_L1INTM, IDDIG_INT_STATUS | musb_readl(mtk_musb->mregs, USB_L1INTM)); #endif }
USB 触发中断代码
/* * handle all the irqs defined by the HDRC core. for now we expect: other * irq sources (phy, dma, etc) will be handled first, musb->int_* values * will be assigned, and the irq will already have been acked. * * called in irq context with spinlock held, irqs blocked */ irqreturn_t musb_interrupt(struct musb *musb) { irqreturn_t retval = IRQ_NONE; u8 devctl, power = 0; #ifndef USE_SSUSB_QMU u32 reg = 0, ep_num = 0; #endif #ifdef POWER_SAVING_MODE if (!(os_readl(U3D_SSUSB_U2_CTRL_0P) & SSUSB_U2_PORT_PDN)) { devctl = (u8) os_readl(U3D_DEVICE_CONTROL); power = (u8) os_readl(U3D_POWER_MANAGEMENT); } else { devctl = 0; power = 0; musb->int_usb = 0; } #else devctl = (u8) os_readl(U3D_DEVICE_CONTROL); power = (u8) os_readl(U3D_POWER_MANAGEMENT); #endif /* dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n", */ os_printk(K_DEBUG, "IRQ %s usb%04x tx%04x rx%04x\n", (devctl & USB_DEVCTL_HOSTMODE) ? "host" : "peripheral", musb->int_usb, musb->int_tx, musb->int_rx); if (unlikely(!musb->softconnect)) { os_printk(K_WARNIN, "!softconnect, IRQ %s usb%04x tx%04x rx%04x\n", (devctl & USB_DEVCTL_HOSTMODE) ? "host" : "peripheral", musb->int_usb, musb->int_tx, musb->int_rx); return IRQ_HANDLED; } /* the core can interrupt us for multiple reasons; docs have * a generic interrupt flowchart to follow */ if (musb->int_usb) retval |= musb_stage0_irq(musb, musb->int_usb, devctl, power); /* "stage 1" is handling endpoint irqs */ /* handle endpoint 0 first */ if (musb->int_tx & 1) retval |= musb_g_ep0_irq(musb); #ifndef USE_SSUSB_QMU /* RX on endpoints 1-15 */ reg = musb->int_rx >> 1; ep_num = 1; while (reg) { if (reg & 1) { /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval = ep->rx_irq(...) */ retval = IRQ_HANDLED; musb_g_rx(musb, ep_num); } reg >>= 1; ep_num++; } /* TX on endpoints 1-15 */ reg = musb->int_tx >> 1; ep_num = 1; while (reg) { if (reg & 1) { /* musb_ep_select(musb->mregs, ep_num); */ /* REVISIT just retval |= ep->tx_irq(...) */ retval = IRQ_HANDLED; musb_g_tx(musb, ep_num); } reg >>= 1; ep_num++; } #endif return retval; } EXPORT_SYMBOL_GPL(musb_interrupt);
中断函数注册,主要是在插入把拔出usb的时候产生中断
/* attach to the IRQ */ if (request_irq(musb->nIrq, musb->isr, IRQF_TRIGGER_LOW, dev_name(dev), musb)) { DBG(0, "request_irq %d failed!\n", musb->nIrq); status = -ENODEV; goto fail3; }3.问题以及分析
我们项目遇到一个问题
插入OTG设备后,再拔掉,仍是OTG模式,没检测到OTG设备拔出
插入OTG设备和拔开OTG设备的软件日志
====插入OTG==== [1623:kworker/0:2][MUSB]musb_id_pin_work 376: work start, is_host=0 [1623:kworker/0:2][MUSB]musb_is_host 231: will mask PMIC charger detection [1623:kworker/0:2][MUSB]musb_is_host 254: iddig_state = 0 [1623:kworker/0:2][MUSB]musb_is_host 283: usb_is_host = 1 [1623:kworker/0:2][MUSB]musb_id_pin_work 384: musb is as host, already lock [1623:kworker/0:2][MUSB]musb_id_pin_work 424: force PHY to host mode, 0x6d=3e, 0x6c=2c [1623:kworker/0:2][MUSB]musb_start 1290: start, is_host=1 is_active=0 [1623:kworker/0:2][MUSB]musb_id_pin_work 464: work end, is_host=1 [1623:kworker/0:2]musb-hdrc musb-hdrc: prop=1, power=1, is_host=1 [1623:kworker/0:2]musb-hdrc musb-hdrc: prop=2, power=1, is_host=1 [1623:kworker/0:2]musb-hdrc musb-hdrc: prop=3, power=1, is_host=1 [646:usb@1.1-service]musb-hdrc musb-hdrc: prop=2, power=1, is_host=1 [646:usb@1.1-service]musb-hdrc musb-hdrc: prop=3, power=1, is_host=1 [646:usb@1.1-service]musb-hdrc musb-hdrc: prop=1, power=1, is_host=1 [0:swapper/0][MUSB]musb_stage0_irq 1102: CONNECT (a_host) devctl 5d [1623:kworker/0:2]scsi host1: usb-storage 1-1:1.0 [1829:cat][MUSB]musb_host_rx 2048: RX end 5 STALL [2423:usb-storage][MUSB]musb_host_rx 2048: RX end 5 STALL [0:swapper/0][MUSB]musb_host_rx 2048: RX end 5 STALL [0:swapper/0][MUSB]musb_host_rx 2048: RX end 5 STALL [0:swapper/0][MUSB]musb_host_rx 2048: RX end 5 STALL [0:swapper/0][MUSB]musb_host_rx 2048: RX end 5 STALL [658:Binder:536_5][MUSB]musb_host_rx 2048: RX end 5 STALL [0:swapper/0][MUSB]musb_host_rx 2048: RX end 5 STALL ====拔下OTG==== [0:swapper/0][MUSB]musb_stage0_irq 1107: DISCONNECT (a_host) as Host, devctl 19 [0:swapper/0][MUSB]musb_root_disconnect 197: host disconnect (a_host) [1623:kworker/0:2][MUSB]musb_id_pin_work 376: work start, is_host=1 [1623:kworker/0:2][MUSB]musb_is_host 231: will mask PMIC charger detection [1623:kworker/0:2][MUSB]musb_is_host 254: iddig_state = 1 [1623:kworker/0:2][MUSB]musb_is_host 274: will unmask PMIC charger detection [1623:kworker/0:2][MUSB]musb_is_host 283: usb_is_host = 0 [1623:kworker/0:2][MUSB]switch_int_to_host 334: enable iddig irq LOW @lin 334 [1623:kworker/0:2][MUSB]switch_int_to_host 340: switch_int_to_host is done [1623:kworker/0:2][MUSB]musb_id_pin_work 464: work end, is_host=0 [1623:kworker/0:2]musb-hdrc musb-hdrc: prop=1, power=0, is_host=0 [1623:kworker/0:2]musb-hdrc musb-hdrc: prop=2, power=0, is_host=0 [1623:kworker/0:2]musb-hdrc musb-hdrc: prop=3, power=0, is_host=0 [646:usb@1.1-service]musb-hdrc musb-hdrc: prop=2, power=0, is_host=0 [646:usb@1.1-service]musb-hdrc musb-hdrc: prop=3, power=0, is_host=0 [646:usb@1.1-service]musb-hdrc musb-hdrc: prop=1, power=0, is_host=0
获取otg状态的函数
static bool musb_is_host(void) { u8 devctl = 0; int iddig_state = 1; bool usb_is_host = 0; DBG(0, "will mask PMIC charger detection\n"); #ifndef FPGA_PLATFORM #ifdef CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT #ifdef CONFIG_MTK_LOAD_SWITCH_FPF3040 pmic_chrdet_int_en(0); #endif #endif #endif musb_platform_enable(mtk_musb); if (iddig_pin < 0) { DBG(0, "iddig_pin is invalid:%d, return non-host!\n", iddig_pin); usb_is_host = 0; return usb_is_host; } #ifdef ID_PIN_USE_EX_EINT #if defined(CONFIG_MTK_LEGACY) iddig_state = mt_get_gpio_in(iddig_pin); #else iddig_state = __gpio_get_value(iddig_pin); #endif DBG(0, "iddig_state = %d\n", iddig_state); #else iddig_state = 0; devctl = musb_readb(mtk_musb->mregs, MUSB_DEVCTL); DBG(0, "devctl = %x before end session\n", devctl); devctl &= ~MUSB_DEVCTL_SESSION; /* this will cause A-device change back to B-device after A-cable plug out*/ musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, devctl); msleep(delay_time); devctl = musb_readb(mtk_musb->mregs, MUSB_DEVCTL); DBG(0, "devctl = %x before set session\n", devctl); devctl |= MUSB_DEVCTL_SESSION; musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, devctl); msleep(delay_time1); devctl = musb_readb(mtk_musb->mregs, MUSB_DEVCTL); DBG(0, "devclt = %x\n", devctl); #endif if (devctl & MUSB_DEVCTL_BDEVICE || iddig_state) { DBG(0, "will unmask PMIC charger detection\n"); #ifndef FPGA_PLATFORM pmic_chrdet_int_en(1); #endif usb_is_host = false; } else { usb_is_host = true; } DBG(0, "usb_is_host = %d\n", usb_is_host); return usb_is_host; }
插拔otg 的时候,会进入这个函数里面进行判断
从日志和下面的代码可以得出一个结论,我们在插入OTG和拔下OTG的时候,软件已经正常运行了,但是拔出后,可能因为某个原因,USB处在一个错误的状态,这个状态导致再插入正常的USB就没有反应了。
static void musb_id_pin_work(struct work_struct *data) { u8 devctl = 0; unsigned long flags; /* need prepare clock because musb_generic_disable may call prepare clock in atomic context */ mt_usb_clock_prepare(mtk_musb); 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; } wake_lock(&mtk_musb->usb_lock); mtk_musb->is_host = musb_is_host(); DBG(0, "musb is as %s, already lock\n", mtk_musb->is_host?"host":"device"); switch_set_state((struct switch_dev *)&otg_state, mtk_musb->is_host); if (mtk_musb->is_host) { /*setup fifo for host mode*/ ep_config_from_table_for_host(mtk_musb); /* wake_lock(&mtk_musb->usb_lock); */ musb_platform_set_vbus(mtk_musb, 1); /* 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))); /* USB MAC OFF*/ /* VBUSVALID=0, AVALID=0, BVALID=0, SESSEND=1, IDDIG=X */ USBPHY_SET8(0x6c, 0x10); USBPHY_CLR8(0x6c, 0x2e); USBPHY_SET8(0x6d, 0x3e); DBG(0, "force PHY to idle, 0x6d=%x, 0x6c=%x\n", USBPHY_READ8(0x6d), USBPHY_READ8(0x6c)); /* wait */ mdelay(5); /* remove babble: NOISE_STILL_SOF:1, BABBLE_CLR_EN:0 */ devctl = musb_readb(mtk_musb->mregs, MUSB_ULPI_REG_DATA); devctl = devctl | 0x80; devctl = devctl & 0xbf; musb_writeb(mtk_musb->mregs, MUSB_ULPI_REG_DATA, devctl); mdelay(5); /* restart session */ devctl = musb_readb(mtk_musb->mregs, MUSB_DEVCTL); musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, (devctl | MUSB_DEVCTL_SESSION)); /* USB MAC ONand Host Mode*/ /* VBUSVALID=1, AVALID=1, BVALID=1, SESSEND=0, IDDIG=0 */ USBPHY_CLR8(0x6c, 0x10); USBPHY_SET8(0x6c, 0x2c); USBPHY_SET8(0x6d, 0x3e); DBG(0, "force PHY to host mode, 0x6d=%x, 0x6c=%x\n", USBPHY_READ8(0x6d), USBPHY_READ8(0x6c)); #endif musb_start(mtk_musb); MUSB_HST_MODE(mtk_musb); switch_int_to_device(mtk_musb); #ifdef CONFIG_PM mtk_musb->is_active = 0; DBG(0, "set active to 0 in Pm runtime issue\n"); #endif } else { DBG(0, "devctl is %x\n", musb_readb(mtk_musb->mregs, MUSB_DEVCTL)); musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0); musb_platform_set_vbus(mtk_musb, 0); /* for no VBUS sensing IP */ #if 1 /* USB MAC OFF*/ /* VBUSVALID=0, AVALID=0, BVALID=0, SESSEND=1, IDDIG=X */ USBPHY_SET8(0x6c, 0x10); USBPHY_CLR8(0x6c, 0x2e); USBPHY_SET8(0x6d, 0x3e); DBG(0, "force PHY to idle, 0x6d=%x, 0x6c=%x\n", USBPHY_READ8(0x6d), USBPHY_READ8(0x6c)); #endif #if !defined(MTK_HDMI_SUPPORT) musb_stop(mtk_musb); #else mt_usb_check_reconnect();/*ALPS01688604, IDDIG noise caused by MHL init*/ #endif if (wake_lock_active(&mtk_musb->usb_lock)) wake_unlock(&mtk_musb->usb_lock); mtk_musb->xceiv->otg->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(mtk_musb); switch_int_to_host(mtk_musb); } out: DBG(0, "work end, is_host=%d\n", mtk_musb->is_host); up(&mtk_musb->musb_lock); mt_usb_clock_unprepare(mtk_musb); }
里面有一个switch_int_to_host 把设备切换成host模式,从上面的日志上看,这个函数已经执行了,但是设备没有成功切换成host模式。
所以让设备恢复正常应该不是这个函数。
void switch_int_to_host(struct musb *musb) { #ifdef ID_PIN_USE_EX_EINT #if defined(CONFIG_MTK_LEGACY) mt_eint_set_polarity(IDDIG_EINT_PIN, MT_EINT_POL_NEG); mt_eint_unmask(IDDIG_EINT_PIN); #else irq_set_irq_type(usb_iddig_number, IRQF_TRIGGER_LOW); enable_irq(usb_iddig_number); irq_set_irq_wake(usb_iddig_number, 1); DBG(0, "enable iddig irq LOW @lin %d\n", __LINE__); #endif #else musb_writel(musb->mregs, USB_L1INTP, IDDIG_INT_STATUS); musb_writel(musb->mregs, USB_L1INTM, IDDIG_INT_STATUS|musb_readl(musb->mregs, USB_L1INTM)); #endif DBG(0, "switch_int_to_host is done\n"); }
最后我解决的方法也很简单,就是在otg拔出的时候,再connect一下usb就好了。
这个connectusb应该不是简单的connect,是让usb进入device的状态。
index b260550fb7..ba66a7444c --- a/kernel-4.4/drivers/misc/mediatek/usb20/mt8167/usb20_host.c +++ b/kernel-4.4/drivers/misc/mediatek/usb20/mt8167/usb20_host.c @@ -459,6 +459,9 @@ static void musb_id_pin_work(struct work_struct *data) mtk_musb->xceiv->otg->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(mtk_musb); switch_int_to_host(mtk_musb); + mt_usb_connect(); + /*weiqifa modify*/ + printk("===weiqifa=== mt_usb_connect() \n"); } out: DBG(0, "work end, is_host=%d\n", mtk_musb->is_host);
这个修改是参考了MTK的补丁,他们的做法是用一个新的GPIO口用来检测USB状态.
就是上图的那个引脚,但是可惜的是,我们引脚上接的这个脚不是GPIO功能脚,所以MTK的补丁用不上,他们的补丁也就是检测是否有USB插入,并通过OTGID脚状态,然后再适配usb的状态。
用两个GPIO一起适配的原因是为了适应系统的低功耗机制,也就是说,USB的状态只有在插入usb的时候才会设置成connect状态,如果拔出,就不是connect状态,这样可以降低功耗。刚好,我们是DC供电,不是电池供电,这个可以忽略。
关于usb状态的轮询,可以看这个函数
如果进入OTG模式后,USB会一直处在DISCONNECT状态中。
#define USB_STATE_MONITOR_DELAY 5000 static struct delayed_work usb_state_monitor_dw; static void do_usb_state_monitor_work(struct work_struct *work) { struct gadget_info *gi = dev_get_drvdata(android_device); struct usb_composite_dev *cdev = &gi->cdev; char *usb_state = "NO-DEV"; unsigned long flags; spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) usb_state = "CONFIGURED"; else if (gi->connected) usb_state = "CONNECTED"; else usb_state = "DISCONNECTED"; spin_unlock_irqrestore(&cdev->lock, flags); pr_info("usb_state<%s>\n", usb_state); schedule_delayed_work(&usb_state_monitor_dw, msecs_to_jiffies(USB_STATE_MONITOR_DELAY)); }4.总结
在接手这个问题之前,我是没有搞过usb相关的,当然了,我看过很多文章和书籍,之前在rockchip平台上,我也有接触过usb相关的知识,解决实际问题还是第一次,看MTK代码的时候,大部分都是通过函数名字和变量定义猜测意图,加上硬件的一些验证。
比如
下面这个引脚的功能,参考设计和我们的设计不同,我们通过验证发现,只有这个引脚有电压,PMU就会工作走开机流程。
type-c 和传统的USB是不同的,传统的USB线为了实现OTG功能会增加一个OTG引脚,但是TPYEC上是没有这个OTG线的,看下TPYEC的引脚图。
上面有CC1、CC2引脚,是用这个来实现OTG功能的。
但是我们引脚设计上,就不会这样搞了,我们是TYPEC接口,但是实现OTG功能还是用的原来的方式,我们没有使用CC1、CC2、这几个引脚。
如下图,是使用TYPEC实现OTG的硬件原理图
普通的TYPE C充电线CC管脚通过56K电阻上拉到VBUS,而OTG线一般这是通过5.1K欧下拉接地。