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 5d21bd8..c6c25aa 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 f0170d2..96eb24b 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 9905a39..4463f1b 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 5e49d80..e599618 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 ad005cb..bd39911 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 70b4c86..53e14de 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 6e0cde4..833671c 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);
        }
 }