2009-01-23 01:05:23 +01:00
/*
* drivers / mmc / host / omap_hsmmc . c
*
* Driver for OMAP2430 / 3430 MMC controller .
*
* Copyright ( C ) 2007 Texas Instruments .
*
* Authors :
* Syed Mohammed Khasim < x0khasim @ ti . com >
* Madhusudhan < madhu . cr @ ti . com >
* Mohit Jalori < mjalori @ ti . com >
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed " as is " without any warranty of any
* kind , whether express or implied .
*/
# include <linux/module.h>
# include <linux/init.h>
2011-05-10 15:51:54 +03:00
# include <linux/kernel.h>
2009-09-22 16:44:38 -07:00
# include <linux/debugfs.h>
2012-04-13 12:14:39 +01:00
# include <linux/dmaengine.h>
2009-09-22 16:44:38 -07:00
# include <linux/seq_file.h>
2013-07-11 16:09:05 +03:00
# include <linux/sizes.h>
2009-01-23 01:05:23 +01:00
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/dma-mapping.h>
# include <linux/platform_device.h>
# include <linux/timer.h>
# include <linux/clk.h>
2012-03-12 20:32:37 +05:30
# include <linux/of.h>
2014-05-29 10:28:00 +02:00
# include <linux/of_irq.h>
2012-03-12 20:32:37 +05:30
# include <linux/of_device.h>
2009-01-23 01:05:23 +01:00
# include <linux/mmc/host.h>
2009-09-22 16:44:53 -07:00
# include <linux/mmc/core.h>
2010-08-11 14:17:48 -07:00
# include <linux/mmc/mmc.h>
2015-01-13 08:23:18 +13:00
# include <linux/mmc/slot-gpio.h>
2009-01-23 01:05:23 +01:00
# include <linux/io.h>
2014-05-29 10:28:00 +02:00
# include <linux/irq.h>
2010-02-15 10:03:34 -08:00
# include <linux/regulator/consumer.h>
2012-10-15 21:35:05 +05:30
# include <linux/pinctrl/consumer.h>
2011-07-01 22:09:35 +05:30
# include <linux/pm_runtime.h>
2015-05-21 15:51:52 -07:00
# include <linux/pm_wakeirq.h>
2014-11-08 15:33:09 +01:00
# include <linux/platform_data/hsmmc-omap.h>
2009-01-23 01:05:23 +01:00
/* OMAP HSMMC Host Controller Registers */
2009-09-22 16:44:43 -07:00
# define OMAP_HSMMC_SYSSTATUS 0x0014
2009-01-23 01:05:23 +01:00
# define OMAP_HSMMC_CON 0x002C
2014-01-21 19:54:42 +05:30
# define OMAP_HSMMC_SDMASA 0x0100
2009-01-23 01:05:23 +01:00
# define OMAP_HSMMC_BLK 0x0104
# define OMAP_HSMMC_ARG 0x0108
# define OMAP_HSMMC_CMD 0x010C
# define OMAP_HSMMC_RSP10 0x0110
# define OMAP_HSMMC_RSP32 0x0114
# define OMAP_HSMMC_RSP54 0x0118
# define OMAP_HSMMC_RSP76 0x011C
# define OMAP_HSMMC_DATA 0x0120
2014-05-29 10:28:01 +02:00
# define OMAP_HSMMC_PSTATE 0x0124
2009-01-23 01:05:23 +01:00
# define OMAP_HSMMC_HCTL 0x0128
# define OMAP_HSMMC_SYSCTL 0x012C
# define OMAP_HSMMC_STAT 0x0130
# define OMAP_HSMMC_IE 0x0134
# define OMAP_HSMMC_ISE 0x0138
2014-01-21 19:54:42 +05:30
# define OMAP_HSMMC_AC12 0x013C
2009-01-23 01:05:23 +01:00
# define OMAP_HSMMC_CAPA 0x0140
# define VS18 (1 << 26)
# define VS30 (1 << 25)
2012-11-19 21:59:58 +05:30
# define HSS (1 << 21)
2009-01-23 01:05:23 +01:00
# define SDVS18 (0x5 << 9)
# define SDVS30 (0x6 << 9)
2009-02-17 14:49:01 -08:00
# define SDVS33 (0x7 << 9)
2009-02-20 13:10:08 +01:00
# define SDVS_MASK 0x00000E00
2009-01-23 01:05:23 +01:00
# define SDVSCLR 0xFFFFF1FF
# define SDVSDET 0x00000400
# define AUTOIDLE 0x1
# define SDBP (1 << 8)
# define DTO 0xe
# define ICE 0x1
# define ICS 0x2
# define CEN (1 << 2)
2013-10-21 00:25:21 +05:30
# define CLKD_MAX 0x3FF /* max clock divisor: 1023 */
2009-01-23 01:05:23 +01:00
# define CLKD_MASK 0x0000FFC0
# define CLKD_SHIFT 6
# define DTO_MASK 0x000F0000
# define DTO_SHIFT 16
# define INIT_STREAM (1 << 1)
2014-01-21 19:54:42 +05:30
# define ACEN_ACMD23 (2 << 2)
2009-01-23 01:05:23 +01:00
# define DP_SELECT (1 << 21)
# define DDIR (1 << 4)
2012-11-19 22:00:01 +05:30
# define DMAE 0x1
2009-01-23 01:05:23 +01:00
# define MSBS (1 << 5)
# define BCE (1 << 1)
# define FOUR_BIT (1 << 1)
2012-11-19 21:59:58 +05:30
# define HSPE (1 << 2)
2014-05-29 10:28:02 +02:00
# define IWE (1 << 24)
2012-04-09 12:08:33 +05:30
# define DDR (1 << 19)
2014-05-29 10:28:02 +02:00
# define CLKEXTFREE (1 << 16)
# define CTPL (1 << 11)
2008-11-21 16:49:54 +02:00
# define DW8 (1 << 5)
2009-01-23 01:05:23 +01:00
# define OD 0x1
# define STAT_CLEAR 0xFFFFFFFF
# define INIT_STREAM_CMD 0x00000000
# define DUAL_VOLT_OCR_BIT 7
# define SRC (1 << 25)
# define SRD (1 << 26)
2009-09-22 16:44:43 -07:00
# define SOFTRESET (1 << 1)
2009-01-23 01:05:23 +01:00
2014-05-29 10:28:03 +02:00
/* PSTATE */
# define DLEV_DAT(x) (1 << (20 + (x)))
2012-11-19 22:00:01 +05:30
/* Interrupt masks for IE and ISE register */
# define CC_EN (1 << 0)
# define TC_EN (1 << 1)
# define BWR_EN (1 << 4)
# define BRR_EN (1 << 5)
2014-05-29 10:28:00 +02:00
# define CIRQ_EN (1 << 8)
2012-11-19 22:00:01 +05:30
# define ERR_EN (1 << 15)
# define CTO_EN (1 << 16)
# define CCRC_EN (1 << 17)
# define CEB_EN (1 << 18)
# define CIE_EN (1 << 19)
# define DTO_EN (1 << 20)
# define DCRC_EN (1 << 21)
# define DEB_EN (1 << 22)
2014-01-21 19:54:42 +05:30
# define ACE_EN (1 << 24)
2012-11-19 22:00:01 +05:30
# define CERR_EN (1 << 28)
# define BADA_EN (1 << 29)
2014-01-21 19:54:42 +05:30
# define INT_EN_MASK (BADA_EN | CERR_EN | ACE_EN | DEB_EN | DCRC_EN |\
2012-11-19 22:00:01 +05:30
DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
BRR_EN | BWR_EN | TC_EN | CC_EN )
2014-01-21 19:54:42 +05:30
# define CNI (1 << 7)
# define ACIE (1 << 4)
# define ACEB (1 << 3)
# define ACCE (1 << 2)
# define ACTO (1 << 1)
# define ACNE (1 << 0)
2011-07-01 22:09:35 +05:30
# define MMC_AUTOSUSPEND_DELAY 100
2013-10-21 00:25:20 +05:30
# define MMC_TIMEOUT_MS 20 /* 20 mSec */
# define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */
2011-07-13 11:16:29 -04:00
# define OMAP_MMC_MIN_CLOCK 400000
# define OMAP_MMC_MAX_CLOCK 52000000
2011-02-28 20:48:05 +05:30
# define DRIVER_NAME "omap_hsmmc"
2009-01-23 01:05:23 +01:00
/*
* One controller can have multiple slots , like on some omap boards using
* omap . c controller driver . Luckily this is not currently done on any known
* omap_hsmmc . c device .
*/
2014-11-08 15:33:14 +01:00
# define mmc_pdata(host) host->pdata
2009-01-23 01:05:23 +01:00
/*
* MMC Host controller read / write API ' s
*/
# define OMAP_HSMMC_READ(base, reg) \
__raw_readl ( ( base ) + OMAP_HSMMC_ # # reg )
# define OMAP_HSMMC_WRITE(base, reg, val) \
__raw_writel ( ( val ) , ( base ) + OMAP_HSMMC_ # # reg )
2011-07-01 18:55:23 +02:00
struct omap_hsmmc_next {
unsigned int dma_len ;
s32 cookie ;
} ;
2009-09-22 16:44:59 -07:00
struct omap_hsmmc_host {
2009-01-23 01:05:23 +01:00
struct device * dev ;
struct mmc_host * mmc ;
struct mmc_request * mrq ;
struct mmc_command * cmd ;
struct mmc_data * data ;
struct clk * fclk ;
struct clk * dbclk ;
2014-02-19 20:26:40 +05:30
struct regulator * pbias ;
2015-10-07 06:22:24 -07:00
bool pbias_enabled ;
2009-01-23 01:05:23 +01:00
void __iomem * base ;
2015-08-27 14:44:04 +05:30
int vqmmc_enabled ;
2009-01-23 01:05:23 +01:00
resource_size_t mapbase ;
2009-09-22 16:44:58 -07:00
spinlock_t irq_lock ; /* Prevent races with irq handler */
2009-01-23 01:05:23 +01:00
unsigned int dma_len ;
2008-11-14 15:22:00 +02:00
unsigned int dma_sg_idx ;
2009-01-23 01:05:23 +01:00
unsigned char bus_mode ;
2009-09-22 16:44:42 -07:00
unsigned char power_mode ;
2009-01-23 01:05:23 +01:00
int suspended ;
2013-10-21 00:25:19 +05:30
u32 con ;
u32 hctl ;
u32 sysctl ;
u32 capa ;
2009-01-23 01:05:23 +01:00
int irq ;
2014-05-29 10:28:00 +02:00
int wake_irq ;
2009-01-23 01:05:23 +01:00
int use_dma , dma_ch ;
2012-04-13 12:14:39 +01:00
struct dma_chan * tx_chan ;
struct dma_chan * rx_chan ;
2009-01-12 16:13:08 +02:00
int response_busy ;
2009-09-22 16:44:43 -07:00
int context_loss ;
2009-09-22 16:45:01 -07:00
int reqs_blocked ;
2010-05-26 14:42:06 -07:00
int req_in_progress ;
2014-01-21 19:54:42 +05:30
unsigned long clk_rate ;
2014-01-21 19:54:42 +05:30
unsigned int flags ;
2014-05-29 10:28:00 +02:00
# define AUTO_CMD23 (1 << 0) /* Auto CMD23 support */
# define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */
2011-07-01 18:55:23 +02:00
struct omap_hsmmc_next next_data ;
2014-11-08 15:33:09 +01:00
struct omap_hsmmc_platform_data * pdata ;
2009-01-23 01:05:23 +01:00
} ;
2014-02-13 23:45:48 -06:00
struct omap_mmc_of_data {
u32 reg_offset ;
u8 controller_flags ;
} ;
2014-01-21 19:54:42 +05:30
static void omap_hsmmc_start_dma_transfer ( struct omap_hsmmc_host * host ) ;
2015-08-27 14:44:06 +05:30
static int omap_hsmmc_enable_supply ( struct mmc_host * mmc )
2015-08-27 14:44:00 +05:30
{
int ret ;
2015-08-27 14:44:04 +05:30
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
2015-08-27 14:44:06 +05:30
struct mmc_ios * ios = & mmc - > ios ;
2015-08-27 14:44:00 +05:30
2017-06-07 14:06:10 +05:30
if ( ! IS_ERR ( mmc - > supply . vmmc ) ) {
2015-08-27 14:44:06 +05:30
ret = mmc_regulator_set_ocr ( mmc , mmc - > supply . vmmc , ios - > vdd ) ;
2015-08-27 14:44:00 +05:30
if ( ret )
return ret ;
}
/* Enable interface voltage rail, if needed */
2017-06-07 14:06:10 +05:30
if ( ! IS_ERR ( mmc - > supply . vqmmc ) & & ! host - > vqmmc_enabled ) {
2015-08-27 14:44:00 +05:30
ret = regulator_enable ( mmc - > supply . vqmmc ) ;
if ( ret ) {
dev_err ( mmc_dev ( mmc ) , " vmmc_aux reg enable failed \n " ) ;
goto err_vqmmc ;
}
2015-08-27 14:44:04 +05:30
host - > vqmmc_enabled = 1 ;
2015-08-27 14:44:00 +05:30
}
return 0 ;
err_vqmmc :
2017-06-07 14:06:10 +05:30
if ( ! IS_ERR ( mmc - > supply . vmmc ) )
2015-08-27 14:44:00 +05:30
mmc_regulator_set_ocr ( mmc , mmc - > supply . vmmc , 0 ) ;
return ret ;
}
static int omap_hsmmc_disable_supply ( struct mmc_host * mmc )
{
int ret ;
int status ;
2015-08-27 14:44:04 +05:30
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
2015-08-27 14:44:00 +05:30
2017-06-07 14:06:10 +05:30
if ( ! IS_ERR ( mmc - > supply . vqmmc ) & & host - > vqmmc_enabled ) {
2015-08-27 14:44:00 +05:30
ret = regulator_disable ( mmc - > supply . vqmmc ) ;
if ( ret ) {
dev_err ( mmc_dev ( mmc ) , " vmmc_aux reg disable failed \n " ) ;
return ret ;
}
2015-08-27 14:44:04 +05:30
host - > vqmmc_enabled = 0 ;
2015-08-27 14:44:00 +05:30
}
2017-06-07 14:06:10 +05:30
if ( ! IS_ERR ( mmc - > supply . vmmc ) ) {
2015-08-27 14:44:00 +05:30
ret = mmc_regulator_set_ocr ( mmc , mmc - > supply . vmmc , 0 ) ;
if ( ret )
goto err_set_ocr ;
}
return 0 ;
err_set_ocr :
2017-06-07 14:06:10 +05:30
if ( ! IS_ERR ( mmc - > supply . vqmmc ) ) {
2015-08-27 14:44:00 +05:30
status = regulator_enable ( mmc - > supply . vqmmc ) ;
if ( status )
dev_err ( mmc_dev ( mmc ) , " vmmc_aux re-enable failed \n " ) ;
}
return ret ;
}
2017-08-31 15:48:44 +05:30
static int omap_hsmmc_set_pbias ( struct omap_hsmmc_host * host , bool power_on )
2015-08-27 14:44:01 +05:30
{
int ret ;
2017-06-07 14:06:10 +05:30
if ( IS_ERR ( host - > pbias ) )
2015-08-27 14:44:01 +05:30
return 0 ;
if ( power_on ) {
2015-10-07 06:22:24 -07:00
if ( host - > pbias_enabled = = 0 ) {
2015-08-27 14:44:01 +05:30
ret = regulator_enable ( host - > pbias ) ;
if ( ret ) {
dev_err ( host - > dev , " pbias reg enable fail \n " ) ;
return ret ;
}
2015-10-07 06:22:24 -07:00
host - > pbias_enabled = 1 ;
2015-08-27 14:44:01 +05:30
}
} else {
2015-10-07 06:22:24 -07:00
if ( host - > pbias_enabled = = 1 ) {
2015-08-27 14:44:01 +05:30
ret = regulator_disable ( host - > pbias ) ;
if ( ret ) {
dev_err ( host - > dev , " pbias reg disable fail \n " ) ;
return ret ;
}
2015-10-07 06:22:24 -07:00
host - > pbias_enabled = 0 ;
2015-08-27 14:44:01 +05:30
}
}
return 0 ;
}
2017-08-31 15:48:44 +05:30
static int omap_hsmmc_set_power ( struct omap_hsmmc_host * host , int power_on )
2010-02-15 10:03:34 -08:00
{
2015-08-27 14:43:57 +05:30
struct mmc_host * mmc = host - > mmc ;
2010-02-15 10:03:34 -08:00
int ret = 0 ;
/*
* If we don ' t see a Vcc regulator , assume it ' s a fixed
* voltage always - on regulator .
*/
2017-06-07 14:06:10 +05:30
if ( IS_ERR ( mmc - > supply . vmmc ) )
2010-02-15 10:03:34 -08:00
return 0 ;
2017-08-31 15:48:44 +05:30
ret = omap_hsmmc_set_pbias ( host , false ) ;
2015-08-27 14:44:01 +05:30
if ( ret )
return ret ;
2014-02-19 20:26:40 +05:30
2010-02-15 10:03:34 -08:00
/*
* Assume Vcc regulator 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 .
*
* 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 .
*/
if ( power_on ) {
2015-08-27 14:44:06 +05:30
ret = omap_hsmmc_enable_supply ( mmc ) ;
2015-08-27 14:44:00 +05:30
if ( ret )
return ret ;
2015-08-27 14:44:02 +05:30
2017-08-31 15:48:44 +05:30
ret = omap_hsmmc_set_pbias ( host , true ) ;
2015-08-27 14:44:02 +05:30
if ( ret )
goto err_set_voltage ;
2010-02-15 10:03:34 -08:00
} else {
2015-08-27 14:44:00 +05:30
ret = omap_hsmmc_disable_supply ( mmc ) ;
if ( ret )
return ret ;
2010-02-15 10:03:34 -08:00
}
2015-08-27 14:43:59 +05:30
return 0 ;
err_set_voltage :
2015-08-27 14:44:00 +05:30
omap_hsmmc_disable_supply ( mmc ) ;
2015-08-27 14:43:59 +05:30
2010-02-15 10:03:34 -08:00
return ret ;
}
2015-08-27 14:44:03 +05:30
static int omap_hsmmc_disable_boot_regulator ( struct regulator * reg )
{
int ret ;
2017-06-07 14:06:10 +05:30
if ( IS_ERR ( reg ) )
2015-08-27 14:44:03 +05:30
return 0 ;
if ( regulator_is_enabled ( reg ) ) {
ret = regulator_enable ( reg ) ;
if ( ret )
return ret ;
ret = regulator_disable ( reg ) ;
if ( ret )
return ret ;
}
return 0 ;
}
static int omap_hsmmc_disable_boot_regulators ( struct omap_hsmmc_host * host )
{
struct mmc_host * mmc = host - > mmc ;
int ret ;
/*
* disable regulators enabled during boot and get the usecount
* right so that regulators can be enabled / disabled by checking
* the return value of regulator_is_enabled
*/
ret = omap_hsmmc_disable_boot_regulator ( mmc - > supply . vmmc ) ;
if ( ret ) {
dev_err ( host - > dev , " fail to disable boot enabled vmmc reg \n " ) ;
return ret ;
}
ret = omap_hsmmc_disable_boot_regulator ( mmc - > supply . vqmmc ) ;
if ( ret ) {
dev_err ( host - > dev ,
" fail to disable boot enabled vmmc_aux reg \n " ) ;
return ret ;
}
ret = omap_hsmmc_disable_boot_regulator ( host - > pbias ) ;
if ( ret ) {
dev_err ( host - > dev ,
" failed to disable boot enabled pbias reg \n " ) ;
return ret ;
}
return 0 ;
}
2010-02-15 10:03:34 -08:00
static int omap_hsmmc_reg_get ( struct omap_hsmmc_host * host )
{
2015-08-27 14:43:53 +05:30
int ret ;
2015-08-27 14:43:57 +05:30
struct mmc_host * mmc = host - > mmc ;
2010-02-15 10:03:34 -08:00
2015-07-07 20:38:43 +02:00
2017-06-07 14:06:11 +05:30
ret = mmc_regulator_get_supply ( mmc ) ;
2017-10-14 21:17:17 +02:00
if ( ret )
2017-06-07 14:06:11 +05:30
return ret ;
2010-02-15 10:03:34 -08:00
2014-02-19 20:26:40 +05:30
/* Allow an aux regulator */
2015-08-27 14:43:57 +05:30
if ( IS_ERR ( mmc - > supply . vqmmc ) ) {
2017-06-07 14:06:11 +05:30
mmc - > supply . vqmmc = devm_regulator_get_optional ( host - > dev ,
" vmmc_aux " ) ;
if ( IS_ERR ( mmc - > supply . vqmmc ) ) {
ret = PTR_ERR ( mmc - > supply . vqmmc ) ;
if ( ( ret ! = - ENODEV ) & & host - > dev - > of_node )
return ret ;
dev_dbg ( host - > dev , " unable to get vmmc_aux regulator %ld \n " ,
PTR_ERR ( mmc - > supply . vqmmc ) ) ;
}
2015-08-27 14:43:54 +05:30
}
2014-02-19 20:26:40 +05:30
2015-08-27 14:43:55 +05:30
host - > pbias = devm_regulator_get_optional ( host - > dev , " pbias " ) ;
if ( IS_ERR ( host - > pbias ) ) {
ret = PTR_ERR ( host - > pbias ) ;
2016-01-14 14:45:20 +05:30
if ( ( ret ! = - ENODEV ) & & host - > dev - > of_node ) {
dev_err ( host - > dev ,
" SD card detect fail? enable CONFIG_REGULATOR_PBIAS \n " ) ;
2015-08-27 14:43:54 +05:30
return ret ;
2016-01-14 14:45:20 +05:30
}
2015-08-27 14:43:54 +05:30
dev_dbg ( host - > dev , " unable to get pbias regulator %ld \n " ,
2015-08-27 14:43:55 +05:30
PTR_ERR ( host - > pbias ) ) ;
2015-08-27 14:43:54 +05:30
}
2014-02-19 20:26:40 +05:30
2014-02-19 20:26:40 +05:30
/* For eMMC do not power off when not in sleep state */
2014-11-08 15:33:14 +01:00
if ( mmc_pdata ( host ) - > no_regulator_off_init )
2014-02-19 20:26:40 +05:30
return 0 ;
2015-08-27 14:44:03 +05:30
ret = omap_hsmmc_disable_boot_regulators ( host ) ;
if ( ret )
return ret ;
2010-02-15 10:03:34 -08:00
return 0 ;
}
2011-05-06 12:14:05 +03:00
/*
* Start clock to the card
*/
static void omap_hsmmc_start_clock ( struct omap_hsmmc_host * host )
{
OMAP_HSMMC_WRITE ( host - > base , SYSCTL ,
OMAP_HSMMC_READ ( host - > base , SYSCTL ) | CEN ) ;
}
2009-01-23 01:05:23 +01:00
/*
* Stop clock to the card
*/
2009-09-22 16:44:59 -07:00
static void omap_hsmmc_stop_clock ( struct omap_hsmmc_host * host )
2009-01-23 01:05:23 +01:00
{
OMAP_HSMMC_WRITE ( host - > base , SYSCTL ,
OMAP_HSMMC_READ ( host - > base , SYSCTL ) & ~ CEN ) ;
if ( ( OMAP_HSMMC_READ ( host - > base , SYSCTL ) & CEN ) ! = 0x0 )
2012-08-05 23:25:40 +09:00
dev_dbg ( mmc_dev ( host - > mmc ) , " MMC Clock is not stopped \n " ) ;
2009-01-23 01:05:23 +01:00
}
2010-08-11 14:17:48 -07:00
static void omap_hsmmc_enable_irq ( struct omap_hsmmc_host * host ,
struct mmc_command * cmd )
2010-05-26 14:42:06 -07:00
{
2014-05-29 10:28:00 +02:00
u32 irq_mask = INT_EN_MASK ;
unsigned long flags ;
2010-05-26 14:42:06 -07:00
if ( host - > use_dma )
2014-05-29 10:28:00 +02:00
irq_mask & = ~ ( BRR_EN | BWR_EN ) ;
2010-05-26 14:42:06 -07:00
2010-08-11 14:17:48 -07:00
/* Disable timeout for erases */
if ( cmd - > opcode = = MMC_ERASE )
2012-11-19 22:00:01 +05:30
irq_mask & = ~ DTO_EN ;
2010-08-11 14:17:48 -07:00
2014-05-29 10:28:00 +02:00
spin_lock_irqsave ( & host - > irq_lock , flags ) ;
2010-05-26 14:42:06 -07:00
OMAP_HSMMC_WRITE ( host - > base , STAT , STAT_CLEAR ) ;
OMAP_HSMMC_WRITE ( host - > base , ISE , irq_mask ) ;
2014-05-29 10:28:00 +02:00
/* latch pending CIRQ, but don't signal MMC core */
if ( host - > flags & HSMMC_SDIO_IRQ_ENABLED )
irq_mask | = CIRQ_EN ;
2010-05-26 14:42:06 -07:00
OMAP_HSMMC_WRITE ( host - > base , IE , irq_mask ) ;
2014-05-29 10:28:00 +02:00
spin_unlock_irqrestore ( & host - > irq_lock , flags ) ;
2010-05-26 14:42:06 -07:00
}
static void omap_hsmmc_disable_irq ( struct omap_hsmmc_host * host )
{
2014-05-29 10:28:00 +02:00
u32 irq_mask = 0 ;
unsigned long flags ;
spin_lock_irqsave ( & host - > irq_lock , flags ) ;
/* no transfer running but need to keep cirq if enabled */
if ( host - > flags & HSMMC_SDIO_IRQ_ENABLED )
irq_mask | = CIRQ_EN ;
OMAP_HSMMC_WRITE ( host - > base , ISE , irq_mask ) ;
OMAP_HSMMC_WRITE ( host - > base , IE , irq_mask ) ;
2010-05-26 14:42:06 -07:00
OMAP_HSMMC_WRITE ( host - > base , STAT , STAT_CLEAR ) ;
2014-05-29 10:28:00 +02:00
spin_unlock_irqrestore ( & host - > irq_lock , flags ) ;
2010-05-26 14:42:06 -07:00
}
2011-05-10 15:51:54 +03:00
/* Calculate divisor for the given clock frequency */
2011-12-20 15:12:00 +05:30
static u16 calc_divisor ( struct omap_hsmmc_host * host , struct mmc_ios * ios )
2011-05-10 15:51:54 +03:00
{
u16 dsor = 0 ;
if ( ios - > clock ) {
2011-12-20 15:12:00 +05:30
dsor = DIV_ROUND_UP ( clk_get_rate ( host - > fclk ) , ios - > clock ) ;
2013-10-21 00:25:21 +05:30
if ( dsor > CLKD_MAX )
dsor = CLKD_MAX ;
2011-05-10 15:51:54 +03:00
}
return dsor ;
}
2011-05-06 12:14:06 +03:00
static void omap_hsmmc_set_clock ( struct omap_hsmmc_host * host )
{
struct mmc_ios * ios = & host - > mmc - > ios ;
unsigned long regval ;
unsigned long timeout ;
2012-11-19 21:59:58 +05:30
unsigned long clkdiv ;
2011-05-06 12:14:06 +03:00
2012-08-07 19:10:38 +05:30
dev_vdbg ( mmc_dev ( host - > mmc ) , " Set clock to %uHz \n " , ios - > clock ) ;
2011-05-06 12:14:06 +03:00
omap_hsmmc_stop_clock ( host ) ;
regval = OMAP_HSMMC_READ ( host - > base , SYSCTL ) ;
regval = regval & ~ ( CLKD_MASK | DTO_MASK ) ;
2012-11-19 21:59:58 +05:30
clkdiv = calc_divisor ( host , ios ) ;
regval = regval | ( clkdiv < < 6 ) | ( DTO < < 16 ) ;
2011-05-06 12:14:06 +03:00
OMAP_HSMMC_WRITE ( host - > base , SYSCTL , regval ) ;
OMAP_HSMMC_WRITE ( host - > base , SYSCTL ,
OMAP_HSMMC_READ ( host - > base , SYSCTL ) | ICE ) ;
/* Wait till the ICS bit is set */
timeout = jiffies + msecs_to_jiffies ( MMC_TIMEOUT_MS ) ;
while ( ( OMAP_HSMMC_READ ( host - > base , SYSCTL ) & ICS ) ! = ICS
& & time_before ( jiffies , timeout ) )
cpu_relax ( ) ;
2012-11-19 21:59:58 +05:30
/*
* Enable High - Speed Support
* Pre - Requisites
* - Controller should support High - Speed - Enable Bit
* - Controller should not be using DDR Mode
* - Controller should advertise that it supports High Speed
* in capabilities register
* - MMC / SD clock coming out of controller > 25 MHz
*/
2014-11-08 15:33:14 +01:00
if ( ( mmc_pdata ( host ) - > features & HSMMC_HAS_HSPE_SUPPORT ) & &
2014-03-14 21:12:27 +09:00
( ios - > timing ! = MMC_TIMING_MMC_DDR52 ) & &
2014-11-25 13:05:13 +01:00
( ios - > timing ! = MMC_TIMING_UHS_DDR50 ) & &
2012-11-19 21:59:58 +05:30
( ( OMAP_HSMMC_READ ( host - > base , CAPA ) & HSS ) = = HSS ) ) {
regval = OMAP_HSMMC_READ ( host - > base , HCTL ) ;
if ( clkdiv & & ( clk_get_rate ( host - > fclk ) / clkdiv ) > 25000000 )
regval | = HSPE ;
else
regval & = ~ HSPE ;
OMAP_HSMMC_WRITE ( host - > base , HCTL , regval ) ;
}
2011-05-06 12:14:06 +03:00
omap_hsmmc_start_clock ( host ) ;
}
2011-07-13 11:31:15 -04:00
static void omap_hsmmc_set_bus_width ( struct omap_hsmmc_host * host )
{
struct mmc_ios * ios = & host - > mmc - > ios ;
u32 con ;
con = OMAP_HSMMC_READ ( host - > base , CON ) ;
2014-11-25 13:05:13 +01:00
if ( ios - > timing = = MMC_TIMING_MMC_DDR52 | |
ios - > timing = = MMC_TIMING_UHS_DDR50 )
2012-04-09 12:08:33 +05:30
con | = DDR ; /* configure in DDR mode */
else
con & = ~ DDR ;
2011-07-13 11:31:15 -04:00
switch ( ios - > bus_width ) {
case MMC_BUS_WIDTH_8 :
OMAP_HSMMC_WRITE ( host - > base , CON , con | DW8 ) ;
break ;
case MMC_BUS_WIDTH_4 :
OMAP_HSMMC_WRITE ( host - > base , CON , con & ~ DW8 ) ;
OMAP_HSMMC_WRITE ( host - > base , HCTL ,
OMAP_HSMMC_READ ( host - > base , HCTL ) | FOUR_BIT ) ;
break ;
case MMC_BUS_WIDTH_1 :
OMAP_HSMMC_WRITE ( host - > base , CON , con & ~ DW8 ) ;
OMAP_HSMMC_WRITE ( host - > base , HCTL ,
OMAP_HSMMC_READ ( host - > base , HCTL ) & ~ FOUR_BIT ) ;
break ;
}
}
static void omap_hsmmc_set_bus_mode ( struct omap_hsmmc_host * host )
{
struct mmc_ios * ios = & host - > mmc - > ios ;
u32 con ;
con = OMAP_HSMMC_READ ( host - > base , CON ) ;
if ( ios - > bus_mode = = MMC_BUSMODE_OPENDRAIN )
OMAP_HSMMC_WRITE ( host - > base , CON , con | OD ) ;
else
OMAP_HSMMC_WRITE ( host - > base , CON , con & ~ OD ) ;
}
2009-09-22 16:44:43 -07:00
# ifdef CONFIG_PM
/*
* Restore the MMC host context , if it was lost as result of a
* power state change .
*/
2009-09-22 16:44:59 -07:00
static int omap_hsmmc_context_restore ( struct omap_hsmmc_host * host )
2009-09-22 16:44:43 -07:00
{
struct mmc_ios * ios = & host - > mmc - > ios ;
2011-07-13 11:31:15 -04:00
u32 hctl , capa ;
2009-09-22 16:44:43 -07:00
unsigned long timeout ;
2013-10-21 00:25:19 +05:30
if ( host - > con = = OMAP_HSMMC_READ ( host - > base , CON ) & &
host - > hctl = = OMAP_HSMMC_READ ( host - > base , HCTL ) & &
host - > sysctl = = OMAP_HSMMC_READ ( host - > base , SYSCTL ) & &
host - > capa = = OMAP_HSMMC_READ ( host - > base , CAPA ) )
return 0 ;
host - > context_loss + + ;
2012-03-07 09:55:30 -05:00
if ( host - > pdata - > controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT ) {
2009-09-22 16:44:43 -07:00
if ( host - > power_mode ! = MMC_POWER_OFF & &
( 1 < < ios - > vdd ) < = MMC_VDD_23_24 )
hctl = SDVS18 ;
else
hctl = SDVS30 ;
capa = VS30 | VS18 ;
} else {
hctl = SDVS18 ;
capa = VS18 ;
}
2014-05-29 10:28:02 +02:00
if ( host - > mmc - > caps & MMC_CAP_SDIO_IRQ )
hctl | = IWE ;
2009-09-22 16:44:43 -07:00
OMAP_HSMMC_WRITE ( host - > base , HCTL ,
OMAP_HSMMC_READ ( host - > base , HCTL ) | hctl ) ;
OMAP_HSMMC_WRITE ( host - > base , CAPA ,
OMAP_HSMMC_READ ( host - > base , CAPA ) | capa ) ;
OMAP_HSMMC_WRITE ( host - > base , HCTL ,
OMAP_HSMMC_READ ( host - > base , HCTL ) | SDBP ) ;
timeout = jiffies + msecs_to_jiffies ( MMC_TIMEOUT_MS ) ;
while ( ( OMAP_HSMMC_READ ( host - > base , HCTL ) & SDBP ) ! = SDBP
& & time_before ( jiffies , timeout ) )
;
2014-05-29 10:28:00 +02:00
OMAP_HSMMC_WRITE ( host - > base , ISE , 0 ) ;
OMAP_HSMMC_WRITE ( host - > base , IE , 0 ) ;
OMAP_HSMMC_WRITE ( host - > base , STAT , STAT_CLEAR ) ;
2009-09-22 16:44:43 -07:00
/* Do not initialize card-specific things if the power is off */
if ( host - > power_mode = = MMC_POWER_OFF )
goto out ;
2011-07-13 11:31:15 -04:00
omap_hsmmc_set_bus_width ( host ) ;
2009-09-22 16:44:43 -07:00
2011-05-06 12:14:06 +03:00
omap_hsmmc_set_clock ( host ) ;
2009-09-22 16:44:43 -07:00
2011-07-13 11:31:15 -04:00
omap_hsmmc_set_bus_mode ( host ) ;
2009-09-22 16:44:43 -07:00
out :
2013-10-21 00:25:19 +05:30
dev_dbg ( mmc_dev ( host - > mmc ) , " context is restored: restore count %d \n " ,
host - > context_loss ) ;
2009-09-22 16:44:43 -07:00
return 0 ;
}
/*
* Save the MMC host context ( store the number of power state changes so far ) .
*/
2009-09-22 16:44:59 -07:00
static void omap_hsmmc_context_save ( struct omap_hsmmc_host * host )
2009-09-22 16:44:43 -07:00
{
2013-10-21 00:25:19 +05:30
host - > con = OMAP_HSMMC_READ ( host - > base , CON ) ;
host - > hctl = OMAP_HSMMC_READ ( host - > base , HCTL ) ;
host - > sysctl = OMAP_HSMMC_READ ( host - > base , SYSCTL ) ;
host - > capa = OMAP_HSMMC_READ ( host - > base , CAPA ) ;
2009-09-22 16:44:43 -07:00
}
# else
2009-09-22 16:44:59 -07:00
static int omap_hsmmc_context_restore ( struct omap_hsmmc_host * host )
2009-09-22 16:44:43 -07:00
{
return 0 ;
}
2009-09-22 16:44:59 -07:00
static void omap_hsmmc_context_save ( struct omap_hsmmc_host * host )
2009-09-22 16:44:43 -07:00
{
}
# endif
2009-01-23 01:05:23 +01:00
/*
* Send init stream sequence to card
* before sending IDLE command
*/
2009-09-22 16:44:59 -07:00
static void send_init_stream ( struct omap_hsmmc_host * host )
2009-01-23 01:05:23 +01:00
{
int reg = 0 ;
unsigned long timeout ;
disable_irq ( host - > irq ) ;
2010-05-26 14:42:06 -07:00
OMAP_HSMMC_WRITE ( host - > base , IE , INT_EN_MASK ) ;
2009-01-23 01:05:23 +01:00
OMAP_HSMMC_WRITE ( host - > base , CON ,
OMAP_HSMMC_READ ( host - > base , CON ) | INIT_STREAM ) ;
OMAP_HSMMC_WRITE ( host - > base , CMD , INIT_STREAM_CMD ) ;
timeout = jiffies + msecs_to_jiffies ( MMC_TIMEOUT_MS ) ;
2012-11-19 22:00:01 +05:30
while ( ( reg ! = CC_EN ) & & time_before ( jiffies , timeout ) )
reg = OMAP_HSMMC_READ ( host - > base , STAT ) & CC_EN ;
2009-01-23 01:05:23 +01:00
OMAP_HSMMC_WRITE ( host - > base , CON ,
OMAP_HSMMC_READ ( host - > base , CON ) & ~ INIT_STREAM ) ;
2009-09-22 16:44:56 -07:00
OMAP_HSMMC_WRITE ( host - > base , STAT , STAT_CLEAR ) ;
OMAP_HSMMC_READ ( host - > base , STAT ) ;
2009-01-23 01:05:23 +01:00
enable_irq ( host - > irq ) ;
}
static ssize_t
2009-09-22 16:44:59 -07:00
omap_hsmmc_show_slot_name ( struct device * dev , struct device_attribute * attr ,
2009-01-23 01:05:23 +01:00
char * buf )
{
struct mmc_host * mmc = container_of ( dev , struct mmc_host , class_dev ) ;
2009-09-22 16:44:59 -07:00
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
2009-01-23 01:05:23 +01:00
2014-11-08 15:33:14 +01:00
return sprintf ( buf , " %s \n " , mmc_pdata ( host ) - > name ) ;
2009-01-23 01:05:23 +01:00
}
2009-09-22 16:44:59 -07:00
static DEVICE_ATTR ( slot_name , S_IRUGO , omap_hsmmc_show_slot_name , NULL ) ;
2009-01-23 01:05:23 +01:00
/*
* Configure the response type and send the cmd .
*/
static void
2009-09-22 16:44:59 -07:00
omap_hsmmc_start_command ( struct omap_hsmmc_host * host , struct mmc_command * cmd ,
2009-01-23 01:05:23 +01:00
struct mmc_data * data )
{
int cmdreg = 0 , resptype = 0 , cmdtype = 0 ;
2012-08-07 19:10:38 +05:30
dev_vdbg ( mmc_dev ( host - > mmc ) , " %s: CMD%d, argument 0x%08x \n " ,
2009-01-23 01:05:23 +01:00
mmc_hostname ( host - > mmc ) , cmd - > opcode , cmd - > arg ) ;
host - > cmd = cmd ;
2010-08-11 14:17:48 -07:00
omap_hsmmc_enable_irq ( host , cmd ) ;
2009-01-23 01:05:23 +01:00
2009-01-12 16:13:08 +02:00
host - > response_busy = 0 ;
2009-01-23 01:05:23 +01:00
if ( cmd - > flags & MMC_RSP_PRESENT ) {
if ( cmd - > flags & MMC_RSP_136 )
resptype = 1 ;
2009-01-12 16:13:08 +02:00
else if ( cmd - > flags & MMC_RSP_BUSY ) {
resptype = 3 ;
host - > response_busy = 1 ;
} else
2009-01-23 01:05:23 +01:00
resptype = 2 ;
}
/*
* Unlike OMAP1 controller , the cmdtype does not seem to be based on
* ac , bc , adtc , bcr . Only commands ending an open ended transfer need
* a val of 0x3 , rest 0x0 .
*/
if ( cmd = = host - > mrq - > stop )
cmdtype = 0x3 ;
cmdreg = ( cmd - > opcode < < 24 ) | ( resptype < < 16 ) | ( cmdtype < < 22 ) ;
2014-01-21 19:54:42 +05:30
if ( ( host - > flags & AUTO_CMD23 ) & & mmc_op_multi ( cmd - > opcode ) & &
host - > mrq - > sbc ) {
cmdreg | = ACEN_ACMD23 ;
OMAP_HSMMC_WRITE ( host - > base , SDMASA , host - > mrq - > sbc - > arg ) ;
}
2009-01-23 01:05:23 +01:00
if ( data ) {
cmdreg | = DP_SELECT | MSBS | BCE ;
if ( data - > flags & MMC_DATA_READ )
cmdreg | = DDIR ;
else
cmdreg & = ~ ( DDIR ) ;
}
if ( host - > use_dma )
2012-11-19 22:00:01 +05:30
cmdreg | = DMAE ;
2009-01-23 01:05:23 +01:00
2010-05-26 14:42:06 -07:00
host - > req_in_progress = 1 ;
2009-09-22 16:44:58 -07:00
2009-01-23 01:05:23 +01:00
OMAP_HSMMC_WRITE ( host - > base , ARG , cmd - > arg ) ;
OMAP_HSMMC_WRITE ( host - > base , CMD , cmdreg ) ;
}
2012-04-13 12:14:39 +01:00
static struct dma_chan * omap_hsmmc_get_dma_chan ( struct omap_hsmmc_host * host ,
struct mmc_data * data )
{
return data - > flags & MMC_DATA_WRITE ? host - > tx_chan : host - > rx_chan ;
}
2010-05-26 14:42:06 -07:00
static void omap_hsmmc_request_done ( struct omap_hsmmc_host * host , struct mmc_request * mrq )
{
int dma_ch ;
2012-04-09 12:08:34 +05:30
unsigned long flags ;
2010-05-26 14:42:06 -07:00
2012-04-09 12:08:34 +05:30
spin_lock_irqsave ( & host - > irq_lock , flags ) ;
2010-05-26 14:42:06 -07:00
host - > req_in_progress = 0 ;
dma_ch = host - > dma_ch ;
2012-04-09 12:08:34 +05:30
spin_unlock_irqrestore ( & host - > irq_lock , flags ) ;
2010-05-26 14:42:06 -07:00
omap_hsmmc_disable_irq ( host ) ;
/* Do not complete the request if DMA is still in progress */
if ( mrq - > data & & host - > use_dma & & dma_ch ! = - 1 )
return ;
host - > mrq = NULL ;
mmc_request_done ( host - > mmc , mrq ) ;
}
2009-01-23 01:05:23 +01:00
/*
* Notify the transfer complete to MMC core
*/
static void
2009-09-22 16:44:59 -07:00
omap_hsmmc_xfer_done ( struct omap_hsmmc_host * host , struct mmc_data * data )
2009-01-23 01:05:23 +01:00
{
2009-01-12 16:13:08 +02:00
if ( ! data ) {
struct mmc_request * mrq = host - > mrq ;
2009-09-22 16:44:57 -07:00
/* TC before CC from CMD6 - don't know why, but it happens */
if ( host - > cmd & & host - > cmd - > opcode = = 6 & &
host - > response_busy ) {
host - > response_busy = 0 ;
return ;
}
2010-05-26 14:42:06 -07:00
omap_hsmmc_request_done ( host , mrq ) ;
2009-01-12 16:13:08 +02:00
return ;
}
2009-01-23 01:05:23 +01:00
host - > data = NULL ;
if ( ! data - > error )
data - > bytes_xfered + = data - > blocks * ( data - > blksz ) ;
else
data - > bytes_xfered = 0 ;
2014-01-21 19:54:42 +05:30
if ( data - > stop & & ( data - > error | | ! host - > mrq - > sbc ) )
omap_hsmmc_start_command ( host , data - > stop , NULL ) ;
else
2010-05-26 14:42:06 -07:00
omap_hsmmc_request_done ( host , data - > mrq ) ;
2009-01-23 01:05:23 +01:00
}
/*
* Notify the core about command completion
*/
static void
2009-09-22 16:44:59 -07:00
omap_hsmmc_cmd_done ( struct omap_hsmmc_host * host , struct mmc_command * cmd )
2009-01-23 01:05:23 +01:00
{
2014-01-21 19:54:42 +05:30
if ( host - > mrq - > sbc & & ( host - > cmd = = host - > mrq - > sbc ) & &
2014-01-21 19:54:42 +05:30
! host - > mrq - > sbc - > error & & ! ( host - > flags & AUTO_CMD23 ) ) {
2014-05-09 22:16:52 +05:30
host - > cmd = NULL ;
2014-01-21 19:54:42 +05:30
omap_hsmmc_start_dma_transfer ( host ) ;
omap_hsmmc_start_command ( host , host - > mrq - > cmd ,
host - > mrq - > data ) ;
return ;
}
2014-05-09 22:16:52 +05:30
host - > cmd = NULL ;
2009-01-23 01:05:23 +01:00
if ( cmd - > flags & MMC_RSP_PRESENT ) {
if ( cmd - > flags & MMC_RSP_136 ) {
/* response type 2 */
cmd - > resp [ 3 ] = OMAP_HSMMC_READ ( host - > base , RSP10 ) ;
cmd - > resp [ 2 ] = OMAP_HSMMC_READ ( host - > base , RSP32 ) ;
cmd - > resp [ 1 ] = OMAP_HSMMC_READ ( host - > base , RSP54 ) ;
cmd - > resp [ 0 ] = OMAP_HSMMC_READ ( host - > base , RSP76 ) ;
} else {
/* response types 1, 1b, 3, 4, 5, 6 */
cmd - > resp [ 0 ] = OMAP_HSMMC_READ ( host - > base , RSP10 ) ;
}
}
2010-05-26 14:42:06 -07:00
if ( ( host - > data = = NULL & & ! host - > response_busy ) | | cmd - > error )
2014-01-21 19:54:42 +05:30
omap_hsmmc_request_done ( host , host - > mrq ) ;
2009-01-23 01:05:23 +01:00
}
/*
* DMA clean up for command errors
*/
2009-09-22 16:44:59 -07:00
static void omap_hsmmc_dma_cleanup ( struct omap_hsmmc_host * host , int errno )
2009-01-23 01:05:23 +01:00
{
2010-05-26 14:42:06 -07:00
int dma_ch ;
2012-04-09 12:08:34 +05:30
unsigned long flags ;
2010-05-26 14:42:06 -07:00
2008-12-05 12:31:46 +02:00
host - > data - > error = errno ;
2009-01-23 01:05:23 +01:00
2012-04-09 12:08:34 +05:30
spin_lock_irqsave ( & host - > irq_lock , flags ) ;
2010-05-26 14:42:06 -07:00
dma_ch = host - > dma_ch ;
host - > dma_ch = - 1 ;
2012-04-09 12:08:34 +05:30
spin_unlock_irqrestore ( & host - > irq_lock , flags ) ;
2010-05-26 14:42:06 -07:00
if ( host - > use_dma & & dma_ch ! = - 1 ) {
2012-04-13 12:14:39 +01:00
struct dma_chan * chan = omap_hsmmc_get_dma_chan ( host , host - > data ) ;
dmaengine_terminate_all ( chan ) ;
dma_unmap_sg ( chan - > device - > dev ,
host - > data - > sg , host - > data - > sg_len ,
2017-03-26 20:45:56 +02:00
mmc_get_dma_dir ( host - > data ) ) ;
2012-04-13 12:14:39 +01:00
2011-11-07 21:55:11 +05:30
host - > data - > host_cookie = 0 ;
2009-01-23 01:05:23 +01:00
}
host - > data = NULL ;
}
/*
* Readable error output
*/
# ifdef CONFIG_MMC_DEBUG
2011-05-06 12:14:01 +03:00
static void omap_hsmmc_dbg_report_irq ( struct omap_hsmmc_host * host , u32 status )
2009-01-23 01:05:23 +01:00
{
/* --- means reserved bit without definition at documentation */
2009-09-22 16:44:59 -07:00
static const char * omap_hsmmc_status_bits [ ] = {
2011-05-06 12:14:01 +03:00
" CC " , " TC " , " BGE " , " --- " , " BWR " , " BRR " , " --- " , " --- " ,
" CIRQ " , " OBI " , " --- " , " --- " , " --- " , " --- " , " --- " , " ERRI " ,
" CTO " , " CCRC " , " CEB " , " CIE " , " DTO " , " DCRC " , " DEB " , " --- " ,
" ACE " , " --- " , " --- " , " --- " , " CERR " , " BADA " , " --- " , " --- "
2009-01-23 01:05:23 +01:00
} ;
char res [ 256 ] ;
char * buf = res ;
int len , i ;
len = sprintf ( buf , " MMC IRQ 0x%x : " , status ) ;
buf + = len ;
2009-09-22 16:44:59 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( omap_hsmmc_status_bits ) ; i + + )
2009-01-23 01:05:23 +01:00
if ( status & ( 1 < < i ) ) {
2009-09-22 16:44:59 -07:00
len = sprintf ( buf , " %s " , omap_hsmmc_status_bits [ i ] ) ;
2009-01-23 01:05:23 +01:00
buf + = len ;
}
2012-08-07 19:10:38 +05:30
dev_vdbg ( mmc_dev ( host - > mmc ) , " %s \n " , res ) ;
2009-01-23 01:05:23 +01:00
}
2011-05-06 12:14:01 +03:00
# else
static inline void omap_hsmmc_dbg_report_irq ( struct omap_hsmmc_host * host ,
u32 status )
{
}
2009-01-23 01:05:23 +01:00
# endif /* CONFIG_MMC_DEBUG */
2009-02-06 16:42:51 +01:00
/*
* MMC controller internal state machines reset
*
* Used to reset command or data internal state machines , using respectively
* SRC or SRD bit of SYSCTL register
* Can be called from interrupt context
*/
2009-09-22 16:44:59 -07:00
static inline void omap_hsmmc_reset_controller_fsm ( struct omap_hsmmc_host * host ,
unsigned long bit )
2009-02-06 16:42:51 +01:00
{
unsigned long i = 0 ;
2013-10-21 00:25:20 +05:30
unsigned long limit = MMC_TIMEOUT_US ;
2009-02-06 16:42:51 +01:00
OMAP_HSMMC_WRITE ( host - > base , SYSCTL ,
OMAP_HSMMC_READ ( host - > base , SYSCTL ) | bit ) ;
2010-10-01 16:35:25 -07:00
/*
* OMAP4 ES2 and greater has an updated reset logic .
* Monitor a 0 - > 1 transition first
*/
2014-11-08 15:33:14 +01:00
if ( mmc_pdata ( host ) - > features & HSMMC_HAS_UPDATED_RESET ) {
2010-11-17 22:35:32 -05:00
while ( ( ! ( OMAP_HSMMC_READ ( host - > base , SYSCTL ) & bit ) )
2010-10-01 16:35:25 -07:00
& & ( i + + < limit ) )
2013-10-21 00:25:20 +05:30
udelay ( 1 ) ;
2010-10-01 16:35:25 -07:00
}
i = 0 ;
2009-02-06 16:42:51 +01:00
while ( ( OMAP_HSMMC_READ ( host - > base , SYSCTL ) & bit ) & &
( i + + < limit ) )
2013-10-21 00:25:20 +05:30
udelay ( 1 ) ;
2009-02-06 16:42:51 +01:00
if ( OMAP_HSMMC_READ ( host - > base , SYSCTL ) & bit )
dev_err ( mmc_dev ( host - > mmc ) ,
" Timeout waiting on controller reset in %s \n " ,
__func__ ) ;
}
2009-01-23 01:05:23 +01:00
2012-11-19 21:59:55 +05:30
static void hsmmc_command_incomplete ( struct omap_hsmmc_host * host ,
int err , int end_cmd )
2012-08-09 20:36:07 +05:30
{
2012-11-19 21:59:55 +05:30
if ( end_cmd ) {
2012-11-19 21:59:56 +05:30
omap_hsmmc_reset_controller_fsm ( host , SRC ) ;
2012-11-19 21:59:55 +05:30
if ( host - > cmd )
host - > cmd - > error = err ;
}
2012-08-09 20:36:07 +05:30
if ( host - > data ) {
omap_hsmmc_reset_controller_fsm ( host , SRD ) ;
omap_hsmmc_dma_cleanup ( host , err ) ;
2012-11-19 21:59:57 +05:30
} else if ( host - > mrq & & host - > mrq - > cmd )
host - > mrq - > cmd - > error = err ;
2012-08-09 20:36:07 +05:30
}
2010-05-26 14:42:06 -07:00
static void omap_hsmmc_do_irq ( struct omap_hsmmc_host * host , int status )
2009-01-23 01:05:23 +01:00
{
struct mmc_data * data ;
2010-05-26 14:42:06 -07:00
int end_cmd = 0 , end_trans = 0 ;
2014-01-21 19:54:42 +05:30
int error = 0 ;
2010-05-26 14:42:06 -07:00
2009-01-23 01:05:23 +01:00
data = host - > data ;
2012-08-07 19:10:38 +05:30
dev_vdbg ( mmc_dev ( host - > mmc ) , " IRQ Status is %x \n " , status ) ;
2009-01-23 01:05:23 +01:00
2012-11-19 22:00:01 +05:30
if ( status & ERR_EN ) {
2011-05-06 12:14:01 +03:00
omap_hsmmc_dbg_report_irq ( host , status ) ;
2012-11-19 21:59:55 +05:30
2017-01-30 15:41:56 +05:30
if ( status & ( CTO_EN | CCRC_EN | CEB_EN ) )
2012-11-19 21:59:55 +05:30
end_cmd = 1 ;
2015-06-16 16:07:17 +05:30
if ( host - > data | | host - > response_busy ) {
end_trans = ! end_cmd ;
host - > response_busy = 0 ;
}
2012-11-19 22:00:01 +05:30
if ( status & ( CTO_EN | DTO_EN ) )
2012-11-19 21:59:55 +05:30
hsmmc_command_incomplete ( host , - ETIMEDOUT , end_cmd ) ;
2015-06-16 16:07:18 +05:30
else if ( status & ( CCRC_EN | DCRC_EN | DEB_EN | CEB_EN |
BADA_EN ) )
2012-11-19 21:59:55 +05:30
hsmmc_command_incomplete ( host , - EILSEQ , end_cmd ) ;
2012-08-09 20:36:07 +05:30
2014-01-21 19:54:42 +05:30
if ( status & ACE_EN ) {
u32 ac12 ;
ac12 = OMAP_HSMMC_READ ( host - > base , AC12 ) ;
if ( ! ( ac12 & ACNE ) & & host - > mrq - > sbc ) {
end_cmd = 1 ;
if ( ac12 & ACTO )
error = - ETIMEDOUT ;
else if ( ac12 & ( ACCE | ACEB | ACIE ) )
error = - EILSEQ ;
host - > mrq - > sbc - > error = error ;
hsmmc_command_incomplete ( host , error , end_cmd ) ;
}
dev_dbg ( mmc_dev ( host - > mmc ) , " AC12 err: 0x%x \n " , ac12 ) ;
}
2009-01-23 01:05:23 +01:00
}
2013-06-29 08:25:12 +02:00
OMAP_HSMMC_WRITE ( host - > base , STAT , status ) ;
2012-11-19 22:00:01 +05:30
if ( end_cmd | | ( ( status & CC_EN ) & & host - > cmd ) )
2009-09-22 16:44:59 -07:00
omap_hsmmc_cmd_done ( host , host - > cmd ) ;
2012-11-19 22:00:01 +05:30
if ( ( end_trans | | ( status & TC_EN ) ) & & host - > mrq )
2009-09-22 16:44:59 -07:00
omap_hsmmc_xfer_done ( host , data ) ;
2010-05-26 14:42:06 -07:00
}
2009-01-23 01:05:23 +01:00
2010-05-26 14:42:06 -07:00
/*
* MMC controller IRQ handler
*/
static irqreturn_t omap_hsmmc_irq ( int irq , void * dev_id )
{
struct omap_hsmmc_host * host = dev_id ;
int status ;
status = OMAP_HSMMC_READ ( host - > base , STAT ) ;
2014-05-29 10:28:00 +02:00
while ( status & ( INT_EN_MASK | CIRQ_EN ) ) {
if ( host - > req_in_progress )
omap_hsmmc_do_irq ( host , status ) ;
if ( status & CIRQ_EN )
mmc_signal_sdio_irq ( host - > mmc ) ;
2012-08-08 15:44:29 +05:30
2010-05-26 14:42:06 -07:00
/* Flush posted write */
status = OMAP_HSMMC_READ ( host - > base , STAT ) ;
2012-08-08 15:44:29 +05:30
}
2009-09-22 16:44:58 -07:00
2009-01-23 01:05:23 +01:00
return IRQ_HANDLED ;
}
2009-09-22 16:44:59 -07:00
static void set_sd_bus_power ( struct omap_hsmmc_host * host )
2009-03-12 17:08:26 +02:00
{
unsigned long i ;
OMAP_HSMMC_WRITE ( host - > base , HCTL ,
OMAP_HSMMC_READ ( host - > base , HCTL ) | SDBP ) ;
for ( i = 0 ; i < loops_per_jiffy ; i + + ) {
if ( OMAP_HSMMC_READ ( host - > base , HCTL ) & SDBP )
break ;
cpu_relax ( ) ;
}
}
2009-01-23 01:05:23 +01:00
/*
2009-02-17 14:49:01 -08:00
* Switch MMC interface voltage . . . only relevant for MMC1 .
*
* MMC2 and MMC3 use fixed 1.8 V levels , and maybe a transceiver .
* The MMC2 transceiver controls are used instead of DAT4 . . DAT7 .
* Some chips , like eMMC ones , use internal transceivers .
2009-01-23 01:05:23 +01:00
*/
2009-09-22 16:44:59 -07:00
static int omap_hsmmc_switch_opcond ( struct omap_hsmmc_host * host , int vdd )
2009-01-23 01:05:23 +01:00
{
u32 reg_val = 0 ;
int ret ;
/* Disable the clocks */
2012-04-09 12:08:35 +05:30
if ( host - > dbclk )
2012-06-27 14:19:54 +05:30
clk_disable_unprepare ( host - > dbclk ) ;
2009-01-23 01:05:23 +01:00
/* Turn the power off */
2017-08-31 15:48:44 +05:30
ret = omap_hsmmc_set_power ( host , 0 ) ;
2009-01-23 01:05:23 +01:00
/* Turn the power ON with given VDD 1.8 or 3.0v */
2009-09-22 16:45:02 -07:00
if ( ! ret )
2017-08-31 15:48:44 +05:30
ret = omap_hsmmc_set_power ( host , 1 ) ;
2012-04-09 12:08:35 +05:30
if ( host - > dbclk )
2012-06-27 14:19:54 +05:30
clk_prepare_enable ( host - > dbclk ) ;
2009-09-22 16:45:02 -07:00
2009-01-23 01:05:23 +01:00
if ( ret ! = 0 )
goto err ;
OMAP_HSMMC_WRITE ( host - > base , HCTL ,
OMAP_HSMMC_READ ( host - > base , HCTL ) & SDVSCLR ) ;
reg_val = OMAP_HSMMC_READ ( host - > base , HCTL ) ;
2009-02-17 14:49:01 -08:00
2009-01-23 01:05:23 +01:00
/*
* If a MMC dual voltage card is detected , the set_ios fn calls
* this fn with VDD bit set for 1.8 V . Upon card removal from the
2009-09-22 16:44:59 -07:00
* slot , omap_hsmmc_set_ios sets the VDD back to 3 V on MMC_POWER_OFF .
2009-01-23 01:05:23 +01:00
*
2009-02-17 14:49:01 -08:00
* Cope with a bit of slop in the range . . . per data sheets :
* - " 1.8V " for vdds_mmc1 / vdds_mmc1a can be up to 2.45 V max ,
* but recommended values are 1.71 V to 1.89 V
* - " 3.0V " for vdds_mmc1 / vdds_mmc1a can be up to 3.5 V max ,
* but recommended values are 2.7 V to 3.3 V
*
* Board setup code shouldn ' t permit anything very out - of - range .
* TWL4030 - family VMMC1 and VSIM regulators are fine ( avoiding the
* middle range ) but VSIM can ' t power DAT4 . . DAT7 at more than 3 V .
2009-01-23 01:05:23 +01:00
*/
2009-02-17 14:49:01 -08:00
if ( ( 1 < < vdd ) < = MMC_VDD_23_24 )
2009-01-23 01:05:23 +01:00
reg_val | = SDVS18 ;
2009-02-17 14:49:01 -08:00
else
reg_val | = SDVS30 ;
2009-01-23 01:05:23 +01:00
OMAP_HSMMC_WRITE ( host - > base , HCTL , reg_val ) ;
2009-03-12 17:08:26 +02:00
set_sd_bus_power ( host ) ;
2009-01-23 01:05:23 +01:00
return 0 ;
err :
2012-11-19 22:00:00 +05:30
dev_err ( mmc_dev ( host - > mmc ) , " Unable to switch operating voltage \n " ) ;
2009-01-23 01:05:23 +01:00
return ret ;
}
2012-04-13 12:14:39 +01:00
static void omap_hsmmc_dma_callback ( void * param )
2009-01-23 01:05:23 +01:00
{
2012-04-13 12:14:39 +01:00
struct omap_hsmmc_host * host = param ;
struct dma_chan * chan ;
2011-05-06 12:14:11 +03:00
struct mmc_data * data ;
2012-04-13 12:14:39 +01:00
int req_in_progress ;
2009-01-23 01:05:23 +01:00
2012-04-13 12:14:39 +01:00
spin_lock_irq ( & host - > irq_lock ) ;
2010-05-26 14:42:06 -07:00
if ( host - > dma_ch < 0 ) {
2012-04-13 12:14:39 +01:00
spin_unlock_irq ( & host - > irq_lock ) ;
2009-01-23 01:05:23 +01:00
return ;
2010-05-26 14:42:06 -07:00
}
2009-01-23 01:05:23 +01:00
2011-05-06 12:14:11 +03:00
data = host - > mrq - > data ;
2012-04-13 12:14:39 +01:00
chan = omap_hsmmc_get_dma_chan ( host , data ) ;
2011-07-01 18:55:23 +02:00
if ( ! data - > host_cookie )
2012-04-13 12:14:39 +01:00
dma_unmap_sg ( chan - > device - > dev ,
data - > sg , data - > sg_len ,
2017-03-26 20:45:56 +02:00
mmc_get_dma_dir ( data ) ) ;
2010-05-26 14:42:06 -07:00
req_in_progress = host - > req_in_progress ;
2009-01-23 01:05:23 +01:00
host - > dma_ch = - 1 ;
2012-04-13 12:14:39 +01:00
spin_unlock_irq ( & host - > irq_lock ) ;
2010-05-26 14:42:06 -07:00
/* If DMA has finished after TC, complete the request */
if ( ! req_in_progress ) {
struct mmc_request * mrq = host - > mrq ;
host - > mrq = NULL ;
mmc_request_done ( host - > mmc , mrq ) ;
}
2009-01-23 01:05:23 +01:00
}
2011-07-01 18:55:23 +02:00
static int omap_hsmmc_pre_dma_transfer ( struct omap_hsmmc_host * host ,
struct mmc_data * data ,
2012-04-13 12:14:39 +01:00
struct omap_hsmmc_next * next ,
2012-04-13 12:27:37 +01:00
struct dma_chan * chan )
2011-07-01 18:55:23 +02:00
{
int dma_len ;
if ( ! next & & data - > host_cookie & &
data - > host_cookie ! = host - > next_data . cookie ) {
2012-02-23 17:02:20 +05:30
dev_warn ( host - > dev , " [%s] invalid cookie: data->host_cookie %d "
2011-07-01 18:55:23 +02:00
" host->next_data.cookie %d \n " ,
__func__ , data - > host_cookie , host - > next_data . cookie ) ;
data - > host_cookie = 0 ;
}
/* Check if next job is already prepared */
2014-01-30 15:15:18 +03:00
if ( next | | data - > host_cookie ! = host - > next_data . cookie ) {
2012-04-13 12:27:37 +01:00
dma_len = dma_map_sg ( chan - > device - > dev , data - > sg , data - > sg_len ,
2017-03-26 20:45:56 +02:00
mmc_get_dma_dir ( data ) ) ;
2011-07-01 18:55:23 +02:00
} else {
dma_len = host - > next_data . dma_len ;
host - > next_data . dma_len = 0 ;
}
if ( dma_len = = 0 )
return - EINVAL ;
if ( next ) {
next - > dma_len = dma_len ;
data - > host_cookie = + + next - > cookie < 0 ? 1 : next - > cookie ;
} else
host - > dma_len = dma_len ;
return 0 ;
}
2009-01-23 01:05:23 +01:00
/*
* Routine to configure and start DMA for the MMC card
*/
2014-01-21 19:54:42 +05:30
static int omap_hsmmc_setup_dma_transfer ( struct omap_hsmmc_host * host ,
2009-09-22 16:44:59 -07:00
struct mmc_request * req )
2009-01-23 01:05:23 +01:00
{
2012-04-13 12:27:37 +01:00
struct dma_async_tx_descriptor * tx ;
int ret = 0 , i ;
2009-01-23 01:05:23 +01:00
struct mmc_data * data = req - > data ;
2012-04-13 12:14:39 +01:00
struct dma_chan * chan ;
2016-09-14 14:22:07 +03:00
struct dma_slave_config cfg = {
. src_addr = host - > mapbase + OMAP_HSMMC_DATA ,
. dst_addr = host - > mapbase + OMAP_HSMMC_DATA ,
. src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES ,
. dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES ,
. src_maxburst = data - > blksz / 4 ,
. dst_maxburst = data - > blksz / 4 ,
} ;
2009-01-23 01:05:23 +01:00
2008-11-14 15:22:00 +02:00
/* Sanity check: all the SG entries must be aligned by block size. */
2009-09-22 16:44:46 -07:00
for ( i = 0 ; i < data - > sg_len ; i + + ) {
2008-11-14 15:22:00 +02:00
struct scatterlist * sgl ;
sgl = data - > sg + i ;
if ( sgl - > length % data - > blksz )
return - EINVAL ;
}
if ( ( data - > blksz % 4 ) ! = 0 )
/* REVISIT: The MMC buffer increments only when MSB is written.
* Return error for blksz which is non multiple of four .
*/
return - EINVAL ;
2010-05-26 14:42:06 -07:00
BUG_ON ( host - > dma_ch ! = - 1 ) ;
2009-01-23 01:05:23 +01:00
2012-04-13 12:14:39 +01:00
chan = omap_hsmmc_get_dma_chan ( host , data ) ;
2012-04-13 12:27:37 +01:00
ret = dmaengine_slave_config ( chan , & cfg ) ;
if ( ret )
2009-01-23 01:05:23 +01:00
return ret ;
2012-04-13 12:14:39 +01:00
2012-04-13 12:27:37 +01:00
ret = omap_hsmmc_pre_dma_transfer ( host , data , NULL , chan ) ;
2011-07-01 18:55:23 +02:00
if ( ret )
return ret ;
2009-01-23 01:05:23 +01:00
2012-04-13 12:27:37 +01:00
tx = dmaengine_prep_slave_sg ( chan , data - > sg , data - > sg_len ,
data - > flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM ,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK ) ;
if ( ! tx ) {
dev_err ( mmc_dev ( host - > mmc ) , " prep_slave_sg() failed \n " ) ;
/* FIXME: cleanup */
return - 1 ;
}
2009-01-23 01:05:23 +01:00
2012-04-13 12:27:37 +01:00
tx - > callback = omap_hsmmc_dma_callback ;
tx - > callback_param = host ;
2009-01-23 01:05:23 +01:00
2012-04-13 12:27:37 +01:00
/* Does not fail */
dmaengine_submit ( tx ) ;
2012-04-13 12:14:39 +01:00
2012-04-13 12:27:37 +01:00
host - > dma_ch = 1 ;
2012-04-13 12:14:39 +01:00
2009-01-23 01:05:23 +01:00
return 0 ;
}
2009-09-22 16:44:59 -07:00
static void set_data_timeout ( struct omap_hsmmc_host * host ,
2017-01-30 15:41:58 +05:30
unsigned long long timeout_ns ,
2009-09-22 16:45:03 -07:00
unsigned int timeout_clks )
2009-01-23 01:05:23 +01:00
{
2017-01-30 15:41:58 +05:30
unsigned long long timeout = timeout_ns ;
unsigned int cycle_ns ;
2009-01-23 01:05:23 +01:00
uint32_t reg , clkd , dto = 0 ;
reg = OMAP_HSMMC_READ ( host - > base , SYSCTL ) ;
clkd = ( reg & CLKD_MASK ) > > CLKD_SHIFT ;
if ( clkd = = 0 )
clkd = 1 ;
2014-01-21 19:54:42 +05:30
cycle_ns = 1000000000 / ( host - > clk_rate / clkd ) ;
2017-01-30 15:41:58 +05:30
do_div ( timeout , cycle_ns ) ;
2009-09-22 16:45:03 -07:00
timeout + = timeout_clks ;
2009-01-23 01:05:23 +01:00
if ( timeout ) {
while ( ( timeout & 0x80000000 ) = = 0 ) {
dto + = 1 ;
timeout < < = 1 ;
}
dto = 31 - dto ;
timeout < < = 1 ;
if ( timeout & & dto )
dto + = 1 ;
if ( dto > = 13 )
dto - = 13 ;
else
dto = 0 ;
if ( dto > 14 )
dto = 14 ;
}
reg & = ~ DTO_MASK ;
reg | = dto < < DTO_SHIFT ;
OMAP_HSMMC_WRITE ( host - > base , SYSCTL , reg ) ;
}
2014-01-21 19:54:42 +05:30
static void omap_hsmmc_start_dma_transfer ( struct omap_hsmmc_host * host )
{
struct mmc_request * req = host - > mrq ;
struct dma_chan * chan ;
if ( ! req - > data )
return ;
OMAP_HSMMC_WRITE ( host - > base , BLK , ( req - > data - > blksz )
| ( req - > data - > blocks < < 16 ) ) ;
set_data_timeout ( host , req - > data - > timeout_ns ,
req - > data - > timeout_clks ) ;
chan = omap_hsmmc_get_dma_chan ( host , req - > data ) ;
dma_async_issue_pending ( chan ) ;
}
2009-01-23 01:05:23 +01:00
/*
* Configure block length for MMC / SD cards and initiate the transfer .
*/
static int
2009-09-22 16:44:59 -07:00
omap_hsmmc_prepare_data ( struct omap_hsmmc_host * host , struct mmc_request * req )
2009-01-23 01:05:23 +01:00
{
int ret ;
2017-01-30 15:41:58 +05:30
unsigned long long timeout ;
2017-01-30 15:41:57 +05:30
2009-01-23 01:05:23 +01:00
host - > data = req - > data ;
if ( req - > data = = NULL ) {
OMAP_HSMMC_WRITE ( host - > base , BLK , 0 ) ;
2017-01-30 15:41:57 +05:30
if ( req - > cmd - > flags & MMC_RSP_BUSY ) {
timeout = req - > cmd - > busy_timeout * NSEC_PER_MSEC ;
/*
* Set an arbitrary 100 ms data timeout for commands with
* busy signal and no indication of busy_timeout .
*/
if ( ! timeout )
timeout = 100000000U ;
set_data_timeout ( host , timeout , 0 ) ;
}
2009-01-23 01:05:23 +01:00
return 0 ;
}
if ( host - > use_dma ) {
2014-01-21 19:54:42 +05:30
ret = omap_hsmmc_setup_dma_transfer ( host , req ) ;
2009-01-23 01:05:23 +01:00
if ( ret ! = 0 ) {
2012-11-19 22:00:00 +05:30
dev_err ( mmc_dev ( host - > mmc ) , " MMC start dma failure \n " ) ;
2009-01-23 01:05:23 +01:00
return ret ;
}
}
return 0 ;
}
2011-07-01 18:55:23 +02:00
static void omap_hsmmc_post_req ( struct mmc_host * mmc , struct mmc_request * mrq ,
int err )
{
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
struct mmc_data * data = mrq - > data ;
2012-04-13 12:27:37 +01:00
if ( host - > use_dma & & data - > host_cookie ) {
2012-04-13 12:14:39 +01:00
struct dma_chan * c = omap_hsmmc_get_dma_chan ( host , data ) ;
2012-04-13 12:27:37 +01:00
dma_unmap_sg ( c - > device - > dev , data - > sg , data - > sg_len ,
2017-03-26 20:45:56 +02:00
mmc_get_dma_dir ( data ) ) ;
2011-07-01 18:55:23 +02:00
data - > host_cookie = 0 ;
}
}
2016-11-23 11:02:24 +01:00
static void omap_hsmmc_pre_req ( struct mmc_host * mmc , struct mmc_request * mrq )
2011-07-01 18:55:23 +02:00
{
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
if ( mrq - > data - > host_cookie ) {
mrq - > data - > host_cookie = 0 ;
return ;
}
2012-04-13 12:14:39 +01:00
if ( host - > use_dma ) {
struct dma_chan * c = omap_hsmmc_get_dma_chan ( host , mrq - > data ) ;
2011-07-01 18:55:23 +02:00
if ( omap_hsmmc_pre_dma_transfer ( host , mrq - > data ,
2012-04-13 12:27:37 +01:00
& host - > next_data , c ) )
2011-07-01 18:55:23 +02:00
mrq - > data - > host_cookie = 0 ;
2012-04-13 12:14:39 +01:00
}
2011-07-01 18:55:23 +02:00
}
2009-01-23 01:05:23 +01:00
/*
* Request function . for read / write operation
*/
2009-09-22 16:44:59 -07:00
static void omap_hsmmc_request ( struct mmc_host * mmc , struct mmc_request * req )
2009-01-23 01:05:23 +01:00
{
2009-09-22 16:44:59 -07:00
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
2009-09-22 16:44:46 -07:00
int err ;
2009-01-23 01:05:23 +01:00
2010-05-26 14:42:06 -07:00
BUG_ON ( host - > req_in_progress ) ;
BUG_ON ( host - > dma_ch ! = - 1 ) ;
2018-09-24 13:30:50 +02:00
if ( host - > reqs_blocked )
2010-05-26 14:42:06 -07:00
host - > reqs_blocked = 0 ;
2009-01-23 01:05:23 +01:00
WARN_ON ( host - > mrq ! = NULL ) ;
host - > mrq = req ;
2014-01-21 19:54:42 +05:30
host - > clk_rate = clk_get_rate ( host - > fclk ) ;
2009-09-22 16:44:59 -07:00
err = omap_hsmmc_prepare_data ( host , req ) ;
2009-09-22 16:44:46 -07:00
if ( err ) {
req - > cmd - > error = err ;
if ( req - > data )
req - > data - > error = err ;
host - > mrq = NULL ;
mmc_request_done ( mmc , req ) ;
return ;
}
2014-01-21 19:54:42 +05:30
if ( req - > sbc & & ! ( host - > flags & AUTO_CMD23 ) ) {
2014-01-21 19:54:42 +05:30
omap_hsmmc_start_command ( host , req - > sbc , NULL ) ;
return ;
}
2009-09-22 16:44:46 -07:00
2014-01-21 19:54:42 +05:30
omap_hsmmc_start_dma_transfer ( host ) ;
2009-09-22 16:44:59 -07:00
omap_hsmmc_start_command ( host , req - > cmd , req - > data ) ;
2009-01-23 01:05:23 +01:00
}
/* Routine to configure clock values. Exposed API to core */
2009-09-22 16:44:59 -07:00
static void omap_hsmmc_set_ios ( struct mmc_host * mmc , struct mmc_ios * ios )
2009-01-23 01:05:23 +01:00
{
2009-09-22 16:44:59 -07:00
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
2009-09-22 16:44:42 -07:00
int do_send_init_stream = 0 ;
2009-01-23 01:05:23 +01:00
2009-09-22 16:44:42 -07:00
if ( ios - > power_mode ! = host - > power_mode ) {
switch ( ios - > power_mode ) {
case MMC_POWER_OFF :
2017-08-31 15:48:44 +05:30
omap_hsmmc_set_power ( host , 0 ) ;
2009-09-22 16:44:42 -07:00
break ;
case MMC_POWER_UP :
2017-08-31 15:48:44 +05:30
omap_hsmmc_set_power ( host , 1 ) ;
2009-09-22 16:44:42 -07:00
break ;
case MMC_POWER_ON :
do_send_init_stream = 1 ;
break ;
}
host - > power_mode = ios - > power_mode ;
2009-01-23 01:05:23 +01:00
}
2009-09-22 16:44:49 -07:00
/* FIXME: set registers based only on changes to ios */
2011-07-13 11:31:15 -04:00
omap_hsmmc_set_bus_width ( host ) ;
2009-01-23 01:05:23 +01:00
2011-02-28 20:48:04 +05:30
if ( host - > pdata - > controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT ) {
2009-02-17 14:49:01 -08:00
/* Only MMC1 can interface at 3V without some flavor
* of external transceiver ; but they all handle 1.8 V .
*/
2009-01-23 01:05:23 +01:00
if ( ( OMAP_HSMMC_READ ( host - > base , HCTL ) & SDVSDET ) & &
2014-02-19 20:26:40 +05:30
( ios - > vdd = = DUAL_VOLT_OCR_BIT ) ) {
2009-01-23 01:05:23 +01:00
/*
* The mmc_select_voltage fn of the core does
* not seem to set the power_mode to
* MMC_POWER_UP upon recalculating the voltage .
* vdd 1.8 v .
*/
2009-09-22 16:44:59 -07:00
if ( omap_hsmmc_switch_opcond ( host , ios - > vdd ) ! = 0 )
dev_dbg ( mmc_dev ( host - > mmc ) ,
2009-01-23 01:05:23 +01:00
" Switch operation failed \n " ) ;
}
}
2011-05-06 12:14:06 +03:00
omap_hsmmc_set_clock ( host ) ;
2009-01-23 01:05:23 +01:00
2009-09-22 16:44:42 -07:00
if ( do_send_init_stream )
2009-01-23 01:05:23 +01:00
send_init_stream ( host ) ;
2011-07-13 11:31:15 -04:00
omap_hsmmc_set_bus_mode ( host ) ;
2009-01-23 01:05:23 +01:00
}
2010-08-10 18:01:52 -07:00
static void omap_hsmmc_init_card ( struct mmc_host * mmc , struct mmc_card * card )
{
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
2019-11-07 11:30:41 +01:00
if ( card - > type = = MMC_TYPE_SDIO | | card - > type = = MMC_TYPE_SD_COMBO ) {
2019-11-07 11:30:37 +01:00
struct device_node * np = mmc_dev ( mmc ) - > of_node ;
/*
* REVISIT : should be moved to sdio core and made more
* general e . g . by expanding the DT bindings of child nodes
* to provide a mechanism to provide this information :
* Documentation / devicetree / bindings / mmc / mmc - card . txt
*/
np = of_get_compatible_child ( np , " ti,wl1251 " ) ;
if ( np ) {
/*
* We have TI wl1251 attached to MMC3 . Pass this
* information to the SDIO core because it can ' t be
* probed by normal methods .
*/
dev_info ( host - > dev , " found wl1251 \n " ) ;
card - > quirks | = MMC_QUIRK_NONSTD_SDIO ;
card - > cccr . wide_bus = 1 ;
card - > cis . vendor = 0x104c ;
card - > cis . device = 0x9066 ;
card - > cis . blksize = 512 ;
card - > cis . max_dtr = 24000000 ;
card - > ocr = 0x80 ;
of_node_put ( np ) ;
}
}
2010-08-10 18:01:52 -07:00
}
2014-05-29 10:28:00 +02:00
static void omap_hsmmc_enable_sdio_irq ( struct mmc_host * mmc , int enable )
{
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
2014-05-29 10:28:02 +02:00
u32 irq_mask , con ;
2014-05-29 10:28:00 +02:00
unsigned long flags ;
spin_lock_irqsave ( & host - > irq_lock , flags ) ;
2014-05-29 10:28:02 +02:00
con = OMAP_HSMMC_READ ( host - > base , CON ) ;
2014-05-29 10:28:00 +02:00
irq_mask = OMAP_HSMMC_READ ( host - > base , ISE ) ;
if ( enable ) {
host - > flags | = HSMMC_SDIO_IRQ_ENABLED ;
irq_mask | = CIRQ_EN ;
2014-05-29 10:28:02 +02:00
con | = CTPL | CLKEXTFREE ;
2014-05-29 10:28:00 +02:00
} else {
host - > flags & = ~ HSMMC_SDIO_IRQ_ENABLED ;
irq_mask & = ~ CIRQ_EN ;
2014-05-29 10:28:02 +02:00
con & = ~ ( CTPL | CLKEXTFREE ) ;
2014-05-29 10:28:00 +02:00
}
2014-05-29 10:28:02 +02:00
OMAP_HSMMC_WRITE ( host - > base , CON , con ) ;
2014-05-29 10:28:00 +02:00
OMAP_HSMMC_WRITE ( host - > base , IE , irq_mask ) ;
/*
* if enable , piggy back detection on current request
* but always disable immediately
*/
if ( ! host - > req_in_progress | | ! enable )
OMAP_HSMMC_WRITE ( host - > base , ISE , irq_mask ) ;
/* flush posted write */
OMAP_HSMMC_READ ( host - > base , IE ) ;
spin_unlock_irqrestore ( & host - > irq_lock , flags ) ;
}
static int omap_hsmmc_configure_wake_irq ( struct omap_hsmmc_host * host )
{
int ret ;
/*
* For omaps with wake - up path , wakeirq will be irq from pinctrl and
* for other omaps , wakeirq will be from GPIO ( dat line remuxed to
* gpio ) . wakeirq is needed to detect sdio irq in runtime suspend state
* with functional clock disabled .
*/
if ( ! host - > dev - > of_node | | ! host - > wake_irq )
return - ENODEV ;
2015-05-21 15:51:52 -07:00
ret = dev_pm_set_dedicated_wake_irq ( host - > dev , host - > wake_irq ) ;
2014-05-29 10:28:00 +02:00
if ( ret ) {
dev_err ( mmc_dev ( host - > mmc ) , " Unable to request wake IRQ \n " ) ;
goto err ;
}
/*
* Some omaps don ' t have wake - up path from deeper idle states
* and need to remux SDIO DAT1 to GPIO for wake - up from idle .
*/
if ( host - > pdata - > controller_flags & OMAP_HSMMC_SWAKEUP_MISSING ) {
2014-05-29 10:28:05 +02:00
struct pinctrl * p = devm_pinctrl_get ( host - > dev ) ;
2017-04-10 16:54:17 +03:00
if ( IS_ERR ( p ) ) {
ret = PTR_ERR ( p ) ;
2014-05-29 10:28:05 +02:00
goto err_free_irq ;
}
if ( IS_ERR ( pinctrl_lookup_state ( p , PINCTRL_STATE_IDLE ) ) ) {
dev_info ( host - > dev , " missing idle pinctrl state \n " ) ;
devm_pinctrl_put ( p ) ;
ret = - EINVAL ;
goto err_free_irq ;
}
devm_pinctrl_put ( p ) ;
2014-05-29 10:28:00 +02:00
}
2014-05-29 10:28:02 +02:00
OMAP_HSMMC_WRITE ( host - > base , HCTL ,
OMAP_HSMMC_READ ( host - > base , HCTL ) | IWE ) ;
2014-05-29 10:28:00 +02:00
return 0 ;
2014-05-29 10:28:05 +02:00
err_free_irq :
2015-05-21 15:51:52 -07:00
dev_pm_clear_wake_irq ( host - > dev ) ;
2014-05-29 10:28:00 +02:00
err :
dev_warn ( host - > dev , " no SDIO IRQ support, falling back to polling \n " ) ;
host - > wake_irq = 0 ;
return ret ;
}
2009-09-22 16:44:59 -07:00
static void omap_hsmmc_conf_bus_power ( struct omap_hsmmc_host * host )
2009-02-20 13:10:08 +01:00
{
u32 hctl , capa , value ;
/* Only MMC1 supports 3.0V */
2011-02-28 20:48:04 +05:30
if ( host - > pdata - > controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT ) {
2009-02-20 13:10:08 +01:00
hctl = SDVS30 ;
capa = VS30 | VS18 ;
} else {
hctl = SDVS18 ;
capa = VS18 ;
}
value = OMAP_HSMMC_READ ( host - > base , HCTL ) & ~ SDVS_MASK ;
OMAP_HSMMC_WRITE ( host - > base , HCTL , value | hctl ) ;
value = OMAP_HSMMC_READ ( host - > base , CAPA ) ;
OMAP_HSMMC_WRITE ( host - > base , CAPA , value | capa ) ;
/* Set SD bus power bit */
2009-03-12 17:08:26 +02:00
set_sd_bus_power ( host ) ;
2009-02-20 13:10:08 +01:00
}
2014-09-08 23:44:51 -07:00
static int omap_hsmmc_multi_io_quirk ( struct mmc_card * card ,
unsigned int direction , int blk_size )
{
/* This controller can't do multiblock reads due to hw bugs */
if ( direction = = MMC_DATA_READ )
return 1 ;
return blk_size ;
}
static struct mmc_host_ops omap_hsmmc_ops = {
2011-07-01 18:55:23 +02:00
. post_req = omap_hsmmc_post_req ,
. pre_req = omap_hsmmc_pre_req ,
2009-09-22 16:44:59 -07:00
. request = omap_hsmmc_request ,
. set_ios = omap_hsmmc_set_ios ,
2018-09-24 13:30:51 +02:00
. get_cd = mmc_gpio_get_cd ,
2015-03-03 13:28:14 +01:00
. get_ro = mmc_gpio_get_ro ,
2010-08-10 18:01:52 -07:00
. init_card = omap_hsmmc_init_card ,
2014-05-29 10:28:00 +02:00
. enable_sdio_irq = omap_hsmmc_enable_sdio_irq ,
2009-09-22 16:44:49 -07:00
} ;
2009-09-22 16:44:38 -07:00
# ifdef CONFIG_DEBUG_FS
2018-12-01 10:24:57 -05:00
static int mmc_regs_show ( struct seq_file * s , void * data )
2009-09-22 16:44:38 -07:00
{
struct mmc_host * mmc = s - > private ;
2009-09-22 16:44:59 -07:00
struct omap_hsmmc_host * host = mmc_priv ( mmc ) ;
2009-09-22 16:44:38 -07:00
2014-05-29 10:28:01 +02:00
seq_printf ( s , " mmc%d: \n " , mmc - > index ) ;
seq_printf ( s , " sdio irq mode \t %s \n " ,
( mmc - > caps & MMC_CAP_SDIO_IRQ ) ? " interrupt " : " polling " ) ;
2009-09-22 16:44:39 -07:00
2014-05-29 10:28:01 +02:00
if ( mmc - > caps & MMC_CAP_SDIO_IRQ ) {
seq_printf ( s , " sdio irq \t %s \n " ,
( host - > flags & HSMMC_SDIO_IRQ_ENABLED ) ? " enabled "
: " disabled " ) ;
}
seq_printf ( s , " ctx_loss: \t %d \n " , host - > context_loss ) ;
2009-09-22 16:44:38 -07:00
2014-05-29 10:28:01 +02:00
pm_runtime_get_sync ( host - > dev ) ;
seq_puts ( s , " \n regs: \n " ) ;
2009-09-22 16:44:38 -07:00
seq_printf ( s , " CON: \t \t 0x%08x \n " ,
OMAP_HSMMC_READ ( host - > base , CON ) ) ;
2014-05-29 10:28:01 +02:00
seq_printf ( s , " PSTATE: \t \t 0x%08x \n " ,
OMAP_HSMMC_READ ( host - > base , PSTATE ) ) ;
2009-09-22 16:44:38 -07:00
seq_printf ( s , " HCTL: \t \t 0x%08x \n " ,
OMAP_HSMMC_READ ( host - > base , HCTL ) ) ;
seq_printf ( s , " SYSCTL: \t \t 0x%08x \n " ,
OMAP_HSMMC_READ ( host - > base , SYSCTL ) ) ;
seq_printf ( s , " IE: \t \t 0x%08x \n " ,
OMAP_HSMMC_READ ( host - > base , IE ) ) ;
seq_printf ( s , " ISE: \t \t 0x%08x \n " ,
OMAP_HSMMC_READ ( host - > base , ISE ) ) ;
seq_printf ( s , " CAPA: \t \t 0x%08x \n " ,
OMAP_HSMMC_READ ( host - > base , CAPA ) ) ;
2009-09-22 16:44:39 -07:00
2011-07-01 22:09:35 +05:30
pm_runtime_mark_last_busy ( host - > dev ) ;
pm_runtime_put_autosuspend ( host - > dev ) ;
2009-09-22 16:44:49 -07:00
2009-09-22 16:44:38 -07:00
return 0 ;
}
2018-12-01 10:24:57 -05:00
DEFINE_SHOW_ATTRIBUTE ( mmc_regs ) ;
2009-09-22 16:44:38 -07:00
2009-09-22 16:44:59 -07:00
static void omap_hsmmc_debugfs ( struct mmc_host * mmc )
2009-09-22 16:44:38 -07:00
{
if ( mmc - > debugfs_root )
debugfs_create_file ( " regs " , S_IRUSR , mmc - > debugfs_root ,
mmc , & mmc_regs_fops ) ;
}
# else
2009-09-22 16:44:59 -07:00
static void omap_hsmmc_debugfs ( struct mmc_host * mmc )
2009-09-22 16:44:38 -07:00
{
}
# endif
2012-03-12 20:32:37 +05:30
# ifdef CONFIG_OF
2014-02-13 23:45:48 -06:00
static const struct omap_mmc_of_data omap3_pre_es3_mmc_of_data = {
/* See 35xx errata 2.1.1.128 in SPRZ278F */
. controller_flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ ,
} ;
static const struct omap_mmc_of_data omap4_mmc_of_data = {
. reg_offset = 0x100 ,
} ;
2014-05-29 10:28:00 +02:00
static const struct omap_mmc_of_data am33xx_mmc_of_data = {
. reg_offset = 0x100 ,
. controller_flags = OMAP_HSMMC_SWAKEUP_MISSING ,
} ;
2012-03-12 20:32:37 +05:30
static const struct of_device_id omap_mmc_of_match [ ] = {
{
. compatible = " ti,omap2-hsmmc " ,
} ,
2014-02-13 23:45:48 -06:00
{
. compatible = " ti,omap3-pre-es3-hsmmc " ,
. data = & omap3_pre_es3_mmc_of_data ,
} ,
2012-03-12 20:32:37 +05:30
{
. compatible = " ti,omap3-hsmmc " ,
} ,
{
. compatible = " ti,omap4-hsmmc " ,
2014-02-13 23:45:48 -06:00
. data = & omap4_mmc_of_data ,
2012-03-12 20:32:37 +05:30
} ,
2014-05-29 10:28:00 +02:00
{
. compatible = " ti,am33xx-hsmmc " ,
. data = & am33xx_mmc_of_data ,
} ,
2012-03-12 20:32:37 +05:30
{ } ,
2012-04-10 09:57:36 -04:00
} ;
2012-03-12 20:32:37 +05:30
MODULE_DEVICE_TABLE ( of , omap_mmc_of_match ) ;
2014-11-08 15:33:09 +01:00
static struct omap_hsmmc_platform_data * of_get_hsmmc_pdata ( struct device * dev )
2012-03-12 20:32:37 +05:30
{
2016-04-26 16:46:23 -07:00
struct omap_hsmmc_platform_data * pdata , * legacy ;
2012-03-12 20:32:37 +05:30
struct device_node * np = dev - > of_node ;
pdata = devm_kzalloc ( dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
2014-02-28 19:08:18 +05:30
return ERR_PTR ( - ENOMEM ) ; /* out of memory */
2012-03-12 20:32:37 +05:30
2016-04-26 16:46:23 -07:00
legacy = dev_get_platdata ( dev ) ;
if ( legacy & & legacy - > name )
pdata - > name = legacy - > name ;
2012-03-12 20:32:37 +05:30
if ( of_find_property ( np , " ti,dual-volt " , NULL ) )
pdata - > controller_flags | = OMAP_HSMMC_SUPPORTS_DUAL_VOLT ;
if ( of_find_property ( np , " ti,non-removable " , NULL ) ) {
2014-11-08 15:33:14 +01:00
pdata - > nonremovable = true ;
pdata - > no_regulator_off_init = true ;
2012-03-12 20:32:37 +05:30
}
if ( of_find_property ( np , " ti,needs-special-reset " , NULL ) )
2014-11-08 15:33:14 +01:00
pdata - > features | = HSMMC_HAS_UPDATED_RESET ;
2012-03-12 20:32:37 +05:30
2012-11-19 21:59:58 +05:30
if ( of_find_property ( np , " ti,needs-special-hs-handling " , NULL ) )
2014-11-08 15:33:14 +01:00
pdata - > features | = HSMMC_HAS_HSPE_SUPPORT ;
2012-11-19 21:59:58 +05:30
2012-03-12 20:32:37 +05:30
return pdata ;
}
# else
2014-11-08 15:33:09 +01:00
static inline struct omap_hsmmc_platform_data
2012-03-12 20:32:37 +05:30
* of_get_hsmmc_pdata ( struct device * dev )
{
2014-02-28 19:08:18 +05:30
return ERR_PTR ( - EINVAL ) ;
2012-03-12 20:32:37 +05:30
}
# endif
2012-11-19 13:23:06 -05:00
static int omap_hsmmc_probe ( struct platform_device * pdev )
2009-01-23 01:05:23 +01:00
{
2014-11-08 15:33:09 +01:00
struct omap_hsmmc_platform_data * pdata = pdev - > dev . platform_data ;
2009-01-23 01:05:23 +01:00
struct mmc_host * mmc ;
2009-09-22 16:44:59 -07:00
struct omap_hsmmc_host * host = NULL ;
2009-01-23 01:05:23 +01:00
struct resource * res ;
2010-02-15 10:03:34 -08:00
int ret , irq ;
2012-03-12 20:32:37 +05:30
const struct of_device_id * match ;
2014-02-13 23:45:48 -06:00
const struct omap_mmc_of_data * data ;
2014-05-09 22:16:51 +05:30
void __iomem * base ;
2012-03-12 20:32:37 +05:30
match = of_match_device ( of_match_ptr ( omap_mmc_of_match ) , & pdev - > dev ) ;
if ( match ) {
pdata = of_get_hsmmc_pdata ( & pdev - > dev ) ;
2013-01-30 10:07:17 +01:00
if ( IS_ERR ( pdata ) )
return PTR_ERR ( pdata ) ;
2012-03-12 20:32:37 +05:30
if ( match - > data ) {
2014-02-13 23:45:48 -06:00
data = match - > data ;
pdata - > reg_offset = data - > reg_offset ;
pdata - > controller_flags | = data - > controller_flags ;
2012-03-12 20:32:37 +05:30
}
}
2009-01-23 01:05:23 +01:00
if ( pdata = = NULL ) {
dev_err ( & pdev - > dev , " Platform Data is missing \n " ) ;
return - ENXIO ;
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
irq = platform_get_irq ( pdev , 0 ) ;
if ( res = = NULL | | irq < 0 )
return - ENXIO ;
2014-05-09 22:16:51 +05:30
base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2009-01-23 01:05:23 +01:00
2009-09-22 16:44:59 -07:00
mmc = mmc_alloc_host ( sizeof ( struct omap_hsmmc_host ) , & pdev - > dev ) ;
2009-01-23 01:05:23 +01:00
if ( ! mmc ) {
ret = - ENOMEM ;
2014-11-08 15:33:15 +01:00
goto err ;
2009-01-23 01:05:23 +01:00
}
2015-01-13 08:23:18 +13:00
ret = mmc_of_parse ( mmc ) ;
if ( ret )
goto err1 ;
2009-01-23 01:05:23 +01:00
host = mmc_priv ( mmc ) ;
host - > mmc = mmc ;
host - > pdata = pdata ;
host - > dev = & pdev - > dev ;
host - > use_dma = 1 ;
host - > dma_ch = - 1 ;
host - > irq = irq ;
2012-04-02 12:26:47 +05:30
host - > mapbase = res - > start + pdata - > reg_offset ;
2014-05-09 22:16:51 +05:30
host - > base = base + pdata - > reg_offset ;
2010-02-15 10:03:34 -08:00
host - > power_mode = MMC_POWER_OFF ;
2011-07-01 18:55:23 +02:00
host - > next_data . cookie = 1 ;
2015-10-07 06:22:24 -07:00
host - > pbias_enabled = 0 ;
2015-08-27 14:44:04 +05:30
host - > vqmmc_enabled = 0 ;
2009-01-23 01:05:23 +01:00
platform_set_drvdata ( pdev , host ) ;
2014-05-29 10:28:00 +02:00
if ( pdev - > dev . of_node )
host - > wake_irq = irq_of_parse_and_map ( pdev - > dev . of_node , 1 ) ;
2011-07-01 22:09:34 +05:30
mmc - > ops = & omap_hsmmc_ops ;
2009-09-22 16:44:49 -07:00
2012-02-19 13:20:33 +01:00
mmc - > f_min = OMAP_MMC_MIN_CLOCK ;
if ( pdata - > max_freq > 0 )
mmc - > f_max = pdata - > max_freq ;
2015-01-13 08:23:18 +13:00
else if ( mmc - > f_max = = 0 )
2012-02-19 13:20:33 +01:00
mmc - > f_max = OMAP_MMC_MAX_CLOCK ;
2009-01-23 01:05:23 +01:00
2009-09-22 16:44:58 -07:00
spin_lock_init ( & host - > irq_lock ) ;
2009-01-23 01:05:23 +01:00
2014-05-09 22:16:48 +05:30
host - > fclk = devm_clk_get ( & pdev - > dev , " fck " ) ;
2009-01-23 01:05:23 +01:00
if ( IS_ERR ( host - > fclk ) ) {
ret = PTR_ERR ( host - > fclk ) ;
host - > fclk = NULL ;
goto err1 ;
}
2011-10-06 14:50:35 -06:00
if ( host - > pdata - > controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ ) {
dev_info ( & pdev - > dev , " multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer \n " ) ;
2014-09-08 23:44:51 -07:00
omap_hsmmc_ops . multi_io_quirk = omap_hsmmc_multi_io_quirk ;
2011-10-06 14:50:35 -06:00
}
2009-09-22 16:44:49 -07:00
2015-05-21 15:51:52 -07:00
device_init_wakeup ( & pdev - > dev , true ) ;
2011-07-01 22:09:35 +05:30
pm_runtime_enable ( host - > dev ) ;
pm_runtime_get_sync ( host - > dev ) ;
pm_runtime_set_autosuspend_delay ( host - > dev , MMC_AUTOSUSPEND_DELAY ) ;
pm_runtime_use_autosuspend ( host - > dev ) ;
2009-01-23 01:05:23 +01:00
2012-02-24 21:14:34 +05:30
omap_hsmmc_context_save ( host ) ;
2014-05-09 22:16:48 +05:30
host - > dbclk = devm_clk_get ( & pdev - > dev , " mmchsdb_fck " ) ;
2012-04-09 12:08:35 +05:30
/*
* MMC can still work without debounce clock .
*/
if ( IS_ERR ( host - > dbclk ) ) {
host - > dbclk = NULL ;
2012-06-27 14:19:54 +05:30
} else if ( clk_prepare_enable ( host - > dbclk ) ! = 0 ) {
2012-04-09 12:08:35 +05:30
dev_warn ( mmc_dev ( host - > mmc ) , " Failed to enable debounce clk \n " ) ;
host - > dbclk = NULL ;
2009-09-22 16:45:02 -07:00
}
2009-01-23 01:05:23 +01:00
2017-06-22 11:57:53 +01:00
/* Set this to a value that allows allocating an entire descriptor
* list within a page ( zero order allocation ) . */
mmc - > max_segs = 64 ;
2008-11-14 15:22:00 +02:00
2009-01-23 01:05:23 +01:00
mmc - > max_blk_size = 512 ; /* Block Length at max can be 1024 */
mmc - > max_blk_count = 0xFFFF ; /* No. of Blocks is 16 bits */
mmc - > max_req_size = mmc - > max_blk_size * mmc - > max_blk_count ;
2009-09-22 16:44:53 -07:00
mmc - > caps | = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
2020-05-08 13:29:02 +02:00
MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_CMD23 ;
2009-01-23 01:05:23 +01:00
2014-11-08 15:33:14 +01:00
mmc - > caps | = mmc_pdata ( host ) - > caps ;
2010-09-15 14:49:23 +00:00
if ( mmc - > caps & MMC_CAP_8_BIT_DATA )
2009-01-23 01:05:23 +01:00
mmc - > caps | = MMC_CAP_4_BIT_DATA ;
2014-11-08 15:33:14 +01:00
if ( mmc_pdata ( host ) - > nonremovable )
2009-09-22 16:44:48 -07:00
mmc - > caps | = MMC_CAP_NONREMOVABLE ;
2015-01-13 08:23:18 +13:00
mmc - > pm_caps | = mmc_pdata ( host ) - > pm_caps ;
2011-11-22 16:02:18 +02:00
2009-09-22 16:44:59 -07:00
omap_hsmmc_conf_bus_power ( host ) ;
2009-01-23 01:05:23 +01:00
2016-04-29 16:06:18 +03:00
host - > rx_chan = dma_request_chan ( & pdev - > dev , " rx " ) ;
if ( IS_ERR ( host - > rx_chan ) ) {
dev_err ( mmc_dev ( host - > mmc ) , " RX DMA channel request failed \n " ) ;
ret = PTR_ERR ( host - > rx_chan ) ;
2012-04-13 12:27:37 +01:00
goto err_irq ;
}
2016-04-29 16:06:18 +03:00
host - > tx_chan = dma_request_chan ( & pdev - > dev , " tx " ) ;
if ( IS_ERR ( host - > tx_chan ) ) {
dev_err ( mmc_dev ( host - > mmc ) , " TX DMA channel request failed \n " ) ;
ret = PTR_ERR ( host - > tx_chan ) ;
2012-04-13 12:27:37 +01:00
goto err_irq ;
2012-04-13 12:14:39 +01:00
}
2009-01-23 01:05:23 +01:00
2018-12-11 14:41:31 +00:00
/*
* Limit the maximum segment size to the lower of the request size
* and the DMA engine device segment size limits . In reality , with
* 32 - bit transfers , the DMA engine can do longer segments than this
* but there is no way to represent that in the DMA model - if we
* increase this figure here , we get warnings from the DMA API debug .
*/
mmc - > max_seg_size = min3 ( mmc - > max_req_size ,
dma_get_max_seg_size ( host - > rx_chan - > device - > dev ) ,
dma_get_max_seg_size ( host - > tx_chan - > device - > dev ) ) ;
2009-01-23 01:05:23 +01:00
/* Request IRQ for MMC operations */
2014-05-09 22:16:49 +05:30
ret = devm_request_irq ( & pdev - > dev , host - > irq , omap_hsmmc_irq , 0 ,
2009-01-23 01:05:23 +01:00
mmc_hostname ( mmc ) , host ) ;
if ( ret ) {
2012-11-19 22:00:00 +05:30
dev_err ( mmc_dev ( host - > mmc ) , " Unable to grab HSMMC IRQ \n " ) ;
2009-01-23 01:05:23 +01:00
goto err_irq ;
}
2015-08-27 14:44:07 +05:30
ret = omap_hsmmc_reg_get ( host ) ;
if ( ret )
goto err_irq ;
2010-02-15 10:03:34 -08:00
2017-06-07 14:06:11 +05:30
if ( ! mmc - > ocr_avail )
mmc - > ocr_avail = mmc_pdata ( host ) - > ocr_mask ;
2009-01-23 01:05:23 +01:00
2010-05-26 14:42:06 -07:00
omap_hsmmc_disable_irq ( host ) ;
2009-01-23 01:05:23 +01:00
2014-05-29 10:28:00 +02:00
/*
* For now , only support SDIO interrupt if we have a separate
* wake - up interrupt configured from device tree . This is because
* the wake - up interrupt is needed for idle state and some
* platforms need special quirks . And we don ' t want to add new
* legacy mux platform init code callbacks any longer as we
* are moving to DT based booting anyways .
*/
ret = omap_hsmmc_configure_wake_irq ( host ) ;
if ( ! ret )
mmc - > caps | = MMC_CAP_SDIO_IRQ ;
2009-01-23 01:05:23 +01:00
mmc_add_host ( mmc ) ;
2014-11-08 15:33:14 +01:00
if ( mmc_pdata ( host ) - > name ! = NULL ) {
2009-01-23 01:05:23 +01:00
ret = device_create_file ( & mmc - > class_dev , & dev_attr_slot_name ) ;
if ( ret < 0 )
goto err_slot_name ;
}
2009-09-22 16:44:59 -07:00
omap_hsmmc_debugfs ( mmc ) ;
2011-07-01 22:09:35 +05:30
pm_runtime_mark_last_busy ( host - > dev ) ;
pm_runtime_put_autosuspend ( host - > dev ) ;
2009-09-22 16:44:38 -07:00
2009-01-23 01:05:23 +01:00
return 0 ;
err_slot_name :
mmc_remove_host ( mmc ) ;
err_irq :
2015-05-21 15:51:52 -07:00
device_init_wakeup ( & pdev - > dev , false ) ;
2016-04-29 16:06:18 +03:00
if ( ! IS_ERR_OR_NULL ( host - > tx_chan ) )
2012-04-13 12:14:39 +01:00
dma_release_channel ( host - > tx_chan ) ;
2016-04-29 16:06:18 +03:00
if ( ! IS_ERR_OR_NULL ( host - > rx_chan ) )
2012-04-13 12:14:39 +01:00
dma_release_channel ( host - > rx_chan ) ;
2016-02-10 15:02:44 -08:00
pm_runtime_dont_use_autosuspend ( host - > dev ) ;
2012-02-24 21:14:33 +05:30
pm_runtime_put_sync ( host - > dev ) ;
2012-03-08 23:41:35 -05:00
pm_runtime_disable ( host - > dev ) ;
2014-05-09 22:16:48 +05:30
if ( host - > dbclk )
2012-06-27 14:19:54 +05:30
clk_disable_unprepare ( host - > dbclk ) ;
2009-01-23 01:05:23 +01:00
err1 :
2010-02-15 10:03:34 -08:00
mmc_free_host ( mmc ) ;
2009-01-23 01:05:23 +01:00
err :
return ret ;
}
2012-11-19 13:26:03 -05:00
static int omap_hsmmc_remove ( struct platform_device * pdev )
2009-01-23 01:05:23 +01:00
{
2009-09-22 16:44:59 -07:00
struct omap_hsmmc_host * host = platform_get_drvdata ( pdev ) ;
2009-01-23 01:05:23 +01:00
2012-03-14 11:18:27 +02:00
pm_runtime_get_sync ( host - > dev ) ;
mmc_remove_host ( host - > mmc ) ;
2009-01-23 01:05:23 +01:00
2015-11-03 13:37:31 +02:00
dma_release_channel ( host - > tx_chan ) ;
dma_release_channel ( host - > rx_chan ) ;
2012-04-13 12:14:39 +01:00
2018-09-02 09:30:58 +02:00
dev_pm_clear_wake_irq ( host - > dev ) ;
2016-02-10 15:02:44 -08:00
pm_runtime_dont_use_autosuspend ( host - > dev ) ;
2012-03-14 11:18:27 +02:00
pm_runtime_put_sync ( host - > dev ) ;
pm_runtime_disable ( host - > dev ) ;
2015-05-21 15:51:52 -07:00
device_init_wakeup ( & pdev - > dev , false ) ;
2014-05-09 22:16:48 +05:30
if ( host - > dbclk )
2012-06-27 14:19:54 +05:30
clk_disable_unprepare ( host - > dbclk ) ;
2009-01-23 01:05:23 +01:00
2012-10-15 21:35:07 +05:30
mmc_free_host ( host - > mmc ) ;
2012-03-14 11:18:27 +02:00
2009-01-23 01:05:23 +01:00
return 0 ;
}
2015-02-27 13:24:34 +02:00
# ifdef CONFIG_PM_SLEEP
2010-05-26 14:42:07 -07:00
static int omap_hsmmc_suspend ( struct device * dev )
2009-01-23 01:05:23 +01:00
{
2012-03-14 11:18:27 +02:00
struct omap_hsmmc_host * host = dev_get_drvdata ( dev ) ;
2009-01-23 01:05:23 +01:00
2012-03-14 11:18:27 +02:00
if ( ! host )
2009-01-23 01:05:23 +01:00
return 0 ;
2012-03-14 11:18:27 +02:00
pm_runtime_get_sync ( host - > dev ) ;
2011-11-22 16:02:17 +02:00
2012-03-14 11:18:27 +02:00
if ( ! ( host - > mmc - > pm_flags & MMC_PM_KEEP_POWER ) ) {
2014-05-29 10:28:00 +02:00
OMAP_HSMMC_WRITE ( host - > base , ISE , 0 ) ;
OMAP_HSMMC_WRITE ( host - > base , IE , 0 ) ;
OMAP_HSMMC_WRITE ( host - > base , STAT , STAT_CLEAR ) ;
2012-03-14 11:18:27 +02:00
OMAP_HSMMC_WRITE ( host - > base , HCTL ,
OMAP_HSMMC_READ ( host - > base , HCTL ) & ~ SDBP ) ;
2009-01-23 01:05:23 +01:00
}
2012-03-14 11:18:27 +02:00
2012-04-09 12:08:35 +05:30
if ( host - > dbclk )
2012-06-27 14:19:54 +05:30
clk_disable_unprepare ( host - > dbclk ) ;
2013-09-25 14:47:06 +02:00
2011-11-22 16:02:17 +02:00
pm_runtime_put_sync ( host - > dev ) ;
2013-09-25 14:47:06 +02:00
return 0 ;
2009-01-23 01:05:23 +01:00
}
/* Routine to resume the MMC device */
2010-05-26 14:42:07 -07:00
static int omap_hsmmc_resume ( struct device * dev )
2009-01-23 01:05:23 +01:00
{
2012-03-14 11:18:27 +02:00
struct omap_hsmmc_host * host = dev_get_drvdata ( dev ) ;
if ( ! host )
return 0 ;
2009-01-23 01:05:23 +01:00
2012-03-14 11:18:27 +02:00
pm_runtime_get_sync ( host - > dev ) ;
2009-09-22 16:44:43 -07:00
2012-04-09 12:08:35 +05:30
if ( host - > dbclk )
2012-06-27 14:19:54 +05:30
clk_prepare_enable ( host - > dbclk ) ;
2009-09-22 16:45:02 -07:00
2012-03-14 11:18:27 +02:00
if ( ! ( host - > mmc - > pm_flags & MMC_PM_KEEP_POWER ) )
omap_hsmmc_conf_bus_power ( host ) ;
2009-02-20 13:10:08 +01:00
2012-03-14 11:18:27 +02:00
pm_runtime_mark_last_busy ( host - > dev ) ;
pm_runtime_put_autosuspend ( host - > dev ) ;
2013-09-25 14:47:06 +02:00
return 0 ;
2009-01-23 01:05:23 +01:00
}
# endif
2011-07-01 22:09:35 +05:30
static int omap_hsmmc_runtime_suspend ( struct device * dev )
{
struct omap_hsmmc_host * host ;
2014-05-29 10:28:00 +02:00
unsigned long flags ;
2014-05-29 10:28:03 +02:00
int ret = 0 ;
2011-07-01 22:09:35 +05:30
2019-04-23 15:50:12 +08:00
host = dev_get_drvdata ( dev ) ;
2011-07-01 22:09:35 +05:30
omap_hsmmc_context_save ( host ) ;
2012-03-14 11:18:27 +02:00
dev_dbg ( dev , " disabled \n " ) ;
2011-07-01 22:09:35 +05:30
2014-05-29 10:28:00 +02:00
spin_lock_irqsave ( & host - > irq_lock , flags ) ;
if ( ( host - > mmc - > caps & MMC_CAP_SDIO_IRQ ) & &
( host - > flags & HSMMC_SDIO_IRQ_ENABLED ) ) {
/* disable sdio irq handling to prevent race */
OMAP_HSMMC_WRITE ( host - > base , ISE , 0 ) ;
OMAP_HSMMC_WRITE ( host - > base , IE , 0 ) ;
2014-05-29 10:28:03 +02:00
if ( ! ( OMAP_HSMMC_READ ( host - > base , PSTATE ) & DLEV_DAT ( 1 ) ) ) {
/*
* dat1 line low , pending sdio irq
* race condition : possible irq handler running on
* multi - core , abort
*/
dev_dbg ( dev , " pending sdio irq, abort suspend \n " ) ;
OMAP_HSMMC_WRITE ( host - > base , STAT , STAT_CLEAR ) ;
OMAP_HSMMC_WRITE ( host - > base , ISE , CIRQ_EN ) ;
OMAP_HSMMC_WRITE ( host - > base , IE , CIRQ_EN ) ;
pm_runtime_mark_last_busy ( dev ) ;
ret = - EBUSY ;
goto abort ;
}
2014-05-29 10:28:00 +02:00
2014-05-29 10:28:04 +02:00
pinctrl_pm_select_idle_state ( dev ) ;
} else {
pinctrl_pm_select_idle_state ( dev ) ;
2014-05-29 10:28:00 +02:00
}
2014-05-29 10:28:04 +02:00
2014-05-29 10:28:03 +02:00
abort :
2014-05-29 10:28:00 +02:00
spin_unlock_irqrestore ( & host - > irq_lock , flags ) ;
2014-05-29 10:28:03 +02:00
return ret ;
2011-07-01 22:09:35 +05:30
}
static int omap_hsmmc_runtime_resume ( struct device * dev )
{
struct omap_hsmmc_host * host ;
2014-05-29 10:28:00 +02:00
unsigned long flags ;
2011-07-01 22:09:35 +05:30
2019-04-23 15:50:12 +08:00
host = dev_get_drvdata ( dev ) ;
2011-07-01 22:09:35 +05:30
omap_hsmmc_context_restore ( host ) ;
2012-03-14 11:18:27 +02:00
dev_dbg ( dev , " enabled \n " ) ;
2011-07-01 22:09:35 +05:30
2014-05-29 10:28:00 +02:00
spin_lock_irqsave ( & host - > irq_lock , flags ) ;
if ( ( host - > mmc - > caps & MMC_CAP_SDIO_IRQ ) & &
( host - > flags & HSMMC_SDIO_IRQ_ENABLED ) ) {
2019-12-06 18:08:17 +01:00
pinctrl_select_default_state ( host - > dev ) ;
2014-05-29 10:28:04 +02:00
/* irq lost, if pinmux incorrect */
2014-05-29 10:28:00 +02:00
OMAP_HSMMC_WRITE ( host - > base , STAT , STAT_CLEAR ) ;
OMAP_HSMMC_WRITE ( host - > base , ISE , CIRQ_EN ) ;
OMAP_HSMMC_WRITE ( host - > base , IE , CIRQ_EN ) ;
2014-05-29 10:28:04 +02:00
} else {
2019-12-06 18:08:17 +01:00
pinctrl_select_default_state ( host - > dev ) ;
2014-05-29 10:28:00 +02:00
}
spin_unlock_irqrestore ( & host - > irq_lock , flags ) ;
2011-07-01 22:09:35 +05:30
return 0 ;
}
2017-06-29 13:39:29 +05:30
static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
2015-02-27 13:24:34 +02:00
SET_SYSTEM_SLEEP_PM_OPS ( omap_hsmmc_suspend , omap_hsmmc_resume )
2011-07-01 22:09:35 +05:30
. runtime_suspend = omap_hsmmc_runtime_suspend ,
. runtime_resume = omap_hsmmc_runtime_resume ,
2010-05-26 14:42:07 -07:00
} ;
static struct platform_driver omap_hsmmc_driver = {
2012-03-14 11:18:28 +02:00
. probe = omap_hsmmc_probe ,
2012-11-19 13:20:26 -05:00
. remove = omap_hsmmc_remove ,
2009-01-23 01:05:23 +01:00
. driver = {
. name = DRIVER_NAME ,
2010-05-26 14:42:07 -07:00
. pm = & omap_hsmmc_dev_pm_ops ,
2012-03-12 20:32:37 +05:30
. of_match_table = of_match_ptr ( omap_mmc_of_match ) ,
2009-01-23 01:05:23 +01:00
} ,
} ;
2012-03-14 11:18:32 +02:00
module_platform_driver ( omap_hsmmc_driver ) ;
2009-01-23 01:05:23 +01:00
MODULE_DESCRIPTION ( " OMAP High Speed Multimedia Card driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform: " DRIVER_NAME ) ;
MODULE_AUTHOR ( " Texas Instruments Inc " ) ;