2012-05-08 17:23:33 -06:00
/*
* MSDI IP block reset
*
* Copyright ( C ) 2012 Texas Instruments , Inc .
* Paul Walmsley
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA
* 02110 - 1301 USA
*
* XXX What about pad muxing ?
*/
# include <linux/kernel.h>
2012-06-26 03:14:20 -07:00
# include <linux/err.h>
2012-08-30 15:37:24 -07:00
# include <linux/platform_data/gpio-omap.h>
2012-05-08 17:23:33 -06:00
# include <plat/omap_hwmod.h>
2012-06-26 03:14:20 -07:00
# include <plat/omap_device.h>
2012-05-08 17:23:33 -06:00
# include "common.h"
2012-06-26 03:14:20 -07:00
# include "control.h"
# include "mux.h"
2012-10-15 12:09:43 -07:00
# include "mmc.h"
2012-05-08 17:23:33 -06:00
/*
* MSDI_CON_OFFSET : offset in bytes of the MSDI IP block ' s CON register
* from the IP block ' s base address
*/
# define MSDI_CON_OFFSET 0x0c
/* Register bitfields in the CON register */
# define MSDI_CON_POW_MASK BIT(11)
# define MSDI_CON_CLKD_MASK (0x3f << 0)
# define MSDI_CON_CLKD_SHIFT 0
/* Maximum microseconds to wait for OMAP module to softreset */
# define MAX_MODULE_SOFTRESET_WAIT 10000
/* MSDI_TARGET_RESET_CLKD: clock divisor to use throughout the reset */
# define MSDI_TARGET_RESET_CLKD 0x3ff
/**
* omap_msdi_reset - reset the MSDI IP block
* @ oh : struct omap_hwmod *
*
* The MSDI IP block on OMAP2420 has to have both the POW and CLKD
* fields set inside its CON register for a reset to complete
* successfully . This is not documented in the TRM . For CLKD , we use
* the value that results in the lowest possible clock rate , to attempt
* to avoid disturbing any cards .
*/
int omap_msdi_reset ( struct omap_hwmod * oh )
{
u16 v = 0 ;
int c = 0 ;
/* Write to the SOFTRESET bit */
omap_hwmod_softreset ( oh ) ;
/* Enable the MSDI core and internal clock */
v | = MSDI_CON_POW_MASK ;
v | = MSDI_TARGET_RESET_CLKD < < MSDI_CON_CLKD_SHIFT ;
omap_hwmod_write ( v , oh , MSDI_CON_OFFSET ) ;
/* Poll on RESETDONE bit */
omap_test_timeout ( ( omap_hwmod_read ( oh , oh - > class - > sysc - > syss_offs )
& SYSS_RESETDONE_MASK ) ,
MAX_MODULE_SOFTRESET_WAIT , c ) ;
if ( c = = MAX_MODULE_SOFTRESET_WAIT )
pr_warning ( " %s: %s: softreset failed (waited %d usec) \n " ,
__func__ , oh - > name , MAX_MODULE_SOFTRESET_WAIT ) ;
else
pr_debug ( " %s: %s: softreset in %d usec \n " , __func__ ,
oh - > name , c ) ;
/* Disable the MSDI internal clock */
v & = ~ MSDI_CON_CLKD_MASK ;
omap_hwmod_write ( v , oh , MSDI_CON_OFFSET ) ;
return 0 ;
}
2012-06-26 03:14:20 -07:00
# if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
static inline void omap242x_mmc_mux ( struct omap_mmc_platform_data
* mmc_controller )
{
if ( ( mmc_controller - > slots [ 0 ] . switch_pin > 0 ) & & \
( mmc_controller - > slots [ 0 ] . switch_pin < OMAP_MAX_GPIO_LINES ) )
omap_mux_init_gpio ( mmc_controller - > slots [ 0 ] . switch_pin ,
OMAP_PIN_INPUT_PULLUP ) ;
if ( ( mmc_controller - > slots [ 0 ] . gpio_wp > 0 ) & & \
( mmc_controller - > slots [ 0 ] . gpio_wp < OMAP_MAX_GPIO_LINES ) )
omap_mux_init_gpio ( mmc_controller - > slots [ 0 ] . gpio_wp ,
OMAP_PIN_INPUT_PULLUP ) ;
omap_mux_init_signal ( " sdmmc_cmd " , 0 ) ;
omap_mux_init_signal ( " sdmmc_clki " , 0 ) ;
omap_mux_init_signal ( " sdmmc_clko " , 0 ) ;
omap_mux_init_signal ( " sdmmc_dat0 " , 0 ) ;
omap_mux_init_signal ( " sdmmc_dat_dir0 " , 0 ) ;
omap_mux_init_signal ( " sdmmc_cmd_dir " , 0 ) ;
if ( mmc_controller - > slots [ 0 ] . caps & MMC_CAP_4_BIT_DATA ) {
omap_mux_init_signal ( " sdmmc_dat1 " , 0 ) ;
omap_mux_init_signal ( " sdmmc_dat2 " , 0 ) ;
omap_mux_init_signal ( " sdmmc_dat3 " , 0 ) ;
omap_mux_init_signal ( " sdmmc_dat_dir1 " , 0 ) ;
omap_mux_init_signal ( " sdmmc_dat_dir2 " , 0 ) ;
omap_mux_init_signal ( " sdmmc_dat_dir3 " , 0 ) ;
}
/*
* Use internal loop - back in MMC / SDIO Module Input Clock
* selection
*/
if ( mmc_controller - > slots [ 0 ] . internal_clock ) {
u32 v = omap_ctrl_readl ( OMAP2_CONTROL_DEVCONF0 ) ;
v | = ( 1 < < 24 ) ;
omap_ctrl_writel ( v , OMAP2_CONTROL_DEVCONF0 ) ;
}
}
void __init omap242x_init_mmc ( struct omap_mmc_platform_data * * mmc_data )
{
struct platform_device * pdev ;
struct omap_hwmod * oh ;
int id = 0 ;
char * oh_name = " msdi1 " ;
char * dev_name = " mmci-omap " ;
if ( ! mmc_data [ 0 ] ) {
pr_err ( " %s fails: Incomplete platform data \n " , __func__ ) ;
return ;
}
omap242x_mmc_mux ( mmc_data [ 0 ] ) ;
oh = omap_hwmod_lookup ( oh_name ) ;
if ( ! oh ) {
pr_err ( " Could not look up %s \n " , oh_name ) ;
return ;
}
pdev = omap_device_build ( dev_name , id , oh , mmc_data [ 0 ] ,
sizeof ( struct omap_mmc_platform_data ) , NULL , 0 , 0 ) ;
if ( IS_ERR ( pdev ) )
WARN ( 1 , " Can'd build omap_device for %s:%s. \n " ,
dev_name , oh - > name ) ;
}
# endif