From c29029bc491e543f48cd3855296fe57c67d644f0 Mon Sep 17 00:00:00 2001 From: Meng Dongyang Date: Tue, 13 Jun 2017 10:05:46 +0800 Subject: [PATCH] phy: rockchip-inno-usb2: disable id irq in pm suspend The otg id voltage is provided from usb2 phy power. On some rockchip platforms (e.g. rk3399), the usb2 phy power will be turned off when enter pm suspend, this will trigger id fall interrupt. But current code enable the ID interrupt consistently, it may result in the mistake of ID changing operation even if the state of ID pin is not changed. So disable ID irq when suspend and enable when resume. Change-Id: Icac35f13861fd639e4b422b31182a68add73836d Signed-off-by: Meng Dongyang --- drivers/phy/phy-rockchip-inno-usb2.c | 187 ++++++++++++++++++--------- 1 file changed, 123 insertions(+), 64 deletions(-) diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c index 020855c0576a..1fbcc5180047 100644 --- a/drivers/phy/phy-rockchip-inno-usb2.c +++ b/drivers/phy/phy-rockchip-inno-usb2.c @@ -440,6 +440,61 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy) return 0; } +/* The caller must hold rport->mutex lock */ +static int rockchip_usb2phy_enable_id_irq(struct rockchip_usb2phy *rphy, + struct rockchip_usb2phy_port *rport, + bool en) +{ + int ret; + + ret = property_enable(rphy, &rport->port_cfg->idfall_det_clr, true); + if (ret) + goto out; + + ret = property_enable(rphy, &rport->port_cfg->idfall_det_en, en); + if (ret) + goto out; + + ret = property_enable(rphy, &rport->port_cfg->idrise_det_clr, true); + if (ret) + goto out; + + ret = property_enable(rphy, &rport->port_cfg->idrise_det_en, en); +out: + return ret; +} + +/* The caller must hold rport->mutex lock */ +static int rockchip_usb2phy_enable_vbus_irq(struct rockchip_usb2phy *rphy, + struct rockchip_usb2phy_port *rport, + bool en) +{ + int ret; + + ret = property_enable(rphy, &rport->port_cfg->bvalid_det_clr, true); + if (ret) + goto out; + + ret = property_enable(rphy, &rport->port_cfg->bvalid_det_en, en); +out: + return ret; +} + +static int rockchip_usb2phy_enable_line_irq(struct rockchip_usb2phy *rphy, + struct rockchip_usb2phy_port *rport, + bool en) +{ + int ret; + + ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true); + if (ret) + goto out; + + ret = property_enable(rphy, &rport->port_cfg->ls_det_en, en); +out: + return ret; +} + static int rockchip_usb2phy_init(struct phy *phy) { struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); @@ -448,70 +503,36 @@ static int rockchip_usb2phy_init(struct phy *phy) mutex_lock(&rport->mutex); - if (rport->port_id == USB2PHY_PORT_OTG) { - if (rport->mode != USB_DR_MODE_HOST && - rport->mode != USB_DR_MODE_UNKNOWN && - !rport->vbus_always_on) { - /* clear bvalid status and enable bvalid detect irq */ - ret = property_enable(rphy, - &rport->port_cfg-> - bvalid_det_clr, - true); - if (ret) - goto out; + if (rport->port_id == USB2PHY_PORT_OTG && + rport->bvalid_irq > 0) { + /* clear bvalid status and enable bvalid detect irq */ + ret = rockchip_usb2phy_enable_vbus_irq(rphy, rport, true); + if (ret) { + dev_err(rphy->dev, + "failed to enable bvalid irq\n"); + goto out; + } - ret = property_enable(rphy, - &rport->port_cfg-> - bvalid_det_en, - true); - if (ret) + /* clear id status and enable id detect irq */ + if (rport->id_irq > 0) { + ret = rockchip_usb2phy_enable_id_irq(rphy, rport, + true); + if (ret) { + dev_err(rphy->dev, + "failed to enable id irq\n"); goto out; - - if (rphy->edev_self) { - ret = property_enable(rphy, - &rport->port_cfg-> - idfall_det_clr, - true); - if (ret) - goto out; - - ret = property_enable(rphy, - &rport->port_cfg-> - idfall_det_en, - true); - if (ret) - goto out; - - ret = property_enable(rphy, - &rport->port_cfg-> - idrise_det_clr, - true); - if (ret) - goto out; - - ret = property_enable(rphy, - &rport->port_cfg-> - idrise_det_en, - true); - if (ret) - goto out; } - - schedule_delayed_work(&rport->otg_sm_work, - OTG_SCHEDULE_DELAY * 3); - } else { - /* If OTG works in host only mode, do nothing. */ - dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode); } + + schedule_delayed_work(&rport->otg_sm_work, + OTG_SCHEDULE_DELAY * 3); } else if (rport->port_id == USB2PHY_PORT_HOST) { /* clear linestate and enable linestate detect irq */ - ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true); - if (ret) - goto out; - - ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true); - if (ret) + ret = rockchip_usb2phy_enable_line_irq(rphy, rport, true); + if (ret) { + dev_err(rphy->dev, "failed to enable linestate irq\n"); goto out; + } schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY); } @@ -1164,8 +1185,7 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work) * activate the linestate detection to get the next device * plug-in irq. */ - property_enable(rphy, &rport->port_cfg->ls_det_clr, true); - property_enable(rphy, &rport->port_cfg->ls_det_en, true); + rockchip_usb2phy_enable_line_irq(rphy, rport, true); /* * we don't need to rearm the delayed work when the phy port @@ -1196,8 +1216,7 @@ static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data) mutex_lock(&rport->mutex); /* disable linestate detect irq and clear its status */ - property_enable(rphy, &rport->port_cfg->ls_det_en, false); - property_enable(rphy, &rport->port_cfg->ls_det_clr, true); + rockchip_usb2phy_enable_line_irq(rphy, rport, false); mutex_unlock(&rport->mutex); @@ -1701,28 +1720,68 @@ static int rockchip_usb2phy_pm_suspend(struct device *dev) struct rockchip_usb2phy *rphy = dev_get_drvdata(dev); struct rockchip_usb2phy_port *rport; int index; + int ret = 0; for (index = 0; index < rphy->phy_cfg->num_ports; index++) { rport = &rphy->ports[index]; if (!rport->phy) continue; + if (rport->port_id == USB2PHY_PORT_OTG && + rport->id_irq > 0) { + mutex_lock(&rport->mutex); + ret = rockchip_usb2phy_enable_id_irq(rphy, rport, + false); + mutex_unlock(&rport->mutex); + if (ret) { + dev_err(rphy->dev, + "failed to disable id irq\n"); + return ret; + } + } + /* activate the linestate to detect the next interrupt. */ - property_enable(rphy, &rport->port_cfg->ls_det_clr, true); - property_enable(rphy, &rport->port_cfg->ls_det_en, true); + mutex_lock(&rport->mutex); + ret = rockchip_usb2phy_enable_line_irq(rphy, rport, true); + mutex_unlock(&rport->mutex); + if (ret) { + dev_err(rphy->dev, "failed to enable linestate irq\n"); + return ret; + } } - return 0; + return ret; } static int rockchip_usb2phy_pm_resume(struct device *dev) { struct rockchip_usb2phy *rphy = dev_get_drvdata(dev); + struct rockchip_usb2phy_port *rport; + int index; int ret = 0; if (rphy->phy_cfg->phy_tuning) ret = rphy->phy_cfg->phy_tuning(rphy); + for (index = 0; index < rphy->phy_cfg->num_ports; index++) { + rport = &rphy->ports[index]; + if (!rport->phy) + continue; + + if (rport->port_id == USB2PHY_PORT_OTG && + rport->id_irq > 0) { + mutex_lock(&rport->mutex); + ret = rockchip_usb2phy_enable_id_irq(rphy, rport, + true); + mutex_unlock(&rport->mutex); + if (ret) { + dev_err(rphy->dev, + "failed to enable id irq\n"); + return ret; + } + } + } + return ret; } -- 2.34.1