2013-06-21 01:26:37 +04:00
/*
* Copyright ( C ) 2013 Broadcom Corporation
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/highmem.h>
# include <linux/platform_device.h>
# include <linux/mmc/host.h>
# include <linux/io.h>
# include <linux/clk.h>
# include <linux/regulator/consumer.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/mmc/slot-gpio.h>
# include "sdhci-pltfm.h"
# include "sdhci.h"
# define SDHCI_SOFT_RESET 0x01000000
# define KONA_SDHOST_CORECTRL 0x8000
# define KONA_SDHOST_CD_PINCTRL 0x00000008
# define KONA_SDHOST_STOP_HCLK 0x00000004
# define KONA_SDHOST_RESET 0x00000002
# define KONA_SDHOST_EN 0x00000001
# define KONA_SDHOST_CORESTAT 0x8004
# define KONA_SDHOST_WP 0x00000002
# define KONA_SDHOST_CD_SW 0x00000001
# define KONA_SDHOST_COREIMR 0x8008
# define KONA_SDHOST_IP 0x00000001
# define KONA_SDHOST_COREISR 0x800C
# define KONA_SDHOST_COREIMSR 0x8010
# define KONA_SDHOST_COREDBG1 0x8014
# define KONA_SDHOST_COREGPO_MASK 0x8018
# define SD_DETECT_GPIO_DEBOUNCE_128MS 128
# define KONA_MMC_AUTOSUSPEND_DELAY (50)
struct sdhci_bcm_kona_dev {
struct mutex write_lock ; /* protect back to back writes */
} ;
static int sdhci_bcm_kona_sd_reset ( struct sdhci_host * host )
{
unsigned int val ;
unsigned long timeout ;
/* This timeout should be sufficent for core to reset */
timeout = jiffies + msecs_to_jiffies ( 100 ) ;
/* reset the host using the top level reset */
val = sdhci_readl ( host , KONA_SDHOST_CORECTRL ) ;
val | = KONA_SDHOST_RESET ;
sdhci_writel ( host , val , KONA_SDHOST_CORECTRL ) ;
while ( ! ( sdhci_readl ( host , KONA_SDHOST_CORECTRL ) & KONA_SDHOST_RESET ) ) {
if ( time_is_before_jiffies ( timeout ) ) {
pr_err ( " Error: sd host is stuck in reset!!! \n " ) ;
return - EFAULT ;
}
}
/* bring the host out of reset */
val = sdhci_readl ( host , KONA_SDHOST_CORECTRL ) ;
val & = ~ KONA_SDHOST_RESET ;
/*
* Back - to - Back register write needs a delay of 1 ms at bootup ( min 10u S )
* Back - to - Back writes to same register needs delay when SD bus clock
* is very low w . r . t AHB clock , mainly during boot - time and during card
* insert - removal .
*/
usleep_range ( 1000 , 5000 ) ;
sdhci_writel ( host , val , KONA_SDHOST_CORECTRL ) ;
return 0 ;
}
static void sdhci_bcm_kona_sd_init ( struct sdhci_host * host )
{
unsigned int val ;
/* enable the interrupt from the IP core */
val = sdhci_readl ( host , KONA_SDHOST_COREIMR ) ;
val | = KONA_SDHOST_IP ;
sdhci_writel ( host , val , KONA_SDHOST_COREIMR ) ;
/* Enable the AHB clock gating module to the host */
val = sdhci_readl ( host , KONA_SDHOST_CORECTRL ) ;
val | = KONA_SDHOST_EN ;
/*
* Back - to - Back register write needs a delay of 1 ms at bootup ( min 10u S )
* Back - to - Back writes to same register needs delay when SD bus clock
* is very low w . r . t AHB clock , mainly during boot - time and during card
* insert - removal .
*/
usleep_range ( 1000 , 5000 ) ;
sdhci_writel ( host , val , KONA_SDHOST_CORECTRL ) ;
}
/*
* Software emulation of the SD card insertion / removal . Set insert = 1 for insert
* and insert = 0 for removal . The card detection is done by GPIO . For Broadcom
* IP to function properly the bit 0 of CORESTAT register needs to be set / reset
* to generate the CD IRQ handled in sdhci . c which schedules card_tasklet .
*/
static int sdhci_bcm_kona_sd_card_emulate ( struct sdhci_host * host , int insert )
{
struct sdhci_pltfm_host * pltfm_priv = sdhci_priv ( host ) ;
struct sdhci_bcm_kona_dev * kona_dev = sdhci_pltfm_priv ( pltfm_priv ) ;
u32 val ;
/*
* Back - to - Back register write needs a delay of min 10u S .
* Back - to - Back writes to same register needs delay when SD bus clock
* is very low w . r . t AHB clock , mainly during boot - time and during card
* insert - removal .
* We keep 20u S
*/
mutex_lock ( & kona_dev - > write_lock ) ;
udelay ( 20 ) ;
val = sdhci_readl ( host , KONA_SDHOST_CORESTAT ) ;
if ( insert ) {
int ret ;
ret = mmc_gpio_get_ro ( host - > mmc ) ;
if ( ret > = 0 )
val = ( val & ~ KONA_SDHOST_WP ) |
( ( ret ) ? KONA_SDHOST_WP : 0 ) ;
val | = KONA_SDHOST_CD_SW ;
sdhci_writel ( host , val , KONA_SDHOST_CORESTAT ) ;
} else {
val & = ~ KONA_SDHOST_CD_SW ;
sdhci_writel ( host , val , KONA_SDHOST_CORESTAT ) ;
}
mutex_unlock ( & kona_dev - > write_lock ) ;
return 0 ;
}
/*
* SD card interrupt event callback
*/
2013-07-08 10:11:53 +04:00
static void sdhci_bcm_kona_card_event ( struct sdhci_host * host )
2013-06-21 01:26:37 +04:00
{
if ( mmc_gpio_get_cd ( host - > mmc ) > 0 ) {
dev_dbg ( mmc_dev ( host - > mmc ) ,
" card inserted \n " ) ;
sdhci_bcm_kona_sd_card_emulate ( host , 1 ) ;
} else {
dev_dbg ( mmc_dev ( host - > mmc ) ,
" card removed \n " ) ;
sdhci_bcm_kona_sd_card_emulate ( host , 0 ) ;
}
}
static void sdhci_bcm_kona_init_74_clocks ( struct sdhci_host * host ,
u8 power_mode )
{
/*
* JEDEC and SD spec specify supplying 74 continuous clocks to
* device after power up . With minimum bus ( 100 KHz ) that
* that translates to 740u s
*/
if ( power_mode ! = MMC_POWER_OFF )
udelay ( 740 ) ;
}
2017-08-07 12:50:41 +03:00
static const struct sdhci_ops sdhci_bcm_kona_ops = {
2014-04-25 15:58:55 +04:00
. set_clock = sdhci_set_clock ,
2015-02-27 10:47:29 +03:00
. get_max_clock = sdhci_pltfm_clk_get_max_clock ,
. get_timeout_clock = sdhci_pltfm_clk_get_max_clock ,
2013-06-21 01:26:37 +04:00
. platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks ,
2014-04-25 15:57:07 +04:00
. set_bus_width = sdhci_set_bus_width ,
2014-04-25 15:57:12 +04:00
. reset = sdhci_reset ,
2014-04-25 15:59:26 +04:00
. set_uhs_signaling = sdhci_set_uhs_signaling ,
2013-06-21 01:26:37 +04:00
. card_event = sdhci_bcm_kona_card_event ,
} ;
2017-08-07 12:50:41 +03:00
static const struct sdhci_pltfm_data sdhci_pltfm_data_kona = {
2013-06-21 01:26:37 +04:00
. ops = & sdhci_bcm_kona_ops ,
. quirks = SDHCI_QUIRK_NO_CARD_NO_RESET |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR |
SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE |
SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN ,
} ;
2014-09-26 02:45:22 +04:00
static const struct of_device_id sdhci_bcm_kona_of_match [ ] = {
2013-08-20 19:37:19 +04:00
{ . compatible = " brcm,kona-sdhci " } ,
{ . compatible = " bcm,kona-sdhci " } , /* deprecated name */
2013-06-21 01:26:37 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , sdhci_bcm_kona_of_match ) ;
2013-08-08 02:39:59 +04:00
static int sdhci_bcm_kona_probe ( struct platform_device * pdev )
2013-06-21 01:26:37 +04:00
{
struct sdhci_bcm_kona_dev * kona_dev = NULL ;
struct sdhci_pltfm_host * pltfm_priv ;
struct device * dev = & pdev - > dev ;
struct sdhci_host * host ;
int ret ;
ret = 0 ;
host = sdhci_pltfm_init ( pdev , & sdhci_pltfm_data_kona ,
sizeof ( * kona_dev ) ) ;
if ( IS_ERR ( host ) )
return PTR_ERR ( host ) ;
dev_dbg ( dev , " %s: inited. IOADDR=%p \n " , __func__ , host - > ioaddr ) ;
pltfm_priv = sdhci_priv ( host ) ;
kona_dev = sdhci_pltfm_priv ( pltfm_priv ) ;
mutex_init ( & kona_dev - > write_lock ) ;
2014-12-18 12:41:40 +03:00
ret = mmc_of_parse ( host - > mmc ) ;
if ( ret )
goto err_pltfm_free ;
2013-06-21 01:26:37 +04:00
if ( ! host - > mmc - > f_max ) {
dev_err ( & pdev - > dev , " Missing max-freq for SDHCI cfg \n " ) ;
ret = - ENXIO ;
goto err_pltfm_free ;
}
2015-02-27 10:47:29 +03:00
/* Get and enable the core clock */
pltfm_priv - > clk = devm_clk_get ( dev , NULL ) ;
if ( IS_ERR ( pltfm_priv - > clk ) ) {
dev_err ( dev , " Failed to get core clock \n " ) ;
ret = PTR_ERR ( pltfm_priv - > clk ) ;
2013-12-05 23:20:41 +04:00
goto err_pltfm_free ;
}
2016-07-28 19:17:44 +03:00
ret = clk_set_rate ( pltfm_priv - > clk , host - > mmc - > f_max ) ;
if ( ret ) {
2015-02-27 10:47:29 +03:00
dev_err ( dev , " Failed to set rate core clock \n " ) ;
2013-12-05 23:20:41 +04:00
goto err_pltfm_free ;
}
2016-07-28 19:17:44 +03:00
ret = clk_prepare_enable ( pltfm_priv - > clk ) ;
if ( ret ) {
2015-02-27 10:47:29 +03:00
dev_err ( dev , " Failed to enable core clock \n " ) ;
2013-12-05 23:20:41 +04:00
goto err_pltfm_free ;
}
2013-06-21 01:26:37 +04:00
dev_dbg ( dev , " non-removable=%c \n " ,
2016-06-21 04:13:26 +03:00
mmc_card_is_removable ( host - > mmc ) ? ' N ' : ' Y ' ) ;
2013-06-21 01:26:37 +04:00
dev_dbg ( dev , " cd_gpio %c, wp_gpio %c \n " ,
( mmc_gpio_get_cd ( host - > mmc ) ! = - ENOSYS ) ? ' Y ' : ' N ' ,
( mmc_gpio_get_ro ( host - > mmc ) ! = - ENOSYS ) ? ' Y ' : ' N ' ) ;
2016-06-21 04:13:26 +03:00
if ( ! mmc_card_is_removable ( host - > mmc ) )
2013-06-21 01:26:37 +04:00
host - > quirks | = SDHCI_QUIRK_BROKEN_CARD_DETECTION ;
dev_dbg ( dev , " is_8bit=%c \n " ,
2015-09-16 12:53:20 +03:00
( host - > mmc - > caps & MMC_CAP_8_BIT_DATA ) ? ' Y ' : ' N ' ) ;
2013-06-21 01:26:37 +04:00
ret = sdhci_bcm_kona_sd_reset ( host ) ;
if ( ret )
2013-12-05 23:20:41 +04:00
goto err_clk_disable ;
2013-06-21 01:26:37 +04:00
sdhci_bcm_kona_sd_init ( host ) ;
ret = sdhci_add_host ( host ) ;
2018-05-25 10:15:09 +03:00
if ( ret )
2013-06-21 01:26:37 +04:00
goto err_reset ;
/* if device is eMMC, emulate card insert right here */
2016-06-21 04:13:26 +03:00
if ( ! mmc_card_is_removable ( host - > mmc ) ) {
2013-06-21 01:26:37 +04:00
ret = sdhci_bcm_kona_sd_card_emulate ( host , 1 ) ;
if ( ret ) {
dev_err ( dev ,
" unable to emulate card insertion \n " ) ;
goto err_remove_host ;
}
}
/*
* Since the card detection GPIO interrupt is configured to be
* edge sensitive , check the initial GPIO value here , emulate
* only if the card is present
*/
if ( mmc_gpio_get_cd ( host - > mmc ) > 0 )
sdhci_bcm_kona_sd_card_emulate ( host , 1 ) ;
dev_dbg ( dev , " initialized properly \n " ) ;
return 0 ;
err_remove_host :
sdhci_remove_host ( host , 0 ) ;
err_reset :
sdhci_bcm_kona_sd_reset ( host ) ;
2013-12-05 23:20:41 +04:00
err_clk_disable :
2015-02-27 10:47:29 +03:00
clk_disable_unprepare ( pltfm_priv - > clk ) ;
2013-12-05 23:20:41 +04:00
2013-06-21 01:26:37 +04:00
err_pltfm_free :
sdhci_pltfm_free ( pdev ) ;
dev_err ( dev , " Probing of sdhci-pltfm failed: %d \n " , ret ) ;
return ret ;
}
static struct platform_driver sdhci_bcm_kona_driver = {
. driver = {
. name = " sdhci-kona " ,
2020-09-04 02:24:36 +03:00
. probe_type = PROBE_PREFER_ASYNCHRONOUS ,
2016-07-27 14:07:21 +03:00
. pm = & sdhci_pltfm_pmops ,
2013-08-08 02:39:59 +04:00
. of_match_table = sdhci_bcm_kona_of_match ,
2013-06-21 01:26:37 +04:00
} ,
. probe = sdhci_bcm_kona_probe ,
2015-02-27 10:47:31 +03:00
. remove = sdhci_pltfm_unregister ,
2013-06-21 01:26:37 +04:00
} ;
module_platform_driver ( sdhci_bcm_kona_driver ) ;
MODULE_DESCRIPTION ( " SDHCI driver for Broadcom Kona platform " ) ;
MODULE_AUTHOR ( " Broadcom " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;