usb: support rk3368 OTG device side and EHCI
authorlyz <lyz@rock-chips.com>
Mon, 15 Dec 2014 12:45:51 +0000 (20:45 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 24 Dec 2014 10:50:05 +0000 (18:50 +0800)
arch/arm64/boot/dts/rk3368-tb_8846.dts
arch/arm64/boot/dts/rk3368.dtsi
drivers/usb/dwc_otg_310/Makefile
drivers/usb/dwc_otg_310/dwc_otg_driver.c
drivers/usb/dwc_otg_310/usbdev_rk.h
drivers/usb/dwc_otg_310/usbdev_rk3368.c [new file with mode: 0644]
drivers/usb/host/ehci-rockchip.c
drivers/usb/host/ohci-rockchip.c

index 31c3cdb872e4c8af152df00d1c2676f0b1dd7d3c..05fae8ba4bf15a56c9cfd13743968af23bbe75a9 100644 (file)
                };
        };
 
-       usb_control {
-               compatible = "rockchip,rk3288-usb-control";
-
-               host_drv_gpio = <&gpio0 GPIO_A4 GPIO_ACTIVE_LOW>;
-               otg_drv_gpio = <&gpio0 GPIO_D1 GPIO_ACTIVE_LOW>;
-
-               rockchip,remote_wakeup;
-               rockchip,usb_irq_wakeup;
-       };
-
        io-domains {
                compatible = "rockchip,rk3368-io-voltage-domain";
                rockchip,grf = <&grf>;
        status="disabled";
 };
 
+&dwc_control_usb {
+               host_drv_gpio = <&gpio0 GPIO_A4 GPIO_ACTIVE_LOW>;
+               otg_drv_gpio = <&gpio0 GPIO_D1 GPIO_ACTIVE_LOW>;
+
+               rockchip,remote_wakeup;
+               rockchip,usb_irq_wakeup;
+       };
+
 /include/ "../../../arm/boot/dts/act8846.dtsi"
 &act8846 {
        gpios =<&gpio0 GPIO_A0 GPIO_ACTIVE_LOW>,<&gpio0 GPIO_A3 GPIO_ACTIVE_HIGH>;
index 77dd88ae53478da8243d5337cdd817c46771fcd1..bcb539fe55f519a4456c3d52776c96a51a7ac5fa 100755 (executable)
                clock-names = "clk_crypto", "sclk_crypto", "mclk_crypto";
                status = "okay";
        };
+       dwc_control_usb: dwc-control-usb {
+               compatible = "rockchip,rk3368-dwc-control-usb";
+               rockchip,grf = <&grf>;
+               interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "otg_id", "otg_bvalid",
+                                 "otg_linestate", "host0_linestate";
+               clocks = <&clk_gates20 6>, <&usbphy_480m>;
+               clock-names = "hclk_usb_peri", "usbphy_480m";
+               //resets = <&reset RK3128_RST_USBPOR>;
+               //reset-names = "usbphy_por";
+               usb_bc{
+                       compatible = "inno,phy";
+                       regbase = &dwc_control_usb;
+                       rk_usb,bvalid     = <0x04b 23 1>;
+                       rk_usb,iddig      = <0x04b 26 1>;
+                       rk_usb,vdmsrcen   = <0x718 12 1>;
+                       rk_usb,vdpsrcen   = <0x718 11 1>;
+                       rk_usb,rdmpden    = <0x718 10 1>;
+                       rk_usb,idpsrcen   = <0x718  9 1>;
+                       rk_usb,idmsinken  = <0x718  8 1>;
+                       rk_usb,idpsinken  = <0x718  7 1>;
+                       rk_usb,dpattach   = <0x4b8 31 1>;
+                       rk_usb,cpdet      = <0x4b8 30 1>;
+                       rk_usb,dcpattach  = <0x4b8 29 1>;
+               };
+       };
+
+       usb0: usb@ff580000 {
+               compatible = "rockchip,rk3368_usb20_otg";
+               reg = <0x0 0xff580000 0x0 0x40000>;
+               interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_gates8 1>, <&clk_gates20 1>;
+               clock-names = "clk_usbphy0", "hclk_otg";
+               resets = <&reset RK3368_SRST_USBOTG0_H>, <&reset RK3368_SRST_USBOTGPHY0>,
+                               <&reset RK3368_SRST_USBOTGC0>;
+               reset-names = "otg_ahb", "otg_phy", "otg_controller";
+               /*0 - Normal, 1 - Force Host, 2 - Force Device*/
+               rockchip,usb-mode = <0>;
+       };
+
+       usb_ehci: usb@ff500000 {
+               compatible = "generic-ehci";
+               reg = <0x0 0xff500000 0x0 0x20000>;
+               interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_gates8 1>, <&clk_gates20 3>;
+               clock-names = "clk_usbphy0", "hclk_ehci";
+               //resets = <&reset RK3288_SOFT_RST_USBHOST0_H>, <&reset RK3288_SOFT_RST_USBHOST0PHY>,
+               //              <&reset RK3288_SOFT_RST_USBHOST0C>, <&reset RK3288_SOFT_RST_USB_HOST0>;
+               //reset-names = "ehci_ahb", "ehci_phy", "ehci_controller", "ehci";
+       };
+
+       usb_ohci: usb@ff520000 {
+               compatible = "generic-ohci";
+               reg = <0x0 0xff520000 0x0 0x20000>;
+               interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_gates8 1>, <&clk_gates20 3>;
+               clock-names =  "clk_usbphy0", "hclk_ohci";
+       };
+
+       usb_hsic: usb@ff5c0000 {
+               compatible = "rockchip,rk3288_rk_hsic_host";
+               reg = <0x0 0xff5c0000 0x0 0x40000>;
+               interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+/*
+               clocks = <&hsicphy_480m>, <&clk_gates7 8>,
+                        <&hsicphy_12m>, <&usbphy_480m>,
+                        <&otgphy1_480m>, <&otgphy2_480m>;
+               clock-names = "hsicphy_480m", "hclk_hsic",
+                             "hsicphy_12m", "usbphy_480m",
+                             "hsic_usbphy1", "hsic_usbphy2";
+               resets = <&reset RK3288_SOFT_RST_HSIC>, <&reset RK3288_SOFT_RST_HSIC_AUX>,
+                               <&reset RK3288_SOFT_RST_HSICPHY>;
+               reset-names = "hsic_ahb", "hsic_aux", "hsic_phy";
+*/
+               status = "disabled";
+       };
 
        pinctrl: pinctrl {
                compatible = "rockchip,rk3368-pinctrl";
index b1656829613ba3fcfc481040f780a8cb7a0ad0bf..a7fd8784976bb5f54f184d03748684e113efa673 100755 (executable)
@@ -25,5 +25,5 @@ endif
 dwc_otg-objs   += common_port/dwc_common_linux.o
 
 #objs relative to RK platform
-dwc_otg-objs   += usbdev_rk30.o usbdev_rk32.o usbdev_rk3036.o usbdev_rk3126.o usbdev_bc.o
+dwc_otg-objs   += usbdev_rk30.o usbdev_rk32.o usbdev_rk3036.o usbdev_rk3126.o usbdev_rk3368.o usbdev_bc.o
 obj-$(CONFIG_DWC_OTG_310) := dwc_otg.o
index cbd3f364e37c7ebb1aa5106803a0c572c0391dbe..d90be6d841d17bba1e85bbd0b4138caab55536cb 100755 (executable)
@@ -959,15 +959,13 @@ static int host20_driver_probe(struct platform_device *_dev)
            of_match_device(of_match_ptr(usb20_host_of_match), &_dev->dev);
 
        if (match && match->data) {
-               dev->platform_data = (void *)match->data;
+               pldata = (void *)match->data;
+               pldata->dev = dev;
        } else {
-               dev_err(dev, "usb20host match failed\n");
+               dev_err(dev, "usb20otg match failed\n");
                return -EINVAL;
        }
 
-       pldata = dev->platform_data;
-       pldata->dev = dev;
-
        if (!node) {
                dev_err(dev, "device node not found\n");
                return -EINVAL;
@@ -1012,8 +1010,7 @@ static int host20_driver_probe(struct platform_device *_dev)
                retval = -ENOMEM;
                goto clk_disable;
        }
-       dev_dbg(&_dev->dev, "base=0x%08x\n",
-               (unsigned)dwc_otg_device->os_dep.base);
+       dev_dbg(&_dev->dev, "base=0x%p\n", dwc_otg_device->os_dep.base);
 
        /* Set device flags indicating whether the HCD supports DMA. */
        if (!_dev->dev.dma_mask)
@@ -1156,18 +1153,18 @@ static int dwc_otg_driver_resume(struct platform_device *_dev)
 static void dwc_otg_driver_shutdown(struct platform_device *_dev)
 {
        struct device *dev = &_dev->dev;
-       struct dwc_otg_platform_data *pldata = dev->platform_data;
        dwc_otg_device_t *otg_dev = dev->platform_data;
        dwc_otg_core_if_t *core_if = otg_dev->core_if;
+       struct dwc_otg_platform_data *pldata = otg_dev->pldata;
        dctl_data_t dctl = {.d32 = 0 };
 
        DWC_PRINTF("%s: disconnect USB %s mode\n", __func__,
                   dwc_otg_is_host_mode(core_if) ? "host" : "device");
 
-    if( pldata->dwc_otg_uart_mode != NULL)
-        pldata->dwc_otg_uart_mode( pldata, PHY_USB_MODE);
-    if(pldata->phy_suspend != NULL)
-        pldata->phy_suspend(pldata, USB_PHY_ENABLED);
+       if (pldata->dwc_otg_uart_mode != NULL)
+               pldata->dwc_otg_uart_mode(pldata, PHY_USB_MODE);
+       if (pldata->phy_suspend != NULL)
+               pldata->phy_suspend(pldata, USB_PHY_ENABLED);
        if (dwc_otg_is_host_mode(core_if)) {
                if (core_if->hcd_cb && core_if->hcd_cb->stop)
                        core_if->hcd_cb->stop(core_if->hcd_cb_p);
@@ -1303,6 +1300,10 @@ static const struct of_device_id usb20_otg_of_match[] = {
         .compatible = "rockchip,rk3126_usb20_otg",
         .data = &usb20otg_pdata_rk3126,
         },
+       {
+        .compatible = "rockchip,rk3368_usb20_otg",
+        .data = &usb20otg_pdata_rk3368,
+        },
        { },
 };
 
@@ -1332,21 +1333,19 @@ static int otg20_driver_probe(struct platform_device *_dev)
        const struct of_device_id *match =
            of_match_device(of_match_ptr(usb20_otg_of_match), &_dev->dev);
 
-       if (match) {
-               dev->platform_data = (void *)match->data;
+       if (match && match->data) {
+               pldata = (void *)match->data;
+               pldata->dev = dev;
        } else {
                dev_err(dev, "usb20otg match failed\n");
                return -EINVAL;
        }
 
-       pldata = dev->platform_data;
-       pldata->dev = dev;
-
        if (!node) {
                dev_err(dev, "device node not found\n");
                return -EINVAL;
        }
-       /*todo : move to usbdev_rk-XX.c */
+
        if (pldata->hw_init)
                pldata->hw_init();
 
@@ -1395,8 +1394,7 @@ static int otg20_driver_probe(struct platform_device *_dev)
                retval = -ENOMEM;
                goto clk_disable;
        }
-       dev_dbg(&_dev->dev, "base=0x%08x\n",
-               (unsigned)dwc_otg_device->os_dep.base);
+       dev_dbg(&_dev->dev, "base=0x%p\n", dwc_otg_device->os_dep.base);
 
        /* Set device flags indicating whether the HCD supports DMA. */
        if (!_dev->dev.dma_mask)
index 16ef6d78c54b246fd0a5ff0128bb711c0bedb72d..bed18c605e887fabd4bdf9becfb350bb53f2a8a1 100755 (executable)
@@ -19,6 +19,8 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/reset.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 #include <linux/rockchip/cru.h>
 #include <linux/rockchip/grf.h>
 #include <linux/rockchip/cpu.h>
@@ -71,6 +73,10 @@ extern struct dwc_otg_platform_data usb20otg_pdata_rk3126;
 extern struct dwc_otg_platform_data usb20host_pdata_rk3126;
 extern struct dwc_otg_platform_data usb20ohci_pdata_rk3126;
 extern struct rkehci_platform_data usb20ehci_pdata_rk3126;
+/* rk3368 platform data */
+extern struct rkehci_platform_data usb20ehci_pdata_rk3368;
+extern struct dwc_otg_platform_data usb20ohci_pdata_rk3368;
+extern struct dwc_otg_platform_data usb20otg_pdata_rk3368;
 
 struct dwc_otg_platform_data {
        void *privdata;
@@ -120,6 +126,7 @@ struct dwc_otg_control_usb {
        pGRF_SOC_STATUS19_RK3288 grf_soc_status19_rk3288;
        pGRF_SOC_STATUS21_RK3288 grf_soc_status21_rk3288;
 
+       struct regmap *grf;
        struct gpio *host_gpios;
        struct gpio *otg_gpios;
        struct clk *hclk_usb_peri;
diff --git a/drivers/usb/dwc_otg_310/usbdev_rk3368.c b/drivers/usb/dwc_otg_310/usbdev_rk3368.c
new file mode 100644 (file)
index 0000000..8be8733
--- /dev/null
@@ -0,0 +1,516 @@
+#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)
+{
+       unsigned int val;
+
+       regmap_read(control_usb->grf, reg, &val);
+       return val;
+}
+
+static void uoc_write(u32 value, u32 reg)
+{
+       regmap_write(control_usb->grf, reg, value);
+}
+
+#ifdef CONFIG_USB20_OTG
+static void usb20otg_hw_init(void)
+{
+       /* Turn off differential receiver in suspend mode */
+       uoc_write(UOC_HIWORD_UPDATE(0, 1, 2), 0x798);
+
+       /* other haredware init,include:
+        * DRV_VBUS GPIO init */
+       if (gpio_is_valid(control_usb->otg_gpios->gpio))
+               gpio_set_value(control_usb->otg_gpios->gpio, 0);
+}
+
+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);
+               usbpdata->phy_status = 1;
+       } else {
+               /* exit suspend */
+               uoc_write(UOC_HIWORD_UPDATE(0x0, 0x1, 0), 0x700);
+               usbpdata->phy_status = 0;
+       }
+}
+
+static void usb20otg_soft_reset(void *pdata, enum rkusb_rst_flag rst_type)
+{
+       struct dwc_otg_platform_data *usbpdata = pdata;
+       struct reset_control *rst_otg_h, *rst_otg_p, *rst_otg_c;
+
+       rst_otg_h = devm_reset_control_get(usbpdata->dev, "otg_ahb");
+       rst_otg_p = devm_reset_control_get(usbpdata->dev, "otg_phy");
+       rst_otg_c = devm_reset_control_get(usbpdata->dev, "otg_controller");
+       if (IS_ERR(rst_otg_h) || IS_ERR(rst_otg_p) || IS_ERR(rst_otg_c)) {
+               dev_err(usbpdata->dev, "Fail to get reset control from dts\n");
+               return;
+       }
+
+       switch (rst_type) {
+       case RST_POR:
+               /* 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);
+
+               /* Controller reset */
+               reset_control_assert(rst_otg_c);
+               reset_control_assert(rst_otg_h);
+
+               udelay(2);
+
+               reset_control_deassert(rst_otg_c);
+               reset_control_deassert(rst_otg_h);
+               break;
+
+       default:
+               break;
+       }
+}
+
+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");
+       if (IS_ERR(ahbclk)) {
+               dev_err(usbpdata->dev, "Failed to get hclk_usb0\n");
+               return;
+       }
+
+       phyclk = devm_clk_get(usbpdata->dev, "clk_usbphy0");
+       if (IS_ERR(phyclk)) {
+               dev_err(usbpdata->dev, "Failed to get clk_usbphy0\n");
+               return;
+       }
+
+       usbpdata->phyclk = phyclk;
+       usbpdata->ahbclk = ahbclk;
+}
+
+static void usb20otg_clock_enable(void *pdata, int enable)
+{
+       struct dwc_otg_platform_data *usbpdata = pdata;
+
+       if (enable) {
+               clk_prepare_enable(usbpdata->ahbclk);
+               clk_prepare_enable(usbpdata->phyclk);
+       } else {
+               clk_disable_unprepare(usbpdata->ahbclk);
+               clk_disable_unprepare(usbpdata->phyclk);
+       }
+}
+
+static int usb20otg_get_status(int id)
+{
+       int ret = -1;
+       u32 soc_status15 = uoc_read(0x4bc);
+
+       switch (id) {
+       case USB_STATUS_BVABLID:
+               /* bvalid in grf */
+               ret = soc_status15 & (0x1 << 23);
+               break;
+       case USB_STATUS_DPDM:
+               /* dpdm in grf */
+               ret = soc_status15 & (0x3 << 24);
+               break;
+       case USB_STATUS_ID:
+               /* id in grf */
+               ret = soc_status15 & (0x1 << 26);
+               break;
+       case USB_CHIP_ID:
+               ret = control_usb->chip_id;
+               break;
+       case USB_REMOTE_WAKEUP:
+               ret = control_usb->remote_wakeup;
+               break;
+       case USB_IRQ_WAKEUP:
+               ret = control_usb->usb_irq_wakeup;
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
+#ifdef CONFIG_RK_USB_UART
+/**
+ *  dwc_otg_uart_enabled - check if a usb-uart bypass func is enabled in DT
+ *
+ *  Returns true if the status property of node "usb_uart" is set to "okay"
+ *  or "ok", if this property is absent it will use the default status "ok"
+ *  0 otherwise
+ */
+static bool dwc_otg_uart_enabled(void)
+{
+       return false;
+}
+
+static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode)
+{
+}
+#else
+static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode)
+{
+}
+#endif
+
+static void usb20otg_power_enable(int enable)
+{
+       if (0 == enable) {
+               /* disable otg_drv power */
+               if (gpio_is_valid(control_usb->otg_gpios->gpio))
+                       gpio_set_value(control_usb->otg_gpios->gpio, 0);
+       } 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);
+       }
+}
+
+struct dwc_otg_platform_data usb20otg_pdata_rk3368 = {
+       .phyclk = NULL,
+       .ahbclk = NULL,
+       .busclk = NULL,
+       .phy_status = 0,
+       .hw_init = usb20otg_hw_init,
+       .phy_suspend = usb20otg_phy_suspend,
+       .soft_reset = usb20otg_soft_reset,
+       .clock_init = usb20otg_clock_init,
+       .clock_enable = usb20otg_clock_enable,
+       .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, */
+};
+#endif
+
+#ifdef CONFIG_USB_EHCI_RK
+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);
+
+       /* other haredware init,include:
+        * DRV_VBUS GPIO init */
+       if (gpio_is_valid(control_usb->host_gpios->gpio)) {
+               if (!gpio_get_value(control_usb->host_gpios->gpio))
+                       gpio_set_value(control_usb->host_gpios->gpio, 1);
+       }
+}
+
+static void usb20ehci_phy_suspend(void *pdata, int suspend)
+{
+       struct rkehci_platform_data *usbpdata = pdata;
+
+       if (suspend) {
+               /* enable soft control */
+               uoc_write(UOC_HIWORD_UPDATE(0x1d5, 0x1ff, 0), 0x728);
+               usbpdata->phy_status = 1;
+       } else {
+               /* exit suspend */
+               uoc_write(UOC_HIWORD_UPDATE(0x0, 0x1, 0), 0x728);
+               usbpdata->phy_status = 0;
+       }
+}
+
+static void usb20ehci_soft_reset(void *pdata, enum rkusb_rst_flag rst_type)
+{
+       struct rkehci_platform_data *usbpdata = pdata;
+       struct reset_control *rst_host_h, *rst_host_p, *rst_host_c;
+
+       rst_host_h = devm_reset_control_get(usbpdata->dev, "host_ahb");
+       rst_host_p = devm_reset_control_get(usbpdata->dev, "host_phy");
+       rst_host_c = devm_reset_control_get(usbpdata->dev, "host_controller");
+       if (IS_ERR(rst_host_h) || IS_ERR(rst_host_p) || IS_ERR(rst_host_c)) {
+               dev_err(usbpdata->dev, "Fail to get reset control from dts\n");
+               return;
+       }
+
+       switch (rst_type) {
+       case RST_POR:
+               /* PHY reset */
+               uoc_write(UOC_HIWORD_UPDATE(0x1, 0x3, 0), 0x728);
+               reset_control_assert(rst_host_p);
+               udelay(15);
+               uoc_write(UOC_HIWORD_UPDATE(0x2, 0x3, 0), 0x728);
+
+               udelay(1500);
+               reset_control_deassert(rst_host_p);
+
+               /* Controller reset */
+               reset_control_assert(rst_host_c);
+               reset_control_assert(rst_host_h);
+
+               udelay(5);
+
+               reset_control_deassert(rst_host_c);
+               reset_control_deassert(rst_host_h);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void usb20ehci_clock_init(void *pdata)
+{
+}
+
+static void usb20ehci_clock_enable(void *pdata, int enable)
+{
+}
+
+static int usb20ehci_get_status(int id)
+{
+       /* For HOST port in rk336x can not get any info from GRF */
+       return -ENOENT;
+}
+
+struct rkehci_platform_data usb20ehci_pdata_rk3368 = {
+       .phyclk = NULL,
+       .ahbclk = NULL,
+       .phy_status = 0,
+       .hw_init = usb20ehci_hw_init,
+       .phy_suspend = usb20ehci_phy_suspend,
+       .soft_reset = usb20ehci_soft_reset,
+       .clock_init = usb20ehci_clock_init,
+       .clock_enable = usb20ehci_clock_enable,
+       .get_status = usb20ehci_get_status,
+};
+#endif
+
+struct dwc_otg_platform_data usb20ohci_pdata_rk3368;
+
+#ifdef CONFIG_OF
+static const struct of_device_id rk_usb_control_id_table[] = {
+       {
+        .compatible = "rockchip,rk3368-usb-control",
+        },
+       {},
+};
+#endif
+/*********************************************************************
+                       rk3126 usb detections
+*********************************************************************/
+
+#define WAKE_LOCK_TIMEOUT (HZ * 10)
+static inline void do_wakeup(struct work_struct *work)
+{
+       /* wake up the system */
+       rk_send_wakeup_key();
+}
+
+static void usb_battery_charger_detect_work(struct work_struct *work)
+{
+       /* 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);
+#ifdef CONFIG_RK_USB_UART
+       /* usb otg dp/dm switch to usb phy */
+       dwc_otg_uart_mode(NULL, PHY_USB_MODE);
+#endif
+
+       if (control_usb->usb_irq_wakeup) {
+               wake_lock_timeout(&control_usb->usb_wakelock,
+                                 WAKE_LOCK_TIMEOUT);
+               schedule_delayed_work(&control_usb->usb_det_wakeup_work,
+                                     HZ / 10);
+       }
+
+       schedule_delayed_work(&control_usb->usb_charger_det_work, HZ / 10);
+
+       return IRQ_HANDLED;
+}
+
+/************* register usb detection irqs **************/
+static int otg_irq_detect_init(struct platform_device *pdev)
+{
+       int ret = 0;
+       int irq = 0;
+
+       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) {
+               ret = request_irq(irq, bvalid_irq_handler,
+                                 0, "otg_bvalid", NULL);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "request_irq %d failed!\n", irq);
+               } else {
+                       /* enable bvalid irq  */
+                       uoc_write(UOC_HIWORD_UPDATE(0x1, 0x1, 3), 0x680);
+               }
+       }
+#endif
+       return 0;
+}
+
+/********** end of usb detections **********/
+#ifdef CONFIG_OF
+static const struct of_device_id dwc_otg_control_usb_id_table[] = {
+       {
+        .compatible = "rockchip,rk3368-dwc-control-usb",
+        },
+       {},
+};
+#endif
+static int dwc_otg_control_usb_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct clk *hclk_usb_peri;
+       struct regmap *grf;
+       int gpio, ret = 0;
+
+       control_usb = devm_kzalloc(dev, sizeof(*control_usb), GFP_KERNEL);
+       if (!control_usb) {
+               dev_err(&pdev->dev, "Unable to alloc memory for control usb\n");
+               return -ENOMEM;
+       }
+
+       /* Init regmap GRF */
+       grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
+       if (IS_ERR(grf)) {
+               dev_err(&pdev->dev, "Missing rockchip,grf property\n");
+               return PTR_ERR(grf);
+       }
+       control_usb->grf = grf;
+
+       /* Init Vbus-drv GPIOs */
+       control_usb->host_gpios =
+           devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
+       if (!control_usb->host_gpios) {
+               dev_err(&pdev->dev, "Unable to alloc memory for host_gpios\n");
+               return -ENOMEM;
+       }
+
+       gpio = of_get_named_gpio(np, "host_drv_gpio", 0);
+       control_usb->host_gpios->gpio = gpio;
+
+       if (gpio_is_valid(gpio)) {
+               if (devm_gpio_request(&pdev->dev, gpio, "usb_host_drv")) {
+                       dev_err(&pdev->dev,
+                               "Failed to request GPIO%d for host_drv\n",
+                               gpio);
+                       return -EINVAL;
+               }
+               gpio_direction_output(control_usb->host_gpios->gpio, 1);
+       }
+
+       control_usb->otg_gpios =
+           devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
+       if (!control_usb->otg_gpios) {
+               dev_err(&pdev->dev, "Unable to alloc memory for otg_gpios\n");
+               return -ENOMEM;
+       }
+
+       gpio = of_get_named_gpio(np, "otg_drv_gpio", 0);
+       control_usb->otg_gpios->gpio = gpio;
+
+       if (gpio_is_valid(gpio)) {
+               if (devm_gpio_request(&pdev->dev, gpio, "usb_otg_drv")) {
+                       dev_err(&pdev->dev,
+                               "failed to request GPIO%d for otg_drv\n", gpio);
+                       return -EINVAL;
+               }
+               gpio_direction_output(control_usb->otg_gpios->gpio, 0);
+       }
+
+
+       control_usb->remote_wakeup = of_property_read_bool(np,
+                                                          "rockchip,remote_wakeup");
+       control_usb->usb_irq_wakeup = of_property_read_bool(np,
+                                                           "rockchip,usb_irq_wakeup");
+
+       /* 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);
+       }
+       control_usb->hclk_usb_peri = hclk_usb_peri;
+       clk_prepare_enable(hclk_usb_peri);
+
+#ifdef CONFIG_USB20_OTG
+       INIT_DELAYED_WORK(&control_usb->usb_charger_det_work,
+                         usb_battery_charger_detect_work);
+
+       if (usb20otg_get_status(USB_STATUS_BVABLID))
+               schedule_delayed_work(&control_usb->usb_charger_det_work,
+                                     HZ / 10);
+#endif
+
+       ret = otg_irq_detect_init(pdev);
+       if (ret < 0)
+               goto err;
+
+       return 0;
+
+err:
+       clk_disable_unprepare(hclk_usb_peri);
+       return ret;
+}
+
+static int dwc_otg_control_usb_remove(struct platform_device *pdev)
+{
+       clk_disable_unprepare(control_usb->hclk_usb_peri);
+       return 0;
+}
+
+static struct platform_driver dwc_otg_control_usb_driver = {
+       .probe = dwc_otg_control_usb_probe,
+       .remove = dwc_otg_control_usb_remove,
+       .driver = {
+                  .name = "rk3368-dwc-control-usb",
+                  .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(dwc_otg_control_usb_id_table),
+                  },
+};
+
+static int __init dwc_otg_control_usb_init(void)
+{
+       int retval = 0;
+
+       retval |= platform_driver_register(&dwc_otg_control_usb_driver);
+       return retval;
+}
+
+subsys_initcall(dwc_otg_control_usb_init);
+
+static void __exit dwc_otg_control_usb_exit(void)
+{
+       platform_driver_unregister(&dwc_otg_control_usb_driver);
+}
+
+module_exit(dwc_otg_control_usb_exit);
+MODULE_ALIAS("platform: dwc_control_usb");
+MODULE_AUTHOR("RockChip Inc.");
+MODULE_DESCRIPTION("RockChip Control Module USB Driver");
+MODULE_LICENSE("GPL v2");
index 874f8008150e6ae65170cb51b1d4107f4ba9adef..022d1deb146572808fb57ed575ad35631487060f 100755 (executable)
@@ -253,6 +253,10 @@ static struct of_device_id rk_ehci_of_match[] = {
         .compatible = "rockchip,rk3126_ehci",
         .data = &usb20ehci_pdata_rk3126,
         },
+       {
+        .compatible = "rockchip,rk3368_ehci",
+        .data = &usb20ehci_pdata_rk3368,
+        },
        {},
 };
 
index 1bc76597882364081d88340550c283a00a7da158..4ea5432844639d17f78eb6560672f8c198a31c9b 100755 (executable)
@@ -93,6 +93,10 @@ static struct of_device_id rk_ohci_of_match[] = {
         .compatible = "rockchip,rk3126_ohci",
         .data = &usb20ohci_pdata_rk3126,
         },
+       {
+        .compatible = "rockchip,rk3368_ohci",
+        .data = &usb20ohci_pdata_rk3368,
+        },
        {},
 };
 
@@ -120,7 +124,7 @@ static int ohci_hcd_rk_probe(struct platform_device *pdev)
                return -ENODEV;
 
        match = of_match_device(of_match_ptr(rk_ohci_of_match), &pdev->dev);
-       if (match) {
+       if (match && match->data) {
                pldata = (struct dwc_otg_platform_data *)match->data;
        } else {
                dev_err(dev, "ohci_rk match failed\n");
@@ -145,6 +149,11 @@ static int ohci_hcd_rk_probe(struct platform_device *pdev)
                goto clk_disable;
        }
 
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+       dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "UHH OHCI get resource failed\n");