Ejemplo n.º 1
0
static int ehci_omap_bus_resume(struct usb_hcd *hcd)
{
	u32 sysconfig;
	unsigned long flags;
	struct ehci_hcd_omap *omap = dev_get_drvdata(hcd->self.controller);

	dev_dbg(hcd->self.controller, "%s %ld %lu\n", __func__,
	in_interrupt(), jiffies);

#ifdef CONFIG_HAS_WAKELOCK
	wake_lock(&omap->ehci->wake_lock_ehci_pm);
#endif
	spin_lock_irqsave(&usb_clocks_lock, flags);
	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		if (omap->usbtll_fck)
			clk_enable(omap->usbtll_fck);
		mdelay(1);
		ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE, 0);
		ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQSTATUS, 7);
		ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF,
			1 | ehci_omap_readl(omap->tll_base,
				OMAP_TLL_SHARED_CONF));
		if (omap->usbhost2_120m_fck)
			clk_enable(omap->usbhost2_120m_fck);
		if (omap->usbhost1_48m_fck)
			clk_enable(omap->usbhost1_48m_fck);

		/* Put UHH in NoStandby mode */
		sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		sysconfig &= ~OMAP_UHH_SYSCONFIG_MIDLEMODE_MASK;
		sysconfig |= OMAP_UHH_SYSCONFIG_NOSTBYMODE;
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig);

		/* Put UHH in NoIdle mode */
		sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		sysconfig &= ~OMAP_UHH_SYSCONFIG_SIDLEMODE_MASK;
		sysconfig |= OMAP_UHH_SYSCONFIG_NOIDLEMODE;
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig);
		sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);

		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		enable_irq(hcd->irq);
	}
	spin_unlock_irqrestore(&usb_clocks_lock, flags);

	return ehci_bus_resume(hcd);
}
Ejemplo n.º 2
0
/*-------------------------------------------------------------------------*/
static int omap_ehci_bus_suspend(struct device *dev)
{
	struct ehci_hcd_omap *omap = gb_omap;
	int ret = 0;
	unsigned reg = 0;

	if (!omap->suspended) {
		/* Enable forced idle mode */
		reg = ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSCONFIG);
		reg &= ~OMAP_USBTLL_SYSCONFIG_SIDLEMASK;
		reg |= OMAP_USBTLL_SYSCONFIG_S_FORCED_IDLE;
		ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, reg);

		/* Enable forced Idle/Standby mode */
		reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK
				| OMAP_UHH_SYSCONFIG_MIDLEMASK);
		reg |= OMAP_UHH_SYSCONFIG_S_FORCED_IDLE
				| OMAP_UHH_SYSCONFIG_M_FORCED_STDBY;
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);

		clk_disable(omap->usbtll_fck);
		clk_put(omap->usbtll_fck);
		omap->usbtll_fck = NULL;

		clk_disable(omap->usbhost_ick);
		clk_put(omap->usbhost_ick);
		omap->usbhost_ick = NULL;

		clk_disable(omap->usbhost1_48m_fck);
		clk_put(omap->usbhost1_48m_fck);
		omap->usbhost1_48m_fck = NULL;

		clk_disable(omap->usbhost2_120m_fck);
		clk_put(omap->usbhost2_120m_fck);
		omap->usbhost2_120m_fck = NULL;

		clk_disable(omap->usbtll_ick);
		clk_put(omap->usbtll_ick);
		omap->usbtll_ick = NULL;
		omap->suspended = 1;
	}

	return ret;
}
Ejemplo n.º 3
0
static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask,
				u8 tll_channel_count)
{
	unsigned reg;
	int i;

	/* Program the 3 TLL channels upfront */
	for (i = 0; i < tll_channel_count; i++) {
		reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));

		/* Disable AutoIdle, BitStuffing and use SDR Mode */
		reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
				| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
				| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
		ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg);
	}

	/* Program Common TLL register */
	reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF);
	reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON
			| OMAP_TLL_SHARED_CONF_USB_DIVRATION
			| OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN);
	reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN;

	ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg);

	/* Enable channels now */
	for (i = 0; i < tll_channel_count; i++) {
		reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));

		/* Enable only the reg that is needed */
		if (!(tll_channel_mask & 1<<i))
			continue;

		reg |= OMAP_TLL_CHANNEL_CONF_CHANEN;
		ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg);

		ehci_omap_writeb(omap->tll_base,
				OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe);
		dev_dbg(omap->dev, "ULPI_SCRATCH_REG[ch=%d]= 0x%02x\n",
				i+1, ehci_omap_readb(omap->tll_base,
				OMAP_TLL_ULPI_SCRATCH_REGISTER(i)));
	}
}
Ejemplo n.º 4
0
/*-------------------------------------------------------------------------
 *
 */
static int setup_tll(struct ehci_hcd_omap *omap)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	int ret = 0;
	u8 tll_ch_mask = 0;

	/* perform TLL soft reset, and wait until reset is complete */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_SOFTRESET);

	/* Wait for TLL reset to complete */
	while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) &
		OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
		cpu_relax();
		if (time_after(jiffies, timeout)) {
			dev_dbg(omap->dev, "operation timed out\n");
			ret = -EINVAL;
			return ret;
		}
	}

	dev_dbg(omap->dev, "TLL RESET DONE\n");
	/* (1<<3) = no idle mode only for initial debugging */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
			OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
			OMAP_USBTLL_SYSCONFIG_CACTIVITY);

	if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
		tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK;
	if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
		tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK;

	if (!cpu_is_omap44xx()) {
		if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK;
		if (tll_ch_mask != 0)
			omap_usb_utmi_init(omap, tll_ch_mask,OMAP_TLL_CHANNEL_COUNT);
	} else {
		if (tll_ch_mask != 0)
			omap_usb_utmi_init(omap, tll_ch_mask, OMAP4_TLL_CHANNEL_COUNT);
	}
	return ret;
}
Ejemplo n.º 5
0
static int omap_ehci_bus_resume(struct usb_hcd *hcd)
{
	struct ehci_hcd_omap *omap;
	unsigned long flags;
	int ret = 0;
	u32 reg;

	omap = ((struct  ehci_hcd *)
		((char *)hcd_to_ehci(hcd)))->omap_p;

	spin_lock_irqsave(&sus_res_lock, flags);
	if(omap->suspended){
		clk_enable(omap->usbtll_fck);

		reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF);
		reg |=1;
		ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg);

		clk_enable(omap->usbhost_fck);
		clk_enable(omap->usbhost_fs_fck);

		omap_writel(OHCI_HC_CTRL_RESUME, OHCI_HC_CONTROL);

		reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		reg &= ~(3 << 12);
		reg &= ~(3 << 3);
		reg |= (1 << 12);
		reg |= (1 << 3);
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);

		omap->suspended = 0;
		ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE, 0);
	}

	ret = ehci_bus_resume(hcd);
	spin_unlock_irqrestore(&sus_res_lock, flags);
	return 0;
}
Ejemplo n.º 6
0
/* omap_start_ehc
 *	- Start the TI USBHOST controller
 */
static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	unsigned reg = 0;
	int ret = 0;
	int reset_delay;
	int i;

	dev_dbg(&omap->dev->dev, "starting TI EHCI USB Controller\n");

	/* Enable Clocks for USBHOST */
	omap->usbhost_ick = clk_get(&omap->dev->dev, "usbhost_ick");
	if (IS_ERR(omap->usbhost_ick)) {
		ret =  PTR_ERR(omap->usbhost_ick);
		goto err_host_ick;
	}
	clk_enable(omap->usbhost_ick);

	omap->usbhost2_120m_fck = clk_get(&omap->dev->dev, "usbhost_120m_fck");
	if (IS_ERR(omap->usbhost2_120m_fck)) {
		ret = PTR_ERR(omap->usbhost2_120m_fck);
		goto err_host_120m_fck;
	}
	clk_enable(omap->usbhost2_120m_fck);

	omap->usbhost1_48m_fck = clk_get(&omap->dev->dev, "usbhost_48m_fck");
	if (IS_ERR(omap->usbhost1_48m_fck)) {
		ret = PTR_ERR(omap->usbhost1_48m_fck);
		goto err_host_48m_fck;
	}
	clk_enable(omap->usbhost1_48m_fck);

	reset_delay = 0;
	for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
		reset_delay = reset_delay > omap->port_data[i].reset_delay ?
			reset_delay : omap->port_data[i].reset_delay;

		if (omap->port_data[i].startup) {
			ret = omap->port_data[i].startup(omap->dev, i);
			if (ret < 0)
				return ret;
		}

		if (omap->port_data[i].reset)
			omap->port_data[i].reset(omap->dev, i, 0);
	}
	if (reset_delay)
		udelay(reset_delay);

	/* Configure TLL for 60Mhz clk for ULPI */
	omap->usbtll_fck = clk_get(&omap->dev->dev, "usbtll_fck");
	if (IS_ERR(omap->usbtll_fck)) {
		ret = PTR_ERR(omap->usbtll_fck);
		goto err_tll_fck;
	}
	clk_enable(omap->usbtll_fck);

	omap->usbtll_ick = clk_get(&omap->dev->dev, "usbtll_ick");
	if (IS_ERR(omap->usbtll_ick)) {
		ret = PTR_ERR(omap->usbtll_ick);
		goto err_tll_ick;
	}
	clk_enable(omap->usbtll_ick);

	/* perform TLL soft reset, and wait until reset is complete */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_SOFTRESET);

	/* Wait for TLL reset to complete */
	while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
			& OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
		cpu_relax();

		if (time_after(jiffies, timeout)) {
			dev_dbg(&omap->dev->dev, "operation timed out\n");
			ret = -EINVAL;
			goto err_sys_status;
		}
	}

	dev_dbg(&omap->dev->dev, "TLL RESET DONE\n");

	/* (1<<3) = no idle mode only for initial debugging */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
			OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
			OMAP_USBTLL_SYSCONFIG_CACTIVITY);


	/* Put UHH in NoIdle/NoStandby mode */
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG,
			 OMAP_UHH_SYSCONFIG_ENAWAKEUP
			 | OMAP_UHH_SYSCONFIG_SIDLEMODE
			 | OMAP_UHH_SYSCONFIG_MIDLEMODE
			 | OMAP_UHH_SYSCONFIG_AUTOIDLE);

	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);

	/* setup ULPI bypass and burst configurations */
	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;


	if (omap->port_data[0].flags != EHCI_HCD_OMAP_FLAG_ENABLED)
		reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
	if (omap->port_data[1].flags != EHCI_HCD_OMAP_FLAG_ENABLED)
		reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
	if (omap->port_data[2].flags != EHCI_HCD_OMAP_FLAG_ENABLED)
		reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;

	/* Bypass the TLL module for PHY mode operation */
	 if (omap_rev() <= OMAP3430_REV_ES2_1) {
		dev_dbg(&omap->dev->dev, "OMAP3 ES version <= ES2.1 \n");
		if (omap_usb_port_ulpi_bypass(omap->port_data[0].mode))
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
		else
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
	} else {
		dev_dbg(&omap->dev->dev, "OMAP3 ES version > ES2.1\n");
		if (omap_usb_port_ulpi_bypass(omap->port_data[0].mode))
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
		else
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;

		if (omap_usb_port_ulpi_bypass(omap->port_data[1].mode))
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
		else
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;

		if (omap_usb_port_ulpi_bypass(omap->port_data[2].mode))
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
		else
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
	}
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
	dev_dbg(&omap->dev->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);

	/* Enable UTMI mode for required TLL channels */
	omap_usb_utmi_init(omap);

	reset_delay = 0;
	for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
		reset_delay = reset_delay > omap->port_data[i].reset_delay ?
				reset_delay : omap->port_data[i].reset_delay;
	}
	if (reset_delay)
		udelay(reset_delay);

	for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
		if (omap->port_data[i].reset)
			omap->port_data[i].reset(omap->dev, i, 1);
	}
	return 0;

err_sys_status:
	clk_disable(omap->usbtll_ick);
	clk_put(omap->usbtll_ick);

err_tll_ick:
	clk_disable(omap->usbtll_fck);
	clk_put(omap->usbtll_fck);

err_tll_fck:
	clk_disable(omap->usbhost1_48m_fck);
	clk_put(omap->usbhost1_48m_fck);

err_host_48m_fck:
	clk_disable(omap->usbhost2_120m_fck);
	clk_put(omap->usbhost2_120m_fck);

err_host_120m_fck:
	clk_disable(omap->usbhost_ick);
	clk_put(omap->usbhost_ick);

err_host_ick:
	return ret;
}
Ejemplo n.º 7
0
static void omap_usb_utmi_init(struct ehci_hcd_omap *omap)
{
	unsigned reg;
	int i;

	/* Program the 3 TLL channels upfront */
	for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
		reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));
		dev_dbg(&omap->dev->dev,
			"port %d: OMAP_TTL_CHANNEL_CONF_%d=%08x\n",
			i, i+1, ehci_omap_readl(omap->tll_base,
						OMAP_TLL_CHANNEL_CONF(i)));

		if (omap->port_data[i].flags & EHCI_HCD_OMAP_FLAG_NOBITSTUFF)
			reg |= OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;
		else
			reg &= ~OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;


		if (omap_usb_port_utmi_chanel_config(omap->port_data[i].mode)) {
			if (omap->port_data[i].flags
				& EHCI_HCD_OMAP_FLAG_AUTOIDLE)
				reg |= OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE;
			else
				reg &= ~OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE;
		} else {
			if (omap->port_data[i].flags
				& EHCI_HCD_OMAP_FLAG_AUTOIDLE)
				reg |= OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE;
			else
				reg &= ~OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE;
		}

		if (omap->port_data[i].mode == EHCI_HCD_OMAP_MODE_ULPI_TLL_DDR)
			reg |= OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE;
		else
			reg &= ~OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE;
		ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg);
	}

	/* Program Common TLL register */
	ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF,
			 OMAP_TLL_SHARED_CONF_FCLK_IS_ON
			| OMAP_TLL_SHARED_CONF_USB_DIVRATION);

	/* Enable channels now */
	for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
		/* Enable only the reg that is needed */
		if (!(omap->port_data[i].flags & EHCI_HCD_OMAP_FLAG_ENABLED))
			continue;

		reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));

		reg |= OMAP_TLL_CHANNEL_CONF_CHANEN;

		if (omap_usb_port_utmi_chanel_config(omap->port_data[i].mode))
			reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE(1);
		else
			reg &= ~OMAP_TLL_CHANNEL_CONF_CHANMODE(3);

		reg &= ~(OMAP_TLL_CHANNEL_CONF_FSLSMODE(0xf));
		reg |= OMAP_TLL_CHANNEL_CONF_FSLSMODE(
			omap_usb_port_fslsmode(omap->port_data[i].mode));

		ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg);
		dev_dbg(&omap->dev->dev,
			"port %d enabled: OMAP_TTL_CHANNEL_CONF_%d=%08x:%08x\n",
			i, i+1, reg, ehci_omap_readl(omap->tll_base,
			OMAP_TLL_CHANNEL_CONF(i)));

		ehci_omap_writeb(omap->tll_base,
				OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe);
		dev_dbg(&omap->dev->dev, "ULPI_SCRATCH_REG[ch=%d]= 0x%02x\n",
				i+1, ehci_omap_readb(omap->tll_base,
				OMAP_TLL_ULPI_SCRATCH_REGISTER(i)));
	}
}
Ejemplo n.º 8
0
static int omap_ehci_bus_resume(struct device *dev)
{
	struct ehci_hcd_omap *omap = gb_omap;
	int ret = 0;
	unsigned reg = 0;

	if (omap->suspended) {
		omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick");
		if (IS_ERR(omap->usbhost_ick)) {
			ret = PTR_ERR(omap->usbhost_ick);
			goto clk_error_usbhost_ick;
		}
		clk_enable(omap->usbhost_ick);
		udelay(30);

		omap->usbhost2_120m_fck =
			clk_get(omap->dev, "usbhost_120m_fck");
		if (IS_ERR(omap->usbhost2_120m_fck)) {
			ret = PTR_ERR(omap->usbhost2_120m_fck);
			goto clk_error_120m_fck;
		}
		clk_enable(omap->usbhost2_120m_fck);
		udelay(30);

		omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck");
		if (IS_ERR(omap->usbhost1_48m_fck)) {
			ret = PTR_ERR(omap->usbhost1_48m_fck);
			goto clk_error_48m_fck;
		}
		clk_enable(omap->usbhost1_48m_fck);
		udelay(30);

		omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck");
		if (IS_ERR(omap->usbtll_fck)) {
			ret = PTR_ERR(omap->usbtll_fck);
			goto clk_error_usbtll_fck;
		}
		clk_enable(omap->usbtll_fck);
		udelay(30);

		omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick");
		if (IS_ERR(omap->usbtll_ick)) {
			ret = PTR_ERR(omap->usbtll_ick);
			goto clk_error_usbtll_ick;
		}
		clk_enable(omap->usbtll_ick);
		udelay(30);
		/* Enable smart idle mode */
		reg = ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSCONFIG);
		reg &= ~OMAP_USBTLL_SYSCONFIG_SIDLEMASK;
		reg |= OMAP_USBTLL_SYSCONFIG_S_SMART_IDLE;
		ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, reg);

		/* Enable smart Idle/Standby mode */
		reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK
				| OMAP_UHH_SYSCONFIG_MIDLEMASK);
		reg |= OMAP_UHH_SYSCONFIG_S_SMART_IDLE
				| OMAP_UHH_SYSCONFIG_M_SMART_STDBY;
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);

		omap->suspended = 0;
	}

	return ret;

clk_error_usbtll_ick:
	clk_disable(omap->usbtll_fck);
	clk_put(omap->usbtll_fck);
	omap->usbtll_fck = NULL;
clk_error_usbtll_fck:
	clk_disable(omap->usbhost1_48m_fck);
	clk_put(omap->usbhost1_48m_fck);
	omap->usbhost1_48m_fck = NULL;
clk_error_48m_fck:
	clk_disable(omap->usbhost2_120m_fck);
	clk_put(omap->usbhost2_120m_fck);
	omap->usbhost2_120m_fck = NULL;
clk_error_120m_fck:
	clk_disable(omap->usbhost_ick);
	clk_put(omap->usbhost_ick);
	omap->usbhost_ick = NULL;
clk_error_usbhost_ick:
	return ret;
}
Ejemplo n.º 9
0
static int omap_init_uhh_registers(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	u8 tll_ch_mask = 0;
	unsigned reg = 0;
	
	/* perform TLL soft reset, and wait until reset is complete */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_SOFTRESET);

	/* Wait for TLL reset to complete */
	while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
			& OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
		cpu_relax();

		if (time_after(jiffies, timeout)) {
			dev_dbg(omap->dev, "operation timed out\n");
			return -EINVAL;
		}
	}

	dev_dbg(omap->dev, "TLL RESET DONE\n");

	/* Enable smart-idle, wakeup */
	reg = OMAP_USBTLL_SYSCONFIG_CACTIVITY
			| OMAP_USBTLL_SYSCONFIG_AUTOIDLE
			| OMAP_USBTLL_SYSCONFIG_ENAWAKEUP
			| OMAP_USBTLL_SYSCONFIG_SMARTIDLE;
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, reg);

	/* Put UHH in NoIdle/NoStandby mode */
	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
	reg |= OMAP_UHH_SYSCONFIG_CACTIVITY
			| OMAP_UHH_SYSCONFIG_AUTOIDLE
			| OMAP_UHH_SYSCONFIG_ENAWAKEUP;
	reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK | OMAP_UHH_SYSCONFIG_MIDLEMASK);
	reg |= OMAP_UHH_SYSCONFIG_NOIDLE
			| OMAP_UHH_SYSCONFIG_NOSTDBY;

	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);

	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);

	/* setup ULPI bypass and burst configurations */
	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;

	if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
		reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
	if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
		reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
	if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
		reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;

	/* Bypass the TLL module for PHY mode operation */
	if (!cpu_is_omap3517() && !cpu_is_omap3505() &&
			(omap_rev() <= OMAP3430_REV_ES2_1)) {
		dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1 \n");
		if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
			(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
				(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
		else
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
	} else {
		dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
		if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
		else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;

		if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
		else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;

		if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
		else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;

	}
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
	dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);


	/*
	 * An undocumented "feature" in the OMAP3 EHCI controller,
	 * causes suspended ports to be taken out of suspend when
	 * the USBCMD.Run/Stop bit is cleared (for example when
	 * we do ehci_bus_suspend).
	 * This breaks suspend-resume if the root-hub is allowed
	 * to suspend. Writing 1 to this undocumented register bit
	 * disables this feature and restores normal behavior.
	 */
	ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04,
				EHCI_INSNREG04_DISABLE_UNSUSPEND);

	if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) ||
		(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) ||
			(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) {

		if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK;
		if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK;
		if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK;

		/* Enable UTMI mode for required TLL channels */
		omap_usb_utmi_init(omap, tll_ch_mask);
	}

	if (omap->phy_reset) {
		/* Refer ISSUE1:
		 * Hold the PHY in RESET for enough time till
		 * PHY is settled and ready
		 */
		udelay(10);

		if (gpio_is_valid(omap->reset_gpio_port[0]))
			gpio_set_value(omap->reset_gpio_port[0], 1);

		if (gpio_is_valid(omap->reset_gpio_port[1]))
			gpio_set_value(omap->reset_gpio_port[1], 1);
	}

	return 0;
}
Ejemplo n.º 10
0
/* omap_start_ehc
 *	- Start the TI USBHOST controller
 */
static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	u8 tll_ch_mask = 0;
	unsigned reg = 0;
	int ret = 0;

	printk("omap_start_ehc kernel 2.6.35 V0.5 [07/12/2011]  \n");
   gpio_direction_output(23, 0);
   PHY_reset = 0;
#ifndef CONFIG_MODEM_SMS   
   gpio_direction_output(4, 1);
   gpio_direction_output(35, 1);
   gpio_direction_output(36, 1);
   modem_PW = 1;
#endif
	dev_dbg(omap->dev, "starting TI EHCI USB Controller\n");
   
   
	/* Get all the clock handles we need */
	omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick");
	if (IS_ERR(omap->usbhost_ick)) {
		dev_err(omap->dev, "could not get usbhost_ick\n");
		ret =  PTR_ERR(omap->usbhost_ick);
		goto err_host_ick;
	}

	omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck");
	if (IS_ERR(omap->usbhost2_120m_fck)) {
		dev_err(omap->dev, "could not get usbhost2_120m_fck\n");
		ret = PTR_ERR(omap->usbhost2_120m_fck);
		goto err_host_120m_fck;
	}

	omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck");
	if (IS_ERR(omap->usbhost1_48m_fck)) {
		dev_err(omap->dev, "could not get usbhost_48m_fck\n");
		ret = PTR_ERR(omap->usbhost1_48m_fck);
		goto err_host_48m_fck;
	}

	
	if (omap->phy_reset) {
		printk(KERN_DEBUG "reset the phys\n");
		/* Refer: ISSUE1 */
		if (gpio_is_valid(omap->reset_gpio_port[0])) 
		{
			gpio_request(omap->reset_gpio_port[0],
						"USB1 PHY reset");
			gpio_direction_output(omap->reset_gpio_port[0], 0);
		}

		if (gpio_is_valid(omap->reset_gpio_port[1])) 
		{
			gpio_request(omap->reset_gpio_port[1],"USB2 PHY reset");
			gpio_direction_output(omap->reset_gpio_port[1], 0);				
		}

		/* Hold the PHY in RESET for enough time till DIR is high */
		udelay(10);
	}

	omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck");
	if (IS_ERR(omap->usbtll_fck)) {
		dev_err(omap->dev, "could not get usbtll_fck\n");
		ret = PTR_ERR(omap->usbtll_fck);
		goto err_tll_fck;
	}

	omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick");
	if (IS_ERR(omap->usbtll_ick)) {
		dev_err(omap->dev, "could not get usbtll_ick\n");
		ret = PTR_ERR(omap->usbtll_ick);
		goto err_tll_ick;
	}

	/* Now enable all the clocks in the correct order */
	ehci_omap_clock_power(omap, 1);

	
	/* Put UHH in NoIdle/NoStandby mode */
	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
	reg |= OMAP_UHH_SYSCONFIG_CACTIVITY
			| OMAP_UHH_SYSCONFIG_AUTOIDLE
			| OMAP_UHH_SYSCONFIG_ENAWAKEUP;
	reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK | OMAP_UHH_SYSCONFIG_MIDLEMASK);
	reg |= OMAP_UHH_SYSCONFIG_NOIDLE
			| OMAP_UHH_SYSCONFIG_NOSTDBY;

	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);

	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);

	/* setup ULPI bypass and burst configurations */
	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;

	if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
		reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
	if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
		reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
	if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
		reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;

	/* Bypass the TLL module for PHY mode operation */
	if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
		dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
		if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
			(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
				(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
		else
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
	} else {
		dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
		if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
		else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;

		if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
		else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;

		if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
		else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;

	}
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
	dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);


	/*
	 * An undocumented "feature" in the OMAP3 EHCI controller,
	 * causes suspended ports to be taken out of suspend when
	 * the USBCMD.Run/Stop bit is cleared (for example when
	 * we do ehci_bus_suspend).
	 * This breaks suspend-resume if the root-hub is allowed
	 * to suspend. Writing 1 to this undocumented register bit
	 * disables this feature and restores normal behavior.
	 */
	ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04,
				EHCI_INSNREG04_DISABLE_UNSUSPEND);

	

	if (omap->phy_reset) {
		printk(KERN_DEBUG "unreset the phys\n");
		/* Refer ISSUE1:
		 * Hold the PHY in RESET for enough time till
		 * PHY is settled and ready
		 */
		udelay(10);

		if (gpio_is_valid(omap->reset_gpio_port[0]))
			gpio_set_value(omap->reset_gpio_port[0], 1);

		if (gpio_is_valid(omap->reset_gpio_port[1]))
			gpio_set_value(omap->reset_gpio_port[1], 1);
		
	}
	//gpio_direction_output(21, 1);   
   //gpio_direction_output(36, 1);
   //gpio_direction_output(35, 1);
	//msleep(10);
	printk("RESET USB PHY\n");
	gpio_direction_output(23, 1);
   PHY_reset = 1;
	return 0;

err_sys_status:
	ehci_omap_clock_power(omap, 0);
	clk_put(omap->usbtll_ick);

err_tll_ick:
	clk_put(omap->usbtll_fck);

err_tll_fck:
	clk_put(omap->usbhost1_48m_fck);

	if (omap->phy_reset) {
		if (gpio_is_valid(omap->reset_gpio_port[0]))
			gpio_free(omap->reset_gpio_port[0]);

		if (gpio_is_valid(omap->reset_gpio_port[1]))
			gpio_free(omap->reset_gpio_port[1]);
	}

err_host_48m_fck:
	clk_put(omap->usbhost2_120m_fck);

err_host_120m_fck:
	clk_put(omap->usbhost_ick);

err_host_ick:
	return ret;
}
Ejemplo n.º 11
0
/* omap_start_ehc
 *	- Start the TI USBHOST controller
 */
static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	unsigned reg = 0;
	int ret = 0;
	int reset_delay;
	int i;

	dev_dbg(&omap->dev->dev, "starting TI EHCI USB Controller\n");

	/* Enable Clocks for USBHOST */
	omap->usbhost_ick = clk_get(&omap->dev->dev, "usbhost_ick");
	if (IS_ERR(omap->usbhost_ick)) {
		ret =  PTR_ERR(omap->usbhost_ick);
		goto err_host_ick;
	}
	clk_enable(omap->usbhost_ick);

	omap->usbhost2_120m_fck = clk_get(&omap->dev->dev, "usbhost_120m_fck");
	if (IS_ERR(omap->usbhost2_120m_fck)) {
		ret = PTR_ERR(omap->usbhost2_120m_fck);
		goto err_host_120m_fck;
	}
	clk_enable(omap->usbhost2_120m_fck);

	omap->usbhost1_48m_fck = clk_get(&omap->dev->dev, "usbhost_48m_fck");
	if (IS_ERR(omap->usbhost1_48m_fck)) {
		ret = PTR_ERR(omap->usbhost1_48m_fck);
		goto err_host_48m_fck;
	}
	clk_enable(omap->usbhost1_48m_fck);

	reset_delay = 0;
	for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
		reset_delay = reset_delay > omap->port_data[i].reset_delay ?
			reset_delay : omap->port_data[i].reset_delay;

		if (omap->port_data[i].startup) {
			ret = omap->port_data[i].startup(omap->dev, i);
			if (ret < 0)
				return ret;
		}

		if (omap->port_data[i].reset)
			omap->port_data[i].reset(omap->dev, i, 0);
	}
	if (reset_delay)
		udelay(reset_delay);

	/* Configure TLL for 60Mhz clk for ULPI */
	omap->usbtll_fck = clk_get(&omap->dev->dev, "usbtll_fck");
	if (IS_ERR(omap->usbtll_fck)) {
		ret = PTR_ERR(omap->usbtll_fck);
		goto err_tll_fck;
	}
	clk_enable(omap->usbtll_fck);

	omap->usbtll_ick = clk_get(&omap->dev->dev, "usbtll_ick");
	if (IS_ERR(omap->usbtll_ick)) {
		ret = PTR_ERR(omap->usbtll_ick);
		goto err_tll_ick;
	}
	clk_enable(omap->usbtll_ick);

	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

#ifndef CONFIG_MAPPHONE_2NDBOOT 
	/* perform TLL soft reset, and wait until reset is complete */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_SOFTRESET);

	/* Wait for TLL reset to complete */
	while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
			& OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
		cpu_relax();

		if (time_after(jiffies, timeout)) {
			dev_dbg(&omap->dev->dev, "operation timed out\n");
			ret = -EINVAL;
			goto err_sys_status;
		}
	}
#endif 

	dev_dbg(&omap->dev->dev, "TLL RESET DONE\n");

	/* SmartIdle mode */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
			OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
			OMAP_USBTLL_SYSCONFIG_AUTOIDLE);

	/* Put UHH in NoIdle/NoStandby mode */
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG,
			OMAP_UHH_SYSCONFIG_ENAWAKEUP |
			OMAP_UHH_SYSCONFIG_NOIDLEMODE |
			OMAP_UHH_SYSCONFIG_NOSTBYMODE |
			OMAP_UHH_SYSCONFIG_AUTOIDLE);
#ifdef CONFIG_MACH_MAPPHONE
	/* We need to suspend OHCI in order for the usbhost
	 * domain to go standby.
	 * OHCI would never be resumed for UMTS modem */
	if (!is_cdma_phone())
		omap_writel(OHCI_HC_CTRL_SUSPEND, OHCI_HC_CONTROL);
#endif

	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);

	/* setup ULPI bypass and burst configurations */
	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;


	if (!(omap->port_data[0].flags & EHCI_HCD_OMAP_FLAG_ENABLED))
		reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
	if (!(omap->port_data[1].flags & EHCI_HCD_OMAP_FLAG_ENABLED))
		reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
	if (!(omap->port_data[2].flags & EHCI_HCD_OMAP_FLAG_ENABLED))
		reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;

	/* Bypass the TLL module for PHY mode operation */
	 if (omap_rev() <= OMAP3430_REV_ES2_1) {
		dev_dbg(&omap->dev->dev, "OMAP3 ES version <= ES2.1 \n");
		if (omap_usb_port_ulpi_bypass(omap->port_data[0].mode))
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
		else
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
	} else {
		dev_dbg(&omap->dev->dev, "OMAP3 ES version > ES2.1\n");
		if (omap_usb_port_ulpi_bypass(omap->port_data[0].mode))
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
		else
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;

		if (omap_usb_port_ulpi_bypass(omap->port_data[1].mode))
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
		else
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;

		if (omap_usb_port_ulpi_bypass(omap->port_data[2].mode))
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
		else
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
	}
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
	dev_dbg(&omap->dev->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);

	/* Enable UTMI mode for required TLL channels */
	omap_usb_utmi_init(omap);

	reset_delay = 0;
	for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
		reset_delay = reset_delay > omap->port_data[i].reset_delay ?
				reset_delay : omap->port_data[i].reset_delay;
	}
	if (reset_delay)
		udelay(reset_delay);

	for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
		if (omap->port_data[i].reset)
			omap->port_data[i].reset(omap->dev, i, 1);
	}

#if defined(CONFIG_MACH_MAPPHONE)
	/* Refer ISSUE2: LINK assumes external charge pump */
	/* use Port1 VBUS to charge externally Port2:
	 *      So for PHY mode operation use Port2 only */
	ehci_omap_writel(omap->ehci_base, EHCI_INSNREG05_ULPI,
		(0xA << EHCI_INSNREG05_ULPI_REGADD_SHIFT) |/* OTG ctrl reg*/
		(2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) |/*   Write */
		(2 << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) |/* Port1 */
		(1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT) |/* Start */
		(0x26));
	while (!(ehci_omap_readl(omap->ehci_base, EHCI_INSNREG05_ULPI) &
		(1<<EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) {
		cpu_relax();
	}
#endif

	return 0;

err_sys_status:
	clk_disable(omap->usbtll_ick);
	clk_put(omap->usbtll_ick);

err_tll_ick:
	clk_disable(omap->usbtll_fck);
	clk_put(omap->usbtll_fck);

err_tll_fck:
	clk_disable(omap->usbhost1_48m_fck);
	clk_put(omap->usbhost1_48m_fck);

err_host_48m_fck:
	clk_disable(omap->usbhost2_120m_fck);
	clk_put(omap->usbhost2_120m_fck);

err_host_120m_fck:
	clk_disable(omap->usbhost_ick);
	clk_put(omap->usbhost_ick);

err_host_ick:
	return ret;
}
Ejemplo n.º 12
0
/*-------------------------------------------------------------------------
 * Setup Usb High Speed Host mode.
 *
 */
static int set_uhh_mode(struct ehci_hcd_omap *omap)
{
	unsigned reg = 0;
	if (cpu_is_omap44xx()) {
		/* Put UHH in NoIdle/NoStandby mode */
		reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		reg &= OMAP_UHH_SYSCONFIG_IDLEMODE_RESET;
		reg |= OMAP_UHH_SYSCONFIG_NIDLEMODE_SET;
		reg &= OMAP_UHH_SYSCONFIG_STDYMODE_RESET;
		reg |= OMAP_UHH_SYSCONFIG_NSTDYMODE_SET;
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);

		/* setup ULPI bypass and burst configurations */
		reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
		reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN |
			OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN |
			OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
		reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;

		/* set p1 & p2 modes */
		reg &= OMAP_UHH_HOST_PORTS_RESET;
		if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
			reg |= OMAP_UHH_HOST_P1_SET_ULPIPHY;
		else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOST_P1_SET_ULPITLL;
		if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
			reg |= OMAP_UHH_HOST_P2_SET_ULPIPHY;
		else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOST_P2_SET_ULPITLL;

		ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
	} else {
		/* Put UHH in NoIdle/NoStandby mode */
		reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		reg |= OMAP_UHH_SYSCONFIG_ENAWAKEUP;
		reg |= OMAP_UHH_SYSCONFIG_SIDLEMODE;
		reg |= OMAP_UHH_SYSCONFIG_CACTIVITY;
		reg |= OMAP_UHH_SYSCONFIG_MIDLEMODE ;
		reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);

		/* setup ULPI bypass and burst configurations */
		reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
		reg |= OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN;
		reg |= OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN;
		reg |= OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN;
		reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;

		if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
		if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
		if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;

		if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
			dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
			if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)||
				(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)||
				(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
			else
				reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
		} else {
			dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
			if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
			else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
			if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
			else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
			if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)
				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
			else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
		}
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);

        /*
         * An undocumented "feature" in the OMAP3 EHCI controller,
         * causes suspended ports to be taken out of suspend when
         * the USBCMD.Run/Stop bit is cleared (for example when
         * we do ehci_bus_suspend).
         * This breaks suspend-resume if the root-hub is allowed
         * to suspend. Writing 1 to this undocumented register bit
         * disables this feature and restores normal behavior.
         */
        ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04,
                                EHCI_INSNREG04_DISABLE_UNSUSPEND);

	}
	dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
	return 0;
}
Ejemplo n.º 13
0
/* omap_start_ehc
 *	- Start the TI USBHOST controller
 */
static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	u8 tll_ch_mask = 0;
	unsigned reg = 0;
	int ret = 0;

	dev_dbg(omap->dev, "starting TI EHCI USB Controller\n");

	/* Enable Clocks for USBHOST */
	omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick");
	if (IS_ERR(omap->usbhost_ick)) {
		ret =  PTR_ERR(omap->usbhost_ick);
		goto err_host_ick;
	}
	clk_enable(omap->usbhost_ick);

	omap->usbhost_hs_fck = clk_get(omap->dev, "hs_fck");
	if (IS_ERR(omap->usbhost_hs_fck)) {
		ret = PTR_ERR(omap->usbhost_hs_fck);
		goto err_host_120m_fck;
	}
	clk_enable(omap->usbhost_hs_fck);

	omap->usbhost_fs_fck = clk_get(omap->dev, "fs_fck");
	if (IS_ERR(omap->usbhost_fs_fck)) {
		ret = PTR_ERR(omap->usbhost_fs_fck);
		goto err_host_48m_fck;
	}
	clk_enable(omap->usbhost_fs_fck);

	if (omap->phy_reset) {
		/* Refer: ISSUE1 */
		if (gpio_is_valid(omap->reset_gpio_port[0])) {
			gpio_request(omap->reset_gpio_port[0],
						"USB1 PHY reset");
			gpio_direction_output(omap->reset_gpio_port[0], 0);
		}

		if (gpio_is_valid(omap->reset_gpio_port[1])) {
			gpio_request(omap->reset_gpio_port[1],
						"USB2 PHY reset");
			gpio_direction_output(omap->reset_gpio_port[1], 0);
		}

		/* Hold the PHY in RESET for enough time till DIR is high */
		udelay(10);
	}

	/* Configure TLL for 60Mhz clk for ULPI */
	omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck");
	if (IS_ERR(omap->usbtll_fck)) {
		ret = PTR_ERR(omap->usbtll_fck);
		goto err_tll_fck;
	}
	clk_enable(omap->usbtll_fck);

	omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick");
	if (IS_ERR(omap->usbtll_ick)) {
		ret = PTR_ERR(omap->usbtll_ick);
		goto err_tll_ick;
	}
	clk_enable(omap->usbtll_ick);

	omap->omap_ehci_rev = ehci_omap_readl(omap->uhh_base,
						OMAP_UHH_REVISION);
	dev_dbg(omap->dev, "OMAP UHH_REVISION 0x%x\n",
					omap->omap_ehci_rev);

	/*
	 * Enable per-port clocks as needed (newer controllers only).
	 * - External ULPI clock for PHY mode
	 * - Internal clocks for TLL and HSIC modes (TODO)
	 */
	if (is_omap_ehci_rev2(omap)) {
		switch (omap->port_mode[0]) {
		case EHCI_HCD_OMAP_MODE_PHY:
			omap->xclk60mhsp1_ck = clk_get(omap->dev,
							"xclk60mhsp1_ck");
			if (IS_ERR(omap->xclk60mhsp1_ck)) {
				ret = PTR_ERR(omap->xclk60mhsp1_ck);
				dev_err(omap->dev,
					"Unable to get Port1 ULPI clock\n");
			}

			omap->utmi_p1_fck = clk_get(omap->dev,
							"utmi_p1_gfclk");
			if (IS_ERR(omap->utmi_p1_fck)) {
				ret = PTR_ERR(omap->utmi_p1_fck);
				dev_err(omap->dev,
					"Unable to get utmi_p1_fck\n");
			}

			ret = clk_set_parent(omap->utmi_p1_fck,
						omap->xclk60mhsp1_ck);
			if (ret != 0) {
				dev_err(omap->dev,
					"Unable to set P1 f-clock\n");
			}
			break;
		case EHCI_HCD_OMAP_MODE_TLL:
			/* TODO */
		default:
			break;
		}
		switch (omap->port_mode[1]) {
		case EHCI_HCD_OMAP_MODE_PHY:
			omap->xclk60mhsp2_ck = clk_get(omap->dev,
							"xclk60mhsp2_ck");
			if (IS_ERR(omap->xclk60mhsp2_ck)) {
				ret = PTR_ERR(omap->xclk60mhsp2_ck);
				dev_err(omap->dev,
					"Unable to get Port2 ULPI clock\n");
			}

			omap->utmi_p2_fck = clk_get(omap->dev,
							"utmi_p2_gfclk");
			if (IS_ERR(omap->utmi_p2_fck)) {
				ret = PTR_ERR(omap->utmi_p2_fck);
				dev_err(omap->dev,
					"Unable to get utmi_p2_fck\n");
			}

			ret = clk_set_parent(omap->utmi_p2_fck,
						omap->xclk60mhsp2_ck);
			if (ret != 0) {
				dev_err(omap->dev,
					"Unable to set P2 f-clock\n");
			}
			break;
		case EHCI_HCD_OMAP_MODE_TLL:
			/* TODO */
		default:
			break;
		}
	}


	/* perform TLL soft reset, and wait until reset is complete */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_SOFTRESET);

	/* Wait for TLL reset to complete */
	while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
			& OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
		cpu_relax();

		if (time_after(jiffies, timeout)) {
			dev_dbg(omap->dev, "operation timed out\n");
			ret = -EINVAL;
			goto err_sys_status;
		}
	}

	dev_dbg(omap->dev, "TLL RESET DONE\n");

	/* (1<<3) = no idle mode only for initial debugging */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
			OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
			OMAP_USBTLL_SYSCONFIG_CACTIVITY);


	/* Put UHH in NoIdle/NoStandby mode */
	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
	if (is_omap_ehci_rev1(omap)) {
		reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
				| OMAP_UHH_SYSCONFIG_SIDLEMODE
				| OMAP_UHH_SYSCONFIG_CACTIVITY
				| OMAP_UHH_SYSCONFIG_MIDLEMODE);
		reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;


	} else if (is_omap_ehci_rev2(omap)) {
		reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
		reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
		reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
		reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
	}
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);

	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);

	/* setup ULPI bypass and burst configurations */
	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;

	if (is_omap_ehci_rev1(omap)) {
		if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
		if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
		if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;

		/* Bypass the TLL module for PHY mode operation */
		if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
			dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
			if (is_ehci_phy_mode(omap->port_mode[0]) ||
				is_ehci_phy_mode(omap->port_mode[1]) ||
					is_ehci_phy_mode(omap->port_mode[2]))
				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
			else
				reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
		} else {
			dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
			if (is_ehci_phy_mode(omap->port_mode[0]))
				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
			else if (is_ehci_tll_mode(omap->port_mode[0]))
				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;

			if (is_ehci_phy_mode(omap->port_mode[1]))
				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
			else if (is_ehci_tll_mode(omap->port_mode[1]))
				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;

			if (is_ehci_phy_mode(omap->port_mode[2]))
				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
			else if (is_ehci_tll_mode(omap->port_mode[2]))
				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
		}
	} else if (is_omap_ehci_rev2(omap)) {
		/* Clear port mode fields for PHY mode*/
		reg &= ~OMAP4_P1_MODE_CLEAR;
		reg &= ~OMAP4_P2_MODE_CLEAR;

		if (is_ehci_tll_mode(omap->port_mode[0]))
			reg |= OMAP4_P1_MODE_TLL;
		else if (is_ehci_hsic_mode(omap->port_mode[0]))
			reg |= OMAP4_P1_MODE_HSIC;

		if (is_ehci_tll_mode(omap->port_mode[1]))
			reg |= OMAP4_P2_MODE_TLL;
		else if (is_ehci_hsic_mode(omap->port_mode[1]))
			reg |= OMAP4_P2_MODE_HSIC;
	}

	ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
	dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);


	/*
	 * An undocumented "feature" in the OMAP3 EHCI controller,
	 * causes suspended ports to be taken out of suspend when
	 * the USBCMD.Run/Stop bit is cleared (for example when
	 * we do ehci_bus_suspend).
	 * This breaks suspend-resume if the root-hub is allowed
	 * to suspend. Writing 1 to this undocumented register bit
	 * disables this feature and restores normal behavior.
	 */
	ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04,
				EHCI_INSNREG04_DISABLE_UNSUSPEND);

	if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) ||
		(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) ||
			(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) {

		if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK;
		if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK;
		if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK;

		/* Enable UTMI mode for required TLL channels */
		omap_usb_utmi_init(omap, tll_ch_mask, OMAP_TLL_CHANNEL_COUNT);
	}

	if (omap->phy_reset) {
		/* Refer ISSUE1:
		 * Hold the PHY in RESET for enough time till
		 * PHY is settled and ready
		 */
		udelay(10);

		if (gpio_is_valid(omap->reset_gpio_port[0]))
			gpio_set_value(omap->reset_gpio_port[0], 1);

		if (gpio_is_valid(omap->reset_gpio_port[1]))
			gpio_set_value(omap->reset_gpio_port[1], 1);
	}

	/* Soft reset the PHY using PHY reset command over ULPI */
	if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
		omap_ehci_soft_phy_reset(omap, 0);
	if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
		omap_ehci_soft_phy_reset(omap, 1);

	return 0;

err_sys_status:
	clk_disable(omap->utmi_p2_fck);
	clk_put(omap->utmi_p2_fck);
	clk_disable(omap->xclk60mhsp2_ck);
	clk_put(omap->xclk60mhsp2_ck);
	clk_disable(omap->utmi_p1_fck);
	clk_put(omap->utmi_p1_fck);
	clk_disable(omap->xclk60mhsp1_ck);
	clk_put(omap->xclk60mhsp1_ck);
	clk_disable(omap->usbtll_ick);
	clk_put(omap->usbtll_ick);

err_tll_ick:
	clk_disable(omap->usbtll_fck);
	clk_put(omap->usbtll_fck);

err_tll_fck:
	clk_disable(omap->usbhost_fs_fck);
	clk_put(omap->usbhost_fs_fck);

	if (omap->phy_reset) {
		if (gpio_is_valid(omap->reset_gpio_port[0]))
			gpio_free(omap->reset_gpio_port[0]);

		if (gpio_is_valid(omap->reset_gpio_port[1]))
			gpio_free(omap->reset_gpio_port[1]);
	}

err_host_48m_fck:
	clk_disable(omap->usbhost_hs_fck);
	clk_put(omap->usbhost_hs_fck);

err_host_120m_fck:
	clk_disable(omap->usbhost_ick);
	clk_put(omap->usbhost_ick);

err_host_ick:
	return ret;
}
Ejemplo n.º 14
0
/* omap_start_ehc
 *	- Start the TI USBHOST controller
 */
static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	u8 tll_ch_mask = 0;
	unsigned reg = 0;
	int ret = 0;

	dev_dbg(omap->dev, "starting TI EHCI USB Controller\n");

	/* Enable Clocks for USBHOST */
	omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick");
	if (IS_ERR(omap->usbhost_ick)) {
		ret =  PTR_ERR(omap->usbhost_ick);
		goto err_host_ick;
	}
	clk_enable(omap->usbhost_ick);

	omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck");
	if (IS_ERR(omap->usbhost2_120m_fck)) {
		ret = PTR_ERR(omap->usbhost2_120m_fck);
		goto err_host_120m_fck;
	}
	clk_enable(omap->usbhost2_120m_fck);

	omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck");
	if (IS_ERR(omap->usbhost1_48m_fck)) {
		ret = PTR_ERR(omap->usbhost1_48m_fck);
		goto err_host_48m_fck;
	}
	clk_enable(omap->usbhost1_48m_fck);

	if (omap->phy_reset) {
		/* Refer: ISSUE1 */
		if (gpio_is_valid(omap->reset_gpio_port[0])) {
			gpio_request(omap->reset_gpio_port[0],
						"USB1 PHY reset");
			gpio_direction_output(omap->reset_gpio_port[0], 0);
		}

		if (gpio_is_valid(omap->reset_gpio_port[1])) {
			gpio_request(omap->reset_gpio_port[1],
						"USB2 PHY reset");
			gpio_direction_output(omap->reset_gpio_port[1], 0);
		}

		/* Hold the PHY in RESET for enough time till DIR is high */
		udelay(10);
	}

	/* Configure TLL for 60Mhz clk for ULPI */
	omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck");
	if (IS_ERR(omap->usbtll_fck)) {
		ret = PTR_ERR(omap->usbtll_fck);
		goto err_tll_fck;
	}
	clk_enable(omap->usbtll_fck);

	omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick");
	if (IS_ERR(omap->usbtll_ick)) {
		ret = PTR_ERR(omap->usbtll_ick);
		goto err_tll_ick;
	}
	clk_enable(omap->usbtll_ick);

	/* perform TLL soft reset, and wait until reset is complete */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_SOFTRESET);

	/* Wait for TLL reset to complete */
	while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
			& OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
		cpu_relax();

		if (time_after(jiffies, timeout)) {
			dev_dbg(omap->dev, "operation timed out\n");
			ret = -EINVAL;
			goto err_sys_status;
		}
	}

	dev_dbg(omap->dev, "TLL RESET DONE\n");

	/* (1<<3) = no idle mode only for initial debugging */
	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
			OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
			OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
			OMAP_USBTLL_SYSCONFIG_CACTIVITY);


	/* Put UHH in NoIdle/NoStandby mode */
	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
	reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
			| OMAP_UHH_SYSCONFIG_SIDLEMODE
			| OMAP_UHH_SYSCONFIG_CACTIVITY
			| OMAP_UHH_SYSCONFIG_MIDLEMODE);
	reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;

	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);

	reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);

	/* setup ULPI bypass and burst configurations */
	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;

	if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
		reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
	if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
		reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
	if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
		reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;

	/* Bypass the TLL module for PHY mode operation */
	 if (omap_rev() <= OMAP3430_REV_ES2_1) {
		dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1 \n");
		if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
			(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
				(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
		else
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
	} else {
		dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
		if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
		else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;

		if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
		else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;

		if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)
			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
		else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;

	}
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
	dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);


	if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) ||
		(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) ||
			(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) {

		if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK;
		if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK;
		if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK;

		/* Enable UTMI mode for required TLL channels */
		omap_usb_utmi_init(omap, tll_ch_mask);
	}

	if (omap->phy_reset) {
		/* Refer ISSUE1:
		 * Hold the PHY in RESET for enough time till
		 * PHY is settled and ready
		 */
		udelay(10);

		if (gpio_is_valid(omap->reset_gpio_port[0]))
			gpio_set_value(omap->reset_gpio_port[0], 1);

		if (gpio_is_valid(omap->reset_gpio_port[1]))
			gpio_set_value(omap->reset_gpio_port[1], 1);
	}

	return 0;

err_sys_status:
	clk_disable(omap->usbtll_ick);
	clk_put(omap->usbtll_ick);

err_tll_ick:
	clk_disable(omap->usbtll_fck);
	clk_put(omap->usbtll_fck);

err_tll_fck:
	clk_disable(omap->usbhost1_48m_fck);
	clk_put(omap->usbhost1_48m_fck);

	if (omap->phy_reset) {
		if (gpio_is_valid(omap->reset_gpio_port[0]))
			gpio_free(omap->reset_gpio_port[0]);

		if (gpio_is_valid(omap->reset_gpio_port[1]))
			gpio_free(omap->reset_gpio_port[1]);
	}

err_host_48m_fck:
	clk_disable(omap->usbhost2_120m_fck);
	clk_put(omap->usbhost2_120m_fck);

err_host_120m_fck:
	clk_disable(omap->usbhost_ick);
	clk_put(omap->usbhost_ick);

err_host_ick:
	return ret;
}
Ejemplo n.º 15
0
static irqreturn_t usbtll_irq(int irq, void *pdev)
{
	unsigned long flags;
	u32 sysconfig;
	u32 usbtll_irqstatus;
	struct ehci_hcd_omap *omap = platform_get_drvdata(
					(struct platform_device *)pdev);
	struct usb_hcd *hcd = ehci_to_hcd(omap->ehci);

	usbtll_irqstatus = ehci_omap_readl(
				omap->tll_base, OMAP_USBTLL_IRQSTATUS);

	spin_lock_irqsave(&usb_clocks_lock, flags);
	if (usbtll_irqstatus & 1) {
		LOG_USBHOST_ACTIVITY(aUsbHostDbg, iUsbHostDbg, 0x30);
		LOG_USBHOST_ACTIVITY(aUsbHostDbg, iUsbHostDbg, jiffies);
		if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
			ehci_omap_writel(omap->tll_base,
				OMAP_USBTLL_IRQSTATUS, usbtll_irqstatus);
			ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE,
				 0);
			spin_unlock_irqrestore(&usb_clocks_lock, flags);
			return IRQ_HANDLED;
		}
#ifdef CONFIG_HAS_WAKELOCK
		wake_lock_timeout(&omap->ehci->wake_lock_ehci_rwu, HZ/2);
#endif
		if (omap->usbtll_fck)
			clk_enable(omap->usbtll_fck);
		/* Disable usbtll irq to prevent race condition in suspend */
		ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF,
				1 | ehci_omap_readl(omap->tll_base,
					OMAP_TLL_SHARED_CONF));
		ehci_omap_writel(omap->tll_base,
			OMAP_USBTLL_IRQSTATUS, usbtll_irqstatus);
		if (omap->usbhost2_120m_fck)
			clk_enable(omap->usbhost2_120m_fck);
		if (omap->usbhost1_48m_fck)
			clk_enable(omap->usbhost1_48m_fck);

		/* Put UHH in NoStandby mode */
		sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		sysconfig &= ~OMAP_UHH_SYSCONFIG_MIDLEMODE_MASK;
		sysconfig |= OMAP_UHH_SYSCONFIG_NOSTBYMODE;
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig);

		/* Put UHH in NoIdle mode */
		sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		sysconfig &= ~OMAP_UHH_SYSCONFIG_SIDLEMODE_MASK;
		sysconfig |= OMAP_UHH_SYSCONFIG_NOIDLEMODE;
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig);
		sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);

		ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE, 0);
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		enable_irq(hcd->irq);
	}
	spin_unlock_irqrestore(&usb_clocks_lock, flags);

	return IRQ_HANDLED;
}
Ejemplo n.º 16
0
static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(100);

	dev_dbg(omap->dev, "stopping TI EHCI USB Controller\n");

	/* Reset OMAP modules for insmod/rmmod to work */
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG,
			OMAP_UHH_SYSCONFIG_SOFTRESET);
	while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
				& (1 << 0))) {
		cpu_relax();

		if (time_after(jiffies, timeout))
			dev_dbg(omap->dev, "operation timed out\n");
	}

	while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
				& (1 << 1))) {
		cpu_relax();

		if (time_after(jiffies, timeout))
			dev_dbg(omap->dev, "operation timed out\n");
	}

	while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
				& (1 << 2))) {
		cpu_relax();

		if (time_after(jiffies, timeout))
			dev_dbg(omap->dev, "operation timed out\n");
	}

	ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1));

	while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
				& (1 << 0))) {
		cpu_relax();

		if (time_after(jiffies, timeout))
			dev_dbg(omap->dev, "operation timed out\n");
	}

	if (omap->usbtll_fck != NULL) {
		clk_disable(omap->usbtll_fck);
		clk_put(omap->usbtll_fck);
		omap->usbtll_fck = NULL;
	}

	if (omap->usbhost_ick != NULL) {
		clk_disable(omap->usbhost_ick);
		clk_put(omap->usbhost_ick);
		omap->usbhost_ick = NULL;
	}

	if (omap->usbhost1_48m_fck != NULL) {
		clk_disable(omap->usbhost1_48m_fck);
		clk_put(omap->usbhost1_48m_fck);
		omap->usbhost1_48m_fck = NULL;
	}

	if (omap->usbhost2_120m_fck != NULL) {
		clk_disable(omap->usbhost2_120m_fck);
		clk_put(omap->usbhost2_120m_fck);
		omap->usbhost2_120m_fck = NULL;
	}

	if (omap->usbtll_ick != NULL) {
		clk_disable(omap->usbtll_ick);
		clk_put(omap->usbtll_ick);
		omap->usbtll_ick = NULL;
	}

	if (omap->phy_reset) {
		if (gpio_is_valid(omap->reset_gpio_port[0]))
			gpio_free(omap->reset_gpio_port[0]);

		if (gpio_is_valid(omap->reset_gpio_port[1]))
			gpio_free(omap->reset_gpio_port[1]);
	}

	dev_dbg(omap->dev, "Clock to USB host has been disabled\n");
}
Ejemplo n.º 17
0
static int ehci_omap_bus_suspend(struct usb_hcd *hcd)
{
	int ret;
	u32 status;
	u32 sysconfig;
	unsigned long flags;
	struct ehci_hcd *ehci;
	struct ehci_hcd_omap_platform_data *pdata;
	struct ehci_hcd_omap *omap = dev_get_drvdata(hcd->self.controller);

	dev_dbg(hcd->self.controller, "%s %ld %lu\n", __func__,
		in_interrupt(), jiffies);
	ehci = hcd_to_ehci(hcd);
	pdata = omap->dev->dev.platform_data;

	/* mask interrupt 77 to avoid race condition with ehci_irq */
	/* omap_writel(0x2000, 0x482000CC); */
	disable_irq(hcd->irq);

	ret = ehci_bus_suspend(hcd);
	if (ret) {
		enable_irq(hcd->irq);
		return ret;
	}

	/* Put UHH in SmartStandby mode */
	sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
	sysconfig &= ~OMAP_UHH_SYSCONFIG_MIDLEMODE_MASK;
	sysconfig |= OMAP_UHH_SYSCONFIG_MIDLEMODE;
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig);

	spin_lock_irqsave(&usb_clocks_lock, flags);
	if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		if (pdata->usbhost_standby_status)
			ret = pdata->usbhost_standby_status();
		if (ret == 0) {
			printk(KERN_ERR "ehci: suspend failed!\n");
			ret = -EBUSY;
			goto end;
		} else
			ret = 0;
		status = ehci_readl(ehci, &ehci->regs->status);
		if (status & INTR_MASK) {
			printk(KERN_ERR "ehci: pending irq, resume!\n");
			ret = -EBUSY;
			goto end;
		}
		ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF,
			ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF) &
			~(1));
		/* Enable the interrupt so that the remote-wakeup
		 * can be detected */
		ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQSTATUS, 7);
		ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE, 1);

		/* Put UHH in ForceIdle mode */
		sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
		sysconfig &= ~OMAP_UHH_SYSCONFIG_SIDLEMODE_MASK;
		ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig);

		if (omap->usbhost1_48m_fck)
			clk_disable(omap->usbhost1_48m_fck);
		if (omap->usbhost2_120m_fck)
			clk_disable(omap->usbhost2_120m_fck);
		if (omap->usbtll_fck)
			clk_disable(omap->usbtll_fck);
		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		LOG_USBHOST_ACTIVITY(aUsbHostDbg, iUsbHostDbg, jiffies);
	}
	spin_unlock_irqrestore(&usb_clocks_lock, flags);
#ifdef CONFIG_HAS_WAKELOCK
	wake_unlock(&ehci->wake_lock_ehci_pm);
#endif
	return 0;

end:
	/* Put UHH in NoStandby mode */
	sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
	sysconfig &= ~OMAP_UHH_SYSCONFIG_MIDLEMODE_MASK;
	sysconfig |= OMAP_UHH_SYSCONFIG_NOSTBYMODE;
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig);

	spin_unlock_irqrestore(&usb_clocks_lock, flags);
	ehci_bus_resume(hcd);
	/* unmask irq 77 */
	/* omap_writel(0x2000, 0x482000C8); */
	enable_irq(hcd->irq);
	return ret;
}
Ejemplo n.º 18
0
static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(100);

	dev_dbg(omap->dev, "stopping TI EHCI USB Controller\n");

	printk(KERN_DEBUG " omap_stop_ehc\n");

	/* Reset OMAP modules for insmod/rmmod to work */
	ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG,
			OMAP_UHH_SYSCONFIG_SOFTRESET);
	while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
				& (1 << 0))) {
		cpu_relax();

		if (time_after(jiffies, timeout))
			dev_dbg(omap->dev, "operation timed out\n");
	}

	while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
				& (1 << 1))) {
		cpu_relax();

		if (time_after(jiffies, timeout))
			dev_dbg(omap->dev, "operation timed out\n");
	}

	while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
				& (1 << 2))) {
		cpu_relax();

		if (time_after(jiffies, timeout))
			dev_dbg(omap->dev, "operation timed out\n");
	}

	

	ehci_omap_clock_power(omap, 0);

	if (omap->usbtll_fck != NULL) {
		clk_put(omap->usbtll_fck);
		omap->usbtll_fck = NULL;
	}

	if (omap->usbhost_ick != NULL) {
		clk_put(omap->usbhost_ick);
		omap->usbhost_ick = NULL;
	}

	if (omap->usbhost1_48m_fck != NULL) {
		clk_put(omap->usbhost1_48m_fck);
		omap->usbhost1_48m_fck = NULL;
	}

	if (omap->usbhost2_120m_fck != NULL) {
		clk_put(omap->usbhost2_120m_fck);
		omap->usbhost2_120m_fck = NULL;
	}

	if (omap->usbtll_ick != NULL) {
		clk_put(omap->usbtll_ick);
		omap->usbtll_ick = NULL;
	}

	if (omap->phy_reset) {
		printk(KERN_DEBUG " free the reset the GPIOs\n");
		if (gpio_is_valid(omap->reset_gpio_port[0]))
			gpio_free(omap->reset_gpio_port[0]);

		if (gpio_is_valid(omap->reset_gpio_port[1]))
			gpio_free(omap->reset_gpio_port[1]);
	}

	dev_dbg(omap->dev, "Clock to USB host has been disabled\n");
	gpio_direction_output(23, 0);
    PHY_reset = 0;
#ifndef CONFIG_MODEM_SMS
   if(!modem_resume_state || !g_sim_carddetect_status){
      gpio_direction_output(4, 0);
      gpio_direction_output(35, 0);
      gpio_direction_output(36, 0);
      modem_PW = 0;
   }
#endif
}
Ejemplo n.º 19
0
/**
 * ehci_hcd_omap_probe - initialize TI-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 ehci_hcd_omap_probe(struct platform_device *pdev)
{
	struct uhhtll_apis *uhhtllp = pdev->dev.platform_data;
	struct ehci_hcd_omap *omap;
	struct usbhs_omap_platform_data *pdata;
	struct usbhs_omap_resource *omapresp;
	struct usb_hcd *hcd;
	int ret = -ENODEV;

	if (!uhhtllp) {
		dev_dbg(&pdev->dev, "missing platform_data\n");
		goto err_end;
	}

	if (usb_disabled())
		goto err_end;

	omap = kzalloc(sizeof(*omap), GFP_KERNEL);
	if (!omap) {
		ret = -ENOMEM;
		goto err_end;
	}

	pdata = &omap->platdata;
	if (uhhtllp->get_platform_data(pdata) != 0) {
		ret = -EINVAL;
		goto err_mem;
	}

	omapresp = &omap->res;
	if (uhhtllp->get_resource(OMAP_EHCI, omapresp) != 0) {
		ret = -EINVAL;
		goto err_mem;
	}

	if (!omapresp->regs) {
		dev_dbg(&pdev->dev, "failed to EHCI regs\n");
		goto err_mem;
	}

	hcd = usb_create_hcd(&ehci_omap_hc_driver, &pdev->dev,
			dev_name(&pdev->dev));
	if (!hcd) {
		dev_dbg(&pdev->dev, "failed to create hcd with err %d\n", ret);
		ret = -ENOMEM;
		goto err_mem;
	}

	platform_set_drvdata(pdev, omap);
	omap->dev		= &pdev->dev;
	omap->ehci		= hcd_to_ehci(hcd);
	omap->ehci->sbrn	= 0x20;

	hcd->rsrc_start = omapresp->start;
	hcd->rsrc_len = omapresp->len;
	hcd->regs =  omapresp->regs;

	/* we know this is the memory we want, no need to ioremap again */
	omap->ehci->caps = hcd->regs;

	ret = uhhtllp->store(OMAP_EHCI, OMAP_USB_HCD, hcd);
	if (ret) {
		dev_dbg(&pdev->dev, "failed to store hcd\n");
		goto err_regs;
	}

	ret = uhhtllp->enable(OMAP_EHCI);
	if (ret) {
		dev_dbg(&pdev->dev, "failed to start ehci\n");
		goto err_regs;
	}

	if (cpu_is_omap34xx()) {

		/*
		 * An undocumented "feature" in the OMAP3 EHCI controller,
		 * causes suspended ports to be taken out of suspend when
		 * the USBCMD.Run/Stop bit is cleared (for example when
		 * we do ehci_bus_suspend).
		 * This breaks suspend-resume if the root-hub is allowed
		 * to suspend. Writing 1 to this undocumented register bit
		 * disables this feature and restores normal behavior.
		 */
		ehci_omap_writel(omap->res.regs, EHCI_INSNREG04,
					EHCI_INSNREG04_DISABLE_UNSUSPEND);

		/* Soft reset the PHY using PHY reset command over ULPI */
		if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
			omap_ehci_soft_phy_reset(omap, 0);
		if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
			omap_ehci_soft_phy_reset(omap, 1);
	}

	if (cpu_is_omap44xx()) {

		/*
		 * Undocumented HW Errata for OMAP4 TLL
		 * the IDGND ULPI bits generate an interrupt when the
		 * controller is enabled from OFF mode. This causes the
		 * port status to be reported as disabled. Mask these
		 * interrupts since TLL does not require them.
		 */
		if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_TLL) {
			omap_writeb(0x10, USB_INT_EN_RISE_CLR_0);
			omap_writeb(0x10, USB_INT_EN_FALL_CLR_0);
			omap_writeb(0x01, OTG_CTRL_SET_0);
		}
		if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_TLL) {
			omap_writeb(0x10, USB_INT_EN_RISE_CLR_1);
			omap_writeb(0x10, USB_INT_EN_FALL_CLR_1);
			omap_writeb(0x01, OTG_CTRL_SET_1);
		}
	}

	omap->ehci->regs = hcd->regs
		+ HC_LENGTH(readl(&omap->ehci->caps->hc_capbase));

	dbg_hcs_params(omap->ehci, "reset");
	dbg_hcc_params(omap->ehci, "reset");

	/* cache this readonly data; minimize chip reads */
	omap->ehci->hcs_params = readl(&omap->ehci->caps->hcs_params);

	ret = usb_add_hcd(hcd, omapresp->irq, IRQF_DISABLED | IRQF_SHARED);
	if (ret) {
		dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
		goto err_add_hcd;
	}

	/* root ports should always stay powered */
	ehci_port_power(omap->ehci, 1);

	return 0;

err_add_hcd:
	uhhtllp->disable(OMAP_EHCI);

err_regs:
	usb_put_hcd(hcd);

err_mem:
	kfree(omap);

err_end:
	return ret;
}