2011-01-01 23:52:56 -05:00
/*
* Copyright ( C ) 2010 Google , Inc .
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
*/
2016-02-29 21:56:25 +01:00
# include <linux/delay.h>
2011-01-01 23:52:56 -05:00
# include <linux/err.h>
2011-07-03 15:15:51 -04:00
# include <linux/module.h>
2011-01-01 23:52:56 -05:00
# include <linux/init.h>
# include <linux/platform_device.h>
# include <linux/clk.h>
# include <linux/io.h>
2011-08-30 13:17:16 -06:00
# include <linux/of.h>
2012-02-01 16:30:55 -07:00
# include <linux/of_device.h>
2017-03-08 20:00:39 +01:00
# include <linux/reset.h>
2011-01-01 23:52:56 -05:00
# include <linux/mmc/card.h>
# include <linux/mmc/host.h>
2015-12-22 19:41:02 +01:00
# include <linux/mmc/mmc.h>
2013-03-11 14:44:11 -06:00
# include <linux/mmc/slot-gpio.h>
2015-03-30 23:39:25 +02:00
# include <linux/gpio/consumer.h>
2011-01-01 23:52:56 -05:00
# include "sdhci-pltfm.h"
2012-04-18 18:48:02 +05:30
/* Tegra SDHOST controller vendor register definitions */
2015-12-22 19:41:01 +01:00
# define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100
2015-12-22 19:41:02 +01:00
# define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000
# define SDHCI_CLOCK_CTRL_TAP_SHIFT 16
# define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5)
2015-12-22 19:41:01 +01:00
# define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3)
# define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2)
2012-04-18 18:48:02 +05:30
# define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120
2014-05-22 08:55:35 -07:00
# define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8
# define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10
2012-04-18 18:48:02 +05:30
# define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20
2014-05-22 08:55:35 -07:00
# define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200
2012-04-18 18:48:02 +05:30
2016-02-29 21:56:25 +01:00
# define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4
# define SDHCI_AUTO_CAL_START BIT(31)
# define SDHCI_AUTO_CAL_ENABLE BIT(29)
2012-02-01 16:30:55 -07:00
# define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
# define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
2012-04-18 18:48:02 +05:30
# define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
2015-12-22 19:41:03 +01:00
# define NVQUIRK_ENABLE_SDR50 BIT(3)
# define NVQUIRK_ENABLE_SDR104 BIT(4)
# define NVQUIRK_ENABLE_DDR50 BIT(5)
2016-02-29 21:56:25 +01:00
# define NVQUIRK_HAS_PADCALIB BIT(6)
2012-02-01 16:30:55 -07:00
struct sdhci_tegra_soc_data {
2013-03-13 19:26:03 +01:00
const struct sdhci_pltfm_data * pdata ;
2012-02-01 16:30:55 -07:00
u32 nvquirks ;
} ;
struct sdhci_tegra {
const struct sdhci_tegra_soc_data * soc_data ;
2015-03-30 23:39:25 +02:00
struct gpio_desc * power_gpio ;
2015-12-22 19:41:00 +01:00
bool ddr_signaling ;
2016-02-29 21:56:25 +01:00
bool pad_calib_required ;
2017-03-08 20:00:39 +01:00
struct reset_control * rst ;
2012-02-01 16:30:55 -07:00
} ;
2011-01-01 23:52:56 -05:00
static u16 tegra_sdhci_readw ( struct sdhci_host * host , int reg )
{
2012-02-01 16:30:55 -07:00
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2016-02-16 21:08:29 +08:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2012-02-01 16:30:55 -07:00
const struct sdhci_tegra_soc_data * soc_data = tegra_host - > soc_data ;
if ( unlikely ( ( soc_data - > nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200 ) & &
( reg = = SDHCI_HOST_VERSION ) ) ) {
2011-01-01 23:52:56 -05:00
/* Erratum: Version register is invalid in HW. */
return SDHCI_SPEC_200 ;
}
return readw ( host - > ioaddr + reg ) ;
}
2015-01-28 11:45:16 -05:00
static void tegra_sdhci_writew ( struct sdhci_host * host , u16 val , int reg )
{
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2015-02-11 12:55:51 -05:00
switch ( reg ) {
case SDHCI_TRANSFER_MODE :
/*
* Postpone this write , we must do it together with a
* command write that is down below .
*/
pltfm_host - > xfer_mode_shadow = val ;
return ;
case SDHCI_COMMAND :
writel ( ( val < < 16 ) | pltfm_host - > xfer_mode_shadow ,
host - > ioaddr + SDHCI_TRANSFER_MODE ) ;
return ;
2015-01-28 11:45:16 -05:00
}
writew ( val , host - > ioaddr + reg ) ;
}
2011-01-01 23:52:56 -05:00
static void tegra_sdhci_writel ( struct sdhci_host * host , u32 val , int reg )
{
2012-02-01 16:30:55 -07:00
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2016-02-16 21:08:29 +08:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2012-02-01 16:30:55 -07:00
const struct sdhci_tegra_soc_data * soc_data = tegra_host - > soc_data ;
2011-01-01 23:52:56 -05:00
/* Seems like we're getting spurious timeout and crc errors, so
* disable signalling of them . In case of real errors software
* timers should take care of eventually detecting them .
*/
if ( unlikely ( reg = = SDHCI_SIGNAL_ENABLE ) )
val & = ~ ( SDHCI_INT_TIMEOUT | SDHCI_INT_CRC ) ;
writel ( val , host - > ioaddr + reg ) ;
2012-02-01 16:30:55 -07:00
if ( unlikely ( ( soc_data - > nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET ) & &
( reg = = SDHCI_INT_ENABLE ) ) ) {
2011-01-01 23:52:56 -05:00
/* Erratum: Must enable block gap interrupt detection */
u8 gap_ctrl = readb ( host - > ioaddr + SDHCI_BLOCK_GAP_CONTROL ) ;
if ( val & SDHCI_INT_CARD_INT )
gap_ctrl | = 0x8 ;
else
gap_ctrl & = ~ 0x8 ;
writeb ( gap_ctrl , host - > ioaddr + SDHCI_BLOCK_GAP_CONTROL ) ;
}
}
2012-02-01 16:30:55 -07:00
static unsigned int tegra_sdhci_get_ro ( struct sdhci_host * host )
2011-01-01 23:52:56 -05:00
{
2013-03-11 14:44:11 -06:00
return mmc_gpio_get_ro ( host - > mmc ) ;
2011-01-01 23:52:56 -05:00
}
2014-04-25 12:57:12 +01:00
static void tegra_sdhci_reset ( struct sdhci_host * host , u8 mask )
2012-04-18 18:48:02 +05:30
{
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2016-02-16 21:08:29 +08:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2012-04-18 18:48:02 +05:30
const struct sdhci_tegra_soc_data * soc_data = tegra_host - > soc_data ;
2015-12-22 19:41:01 +01:00
u32 misc_ctrl , clk_ctrl ;
2012-04-18 18:48:02 +05:30
2014-04-25 12:57:12 +01:00
sdhci_reset ( host , mask ) ;
2012-04-18 18:48:02 +05:30
if ( ! ( mask & SDHCI_RESET_ALL ) )
return ;
2015-12-22 19:41:04 +01:00
misc_ctrl = sdhci_readl ( host , SDHCI_TEGRA_VENDOR_MISC_CTRL ) ;
2015-12-22 19:41:01 +01:00
clk_ctrl = sdhci_readl ( host , SDHCI_TEGRA_VENDOR_CLOCK_CTRL ) ;
2016-07-12 14:53:37 +01:00
misc_ctrl & = ~ ( SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 |
SDHCI_MISC_CTRL_ENABLE_SDR50 |
SDHCI_MISC_CTRL_ENABLE_DDR50 |
SDHCI_MISC_CTRL_ENABLE_SDR104 ) ;
2015-12-22 19:41:01 +01:00
clk_ctrl & = ~ SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE ;
2016-07-12 14:53:37 +01:00
/*
* If the board does not define a regulator for the SDHCI
* IO voltage , then don ' t advertise support for UHS modes
* even if the device supports it because the IO voltage
* cannot be configured .
*/
if ( ! IS_ERR ( host - > mmc - > supply . vqmmc ) ) {
/* Erratum: Enable SDHCI spec v3.00 support */
if ( soc_data - > nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300 )
misc_ctrl | = SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 ;
/* Advertise UHS modes as supported by host */
if ( soc_data - > nvquirks & NVQUIRK_ENABLE_SDR50 )
misc_ctrl | = SDHCI_MISC_CTRL_ENABLE_SDR50 ;
if ( soc_data - > nvquirks & NVQUIRK_ENABLE_DDR50 )
misc_ctrl | = SDHCI_MISC_CTRL_ENABLE_DDR50 ;
if ( soc_data - > nvquirks & NVQUIRK_ENABLE_SDR104 )
misc_ctrl | = SDHCI_MISC_CTRL_ENABLE_SDR104 ;
if ( soc_data - > nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50 )
clk_ctrl | = SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE ;
}
sdhci_writel ( host , misc_ctrl , SDHCI_TEGRA_VENDOR_MISC_CTRL ) ;
2015-12-22 19:41:01 +01:00
sdhci_writel ( host , clk_ctrl , SDHCI_TEGRA_VENDOR_CLOCK_CTRL ) ;
2016-02-29 21:56:25 +01:00
if ( soc_data - > nvquirks & NVQUIRK_HAS_PADCALIB )
tegra_host - > pad_calib_required = true ;
2015-12-22 19:41:00 +01:00
tegra_host - > ddr_signaling = false ;
2012-04-18 18:48:02 +05:30
}
2016-02-29 21:56:25 +01:00
static void tegra_sdhci_pad_autocalib ( struct sdhci_host * host )
{
u32 val ;
mdelay ( 1 ) ;
val = sdhci_readl ( host , SDHCI_TEGRA_AUTO_CAL_CONFIG ) ;
val | = SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START ;
sdhci_writel ( host , val , SDHCI_TEGRA_AUTO_CAL_CONFIG ) ;
}
2015-12-22 19:41:00 +01:00
static void tegra_sdhci_set_clock ( struct sdhci_host * host , unsigned int clock )
{
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2016-02-16 21:08:29 +08:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2015-12-22 19:41:00 +01:00
unsigned long host_clk ;
if ( ! clock )
2016-02-29 21:56:24 +01:00
return sdhci_set_clock ( host , clock ) ;
2015-12-22 19:41:00 +01:00
host_clk = tegra_host - > ddr_signaling ? clock * 2 : clock ;
clk_set_rate ( pltfm_host - > clk , host_clk ) ;
host - > max_clk = clk_get_rate ( pltfm_host - > clk ) ;
2016-02-29 21:56:25 +01:00
sdhci_set_clock ( host , clock ) ;
if ( tegra_host - > pad_calib_required ) {
tegra_sdhci_pad_autocalib ( host ) ;
tegra_host - > pad_calib_required = false ;
}
2015-12-22 19:41:00 +01:00
}
static void tegra_sdhci_set_uhs_signaling ( struct sdhci_host * host ,
unsigned timing )
{
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2016-02-16 21:08:29 +08:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2015-12-22 19:41:00 +01:00
if ( timing = = MMC_TIMING_UHS_DDR50 )
tegra_host - > ddr_signaling = true ;
return sdhci_set_uhs_signaling ( host , timing ) ;
}
static unsigned int tegra_sdhci_get_max_clock ( struct sdhci_host * host )
{
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
/*
* DDR modes require the host to run at double the card frequency , so
* the maximum rate we can support is half of the module input clock .
*/
return clk_round_rate ( pltfm_host - > clk , UINT_MAX ) / 2 ;
}
2015-12-22 19:41:02 +01:00
static void tegra_sdhci_set_tap ( struct sdhci_host * host , unsigned int tap )
{
u32 reg ;
reg = sdhci_readl ( host , SDHCI_TEGRA_VENDOR_CLOCK_CTRL ) ;
reg & = ~ SDHCI_CLOCK_CTRL_TAP_MASK ;
reg | = tap < < SDHCI_CLOCK_CTRL_TAP_SHIFT ;
sdhci_writel ( host , reg , SDHCI_TEGRA_VENDOR_CLOCK_CTRL ) ;
}
static int tegra_sdhci_execute_tuning ( struct sdhci_host * host , u32 opcode )
{
unsigned int min , max ;
/*
* Start search for minimum tap value at 10 , as smaller values are
* may wrongly be reported as working but fail at higher speeds ,
* according to the TRM .
*/
min = 10 ;
while ( min < 255 ) {
tegra_sdhci_set_tap ( host , min ) ;
if ( ! mmc_send_tuning ( host - > mmc , opcode , NULL ) )
break ;
min + + ;
}
/* Find the maximum tap value that still passes. */
max = min + 1 ;
while ( max < 255 ) {
tegra_sdhci_set_tap ( host , max ) ;
if ( mmc_send_tuning ( host - > mmc , opcode , NULL ) ) {
max - - ;
break ;
}
max + + ;
}
/* The TRM states the ideal tap value is at 75% in the passing range. */
tegra_sdhci_set_tap ( host , min + ( ( max - min ) * 3 / 4 ) ) ;
return mmc_send_tuning ( host - > mmc , opcode , NULL ) ;
}
2016-02-29 21:56:25 +01:00
static void tegra_sdhci_voltage_switch ( struct sdhci_host * host )
{
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
const struct sdhci_tegra_soc_data * soc_data = tegra_host - > soc_data ;
if ( soc_data - > nvquirks & NVQUIRK_HAS_PADCALIB )
tegra_host - > pad_calib_required = true ;
}
2013-03-13 19:26:05 +01:00
static const struct sdhci_ops tegra_sdhci_ops = {
2011-05-27 23:48:12 +08:00
. get_ro = tegra_sdhci_get_ro ,
. read_w = tegra_sdhci_readw ,
. write_l = tegra_sdhci_writel ,
2015-12-22 19:41:00 +01:00
. set_clock = tegra_sdhci_set_clock ,
2017-08-14 22:00:24 +02:00
. set_bus_width = sdhci_set_bus_width ,
2014-04-25 12:57:12 +01:00
. reset = tegra_sdhci_reset ,
2015-12-22 19:41:02 +01:00
. platform_execute_tuning = tegra_sdhci_execute_tuning ,
2015-12-22 19:41:00 +01:00
. set_uhs_signaling = tegra_sdhci_set_uhs_signaling ,
2016-02-29 21:56:25 +01:00
. voltage_switch = tegra_sdhci_voltage_switch ,
2015-12-22 19:41:00 +01:00
. get_max_clock = tegra_sdhci_get_max_clock ,
2011-05-27 23:48:12 +08:00
} ;
2013-03-13 19:26:03 +01:00
static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
2012-02-01 16:30:55 -07:00
. quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
2014-05-22 08:55:36 -07:00
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
2012-02-01 16:30:55 -07:00
. ops = & tegra_sdhci_ops ,
} ;
2015-11-16 10:27:14 +01:00
static const struct sdhci_tegra_soc_data soc_data_tegra20 = {
2012-02-01 16:30:55 -07:00
. pdata = & sdhci_tegra20_pdata ,
. nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
NVQUIRK_ENABLE_BLOCK_GAP_DET ,
} ;
2013-03-13 19:26:03 +01:00
static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
2011-05-27 23:48:12 +08:00
. quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
2012-02-01 16:30:55 -07:00
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
2011-05-27 23:48:12 +08:00
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
2014-05-22 08:55:36 -07:00
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
2015-12-22 19:41:00 +01:00
. quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN ,
2011-05-27 23:48:12 +08:00
. ops = & tegra_sdhci_ops ,
} ;
2011-01-01 23:52:56 -05:00
2015-11-16 10:27:14 +01:00
static const struct sdhci_tegra_soc_data soc_data_tegra30 = {
2012-02-01 16:30:55 -07:00
. pdata = & sdhci_tegra30_pdata ,
2014-05-22 08:55:35 -07:00
. nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 |
2015-12-22 19:41:03 +01:00
NVQUIRK_ENABLE_SDR50 |
2016-02-29 21:56:25 +01:00
NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_PADCALIB ,
2012-02-01 16:30:55 -07:00
} ;
2015-02-11 12:55:51 -05:00
static const struct sdhci_ops tegra114_sdhci_ops = {
. get_ro = tegra_sdhci_get_ro ,
. read_w = tegra_sdhci_readw ,
. write_w = tegra_sdhci_writew ,
. write_l = tegra_sdhci_writel ,
2015-12-22 19:41:00 +01:00
. set_clock = tegra_sdhci_set_clock ,
2017-08-14 22:00:24 +02:00
. set_bus_width = sdhci_set_bus_width ,
2015-02-11 12:55:51 -05:00
. reset = tegra_sdhci_reset ,
2015-12-22 19:41:02 +01:00
. platform_execute_tuning = tegra_sdhci_execute_tuning ,
2015-12-22 19:41:00 +01:00
. set_uhs_signaling = tegra_sdhci_set_uhs_signaling ,
2016-02-29 21:56:25 +01:00
. voltage_switch = tegra_sdhci_voltage_switch ,
2015-12-22 19:41:00 +01:00
. get_max_clock = tegra_sdhci_get_max_clock ,
2015-02-11 12:55:51 -05:00
} ;
2013-03-13 19:26:03 +01:00
static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
2013-02-20 13:35:17 -05:00
. quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
2014-05-22 08:55:36 -07:00
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
2015-12-22 19:41:00 +01:00
. quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN ,
2015-02-11 12:55:51 -05:00
. ops = & tegra114_sdhci_ops ,
2013-02-20 13:35:17 -05:00
} ;
2015-11-16 10:27:14 +01:00
static const struct sdhci_tegra_soc_data soc_data_tegra114 = {
2013-02-20 13:35:17 -05:00
. pdata = & sdhci_tegra114_pdata ,
2016-02-26 09:34:17 +00:00
} ;
2016-09-01 13:46:17 +02:00
static const struct sdhci_pltfm_data sdhci_tegra124_pdata = {
. quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
. quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
/*
* The TRM states that the SD / MMC controller found on
* Tegra124 can address 34 bits ( the maximum supported by
* the Tegra memory controller ) , but tests show that DMA
* to or from above 4 GiB doesn ' t work . This is possibly
* caused by missing programming , though it ' s not obvious
* what sequence is required . Mark 64 - bit DMA broken for
* now to fix this for existing users ( e . g . Nyan boards ) .
*/
SDHCI_QUIRK2_BROKEN_64_BIT_DMA ,
. ops = & tegra114_sdhci_ops ,
} ;
static const struct sdhci_tegra_soc_data soc_data_tegra124 = {
. pdata = & sdhci_tegra124_pdata ,
} ;
2015-11-16 10:27:15 +01:00
static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
. quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
2015-12-22 19:41:00 +01:00
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
. quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN ,
2015-11-16 10:27:15 +01:00
. ops = & tegra114_sdhci_ops ,
} ;
static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
. pdata = & sdhci_tegra210_pdata ,
} ;
2017-03-08 20:00:40 +01:00
static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
. quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
2017-09-08 12:48:33 -07:00
. quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
/* SDHCI controllers on Tegra186 support 40-bit addressing.
* IOVA addresses are 48 - bit wide on Tegra186 .
* With 64 - bit dma mask used for SDHCI , accesses can
* be broken . Disable 64 - bit dma , which would fall back
* to 32 - bit dma mask . Ideally 40 - bit dma mask would work ,
* But it is not supported as of now .
*/
SDHCI_QUIRK2_BROKEN_64_BIT_DMA ,
2017-03-08 20:00:40 +01:00
. ops = & tegra114_sdhci_ops ,
} ;
static const struct sdhci_tegra_soc_data soc_data_tegra186 = {
. pdata = & sdhci_tegra186_pdata ,
} ;
2012-11-19 13:24:22 -05:00
static const struct of_device_id sdhci_tegra_dt_match [ ] = {
2017-03-08 20:00:40 +01:00
{ . compatible = " nvidia,tegra186-sdhci " , . data = & soc_data_tegra186 } ,
2015-11-16 10:27:15 +01:00
{ . compatible = " nvidia,tegra210-sdhci " , . data = & soc_data_tegra210 } ,
2016-09-01 13:46:17 +02:00
{ . compatible = " nvidia,tegra124-sdhci " , . data = & soc_data_tegra124 } ,
2013-02-20 13:35:17 -05:00
{ . compatible = " nvidia,tegra114-sdhci " , . data = & soc_data_tegra114 } ,
2012-02-01 16:30:55 -07:00
{ . compatible = " nvidia,tegra30-sdhci " , . data = & soc_data_tegra30 } ,
{ . compatible = " nvidia,tegra20-sdhci " , . data = & soc_data_tegra20 } ,
2011-08-23 12:15:33 -06:00
{ }
} ;
2013-04-23 15:05:57 -04:00
MODULE_DEVICE_TABLE ( of , sdhci_tegra_dt_match ) ;
2011-08-23 12:15:33 -06:00
2012-11-19 13:23:06 -05:00
static int sdhci_tegra_probe ( struct platform_device * pdev )
2011-01-01 23:52:56 -05:00
{
2012-02-01 16:30:55 -07:00
const struct of_device_id * match ;
const struct sdhci_tegra_soc_data * soc_data ;
struct sdhci_host * host ;
2011-05-27 23:48:12 +08:00
struct sdhci_pltfm_host * pltfm_host ;
2012-02-01 16:30:55 -07:00
struct sdhci_tegra * tegra_host ;
2011-01-01 23:52:56 -05:00
struct clk * clk ;
int rc ;
2012-02-01 16:30:55 -07:00
match = of_match_device ( sdhci_tegra_dt_match , & pdev - > dev ) ;
2012-08-17 15:04:31 +08:00
if ( ! match )
return - EINVAL ;
soc_data = match - > data ;
2012-02-01 16:30:55 -07:00
2016-02-16 21:08:29 +08:00
host = sdhci_pltfm_init ( pdev , soc_data - > pdata , sizeof ( * tegra_host ) ) ;
2011-05-27 23:48:12 +08:00
if ( IS_ERR ( host ) )
return PTR_ERR ( host ) ;
pltfm_host = sdhci_priv ( host ) ;
2016-02-16 21:08:29 +08:00
tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2015-12-22 19:41:00 +01:00
tegra_host - > ddr_signaling = false ;
2016-02-29 21:56:25 +01:00
tegra_host - > pad_calib_required = false ;
2012-02-01 16:30:55 -07:00
tegra_host - > soc_data = soc_data ;
2011-08-23 12:15:33 -06:00
2015-03-30 23:39:25 +02:00
rc = mmc_of_parse ( host - > mmc ) ;
2013-06-09 22:14:16 +02:00
if ( rc )
goto err_parse_dt ;
2013-02-15 15:07:19 -07:00
2015-12-22 19:41:03 +01:00
if ( tegra_host - > soc_data - > nvquirks & NVQUIRK_ENABLE_DDR50 )
2015-12-22 19:41:02 +01:00
host - > mmc - > caps | = MMC_CAP_1_8V_DDR ;
2015-03-30 23:39:25 +02:00
tegra_host - > power_gpio = devm_gpiod_get_optional ( & pdev - > dev , " power " ,
GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( tegra_host - > power_gpio ) ) {
rc = PTR_ERR ( tegra_host - > power_gpio ) ;
goto err_power_req ;
2011-01-01 23:52:56 -05:00
}
2015-02-27 15:47:27 +08:00
clk = devm_clk_get ( mmc_dev ( host - > mmc ) , NULL ) ;
2011-01-01 23:52:56 -05:00
if ( IS_ERR ( clk ) ) {
dev_err ( mmc_dev ( host - > mmc ) , " clk err \n " ) ;
rc = PTR_ERR ( clk ) ;
2011-05-27 23:48:12 +08:00
goto err_clk_get ;
2011-01-01 23:52:56 -05:00
}
2012-06-05 09:59:37 +05:30
clk_prepare_enable ( clk ) ;
2011-01-01 23:52:56 -05:00
pltfm_host - > clk = clk ;
2017-07-19 17:25:45 +02:00
tegra_host - > rst = devm_reset_control_get_exclusive ( & pdev - > dev ,
" sdhci " ) ;
2017-03-08 20:00:39 +01:00
if ( IS_ERR ( tegra_host - > rst ) ) {
rc = PTR_ERR ( tegra_host - > rst ) ;
dev_err ( & pdev - > dev , " failed to get reset control: %d \n " , rc ) ;
goto err_rst_get ;
}
rc = reset_control_assert ( tegra_host - > rst ) ;
if ( rc )
goto err_rst_get ;
usleep_range ( 2000 , 4000 ) ;
rc = reset_control_deassert ( tegra_host - > rst ) ;
if ( rc )
goto err_rst_get ;
usleep_range ( 2000 , 4000 ) ;
2011-05-27 23:48:12 +08:00
rc = sdhci_add_host ( host ) ;
if ( rc )
goto err_add_host ;
2011-01-01 23:52:56 -05:00
return 0 ;
2011-05-27 23:48:12 +08:00
err_add_host :
2017-03-08 20:00:39 +01:00
reset_control_assert ( tegra_host - > rst ) ;
err_rst_get :
2012-06-05 09:59:37 +05:30
clk_disable_unprepare ( pltfm_host - > clk ) ;
2011-05-27 23:48:12 +08:00
err_clk_get :
err_power_req :
2013-06-09 22:14:16 +02:00
err_parse_dt :
2011-05-27 23:48:12 +08:00
sdhci_pltfm_free ( pdev ) ;
2011-01-01 23:52:56 -05:00
return rc ;
}
2017-03-08 20:00:39 +01:00
static int sdhci_tegra_remove ( struct platform_device * pdev )
{
struct sdhci_host * host = platform_get_drvdata ( pdev ) ;
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
sdhci_remove_host ( host , 0 ) ;
reset_control_assert ( tegra_host - > rst ) ;
usleep_range ( 2000 , 4000 ) ;
clk_disable_unprepare ( pltfm_host - > clk ) ;
sdhci_pltfm_free ( pdev ) ;
return 0 ;
}
2011-05-27 23:48:12 +08:00
static struct platform_driver sdhci_tegra_driver = {
. driver = {
. name = " sdhci-tegra " ,
2011-08-23 12:15:33 -06:00
. of_match_table = sdhci_tegra_dt_match ,
2016-07-27 13:07:21 +02:00
. pm = & sdhci_pltfm_pmops ,
2011-05-27 23:48:12 +08:00
} ,
. probe = sdhci_tegra_probe ,
2017-03-08 20:00:39 +01:00
. remove = sdhci_tegra_remove ,
2011-01-01 23:52:56 -05:00
} ;
2011-11-26 12:55:43 +08:00
module_platform_driver ( sdhci_tegra_driver ) ;
2011-05-27 23:48:12 +08:00
MODULE_DESCRIPTION ( " SDHCI driver for Tegra " ) ;
2012-02-01 16:30:55 -07:00
MODULE_AUTHOR ( " Google, Inc. " ) ;
2011-05-27 23:48:12 +08:00
MODULE_LICENSE ( " GPL v2 " ) ;