USB: RK3288 USB CTLR initialization

This commit is contained in:
wlf
2014-03-11 11:14:10 +08:00
parent 3639a7091d
commit 7f63aac704
15 changed files with 1767 additions and 265 deletions

View File

@@ -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>,

View File

@@ -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";*/
};
};

View File

@@ -19,6 +19,7 @@ config USB_ARCH_HAS_OHCI
default y if ARCH_CNS3XXX
default y if PLAT_SPEAR
default y if ARCH_EXYNOS
default y if ARCH_ROCKCHIP
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx

View File

@@ -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

View File

@@ -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,

View 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

View File

@@ -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

View File

@@ -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)

View 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");

View File

@@ -102,6 +102,7 @@ if USB_EHCI_HCD
config USB_EHCI_RKHSIC
tristate "Rockchip EHCI HSIC support"
depends on ARCH_ROCKCHIP
select USB_EHCI_ROOT_HUB_TT
default n
---help---
@@ -109,6 +110,7 @@ config USB_EHCI_RKHSIC
config USB_EHCI_RK
tristate "Rockchip EHCI HOST20 support"
depends on ARCH_ROCKCHIP
select USB_EHCI_ROOT_HUB_TT
default n
---help---
@@ -379,6 +381,13 @@ config USB_OHCI_HCD
if USB_OHCI_HCD
config USB_OHCI_HCD_RK
bool "OHCI support for RK3288 and later chips"
depends on ARCH_ROCKCHIP
default n
---help---
Enable support for the OHCI controller on RK3288 and later chips.
config USB_OHCI_HCD_OMAP1
bool "OHCI support for OMAP1/2 chips"
depends on ARCH_OMAP1

View File

@@ -1268,7 +1268,7 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_USB_EHCI_RKHSIC
#include "ehci-rkhsic.c"
#define PLATFORM_DRIVER ehci_rkhsic_driver
#define RK_PLATFORM_DRIVER ehci_rkhsic_driver
#endif
#ifdef CONFIG_USB_EHCI_HCD_PMC_MSP
@@ -1346,8 +1346,19 @@ static int __init ehci_hcd_init(void)
if (retval < 0)
goto clean4;
#endif
#ifdef RK_PLATFORM_DRIVER
retval = platform_driver_register(&RK_PLATFORM_DRIVER);
if (retval < 0)
goto clean5;
#endif
return retval;
#ifdef RK_PLATFORM_DRIVER
platform_driver_unregister(&RK_PLATFORM_DRIVER);
clean5:
#endif
#ifdef XILINX_OF_PLATFORM_DRIVER
/* platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER); */
clean4:
@@ -1376,6 +1387,9 @@ module_init(ehci_hcd_init);
static void __exit ehci_hcd_cleanup(void)
{
#ifdef RK_PLATFORM_DRIVER
platform_driver_unregister(&RK_PLATFORM_DRIVER);
#endif
#ifdef XILINX_OF_PLATFORM_DRIVER
platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER);
#endif

View File

@@ -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,

View File

@@ -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,

View File

@@ -1191,6 +1191,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_tilegx_driver
#endif
#ifdef CONFIG_USB_OHCI_HCD_RK
#include "ohci-rk.c"
#define PLATFORM_DRIVER ohci_hcd_rk_driver
#endif
#ifdef CONFIG_USB_OHCI_HCD_PLATFORM
#include "ohci-platform.c"
#define PLATFORM_DRIVER ohci_platform_driver

258
drivers/usb/host/ohci-rk.c Executable file
View 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");