/*
 * Freescale i.MX28 USB Host driver
 *
 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
 * on behalf of DENX Software Engineering GmbH
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <common.h>
#include <asm/io.h>
#include <asm/arch/regs-common.h>
#include <asm/arch/regs-base.h>
#include <asm/arch/regs-clkctrl-mx28.h>
#include <asm/arch/regs-usb.h>
#include <asm/arch/regs-usbphy.h>

#include "ehci.h"

#if	(CONFIG_EHCI_MXS_PORT != 0) && (CONFIG_EHCI_MXS_PORT != 1)
#error	"MXS EHCI: Invalid port selected!"
#endif

#ifndef	CONFIG_EHCI_MXS_PORT
#error	"MXS EHCI: Please define correct port using CONFIG_EHCI_MXS_PORT!"
#endif

static struct ehci_mxs {
	struct mxs_usb_regs	*usb_regs;
	struct mxs_usbphy_regs	*phy_regs;
} ehci_mxs;

int mxs_ehci_get_port(struct ehci_mxs *mxs_usb, int port)
{
	uint32_t usb_base, phy_base;
	switch (port) {
	case 0:
		usb_base = MXS_USBCTRL0_BASE;
		phy_base = MXS_USBPHY0_BASE;
		break;
	case 1:
		usb_base = MXS_USBCTRL1_BASE;
		phy_base = MXS_USBPHY1_BASE;
		break;
	default:
		printf("CONFIG_EHCI_MXS_PORT (port = %d)\n", port);
		return -1;
	}

	mxs_usb->usb_regs = (struct mxs_usb_regs *)usb_base;
	mxs_usb->phy_regs = (struct mxs_usbphy_regs *)phy_base;
	return 0;
}

/* This DIGCTL register ungates clock to USB */
#define	HW_DIGCTL_CTRL			0x8001c000
#define	HW_DIGCTL_CTRL_USB0_CLKGATE	(1 << 2)
#define	HW_DIGCTL_CTRL_USB1_CLKGATE	(1 << 16)

int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{

	int ret;
	uint32_t usb_base, cap_base;
	struct mxs_register_32 *digctl_ctrl =
		(struct mxs_register_32 *)HW_DIGCTL_CTRL;
	struct mxs_clkctrl_regs *clkctrl_regs =
		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;

	ret = mxs_ehci_get_port(&ehci_mxs, CONFIG_EHCI_MXS_PORT);
	if (ret)
		return ret;

	/* Reset the PHY block */
	writel(USBPHY_CTRL_SFTRST, &ehci_mxs.phy_regs->hw_usbphy_ctrl_set);
	udelay(10);
	writel(USBPHY_CTRL_SFTRST | USBPHY_CTRL_CLKGATE,
		&ehci_mxs.phy_regs->hw_usbphy_ctrl_clr);

	/* Enable USB clock */
	writel(CLKCTRL_PLL0CTRL0_EN_USB_CLKS | CLKCTRL_PLL0CTRL0_POWER,
			&clkctrl_regs->hw_clkctrl_pll0ctrl0_set);
	writel(CLKCTRL_PLL1CTRL0_EN_USB_CLKS | CLKCTRL_PLL1CTRL0_POWER,
			&clkctrl_regs->hw_clkctrl_pll1ctrl0_set);

	writel(HW_DIGCTL_CTRL_USB0_CLKGATE | HW_DIGCTL_CTRL_USB1_CLKGATE,
		&digctl_ctrl->reg_clr);

	/* Start USB PHY */
	writel(0, &ehci_mxs.phy_regs->hw_usbphy_pwd);

	/* Enable UTMI+ Level 2 and Level 3 compatibility */
	writel(USBPHY_CTRL_ENUTMILEVEL3 | USBPHY_CTRL_ENUTMILEVEL2 | 1,
		&ehci_mxs.phy_regs->hw_usbphy_ctrl_set);

	usb_base = ((uint32_t)ehci_mxs.usb_regs) + 0x100;
	*hccr = (struct ehci_hccr *)usb_base;

	cap_base = ehci_readl(&(*hccr)->cr_capbase);
	*hcor = (struct ehci_hcor *)(usb_base + HC_LENGTH(cap_base));

	return 0;
}

int ehci_hcd_stop(int index)
{
	int ret;
	uint32_t usb_base, cap_base, tmp;
	struct mxs_register_32 *digctl_ctrl =
		(struct mxs_register_32 *)HW_DIGCTL_CTRL;
	struct mxs_clkctrl_regs *clkctrl_regs =
		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
	struct ehci_hccr *hccr;
	struct ehci_hcor *hcor;

	ret = mxs_ehci_get_port(&ehci_mxs, CONFIG_EHCI_MXS_PORT);
	if (ret)
		return ret;

	/* Stop the USB port */
	usb_base = ((uint32_t)ehci_mxs.usb_regs) + 0x100;
	hccr = (struct ehci_hccr *)usb_base;
	cap_base = ehci_readl(&hccr->cr_capbase);
	hcor = (struct ehci_hcor *)(usb_base + HC_LENGTH(cap_base));

	tmp = ehci_readl(&hcor->or_usbcmd);
	tmp &= ~CMD_RUN;
	ehci_writel(tmp, &hcor->or_usbcmd);

	/* Disable the PHY */
	tmp = USBPHY_PWD_RXPWDRX | USBPHY_PWD_RXPWDDIFF |
		USBPHY_PWD_RXPWD1PT1 | USBPHY_PWD_RXPWDENV |
		USBPHY_PWD_TXPWDV2I | USBPHY_PWD_TXPWDIBIAS |
		USBPHY_PWD_TXPWDFS;
	writel(tmp, &ehci_mxs.phy_regs->hw_usbphy_pwd);

	/* Disable USB clock */
	writel(CLKCTRL_PLL0CTRL0_EN_USB_CLKS,
			&clkctrl_regs->hw_clkctrl_pll0ctrl0_clr);
	writel(CLKCTRL_PLL1CTRL0_EN_USB_CLKS,
			&clkctrl_regs->hw_clkctrl_pll1ctrl0_clr);

	/* Gate off the USB clock */
	writel(HW_DIGCTL_CTRL_USB0_CLKGATE | HW_DIGCTL_CTRL_USB1_CLKGATE,
		&digctl_ctrl->reg_set);

	return 0;
}
