From 7f63aac7046422b5e1e5aec96af1eccde0e753ca Mon Sep 17 00:00:00 2001 From: wlf Date: Tue, 11 Mar 2014 11:14:10 +0800 Subject: [PATCH] USB: RK3288 USB CTLR initialization --- arch/arm/boot/dts/rk3188.dtsi | 8 +- arch/arm/boot/dts/rk3288.dtsi | 66 ++ drivers/usb/Kconfig | 1 + drivers/usb/dwc_otg_310/Makefile | 2 +- drivers/usb/dwc_otg_310/dwc_otg_driver.c | 113 +++- drivers/usb/dwc_otg_310/usbdev_grf_regs.h | 155 +++++ drivers/usb/dwc_otg_310/usbdev_rk.h | 45 +- drivers/usb/dwc_otg_310/usbdev_rk30.c | 247 +++----- drivers/usb/dwc_otg_310/usbdev_rk32.c | 737 ++++++++++++++++++++++ drivers/usb/host/Kconfig | 9 + drivers/usb/host/ehci-hcd.c | 16 +- drivers/usb/host/ehci-rk.c | 209 +++++- drivers/usb/host/ehci-rkhsic.c | 165 +++-- drivers/usb/host/ohci-hcd.c | 5 + drivers/usb/host/ohci-rk.c | 258 ++++++++ 15 files changed, 1769 insertions(+), 267 deletions(-) create mode 100644 drivers/usb/dwc_otg_310/usbdev_grf_regs.h create mode 100644 drivers/usb/dwc_otg_310/usbdev_rk32.c create mode 100755 drivers/usb/host/ohci-rk.c diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi index 6a6cdd5f1802..612c3c8357e5 100755 --- a/arch/arm/boot/dts/rk3188.dtsi +++ b/arch/arm/boot/dts/rk3188.dtsi @@ -619,7 +619,7 @@ }; }; - 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>, @@ -639,7 +639,7 @@ }; usb@10180000 { - compatible = "rockchip,usb20_otg"; + compatible = "rockchip,rk3188_usb20_otg"; reg = <0x10180000 0x40000>; interrupts = ; clocks = <&clk_otgphy0_480m>, <&clk_gates5 13>; @@ -647,7 +647,7 @@ }; usb@101c0000 { - compatible = "rockchip,usb20_host"; + compatible = "rockchip,rk3188_usb20_host"; reg = <0x101c0000 0x40000>; interrupts = ; clocks = <&clk_otgphy1_480m>, <&clk_gates7 3>; @@ -655,7 +655,7 @@ }; hsic@10240000 { - compatible = "rockchip,rk_hsic_host"; + compatible = "rockchip,rk3188_rk_hsic_host"; reg = <0x10240000 0x40000>; interrupts = ; clocks = <&clk_hsicphy480m>, <&clk_gates7 4>, diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index b913ba5e19dc..9eb911f9fdac 100755 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -409,4 +409,70 @@ 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 = , , + , , + ; + 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 = ; + /*clocks = <&clk_otgphy0_480m>, <&clk_gates5 13>;*/ + /*clock-names = "otgphy0", "hclk_otg0";*/ + }; + + usb2: usb@ff540000 { + compatible = "rockchip,rk3288_usb20_host"; + reg = <0xff540000 0x40000>; + interrupts = ; + /*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 = ; + /*clocks = ;*/ + /*clock-names = ;*/ + }; + + usb4: usb@ff500000 { + compatible = "rockchip,rk3288_rk_ehci_host"; + reg = <0xff500000 0x20000>; + interrupts = ; + /*clocks = ;*/ + /*clock-names = ;*/ + }; + + usb5: hsic@ff5c0000 { + compatible = "rockchip,rk3288_rk_hsic_host"; + reg = <0xff5c0000 0x40000>; + interrupts = ; + /*clocks = <&clk_hsicphy480m>, <&clk_gates7 4>,*/ + /* <&clk_hsicphy12m>, <&clk_otgphy1_480m>;*/ + /*clock-names = "hsicphy480m", "hclk_hsic",*/ + /* "hsicphy12m", "hsic_otgphy1";*/ + }; }; diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index a8a0d66f44dd..e6e3388213a6 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -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 diff --git a/drivers/usb/dwc_otg_310/Makefile b/drivers/usb/dwc_otg_310/Makefile index 582efa698edb..2850418f5854 100755 --- a/drivers/usb/dwc_otg_310/Makefile +++ b/drivers/usb/dwc_otg_310/Makefile @@ -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 diff --git a/drivers/usb/dwc_otg_310/dwc_otg_driver.c b/drivers/usb/dwc_otg_310/dwc_otg_driver.c index d06e4970c4f5..7d3a5fb2209c 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_driver.c @@ -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 index 000000000000..c74063a99135 --- /dev/null +++ b/drivers/usb/dwc_otg_310/usbdev_grf_regs.h @@ -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 diff --git a/drivers/usb/dwc_otg_310/usbdev_rk.h b/drivers/usb/dwc_otg_310/usbdev_rk.h index 207654a83a21..70728e814aa3 100755 --- a/drivers/usb/dwc_otg_310/usbdev_rk.h +++ b/drivers/usb/dwc_otg_310/usbdev_rk.h @@ -1,5 +1,8 @@ #ifndef __USBDEV_RK_H #define __USBDEV_RK_H +#include +#include +#include "usbdev_grf_regs.h" #define USB_PHY_ENABLED (0) #define USB_PHY_SUSPEND (1) @@ -12,6 +15,17 @@ #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 diff --git a/drivers/usb/dwc_otg_310/usbdev_rk30.c b/drivers/usb/dwc_otg_310/usbdev_rk30.c index 183ff9225096..864fec492933 100755 --- a/drivers/usb/dwc_otg_310/usbdev_rk30.c +++ b/drivers/usb/dwc_otg_310/usbdev_rk30.c @@ -15,65 +15,58 @@ #include #include #include +#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 index 000000000000..6100b4e2e334 --- /dev/null +++ b/drivers/usb/dwc_otg_310/usbdev_rk32.c @@ -0,0 +1,737 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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"); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index f70e0f0af0b3..8aa99da0d239 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -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 diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index a17d73217e65..16068290a74f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -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 diff --git a/drivers/usb/host/ehci-rk.c b/drivers/usb/host/ehci-rk.c index 9b6fae73c0c1..9bab80435673 100755 --- a/drivers/usb/host/ehci-rk.c +++ b/drivers/usb/host/ehci-rk.c @@ -30,12 +30,40 @@ #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, diff --git a/drivers/usb/host/ehci-rkhsic.c b/drivers/usb/host/ehci-rkhsic.c index 37e19e3e8ca6..7bfcade0fca1 100755 --- a/drivers/usb/host/ehci-rkhsic.c +++ b/drivers/usb/host/ehci-rkhsic.c @@ -36,14 +36,23 @@ # 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, diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 865946cde765..e0880a185cea 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -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 index 000000000000..3ca915185aa5 --- /dev/null +++ b/drivers/usb/host/ohci-rk.c @@ -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 +#include +#include +#include +#include +#include +#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"); -- 2.34.1