/drivers/usb/gadget/fsl_mxc_udc.c
C | 124 lines | 91 code | 16 blank | 17 comment | 18 complexity | 1ad2becb3e7b2a5180a8bda2f10b148e MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
1/* 2 * Copyright (C) 2009 3 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> 4 * 5 * Description: 6 * Helper routines for i.MX3x SoCs from Freescale, needed by the fsl_usb2_udc.c 7 * driver to function correctly on these systems. 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14#include <linux/clk.h> 15#include <linux/delay.h> 16#include <linux/err.h> 17#include <linux/fsl_devices.h> 18#include <linux/platform_device.h> 19 20#include <mach/hardware.h> 21 22static struct clk *mxc_ahb_clk; 23static struct clk *mxc_usb_clk; 24 25/* workaround ENGcm09152 for i.MX35 */ 26#define USBPHYCTRL_OTGBASE_OFFSET 0x608 27#define USBPHYCTRL_EVDO (1 << 23) 28 29int fsl_udc_clk_init(struct platform_device *pdev) 30{ 31 struct fsl_usb2_platform_data *pdata; 32 unsigned long freq; 33 int ret; 34 35 pdata = pdev->dev.platform_data; 36 37 if (!cpu_is_mx35() && !cpu_is_mx25()) { 38 mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb"); 39 if (IS_ERR(mxc_ahb_clk)) 40 return PTR_ERR(mxc_ahb_clk); 41 42 ret = clk_enable(mxc_ahb_clk); 43 if (ret < 0) { 44 dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n"); 45 goto eenahb; 46 } 47 } 48 49 /* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */ 50 mxc_usb_clk = clk_get(&pdev->dev, "usb"); 51 if (IS_ERR(mxc_usb_clk)) { 52 dev_err(&pdev->dev, "clk_get(\"usb\") failed\n"); 53 ret = PTR_ERR(mxc_usb_clk); 54 goto egusb; 55 } 56 57 if (!cpu_is_mx51()) { 58 freq = clk_get_rate(mxc_usb_clk); 59 if (pdata->phy_mode != FSL_USB2_PHY_ULPI && 60 (freq < 59999000 || freq > 60001000)) { 61 dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq); 62 ret = -EINVAL; 63 goto eclkrate; 64 } 65 } 66 67 ret = clk_enable(mxc_usb_clk); 68 if (ret < 0) { 69 dev_err(&pdev->dev, "clk_enable(\"usb_clk\") failed\n"); 70 goto eenusb; 71 } 72 73 return 0; 74 75eenusb: 76eclkrate: 77 clk_put(mxc_usb_clk); 78 mxc_usb_clk = NULL; 79egusb: 80 if (!cpu_is_mx35()) 81 clk_disable(mxc_ahb_clk); 82eenahb: 83 if (!cpu_is_mx35()) 84 clk_put(mxc_ahb_clk); 85 return ret; 86} 87 88void fsl_udc_clk_finalize(struct platform_device *pdev) 89{ 90 struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; 91#if defined(CONFIG_SOC_IMX35) 92 if (cpu_is_mx35()) { 93 unsigned int v; 94 95 /* workaround ENGcm09152 for i.MX35 */ 96 if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { 97 v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + 98 USBPHYCTRL_OTGBASE_OFFSET)); 99 writel(v | USBPHYCTRL_EVDO, 100 MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + 101 USBPHYCTRL_OTGBASE_OFFSET)); 102 } 103 } 104#endif 105 106 /* ULPI transceivers don't need usbpll */ 107 if (pdata->phy_mode == FSL_USB2_PHY_ULPI) { 108 clk_disable(mxc_usb_clk); 109 clk_put(mxc_usb_clk); 110 mxc_usb_clk = NULL; 111 } 112} 113 114void fsl_udc_clk_release(void) 115{ 116 if (mxc_usb_clk) { 117 clk_disable(mxc_usb_clk); 118 clk_put(mxc_usb_clk); 119 } 120 if (!cpu_is_mx35()) { 121 clk_disable(mxc_ahb_clk); 122 clk_put(mxc_ahb_clk); 123 } 124}