fsl/usb: Add controller version based ULPI and UTMI phy support
authorRamneek Mehresh <ramneek.mehresh@freescale.com>
Tue, 20 Mar 2012 05:05:50 +0000 (10:35 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 18 Apr 2012 20:46:42 +0000 (13:46 -0700)
Add support for ULPI and UTMI PHYs based on usb controller
version info read from device-tree

Example of USB Controller versioning info:
Version 1.2 and below : MPC8536, MPC8315, etc
Version 1.6 : P1020, P1010, P2020, P5020, etc
Version 2.2 : PSC9131, PSC9132, P3060, etc

No changes for non-DT users

Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com>
Acked-by: Li Yang <leoli@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fsl_usb2_udc.h
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-fsl.h
drivers/usb/host/fsl-mph-dr-of.c
include/linux/fsl_devices.h

index 5f94e79..6087fa6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2004-2007,2011-2012 Freescale Semiconductor, Inc.
  * All rights reserved.
  *
  * Author: Li Yang <leoli@freescale.com>
@@ -58,9 +58,8 @@ static const char driver_name[] = "fsl-usb2-udc";
 static const char driver_desc[] = DRIVER_DESC;
 
 static struct usb_dr_device *dr_regs;
-#ifndef CONFIG_ARCH_MXC
+
 static struct usb_sys_interface *usb_sys_regs;
-#endif
 
 /* it is initialized in probe()  */
 static struct fsl_udc *udc_controller = NULL;
@@ -244,10 +243,9 @@ static int dr_controller_setup(struct fsl_udc *udc)
 {
        unsigned int tmp, portctrl, ep_num;
        unsigned int max_no_of_ep;
-#ifndef CONFIG_ARCH_MXC
        unsigned int ctrl;
-#endif
        unsigned long timeout;
+
 #define FSL_UDC_RESET_TIMEOUT 1000
 
        /* Config PHY interface */
@@ -255,12 +253,32 @@ static int dr_controller_setup(struct fsl_udc *udc)
        portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
        switch (udc->phy_mode) {
        case FSL_USB2_PHY_ULPI:
+               if (udc->pdata->have_sysif_regs) {
+                       if (udc->pdata->controller_ver) {
+                               /* controller version 1.6 or above */
+                               ctrl = __raw_readl(&usb_sys_regs->control);
+                               ctrl &= ~USB_CTRL_UTMI_PHY_EN;
+                               ctrl |= USB_CTRL_USB_EN;
+                               __raw_writel(ctrl, &usb_sys_regs->control);
+                       }
+               }
                portctrl |= PORTSCX_PTS_ULPI;
                break;
        case FSL_USB2_PHY_UTMI_WIDE:
                portctrl |= PORTSCX_PTW_16BIT;
                /* fall through */
        case FSL_USB2_PHY_UTMI:
+               if (udc->pdata->have_sysif_regs) {
+                       if (udc->pdata->controller_ver) {
+                               /* controller version 1.6 or above */
+                               ctrl = __raw_readl(&usb_sys_regs->control);
+                               ctrl |= (USB_CTRL_UTMI_PHY_EN |
+                                       USB_CTRL_USB_EN);
+                               __raw_writel(ctrl, &usb_sys_regs->control);
+                               mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI
+                                       PHY CLK to become stable - 10ms*/
+                       }
+               }
                portctrl |= PORTSCX_PTS_UTMI;
                break;
        case FSL_USB2_PHY_SERIAL:
index e651469..1212646 100644 (file)
@@ -1,4 +1,12 @@
 /*
+ * Copyright (C) 2004,2012 Freescale Semiconductor, Inc
+ * All rights reserved.
+ *
+ * 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.
+ *
  * Freescale USB device/endpoint management registers
  */
 #ifndef __FSL_USB2_UDC_H
@@ -348,6 +356,9 @@ struct usb_sys_interface {
 /* control Register Bit Masks */
 #define  USB_CTRL_IOENB                       0x00000004
 #define  USB_CTRL_ULPI_INT0EN                 0x00000001
+#define USB_CTRL_UTMI_PHY_EN                 0x00000200
+#define USB_CTRL_USB_EN                              0x00000004
+#define USB_CTRL_ULPI_PHY_CLK_SEL            0x00000400
 
 /* Endpoint Queue Head data struct
  * Rem: all the variables of qh are LittleEndian Mode
index 3e73451..653e577 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005-2009 MontaVista Software, Inc.
- * Copyright 2008      Freescale Semiconductor, Inc.
+ * Copyright 2008,2012      Freescale Semiconductor, Inc.
  *
  * 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
@@ -211,19 +211,32 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
        usb_put_hcd(hcd);
 }
 
-static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
+static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
                               enum fsl_usb2_phy_modes phy_mode,
                               unsigned int port_offset)
 {
-       u32 portsc;
-       struct usb_hcd *hcd = ehci_to_hcd(ehci);
+       u32 portsc, temp;
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        void __iomem *non_ehci = hcd->regs;
+       struct device *dev = hcd->self.controller;
+       struct fsl_usb2_platform_data *pdata = dev->platform_data;
+
+       if (pdata->controller_ver < 0) {
+               dev_warn(hcd->self.controller, "Could not get controller version\n");
+               return;
+       }
 
        portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
        portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
 
        switch (phy_mode) {
        case FSL_USB2_PHY_ULPI:
+               if (pdata->controller_ver) {
+                       /* controller version 1.6 or above */
+                       temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+                       out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
+                               USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL);
+               }
                portsc |= PORT_PTS_ULPI;
                break;
        case FSL_USB2_PHY_SERIAL:
@@ -233,6 +246,14 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
                portsc |= PORT_PTS_PTW;
                /* fall through */
        case FSL_USB2_PHY_UTMI:
+               if (pdata->controller_ver) {
+                       /* controller version 1.6 or above */
+                       temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+                       out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
+                               UTMI_PHY_EN | USB_CTRL_USB_EN);
+                       mdelay(FSL_UTMI_PHY_DLY);  /* Delay for UTMI PHY CLK to
+                                               become stable - 10ms*/
+               }
                /* enable UTMI PHY */
                setbits32(non_ehci + FSL_SOC_USB_CTRL, CTRL_UTMI_PHY_EN);
                portsc |= PORT_PTS_UTMI;
@@ -271,7 +292,7 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 
        if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
                        (pdata->operating_mode == FSL_USB2_DR_OTG))
-               ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
+               ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
 
        if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
                unsigned int chip, rev, svr;
@@ -285,9 +306,9 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
                        ehci->has_fsl_port_bug = 1;
 
                if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-                       ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
+                       ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
                if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-                       ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
+                       ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1);
        }
 
        if (pdata->have_sysif_regs) {
index 863fb0c..8840368 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc.
+/* Copyright (C) 2005-2010,2012 Freescale Semiconductor, Inc.
  * Copyright (c) 2005 MontaVista Software
  *
  * This program is free software; you can redistribute  it and/or modify it
 #define CTRL_UTMI_PHY_EN       (1<<9)
 #define CTRL_PHY_CLK_VALID     (1 << 17)
 #define SNOOP_SIZE_2GB         0x1e
+
+/* control Register Bit Masks */
+#define ULPI_INT_EN             (1<<0)
+#define WU_INT_EN               (1<<1)
+#define USB_CTRL_USB_EN         (1<<2)
+#define LINE_STATE_FILTER__EN   (1<<3)
+#define KEEP_OTG_ON             (1<<4)
+#define OTG_PORT                (1<<5)
+#define PLL_RESET               (1<<8)
+#define UTMI_PHY_EN             (1<<9)
+#define ULPI_PHY_CLK_SEL        (1<<10)
 #endif                         /* _EHCI_FSL_H */
index ab333ac..22ff6b3 100644 (file)
@@ -119,6 +119,39 @@ error:
 
 static const struct of_device_id fsl_usb2_mph_dr_of_match[];
 
+static int usb_get_ver_info(struct device_node *np)
+{
+       int ver = -1;
+
+       /*
+        * returns 1 for usb controller version 1.6
+        * returns 2 for usb controller version 2.2
+        * returns 0 otherwise
+        */
+       if (of_device_is_compatible(np, "fsl-usb2-dr")) {
+               if (of_device_is_compatible(np, "fsl-usb2-dr-v1.6"))
+                       ver = FSL_USB_VER_1_6;
+               else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2"))
+                       ver = FSL_USB_VER_2_2;
+               else /* for previous controller versions */
+                       ver = FSL_USB_VER_OLD;
+
+               if (ver > -1)
+                       return ver;
+       }
+
+       if (of_device_is_compatible(np, "fsl-usb2-mph")) {
+               if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6"))
+                       ver = FSL_USB_VER_1_6;
+               else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2"))
+                       ver = FSL_USB_VER_2_2;
+               else /* for previous controller versions */
+                       ver = FSL_USB_VER_OLD;
+       }
+
+       return ver;
+}
+
 static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
 {
        struct device_node *np = ofdev->dev.of_node;
@@ -166,6 +199,14 @@ static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
 
        prop = of_get_property(np, "phy_type", NULL);
        pdata->phy_mode = determine_usb_phy(prop);
+       pdata->controller_ver = usb_get_ver_info(np);
+
+       if (pdata->have_sysif_regs) {
+               if (pdata->controller_ver < 0) {
+                       dev_warn(&ofdev->dev, "Could not get controller version\n");
+                       return -ENODEV;
+               }
+       }
 
        for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
                if (!dev_data->drivers[i])
index fffdf00..15be561 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
- * Copyright 2004 Freescale Semiconductor, Inc
+ * Copyright 2004,2012 Freescale Semiconductor, Inc
  *
  * 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
 #ifndef _FSL_DEVICE_H_
 #define _FSL_DEVICE_H_
 
+#define FSL_UTMI_PHY_DLY       10      /*As per P1010RM, delay for UTMI
+                               PHY CLK to become stable - 10ms*/
+#define FSL_USB_VER_OLD                0
+#define FSL_USB_VER_1_6                1
+#define FSL_USB_VER_2_2                2
+
 #include <linux/types.h>
 
 /*
@@ -63,6 +69,7 @@ struct platform_device;
 
 struct fsl_usb2_platform_data {
        /* board specific information */
+       int                             controller_ver;
        enum fsl_usb2_operating_modes   operating_mode;
        enum fsl_usb2_phy_modes         phy_mode;
        unsigned int                    port_enables;