2011-01-02 07:52:56 +03: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 23:56:25 +03:00
# include <linux/delay.h>
2011-01-02 07:52:56 +03:00
# include <linux/err.h>
2011-07-03 23:15:51 +04:00
# include <linux/module.h>
2011-01-02 07:52:56 +03:00
# include <linux/init.h>
# include <linux/platform_device.h>
# include <linux/clk.h>
# include <linux/io.h>
2011-08-30 23:17:16 +04:00
# include <linux/of.h>
2012-02-02 03:30:55 +04:00
# include <linux/of_device.h>
2017-03-08 22:00:39 +03:00
# include <linux/reset.h>
2011-01-02 07:52:56 +03:00
# include <linux/mmc/card.h>
# include <linux/mmc/host.h>
2015-12-22 21:41:02 +03:00
# include <linux/mmc/mmc.h>
2013-03-12 00:44:11 +04:00
# include <linux/mmc/slot-gpio.h>
2015-03-31 00:39:25 +03:00
# include <linux/gpio/consumer.h>
2011-01-02 07:52:56 +03:00
# include "sdhci-pltfm.h"
2012-04-18 17:18:02 +04:00
/* Tegra SDHOST controller vendor register definitions */
2015-12-22 21:41:01 +03:00
# define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100
2015-12-22 21:41:02 +03: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 21:41:01 +03:00
# define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3)
# define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2)
2012-04-18 17:18:02 +04:00
# define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120
2014-05-22 19:55:35 +04:00
# define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8
# define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10
2012-04-18 17:18:02 +04:00
# define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20
2014-05-22 19:55:35 +04:00
# define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200
2012-04-18 17:18:02 +04:00
2016-02-29 23:56:25 +03:00
# define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4
# define SDHCI_AUTO_CAL_START BIT(31)
# define SDHCI_AUTO_CAL_ENABLE BIT(29)
2012-02-02 03:30:55 +04:00
# define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
# define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
2012-04-18 17:18:02 +04:00
# define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
2015-12-22 21:41:03 +03:00
# define NVQUIRK_ENABLE_SDR50 BIT(3)
# define NVQUIRK_ENABLE_SDR104 BIT(4)
# define NVQUIRK_ENABLE_DDR50 BIT(5)
2016-02-29 23:56:25 +03:00
# define NVQUIRK_HAS_PADCALIB BIT(6)
2012-02-02 03:30:55 +04:00
struct sdhci_tegra_soc_data {
2013-03-13 22:26:03 +04:00
const struct sdhci_pltfm_data * pdata ;
2012-02-02 03:30:55 +04:00
u32 nvquirks ;
} ;
struct sdhci_tegra {
const struct sdhci_tegra_soc_data * soc_data ;
2015-03-31 00:39:25 +03:00
struct gpio_desc * power_gpio ;
2015-12-22 21:41:00 +03:00
bool ddr_signaling ;
2016-02-29 23:56:25 +03:00
bool pad_calib_required ;
2017-03-08 22:00:39 +03:00
struct reset_control * rst ;
2012-02-02 03:30:55 +04:00
} ;
2011-01-02 07:52:56 +03:00
static u16 tegra_sdhci_readw ( struct sdhci_host * host , int reg )
{
2012-02-02 03:30:55 +04:00
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2016-02-16 16:08:29 +03:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2012-02-02 03:30:55 +04: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-02 07:52:56 +03:00
/* Erratum: Version register is invalid in HW. */
return SDHCI_SPEC_200 ;
}
return readw ( host - > ioaddr + reg ) ;
}
2015-01-28 19:45:16 +03: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 20:55:51 +03: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 19:45:16 +03:00
}
writew ( val , host - > ioaddr + reg ) ;
}
2011-01-02 07:52:56 +03:00
static void tegra_sdhci_writel ( struct sdhci_host * host , u32 val , int reg )
{
2012-02-02 03:30:55 +04:00
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2016-02-16 16:08:29 +03:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2012-02-02 03:30:55 +04:00
const struct sdhci_tegra_soc_data * soc_data = tegra_host - > soc_data ;
2011-01-02 07:52:56 +03: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-02 03:30:55 +04:00
if ( unlikely ( ( soc_data - > nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET ) & &
( reg = = SDHCI_INT_ENABLE ) ) ) {
2011-01-02 07:52:56 +03: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-02 03:30:55 +04:00
static unsigned int tegra_sdhci_get_ro ( struct sdhci_host * host )
2011-01-02 07:52:56 +03:00
{
2013-03-12 00:44:11 +04:00
return mmc_gpio_get_ro ( host - > mmc ) ;
2011-01-02 07:52:56 +03:00
}
2014-04-25 15:57:12 +04:00
static void tegra_sdhci_reset ( struct sdhci_host * host , u8 mask )
2012-04-18 17:18:02 +04:00
{
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2016-02-16 16:08:29 +03:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2012-04-18 17:18:02 +04:00
const struct sdhci_tegra_soc_data * soc_data = tegra_host - > soc_data ;
2015-12-22 21:41:01 +03:00
u32 misc_ctrl , clk_ctrl ;
2012-04-18 17:18:02 +04:00
2014-04-25 15:57:12 +04:00
sdhci_reset ( host , mask ) ;
2012-04-18 17:18:02 +04:00
if ( ! ( mask & SDHCI_RESET_ALL ) )
return ;
2015-12-22 21:41:04 +03:00
misc_ctrl = sdhci_readl ( host , SDHCI_TEGRA_VENDOR_MISC_CTRL ) ;
2015-12-22 21:41:01 +03:00
clk_ctrl = sdhci_readl ( host , SDHCI_TEGRA_VENDOR_CLOCK_CTRL ) ;
2016-07-12 16:53:37 +03: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 21:41:01 +03:00
clk_ctrl & = ~ SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE ;
2016-07-12 16:53:37 +03: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 21:41:01 +03:00
sdhci_writel ( host , clk_ctrl , SDHCI_TEGRA_VENDOR_CLOCK_CTRL ) ;
2016-02-29 23:56:25 +03:00
if ( soc_data - > nvquirks & NVQUIRK_HAS_PADCALIB )
tegra_host - > pad_calib_required = true ;
2015-12-22 21:41:00 +03:00
tegra_host - > ddr_signaling = false ;
2012-04-18 17:18:02 +04:00
}
2014-04-25 15:57:07 +04:00
static void tegra_sdhci_set_bus_width ( struct sdhci_host * host , int bus_width )
2011-01-02 07:52:56 +03:00
{
u32 ctrl ;
ctrl = sdhci_readb ( host , SDHCI_HOST_CONTROL ) ;
2013-03-12 00:44:11 +04:00
if ( ( host - > mmc - > caps & MMC_CAP_8_BIT_DATA ) & &
( bus_width = = MMC_BUS_WIDTH_8 ) ) {
2011-01-02 07:52:56 +03:00
ctrl & = ~ SDHCI_CTRL_4BITBUS ;
ctrl | = SDHCI_CTRL_8BITBUS ;
} else {
ctrl & = ~ SDHCI_CTRL_8BITBUS ;
if ( bus_width = = MMC_BUS_WIDTH_4 )
ctrl | = SDHCI_CTRL_4BITBUS ;
else
ctrl & = ~ SDHCI_CTRL_4BITBUS ;
}
sdhci_writeb ( host , ctrl , SDHCI_HOST_CONTROL ) ;
}
2016-02-29 23:56:25 +03: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 21:41:00 +03: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 16:08:29 +03:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2015-12-22 21:41:00 +03:00
unsigned long host_clk ;
if ( ! clock )
2016-02-29 23:56:24 +03:00
return sdhci_set_clock ( host , clock ) ;
2015-12-22 21:41:00 +03: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 23:56:25 +03: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 21:41:00 +03: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 16:08:29 +03:00
struct sdhci_tegra * tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2015-12-22 21:41:00 +03: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 21:41:02 +03: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 23:56:25 +03: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 22:26:05 +04:00
static const struct sdhci_ops tegra_sdhci_ops = {
2011-05-27 19:48:12 +04:00
. get_ro = tegra_sdhci_get_ro ,
. read_w = tegra_sdhci_readw ,
. write_l = tegra_sdhci_writel ,
2015-12-22 21:41:00 +03:00
. set_clock = tegra_sdhci_set_clock ,
2014-04-25 15:57:07 +04:00
. set_bus_width = tegra_sdhci_set_bus_width ,
2014-04-25 15:57:12 +04:00
. reset = tegra_sdhci_reset ,
2015-12-22 21:41:02 +03:00
. platform_execute_tuning = tegra_sdhci_execute_tuning ,
2015-12-22 21:41:00 +03:00
. set_uhs_signaling = tegra_sdhci_set_uhs_signaling ,
2016-02-29 23:56:25 +03:00
. voltage_switch = tegra_sdhci_voltage_switch ,
2015-12-22 21:41:00 +03:00
. get_max_clock = tegra_sdhci_get_max_clock ,
2011-05-27 19:48:12 +04:00
} ;
2013-03-13 22:26:03 +04:00
static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
2012-02-02 03:30:55 +04:00
. quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
2014-05-22 19:55:36 +04:00
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
2012-02-02 03:30:55 +04:00
. ops = & tegra_sdhci_ops ,
} ;
2015-11-16 12:27:14 +03:00
static const struct sdhci_tegra_soc_data soc_data_tegra20 = {
2012-02-02 03:30:55 +04:00
. pdata = & sdhci_tegra20_pdata ,
. nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
NVQUIRK_ENABLE_BLOCK_GAP_DET ,
} ;
2013-03-13 22:26:03 +04:00
static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
2011-05-27 19:48:12 +04:00
. quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
2012-02-02 03:30:55 +04:00
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
2011-05-27 19:48:12 +04:00
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
2014-05-22 19:55:36 +04:00
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
2015-12-22 21:41:00 +03:00
. quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN ,
2011-05-27 19:48:12 +04:00
. ops = & tegra_sdhci_ops ,
} ;
2011-01-02 07:52:56 +03:00
2015-11-16 12:27:14 +03:00
static const struct sdhci_tegra_soc_data soc_data_tegra30 = {
2012-02-02 03:30:55 +04:00
. pdata = & sdhci_tegra30_pdata ,
2014-05-22 19:55:35 +04:00
. nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 |
2015-12-22 21:41:03 +03:00
NVQUIRK_ENABLE_SDR50 |
2016-02-29 23:56:25 +03:00
NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_PADCALIB ,
2012-02-02 03:30:55 +04:00
} ;
2015-02-11 20:55:51 +03: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 21:41:00 +03:00
. set_clock = tegra_sdhci_set_clock ,
2015-02-11 20:55:51 +03:00
. set_bus_width = tegra_sdhci_set_bus_width ,
. reset = tegra_sdhci_reset ,
2015-12-22 21:41:02 +03:00
. platform_execute_tuning = tegra_sdhci_execute_tuning ,
2015-12-22 21:41:00 +03:00
. set_uhs_signaling = tegra_sdhci_set_uhs_signaling ,
2016-02-29 23:56:25 +03:00
. voltage_switch = tegra_sdhci_voltage_switch ,
2015-12-22 21:41:00 +03:00
. get_max_clock = tegra_sdhci_get_max_clock ,
2015-02-11 20:55:51 +03:00
} ;
2013-03-13 22:26:03 +04:00
static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
2013-02-20 22:35:17 +04: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 19:55:36 +04:00
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
2015-12-22 21:41:00 +03:00
. quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN ,
2015-02-11 20:55:51 +03:00
. ops = & tegra114_sdhci_ops ,
2013-02-20 22:35:17 +04:00
} ;
2015-11-16 12:27:14 +03:00
static const struct sdhci_tegra_soc_data soc_data_tegra114 = {
2013-02-20 22:35:17 +04:00
. pdata = & sdhci_tegra114_pdata ,
2016-02-26 12:34:17 +03:00
} ;
2016-09-01 14:46:17 +03: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 12:27:15 +03: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 21:41:00 +03:00
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
. quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN ,
2015-11-16 12:27:15 +03:00
. ops = & tegra114_sdhci_ops ,
} ;
static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
. pdata = & sdhci_tegra210_pdata ,
} ;
2012-11-19 22:24:22 +04:00
static const struct of_device_id sdhci_tegra_dt_match [ ] = {
2015-11-16 12:27:15 +03:00
{ . compatible = " nvidia,tegra210-sdhci " , . data = & soc_data_tegra210 } ,
2016-09-01 14:46:17 +03:00
{ . compatible = " nvidia,tegra124-sdhci " , . data = & soc_data_tegra124 } ,
2013-02-20 22:35:17 +04:00
{ . compatible = " nvidia,tegra114-sdhci " , . data = & soc_data_tegra114 } ,
2012-02-02 03:30:55 +04:00
{ . compatible = " nvidia,tegra30-sdhci " , . data = & soc_data_tegra30 } ,
{ . compatible = " nvidia,tegra20-sdhci " , . data = & soc_data_tegra20 } ,
2011-08-23 22:15:33 +04:00
{ }
} ;
2013-04-23 23:05:57 +04:00
MODULE_DEVICE_TABLE ( of , sdhci_tegra_dt_match ) ;
2011-08-23 22:15:33 +04:00
2012-11-19 22:23:06 +04:00
static int sdhci_tegra_probe ( struct platform_device * pdev )
2011-01-02 07:52:56 +03:00
{
2012-02-02 03:30:55 +04:00
const struct of_device_id * match ;
const struct sdhci_tegra_soc_data * soc_data ;
struct sdhci_host * host ;
2011-05-27 19:48:12 +04:00
struct sdhci_pltfm_host * pltfm_host ;
2012-02-02 03:30:55 +04:00
struct sdhci_tegra * tegra_host ;
2011-01-02 07:52:56 +03:00
struct clk * clk ;
int rc ;
2012-02-02 03:30:55 +04:00
match = of_match_device ( sdhci_tegra_dt_match , & pdev - > dev ) ;
2012-08-17 11:04:31 +04:00
if ( ! match )
return - EINVAL ;
soc_data = match - > data ;
2012-02-02 03:30:55 +04:00
2016-02-16 16:08:29 +03:00
host = sdhci_pltfm_init ( pdev , soc_data - > pdata , sizeof ( * tegra_host ) ) ;
2011-05-27 19:48:12 +04:00
if ( IS_ERR ( host ) )
return PTR_ERR ( host ) ;
pltfm_host = sdhci_priv ( host ) ;
2016-02-16 16:08:29 +03:00
tegra_host = sdhci_pltfm_priv ( pltfm_host ) ;
2015-12-22 21:41:00 +03:00
tegra_host - > ddr_signaling = false ;
2016-02-29 23:56:25 +03:00
tegra_host - > pad_calib_required = false ;
2012-02-02 03:30:55 +04:00
tegra_host - > soc_data = soc_data ;
2011-08-23 22:15:33 +04:00
2015-03-31 00:39:25 +03:00
rc = mmc_of_parse ( host - > mmc ) ;
2013-06-10 00:14:16 +04:00
if ( rc )
goto err_parse_dt ;
2013-02-16 02:07:19 +04:00
2015-12-22 21:41:03 +03:00
if ( tegra_host - > soc_data - > nvquirks & NVQUIRK_ENABLE_DDR50 )
2015-12-22 21:41:02 +03:00
host - > mmc - > caps | = MMC_CAP_1_8V_DDR ;
2015-03-31 00:39:25 +03: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-02 07:52:56 +03:00
}
2015-02-27 10:47:27 +03:00
clk = devm_clk_get ( mmc_dev ( host - > mmc ) , NULL ) ;
2011-01-02 07:52:56 +03:00
if ( IS_ERR ( clk ) ) {
dev_err ( mmc_dev ( host - > mmc ) , " clk err \n " ) ;
rc = PTR_ERR ( clk ) ;
2011-05-27 19:48:12 +04:00
goto err_clk_get ;
2011-01-02 07:52:56 +03:00
}
2012-06-05 08:29:37 +04:00
clk_prepare_enable ( clk ) ;
2011-01-02 07:52:56 +03:00
pltfm_host - > clk = clk ;
2017-03-08 22:00:39 +03:00
tegra_host - > rst = devm_reset_control_get ( & pdev - > dev , " sdhci " ) ;
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 19:48:12 +04:00
rc = sdhci_add_host ( host ) ;
if ( rc )
goto err_add_host ;
2011-01-02 07:52:56 +03:00
return 0 ;
2011-05-27 19:48:12 +04:00
err_add_host :
2017-03-08 22:00:39 +03:00
reset_control_assert ( tegra_host - > rst ) ;
err_rst_get :
2012-06-05 08:29:37 +04:00
clk_disable_unprepare ( pltfm_host - > clk ) ;
2011-05-27 19:48:12 +04:00
err_clk_get :
err_power_req :
2013-06-10 00:14:16 +04:00
err_parse_dt :
2011-05-27 19:48:12 +04:00
sdhci_pltfm_free ( pdev ) ;
2011-01-02 07:52:56 +03:00
return rc ;
}
2017-03-08 22:00:39 +03: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 19:48:12 +04:00
static struct platform_driver sdhci_tegra_driver = {
. driver = {
. name = " sdhci-tegra " ,
2011-08-23 22:15:33 +04:00
. of_match_table = sdhci_tegra_dt_match ,
2016-07-27 14:07:21 +03:00
. pm = & sdhci_pltfm_pmops ,
2011-05-27 19:48:12 +04:00
} ,
. probe = sdhci_tegra_probe ,
2017-03-08 22:00:39 +03:00
. remove = sdhci_tegra_remove ,
2011-01-02 07:52:56 +03:00
} ;
2011-11-26 08:55:43 +04:00
module_platform_driver ( sdhci_tegra_driver ) ;
2011-05-27 19:48:12 +04:00
MODULE_DESCRIPTION ( " SDHCI driver for Tegra " ) ;
2012-02-02 03:30:55 +04:00
MODULE_AUTHOR ( " Google, Inc. " ) ;
2011-05-27 19:48:12 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;