mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 21:07:02 +09:00
usb: support for rk3026
This commit is contained in:
@@ -147,3 +147,52 @@ static int __init bvalid_init(void)
|
||||
}
|
||||
late_initcall(bvalid_init);
|
||||
#endif
|
||||
|
||||
#if defined(IRQ_OTG0_ID) && defined(CONFIG_ARCH_RK3026)
|
||||
#include <linux/io.h>
|
||||
#include <mach/iomux.h>
|
||||
|
||||
static irqreturn_t otg_id_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
unsigned int uoc_con;
|
||||
/* clear irq */
|
||||
uoc_con = readl_relaxed(RK2928_GRF_BASE + GRF_UOC_CON);
|
||||
|
||||
#ifdef CONFIG_RK_USB_UART
|
||||
/* to do @lyz*/
|
||||
#endif
|
||||
|
||||
if(uoc_con & (1<<1)) //id rise
|
||||
{
|
||||
writel_relaxed((0x1 << 16) | 0x1, RK2928_GRF_BASE + GRF_UOC_CON);;//clear id rise irq pandding
|
||||
}
|
||||
if(uoc_con & (1<<3))//id fall
|
||||
{
|
||||
writel_relaxed((0x3 << 16) | 0x3, RK2928_GRF_BASE + GRF_UOC_CON);;//clear id fall irq pandding
|
||||
}
|
||||
rk28_send_wakeup_key();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init otg_id_irq_init(void)
|
||||
{
|
||||
int ret;
|
||||
int irq = IRQ_OTG0_ID;
|
||||
|
||||
ret = request_irq(irq, otg_id_irq_handler, 0, "otg_id_change", NULL);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: request_irq(%d) failed\n", __func__, irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* clear & enable otg change irq */
|
||||
/* for rk3026 enable and clear id_fall_irq & id_rise_irq*/
|
||||
writel_relaxed((0xf << 16) | 0xf, RK2928_GRF_BASE + GRF_UOC_CON);
|
||||
|
||||
enable_irq_wake(irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall(otg_id_irq_init);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -29,6 +29,6 @@ dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
|
||||
dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
|
||||
dwc_otg-objs += dwc_otg_pcd.o dwc_otg_pcd_intr.o
|
||||
dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o
|
||||
dwc_otg-objs += usbdev_rk30.o usbdev_rk2928.o
|
||||
dwc_otg-objs += usbdev_rk30.o usbdev_rk2928.o usbdev_rk3026.o
|
||||
|
||||
obj-$(CONFIG_DWC_OTG) := dwc_otg.o
|
||||
|
||||
418
drivers/usb/dwc_otg/usbdev_rk3026.c
Executable file
418
drivers/usb/dwc_otg/usbdev_rk3026.c
Executable file
@@ -0,0 +1,418 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/iomux.h>
|
||||
#include <mach/cru.h>
|
||||
#ifdef CONFIG_RK_CONFIG
|
||||
#include <mach/config.h>
|
||||
#endif
|
||||
|
||||
#include "usbdev_rk.h"
|
||||
#include "dwc_otg_regs.h"
|
||||
#ifdef CONFIG_ARCH_RK3026
|
||||
|
||||
#define GRF_REG_BASE RK2928_GRF_BASE
|
||||
#define USBOTG_SIZE RK2928_USBOTG20_SIZE
|
||||
|
||||
#define USBGRF_SOC_STATUS0 (GRF_REG_BASE+0x14c)
|
||||
|
||||
#define USBGRF_UOC0_CON0 (GRF_REG_BASE+0x17c)
|
||||
#define USBGRF_UOC1_CON0 (GRF_REG_BASE+0X190)
|
||||
#define USBGRF_UOC1_CON1 (GRF_REG_BASE+0x194)
|
||||
|
||||
|
||||
int dwc_otg_check_dpdm(void)
|
||||
{
|
||||
static uint8_t * reg_base = 0;
|
||||
volatile unsigned int * otg_dctl;
|
||||
volatile unsigned int * otg_gotgctl;
|
||||
volatile unsigned int * otg_hprt0;
|
||||
int bus_status = 0;
|
||||
unsigned int * otg_phy_con0 = (unsigned int*)(USBGRF_UOC0_CON0) ;
|
||||
|
||||
*(unsigned int*)(RK2928_CRU_BASE+0x120) = ((7<<5)<<16)|(7<<5); // otg0 phy clkgate
|
||||
udelay(3);
|
||||
*(unsigned int*)(RK2928_CRU_BASE+0x120) = ((7<<5)<<16)|(0<<5); // otg0 phy clkgate
|
||||
dsb();
|
||||
*(unsigned int*)(RK2928_CRU_BASE+0xd4) = ((1<<5)<<16); // otg0 phy clkgate
|
||||
*(unsigned int*)(RK2928_CRU_BASE+0xe4) = ((1<<13)<<16); // otg0 hclk clkgate
|
||||
*(unsigned int*)(RK2928_CRU_BASE+0xf4) = ((3<<10)<<16); // hclk usb clkgat
|
||||
|
||||
// exit phy suspend
|
||||
*otg_phy_con0 = ((0x01<<0)<<16);
|
||||
|
||||
// soft connect
|
||||
if(reg_base == 0){
|
||||
reg_base = ioremap(RK2928_USBOTG20_PHYS,USBOTG_SIZE);
|
||||
if(!reg_base){
|
||||
bus_status = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
mdelay(105);
|
||||
//printk("regbase %p 0x%x, otg_phy_con%p, 0x%x\n",
|
||||
// reg_base, *(reg_base), otg_phy_con1, *otg_phy_con1);
|
||||
otg_dctl = (unsigned int * )(reg_base+0x804);
|
||||
otg_gotgctl = (unsigned int * )(reg_base);
|
||||
otg_hprt0 = (unsigned int * )(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
|
||||
if(*otg_gotgctl &(1<<19)){
|
||||
bus_status = 1;
|
||||
//*(unsigned int*)(GRF_REG_BASE + GRF_UOC0_CON0) = 0x10000000;//exit usbphy io hi-z state ***NO NEED FOR
|
||||
*otg_dctl &= ~(0x01<<1);//exit soft-disconnect mode
|
||||
mdelay(1); // delay about 1ms
|
||||
// check dp,dm
|
||||
if((*otg_hprt0 & 0xc00)==0xc00)//check hprt[11:10]
|
||||
bus_status = 2;
|
||||
//*(unsigned int*)(GRF_REG_BASE + GRF_UOC0_CON0) = 0x10001000;
|
||||
}
|
||||
out:
|
||||
return bus_status;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dwc_otg_check_dpdm);
|
||||
|
||||
|
||||
#ifdef CONFIG_USB20_OTG
|
||||
/*DWC_OTG*/
|
||||
static struct resource usb20_otg_resource[] = {
|
||||
{
|
||||
.start = IRQ_USB_OTG,
|
||||
.end = IRQ_USB_OTG,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = RK2928_USBOTG20_PHYS,
|
||||
.end = RK2928_USBOTG20_PHYS + RK2928_USBOTG20_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
void usb20otg_hw_init(void)
|
||||
{
|
||||
#ifndef CONFIG_USB20_HOST
|
||||
// close USB 2.0 HOST phy and clock
|
||||
unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON1);
|
||||
*otg_phy_con1 = 0x1D5 |(0x1ff<<16); // enter suspend.
|
||||
#endif
|
||||
// usb phy config init
|
||||
|
||||
// other hardware init
|
||||
#ifdef CONFIG_RK_CONFIG
|
||||
otg_drv_init(0);
|
||||
#else
|
||||
rk30_mux_api_set(GPIO3_C1, 1);
|
||||
#endif
|
||||
}
|
||||
void usb20otg_phy_suspend(void* pdata, int suspend)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON0);
|
||||
if(suspend){
|
||||
*otg_phy_con1 = 0x55 |(0x7f<<16); // enter suspend.
|
||||
usbpdata->phy_status = 1;
|
||||
}
|
||||
else{
|
||||
*otg_phy_con1 = (0x01<<16); // exit suspend.
|
||||
usbpdata->phy_status = 0;
|
||||
}
|
||||
}
|
||||
void usb20otg_soft_reset(void)
|
||||
{
|
||||
#if 0 //@lyz todo for 3028 phy
|
||||
printk("~~~~~~~~~~usb20otg_soft_reset\n");
|
||||
//phy reset
|
||||
*(unsigned int*)(USBGRF_UOC0_CON0) = 0x00030001;
|
||||
*(unsigned int*)(USBGRF_UOC1_CON1) = 0x00030001;
|
||||
|
||||
|
||||
cru_set_soft_reset(SOFT_RST_USBPOR, true);
|
||||
|
||||
cru_set_soft_reset(SOFT_RST_UTMI0, true);
|
||||
cru_set_soft_reset(SOFT_RST_UTMI1, true);
|
||||
|
||||
udelay(15);
|
||||
|
||||
*(unsigned int*)(USBGRF_UOC0_CON0) = 0x00030002;
|
||||
*(unsigned int*)(USBGRF_UOC1_CON1) = 0x00030002;
|
||||
|
||||
udelay(1500);
|
||||
cru_set_soft_reset(SOFT_RST_USBPOR, false);
|
||||
udelay(2);
|
||||
cru_set_soft_reset(SOFT_RST_UTMI0, false);
|
||||
cru_set_soft_reset(SOFT_RST_UTMI1, false);
|
||||
|
||||
//ctrler reset
|
||||
cru_set_soft_reset(SOFT_RST_OTGC0, true);
|
||||
cru_set_soft_reset(SOFT_RST_OTGC1, true);
|
||||
udelay(2);
|
||||
|
||||
cru_set_soft_reset(SOFT_RST_USBOTG0, true);
|
||||
cru_set_soft_reset(SOFT_RST_USBOTG1, true);
|
||||
udelay(2);
|
||||
|
||||
cru_set_soft_reset(SOFT_RST_OTGC0,false);
|
||||
cru_set_soft_reset(SOFT_RST_OTGC1,false);
|
||||
cru_set_soft_reset(SOFT_RST_USBOTG0,false);
|
||||
cru_set_soft_reset(SOFT_RST_USBOTG1,false);
|
||||
#endif
|
||||
}
|
||||
void usb20otg_clock_init(void* pdata)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
struct clk* ahbclk,*phyclk;
|
||||
ahbclk = clk_get(NULL, "hclk_otg0");
|
||||
phyclk = clk_get(NULL, "otgphy0");
|
||||
usbpdata->phyclk = phyclk;
|
||||
usbpdata->ahbclk = ahbclk;
|
||||
}
|
||||
void usb20otg_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
#if 1
|
||||
if(enable){
|
||||
clk_enable(usbpdata->ahbclk);
|
||||
clk_enable(usbpdata->phyclk);
|
||||
}
|
||||
else{
|
||||
// clk_disable(usbpdata->phyclk); /* otg/host20 use the same phyclk, so can't disable phyclk in case host20 is used.*/
|
||||
clk_disable(usbpdata->ahbclk);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
int usb20otg_get_status(int id)
|
||||
{
|
||||
int ret = -1;
|
||||
unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);
|
||||
unsigned int uoc1_con0 = *(unsigned int*)(USBGRF_UOC1_CON0);
|
||||
switch(id)
|
||||
{
|
||||
case USB_STATUS_BVABLID:
|
||||
// bvalid in grf
|
||||
ret = (usbgrf_status &(1<<7));
|
||||
break;
|
||||
case USB_STATUS_DPDM:
|
||||
// dpdm in grf
|
||||
ret = (usbgrf_status &(3<<8));
|
||||
break;
|
||||
case USB_STATUS_ID:
|
||||
// id in grf
|
||||
ret = (usbgrf_status &(1<<10));
|
||||
break;
|
||||
case USB_STATUS_UARTMODE:
|
||||
// usb_uart_mode in grf
|
||||
ret = (uoc1_con0 &(1<<13));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)
|
||||
{
|
||||
#ifdef CONFIG_RK_USB_UART
|
||||
//struct dwc_otg_platform_data *usbpdata=pdata;//1:uart 0:usb
|
||||
unsigned int * otg_phy_con0 = (unsigned int*)(USBGRF_UOC1_CON0);
|
||||
//printk("usb_uart_mode = %d,enter_usb_uart_mode = %d\n",otg_phy_con1,enter_usb_uart_mode);
|
||||
if(1 == enter_usb_uart_mode) //uart mode
|
||||
{
|
||||
*otg_phy_con0 = (0x03 << 12 | (0x03<<(16+12)));//bypass dm
|
||||
//printk("phy enter uart mode USBGRF_UOC1_CON0 = %08x\n",*otg_phy_con1);
|
||||
|
||||
}
|
||||
if(0 == enter_usb_uart_mode) //usb mode
|
||||
{
|
||||
*otg_phy_con0 = (0x03<<(12+16)); //bypass dm disable
|
||||
//printk("phy enter usb mode USBGRF_UOC1_CON0 = %8x\n",*otg_phy_con1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void usb20otg_power_enable(int enable)
|
||||
{
|
||||
#ifdef CONFIG_RK_CONFIG
|
||||
if(enable)
|
||||
otg_drv_on();
|
||||
else
|
||||
otg_drv_off();
|
||||
#endif
|
||||
}
|
||||
struct dwc_otg_platform_data usb20otg_pdata = {
|
||||
.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,
|
||||
.dwc_otg_uart_mode=dwc_otg_uart_mode,
|
||||
};
|
||||
|
||||
struct platform_device device_usb20_otg = {
|
||||
.name = "usb20_otg",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(usb20_otg_resource),
|
||||
.resource = usb20_otg_resource,
|
||||
.dev = {
|
||||
.platform_data = &usb20otg_pdata,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_USB20_HOST
|
||||
static struct resource usb20_host_resource[] = {
|
||||
{
|
||||
.start = IRQ_USB_HOST,
|
||||
.end = IRQ_USB_HOST,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = RK2928_USBHOST20_PHYS,
|
||||
.end = RK2928_USBHOST20_PHYS + RK2928_USBHOST20_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
void usb20host_hw_init(void)
|
||||
{
|
||||
// usb phy config init
|
||||
|
||||
// other haredware init
|
||||
#ifdef CONFIG_RK_CONFIG
|
||||
host_drv_init(1);
|
||||
#endif
|
||||
}
|
||||
void usb20host_phy_suspend(void* pdata, int suspend)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON1);
|
||||
|
||||
if(suspend){
|
||||
//*otg_phy_con2 = (1 << 12 | 1 << (12+16));//host io set to High-Z state ***NO NEED FOR 3026
|
||||
*otg_phy_con1 = 0x1D5 |(0x1ff<<16); // enter suspend.
|
||||
usbpdata->phy_status = 1;
|
||||
}
|
||||
else{
|
||||
//*otg_phy_con2 = (1 << 12+16);//host io exit High-Z state ***NO NEED FOR 3026
|
||||
*otg_phy_con1 = (0x01<<16); // exit suspend.
|
||||
usbpdata->phy_status = 0;
|
||||
}
|
||||
}
|
||||
void usb20host_soft_reset(void)
|
||||
{
|
||||
#if 0
|
||||
cru_set_soft_reset(SOFT_RST_USBOTG1, true);
|
||||
//cru_set_soft_reset(SOFT_RST_USBPHY1, true);
|
||||
cru_set_soft_reset(SOFT_RST_OTGC1, true);
|
||||
|
||||
udelay(1);
|
||||
|
||||
cru_set_soft_reset(SOFT_RST_USBOTG1, false);
|
||||
//cru_set_soft_reset(SOFT_RST_USBPHY1, false);
|
||||
cru_set_soft_reset(SOFT_RST_OTGC1, false);
|
||||
mdelay(1);
|
||||
#endif
|
||||
}
|
||||
void usb20host_clock_init(void* pdata)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
struct clk* ahbclk,*phyclk;
|
||||
ahbclk = clk_get(NULL, "hclk_otg1");
|
||||
phyclk = clk_get(NULL, "otgphy1");
|
||||
usbpdata->phyclk = phyclk;
|
||||
usbpdata->ahbclk = ahbclk;
|
||||
}
|
||||
void usb20host_clock_enable(void* pdata, int enable)
|
||||
{
|
||||
struct dwc_otg_platform_data *usbpdata=pdata;
|
||||
#if 1
|
||||
if(enable){
|
||||
clk_enable(usbpdata->ahbclk);
|
||||
clk_enable(usbpdata->phyclk);
|
||||
}
|
||||
else{
|
||||
clk_disable(usbpdata->phyclk);
|
||||
clk_disable(usbpdata->ahbclk);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
int usb20host_get_status(int id)
|
||||
{
|
||||
int ret = -1;
|
||||
unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);
|
||||
switch(id)
|
||||
{
|
||||
case USB_STATUS_BVABLID:
|
||||
// bvalid in grf
|
||||
ret = (usbgrf_status &(1<<12));
|
||||
break;
|
||||
case USB_STATUS_DPDM:
|
||||
// dpdm in grf
|
||||
ret = (usbgrf_status &(3<<13));
|
||||
break;
|
||||
case USB_STATUS_ID:
|
||||
// id in grf
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
void usb20host_power_enable(int enable)
|
||||
{
|
||||
#ifdef CONFIG_RK_CONFIG
|
||||
if(enable)
|
||||
host_drv_on();
|
||||
else
|
||||
host_drv_off();
|
||||
#endif
|
||||
}
|
||||
struct dwc_otg_platform_data usb20host_pdata = {
|
||||
.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,
|
||||
};
|
||||
|
||||
struct platform_device device_usb20_host = {
|
||||
.name = "usb20_host",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(usb20_host_resource),
|
||||
.resource = usb20_host_resource,
|
||||
.dev = {
|
||||
.platform_data = &usb20host_pdata,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
static int __init usbdev_init_devices(void)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef CONFIG_USB20_OTG
|
||||
ret = platform_device_register(&device_usb20_otg);
|
||||
if(ret < 0){
|
||||
printk("%s: platform_device_register(usb20_otg) failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_USB20_HOST
|
||||
ret = platform_device_register(&device_usb20_host);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
arch_initcall(usbdev_init_devices);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user