USB: RK3288 USB CTLR initialization
authorwlf <wulf@rock-chips.com>
Tue, 11 Mar 2014 03:14:10 +0000 (11:14 +0800)
committerwlf <wulf@rock-chips.com>
Tue, 11 Mar 2014 03:14:10 +0000 (11:14 +0800)
15 files changed:
arch/arm/boot/dts/rk3188.dtsi
arch/arm/boot/dts/rk3288.dtsi
drivers/usb/Kconfig
drivers/usb/dwc_otg_310/Makefile
drivers/usb/dwc_otg_310/dwc_otg_driver.c
drivers/usb/dwc_otg_310/usbdev_grf_regs.h [new file with mode: 0644]
drivers/usb/dwc_otg_310/usbdev_rk.h
drivers/usb/dwc_otg_310/usbdev_rk30.c
drivers/usb/dwc_otg_310/usbdev_rk32.c [new file with mode: 0644]
drivers/usb/host/Kconfig
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-rk.c
drivers/usb/host/ehci-rkhsic.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-rk.c [new file with mode: 0755]

index 6a6cdd5f18025d77c99fc89a449530e3ba6f947e..612c3c8357e549cf06fc471cf59b1e57530a02c7 100755 (executable)
                };
        };
 
-       dwc_control_usb: dwc-control-usb@0x200080ac {
+       dwc_control_usb: dwc-control-usb@200080ac {
                compatible = "rockchip,rk3188-dwc-control-usb";
                reg = <0x200080ac 0x4>,
                      <0x2000810c 0x10>,
        };
 
        usb@10180000 {
-               compatible = "rockchip,usb20_otg";
+               compatible = "rockchip,rk3188_usb20_otg";
                reg = <0x10180000 0x40000>;
                interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&clk_otgphy0_480m>, <&clk_gates5 13>;
        };
 
        usb@101c0000 {
-               compatible = "rockchip,usb20_host";
+               compatible = "rockchip,rk3188_usb20_host";
                reg = <0x101c0000 0x40000>;
                interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&clk_otgphy1_480m>, <&clk_gates7 3>;
        };
 
        hsic@10240000 {
-               compatible = "rockchip,rk_hsic_host";
+               compatible = "rockchip,rk3188_rk_hsic_host";
                reg = <0x10240000 0x40000>;
                interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&clk_hsicphy480m>, <&clk_gates7 4>,
index b913ba5e19dc78e81954291e3b15e64323c304d8..9eb911f9fdacf87e466dd99b1288e2690af535fc 100755 (executable)
                clock_names = "aclk_iep", "hclk_iep";*/
                status = "disabled";
         };
+
+       dwc_control_usb: dwc-control-usb@ff770284 {
+               compatible = "rockchip,rk3288-dwc-control-usb";
+               reg = <0xff770284 0x04>, <0xff770288 0x04>,
+                     <0xff7702cc 0x04>, <0xff7702d4 0x04>,
+                     <0xff770320 0x14>, <0xff770334 0x14>,
+                     <0xff770348 0x10>, <0xff770358 0x08>,
+                     <0xff770360 0x08>;
+               reg-names = "GRF_SOC_STATUS1" ,"GRF_SOC_STATUS2",
+                           "GRF_SOC_STATUS19", "GRF_SOC_STATUS21",
+                           "GRF_UOC0_BASE", "GRF_UOC1_BASE",
+                           "GRF_UOC2_BASE", "GRF_UOC3_BASE",
+                           "GRF_UOC4_BASE";
+               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>,
+                            <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "otg_id", "bvalid",
+                                 "otg_linestate", "host0_linestate",
+                                 "host1_linestate";
+               /*gpios = <&gpio0 GPIO_B6 GPIO_ACTIVE_LOW>,*//*HOST_VBUS_DRV*/
+               /*      <&gpio0 GPIO_B4 GPIO_ACTIVE_LOW>;*//*OTG_VBUS_DRV*/
+               /*clocks = <&clk_gates4 5>;*/
+               /*clock-names = "hclk_usb_peri";*/
+       };
+
+       usb1: usb@ff580000 {
+               compatible = "rockchip,rk3288_usb20_otg";
+               reg = <0xff580000 0x40000>;
+               interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+               /*clocks = <&clk_otgphy0_480m>, <&clk_gates5 13>;*/
+               /*clock-names = "otgphy0", "hclk_otg0";*/
+       };
+
+       usb2: usb@ff540000 {
+               compatible = "rockchip,rk3288_usb20_host";
+               reg = <0xff540000 0x40000>;
+               interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+               /*clocks = <&clk_otgphy1_480m>, <&clk_gates7 3>;*/
+               /*clock-names = "otgphy1", "hclk_otg1";*/
+       };
+
+       usb3: usb@ff520000 {
+               compatible = "rockchip,rk3288_rk_ohci_host";
+               reg = <0xff520000 0x20000>;
+               interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+               /*clocks = ;*/
+               /*clock-names = ;*/
+       };
+
+       usb4: usb@ff500000 {
+               compatible = "rockchip,rk3288_rk_ehci_host";
+               reg = <0xff500000 0x20000>;
+               interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+               /*clocks = ;*/
+               /*clock-names = ;*/
+       };
+
+       usb5: hsic@ff5c0000 {
+               compatible = "rockchip,rk3288_rk_hsic_host";
+               reg = <0xff5c0000 0x40000>;
+               interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+               /*clocks = <&clk_hsicphy480m>, <&clk_gates7 4>,*/
+               /*       <&clk_hsicphy12m>, <&clk_otgphy1_480m>;*/
+               /*clock-names = "hsicphy480m", "hclk_hsic",*/
+               /*            "hsicphy12m", "hsic_otgphy1";*/
+       };
 };
index a8a0d66f44dd553ba516da60106e224a1e936a16..e6e3388213a6fc24292909a9a7bad731c80d2dec 100644 (file)
@@ -19,6 +19,7 @@ config USB_ARCH_HAS_OHCI
        default y if ARCH_CNS3XXX
        default y if PLAT_SPEAR
        default y if ARCH_EXYNOS
+       default y if ARCH_ROCKCHIP
        # PPC:
        default y if STB03xxx
        default y if PPC_MPC52xx
index 582efa698edb28c099bc7f311ed1f03c160b51b5..2850418f5854f045708fc03ce8acb8fac78370a4 100755 (executable)
@@ -25,7 +25,7 @@ endif
 dwc_otg-objs   += common_port/dwc_common_linux.o
 
 #objs relative to RK platform 
-dwc_otg-objs   += usbdev_rk30.o
+dwc_otg-objs   += usbdev_rk30.o usbdev_rk32.o
 #dwc_otg-objs  += usbdev_rk3190.o
 #dwc_otg-objs  += dwc_otg_rk_common.o
 obj-$(CONFIG_DWC_OTG_310) := dwc_otg.o
index d06e4970c4f57dbdbb34e443c850d641592ac8ac..7d3a5fb2209c493551758c22ae0a80ca5a623a40 100755 (executable)
@@ -76,8 +76,29 @@ extern int pcd_remove(     struct platform_device *_dev );
 extern void hcd_remove(     struct platform_device *_dev);
 extern void dwc_otg_adp_start( dwc_otg_core_if_t * core_if, uint8_t is_host);
 
-extern struct dwc_otg_platform_data usb20otg_pdata;
-extern struct dwc_otg_platform_data usb20host_pdata;
+static struct usb20otg_pdata_id usb20otg_pdata[] = {
+       {
+               .name = "rk3188-usb20otg",
+               .pdata = &usb20otg_pdata_rk3188,
+       },
+       {
+               .name = "rk3288-usb20otg",
+               .pdata = &usb20otg_pdata_rk3288,
+       },
+       { },
+};
+
+static struct usb20host_pdata_id usb20host_pdata[] = {
+       {
+               .name = "rk3188-usb20host",
+               .pdata = &usb20host_pdata_rk3188,
+       },
+       {
+               .name = "rk3288-usb20host",
+               .pdata = &usb20host_pdata_rk3288,
+       },
+       { },
+};
 
 /*-------------------------------------------------------------------------*/
 /* Encapsulate the module parameter settings */
@@ -755,6 +776,19 @@ static int host20_driver_remove( struct platform_device *_dev )
        return 0;
 }
 
+static const struct of_device_id usb20_host_of_match[] = {
+       {
+               .compatible = "rockchip,rk3188_usb20_host", 
+               .data = &usb20host_pdata[RK3188_USB_CTLR],
+       },
+       {
+               .compatible = "rockchip,rk3288_usb20_host",
+               .data = &usb20host_pdata[RK3288_USB_CTLR],
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, usb20_host_of_match);
+
 /**
  * This function is called when an lm_device is bound to a
  * dwc_otg_driver. It creates the driver components required to
@@ -766,7 +800,7 @@ static int host20_driver_remove( struct platform_device *_dev )
  *
  * @param _dev Bus device
  */
-static int host20_driver_probe(      struct platform_device *_dev)
+static int host20_driver_probe(struct platform_device *_dev)
 {
        int retval = 0;
        int irq;
@@ -775,8 +809,18 @@ static int host20_driver_probe(      struct platform_device *_dev)
        struct device           *dev = &_dev->dev;
        struct device_node      *node = _dev->dev.of_node;
        struct dwc_otg_platform_data *pldata;
+       struct usb20host_pdata_id *p;
+       const struct of_device_id *match =
+               of_match_device(of_match_ptr( usb20_host_of_match ), &_dev->dev);
+
+       if (match){
+               p = (struct usb20host_pdata_id *)match->data;
+       }else{
+               dev_err(dev, "usb20host match failed\n");
+               return -EINVAL;
+       }
 
-       dev->platform_data = &usb20host_pdata;
+       dev->platform_data = p->pdata;
        pldata = dev->platform_data;
        pldata->dev = dev;
 
@@ -805,7 +849,8 @@ static int host20_driver_probe(      struct platform_device *_dev)
 
        if (!dwc_otg_device) {
                dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
-               return -ENOMEM;
+               retval = -ENOMEM;
+               goto clk_disable;
        }
 
        memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
@@ -820,7 +865,8 @@ static int host20_driver_probe(      struct platform_device *_dev)
        if (!dwc_otg_device->os_dep.base) {
                dev_err(&_dev->dev, "ioremap() failed\n");
                DWC_FREE(dwc_otg_device);
-               return -ENOMEM;
+               retval = -ENOMEM;
+               goto clk_disable;
        }
        dev_dbg(&_dev->dev, "base=0x%08x\n",
                (unsigned)dwc_otg_device->os_dep.base);
@@ -929,6 +975,10 @@ static int host20_driver_probe(      struct platform_device *_dev)
 
 fail:
        host20_driver_remove(_dev);
+clk_disable:
+       if(pldata->clock_enable)
+               pldata->clock_enable(pldata, 0);
+
        return retval;
 }
 
@@ -982,11 +1032,6 @@ static void dwc_otg_driver_shutdown(struct platform_device *_dev )
  * to this driver. The remove function is called when a device is
  * unregistered with the bus driver.
  */
-static const struct of_device_id usb20_host_of_match[] = {
-       { .compatible = "rockchip,usb20_host", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, usb20_host_of_match);
 
 static struct platform_driver dwc_host_driver = {
        .driver = {
@@ -1077,6 +1122,19 @@ static int otg20_driver_remove( struct platform_device *_dev )
        return 0;
 }
 
+static const struct of_device_id usb20_otg_of_match[] = {
+       {
+               .compatible = "rockchip,rk3188_usb20_otg",
+               .data = &usb20otg_pdata[RK3188_USB_CTLR],
+       },
+       {
+               .compatible = "rockchip,rk3288_usb20_otg",
+               .data = &usb20otg_pdata[RK3288_USB_CTLR],
+       },
+       {
+       },
+};
+MODULE_DEVICE_TABLE(of, usb20_otg_of_match);
 
 /**
  * This function is called when an lm_device is bound to a
@@ -1089,7 +1147,7 @@ static int otg20_driver_remove( struct platform_device *_dev )
  *
  * @param _dev Bus device
  */
-static int otg20_driver_probe(      struct platform_device *_dev)
+static int otg20_driver_probe(struct platform_device *_dev)
 {
        int retval = 0;
        int irq;
@@ -1098,9 +1156,19 @@ static int otg20_driver_probe(      struct platform_device *_dev)
        struct device           *dev = &_dev->dev;
        struct device_node      *node = _dev->dev.of_node;
        struct dwc_otg_platform_data *pldata;
+       struct usb20otg_pdata_id *p;
+       const struct of_device_id *match =
+               of_match_device(of_match_ptr( usb20_otg_of_match ), &_dev->dev);
+
+       if (match){
+               p = (struct usb20otg_pdata_id *)match->data;
+       }else{
+               dev_err(dev, "usb20otg match failed\n");
+               return -EINVAL;
+       }
 
-
-       dev->platform_data = &usb20otg_pdata;
+       dev->platform_data = p->pdata;
+//     dev->platform_data = &usb20otg_pdata;
        pldata =  dev->platform_data;
        pldata->dev = dev;
 
@@ -1108,7 +1176,6 @@ static int otg20_driver_probe(      struct platform_device *_dev)
                dev_err(dev, "device node not found\n");
                return -EINVAL;
        }
-
        /*todo : move to usbdev_rk-XX.c*/
        if(pldata->hw_init)
                pldata->hw_init();
@@ -1132,7 +1199,8 @@ static int otg20_driver_probe(      struct platform_device *_dev)
 
        if (!dwc_otg_device) {
                dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
-               return -ENOMEM;
+               retval = -ENOMEM;       
+               goto clk_disable;
        }
 
        memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
@@ -1147,7 +1215,8 @@ static int otg20_driver_probe(      struct platform_device *_dev)
        if (!dwc_otg_device->os_dep.base) {
                dev_err(&_dev->dev, "ioremap() failed\n");
                DWC_FREE(dwc_otg_device);
-               return -ENOMEM;
+               retval = -ENOMEM;
+               goto clk_disable;
        }
        dev_dbg(&_dev->dev, "base=0x%08x\n",
                (unsigned)dwc_otg_device->os_dep.base);
@@ -1267,14 +1336,14 @@ static int otg20_driver_probe(      struct platform_device *_dev)
 
 fail:
        otg20_driver_remove(_dev);
+
+clk_disable:
+       if(pldata->clock_enable)
+               pldata->clock_enable(pldata, 0);
+
        return retval;
 }
 
-static const struct of_device_id usb20_otg_of_match[] = {
-       { .compatible = "rockchip,usb20_otg", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, usb20_otg_of_match);
 static struct platform_driver dwc_otg_driver = {
        .driver = {
                .name = (char *)dwc_otg20_driver_name,
diff --git a/drivers/usb/dwc_otg_310/usbdev_grf_regs.h b/drivers/usb/dwc_otg_310/usbdev_grf_regs.h
new file mode 100644 (file)
index 0000000..c74063a
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef __USBDEV_GRF_REGS_H__
+#define __USBDEV_GRF_REGS_H__
+
+typedef volatile struct tag_grf_uoc0_reg
+{
+       /* OTG */
+       u32 CON0;
+       u32 CON1;
+       u32 CON2;
+       u32 CON3;
+       u32 CON4;
+}GRF_UOC0_REG, *pGRF_UOC0_REG;
+
+typedef volatile struct tag_grf_uoc1_reg
+{
+       /* HOST0 
+        * RK3188: DWC_OTG
+        * RK3288: OHCI & EHCI
+        */
+       u32 CON0;
+       u32 CON1;
+       u32 CON2;
+       u32 CON3;
+       u32 CON4;
+}GRF_UOC1_REG, *pGRF_UOC1_REG;
+
+
+typedef volatile struct tag_grf_uoc2_reg
+{
+       /* RK3188: HISC PHY
+        * RK3288: HOST1 DWC_OTG
+        */
+       u32 CON0;
+       u32 CON1;
+       u32 CON2;
+       u32 CON3;
+}GRF_UOC2_REG, *pGRF_UOC2_REG;
+
+typedef volatile struct tag_grf_uoc3_reg
+{
+       /* RK3188: HSIC CTLR
+        * RK3288: HSIC PHY 
+        */
+       u32 CON0;
+       u32 CON1;
+       u32 CON2;
+       u32 CON3;
+}GRF_UOC3_REG, *pGRF_UOC3_REG;
+
+typedef volatile struct tag_grf_uoc4_reg
+{
+       /* RK3288: HSIC CTLR */
+       u32 CON0;
+       u32 CON1;
+       u32 CON2;
+       u32 CON3;
+}GRF_UOC4_REG, *pGRF_UOC4_REG;
+
+typedef volatile struct tag_grf_soc_status0_rk3188
+{
+       unsigned reserved2 : 9;
+       /* OTG20 */
+       unsigned otg_vbusvalid : 1;
+       unsigned otg_bvalid : 1;
+       unsigned otg_linestate : 2;
+       unsigned otg_iddig : 1;
+       unsigned otg_adpsns : 1;
+       unsigned otg_adpprb : 1;
+       /* HOST20 */
+       unsigned uhost_vbusvalid : 1;
+       unsigned uhost_bvalid : 1;
+       unsigned uhost_linestate : 2;
+       unsigned uhost_iddig : 1;
+       unsigned uhost_adpsns : 1;
+       unsigned uhost_adpprb : 1;
+       unsigned reserved1 : 9;
+
+}GRF_SOC_STATUS_RK3188, *pGRF_SOC_STATUS_RK3188;
+
+typedef volatile struct tag_grf_soc_status1_rk3288
+{
+       unsigned reserved2 : 16;
+       unsigned hsic_ehci_usbsts : 6;
+       unsigned hsic_ehci_lpsmc_state : 4;
+       unsigned reserved1 : 6;
+
+}GRF_SOC_STATUS1_RK3288, *pGRF_SOC_STATUS1_RK3288;
+
+typedef volatile struct tag_grf_soc_status2_rk3288
+{
+       /* HSIC  */
+       unsigned hsic_ehci_xfer_cnt : 11;
+       unsigned hsic_ehci_xfer_prdc : 1;
+       unsigned reserved2 : 1;
+       /* OTG20  */
+       unsigned otg_vbusvalid : 1;
+       unsigned otg_bvalid : 1;
+       unsigned otg_linestate : 2;
+       unsigned otg_iddig : 1;
+       /* HOST1 DWC_OTG*/
+       unsigned host1_chirp_on : 1;
+       unsigned host1_vbusvalid : 1;
+       unsigned host1_bvalid : 1;
+       unsigned host1_linestate : 2;
+       unsigned host1_iddig : 1;
+       /* HOST0 OHCI */
+       unsigned host0_ohci_ccs : 1;
+       unsigned host0_ohci_rwe : 1;
+       unsigned host0_ohci_drwe : 1;
+       unsigned host0_linestate : 2;
+       unsigned host0_ohci_rmtwkp : 1;
+       unsigned host0_ohci_bufacc : 1;
+       unsigned reserved1 : 1;
+}GRF_SOC_STATUS2_RK3288, *pGRF_SOC_STATUS2_RK3288;
+
+typedef volatile struct tag_grf_soc_status19_rk3288
+{
+       unsigned host_sidle_ack : 2;
+       unsigned host_mstandby : 1;
+       unsigned host_mwakeup : 1;
+       unsigned host_mwait_out : 1;
+       unsigned host_eoi_out : 2;
+       unsigned host_wakeack : 1;
+       unsigned host_l3_ocp_mconnect : 2;
+       unsigned host_l3_ocp_tactive : 1;
+       unsigned host_l3_ocp_sconnect : 3;
+       unsigned reserved : 9;
+       /* OTG20 PHY STATUS */
+       unsigned otg_chgdet : 1;
+       unsigned otg_fsvplus : 1;
+       unsigned otg_fsvminus : 1;
+       /* HOST0 PHY STATUS */
+       unsigned host0_chgdet : 1;
+       unsigned host0_fsvplus : 1;
+       unsigned host0_fsvminus : 1;
+       /* HOST1 PHY STATUS */
+       unsigned host1_chgdet : 1;
+       unsigned host1_fsvplus : 1;
+       unsigned host1_fsvminus : 1;
+}GRF_SOC_STATUS19_RK3288, *pGRF_SOC_STATUS19_RK3288;
+
+typedef volatile struct tag_grf_soc_status21_rk3288
+{
+       unsigned reserved : 8;
+       /* HOST0 OHCI  */
+       unsigned host0_ohci_globalsuspend : 1;
+       /* HOST0 EHCI  */
+       unsigned host0_ehci_bufacc : 1;
+       unsigned host0_ehci_lpsmc_state : 4;
+       unsigned host0_ehci_xfer_prdc : 1;
+       unsigned host0_ehci_xfer_cnt : 11;
+       unsigned host0_ehci_usbsts : 6;
+}GRF_SOC_STATUS21_RK3288, *pGRF_SOC_STATUS21_RK3288;
+
+#endif
index 207654a83a218b9cf3f084d23fc10f7a86221d60..70728e814aa3b1860d5d8a135b3a1700db114f47 100755 (executable)
@@ -1,5 +1,8 @@
 #ifndef __USBDEV_RK_H
 #define __USBDEV_RK_H
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
+#include "usbdev_grf_regs.h"
 
 #define USB_PHY_ENABLED (0)
 #define USB_PHY_SUSPEND (1)
 #define USB_STATUS_ID         (3)
 #define USB_STATUS_UARTMODE   (4)
 
+/* rk3188 platform data */
+extern struct dwc_otg_platform_data usb20otg_pdata_rk3188;
+extern struct dwc_otg_platform_data usb20host_pdata_rk3188;
+extern struct rkehci_platform_data rkhsic_pdata_rk3188;
+/* rk3288 platform data */
+extern struct dwc_otg_platform_data usb20otg_pdata_rk3288;
+extern struct dwc_otg_platform_data usb20host_pdata_rk3288;
+extern struct rkehci_platform_data rkhsic_pdata_rk3288;
+extern struct rkehci_platform_data rkehci_pdata_rk3288;
+extern struct rkehci_platform_data rkohci_pdata_rk3288;
+
 struct dwc_otg_platform_data {
     void *privdata;
     struct device *dev;
@@ -35,6 +49,8 @@ struct rkehci_platform_data{
        struct clk* hclk_hsic;
        struct clk* hsic_phy_480m;
        struct clk* hsic_phy_12m;
+       struct clk* phyclk;
+       struct clk* ahbclk;
        void (*hw_init)(void);
        void (*clock_init)(void* pdata);
        void (*clock_enable)(void *pdata, int enable);
@@ -44,11 +60,16 @@ struct rkehci_platform_data{
 };
 
 struct dwc_otg_control_usb {
-       void *grf_soc_status0;
-       void *grf_uoc0_base;
-       void *grf_uoc1_base;
-       void *grf_uoc2_base;
-       void *grf_uoc3_base;
+       pGRF_UOC0_REG grf_uoc0_base;
+       pGRF_UOC1_REG grf_uoc1_base;
+       pGRF_UOC2_REG grf_uoc2_base;
+       pGRF_UOC3_REG grf_uoc3_base;
+       pGRF_UOC4_REG grf_uoc4_base;
+       pGRF_SOC_STATUS_RK3188 grf_soc_status0_rk3188;
+       pGRF_SOC_STATUS1_RK3288 grf_soc_status1_rk3288;
+       pGRF_SOC_STATUS2_RK3288 grf_soc_status2_rk3288;
+       pGRF_SOC_STATUS19_RK3288 grf_soc_status19_rk3288;
+       pGRF_SOC_STATUS21_RK3288 grf_soc_status21_rk3288;
        struct gpio *host_gpios;
        struct gpio *otg_gpios;
        struct clk* hclk_usb_peri;
@@ -62,4 +83,18 @@ enum {
        RK3288_USB_CTLR,        /* rk3288 chip usb */
 };
 
+struct usb20otg_pdata_id {
+       char name[32];
+       struct dwc_otg_platform_data *pdata;
+};
+
+struct usb20host_pdata_id {
+       char name[32];
+       struct dwc_otg_platform_data *pdata;
+};
+
+struct rkehci_pdata_id {
+       char name[32];
+       struct rkehci_platform_data *pdata;
+};
 #endif
index 183ff92250963f95a2956a0cb3e8e2dbde9055d0..864fec49293384654d6c4085c0a3406d969910ac 100755 (executable)
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include "usbdev_grf_regs.h"
 #include "usbdev_rk.h"
 #include "dwc_otg_regs.h"
 
 static struct dwc_otg_control_usb *control_usb;
 
-int usb_get_chip_id(void)
+static int usb_get_chip_id(void)
 {
        return control_usb->chip_id;
 }
 
-int dwc_otg_check_dpdm(void)
-{
-       int bus_status = 0;
-       return bus_status;
-}
-
-EXPORT_SYMBOL(dwc_otg_check_dpdm);
-
 #ifdef CONFIG_USB20_OTG
 
-void usb20otg_hw_init(void)
+static void usb20otg_hw_init(void)
 {
 #ifndef CONFIG_USB20_HOST
-       unsigned int * otg_phy_con1 = (control_usb->grf_uoc1_base + 0x8);
-       unsigned int * otg_phy_con2 = (control_usb->grf_uoc1_base + 0xc);
-       *otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16);     //enable soft control
-       *otg_phy_con2 = 0x2A|(0x3F<<16);               // enter suspend
+       //enable soft control
+       control_usb->grf_uoc1_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
+       // enter suspend
+       control_usb->grf_uoc1_base->CON3 = 0x2A|(0x3F<<16);
 #endif
        /* usb phy config init
         * usb phy enter usb mode */
-       unsigned int * otg_phy_con3 = (control_usb->grf_uoc0_base);
-       *otg_phy_con3 = (0x0300 << 16);
+       control_usb->grf_uoc0_base->CON0 = (0x0300 << 16);
 
        /* other haredware init,include:
         * DRV_VBUS GPIO init */
        gpio_direction_output(control_usb->otg_gpios->gpio, 0);
 }
 
-void usb20otg_phy_suspend(void* pdata, int suspend)
+static void usb20otg_phy_suspend(void* pdata, int suspend)
 {
        struct dwc_otg_platform_data *usbpdata=pdata;
-       unsigned int * otg_phy_con1 = (control_usb->grf_uoc0_base + 0x8);
-       unsigned int * otg_phy_con2 = (control_usb->grf_uoc0_base + 0xc);
 
        if(suspend){
-               *otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16);      //enable soft control
-               *otg_phy_con2 = 0x2A|(0x3F<<16);                // enter suspend
+               //enable soft control
+               control_usb->grf_uoc0_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
+               // enter suspend
+               control_usb->grf_uoc0_base->CON3 = 0x2A|(0x3F<<16);
                usbpdata->phy_status = 1;
        }else{
-               *otg_phy_con1 = ((0x01<<2)<<16);                // exit suspend.
+               // exit suspend.
+               control_usb->grf_uoc0_base->CON2 = ((0x01<<2)<<16);
                usbpdata->phy_status = 0;
        }
 }
 
-void usb20otg_soft_reset(void)
+static void usb20otg_soft_reset(void)
 {
 }
 
-void usb20otg_clock_init(void* pdata)
+static void usb20otg_clock_init(void* pdata)
 {
        struct dwc_otg_platform_data *usbpdata=pdata;
        struct clk* ahbclk,*phyclk;
@@ -94,7 +87,7 @@ void usb20otg_clock_init(void* pdata)
        usbpdata->ahbclk = ahbclk;
 }
 
-void usb20otg_clock_enable(void* pdata, int enable)
+static void usb20otg_clock_enable(void* pdata, int enable)
 {
        struct dwc_otg_platform_data *usbpdata=pdata;
 
@@ -107,23 +100,22 @@ void usb20otg_clock_enable(void* pdata, int enable)
        }
 }
 
-int usb20otg_get_status(int id)
+static int usb20otg_get_status(int id)
 {
        int ret = -1;
-       unsigned int usbgrf_status = *(unsigned int*)(control_usb->grf_soc_status0);
 
        switch(id){
                case USB_STATUS_BVABLID:
                        // bvalid in grf
-                       ret = (usbgrf_status &(1<<10));
+                       ret = control_usb->grf_soc_status0_rk3188->otg_bvalid;
                        break;
                case USB_STATUS_DPDM:
                        // dpdm in grf
-                       ret = (usbgrf_status &(3<<11));
+                       ret = control_usb->grf_soc_status0_rk3188->otg_linestate;
                        break;
                case USB_STATUS_ID:
                        // id in grf
-                       ret = (usbgrf_status &(1<<13));
+                       ret = control_usb->grf_soc_status0_rk3188->otg_iddig;
                        break;
                default:
                        break;
@@ -133,25 +125,24 @@ int usb20otg_get_status(int id)
 }
 
 #ifdef CONFIG_RK_USB_UART
-void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)
+static void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)
 {
-       unsigned int * otg_phy_con1 = (unsigned int*)(control_usb->grf_uoc0_base);
-
        if(1 == enter_usb_uart_mode){
                /* enter uart mode
                 * note: can't disable otg here! If otg disable, the ID change
                 * interrupt can't be triggered when otg cable connect without
                 * device.At the same time, uart can't be used normally
                 */
-               *otg_phy_con1 = (0x0300 | (0x0300 << 16));      //bypass dm
+               /* bypass dm, enter uart mode */
+               control_usb->grf_uoc0_base->CON0 = (0x0300 | (0x0300 << 16));
        }else if(0 == enter_usb_uart_mode){
                /* enter usb mode */
-               *otg_phy_con1 = (0x0300 << 16);                 //bypass dm disable
+               control_usb->grf_uoc0_base->CON0 = (0x0300 << 16);
        }
 }
 #endif
 
-void usb20otg_power_enable(int enable)
+static void usb20otg_power_enable(int enable)
 {
        if(0 == enable){//disable otg_drv power
                gpio_set_value(control_usb->otg_gpios->gpio, 0);
@@ -160,7 +151,7 @@ void usb20otg_power_enable(int enable)
        }
 }
 
-struct dwc_otg_platform_data usb20otg_pdata = {
+struct dwc_otg_platform_data usb20otg_pdata_rk3188 = {
        .phyclk = NULL,
        .ahbclk = NULL,
        .busclk = NULL,
@@ -181,7 +172,7 @@ struct dwc_otg_platform_data usb20otg_pdata = {
 #endif
 
 #ifdef CONFIG_USB20_HOST
-void usb20host_hw_init(void)
+static void usb20host_hw_init(void)
 {
        /* usb phy config init */
 
@@ -191,27 +182,28 @@ void usb20host_hw_init(void)
 
 }
 
-void usb20host_phy_suspend(void* pdata, int suspend)
+static void usb20host_phy_suspend(void* pdata, int suspend)
 {
        struct dwc_otg_platform_data *usbpdata=pdata;
-       unsigned int * otg_phy_con1 = (unsigned int*)(control_usb->grf_uoc1_base + 0x8);
-       unsigned int * otg_phy_con2 = (unsigned int*)(control_usb->grf_uoc1_base + 0xc);
 
        if(suspend){
-               *otg_phy_con1 =  (0x01<<2)|((0x01<<2)<<16);     // enable soft control
-               *otg_phy_con2 =  0x2A|(0x3F<<16);               // enter suspend
+               // enable soft control
+               control_usb->grf_uoc1_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
+               // enter suspend
+               control_usb->grf_uoc1_base->CON3 = 0x2A|(0x3F<<16); 
                usbpdata->phy_status = 1;
        }else{
-               *otg_phy_con1 = ((0x01<<2)<<16);                // exit suspend.
+               //exit suspend.
+               control_usb->grf_uoc1_base->CON2 = ((0x01<<2)<<16);
                usbpdata->phy_status = 0;
        }
 }
 
-void usb20host_soft_reset(void)
+static void usb20host_soft_reset(void)
 {
 }
 
-void usb20host_clock_init(void* pdata)
+static void usb20host_clock_init(void* pdata)
 {
        struct dwc_otg_platform_data *usbpdata=pdata;
        struct clk* ahbclk,*phyclk;
@@ -232,7 +224,7 @@ void usb20host_clock_init(void* pdata)
        usbpdata->ahbclk = ahbclk;
 }
 
-void usb20host_clock_enable(void* pdata, int enable)
+static void usb20host_clock_enable(void* pdata, int enable)
 {
        struct dwc_otg_platform_data *usbpdata=pdata;
 
@@ -245,23 +237,22 @@ void usb20host_clock_enable(void* pdata, int enable)
        }
 }
 
-int usb20host_get_status(int id)
+static int usb20host_get_status(int id)
 {
        int ret = -1;
-       unsigned int usbgrf_status = *(unsigned int*)(control_usb->grf_soc_status0);
 
        switch(id){
                case USB_STATUS_BVABLID:
                        // bvalid in grf
-                       ret = (usbgrf_status &(1<<17));
+                       ret = control_usb->grf_soc_status0_rk3188->uhost_bvalid;
                        break;
                case USB_STATUS_DPDM:
                        // dpdm in grf
-                       ret = (usbgrf_status &(3<<18));
+                       ret = control_usb->grf_soc_status0_rk3188->uhost_linestate;
                        break;
                case USB_STATUS_ID:
                        // id in grf
-                       ret = (usbgrf_status &(1<<20));
+                       ret = control_usb->grf_soc_status0_rk3188->uhost_iddig;
                        break;
                default:
                        break;
@@ -270,7 +261,7 @@ int usb20host_get_status(int id)
        return ret;
 }
 
-void usb20host_power_enable(int enable)
+static void usb20host_power_enable(int enable)
 {
        if(0 == enable){//disable host_drv power
                //do not disable power in default
@@ -279,7 +270,7 @@ void usb20host_power_enable(int enable)
        }
 }
 
-struct dwc_otg_platform_data usb20host_pdata = {
+struct dwc_otg_platform_data usb20host_pdata_rk3188 = {
        .phyclk = NULL,
        .ahbclk = NULL,
        .busclk = NULL,
@@ -296,31 +287,26 @@ struct dwc_otg_platform_data usb20host_pdata = {
 #endif
 
 #ifdef CONFIG_USB_EHCI_RKHSIC
-void rk_hsic_hw_init(void)
+static void rk_hsic_hw_init(void)
 {
-       unsigned int * phy_con0 = (control_usb->grf_uoc0_base);
-       unsigned int * phy_con1 = (control_usb->grf_uoc1_base);
-       unsigned int * phy_con2 = (control_usb->grf_uoc2_base);
-       unsigned int * phy_con3 = (control_usb->grf_uoc3_base);
-
        // usb phy config init
        // hsic phy config init, set hsicphy_txsrtune
-       *phy_con2 = ((0xf<<6)<<16)|(0xf<<6);
+       control_usb->grf_uoc2_base->CON0 = ((0xf<<6)<<16)|(0xf<<6);
 
        /* other haredware init
         * set common_on, in suspend mode, otg/host PLL blocks remain powered
-        * for RK3168 set *phy_con0 = (1<<16)|0;
-        * for Rk3188 set *phy_con1 = (1<<16)|0;
+        * for RK3168 set control_usb->grf_uoc0_base->CON0 = (1<<16)|0;
+        * for Rk3188 set control_usb->grf_uoc1_base->CON0 = (1<<16)|0;
         */
-       *phy_con1 = (1<<16)|0;
+       control_usb->grf_uoc1_base->CON0 = (1<<16)|0;
 
        /* change INCR to INCR16 or INCR8(beats less than 16)
         * or INCR4(beats less than 8) or SINGLE(beats less than 4)
         */
-       *phy_con3 = 0x00ff00bc;
+       control_usb->grf_uoc3_base->CON0 = 0x00ff00bc;
 }
 
-void rk_hsic_clock_init(void* pdata)
+static void rk_hsic_clock_init(void* pdata)
 {
        /* By default, hsicphy_480m's parent is otg phy 480MHz clk
         * rk3188 must use host phy 480MHz clk, because if otg bypass
@@ -360,7 +346,7 @@ void rk_hsic_clock_init(void* pdata)
        usbpdata->hsic_phy_12m = phyclk12m_hsic;
 }
 
-void rk_hsic_clock_enable(void* pdata, int enable)
+static void rk_hsic_clock_enable(void* pdata, int enable)
 {
        struct rkehci_platform_data *usbpdata=pdata;
 
@@ -379,12 +365,12 @@ void rk_hsic_clock_enable(void* pdata, int enable)
        }
 }
 
-void rk_hsic_soft_reset(void)
+static void rk_hsic_soft_reset(void)
 {
 
 }
 
-struct rkehci_platform_data rkhsic_pdata = {
+struct rkehci_platform_data rkhsic_pdata_rk3188 = {
        .hclk_hsic = NULL,
        .hsic_phy_12m = NULL,
        .hsic_phy_480m = NULL,
@@ -409,13 +395,8 @@ inline static void do_wakeup(struct work_struct *work)
 /********** handler for bvalid irq **********/
 static irqreturn_t bvalid_irq_handler(int irq, void *dev_id)
 {
-       unsigned int * phy_con0;
-
        /* clear irq */
-       if( usb_get_chip_id() == RK3188_USB_CTLR){
-               phy_con0 = (control_usb->grf_uoc0_base + 0xc);
-               *phy_con0 = (1 << 31) | (1 << 15);
-       }
+       control_usb->grf_uoc0_base->CON3 = (1 << 31) | (1 << 15);
 
 #ifdef CONFIG_RK_USB_UART
        /* usb otg dp/dm switch to usb phy */
@@ -430,28 +411,11 @@ static irqreturn_t bvalid_irq_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/********** handler for otg id rise and fall edge **********/
-static irqreturn_t id_irq_handler(int irq, void *dev_id)
-{
-       /* clear irq */
-       if( usb_get_chip_id() == RK3288_USB_CTLR){
-
-       }
-
-#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
-       wake_lock_timeout(&control_usb->usb_wakelock, WAKE_LOCK_TIMEOUT);
-       schedule_delayed_work(&control_usb->usb_det_wakeup_work, HZ/10);
-#endif
-
-       return IRQ_HANDLED;
-}
-
-/************* register bvalid and otg_id irq **************/
+/************* register bvalid irq **************/
 static int otg_irq_detect_init(struct platform_device *pdev)
 {
        int ret = 0;
        int irq = 0;
-       unsigned int * phy_con0;
 
 #ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
        wake_lock_init(&control_usb->usb_wakelock, WAKE_LOCK_SUSPEND, "usb_detect");
@@ -467,29 +431,7 @@ static int otg_irq_detect_init(struct platform_device *pdev)
                }
 
                /* clear & enable bvalid irq */
-               if( usb_get_chip_id() == RK3188_USB_CTLR){
-                       phy_con0 = (control_usb->grf_uoc0_base + 0xc);
-                       *phy_con0 = (3 << 30) | (3 << 14);
-               }
-
-#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
-               enable_irq_wake(irq);
-#endif
-       }
-
-       irq = platform_get_irq_byname(pdev, "otg_id");
-       if (irq > 0) {
-               ret = request_irq(irq, id_irq_handler, 0, "otg_id", NULL);
-               if(ret < 0){
-                       dev_err(&pdev->dev, "request_irq %d failed!\n", irq);
-                       return ret;
-               }
-
-               /* clear & enable otg_id change irq */
-               /* for rk3026 & rk3288 enable and clear id_fall_irq & id_rise_irq*/
-               if( usb_get_chip_id() == RK3288_USB_CTLR){
-
-               }
+               control_usb->grf_uoc0_base->CON3 = (3 << 30) | (3 << 14);
 
 #ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
                enable_irq_wake(irq);
@@ -503,71 +445,65 @@ static int usb_grf_ioremap(struct platform_device *pdev)
 {
        int ret = 0;
        struct resource *res;
+       void *grf_soc_status0;
+       void *grf_uoc0_base;
+       void *grf_uoc1_base;
+       void *grf_uoc2_base;
+       void *grf_uoc3_base;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                "GRF_SOC_STATUS0");
-       control_usb->grf_soc_status0 = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(control_usb->grf_soc_status0)){
-               ret = PTR_ERR(control_usb->grf_soc_status0);
+       grf_soc_status0 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_soc_status0)){
+               ret = PTR_ERR(grf_soc_status0);
                return ret;
        }
+       control_usb->grf_soc_status0_rk3188 = (pGRF_SOC_STATUS_RK3188)grf_soc_status0;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                "GRF_UOC0_BASE");
-       control_usb->grf_uoc0_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(control_usb->grf_uoc0_base)){
-               ret = PTR_ERR(control_usb->grf_uoc0_base);
+       grf_uoc0_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_uoc0_base)){
+               ret = PTR_ERR(grf_uoc0_base);
                return ret;
        }
+       control_usb->grf_uoc0_base = (pGRF_UOC0_REG)grf_uoc0_base;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                "GRF_UOC1_BASE");
-       control_usb->grf_uoc1_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(control_usb->grf_uoc1_base)){
-               ret = PTR_ERR(control_usb->grf_uoc1_base);
+       grf_uoc1_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_uoc1_base)){
+               ret = PTR_ERR(grf_uoc1_base);
                return ret;
        }
+       control_usb->grf_uoc1_base = (pGRF_UOC1_REG)grf_uoc1_base;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                "GRF_UOC2_BASE");
-       control_usb->grf_uoc2_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(control_usb->grf_uoc2_base)){
-               ret = PTR_ERR(control_usb->grf_uoc2_base);
+       grf_uoc2_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_uoc2_base)){
+               ret = PTR_ERR(grf_uoc2_base);
                return ret;
        }
+       control_usb->grf_uoc2_base = (pGRF_UOC2_REG)grf_uoc2_base;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                "GRF_UOC3_BASE");
-       control_usb->grf_uoc3_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(control_usb->grf_uoc3_base)){
-               ret = PTR_ERR(control_usb->grf_uoc3_base);
+       grf_uoc3_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_uoc3_base)){
+               ret = PTR_ERR(grf_uoc3_base);
                return ret;
        }
+       control_usb->grf_uoc3_base = (pGRF_UOC3_REG)grf_uoc3_base;
 
        return ret;
 }
 
 #ifdef CONFIG_OF
-static struct platform_device_id rk_usb_devtype[] = {
-       {
-               .name = "rk3188-usb",
-               .driver_data = RK3188_USB_CTLR,
-       },
-       {
-               .name = "rk3288-usb",
-               .driver_data = RK3288_USB_CTLR,
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(platform, rk_usb_devtype);
 
 static const struct of_device_id dwc_otg_control_usb_id_table[] = {
-       {       .compatible = "rockchip,rk3188-dwc-control-usb",
-               .data = &rk_usb_devtype[RK3188_USB_CTLR],
-       },
        {
-               .compatible = "rockchip,rk3288-dwc-control-usb",
-               .data = &rk_usb_devtype[RK3288_USB_CTLR],
+               .compatible = "rockchip,rk3188-dwc-control-usb",
        },
        { },
 };
@@ -580,15 +516,6 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct clk* hclk_usb_peri;
        int ret = 0;
-       const struct of_device_id *match =
-               of_match_device(of_match_ptr(dwc_otg_control_usb_id_table), &pdev->dev);
-
-       if (match)
-               pdev->id_entry = match->data;
-       else{
-               ret = -EINVAL;
-               goto err1;
-       }
 
        control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),GFP_KERNEL);
        if (!control_usb) {
@@ -597,7 +524,7 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
                goto err1;
        }
 
-       control_usb->chip_id = pdev->id_entry->driver_data;
+       control_usb->chip_id = RK3188_USB_CTLR;
 
        hclk_usb_peri = devm_clk_get(&pdev->dev, "hclk_usb_peri");
        if (IS_ERR(hclk_usb_peri)) {
@@ -605,6 +532,7 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
                ret = -EINVAL;
                goto err1;
        }
+
        control_usb->hclk_usb_peri = hclk_usb_peri;
        clk_prepare_enable(hclk_usb_peri);
 
@@ -672,11 +600,10 @@ static struct platform_driver dwc_otg_control_usb_driver = {
        .probe          = dwc_otg_control_usb_probe,
        .remove         = dwc_otg_control_usb_remove,
        .driver         = {
-               .name   = "dwc-control-usb",
+               .name   = "rk3188-dwc-control-usb",
                .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(dwc_otg_control_usb_id_table),
        },
-       .id_table       = rk_usb_devtype,
 };
 
 static int __init dwc_otg_control_usb_init(void)
diff --git a/drivers/usb/dwc_otg_310/usbdev_rk32.c b/drivers/usb/dwc_otg_310/usbdev_rk32.c
new file mode 100644 (file)
index 0000000..6100b4e
--- /dev/null
@@ -0,0 +1,737 @@
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/gpio.h>
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include "usbdev_grf_regs.h"
+#include "usbdev_rk.h"
+#include "dwc_otg_regs.h"
+static struct dwc_otg_control_usb *control_usb;
+
+static int usb_get_chip_id(void)
+{
+       return control_usb->chip_id;
+}
+
+#ifdef CONFIG_USB20_OTG
+static void usb20otg_hw_init(void)
+{
+#ifndef CONFIG_USB20_HOST
+       //enable soft control
+       control_usb->grf_uoc2_base->CON2 = (0x01<<2)|((0x01<<2)<<16);   
+       // enter suspend
+       control_usb->grf_uoc2_base->CON3 = 0x2A|(0x3F<<16);     
+#endif
+       /* usb phy config init
+        * usb phy enter usb mode */
+       control_usb->grf_uoc0_base->CON3 = (0x00c0 << 16);
+
+       /* other haredware init,include:
+        * DRV_VBUS GPIO init */
+//     gpio_direction_output(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
+               control_usb->grf_uoc0_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
+               //enter suspend
+               control_usb->grf_uoc0_base->CON3 = 0x2A|(0x3F<<16);
+               usbpdata->phy_status = 1;
+       }else{
+               // exit suspend.
+               control_usb->grf_uoc0_base->CON2 = ((0x01<<2)<<16);
+               usbpdata->phy_status = 0;
+       }
+}
+
+static void usb20otg_soft_reset(void)
+{
+}
+
+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_otg0");
+       if (IS_ERR(ahbclk)) {
+               dev_err(usbpdata->dev, "Failed to get hclk_otg0\n");
+               return;
+       }
+
+       phyclk = devm_clk_get(usbpdata->dev, "otgphy0");
+       if (IS_ERR(phyclk)) {
+               dev_err(usbpdata->dev, "Failed to get otgphy0\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;
+
+       switch(id){
+               case USB_STATUS_BVABLID:
+                       // bvalid in grf
+                       ret = control_usb->grf_soc_status2_rk3288->otg_bvalid;
+                       break;
+               case USB_STATUS_DPDM:
+                       // dpdm in grf
+                       ret = control_usb->grf_soc_status2_rk3288->otg_linestate;
+                       break;
+               case USB_STATUS_ID:
+                       // id in grf
+                       ret = control_usb->grf_soc_status2_rk3288->otg_iddig;
+                       break;
+               default:
+                       break;
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_RK_USB_UART
+static void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)
+{
+       if(1 == enter_usb_uart_mode){
+               /* bypass dm, enter uart mode*/
+               control_usb->grf_uoc0_base->CON3 = (0x00c0 | (0x00c0 << 16));
+       
+       }else if(0 == enter_usb_uart_mode){
+               /* enter usb mode */
+               control_usb->grf_uoc0_base->CON3 = (0x00c0 << 16);
+       }
+}
+#endif
+
+static void usb20otg_power_enable(int enable)
+{      /*
+       if(0 == enable){//disable otg_drv power
+               gpio_set_value(control_usb->otg_gpios->gpio, 0);
+       }else if(1 == enable){//enable otg_drv power
+               gpio_set_value(control_usb->otg_gpios->gpio, 1);
+       }*/
+}
+
+
+struct dwc_otg_platform_data usb20otg_pdata_rk3288 = {
+       .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,
+       .get_chip_id = usb_get_chip_id,
+       
+       .power_enable = usb20otg_power_enable,
+#ifdef CONFIG_RK_USB_UART
+       .dwc_otg_uart_mode = dwc_otg_uart_mode,
+#endif
+};
+
+#endif
+
+#ifdef CONFIG_USB20_HOST
+
+static void usb20host_hw_init(void)
+{
+       /* usb phy config init */
+
+       /* other haredware init,include:
+        * DRV_VBUS GPIO init */
+//     gpio_direction_output(control_usb->host_gpios->gpio, 1);
+}
+
+static void usb20host_phy_suspend(void* pdata, int suspend)
+{
+       struct dwc_otg_platform_data *usbpdata=pdata;
+
+       if(suspend){
+               // enable soft control
+               control_usb->grf_uoc2_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
+               // enter suspend
+               control_usb->grf_uoc2_base->CON3 = 0x2A|(0x3F<<16); 
+               usbpdata->phy_status = 1;
+       }else{
+               //exit suspend.
+               control_usb->grf_uoc2_base->CON2 = ((0x01<<2)<<16);
+               usbpdata->phy_status = 0;
+       }
+}
+
+static void usb20host_soft_reset(void)
+{
+}
+
+static void usb20host_clock_init(void* pdata)
+{
+       /*
+       struct dwc_otg_platform_data *usbpdata=pdata;
+       struct clk* ahbclk,*phyclk;
+
+       ahbclk = devm_clk_get(usbpdata->dev, "hclk_otg1");
+       if (IS_ERR(ahbclk)) {
+               dev_err(usbpdata->dev, "Failed to get hclk_otg1\n");
+               return;
+       }
+
+       phyclk = devm_clk_get(usbpdata->dev, "otgphy1");
+       if (IS_ERR(phyclk)) {
+               dev_err(usbpdata->dev, "Failed to get otgphy1\n");
+               return;
+       }
+
+       usbpdata->phyclk = phyclk;
+       usbpdata->ahbclk = ahbclk;
+       */
+}
+
+static void usb20host_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 usb20host_get_status(int id)
+{
+       int ret = -1;
+
+       switch(id){
+               case USB_STATUS_BVABLID:
+                       // bvalid in grf
+                       ret = control_usb->grf_soc_status2_rk3288->host1_bvalid;        
+                       break;
+               case USB_STATUS_DPDM:
+                       // dpdm in grf
+                       ret = control_usb->grf_soc_status2_rk3288->host1_linestate;
+                       break;
+               case USB_STATUS_ID:
+                       // id in grf
+                       ret = control_usb->grf_soc_status2_rk3288->host1_iddig;
+                       break;
+               default:
+                       break;
+       }
+
+       return ret;
+}
+
+static void usb20host_power_enable(int enable)
+{      /*
+       if(0 == enable){//disable host_drv power
+               //do not disable power in default
+       }else if(1 == enable){//enable host_drv power
+               gpio_set_value(control_usb->host_gpios->gpio, 1);
+       }*/
+}
+
+
+struct dwc_otg_platform_data usb20host_pdata_rk3288 = {
+       .phyclk = NULL,
+       .ahbclk = NULL,
+       .busclk = NULL,
+       .phy_status = 0,
+       .hw_init = usb20host_hw_init,
+       .phy_suspend = usb20host_phy_suspend,
+       .soft_reset = usb20host_soft_reset,
+       .clock_init = usb20host_clock_init,
+       .clock_enable = usb20host_clock_enable,
+       .get_status = usb20host_get_status,
+       .get_chip_id = usb_get_chip_id,
+       .power_enable = usb20host_power_enable,
+};
+
+#endif
+
+#ifdef CONFIG_USB_EHCI_RKHSIC
+static void rk_hsic_hw_init(void)
+{
+       // usb phy config init
+       // hsic phy config init, set hsicphy_txsrtune
+       control_usb->grf_uoc3_base->CON0 = ((0xf<<6)<<16)|(0xf<<6);
+
+       /* other haredware init
+        * set common_on, in suspend mode, otg/host PLL blocks remain powered
+        */
+
+
+       /* change INCR to INCR16 or INCR8(beats less than 16)
+        * or INCR4(beats less than 8) or SINGLE(beats less than 4)
+        */
+       control_usb->grf_uoc4_base->CON0 = 0x00ff00bc;
+}
+
+static void rk_hsic_clock_init(void* pdata)
+{
+       /* By default, hsicphy_480m's parent is otg phy 480MHz clk
+        * rk3188 must use host phy 480MHz clk, because if otg bypass
+        * to uart mode, otg phy 480MHz clk will be closed automatically
+        */
+       /*
+       struct rkehci_platform_data *usbpdata=pdata;
+       struct clk *ahbclk, *phyclk480m_hsic, *phyclk12m_hsic, *phyclk_otgphy1;
+
+       phyclk480m_hsic = devm_clk_get(usbpdata->dev, "hsicphy480m");
+       if (IS_ERR(phyclk480m_hsic)) {
+               dev_err(usbpdata->dev, "Failed to get hsicphy480m\n");
+               return;
+       }
+
+       phyclk12m_hsic = devm_clk_get(usbpdata->dev, "hsicphy12m");
+       if (IS_ERR(phyclk12m_hsic)) {
+               dev_err(usbpdata->dev, "Failed to get hsicphy12m\n");
+               return;
+       }
+
+       phyclk_otgphy1 = devm_clk_get(usbpdata->dev, "hsic_otgphy1");
+       if (IS_ERR(phyclk_otgphy1)) {
+               dev_err(usbpdata->dev, "Failed to get hsic_otgphy1\n");
+               return;
+       }
+
+       ahbclk = devm_clk_get(usbpdata->dev, "hclk_hsic");
+       if (IS_ERR(ahbclk)) {
+               dev_err(usbpdata->dev, "Failed to get hclk_hsic\n");
+               return;
+       }
+
+       clk_set_parent(phyclk480m_hsic, phyclk_otgphy1);
+       
+       usbpdata->hclk_hsic = ahbclk;
+       usbpdata->hsic_phy_480m = phyclk480m_hsic;
+       usbpdata->hsic_phy_12m = phyclk12m_hsic;
+       */
+}
+
+static void rk_hsic_clock_enable(void* pdata, int enable)
+{
+       /*
+       struct rkehci_platform_data *usbpdata=pdata;
+
+       if(enable == usbpdata->clk_status)
+               return;
+       if(enable){
+               clk_prepare_enable(usbpdata->hclk_hsic);
+               clk_prepare_enable(usbpdata->hsic_phy_480m);
+               clk_prepare_enable(usbpdata->hsic_phy_12m);
+               usbpdata->clk_status = 1;
+       }else{
+               clk_disable_unprepare(usbpdata->hclk_hsic);
+               clk_disable_unprepare(usbpdata->hsic_phy_480m);
+               clk_disable_unprepare(usbpdata->hsic_phy_12m);
+               usbpdata->clk_status = 0;
+       }
+       */
+}
+
+static void rk_hsic_soft_reset(void)
+{
+}
+
+struct rkehci_platform_data rkhsic_pdata_rk3288 = {
+       .hclk_hsic = NULL,
+       .hsic_phy_12m = NULL,
+       .hsic_phy_480m = NULL,
+       .clk_status = -1,
+       .hw_init = rk_hsic_hw_init,
+       .clock_init = rk_hsic_clock_init,
+       .clock_enable = rk_hsic_clock_enable,
+       .soft_reset = rk_hsic_soft_reset,
+       .get_chip_id = usb_get_chip_id,
+};
+#endif
+
+#ifdef CONFIG_USB_EHCI_RK
+static void rk_ehci_hw_init(void)
+{
+
+}
+
+static void rk_ehci_clock_init(void* pdata)
+{
+
+}
+
+static void rk_ehci_clock_enable(void* pdata, int enable)
+{
+
+}
+
+static void rk_ehci_soft_reset(void)
+{
+
+}
+
+struct rkehci_platform_data rkehci_pdata_rk3288 = {
+       .phyclk = NULL,
+       .ahbclk = NULL,
+       .clk_status = -1,
+       .hw_init = rk_ehci_hw_init,
+       .clock_init = rk_ehci_clock_init,
+       .clock_enable = rk_ehci_clock_enable,
+       .soft_reset = rk_ehci_soft_reset,
+       .get_chip_id = usb_get_chip_id,
+};
+#endif
+
+#ifdef CONFIG_USB_OHCI_HCD_RK
+static void rk_ohci_hw_init(void)
+{
+}
+
+static void rk_ohci_clock_init(void* pdata)
+{
+}
+
+static void rk_ohci_clock_enable(void* pdata, int enable)
+{
+}
+
+static void rk_ohci_soft_reset(void)
+{
+}
+
+struct rkehci_platform_data rkohci_pdata_rk3288 = {
+       .phyclk = NULL,
+       .ahbclk = NULL,
+       .clk_status = -1,
+       .hw_init = rk_ohci_hw_init,
+       .clock_init = rk_ohci_clock_init,
+       .clock_enable = rk_ohci_clock_enable,
+       .soft_reset = rk_ohci_soft_reset,
+       .get_chip_id = usb_get_chip_id,
+};
+#endif
+
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+#define WAKE_LOCK_TIMEOUT (HZ * 10)
+inline static void do_wakeup(struct work_struct *work)
+{
+//      rk28_send_wakeup_key();
+}
+#endif
+
+/********** handler for bvalid irq **********/
+static irqreturn_t bvalid_irq_handler(int irq, void *dev_id)
+{
+       /* clear irq */
+       control_usb->grf_uoc0_base->CON4 = (0x0008 | (0x0008 << 16));
+
+#ifdef CONFIG_RK_USB_UART
+       /* usb otg dp/dm switch to usb phy */
+       dwc_otg_uart_mode(NULL, PHY_USB_MODE);
+#endif
+
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+       wake_lock_timeout(&control_usb->usb_wakelock, WAKE_LOCK_TIMEOUT);
+       schedule_delayed_work(&control_usb->usb_det_wakeup_work, HZ/10);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+/************* register usb irq **************/
+static int otg_irq_detect_init(struct platform_device *pdev)
+{
+       int ret = 0;
+       int irq = 0;
+
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+       wake_lock_init(&control_usb->usb_wakelock, WAKE_LOCK_SUSPEND, "usb_detect");
+       INIT_DELAYED_WORK(&control_usb->usb_det_wakeup_work, do_wakeup);
+#endif
+
+       irq = platform_get_irq_byname(pdev, "bvalid");
+       if (irq > 0) {
+               ret = request_irq(irq, bvalid_irq_handler, 0, "bvalid", NULL);
+               if(ret < 0){
+                       dev_err(&pdev->dev, "request_irq %d failed!\n", irq);
+                       return ret;
+               }
+
+               /* clear & enable bvalid irq */
+               control_usb->grf_uoc0_base->CON4 = (0x000c | (0x000c << 16));
+
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+               enable_irq_wake(irq);
+#endif
+       }
+
+
+       return ret;
+}
+
+static int usb_grf_ioremap(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct resource *res;
+       void *grf_soc_status1;
+       void *grf_soc_status2;
+       void *grf_soc_status19;
+       void *grf_soc_status21;
+       void *grf_uoc0_base;
+       void *grf_uoc1_base;
+       void *grf_uoc2_base;
+       void *grf_uoc3_base;
+       void *grf_uoc4_base;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_SOC_STATUS1");
+       grf_soc_status1 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_soc_status1)){
+               ret = PTR_ERR(grf_soc_status1);
+               return ret;
+       }
+       control_usb->grf_soc_status1_rk3288 = (pGRF_SOC_STATUS1_RK3288)grf_soc_status1;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_SOC_STATUS2");
+       grf_soc_status2 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_soc_status2)){
+               ret = PTR_ERR(grf_soc_status2);
+               return ret;
+       }
+       control_usb->grf_soc_status2_rk3288 = (pGRF_SOC_STATUS2_RK3288)grf_soc_status2;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_SOC_STATUS19");
+       grf_soc_status19 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_soc_status19)){
+               ret = PTR_ERR(grf_soc_status19);
+               return ret;
+       }
+       control_usb->grf_soc_status19_rk3288 = (pGRF_SOC_STATUS19_RK3288)grf_soc_status19;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_SOC_STATUS21");
+       grf_soc_status21 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_soc_status21)){
+               ret = PTR_ERR(grf_soc_status21);
+               return ret;
+       }
+       control_usb->grf_soc_status21_rk3288 = (pGRF_SOC_STATUS21_RK3288)grf_soc_status21;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_UOC0_BASE");
+       grf_uoc0_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_uoc0_base)){
+               ret = PTR_ERR(grf_uoc0_base);
+               return ret;
+       }
+       control_usb->grf_uoc0_base = (pGRF_UOC0_REG)grf_uoc0_base;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_UOC1_BASE");
+       grf_uoc1_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_uoc1_base)){
+               ret = PTR_ERR(grf_uoc1_base);
+               return ret;
+       }
+       control_usb->grf_uoc1_base = (pGRF_UOC1_REG)grf_uoc1_base;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_UOC2_BASE");
+       grf_uoc2_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_uoc2_base)){
+               ret = PTR_ERR(grf_uoc2_base);
+               return ret;
+       }
+       control_usb->grf_uoc2_base = (pGRF_UOC2_REG)grf_uoc2_base;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_UOC3_BASE");
+       grf_uoc3_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_uoc3_base)){
+               ret = PTR_ERR(grf_uoc3_base);
+               return ret;
+       }
+       control_usb->grf_uoc3_base = (pGRF_UOC3_REG)grf_uoc3_base;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_UOC4_BASE");
+       grf_uoc4_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(grf_uoc4_base)){
+               ret = PTR_ERR(grf_uoc4_base);
+               return ret;
+       }
+       control_usb->grf_uoc4_base = (pGRF_UOC4_REG)grf_uoc4_base;
+
+       return ret;
+}
+
+#ifdef CONFIG_OF
+
+static const struct of_device_id dwc_otg_control_usb_id_table[] = {
+       {
+               .compatible = "rockchip,rk3288-dwc-control-usb",
+       },
+       { },
+};
+
+#endif
+
+static int dwc_otg_control_usb_probe(struct platform_device *pdev)
+{
+       int gpio, err;
+       struct device_node *np = pdev->dev.of_node;
+//     struct clk* hclk_usb_peri;
+       int ret = 0;
+
+       control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),GFP_KERNEL);
+       if (!control_usb) {
+               dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+               ret =  -ENOMEM;
+               goto err1;
+       }
+
+       control_usb->chip_id = RK3288_USB_CTLR;
+/*     disable for debug
+       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");
+               ret = -EINVAL;
+               goto err1;
+       }
+
+       control_usb->hclk_usb_peri = hclk_usb_peri;
+       clk_prepare_enable(hclk_usb_peri);
+*/
+       ret = usb_grf_ioremap(pdev);
+       if(ret){
+               dev_err(&pdev->dev, "Failed to ioremap usb grf\n");
+               goto err2;
+       }
+/*
+       control_usb->host_gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
+
+       gpio =  of_get_named_gpio(np, "gpios", 0);
+       if(!gpio_is_valid(gpio)){
+               dev_err(&pdev->dev, "invalid host gpio%d\n", gpio);
+               ret = -EINVAL;
+               goto err2;
+       }
+       control_usb->host_gpios->gpio = gpio;
+       err = devm_gpio_request(&pdev->dev, gpio, "host_drv_gpio");
+       if (err) {
+               dev_err(&pdev->dev,
+                       "failed to request GPIO%d for host_drv\n",
+                       gpio);
+               ret = err;
+               goto err2;
+       }
+
+       control_usb->otg_gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
+
+       gpio =  of_get_named_gpio(np, "gpios", 1);
+       if(!gpio_is_valid(gpio)){
+               dev_err(&pdev->dev, "invalid otg gpio%d\n", gpio);
+               ret = -EINVAL;
+               goto err2;
+       }
+       control_usb->otg_gpios->gpio = gpio;
+       err = devm_gpio_request(&pdev->dev, gpio, "otg_drv_gpio");
+       if (err) {
+               dev_err(&pdev->dev,
+                       "failed to request GPIO%d for otg_drv\n",
+                       gpio);
+               ret = err;
+               goto err2;
+       }
+*/
+#if 0 //disable for debug
+       ret = otg_irq_detect_init(pdev);
+       if (ret < 0)
+               goto err2;
+#endif
+       return 0;
+
+err2:
+//     disable for debug
+//     clk_disable_unprepare(hclk_usb_peri);
+err1:
+       return ret;
+}
+
+static int dwc_otg_control_usb_remove(struct platform_device *pdev)
+{
+//     disable for debug
+//     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   = "rk3288-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)
+{
+       return platform_driver_register(&dwc_otg_control_usb_driver);
+}
+
+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 f70e0f0af0b3ccb3195161ea9d73fcc0137df523..8aa99da0d2393eae47d7543aaa7a67bd8886c0c0 100644 (file)
@@ -102,6 +102,7 @@ if USB_EHCI_HCD
 
 config USB_EHCI_RKHSIC
        tristate "Rockchip EHCI HSIC support"
+       depends on ARCH_ROCKCHIP
        select USB_EHCI_ROOT_HUB_TT
        default n
        ---help---
@@ -109,6 +110,7 @@ config USB_EHCI_RKHSIC
 
 config USB_EHCI_RK
        tristate "Rockchip EHCI HOST20 support"
+       depends on ARCH_ROCKCHIP
        select USB_EHCI_ROOT_HUB_TT
        default n
        ---help---
@@ -379,6 +381,13 @@ config USB_OHCI_HCD
 
 if USB_OHCI_HCD
 
+config USB_OHCI_HCD_RK
+       bool "OHCI support for RK3288 and later chips"
+       depends on ARCH_ROCKCHIP
+       default n
+       ---help---
+         Enable support for the OHCI controller on RK3288 and later chips.
+
 config USB_OHCI_HCD_OMAP1
        bool "OHCI support for OMAP1/2 chips"
        depends on ARCH_OMAP1
index a17d73217e6547906c30fa012263b63c8735b9c0..16068290a74f4a221cff76d0d9cc59803cb8705a 100644 (file)
@@ -1268,7 +1268,7 @@ MODULE_LICENSE ("GPL");
 
 #ifdef CONFIG_USB_EHCI_RKHSIC
 #include "ehci-rkhsic.c"
-#define PLATFORM_DRIVER         ehci_rkhsic_driver
+#define RK_PLATFORM_DRIVER         ehci_rkhsic_driver
 #endif
 
 #ifdef CONFIG_USB_EHCI_HCD_PMC_MSP
@@ -1346,8 +1346,19 @@ static int __init ehci_hcd_init(void)
        if (retval < 0)
                goto clean4;
 #endif
+
+#ifdef RK_PLATFORM_DRIVER
+       retval = platform_driver_register(&RK_PLATFORM_DRIVER);
+       if (retval < 0)
+               goto clean5;
+#endif
        return retval;
 
+#ifdef RK_PLATFORM_DRIVER
+       platform_driver_unregister(&RK_PLATFORM_DRIVER);
+clean5:
+#endif
+
 #ifdef XILINX_OF_PLATFORM_DRIVER
        /* platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER); */
 clean4:
@@ -1376,6 +1387,9 @@ module_init(ehci_hcd_init);
 
 static void __exit ehci_hcd_cleanup(void)
 {
+#ifdef RK_PLATFORM_DRIVER
+       platform_driver_unregister(&RK_PLATFORM_DRIVER);
+#endif
 #ifdef XILINX_OF_PLATFORM_DRIVER
        platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER);
 #endif
index 9b6fae73c0c192318162ddab17c83c3355a3354d..9bab80435673da9ea9500286f9790f103e0639b6 100755 (executable)
 #endif
 
 static int rkehci_status = 1;
+static struct ehci_hcd *g_ehci;
+#define EHCI_PRINT(x...)   printk( KERN_INFO "EHCI: " x )
+
+static struct rkehci_pdata_id rkehci_pdata[] = {
+       {
+               .name = "rk3188-reserved",
+               .pdata = NULL,
+       },
+       {
+               .name = "rk3288-ehci",
+               .pdata = &rkehci_pdata_rk3288,
+       },
+       { },
+};
+
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
 {
+       unsigned port;
+
+       if (!HCS_PPC (ehci->hcs_params))
+               return;
 
+       ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down");
+       for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
+               (void) ehci_hub_control(ehci_to_hcd(ehci),
+                               is_on ? SetPortFeature : ClearPortFeature,
+                               USB_PORT_FEAT_POWER,
+                               port--, NULL, 0);
+       /* Flush those writes */
+       ehci_readl(ehci, &ehci->regs->command);
+       msleep(20);
 }
 
-static struct hc_driver rk_hc_driver = {
+static struct hc_driver rk_ehci_hc_driver = {
        .description            = hcd_name,
        .product_desc           = "Rockchip On-Chip EHCI Host Controller",
        .hcd_priv_size          = sizeof(struct ehci_hcd),
@@ -91,19 +119,191 @@ static ssize_t ehci_power_store( struct device *_dev,
                                        struct device_attribute *attr,
                                        const char *buf, size_t count )
 {
+       uint32_t val = simple_strtoul(buf, NULL, 16);
+       struct usb_hcd *hcd = dev_get_drvdata(_dev);
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       struct rkehci_platform_data *pldata = _dev->platform_data;
+
+       printk("%s: %d setting to: %d\n", __func__, rkehci_status, val);
+       if(val == rkehci_status)
+               goto out;
+
+       rkehci_status = val;
+       switch(val){
+               case 0: //power down
+                       ehci_port_power(ehci, 0);
+                       msleep(5);
+                       usb_remove_hcd(hcd);
+                       break;
+               case 1:// power on
+                       pldata->soft_reset();
+                       usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
+                       ehci_port_power(ehci, 1);
+                       writel_relaxed(0x1d4d ,hcd->regs +0x90);
+                       writel_relaxed(0x4 ,hcd->regs +0xa0);
+                       dsb();
+                       break;
+               default:
+                       break;
+       }
+out:
        return count;
 }
 static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store);
 static ssize_t debug_show( struct device *_dev,
                                struct device_attribute *attr, char *buf)
 {
+       volatile uint32_t *addr;
+
+       EHCI_PRINT("******** EHCI Capability Registers **********\n");
+       addr = &g_ehci->caps->hc_capbase;
+       EHCI_PRINT("HCIVERSION / CAPLENGTH  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->caps->hcs_params;
+       EHCI_PRINT("HCSPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->caps->hcc_params;
+       EHCI_PRINT("HCCPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       EHCI_PRINT("********* EHCI Operational Registers *********\n");
+       addr = &g_ehci->regs->command;
+       EHCI_PRINT("USBCMD                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->status;
+       EHCI_PRINT("USBSTS                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->intr_enable;
+       EHCI_PRINT("USBINTR                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->frame_index;
+       EHCI_PRINT("FRINDEX                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->segment;
+       EHCI_PRINT("CTRLDSSEGMENT           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->frame_list;
+       EHCI_PRINT("PERIODICLISTBASE        @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); 
+       addr = &g_ehci->regs->async_next;
+       EHCI_PRINT("ASYNCLISTADDR           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->configured_flag;
+       EHCI_PRINT("CONFIGFLAG              @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = g_ehci->regs->port_status;
+       EHCI_PRINT("PORTSC                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
        return sprintf(buf, "EHCI Registers Dump\n");
 }
 static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL);
+
+static struct of_device_id rk_ehci_of_match[] = {
+       {
+               .compatible = "rockchip,rk3288_rk_ehci_host",
+               .data = &rkehci_pdata[RK3288_USB_CTLR],
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, rk_ehci_of_match);
+
 static int ehci_rk_probe(struct platform_device *pdev)
 {
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       struct rkehci_platform_data *pldata;
+       int ret;
+       int retval = 0;
+       static u64 usb_dmamask = 0xffffffffUL;
+       struct device_node *node = pdev->dev.of_node;
+       struct rkehci_pdata_id *p;
+       const struct of_device_id *match =
+               of_match_device(of_match_ptr( rk_ehci_of_match ), &pdev->dev);
+
        dev_dbg(&pdev->dev, "ehci_rk proble\n");
+       
+       if (match){
+               p = (struct rkehci_pdata_id *)match->data;
+       }else{
+               dev_err(dev, "ehci_rk match failed\n");
+               return -EINVAL;
+       }
+
+       dev->platform_data = p->pdata;
+       pldata = dev->platform_data;
+       pldata->dev = dev;
+
+       if (!node) {
+               dev_err(dev, "device node not found\n");
+               return -EINVAL;
+       }
+
+       dev->dma_mask = &usb_dmamask;
+
+       retval = device_create_file(dev, &dev_attr_ehci_power);
+       retval = device_create_file(dev, &dev_attr_debug_ehci);
+       hcd = usb_create_hcd(&rk_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+       if (!hcd) {
+               dev_err(&pdev->dev, "Unable to create HCD\n");
+               return  -ENOMEM;
+       }
+
+       if(pldata->hw_init)
+               pldata->hw_init();
+
+       if(pldata->clock_init){
+               pldata->clock_init(pldata);
+               pldata->clock_enable(pldata, 1);
+       }
+
+       if(pldata->soft_reset)
+               pldata->soft_reset();
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get memory resource\n");
+               ret = -ENODEV;
+               goto put_hcd;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+       hcd->regs = devm_ioremap_resource(dev, res);
+
+       if (!hcd->regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto put_hcd;
+       }
+
+       hcd->irq = platform_get_irq(pdev, 0);
+       if (hcd->irq < 0) {
+               dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+               ret = hcd->irq;
+               goto put_hcd;
+       }
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs + 0x10;
+       printk("%s %p %p\n", __func__, ehci->caps, ehci->regs);
+
+       dbg_hcs_params(ehci, "reset");
+       dbg_hcc_params(ehci, "reset");
+
+       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+       ret = usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to add USB HCD\n");
+               goto put_hcd;
+       }
+
+       g_ehci = ehci;
+       ehci_port_power(ehci, 1);
+       writel_relaxed(0x1d4d ,hcd->regs +0x90);
+       writel_relaxed(0x4 ,hcd->regs +0xa0);
+       dsb();
+
+       printk("%s ok\n", __func__);
+
        return 0;
+put_hcd:
+       if(pldata->clock_enable)
+               pldata->clock_enable(pldata, 0);
+       usb_put_hcd(hcd);
+
+       return ret;
 }
 static int ehci_rk_remove(struct platform_device *pdev)
 {
@@ -156,13 +356,6 @@ static const struct dev_pm_ops ehci_rk_dev_pm_ops = {
        .resume          = ehci_rk_pm_resume,
 };
 
-static struct of_device_id rk_ehci_of_match[] = {
-       { .compatible = "rockchip,rk_ehci_host", },
-       { },
-};
-
-MODULE_DEVICE_TABLE(of, rk_ehci_of_match);
-
 static struct platform_driver ehci_rk_driver = {
        .probe  = ehci_rk_probe,
        .remove = ehci_rk_remove,
index 37e19e3e8ca62a61e1eea92be1ebbcfec541b1b0..7bfcade0fca1b61d9b9d820be7c2d0429ec8a477 100755 (executable)
 # include "../dwc_otg_310/usbdev_rk.h"
 #endif
 
-static int rkehci_status = 1;
-static struct ehci_hcd *g_ehci;
-#define EHCI_DEVICE_FILE        "/sys/devices/platform/rk_hsusb_host/ehci_power"
-#define EHCI_PRINT(x...)       printk( KERN_INFO "EHCI: " x )
-
-extern struct rkehci_platform_data rkhsic_pdata;
+static int rkhsic_status = 1;
+static struct ehci_hcd *g_hsic_ehci;
+#define HSIC_EHCI_PRINT(x...)  printk( KERN_INFO "HSIC_EHCI: " x )
+
+static struct rkehci_pdata_id rkhsic_pdata[] = {
+       {
+               .name = "rk3188-hsic",
+               .pdata = &rkhsic_pdata_rk3188,
+       },
+       {
+               .name = "rk3288-hsic",
+               .pdata = &rkhsic_pdata_rk3288,
+       },
+       { },
+};
 
-static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
+static void ehci_rkhsic_port_power (struct ehci_hcd *ehci, int is_on)
 {
        unsigned port;
 
@@ -61,9 +70,9 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
        msleep(20);
 }
 
-static struct hc_driver rk_hc_driver = {
+static struct hc_driver rk_hsic_driver = {
        .description            = hcd_name,
-       .product_desc           = "Rockchip On-Chip EHCI Host Controller",
+       .product_desc           = "Rockchip On-Chip HSIC EHCI Host Controller",
        .hcd_priv_size          = sizeof(struct ehci_hcd),
 
        /*
@@ -109,12 +118,12 @@ static struct hc_driver rk_hc_driver = {
 #endif
 };
 
-static ssize_t ehci_power_show( struct device *_dev, 
+static ssize_t ehci_rkhsic_power_show( struct device *_dev, 
                                struct device_attribute *attr, char *buf) 
 {
-       return sprintf(buf, "%d\n", rkehci_status);
+       return sprintf(buf, "%d\n", rkhsic_status);
 }
-static ssize_t ehci_power_store( struct device *_dev,
+static ssize_t ehci_rkhsic_power_store( struct device *_dev,
                                        struct device_attribute *attr, 
                                        const char *buf, size_t count ) 
 {
@@ -123,14 +132,14 @@ static ssize_t ehci_power_store( struct device *_dev,
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        struct rkehci_platform_data *pldata = _dev->platform_data;
 
-       printk("%s: %d setting to: %d\n", __func__, rkehci_status, val);
-       if(val == rkehci_status)
+       printk("%s: %d setting to: %d\n", __func__, rkhsic_status, val);
+       if(val == rkhsic_status)
                goto out;
        
-       rkehci_status = val;
+       rkhsic_status = val;
        switch(val){
                case 0: //power down
-                       ehci_port_power(ehci, 0);
+                       ehci_rkhsic_port_power(ehci, 0);
                        writel_relaxed(0 ,hcd->regs +0xb0);
                        dsb();
                        msleep(5);
@@ -140,7 +149,7 @@ static ssize_t ehci_power_store( struct device *_dev,
                        pldata->soft_reset();
                        usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
         
-                       ehci_port_power(ehci, 1);
+                       ehci_rkhsic_port_power(ehci, 1);
                        writel_relaxed(1 ,hcd->regs +0xb0);
                        writel_relaxed(0x1d4d ,hcd->regs +0x90);
                        writel_relaxed(0x4 ,hcd->regs +0xa0);
@@ -152,42 +161,56 @@ static ssize_t ehci_power_store( struct device *_dev,
 out:
        return count;
 }
-static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store);
+static DEVICE_ATTR(ehci_rkhsic_power, S_IRUGO|S_IWUSR, ehci_rkhsic_power_show, ehci_rkhsic_power_store);
 
-static ssize_t debug_show( struct device *_dev,
+static ssize_t hsic_debug_show( struct device *_dev,
                                struct device_attribute *attr, char *buf)
 {
        volatile uint32_t *addr;
 
-       EHCI_PRINT("******** EHCI Capability Registers **********\n");
-       addr = &g_ehci->caps->hc_capbase;
-       EHCI_PRINT("HCIVERSION / CAPLENGTH  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       addr = &g_ehci->caps->hcs_params;
-       EHCI_PRINT("HCSPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       addr = &g_ehci->caps->hcc_params;
-       EHCI_PRINT("HCCPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       EHCI_PRINT("********* EHCI Operational Registers *********\n");
-       addr = &g_ehci->regs->command;
-       EHCI_PRINT("USBCMD                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       addr = &g_ehci->regs->status;
-       EHCI_PRINT("USBSTS                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       addr = &g_ehci->regs->intr_enable;
-       EHCI_PRINT("USBINTR                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       addr = &g_ehci->regs->frame_index;
-       EHCI_PRINT("FRINDEX                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       addr = &g_ehci->regs->segment;
-       EHCI_PRINT("CTRLDSSEGMENT           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       addr = &g_ehci->regs->frame_list;
-       EHCI_PRINT("PERIODICLISTBASE        @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); 
-       addr = &g_ehci->regs->async_next;
-       EHCI_PRINT("ASYNCLISTADDR           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       addr = &g_ehci->regs->configured_flag;
-       EHCI_PRINT("CONFIGFLAG              @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       addr = g_ehci->regs->port_status;
-       EHCI_PRINT("PORTSC                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
-       return sprintf(buf, "EHCI Registers Dump\n");
+       HSIC_EHCI_PRINT("******** EHCI Capability Registers **********\n");
+       addr = &g_hsic_ehci->caps->hc_capbase;
+       HSIC_EHCI_PRINT("HCIVERSION / CAPLENGTH  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_hsic_ehci->caps->hcs_params;
+       HSIC_EHCI_PRINT("HCSPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_hsic_ehci->caps->hcc_params;
+       HSIC_EHCI_PRINT("HCCPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       HSIC_EHCI_PRINT("********* EHCI Operational Registers *********\n");
+       addr = &g_hsic_ehci->regs->command;
+       HSIC_EHCI_PRINT("USBCMD                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_hsic_ehci->regs->status;
+       HSIC_EHCI_PRINT("USBSTS                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_hsic_ehci->regs->intr_enable;
+       HSIC_EHCI_PRINT("USBINTR                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_hsic_ehci->regs->frame_index;
+       HSIC_EHCI_PRINT("FRINDEX                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_hsic_ehci->regs->segment;
+       HSIC_EHCI_PRINT("CTRLDSSEGMENT           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_hsic_ehci->regs->frame_list;
+       HSIC_EHCI_PRINT("PERIODICLISTBASE        @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); 
+       addr = &g_hsic_ehci->regs->async_next;
+       HSIC_EHCI_PRINT("ASYNCLISTADDR           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_hsic_ehci->regs->configured_flag;
+       HSIC_EHCI_PRINT("CONFIGFLAG              @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = g_hsic_ehci->regs->port_status;
+       HSIC_EHCI_PRINT("PORTSC                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       return sprintf(buf, "HSIC_EHCI Registers Dump\n");
 }
-static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL);
+static DEVICE_ATTR(hsic_debug_ehci, S_IRUGO, hsic_debug_show, NULL);
+
+static struct of_device_id rk_hsic_of_match[] = {
+       {
+               .compatible = "rockchip,rk3188_rk_hsic_host",
+               .data = &rkhsic_pdata[RK3188_USB_CTLR],
+       },
+       {
+               .compatible = "rockchip,rk3288_rk_hsic_host",
+               .data = &rkhsic_pdata[RK3288_USB_CTLR],
+       },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, rk_hsic_of_match);
 
 static int ehci_rkhsic_probe(struct platform_device *pdev)
 {
@@ -200,10 +223,20 @@ static int ehci_rkhsic_probe(struct platform_device *pdev)
        int retval = 0;
        static u64 usb_dmamask = 0xffffffffUL;
        struct device_node *node = pdev->dev.of_node;
+       struct rkehci_pdata_id *p;
+       const struct of_device_id *match =
+               of_match_device(of_match_ptr( rk_hsic_of_match ), &pdev->dev);
 
        dev_dbg(&pdev->dev, "ehci_rkhsic proble\n");
 
-       dev->platform_data = &rkhsic_pdata;
+       if (match){
+               p = (struct rkehci_pdata_id *)match->data;
+       }else{
+               dev_err(dev, "ehci_rkhsic match failed\n");
+               return -EINVAL;
+       }
+
+       dev->platform_data = p->pdata;
        pldata = dev->platform_data;
        pldata->dev = dev;
 
@@ -214,17 +247,24 @@ static int ehci_rkhsic_probe(struct platform_device *pdev)
 
        dev->dma_mask = &usb_dmamask;
 
-       retval = device_create_file(dev, &dev_attr_ehci_power);
-       retval = device_create_file(dev, &dev_attr_debug_ehci);
-       hcd = usb_create_hcd(&rk_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+       retval = device_create_file(dev, &dev_attr_ehci_rkhsic_power);
+       retval = device_create_file(dev, &dev_attr_hsic_debug_ehci);
+       hcd = usb_create_hcd(&rk_hsic_driver, &pdev->dev, dev_name(&pdev->dev));
        if (!hcd) {
                dev_err(&pdev->dev, "Unable to create HCD\n");
                return  -ENOMEM;
        }
+       
+       if(pldata->hw_init)
+               pldata->hw_init();
 
-       pldata->hw_init();
-       pldata->clock_init(pldata);
-       pldata->clock_enable(pldata, 1);
+       if(pldata->clock_init){
+               pldata->clock_init(pldata);
+               pldata->clock_enable(pldata, 1);
+       }
+       
+       if(pldata->soft_reset)
+               pldata->soft_reset();
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -263,11 +303,11 @@ static int ehci_rkhsic_probe(struct platform_device *pdev)
        ret = usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
        if (ret) {
                dev_err(&pdev->dev, "Failed to add USB HCD\n");
-               goto unmap;
+               goto put_hcd;
        }
        
-       g_ehci = ehci;
-       ehci_port_power(ehci, 1);
+       g_hsic_ehci = ehci;
+       ehci_rkhsic_port_power(ehci, 1);
        writel_relaxed(1 ,hcd->regs +0xb0);
        writel_relaxed(0x1d4d ,hcd->regs +0x90);
        writel_relaxed(0x4 ,hcd->regs +0xa0);
@@ -278,9 +318,9 @@ static int ehci_rkhsic_probe(struct platform_device *pdev)
 
        return 0;
 
-unmap:
-       iounmap(hcd->regs);
 put_hcd:
+       if(pldata->clock_enable)
+               pldata->clock_enable(pldata, 0);
        usb_put_hcd(hcd);
 
        return ret;
@@ -338,13 +378,6 @@ static const struct dev_pm_ops ehci_rkhsic_dev_pm_ops = {
        .resume          = ehci_rkhsic_pm_resume,
 };
 
-static struct of_device_id rk_hsic_of_match[] = {
-       { .compatible = "rockchip,rk_hsic_host", },
-       { },
-};
-
-MODULE_DEVICE_TABLE(of, rk_hsic_of_match);
-
 static struct platform_driver ehci_rkhsic_driver = {
        .probe  = ehci_rkhsic_probe,
        .remove = ehci_rkhsic_remove,
index 865946cde765b130845c07fea81124b6fe25b2f3..e0880a185cea575e76219ec15e78b9fa1c13698a 100644 (file)
@@ -1191,6 +1191,11 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ohci_hcd_tilegx_driver
 #endif
 
+#ifdef CONFIG_USB_OHCI_HCD_RK
+#include "ohci-rk.c"
+#define PLATFORM_DRIVER                ohci_hcd_rk_driver
+#endif
+
 #ifdef CONFIG_USB_OHCI_HCD_PLATFORM
 #include "ohci-platform.c"
 #define PLATFORM_DRIVER                ohci_platform_driver
diff --git a/drivers/usb/host/ohci-rk.c b/drivers/usb/host/ohci-rk.c
new file mode 100755 (executable)
index 0000000..3ca9151
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * ROCKCHIP USB HOST OHCI Controller
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_platform.h>
+#ifdef CONFIG_DWC_OTG_274
+# include "../dwc_otg/usbdev_rk.h"
+#endif
+#ifdef CONFIG_DWC_OTG_310
+# include "../dwc_otg_310/usbdev_rk.h"
+#endif
+
+static struct rkehci_pdata_id rkohci_pdata[] = {
+       {
+               .name = "rk3188-reserved",
+               .pdata = NULL,
+       },
+       {       
+               .name = "rk3288-ohci",
+               .pdata = &rkohci_pdata_rk3288,
+       },
+       { },
+};
+
+static int ohci_rk_init(struct usb_hcd *hcd)
+{
+       dev_dbg(hcd->self.controller, "starting OHCI controller\n");
+
+       return ohci_init(hcd_to_ohci(hcd));
+}
+
+static int ohci_rk_start(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+       int ret;
+
+       /*
+        * RemoteWakeupConnected has to be set explicitly before
+        * calling ohci_run. The reset value of RWC is 0.
+        */
+       ohci->hc_control = OHCI_CTRL_RWC;
+       writel(OHCI_CTRL_RWC, &ohci->regs->control);
+
+       ret = ohci_run(ohci);
+
+       if (ret < 0) {
+               dev_err(hcd->self.controller, "can't start\n");
+               ohci_stop(hcd);
+       }
+
+       return ret;
+}
+
+static const struct hc_driver ohci_rk_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "RK OHCI Host Controller",
+       .hcd_priv_size =        sizeof(struct ohci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_USB11 | HCD_MEMORY,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset =                ohci_rk_init,
+       .start =                ohci_rk_start,
+       .stop =                 ohci_stop,
+       .shutdown =             ohci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+#ifdef CONFIG_PM
+       .bus_suspend =          ohci_bus_suspend,
+       .bus_resume =           ohci_bus_resume,
+#endif
+       .start_port_reset =     ohci_start_port_reset,
+};
+
+static struct of_device_id rk_ohci_of_match[] = {
+       {
+               .compatible = "rockchip,rk3288_rk_ohci_host",
+               .data = &rkohci_pdata[RK3288_USB_CTLR],
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, rk_ohci_of_match);
+
+/* ohci_hcd_rk_probe - initialize RK-based HCDs
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+static int ohci_hcd_rk_probe(struct platform_device *pdev)
+{
+       struct device           *dev = &pdev->dev;
+       struct usb_hcd          *hcd = NULL;
+       void __iomem            *regs = NULL;
+       struct resource         *res;
+       int                     ret = -ENODEV;
+       int                     irq;
+       struct rkehci_platform_data *pldata;
+       struct device_node      *node = pdev->dev.of_node;
+       struct rkehci_pdata_id *p;
+       const struct of_device_id *match =
+               of_match_device(of_match_ptr( rk_ohci_of_match ), &pdev->dev);
+
+       dev_dbg(&pdev->dev, "ohci_hcd_rk_probe\n");
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       if (match){
+               p = (struct rkehci_pdata_id *)match->data;
+       }else{
+               dev_err(dev, "ohci_rk match failed\n");
+               return -EINVAL;
+       }
+
+       dev->platform_data = p->pdata;
+       pldata = dev->platform_data;
+       pldata->dev = dev;
+
+       if (!node) {
+               dev_err(dev, "device node not found\n");
+               return -EINVAL;
+       }
+       
+       if(pldata->hw_init)
+               pldata->hw_init();
+
+       if(pldata->clock_init){
+               pldata->clock_init(pldata);
+               pldata->clock_enable(pldata, 1);
+       }
+
+       if(pldata->soft_reset)
+               pldata->soft_reset();
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "OHCI irq failed\n");
+               ret = irq;
+               goto clk_disable;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "UHH OHCI get resource failed\n");
+               ret = -ENOMEM;
+               goto clk_disable;
+       }
+
+       regs = devm_ioremap_resource(dev, res);
+       if (!regs) {
+               dev_err(dev, "UHH OHCI ioremap failed\n");
+               ret = -ENOMEM;
+               goto clk_disable;
+       }
+
+       /*
+        * Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       if (!dev->dma_mask)
+               dev->dma_mask = &dev->coherent_dma_mask;
+       if (!dev->coherent_dma_mask)
+               dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+       hcd = usb_create_hcd(&ohci_rk_hc_driver, dev,
+                       dev_name(dev));
+       if (!hcd) {
+               dev_err(dev, "usb_create_hcd failed\n");
+               ret = -ENOMEM;
+               goto clk_disable;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+       hcd->regs =  regs;
+
+       ohci_hcd_init(hcd_to_ohci(hcd));
+
+       ret = usb_add_hcd(hcd, irq, 0);
+       if (ret) {
+               dev_dbg(dev, "failed to add hcd with err %d\n", ret);
+               goto err_add_hcd;
+       }
+
+       return 0;
+
+err_add_hcd:
+       usb_put_hcd(hcd);
+
+clk_disable:
+       if(pldata->clock_enable)
+               pldata->clock_enable(pldata, 0);
+
+       return ret;
+}
+
+static int ohci_hcd_rk_remove(struct platform_device *pdev)
+{
+       struct device *dev      = &pdev->dev;
+       struct usb_hcd *hcd     = dev_get_drvdata(dev);
+
+       usb_remove_hcd(hcd);
+       usb_put_hcd(hcd);
+       return 0;
+}
+
+static void ohci_hcd_rk_shutdown(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
+
+       if (hcd->driver->shutdown)
+               hcd->driver->shutdown(hcd);
+}
+
+static struct platform_driver ohci_hcd_rk_driver = {
+       .probe          = ohci_hcd_rk_probe,
+       .remove         = ohci_hcd_rk_remove,
+       .shutdown       = ohci_hcd_rk_shutdown,
+       .driver         = {
+               .name   = "ohci-rk",
+               .of_match_table = of_match_ptr(rk_ohci_of_match),
+       },
+};
+MODULE_ALIAS("platform:rockchip-ohci");