2013-03-21 16:27:19 +08:00
/*
* SDHCI support for SiRF primaII and marco SoCs
*
* Copyright ( c ) 2011 Cambridge Silicon Radio Limited , a CSR plc group company .
*
* Licensed under GPLv2 or later .
*/
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/mmc/host.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_gpio.h>
# include <linux/mmc/slot-gpio.h>
# include "sdhci-pltfm.h"
2014-12-04 20:09:20 +08:00
# define SDHCI_CLK_DELAY_SETTING 0x4C
2014-08-26 10:50:42 +08:00
# define SDHCI_SIRF_8BITBUS BIT(3)
2014-12-04 20:09:20 +08:00
# define SIRF_TUNING_COUNT 128
2014-08-26 10:50:42 +08:00
2013-03-21 16:27:19 +08:00
struct sdhci_sirf_priv {
struct clk * clk ;
int gpio_cd ;
} ;
static unsigned int sdhci_sirf_get_max_clk ( struct sdhci_host * host )
{
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2013-06-27 11:17:25 -04:00
struct sdhci_sirf_priv * priv = sdhci_pltfm_priv ( pltfm_host ) ;
2013-03-21 16:27:19 +08:00
return clk_get_rate ( priv - > clk ) ;
}
2014-08-26 10:50:42 +08:00
static void sdhci_sirf_set_bus_width ( struct sdhci_host * host , int width )
{
u8 ctrl ;
ctrl = sdhci_readb ( host , SDHCI_HOST_CONTROL ) ;
ctrl & = ~ ( SDHCI_CTRL_4BITBUS | SDHCI_SIRF_8BITBUS ) ;
/*
* CSR atlas7 and prima2 SD host version is not 3.0
* 8 bit - width enable bit of CSR SD hosts is 3 ,
* while stardard hosts use bit 5
*/
if ( width = = MMC_BUS_WIDTH_8 )
ctrl | = SDHCI_SIRF_8BITBUS ;
else if ( width = = MMC_BUS_WIDTH_4 )
ctrl | = SDHCI_CTRL_4BITBUS ;
sdhci_writeb ( host , ctrl , SDHCI_HOST_CONTROL ) ;
}
2014-12-04 20:09:20 +08:00
static int sdhci_sirf_execute_tuning ( struct sdhci_host * host , u32 opcode )
{
int tuning_seq_cnt = 3 ;
u8 phase , tuned_phases [ SIRF_TUNING_COUNT ] ;
u8 tuned_phase_cnt = 0 ;
2015-02-15 23:43:51 +08:00
int rc = 0 , longest_range = 0 ;
2014-12-04 20:09:20 +08:00
int start = - 1 , end = 0 , tuning_value = - 1 , range = 0 ;
u16 clock_setting ;
struct mmc_host * mmc = host - > mmc ;
clock_setting = sdhci_readw ( host , SDHCI_CLK_DELAY_SETTING ) ;
clock_setting & = ~ 0x3fff ;
retry :
phase = 0 ;
do {
sdhci_writel ( host ,
2015-02-15 23:43:51 +08:00
clock_setting | phase ,
2014-12-04 20:09:20 +08:00
SDHCI_CLK_DELAY_SETTING ) ;
if ( ! mmc_send_tuning ( mmc ) ) {
/* Tuning is successful at this tuning point */
tuned_phases [ tuned_phase_cnt + + ] = phase ;
dev_dbg ( mmc_dev ( mmc ) , " %s: Found good phase = %d \n " ,
mmc_hostname ( mmc ) , phase ) ;
if ( start = = - 1 )
start = phase ;
end = phase ;
range + + ;
if ( phase = = ( SIRF_TUNING_COUNT - 1 )
& & range > longest_range )
tuning_value = ( start + end ) / 2 ;
} else {
dev_dbg ( mmc_dev ( mmc ) , " %s: Found bad phase = %d \n " ,
mmc_hostname ( mmc ) , phase ) ;
if ( range > longest_range ) {
tuning_value = ( start + end ) / 2 ;
longest_range = range ;
}
start = - 1 ;
end = range = 0 ;
}
} while ( + + phase < ARRAY_SIZE ( tuned_phases ) ) ;
if ( tuned_phase_cnt & & tuning_value > 0 ) {
/*
* Finally set the selected phase in delay
* line hw block .
*/
phase = tuning_value ;
sdhci_writel ( host ,
2015-02-15 23:43:51 +08:00
clock_setting | phase ,
2014-12-04 20:09:20 +08:00
SDHCI_CLK_DELAY_SETTING ) ;
dev_dbg ( mmc_dev ( mmc ) , " %s: Setting the tuning phase to %d \n " ,
mmc_hostname ( mmc ) , phase ) ;
} else {
if ( - - tuning_seq_cnt )
goto retry ;
/* Tuning failed */
dev_dbg ( mmc_dev ( mmc ) , " %s: No tuning point found \n " ,
mmc_hostname ( mmc ) ) ;
rc = - EIO ;
}
return rc ;
}
2013-03-21 16:27:19 +08:00
static struct sdhci_ops sdhci_sirf_ops = {
2014-12-04 20:09:20 +08:00
. platform_execute_tuning = sdhci_sirf_execute_tuning ,
2014-04-25 12:58:55 +01:00
. set_clock = sdhci_set_clock ,
2013-03-21 16:27:19 +08:00
. get_max_clock = sdhci_sirf_get_max_clk ,
2014-08-26 10:50:42 +08:00
. set_bus_width = sdhci_sirf_set_bus_width ,
2014-04-25 12:57:12 +01:00
. reset = sdhci_reset ,
2014-04-25 12:59:26 +01:00
. set_uhs_signaling = sdhci_set_uhs_signaling ,
2013-03-21 16:27:19 +08:00
} ;
static struct sdhci_pltfm_data sdhci_sirf_pdata = {
. ops = & sdhci_sirf_ops ,
. quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
SDHCI_QUIRK_DELAY_AFTER_POWER ,
} ;
static int sdhci_sirf_probe ( struct platform_device * pdev )
{
struct sdhci_host * host ;
struct sdhci_pltfm_host * pltfm_host ;
struct sdhci_sirf_priv * priv ;
2013-06-27 11:17:25 -04:00
struct clk * clk ;
int gpio_cd ;
2013-03-21 16:27:19 +08:00
int ret ;
2013-06-27 11:17:25 -04:00
clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( clk ) ) {
2013-03-21 16:27:19 +08:00
dev_err ( & pdev - > dev , " unable to get clock " ) ;
2013-06-27 11:17:25 -04:00
return PTR_ERR ( clk ) ;
2013-03-21 16:27:19 +08:00
}
2013-06-27 11:17:25 -04:00
if ( pdev - > dev . of_node )
gpio_cd = of_get_named_gpio ( pdev - > dev . of_node , " cd-gpios " , 0 ) ;
else
gpio_cd = - EINVAL ;
2013-03-21 16:27:19 +08:00
2013-06-27 11:17:25 -04:00
host = sdhci_pltfm_init ( pdev , & sdhci_sirf_pdata , sizeof ( struct sdhci_sirf_priv ) ) ;
if ( IS_ERR ( host ) )
return PTR_ERR ( host ) ;
2013-03-21 16:27:19 +08:00
pltfm_host = sdhci_priv ( host ) ;
2013-06-27 11:17:25 -04:00
priv = sdhci_pltfm_priv ( pltfm_host ) ;
priv - > clk = clk ;
priv - > gpio_cd = gpio_cd ;
2013-03-21 16:27:19 +08:00
sdhci_get_of_property ( pdev ) ;
2013-06-27 11:17:25 -04:00
ret = clk_prepare_enable ( priv - > clk ) ;
if ( ret )
goto err_clk_prepare ;
2013-03-21 16:27:19 +08:00
ret = sdhci_add_host ( host ) ;
if ( ret )
goto err_sdhci_add ;
/*
* We must request the IRQ after sdhci_add_host ( ) , as the tasklet only
* gets setup in sdhci_add_host ( ) and we oops .
*/
if ( gpio_is_valid ( priv - > gpio_cd ) ) {
2013-08-08 12:38:31 +02:00
ret = mmc_gpio_request_cd ( host - > mmc , priv - > gpio_cd , 0 ) ;
2013-03-21 16:27:19 +08:00
if ( ret ) {
dev_err ( & pdev - > dev , " card detect irq request failed: %d \n " ,
ret ) ;
goto err_request_cd ;
}
mmc: don't request CD IRQ until mmc_start_host()
As soon as the CD IRQ is requested, it can trigger, since it's an
externally controlled event. If it does, delayed_work host->detect will
be scheduled.
Many host controller probe()s are roughly structured as:
*_probe() {
host = sdhci_pltfm_init();
mmc_of_parse(host->mmc);
rc = sdhci_add_host(host);
if (rc) {
sdhci_pltfm_free();
return rc;
}
In 3.17, CD IRQs can are enabled quite early via *_probe() ->
mmc_of_parse() -> mmc_gpio_request_cd() -> mmc_gpiod_request_cd_irq().
Note that in linux-next, mmc_of_parse() calls mmc_gpio*d*_request_cd()
rather than mmc_gpio_request_cd(), and mmc_gpio*d*_request_cd() doesn't
call mmc_gpiod_request_cd_irq(). However, this issue still exists if
mmc_gpio_request_cd() is called directly before mmc_start_host().
sdhci_add_host() may fail part way through (e.g. due to deferred
probe for a vmmc regulator), and sdhci_pltfm_free() does nothing to
unrequest the CD IRQ nor cancel the delayed_work. sdhci_pltfm_free() is
coded to assume that if sdhci_add_host() failed, then the delayed_work
cannot (or should not) have been triggered.
This can lead to the following with CONFIG_DEBUG_OBJECTS_* enabled, when
kfree(host) is eventually called inside sdhci_pltfm_free():
WARNING: CPU: 2 PID: 6 at lib/debugobjects.c:263 debug_print_object+0x8c/0xb4()
ODEBUG: free active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x18
The object being complained about is host->detect.
There's no need to request the CD IRQ so early; mmc_start_host() already
requests it. For most SDHCI hosts at least, the typical call path that
does this is: *_probe() -> sdhci_add_host() -> mmc_add_host() ->
mmc_start_host(). Therefore, remove the call to mmc_gpiod_request_cd_irq()
from mmc_gpio_request_cd(). This also matches mmc_gpio*d*_request_cd(),
which already doesn't call mmc_gpiod_request_cd_irq().
However, some host controller drivers call mmc_gpio_request_cd() after
mmc_start_host() has already been called, and assume that this will also
call mmc_gpiod_request_cd_irq(). Update those drivers to explicitly call
mmc_gpiod_request_cd_irq() themselves. Ideally, these drivers should be
modified to move their call to mmc_gpio_request_cd() before their call
to mmc_add_host(). However that's too large a change for stable.
This solves the problem (eliminates the kernel error message above),
since it guarantees that the IRQ can't trigger before mmc_start_host()
is called.
The critical point here is that once sdhci_add_host() calls
mmc_add_host() -> mmc_start_host(), sdhci_add_host() is coded not to
fail. In other words, if there's a chance that mmc_start_host() may have
been called, and CD IRQs triggered, and the delayed_work scheduled,
sdhci_add_host() won't fail, and so cleanup is no longer via
sdhci_pltfm_free() (which doesn't free the IRQ or cancel the work queue)
but instead must be via sdhci_remove_host(), which calls mmc_remove_host()
-> mmc_stop_host(), which does free the IRQ and cancel the work queue.
CC: Russell King <linux@arm.linux.org.uk>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexandre Courbot <acourbot@nvidia.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: <stable@vger.kernel.org> # v3.15+
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
2014-09-22 09:57:42 -06:00
mmc_gpiod_request_cd_irq ( host - > mmc ) ;
2013-03-21 16:27:19 +08:00
}
return 0 ;
err_request_cd :
sdhci_remove_host ( host , 0 ) ;
err_sdhci_add :
clk_disable_unprepare ( priv - > clk ) ;
2013-06-27 11:17:25 -04:00
err_clk_prepare :
2013-03-21 16:27:19 +08:00
sdhci_pltfm_free ( pdev ) ;
return ret ;
}
static int sdhci_sirf_remove ( struct platform_device * pdev )
{
struct sdhci_host * host = platform_get_drvdata ( pdev ) ;
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2013-06-27 11:17:25 -04:00
struct sdhci_sirf_priv * priv = sdhci_pltfm_priv ( pltfm_host ) ;
2013-03-21 16:27:19 +08:00
sdhci_pltfm_unregister ( pdev ) ;
clk_disable_unprepare ( priv - > clk ) ;
return 0 ;
}
# ifdef CONFIG_PM_SLEEP
static int sdhci_sirf_suspend ( struct device * dev )
{
struct sdhci_host * host = dev_get_drvdata ( dev ) ;
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2013-06-27 11:17:25 -04:00
struct sdhci_sirf_priv * priv = sdhci_pltfm_priv ( pltfm_host ) ;
2013-03-21 16:27:19 +08:00
int ret ;
ret = sdhci_suspend_host ( host ) ;
if ( ret )
return ret ;
clk_disable ( priv - > clk ) ;
return 0 ;
}
static int sdhci_sirf_resume ( struct device * dev )
{
struct sdhci_host * host = dev_get_drvdata ( dev ) ;
struct sdhci_pltfm_host * pltfm_host = sdhci_priv ( host ) ;
2013-06-27 11:17:25 -04:00
struct sdhci_sirf_priv * priv = sdhci_pltfm_priv ( pltfm_host ) ;
2013-03-21 16:27:19 +08:00
int ret ;
ret = clk_enable ( priv - > clk ) ;
if ( ret ) {
dev_dbg ( dev , " Resume: Error enabling clock \n " ) ;
return ret ;
}
return sdhci_resume_host ( host ) ;
}
static SIMPLE_DEV_PM_OPS ( sdhci_sirf_pm_ops , sdhci_sirf_suspend , sdhci_sirf_resume ) ;
# endif
static const struct of_device_id sdhci_sirf_of_match [ ] = {
{ . compatible = " sirf,prima2-sdhc " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , sdhci_sirf_of_match ) ;
static struct platform_driver sdhci_sirf_driver = {
. driver = {
. name = " sdhci-sirf " ,
. of_match_table = sdhci_sirf_of_match ,
# ifdef CONFIG_PM_SLEEP
. pm = & sdhci_sirf_pm_ops ,
# endif
} ,
. probe = sdhci_sirf_probe ,
. remove = sdhci_sirf_remove ,
} ;
module_platform_driver ( sdhci_sirf_driver ) ;
MODULE_DESCRIPTION ( " SDHCI driver for SiRFprimaII/SiRFmarco " ) ;
MODULE_AUTHOR ( " Barry Song <21cnbao@gmail.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;