mxs_phy
#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy)
return mxs_phy->data == &imx6q_phy_data;
static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy)
return mxs_phy->data == &imx6sl_phy_data;
static inline bool is_imx7ulp_phy(struct mxs_phy *mxs_phy)
return mxs_phy->data == &imx7ulp_phy_data;
static inline bool is_imx6ul_phy(struct mxs_phy *mxs_phy)
return mxs_phy->data == &imx6ul_phy_data;
static void mxs_phy_tx_init(struct mxs_phy *mxs_phy)
void __iomem *base = mxs_phy->phy.io_priv;
if (mxs_phy->tx_reg_mask) {
phytx &= ~mxs_phy->tx_reg_mask;
phytx |= mxs_phy->tx_reg_set;
static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
void __iomem *base = mxs_phy->phy.io_priv;
if (is_imx7ulp_phy(mxs_phy)) {
if (mxs_phy->phy_3p0) {
ret = regulator_enable(mxs_phy->phy_3p0);
dev_err(mxs_phy->phy.dev,
if (mxs_phy->data->flags & MXS_PHY_NEED_IP_FIX)
if (mxs_phy->regmap_anatop) {
unsigned int reg = mxs_phy->port_id ?
regmap_write(mxs_phy->regmap_anatop, reg,
mxs_phy_tx_init(mxs_phy);
if (is_imx7ulp_phy(mxs_phy))
static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy)
if (!mxs_phy->regmap_anatop)
if (mxs_phy->port_id == 0)
regmap_read(mxs_phy->regmap_anatop,
else if (mxs_phy->port_id == 1)
regmap_read(mxs_phy->regmap_anatop,
static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
void __iomem *base = mxs_phy->phy.io_priv;
if (mxs_phy->port_id == 0) {
regmap_write(mxs_phy->regmap_anatop, reg,
} else if (mxs_phy->port_id == 1) {
regmap_write(mxs_phy->regmap_anatop, reg,
static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
return mxs_phy->phy.last_event == USB_EVENT_ID;
static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
enum usb_phy_events last_event = mxs_phy->phy.last_event;
if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS))
if (!mxs_phy->regmap_anatop)
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
if (on && ((!vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
__mxs_phy_disconnect_line(mxs_phy, true);
__mxs_phy_disconnect_line(mxs_phy, false);
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
ret = clk_prepare_enable(mxs_phy->clk);
return mxs_phy_hw_init(mxs_phy);
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
if (is_imx7ulp_phy(mxs_phy))
if (mxs_phy->phy_3p0)
regulator_disable(mxs_phy->phy_3p0);
clk_disable_unprepare(mxs_phy->clk);
static bool mxs_phy_is_low_speed_connection(struct mxs_phy *mxs_phy)
if (!mxs_phy->regmap_anatop)
if (mxs_phy->port_id == 0)
else if (mxs_phy->port_id == 1)
regmap_read(mxs_phy->regmap_anatop, reg, &line_state);
struct mxs_phy *mxs_phy = to_mxs_phy(x);
low_speed_connection = mxs_phy_is_low_speed_connection(mxs_phy);
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
if (!(mxs_phy->port_id == 1 &&
(mxs_phy->data->flags &
clk_disable_unprepare(mxs_phy->clk);
if (!(mxs_phy->port_id == 1 &&
(mxs_phy->data->flags &
ret = clk_prepare_enable(mxs_phy->clk);
struct mxs_phy *mxs_phy = to_mxs_phy(x);
mxs_phy_disconnect_line(mxs_phy, true);
mxs_phy_disconnect_line(mxs_phy, false);
static int mxs_charger_data_contact_detect(struct mxs_phy *x)
static enum usb_charger_type mxs_charger_primary_detection(struct mxs_phy *x)
static enum usb_charger_type mxs_charger_secondary_detection(struct mxs_phy *x)
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
struct regmap *regmap = mxs_phy->regmap_anatop;
if (mxs_charger_data_contact_detect(mxs_phy))
chgr_type = mxs_charger_primary_detection(mxs_phy);
chgr_type = mxs_charger_secondary_detection(mxs_phy);
struct mxs_phy *mxs_phy;
mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL);
if (!mxs_phy)
mxs_phy->regmap_anatop = syscon_regmap_lookup_by_phandle
if (IS_ERR(mxs_phy->regmap_anatop)) {
return PTR_ERR(mxs_phy->regmap_anatop);
mxs_phy->regmap_sim = syscon_regmap_lookup_by_phandle
if (IS_ERR(mxs_phy->regmap_sim)) {
return PTR_ERR(mxs_phy->regmap_sim);
mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DN(~0);
mxs_phy->tx_reg_set |= GM_USBPHY_TX_TXCAL45DN(val);
mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DP(~0);
mxs_phy->tx_reg_set |= GM_USBPHY_TX_TXCAL45DP(val);
mxs_phy->tx_reg_mask |= GM_USBPHY_TX_D_CAL(~0);
mxs_phy->tx_reg_set |= GM_USBPHY_TX_D_CAL(val);
mxs_phy->port_id = ret;
mxs_phy->phy.io_priv = base;
mxs_phy->phy.dev = &pdev->dev;
mxs_phy->phy.label = DRIVER_NAME;
mxs_phy->phy.init = mxs_phy_init;
mxs_phy->phy.shutdown = mxs_phy_shutdown;
mxs_phy->phy.set_suspend = mxs_phy_suspend;
mxs_phy->phy.notify_connect = mxs_phy_on_connect;
mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
mxs_phy->phy.type = USB_PHY_TYPE_USB2;
mxs_phy->phy.set_wakeup = mxs_phy_set_wakeup;
mxs_phy->phy.charger_detect = mxs_phy_charger_detect;
mxs_phy->clk = clk;
mxs_phy->data = of_device_get_match_data(&pdev->dev);
mxs_phy->phy_3p0 = devm_regulator_get(&pdev->dev, "phy-3p0");
if (PTR_ERR(mxs_phy->phy_3p0) == -ENODEV)
mxs_phy->phy_3p0 = NULL;
else if (IS_ERR(mxs_phy->phy_3p0))
return dev_err_probe(&pdev->dev, PTR_ERR(mxs_phy->phy_3p0),
if (mxs_phy->phy_3p0)
regulator_set_voltage(mxs_phy->phy_3p0, 3200000, 3200000);
platform_set_drvdata(pdev, mxs_phy);
return usb_add_phy_dev(&mxs_phy->phy);
struct mxs_phy *mxs_phy = platform_get_drvdata(pdev);
usb_remove_phy(&mxs_phy->phy);
static void mxs_phy_wakeup_enable(struct mxs_phy *mxs_phy, bool on)
if (!mxs_phy->regmap_sim)
regmap_update_bits(mxs_phy->regmap_sim, SIM_GPR1, mask, mask);
regmap_update_bits(mxs_phy->regmap_sim, SIM_GPR1, mask, 0);
static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on)
if (!mxs_phy->regmap_anatop)
if (is_imx6q_phy(mxs_phy)) {
regmap_write(mxs_phy->regmap_anatop, reg,
} else if (is_imx6sl_phy(mxs_phy)) {
regmap_write(mxs_phy->regmap_anatop,
} else if (is_imx6ul_phy(mxs_phy)) {
if (mxs_phy_get_vbus_status(mxs_phy) && on)
regmap_write(mxs_phy->regmap_anatop, reg, value);
regmap_write(mxs_phy->regmap_anatop, reg, value);
struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
mxs_phy_enable_ldo_in_suspend(mxs_phy, true);
mxs_phy_wakeup_enable(mxs_phy, true);
struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
mxs_phy_enable_ldo_in_suspend(mxs_phy, false);
mxs_phy_wakeup_enable(mxs_phy, false);