summary refs log tree commit diff
path: root/drivers/usb/gadget/mv_udc_phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/mv_udc_phy.c')
-rw-r--r--drivers/usb/gadget/mv_udc_phy.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/drivers/usb/gadget/mv_udc_phy.c b/drivers/usb/gadget/mv_udc_phy.c
new file mode 100644
index 000000000000..d4dea97e38a5
--- /dev/null
+++ b/drivers/usb/gadget/mv_udc_phy.c
@@ -0,0 +1,214 @@
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+
+#include <mach/cputype.h>
+
+#ifdef CONFIG_ARCH_MMP
+
+#define UTMI_REVISION		0x0
+#define UTMI_CTRL		0x4
+#define UTMI_PLL		0x8
+#define UTMI_TX			0xc
+#define UTMI_RX			0x10
+#define UTMI_IVREF		0x14
+#define UTMI_T0			0x18
+#define UTMI_T1			0x1c
+#define UTMI_T2			0x20
+#define UTMI_T3			0x24
+#define UTMI_T4			0x28
+#define UTMI_T5			0x2c
+#define UTMI_RESERVE		0x30
+#define UTMI_USB_INT		0x34
+#define UTMI_DBG_CTL		0x38
+#define UTMI_OTG_ADDON		0x3c
+
+/* For UTMICTRL Register */
+#define UTMI_CTRL_USB_CLK_EN			(1 << 31)
+/* pxa168 */
+#define UTMI_CTRL_SUSPEND_SET1			(1 << 30)
+#define UTMI_CTRL_SUSPEND_SET2			(1 << 29)
+#define UTMI_CTRL_RXBUF_PDWN			(1 << 24)
+#define UTMI_CTRL_TXBUF_PDWN			(1 << 11)
+
+#define UTMI_CTRL_INPKT_DELAY_SHIFT		30
+#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT		28
+#define UTMI_CTRL_PU_REF_SHIFT			20
+#define UTMI_CTRL_ARC_PULLDN_SHIFT		12
+#define UTMI_CTRL_PLL_PWR_UP_SHIFT		1
+#define UTMI_CTRL_PWR_UP_SHIFT			0
+/* For UTMI_PLL Register */
+#define UTMI_PLL_CLK_BLK_EN_SHIFT		24
+#define UTMI_PLL_FBDIV_SHIFT			4
+#define UTMI_PLL_REFDIV_SHIFT			0
+#define UTMI_PLL_FBDIV_MASK			0x00000FF0
+#define UTMI_PLL_REFDIV_MASK			0x0000000F
+#define UTMI_PLL_ICP_MASK			0x00007000
+#define UTMI_PLL_KVCO_MASK			0x00031000
+#define UTMI_PLL_PLLCALI12_SHIFT		29
+#define UTMI_PLL_PLLCALI12_MASK			(0x3 << 29)
+#define UTMI_PLL_PLLVDD18_SHIFT			27
+#define UTMI_PLL_PLLVDD18_MASK			(0x3 << 27)
+#define UTMI_PLL_PLLVDD12_SHIFT			25
+#define UTMI_PLL_PLLVDD12_MASK			(0x3 << 25)
+#define UTMI_PLL_KVCO_SHIFT			15
+#define UTMI_PLL_ICP_SHIFT			12
+/* For UTMI_TX Register */
+#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT		27
+#define UTMI_TX_REG_EXT_FS_RCAL_MASK		(0xf << 27)
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK		26
+#define UTMI_TX_REG_EXT_FS_RCAL_EN		(0x1 << 26)
+#define UTMI_TX_LOW_VDD_EN_SHIFT		11
+#define UTMI_TX_IMPCAL_VTH_SHIFT		14
+#define UTMI_TX_IMPCAL_VTH_MASK			(0x7 << 14)
+#define UTMI_TX_CK60_PHSEL_SHIFT		17
+#define UTMI_TX_CK60_PHSEL_MASK			(0xf << 17)
+#define UTMI_TX_TXVDD12_SHIFT                   22
+#define UTMI_TX_TXVDD12_MASK			(0x3 << 22)
+#define UTMI_TX_AMP_SHIFT			0
+#define UTMI_TX_AMP_MASK			(0x7 << 0)
+/* For UTMI_RX Register */
+#define UTMI_RX_SQ_THRESH_SHIFT			4
+#define UTMI_RX_SQ_THRESH_MASK			(0xf << 4)
+#define UTMI_REG_SQ_LENGTH_SHIFT		15
+#define UTMI_REG_SQ_LENGTH_MASK			(0x3 << 15)
+
+#define REG_RCAL_START				0x00001000
+#define VCOCAL_START				0x00200000
+#define KVCO_EXT				0x00400000
+#define PLL_READY				0x00800000
+#define CLK_BLK_EN				0x01000000
+#endif
+
+static unsigned int u2o_read(unsigned int base, unsigned int offset)
+{
+	return readl(base + offset);
+}
+
+static void u2o_set(unsigned int base, unsigned int offset, unsigned int value)
+{
+	unsigned int reg;
+
+	reg = readl(base + offset);
+	reg |= value;
+	writel(reg, base + offset);
+	readl(base + offset);
+}
+
+static void u2o_clear(unsigned int base, unsigned int offset,
+	unsigned int value)
+{
+	unsigned int reg;
+
+	reg = readl(base + offset);
+	reg &= ~value;
+	writel(reg, base + offset);
+	readl(base + offset);
+}
+
+static void u2o_write(unsigned int base, unsigned int offset,
+	unsigned int value)
+{
+	writel(value, base + offset);
+	readl(base + offset);
+}
+
+#ifdef CONFIG_ARCH_MMP
+int mv_udc_phy_init(unsigned int base)
+{
+	unsigned long timeout;
+
+	/* Initialize the USB PHY power */
+	if (cpu_is_pxa910()) {
+		u2o_set(base, UTMI_CTRL, (1 << UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
+			| (1 << UTMI_CTRL_PU_REF_SHIFT));
+	}
+
+	u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PLL_PWR_UP_SHIFT);
+	u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PWR_UP_SHIFT);
+
+	/* UTMI_PLL settings */
+	u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
+		| UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
+		| UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
+		| UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
+
+	u2o_set(base, UTMI_PLL, (0xee << UTMI_PLL_FBDIV_SHIFT)
+		| (0xb << UTMI_PLL_REFDIV_SHIFT)
+		| (3 << UTMI_PLL_PLLVDD18_SHIFT)
+		| (3 << UTMI_PLL_PLLVDD12_SHIFT)
+		| (3 << UTMI_PLL_PLLCALI12_SHIFT)
+		| (1 << UTMI_PLL_ICP_SHIFT) | (3 << UTMI_PLL_KVCO_SHIFT));
+
+	/* UTMI_TX */
+	u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
+		| UTMI_TX_TXVDD12_MASK
+		| UTMI_TX_CK60_PHSEL_MASK | UTMI_TX_IMPCAL_VTH_MASK
+		| UTMI_TX_REG_EXT_FS_RCAL_MASK | UTMI_TX_AMP_MASK);
+	u2o_set(base, UTMI_TX, (3 << UTMI_TX_TXVDD12_SHIFT)
+		| (4 << UTMI_TX_CK60_PHSEL_SHIFT)
+		| (4 << UTMI_TX_IMPCAL_VTH_SHIFT)
+		| (8 << UTMI_TX_REG_EXT_FS_RCAL_SHIFT)
+		| (3 << UTMI_TX_AMP_SHIFT));
+
+	/* UTMI_RX */
+	u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
+		| UTMI_REG_SQ_LENGTH_MASK);
+	if (cpu_is_pxa168())
+		u2o_set(base, UTMI_RX, (7 << UTMI_RX_SQ_THRESH_SHIFT)
+			| (2 << UTMI_REG_SQ_LENGTH_SHIFT));
+	else
+		u2o_set(base, UTMI_RX, (0x7 << UTMI_RX_SQ_THRESH_SHIFT)
+			| (2 << UTMI_REG_SQ_LENGTH_SHIFT));
+
+	/* UTMI_IVREF */
+	if (cpu_is_pxa168())
+		/*
+		 * fixing Microsoft Altair board interface with NEC hub issue -
+		 * Set UTMI_IVREF from 0x4a3 to 0x4bf
+		 */
+		u2o_write(base, UTMI_IVREF, 0x4bf);
+
+	/* calibrate */
+	timeout = jiffies + 100;
+	while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
+		if (time_after(jiffies, timeout))
+			return -ETIME;
+		cpu_relax();
+	}
+
+	/* toggle VCOCAL_START bit of UTMI_PLL */
+	udelay(200);
+	u2o_set(base, UTMI_PLL, VCOCAL_START);
+	udelay(40);
+	u2o_clear(base, UTMI_PLL, VCOCAL_START);
+
+	/* toggle REG_RCAL_START bit of UTMI_TX */
+	udelay(200);
+	u2o_set(base, UTMI_TX, REG_RCAL_START);
+	udelay(40);
+	u2o_clear(base, UTMI_TX, REG_RCAL_START);
+	udelay(200);
+
+	/* make sure phy is ready */
+	timeout = jiffies + 100;
+	while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
+		if (time_after(jiffies, timeout))
+			return -ETIME;
+		cpu_relax();
+	}
+
+	if (cpu_is_pxa168()) {
+		u2o_set(base, UTMI_RESERVE, 1 << 5);
+		/* Turn on UTMI PHY OTG extension */
+		u2o_write(base, UTMI_OTG_ADDON, 1);
+	}
+	return 0;
+}
+#else
+int mv_udc_phy_init(unsigned int base)
+{
+	return 0;
+}
+#endif