usb: dwc_otg_310: fix usb vbus power controlled by pmic
authorWilliam Wu <wulf@rock-chips.com>
Fri, 7 Apr 2017 10:36:22 +0000 (18:36 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 11 Apr 2017 07:40:51 +0000 (15:40 +0800)
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 <wulf@rock-chips.com>
Documentation/devicetree/bindings/usb/rockchip-usb.txt
drivers/usb/dwc_otg_310/dwc_otg_cil.h
drivers/usb/dwc_otg_310/dwc_otg_driver.c
drivers/usb/dwc_otg_310/usbdev_rk3036.c
drivers/usb/dwc_otg_310/usbdev_rk3126.c
drivers/usb/dwc_otg_310/usbdev_rk32.c
drivers/usb/dwc_otg_310/usbdev_rk3368.c

index 5d21bd8277604d3891dd324b68afe2398f0e7b28..c6c25aaa18ea176ec0df4dc1ab089e4a43f77d51 100644 (file)
@@ -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
 
index f0170d2a52308ced60d0711d0c8eda2541e2e99e..96eb24b039932bca15643f2004a56d87520dcaf7 100755 (executable)
@@ -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
index 9905a393d6d6e9025401e3b64278ed561b2af19c..4463f1bb35d2e393f92dd24cdcb19d67559b0afb 100644 (file)
@@ -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
index 5e49d800de65bd2ffefbf62b364a45d3f722982c..e5996181a0839cd2003b42c729fc218c43f84fee 100755 (executable)
@@ -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)
index ad005cbee57059b082cefdc1862c26716618ebfa..bd3991183b728ec290a8a39e0883be7ff49aeca0 100755 (executable)
@@ -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)
index 70b4c86ec46f4dbc20e6207bce588eb3f7a01d98..53e14def84d487fc956f7bc03b8f964d1d62f831 100644 (file)
@@ -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);
        }
 }
 
index 6e0cde4c740499b05d0c3b15890fe6299a03a90d..833671c1e1e51f24a1194b35122ab0b9151a97a2 100644 (file)
@@ -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);
        }
 }