usb: dwc_otg_310: support vbus controlled by both gpio and pmic
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg_310 / usbdev_rk3368.c
index 8be87337097a66411b377c9855fc0285ccd283a9..3272e4e99c5fcdd604c1c7f9be0d9e40f1cef616 100644 (file)
@@ -1,6 +1,7 @@
+#ifdef CONFIG_ARM64
 #include "usbdev_rk.h"
-#include "usbdev_grf_regs.h"
 #include "dwc_otg_regs.h"
+
 static struct dwc_otg_control_usb *control_usb;
 
 static u32 uoc_read(u32 reg)
@@ -22,6 +23,9 @@ static void usb20otg_hw_init(void)
        /* Turn off differential receiver in suspend mode */
        uoc_write(UOC_HIWORD_UPDATE(0, 1, 2), 0x798);
 
+       /* Set disconnect detection trigger point to 625mv */
+       uoc_write(UOC_HIWORD_UPDATE(0x9, 0xf, 11), 0x79c);
+
        /* other haredware init,include:
         * DRV_VBUS GPIO init */
        if (gpio_is_valid(control_usb->otg_gpios->gpio))
@@ -31,10 +35,9 @@ static void usb20otg_hw_init(void)
 static void usb20otg_phy_suspend(void *pdata, int suspend)
 {
        struct dwc_otg_platform_data *usbpdata = pdata;
-
        if (suspend) {
                /* enable soft control */
-               uoc_write(UOC_HIWORD_UPDATE(0x55, 0x7f, 0), 0x700);
+               uoc_write(UOC_HIWORD_UPDATE(0x1d5, 0x1ff, 0), 0x700);
                usbpdata->phy_status = 1;
        } else {
                /* exit suspend */
@@ -76,7 +79,16 @@ static void usb20otg_soft_reset(void *pdata, enum rkusb_rst_flag rst_type)
                reset_control_deassert(rst_otg_c);
                reset_control_deassert(rst_otg_h);
                break;
-
+       case RST_CHN_HALT:
+               /* PHY reset */
+               uoc_write(UOC_HIWORD_UPDATE(0x1, 0x3, 0), 0x700);
+               reset_control_assert(rst_otg_p);
+               udelay(15);
+               uoc_write(UOC_HIWORD_UPDATE(0x2, 0x3, 0), 0x700);
+               udelay(1500);
+               reset_control_deassert(rst_otg_p);
+               udelay(2);
+               break;
        default:
                break;
        }
@@ -87,15 +99,15 @@ static void usb20otg_clock_init(void *pdata)
        struct dwc_otg_platform_data *usbpdata = pdata;
        struct clk *ahbclk, *phyclk;
 
-       ahbclk = devm_clk_get(usbpdata->dev, "hclk_otg");
+       ahbclk = devm_clk_get(usbpdata->dev, "otg");
        if (IS_ERR(ahbclk)) {
-               dev_err(usbpdata->dev, "Failed to get hclk_usb0\n");
+               dev_err(usbpdata->dev, "Failed to get otg clk\n");
                return;
        }
 
-       phyclk = devm_clk_get(usbpdata->dev, "clk_usbphy0");
+       phyclk = devm_clk_get(usbpdata->dev, "sclk_otgphy0");
        if (IS_ERR(phyclk)) {
-               dev_err(usbpdata->dev, "Failed to get clk_usbphy0\n");
+               dev_err(usbpdata->dev, "Failed to get sclk_otgphy0\n");
                return;
        }
 
@@ -119,7 +131,7 @@ static void usb20otg_clock_enable(void *pdata, int enable)
 static int usb20otg_get_status(int id)
 {
        int ret = -1;
-       u32 soc_status15 = uoc_read(0x4bc);
+       u32 soc_status15 = uoc_read(control_usb->grf_otg_st_offset);
 
        switch (id) {
        case USB_STATUS_BVABLID:
@@ -177,10 +189,15 @@ static void usb20otg_power_enable(int enable)
                /* disable otg_drv power */
                if (gpio_is_valid(control_usb->otg_gpios->gpio))
                        gpio_set_value(control_usb->otg_gpios->gpio, 0);
+
+               rk_battery_charger_detect_cb(USB_OTG_POWER_OFF);
        } else if (1 == enable) {
                /* enable otg_drv power */
                if (gpio_is_valid(control_usb->otg_gpios->gpio))
                        gpio_set_value(control_usb->otg_gpios->gpio, 1);
+
+               if (!usb20otg_get_status(USB_STATUS_BVABLID))
+                       rk_battery_charger_detect_cb(USB_OTG_POWER_ON);
        }
 }
 
@@ -197,7 +214,7 @@ struct dwc_otg_platform_data usb20otg_pdata_rk3368 = {
        .get_status = usb20otg_get_status,
        .power_enable = usb20otg_power_enable,
        .dwc_otg_uart_mode = dwc_otg_uart_mode,
-       /* .bc_detect_cb = rk_battery_charger_detect_cb, */
+       .bc_detect_cb = rk_battery_charger_detect_cb,
 };
 #endif
 
@@ -206,8 +223,8 @@ static void usb20ehci_hw_init(void)
 {
        /* Turn off differential receiver in suspend mode */
        uoc_write(UOC_HIWORD_UPDATE(0, 1, 2), 0x7b8);
-       /* Set disconnect detection trigger point to 600mv */
-       uoc_write(UOC_HIWORD_UPDATE(1, 0xf, 11), 0x7bc);
+       /* Set disconnect detection trigger point to 625mv */
+       uoc_write(UOC_HIWORD_UPDATE(0x9, 0xf, 11), 0x7bc);
 
        /* other haredware init,include:
         * DRV_VBUS GPIO init */
@@ -321,14 +338,14 @@ static inline void do_wakeup(struct work_struct *work)
 
 static void usb_battery_charger_detect_work(struct work_struct *work)
 {
-       /* rk_battery_charger_detect_cb(usb_battery_charger_detect(1)); */
+       rk_battery_charger_detect_cb(usb_battery_charger_detect(1));
 }
 
 /********** handler for bvalid irq **********/
 static irqreturn_t bvalid_irq_handler(int irq, void *dev_id)
 {
        /* clear irq */
-       uoc_write(UOC_HIWORD_UPDATE(0x1, 0x1, 3), 0x690);
+       uoc_write(UOC_HIWORD_UPDATE(0x1, 0x1, 3), 0x6a0);
 #ifdef CONFIG_RK_USB_UART
        /* usb otg dp/dm switch to usb phy */
        dwc_otg_uart_mode(NULL, PHY_USB_MODE);
@@ -355,7 +372,7 @@ static int otg_irq_detect_init(struct platform_device *pdev)
        wake_lock_init(&control_usb->usb_wakelock, WAKE_LOCK_SUSPEND,
                       "usb_detect");
        INIT_DELAYED_WORK(&control_usb->usb_det_wakeup_work, do_wakeup);
-#if 0
+
        /*register otg_bvalid irq */
        irq = platform_get_irq_byname(pdev, "otg_bvalid");
        if ((irq > 0) && control_usb->usb_irq_wakeup) {
@@ -368,7 +385,7 @@ static int otg_irq_detect_init(struct platform_device *pdev)
                        uoc_write(UOC_HIWORD_UPDATE(0x1, 0x1, 3), 0x680);
                }
        }
-#endif
+
        return 0;
 }
 
@@ -388,6 +405,7 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
        struct clk *hclk_usb_peri;
        struct regmap *grf;
        int gpio, ret = 0;
+       u32 offset;
 
        control_usb = devm_kzalloc(dev, sizeof(*control_usb), GFP_KERNEL);
        if (!control_usb) {
@@ -403,6 +421,14 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
        }
        control_usb->grf = grf;
 
+       /* get the reg offset of GRF_SOC_STATUS for USB2.0 OTG */
+       if (of_property_read_u32(np, "grf-offset", &offset)) {
+               dev_err(&pdev->dev, "missing reg property in node %s\n",
+                       np->name);
+               return -EINVAL;
+       }
+       control_usb->grf_otg_st_offset = offset;
+
        /* Init Vbus-drv GPIOs */
        control_usb->host_gpios =
            devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
@@ -452,8 +478,8 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
        /* Init hclk_usb_peri */
        hclk_usb_peri = devm_clk_get(&pdev->dev, "hclk_usb_peri");
        if (IS_ERR(hclk_usb_peri)) {
-               dev_err(&pdev->dev, "Failed to get hclk_usb_peri\n");
-               return PTR_ERR(hclk_usb_peri);
+               dev_info(&pdev->dev, "no hclk_usb_peri clk specified\n");
+               hclk_usb_peri = NULL;
        }
        control_usb->hclk_usb_peri = hclk_usb_peri;
        clk_prepare_enable(hclk_usb_peri);
@@ -514,3 +540,4 @@ MODULE_ALIAS("platform: dwc_control_usb");
 MODULE_AUTHOR("RockChip Inc.");
 MODULE_DESCRIPTION("RockChip Control Module USB Driver");
 MODULE_LICENSE("GPL v2");
+#endif