diff options
Diffstat (limited to 'drivers/mmc/core')
| -rw-r--r-- | drivers/mmc/core/core.c | 35 | ||||
| -rw-r--r-- | drivers/mmc/core/host.c | 12 | ||||
| -rw-r--r-- | drivers/mmc/core/host.h | 8 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.c | 81 | 
4 files changed, 94 insertions, 42 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 91a0a7460eb..b27b94078c2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -133,7 +133,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)  		if (mrq->done)  			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)  			mrq->stop->mrq = mrq;  		}  	} -	mmc_host_clk_ungate(host); +	mmc_host_clk_hold(host);  	led_trigger_event(host->led, LED_FULL);  	host->ops->request(host, mrq);  } @@ -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)  { +	mmc_host_clk_hold(host);  	host->ios.chip_select = mode;  	mmc_set_ios(host); +	mmc_host_clk_release(host);  }  /*   * Sets the host clock to the highest possible frequency that   * 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); @@ -747,6 +749,13 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)  	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  /*   * This gates the clock by setting it to 0 Hz. @@ -779,7 +788,7 @@ void mmc_ungate_clock(struct mmc_host *host)  	if (host->clk_old) {  		BUG_ON(host->ios.clock);  		/* 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)   */  void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)  { +	mmc_host_clk_hold(host);  	host->ios.bus_mode = mode;  	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)   */  void mmc_set_bus_width(struct mmc_host *host, unsigned int width)  { +	mmc_host_clk_hold(host);  	host->ios.bus_width = width;  	mmc_set_ios(host); +	mmc_host_clk_release(host);  }  /** @@ -1015,8 +1028,10 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)  		ocr &= 3 << bit; +		mmc_host_clk_hold(host);  		host->ios.vdd = bit;  		mmc_set_ios(host); +		mmc_host_clk_release(host);  	} else {  		pr_warning("%s: host doesn't support card's voltages\n",  				mmc_hostname(host)); @@ -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)  { +	mmc_host_clk_hold(host);  	host->ios.timing = timing;  	mmc_set_ios(host); +	mmc_host_clk_release(host);  }  /* @@ -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)  { +	mmc_host_clk_hold(host);  	host->ios.drv_type = drv_type;  	mmc_set_ios(host); +	mmc_host_clk_release(host);  }  /* @@ -1091,6 +1110,8 @@ static void mmc_power_up(struct mmc_host *host)  {  	int bit; +	mmc_host_clk_hold(host); +  	/* If ocr is set, we use it */  	if (host->ocr)  		bit = ffs(host->ocr) - 1; @@ -1126,10 +1147,14 @@ static void mmc_power_up(struct mmc_host *host)  	 * time required to reach a stable voltage.  	 */  	mmc_delay(10); + +	mmc_host_clk_release(host);  }  static void mmc_power_off(struct mmc_host *host)  { +	mmc_host_clk_hold(host); +  	host->ios.clock = 0;  	host->ios.vdd = 0; @@ -1147,6 +1172,8 @@ static void mmc_power_off(struct mmc_host *host)  	host->ios.bus_width = MMC_BUS_WIDTH_1;  	host->ios.timing = MMC_TIMING_LEGACY;  	mmc_set_ios(host); + +	mmc_host_clk_release(host);  }  /* diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index b29d3e8fd3a..793d0a0dad8 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -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.   *   *	Makes sure the host ios.clock is restored to a non-zero value   *	past this call.	Increase clock reference count and ungate clock   *	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; @@ -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.   *   *	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   *	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; @@ -179,7 +179,7 @@ void mmc_host_clk_gate(struct mmc_host *host)  	host->clk_requests--;  	if (mmc_host_may_gate_card(host->card) &&  	    !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);  } @@ -231,7 +231,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)  	if (cancel_work_sync(&host->clk_gate_work))  		mmc_host_clk_gate_delayed(host);  	if (host->clk_gated) -		mmc_host_clk_ungate(host); +		mmc_host_clk_hold(host);  	/* There should be only one user now */  	WARN_ON(host->clk_requests > 1);  } diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index de199f91192..fb8a5cd2e4a 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -16,16 +16,16 @@ int mmc_register_host_class(void);  void mmc_unregister_host_class(void);  #ifdef CONFIG_MMC_CLKGATE -void mmc_host_clk_ungate(struct mmc_host *host); -void mmc_host_clk_gate(struct mmc_host *host); +void mmc_host_clk_hold(struct mmc_host *host); +void mmc_host_clk_release(struct mmc_host *host);  unsigned int mmc_host_clk_rate(struct mmc_host *host);  #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)  {  } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 633975ff2bb..0370e03e314 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -469,56 +469,75 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)  	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  	 * default speed.  	 */  	if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | -	    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) -		return 0; +	    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) { +		card->sd_bus_speed = 0; +		return; +	}  	if ((card->host->caps & MMC_CAP_UHS_SDR104) &&  	    (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) { -			bus_speed = UHS_SDR104_BUS_SPEED; -			timing = MMC_TIMING_UHS_SDR104; -			card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; +			card->sd_bus_speed = UHS_SDR104_BUS_SPEED;  	} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&  		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) { -			bus_speed = UHS_DDR50_BUS_SPEED; -			timing = MMC_TIMING_UHS_DDR50; -			card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; +			card->sd_bus_speed = UHS_DDR50_BUS_SPEED;  	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |  		    MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &  		    SD_MODE_UHS_SDR50)) { -			bus_speed = UHS_SDR50_BUS_SPEED; -			timing = MMC_TIMING_UHS_SDR50; -			card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; +			card->sd_bus_speed = UHS_SDR50_BUS_SPEED;  	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |  		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&  		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) { -			bus_speed = UHS_SDR25_BUS_SPEED; -			timing = MMC_TIMING_UHS_SDR25; -			card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR; +			card->sd_bus_speed = UHS_SDR25_BUS_SPEED;  	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |  		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |  		    MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &  		    SD_MODE_UHS_SDR12)) { -			bus_speed = UHS_SDR12_BUS_SPEED; -			timing = MMC_TIMING_UHS_SDR12; -			card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; +			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; +		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, bus_speed, status); +	err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status);  	if (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",  			mmc_hostname(card->host));  	else { @@ -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);  	} +	/* +	 * Select the bus speed mode depending on host +	 * and card capability. +	 */ +	sd_update_bus_speed_mode(card); +  	/* Set the driver strength for the card */  	err = sd_select_driver_type(card, status);  	if (err)  		goto out; -	/* Set bus speed mode of the card */ -	err = sd_set_bus_speed_mode(card, status); +	/* Set current limit for the card */ +	err = sd_set_current_limit(card, status);  	if (err)  		goto out; -	/* Set current limit for the card */ -	err = sd_set_current_limit(card, status); +	/* Set bus speed mode of the card */ +	err = sd_set_bus_speed_mode(card, status);  	if (err)  		goto out;  |