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>
# include <linux/i2c/twl4030.h>
2009-03-23 18:23:47 -07:00
# include <linux/regulator/machine.h>
2008-12-10 17:37:17 -08:00
# include <mach/hardware.h>
# include <mach/control.h>
# include <mach/mmc.h>
# include <mach/board.h>
# include "mmc-twl4030.h"
# if defined(CONFIG_TWL4030_CORE) && \
( defined ( CONFIG_MMC_OMAP_HS ) | | defined ( CONFIG_MMC_OMAP_HS_MODULE ) )
# define LDO_CLR 0x00
# define VSEL_S2_CLR 0x40
# define VMMC1_DEV_GRP 0x27
# define VMMC1_CLR 0x00
# define VMMC1_315V 0x03
# define VMMC1_300V 0x02
# define VMMC1_285V 0x01
# define VMMC1_185V 0x00
# define VMMC1_DEDICATED 0x2A
# define VMMC2_DEV_GRP 0x2B
# define VMMC2_CLR 0x40
# define VMMC2_315V 0x0c
# define VMMC2_300V 0x0b
# define VMMC2_285V 0x0a
2009-03-23 18:23:47 -07:00
# define VMMC2_280V 0x09
2008-12-10 17:37:17 -08:00
# define VMMC2_260V 0x08
# define VMMC2_185V 0x06
# define VMMC2_DEDICATED 0x2E
# define VMMC_DEV_GRP_P1 0x20
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 ;
u8 twl_vmmc_dev_grp ;
u8 twl_mmc_dedicated ;
2009-03-23 18:23:46 -07:00
char name [ HSMMC_NAME_LEN + 1 ] ;
2009-03-23 18:23:47 -07:00
} hsmmc [ OMAP34XX_NR_MMC ] = {
2008-12-10 17:37:17 -08:00
{
. twl_vmmc_dev_grp = VMMC1_DEV_GRP ,
. twl_mmc_dedicated = VMMC1_DEDICATED ,
} ,
{
. twl_vmmc_dev_grp = VMMC2_DEV_GRP ,
. twl_mmc_dedicated = VMMC2_DEDICATED ,
} ,
} ;
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 ) ;
}
/*
* 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 ;
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 ;
for ( i = 0 ; i < ARRAY_SIZE ( hsmmc ) ; i + + ) {
if ( hsmmc [ i ] . name = = mmc - > slots [ 0 ] . name ) {
hsmmc [ i ] . mmc = mmc ;
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 ;
gpio_free ( mmc - > slots [ 0 ] . switch_pin ) ;
}
# 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
/*
* Sets the MMC voltage in twl4030
*/
2009-03-23 18:23:47 -07:00
# define MMC1_OCR (MMC_VDD_165_195 \
| MMC_VDD_28_29 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 )
# define MMC2_OCR (MMC_VDD_165_195 \
| MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
| MMC_VDD_28_29 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 )
2008-12-10 17:37:17 -08:00
static int twl_mmc_set_voltage ( struct twl_mmc_controller * c , int vdd )
{
int ret ;
2009-03-23 18:23:48 -07:00
u8 vmmc = 0 , dev_grp_val ;
if ( ! vdd )
goto doit ;
2008-12-10 17:37:17 -08:00
2009-03-23 18:23:47 -07:00
if ( c - > twl_vmmc_dev_grp = = VMMC1_DEV_GRP ) {
/* VMMC1: max 220 mA. And for 8-bit mode,
* VSIM : max 50 mA
*/
switch ( 1 < < vdd ) {
case MMC_VDD_165_195 :
2008-12-10 17:37:17 -08:00
vmmc = VMMC1_185V ;
2009-03-23 18:23:47 -07:00
/* and VSIM_180V */
break ;
case MMC_VDD_28_29 :
vmmc = VMMC1_285V ;
/* and VSIM_280V */
break ;
case MMC_VDD_29_30 :
case MMC_VDD_30_31 :
vmmc = VMMC1_300V ;
/* and VSIM_300V */
break ;
case MMC_VDD_31_32 :
vmmc = VMMC1_315V ;
/* error if VSIM needed */
break ;
default :
2009-03-23 18:23:48 -07:00
return - EINVAL ;
2009-03-23 18:23:47 -07:00
}
} else if ( c - > twl_vmmc_dev_grp = = VMMC2_DEV_GRP ) {
/* VMMC2: max 100 mA */
switch ( 1 < < vdd ) {
case MMC_VDD_165_195 :
2008-12-10 17:37:17 -08:00
vmmc = VMMC2_185V ;
2009-03-23 18:23:47 -07:00
break ;
case MMC_VDD_25_26 :
case MMC_VDD_26_27 :
vmmc = VMMC2_260V ;
break ;
case MMC_VDD_27_28 :
vmmc = VMMC2_280V ;
break ;
case MMC_VDD_28_29 :
vmmc = VMMC2_285V ;
break ;
case MMC_VDD_29_30 :
case MMC_VDD_30_31 :
vmmc = VMMC2_300V ;
break ;
case MMC_VDD_31_32 :
vmmc = VMMC2_315V ;
break ;
default :
2009-03-23 18:23:48 -07:00
return - EINVAL ;
2009-03-23 18:23:47 -07:00
}
} else {
2009-03-23 18:23:48 -07:00
return - EINVAL ;
2008-12-10 17:37:17 -08:00
}
2009-03-23 18:23:48 -07:00
doit :
if ( vdd )
2008-12-10 17:37:17 -08:00
dev_grp_val = VMMC_DEV_GRP_P1 ; /* Power up */
else
dev_grp_val = LDO_CLR ; /* Power down */
ret = twl4030_i2c_write_u8 ( TWL4030_MODULE_PM_RECEIVER ,
dev_grp_val , c - > twl_vmmc_dev_grp ) ;
2009-03-23 18:23:48 -07:00
if ( ret | | ! vdd )
2008-12-10 17:37:17 -08:00
return ret ;
ret = twl4030_i2c_write_u8 ( TWL4030_MODULE_PM_RECEIVER ,
vmmc , c - > twl_mmc_dedicated ) ;
return ret ;
}
static int twl_mmc1_set_power ( struct device * dev , int slot , int power_on ,
int vdd )
{
u32 reg ;
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
* card using the same TWL VMMC1 supply ( hsmmc [ 0 ] ) ; OMAP has both
* 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 .
*/
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 ) ;
reg | = OMAP2_PBIASSPEEDCTRL0 ;
reg & = ~ OMAP2_PBIASLITEPWRDNZ0 ;
omap_ctrl_writel ( reg , control_pbias_offset ) ;
ret = twl_mmc_set_voltage ( c , vdd ) ;
/* 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 ) ;
ret = twl_mmc_set_voltage ( c , 0 ) ;
/* 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 ;
}
static int twl_mmc2_set_power ( struct device * dev , int slot , int power_on , int vdd )
{
int ret ;
struct twl_mmc_controller * c = & hsmmc [ 1 ] ;
struct omap_mmc_platform_data * mmc = dev - > platform_data ;
2009-03-23 18:23:47 -07:00
/*
* Assume TWL VMMC2 ( hsmmc [ 1 ] ) is used only to power the card . . . OMAP
* 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 .
*/
2008-12-10 17:37:17 -08:00
if ( power_on ) {
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 ) ;
}
ret = twl_mmc_set_voltage ( c , vdd ) ;
} else {
ret = twl_mmc_set_voltage ( c , 0 ) ;
}
return ret ;
}
2009-03-23 18:23:47 -07:00
static int twl_mmc3_set_power ( struct device * dev , int slot , int power_on ,
int vdd )
{
/*
* Assume MMC3 has self - powered device connected , for example on - board
* chip with external power source .
*/
return 0 ;
}
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:46 -07:00
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 ;
/* note: twl4030 card detect GPIOs normally switch VMMCx ... */
if ( gpio_is_valid ( c - > gpio_cd ) ) {
mmc - > init = twl_mmc_late_init ;
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 ) ;
mmc - > slots [ 0 ] . card_detect = twl_mmc_card_detect ;
} else
mmc - > slots [ 0 ] . switch_pin = - EINVAL ;
/* 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 ;
/* NOTE: we assume OMAP's MMC1 and MMC2 use
* the TWL4030 ' s VMMC1 and VMMC2 , respectively ;
2009-03-23 18:23:47 -07:00
* and that MMC3 device has it ' s own power source .
2008-12-10 17:37:17 -08:00
*/
switch ( c - > mmc ) {
case 1 :
mmc - > slots [ 0 ] . set_power = twl_mmc1_set_power ;
2009-03-23 18:23:47 -07:00
mmc - > slots [ 0 ] . ocr_mask = MMC1_OCR ;
2008-12-10 17:37:17 -08:00
break ;
case 2 :
mmc - > slots [ 0 ] . set_power = twl_mmc2_set_power ;
2009-03-23 18:23:47 -07:00
if ( c - > transceiver )
mmc - > slots [ 0 ] . ocr_mask = MMC2_OCR ;
else
mmc - > slots [ 0 ] . ocr_mask = MMC_VDD_165_195 ;
2008-12-10 17:37:17 -08:00
break ;
2009-03-23 18:23:47 -07:00
case 3 :
mmc - > slots [ 0 ] . set_power = twl_mmc3_set_power ;
mmc - > slots [ 0 ] . ocr_mask = MMC_VDD_165_195 ;
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