Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/cjb/mmc

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (39 commits)
  mmc: davinci: add support for SDIO irq handling
  mmc: fix division by zero in MMC core
  mmc: tmio_mmc: fix CMD irq handling
  mmc: tmio_mmc: handle missing HW interrupts
  mfd: sh_mobile_sdhi: activate SDIO IRQ for tmio_mmc
  mmc: tmio_mmc: implement SDIO IRQ support
  mfd: sdhi: require the tmio-mmc driver to bounce unaligned buffers
  mmc: tmio_mmc: silence compiler warnings
  mmc: tmio_mmc: implement a bounce buffer for unaligned DMA
  mmc: tmio_mmc: merge the private header into the driver
  mmc: tmio_mmc: fix PIO fallback on DMA descriptor allocation failure
  mmc: tmio_mmc: allow multi-element scatter-gather lists
  mmc: Register debugfs dir before calling card probe function.
  mmc: MMC_BLOCK_MINORS should depend on MMC_BLOCK.
  mmc: Explain why we make adjacent mmc_bus_{put,get} calls during rescan.
  mmc: Fix sd/sdio/mmc initialization frequency retries
  mmc: fix mmc_set_bus_width_ddr() call without bus-width-test cap
  mmc: dw_mmc: Add Synopsys DesignWare mmc host driver.
  mmc: add sdhci-tegra driver for Tegra SoCs
  mmc: sdhci: add quirk for max len ADMA descriptors
  ...
  • Loading branch information
Linus Torvalds committed Jan 11, 2011
2 parents 5b2eef9 + f9db92c commit edb2877
Show file tree
Hide file tree
Showing 39 changed files with 4,083 additions and 492 deletions.
4 changes: 2 additions & 2 deletions arch/arm/mach-dove/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ static struct resource dove_sdio0_resources[] = {
};

static struct platform_device dove_sdio0 = {
.name = "sdhci-mv",
.name = "sdhci-dove",
.id = 0,
.dev = {
.dma_mask = &sdio_dmamask,
Expand Down Expand Up @@ -798,7 +798,7 @@ static struct resource dove_sdio1_resources[] = {
};

static struct platform_device dove_sdio1 = {
.name = "sdhci-mv",
.name = "sdhci-dove",
.id = 1,
.dev = {
.dma_mask = &sdio_dmamask,
Expand Down
29 changes: 29 additions & 0 deletions arch/arm/mach-tegra/include/mach/sdhci.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* include/asm-arm/arch-tegra/include/mach/sdhci.h
*
* Copyright (C) 2009 Palm, Inc.
* Author: Yvonne Yip <y@palm.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __ASM_ARM_ARCH_TEGRA_SDHCI_H
#define __ASM_ARM_ARCH_TEGRA_SDHCI_H

#include <linux/mmc/host.h>

struct tegra_sdhci_platform_data {
int cd_gpio;
int wp_gpio;
int power_gpio;
int is_8bit;
};

#endif
6 changes: 6 additions & 0 deletions drivers/mfd/sh_mobile_sdhi.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,17 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
*/
mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES;

/*
* All SDHI blocks support SDIO IRQ signalling.
*/
mmc_data->flags |= TMIO_MMC_SDIO_IRQ;

if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) {
priv->param_tx.slave_id = p->dma_slave_tx;
priv->param_rx.slave_id = p->dma_slave_rx;
priv->dma_priv.chan_priv_tx = &priv->param_tx;
priv->dma_priv.chan_priv_rx = &priv->param_rx;
priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
mmc_data->dma = &priv->dma_priv;
}

Expand Down
1 change: 1 addition & 0 deletions drivers/mmc/card/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ config MMC_BLOCK

config MMC_BLOCK_MINORS
int "Number of minors per block device"
depends on MMC_BLOCK
range 4 256
default 8
help
Expand Down
11 changes: 11 additions & 0 deletions drivers/mmc/core/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,14 @@ config MMC_UNSAFE_RESUME

This option sets a default which can be overridden by the
module parameter "removable=0" or "removable=1".

config MMC_CLKGATE
bool "MMC host clock gating (EXPERIMENTAL)"
depends on EXPERIMENTAL
help
This will attempt to aggressively gate the clock to the MMC card.
This is done to save power due to gating off the logic and bus
noise when the MMC card is not in use. Your host driver has to
support handling this in order for it to be of any use.

If unsure, say N.
8 changes: 4 additions & 4 deletions drivers/mmc/core/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,14 +303,14 @@ int mmc_add_card(struct mmc_card *card)
type, card->rca);
}

ret = device_add(&card->dev);
if (ret)
return ret;

#ifdef CONFIG_DEBUG_FS
mmc_add_card_debugfs(card);
#endif

ret = device_add(&card->dev);
if (ret)
return ret;

mmc_card_set_present(card);

return 0;
Expand Down
206 changes: 122 additions & 84 deletions drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/scatterlist.h>
#include <linux/log2.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
Expand Down Expand Up @@ -130,6 +131,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)

if (mrq->done)
mrq->done(mrq);

mmc_host_clk_gate(host);
}
}

Expand Down Expand Up @@ -190,6 +193,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->mrq = mrq;
}
}
mmc_host_clk_ungate(host);
host->ops->request(host, mrq);
}

Expand Down Expand Up @@ -295,8 +299,9 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
unsigned int timeout_us, limit_us;

timeout_us = data->timeout_ns / 1000;
timeout_us += data->timeout_clks * 1000 /
(card->host->ios.clock / 1000);
if (mmc_host_clk_rate(card->host))
timeout_us += data->timeout_clks * 1000 /
(mmc_host_clk_rate(card->host) / 1000);

if (data->flags & MMC_DATA_WRITE)
/*
Expand Down Expand Up @@ -614,6 +619,8 @@ static inline void mmc_set_ios(struct mmc_host *host)
ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width, ios->timing);

if (ios->clock > 0)
mmc_set_ungated(host);
host->ops->set_ios(host, ios);
}

Expand Down Expand Up @@ -641,6 +648,61 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)
mmc_set_ios(host);
}

#ifdef CONFIG_MMC_CLKGATE
/*
* This gates the clock by setting it to 0 Hz.
*/
void mmc_gate_clock(struct mmc_host *host)
{
unsigned long flags;

spin_lock_irqsave(&host->clk_lock, flags);
host->clk_old = host->ios.clock;
host->ios.clock = 0;
host->clk_gated = true;
spin_unlock_irqrestore(&host->clk_lock, flags);
mmc_set_ios(host);
}

/*
* This restores the clock from gating by using the cached
* clock value.
*/
void mmc_ungate_clock(struct mmc_host *host)
{
/*
* We should previously have gated the clock, so the clock shall
* be 0 here! The clock may however be 0 during initialization,
* when some request operations are performed before setting
* the frequency. When ungate is requested in that situation
* we just ignore the call.
*/
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);
}
}

void mmc_set_ungated(struct mmc_host *host)
{
unsigned long flags;

/*
* We've been given a new frequency while the clock is gated,
* so make sure we regard this as ungating it.
*/
spin_lock_irqsave(&host->clk_lock, flags);
host->clk_gated = false;
spin_unlock_irqrestore(&host->clk_lock, flags);
}

#else
void mmc_set_ungated(struct mmc_host *host)
{
}
#endif

/*
* Change the bus mode (open drain/push-pull) of a host.
*/
Expand Down Expand Up @@ -1424,35 +1486,57 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
}
EXPORT_SYMBOL(mmc_set_blocklen);

static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;

#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init);
#endif
mmc_power_up(host);
sdio_reset(host);
mmc_go_idle(host);

mmc_send_if_cond(host, host->ocr_avail);

/* Order's important: probe SDIO, then SD, then MMC */
if (!mmc_attach_sdio(host))
return 0;
if (!mmc_attach_sd(host))
return 0;
if (!mmc_attach_mmc(host))
return 0;

mmc_power_off(host);
return -EIO;
}

void mmc_rescan(struct work_struct *work)
{
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
struct mmc_host *host =
container_of(work, struct mmc_host, detect.work);
u32 ocr;
int err;
unsigned long flags;
int i;
const unsigned freqs[] = { 400000, 300000, 200000, 100000 };

spin_lock_irqsave(&host->lock, flags);

if (host->rescan_disable) {
spin_unlock_irqrestore(&host->lock, flags);
if (host->rescan_disable)
return;
}

spin_unlock_irqrestore(&host->lock, flags);


mmc_bus_get(host);

/* if there is a card registered, check whether it is still present */
if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead)
/*
* if there is a _removable_ card registered, check whether it is
* still present
*/
if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
&& mmc_card_is_removable(host))
host->bus_ops->detect(host);

/*
* Let mmc_bus_put() free the bus/bus_ops if we've found that
* the card is no longer present.
*/
mmc_bus_put(host);


mmc_bus_get(host);

/* if there still is a card present, stop here */
Expand All @@ -1461,8 +1545,6 @@ void mmc_rescan(struct work_struct *work)
goto out;
}

/* detect a newly inserted card */

/*
* Only we can add a new handler, so it's safe to
* release the lock here.
Expand All @@ -1472,72 +1554,16 @@ void mmc_rescan(struct work_struct *work)
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out;

mmc_claim_host(host);
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
mmc_claim_host(host);

if (freqs[i] >= host->f_min)
host->f_init = freqs[i];
else if (!i || freqs[i-1] > host->f_min)
host->f_init = host->f_min;
else {
mmc_release_host(host);
goto out;
}
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init);
#endif
mmc_power_up(host);
sdio_reset(host);
mmc_go_idle(host);

mmc_send_if_cond(host, host->ocr_avail);

/*
* First we search for SDIO...
*/
err = mmc_send_io_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_sdio(host, ocr)) {
mmc_claim_host(host);
/*
* Try SDMEM (but not MMC) even if SDIO
* is broken.
*/
if (mmc_send_app_op_cond(host, 0, &ocr))
goto out_fail;

if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
}
goto out;
}

/*
* ...then normal SD...
*/
err = mmc_send_app_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
goto out;
}

/*
* ...and finally MMC.
*/
err = mmc_send_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_mmc(host, ocr))
mmc_power_off(host);
goto out;
}

out_fail:
mmc_release_host(host);
mmc_power_off(host);
if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
break;
if (freqs[i] < host->f_min)
break;
}
out:
mmc_release_host(host);

out:
if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ);
}
Expand Down Expand Up @@ -1721,6 +1747,18 @@ int mmc_resume_host(struct mmc_host *host)
if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
mmc_power_up(host);
mmc_select_voltage(host, host->ocr);
/*
* Tell runtime PM core we just powered up the card,
* since it still believes the card is powered off.
* Note that currently runtime PM is only enabled
* for SDIO cards that are MMC_CAP_POWER_OFF_CARD
*/
if (mmc_card_sdio(host->card) &&
(host->caps & MMC_CAP_POWER_OFF_CARD)) {
pm_runtime_disable(&host->card->dev);
pm_runtime_set_active(&host->card->dev);
pm_runtime_enable(&host->card->dev);
}
}
BUG_ON(!host->bus_ops->resume);
err = host->bus_ops->resume(host);
Expand Down
Loading

0 comments on commit edb2877

Please sign in to comment.