最近在调试RK3399开发板时遇到一个典型问题:当使用TypeC转USB延长线连接U盘时无法识别,但用双头USB线连接电脑却能正常进行ADB调试。这个问题在工厂试产阶段被发现,直接影响产品的基础功能体验。
经过排查发现问题根源在于硬件设计。我们的TypeC转USB延长线只接了4根线(D+、D-、VCC、GND),而完整的TypeC OTG功能需要CC1/CC2引脚进行模式识别。这就好比给手机配了充电线却少了数据传输线——能充电但传不了数据。fusb302这颗TypeC控制芯片由于缺少CC引脚输入,无法自动判断该进入HOST模式(接U盘)还是DEVICE模式(接电脑)。
TypeC接口包含24个引脚,但实际使用中往往只需要部分关键引脚:
我们的转接线方案相当于"阉割版"TypeC,只保留了最基础的USB2.0功能。这就导致了一个尴尬局面:设备可以供电(VBUS正常),但无法智能识别设备角色。
fusb302作为TypeC端口控制器,其核心工作流程如下:
当CC引脚悬空时,芯片会始终保持在未连接状态(unattached)。这就解释了为什么修改驱动初始状态能临时解决问题——我们手动跳过了检测环节。
最初尝试在/sys目录下创建控制节点,核心代码如下:
c复制// 创建属性文件
static DEVICE_ATTR(usb_mode, 0644, show_mode, store_mode);
// 写入回调
static ssize_t store_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if(strncmp(buf,"host",4)==0) {
set_state(chip, attached_source);
} else {
set_state(chip, attached_sink);
}
return count;
}
这个方法虽然能实现一次切换,但再次切换时失效。调试发现fusb302内部状态机需要完整的流程重置,简单跳转状态无法满足要求。
尝试编译两个驱动模块:
操作步骤:
bash复制# 切换为HOST模式
rmmod fusb302
insmod fusb302_host.ko
# 切换为DEVICE模式
rmmod fusb302_host
insmod fusb302_device.ko
但实际测试发现重新加载会导致系统重启,原因是供电管理模块对驱动卸载处理不完善。
通过阅读RK官方文档,理清了关键架构:
code复制USB3.0 OTG控制器
├── USB3.0通道 → TypeC高速接口
└── USB2.0通道 → TypeC基础接口
├── HOST模式
└── DEVICE模式
关键发现:TypeC接口的USB2.0部分可以独立控制,无需涉及CC引脚检测。
在dtsi文件中强制指定模式:
dts复制fusb0: fusb30x@22 {
compatible = "fairchild,fusb302";
reg = <0x22>;
fusb302,role = "ROLE_MODE_DRP";
// 改为固定模式
fusb302,try_role = "ROLE_MODE_DFP";
status = "okay";
};
同时需要修改USB PHY配置:
dts复制&u2phy0 {
status = "okay";
u2phy0_otg: otg-port {
rockchip,vbus-always-on;
status = "okay";
};
};
c复制static ssize_t force_mode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (sysfs_streq(buf, "host")) {
tcpm_set_cc(chip, ROLE_MODE_DFP);
set_state(chip, attached_source);
} else if (sysfs_streq(buf, "device")) {
tcpm_set_cc(chip, ROLE_MODE_UFP);
set_state(chip, attached_sink);
}
return count;
}
c复制static struct attribute *fusb302_attrs[] = {
&dev_attr_force_mode.attr,
NULL
};
创建控制脚本/usr/bin/usb_mode_ctrl:
bash复制#!/system/bin/sh
case $1 in
host)
echo host > /sys/class/typec/port0/force_mode
;;
device)
echo device > /sys/class/typec/port0/force_mode
;;
esac
在Settings应用中添加切换选项:
java复制public class UsbModePreferenceController {
public boolean onPreferenceChange(Preference preference, Object newValue) {
if ("host".equals(newValue)) {
SystemProperties.set("persist.usb.mode", "host");
Runtime.getRuntime().exec("usb_mode_ctrl host");
} else {
SystemProperties.set("persist.usb.mode", "device");
Runtime.getRuntime().exec("usb_mode_ctrl device");
}
return true;
}
}
测试环境搭建:
测试结果:
| 操作步骤 | 预期结果 | 实际结果 |
|---|---|---|
| 切换为HOST模式后插入U盘 | 正确识别并挂载 | 成功 |
| 切换为DEVICE模式连接PC | 正常ADB连接 | 成功 |
| 快速模式切换测试 | 无系统崩溃 | 稳定运行 |
| 持续工作24小时 | 无异常断开 | 稳定 |
功耗对比:
在调试过程中有几个关键发现:
常见问题排查:
这个方案虽然解决了自动识别缺失的问题,但最佳实践还是应该在硬件设计上完善CC引脚线路。对于已经量产的设备,这个软件方案提供了可靠的补救措施。