Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1543645c authored by Frank Wang's avatar Frank Wang Committed by Kishon Vijay Abraham I
Browse files

phy: rockchip-inno-usb2: add support for rockchip,usbgrf property



The registers of usb-phy are distributed in grf and usbgrf on some
Rockchip SoCs (e.g RV1108), this patch add a new rockchip,usbgrf
property to support this companion grf design.

Signed-off-by: default avatarFrank Wang <frank.wang@rock-chips.com>
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent 4b63743c
Loading
Loading
Loading
Loading
+71 −38
Original line number Original line Diff line number Diff line
@@ -202,6 +202,7 @@ struct rockchip_usb2phy_port {
/**
/**
 * struct rockchip_usb2phy: usb2.0 phy driver data.
 * struct rockchip_usb2phy: usb2.0 phy driver data.
 * @grf: General Register Files regmap.
 * @grf: General Register Files regmap.
 * @usbgrf: USB General Register Files regmap.
 * @clk: clock struct of phy input clk.
 * @clk: clock struct of phy input clk.
 * @clk480m: clock struct of phy output clk.
 * @clk480m: clock struct of phy output clk.
 * @clk_hw: clock struct of phy output clk management.
 * @clk_hw: clock struct of phy output clk management.
@@ -216,6 +217,7 @@ struct rockchip_usb2phy_port {
struct rockchip_usb2phy {
struct rockchip_usb2phy {
	struct device	*dev;
	struct device	*dev;
	struct regmap	*grf;
	struct regmap	*grf;
	struct regmap	*usbgrf;
	struct clk	*clk;
	struct clk	*clk;
	struct clk	*clk480m;
	struct clk	*clk480m;
	struct clk_hw	clk480m_hw;
	struct clk_hw	clk480m_hw;
@@ -227,7 +229,12 @@ struct rockchip_usb2phy {
	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];
	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];
};
};


static inline int property_enable(struct rockchip_usb2phy *rphy,
static inline struct regmap *get_reg_base(struct rockchip_usb2phy *rphy)
{
	return rphy->usbgrf == NULL ? rphy->grf : rphy->usbgrf;
}

static inline int property_enable(struct regmap *base,
				  const struct usb2phy_reg *reg, bool en)
				  const struct usb2phy_reg *reg, bool en)
{
{
	unsigned int val, mask, tmp;
	unsigned int val, mask, tmp;
@@ -236,17 +243,17 @@ static inline int property_enable(struct rockchip_usb2phy *rphy,
	mask = GENMASK(reg->bitend, reg->bitstart);
	mask = GENMASK(reg->bitend, reg->bitstart);
	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);


	return regmap_write(rphy->grf, reg->offset, val);
	return regmap_write(base, reg->offset, val);
}
}


static inline bool property_enabled(struct rockchip_usb2phy *rphy,
static inline bool property_enabled(struct regmap *base,
				    const struct usb2phy_reg *reg)
				    const struct usb2phy_reg *reg)
{
{
	int ret;
	int ret;
	unsigned int tmp, orig;
	unsigned int tmp, orig;
	unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
	unsigned int mask = GENMASK(reg->bitend, reg->bitstart);


	ret = regmap_read(rphy->grf, reg->offset, &orig);
	ret = regmap_read(base, reg->offset, &orig);
	if (ret)
	if (ret)
		return false;
		return false;


@@ -258,11 +265,12 @@ static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)
{
{
	struct rockchip_usb2phy *rphy =
	struct rockchip_usb2phy *rphy =
		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
	struct regmap *base = get_reg_base(rphy);
	int ret;
	int ret;


	/* turn on 480m clk output if it is off */
	/* turn on 480m clk output if it is off */
	if (!property_enabled(rphy, &rphy->phy_cfg->clkout_ctl)) {
	if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) {
		ret = property_enable(rphy, &rphy->phy_cfg->clkout_ctl, true);
		ret = property_enable(base, &rphy->phy_cfg->clkout_ctl, true);
		if (ret)
		if (ret)
			return ret;
			return ret;


@@ -277,17 +285,19 @@ static void rockchip_usb2phy_clk480m_unprepare(struct clk_hw *hw)
{
{
	struct rockchip_usb2phy *rphy =
	struct rockchip_usb2phy *rphy =
		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
	struct regmap *base = get_reg_base(rphy);


	/* turn off 480m clk output */
	/* turn off 480m clk output */
	property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false);
	property_enable(base, &rphy->phy_cfg->clkout_ctl, false);
}
}


static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw)
static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw)
{
{
	struct rockchip_usb2phy *rphy =
	struct rockchip_usb2phy *rphy =
		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
	struct regmap *base = get_reg_base(rphy);


	return property_enabled(rphy, &rphy->phy_cfg->clkout_ctl);
	return property_enabled(base, &rphy->phy_cfg->clkout_ctl);
}
}


static unsigned long
static unsigned long
@@ -409,13 +419,13 @@ static int rockchip_usb2phy_init(struct phy *phy)
		if (rport->mode != USB_DR_MODE_HOST &&
		if (rport->mode != USB_DR_MODE_HOST &&
		    rport->mode != USB_DR_MODE_UNKNOWN) {
		    rport->mode != USB_DR_MODE_UNKNOWN) {
			/* clear bvalid status and enable bvalid detect irq */
			/* clear bvalid status and enable bvalid detect irq */
			ret = property_enable(rphy,
			ret = property_enable(rphy->grf,
					      &rport->port_cfg->bvalid_det_clr,
					      &rport->port_cfg->bvalid_det_clr,
					      true);
					      true);
			if (ret)
			if (ret)
				goto out;
				goto out;


			ret = property_enable(rphy,
			ret = property_enable(rphy->grf,
					      &rport->port_cfg->bvalid_det_en,
					      &rport->port_cfg->bvalid_det_en,
					      true);
					      true);
			if (ret)
			if (ret)
@@ -429,11 +439,13 @@ static int rockchip_usb2phy_init(struct phy *phy)
		}
		}
	} else if (rport->port_id == USB2PHY_PORT_HOST) {
	} else if (rport->port_id == USB2PHY_PORT_HOST) {
		/* clear linestate and enable linestate detect irq */
		/* clear linestate and enable linestate detect irq */
		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
		ret = property_enable(rphy->grf,
				      &rport->port_cfg->ls_det_clr, true);
		if (ret)
		if (ret)
			goto out;
			goto out;


		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
		ret = property_enable(rphy->grf,
				      &rport->port_cfg->ls_det_en, true);
		if (ret)
		if (ret)
			goto out;
			goto out;


@@ -449,6 +461,7 @@ static int rockchip_usb2phy_power_on(struct phy *phy)
{
{
	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
	struct regmap *base = get_reg_base(rphy);
	int ret;
	int ret;


	dev_dbg(&rport->phy->dev, "port power on\n");
	dev_dbg(&rport->phy->dev, "port power on\n");
@@ -460,7 +473,7 @@ static int rockchip_usb2phy_power_on(struct phy *phy)
	if (ret)
	if (ret)
		return ret;
		return ret;


	ret = property_enable(rphy, &rport->port_cfg->phy_sus, false);
	ret = property_enable(base, &rport->port_cfg->phy_sus, false);
	if (ret)
	if (ret)
		return ret;
		return ret;


@@ -475,6 +488,7 @@ static int rockchip_usb2phy_power_off(struct phy *phy)
{
{
	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
	struct regmap *base = get_reg_base(rphy);
	int ret;
	int ret;


	dev_dbg(&rport->phy->dev, "port power off\n");
	dev_dbg(&rport->phy->dev, "port power off\n");
@@ -482,7 +496,7 @@ static int rockchip_usb2phy_power_off(struct phy *phy)
	if (rport->suspended)
	if (rport->suspended)
		return 0;
		return 0;


	ret = property_enable(rphy, &rport->port_cfg->phy_sus, true);
	ret = property_enable(base, &rport->port_cfg->phy_sus, true);
	if (ret)
	if (ret)
		return ret;
		return ret;


@@ -526,11 +540,11 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
	bool vbus_attach, sch_work, notify_charger;
	bool vbus_attach, sch_work, notify_charger;


	if (rport->utmi_avalid)
	if (rport->utmi_avalid)
		vbus_attach =
		vbus_attach = property_enabled(rphy->grf,
			property_enabled(rphy, &rport->port_cfg->utmi_avalid);
					       &rport->port_cfg->utmi_avalid);
	else
	else
		vbus_attach =
		vbus_attach = property_enabled(rphy->grf,
			property_enabled(rphy, &rport->port_cfg->utmi_bvalid);
					       &rport->port_cfg->utmi_bvalid);


	sch_work = false;
	sch_work = false;
	notify_charger = false;
	notify_charger = false;
@@ -650,22 +664,28 @@ static const char *chg_to_string(enum power_supply_type chg_type)
static void rockchip_chg_enable_dcd(struct rockchip_usb2phy *rphy,
static void rockchip_chg_enable_dcd(struct rockchip_usb2phy *rphy,
				    bool en)
				    bool en)
{
{
	property_enable(rphy, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en);
	struct regmap *base = get_reg_base(rphy);
	property_enable(rphy, &rphy->phy_cfg->chg_det.idp_src_en, en);

	property_enable(base, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en);
	property_enable(base, &rphy->phy_cfg->chg_det.idp_src_en, en);
}
}


static void rockchip_chg_enable_primary_det(struct rockchip_usb2phy *rphy,
static void rockchip_chg_enable_primary_det(struct rockchip_usb2phy *rphy,
					    bool en)
					    bool en)
{
{
	property_enable(rphy, &rphy->phy_cfg->chg_det.vdp_src_en, en);
	struct regmap *base = get_reg_base(rphy);
	property_enable(rphy, &rphy->phy_cfg->chg_det.idm_sink_en, en);

	property_enable(base, &rphy->phy_cfg->chg_det.vdp_src_en, en);
	property_enable(base, &rphy->phy_cfg->chg_det.idm_sink_en, en);
}
}


static void rockchip_chg_enable_secondary_det(struct rockchip_usb2phy *rphy,
static void rockchip_chg_enable_secondary_det(struct rockchip_usb2phy *rphy,
					      bool en)
					      bool en)
{
{
	property_enable(rphy, &rphy->phy_cfg->chg_det.vdm_src_en, en);
	struct regmap *base = get_reg_base(rphy);
	property_enable(rphy, &rphy->phy_cfg->chg_det.idp_sink_en, en);

	property_enable(base, &rphy->phy_cfg->chg_det.vdm_src_en, en);
	property_enable(base, &rphy->phy_cfg->chg_det.idp_sink_en, en);
}
}


#define CHG_DCD_POLL_TIME	(100 * HZ / 1000)
#define CHG_DCD_POLL_TIME	(100 * HZ / 1000)
@@ -677,6 +697,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)
	struct rockchip_usb2phy_port *rport =
	struct rockchip_usb2phy_port *rport =
		container_of(work, struct rockchip_usb2phy_port, chg_work.work);
		container_of(work, struct rockchip_usb2phy_port, chg_work.work);
	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
	struct regmap *base = get_reg_base(rphy);
	bool is_dcd, tmout, vout;
	bool is_dcd, tmout, vout;
	unsigned long delay;
	unsigned long delay;


@@ -687,7 +708,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)
		if (!rport->suspended)
		if (!rport->suspended)
			rockchip_usb2phy_power_off(rport->phy);
			rockchip_usb2phy_power_off(rport->phy);
		/* put the controller in non-driving mode */
		/* put the controller in non-driving mode */
		property_enable(rphy, &rphy->phy_cfg->chg_det.opmode, false);
		property_enable(base, &rphy->phy_cfg->chg_det.opmode, false);
		/* Start DCD processing stage 1 */
		/* Start DCD processing stage 1 */
		rockchip_chg_enable_dcd(rphy, true);
		rockchip_chg_enable_dcd(rphy, true);
		rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
		rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
@@ -696,7 +717,8 @@ static void rockchip_chg_detect_work(struct work_struct *work)
		break;
		break;
	case USB_CHG_STATE_WAIT_FOR_DCD:
	case USB_CHG_STATE_WAIT_FOR_DCD:
		/* get data contact detection status */
		/* get data contact detection status */
		is_dcd = property_enabled(rphy, &rphy->phy_cfg->chg_det.dp_det);
		is_dcd = property_enabled(rphy->grf,
					  &rphy->phy_cfg->chg_det.dp_det);
		tmout = ++rphy->dcd_retries == CHG_DCD_MAX_RETRIES;
		tmout = ++rphy->dcd_retries == CHG_DCD_MAX_RETRIES;
		/* stage 2 */
		/* stage 2 */
		if (is_dcd || tmout) {
		if (is_dcd || tmout) {
@@ -713,7 +735,8 @@ static void rockchip_chg_detect_work(struct work_struct *work)
		}
		}
		break;
		break;
	case USB_CHG_STATE_DCD_DONE:
	case USB_CHG_STATE_DCD_DONE:
		vout = property_enabled(rphy, &rphy->phy_cfg->chg_det.cp_det);
		vout = property_enabled(rphy->grf,
					&rphy->phy_cfg->chg_det.cp_det);
		rockchip_chg_enable_primary_det(rphy, false);
		rockchip_chg_enable_primary_det(rphy, false);
		if (vout) {
		if (vout) {
			/* Voltage Source on DM, Probe on DP  */
			/* Voltage Source on DM, Probe on DP  */
@@ -734,7 +757,8 @@ static void rockchip_chg_detect_work(struct work_struct *work)
		}
		}
		break;
		break;
	case USB_CHG_STATE_PRIMARY_DONE:
	case USB_CHG_STATE_PRIMARY_DONE:
		vout = property_enabled(rphy, &rphy->phy_cfg->chg_det.dcp_det);
		vout = property_enabled(rphy->grf,
					&rphy->phy_cfg->chg_det.dcp_det);
		/* Turn off voltage source */
		/* Turn off voltage source */
		rockchip_chg_enable_secondary_det(rphy, false);
		rockchip_chg_enable_secondary_det(rphy, false);
		if (vout)
		if (vout)
@@ -748,7 +772,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)
		/* fall through */
		/* fall through */
	case USB_CHG_STATE_DETECTED:
	case USB_CHG_STATE_DETECTED:
		/* put the controller in normal mode */
		/* put the controller in normal mode */
		property_enable(rphy, &rphy->phy_cfg->chg_det.opmode, true);
		property_enable(base, &rphy->phy_cfg->chg_det.opmode, true);
		rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
		rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
		dev_info(&rport->phy->dev, "charger = %s\n",
		dev_info(&rport->phy->dev, "charger = %s\n",
			 chg_to_string(rphy->chg_type));
			 chg_to_string(rphy->chg_type));
@@ -790,8 +814,7 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work)
	if (ret < 0)
	if (ret < 0)
		goto next_schedule;
		goto next_schedule;


	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset,
	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, &uhd);
			  &uhd);
	if (ret < 0)
	if (ret < 0)
		goto next_schedule;
		goto next_schedule;


@@ -845,8 +868,8 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work)
		 * activate the linestate detection to get the next device
		 * activate the linestate detection to get the next device
		 * plug-in irq.
		 * plug-in irq.
		 */
		 */
		property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
		property_enable(rphy->grf, &rport->port_cfg->ls_det_clr, true);
		property_enable(rphy, &rport->port_cfg->ls_det_en, true);
		property_enable(rphy->grf, &rport->port_cfg->ls_det_en, true);


		/*
		/*
		 * we don't need to rearm the delayed work when the phy port
		 * we don't need to rearm the delayed work when the phy port
@@ -869,14 +892,14 @@ static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data)
	struct rockchip_usb2phy_port *rport = data;
	struct rockchip_usb2phy_port *rport = data;
	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);


	if (!property_enabled(rphy, &rport->port_cfg->ls_det_st))
	if (!property_enabled(rphy->grf, &rport->port_cfg->ls_det_st))
		return IRQ_NONE;
		return IRQ_NONE;


	mutex_lock(&rport->mutex);
	mutex_lock(&rport->mutex);


	/* disable linestate detect irq and clear its status */
	/* disable linestate detect irq and clear its status */
	property_enable(rphy, &rport->port_cfg->ls_det_en, false);
	property_enable(rphy->grf, &rport->port_cfg->ls_det_en, false);
	property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
	property_enable(rphy->grf, &rport->port_cfg->ls_det_clr, true);


	mutex_unlock(&rport->mutex);
	mutex_unlock(&rport->mutex);


@@ -896,13 +919,13 @@ static irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data)
	struct rockchip_usb2phy_port *rport = data;
	struct rockchip_usb2phy_port *rport = data;
	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);


	if (!property_enabled(rphy, &rport->port_cfg->bvalid_det_st))
	if (!property_enabled(rphy->grf, &rport->port_cfg->bvalid_det_st))
		return IRQ_NONE;
		return IRQ_NONE;


	mutex_lock(&rport->mutex);
	mutex_lock(&rport->mutex);


	/* clear bvalid detect irq pending status */
	/* clear bvalid detect irq pending status */
	property_enable(rphy, &rport->port_cfg->bvalid_det_clr, true);
	property_enable(rphy->grf, &rport->port_cfg->bvalid_det_clr, true);


	mutex_unlock(&rport->mutex);
	mutex_unlock(&rport->mutex);


@@ -1045,6 +1068,16 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
	if (IS_ERR(rphy->grf))
	if (IS_ERR(rphy->grf))
		return PTR_ERR(rphy->grf);
		return PTR_ERR(rphy->grf);


	if (of_device_is_compatible(np, "rockchip,rv1108-usb2phy")) {
		rphy->usbgrf =
			syscon_regmap_lookup_by_phandle(dev->of_node,
							"rockchip,usbgrf");
		if (IS_ERR(rphy->usbgrf))
			return PTR_ERR(rphy->usbgrf);
	} else {
		rphy->usbgrf = NULL;
	}

	if (of_property_read_u32(np, "reg", &reg)) {
	if (of_property_read_u32(np, "reg", &reg)) {
		dev_err(dev, "the reg property is not assigned in %s node\n",
		dev_err(dev, "the reg property is not assigned in %s node\n",
			np->name);
			np->name);