Commit a6a5ed0d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://dev.laptop.org/users/cjb/mmc

* 'for-linus' of git://dev.laptop.org/users/cjb/mmc:
  mmc: sdhci-s3c: Fix mmc card I/O problem
  mmc: sd: UHS-I bus speed should be set last in UHS initialization
  mmc: sdhi: initialise mmc_data->flags before use
  mmc: core: use non-reentrant workqueue for clock gating
  mmc: core: prevent aggressive clock gating racing with ios updates
  mmc: rename mmc_host_clk_{ungate|gate} to mmc_host_clk_{hold|release}
  mmc: sdhci-esdhc-imx: add missing inclusion of linux/module.h
parents 0d20fbbe 49bb1e61
...@@ -133,7 +133,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) ...@@ -133,7 +133,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
if (mrq->done) if (mrq->done)
mrq->done(mrq); mrq->done(mrq);
mmc_host_clk_gate(host); mmc_host_clk_release(host);
} }
} }
...@@ -192,7 +192,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) ...@@ -192,7 +192,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->mrq = mrq; mrq->stop->mrq = mrq;
} }
} }
mmc_host_clk_ungate(host); mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL); led_trigger_event(host->led, LED_FULL);
host->ops->request(host, mrq); host->ops->request(host, mrq);
} }
...@@ -728,15 +728,17 @@ static inline void mmc_set_ios(struct mmc_host *host) ...@@ -728,15 +728,17 @@ static inline void mmc_set_ios(struct mmc_host *host)
*/ */
void mmc_set_chip_select(struct mmc_host *host, int mode) void mmc_set_chip_select(struct mmc_host *host, int mode)
{ {
mmc_host_clk_hold(host);
host->ios.chip_select = mode; host->ios.chip_select = mode;
mmc_set_ios(host); mmc_set_ios(host);
mmc_host_clk_release(host);
} }
/* /*
* Sets the host clock to the highest possible frequency that * Sets the host clock to the highest possible frequency that
* is below "hz". * is below "hz".
*/ */
void mmc_set_clock(struct mmc_host *host, unsigned int hz) static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
{ {
WARN_ON(hz < host->f_min); WARN_ON(hz < host->f_min);
...@@ -747,6 +749,13 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz) ...@@ -747,6 +749,13 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)
mmc_set_ios(host); mmc_set_ios(host);
} }
void mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
mmc_host_clk_hold(host);
__mmc_set_clock(host, hz);
mmc_host_clk_release(host);
}
#ifdef CONFIG_MMC_CLKGATE #ifdef CONFIG_MMC_CLKGATE
/* /*
* This gates the clock by setting it to 0 Hz. * This gates the clock by setting it to 0 Hz.
...@@ -779,7 +788,7 @@ void mmc_ungate_clock(struct mmc_host *host) ...@@ -779,7 +788,7 @@ void mmc_ungate_clock(struct mmc_host *host)
if (host->clk_old) { if (host->clk_old) {
BUG_ON(host->ios.clock); BUG_ON(host->ios.clock);
/* This call will also set host->clk_gated to false */ /* This call will also set host->clk_gated to false */
mmc_set_clock(host, host->clk_old); __mmc_set_clock(host, host->clk_old);
} }
} }
...@@ -807,8 +816,10 @@ void mmc_set_ungated(struct mmc_host *host) ...@@ -807,8 +816,10 @@ void mmc_set_ungated(struct mmc_host *host)
*/ */
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
{ {
mmc_host_clk_hold(host);
host->ios.bus_mode = mode; host->ios.bus_mode = mode;
mmc_set_ios(host); mmc_set_ios(host);
mmc_host_clk_release(host);
} }
/* /*
...@@ -816,8 +827,10 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) ...@@ -816,8 +827,10 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
*/ */
void mmc_set_bus_width(struct mmc_host *host, unsigned int width) void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{ {
mmc_host_clk_hold(host);
host->ios.bus_width = width; host->ios.bus_width = width;
mmc_set_ios(host); mmc_set_ios(host);
mmc_host_clk_release(host);
} }
/** /**
...@@ -1015,8 +1028,10 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) ...@@ -1015,8 +1028,10 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
ocr &= 3 << bit; ocr &= 3 << bit;
mmc_host_clk_hold(host);
host->ios.vdd = bit; host->ios.vdd = bit;
mmc_set_ios(host); mmc_set_ios(host);
mmc_host_clk_release(host);
} else { } else {
pr_warning("%s: host doesn't support card's voltages\n", pr_warning("%s: host doesn't support card's voltages\n",
mmc_hostname(host)); mmc_hostname(host));
...@@ -1063,8 +1078,10 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11 ...@@ -1063,8 +1078,10 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
*/ */
void mmc_set_timing(struct mmc_host *host, unsigned int timing) void mmc_set_timing(struct mmc_host *host, unsigned int timing)
{ {
mmc_host_clk_hold(host);
host->ios.timing = timing; host->ios.timing = timing;
mmc_set_ios(host); mmc_set_ios(host);
mmc_host_clk_release(host);
} }
/* /*
...@@ -1072,8 +1089,10 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing) ...@@ -1072,8 +1089,10 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
*/ */
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type) void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
{ {
mmc_host_clk_hold(host);
host->ios.drv_type = drv_type; host->ios.drv_type = drv_type;
mmc_set_ios(host); mmc_set_ios(host);
mmc_host_clk_release(host);
} }
/* /*
...@@ -1091,6 +1110,8 @@ static void mmc_power_up(struct mmc_host *host) ...@@ -1091,6 +1110,8 @@ static void mmc_power_up(struct mmc_host *host)
{ {
int bit; int bit;
mmc_host_clk_hold(host);
/* If ocr is set, we use it */ /* If ocr is set, we use it */
if (host->ocr) if (host->ocr)
bit = ffs(host->ocr) - 1; bit = ffs(host->ocr) - 1;
...@@ -1126,10 +1147,14 @@ static void mmc_power_up(struct mmc_host *host) ...@@ -1126,10 +1147,14 @@ static void mmc_power_up(struct mmc_host *host)
* time required to reach a stable voltage. * time required to reach a stable voltage.
*/ */
mmc_delay(10); mmc_delay(10);
mmc_host_clk_release(host);
} }
static void mmc_power_off(struct mmc_host *host) static void mmc_power_off(struct mmc_host *host)
{ {
mmc_host_clk_hold(host);
host->ios.clock = 0; host->ios.clock = 0;
host->ios.vdd = 0; host->ios.vdd = 0;
...@@ -1147,6 +1172,8 @@ static void mmc_power_off(struct mmc_host *host) ...@@ -1147,6 +1172,8 @@ static void mmc_power_off(struct mmc_host *host)
host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY; host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host); mmc_set_ios(host);
mmc_host_clk_release(host);
} }
/* /*
......
...@@ -119,14 +119,14 @@ static void mmc_host_clk_gate_work(struct work_struct *work) ...@@ -119,14 +119,14 @@ static void mmc_host_clk_gate_work(struct work_struct *work)
} }
/** /**
* mmc_host_clk_ungate - ungate hardware MCI clocks * mmc_host_clk_hold - ungate hardware MCI clocks
* @host: host to ungate. * @host: host to ungate.
* *
* Makes sure the host ios.clock is restored to a non-zero value * Makes sure the host ios.clock is restored to a non-zero value
* past this call. Increase clock reference count and ungate clock * past this call. Increase clock reference count and ungate clock
* if we're the first user. * if we're the first user.
*/ */
void mmc_host_clk_ungate(struct mmc_host *host) void mmc_host_clk_hold(struct mmc_host *host)
{ {
unsigned long flags; unsigned long flags;
...@@ -164,14 +164,14 @@ static bool mmc_host_may_gate_card(struct mmc_card *card) ...@@ -164,14 +164,14 @@ static bool mmc_host_may_gate_card(struct mmc_card *card)
} }
/** /**
* mmc_host_clk_gate - gate off hardware MCI clocks * mmc_host_clk_release - gate off hardware MCI clocks
* @host: host to gate. * @host: host to gate.
* *
* Calls the host driver with ios.clock set to zero as often as possible * Calls the host driver with ios.clock set to zero as often as possible
* in order to gate off hardware MCI clocks. Decrease clock reference * in order to gate off hardware MCI clocks. Decrease clock reference
* count and schedule disabling of clock. * count and schedule disabling of clock.
*/ */
void mmc_host_clk_gate(struct mmc_host *host) void mmc_host_clk_release(struct mmc_host *host)
{ {
unsigned long flags; unsigned long flags;
...@@ -179,7 +179,7 @@ void mmc_host_clk_gate(struct mmc_host *host) ...@@ -179,7 +179,7 @@ void mmc_host_clk_gate(struct mmc_host *host)
host->clk_requests--; host->clk_requests--;
if (mmc_host_may_gate_card(host->card) && if (mmc_host_may_gate_card(host->card) &&
!host->clk_requests) !host->clk_requests)
schedule_work(&host->clk_gate_work); queue_work(system_nrt_wq, &host->clk_gate_work);
spin_unlock_irqrestore(&host->clk_lock, flags); spin_unlock_irqrestore(&host->clk_lock, flags);
} }
...@@ -231,7 +231,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) ...@@ -231,7 +231,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
if (cancel_work_sync(&host->clk_gate_work)) if (cancel_work_sync(&host->clk_gate_work))
mmc_host_clk_gate_delayed(host); mmc_host_clk_gate_delayed(host);
if (host->clk_gated) if (host->clk_gated)
mmc_host_clk_ungate(host); mmc_host_clk_hold(host);
/* There should be only one user now */ /* There should be only one user now */
WARN_ON(host->clk_requests > 1); WARN_ON(host->clk_requests > 1);
} }
......
...@@ -16,16 +16,16 @@ int mmc_register_host_class(void); ...@@ -16,16 +16,16 @@ int mmc_register_host_class(void);
void mmc_unregister_host_class(void); void mmc_unregister_host_class(void);
#ifdef CONFIG_MMC_CLKGATE #ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_ungate(struct mmc_host *host); void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_gate(struct mmc_host *host); void mmc_host_clk_release(struct mmc_host *host);
unsigned int mmc_host_clk_rate(struct mmc_host *host); unsigned int mmc_host_clk_rate(struct mmc_host *host);
#else #else
static inline void mmc_host_clk_ungate(struct mmc_host *host) static inline void mmc_host_clk_hold(struct mmc_host *host)
{ {
} }
static inline void mmc_host_clk_gate(struct mmc_host *host) static inline void mmc_host_clk_release(struct mmc_host *host)
{ {
} }
......
...@@ -469,56 +469,75 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) ...@@ -469,56 +469,75 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
return 0; return 0;
} }
static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status) static void sd_update_bus_speed_mode(struct mmc_card *card)
{ {
unsigned int bus_speed = 0, timing = 0;
int err;
/* /*
* If the host doesn't support any of the UHS-I modes, fallback on * If the host doesn't support any of the UHS-I modes, fallback on
* default speed. * default speed.
*/ */
if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) {
return 0; card->sd_bus_speed = 0;
return;
}
if ((card->host->caps & MMC_CAP_UHS_SDR104) && if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) { (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
bus_speed = UHS_SDR104_BUS_SPEED; card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
timing = MMC_TIMING_UHS_SDR104;
card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) && } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) { (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
bus_speed = UHS_DDR50_BUS_SPEED; card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
timing = MMC_TIMING_UHS_DDR50;
card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode & MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR50)) { SD_MODE_UHS_SDR50)) {
bus_speed = UHS_SDR50_BUS_SPEED; card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
timing = MMC_TIMING_UHS_SDR50;
card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) && MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) { (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
bus_speed = UHS_SDR25_BUS_SPEED; card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
timing = MMC_TIMING_UHS_SDR25;
card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode & MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR12)) { SD_MODE_UHS_SDR12)) {
bus_speed = UHS_SDR12_BUS_SPEED; card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
}
}
static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
{
int err;
unsigned int timing = 0;
switch (card->sd_bus_speed) {
case UHS_SDR104_BUS_SPEED:
timing = MMC_TIMING_UHS_SDR104;
card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
break;
case UHS_DDR50_BUS_SPEED:
timing = MMC_TIMING_UHS_DDR50;
card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
break;
case UHS_SDR50_BUS_SPEED:
timing = MMC_TIMING_UHS_SDR50;
card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
break;
case UHS_SDR25_BUS_SPEED:
timing = MMC_TIMING_UHS_SDR25;
card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
break;
case UHS_SDR12_BUS_SPEED:
timing = MMC_TIMING_UHS_SDR12; timing = MMC_TIMING_UHS_SDR12;
card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
break;
default:
return 0;
} }
card->sd_bus_speed = bus_speed; err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status);
err = mmc_sd_switch(card, 1, 0, bus_speed, status);
if (err) if (err)
return err; return err;
if ((status[16] & 0xF) != bus_speed) if ((status[16] & 0xF) != card->sd_bus_speed)
printk(KERN_WARNING "%s: Problem setting bus speed mode!\n", printk(KERN_WARNING "%s: Problem setting bus speed mode!\n",
mmc_hostname(card->host)); mmc_hostname(card->host));
else { else {
...@@ -618,18 +637,24 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) ...@@ -618,18 +637,24 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
} }
/*
* Select the bus speed mode depending on host
* and card capability.
*/
sd_update_bus_speed_mode(card);
/* Set the driver strength for the card */ /* Set the driver strength for the card */
err = sd_select_driver_type(card, status); err = sd_select_driver_type(card, status);
if (err) if (err)
goto out; goto out;
/* Set bus speed mode of the card */ /* Set current limit for the card */
err = sd_set_bus_speed_mode(card, status); err = sd_set_current_limit(card, status);
if (err) if (err)
goto out; goto out;
/* Set current limit for the card */ /* Set bus speed mode of the card */
err = sd_set_current_limit(card, status); err = sd_set_bus_speed_mode(card, status);
if (err) if (err)
goto out; goto out;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
......
...@@ -302,6 +302,8 @@ static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width) ...@@ -302,6 +302,8 @@ static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width)
ctrl &= ~SDHCI_CTRL_8BITBUS; ctrl &= ~SDHCI_CTRL_8BITBUS;
break; break;
default: default:
ctrl &= ~SDHCI_CTRL_4BITBUS;
ctrl &= ~SDHCI_CTRL_8BITBUS;
break; break;
} }
......
...@@ -120,11 +120,11 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -120,11 +120,11 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
mmc_data->hclk = clk_get_rate(priv->clk); mmc_data->hclk = clk_get_rate(priv->clk);
mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
mmc_data->get_cd = sh_mobile_sdhi_get_cd; mmc_data->get_cd = sh_mobile_sdhi_get_cd;
if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
if (p) { if (p) {
mmc_data->flags = p->tmio_flags; mmc_data->flags = p->tmio_flags;
if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->ocr_mask = p->tmio_ocr_mask; mmc_data->ocr_mask = p->tmio_ocr_mask;
mmc_data->capabilities |= p->tmio_caps; mmc_data->capabilities |= p->tmio_caps;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment