From ec42359f2660cfd0afa81c4e38b9e3695a1828a0 Mon Sep 17 00:00:00 2001 From: William Wu Date: Fri, 7 Apr 2017 18:36:22 +0800 Subject: [PATCH] usb: dwc_otg_310: fix usb vbus power controlled by pmic On rockchip platforms, usb vbus 5V can be controlled by gpio or pmic while otg work as host mode. If vbus 5v is supplied from pmic, and usb charger circuit also connect to pmic, we need to ensure usb vbus is disconnected from external power source (e.g. PC or USB adapter) before power on vbus 5v from pmic, otherwise, the pmic may be broken by the external power. It always happens with rk816 which support usb charge and usb vbus power function. With this patch, if we use pmic for usb vbus 5v, it needs to add a new property 'rockchip,usb-pmic-vbus' in dts usb node, like this: &usb0 { rockchip,usb-pmic-vbus; }; Change-Id: I1055f637e77fb5dd681994ff440293a6682b2a12 Signed-off-by: William Wu --- .../devicetree/bindings/usb/rockchip-usb.txt | 4 ++++ drivers/usb/dwc_otg_310/dwc_otg_cil.h | 3 +++ drivers/usb/dwc_otg_310/dwc_otg_driver.c | 14 +++++++++++++- drivers/usb/dwc_otg_310/usbdev_rk3036.c | 6 ++++-- drivers/usb/dwc_otg_310/usbdev_rk3126.c | 6 ++++-- drivers/usb/dwc_otg_310/usbdev_rk32.c | 6 ++++-- drivers/usb/dwc_otg_310/usbdev_rk3368.c | 6 ++++-- 7 files changed, 36 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/rockchip-usb.txt b/Documentation/devicetree/bindings/usb/rockchip-usb.txt index 5d21bd827760..c6c25aaa18ea 100644 --- a/Documentation/devicetree/bindings/usb/rockchip-usb.txt +++ b/Documentation/devicetree/bindings/usb/rockchip-usb.txt @@ -18,6 +18,10 @@ Required properties: "1" represents that force otg to host only mode, "2" represents that force otg to device only mode. +Optional properties: + - rockchip,usb-pmic-vbus: If present, OTG VBUS 5V is supplied + from PMIC. + Example: - RK3288 diff --git a/drivers/usb/dwc_otg_310/dwc_otg_cil.h b/drivers/usb/dwc_otg_310/dwc_otg_cil.h index f0170d2a5230..96eb24b03993 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_cil.h +++ b/drivers/usb/dwc_otg_310/dwc_otg_cil.h @@ -849,6 +849,9 @@ struct dwc_otg_core_if { #define USB_MODE_FORCE_HOST (1) #define USB_MODE_FORCE_DEVICE (2) + /* Indicate USB get VBUS 5V from PMIC(e.g. rk81x) */ + bool pmic_vbus; + #ifdef DWC_DEV_SRPCAP /* This timer is needed to power on the hibernated host core if SRP is not * initiated on connected SRP capable device for limited period of time diff --git a/drivers/usb/dwc_otg_310/dwc_otg_driver.c b/drivers/usb/dwc_otg_310/dwc_otg_driver.c index 9905a393d6d6..4463f1bb35d2 100644 --- a/drivers/usb/dwc_otg_310/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_driver.c @@ -352,13 +352,21 @@ extern void dwc_otg_hub_disconnect_device(struct usb_hub *hub); void dwc_otg_force_host(dwc_otg_core_if_t *core_if) { dwc_otg_device_t *otg_dev = core_if->otg_dev; + struct dwc_otg_platform_data *pdata = otg_dev->pldata; dctl_data_t dctl = {.d32 = 0 }; unsigned long flags; if (core_if->op_state == A_HOST) { - printk("dwc_otg_force_host,already in A_HOST mode,everest\n"); + dev_info(pdata->dev, + "dwc_otg_force_host,already in A_HOST mode,everest\n"); + return; + } else if (pdata->get_status(USB_STATUS_BVABLID) && + core_if->pmic_vbus) { + dev_info(pdata->dev, + "Please disconnect the USB cable first, and try again!\n"); return; } + core_if->op_state = A_HOST; cancel_delayed_work(&otg_dev->pcd->check_vbus_work); @@ -1504,6 +1512,10 @@ static int otg20_driver_probe(struct platform_device *_dev) of_property_read_u32(node, "rockchip,usb-mode", &val); dwc_otg_device->core_if->usb_mode = val; + /* Indicate usb vbus get from pmic (e.g. rk81x) */ + dwc_otg_device->core_if->pmic_vbus = of_property_read_bool(node, + "rockchip,usb-pmic-vbus"); + #ifndef DWC_HOST_ONLY /* * Initialize the PCD diff --git a/drivers/usb/dwc_otg_310/usbdev_rk3036.c b/drivers/usb/dwc_otg_310/usbdev_rk3036.c index 5e49d800de65..e5996181a083 100755 --- a/drivers/usb/dwc_otg_310/usbdev_rk3036.c +++ b/drivers/usb/dwc_otg_310/usbdev_rk3036.c @@ -182,15 +182,17 @@ static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode) static void usb20otg_power_enable(int enable) { if (0 == enable) { - rk_battery_charger_detect_cb(USB_OTG_POWER_OFF); /* disable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 0); + else if (usb20otg_get_status(USB_STATUS_BVABLID)) + rk_battery_charger_detect_cb(USB_OTG_POWER_OFF); } else if (1 == enable) { - rk_battery_charger_detect_cb(USB_OTG_POWER_ON); /* enable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 1); + else if (!usb20otg_get_status(USB_STATUS_BVABLID)) + rk_battery_charger_detect_cb(USB_OTG_POWER_ON); } } static void usb20otg_phy_power_down(int power_down) diff --git a/drivers/usb/dwc_otg_310/usbdev_rk3126.c b/drivers/usb/dwc_otg_310/usbdev_rk3126.c index ad005cbee570..bd3991183b72 100755 --- a/drivers/usb/dwc_otg_310/usbdev_rk3126.c +++ b/drivers/usb/dwc_otg_310/usbdev_rk3126.c @@ -191,15 +191,17 @@ static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode) static void usb20otg_power_enable(int enable) { if (0 == enable) { - rk_battery_charger_detect_cb(USB_OTG_POWER_OFF); /* disable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 0); + else if (usb20otg_get_status(USB_STATUS_BVABLID)) + rk_battery_charger_detect_cb(USB_OTG_POWER_OFF); } else if (1 == enable) { - rk_battery_charger_detect_cb(USB_OTG_POWER_ON); /* enable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 1); + else if (!usb20otg_get_status(USB_STATUS_BVABLID)) + rk_battery_charger_detect_cb(USB_OTG_POWER_ON); } } static void usb20otg_phy_power_down(int power_down) diff --git a/drivers/usb/dwc_otg_310/usbdev_rk32.c b/drivers/usb/dwc_otg_310/usbdev_rk32.c index 70b4c86ec46f..53e14def84d4 100644 --- a/drivers/usb/dwc_otg_310/usbdev_rk32.c +++ b/drivers/usb/dwc_otg_310/usbdev_rk32.c @@ -180,15 +180,17 @@ static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode) static void usb20otg_power_enable(int enable) { if (0 == enable) { - rk_battery_charger_detect_cb(USB_OTG_POWER_OFF); /* disable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 0); + else if (usb20otg_get_status(USB_STATUS_BVABLID)) + rk_battery_charger_detect_cb(USB_OTG_POWER_OFF); } else if (1 == enable) { - rk_battery_charger_detect_cb(USB_OTG_POWER_ON); /* enable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 1); + else if (!usb20otg_get_status(USB_STATUS_BVABLID)) + rk_battery_charger_detect_cb(USB_OTG_POWER_ON); } } diff --git a/drivers/usb/dwc_otg_310/usbdev_rk3368.c b/drivers/usb/dwc_otg_310/usbdev_rk3368.c index 6e0cde4c7404..833671c1e1e5 100644 --- a/drivers/usb/dwc_otg_310/usbdev_rk3368.c +++ b/drivers/usb/dwc_otg_310/usbdev_rk3368.c @@ -186,15 +186,17 @@ static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode) static void usb20otg_power_enable(int enable) { if (0 == enable) { - rk_battery_charger_detect_cb(USB_OTG_POWER_OFF); /* disable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 0); + else if (usb20otg_get_status(USB_STATUS_BVABLID)) + rk_battery_charger_detect_cb(USB_OTG_POWER_OFF); } else if (1 == enable) { - rk_battery_charger_detect_cb(USB_OTG_POWER_ON); /* enable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 1); + else if (!usb20otg_get_status(USB_STATUS_BVABLID)) + rk_battery_charger_detect_cb(USB_OTG_POWER_ON); } } -- 2.34.1