diff options
Diffstat (limited to 'drivers/phy/rockchip/phy-rockchip-inno-usb2.c')
-rw-r--r-- | drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 260 |
1 files changed, 205 insertions, 55 deletions
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 1938365abbb3..eca77e44a4c1 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -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]; }; @@ -750,7 +752,6 @@ static void rockchip_chg_detect_work(struct work_struct *work) fallthrough; case USB_CHG_STATE_SECONDARY_DONE: rphy->chg_state = USB_CHG_STATE_DETECTED; - delay = 0; fallthrough; case USB_CHG_STATE_DETECTED: /* put the controller in normal mode */ @@ -927,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) @@ -940,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; } @@ -1000,43 +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)) { @@ -1074,12 +1129,19 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) return -EINVAL; } - if (!dev->parent || !dev->parent->of_node) - return -EINVAL; + if (!dev->parent || !dev->parent->of_node) { + rphy->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,usbgrf"); + if (IS_ERR(rphy->grf)) { + dev_err(dev, "failed to locate usbgrf\n"); + return PTR_ERR(rphy->grf); + } + } - rphy->grf = syscon_node_to_regmap(dev->parent->of_node); - if (IS_ERR(rphy->grf)) - return PTR_ERR(rphy->grf); + else { + rphy->grf = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(rphy->grf)) + return PTR_ERR(rphy->grf); + } if (of_device_is_compatible(np, "rockchip,rv1108-usb2phy")) { rphy->usbgrf = @@ -1091,16 +1153,26 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) rphy->usbgrf = NULL; } - if (of_property_read_u32(np, "reg", ®)) { + if (of_property_read_u32_index(np, "reg", 0, ®)) { dev_err(dev, "the reg property is not assigned in %pOFn node\n", np); return -EINVAL; } + /* support address_cells=2 */ + if (reg == 0) { + if (of_property_read_u32_index(np, "reg", 1, ®)) { + dev_err(dev, "the reg property is not assigned in %pOFn node\n", + np); + return -EINVAL; + } + } + rphy->dev = dev; 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); @@ -1180,6 +1252,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: @@ -1418,6 +1504,69 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { { /* sentinel */ } }; +static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { + { + .reg = 0xfe8a0000, + .num_ports = 2, + .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x0000, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x0080, 2, 2, 0, 1 }, + .bvalid_det_st = { 0x0084, 2, 2, 0, 1 }, + .bvalid_det_clr = { 0x0088, 2, 2, 0, 1 }, + .utmi_avalid = { 0x00c0, 10, 10, 0, 1 }, + .utmi_bvalid = { 0x00c0, 9, 9, 0, 1 }, + }, + [USB2PHY_PORT_HOST] = { + /* Select suspend control from controller */ + .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d2 }, + .ls_det_en = { 0x0080, 1, 1, 0, 1 }, + .ls_det_st = { 0x0084, 1, 1, 0, 1 }, + .ls_det_clr = { 0x0088, 1, 1, 0, 1 }, + .utmi_ls = { 0x00c0, 17, 16, 0, 1 }, + .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 } + } + }, + .chg_det = { + .opmode = { 0x0000, 3, 0, 5, 1 }, + .cp_det = { 0x00c0, 24, 24, 0, 1 }, + .dcp_det = { 0x00c0, 23, 23, 0, 1 }, + .dp_det = { 0x00c0, 25, 25, 0, 1 }, + .idm_sink_en = { 0x0008, 8, 8, 0, 1 }, + .idp_sink_en = { 0x0008, 7, 7, 0, 1 }, + .idp_src_en = { 0x0008, 9, 9, 0, 1 }, + .rdm_pdwn_en = { 0x0008, 10, 10, 0, 1 }, + .vdm_src_en = { 0x0008, 12, 12, 0, 1 }, + .vdp_src_en = { 0x0008, 11, 11, 0, 1 }, + }, + }, + { + .reg = 0xfe8b0000, + .num_ports = 2, + .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x0000, 8, 0, 0x1d2, 0x1d1 }, + .ls_det_en = { 0x0080, 0, 0, 0, 1 }, + .ls_det_st = { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, + .utmi_ls = { 0x00c0, 5, 4, 0, 1 }, + .utmi_hstdet = { 0x00c0, 7, 7, 0, 1 } + }, + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d1 }, + .ls_det_en = { 0x0080, 1, 1, 0, 1 }, + .ls_det_st = { 0x0084, 1, 1, 0, 1 }, + .ls_det_clr = { 0x0088, 1, 1, 0, 1 }, + .utmi_ls = { 0x00c0, 17, 16, 0, 1 }, + .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 } + } + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = { { .reg = 0x100, @@ -1467,6 +1616,7 @@ static const struct of_device_id rockchip_usb2phy_dt_match[] = { { .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs }, { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, + { .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs }, { .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs }, {} }; |