diff options
Diffstat (limited to 'drivers/usb/host/ehci-tegra.c')
| -rw-r--r-- | drivers/usb/host/ehci-tegra.c | 68 | 
1 files changed, 43 insertions, 25 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 78fa76da332..6fdcb8ad229 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -17,7 +17,6 @@   */  #include <linux/clk.h> -#include <linux/clk/tegra.h>  #include <linux/dma-mapping.h>  #include <linux/err.h>  #include <linux/gpio.h> @@ -29,6 +28,7 @@  #include <linux/of_gpio.h>  #include <linux/platform_device.h>  #include <linux/pm_runtime.h> +#include <linux/reset.h>  #include <linux/slab.h>  #include <linux/usb/ehci_def.h>  #include <linux/usb/tegra_usb_phy.h> @@ -38,10 +38,6 @@  #include "ehci.h" -#define TEGRA_USB_BASE			0xC5000000 -#define TEGRA_USB2_BASE			0xC5004000 -#define TEGRA_USB3_BASE			0xC5008000 -  #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)  #define TEGRA_USB_DMA_ALIGN 32 @@ -55,13 +51,10 @@ struct tegra_ehci_soc_config {  	bool has_hostpc;  }; -static int (*orig_hub_control)(struct usb_hcd *hcd, -				u16 typeReq, u16 wValue, u16 wIndex, -				char *buf, u16 wLength); -  struct tegra_ehci_hcd {  	struct tegra_usb_phy *phy;  	struct clk *clk; +	struct reset_control *rst;  	int port_resuming;  	bool needs_double_reset;  	enum tegra_usb_phy_port_speed port_speed; @@ -239,7 +232,7 @@ static int tegra_ehci_hub_control(  	spin_unlock_irqrestore(&ehci->lock, flags);  	/* Handle the hub control events here */ -	return orig_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); +	return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);  done:  	spin_unlock_irqrestore(&ehci->lock, flags); @@ -362,10 +355,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)  	 * Since shared usb code relies on it, set it here for now.  	 * Once we have dma capability bindings this can go away.  	 */ -	if (!pdev->dev.dma_mask) -		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (err) +		return err;  	hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,  					dev_name(&pdev->dev)); @@ -386,13 +378,20 @@ static int tegra_ehci_probe(struct platform_device *pdev)  		goto cleanup_hcd_create;  	} +	tegra->rst = devm_reset_control_get(&pdev->dev, "usb"); +	if (IS_ERR(tegra->rst)) { +		dev_err(&pdev->dev, "Can't get ehci reset\n"); +		err = PTR_ERR(tegra->rst); +		goto cleanup_hcd_create; +	} +  	err = clk_prepare_enable(tegra->clk);  	if (err) -		goto cleanup_clk_get; +		goto cleanup_hcd_create; -	tegra_periph_reset_assert(tegra->clk); +	reset_control_assert(tegra->rst);  	udelay(1); -	tegra_periph_reset_deassert(tegra->clk); +	reset_control_deassert(tegra->rst);  	u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);  	if (IS_ERR(u_phy)) { @@ -412,10 +411,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)  	}  	hcd->rsrc_start = res->start;  	hcd->rsrc_len = resource_size(res); -	hcd->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); -	if (!hcd->regs) { -		dev_err(&pdev->dev, "Failed to remap I/O memory\n"); -		err = -ENOMEM; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		err = PTR_ERR(hcd->regs);  		goto cleanup_clk_en;  	}  	ehci->caps = hcd->regs + 0x100; @@ -456,6 +454,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "Failed to add USB HCD\n");  		goto cleanup_otg_set_host;  	} +	device_wakeup_enable(hcd->self.controller);  	return err; @@ -465,8 +464,6 @@ cleanup_phy:  	usb_phy_shutdown(hcd->phy);  cleanup_clk_en:  	clk_disable_unprepare(tegra->clk); -cleanup_clk_get: -	clk_put(tegra->clk);  cleanup_hcd_create:  	usb_put_hcd(hcd);  	return err; @@ -507,8 +504,31 @@ static struct platform_driver tegra_ehci_driver = {  	}  }; +static int tegra_ehci_reset(struct usb_hcd *hcd) +{ +	struct ehci_hcd *ehci = hcd_to_ehci(hcd); +	int retval; +	int txfifothresh; + +	retval = ehci_setup(hcd); +	if (retval) +		return retval; + +	/* +	 * We should really pull this value out of tegra_ehci_soc_config, but +	 * to avoid needing access to it, make use of the fact that Tegra20 is +	 * the only one so far that needs a value of 10, and Tegra20 is the +	 * only one which doesn't set has_hostpc. +	 */ +	txfifothresh = ehci->has_hostpc ? 0x10 : 10; +	ehci_writel(ehci, txfifothresh << 16, &ehci->regs->txfill_tuning); + +	return 0; +} +  static const struct ehci_driver_overrides tegra_overrides __initconst = {  	.extra_priv_size	= sizeof(struct tegra_ehci_hcd), +	.reset			= tegra_ehci_reset,  };  static int __init ehci_tegra_init(void) @@ -529,8 +549,6 @@ static int __init ehci_tegra_init(void)  	 * too easy.  	 */ -	orig_hub_control = tegra_ehci_hc_driver.hub_control; -  	tegra_ehci_hc_driver.map_urb_for_dma = tegra_ehci_map_urb_for_dma;  	tegra_ehci_hc_driver.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma;  	tegra_ehci_hc_driver.hub_control = tegra_ehci_hub_control;  | 
