USB-OTG:3、实现OTG的自动切换

目录

🍅点击这里查看所有博文

  随着自己工作的进行,接触到的技术栈也越来越多。给我一个很直观的感受就是,某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了,只有经常会用到的东西才有可能真正记下来。存在很多在特殊情况下有一点用处的技巧,用的不多的技巧可能一个星期就忘了。

  想了很久想通过一些手段把这些事情记录下来。也尝试过在书上记笔记,这也只是一时的,书不在手边的时候那些笔记就和没记一样,不是很方便。

  很多时候我们遇到了问题,一般情况下都是选择在搜索引擎检索相关内容,这样来的也更快一点,除非真的找不到才会去选择翻书。后来就想到了写博客,博客作为自己的一个笔记平台倒是挺合适的。随时可以查阅,不用随身携带。

  同时由于写博客是对外的,既然是对外的就不能随便写,任何人都可以看到。经验对于我来说那就只是经验而已,公布出来说不一定我的一些经验可以帮助到其他的人。遇到和我相同问题时可以少走一些弯路。

  既然决定了要写博客,那就只能认真去写。不管写的好不好,尽力就行。千里之行始于足下,一步一个脚印,慢慢来 ,写的多了慢慢也会变好的。权当是记录自己的成长的一个过程,等到以后再往回看时,就会发现自己以前原来这么菜😂。

  本系列博客所述资料均来自互联网,并不是本人原创(只有博客是自己写的)。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,没有为自己谋取私利的想法。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。

  前面第一、第二小节我们介绍到了OTG的原理和硬件。软件层面上OTG实际很简单,其主要作用就是设备在检测到USB_ID拉低之后,自动将自身模式切换为主机模式,同时开启VBUS对外供电。

驱动实现

  Linux主线代码中实现了extcon-usb-gpio驱动,其中usb_extcon_detect_cable函数则定义了OTG的行为。

  USB_ID如果为真(高电平未接入设备),则设置VBUS为低电平,同时设置USB_HOST为FALSE。

  USB_ID如果为假(低电平已接入设备),则设置VBUS为高电平,同时设置USB_HOST为TRUE。


static void usb_extcon_detect_cable(struct work_struct *work)
{
	int id, vbus;
	struct usb_extcon_info *info = container_of(to_delayed_work(work),struct usb_extcon_info,wq_detcable);
	/* check ID and VBUS and update cable state */
	id = info->id_gpiod ?
		gpiod_get_value_cansleep(info->id_gpiod) : 1;
	vbus = info->vbus_gpiod ?
		gpiod_get_value_cansleep(info->vbus_gpiod) : id;
	/* at first we clean states which are no longer active */
	if (id) {
		if (info->vbus_out_gpiod)
			gpiod_set_value_cansleep(info->vbus_out_gpiod, 0);
		extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false);
	}
	if (!vbus)
		extcon_set_state_sync(info->edev, EXTCON_USB, false);
	if (!id) {
		if (info->vbus_out_gpiod)
			gpiod_set_value_cansleep(info->vbus_out_gpiod, 1);
		extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true);
	} else {
		if (vbus)
			extcon_set_state_sync(info->edev, EXTCON_USB, true);
	}
}

  驱动在加载的过程中通过读取设备树的配置,来获取USB_ID和VBUS-OUT的硬件配置。也就是说我们如果想要让OTG正常工作,则只需要配置相应的设备树节点即可。

static int usb_extcon_probe(struct platform_device *pdev)
{
	xxxxxxx

	info->dev = dev;
	info->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id", GPIOD_IN);
	info->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus",
						   GPIOD_IN);
	info->vbus_out_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus-out",
						   GPIOD_OUT_HIGH);
	xxxxxxx
}

  extcon-usb-gpio驱动可能默认并没有被编译进内核,这时需要手动修改内核的配置文件,添加CONFIG_EXTCON_USB_GPIO宏,以启用功能。

/*pinnacles_apps/apps_proc/owrt/src/kernel-5.15/kernel_platform/msm-kernel/arch/arm64/configs/vendor/sdxpinn.config*/
xxxxxxxxxxxxxxx    
CONFIG_EXTCON_USB_GPIO=y
xxxxxxxxxxxxxxx    

设备树配置

   设备树的配置,不同的平台是不一样的。我这边以SDX7X举例,首先在&soc 节点中新增usb_otg_extcon配置,并且在&usb节点中进行引用。

   usb_otg_extcon就有关于id-gpiovbus-out-gpio的描述,键值对的键大家都是一样的。键值对的值和具体的硬件设计有关,不要盲目抄,避免烧坏设备。

/*kernel-5.15/kernel_platform/msm-kernel/arch/arm64/boot/dts/vendor/qcom/sdxpinn-idp-cpe.dtsi*/
&soc {
	xxxxxxxxxxxxxxx
	usb_otg_extcon: usb_otg_extcon {
		compatible = "linux,extcon-usb-gpio";
		id-gpio = <&tlmm 50 GPIO_ACTIVE_HIGH>;
		vbus-out-gpio = <&pmx75_gpios 16 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&usb_id_det_default
					&usb_vbus_boost_default>;
	};
	xxxxxxxxxxxxxxx
}

&usb {
	/*Default device tree configuration, OTG is not supported */
	/*extcon = <&pmx75_vbus_detect>, <&eud>; */

	/*added support for OTG*/
	extcon = <&pmx75_vbus_detect>, <&usb_otg_extcon>, <&eud>;
};

  最后关于id-gpiovbus-out-gpio这两个GPIO的初始化,就要找到对应的位置了。可以参考其他的GPIO进行设置,这里不做推荐。下面的示例最好不要参考,写下来只是做个记录。

/*pinnacles_apps/apps_proc/owrt/src/kernel-5.15/kernel_platform/msm-kernel/arch/arm64/boot/dts/vendor/qcom/pmx75.dtsi*/

&spmi_bus {
	xxxxxxxxxxxxxxx
	qcom,pmx75@1 {
		pmx75_vbus_detect: qcom,pmd-vbus-det@1500 {
			compatible = "qcom,pm8941-misc";
			reg = <0x1500>;
			interrupts = <0x1 0x15 0x0 IRQ_TYPE_EDGE_BOTH>;
			interrupt-names = "usb_vbus";
			status = "disabled";
		};
		pmx75_gpios: pinctrl@8800 {
			xxxxxxxxxxxxxxx
			pmx75_16_gpios {
				usb_vbus_boost_default: usb_vbus_boost_default {
					pins = "gpio16";
					function = "normal";
					output-enable;
					output-low;
					bias-pull-down;
					qcom,drive-strength = <2>;
					power-source = <1>;
				};
			};	
			xxxxxxxxxxxxxxx
		}
		xxxxxxxxxxxxxxx
	}
}

/*pinnacles_apps/apps_proc/owrt/src/kernel-5.15/kernel_platform/msm-kernel/arch/arm64/boot/dts/vendor/qcom/sdxpinn-pinctrl.dtsi*/
&tlmm {
	xxxxxxxxxxxxxxx
	usb_id_det_default: usb_id_det_default {
		mux {
			pins = "gpio50";
			function = "gpio";
		};
		config {
			pins = "gpio50";
			input-enable;
			bias-pull-up;
		};
	};
	xxxxxxxxxxxxxxx    
}

  那么本篇博客就到此结束了,这里只是记录了一些我个人的学习笔记,其中存在大量我自己的理解。文中所述不一定是完全正确的,可能有的地方我自己也理解错了。如果有些错的地方,欢迎大家批评指正。如有问题直接在对应的博客评论区指出即可,不需要私聊我。我们交流的内容留下来也有助于其他人查看,说不一定也有其他人遇到了同样的问题呢😂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

遇雪长安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值