diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts index d02d053..ed2e44d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts @@ -93,7 +93,7 @@ pinctrl-names = "default"; pinctrl-0 = <&vcc5v0_typec_en>; regulator-name = "vcc5v0_typec"; - regulator-always-on; + // regulator-always-on; vin-supply = <&vcc5v0_sys>; }; @@ -631,6 +631,7 @@ status = "okay"; u2phy0_otg: otg-port { + vbus-supply = <&vcc5v0_typec>; status = "okay"; }; @@ -696,6 +697,7 @@ &usbdrd_dwc3_0 { status = "okay"; + extcon = <&u2phy0>; dr_mode = "otg"; }; diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index eae865f..20d79232 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -69,6 +69,7 @@ enum usb_chg_state { 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, @@ -129,13 +130,29 @@ struct rockchip_usb2phy_port_cfg { struct usb2phy_reg bvalid_det_en; struct usb2phy_reg bvalid_det_st; struct usb2phy_reg bvalid_det_clr; + struct usb2phy_reg bypass_dm_en; + struct usb2phy_reg bypass_sel; + struct usb2phy_reg bypass_iomux; + struct usb2phy_reg bypass_bc; + struct usb2phy_reg bypass_otg; + struct usb2phy_reg bypass_host; struct usb2phy_reg ls_det_en; struct usb2phy_reg ls_det_st; struct usb2phy_reg ls_det_clr; + struct usb2phy_reg iddig_output; + struct usb2phy_reg iddig_en; + 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 usb2phy_reg vbus_det_en; }; @@ -178,13 +195,16 @@ struct rockchip_usb2phy_port { unsigned int port_id; bool suspended; bool vbus_attached; + bool vbus_enabled; int bvalid_irq; int ls_irq; int otg_mux_irq; + int id_irq; struct mutex mutex; struct delayed_work chg_work; struct delayed_work otg_sm_work; struct delayed_work sm_work; + struct regulator *vbus; const struct rockchip_usb2phy_port_cfg *port_cfg; struct notifier_block event_nb; enum usb_otg_state state; @@ -214,6 +234,7 @@ struct rockchip_usb2phy { struct clk *clk; struct clk *clk480m; struct clk_hw clk480m_hw; + bool edev_self; enum usb_chg_state chg_state; enum power_supply_type chg_type; u8 dcd_retries; @@ -393,6 +414,8 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy) dev_err(rphy->dev, "failed to register extcon device\n"); return ret; } + + rphy->edev_self = true; } rphy->edev = edev; @@ -400,6 +423,28 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy) return 0; } +static int rockchip_set_vbus_power(struct rockchip_usb2phy_port *rport,bool en) +{ + int ret = 0; + + if (!rport->vbus) + return 0; + + if (en && !rport->vbus_enabled) { + ret = regulator_enable(rport->vbus); + if (ret) + dev_err(&rport->phy->dev, + "Failed to enable VBUS supply\n"); + } else if (!en && rport->vbus_enabled) { + ret = regulator_disable(rport->vbus); + } + + if (ret == 0) + rport->vbus_enabled = en; + + return ret; +} + static int rockchip_usb2phy_init(struct phy *phy) { struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); @@ -407,10 +452,11 @@ static int rockchip_usb2phy_init(struct phy *phy) int ret = 0; mutex_lock(&rport->mutex); - +printk("busb rport->port_id=%d\n",rport->port_id ); if (rport->port_id == USB2PHY_PORT_OTG) { if (rport->mode != USB_DR_MODE_HOST && rport->mode != USB_DR_MODE_UNKNOWN) { + printk("busb enabled irq\n"); /* clear bvalid status and enable bvalid detect irq */ ret = property_enable(rphy->grf, &rport->port_cfg->bvalid_det_clr, @@ -423,9 +469,34 @@ static int rockchip_usb2phy_init(struct phy *phy) true); if (ret) goto out; + + /* clear id status and enable id detect irq */ + ret = property_enable(rphy->grf, + &rport->port_cfg->idfall_det_clr, + true); + if (ret) + goto out; + + ret = property_enable(rphy->grf, + &rport->port_cfg->idfall_det_en, + true); + if (ret) + goto out; + + ret = property_enable(rphy->grf, + &rport->port_cfg->idrise_det_clr, + true); + if (ret) + goto out; + + ret = property_enable(rphy->grf, + &rport->port_cfg->idrise_det_en, + true); + if (ret) + goto out; schedule_delayed_work(&rport->otg_sm_work, OTG_SCHEDULE_DELAY * 3); } else { /* If OTG works in host only mode, do nothing. */ dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode); @@ -458,7 +529,7 @@ static int rockchip_usb2phy_power_on(struct phy *phy) int ret; dev_dbg(&rport->phy->dev, "port power on\n"); - +printk("busb port power on\n"); if (!rport->suspended) return 0; @@ -502,7 +573,7 @@ static int rockchip_usb2phy_power_off(struct phy *phy) static int rockchip_usb2phy_exit(struct phy *phy) { struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); - +printk("busb rockchip_usb2phy_exit \n"); if (rport->port_id == USB2PHY_PORT_OTG && rport->mode != USB_DR_MODE_HOST && rport->mode != USB_DR_MODE_UNKNOWN) { @@ -514,11 +585,61 @@ static int rockchip_usb2phy_exit(struct phy *phy) return 0; } +static int rockchip_usb2phy_set_mode(struct phy *phy, enum phy_mode mode , int submode) +{ + struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); + struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); + bool vbus_det_en; + int ret = 0; + if (rport->port_id != USB2PHY_PORT_OTG) + return ret; + +printk("busb rockchip_usb2phy_set_mode mode = %d,submode=%d\n",mode,submode); + switch (mode) { + case PHY_MODE_USB_OTG: + /* + * In case of using vbus to detect connect state by u2phy, + * enable vbus detect on otg mode. + * + * fallthrough + */ + case PHY_MODE_USB_DEVICE: + /* Disable VBUS supply */ + rockchip_set_vbus_power(rport, false); + extcon_set_state_sync(rphy->edev, EXTCON_USB_VBUS_EN, false); + vbus_det_en = true; + break; + case PHY_MODE_USB_HOST: + /* Enable VBUS supply */ + ret = rockchip_set_vbus_power(rport, true); + if (ret) { + dev_err(&rport->phy->dev, + "Failed to set host mode\n"); + return ret; + } + + extcon_set_state_sync(rphy->edev, EXTCON_USB_VBUS_EN, true); + /* fallthrough */ + case PHY_MODE_INVALID: + vbus_det_en = false; + break; + default: + dev_info(&rport->phy->dev, "illegal mode\n"); + printk("busb illegal mode\n"); + return ret; + } + + ret = property_enable(rphy->grf, &rport->port_cfg->vbus_det_en, vbus_det_en); + + return ret; +} + static const struct phy_ops rockchip_usb2phy_ops = { .init = rockchip_usb2phy_init, .exit = rockchip_usb2phy_exit, .power_on = rockchip_usb2phy_power_on, .power_off = rockchip_usb2phy_power_off, +// .set_mode = rockchip_usb2phy_set_mode, .owner = THIS_MODULE, }; @@ -540,7 +661,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) delay = OTG_SCHEDULE_DELAY; dev_dbg(&rport->phy->dev, "%s otg sm work\n", usb_otg_state_string(rport->state)); - + printk("busb rockchip_usb2phy_otg_sm_work %s otg sm work %d\n",usb_otg_state_string(rport->state),rport->state); switch (rport->state) { case OTG_STATE_UNDEFINED: rport->state = OTG_STATE_B_IDLE; @@ -548,13 +669,16 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) rockchip_usb2phy_power_off(rport->phy); /* fall through */ case OTG_STATE_B_IDLE: + printk("busb HOST = %d,VBUS_EN=%d,vbus_attached=%d\n",extcon_get_state(rphy->edev, EXTCON_USB_HOST),extcon_get_state(rphy->edev,EXTCON_USB_VBUS_EN),rport->vbus_attached); if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) { dev_dbg(&rport->phy->dev, "usb otg host connect\n"); + printk("busb usb otg host connect\n"); rport->state = OTG_STATE_A_HOST; rockchip_usb2phy_power_on(rport->phy); return; } else if (vbus_attach) { dev_dbg(&rport->phy->dev, "vbus_attach\n"); + printk("busb vbus_attach rphy->chg_state = %d\n",rphy->chg_state); switch (rphy->chg_state) { case USB_CHG_STATE_UNDEFINED: schedule_delayed_work(&rport->chg_work, 0); @@ -689,7 +813,7 @@ static void rockchip_chg_detect_work(struct work_struct *work) struct regmap *base = get_reg_base(rphy); bool is_dcd, tmout, vout; unsigned long delay; - +printk("busb chg detection work state = %d\n",rphy->chg_state); dev_dbg(&rport->phy->dev, "chg detection work state = %d\n", rphy->chg_state); switch (rphy->chg_state) { @@ -923,6 +1047,42 @@ static irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data) 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); + bool cable_vbus_state = false; +printk("brian rockchip_usb2phy_id_irq \n"); + if (!property_enabled(rphy->grf, &rport->port_cfg->idfall_det_st) && + !property_enabled(rphy->grf, &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->grf, &rport->port_cfg->idfall_det_st)) { + property_enable(rphy->grf, &rport->port_cfg->idfall_det_clr, + true); + cable_vbus_state = true; + } else if (property_enabled(rphy->grf, &rport->port_cfg->idrise_det_st)) { + property_enable(rphy->grf, &rport->port_cfg->idrise_det_clr, + true); + cable_vbus_state = false; + } + + extcon_set_state(rphy->edev, EXTCON_USB_HOST, cable_vbus_state); + extcon_set_state(rphy->edev, EXTCON_USB_VBUS_EN, cable_vbus_state); + + extcon_sync(rphy->edev, EXTCON_USB_HOST); + extcon_sync(rphy->edev, EXTCON_USB_VBUS_EN); + + rockchip_set_vbus_power(rport, cable_vbus_state); + + mutex_unlock(&rport->mutex); + + return IRQ_HANDLED; +} + static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data) { struct rockchip_usb2phy_port *rport = data; @@ -980,7 +1140,8 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, struct rockchip_usb2phy_port *rport, struct device_node *child_np) { - int ret; + int ret = 0; + int iddig; rport->port_id = USB2PHY_PORT_OTG; rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG]; @@ -994,13 +1155,34 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, */ rport->suspended = true; rport->vbus_attached = false; + rport->vbus_enabled = false; + rport->vbus = devm_regulator_get_optional(&rport->phy->dev, "vbus"); + if (IS_ERR(rport->vbus)) { + ret = PTR_ERR(rport->vbus); + if (ret == -EPROBE_DEFER) + return ret; + printk("busb Failed to get VBUS supply regulator\n"); + dev_warn(&rport->phy->dev, "Failed to get VBUS supply regulator\n"); + rport->vbus = NULL; + } + if(rport->vbus != NULL) + printk("busb get rport->vbus ok\n"); mutex_init(&rport->mutex); rport->mode = of_usb_get_dr_mode_by_phy(child_np, -1); if (rport->mode == USB_DR_MODE_HOST || rport->mode == USB_DR_MODE_UNKNOWN) { - ret = 0; + if(rphy->edev_self) { + 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); + ret = rockchip_set_vbus_power(rport, true); + printk("busb rockchip_set_vbus_power ret=%d\n",ret); + if(ret) + return ret; + } + //ret = 0; goto out; } @@ -1044,6 +1226,37 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, "failed to request otg-bvalid irq handle\n"); goto out; } + + 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"); + ret = rport->id_irq; + goto out; + } + + 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->grf, &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); + + ret = rockchip_set_vbus_power(rport, true); + printk("busb rockchip_set_vbus_power ret=%d\n",ret); + if (ret) + return ret; + } + } } if (!IS_ERR(rphy->edev)) { @@ -1108,6 +1321,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->edev_self = false; platform_set_drvdata(pdev, rphy); ret = rockchip_usb2phy_extcon_register(rphy); @@ -1329,6 +1543,17 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { .bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 }, .bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 }, .bvalid_det_clr = { 0xe3d0, 3, 3, 0, 1 }, + .bypass_dm_en = { 0xe450, 2, 2, 0, 1 }, + .bypass_sel = { 0xe450, 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 }, }, diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 2bdf643..1c8e971 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -37,6 +37,7 @@ /* USB external connector */ #define EXTCON_USB 1 #define EXTCON_USB_HOST 2 +#define EXTCON_USB_VBUS_EN 3 /* * Charging external connector