mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
USB: RK3288 USB CTLR initialization
This commit is contained in:
@@ -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 = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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 = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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 = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk_hsicphy480m>, <&clk_gates7 4>,
|
||||
|
||||
@@ -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 = <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";*/
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
dev->platform_data = &usb20host_pdata;
|
||||
if (match){
|
||||
p = (struct usb20host_pdata_id *)match->data;
|
||||
}else{
|
||||
dev_err(dev, "usb20host match failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
155
drivers/usb/dwc_otg_310/usbdev_grf_regs.h
Normal file
155
drivers/usb/dwc_otg_310/usbdev_grf_regs.h
Normal file
@@ -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
|
||||
@@ -1,5 +1,8 @@
|
||||
#ifndef __USBDEV_RK_H
|
||||
#define __USBDEV_RK_H
|
||||
#include <linux/wakelock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include "usbdev_grf_regs.h"
|
||||
|
||||
#define USB_PHY_ENABLED (0)
|
||||
#define USB_PHY_SUSPEND (1)
|
||||
@@ -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
|
||||
|
||||
@@ -15,65 +15,58 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include "usbdev_grf_regs.h"
|
||||
#include "usbdev_rk.h"
|
||||
#include "dwc_otg_regs.h"
|
||||
|
||||
static struct dwc_otg_control_usb *control_usb;
|
||||
|
||||
int usb_get_chip_id(void)
|
||||
static int usb_get_chip_id(void)
|
||||
{
|
||||
return control_usb->chip_id;
|
||||
}
|
||||
|
||||
int dwc_otg_check_dpdm(void)
|
||||
{
|
||||
int bus_status = 0;
|
||||
return bus_status;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dwc_otg_check_dpdm);
|
||||
|
||||
#ifdef CONFIG_USB20_OTG
|
||||
|
||||
void usb20otg_hw_init(void)
|
||||
static void usb20otg_hw_init(void)
|
||||
{
|
||||
#ifndef CONFIG_USB20_HOST
|
||||
unsigned int * otg_phy_con1 = (control_usb->grf_uoc1_base + 0x8);
|
||||
unsigned int * otg_phy_con2 = (control_usb->grf_uoc1_base + 0xc);
|
||||
*otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16); //enable soft control
|
||||
*otg_phy_con2 = 0x2A|(0x3F<<16); // enter suspend
|
||||
//enable soft control
|
||||
control_usb->grf_uoc1_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
|
||||
// enter suspend
|
||||
control_usb->grf_uoc1_base->CON3 = 0x2A|(0x3F<<16);
|
||||
#endif
|
||||
/* usb phy config init
|
||||
* usb phy enter usb mode */
|
||||
unsigned int * otg_phy_con3 = (control_usb->grf_uoc0_base);
|
||||
*otg_phy_con3 = (0x0300 << 16);
|
||||
control_usb->grf_uoc0_base->CON0 = (0x0300 << 16);
|
||||
|
||||
/* other haredware init,include:
|
||||
* DRV_VBUS GPIO init */
|
||||
gpio_direction_output(control_usb->otg_gpios->gpio, 0);
|
||||
}
|
||||
|
||||
void usb20otg_phy_suspend(void* pdata, int suspend)
|
||||
static void usb20otg_phy_suspend(void* pdata, int suspend)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
unsigned int * otg_phy_con1 = (control_usb->grf_uoc0_base + 0x8);
|
||||
unsigned int * otg_phy_con2 = (control_usb->grf_uoc0_base + 0xc);
|
||||
|
||||
if(suspend){
|
||||
*otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16); //enable soft control
|
||||
*otg_phy_con2 = 0x2A|(0x3F<<16); // enter suspend
|
||||
//enable soft control
|
||||
control_usb->grf_uoc0_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
|
||||
// enter suspend
|
||||
control_usb->grf_uoc0_base->CON3 = 0x2A|(0x3F<<16);
|
||||
usbpdata->phy_status = 1;
|
||||
}else{
|
||||
*otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
|
||||
// exit suspend.
|
||||
control_usb->grf_uoc0_base->CON2 = ((0x01<<2)<<16);
|
||||
usbpdata->phy_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void usb20otg_soft_reset(void)
|
||||
static void usb20otg_soft_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
void usb20otg_clock_init(void* pdata)
|
||||
static void usb20otg_clock_init(void* pdata)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
struct clk* ahbclk,*phyclk;
|
||||
@@ -94,7 +87,7 @@ void usb20otg_clock_init(void* pdata)
|
||||
usbpdata->ahbclk = ahbclk;
|
||||
}
|
||||
|
||||
void usb20otg_clock_enable(void* pdata, int enable)
|
||||
static void usb20otg_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
|
||||
@@ -107,23 +100,22 @@ void usb20otg_clock_enable(void* pdata, int enable)
|
||||
}
|
||||
}
|
||||
|
||||
int usb20otg_get_status(int id)
|
||||
static int usb20otg_get_status(int id)
|
||||
{
|
||||
int ret = -1;
|
||||
unsigned int usbgrf_status = *(unsigned int*)(control_usb->grf_soc_status0);
|
||||
|
||||
switch(id){
|
||||
case USB_STATUS_BVABLID:
|
||||
// bvalid in grf
|
||||
ret = (usbgrf_status &(1<<10));
|
||||
ret = control_usb->grf_soc_status0_rk3188->otg_bvalid;
|
||||
break;
|
||||
case USB_STATUS_DPDM:
|
||||
// dpdm in grf
|
||||
ret = (usbgrf_status &(3<<11));
|
||||
ret = control_usb->grf_soc_status0_rk3188->otg_linestate;
|
||||
break;
|
||||
case USB_STATUS_ID:
|
||||
// id in grf
|
||||
ret = (usbgrf_status &(1<<13));
|
||||
ret = control_usb->grf_soc_status0_rk3188->otg_iddig;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -133,25 +125,24 @@ int usb20otg_get_status(int id)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RK_USB_UART
|
||||
void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)
|
||||
static void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)
|
||||
{
|
||||
unsigned int * otg_phy_con1 = (unsigned int*)(control_usb->grf_uoc0_base);
|
||||
|
||||
if(1 == enter_usb_uart_mode){
|
||||
/* enter uart mode
|
||||
* note: can't disable otg here! If otg disable, the ID change
|
||||
* interrupt can't be triggered when otg cable connect without
|
||||
* device.At the same time, uart can't be used normally
|
||||
*/
|
||||
*otg_phy_con1 = (0x0300 | (0x0300 << 16)); //bypass dm
|
||||
/* bypass dm, enter uart mode */
|
||||
control_usb->grf_uoc0_base->CON0 = (0x0300 | (0x0300 << 16));
|
||||
}else if(0 == enter_usb_uart_mode){
|
||||
/* enter usb mode */
|
||||
*otg_phy_con1 = (0x0300 << 16); //bypass dm disable
|
||||
control_usb->grf_uoc0_base->CON0 = (0x0300 << 16);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void usb20otg_power_enable(int enable)
|
||||
static void usb20otg_power_enable(int enable)
|
||||
{
|
||||
if(0 == enable){//disable otg_drv power
|
||||
gpio_set_value(control_usb->otg_gpios->gpio, 0);
|
||||
@@ -160,7 +151,7 @@ void usb20otg_power_enable(int enable)
|
||||
}
|
||||
}
|
||||
|
||||
struct dwc_otg_platform_data usb20otg_pdata = {
|
||||
struct dwc_otg_platform_data usb20otg_pdata_rk3188 = {
|
||||
.phyclk = NULL,
|
||||
.ahbclk = NULL,
|
||||
.busclk = NULL,
|
||||
@@ -181,7 +172,7 @@ struct dwc_otg_platform_data usb20otg_pdata = {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB20_HOST
|
||||
void usb20host_hw_init(void)
|
||||
static void usb20host_hw_init(void)
|
||||
{
|
||||
/* usb phy config init */
|
||||
|
||||
@@ -191,27 +182,28 @@ void usb20host_hw_init(void)
|
||||
|
||||
}
|
||||
|
||||
void usb20host_phy_suspend(void* pdata, int suspend)
|
||||
static void usb20host_phy_suspend(void* pdata, int suspend)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
unsigned int * otg_phy_con1 = (unsigned int*)(control_usb->grf_uoc1_base + 0x8);
|
||||
unsigned int * otg_phy_con2 = (unsigned int*)(control_usb->grf_uoc1_base + 0xc);
|
||||
|
||||
if(suspend){
|
||||
*otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16); // enable soft control
|
||||
*otg_phy_con2 = 0x2A|(0x3F<<16); // enter suspend
|
||||
// enable soft control
|
||||
control_usb->grf_uoc1_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
|
||||
// enter suspend
|
||||
control_usb->grf_uoc1_base->CON3 = 0x2A|(0x3F<<16);
|
||||
usbpdata->phy_status = 1;
|
||||
}else{
|
||||
*otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
|
||||
//exit suspend.
|
||||
control_usb->grf_uoc1_base->CON2 = ((0x01<<2)<<16);
|
||||
usbpdata->phy_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void usb20host_soft_reset(void)
|
||||
static void usb20host_soft_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
void usb20host_clock_init(void* pdata)
|
||||
static void usb20host_clock_init(void* pdata)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
struct clk* ahbclk,*phyclk;
|
||||
@@ -232,7 +224,7 @@ void usb20host_clock_init(void* pdata)
|
||||
usbpdata->ahbclk = ahbclk;
|
||||
}
|
||||
|
||||
void usb20host_clock_enable(void* pdata, int enable)
|
||||
static void usb20host_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
|
||||
@@ -245,23 +237,22 @@ void usb20host_clock_enable(void* pdata, int enable)
|
||||
}
|
||||
}
|
||||
|
||||
int usb20host_get_status(int id)
|
||||
static int usb20host_get_status(int id)
|
||||
{
|
||||
int ret = -1;
|
||||
unsigned int usbgrf_status = *(unsigned int*)(control_usb->grf_soc_status0);
|
||||
|
||||
switch(id){
|
||||
case USB_STATUS_BVABLID:
|
||||
// bvalid in grf
|
||||
ret = (usbgrf_status &(1<<17));
|
||||
ret = control_usb->grf_soc_status0_rk3188->uhost_bvalid;
|
||||
break;
|
||||
case USB_STATUS_DPDM:
|
||||
// dpdm in grf
|
||||
ret = (usbgrf_status &(3<<18));
|
||||
ret = control_usb->grf_soc_status0_rk3188->uhost_linestate;
|
||||
break;
|
||||
case USB_STATUS_ID:
|
||||
// id in grf
|
||||
ret = (usbgrf_status &(1<<20));
|
||||
ret = control_usb->grf_soc_status0_rk3188->uhost_iddig;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -270,7 +261,7 @@ int usb20host_get_status(int id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void usb20host_power_enable(int enable)
|
||||
static void usb20host_power_enable(int enable)
|
||||
{
|
||||
if(0 == enable){//disable host_drv power
|
||||
//do not disable power in default
|
||||
@@ -279,7 +270,7 @@ void usb20host_power_enable(int enable)
|
||||
}
|
||||
}
|
||||
|
||||
struct dwc_otg_platform_data usb20host_pdata = {
|
||||
struct dwc_otg_platform_data usb20host_pdata_rk3188 = {
|
||||
.phyclk = NULL,
|
||||
.ahbclk = NULL,
|
||||
.busclk = NULL,
|
||||
@@ -296,31 +287,26 @@ struct dwc_otg_platform_data usb20host_pdata = {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_RKHSIC
|
||||
void rk_hsic_hw_init(void)
|
||||
static void rk_hsic_hw_init(void)
|
||||
{
|
||||
unsigned int * phy_con0 = (control_usb->grf_uoc0_base);
|
||||
unsigned int * phy_con1 = (control_usb->grf_uoc1_base);
|
||||
unsigned int * phy_con2 = (control_usb->grf_uoc2_base);
|
||||
unsigned int * phy_con3 = (control_usb->grf_uoc3_base);
|
||||
|
||||
// usb phy config init
|
||||
// hsic phy config init, set hsicphy_txsrtune
|
||||
*phy_con2 = ((0xf<<6)<<16)|(0xf<<6);
|
||||
control_usb->grf_uoc2_base->CON0 = ((0xf<<6)<<16)|(0xf<<6);
|
||||
|
||||
/* other haredware init
|
||||
* set common_on, in suspend mode, otg/host PLL blocks remain powered
|
||||
* for RK3168 set *phy_con0 = (1<<16)|0;
|
||||
* for Rk3188 set *phy_con1 = (1<<16)|0;
|
||||
* for RK3168 set control_usb->grf_uoc0_base->CON0 = (1<<16)|0;
|
||||
* for Rk3188 set control_usb->grf_uoc1_base->CON0 = (1<<16)|0;
|
||||
*/
|
||||
*phy_con1 = (1<<16)|0;
|
||||
control_usb->grf_uoc1_base->CON0 = (1<<16)|0;
|
||||
|
||||
/* change INCR to INCR16 or INCR8(beats less than 16)
|
||||
* or INCR4(beats less than 8) or SINGLE(beats less than 4)
|
||||
*/
|
||||
*phy_con3 = 0x00ff00bc;
|
||||
control_usb->grf_uoc3_base->CON0 = 0x00ff00bc;
|
||||
}
|
||||
|
||||
void rk_hsic_clock_init(void* pdata)
|
||||
static void rk_hsic_clock_init(void* pdata)
|
||||
{
|
||||
/* By default, hsicphy_480m's parent is otg phy 480MHz clk
|
||||
* rk3188 must use host phy 480MHz clk, because if otg bypass
|
||||
@@ -360,7 +346,7 @@ void rk_hsic_clock_init(void* pdata)
|
||||
usbpdata->hsic_phy_12m = phyclk12m_hsic;
|
||||
}
|
||||
|
||||
void rk_hsic_clock_enable(void* pdata, int enable)
|
||||
static void rk_hsic_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
struct rkehci_platform_data *usbpdata=pdata;
|
||||
|
||||
@@ -379,12 +365,12 @@ void rk_hsic_clock_enable(void* pdata, int enable)
|
||||
}
|
||||
}
|
||||
|
||||
void rk_hsic_soft_reset(void)
|
||||
static void rk_hsic_soft_reset(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct rkehci_platform_data rkhsic_pdata = {
|
||||
struct rkehci_platform_data rkhsic_pdata_rk3188 = {
|
||||
.hclk_hsic = NULL,
|
||||
.hsic_phy_12m = NULL,
|
||||
.hsic_phy_480m = NULL,
|
||||
@@ -409,13 +395,8 @@ inline static void do_wakeup(struct work_struct *work)
|
||||
/********** handler for bvalid irq **********/
|
||||
static irqreturn_t bvalid_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
unsigned int * phy_con0;
|
||||
|
||||
/* clear irq */
|
||||
if( usb_get_chip_id() == RK3188_USB_CTLR){
|
||||
phy_con0 = (control_usb->grf_uoc0_base + 0xc);
|
||||
*phy_con0 = (1 << 31) | (1 << 15);
|
||||
}
|
||||
control_usb->grf_uoc0_base->CON3 = (1 << 31) | (1 << 15);
|
||||
|
||||
#ifdef CONFIG_RK_USB_UART
|
||||
/* usb otg dp/dm switch to usb phy */
|
||||
@@ -430,28 +411,11 @@ static irqreturn_t bvalid_irq_handler(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/********** handler for otg id rise and fall edge **********/
|
||||
static irqreturn_t id_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
/* clear irq */
|
||||
if( usb_get_chip_id() == RK3288_USB_CTLR){
|
||||
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
|
||||
wake_lock_timeout(&control_usb->usb_wakelock, WAKE_LOCK_TIMEOUT);
|
||||
schedule_delayed_work(&control_usb->usb_det_wakeup_work, HZ/10);
|
||||
#endif
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/************* register bvalid and otg_id irq **************/
|
||||
/************* register bvalid irq **************/
|
||||
static int otg_irq_detect_init(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
int irq = 0;
|
||||
unsigned int * phy_con0;
|
||||
|
||||
#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
|
||||
wake_lock_init(&control_usb->usb_wakelock, WAKE_LOCK_SUSPEND, "usb_detect");
|
||||
@@ -467,29 +431,7 @@ static int otg_irq_detect_init(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* clear & enable bvalid irq */
|
||||
if( usb_get_chip_id() == RK3188_USB_CTLR){
|
||||
phy_con0 = (control_usb->grf_uoc0_base + 0xc);
|
||||
*phy_con0 = (3 << 30) | (3 << 14);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
|
||||
enable_irq_wake(irq);
|
||||
#endif
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "otg_id");
|
||||
if (irq > 0) {
|
||||
ret = request_irq(irq, id_irq_handler, 0, "otg_id", NULL);
|
||||
if(ret < 0){
|
||||
dev_err(&pdev->dev, "request_irq %d failed!\n", irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* clear & enable otg_id change irq */
|
||||
/* for rk3026 & rk3288 enable and clear id_fall_irq & id_rise_irq*/
|
||||
if( usb_get_chip_id() == RK3288_USB_CTLR){
|
||||
|
||||
}
|
||||
control_usb->grf_uoc0_base->CON3 = (3 << 30) | (3 << 14);
|
||||
|
||||
#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
|
||||
enable_irq_wake(irq);
|
||||
@@ -503,71 +445,65 @@ static int usb_grf_ioremap(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct resource *res;
|
||||
void *grf_soc_status0;
|
||||
void *grf_uoc0_base;
|
||||
void *grf_uoc1_base;
|
||||
void *grf_uoc2_base;
|
||||
void *grf_uoc3_base;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_SOC_STATUS0");
|
||||
control_usb->grf_soc_status0 = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(control_usb->grf_soc_status0)){
|
||||
ret = PTR_ERR(control_usb->grf_soc_status0);
|
||||
grf_soc_status0 = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_soc_status0)){
|
||||
ret = PTR_ERR(grf_soc_status0);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_soc_status0_rk3188 = (pGRF_SOC_STATUS_RK3188)grf_soc_status0;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_UOC0_BASE");
|
||||
control_usb->grf_uoc0_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(control_usb->grf_uoc0_base)){
|
||||
ret = PTR_ERR(control_usb->grf_uoc0_base);
|
||||
grf_uoc0_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_uoc0_base)){
|
||||
ret = PTR_ERR(grf_uoc0_base);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_uoc0_base = (pGRF_UOC0_REG)grf_uoc0_base;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_UOC1_BASE");
|
||||
control_usb->grf_uoc1_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(control_usb->grf_uoc1_base)){
|
||||
ret = PTR_ERR(control_usb->grf_uoc1_base);
|
||||
grf_uoc1_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_uoc1_base)){
|
||||
ret = PTR_ERR(grf_uoc1_base);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_uoc1_base = (pGRF_UOC1_REG)grf_uoc1_base;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_UOC2_BASE");
|
||||
control_usb->grf_uoc2_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(control_usb->grf_uoc2_base)){
|
||||
ret = PTR_ERR(control_usb->grf_uoc2_base);
|
||||
grf_uoc2_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_uoc2_base)){
|
||||
ret = PTR_ERR(grf_uoc2_base);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_uoc2_base = (pGRF_UOC2_REG)grf_uoc2_base;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_UOC3_BASE");
|
||||
control_usb->grf_uoc3_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(control_usb->grf_uoc3_base)){
|
||||
ret = PTR_ERR(control_usb->grf_uoc3_base);
|
||||
grf_uoc3_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_uoc3_base)){
|
||||
ret = PTR_ERR(grf_uoc3_base);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_uoc3_base = (pGRF_UOC3_REG)grf_uoc3_base;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct platform_device_id rk_usb_devtype[] = {
|
||||
{
|
||||
.name = "rk3188-usb",
|
||||
.driver_data = RK3188_USB_CTLR,
|
||||
},
|
||||
{
|
||||
.name = "rk3288-usb",
|
||||
.driver_data = RK3288_USB_CTLR,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, rk_usb_devtype);
|
||||
|
||||
static const struct of_device_id dwc_otg_control_usb_id_table[] = {
|
||||
{ .compatible = "rockchip,rk3188-dwc-control-usb",
|
||||
.data = &rk_usb_devtype[RK3188_USB_CTLR],
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3288-dwc-control-usb",
|
||||
.data = &rk_usb_devtype[RK3288_USB_CTLR],
|
||||
.compatible = "rockchip,rk3188-dwc-control-usb",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
@@ -580,15 +516,6 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct clk* hclk_usb_peri;
|
||||
int ret = 0;
|
||||
const struct of_device_id *match =
|
||||
of_match_device(of_match_ptr(dwc_otg_control_usb_id_table), &pdev->dev);
|
||||
|
||||
if (match)
|
||||
pdev->id_entry = match->data;
|
||||
else{
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),GFP_KERNEL);
|
||||
if (!control_usb) {
|
||||
@@ -597,7 +524,7 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
|
||||
goto err1;
|
||||
}
|
||||
|
||||
control_usb->chip_id = pdev->id_entry->driver_data;
|
||||
control_usb->chip_id = RK3188_USB_CTLR;
|
||||
|
||||
hclk_usb_peri = devm_clk_get(&pdev->dev, "hclk_usb_peri");
|
||||
if (IS_ERR(hclk_usb_peri)) {
|
||||
@@ -605,6 +532,7 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
control_usb->hclk_usb_peri = hclk_usb_peri;
|
||||
clk_prepare_enable(hclk_usb_peri);
|
||||
|
||||
@@ -672,11 +600,10 @@ static struct platform_driver dwc_otg_control_usb_driver = {
|
||||
.probe = dwc_otg_control_usb_probe,
|
||||
.remove = dwc_otg_control_usb_remove,
|
||||
.driver = {
|
||||
.name = "dwc-control-usb",
|
||||
.name = "rk3188-dwc-control-usb",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(dwc_otg_control_usb_id_table),
|
||||
},
|
||||
.id_table = rk_usb_devtype,
|
||||
};
|
||||
|
||||
static int __init dwc_otg_control_usb_init(void)
|
||||
|
||||
737
drivers/usb/dwc_otg_310/usbdev_rk32.c
Normal file
737
drivers/usb/dwc_otg_310/usbdev_rk32.c
Normal file
@@ -0,0 +1,737 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/wakelock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include "usbdev_grf_regs.h"
|
||||
#include "usbdev_rk.h"
|
||||
#include "dwc_otg_regs.h"
|
||||
static struct dwc_otg_control_usb *control_usb;
|
||||
|
||||
static int usb_get_chip_id(void)
|
||||
{
|
||||
return control_usb->chip_id;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB20_OTG
|
||||
static void usb20otg_hw_init(void)
|
||||
{
|
||||
#ifndef CONFIG_USB20_HOST
|
||||
//enable soft control
|
||||
control_usb->grf_uoc2_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
|
||||
// enter suspend
|
||||
control_usb->grf_uoc2_base->CON3 = 0x2A|(0x3F<<16);
|
||||
#endif
|
||||
/* usb phy config init
|
||||
* usb phy enter usb mode */
|
||||
control_usb->grf_uoc0_base->CON3 = (0x00c0 << 16);
|
||||
|
||||
/* other haredware init,include:
|
||||
* DRV_VBUS GPIO init */
|
||||
// gpio_direction_output(control_usb->otg_gpios->gpio, 0);
|
||||
|
||||
}
|
||||
|
||||
static void usb20otg_phy_suspend(void* pdata, int suspend)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
|
||||
if(suspend){
|
||||
//enable soft control
|
||||
control_usb->grf_uoc0_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
|
||||
//enter suspend
|
||||
control_usb->grf_uoc0_base->CON3 = 0x2A|(0x3F<<16);
|
||||
usbpdata->phy_status = 1;
|
||||
}else{
|
||||
// exit suspend.
|
||||
control_usb->grf_uoc0_base->CON2 = ((0x01<<2)<<16);
|
||||
usbpdata->phy_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb20otg_soft_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void usb20otg_clock_init(void* pdata)
|
||||
{
|
||||
/*
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
struct clk* ahbclk,*phyclk;
|
||||
|
||||
ahbclk = devm_clk_get(usbpdata->dev, "hclk_otg0");
|
||||
if (IS_ERR(ahbclk)) {
|
||||
dev_err(usbpdata->dev, "Failed to get hclk_otg0\n");
|
||||
return;
|
||||
}
|
||||
|
||||
phyclk = devm_clk_get(usbpdata->dev, "otgphy0");
|
||||
if (IS_ERR(phyclk)) {
|
||||
dev_err(usbpdata->dev, "Failed to get otgphy0\n");
|
||||
return;
|
||||
}
|
||||
|
||||
usbpdata->phyclk = phyclk;
|
||||
usbpdata->ahbclk = ahbclk;
|
||||
*/
|
||||
}
|
||||
|
||||
static void usb20otg_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
/*
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
|
||||
if(enable){
|
||||
clk_prepare_enable(usbpdata->ahbclk);
|
||||
clk_prepare_enable(usbpdata->phyclk);
|
||||
}else{
|
||||
clk_disable_unprepare(usbpdata->ahbclk);
|
||||
clk_disable_unprepare(usbpdata->phyclk);
|
||||
}*/
|
||||
}
|
||||
|
||||
static int usb20otg_get_status(int id)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
switch(id){
|
||||
case USB_STATUS_BVABLID:
|
||||
// bvalid in grf
|
||||
ret = control_usb->grf_soc_status2_rk3288->otg_bvalid;
|
||||
break;
|
||||
case USB_STATUS_DPDM:
|
||||
// dpdm in grf
|
||||
ret = control_usb->grf_soc_status2_rk3288->otg_linestate;
|
||||
break;
|
||||
case USB_STATUS_ID:
|
||||
// id in grf
|
||||
ret = control_usb->grf_soc_status2_rk3288->otg_iddig;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RK_USB_UART
|
||||
static void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)
|
||||
{
|
||||
if(1 == enter_usb_uart_mode){
|
||||
/* bypass dm, enter uart mode*/
|
||||
control_usb->grf_uoc0_base->CON3 = (0x00c0 | (0x00c0 << 16));
|
||||
|
||||
}else if(0 == enter_usb_uart_mode){
|
||||
/* enter usb mode */
|
||||
control_usb->grf_uoc0_base->CON3 = (0x00c0 << 16);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usb20otg_power_enable(int enable)
|
||||
{ /*
|
||||
if(0 == enable){//disable otg_drv power
|
||||
gpio_set_value(control_usb->otg_gpios->gpio, 0);
|
||||
}else if(1 == enable){//enable otg_drv power
|
||||
gpio_set_value(control_usb->otg_gpios->gpio, 1);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
struct dwc_otg_platform_data usb20otg_pdata_rk3288 = {
|
||||
.phyclk = NULL,
|
||||
.ahbclk = NULL,
|
||||
.busclk = NULL,
|
||||
.phy_status = 0,
|
||||
.hw_init = usb20otg_hw_init,
|
||||
.phy_suspend = usb20otg_phy_suspend,
|
||||
.soft_reset = usb20otg_soft_reset,
|
||||
.clock_init = usb20otg_clock_init,
|
||||
.clock_enable = usb20otg_clock_enable,
|
||||
.get_status = usb20otg_get_status,
|
||||
.get_chip_id = usb_get_chip_id,
|
||||
|
||||
.power_enable = usb20otg_power_enable,
|
||||
#ifdef CONFIG_RK_USB_UART
|
||||
.dwc_otg_uart_mode = dwc_otg_uart_mode,
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB20_HOST
|
||||
|
||||
static void usb20host_hw_init(void)
|
||||
{
|
||||
/* usb phy config init */
|
||||
|
||||
/* other haredware init,include:
|
||||
* DRV_VBUS GPIO init */
|
||||
// gpio_direction_output(control_usb->host_gpios->gpio, 1);
|
||||
}
|
||||
|
||||
static void usb20host_phy_suspend(void* pdata, int suspend)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
|
||||
if(suspend){
|
||||
// enable soft control
|
||||
control_usb->grf_uoc2_base->CON2 = (0x01<<2)|((0x01<<2)<<16);
|
||||
// enter suspend
|
||||
control_usb->grf_uoc2_base->CON3 = 0x2A|(0x3F<<16);
|
||||
usbpdata->phy_status = 1;
|
||||
}else{
|
||||
//exit suspend.
|
||||
control_usb->grf_uoc2_base->CON2 = ((0x01<<2)<<16);
|
||||
usbpdata->phy_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb20host_soft_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void usb20host_clock_init(void* pdata)
|
||||
{
|
||||
/*
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
struct clk* ahbclk,*phyclk;
|
||||
|
||||
ahbclk = devm_clk_get(usbpdata->dev, "hclk_otg1");
|
||||
if (IS_ERR(ahbclk)) {
|
||||
dev_err(usbpdata->dev, "Failed to get hclk_otg1\n");
|
||||
return;
|
||||
}
|
||||
|
||||
phyclk = devm_clk_get(usbpdata->dev, "otgphy1");
|
||||
if (IS_ERR(phyclk)) {
|
||||
dev_err(usbpdata->dev, "Failed to get otgphy1\n");
|
||||
return;
|
||||
}
|
||||
|
||||
usbpdata->phyclk = phyclk;
|
||||
usbpdata->ahbclk = ahbclk;
|
||||
*/
|
||||
}
|
||||
|
||||
static void usb20host_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
/*
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
|
||||
if(enable){
|
||||
clk_prepare_enable(usbpdata->ahbclk);
|
||||
clk_prepare_enable(usbpdata->phyclk);
|
||||
}else{
|
||||
clk_disable_unprepare(usbpdata->ahbclk);
|
||||
clk_disable_unprepare(usbpdata->phyclk);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static int usb20host_get_status(int id)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
switch(id){
|
||||
case USB_STATUS_BVABLID:
|
||||
// bvalid in grf
|
||||
ret = control_usb->grf_soc_status2_rk3288->host1_bvalid;
|
||||
break;
|
||||
case USB_STATUS_DPDM:
|
||||
// dpdm in grf
|
||||
ret = control_usb->grf_soc_status2_rk3288->host1_linestate;
|
||||
break;
|
||||
case USB_STATUS_ID:
|
||||
// id in grf
|
||||
ret = control_usb->grf_soc_status2_rk3288->host1_iddig;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb20host_power_enable(int enable)
|
||||
{ /*
|
||||
if(0 == enable){//disable host_drv power
|
||||
//do not disable power in default
|
||||
}else if(1 == enable){//enable host_drv power
|
||||
gpio_set_value(control_usb->host_gpios->gpio, 1);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
struct dwc_otg_platform_data usb20host_pdata_rk3288 = {
|
||||
.phyclk = NULL,
|
||||
.ahbclk = NULL,
|
||||
.busclk = NULL,
|
||||
.phy_status = 0,
|
||||
.hw_init = usb20host_hw_init,
|
||||
.phy_suspend = usb20host_phy_suspend,
|
||||
.soft_reset = usb20host_soft_reset,
|
||||
.clock_init = usb20host_clock_init,
|
||||
.clock_enable = usb20host_clock_enable,
|
||||
.get_status = usb20host_get_status,
|
||||
.get_chip_id = usb_get_chip_id,
|
||||
.power_enable = usb20host_power_enable,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_RKHSIC
|
||||
static void rk_hsic_hw_init(void)
|
||||
{
|
||||
// usb phy config init
|
||||
// hsic phy config init, set hsicphy_txsrtune
|
||||
control_usb->grf_uoc3_base->CON0 = ((0xf<<6)<<16)|(0xf<<6);
|
||||
|
||||
/* other haredware init
|
||||
* set common_on, in suspend mode, otg/host PLL blocks remain powered
|
||||
*/
|
||||
|
||||
|
||||
/* change INCR to INCR16 or INCR8(beats less than 16)
|
||||
* or INCR4(beats less than 8) or SINGLE(beats less than 4)
|
||||
*/
|
||||
control_usb->grf_uoc4_base->CON0 = 0x00ff00bc;
|
||||
}
|
||||
|
||||
static void rk_hsic_clock_init(void* pdata)
|
||||
{
|
||||
/* By default, hsicphy_480m's parent is otg phy 480MHz clk
|
||||
* rk3188 must use host phy 480MHz clk, because if otg bypass
|
||||
* to uart mode, otg phy 480MHz clk will be closed automatically
|
||||
*/
|
||||
/*
|
||||
struct rkehci_platform_data *usbpdata=pdata;
|
||||
struct clk *ahbclk, *phyclk480m_hsic, *phyclk12m_hsic, *phyclk_otgphy1;
|
||||
|
||||
phyclk480m_hsic = devm_clk_get(usbpdata->dev, "hsicphy480m");
|
||||
if (IS_ERR(phyclk480m_hsic)) {
|
||||
dev_err(usbpdata->dev, "Failed to get hsicphy480m\n");
|
||||
return;
|
||||
}
|
||||
|
||||
phyclk12m_hsic = devm_clk_get(usbpdata->dev, "hsicphy12m");
|
||||
if (IS_ERR(phyclk12m_hsic)) {
|
||||
dev_err(usbpdata->dev, "Failed to get hsicphy12m\n");
|
||||
return;
|
||||
}
|
||||
|
||||
phyclk_otgphy1 = devm_clk_get(usbpdata->dev, "hsic_otgphy1");
|
||||
if (IS_ERR(phyclk_otgphy1)) {
|
||||
dev_err(usbpdata->dev, "Failed to get hsic_otgphy1\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ahbclk = devm_clk_get(usbpdata->dev, "hclk_hsic");
|
||||
if (IS_ERR(ahbclk)) {
|
||||
dev_err(usbpdata->dev, "Failed to get hclk_hsic\n");
|
||||
return;
|
||||
}
|
||||
|
||||
clk_set_parent(phyclk480m_hsic, phyclk_otgphy1);
|
||||
|
||||
usbpdata->hclk_hsic = ahbclk;
|
||||
usbpdata->hsic_phy_480m = phyclk480m_hsic;
|
||||
usbpdata->hsic_phy_12m = phyclk12m_hsic;
|
||||
*/
|
||||
}
|
||||
|
||||
static void rk_hsic_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
/*
|
||||
struct rkehci_platform_data *usbpdata=pdata;
|
||||
|
||||
if(enable == usbpdata->clk_status)
|
||||
return;
|
||||
if(enable){
|
||||
clk_prepare_enable(usbpdata->hclk_hsic);
|
||||
clk_prepare_enable(usbpdata->hsic_phy_480m);
|
||||
clk_prepare_enable(usbpdata->hsic_phy_12m);
|
||||
usbpdata->clk_status = 1;
|
||||
}else{
|
||||
clk_disable_unprepare(usbpdata->hclk_hsic);
|
||||
clk_disable_unprepare(usbpdata->hsic_phy_480m);
|
||||
clk_disable_unprepare(usbpdata->hsic_phy_12m);
|
||||
usbpdata->clk_status = 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static void rk_hsic_soft_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
struct rkehci_platform_data rkhsic_pdata_rk3288 = {
|
||||
.hclk_hsic = NULL,
|
||||
.hsic_phy_12m = NULL,
|
||||
.hsic_phy_480m = NULL,
|
||||
.clk_status = -1,
|
||||
.hw_init = rk_hsic_hw_init,
|
||||
.clock_init = rk_hsic_clock_init,
|
||||
.clock_enable = rk_hsic_clock_enable,
|
||||
.soft_reset = rk_hsic_soft_reset,
|
||||
.get_chip_id = usb_get_chip_id,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_RK
|
||||
static void rk_ehci_hw_init(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void rk_ehci_clock_init(void* pdata)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void rk_ehci_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void rk_ehci_soft_reset(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct rkehci_platform_data rkehci_pdata_rk3288 = {
|
||||
.phyclk = NULL,
|
||||
.ahbclk = NULL,
|
||||
.clk_status = -1,
|
||||
.hw_init = rk_ehci_hw_init,
|
||||
.clock_init = rk_ehci_clock_init,
|
||||
.clock_enable = rk_ehci_clock_enable,
|
||||
.soft_reset = rk_ehci_soft_reset,
|
||||
.get_chip_id = usb_get_chip_id,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_OHCI_HCD_RK
|
||||
static void rk_ohci_hw_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void rk_ohci_clock_init(void* pdata)
|
||||
{
|
||||
}
|
||||
|
||||
static void rk_ohci_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
}
|
||||
|
||||
static void rk_ohci_soft_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
struct rkehci_platform_data rkohci_pdata_rk3288 = {
|
||||
.phyclk = NULL,
|
||||
.ahbclk = NULL,
|
||||
.clk_status = -1,
|
||||
.hw_init = rk_ohci_hw_init,
|
||||
.clock_init = rk_ohci_clock_init,
|
||||
.clock_enable = rk_ohci_clock_enable,
|
||||
.soft_reset = rk_ohci_soft_reset,
|
||||
.get_chip_id = usb_get_chip_id,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
|
||||
#define WAKE_LOCK_TIMEOUT (HZ * 10)
|
||||
inline static void do_wakeup(struct work_struct *work)
|
||||
{
|
||||
// rk28_send_wakeup_key();
|
||||
}
|
||||
#endif
|
||||
|
||||
/********** handler for bvalid irq **********/
|
||||
static irqreturn_t bvalid_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
/* clear irq */
|
||||
control_usb->grf_uoc0_base->CON4 = (0x0008 | (0x0008 << 16));
|
||||
|
||||
#ifdef CONFIG_RK_USB_UART
|
||||
/* usb otg dp/dm switch to usb phy */
|
||||
dwc_otg_uart_mode(NULL, PHY_USB_MODE);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
|
||||
wake_lock_timeout(&control_usb->usb_wakelock, WAKE_LOCK_TIMEOUT);
|
||||
schedule_delayed_work(&control_usb->usb_det_wakeup_work, HZ/10);
|
||||
#endif
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/************* register usb irq **************/
|
||||
static int otg_irq_detect_init(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
int irq = 0;
|
||||
|
||||
#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
|
||||
wake_lock_init(&control_usb->usb_wakelock, WAKE_LOCK_SUSPEND, "usb_detect");
|
||||
INIT_DELAYED_WORK(&control_usb->usb_det_wakeup_work, do_wakeup);
|
||||
#endif
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "bvalid");
|
||||
if (irq > 0) {
|
||||
ret = request_irq(irq, bvalid_irq_handler, 0, "bvalid", NULL);
|
||||
if(ret < 0){
|
||||
dev_err(&pdev->dev, "request_irq %d failed!\n", irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* clear & enable bvalid irq */
|
||||
control_usb->grf_uoc0_base->CON4 = (0x000c | (0x000c << 16));
|
||||
|
||||
#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
|
||||
enable_irq_wake(irq);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_grf_ioremap(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct resource *res;
|
||||
void *grf_soc_status1;
|
||||
void *grf_soc_status2;
|
||||
void *grf_soc_status19;
|
||||
void *grf_soc_status21;
|
||||
void *grf_uoc0_base;
|
||||
void *grf_uoc1_base;
|
||||
void *grf_uoc2_base;
|
||||
void *grf_uoc3_base;
|
||||
void *grf_uoc4_base;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_SOC_STATUS1");
|
||||
grf_soc_status1 = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_soc_status1)){
|
||||
ret = PTR_ERR(grf_soc_status1);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_soc_status1_rk3288 = (pGRF_SOC_STATUS1_RK3288)grf_soc_status1;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_SOC_STATUS2");
|
||||
grf_soc_status2 = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_soc_status2)){
|
||||
ret = PTR_ERR(grf_soc_status2);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_soc_status2_rk3288 = (pGRF_SOC_STATUS2_RK3288)grf_soc_status2;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_SOC_STATUS19");
|
||||
grf_soc_status19 = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_soc_status19)){
|
||||
ret = PTR_ERR(grf_soc_status19);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_soc_status19_rk3288 = (pGRF_SOC_STATUS19_RK3288)grf_soc_status19;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_SOC_STATUS21");
|
||||
grf_soc_status21 = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_soc_status21)){
|
||||
ret = PTR_ERR(grf_soc_status21);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_soc_status21_rk3288 = (pGRF_SOC_STATUS21_RK3288)grf_soc_status21;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_UOC0_BASE");
|
||||
grf_uoc0_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_uoc0_base)){
|
||||
ret = PTR_ERR(grf_uoc0_base);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_uoc0_base = (pGRF_UOC0_REG)grf_uoc0_base;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_UOC1_BASE");
|
||||
grf_uoc1_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_uoc1_base)){
|
||||
ret = PTR_ERR(grf_uoc1_base);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_uoc1_base = (pGRF_UOC1_REG)grf_uoc1_base;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_UOC2_BASE");
|
||||
grf_uoc2_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_uoc2_base)){
|
||||
ret = PTR_ERR(grf_uoc2_base);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_uoc2_base = (pGRF_UOC2_REG)grf_uoc2_base;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_UOC3_BASE");
|
||||
grf_uoc3_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_uoc3_base)){
|
||||
ret = PTR_ERR(grf_uoc3_base);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_uoc3_base = (pGRF_UOC3_REG)grf_uoc3_base;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"GRF_UOC4_BASE");
|
||||
grf_uoc4_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(grf_uoc4_base)){
|
||||
ret = PTR_ERR(grf_uoc4_base);
|
||||
return ret;
|
||||
}
|
||||
control_usb->grf_uoc4_base = (pGRF_UOC4_REG)grf_uoc4_base;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
static const struct of_device_id dwc_otg_control_usb_id_table[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3288-dwc-control-usb",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static int dwc_otg_control_usb_probe(struct platform_device *pdev)
|
||||
{
|
||||
int gpio, err;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
// struct clk* hclk_usb_peri;
|
||||
int ret = 0;
|
||||
|
||||
control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),GFP_KERNEL);
|
||||
if (!control_usb) {
|
||||
dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
control_usb->chip_id = RK3288_USB_CTLR;
|
||||
/* disable for debug
|
||||
hclk_usb_peri = devm_clk_get(&pdev->dev, "hclk_usb_peri");
|
||||
if (IS_ERR(hclk_usb_peri)) {
|
||||
dev_err(&pdev->dev, "Failed to get hclk_usb_peri\n");
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
control_usb->hclk_usb_peri = hclk_usb_peri;
|
||||
clk_prepare_enable(hclk_usb_peri);
|
||||
*/
|
||||
ret = usb_grf_ioremap(pdev);
|
||||
if(ret){
|
||||
dev_err(&pdev->dev, "Failed to ioremap usb grf\n");
|
||||
goto err2;
|
||||
}
|
||||
/*
|
||||
control_usb->host_gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
|
||||
|
||||
gpio = of_get_named_gpio(np, "gpios", 0);
|
||||
if(!gpio_is_valid(gpio)){
|
||||
dev_err(&pdev->dev, "invalid host gpio%d\n", gpio);
|
||||
ret = -EINVAL;
|
||||
goto err2;
|
||||
}
|
||||
control_usb->host_gpios->gpio = gpio;
|
||||
err = devm_gpio_request(&pdev->dev, gpio, "host_drv_gpio");
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to request GPIO%d for host_drv\n",
|
||||
gpio);
|
||||
ret = err;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
control_usb->otg_gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
|
||||
|
||||
gpio = of_get_named_gpio(np, "gpios", 1);
|
||||
if(!gpio_is_valid(gpio)){
|
||||
dev_err(&pdev->dev, "invalid otg gpio%d\n", gpio);
|
||||
ret = -EINVAL;
|
||||
goto err2;
|
||||
}
|
||||
control_usb->otg_gpios->gpio = gpio;
|
||||
err = devm_gpio_request(&pdev->dev, gpio, "otg_drv_gpio");
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to request GPIO%d for otg_drv\n",
|
||||
gpio);
|
||||
ret = err;
|
||||
goto err2;
|
||||
}
|
||||
*/
|
||||
#if 0 //disable for debug
|
||||
ret = otg_irq_detect_init(pdev);
|
||||
if (ret < 0)
|
||||
goto err2;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
// disable for debug
|
||||
// clk_disable_unprepare(hclk_usb_peri);
|
||||
err1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc_otg_control_usb_remove(struct platform_device *pdev)
|
||||
{
|
||||
// disable for debug
|
||||
// clk_disable_unprepare(control_usb->hclk_usb_peri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver dwc_otg_control_usb_driver = {
|
||||
.probe = dwc_otg_control_usb_probe,
|
||||
.remove = dwc_otg_control_usb_remove,
|
||||
.driver = {
|
||||
.name = "rk3288-dwc-control-usb",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(dwc_otg_control_usb_id_table),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dwc_otg_control_usb_init(void)
|
||||
{
|
||||
return platform_driver_register(&dwc_otg_control_usb_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(dwc_otg_control_usb_init);
|
||||
|
||||
static void __exit dwc_otg_control_usb_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&dwc_otg_control_usb_driver);
|
||||
}
|
||||
|
||||
module_exit(dwc_otg_control_usb_exit);
|
||||
MODULE_ALIAS("platform: dwc_control_usb");
|
||||
MODULE_AUTHOR("RockChip Inc.");
|
||||
MODULE_DESCRIPTION("RockChip Control Module USB Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 )
|
||||
static int rkhsic_status = 1;
|
||||
static struct ehci_hcd *g_hsic_ehci;
|
||||
#define HSIC_EHCI_PRINT(x...) printk( KERN_INFO "HSIC_EHCI: " x )
|
||||
|
||||
extern struct rkehci_platform_data rkhsic_pdata;
|
||||
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,
|
||||
|
||||
@@ -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
|
||||
|
||||
258
drivers/usb/host/ohci-rk.c
Executable file
258
drivers/usb/host/ohci-rk.c
Executable file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* ROCKCHIP USB HOST OHCI Controller
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of_platform.h>
|
||||
#ifdef CONFIG_DWC_OTG_274
|
||||
# include "../dwc_otg/usbdev_rk.h"
|
||||
#endif
|
||||
#ifdef CONFIG_DWC_OTG_310
|
||||
# include "../dwc_otg_310/usbdev_rk.h"
|
||||
#endif
|
||||
|
||||
static struct rkehci_pdata_id rkohci_pdata[] = {
|
||||
{
|
||||
.name = "rk3188-reserved",
|
||||
.pdata = NULL,
|
||||
},
|
||||
{
|
||||
.name = "rk3288-ohci",
|
||||
.pdata = &rkohci_pdata_rk3288,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static int ohci_rk_init(struct usb_hcd *hcd)
|
||||
{
|
||||
dev_dbg(hcd->self.controller, "starting OHCI controller\n");
|
||||
|
||||
return ohci_init(hcd_to_ohci(hcd));
|
||||
}
|
||||
|
||||
static int ohci_rk_start(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* RemoteWakeupConnected has to be set explicitly before
|
||||
* calling ohci_run. The reset value of RWC is 0.
|
||||
*/
|
||||
ohci->hc_control = OHCI_CTRL_RWC;
|
||||
writel(OHCI_CTRL_RWC, &ohci->regs->control);
|
||||
|
||||
ret = ohci_run(ohci);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(hcd->self.controller, "can't start\n");
|
||||
ohci_stop(hcd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct hc_driver ohci_rk_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "RK OHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ohci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ohci_irq,
|
||||
.flags = HCD_USB11 | HCD_MEMORY,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ohci_rk_init,
|
||||
.start = ohci_rk_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ohci_urb_enqueue,
|
||||
.urb_dequeue = ohci_urb_dequeue,
|
||||
.endpoint_disable = ohci_endpoint_disable,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ohci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ohci_hub_status_data,
|
||||
.hub_control = ohci_hub_control,
|
||||
#ifdef CONFIG_PM
|
||||
.bus_suspend = ohci_bus_suspend,
|
||||
.bus_resume = ohci_bus_resume,
|
||||
#endif
|
||||
.start_port_reset = ohci_start_port_reset,
|
||||
};
|
||||
|
||||
static struct of_device_id rk_ohci_of_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3288_rk_ohci_host",
|
||||
.data = &rkohci_pdata[RK3288_USB_CTLR],
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk_ohci_of_match);
|
||||
|
||||
/* ohci_hcd_rk_probe - initialize RK-based HCDs
|
||||
* Allocates basic resources for this USB host controller, and
|
||||
* then invokes the start() method for the HCD associated with it
|
||||
* through the hotplug entry's driver_data.
|
||||
*/
|
||||
static int ohci_hcd_rk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct usb_hcd *hcd = NULL;
|
||||
void __iomem *regs = NULL;
|
||||
struct resource *res;
|
||||
int ret = -ENODEV;
|
||||
int irq;
|
||||
struct rkehci_platform_data *pldata;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct rkehci_pdata_id *p;
|
||||
const struct of_device_id *match =
|
||||
of_match_device(of_match_ptr( rk_ohci_of_match ), &pdev->dev);
|
||||
|
||||
dev_dbg(&pdev->dev, "ohci_hcd_rk_probe\n");
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
if (match){
|
||||
p = (struct rkehci_pdata_id *)match->data;
|
||||
}else{
|
||||
dev_err(dev, "ohci_rk match failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev->platform_data = p->pdata;
|
||||
pldata = dev->platform_data;
|
||||
pldata->dev = dev;
|
||||
|
||||
if (!node) {
|
||||
dev_err(dev, "device node not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(pldata->hw_init)
|
||||
pldata->hw_init();
|
||||
|
||||
if(pldata->clock_init){
|
||||
pldata->clock_init(pldata);
|
||||
pldata->clock_enable(pldata, 1);
|
||||
}
|
||||
|
||||
if(pldata->soft_reset)
|
||||
pldata->soft_reset();
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "OHCI irq failed\n");
|
||||
ret = irq;
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "UHH OHCI get resource failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
regs = devm_ioremap_resource(dev, res);
|
||||
if (!regs) {
|
||||
dev_err(dev, "UHH OHCI ioremap failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
/*
|
||||
* Right now device-tree probed devices don't get dma_mask set.
|
||||
* Since shared usb code relies on it, set it here for now.
|
||||
* Once we have dma capability bindings this can go away.
|
||||
*/
|
||||
if (!dev->dma_mask)
|
||||
dev->dma_mask = &dev->coherent_dma_mask;
|
||||
if (!dev->coherent_dma_mask)
|
||||
dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
hcd = usb_create_hcd(&ohci_rk_hc_driver, dev,
|
||||
dev_name(dev));
|
||||
if (!hcd) {
|
||||
dev_err(dev, "usb_create_hcd failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
hcd->regs = regs;
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, 0);
|
||||
if (ret) {
|
||||
dev_dbg(dev, "failed to add hcd with err %d\n", ret);
|
||||
goto err_add_hcd;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_hcd:
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
clk_disable:
|
||||
if(pldata->clock_enable)
|
||||
pldata->clock_enable(pldata, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ohci_hcd_rk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
usb_put_hcd(hcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ohci_hcd_rk_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
if (hcd->driver->shutdown)
|
||||
hcd->driver->shutdown(hcd);
|
||||
}
|
||||
|
||||
static struct platform_driver ohci_hcd_rk_driver = {
|
||||
.probe = ohci_hcd_rk_probe,
|
||||
.remove = ohci_hcd_rk_remove,
|
||||
.shutdown = ohci_hcd_rk_shutdown,
|
||||
.driver = {
|
||||
.name = "ohci-rk",
|
||||
.of_match_table = of_match_ptr(rk_ohci_of_match),
|
||||
},
|
||||
};
|
||||
MODULE_ALIAS("platform:rockchip-ohci");
|
||||
Reference in New Issue
Block a user