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#include <linux/io.h> 20 21#include <mach/hardware.h> 22 23static struct clk *mxc_ahb_clk; 24static struct clk *mxc_usb_clk; 25 26/* workaround ENGcm09152 for i.MX35 */ 27#define USBPHYCTRL_OTGBASE_OFFSET 0x608 28#define USBPHYCTRL_EVDO (1 << 23) 29 30int fsl_udc_clk_init(struct platform_device *pdev) 31{ 32 struct fsl_usb2_platform_data *pdata; 33 unsigned long freq; 34 int ret; 35 36 pdata = pdev->dev.platform_data; 37 38 if (!cpu_is_mx35() && !cpu_is_mx25()) { 39 mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb"); 40 if (IS_ERR(mxc_ahb_clk)) 41 return PTR_ERR(mxc_ahb_clk); 42 43 ret = clk_enable(mxc_ahb_clk); 44 if (ret < 0) { 45 dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n"); 46 goto eenahb; 47 } 48 } 49 50 /* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */ 51 mxc_usb_clk = clk_get(&pdev->dev, "usb"); 52 if (IS_ERR(mxc_usb_clk)) { 53 dev_err(&pdev->dev, "clk_get(\"usb\") failed\n"); 54 ret = PTR_ERR(mxc_usb_clk); 55 goto egusb; 56 } 57 58 if (!cpu_is_mx51()) { 59 freq = clk_get_rate(mxc_usb_clk); 60 if (pdata->phy_mode != FSL_USB2_PHY_ULPI && 61 (freq < 59999000 || freq > 60001000)) { 62 dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq); 63 ret = -EINVAL; 64 goto eclkrate; 65 } 66 } 67 68 ret = clk_enable(mxc_usb_clk); 69 if (ret < 0) { 70 dev_err(&pdev->dev, "clk_enable(\"usb_clk\") failed\n"); 71 goto eenusb; 72 } 73 74 return 0; 75 76eenusb: 77eclkrate: 78 clk_put(mxc_usb_clk); 79 mxc_usb_clk = NULL; 80egusb: 81 if (!cpu_is_mx35()) 82 clk_disable(mxc_ahb_clk); 83eenahb: 84 if (!cpu_is_mx35()) 85 clk_put(mxc_ahb_clk); 86 return ret; 87} 88 89void fsl_udc_clk_finalize(struct platform_device *pdev) 90{ 91 struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; 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 105 /* ULPI transceivers don't need usbpll */ 106 if (pdata->phy_mode == FSL_USB2_PHY_ULPI) { 107 clk_disable(mxc_usb_clk); 108 clk_put(mxc_usb_clk); 109 mxc_usb_clk = NULL; 110 } 111} 112 113void fsl_udc_clk_release(void) 114{ 115 if (mxc_usb_clk) { 116 clk_disable(mxc_usb_clk); 117 clk_put(mxc_usb_clk); 118 } 119 if (!cpu_is_mx35()) { 120 clk_disable(mxc_ahb_clk); 121 clk_put(mxc_ahb_clk); 122 } 123} 124