/* * ip-sleep wakeup mode: * all clocks can be turn off, but power domain should be kept on
*/ staticvoid ssusb_wakeup_ip_sleep_set(struct ssusb_mtk *ssusb, bool enable)
{
u32 reg, msk, val;
/* only configure ports will be used later */ staticint ssusb_host_enable(struct ssusb_mtk *ssusb)
{ void __iomem *ibase = ssusb->ippc_base; int num_u3p = ssusb->u3_ports; int num_u2p = ssusb->u2_ports; int u3_ports_disabled;
u32 check_clk;
u32 value; int i;
/* power on host ip */
mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
/* power on and enable u3 ports except skipped ones */
u3_ports_disabled = 0; for (i = 0; i < num_u3p; i++) { if ((0x1 << i) & ssusb->u3p_dis_msk) {
u3_ports_disabled++; continue;
}
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
value |= SSUSB_U3_PORT_HOST_SEL;
mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
}
/* power on and enable all u2 ports */ for (i = 0; i < num_u2p; i++) { if ((0x1 << i) & ssusb->u2p_dis_msk) continue;
value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS);
value |= SSUSB_U2_PORT_HOST_SEL;
mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
}
check_clk = SSUSB_XHCI_RST_B_STS; if (num_u3p > u3_ports_disabled)
check_clk = SSUSB_U3_MAC_RST_B_STS;
return ssusb_check_clocks(ssusb, check_clk);
}
staticint ssusb_host_disable(struct ssusb_mtk *ssusb)
{ void __iomem *ibase = ssusb->ippc_base; int num_u3p = ssusb->u3_ports; int num_u2p = ssusb->u2_ports;
u32 value; int i;
/* power down and disable u3 ports except skipped ones */ for (i = 0; i < num_u3p; i++) { if ((0x1 << i) & ssusb->u3p_dis_msk) continue;
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS;
mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
}
/* power down and disable u2 ports except skipped ones */ for (i = 0; i < num_u2p; i++) { if ((0x1 << i) & ssusb->u2p_dis_msk) continue;
value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS;
mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
}
/* power down host ip */
mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
return 0;
}
int ssusb_host_resume(struct ssusb_mtk *ssusb, bool p0_skipped)
{ void __iomem *ibase = ssusb->ippc_base; int u3p_skip_msk = ssusb->u3p_dis_msk; int u2p_skip_msk = ssusb->u2p_dis_msk; int num_u3p = ssusb->u3_ports; int num_u2p = ssusb->u2_ports;
u32 value; int i;
if (p0_skipped) {
u2p_skip_msk |= 0x1; if (ssusb->otg_switch.is_u3_drd)
u3p_skip_msk |= 0x1;
}
/* power on host ip */
mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
/* power on u3 ports except skipped ones */ for (i = 0; i < num_u3p; i++) { if ((0x1 << i) & u3p_skip_msk) continue;
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value &= ~SSUSB_U3_PORT_PDN;
mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
}
/* power on all u2 ports except skipped ones */ for (i = 0; i < num_u2p; i++) { if ((0x1 << i) & u2p_skip_msk) continue;
value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
value &= ~SSUSB_U2_PORT_PDN;
mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
}
return 0;
}
/* here not skip port0 due to PDN can be set repeatedly */ int ssusb_host_suspend(struct ssusb_mtk *ssusb)
{ void __iomem *ibase = ssusb->ippc_base; int num_u3p = ssusb->u3_ports; int num_u2p = ssusb->u2_ports;
u32 value; int i;
/* power down u3 ports except skipped ones */ for (i = 0; i < num_u3p; i++) { if ((0x1 << i) & ssusb->u3p_dis_msk) continue;
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value |= SSUSB_U3_PORT_PDN;
mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
}
/* power down u2 ports except skipped ones */ for (i = 0; i < num_u2p; i++) { if ((0x1 << i) & ssusb->u2p_dis_msk) continue;
value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
value |= SSUSB_U2_PORT_PDN;
mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
}
/* power down host ip */
mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
/* * power on host and power on/enable all ports * if support OTG, gadget driver will switch port0 to device mode
*/
ssusb_host_enable(ssusb);
ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
/* if port0 supports dual-role, works as host mode by default */
ssusb_set_vbus(&ssusb->otg_switch, 1);
}
staticvoid ssusb_host_cleanup(struct ssusb_mtk *ssusb)
{ if (ssusb->is_host)
ssusb_set_vbus(&ssusb->otg_switch, 0);
ssusb_host_disable(ssusb);
}
/* * If host supports multiple ports, the VBUSes(5V) of ports except port0 * which supports OTG are better to be enabled by default in DTS. * Because the host driver will keep link with devices attached when system * enters suspend mode, so no need to control VBUSes after initialization.
*/ int ssusb_host_init(struct ssusb_mtk *ssusb, struct device_node *parent_dn)
{ struct device *parent_dev = ssusb->dev; int ret;
ssusb_host_setup(ssusb);
ret = of_platform_populate(parent_dn, NULL, NULL, parent_dev); if (ret) {
dev_dbg(parent_dev, "failed to create child devices at %pOF\n",
parent_dn); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.