diff options
author | Nitin Kumbhar <nkumbhar@nvidia.com> | 2011-03-07 18:38:30 +0530 |
---|---|---|
committer | Nitin Kumbhar <nkumbhar@nvidia.com> | 2011-03-07 18:38:30 +0530 |
commit | 04db8ee9121dbddcccfa5fb0e0e34b9a5028c6c3 (patch) | |
tree | 2a5e287b5f2b58e98e57406f5f8d1b6f6e6b5a38 /drivers/usb | |
parent | 0355ab1e7e6b3c8bf4ce9414cf0afa00cb4e113f (diff) | |
parent | 07a84a1ce6dae0bd521ac30c56ffc22f31da10b1 (diff) |
merging android-tegra-2.6.36 into git-master/linux-2.6/android-tegra-2.6.36
Conflicts:
arch/arm/mach-tegra/include/mach/system.h
arch/arm/mach-tegra/include/mach/usb_phy.h
arch/arm/mach-tegra/usb_phy.c
drivers/usb/host/ehci-tegra.c
drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/hdmi.c
include/linux/tegra_usb.h
Change-Id: Ic1f4f2b360893e8de6b867a8ecc239aca02367da
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/host/Kconfig | 16 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 234 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 1 | ||||
-rw-r--r-- | drivers/usb/otg/Kconfig | 7 | ||||
-rw-r--r-- | drivers/usb/otg/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/otg/tegra-otg.c | 4 | ||||
-rw-r--r-- | drivers/usb/otg/ulpi_viewport.c | 80 |
9 files changed, 172 insertions, 177 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 69e8a096c35a..4aa00e6e57ad 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -61,7 +61,6 @@ config USB_ARCH_HAS_EHCI default y if PPC_83xx default y if SOC_AU1200 default y if ARCH_IXP4XX - default y if ARCH_TEGRA default y if ARCH_W90X900 default y if ARCH_AT91SAM9G45 default y if ARCH_MXC diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 10f6ab5f9150..28deb1ac09b0 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -126,6 +126,14 @@ config USB_EHCI_MXC ---help--- Variation of ARC USB block used in some Freescale chips. +config USB_EHCI_TEGRA + boolean "NVIDIA Tegra HCD support" + depends on USB_EHCI_HCD && ARCH_TEGRA + select USB_EHCI_ROOT_HUB_TT + help + This driver enables support for the internal USB Host Controller + found in NVIDIA Tegra SoCs. The Tegra controller is EHCI compliant. + config USB_EHCI_HCD_PPC_OF bool "EHCI support for PPC USB controller on OF platform bus" depends on USB_EHCI_HCD && PPC_OF @@ -418,14 +426,6 @@ config USB_HWA_HCD To compile this driver a module, choose M here: the module will be called "hwa-hc". -config USB_TEGRA_HCD - boolean "NVIDIA Tegra HCD support" - depends on USB && ARCH_TEGRA && USB_EHCI_HCD - select USB_EHCI_ROOT_HUB_TT - help - This driver enables support for the internal USB Host Controller - found in NVIDIA Tegra SoCs. The Tegra controller is EHCI compliant. - config USB_IMX21_HCD tristate "iMX21 HCD support" depends on USB && ARM && MACH_MX21 diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 74cc97b80c4b..66505a0d9703 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -259,8 +259,7 @@ static int ehci_reset (struct ehci_hcd *ehci) command |= CMD_RESET; dbg_cmd (ehci, "reset", command); - if (!ehci->controller_resets_phy) - ehci_writel(ehci, command, &ehci->regs->command); + ehci_writel(ehci, command, &ehci->regs->command); ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci->next_statechange = jiffies; retval = handshake (ehci, &ehci->regs->command, @@ -1200,7 +1199,7 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_ARCH_TEGRA #include "ehci-tegra.c" -#define PLATFORM_DRIVER tegra_ehci_driver +#define PLATFORM_DRIVER tegra_ehci_driver #endif #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 85b99f1936e1..6de0d3a5ad9f 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -14,24 +14,16 @@ * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/clk.h> #include <linux/platform_device.h> -#include <linux/tegra_usb.h> +#include <linux/platform_data/tegra_usb.h> #include <linux/irq.h> #include <linux/usb/otg.h> #include <mach/usb_phy.h> #include <mach/iomap.h> -#define TEGRA_USB_USBCMD_REG_OFFSET 0x140 -#define TEGRA_USB_USBCMD_RESET (1 << 1) -#define TEGRA_USB_USBMODE_REG_OFFSET 0x1a8 -#define TEGRA_USB_USBMODE_HOST (3 << 0) -#define TEGRA_USB_PORTSC1_PTC(x) (((x) & 0xf) << 16) #define TEGRA_USB_PORTSC_PHCD (1 << 23) #define TEGRA_USB_SUSP_CTRL_OFFSET 0x400 @@ -44,16 +36,6 @@ #define TEGRA_USB_DMA_ALIGN 32 -struct tegra_ehci_context { - bool valid; - u32 command; - u32 frame_list; - u32 async_next; - u32 txfilltunning; - u32 otgsc; - enum tegra_usb_phy_port_speed port_speed; -}; - struct tegra_ehci_hcd { struct ehci_hcd *ehci; struct tegra_usb_phy *phy; @@ -63,9 +45,9 @@ struct tegra_ehci_hcd { int host_resumed; int bus_suspended; int port_resuming; - struct tegra_ehci_context context; int power_down_on_bus_suspend; struct delayed_work work; + enum tegra_usb_phy_port_speed port_speed; }; static void tegra_ehci_power_up(struct usb_hcd *hcd) @@ -123,13 +105,13 @@ static int tegra_ehci_hub_control( * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits */ if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) { - temp = ehci_readl(ehci, status_reg); - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) & ~PORT_PE, status_reg); + temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS; + ehci_writel(ehci, temp & ~PORT_PE, status_reg); goto done; } else if (typeReq == GetPortStatus) { temp = ehci_readl(ehci, status_reg); if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { - /* resume completed */ + /* Resume completed, re-enable disconnect detection */ tegra->port_resuming = 0; tegra_usb_phy_postresume(tegra->phy); } @@ -140,29 +122,31 @@ static int tegra_ehci_hub_control( goto done; } - /* After above check the port must be connected. - * Set appropriate bit thus could put phy into low power - * mode if we have hostpc feature - */ temp &= ~PORT_WKCONN_E; temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); + + /* + * If a transaction is in progress, there may be a delay in + * suspending the port. Poll until the port is suspended. + */ if (handshake(ehci, status_reg, PORT_SUSPEND, PORT_SUSPEND, 5000)) - pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__); + pr_err("%s: timeout waiting for SUSPEND\n", __func__); + set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); goto done; } /* - * Tegra host controller will time the resume operation to clear the bit - * when the port control state switches to HS or FS Idle. This behavior - * is different from EHCI where the host controller driver is required - * to set this bit to a zero after the resume duration is timed in the - * driver. - */ - - else if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { + * Tegra host controller will time the resume operation to clear the bit + * when the port control state switches to HS or FS Idle. This behavior + * is different from EHCI where the host controller driver is required + * to set this bit to a zero after the resume duration is timed in the + * driver. + */ + else if (typeReq == ClearPortFeature && + wValue == USB_PORT_FEAT_SUSPEND) { temp = ehci_readl(ehci, status_reg); if ((temp & PORT_RESET) || !(temp & PORT_PE)) { retval = -EPIPE; @@ -172,6 +156,7 @@ static int tegra_ehci_hub_control( if (!(temp & PORT_SUSPEND)) goto done; + /* Disable disconnect detection during port resume */ tegra_usb_phy_preresume(tegra->phy); ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); @@ -184,13 +169,11 @@ static int tegra_ehci_hub_control( msleep(20); spin_lock_irqsave(&ehci->lock, flags); - /* polling PORT_RESUME until the controller clear this bit */ + /* Poll until the controller clears RESUME and SUSPEND */ if (handshake(ehci, status_reg, PORT_RESUME, 0, 2000)) - pr_err("%s: timeout waiting for PORT_RESUME\n", __func__); - - /* polling PORT_SUSPEND until the controller clear this bit */ + pr_err("%s: timeout waiting for RESUME\n", __func__); if (handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) - pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__); + pr_err("%s: timeout waiting for SUSPEND\n", __func__); ehci->reset_done[wIndex-1] = 0; @@ -268,18 +251,10 @@ done: static void tegra_ehci_restart(struct usb_hcd *hcd) { - unsigned int temp; struct ehci_hcd *ehci = hcd_to_ehci(hcd); + unsigned int temp; - /* Set to Host mode by setting bit 0-1 of USB device mode register */ - temp = readl(hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET); - writel((temp | TEGRA_USB_USBMODE_HOST), - (hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET)); - - /* reset the ehci controller */ - ehci->controller_resets_phy = 0; ehci_reset(ehci); - ehci->controller_resets_phy = 1; /* setup the frame list and Async q heads */ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); @@ -310,7 +285,6 @@ static int tegra_usb_suspend(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct ehci_regs __iomem *hw = tegra->ehci->regs; - struct tegra_ehci_context *context = &tegra->context; unsigned long flags; int hsic = 0; struct tegra_ulpi_config *config; @@ -322,38 +296,23 @@ static int tegra_usb_suspend(struct usb_hcd *hcd) spin_lock_irqsave(&tegra->ehci->lock, flags); - context->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3; - - if ((context->port_speed > TEGRA_USB_PHY_PORT_HIGH) || hsic) { - /* If no device connection or invalid speeds, - * don't save the context */ - context->valid = false; - } else { - context->command = readl(&hw->command); - context->frame_list = readl(&hw->frame_list); - context->async_next = readl(&hw->async_next); - context->txfilltunning = readl(&hw->reserved[2]); - context->otgsc = readl(&hw->reserved[18]); - context->valid = true; - } - + tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3; ehci_halt(tegra->ehci); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irqrestore(&tegra->ehci->lock, flags); - tegra_ehci_power_down(ehci_to_hcd(tegra->ehci)); + tegra_ehci_power_down(hcd); return 0; } static int tegra_usb_resume(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - struct tegra_ehci_context *context = &tegra->context; struct usb_device *udev = hcd->self.root_hub; - struct ehci_regs __iomem *hw = tegra->ehci->regs; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct ehci_regs __iomem *hw = ehci->regs; unsigned long val; - int lp0_resume = 0; int hsic = 0; struct tegra_ulpi_config *config; @@ -361,30 +320,22 @@ static int tegra_usb_resume(struct usb_hcd *hcd) config = tegra->phy->config; hsic = (config->inf_type == TEGRA_USB_UHSIC); } - tegra_ehci_power_up(ehci_to_hcd(tegra->ehci)); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + tegra_ehci_power_up(hcd); - if (!context->valid) { + if (tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) { /* Wait for the phy to detect new devices * before we restart the controller */ msleep(10); goto restart; } - tegra_ehci_phy_restore_start(tegra->phy, context->port_speed); + /* Force the phy to keep data lines in suspend state */ + tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed); - /* Check if the phy resume from LP0. When the phy resume from LP0 - * USB register will be reset. */ - if (!readl(&hw->async_next)) - lp0_resume = 1; - - /* Restore register context */ - writel(TEGRA_USB_USBMODE_HOST, &hw->reserved[19]); - writel(context->otgsc, &hw->reserved[18]); - writel(context->txfilltunning, &hw->reserved[2]); - writel(context->async_next, &hw->async_next); - writel(context->frame_list, &hw->frame_list); - writel(context->command, &hw->command); + /* Enable host mode */ + tdi_reset(ehci); /* Enable Port Power */ val = readl(&hw->port_status[0]); @@ -392,36 +343,38 @@ static int tegra_usb_resume(struct usb_hcd *hcd) writel(val, &hw->port_status[0]); udelay(10); - if (lp0_resume) { - /* Program the field PTC in PORTSC based on the saved speed mode */ + /* Check if the phy resume from LP0. When the phy resume from LP0 + * USB register will be reset. */ + if (!readl(&hw->async_next)) { + /* Program the field PTC based on the saved speed mode */ val = readl(&hw->port_status[0]); - val &= ~(TEGRA_USB_PORTSC1_PTC(~0)); - if (context->port_speed == TEGRA_USB_PHY_PORT_HIGH) - val |= TEGRA_USB_PORTSC1_PTC(5); - else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) - val |= TEGRA_USB_PORTSC1_PTC(6); - else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) - val |= TEGRA_USB_PORTSC1_PTC(7); + val &= ~PORT_TEST(~0); + if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH) + val |= PORT_TEST_FORCE; + else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) + val |= PORT_TEST(6); + else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) + val |= PORT_TEST(7); writel(val, &hw->port_status[0]); udelay(10); - } - /* Disable test mode by setting PTC field to NORMAL_OP */ - val = readl(&hw->port_status[0]); - val &= ~(TEGRA_USB_PORTSC1_PTC(~0)); - writel(val, &hw->port_status[0]); - udelay(10); + /* Disable test mode by setting PTC field to NORMAL_OP */ + val = readl(&hw->port_status[0]); + val &= ~PORT_TEST(~0); + writel(val, &hw->port_status[0]); + udelay(10); + } /* Poll until CCS is enabled */ - if (handshake(tegra->ehci, &hw->port_status[0], PORT_CONNECT, - PORT_CONNECT, 2000)) { + if (handshake(ehci, &hw->port_status[0], PORT_CONNECT, + PORT_CONNECT, 2000)) { pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__); goto restart; } /* Poll until PE is enabled */ - if (handshake(tegra->ehci, &hw->port_status[0], PORT_PE, - PORT_PE, 2000)) { + if (handshake(ehci, &hw->port_status[0], PORT_PE, + PORT_PE, 2000)) { pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__); goto restart; } @@ -438,8 +391,8 @@ static int tegra_usb_resume(struct usb_hcd *hcd) writel(val, &hw->port_status[0]); /* Wait until port suspend completes */ - if (handshake(tegra->ehci, &hw->port_status[0], PORT_SUSPEND, - PORT_SUSPEND, 1000)) { + if (handshake(ehci, &hw->port_status[0], PORT_SUSPEND, + PORT_SUSPEND, 1000)) { pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__); goto restart; @@ -447,11 +400,10 @@ static int tegra_usb_resume(struct usb_hcd *hcd) } tegra_ehci_phy_restore_end(tegra->phy); - return 0; restart: - if (context->valid) + if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) tegra_ehci_phy_restore_end(tegra->phy); if (hsic) { val = readl(&hw->port_status[0]); @@ -469,43 +421,15 @@ restart: return 0; } -static int tegra_ehci_reset(struct usb_hcd *hcd) -{ - unsigned long temp; - int usec = 250*1000; /* see ehci_reset */ - - temp = readl(hcd->regs + TEGRA_USB_USBCMD_REG_OFFSET); - temp |= TEGRA_USB_USBCMD_RESET; - writel(temp, hcd->regs + TEGRA_USB_USBCMD_REG_OFFSET); - - do { - temp = readl(hcd->regs + TEGRA_USB_USBCMD_REG_OFFSET); - if (!(temp & TEGRA_USB_USBCMD_RESET)) - break; - udelay(1); - usec--; - } while (usec); - - if (!usec) - return -ETIMEDOUT; - - /* Set to Host mode by setting bit 0-1 of USB device mode register */ - temp = readl(hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET); - writel((temp | TEGRA_USB_USBMODE_HOST), - (hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET)); - - return 0; -} - static void tegra_ehci_shutdown(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); + /* ehci_shutdown touches the USB controller registers, make sure * controller has clocks to it */ if (!tegra->host_resumed) tegra_ehci_power_up(hcd); - /* call ehci shut down */ ehci_shutdown(hcd); /* we are ready to shut down, powerdown the phy */ @@ -528,6 +452,10 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) /* cache this readonly data; minimize chip reads */ ehci->hcs_params = readl(&ehci->caps->hcs_params); + /* switch to host mode */ + hcd->has_tt = 1; + ehci_reset(ehci); + retval = ehci_halt(ehci); if (retval) return retval; @@ -537,19 +465,8 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) if (retval) return retval; - hcd->has_tt = 1; ehci->sbrn = 0x20; - ehci_reset(ehci); - - /* - * Resetting the controller has the side effect of resetting the PHY. - * So, never reset the controller after the calling - * tegra_ehci_reinit API. - */ - ehci->controller_resets_phy = 1; - ehci->port_reset_no_wait = 1; - ehci_port_power(ehci, 1); return retval; } @@ -855,10 +772,8 @@ static int tegra_ehci_probe(struct platform_device *pdev) { struct resource *res; struct usb_hcd *hcd; - struct ehci_hcd *ehci; struct tegra_ehci_hcd *tegra; struct tegra_ehci_platform_data *pdata; - struct tegra_utmip_config *config; int err = 0; int irq; int instance = pdev->id; @@ -919,11 +834,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail_io; } - config = pdata->phy_config; - INIT_DELAYED_WORK(&tegra->work, tegra_hsic_connection_work); - tegra->phy = tegra_usb_phy_open(instance, hcd->regs, config, + tegra->phy = tegra_usb_phy_open(instance, hcd->regs, pdata->phy_config, TEGRA_USB_PHY_MODE_HOST); if (IS_ERR(tegra->phy)) { dev_err(&pdev->dev, "Failed to open USB phy\n"); @@ -931,15 +844,15 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail_phy; } - err = tegra_ehci_reset(hcd); + err = tegra_usb_phy_power_on(tegra->phy); if (err) { - dev_err(&pdev->dev, "Failed to reset controller\n"); + dev_err(&pdev->dev, "Failed to power on the phy\n"); goto fail; } - tegra_usb_phy_power_on(tegra->phy); tegra->host_resumed = 1; tegra->power_down_on_bus_suspend = pdata->power_down_on_bus_suspend; + tegra->ehci = hcd_to_ehci(hcd); irq = platform_get_irq(pdev, 0); if (!irq) { @@ -947,18 +860,15 @@ static int tegra_ehci_probe(struct platform_device *pdev) err = -ENODEV; goto fail; } - set_irq_flags(irq, IRQF_VALID); - ehci = hcd_to_ehci(hcd); - tegra->ehci = ehci; - #ifdef CONFIG_USB_EHCI_ONOFF_FEATURE if (instance == 1) { ehci_tegra_irq = irq; - create_ehci_sys_file(ehci); + create_ehci_sys_file(tegra->ehci); } #endif + #ifdef CONFIG_USB_OTG_UTILS if (pdata->operating_mode == TEGRA_USB_OTG) { tegra->transceiver = otg_get_transceiver(); @@ -968,7 +878,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) #endif err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); - if (err != 0) { + if (err) { dev_err(&pdev->dev, "Failed to add USB HCD\n"); goto fail; } diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 530540a4bdd4..6f62e68e0e6f 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -132,7 +132,6 @@ struct ehci_hcd { /* one per controller */ unsigned need_io_watchdog:1; unsigned broken_periodic:1; unsigned fs_i_thresh:1; /* Intel iso scheduling */ - unsigned controller_resets_phy:1; unsigned port_reset_no_wait:1; /* required for usb32 quirk */ diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 2240602fc81b..5ea7329e7f98 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -49,6 +49,13 @@ config USB_ULPI Enable this to support ULPI connected USB OTG transceivers which are likely found on embedded boards. +config USB_ULPI_VIEWPORT + bool + depends on USB_ULPI + help + Provides read/write operations to the ULPI phy register set for + controllers with a viewport register (e.g. Chipidea/ARC controllers). + config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" depends on TWL4030_CORE && REGULATOR_TWL4030 diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index fbf2a25a2e8c..8ca50cf114f2 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o obj-$(CONFIG_USB_ULPI) += ulpi.o +obj-$(CONFIG_USB_ULPI_VIEWPORT) += ulpi_viewport.o ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index 5230f9f6ee82..b4804c022098 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -26,7 +26,7 @@ #include <linux/usb/gadget.h> #include <linux/usb/hcd.h> #include <linux/platform_device.h> -#include <linux/tegra_usb.h> +#include <linux/platform_data/tegra_usb.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/delay.h> @@ -339,7 +339,7 @@ static int __exit tegra_otg_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int tegra_otg_suspend(struct platform_device *pdev) +static int tegra_otg_suspend(struct platform_device *pdev, pm_message_t state) { struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev); diff --git a/drivers/usb/otg/ulpi_viewport.c b/drivers/usb/otg/ulpi_viewport.c new file mode 100644 index 000000000000..e9a37f90994f --- /dev/null +++ b/drivers/usb/otg/ulpi_viewport.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/usb.h> +#include <linux/io.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> + +#define ULPI_VIEW_WAKEUP (1 << 31) +#define ULPI_VIEW_RUN (1 << 30) +#define ULPI_VIEW_WRITE (1 << 29) +#define ULPI_VIEW_READ (0 << 29) +#define ULPI_VIEW_ADDR(x) (((x) & 0xff) << 16) +#define ULPI_VIEW_DATA_READ(x) (((x) >> 8) & 0xff) +#define ULPI_VIEW_DATA_WRITE(x) ((x) & 0xff) + +static int ulpi_viewport_wait(void __iomem *view, u32 mask) +{ + unsigned long usec = 2000; + + while (usec--) { + if (!(readl(view) & mask)) + return 0; + + udelay(1); + }; + + return -ETIMEDOUT; +} + +static int ulpi_viewport_read(struct otg_transceiver *otg, u32 reg) +{ + int ret; + void __iomem *view = otg->io_priv; + + writel(ULPI_VIEW_WAKEUP | ULPI_VIEW_WRITE, view); + ret = ulpi_viewport_wait(view, ULPI_VIEW_WAKEUP); + if (ret) + return ret; + + writel(ULPI_VIEW_RUN | ULPI_VIEW_READ | ULPI_VIEW_ADDR(reg), view); + ret = ulpi_viewport_wait(view, ULPI_VIEW_RUN); + if (ret) + return ret; + + return ULPI_VIEW_DATA_READ(readl(view)); +} + +static int ulpi_viewport_write(struct otg_transceiver *otg, u32 val, u32 reg) +{ + int ret; + void __iomem *view = otg->io_priv; + + writel(ULPI_VIEW_WAKEUP | ULPI_VIEW_WRITE, view); + ret = ulpi_viewport_wait(view, ULPI_VIEW_WAKEUP); + if (ret) + return ret; + + writel(ULPI_VIEW_RUN | ULPI_VIEW_WRITE | ULPI_VIEW_DATA_WRITE(val) | + ULPI_VIEW_ADDR(reg), view); + + return ulpi_viewport_wait(view, ULPI_VIEW_RUN); +} + +struct otg_io_access_ops ulpi_viewport_access_ops = { + .read = ulpi_viewport_read, + .write = ulpi_viewport_write, +}; |