USB_HOST_GADGET_SWITCH
相关文件
kernel_imx\arch\arm64\boot\dts\freescale\fsl-imx8qm-mek-domu.dts
: 如果开机固定为host模式,只需修改dr_mode = “host”;如果需要OTG功能切换,底层是根据ID PIN引脚的高低电平进行判断(host device),软件上通过otgsc register判断。&usbotg1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usbotg1>; srp-disable; hnp-disable; adp-disable; power-polarity-active-high; disable-over-current; dr_mode = "host"; status = "okay"; };
kernel_imx/drivers/usb/common/common.c
-------------------------------------------------- platform_device-> ci_get_platdata(dev, platdata); ->usb_get_dr_mode(dev); -------------------------------------------------- enum usb_dr_mode usb_get_dr_mode(struct device *dev) { const char *dr_mode; int err; err = device_property_read_string(dev, "dr_mode", &dr_mode); if (err < 0) return USB_DR_MODE_UNKNOWN; return usb_get_dr_mode_from_string(dr_mode); } EXPORT_SYMBOL_GPL(usb_get_dr_mode);
kernel_imx\drivers\usb\chipidea\core.c
: 由于我们ID脚悬空,则不适用OTG功能,在DTS中直接设置成host,则进入else判断分支。-------------------------------------------------- ci_hdrc_probe-> -> ci->role = ci_get_role(ci); -------------------------------------------------- static enum ci_role ci_get_role(struct ci_hdrc *ci) { if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { if (ci->is_otg) { hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE); return ci_otg_role(ci); } else { /* * If the controller is not OTG capable, but support * role switch, the defalt role is gadget, and the * user can switch it through debugfs. */ return CI_ROLE_GADGET; } } else { return ci->roles[CI_ROLE_HOST] ? CI_ROLE_HOST : CI_ROLE_GADGET; } }
kernel_imx/drivers/usb/chipidea/otg.c
: 此为OTG功能时读取OTGSC寄存器进行判断。/** * ci_otg_role - pick role based on ID pin state * @ci: the controller */ enum ci_role ci_otg_role(struct ci_hdrc *ci) { enum ci_role role = hw_read_otgsc(ci, OTGSC_ID) ? CI_ROLE_GADGET : CI_ROLE_HOST; return role; } /** * hw_read_otgsc returns otgsc register bits value. * @mask: bitfield mask */ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) { struct ci_hdrc_cable *cable; u32 val = hw_read(ci, OP_OTGSC, mask); /* * If using extcon framework for VBUS and/or ID signal * detection overwrite OTGSC register value */ cable = &ci->platdata->vbus_extcon; if (!IS_ERR(cable->edev)) { if (cable->changed) val |= OTGSC_BSVIS; else val &= ~OTGSC_BSVIS; if (cable->connected) val |= OTGSC_BSV; else val &= ~OTGSC_BSV; if (cable->enabled) val |= OTGSC_BSVIE; else val &= ~OTGSC_BSVIE; } cable = &ci->platdata->id_extcon; if (!IS_ERR(cable->edev)) { if (cable->changed) val |= OTGSC_IDIS; else val &= ~OTGSC_IDIS; if (cable->connected) val &= ~OTGSC_ID; /* host */ else val |= OTGSC_ID; /* device */ if (cable->enabled) val |= OTGSC_IDIE; else val &= ~OTGSC_IDIE; } return val & mask; }