};
};
- 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>,
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";*/
+ };
};
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
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
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 */
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
*
* @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;
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;
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));
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);
fail:
host20_driver_remove(_dev);
+clk_disable:
+ if(pldata->clock_enable)
+ pldata->clock_enable(pldata, 0);
+
return retval;
}
* 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 = {
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
*
* @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;
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;
dev_err(dev, "device node not found\n");
return -EINVAL;
}
-
/*todo : move to usbdev_rk-XX.c*/
if(pldata->hw_init)
pldata->hw_init();
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));
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);
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,
--- /dev/null
+#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
#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;
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);
};
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;
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
#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;
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;
}
}
-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;
}
#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);
}
}
-struct dwc_otg_platform_data usb20otg_pdata = {
+struct dwc_otg_platform_data usb20otg_pdata_rk3188 = {
.phyclk = NULL,
.ahbclk = NULL,
.busclk = NULL,
#endif
#ifdef CONFIG_USB20_HOST
-void usb20host_hw_init(void)
+static void usb20host_hw_init(void)
{
/* usb phy config init */
}
-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;
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;
}
}
-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;
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
}
}
-struct dwc_otg_platform_data usb20host_pdata = {
+struct dwc_otg_platform_data usb20host_pdata_rk3188 = {
.phyclk = NULL,
.ahbclk = NULL,
.busclk = NULL,
#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
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;
}
}
-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,
/********** 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 */
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");
}
/* 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);
{
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",
},
{ },
};
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) {
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)) {
ret = -EINVAL;
goto err1;
}
+
control_usb->hclk_usb_peri = hclk_usb_peri;
clk_prepare_enable(hclk_usb_peri);
.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)
--- /dev/null
+#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");
config USB_EHCI_RKHSIC
tristate "Rockchip EHCI HSIC support"
+ depends on ARCH_ROCKCHIP
select USB_EHCI_ROOT_HUB_TT
default n
---help---
config USB_EHCI_RK
tristate "Rockchip EHCI HOST20 support"
+ depends on ARCH_ROCKCHIP
select USB_EHCI_ROOT_HUB_TT
default n
---help---
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
#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
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:
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
#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),
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)
{
.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,
# 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;
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),
/*
#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 )
{
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);
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);
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)
{
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;
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) {
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);
return 0;
-unmap:
- iounmap(hcd->regs);
put_hcd:
+ if(pldata->clock_enable)
+ pldata->clock_enable(pldata, 0);
usb_put_hcd(hcd);
return ret;
.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,
#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
--- /dev/null
+/*
+ * 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");