blob: 1525507a5b508613f7ac4e486b8124bf2cca6b9f [file] [log] [blame]
/*
* usb.c - contains block specific initialisation routines
*
* Copyright (C) 2009-2012 Imagination Technologies Ltd.
*
*/
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
#include <asm/global_lock.h>
#include <asm/soc-tz1090/defs.h>
#include <asm/soc-tz1090/usb.h>
#define COMET_XTAL5 12000000
/*
* Note: To use USB XTAL5 must be fitted with a 12 or 24MHz XTAL and the Jumpers
* set appropriately to select this as the clock source for the USB PHY.
*/
static void vbus_valid(int normal)
{
int lstat;
u32 temp;
/*
* When this bit is clear, host communication is prevented, allowing the
* device to complete power-up and initialisation without the host
* seeing errors.
*/
__global_lock2(lstat);
temp = readl(CR_PERIP_USB_PHY_TUNE_CONTROL);
if (normal)
temp |= CR_PERIP_USB_VMT_VBUSVALID;
else
temp &= ~CR_PERIP_USB_VMT_VBUSVALID;
writel(temp, CR_PERIP_USB_PHY_TUNE_CONTROL);
__global_unlock2(lstat);
}
static void comet_usb_init(void)
{
int lstat;
u8 xtal_val = 1;
u32 temp;
/*enable module clock*/
__global_lock2(lstat);
temp = readl(CR_TOP_CLKENAB);
temp |= (1<<CR_TOP_USB_CLK_1_EN_BIT);
writel(temp, CR_TOP_CLKENAB);
__global_unlock2(lstat);
/* Set up REFCLKS, Need to assert power on reset while we change this */
if (COMET_XTAL5 == 12000000)
xtal_val = 0;
else if (COMET_XTAL5 == 24000000)
xtal_val = 1;
else
printk(KERN_WARNING "Comet USB Init: "
"Unsupported value for XTAL 5\n");
/* Delay host comms until we're set up */
vbus_valid(0);
__global_lock2(lstat);
/* Reset USB Block*/
temp = readl(CR_PERIP_SRST);
temp |= CR_PERIP_USB_PHY_PON_RESET_BIT;
temp |= CR_PERIP_USB_PHY_PORTRESET_BIT;
writel(temp, CR_PERIP_SRST);
/*Set Clock input to XTAL5 and set frequency */
temp = readl(CR_PERIP_USB_PHY_STRAP_CONTROL);
temp &= ~CR_PERIP_USB_REFCLKSEL_BITS;
temp |= (0 << CR_PERIP_USB_REFCLKSEL_SHIFT);
temp &= ~CR_PERIP_USB_REFCLKDIV_BITS;
temp |= xtal_val << CR_PERIP_USB_REFCLKDIV_SHIFT;
writel(temp, CR_PERIP_USB_PHY_STRAP_CONTROL);
/* Release Reset of USB BLock*/
temp = readl(CR_PERIP_SRST);
temp &= ~CR_PERIP_USB_PHY_PON_RESET_BIT;
temp &= ~CR_PERIP_USB_PHY_PORTRESET_BIT;
writel(temp, CR_PERIP_SRST);
__global_unlock2(lstat);
/*Now configure the PHY*/
/* Turn isolation off (done in sample code note sure why ??)*/
__global_lock2(lstat);
temp = readl(CR_PERIP_USB_PHY_STRAP_CONTROL);
temp |= CR_PERIP_USB_ISO_PHY_BIT;
writel(temp, CR_PERIP_USB_PHY_STRAP_CONTROL);
__global_unlock2(lstat);
/*Wait until PHY and UTMI are ready */
#if 0 /*THIS CODE WON'T WORK FOR ES1 DUE TO A HARDWARE PROBLEM*/
while (1) {
u32 temp2 = readl(CR_PERIP_USB_PHY_STATUS);
if ((temp2 & CR_PERIP_USB_RX_PHY_CLK) &&
(temp2 & CR_PERIP_USB_RX_UTMI_CLK))
break;
}
#endif
}
static struct dwc_otg_board comet_usb_board_data = {
.vbus_valid = vbus_valid,
};
static struct resource comet_usb_resources[] = {
[0] = {
.start = USB_IRQ_NUM,
/* mapped in comet_usb_setup() */
.flags = IORESOURCE_IRQ,
},
[1] = {
.start = USB_BASE_ADDR,
.end = USB_BASE_ADDR + USB_SIZE,
.flags = IORESOURCE_MEM,
},
};
static u64 usb_dmamask = DMA_BIT_MASK(32);
static struct platform_device comet_usb_device = {
.name = "dwc_otg",
.id = 0,
.num_resources = ARRAY_SIZE(comet_usb_resources),
.resource = comet_usb_resources,
.dev = {
.dma_mask = &usb_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &comet_usb_board_data,
},
};
#ifdef CONFIG_PM_SLEEP
static int comet_usb_suspend(void)
{
return 0;
}
static void comet_usb_resume(void)
{
comet_usb_init();
}
#else
#define comet_usb_suspend NULL
#define comet_usb_resume NULL
#endif /* CONFIG_PM_SLEEP */
static struct syscore_ops comet_usb_syscore_ops = {
.suspend = comet_usb_suspend,
.resume = comet_usb_resume,
};
int __init comet_usb_setup(const struct dwc_otg_board *board)
{
int ret;
/* use board specific vbus callbacks */
comet_usb_board_data.enable_vbus = board->enable_vbus;
comet_usb_board_data.disable_vbus = board->disable_vbus;
/* map irq */
ret = external_irq_map(comet_usb_resources[0].start);
if (ret < 0)
goto out;
comet_usb_resources[0].start = ret;
comet_usb_resources[0].end = ret;
comet_usb_init();
ret = platform_device_register(&comet_usb_device);
if (ret)
goto out;
register_syscore_ops(&comet_usb_syscore_ops);
out:
return ret;
}