Commit ed2b5a8e authored by Peter Geis's avatar Peter Geis Committed by Vinod Koul
Browse files

phy: phy-rockchip-inno-usb2: support muxed interrupts



The rk3568 usb2phy has a single muxed interrupt that handles all
interrupts.
Allow the driver to plug in only a single interrupt as necessary.

Signed-off-by: default avatarPeter Geis <pgwipeout@gmail.com>
Tested-by: default avatarMichael Riesch <michael.riesch@wolfvision.net>
Link: https://lore.kernel.org/r/20211215210252.120923-6-pgwipeout@gmail.com


Signed-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent e6915e1a
Loading
Loading
Loading
Loading
+119 −49
Original line number Diff line number Diff line
@@ -204,6 +204,7 @@ struct rockchip_usb2phy_port {
 * @dcd_retries: The retry count used to track Data contact
 *		 detection process.
 * @edev: extcon device for notification registration
 * @irq: muxed interrupt for single irq configuration
 * @phy_cfg: phy register configuration, assigned by driver data.
 * @ports: phy port instance.
 */
@@ -218,6 +219,7 @@ struct rockchip_usb2phy {
	enum power_supply_type	chg_type;
	u8			dcd_retries;
	struct extcon_dev	*edev;
	int			irq;
	const struct rockchip_usb2phy_cfg	*phy_cfg;
	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];
};
@@ -926,19 +928,40 @@ static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data)
		return IRQ_NONE;
}

static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
static irqreturn_t rockchip_usb2phy_irq(int irq, void *data)
{
	struct rockchip_usb2phy *rphy = data;
	struct rockchip_usb2phy_port *rport;
	irqreturn_t ret = IRQ_NONE;
	unsigned int index;

	for (index = 0; index < rphy->phy_cfg->num_ports; index++) {
		rport = &rphy->ports[index];
		if (!rport->phy)
			continue;

		/* Handle linestate irq for both otg port and host port */
		ret = rockchip_usb2phy_linestate_irq(irq, rport);
	}

	return ret;
}

static int rockchip_usb2phy_port_irq_init(struct rockchip_usb2phy *rphy,
					  struct rockchip_usb2phy_port *rport,
					  struct device_node *child_np)
{
	int ret;

	rport->port_id = USB2PHY_PORT_HOST;
	rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST];
	rport->suspended = true;

	mutex_init(&rport->mutex);
	INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);
	/*
	 * If the usb2 phy used combined irq for otg and host port,
	 * don't need to init otg and host port irq separately.
	 */
	if (rphy->irq > 0)
		return 0;

	switch (rport->port_id) {
	case USB2PHY_PORT_HOST:
		rport->ls_irq = of_irq_get_byname(child_np, "linestate");
		if (rport->ls_irq < 0) {
			dev_err(rphy->dev, "no linestate irq provided\n");
@@ -953,6 +976,72 @@ static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
			dev_err(rphy->dev, "failed to request linestate irq handle\n");
			return ret;
		}
		break;
	case USB2PHY_PORT_OTG:
		/*
		 * Some SoCs use one interrupt with otg-id/otg-bvalid/linestate
		 * interrupts muxed together, so probe the otg-mux interrupt first,
		 * if not found, then look for the regular interrupts one by one.
		 */
		rport->otg_mux_irq = of_irq_get_byname(child_np, "otg-mux");
		if (rport->otg_mux_irq > 0) {
			ret = devm_request_threaded_irq(rphy->dev, rport->otg_mux_irq,
							NULL,
							rockchip_usb2phy_otg_mux_irq,
							IRQF_ONESHOT,
							"rockchip_usb2phy_otg",
							rport);
			if (ret) {
				dev_err(rphy->dev,
					"failed to request otg-mux irq handle\n");
				return ret;
			}
		} else {
			rport->bvalid_irq = of_irq_get_byname(child_np, "otg-bvalid");
			if (rport->bvalid_irq < 0) {
				dev_err(rphy->dev, "no vbus valid irq provided\n");
				ret = rport->bvalid_irq;
				return ret;
			}

			ret = devm_request_threaded_irq(rphy->dev, rport->bvalid_irq,
							NULL,
							rockchip_usb2phy_bvalid_irq,
							IRQF_ONESHOT,
							"rockchip_usb2phy_bvalid",
							rport);
			if (ret) {
				dev_err(rphy->dev,
					"failed to request otg-bvalid irq handle\n");
				return ret;
			}
		}
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
					   struct rockchip_usb2phy_port *rport,
					   struct device_node *child_np)
{
	int ret;

	rport->port_id = USB2PHY_PORT_HOST;
	rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST];
	rport->suspended = true;

	mutex_init(&rport->mutex);
	INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);

	ret = rockchip_usb2phy_port_irq_init(rphy, rport, child_np);
	if (ret) {
		dev_err(rphy->dev, "failed to setup host irq\n");
		return ret;
	}

	return 0;
}
@@ -999,44 +1088,10 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
	INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
	INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work);

	/*
	 * Some SoCs use one interrupt with otg-id/otg-bvalid/linestate
	 * interrupts muxed together, so probe the otg-mux interrupt first,
	 * if not found, then look for the regular interrupts one by one.
	 */
	rport->otg_mux_irq = of_irq_get_byname(child_np, "otg-mux");
	if (rport->otg_mux_irq > 0) {
		ret = devm_request_threaded_irq(rphy->dev, rport->otg_mux_irq,
						NULL,
						rockchip_usb2phy_otg_mux_irq,
						IRQF_ONESHOT,
						"rockchip_usb2phy_otg",
						rport);
	ret = rockchip_usb2phy_port_irq_init(rphy, rport, child_np);
	if (ret) {
			dev_err(rphy->dev,
				"failed to request otg-mux irq handle\n");
			goto out;
		}
	} else {
		rport->bvalid_irq = of_irq_get_byname(child_np, "otg-bvalid");
		if (rport->bvalid_irq < 0) {
			dev_err(rphy->dev, "no vbus valid irq provided\n");
			ret = rport->bvalid_irq;
		dev_err(rphy->dev, "failed to init irq for host port\n");
		goto out;
		}

		ret = devm_request_threaded_irq(rphy->dev, rport->bvalid_irq,
						NULL,
						rockchip_usb2phy_bvalid_irq,
						IRQF_ONESHOT,
						"rockchip_usb2phy_bvalid",
						rport);
		if (ret) {
			dev_err(rphy->dev,
				"failed to request otg-bvalid irq handle\n");
			goto out;
		}
	}

	if (!IS_ERR(rphy->edev)) {
		rport->event_nb.notifier_call = rockchip_otg_event;
@@ -1116,6 +1171,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
	phy_cfgs = match->data;
	rphy->chg_state = USB_CHG_STATE_UNDEFINED;
	rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
	rphy->irq = platform_get_irq_optional(pdev, 0);
	platform_set_drvdata(pdev, rphy);

	ret = rockchip_usb2phy_extcon_register(rphy);
@@ -1195,6 +1251,20 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
	}

	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);

	if (rphy->irq > 0) {
		ret = devm_request_threaded_irq(rphy->dev, rphy->irq, NULL,
						rockchip_usb2phy_irq,
						IRQF_ONESHOT,
						"rockchip_usb2phy",
						rphy);
		if (ret) {
			dev_err(rphy->dev,
				"failed to request usb2phy irq handle\n");
			goto put_child;
		}
	}

	return PTR_ERR_OR_ZERO(provider);

put_child: