phy: phy-rockchip-inno-usb2: support muxed interrupts
authorPeter Geis <pgwipeout@gmail.com>
Wed, 15 Dec 2021 21:02:49 +0000 (16:02 -0500)
committerVinod Koul <vkoul@kernel.org>
Thu, 23 Dec 2021 11:24:48 +0000 (16:54 +0530)
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: Peter Geis <pgwipeout@gmail.com>
Tested-by: Michael Riesch <michael.riesch@wolfvision.net>
Link: https://lore.kernel.org/r/20211215210252.120923-6-pgwipeout@gmail.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/phy/rockchip/phy-rockchip-inno-usb2.c

index 1cdd9ae..17098a6 100644 (file)
@@ -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,6 +928,102 @@ static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data)
                return IRQ_NONE;
 }
 
+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;
+
+       /*
+        * 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");
+                       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;
+               }
+               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)
@@ -939,18 +1037,9 @@ static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
        mutex_init(&rport->mutex);
        INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);
 
-       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);
+       ret = rockchip_usb2phy_port_irq_init(rphy, rport, child_np);
        if (ret) {
-               dev_err(rphy->dev, "failed to request linestate irq handle\n");
+               dev_err(rphy->dev, "failed to setup host irq\n");
                return ret;
        }
 
@@ -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);
-               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;
-                       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;
-               }
-       }
+       ret = rockchip_usb2phy_port_irq_init(rphy, rport, child_np);
+       if (ret) {
+               dev_err(rphy->dev, "failed to init irq for host port\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 @@ next_child:
        }
 
        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: