#include <linux/power_supply.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
+#include <linux/usb/of.h>
#include <linux/usb/otg.h>
#include <linux/wakelock.h>
static const unsigned int rockchip_usb2phy_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
+ EXTCON_USB_VBUS_EN,
EXTCON_CHG_USB_SDP,
EXTCON_CHG_USB_CDP,
EXTCON_CHG_USB_DCP,
* @ls_det_en: linestate detection enable register.
* @ls_det_st: linestate detection state register.
* @ls_det_clr: linestate detection clear register.
+ * @idfall_det_en: id fall detection enable register.
+ * @idfall_det_st: id fall detection state register.
+ * @idfall_det_clr: id fall detection clear register.
+ * @idrise_det_en: id rise detection enable register.
+ * @idrise_det_st: id rise detection state register.
+ * @idrise_det_clr: id rise detection clear register.
* @utmi_avalid: utmi vbus avalid status register.
* @utmi_bvalid: utmi vbus bvalid status register.
+ * @utmi_iddig: otg port id pin status register.
* @utmi_ls: utmi linestate state register.
* @utmi_hstdet: utmi host disconnect register.
*/
struct usb2phy_reg ls_det_en;
struct usb2phy_reg ls_det_st;
struct usb2phy_reg ls_det_clr;
+ struct usb2phy_reg idfall_det_en;
+ struct usb2phy_reg idfall_det_st;
+ struct usb2phy_reg idfall_det_clr;
+ struct usb2phy_reg idrise_det_en;
+ struct usb2phy_reg idrise_det_st;
+ struct usb2phy_reg idrise_det_clr;
struct usb2phy_reg utmi_avalid;
struct usb2phy_reg utmi_bvalid;
+ struct usb2phy_reg utmi_iddig;
struct usb2phy_reg utmi_ls;
struct usb2phy_reg utmi_hstdet;
};
/**
* struct rockchip_usb2phy_port: usb-phy port data.
* @port_id: flag for otg port or host port.
+ * @perip_connected: flag for periphyeral connect status.
* @suspended: phy suspended flag.
* @utmi_avalid: utmi avalid status usage flag.
* true - use avalid to get vbus status
* flase - use bvalid to get vbus status
* @vbus_attached: otg device vbus status.
+ * @vbus_always_on: otg vbus is always powered on.
* @bvalid_irq: IRQ number assigned for vbus valid rise detection.
* @ls_irq: IRQ number assigned for linestate detection.
+ * @id_irq: IRQ number assigned for id fall or rise detection.
* @mutex: for register updating in sm_work.
* @chg_work: charge detect work.
* @otg_sm_work: OTG state machine work.
* @wakelock: wake lock struct to prevent system suspend
* when USB is active.
* @state: define OTG enumeration states before device reset.
+ * @mode: the dr_mode of the controller.
*/
struct rockchip_usb2phy_port {
struct phy *phy;
unsigned int port_id;
+ bool perip_connected;
bool suspended;
bool utmi_avalid;
bool vbus_attached;
+ bool vbus_always_on;
int bvalid_irq;
int ls_irq;
+ int id_irq;
struct mutex mutex;
struct delayed_work chg_work;
struct delayed_work otg_sm_work;
struct notifier_block event_nb;
struct wake_lock wakelock;
enum usb_otg_state state;
+ enum usb_dr_mode mode;
};
/**
* @chg_type: USB charger types.
* @dcd_retries: The retry count used to track Data contact
* detection process.
+ * @edev_self: represent the source of extcon.
* @edev: extcon device for notification registration
* @phy_cfg: phy register configuration, assigned by driver data.
* @ports: phy port instance.
enum usb_chg_state chg_state;
enum power_supply_type chg_type;
u8 dcd_retries;
+ u8 primary_retries;
+ bool edev_self;
struct extcon_dev *edev;
const struct rockchip_usb2phy_cfg *phy_cfg;
struct rockchip_usb2phy_port ports[USB2PHY_NUM_PORTS];
return tmp == reg->enable;
}
-static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw)
+static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)
{
struct rockchip_usb2phy *rphy =
container_of(hw, struct rockchip_usb2phy, clk480m_hw);
if (ret)
return ret;
- /* waitting for the clk become stable */
- mdelay(1);
+ /* waiting for the clk become stable */
+ usleep_range(1200, 1300);
}
return 0;
}
-static void rockchip_usb2phy_clk480m_disable(struct clk_hw *hw)
+static void rockchip_usb2phy_clk480m_unprepare(struct clk_hw *hw)
{
struct rockchip_usb2phy *rphy =
container_of(hw, struct rockchip_usb2phy, clk480m_hw);
property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false);
}
-static int rockchip_usb2phy_clk480m_enabled(struct clk_hw *hw)
+static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw)
{
struct rockchip_usb2phy *rphy =
container_of(hw, struct rockchip_usb2phy, clk480m_hw);
}
static const struct clk_ops rockchip_usb2phy_clkout_ops = {
- .enable = rockchip_usb2phy_clk480m_enable,
- .disable = rockchip_usb2phy_clk480m_disable,
- .is_enabled = rockchip_usb2phy_clk480m_enabled,
+ .prepare = rockchip_usb2phy_clk480m_prepare,
+ .unprepare = rockchip_usb2phy_clk480m_unprepare,
+ .is_prepared = rockchip_usb2phy_clk480m_prepared,
.recalc_rate = rockchip_usb2phy_clk480m_recalc_rate,
};
dev_err(rphy->dev, "failed to register extcon device\n");
return ret;
}
+
+ rphy->edev_self = true;
}
rphy->edev = edev;
{
struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
- int ret;
+ int ret = 0;
mutex_lock(&rport->mutex);
if (rport->port_id == USB2PHY_PORT_OTG) {
- /* clear bvalid status and enable bvalid detect irq */
- ret = property_enable(rphy,
- &rport->port_cfg->bvalid_det_clr, true);
- if (ret) {
- mutex_unlock(&rport->mutex);
- return ret;
- }
-
- ret = property_enable(rphy,
- &rport->port_cfg->bvalid_det_en, true);
- if (ret) {
- mutex_unlock(&rport->mutex);
- return ret;
- }
+ if (rport->mode != USB_DR_MODE_HOST &&
+ !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;
- mutex_unlock(&rport->mutex);
- schedule_delayed_work(&rport->otg_sm_work, OTG_SCHEDULE_DELAY);
+ ret = property_enable(rphy,
+ &rport->port_cfg->
+ bvalid_det_en,
+ true);
+ if (ret)
+ 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);
+ } else {
+ /* If OTG works in host only mode, do nothing. */
+ dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode);
+ }
} 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) {
- mutex_unlock(&rport->mutex);
- return ret;
- }
+ if (ret)
+ goto out;
ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
- if (ret) {
- mutex_unlock(&rport->mutex);
- return ret;
- }
+ if (ret)
+ goto out;
- mutex_unlock(&rport->mutex);
schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
}
- return 0;
+out:
+ mutex_unlock(&rport->mutex);
+ return ret;
}
static int rockchip_usb2phy_power_on(struct phy *phy)
{
struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
- if (rport->port_id == USB2PHY_PORT_OTG) {
+ if (rport->port_id == USB2PHY_PORT_OTG &&
+ rport->mode != USB_DR_MODE_HOST &&
+ !rport->vbus_always_on)
cancel_delayed_work_sync(&rport->chg_work);
- cancel_delayed_work_sync(&rport->otg_sm_work);
- } else if (rport->port_id == USB2PHY_PORT_HOST)
+ else if (rport->port_id == USB2PHY_PORT_HOST)
cancel_delayed_work_sync(&rport->sm_work);
return 0;
struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
static unsigned int cable;
unsigned long delay;
- bool vbus_attach, sch_work, notify_charger;
+ bool sch_work;
if (rport->utmi_avalid)
- vbus_attach =
+ rport->vbus_attached =
property_enabled(rphy, &rport->port_cfg->utmi_avalid);
else
- vbus_attach =
+ rport->vbus_attached =
property_enabled(rphy, &rport->port_cfg->utmi_bvalid);
sch_work = false;
- notify_charger = false;
delay = OTG_SCHEDULE_DELAY;
+
dev_dbg(&rport->phy->dev, "%s otg sm work\n",
usb_otg_state_string(rport->state));
switch (rport->state) {
case OTG_STATE_UNDEFINED:
rport->state = OTG_STATE_B_IDLE;
- if (!vbus_attach)
+ if (!rport->vbus_attached)
rockchip_usb2phy_power_off(rport->phy);
/* fall through */
case OTG_STATE_B_IDLE:
- if (extcon_get_cable_state_(rphy->edev, EXTCON_USB_HOST) > 0) {
+ if (extcon_get_cable_state_(rphy->edev, EXTCON_USB_HOST) > 0 ||
+ extcon_get_cable_state_(rphy->edev,
+ EXTCON_USB_VBUS_EN) > 0) {
dev_dbg(&rport->phy->dev, "usb otg host connect\n");
rport->state = OTG_STATE_A_HOST;
rockchip_usb2phy_power_on(rport->phy);
return;
- } else if (vbus_attach) {
+ } else if (rport->vbus_attached) {
dev_dbg(&rport->phy->dev, "vbus_attach\n");
switch (rphy->chg_state) {
case USB_CHG_STATE_UNDEFINED:
dev_dbg(&rport->phy->dev,
"sdp cable is connecetd\n");
wake_lock(&rport->wakelock);
+ cable = EXTCON_CHG_USB_SDP;
rockchip_usb2phy_power_on(rport->phy);
rport->state = OTG_STATE_B_PERIPHERAL;
- notify_charger = true;
+ rport->perip_connected = true;
sch_work = true;
- cable = EXTCON_CHG_USB_SDP;
break;
case POWER_SUPPLY_TYPE_USB_DCP:
dev_dbg(&rport->phy->dev,
"dcp cable is connecetd\n");
+ cable = EXTCON_CHG_USB_DCP;
rockchip_usb2phy_power_off(rport->phy);
- notify_charger = true;
sch_work = true;
- cable = EXTCON_CHG_USB_DCP;
break;
case POWER_SUPPLY_TYPE_USB_CDP:
dev_dbg(&rport->phy->dev,
"cdp cable is connecetd\n");
wake_lock(&rport->wakelock);
+ cable = EXTCON_CHG_USB_CDP;
rockchip_usb2phy_power_on(rport->phy);
rport->state = OTG_STATE_B_PERIPHERAL;
- notify_charger = true;
+ rport->perip_connected = true;
sch_work = true;
- cable = EXTCON_CHG_USB_CDP;
break;
case POWER_SUPPLY_TYPE_USB_FLOATING:
dev_dbg(&rport->phy->dev,
"floating cable is connecetd\n");
+ cable = EXTCON_CHG_USB_DCP;
rockchip_usb2phy_power_off(rport->phy);
- notify_charger = true;
sch_work = true;
- cable = EXTCON_CHG_USB_SLOW;
break;
default:
break;
break;
}
} else {
- notify_charger = true;
rphy->chg_state = USB_CHG_STATE_UNDEFINED;
rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
}
-
- if (rport->vbus_attached != vbus_attach) {
- rport->vbus_attached = vbus_attach;
-
- if (notify_charger && rphy->edev)
- extcon_set_cable_state_(rphy->edev,
- cable, vbus_attach);
- }
break;
case OTG_STATE_B_PERIPHERAL:
- if (!vbus_attach) {
+ if (!rport->vbus_attached) {
dev_dbg(&rport->phy->dev, "usb disconnect\n");
rphy->chg_state = USB_CHG_STATE_UNDEFINED;
rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
rport->state = OTG_STATE_B_IDLE;
+ rport->perip_connected = false;
delay = 0;
rockchip_usb2phy_power_off(rport->phy);
wake_unlock(&rport->wakelock);
+ } else {
+ sch_work = true;
}
- sch_work = true;
break;
case OTG_STATE_A_HOST:
if (extcon_get_cable_state_(rphy->edev, EXTCON_USB_HOST) == 0) {
rport->state = OTG_STATE_B_IDLE;
rockchip_usb2phy_power_off(rport->phy);
}
- break;
+ return;
default:
- break;
+ return;
}
+ if (extcon_get_state(rphy->edev, cable) != rport->vbus_attached)
+ extcon_set_cable_state_(rphy->edev,
+ cable, rport->vbus_attached);
+
+ if (rphy->edev_self &&
+ (extcon_get_state(rphy->edev, EXTCON_USB) !=
+ rport->perip_connected))
+ extcon_set_cable_state_(rphy->edev,
+ EXTCON_USB,
+ rport->perip_connected);
+
if (sch_work)
schedule_delayed_work(&rport->otg_sm_work, delay);
}
rockchip_chg_enable_dcd(rphy, true);
rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
rphy->dcd_retries = 0;
+ rphy->primary_retries = 0;
delay = CHG_DCD_POLL_TIME;
break;
case USB_CHG_STATE_WAIT_FOR_DCD:
delay = CHG_SECONDARY_DET_TIME;
rphy->chg_state = USB_CHG_STATE_PRIMARY_DONE;
} else {
- if (tmout) {
+ if (rphy->dcd_retries == CHG_DCD_MAX_RETRIES) {
/* floating charger found */
rphy->chg_type = POWER_SUPPLY_TYPE_USB_FLOATING;
rphy->chg_state = USB_CHG_STATE_DETECTED;
delay = 0;
} else {
+ if (rphy->primary_retries < 2) {
+ /* Turn off DCD circuitry */
+ rockchip_chg_enable_dcd(rphy, false);
+ /* Voltage Source on DP, Probe on DM */
+ rockchip_chg_enable_primary_det(rphy,
+ true);
+ delay = CHG_PRIMARY_DET_TIME;
+ rphy->chg_state =
+ USB_CHG_STATE_DCD_DONE;
+ rphy->primary_retries++;
+ /* break USB_CHG_STATE_DCD_DONE */
+ break;
+ }
rphy->chg_type = POWER_SUPPLY_TYPE_USB;
rphy->chg_state = USB_CHG_STATE_DETECTED;
delay = 0;
if (!property_enabled(rphy, &rport->port_cfg->ls_det_st))
return IRQ_NONE;
+ dev_dbg(&rport->phy->dev, "linestate interrupt\n");
+
mutex_lock(&rport->mutex);
/* disable linestate detect irq and clear its status */
* meanwhile, if the phy port is suspended, we need rearm the work to
* resume it and mange its states; otherwise, we do nothing about that.
*/
- if (rport->suspended && rport->port_id == USB2PHY_PORT_HOST)
- rockchip_usb2phy_sm_work(&rport->sm_work.work);
+ if (rport->suspended) {
+ if (rport->port_id == USB2PHY_PORT_HOST)
+ rockchip_usb2phy_sm_work(&rport->sm_work.work);
+ else
+ rockchip_usb2phy_power_on(rport->phy);
+ }
return IRQ_HANDLED;
}
return IRQ_HANDLED;
}
+static irqreturn_t rockchip_usb2phy_id_irq(int irq, void *data)
+{
+ struct rockchip_usb2phy_port *rport = data;
+ struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+
+ if (!property_enabled(rphy, &rport->port_cfg->idfall_det_st) &&
+ !property_enabled(rphy, &rport->port_cfg->idrise_det_st))
+ return IRQ_NONE;
+
+ mutex_lock(&rport->mutex);
+
+ /* clear id fall or rise detect irq pending status */
+ if (property_enabled(rphy, &rport->port_cfg->idfall_det_st)) {
+ property_enable(rphy, &rport->port_cfg->idfall_det_clr,
+ true);
+ extcon_set_state(rphy->edev, EXTCON_USB_HOST, true);
+ extcon_set_state(rphy->edev, EXTCON_USB_VBUS_EN, true);
+ } else if (property_enabled(rphy, &rport->port_cfg->idrise_det_st)) {
+ property_enable(rphy, &rport->port_cfg->idrise_det_clr,
+ true);
+ extcon_set_state(rphy->edev, EXTCON_USB_HOST, false);
+ extcon_set_state(rphy->edev, EXTCON_USB_VBUS_EN, false);
+ }
+
+ extcon_sync(rphy->edev, EXTCON_USB_HOST);
+ extcon_sync(rphy->edev, EXTCON_USB_VBUS_EN);
+
+ mutex_unlock(&rport->mutex);
+
+ return IRQ_HANDLED;
+}
+
static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
struct rockchip_usb2phy_port *rport,
struct device_node *child_np)
struct device_node *child_np)
{
int ret;
+ int iddig;
rport->port_id = USB2PHY_PORT_OTG;
rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
rport->state = OTG_STATE_UNDEFINED;
+
/*
* set suspended flag to true, but actually don't
* put phy in suspend mode, it aims to enable usb
*/
rport->suspended = true;
rport->vbus_attached = false;
+ rport->perip_connected = false;
mutex_init(&rport->mutex);
+
+ rport->ls_irq = of_irq_get_byname(child_np, "linestate");
+ if (rport->ls_irq < 0) {
+ dev_err(rphy->dev, "no linestate irq provided\n");
+ return rport->ls_irq;
+ }
+
+ ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL,
+ rockchip_usb2phy_linestate_irq,
+ IRQF_ONESHOT,
+ "rockchip_usb2phy", rport);
+ if (ret) {
+ dev_err(rphy->dev, "failed to request linestate irq handle\n");
+ return ret;
+ }
+
+ rport->vbus_always_on =
+ of_property_read_bool(child_np, "rockchip,vbus-always-on");
+
+ rport->mode = of_usb_get_dr_mode_by_phy(child_np, -1);
+ if (rport->mode == USB_DR_MODE_HOST || rport->vbus_always_on)
+ return 0;
+
wake_lock_init(&rport->wakelock, WAKE_LOCK_SUSPEND, "rockchip_otg");
INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work);
return ret;
}
+ if (rphy->edev_self) {
+ rport->id_irq = of_irq_get_byname(child_np, "otg-id");
+ if (rport->id_irq < 0) {
+ dev_err(rphy->dev, "no otg id irq provided\n");
+ return rport->id_irq;
+ }
+
+ ret = devm_request_threaded_irq(rphy->dev, rport->id_irq, NULL,
+ rockchip_usb2phy_id_irq,
+ IRQF_ONESHOT,
+ "rockchip_usb2phy_id", rport);
+ if (ret) {
+ dev_err(rphy->dev, "failed to request otg-id irq handle\n");
+ return ret;
+ }
+
+ iddig = property_enabled(rphy, &rport->port_cfg->utmi_iddig);
+ if (!iddig) {
+ extcon_set_state(rphy->edev, EXTCON_USB, false);
+ extcon_set_state(rphy->edev, EXTCON_USB_HOST, true);
+ extcon_set_state(rphy->edev, EXTCON_USB_VBUS_EN, true);
+ } else {
+ extcon_set_state(rphy->edev, EXTCON_USB_HOST, false);
+ extcon_set_state(rphy->edev, EXTCON_USB_VBUS_EN, false);
+ }
+ }
+
if (!IS_ERR(rphy->edev)) {
rport->event_nb.notifier_call = rockchip_otg_event;
phy_cfgs = match->data;
rphy->chg_state = USB_CHG_STATE_UNDEFINED;
rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
+ rphy->edev_self = false;
platform_set_drvdata(pdev, rphy);
ret = rockchip_usb2phy_extcon_register(rphy);
return ret;
}
+static int rk3399_usb2phy_tuning(struct rockchip_usb2phy *rphy)
+{
+ struct device_node *node = rphy->dev->of_node;
+ int ret = 0;
+
+ if (!of_property_read_bool(node, "rockchip,u2phy-tuning"))
+ return ret;
+
+ if (rphy->phy_cfg->reg == 0xe450) {
+ /*
+ * Set max ODT compensation voltage and
+ * current tuning reference for PHY0.
+ */
+ ret |= regmap_write(rphy->grf, 0x448c,
+ GENMASK(23, 16) | 0xe3);
+
+ /* Set max pre-emphasis level for PHY0 */
+ ret |= regmap_write(rphy->grf, 0x44b0,
+ GENMASK(18, 16) | 0x07);
+
+ /*
+ * Disable the pre-emphasize in eop state
+ * and chirp state to avoid mis-trigger the
+ * disconnect detection and also avoid hs
+ * handshake fail for PHY0.
+ */
+ ret |= regmap_write(rphy->grf, 0x4480,
+ GENMASK(17, 16) | 0x0);
+ ret |= regmap_write(rphy->grf, 0x44b4,
+ GENMASK(17, 16) | 0x0);
+ } else {
+ /*
+ * Set max ODT compensation voltage and
+ * current tuning reference for PHY1.
+ */
+ ret |= regmap_write(rphy->grf, 0x450c,
+ GENMASK(23, 16) | 0xe3);
+
+ /* Set max pre-emphasis level for PHY1 */
+ ret |= regmap_write(rphy->grf, 0x4530,
+ GENMASK(18, 16) | 0x07);
+
+ /*
+ * Disable the pre-emphasize in eop state
+ * and chirp state to avoid mis-trigger the
+ * disconnect detection and also avoid hs
+ * handshake fail for PHY1.
+ */
+ ret |= regmap_write(rphy->grf, 0x4500,
+ GENMASK(17, 16) | 0x0);
+ ret |= regmap_write(rphy->grf, 0x4534,
+ GENMASK(17, 16) | 0x0);
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_usb2phy_pm_suspend(struct device *dev)
+{
+ struct rockchip_usb2phy *rphy = dev_get_drvdata(dev);
+ struct rockchip_usb2phy_port *rport;
+ int index;
+
+ for (index = 0; index < rphy->phy_cfg->num_ports; index++) {
+ rport = &rphy->ports[index];
+ if (!rport->phy)
+ continue;
+
+ /* 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);
+ }
+
+ return 0;
+}
+
+static int rockchip_usb2phy_pm_resume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops rockchip_usb2phy_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(rockchip_usb2phy_pm_suspend,
+ rockchip_usb2phy_pm_resume)
+};
+
+#define ROCKCHIP_USB2PHY_DEV_PM (&rockchip_usb2phy_dev_pm_ops)
+#else
+#define ROCKCHIP_USB2PHY_DEV_PM NULL
+#endif /* CONFIG_PM_SLEEP */
+
static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
{
.reg = 0x700,
{
.reg = 0xe450,
.num_ports = 2,
+ .phy_tuning = rk3399_usb2phy_tuning,
.clkout_ctl = { 0xe450, 4, 4, 1, 0 },
.port_cfgs = {
[USB2PHY_PORT_OTG] = {
- .phy_sus = { 0xe454, 1, 0, 2, 1 },
+ .phy_sus = { 0xe454, 15, 0, 0x1452, 0x15d1 },
.bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 },
.bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 },
.bvalid_det_clr = { 0xe3d0, 3, 3, 0, 1 },
+ .idfall_det_en = { 0xe3c0, 5, 5, 0, 1 },
+ .idfall_det_st = { 0xe3e0, 5, 5, 0, 1 },
+ .idfall_det_clr = { 0xe3d0, 5, 5, 0, 1 },
+ .idrise_det_en = { 0xe3c0, 4, 4, 0, 1 },
+ .idrise_det_st = { 0xe3e0, 4, 4, 0, 1 },
+ .idrise_det_clr = { 0xe3d0, 4, 4, 0, 1 },
+ .ls_det_en = { 0xe3c0, 2, 2, 0, 1 },
+ .ls_det_st = { 0xe3e0, 2, 2, 0, 1 },
+ .ls_det_clr = { 0xe3d0, 2, 2, 0, 1 },
.utmi_avalid = { 0xe2ac, 7, 7, 0, 1 },
.utmi_bvalid = { 0xe2ac, 12, 12, 0, 1 },
+ .utmi_iddig = { 0xe2ac, 8, 8, 0, 1 },
+ .utmi_ls = { 0xe2ac, 14, 13, 0, 1 },
},
[USB2PHY_PORT_HOST] = {
.phy_sus = { 0xe458, 1, 0, 0x2, 0x1 },
{
.reg = 0xe460,
.num_ports = 2,
+ .phy_tuning = rk3399_usb2phy_tuning,
.clkout_ctl = { 0xe460, 4, 4, 1, 0 },
.port_cfgs = {
[USB2PHY_PORT_OTG] = {
- .phy_sus = { 0xe464, 1, 0, 2, 1 },
+ .phy_sus = { 0xe464, 15, 0, 0x1452, 0x15d1 },
.bvalid_det_en = { 0xe3c0, 8, 8, 0, 1 },
.bvalid_det_st = { 0xe3e0, 8, 8, 0, 1 },
.bvalid_det_clr = { 0xe3d0, 8, 8, 0, 1 },
+ .idfall_det_en = { 0xe3c0, 10, 10, 0, 1 },
+ .idfall_det_st = { 0xe3e0, 10, 10, 0, 1 },
+ .idfall_det_clr = { 0xe3d0, 10, 10, 0, 1 },
+ .idrise_det_en = { 0xe3c0, 9, 9, 0, 1 },
+ .idrise_det_st = { 0xe3e0, 9, 9, 0, 1 },
+ .idrise_det_clr = { 0xe3d0, 9, 9, 0, 1 },
+ .ls_det_en = { 0xe3c0, 7, 7, 0, 1 },
+ .ls_det_st = { 0xe3e0, 7, 7, 0, 1 },
+ .ls_det_clr = { 0xe3d0, 7, 7, 0, 1 },
.utmi_avalid = { 0xe2ac, 10, 10, 0, 1 },
.utmi_bvalid = { 0xe2ac, 16, 16, 0, 1 },
+ .utmi_iddig = { 0xe2ac, 11, 11, 0, 1 },
+ .utmi_ls = { 0xe2ac, 18, 17, 0, 1 },
},
[USB2PHY_PORT_HOST] = {
.phy_sus = { 0xe468, 1, 0, 0x2, 0x1 },
.probe = rockchip_usb2phy_probe,
.driver = {
.name = "rockchip-usb2phy",
+ .pm = ROCKCHIP_USB2PHY_DEV_PM,
.of_match_table = rockchip_usb2phy_dt_match,
},
};