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;
}