2009-04-15 14:25:33 +02:00
/*
* Copyright ( C ) 2009
* Guennadi Liakhovetski , DENX Software Engineering , < lg @ denx . de >
*
* Description :
* Helper routines for i . MX3x SoCs from Freescale , needed by the fsl_usb2_udc . c
* driver to function correctly on these systems .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/fsl_devices.h>
# include <linux/platform_device.h>
2011-11-22 13:48:28 -02:00
# include <linux/io.h>
2009-04-15 14:25:33 +02:00
static struct clk * mxc_ahb_clk ;
2012-06-15 18:39:02 -03:00
static struct clk * mxc_per_clk ;
static struct clk * mxc_ipg_clk ;
2009-04-15 14:25:33 +02:00
2010-10-15 14:30:58 +02:00
/* workaround ENGcm09152 for i.MX35 */
# define USBPHYCTRL_OTGBASE_OFFSET 0x608
# define USBPHYCTRL_EVDO (1 << 23)
2009-04-15 14:25:33 +02:00
int fsl_udc_clk_init ( struct platform_device * pdev )
{
struct fsl_usb2_platform_data * pdata ;
unsigned long freq ;
int ret ;
pdata = pdev - > dev . platform_data ;
2012-06-15 18:39:02 -03:00
mxc_ipg_clk = devm_clk_get ( & pdev - > dev , " ipg " ) ;
if ( IS_ERR ( mxc_ipg_clk ) ) {
dev_err ( & pdev - > dev , " clk_get( \" ipg \" ) failed \n " ) ;
return PTR_ERR ( mxc_ipg_clk ) ;
}
2009-04-15 14:25:33 +02:00
2012-06-15 18:39:02 -03:00
mxc_ahb_clk = devm_clk_get ( & pdev - > dev , " ahb " ) ;
if ( IS_ERR ( mxc_ahb_clk ) ) {
dev_err ( & pdev - > dev , " clk_get( \" ahb \" ) failed \n " ) ;
return PTR_ERR ( mxc_ahb_clk ) ;
2009-04-15 14:25:33 +02:00
}
2012-06-15 18:39:02 -03:00
mxc_per_clk = devm_clk_get ( & pdev - > dev , " per " ) ;
if ( IS_ERR ( mxc_per_clk ) ) {
dev_err ( & pdev - > dev , " clk_get( \" per \" ) failed \n " ) ;
return PTR_ERR ( mxc_per_clk ) ;
2009-04-15 14:25:33 +02:00
}
2012-06-15 18:39:02 -03:00
clk_prepare_enable ( mxc_ipg_clk ) ;
clk_prepare_enable ( mxc_ahb_clk ) ;
clk_prepare_enable ( mxc_per_clk ) ;
/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
2013-01-17 18:03:15 +08:00
if ( ! strcmp ( pdev - > id_entry - > name , " imx-udc-mx27 " ) ) {
2012-06-15 18:39:02 -03:00
freq = clk_get_rate ( mxc_per_clk ) ;
2010-05-10 11:21:57 -05:00
if ( pdata - > phy_mode ! = FSL_USB2_PHY_ULPI & &
( freq < 59999000 | | freq > 60001000 ) ) {
dev_err ( & pdev - > dev , " USB_CLK=%lu, should be 60MHz \n " , freq ) ;
ret = - EINVAL ;
goto eclkrate ;
}
2009-04-15 14:25:33 +02:00
}
return 0 ;
eclkrate :
2012-06-15 18:39:02 -03:00
clk_disable_unprepare ( mxc_ipg_clk ) ;
clk_disable_unprepare ( mxc_ahb_clk ) ;
clk_disable_unprepare ( mxc_per_clk ) ;
mxc_per_clk = NULL ;
2009-04-15 14:25:33 +02:00
return ret ;
}
void fsl_udc_clk_finalize ( struct platform_device * pdev )
{
struct fsl_usb2_platform_data * pdata = pdev - > dev . platform_data ;
2013-01-17 18:03:15 +08:00
unsigned int v ;
/* workaround ENGcm09152 for i.MX35 */
if ( pdata - > workaround & FLS_USB2_WORKAROUND_ENGCM09152 ) {
v = readl ( MX35_IO_ADDRESS ( MX35_USB_BASE_ADDR +
USBPHYCTRL_OTGBASE_OFFSET ) ) ;
writel ( v | USBPHYCTRL_EVDO ,
MX35_IO_ADDRESS ( MX35_USB_BASE_ADDR +
USBPHYCTRL_OTGBASE_OFFSET ) ) ;
2010-10-15 14:30:58 +02:00
}
2009-04-15 14:25:33 +02:00
/* ULPI transceivers don't need usbpll */
if ( pdata - > phy_mode = = FSL_USB2_PHY_ULPI ) {
2012-06-15 18:39:02 -03:00
clk_disable_unprepare ( mxc_per_clk ) ;
mxc_per_clk = NULL ;
2009-04-15 14:25:33 +02:00
}
}
void fsl_udc_clk_release ( void )
{
2012-06-15 18:39:02 -03:00
if ( mxc_per_clk )
clk_disable_unprepare ( mxc_per_clk ) ;
clk_disable_unprepare ( mxc_ahb_clk ) ;
clk_disable_unprepare ( mxc_ipg_clk ) ;
2009-04-15 14:25:33 +02:00
}