2008-12-10 17:37:17 -08:00
/*
* linux / arch / arm / mach - omap2 / mmc - twl4030 . c
*
* Copyright ( C ) 2007 - 2008 Texas Instruments
* Copyright ( C ) 2008 Nokia Corporation
* Author : Texas Instruments
*
* 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 .
*/
# include <linux/err.h>
# include <linux/io.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/gpio.h>
2009-05-28 14:04:03 -07:00
# include <linux/mmc/host.h>
# include <linux/regulator/consumer.h>
2008-12-10 17:37:17 -08:00
# include <mach/hardware.h>
2009-10-20 09:40:47 -07:00
# include <plat/control.h>
# include <plat/mmc.h>
# include <plat/board.h>
2008-12-10 17:37:17 -08:00
# include "mmc-twl4030.h"
2009-05-28 14:04:03 -07:00
# if defined(CONFIG_REGULATOR) && \
( defined ( CONFIG_MMC_OMAP_HS ) | | defined ( CONFIG_MMC_OMAP_HS_MODULE ) )
2008-12-10 17:37:17 -08:00
static u16 control_pbias_offset ;
static u16 control_devconf1_offset ;
# define HSMMC_NAME_LEN 9
static struct twl_mmc_controller {
struct omap_mmc_platform_data * mmc ;
2009-05-28 14:04:03 -07:00
/* Vcc == configured supply
* Vcc_alt = = optional
* - MMC1 , supply for DAT4 . . DAT7
* - MMC2 / MMC2 , external level shifter voltage supply , for
* chip ( SDIO , eMMC , etc ) or transceiver ( MMC2 only )
*/
struct regulator * vcc ;
struct regulator * vcc_aux ;
char name [ HSMMC_NAME_LEN + 1 ] ;
} hsmmc [ OMAP34XX_NR_MMC ] ;
2008-12-10 17:37:17 -08:00
static int twl_mmc_card_detect ( int irq )
{
unsigned i ;
for ( i = 0 ; i < ARRAY_SIZE ( hsmmc ) ; i + + ) {
struct omap_mmc_platform_data * mmc ;
mmc = hsmmc [ i ] . mmc ;
if ( ! mmc )
continue ;
if ( irq ! = mmc - > slots [ 0 ] . card_detect_irq )
continue ;
/* NOTE: assumes card detect signal is active-low */
return ! gpio_get_value_cansleep ( mmc - > slots [ 0 ] . switch_pin ) ;
}
return - ENOSYS ;
}
static int twl_mmc_get_ro ( struct device * dev , int slot )
{
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
/* NOTE: assumes write protect signal is active-high */
return gpio_get_value_cansleep ( mmc - > slots [ 0 ] . gpio_wp ) ;
}
2009-03-23 18:23:48 -07:00
static int twl_mmc_get_cover_state ( struct device * dev , int slot )
{
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
/* NOTE: assumes card detect signal is active-low */
return ! gpio_get_value_cansleep ( mmc - > slots [ 0 ] . switch_pin ) ;
}
2008-12-10 17:37:17 -08:00
/*
* MMC Slot Initialization .
*/
static int twl_mmc_late_init ( struct device * dev )
{
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
int ret = 0 ;
int i ;
2009-05-28 14:04:03 -07:00
/* MMC/SD/SDIO doesn't require a card detect switch */
if ( gpio_is_valid ( mmc - > slots [ 0 ] . switch_pin ) ) {
ret = gpio_request ( mmc - > slots [ 0 ] . switch_pin , " mmc_cd " ) ;
if ( ret )
goto done ;
ret = gpio_direction_input ( mmc - > slots [ 0 ] . switch_pin ) ;
if ( ret )
goto err ;
}
2008-12-10 17:37:17 -08:00
2009-05-28 14:04:03 -07:00
/* require at least main regulator */
2008-12-10 17:37:17 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( hsmmc ) ; i + + ) {
if ( hsmmc [ i ] . name = = mmc - > slots [ 0 ] . name ) {
2009-05-28 14:04:03 -07:00
struct regulator * reg ;
2008-12-10 17:37:17 -08:00
hsmmc [ i ] . mmc = mmc ;
2009-05-28 14:04:03 -07:00
reg = regulator_get ( dev , " vmmc " ) ;
if ( IS_ERR ( reg ) ) {
dev_dbg ( dev , " vmmc regulator missing \n " ) ;
/* HACK: until fixed.c regulator is usable,
* we don ' t require a main regulator
* for MMC2 or MMC3
*/
if ( i ! = 0 )
break ;
ret = PTR_ERR ( reg ) ;
2009-08-10 14:49:51 +03:00
hsmmc [ i ] . vcc = NULL ;
2009-05-28 14:04:03 -07:00
goto err ;
}
hsmmc [ i ] . vcc = reg ;
mmc - > slots [ 0 ] . ocr_mask = mmc_regulator_get_ocrmask ( reg ) ;
/* allow an aux regulator */
reg = regulator_get ( dev , " vmmc_aux " ) ;
hsmmc [ i ] . vcc_aux = IS_ERR ( reg ) ? NULL : reg ;
/* UGLY HACK: workaround regulator framework bugs.
* When the bootloader leaves a supply active , it ' s
* initialized with zero usecount . . . and we can ' t
* disable it without first enabling it . Until the
* framework is fixed , we need a workaround like this
* ( which is safe for MMC , but not in general ) .
*/
if ( regulator_is_enabled ( hsmmc [ i ] . vcc ) > 0 ) {
regulator_enable ( hsmmc [ i ] . vcc ) ;
regulator_disable ( hsmmc [ i ] . vcc ) ;
}
if ( hsmmc [ i ] . vcc_aux ) {
if ( regulator_is_enabled ( reg ) > 0 ) {
regulator_enable ( reg ) ;
regulator_disable ( reg ) ;
}
}
2008-12-10 17:37:17 -08:00
break ;
}
}
return 0 ;
err :
gpio_free ( mmc - > slots [ 0 ] . switch_pin ) ;
done :
mmc - > slots [ 0 ] . card_detect_irq = 0 ;
mmc - > slots [ 0 ] . card_detect = NULL ;
dev_err ( dev , " err %d configuring card detect \n " , ret ) ;
return ret ;
}
static void twl_mmc_cleanup ( struct device * dev )
{
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
2009-08-10 14:49:51 +03:00
int i ;
2008-12-10 17:37:17 -08:00
gpio_free ( mmc - > slots [ 0 ] . switch_pin ) ;
2009-08-10 14:49:51 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( hsmmc ) ; i + + ) {
regulator_put ( hsmmc [ i ] . vcc ) ;
regulator_put ( hsmmc [ i ] . vcc_aux ) ;
}
2008-12-10 17:37:17 -08:00
}
# ifdef CONFIG_PM
static int twl_mmc_suspend ( struct device * dev , int slot )
{
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
disable_irq ( mmc - > slots [ 0 ] . card_detect_irq ) ;
return 0 ;
}
static int twl_mmc_resume ( struct device * dev , int slot )
{
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
enable_irq ( mmc - > slots [ 0 ] . card_detect_irq ) ;
return 0 ;
}
# else
# define twl_mmc_suspend NULL
# define twl_mmc_resume NULL
# endif
2009-09-22 16:44:40 -07:00
# if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
static int twl4030_mmc_get_context_loss ( struct device * dev )
{
/* FIXME: PM DPS not implemented yet */
return 0 ;
}
# else
# define twl4030_mmc_get_context_loss NULL
# endif
2008-12-10 17:37:17 -08:00
static int twl_mmc1_set_power ( struct device * dev , int slot , int power_on ,
int vdd )
{
2009-11-22 10:11:08 -08:00
u32 reg , prog_io ;
2008-12-10 17:37:17 -08:00
int ret = 0 ;
struct twl_mmc_controller * c = & hsmmc [ 0 ] ;
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
2009-03-23 18:23:47 -07:00
/*
* Assume we power both OMAP VMMC1 ( for CMD , CLK , DAT0 . .3 ) and the
2009-05-28 14:04:03 -07:00
* card with Vcc regulator ( from twl4030 or whatever ) . OMAP has both
2009-03-23 18:23:47 -07:00
* 1.8 V and 3.0 V modes , controlled by the PBIAS register .
*
* In 8 - bit modes , OMAP VMMC1A ( for DAT4 . .7 ) needs a supply , which
* is most naturally TWL VSIM ; those pins also use PBIAS .
2009-05-28 14:04:03 -07:00
*
* FIXME handle VMMC1A as needed . . .
2009-03-23 18:23:47 -07:00
*/
2008-12-10 17:37:17 -08:00
if ( power_on ) {
if ( cpu_is_omap2430 ( ) ) {
reg = omap_ctrl_readl ( OMAP243X_CONTROL_DEVCONF1 ) ;
if ( ( 1 < < vdd ) > = MMC_VDD_30_31 )
reg | = OMAP243X_MMC1_ACTIVE_OVERWRITE ;
else
reg & = ~ OMAP243X_MMC1_ACTIVE_OVERWRITE ;
omap_ctrl_writel ( reg , OMAP243X_CONTROL_DEVCONF1 ) ;
}
if ( mmc - > slots [ 0 ] . internal_clock ) {
reg = omap_ctrl_readl ( OMAP2_CONTROL_DEVCONF0 ) ;
reg | = OMAP2_MMCSDIO1ADPCLKISEL ;
omap_ctrl_writel ( reg , OMAP2_CONTROL_DEVCONF0 ) ;
}
reg = omap_ctrl_readl ( control_pbias_offset ) ;
2009-11-22 10:11:08 -08:00
if ( cpu_is_omap3630 ( ) ) {
/* Set MMC I/O to 52Mhz */
prog_io = omap_ctrl_readl ( OMAP343X_CONTROL_PROG_IO1 ) ;
prog_io | = OMAP3630_PRG_SDMMC1_SPEEDCTRL ;
omap_ctrl_writel ( prog_io , OMAP343X_CONTROL_PROG_IO1 ) ;
} else {
reg | = OMAP2_PBIASSPEEDCTRL0 ;
}
2008-12-10 17:37:17 -08:00
reg & = ~ OMAP2_PBIASLITEPWRDNZ0 ;
omap_ctrl_writel ( reg , control_pbias_offset ) ;
2009-05-28 14:04:03 -07:00
ret = mmc_regulator_set_ocr ( c - > vcc , vdd ) ;
2008-12-10 17:37:17 -08:00
/* 100ms delay required for PBIAS configuration */
msleep ( 100 ) ;
reg = omap_ctrl_readl ( control_pbias_offset ) ;
reg | = ( OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0 ) ;
if ( ( 1 < < vdd ) < = MMC_VDD_165_195 )
reg & = ~ OMAP2_PBIASLITEVMODE0 ;
else
reg | = OMAP2_PBIASLITEVMODE0 ;
omap_ctrl_writel ( reg , control_pbias_offset ) ;
} else {
reg = omap_ctrl_readl ( control_pbias_offset ) ;
reg & = ~ OMAP2_PBIASLITEPWRDNZ0 ;
omap_ctrl_writel ( reg , control_pbias_offset ) ;
2009-05-28 14:04:03 -07:00
ret = mmc_regulator_set_ocr ( c - > vcc , 0 ) ;
2008-12-10 17:37:17 -08:00
/* 100ms delay required for PBIAS configuration */
msleep ( 100 ) ;
reg = omap_ctrl_readl ( control_pbias_offset ) ;
reg | = ( OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 |
OMAP2_PBIASLITEVMODE0 ) ;
omap_ctrl_writel ( reg , control_pbias_offset ) ;
}
return ret ;
}
2009-05-28 14:04:03 -07:00
static int twl_mmc23_set_power ( struct device * dev , int slot , int power_on , int vdd )
2008-12-10 17:37:17 -08:00
{
2009-05-28 14:04:03 -07:00
int ret = 0 ;
2009-06-23 13:30:22 +03:00
struct twl_mmc_controller * c = NULL ;
2008-12-10 17:37:17 -08:00
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
2009-06-23 13:30:22 +03:00
int i ;
for ( i = 1 ; i < ARRAY_SIZE ( hsmmc ) ; i + + ) {
if ( mmc = = hsmmc [ i ] . mmc ) {
c = & hsmmc [ i ] ;
break ;
}
}
if ( c = = NULL )
return - ENODEV ;
2008-12-10 17:37:17 -08:00
2009-05-28 14:04:03 -07:00
/* If we don't see a Vcc regulator, assume it's a fixed
* voltage always - on regulator .
*/
if ( ! c - > vcc )
return 0 ;
2009-03-23 18:23:47 -07:00
/*
2009-05-28 14:04:03 -07:00
* Assume Vcc regulator is used only to power the card . . . OMAP
2009-03-23 18:23:47 -07:00
* VDDS is used to power the pins , optionally with a transceiver to
* support cards using voltages other than VDDS ( 1.8 V nominal ) . When a
* transceiver is used , DAT3 . .7 are muxed as transceiver control pins .
2009-05-28 14:04:03 -07:00
*
* In some cases this regulator won ' t support enable / disable ;
* e . g . it ' s a fixed rail for a WLAN chip .
*
* In other cases vcc_aux switches interface power . Example , for
* eMMC cards it represents VccQ . Sometimes transceivers or SDIO
* chips / cards need an interface voltage rail too .
2009-03-23 18:23:47 -07:00
*/
2008-12-10 17:37:17 -08:00
if ( power_on ) {
2009-05-28 14:04:03 -07:00
/* only MMC2 supports a CLKIN */
2008-12-10 17:37:17 -08:00
if ( mmc - > slots [ 0 ] . internal_clock ) {
u32 reg ;
reg = omap_ctrl_readl ( control_devconf1_offset ) ;
reg | = OMAP2_MMCSDIO2ADPCLKISEL ;
omap_ctrl_writel ( reg , control_devconf1_offset ) ;
}
2009-05-28 14:04:03 -07:00
ret = mmc_regulator_set_ocr ( c - > vcc , vdd ) ;
/* enable interface voltage rail, if needed */
if ( ret = = 0 & & c - > vcc_aux ) {
ret = regulator_enable ( c - > vcc_aux ) ;
if ( ret < 0 )
ret = mmc_regulator_set_ocr ( c - > vcc , 0 ) ;
}
2008-12-10 17:37:17 -08:00
} else {
2009-05-28 14:04:03 -07:00
if ( c - > vcc_aux & & ( ret = regulator_is_enabled ( c - > vcc_aux ) ) > 0 )
ret = regulator_disable ( c - > vcc_aux ) ;
if ( ret = = 0 )
ret = mmc_regulator_set_ocr ( c - > vcc , 0 ) ;
2008-12-10 17:37:17 -08:00
}
return ret ;
}
2009-09-22 16:44:50 -07:00
static int twl_mmc1_set_sleep ( struct device * dev , int slot , int sleep , int vdd ,
int cardsleep )
{
struct twl_mmc_controller * c = & hsmmc [ 0 ] ;
int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL ;
return regulator_set_mode ( c - > vcc , mode ) ;
}
static int twl_mmc23_set_sleep ( struct device * dev , int slot , int sleep , int vdd ,
int cardsleep )
{
struct twl_mmc_controller * c = NULL ;
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
int i , err , mode ;
for ( i = 1 ; i < ARRAY_SIZE ( hsmmc ) ; i + + ) {
if ( mmc = = hsmmc [ i ] . mmc ) {
c = & hsmmc [ i ] ;
break ;
}
}
if ( c = = NULL )
return - ENODEV ;
/*
* If we don ' t see a Vcc regulator , assume it ' s a fixed
* voltage always - on regulator .
*/
if ( ! c - > vcc )
return 0 ;
mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL ;
if ( ! c - > vcc_aux )
return regulator_set_mode ( c - > vcc , mode ) ;
if ( cardsleep ) {
/* VCC can be turned off if card is asleep */
struct regulator * vcc_aux = c - > vcc_aux ;
c - > vcc_aux = NULL ;
if ( sleep )
err = twl_mmc23_set_power ( dev , slot , 0 , 0 ) ;
else
err = twl_mmc23_set_power ( dev , slot , 1 , vdd ) ;
c - > vcc_aux = vcc_aux ;
} else
err = regulator_set_mode ( c - > vcc , mode ) ;
if ( err )
return err ;
return regulator_set_mode ( c - > vcc_aux , mode ) ;
}
2008-12-10 17:37:17 -08:00
static struct omap_mmc_platform_data * hsmmc_data [ OMAP34XX_NR_MMC ] __initdata ;
void __init twl4030_mmc_init ( struct twl4030_hsmmc_info * controllers )
{
struct twl4030_hsmmc_info * c ;
int nr_hsmmc = ARRAY_SIZE ( hsmmc_data ) ;
if ( cpu_is_omap2430 ( ) ) {
control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE ;
control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1 ;
nr_hsmmc = 2 ;
} else {
control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE ;
control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1 ;
}
for ( c = controllers ; c - > mmc ; c + + ) {
struct twl_mmc_controller * twl = hsmmc + c - > mmc - 1 ;
struct omap_mmc_platform_data * mmc = hsmmc_data [ c - > mmc - 1 ] ;
if ( ! c - > mmc | | c - > mmc > nr_hsmmc ) {
pr_debug ( " MMC%d: no such controller \n " , c - > mmc ) ;
continue ;
}
if ( mmc ) {
pr_debug ( " MMC%d: already configured \n " , c - > mmc ) ;
continue ;
}
mmc = kzalloc ( sizeof ( struct omap_mmc_platform_data ) , GFP_KERNEL ) ;
if ( ! mmc ) {
pr_err ( " Cannot allocate memory for mmc device! \n " ) ;
return ;
}
2009-03-23 18:23:48 -07:00
if ( c - > name )
strncpy ( twl - > name , c - > name , HSMMC_NAME_LEN ) ;
else
snprintf ( twl - > name , ARRAY_SIZE ( twl - > name ) ,
" mmc%islot%i " , c - > mmc , 1 ) ;
2008-12-10 17:37:17 -08:00
mmc - > slots [ 0 ] . name = twl - > name ;
mmc - > nr_slots = 1 ;
mmc - > slots [ 0 ] . wires = c - > wires ;
mmc - > slots [ 0 ] . internal_clock = ! c - > ext_clock ;
mmc - > dma_mask = 0xffffffff ;
2009-05-28 14:04:03 -07:00
mmc - > init = twl_mmc_late_init ;
2008-12-10 17:37:17 -08:00
2009-05-28 14:04:03 -07:00
/* note: twl4030 card detect GPIOs can disable VMMCx ... */
2008-12-10 17:37:17 -08:00
if ( gpio_is_valid ( c - > gpio_cd ) ) {
mmc - > cleanup = twl_mmc_cleanup ;
mmc - > suspend = twl_mmc_suspend ;
mmc - > resume = twl_mmc_resume ;
mmc - > slots [ 0 ] . switch_pin = c - > gpio_cd ;
mmc - > slots [ 0 ] . card_detect_irq = gpio_to_irq ( c - > gpio_cd ) ;
2009-03-23 18:23:48 -07:00
if ( c - > cover_only )
mmc - > slots [ 0 ] . get_cover_state = twl_mmc_get_cover_state ;
else
mmc - > slots [ 0 ] . card_detect = twl_mmc_card_detect ;
2008-12-10 17:37:17 -08:00
} else
mmc - > slots [ 0 ] . switch_pin = - EINVAL ;
2009-09-22 16:44:40 -07:00
mmc - > get_context_loss_count =
twl4030_mmc_get_context_loss ;
2008-12-10 17:37:17 -08:00
/* write protect normally uses an OMAP gpio */
if ( gpio_is_valid ( c - > gpio_wp ) ) {
gpio_request ( c - > gpio_wp , " mmc_wp " ) ;
gpio_direction_input ( c - > gpio_wp ) ;
mmc - > slots [ 0 ] . gpio_wp = c - > gpio_wp ;
mmc - > slots [ 0 ] . get_ro = twl_mmc_get_ro ;
} else
mmc - > slots [ 0 ] . gpio_wp = - EINVAL ;
2009-09-22 16:44:48 -07:00
if ( c - > nonremovable )
mmc - > slots [ 0 ] . nonremovable = 1 ;
2009-09-22 16:44:49 -07:00
if ( c - > power_saving )
mmc - > slots [ 0 ] . power_saving = 1 ;
2009-05-28 14:04:03 -07:00
/* NOTE: MMC slots should have a Vcc regulator set up.
* This may be from a TWL4030 - family chip , another
* controllable regulator , or a fixed supply .
*
* temporary HACK : ocr_mask instead of fixed supply
2008-12-10 17:37:17 -08:00
*/
2009-05-28 14:04:03 -07:00
mmc - > slots [ 0 ] . ocr_mask = c - > ocr_mask ;
2008-12-10 17:37:17 -08:00
switch ( c - > mmc ) {
case 1 :
2009-05-28 14:04:03 -07:00
/* on-chip level shifting via PBIAS0/PBIAS1 */
2008-12-10 17:37:17 -08:00
mmc - > slots [ 0 ] . set_power = twl_mmc1_set_power ;
2009-09-22 16:44:50 -07:00
mmc - > slots [ 0 ] . set_sleep = twl_mmc1_set_sleep ;
2009-11-22 10:11:07 -08:00
/* Omap3630 HSMMC1 supports only 4-bit */
if ( cpu_is_omap3630 ( ) & & c - > wires > 4 ) {
c - > wires = 4 ;
mmc - > slots [ 0 ] . wires = c - > wires ;
}
2008-12-10 17:37:17 -08:00
break ;
case 2 :
2009-05-28 14:04:03 -07:00
if ( c - > ext_clock )
c - > transceiver = 1 ;
if ( c - > transceiver & & c - > wires > 4 )
c - > wires = 4 ;
/* FALLTHROUGH */
2009-03-23 18:23:47 -07:00
case 3 :
2009-05-28 14:04:03 -07:00
/* off-chip level shifting, or none */
mmc - > slots [ 0 ] . set_power = twl_mmc23_set_power ;
2009-09-22 16:44:50 -07:00
mmc - > slots [ 0 ] . set_sleep = twl_mmc23_set_sleep ;
2009-03-23 18:23:47 -07:00
break ;
2008-12-10 17:37:17 -08:00
default :
pr_err ( " MMC%d configuration not supported! \n " , c - > mmc ) ;
2009-03-23 18:23:47 -07:00
kfree ( mmc ) ;
2008-12-10 17:37:17 -08:00
continue ;
}
hsmmc_data [ c - > mmc - 1 ] = mmc ;
}
omap2_init_mmc ( hsmmc_data , OMAP34XX_NR_MMC ) ;
2009-03-23 18:23:47 -07:00
/* pass the device nodes back to board setup code */
for ( c = controllers ; c - > mmc ; c + + ) {
struct omap_mmc_platform_data * mmc = hsmmc_data [ c - > mmc - 1 ] ;
if ( ! c - > mmc | | c - > mmc > nr_hsmmc )
continue ;
c - > dev = mmc - > dev ;
}
2008-12-10 17:37:17 -08:00
}
# endif