Skip to content

Commit

Permalink
mmc: omap_hsmmc: fix a few bugs when setting the clock divisor
Browse files Browse the repository at this point in the history
There are two pieces of code which are similar, but not the same.
Each of them contains a bug.

The SYSCTL register should be read before writing to it in
omap_hsmmc_context_restore() to retain the state of the reserved bits.

Before setting the clock divisor and DTO bits the value from the SYSCTL
register should be masked properly. We were lucky to have no problems
with DTO bits. So, make sure we have clear DTO bits properly in
omap_hsmmc_set_ios().

Additionally get rid of msleep(1). The actual time is rarely higher
than 30us on OMAP 3630.

The resulting pieces of code are refactored into the
omap_hsmmc_set_clock() function.

Signed-off-by: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
  • Loading branch information
Andy Shevchenko authored and Chris Ball committed Jul 21, 2011
1 parent e0c7f99 commit 5934df2
Showing 1 changed file with 28 additions and 31 deletions.
59 changes: 28 additions & 31 deletions drivers/mmc/host/omap_hsmmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,32 @@ static u16 calc_divisor(struct mmc_ios *ios)
return dsor;
}

static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
{
struct mmc_ios *ios = &host->mmc->ios;
unsigned long regval;
unsigned long timeout;

dev_dbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);

omap_hsmmc_stop_clock(host);

regval = OMAP_HSMMC_READ(host->base, SYSCTL);
regval = regval & ~(CLKD_MASK | DTO_MASK);
regval = regval | (calc_divisor(ios) << 6) | (DTO << 16);
OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);

/* Wait till the ICS bit is set */
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
&& time_before(jiffies, timeout))
cpu_relax();

omap_hsmmc_start_clock(host);
}

#ifdef CONFIG_PM

/*
Expand Down Expand Up @@ -702,19 +728,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
break;
}

omap_hsmmc_stop_clock(host);

OMAP_HSMMC_WRITE(host->base, SYSCTL,
(calc_divisor(ios) << 6) | (DTO << 16));
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);

timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
&& time_before(jiffies, timeout))
;

omap_hsmmc_start_clock(host);
omap_hsmmc_set_clock(host);

con = OMAP_HSMMC_READ(host->base, CON);
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
Expand Down Expand Up @@ -1614,8 +1628,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
unsigned long regval;
unsigned long timeout;
u32 con;
int do_send_init_stream = 0;

Expand Down Expand Up @@ -1677,22 +1689,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
}

omap_hsmmc_stop_clock(host);

regval = OMAP_HSMMC_READ(host->base, SYSCTL);
regval = regval & ~(CLKD_MASK);
regval = regval | (calc_divisor(ios) << 6) | (DTO << 16);
OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);

/* Wait till the ICS bit is set */
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
&& time_before(jiffies, timeout))
msleep(1);

omap_hsmmc_start_clock(host);
omap_hsmmc_set_clock(host);

if (do_send_init_stream)
send_init_stream(host);
Expand Down

0 comments on commit 5934df2

Please sign in to comment.