| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 1 | /* | 
| Anton Vorontsov | 1af1077 | 2009-12-14 18:41:12 +0300 | [diff] [blame] | 2 |  * Copyright 2005-2009 MontaVista Software, Inc. | 
 | 3 |  * Copyright 2008      Freescale Semiconductor, Inc. | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 4 |  * | 
 | 5 |  * This program is free software; you can redistribute it and/or modify it | 
 | 6 |  * under the terms of the GNU General Public License as published by the | 
 | 7 |  * Free Software Foundation; either version 2 of the License, or (at your | 
 | 8 |  * option) any later version. | 
 | 9 |  * | 
 | 10 |  * This program is distributed in the hope that it will be useful, but | 
 | 11 |  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 
 | 12 |  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
 | 13 |  * for more details. | 
 | 14 |  * | 
 | 15 |  * You should have received a copy of the GNU General Public License | 
 | 16 |  * along with this program; if not, write to the Free Software Foundation, | 
 | 17 |  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
 | 18 |  * | 
 | 19 |  * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided | 
 | 20 |  * by Hunter Wu. | 
| Anton Vorontsov | 1af1077 | 2009-12-14 18:41:12 +0300 | [diff] [blame] | 21 |  * Power Management support by Dave Liu <daveliu@freescale.com>, | 
 | 22 |  * Jerry Huang <Chang-Ming.Huang@freescale.com> and | 
 | 23 |  * Anton Vorontsov <avorontsov@ru.mvista.com>. | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 24 |  */ | 
 | 25 |  | 
| Anton Vorontsov | 1af1077 | 2009-12-14 18:41:12 +0300 | [diff] [blame] | 26 | #include <linux/kernel.h> | 
 | 27 | #include <linux/types.h> | 
 | 28 | #include <linux/delay.h> | 
 | 29 | #include <linux/pm.h> | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 30 | #include <linux/platform_device.h> | 
 | 31 | #include <linux/fsl_devices.h> | 
 | 32 |  | 
 | 33 | #include "ehci-fsl.h" | 
 | 34 |  | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 35 | /* configure so an HC device and id are always provided */ | 
 | 36 | /* always called with process context; sleeping is OK */ | 
 | 37 |  | 
 | 38 | /** | 
 | 39 |  * usb_hcd_fsl_probe - initialize FSL-based HCDs | 
 | 40 |  * @drvier: Driver to be used for this HCD | 
 | 41 |  * @pdev: USB Host Controller being probed | 
 | 42 |  * Context: !in_interrupt() | 
 | 43 |  * | 
 | 44 |  * Allocates basic resources for this USB host controller. | 
 | 45 |  * | 
 | 46 |  */ | 
| Anton Vorontsov | dad3843 | 2009-12-14 18:41:05 +0300 | [diff] [blame] | 47 | static int usb_hcd_fsl_probe(const struct hc_driver *driver, | 
 | 48 | 			     struct platform_device *pdev) | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 49 | { | 
 | 50 | 	struct fsl_usb2_platform_data *pdata; | 
 | 51 | 	struct usb_hcd *hcd; | 
 | 52 | 	struct resource *res; | 
 | 53 | 	int irq; | 
 | 54 | 	int retval; | 
 | 55 | 	unsigned int temp; | 
 | 56 |  | 
 | 57 | 	pr_debug("initializing FSL-SOC USB Controller\n"); | 
 | 58 |  | 
 | 59 | 	/* Need platform data for setup */ | 
 | 60 | 	pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; | 
 | 61 | 	if (!pdata) { | 
 | 62 | 		dev_err(&pdev->dev, | 
| Kay Sievers | 7071a3c | 2008-05-02 06:02:41 +0200 | [diff] [blame] | 63 | 			"No platform data for %s.\n", dev_name(&pdev->dev)); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 64 | 		return -ENODEV; | 
 | 65 | 	} | 
 | 66 |  | 
 | 67 | 	/* | 
 | 68 | 	 * This is a host mode driver, verify that we're supposed to be | 
 | 69 | 	 * in host mode. | 
 | 70 | 	 */ | 
 | 71 | 	if (!((pdata->operating_mode == FSL_USB2_DR_HOST) || | 
| Li Yang | ba02978 | 2007-05-11 17:09:55 +0800 | [diff] [blame] | 72 | 	      (pdata->operating_mode == FSL_USB2_MPH_HOST) || | 
 | 73 | 	      (pdata->operating_mode == FSL_USB2_DR_OTG))) { | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 74 | 		dev_err(&pdev->dev, | 
 | 75 | 			"Non Host Mode configured for %s. Wrong driver linked.\n", | 
| Kay Sievers | 7071a3c | 2008-05-02 06:02:41 +0200 | [diff] [blame] | 76 | 			dev_name(&pdev->dev)); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 77 | 		return -ENODEV; | 
 | 78 | 	} | 
 | 79 |  | 
 | 80 | 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 
 | 81 | 	if (!res) { | 
 | 82 | 		dev_err(&pdev->dev, | 
 | 83 | 			"Found HC with no IRQ. Check %s setup!\n", | 
| Kay Sievers | 7071a3c | 2008-05-02 06:02:41 +0200 | [diff] [blame] | 84 | 			dev_name(&pdev->dev)); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 85 | 		return -ENODEV; | 
 | 86 | 	} | 
 | 87 | 	irq = res->start; | 
 | 88 |  | 
| Kay Sievers | 7071a3c | 2008-05-02 06:02:41 +0200 | [diff] [blame] | 89 | 	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 90 | 	if (!hcd) { | 
 | 91 | 		retval = -ENOMEM; | 
 | 92 | 		goto err1; | 
 | 93 | 	} | 
 | 94 |  | 
 | 95 | 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
 | 96 | 	if (!res) { | 
 | 97 | 		dev_err(&pdev->dev, | 
 | 98 | 			"Found HC with no register addr. Check %s setup!\n", | 
| Kay Sievers | 7071a3c | 2008-05-02 06:02:41 +0200 | [diff] [blame] | 99 | 			dev_name(&pdev->dev)); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 100 | 		retval = -ENODEV; | 
 | 101 | 		goto err2; | 
 | 102 | 	} | 
 | 103 | 	hcd->rsrc_start = res->start; | 
 | 104 | 	hcd->rsrc_len = res->end - res->start + 1; | 
 | 105 | 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, | 
 | 106 | 				driver->description)) { | 
 | 107 | 		dev_dbg(&pdev->dev, "controller already in use\n"); | 
 | 108 | 		retval = -EBUSY; | 
 | 109 | 		goto err2; | 
 | 110 | 	} | 
 | 111 | 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | 
 | 112 |  | 
 | 113 | 	if (hcd->regs == NULL) { | 
 | 114 | 		dev_dbg(&pdev->dev, "error mapping memory\n"); | 
 | 115 | 		retval = -EFAULT; | 
 | 116 | 		goto err3; | 
 | 117 | 	} | 
 | 118 |  | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 119 | 	pdata->regs = hcd->regs; | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 120 |  | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 121 | 	/* | 
 | 122 | 	 * do platform specific init: check the clock, grab/config pins, etc. | 
 | 123 | 	 */ | 
 | 124 | 	if (pdata->init && pdata->init(pdev)) { | 
 | 125 | 		retval = -ENODEV; | 
 | 126 | 		goto err3; | 
 | 127 | 	} | 
 | 128 |  | 
 | 129 | 	/* | 
 | 130 | 	 * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs | 
 | 131 | 	 * flag for 83xx or 8536 system interface registers. | 
 | 132 | 	 */ | 
 | 133 | 	if (pdata->big_endian_mmio) | 
 | 134 | 		temp = in_be32(hcd->regs + FSL_SOC_USB_ID); | 
 | 135 | 	else | 
 | 136 | 		temp = in_le32(hcd->regs + FSL_SOC_USB_ID); | 
 | 137 |  | 
 | 138 | 	if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK)) | 
 | 139 | 		pdata->have_sysif_regs = 1; | 
 | 140 |  | 
 | 141 | 	/* Enable USB controller, 83xx or 8536 */ | 
 | 142 | 	if (pdata->have_sysif_regs) | 
 | 143 | 		setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); | 
 | 144 |  | 
 | 145 | 	/* Don't need to set host mode here. It will be done by tdi_reset() */ | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 146 |  | 
| Alan Stern | 442258e | 2007-12-06 14:47:08 -0500 | [diff] [blame] | 147 | 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 148 | 	if (retval != 0) | 
 | 149 | 		goto err4; | 
 | 150 | 	return retval; | 
 | 151 |  | 
 | 152 |       err4: | 
 | 153 | 	iounmap(hcd->regs); | 
 | 154 |       err3: | 
 | 155 | 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 
 | 156 |       err2: | 
 | 157 | 	usb_put_hcd(hcd); | 
 | 158 |       err1: | 
| Kay Sievers | 7071a3c | 2008-05-02 06:02:41 +0200 | [diff] [blame] | 159 | 	dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 160 | 	if (pdata->exit) | 
 | 161 | 		pdata->exit(pdev); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 162 | 	return retval; | 
 | 163 | } | 
 | 164 |  | 
 | 165 | /* may be called without controller electrically present */ | 
 | 166 | /* may be called with controller, bus, and devices active */ | 
 | 167 |  | 
 | 168 | /** | 
 | 169 |  * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs | 
 | 170 |  * @dev: USB Host Controller being removed | 
 | 171 |  * Context: !in_interrupt() | 
 | 172 |  * | 
 | 173 |  * Reverses the effect of usb_hcd_fsl_probe(). | 
 | 174 |  * | 
 | 175 |  */ | 
| Anton Vorontsov | dad3843 | 2009-12-14 18:41:05 +0300 | [diff] [blame] | 176 | static void usb_hcd_fsl_remove(struct usb_hcd *hcd, | 
 | 177 | 			       struct platform_device *pdev) | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 178 | { | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 179 | 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; | 
 | 180 |  | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 181 | 	usb_remove_hcd(hcd); | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 182 |  | 
 | 183 | 	/* | 
 | 184 | 	 * do platform specific un-initialization: | 
 | 185 | 	 * release iomux pins, disable clock, etc. | 
 | 186 | 	 */ | 
 | 187 | 	if (pdata->exit) | 
 | 188 | 		pdata->exit(pdev); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 189 | 	iounmap(hcd->regs); | 
 | 190 | 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 
 | 191 | 	usb_put_hcd(hcd); | 
 | 192 | } | 
 | 193 |  | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 194 | static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, | 
 | 195 | 			       enum fsl_usb2_phy_modes phy_mode, | 
 | 196 | 			       unsigned int port_offset) | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 197 | { | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 198 | 	u32 portsc; | 
 | 199 |  | 
 | 200 | 	portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]); | 
 | 201 | 	portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW); | 
 | 202 |  | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 203 | 	switch (phy_mode) { | 
 | 204 | 	case FSL_USB2_PHY_ULPI: | 
 | 205 | 		portsc |= PORT_PTS_ULPI; | 
 | 206 | 		break; | 
 | 207 | 	case FSL_USB2_PHY_SERIAL: | 
 | 208 | 		portsc |= PORT_PTS_SERIAL; | 
 | 209 | 		break; | 
 | 210 | 	case FSL_USB2_PHY_UTMI_WIDE: | 
 | 211 | 		portsc |= PORT_PTS_PTW; | 
 | 212 | 		/* fall through */ | 
 | 213 | 	case FSL_USB2_PHY_UTMI: | 
 | 214 | 		portsc |= PORT_PTS_UTMI; | 
 | 215 | 		break; | 
 | 216 | 	case FSL_USB2_PHY_NONE: | 
 | 217 | 		break; | 
 | 218 | 	} | 
| Benjamin Herrenschmidt | 083522d | 2006-12-15 06:54:08 +1100 | [diff] [blame] | 219 | 	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 220 | } | 
 | 221 |  | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 222 | static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 223 | { | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 224 | 	struct usb_hcd *hcd = ehci_to_hcd(ehci); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 225 | 	struct fsl_usb2_platform_data *pdata; | 
 | 226 | 	void __iomem *non_ehci = hcd->regs; | 
| Li Yang | ba02978 | 2007-05-11 17:09:55 +0800 | [diff] [blame] | 227 | 	u32 temp; | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 228 |  | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 229 | 	pdata = hcd->self.controller->platform_data; | 
 | 230 |  | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 231 | 	/* Enable PHY interface in the control reg. */ | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 232 | 	if (pdata->have_sysif_regs) { | 
 | 233 | 		temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); | 
 | 234 | 		out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004); | 
 | 235 | 		out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b); | 
 | 236 | 	} | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 237 |  | 
| Li Yang | 40acc09 | 2007-05-23 13:58:17 -0700 | [diff] [blame] | 238 | #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) | 
 | 239 | 	/* | 
 | 240 | 	 * Turn on cache snooping hardware, since some PowerPC platforms | 
 | 241 | 	 * wholly rely on hardware to deal with cache coherent | 
 | 242 | 	 */ | 
 | 243 |  | 
 | 244 | 	/* Setup Snooping for all the 4GB space */ | 
 | 245 | 	/* SNOOP1 starts from 0x0, size 2G */ | 
 | 246 | 	out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB); | 
 | 247 | 	/* SNOOP2 starts from 0x80000000, size 2G */ | 
 | 248 | 	out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB); | 
 | 249 | #endif | 
 | 250 |  | 
| Li Yang | ba02978 | 2007-05-11 17:09:55 +0800 | [diff] [blame] | 251 | 	if ((pdata->operating_mode == FSL_USB2_DR_HOST) || | 
 | 252 | 			(pdata->operating_mode == FSL_USB2_DR_OTG)) | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 253 | 		ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 254 |  | 
 | 255 | 	if (pdata->operating_mode == FSL_USB2_MPH_HOST) { | 
| Kumar Gala | 8cd42e9 | 2006-01-20 13:57:52 -0800 | [diff] [blame] | 256 | 		unsigned int chip, rev, svr; | 
 | 257 |  | 
 | 258 | 		svr = mfspr(SPRN_SVR); | 
 | 259 | 		chip = svr >> 16; | 
 | 260 | 		rev = (svr >> 4) & 0xf; | 
 | 261 |  | 
 | 262 | 		/* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */ | 
 | 263 | 		if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055)) | 
 | 264 | 			ehci->has_fsl_port_bug = 1; | 
 | 265 |  | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 266 | 		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 267 | 			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 268 | 		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 269 | 			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 270 | 	} | 
 | 271 |  | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 272 | 	if (pdata->have_sysif_regs) { | 
| Srikanth Srinivasan | 4f53425 | 2008-07-02 02:14:33 -0500 | [diff] [blame] | 273 | #ifdef CONFIG_PPC_85xx | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 274 | 		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008); | 
 | 275 | 		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080); | 
| Srikanth Srinivasan | 4f53425 | 2008-07-02 02:14:33 -0500 | [diff] [blame] | 276 | #else | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 277 | 		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c); | 
 | 278 | 		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040); | 
| Srikanth Srinivasan | 4f53425 | 2008-07-02 02:14:33 -0500 | [diff] [blame] | 279 | #endif | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 280 | 		out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); | 
 | 281 | 	} | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 282 | } | 
 | 283 |  | 
 | 284 | /* called after powerup, by probe or system-pm "wakeup" */ | 
 | 285 | static int ehci_fsl_reinit(struct ehci_hcd *ehci) | 
 | 286 | { | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 287 | 	ehci_fsl_usb_setup(ehci); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 288 | 	ehci_port_power(ehci, 0); | 
 | 289 |  | 
 | 290 | 	return 0; | 
 | 291 | } | 
 | 292 |  | 
 | 293 | /* called during probe() after chip reset completes */ | 
 | 294 | static int ehci_fsl_setup(struct usb_hcd *hcd) | 
 | 295 | { | 
 | 296 | 	struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 
 | 297 | 	int retval; | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 298 | 	struct fsl_usb2_platform_data *pdata; | 
 | 299 |  | 
 | 300 | 	pdata = hcd->self.controller->platform_data; | 
 | 301 | 	ehci->big_endian_desc = pdata->big_endian_desc; | 
 | 302 | 	ehci->big_endian_mmio = pdata->big_endian_mmio; | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 303 |  | 
 | 304 | 	/* EHCI registers start at offset 0x100 */ | 
 | 305 | 	ehci->caps = hcd->regs + 0x100; | 
 | 306 | 	ehci->regs = hcd->regs + 0x100 + | 
| Benjamin Herrenschmidt | 083522d | 2006-12-15 06:54:08 +1100 | [diff] [blame] | 307 | 	    HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 308 | 	dbg_hcs_params(ehci, "reset"); | 
 | 309 | 	dbg_hcc_params(ehci, "reset"); | 
 | 310 |  | 
 | 311 | 	/* cache this readonly data; minimize chip reads */ | 
| Benjamin Herrenschmidt | 083522d | 2006-12-15 06:54:08 +1100 | [diff] [blame] | 312 | 	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 313 |  | 
| Matthieu CASTET | 65fd427 | 2010-09-06 18:26:56 +0200 | [diff] [blame] | 314 | 	hcd->has_tt = 1; | 
 | 315 |  | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 316 | 	retval = ehci_halt(ehci); | 
 | 317 | 	if (retval) | 
 | 318 | 		return retval; | 
 | 319 |  | 
 | 320 | 	/* data structure init */ | 
 | 321 | 	retval = ehci_init(hcd); | 
 | 322 | 	if (retval) | 
 | 323 | 		return retval; | 
 | 324 |  | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 325 | 	ehci->sbrn = 0x20; | 
 | 326 |  | 
 | 327 | 	ehci_reset(ehci); | 
 | 328 |  | 
 | 329 | 	retval = ehci_fsl_reinit(ehci); | 
 | 330 | 	return retval; | 
 | 331 | } | 
 | 332 |  | 
| Anton Vorontsov | 1af1077 | 2009-12-14 18:41:12 +0300 | [diff] [blame] | 333 | struct ehci_fsl { | 
 | 334 | 	struct ehci_hcd	ehci; | 
 | 335 |  | 
 | 336 | #ifdef CONFIG_PM | 
 | 337 | 	/* Saved USB PHY settings, need to restore after deep sleep. */ | 
 | 338 | 	u32 usb_ctrl; | 
 | 339 | #endif | 
 | 340 | }; | 
 | 341 |  | 
 | 342 | #ifdef CONFIG_PM | 
 | 343 |  | 
 | 344 | static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd) | 
 | 345 | { | 
 | 346 | 	struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 
 | 347 |  | 
 | 348 | 	return container_of(ehci, struct ehci_fsl, ehci); | 
 | 349 | } | 
 | 350 |  | 
 | 351 | static int ehci_fsl_drv_suspend(struct device *dev) | 
 | 352 | { | 
 | 353 | 	struct usb_hcd *hcd = dev_get_drvdata(dev); | 
 | 354 | 	struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); | 
 | 355 | 	void __iomem *non_ehci = hcd->regs; | 
 | 356 |  | 
| Alan Stern | 4147200 | 2010-06-25 14:02:14 -0400 | [diff] [blame] | 357 | 	ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), | 
 | 358 | 			device_may_wakeup(dev)); | 
| Anton Vorontsov | 1af1077 | 2009-12-14 18:41:12 +0300 | [diff] [blame] | 359 | 	if (!fsl_deep_sleep()) | 
 | 360 | 		return 0; | 
 | 361 |  | 
 | 362 | 	ehci_fsl->usb_ctrl = in_be32(non_ehci + FSL_SOC_USB_CTRL); | 
 | 363 | 	return 0; | 
 | 364 | } | 
 | 365 |  | 
 | 366 | static int ehci_fsl_drv_resume(struct device *dev) | 
 | 367 | { | 
 | 368 | 	struct usb_hcd *hcd = dev_get_drvdata(dev); | 
 | 369 | 	struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); | 
 | 370 | 	struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 
 | 371 | 	void __iomem *non_ehci = hcd->regs; | 
 | 372 |  | 
| Alan Stern | 16032c4 | 2010-05-12 18:21:35 -0400 | [diff] [blame] | 373 | 	ehci_prepare_ports_for_controller_resume(ehci); | 
| Anton Vorontsov | 1af1077 | 2009-12-14 18:41:12 +0300 | [diff] [blame] | 374 | 	if (!fsl_deep_sleep()) | 
 | 375 | 		return 0; | 
 | 376 |  | 
 | 377 | 	usb_root_hub_lost_power(hcd->self.root_hub); | 
 | 378 |  | 
 | 379 | 	/* Restore USB PHY settings and enable the controller. */ | 
 | 380 | 	out_be32(non_ehci + FSL_SOC_USB_CTRL, ehci_fsl->usb_ctrl); | 
 | 381 |  | 
 | 382 | 	ehci_reset(ehci); | 
 | 383 | 	ehci_fsl_reinit(ehci); | 
 | 384 |  | 
 | 385 | 	return 0; | 
 | 386 | } | 
 | 387 |  | 
 | 388 | static int ehci_fsl_drv_restore(struct device *dev) | 
 | 389 | { | 
 | 390 | 	struct usb_hcd *hcd = dev_get_drvdata(dev); | 
 | 391 |  | 
 | 392 | 	usb_root_hub_lost_power(hcd->self.root_hub); | 
 | 393 | 	return 0; | 
 | 394 | } | 
 | 395 |  | 
 | 396 | static struct dev_pm_ops ehci_fsl_pm_ops = { | 
 | 397 | 	.suspend = ehci_fsl_drv_suspend, | 
 | 398 | 	.resume = ehci_fsl_drv_resume, | 
 | 399 | 	.restore = ehci_fsl_drv_restore, | 
 | 400 | }; | 
 | 401 |  | 
 | 402 | #define EHCI_FSL_PM_OPS		(&ehci_fsl_pm_ops) | 
 | 403 | #else | 
 | 404 | #define EHCI_FSL_PM_OPS		NULL | 
 | 405 | #endif /* CONFIG_PM */ | 
 | 406 |  | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 407 | static const struct hc_driver ehci_fsl_hc_driver = { | 
 | 408 | 	.description = hcd_name, | 
 | 409 | 	.product_desc = "Freescale On-Chip EHCI Host Controller", | 
| Anton Vorontsov | 1af1077 | 2009-12-14 18:41:12 +0300 | [diff] [blame] | 410 | 	.hcd_priv_size = sizeof(struct ehci_fsl), | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 411 |  | 
 | 412 | 	/* | 
 | 413 | 	 * generic hardware linkage | 
 | 414 | 	 */ | 
 | 415 | 	.irq = ehci_irq, | 
| Anatolij Gustschin | 230f7ed | 2010-09-28 20:55:21 +0200 | [diff] [blame] | 416 | 	.flags = HCD_USB2 | HCD_MEMORY, | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 417 |  | 
 | 418 | 	/* | 
 | 419 | 	 * basic lifecycle operations | 
 | 420 | 	 */ | 
 | 421 | 	.reset = ehci_fsl_setup, | 
 | 422 | 	.start = ehci_run, | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 423 | 	.stop = ehci_stop, | 
| Aleksey Gorelov | 64a21d0 | 2006-08-08 17:24:08 -0700 | [diff] [blame] | 424 | 	.shutdown = ehci_shutdown, | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 425 |  | 
 | 426 | 	/* | 
 | 427 | 	 * managing i/o requests and associated device resources | 
 | 428 | 	 */ | 
 | 429 | 	.urb_enqueue = ehci_urb_enqueue, | 
 | 430 | 	.urb_dequeue = ehci_urb_dequeue, | 
 | 431 | 	.endpoint_disable = ehci_endpoint_disable, | 
| Alan Stern | b18ffd4 | 2009-05-27 18:21:56 -0400 | [diff] [blame] | 432 | 	.endpoint_reset = ehci_endpoint_reset, | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 433 |  | 
 | 434 | 	/* | 
 | 435 | 	 * scheduling support | 
 | 436 | 	 */ | 
 | 437 | 	.get_frame_number = ehci_get_frame, | 
 | 438 |  | 
 | 439 | 	/* | 
 | 440 | 	 * root hub support | 
 | 441 | 	 */ | 
 | 442 | 	.hub_status_data = ehci_hub_status_data, | 
 | 443 | 	.hub_control = ehci_hub_control, | 
 | 444 | 	.bus_suspend = ehci_bus_suspend, | 
 | 445 | 	.bus_resume = ehci_bus_resume, | 
| Balaji Rao | 90da096 | 2007-11-22 01:58:14 +0530 | [diff] [blame] | 446 | 	.relinquish_port = ehci_relinquish_port, | 
| Alan Stern | 3a31155 | 2008-05-20 16:58:29 -0400 | [diff] [blame] | 447 | 	.port_handed_over = ehci_port_handed_over, | 
| Alan Stern | 914b701 | 2009-06-29 10:47:30 -0400 | [diff] [blame] | 448 |  | 
 | 449 | 	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 450 | }; | 
 | 451 |  | 
 | 452 | static int ehci_fsl_drv_probe(struct platform_device *pdev) | 
 | 453 | { | 
 | 454 | 	if (usb_disabled()) | 
 | 455 | 		return -ENODEV; | 
 | 456 |  | 
| David Brownell | 135db04 | 2008-02-11 18:40:46 -0800 | [diff] [blame] | 457 | 	/* FIXME we only want one one probe() not two */ | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 458 | 	return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev); | 
 | 459 | } | 
 | 460 |  | 
 | 461 | static int ehci_fsl_drv_remove(struct platform_device *pdev) | 
 | 462 | { | 
 | 463 | 	struct usb_hcd *hcd = platform_get_drvdata(pdev); | 
 | 464 |  | 
| David Brownell | 135db04 | 2008-02-11 18:40:46 -0800 | [diff] [blame] | 465 | 	/* FIXME we only want one one remove() not two */ | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 466 | 	usb_hcd_fsl_remove(hcd, pdev); | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 467 | 	return 0; | 
 | 468 | } | 
 | 469 |  | 
| David Brownell | 135db04 | 2008-02-11 18:40:46 -0800 | [diff] [blame] | 470 | MODULE_ALIAS("platform:fsl-ehci"); | 
| Kumar Gala | 01cced2 | 2006-04-11 10:07:16 -0500 | [diff] [blame] | 471 |  | 
 | 472 | static struct platform_driver ehci_fsl_driver = { | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 473 | 	.probe = ehci_fsl_drv_probe, | 
 | 474 | 	.remove = ehci_fsl_drv_remove, | 
| Aleksey Gorelov | 64a21d0 | 2006-08-08 17:24:08 -0700 | [diff] [blame] | 475 | 	.shutdown = usb_hcd_platform_shutdown, | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 476 | 	.driver = { | 
| Anton Vorontsov | 1af1077 | 2009-12-14 18:41:12 +0300 | [diff] [blame] | 477 | 		.name = "fsl-ehci", | 
 | 478 | 		.pm = EHCI_FSL_PM_OPS, | 
| David Brownell | 135db04 | 2008-02-11 18:40:46 -0800 | [diff] [blame] | 479 | 	}, | 
| Randy Vinson | 80cb9ae | 2006-01-20 13:53:38 -0800 | [diff] [blame] | 480 | }; |