Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa550189 authored by Ulf Hansson's avatar Ulf Hansson Committed by Chris Ball
Browse files

mmc: core: Prevent eMMC VCC supply to be cut from late init



For eMMC cards that has been initialized from a bootloader,
the VCC voltage supply must not be cut in an uncontrolled
manner, without first sending SLEEP or POWEROFF_NOTIFY.

The regulator_init_complete late initcall, may cut the VCC
regulator if it's reference counter is zero. To be able to
prevent the regulator from being cut, mmc_start_host, which
should execute at device init and thus before late init,
calls mmc_power_up. Then the host driver is able to increase
the reference to the regulator.

Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Reviewed-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 95dcc2cb
Loading
Loading
Loading
Loading
+15 −3
Original line number Original line Diff line number Diff line
@@ -42,6 +42,7 @@
#include "sdio_ops.h"
#include "sdio_ops.h"


static struct workqueue_struct *workqueue;
static struct workqueue_struct *workqueue;
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };


/*
/*
 * Enabling software CRCs on the data blocks can be a significant (30%)
 * Enabling software CRCs on the data blocks can be a significant (30%)
@@ -1157,6 +1158,9 @@ static void mmc_power_up(struct mmc_host *host)
{
{
	int bit;
	int bit;


	if (host->ios.power_mode == MMC_POWER_ON)
		return;

	mmc_host_clk_hold(host);
	mmc_host_clk_hold(host);


	/* If ocr is set, we use it */
	/* If ocr is set, we use it */
@@ -1199,6 +1203,10 @@ static void mmc_power_up(struct mmc_host *host)
void mmc_power_off(struct mmc_host *host)
void mmc_power_off(struct mmc_host *host)
{
{
	int err = 0;
	int err = 0;

	if (host->ios.power_mode == MMC_POWER_OFF)
		return;

	mmc_host_clk_hold(host);
	mmc_host_clk_hold(host);


	host->ios.clock = 0;
	host->ios.clock = 0;
@@ -2005,7 +2013,6 @@ EXPORT_SYMBOL(mmc_detect_card_removed);


void mmc_rescan(struct work_struct *work)
void mmc_rescan(struct work_struct *work)
{
{
	static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
	struct mmc_host *host =
	struct mmc_host *host =
		container_of(work, struct mmc_host, detect.work);
		container_of(work, struct mmc_host, detect.work);
	int i;
	int i;
@@ -2044,8 +2051,12 @@ void mmc_rescan(struct work_struct *work)
	 */
	 */
	mmc_bus_put(host);
	mmc_bus_put(host);


	if (host->ops->get_cd && host->ops->get_cd(host) == 0)
	if (host->ops->get_cd && host->ops->get_cd(host) == 0) {
		mmc_claim_host(host);
		mmc_power_off(host);
		mmc_release_host(host);
		goto out;
		goto out;
	}


	mmc_claim_host(host);
	mmc_claim_host(host);
	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
@@ -2063,7 +2074,8 @@ void mmc_rescan(struct work_struct *work)


void mmc_start_host(struct mmc_host *host)
void mmc_start_host(struct mmc_host *host)
{
{
	mmc_power_off(host);
	host->f_init = max(freqs[0], host->f_min);
	mmc_power_up(host);
	mmc_detect_change(host, 0);
	mmc_detect_change(host, 0);
}
}