Android中的otg检测

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mike8825/article/details/83246812

先来看下usb otg线和micro usb线的区别。

对应的usb连线如下

检测原理

      当手机连接到电脑时,vbus为高电平,触发了vbus中断,在中断中确认为高电平后,手机的usb设置从设备,摆出usb线时,vbus变低。

     当otg线(id脚和gnd脚是短路的)连接手机后,触发了id中断,检测到id脚为低电平后,手机的usb设置主设备,摆出usb线时,id脚变高。

这里以展讯的代码示例如下,

kernel/drivers/usb/musb/musb_sprd.c

static void musb_sprd_set_otg_en(struct sprd_glue *glue, int enable)
{
	if (gpio_is_valid(glue->gpio_otg)) {
		dev_dbg(glue->dev, "musb gpio_set_value  %d\n", enable);
		if (enable) {
			/*
			 * Two mode for ext IC:
			 * mode 1. set gpio_otg high for 0.25A
			 * mode 2. make a gpio_otg pulse high-low-high for 0.55A,
			 * mode 2 is the typical mode suggest by provider.
			 */
			gpio_set_value(glue->gpio_otg, 1);
			gpio_set_value(glue->gpio_otg, 0);
			gpio_set_value(glue->gpio_otg, 1);
		} else {
			gpio_set_value(glue->gpio_otg, 0);
		}
	} else {
		sprd_extic_otg_power(!!enable);
	}
}

static irqreturn_t musb_sprd_vbus_handler(int irq, void *dev_id)
{
	struct sprd_glue *glue = (struct sprd_glue *)dev_id;
	struct musb *musb = platform_get_drvdata(glue->musb);
	int value;

	value = !!gpio_get_value(glue->gpio_device);
	irq_set_irq_type(irq,value ? IRQ_TYPE_LEVEL_LOW : IRQ_TYPE_LEVEL_HIGH);

	if (glue->vbus_active == value)//vbus_active在probe里初始化为0,如果与上一次电平一致,不需要出来
		return IRQ_HANDLED;
	else if (value)// usb线插入
		glue->wq_mode = USB_DR_MODE_PERIPHERAL;
	else if (glue->dr_mode != USB_DR_MODE_PERIPHERAL) {//不是从设备拔出没意义

		dev_info(glue->dev, "%s ignore the vbus event\n", __func__);
		return IRQ_HANDLED;
	}
	glue->vbus_active = value;//记录vbus的电平
	MUSB_DEV_MODE(musb);
	schedule_work(&glue->work);
	return IRQ_HANDLED;
} 


static irqreturn_t musb_sprd_usbid_handler(int irq, void *dev_id)
{
	struct sprd_glue *glue = (struct sprd_glue *)dev_id;
	int value;

	value = !!gpio_get_value(glue->gpio_host);
	value = !value;
	irq_set_irq_type(irq,value ? IRQ_TYPE_LEVEL_HIGH : IRQ_TYPE_LEVEL_LOW);

	glue->vbus_active = value;
	glue->wq_mode = USB_DR_MODE_HOST;

	schedule_work(&glue->work);

	return IRQ_HANDLED;  
}


static void sprd_musb_work(struct work_struct *work)
{
	struct sprd_glue *glue = container_of(work, struct sprd_glue, work);
	struct musb *musb = platform_get_drvdata(glue->musb);
	struct usb_charger *uchger = musb->g.charger;
	unsigned long flags;
	bool charging_only = false;
	int ret;
	int cnt = 100;

	glue->dr_mode = glue->wq_mode;
	dev_dbg(glue->dev, "%s enter: vbus = %d mode = %d\n",
			__func__, glue->vbus_active, glue->dr_mode);

	disable_irq_nosync(glue->vbus_irq);
	if (glue->vbus_active) {
		if (glue->dr_mode == USB_DR_MODE_PERIPHERAL)
			usb_gadget_set_state(&musb->g, USB_STATE_ATTACHED);
		
		if (glue->dr_mode == USB_DR_MODE_HOST)
			musb_sprd_set_otg_en(glue, 1);


		goto end;
	} else {
		usb_gadget_set_state(&musb->g, USB_STATE_REMOVED);
		if (glue->dr_mode == USB_DR_MODE_PERIPHERAL) {
			u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);

			musb_writeb(musb->mregs, MUSB_DEVCTL,
				devctl & ~MUSB_DEVCTL_SESSION);
			musb->shutdowning = 1;
			usb_phy_post_init(glue->xceiv);
			cnt = 10;
			while (musb->shutdowning && cnt-- > 0)
				msleep(50);
		}

		if (glue->dr_mode == USB_DR_MODE_HOST)
			musb_sprd_set_otg_en(glue, 0);
		goto end;
	}
end:
	enable_irq(glue->vbus_irq);
} 

当usb作为主设备时,需要提供5v的电压给从设备供电(cpu和pmic这边的电压一般不超过3.3),一般需要增加升压芯片或者由支持otg的充电ic提供。

猜你喜欢

转载自blog.csdn.net/mike8825/article/details/83246812
OTG