diff options
Diffstat (limited to 'drivers/usb/dwc3/dwc3-exynos.c')
| -rw-r--r-- | drivers/usb/dwc3/dwc3-exynos.c | 96 | 
1 files changed, 62 insertions, 34 deletions
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index b082bec7343..a8afe6e2662 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -22,9 +22,9 @@  #include <linux/usb/otg.h>  #include <linux/usb/nop-usb-xceiv.h>  #include <linux/of.h> +#include <linux/of_platform.h>  struct dwc3_exynos { -	struct platform_device	*dwc3;  	struct platform_device	*usb2_phy;  	struct platform_device	*usb3_phy;  	struct device		*dev; @@ -86,21 +86,30 @@ err1:  	return ret;  } +static int dwc3_exynos_remove_child(struct device *dev, void *unused) +{ +	struct platform_device *pdev = to_platform_device(dev); + +	platform_device_unregister(pdev); + +	return 0; +} +  static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32);  static int dwc3_exynos_probe(struct platform_device *pdev)  { -	struct platform_device	*dwc3;  	struct dwc3_exynos	*exynos;  	struct clk		*clk;  	struct device		*dev = &pdev->dev; +	struct device_node	*node = dev->of_node;  	int			ret = -ENOMEM;  	exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);  	if (!exynos) {  		dev_err(dev, "not enough memory\n"); -		return -ENOMEM; +		goto err1;  	}  	/* @@ -108,21 +117,15 @@ static int dwc3_exynos_probe(struct platform_device *pdev)  	 * Since shared usb code relies on it, set it here for now.  	 * Once we move to full device tree support this will vanish off.  	 */ -	if (!pdev->dev.dma_mask) -		pdev->dev.dma_mask = &dwc3_exynos_dma_mask; +	if (!dev->dma_mask) +		dev->dma_mask = &dwc3_exynos_dma_mask;  	platform_set_drvdata(pdev, exynos);  	ret = dwc3_exynos_register_phys(exynos);  	if (ret) {  		dev_err(dev, "couldn't register PHYs\n"); -		return ret; -	} - -	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); -	if (!dwc3) { -		dev_err(dev, "couldn't allocate dwc3 device\n"); -		return -ENOMEM; +		goto err1;  	}  	clk = devm_clk_get(dev, "usbdrd30"); @@ -132,37 +135,28 @@ static int dwc3_exynos_probe(struct platform_device *pdev)  		goto err1;  	} -	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); - -	dwc3->dev.parent = dev; -	dwc3->dev.dma_mask = dev->dma_mask; -	dwc3->dev.dma_parms = dev->dma_parms; -	exynos->dwc3	= dwc3;  	exynos->dev	= dev;  	exynos->clk	= clk; -	clk_enable(exynos->clk); - -	ret = platform_device_add_resources(dwc3, pdev->resource, -			pdev->num_resources); -	if (ret) { -		dev_err(dev, "couldn't add resources to dwc3 device\n"); -		goto err2; -	} +	clk_prepare_enable(exynos->clk); -	ret = platform_device_add(dwc3); -	if (ret) { -		dev_err(dev, "failed to register dwc3 device\n"); +	if (node) { +		ret = of_platform_populate(node, NULL, NULL, dev); +		if (ret) { +			dev_err(dev, "failed to add dwc3 core\n"); +			goto err2; +		} +	} else { +		dev_err(dev, "no device node, failed to add dwc3 core\n"); +		ret = -ENODEV;  		goto err2;  	}  	return 0;  err2: -	clk_disable(clk); +	clk_disable_unprepare(clk);  err1: -	platform_device_put(dwc3); -  	return ret;  } @@ -170,11 +164,11 @@ static int dwc3_exynos_remove(struct platform_device *pdev)  {  	struct dwc3_exynos	*exynos = platform_get_drvdata(pdev); -	platform_device_unregister(exynos->dwc3);  	platform_device_unregister(exynos->usb2_phy);  	platform_device_unregister(exynos->usb3_phy); +	device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); -	clk_disable(exynos->clk); +	clk_disable_unprepare(exynos->clk);  	return 0;  } @@ -187,12 +181,46 @@ static const struct of_device_id exynos_dwc3_match[] = {  MODULE_DEVICE_TABLE(of, exynos_dwc3_match);  #endif +#ifdef CONFIG_PM_SLEEP +static int dwc3_exynos_suspend(struct device *dev) +{ +	struct dwc3_exynos *exynos = dev_get_drvdata(dev); + +	clk_disable(exynos->clk); + +	return 0; +} + +static int dwc3_exynos_resume(struct device *dev) +{ +	struct dwc3_exynos *exynos = dev_get_drvdata(dev); + +	clk_enable(exynos->clk); + +	/* runtime set active to reflect active state. */ +	pm_runtime_disable(dev); +	pm_runtime_set_active(dev); +	pm_runtime_enable(dev); + +	return 0; +} + +static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume) +}; + +#define DEV_PM_OPS	(&dwc3_exynos_dev_pm_ops) +#else +#define DEV_PM_OPS	NULL +#endif /* CONFIG_PM_SLEEP */ +  static struct platform_driver dwc3_exynos_driver = {  	.probe		= dwc3_exynos_probe,  	.remove		= dwc3_exynos_remove,  	.driver		= {  		.name	= "exynos-dwc3",  		.of_match_table = of_match_ptr(exynos_dwc3_match), +		.pm	= DEV_PM_OPS,  	},  };  |