1
0
Fork 0

MMC highlights for 3.6:

Core:
  - Rename cd-gpio to slot-gpio and extend it to support more
    slot GPIO functions, such as write-protect.
  - Add a function to get regulators (Vdd and Vccq) for a host.
 
 Drivers:
  - sdhci-pxav2, sdhci-pxav3: Add device tree support.
  - sdhi: Add device tree support.
  - sh_mmcif: Add support for regulators, device tree, slot-gpio.
  - tmio: Add regulator support, use slot-gpio.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJQDGaKAAoJEHNBYZ7TNxYMskYQAI0RsnncLyT8DXsnZw5jjNf2
 sB7h3Sc2ExIQUIrqwxaRbzbAyVCDBAK4+FyBK7iN3KqyaL6G6mWAzXInxfw0hkpy
 kV66hIXzzTbGryvndlPzwRcswJrPKWwwTMOx68Cyw12UIPn1ZK7LRGYTeUOEBkYf
 QNGYo8Jcq+Kr+FnR6Ios5NH1t9EghCUDVquTzqOalhovN8QeMD2FxbgbegSS3Tu0
 qqle1eCCd5uaDwC13Nf0kb8qvlXi164UlT367T+C0QXKoQiaB7/K6tr2BgzQBNgI
 chAi3JEGU70WnQ2LavfWxO/F7nEEp+In3g1uMb6kj1yWhBq2yJV7seMCCEt6gzqe
 djFm4JfRgEPBSUnUD0G6vP8SVJNHr/L6WXyGgtFyOa+kFVNF2rhN1Y+rzBoLdxt3
 R0sZp5lhSQtuxT88GfEqG1bqOkGbiWWvuzQqLn1Z/32pwY/6/ZvN9K52xr4pY4Tn
 xZ7vNij8Vho0MaUSueVrrLHoTcwYqZjujMlDm0Uyu3eRHSH7ON7DC9rwPJ2PWXxR
 vxKgatXSIMpL9COQfoB9LWlRPrZLsKmt0WcBCRYS49zO6bkWmsZkzyUnJ0PuBIl2
 NojLQNbaAAwtfhGmmxhaCNT9QeBfNg2U0jhCct0wLe3eCw0V1PFvb8HBlPBqrttc
 A1sqnOt5LHBxgh2uRB5a
 =OBTA
 -----END PGP SIGNATURE-----

Merge tag 'mmc-merge-for-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

Pull MMC updates from Chris Ball:
 "MMC highlights for 3.6:

  Core:
   - Rename cd-gpio to slot-gpio and extend it to support more slot GPIO
     functions, such as write-protect.
   - Add a function to get regulators (Vdd and Vccq) for a host.

  Drivers:
   - sdhci-pxav2, sdhci-pxav3: Add device tree support.
   - sdhi: Add device tree support.
   - sh_mmcif: Add support for regulators, device tree, slot-gpio.
   - tmio: Add regulator support, use slot-gpio."

* tag 'mmc-merge-for-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (62 commits)
  mmc: sdhci-dove: Prepare for common clock framework
  mmc: sdhci-dove: Add SDHCI_QUIRK_NO_HISPD_BIT
  mmc: omap_hsmmc: ensure probe returns error upon resource failure
  mmc: mxs-mmc: Add wp-inverted property
  mmc: esdhc: Fix DMA_MASK to not break mx25 DMA access
  mmc: core: reset signal voltage on power up
  mmc: sd: Fix sd current limit setting
  mmc: omap_hsmmc: add clk_prepare and clk_unprepare
  mmc: sdhci: When a UHS switch fails, cycle power if regulator is used
  mmc: atmel-mci: modify CLKDIV displaying in debugfs
  mmc: atmel-mci: fix incorrect setting of host->data to NULL
  mmc: sdhci: poll for card even when card is logically unremovable
  mmc: sdhci: Introduce new flag SDHCI_USING_RETUNING_TIMER
  mmc: sdio: Change pr_warning to pr_warn_ratelimited
  mmc: core: Simplify and fix for SD switch processing
  mmc: sdhci: restore host settings when card is removed
  mmc: sdhci: fix incorrect command used in tuning
  mmc: sdhci-pci: CaFe has broken card detection
  mmc: sdhci: Report failure reasons for all cases in sdhci_add_host()
  mmc: s3cmci: Convert s3cmci driver to gpiolib API
  ...
hifive-unleashed-5.1
Linus Torvalds 2012-07-22 16:36:08 -07:00
commit a6be1fcbc5
43 changed files with 1057 additions and 519 deletions

View File

@ -3,21 +3,22 @@
The Enhanced Secure Digital Host Controller provides an interface
for MMC, SD, and SDIO types of memory cards.
This file documents differences between the core properties described
by mmc.txt and the properties used by the sdhci-esdhc driver.
Required properties:
- compatible : should be
"fsl,<chip>-esdhc", "fsl,esdhc"
- reg : should contain eSDHC registers location and length.
- interrupts : should contain eSDHC interrupt.
- interrupt-parent : interrupt source phandle.
- clock-frequency : specifies eSDHC base clock frequency.
- sdhci,wp-inverted : (optional) specifies that eSDHC controller
reports inverted write-protect state; New devices should use
the generic "wp-inverted" property.
- sdhci,1-bit-only : (optional) specifies that a controller can
only handle 1-bit data transfers. New devices should use the
generic "bus-width = <1>" property.
- sdhci,auto-cmd12: (optional) specifies that a controller can
only handle auto CMD12.
Optional properties:
- sdhci,wp-inverted : specifies that eSDHC controller reports
inverted write-protect state; New devices should use the generic
"wp-inverted" property.
- sdhci,1-bit-only : specifies that a controller can only handle
1-bit data transfers. New devices should use the generic
"bus-width = <1>" property.
- sdhci,auto-cmd12: specifies that a controller can only handle auto
CMD12.
Example:

View File

@ -3,17 +3,15 @@
The Enhanced Secure Digital Host Controller on Freescale i.MX family
provides an interface for MMC, SD, and SDIO types of memory cards.
This file documents differences between the core properties described
by mmc.txt and the properties used by the sdhci-esdhc-imx driver.
Required properties:
- compatible : Should be "fsl,<chip>-esdhc"
- reg : Should contain eSDHC registers location and length
- interrupts : Should contain eSDHC interrupt
Optional properties:
- non-removable : Indicate the card is wired to host permanently
- fsl,cd-internal : Indicate to use controller internal card detection
- fsl,wp-internal : Indicate to use controller internal write protection
- cd-gpios : Specify GPIOs for card detection
- wp-gpios : Specify GPIOs for write protection
Examples:

View File

@ -1,8 +1,9 @@
MMC/SD/SDIO slot directly connected to a SPI bus
This file documents differences between the core properties described
by mmc.txt and the properties used by the mmc_spi driver.
Required properties:
- compatible : should be "mmc-spi-slot".
- reg : should specify SPI address (chip-select number).
- spi-max-frequency : maximum frequency for this device (Hz).
- voltage-ranges : two cells are required, first cell specifies minimum
slot voltage (mV), second cell specifies maximum slot voltage (mV).
@ -11,8 +12,7 @@ Required properties:
Optional properties:
- gpios : may specify GPIOs in this order: Card-Detect GPIO,
Write-Protect GPIO. Note that this does not follow the
binding from mmc.txt, for historic reasons.
- interrupts : the interrupt of a card detect interrupt.
binding from mmc.txt, for historical reasons.
- interrupt-parent : the phandle for the interrupt controller that
services interrupts for this device.

View File

@ -2,13 +2,17 @@ These properties are common to multiple MMC host controllers. Any host
that requires the respective functionality should implement them using
these definitions.
Interpreted by the OF core:
- reg: Registers location and length.
- interrupts: Interrupts used by the MMC controller.
Required properties:
- bus-width: Number of data lines, can be <1>, <4>, or <8>
Optional properties:
- cd-gpios : Specify GPIOs for card detection, see gpio binding
- wp-gpios : Specify GPIOs for write protection, see gpio binding
- cd-inverted: when present, polarity on the wp gpio line is inverted
- cd-gpios: Specify GPIOs for card detection, see gpio binding
- wp-gpios: Specify GPIOs for write protection, see gpio binding
- cd-inverted: when present, polarity on the cd gpio line is inverted
- wp-inverted: when present, polarity on the wp gpio line is inverted
- non-removable: non-removable slot (like eMMC)
- max-frequency: maximum operating clock frequency

View File

@ -1,19 +1,15 @@
* ARM PrimeCell MultiMedia Card Interface (MMCI) PL180/1
The ARM PrimeCell MMCI PL180 and PL181 provides and interface for
The ARM PrimeCell MMCI PL180 and PL181 provides an interface for
reading and writing to MultiMedia and SD cards alike.
This file documents differences between the core properties described
by mmc.txt and the properties used by the mmci driver.
Required properties:
- compatible : contains "arm,pl18x", "arm,primecell".
- reg : contains pl18x registers and length.
- interrupts : contains the device IRQ(s).
- arm,primecell-periphid : contains the PrimeCell Peripheral ID.
Optional properties:
- wp-gpios : contains any write protect (ro) gpios
- cd-gpios : contains any card detection gpios
- cd-inverted : indicates whether the cd gpio is inverted
- max-frequency : contains the maximum operating frequency
- bus-width : number of data lines, can be <1>, <4>, or <8>
- mmc-cap-mmc-highspeed : indicates whether MMC is high speed capable
- mmc-cap-sd-highspeed : indicates whether SD is high speed capable

View File

@ -3,16 +3,14 @@
The Freescale MXS Synchronous Serial Ports (SSP) can act as a MMC controller
to support MMC, SD, and SDIO types of memory cards.
This file documents differences between the core properties in mmc.txt
and the properties used by the mxsmmc driver.
Required properties:
- compatible: Should be "fsl,<chip>-mmc". The supported chips include
imx23 and imx28.
- reg: Should contain registers location and length
- interrupts: Should contain ERROR and DMA interrupts
- fsl,ssp-dma-channel: APBH DMA channel for the SSP
- bus-width: Number of data lines, can be <1>, <4>, or <8>
Optional properties:
- wp-gpios: Specify GPIOs for write protection
Examples:

View File

@ -3,15 +3,13 @@
This controller on Tegra family SoCs provides an interface for MMC, SD,
and SDIO types of memory cards.
This file documents differences between the core properties described
by mmc.txt and the properties used by the sdhci-tegra driver.
Required properties:
- compatible : Should be "nvidia,<chip>-sdhci"
- reg : Should contain SD/MMC registers location and length
- interrupts : Should contain SD/MMC interrupt
- bus-width : Number of data lines, can be <1>, <4>, or <8>
Optional properties:
- cd-gpios : Specify GPIOs for card detection
- wp-gpios : Specify GPIOs for write protection
- power-gpios : Specify GPIOs for power control
Example:

View File

@ -0,0 +1,21 @@
* Marvell sdhci-pxa v2/v3 controller
This file documents differences between the core properties in mmc.txt
and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
Required properties:
- compatible: Should be "mrvl,pxav2-mmc" or "mrvl,pxav3-mmc".
Optional properties:
- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
Example:
sdhci@d4280800 {
compatible = "mrvl,pxav3-mmc";
reg = <0xd4280800 0x800>;
bus-width = <8>;
interrupts = <27>;
non-removable;
mrvl,clk-delay-cycles = <31>;
};

View File

@ -3,21 +3,20 @@
The Highspeed MMC Host Controller on TI OMAP family
provides an interface for MMC, SD, and SDIO types of memory cards.
This file documents differences between the core properties described
by mmc.txt and the properties used by the omap_hsmmc driver.
Required properties:
- compatible:
Should be "ti,omap2-hsmmc", for OMAP2 controllers
Should be "ti,omap3-hsmmc", for OMAP3 controllers
Should be "ti,omap4-hsmmc", for OMAP4 controllers
- ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
- reg : should contain hsmmc registers location and length
Optional properties:
ti,dual-volt: boolean, supports dual voltage cards
<supply-name>-supply: phandle to the regulator device tree node
"supply-name" examples are "vmmc", "vmmc_aux" etc
bus-width: Number of data lines, default assumed is 1 if the property is missing.
cd-gpios: GPIOs for card detection
wp-gpios: GPIOs for write protection
ti,non-removable: non-removable slot (like eMMC)
ti,needs-special-reset: Requires a special softreset sequence

View File

@ -850,9 +850,7 @@ out:
goto retry;
if (!err)
mmc_blk_reset_success(md, type);
spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
blk_end_request(req, err, blk_rq_bytes(req));
return err ? 0 : 1;
}
@ -934,9 +932,7 @@ out_retry:
if (!err)
mmc_blk_reset_success(md, type);
out:
spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
blk_end_request(req, err, blk_rq_bytes(req));
return err ? 0 : 1;
}
@ -951,9 +947,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
if (ret)
ret = -EIO;
spin_lock_irq(&md->lock);
__blk_end_request_all(req, ret);
spin_unlock_irq(&md->lock);
blk_end_request_all(req, ret);
return ret ? 0 : 1;
}
@ -1252,14 +1246,10 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
blocks = mmc_sd_num_wr_blocks(card);
if (blocks != (u32)-1) {
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, 0, blocks << 9);
spin_unlock_irq(&md->lock);
ret = blk_end_request(req, 0, blocks << 9);
}
} else {
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
spin_unlock_irq(&md->lock);
ret = blk_end_request(req, 0, brq->data.bytes_xfered);
}
return ret;
}
@ -1311,10 +1301,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
* A block was successfully transferred.
*/
mmc_blk_reset_success(md, type);
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, 0,
ret = blk_end_request(req, 0,
brq->data.bytes_xfered);
spin_unlock_irq(&md->lock);
/*
* If the blk_end_request function returns non-zero even
* though all data has been transferred and no errors
@ -1364,10 +1352,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
* time, so we only reach here after trying to
* read a single sector.
*/
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, -EIO,
ret = blk_end_request(req, -EIO,
brq->data.blksz);
spin_unlock_irq(&md->lock);
if (!ret)
goto start_new_req;
break;
@ -1388,12 +1374,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
return 1;
cmd_abort:
spin_lock_irq(&md->lock);
if (mmc_card_removed(card))
req->cmd_flags |= REQ_QUIET;
while (ret)
ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
spin_unlock_irq(&md->lock);
ret = blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
start_new_req:
if (rqc) {
@ -1417,9 +1401,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
ret = mmc_blk_part_switch(card, md);
if (ret) {
if (req) {
spin_lock_irq(&md->lock);
__blk_end_request_all(req, -EIO);
spin_unlock_irq(&md->lock);
blk_end_request_all(req, -EIO);
}
ret = 0;
goto out;

View File

@ -7,6 +7,6 @@ mmc_core-y := core.o bus.o host.o \
mmc.o mmc_ops.o sd.o sd_ops.o \
sdio.o sdio_ops.o sdio_bus.o \
sdio_cis.o sdio_io.o sdio_irq.o \
quirks.o cd-gpio.o
quirks.o slot-gpio.o
mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o

View File

@ -1,83 +0,0 @@
/*
* Generic GPIO card-detect helper
*
* Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/mmc/cd-gpio.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/slab.h>
struct mmc_cd_gpio {
unsigned int gpio;
char label[0];
};
static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id)
{
/* Schedule a card detection after a debounce timeout */
mmc_detect_change(dev_id, msecs_to_jiffies(100));
return IRQ_HANDLED;
}
int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio)
{
size_t len = strlen(dev_name(host->parent)) + 4;
struct mmc_cd_gpio *cd;
int irq = gpio_to_irq(gpio);
int ret;
if (irq < 0)
return irq;
cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
if (!cd)
return -ENOMEM;
snprintf(cd->label, len, "%s cd", dev_name(host->parent));
ret = gpio_request_one(gpio, GPIOF_DIR_IN, cd->label);
if (ret < 0)
goto egpioreq;
ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_ONESHOT, cd->label, host);
if (ret < 0)
goto eirqreq;
cd->gpio = gpio;
host->hotplug.irq = irq;
host->hotplug.handler_priv = cd;
return 0;
eirqreq:
gpio_free(gpio);
egpioreq:
kfree(cd);
return ret;
}
EXPORT_SYMBOL(mmc_cd_gpio_request);
void mmc_cd_gpio_free(struct mmc_host *host)
{
struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
if (!cd)
return;
free_irq(host->hotplug.irq, host);
gpio_free(cd->gpio);
kfree(cd);
}
EXPORT_SYMBOL(mmc_cd_gpio_free);

View File

@ -404,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card)
{
int err;
u32 status;
unsigned long prg_wait;
BUG_ON(!card);
@ -419,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card)
goto out;
}
/*
* If the card status is in PRG-state, we can send the HPI command.
*/
if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
do {
/*
* We don't know when the HPI command will finish
* processing, so we need to resend HPI until out
* of prg-state, and keep checking the card status
* with SEND_STATUS. If a timeout error occurs when
* sending the HPI command, we are already out of
* prg-state.
*/
err = mmc_send_hpi_cmd(card, &status);
if (err)
pr_debug("%s: abort HPI (%d error)\n",
mmc_hostname(card->host), err);
switch (R1_CURRENT_STATE(status)) {
case R1_STATE_IDLE:
case R1_STATE_READY:
case R1_STATE_STBY:
/*
* In idle states, HPI is not needed and the caller
* can issue the next intended command immediately
*/
goto out;
case R1_STATE_PRG:
break;
default:
/* In all other states, it's illegal to issue HPI */
pr_debug("%s: HPI cannot be sent. Card state=%d\n",
mmc_hostname(card->host), R1_CURRENT_STATE(status));
err = -EINVAL;
goto out;
}
err = mmc_send_status(card, &status);
if (err)
break;
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
} else
pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
err = mmc_send_hpi_cmd(card, &status);
if (err)
goto out;
prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time);
do {
err = mmc_send_status(card, &status);
if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN)
break;
if (time_after(jiffies, prg_wait))
err = -ETIMEDOUT;
} while (!err);
out:
mmc_release_host(card->host);
@ -941,7 +950,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
return result;
}
EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
EXPORT_SYMBOL_GPL(mmc_regulator_get_ocrmask);
/**
* mmc_regulator_set_ocr - set regulator to match host->ios voltage
@ -1011,7 +1020,30 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
"could not set regulator OCR (%d)\n", result);
return result;
}
EXPORT_SYMBOL(mmc_regulator_set_ocr);
EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr);
int mmc_regulator_get_supply(struct mmc_host *mmc)
{
struct device *dev = mmc_dev(mmc);
struct regulator *supply;
int ret;
supply = devm_regulator_get(dev, "vmmc");
mmc->supply.vmmc = supply;
mmc->supply.vqmmc = devm_regulator_get(dev, "vqmmc");
if (IS_ERR(supply))
return PTR_ERR(supply);
ret = mmc_regulator_get_ocrmask(supply);
if (ret > 0)
mmc->ocr_avail = ret;
else
dev_warn(mmc_dev(mmc), "Failed getting OCR mask: %d\n", ret);
return 0;
}
EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
#endif /* CONFIG_REGULATOR */
@ -1180,6 +1212,9 @@ static void mmc_power_up(struct mmc_host *host)
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
/* Set signal voltage to 3.3V */
mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
/*
* This delay should be sufficient to allow the power supply
* to reach the minimum voltage.
@ -1931,9 +1966,6 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
*/
mmc_hw_reset_for_init(host);
/* Initialization should be done at 3.3 V I/O voltage. */
mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
/*
* sdio_reset sends CMD52 to reset card. Since we do not know
* if the card is being re-initialized, just send it. CMD52
@ -2075,6 +2107,7 @@ void mmc_rescan(struct work_struct *work)
void mmc_start_host(struct mmc_host *host)
{
host->f_init = max(freqs[0], host->f_min);
host->rescan_disable = 0;
mmc_power_up(host);
mmc_detect_change(host, 0);
}
@ -2088,6 +2121,7 @@ void mmc_stop_host(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
#endif
host->rescan_disable = 1;
cancel_delayed_work_sync(&host->detect);
mmc_flush_scheduled_work();

View File

@ -32,6 +32,7 @@
static void mmc_host_classdev_release(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
mutex_destroy(&host->slot.lock);
kfree(host);
}
@ -312,6 +313,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
if (!host)
return NULL;
/* scanning will be enabled when we're ready */
host->rescan_disable = 1;
spin_lock(&mmc_host_lock);
err = idr_get_new(&mmc_host_idr, host, &host->index);
spin_unlock(&mmc_host_lock);
@ -327,6 +330,9 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
mmc_host_clk_init(host);
mutex_init(&host->slot.lock);
host->slot.cd_irq = -EINVAL;
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);

View File

@ -818,9 +818,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!mmc_host_is_spi(host))
mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
/* Initialization should be done at 3.3 V I/O voltage. */
mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
/*
* Since we're changing the OCR value, we seem to
* need to tell some cards to go back to the idle

View File

@ -569,7 +569,6 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
cmd.opcode = opcode;
cmd.arg = card->rca << 16 | 1;
cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {

View File

@ -244,7 +244,7 @@ static int mmc_read_ssr(struct mmc_card *card)
* bitfield positions accordingly.
*/
au = UNSTUFF_BITS(ssr, 428 - 384, 4);
if (au > 0 || au <= 9) {
if (au > 0 && au <= 9) {
card->ssr.au = 1 << (au + 4);
es = UNSTUFF_BITS(ssr, 408 - 384, 16);
et = UNSTUFF_BITS(ssr, 402 - 384, 6);
@ -290,8 +290,12 @@ static int mmc_read_switch(struct mmc_card *card)
return -ENOMEM;
}
/* Find out the supported Bus Speed Modes. */
err = mmc_sd_switch(card, 0, 0, 1, status);
/*
* Find out the card's support bits with a mode 0 operation.
* The argument does not matter, as the support bits do not
* change with the arguments.
*/
err = mmc_sd_switch(card, 0, 0, 0, status);
if (err) {
/*
* If the host or the card can't do the switch,
@ -312,46 +316,8 @@ static int mmc_read_switch(struct mmc_card *card)
if (card->scr.sda_spec3) {
card->sw_caps.sd3_bus_mode = status[13];
/* Find out Driver Strengths supported by the card */
err = mmc_sd_switch(card, 0, 2, 1, status);
if (err) {
/*
* If the host or the card can't do the switch,
* fail more gracefully.
*/
if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
goto out;
pr_warning("%s: problem reading "
"Driver Strength.\n",
mmc_hostname(card->host));
err = 0;
goto out;
}
/* Driver Strengths supported by the card */
card->sw_caps.sd3_drv_type = status[9];
/* Find out Current Limits supported by the card */
err = mmc_sd_switch(card, 0, 3, 1, status);
if (err) {
/*
* If the host or the card can't do the switch,
* fail more gracefully.
*/
if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
goto out;
pr_warning("%s: problem reading "
"Current Limit.\n",
mmc_hostname(card->host));
err = 0;
goto out;
}
card->sw_caps.sd3_curr_limit = status[7];
}
out:
@ -551,60 +517,80 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
return 0;
}
/* Get host's max current setting at its current voltage */
static u32 sd_get_host_max_current(struct mmc_host *host)
{
u32 voltage, max_current;
voltage = 1 << host->ios.vdd;
switch (voltage) {
case MMC_VDD_165_195:
max_current = host->max_current_180;
break;
case MMC_VDD_29_30:
case MMC_VDD_30_31:
max_current = host->max_current_300;
break;
case MMC_VDD_32_33:
case MMC_VDD_33_34:
max_current = host->max_current_330;
break;
default:
max_current = 0;
}
return max_current;
}
static int sd_set_current_limit(struct mmc_card *card, u8 *status)
{
int current_limit = 0;
int current_limit = SD_SET_CURRENT_NO_CHANGE;
int err;
u32 max_current;
/*
* Current limit switch is only defined for SDR50, SDR104, and DDR50
* bus speed modes. For other bus speed modes, we set the default
* current limit of 200mA.
* bus speed modes. For other bus speed modes, we do not change the
* current limit.
*/
if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
(card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
(card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
if (card->host->caps & MMC_CAP_MAX_CURRENT_800) {
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
current_limit = SD_SET_CURRENT_LIMIT_800;
else if (card->sw_caps.sd3_curr_limit &
SD_MAX_CURRENT_600)
current_limit = SD_SET_CURRENT_LIMIT_600;
else if (card->sw_caps.sd3_curr_limit &
SD_MAX_CURRENT_400)
current_limit = SD_SET_CURRENT_LIMIT_400;
else if (card->sw_caps.sd3_curr_limit &
SD_MAX_CURRENT_200)
current_limit = SD_SET_CURRENT_LIMIT_200;
} else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) {
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
current_limit = SD_SET_CURRENT_LIMIT_600;
else if (card->sw_caps.sd3_curr_limit &
SD_MAX_CURRENT_400)
current_limit = SD_SET_CURRENT_LIMIT_400;
else if (card->sw_caps.sd3_curr_limit &
SD_MAX_CURRENT_200)
current_limit = SD_SET_CURRENT_LIMIT_200;
} else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) {
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
current_limit = SD_SET_CURRENT_LIMIT_400;
else if (card->sw_caps.sd3_curr_limit &
SD_MAX_CURRENT_200)
current_limit = SD_SET_CURRENT_LIMIT_200;
} else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) {
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
current_limit = SD_SET_CURRENT_LIMIT_200;
}
} else
if ((card->sd_bus_speed != UHS_SDR50_BUS_SPEED) &&
(card->sd_bus_speed != UHS_SDR104_BUS_SPEED) &&
(card->sd_bus_speed != UHS_DDR50_BUS_SPEED))
return 0;
/*
* Host has different current capabilities when operating at
* different voltages, so find out its max current first.
*/
max_current = sd_get_host_max_current(card->host);
/*
* We only check host's capability here, if we set a limit that is
* higher than the card's maximum current, the card will be using its
* maximum current, e.g. if the card's maximum current is 300ma, and
* when we set current limit to 200ma, the card will draw 200ma, and
* when we set current limit to 400/600/800ma, the card will draw its
* maximum 300ma from the host.
*/
if (max_current >= 800)
current_limit = SD_SET_CURRENT_LIMIT_800;
else if (max_current >= 600)
current_limit = SD_SET_CURRENT_LIMIT_600;
else if (max_current >= 400)
current_limit = SD_SET_CURRENT_LIMIT_400;
else if (max_current >= 200)
current_limit = SD_SET_CURRENT_LIMIT_200;
err = mmc_sd_switch(card, 1, 3, current_limit, status);
if (err)
return err;
if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
err = mmc_sd_switch(card, 1, 3, current_limit, status);
if (err)
return err;
if (((status[15] >> 4) & 0x0F) != current_limit)
pr_warning("%s: Problem setting current limit!\n",
mmc_hostname(card->host));
if (((status[15] >> 4) & 0x0F) != current_limit)
pr_warning("%s: Problem setting current limit!\n",
mmc_hostname(card->host));
}
return 0;
}
@ -726,6 +712,7 @@ struct device_type sd_type = {
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
{
int err;
u32 max_current;
/*
* Since we're changing the OCR value, we seem to
@ -753,9 +740,12 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
ocr |= SD_OCR_S18R;
/* If the host can supply more than 150mA, XPC should be set to 1. */
if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
MMC_CAP_SET_XPC_180))
/*
* If the host can supply more than 150mA at current voltage,
* XPC should be set to 1.
*/
max_current = sd_get_host_max_current(host);
if (max_current > 150)
ocr |= SD_OCR_XPC;
try_again:
@ -911,9 +901,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
BUG_ON(!host);
WARN_ON(!host->claimed);
/* The initialization should be done at 3.3 V I/O voltage. */
mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
err = mmc_sd_get_cid(host, ocr, cid, &rocr);
if (err)
return err;

View File

@ -591,9 +591,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
* Inform the card of the voltage
*/
if (!powered_resume) {
/* The initialization should be done at 3.3 V I/O voltage. */
mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
err = mmc_send_io_op_cond(host, host->ocr, &ocr);
if (err)
goto err;
@ -1006,10 +1003,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
* restore the correct voltage setting of the card.
*/
/* The initialization should be done at 3.3 V I/O voltage. */
if (!mmc_card_keep_power(host))
mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);

View File

@ -313,7 +313,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
if (ret == -ENOENT) {
/* warn about unknown tuples */
pr_warning("%s: queuing unknown"
pr_warn_ratelimited("%s: queuing unknown"
" CIS tuple 0x%02x (%u bytes)\n",
mmc_hostname(card->host),
tpl_code, tpl_link);

View File

@ -0,0 +1,188 @@
/*
* Generic GPIO card-detect helper
*
* Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
#include <linux/slab.h>
struct mmc_gpio {
int ro_gpio;
int cd_gpio;
char *ro_label;
char cd_label[0];
};
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
/* Schedule a card detection after a debounce timeout */
mmc_detect_change(dev_id, msecs_to_jiffies(100));
return IRQ_HANDLED;
}
static int mmc_gpio_alloc(struct mmc_host *host)
{
size_t len = strlen(dev_name(host->parent)) + 4;
struct mmc_gpio *ctx;
mutex_lock(&host->slot.lock);
ctx = host->slot.handler_priv;
if (!ctx) {
/*
* devm_kzalloc() can be called after device_initialize(), even
* before device_add(), i.e., between mmc_alloc_host() and
* mmc_add_host()
*/
ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + 2 * len,
GFP_KERNEL);
if (ctx) {
ctx->ro_label = ctx->cd_label + len;
snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
ctx->cd_gpio = -EINVAL;
ctx->ro_gpio = -EINVAL;
host->slot.handler_priv = ctx;
}
}
mutex_unlock(&host->slot.lock);
return ctx ? 0 : -ENOMEM;
}
int mmc_gpio_get_ro(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
if (!ctx || !gpio_is_valid(ctx->ro_gpio))
return -ENOSYS;
return !gpio_get_value_cansleep(ctx->ro_gpio) ^
!!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH);
}
EXPORT_SYMBOL(mmc_gpio_get_ro);
int mmc_gpio_get_cd(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
if (!ctx || !gpio_is_valid(ctx->cd_gpio))
return -ENOSYS;
return !gpio_get_value_cansleep(ctx->cd_gpio) ^
!!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
}
EXPORT_SYMBOL(mmc_gpio_get_cd);
int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
{
struct mmc_gpio *ctx;
int ret;
if (!gpio_is_valid(gpio))
return -EINVAL;
ret = mmc_gpio_alloc(host);
if (ret < 0)
return ret;
ctx = host->slot.handler_priv;
return gpio_request_one(gpio, GPIOF_DIR_IN, ctx->ro_label);
}
EXPORT_SYMBOL(mmc_gpio_request_ro);
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
{
struct mmc_gpio *ctx;
int irq = gpio_to_irq(gpio);
int ret;
ret = mmc_gpio_alloc(host);
if (ret < 0)
return ret;
ctx = host->slot.handler_priv;
ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
if (ret < 0)
/*
* don't bother freeing memory. It might still get used by other
* slot functions, in any case it will be freed, when the device
* is destroyed.
*/
return ret;
/*
* Even if gpio_to_irq() returns a valid IRQ number, the platform might
* still prefer to poll, e.g., because that IRQ number is already used
* by another unit and cannot be shared.
*/
if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
irq = -EINVAL;
if (irq >= 0) {
ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
ctx->cd_label, host);
if (ret < 0)
irq = ret;
}
host->slot.cd_irq = irq;
if (irq < 0)
host->caps |= MMC_CAP_NEEDS_POLL;
ctx->cd_gpio = gpio;
return 0;
}
EXPORT_SYMBOL(mmc_gpio_request_cd);
void mmc_gpio_free_ro(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
int gpio;
if (!ctx || !gpio_is_valid(ctx->ro_gpio))
return;
gpio = ctx->ro_gpio;
ctx->ro_gpio = -EINVAL;
gpio_free(gpio);
}
EXPORT_SYMBOL(mmc_gpio_free_ro);
void mmc_gpio_free_cd(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
int gpio;
if (!ctx || !gpio_is_valid(ctx->cd_gpio))
return;
if (host->slot.cd_irq >= 0) {
free_irq(host->slot.cd_irq, host);
host->slot.cd_irq = -EINVAL;
}
gpio = ctx->cd_gpio;
ctx->cd_gpio = -EINVAL;
gpio_free(gpio);
}
EXPORT_SYMBOL(mmc_gpio_free_cd);

View File

@ -391,11 +391,17 @@ static int atmci_regs_show(struct seq_file *s, void *v)
clk_disable(host->mck);
spin_unlock_bh(&host->lock);
seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
seq_printf(s, "MR:\t0x%08x%s%s ",
buf[ATMCI_MR / 4],
buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "",
buf[ATMCI_MR / 4] & 0xff);
buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "");
if (host->caps.has_odd_clk_div)
seq_printf(s, "{CLKDIV,CLKODD}=%u\n",
((buf[ATMCI_MR / 4] & 0xff) << 1)
| ((buf[ATMCI_MR / 4] >> 16) & 1));
else
seq_printf(s, "CLKDIV=%u\n",
(buf[ATMCI_MR / 4] & 0xff));
seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]);
seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]);
seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]);
@ -1685,7 +1691,6 @@ static void atmci_tasklet_func(unsigned long priv)
dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
host->cmd = NULL;
host->data = NULL;
data->bytes_xfered = data->blocks * data->blksz;
data->error = 0;
atmci_command_complete(host, mrq->stop);
@ -1699,6 +1704,7 @@ static void atmci_tasklet_func(unsigned long priv)
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
state = STATE_WAITING_NOTBUSY;
}
host->data = NULL;
break;
case STATE_END_REQUEST:

View File

@ -405,11 +405,23 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
static int dw_mci_idmac_init(struct dw_mci *host)
{
struct idmac_desc *p;
int i;
int i, dma_support;
/* Number of descriptors in the ring buffer */
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
/* Check if Hardware Configuration Register has support for DMA */
dma_support = (mci_readl(host, HCON) >> 16) & 0x3;
if (!dma_support || dma_support > 2) {
dev_err(&host->dev,
"Host Controller does not support IDMA Tx.\n");
host->dma_ops = NULL;
return -ENODEV;
}
dev_info(&host->dev, "Using internal DMA controller.\n");
/* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
@ -1876,7 +1888,6 @@ static void dw_mci_init_dma(struct dw_mci *host)
/* Determine which DMA interface to use */
#ifdef CONFIG_MMC_DW_IDMAC
host->dma_ops = &dw_mci_idmac_ops;
dev_info(&host->dev, "Using internal DMA controller.\n");
#endif
if (!host->dma_ops)
@ -2175,7 +2186,7 @@ int dw_mci_resume(struct dw_mci *host)
return ret;
}
if (host->dma_ops->init)
if (host->use_dma && host->dma_ops->init)
host->dma_ops->init(host);
/* Restore the old value at FIFOTH register */

View File

@ -164,16 +164,23 @@ struct mxs_mmc_host {
spinlock_t lock;
int sdio_irq_en;
int wp_gpio;
bool wp_inverted;
};
static int mxs_mmc_get_ro(struct mmc_host *mmc)
{
struct mxs_mmc_host *host = mmc_priv(mmc);
int ret;
if (!gpio_is_valid(host->wp_gpio))
return -EINVAL;
return gpio_get_value(host->wp_gpio);
ret = gpio_get_value(host->wp_gpio);
if (host->wp_inverted)
ret = !ret;
return ret;
}
static int mxs_mmc_get_cd(struct mmc_host *mmc)
@ -707,6 +714,8 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct pinctrl *pinctrl;
int ret = 0, irq_err, irq_dma;
dma_cap_mask_t mask;
struct regulator *reg_vmmc;
enum of_gpio_flags flags;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@ -747,6 +756,16 @@ static int mxs_mmc_probe(struct platform_device *pdev)
host->mmc = mmc;
host->sdio_irq_en = 0;
reg_vmmc = devm_regulator_get(&pdev->dev, "vmmc");
if (!IS_ERR(reg_vmmc)) {
ret = regulator_enable(reg_vmmc);
if (ret) {
dev_err(&pdev->dev,
"Failed to enable vmmc regulator: %d\n", ret);
goto out_mmc_free;
}
}
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl);
@ -785,7 +804,10 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mmc->caps |= MMC_CAP_4_BIT_DATA;
else if (bus_width == 8)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
host->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0,
&flags);
if (flags & OF_GPIO_ACTIVE_LOW)
host->wp_inverted = 1;
} else {
if (pdata->flags & SLOTF_8_BIT_CAPABLE)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;

View File

@ -1089,7 +1089,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
/* Disable the clocks */
pm_runtime_put_sync(host->dev);
if (host->dbclk)
clk_disable(host->dbclk);
clk_disable_unprepare(host->dbclk);
/* Turn the power off */
ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
@ -1100,7 +1100,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
vdd);
pm_runtime_get_sync(host->dev);
if (host->dbclk)
clk_enable(host->dbclk);
clk_prepare_enable(host->dbclk);
if (ret != 0)
goto err;
@ -1899,7 +1899,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
if (IS_ERR(host->dbclk)) {
dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n");
host->dbclk = NULL;
} else if (clk_enable(host->dbclk) != 0) {
} else if (clk_prepare_enable(host->dbclk) != 0) {
dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
clk_put(host->dbclk);
host->dbclk = NULL;
@ -1931,6 +1931,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
if (!res) {
dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
ret = -ENXIO;
goto err_irq;
}
host->dma_line_tx = res->start;
@ -1938,6 +1939,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
if (!res) {
dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
ret = -ENXIO;
goto err_irq;
}
host->dma_line_rx = res->start;
@ -2023,7 +2025,7 @@ err_irq:
pm_runtime_disable(host->dev);
clk_put(host->fclk);
if (host->dbclk) {
clk_disable(host->dbclk);
clk_disable_unprepare(host->dbclk);
clk_put(host->dbclk);
}
err1:
@ -2058,7 +2060,7 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
pm_runtime_disable(host->dev);
clk_put(host->fclk);
if (host->dbclk) {
clk_disable(host->dbclk);
clk_disable_unprepare(host->dbclk);
clk_put(host->dbclk);
}
@ -2116,7 +2118,7 @@ static int omap_hsmmc_suspend(struct device *dev)
}
if (host->dbclk)
clk_disable(host->dbclk);
clk_disable_unprepare(host->dbclk);
err:
pm_runtime_put_sync(host->dev);
return ret;
@ -2137,7 +2139,7 @@ static int omap_hsmmc_resume(struct device *dev)
pm_runtime_get_sync(host->dev);
if (host->dbclk)
clk_enable(host->dbclk);
clk_prepare_enable(host->dbclk);
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
omap_hsmmc_conf_bus_power(host);

View File

@ -26,7 +26,6 @@
#include <mach/dma.h>
#include <mach/regs-sdi.h>
#include <mach/regs-gpio.h>
#include <plat/mci.h>
@ -1237,12 +1236,9 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_ON:
case MMC_POWER_UP:
s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK);
s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD);
s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0);
s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2);
s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3);
/* Configure GPE5...GPE10 pins in SD mode */
s3c_gpio_cfgall_range(S3C2410_GPE(5), 6, S3C_GPIO_SFN(2),
S3C_GPIO_PULL_NONE);
if (host->pdata->set_power)
host->pdata->set_power(ios->power_mode, ios->vdd);

View File

@ -20,11 +20,17 @@
*/
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/mmc/host.h>
#include "sdhci-pltfm.h"
struct sdhci_dove_priv {
struct clk *clk;
};
static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
{
u16 ret;
@ -66,16 +72,57 @@ static struct sdhci_pltfm_data sdhci_dove_pdata = {
.quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
SDHCI_QUIRK_NO_BUSY_IRQ |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_FORCE_DMA,
SDHCI_QUIRK_FORCE_DMA |
SDHCI_QUIRK_NO_HISPD_BIT,
};
static int __devinit sdhci_dove_probe(struct platform_device *pdev)
{
return sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_dove_priv *priv;
int ret;
ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
if (ret)
goto sdhci_dove_register_fail;
priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv),
GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "unable to allocate private data");
ret = -ENOMEM;
goto sdhci_dove_allocate_fail;
}
host = platform_get_drvdata(pdev);
pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv;
priv->clk = clk_get(&pdev->dev, NULL);
if (!IS_ERR(priv->clk))
clk_prepare_enable(priv->clk);
return 0;
sdhci_dove_allocate_fail:
sdhci_pltfm_unregister(pdev);
sdhci_dove_register_fail:
return ret;
}
static int __devexit sdhci_dove_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_dove_priv *priv = pltfm_host->priv;
if (priv->clk) {
if (!IS_ERR(priv->clk)) {
clk_disable_unprepare(priv->clk);
clk_put(priv->clk);
}
devm_kfree(&pdev->dev, priv->clk);
}
return sdhci_pltfm_unregister(pdev);
}

View File

@ -299,6 +299,8 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
u32 new_val;
switch (reg) {
@ -315,8 +317,11 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
SDHCI_CTRL_D3CD);
/* ensure the endianess */
new_val |= ESDHC_HOST_CONTROL_LE;
/* DMA mode bits are shifted */
new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
/* bits 8&9 are reserved on mx25 */
if (!is_imx25_esdhc(imx_data)) {
/* DMA mode bits are shifted */
new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
}
esdhc_clrset_le(host, 0xffff, new_val, reg);
return;

View File

@ -157,6 +157,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = {
static const struct sdhci_pci_fixes sdhci_cafe = {
.quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
SDHCI_QUIRK_NO_BUSY_IRQ |
SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
};

View File

@ -28,6 +28,9 @@
#include <linux/mmc/host.h>
#include <linux/platform_data/pxa_sdhci.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
@ -121,6 +124,48 @@ static struct sdhci_ops pxav2_sdhci_ops = {
.platform_8bit_width = pxav2_mmc_set_width,
};
#ifdef CONFIG_OF
static const struct of_device_id sdhci_pxav2_of_match[] = {
{
.compatible = "mrvl,pxav2-mmc",
},
{},
};
MODULE_DEVICE_TABLE(of, sdhci_pxav2_of_match);
static struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev)
{
struct sdhci_pxa_platdata *pdata;
struct device_node *np = dev->of_node;
u32 bus_width;
u32 clk_delay_cycles;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
if (of_find_property(np, "non-removable", NULL))
pdata->flags |= PXA_FLAG_CARD_PERMANENT;
of_property_read_u32(np, "bus-width", &bus_width);
if (bus_width == 8)
pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT;
of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
if (clk_delay_cycles > 0) {
pdata->clk_delay_sel = 1;
pdata->clk_delay_cycles = clk_delay_cycles;
}
return pdata;
}
#else
static inline struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev)
{
return NULL;
}
#endif
static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
{
struct sdhci_pltfm_host *pltfm_host;
@ -128,6 +173,8 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct sdhci_host *host = NULL;
struct sdhci_pxa *pxa = NULL;
const struct of_device_id *match;
int ret;
struct clk *clk;
@ -156,6 +203,10 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
| SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
match = of_match_device(of_match_ptr(sdhci_pxav2_of_match), &pdev->dev);
if (match) {
pdata = pxav2_get_mmc_pdata(dev);
}
if (pdata) {
if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
/* on-chip device */
@ -218,6 +269,9 @@ static struct platform_driver sdhci_pxav2_driver = {
.driver = {
.name = "sdhci-pxav2",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = sdhci_pxav2_of_match,
#endif
.pm = SDHCI_PLTFM_PMOPS,
},
.probe = sdhci_pxav2_probe,

View File

@ -28,6 +28,9 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
@ -164,6 +167,46 @@ static struct sdhci_ops pxav3_sdhci_ops = {
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
};
#ifdef CONFIG_OF
static const struct of_device_id sdhci_pxav3_of_match[] = {
{
.compatible = "mrvl,pxav3-mmc",
},
{},
};
MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
{
struct sdhci_pxa_platdata *pdata;
struct device_node *np = dev->of_node;
u32 bus_width;
u32 clk_delay_cycles;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
if (of_find_property(np, "non-removable", NULL))
pdata->flags |= PXA_FLAG_CARD_PERMANENT;
of_property_read_u32(np, "bus-width", &bus_width);
if (bus_width == 8)
pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT;
of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
if (clk_delay_cycles > 0)
pdata->clk_delay_cycles = clk_delay_cycles;
return pdata;
}
#else
static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
{
return NULL;
}
#endif
static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
{
struct sdhci_pltfm_host *pltfm_host;
@ -171,6 +214,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct sdhci_host *host = NULL;
struct sdhci_pxa *pxa = NULL;
const struct of_device_id *match;
int ret;
struct clk *clk;
@ -202,6 +247,10 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
/* enable 1/8V DDR capable */
host->mmc->caps |= MMC_CAP_1_8V_DDR;
match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
if (match)
pdata = pxav3_get_mmc_pdata(dev);
if (pdata) {
if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
/* on-chip device */
@ -263,6 +312,9 @@ static int __devexit sdhci_pxav3_remove(struct platform_device *pdev)
static struct platform_driver sdhci_pxav3_driver = {
.driver = {
.name = "sdhci-pxav3",
#ifdef CONFIG_OF
.of_match_table = sdhci_pxav3_of_match,
#endif
.owner = THIS_MODULE,
.pm = SDHCI_PLTFM_PMOPS,
},

View File

@ -27,6 +27,7 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include "sdhci.h"
@ -244,6 +245,19 @@ static void sdhci_init(struct sdhci_host *host, int soft)
static void sdhci_reinit(struct sdhci_host *host)
{
sdhci_init(host, 0);
/*
* Retuning stuffs are affected by different cards inserted and only
* applicable to UHS-I cards. So reset these fields to their initial
* value when card is removed.
*/
if (host->flags & SDHCI_USING_RETUNING_TIMER) {
host->flags &= ~SDHCI_USING_RETUNING_TIMER;
del_timer_sync(&host->tuning_timer);
host->flags &= ~SDHCI_NEEDS_RETUNING;
host->mmc->max_blk_count =
(host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
}
sdhci_enable_card_detection(host);
}
@ -1245,6 +1259,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
struct sdhci_host *host;
bool present;
unsigned long flags;
u32 tuning_opcode;
host = mmc_priv(mmc);
@ -1292,8 +1307,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
*/
if ((host->flags & SDHCI_NEEDS_RETUNING) &&
!(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
/* eMMC uses cmd21 while sd and sdio use cmd19 */
tuning_opcode = mmc->card->type == MMC_TYPE_MMC ?
MMC_SEND_TUNING_BLOCK_HS200 :
MMC_SEND_TUNING_BLOCK;
spin_unlock_irqrestore(&host->lock, flags);
sdhci_execute_tuning(mmc, mrq->cmd->opcode);
sdhci_execute_tuning(mmc, tuning_opcode);
spin_lock_irqsave(&host->lock, flags);
/* Restore original mmc_request structure */
@ -1663,11 +1682,15 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
pwr &= ~SDHCI_POWER_ON;
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
if (host->vmmc)
regulator_disable(host->vmmc);
/* Wait for 1ms as per the spec */
usleep_range(1000, 1500);
pwr |= SDHCI_POWER_ON;
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
if (host->vmmc)
regulator_enable(host->vmmc);
pr_info(DRIVER_NAME ": Switching to 1.8V signalling "
"voltage failed, retrying with S18R set to 0\n");
@ -1855,6 +1878,7 @@ out:
*/
if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count &&
(host->tuning_mode == SDHCI_TUNING_MODE_1)) {
host->flags |= SDHCI_USING_RETUNING_TIMER;
mod_timer(&host->tuning_timer, jiffies +
host->tuning_count * HZ);
/* Tuning mode 1 limits the maximum data length to 4MB */
@ -1872,10 +1896,10 @@ out:
* try tuning again at a later time, when the re-tuning timer expires.
* So for these controllers, we return 0. Since there might be other
* controllers who do not have this capability, we return error for
* them.
* them. SDHCI_USING_RETUNING_TIMER means the host is currently using
* a retuning timer to do the retuning for the card.
*/
if (err && host->tuning_count &&
host->tuning_mode == SDHCI_TUNING_MODE_1)
if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
err = 0;
sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
@ -2382,7 +2406,6 @@ out:
int sdhci_suspend_host(struct sdhci_host *host)
{
int ret;
bool has_tuning_timer;
if (host->ops->platform_suspend)
host->ops->platform_suspend(host);
@ -2390,16 +2413,14 @@ int sdhci_suspend_host(struct sdhci_host *host)
sdhci_disable_card_detection(host);
/* Disable tuning since we are suspending */
has_tuning_timer = host->version >= SDHCI_SPEC_300 &&
host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1;
if (has_tuning_timer) {
if (host->flags & SDHCI_USING_RETUNING_TIMER) {
del_timer_sync(&host->tuning_timer);
host->flags &= ~SDHCI_NEEDS_RETUNING;
}
ret = mmc_suspend_host(host->mmc);
if (ret) {
if (has_tuning_timer) {
if (host->flags & SDHCI_USING_RETUNING_TIMER) {
host->flags |= SDHCI_NEEDS_RETUNING;
mod_timer(&host->tuning_timer, jiffies +
host->tuning_count * HZ);
@ -2450,8 +2471,7 @@ int sdhci_resume_host(struct sdhci_host *host)
host->ops->platform_resume(host);
/* Set the re-tuning expiration flag */
if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
(host->tuning_mode == SDHCI_TUNING_MODE_1))
if (host->flags & SDHCI_USING_RETUNING_TIMER)
host->flags |= SDHCI_NEEDS_RETUNING;
return ret;
@ -2490,8 +2510,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
int ret = 0;
/* Disable tuning since we are suspending */
if (host->version >= SDHCI_SPEC_300 &&
host->tuning_mode == SDHCI_TUNING_MODE_1) {
if (host->flags & SDHCI_USING_RETUNING_TIMER) {
del_timer_sync(&host->tuning_timer);
host->flags &= ~SDHCI_NEEDS_RETUNING;
}
@ -2532,8 +2551,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
sdhci_do_enable_preset_value(host, true);
/* Set the re-tuning expiration flag */
if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
(host->tuning_mode == SDHCI_TUNING_MODE_1))
if (host->flags & SDHCI_USING_RETUNING_TIMER)
host->flags |= SDHCI_NEEDS_RETUNING;
spin_lock_irqsave(&host->lock, flags);
@ -2584,7 +2602,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
int sdhci_add_host(struct sdhci_host *host)
{
struct mmc_host *mmc;
u32 caps[2];
u32 caps[2] = {0, 0};
u32 max_current_caps;
unsigned int ocr_avail;
int ret;
@ -2614,8 +2632,10 @@ int sdhci_add_host(struct sdhci_host *host)
caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
sdhci_readl(host, SDHCI_CAPABILITIES);
caps[1] = (host->version >= SDHCI_SPEC_300) ?
sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0;
if (host->version >= SDHCI_SPEC_300)
caps[1] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ?
host->caps1 :
sdhci_readl(host, SDHCI_CAPABILITIES_1);
if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
host->flags |= SDHCI_USE_SDMA;
@ -2779,7 +2799,7 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
mmc_card_is_removable(mmc))
!(host->mmc->caps & MMC_CAP_NONREMOVABLE))
mmc->caps |= MMC_CAP_NEEDS_POLL;
/* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
@ -2837,6 +2857,30 @@ int sdhci_add_host(struct sdhci_host *host)
SDHCI_RETUNING_MODE_SHIFT;
ocr_avail = 0;
host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
host->vmmc = NULL;
}
#ifdef CONFIG_REGULATOR
if (host->vmmc) {
ret = regulator_is_supported_voltage(host->vmmc, 3300000,
3300000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
caps[0] &= ~SDHCI_CAN_VDD_330;
ret = regulator_is_supported_voltage(host->vmmc, 3000000,
3000000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
caps[0] &= ~SDHCI_CAN_VDD_300;
ret = regulator_is_supported_voltage(host->vmmc, 1800000,
1800000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
caps[0] &= ~SDHCI_CAN_VDD_180;
}
#endif /* CONFIG_REGULATOR */
/*
* According to SD Host Controller spec v3.00, if the Host System
* can afford more than 150mA, Host Driver should set XPC to 1. Also
@ -2845,55 +2889,45 @@ int sdhci_add_host(struct sdhci_host *host)
* value.
*/
max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
if (!max_current_caps && host->vmmc) {
u32 curr = regulator_get_current_limit(host->vmmc);
if (curr > 0) {
/* convert to SDHCI_MAX_CURRENT format */
curr = curr/1000; /* convert to mA */
curr = curr/SDHCI_MAX_CURRENT_MULTIPLIER;
curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
max_current_caps =
(curr << SDHCI_MAX_CURRENT_330_SHIFT) |
(curr << SDHCI_MAX_CURRENT_300_SHIFT) |
(curr << SDHCI_MAX_CURRENT_180_SHIFT);
}
}
if (caps[0] & SDHCI_CAN_VDD_330) {
int max_current_330;
ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
max_current_330 = ((max_current_caps &
mmc->max_current_330 = ((max_current_caps &
SDHCI_MAX_CURRENT_330_MASK) >>
SDHCI_MAX_CURRENT_330_SHIFT) *
SDHCI_MAX_CURRENT_MULTIPLIER;
if (max_current_330 > 150)
mmc->caps |= MMC_CAP_SET_XPC_330;
}
if (caps[0] & SDHCI_CAN_VDD_300) {
int max_current_300;
ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
max_current_300 = ((max_current_caps &
mmc->max_current_300 = ((max_current_caps &
SDHCI_MAX_CURRENT_300_MASK) >>
SDHCI_MAX_CURRENT_300_SHIFT) *
SDHCI_MAX_CURRENT_MULTIPLIER;
if (max_current_300 > 150)
mmc->caps |= MMC_CAP_SET_XPC_300;
}
if (caps[0] & SDHCI_CAN_VDD_180) {
int max_current_180;
ocr_avail |= MMC_VDD_165_195;
max_current_180 = ((max_current_caps &
mmc->max_current_180 = ((max_current_caps &
SDHCI_MAX_CURRENT_180_MASK) >>
SDHCI_MAX_CURRENT_180_SHIFT) *
SDHCI_MAX_CURRENT_MULTIPLIER;
if (max_current_180 > 150)
mmc->caps |= MMC_CAP_SET_XPC_180;
/* Maximum current capabilities of the host at 1.8V */
if (max_current_180 >= 800)
mmc->caps |= MMC_CAP_MAX_CURRENT_800;
else if (max_current_180 >= 600)
mmc->caps |= MMC_CAP_MAX_CURRENT_600;
else if (max_current_180 >= 400)
mmc->caps |= MMC_CAP_MAX_CURRENT_400;
else
mmc->caps |= MMC_CAP_MAX_CURRENT_200;
}
mmc->ocr_avail = ocr_avail;
@ -2992,13 +3026,10 @@ int sdhci_add_host(struct sdhci_host *host)
ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
mmc_hostname(mmc), host);
if (ret)
if (ret) {
pr_err("%s: Failed to request IRQ %d: %d\n",
mmc_hostname(mmc), host->irq, ret);
goto untasklet;
host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
host->vmmc = NULL;
}
sdhci_init(host, 0);
@ -3016,8 +3047,11 @@ int sdhci_add_host(struct sdhci_host *host)
host->led.brightness_set = sdhci_led_control;
ret = led_classdev_register(mmc_dev(mmc), &host->led);
if (ret)
if (ret) {
pr_err("%s: Failed to register LED device: %d\n",
mmc_hostname(mmc), ret);
goto reset;
}
#endif
mmiowb();
@ -3081,8 +3115,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
free_irq(host->irq, host);
del_timer_sync(&host->timer);
if (host->version >= SDHCI_SPEC_300)
del_timer_sync(&host->tuning_timer);
tasklet_kill(&host->card_tasklet);
tasklet_kill(&host->finish_tasklet);

View File

@ -205,6 +205,7 @@
#define SDHCI_CAPABILITIES_1 0x44
#define SDHCI_MAX_CURRENT 0x48
#define SDHCI_MAX_CURRENT_LIMIT 0xFF
#define SDHCI_MAX_CURRENT_330_MASK 0x0000FF
#define SDHCI_MAX_CURRENT_330_SHIFT 0
#define SDHCI_MAX_CURRENT_300_MASK 0x00FF00

View File

@ -54,6 +54,8 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sh_mmcif.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/mod_devicetable.h>
#include <linux/pagemap.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
@ -384,6 +386,9 @@ static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
struct sh_dmae_slave *tx, *rx;
host->dma_active = false;
if (!pdata)
return;
/* We can only either use DMA for both Tx and Rx or not use it at all */
if (pdata->dma) {
dev_warn(&host->pd->dev,
@ -444,13 +449,14 @@ static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
{
struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
bool sup_pclk = p ? p->sup_pclk : false;
sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR);
if (!clk)
return;
if (p->sup_pclk && clk == host->clk)
if (sup_pclk && clk == host->clk)
sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
else
sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
@ -892,21 +898,15 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
switch (mrq->cmd->opcode) {
/* MMCIF does not support SD/SDIO command */
case SD_IO_SEND_OP_COND:
case MMC_SLEEP_AWAKE: /* = SD_IO_SEND_OP_COND (5) */
case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
if ((mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_BCR)
break;
case MMC_APP_CMD:
host->state = STATE_IDLE;
mrq->cmd->error = -ETIMEDOUT;
mmc_request_done(mmc, mrq);
return;
case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
if (!mrq->data) {
/* send_if_cond cmd (not support) */
host->state = STATE_IDLE;
mrq->cmd->error = -ETIMEDOUT;
mmc_request_done(mmc, mrq);
return;
}
break;
default:
break;
}
@ -916,10 +916,35 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
sh_mmcif_start_cmd(host, mrq);
}
static int sh_mmcif_clk_update(struct sh_mmcif_host *host)
{
int ret = clk_enable(host->hclk);
if (!ret) {
host->clk = clk_get_rate(host->hclk);
host->mmc->f_max = host->clk / 2;
host->mmc->f_min = host->clk / 512;
}
return ret;
}
static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios)
{
struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data;
struct mmc_host *mmc = host->mmc;
if (pd && pd->set_pwr)
pd->set_pwr(host->pd, ios->power_mode != MMC_POWER_OFF);
if (!IS_ERR(mmc->supply.vmmc))
/* Errors ignored... */
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
ios->power_mode ? ios->vdd : 0);
}
static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct sh_mmcif_host *host = mmc_priv(mmc);
struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
@ -937,6 +962,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
sh_mmcif_request_dma(host, host->pd->dev.platform_data);
host->card_present = true;
}
sh_mmcif_set_power(host, ios);
} else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
/* clock stop */
sh_mmcif_clock_control(host, 0);
@ -948,9 +974,10 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
if (host->power) {
pm_runtime_put(&host->pd->dev);
clk_disable(host->hclk);
host->power = false;
if (p->down_pwr && ios->power_mode == MMC_POWER_OFF)
p->down_pwr(host->pd);
if (ios->power_mode == MMC_POWER_OFF)
sh_mmcif_set_power(host, ios);
}
host->state = STATE_IDLE;
return;
@ -958,8 +985,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->clock) {
if (!host->power) {
if (p->set_pwr)
p->set_pwr(host->pd, ios->power_mode);
sh_mmcif_clk_update(host);
pm_runtime_get_sync(&host->pd->dev);
host->power = true;
sh_mmcif_sync_reset(host);
@ -975,8 +1001,12 @@ static int sh_mmcif_get_cd(struct mmc_host *mmc)
{
struct sh_mmcif_host *host = mmc_priv(mmc);
struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
int ret = mmc_gpio_get_cd(mmc);
if (!p->get_cd)
if (ret >= 0)
return ret;
if (!p || !p->get_cd)
return -ENOSYS;
else
return p->get_cd(host->pd);
@ -1242,12 +1272,28 @@ static void mmcif_timeout_work(struct work_struct *work)
mmc_request_done(host->mmc, mrq);
}
static void sh_mmcif_init_ocr(struct sh_mmcif_host *host)
{
struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data;
struct mmc_host *mmc = host->mmc;
mmc_regulator_get_supply(mmc);
if (!pd)
return;
if (!mmc->ocr_avail)
mmc->ocr_avail = pd->ocr;
else if (pd->ocr)
dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
}
static int __devinit sh_mmcif_probe(struct platform_device *pdev)
{
int ret = 0, irq[2];
struct mmc_host *mmc;
struct sh_mmcif_host *host;
struct sh_mmcif_plat_data *pd;
struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
struct resource *res;
void __iomem *reg;
char clk_name[8];
@ -1268,42 +1314,26 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "ioremap error.\n");
return -ENOMEM;
}
pd = pdev->dev.platform_data;
if (!pd) {
dev_err(&pdev->dev, "sh_mmcif plat data error.\n");
ret = -ENXIO;
goto clean_up;
}
mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev);
if (!mmc) {
ret = -ENOMEM;
goto clean_up;
goto ealloch;
}
host = mmc_priv(mmc);
host->mmc = mmc;
host->addr = reg;
host->timeout = 1000;
snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
host->hclk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(host->hclk)) {
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
ret = PTR_ERR(host->hclk);
goto clean_up1;
}
clk_enable(host->hclk);
host->clk = clk_get_rate(host->hclk);
host->pd = pdev;
spin_lock_init(&host->lock);
mmc->ops = &sh_mmcif_ops;
mmc->f_max = host->clk / 2;
mmc->f_min = host->clk / 512;
if (pd->ocr)
mmc->ocr_avail = pd->ocr;
sh_mmcif_init_ocr(host);
mmc->caps = MMC_CAP_MMC_HIGHSPEED;
if (pd->caps)
if (pd && pd->caps)
mmc->caps |= pd->caps;
mmc->max_segs = 32;
mmc->max_blk_size = 512;
@ -1311,34 +1341,52 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size;
mmc->max_seg_size = mmc->max_req_size;
sh_mmcif_sync_reset(host);
platform_set_drvdata(pdev, host);
pm_runtime_enable(&pdev->dev);
host->power = false;
snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
host->hclk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(host->hclk)) {
ret = PTR_ERR(host->hclk);
dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret);
goto eclkget;
}
ret = sh_mmcif_clk_update(host);
if (ret < 0)
goto eclkupdate;
ret = pm_runtime_resume(&pdev->dev);
if (ret < 0)
goto clean_up2;
goto eresume;
INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work);
sh_mmcif_sync_reset(host);
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host);
if (ret) {
dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
goto clean_up3;
goto ereqirq0;
}
ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host);
if (ret) {
dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
goto clean_up4;
goto ereqirq1;
}
if (pd && pd->use_cd_gpio) {
ret = mmc_gpio_request_cd(mmc, pd->cd_gpio);
if (ret < 0)
goto erqcd;
}
clk_disable(host->hclk);
ret = mmc_add_host(mmc);
if (ret < 0)
goto clean_up5;
goto emmcaddh;
dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
@ -1347,33 +1395,42 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
return ret;
clean_up5:
emmcaddh:
if (pd && pd->use_cd_gpio)
mmc_gpio_free_cd(mmc);
erqcd:
free_irq(irq[1], host);
clean_up4:
ereqirq1:
free_irq(irq[0], host);
clean_up3:
ereqirq0:
pm_runtime_suspend(&pdev->dev);
clean_up2:
pm_runtime_disable(&pdev->dev);
eresume:
clk_disable(host->hclk);
clean_up1:
eclkupdate:
clk_put(host->hclk);
eclkget:
pm_runtime_disable(&pdev->dev);
mmc_free_host(mmc);
clean_up:
if (reg)
iounmap(reg);
ealloch:
iounmap(reg);
return ret;
}
static int __devexit sh_mmcif_remove(struct platform_device *pdev)
{
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
int irq[2];
host->dying = true;
clk_enable(host->hclk);
pm_runtime_get_sync(&pdev->dev);
dev_pm_qos_hide_latency_limit(&pdev->dev);
if (pd && pd->use_cd_gpio)
mmc_gpio_free_cd(host->mmc);
mmc_remove_host(host->mmc);
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
@ -1395,9 +1452,9 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
clk_disable(host->hclk);
mmc_free_host(host->mmc);
pm_runtime_put_sync(&pdev->dev);
clk_disable(host->hclk);
pm_runtime_disable(&pdev->dev);
return 0;
@ -1406,24 +1463,18 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int sh_mmcif_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
struct sh_mmcif_host *host = dev_get_drvdata(dev);
int ret = mmc_suspend_host(host->mmc);
if (!ret) {
if (!ret)
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
clk_disable(host->hclk);
}
return ret;
}
static int sh_mmcif_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
clk_enable(host->hclk);
struct sh_mmcif_host *host = dev_get_drvdata(dev);
return mmc_resume_host(host->mmc);
}
@ -1432,6 +1483,12 @@ static int sh_mmcif_resume(struct device *dev)
#define sh_mmcif_resume NULL
#endif /* CONFIG_PM */
static const struct of_device_id mmcif_of_match[] = {
{ .compatible = "renesas,sh-mmcif" },
{ }
};
MODULE_DEVICE_TABLE(of, mmcif_of_match);
static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
.suspend = sh_mmcif_suspend,
.resume = sh_mmcif_resume,
@ -1443,6 +1500,8 @@ static struct platform_driver sh_mmcif_driver = {
.driver = {
.name = DRIVER_NAME,
.pm = &sh_mmcif_dev_pm_ops,
.owner = THIS_MODULE,
.of_match_table = mmcif_of_match,
},
};

View File

@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mmc/host.h>
@ -39,22 +40,39 @@ struct sh_mobile_sdhi {
struct tmio_mmc_dma dma_priv;
};
static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
{
struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
struct tmio_mmc_host *host = mmc_priv(mmc);
struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
int ret = clk_enable(priv->clk);
if (ret < 0)
return ret;
*f = clk_get_rate(priv->clk);
return 0;
}
static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
{
struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
struct tmio_mmc_host *host = mmc_priv(mmc);
struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
clk_disable(priv->clk);
}
static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
{
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
if (p && p->set_pwr)
p->set_pwr(pdev, state);
p->set_pwr(pdev, state);
}
static int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
{
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
if (p && p->get_cd)
return p->get_cd(pdev);
else
return -ENOSYS;
return p->get_cd(pdev);
}
static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
@ -116,12 +134,14 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
}
mmc_data = &priv->mmc_data;
p->pdata = mmc_data;
if (p->init) {
ret = p->init(pdev, &sdhi_ops);
if (ret)
goto einit;
if (p) {
p->pdata = mmc_data;
if (p->init) {
ret = p->init(pdev, &sdhi_ops);
if (ret)
goto einit;
}
}
snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
@ -132,9 +152,8 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
goto eclkget;
}
mmc_data->hclk = clk_get_rate(priv->clk);
mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
mmc_data->get_cd = sh_mobile_sdhi_get_cd;
mmc_data->clk_enable = sh_mobile_sdhi_clk_enable;
mmc_data->clk_disable = sh_mobile_sdhi_clk_disable;
mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
if (p) {
mmc_data->flags = p->tmio_flags;
@ -142,7 +161,12 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->ocr_mask = p->tmio_ocr_mask;
mmc_data->capabilities |= p->tmio_caps;
mmc_data->capabilities2 |= p->tmio_caps2;
mmc_data->cd_gpio = p->cd_gpio;
if (p->set_pwr)
mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
if (p->get_cd)
mmc_data->get_cd = sh_mobile_sdhi_get_cd;
if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
priv->param_tx.slave_id = p->dma_slave_tx;
@ -248,7 +272,7 @@ eirq_card_detect:
eprobe:
clk_put(priv->clk);
eclkget:
if (p->cleanup)
if (p && p->cleanup)
p->cleanup(pdev);
einit:
kfree(priv);
@ -263,7 +287,8 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
int i = 0, irq;
p->pdata = NULL;
if (p)
p->pdata = NULL;
tmio_mmc_host_remove(host);
@ -276,7 +301,7 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
clk_put(priv->clk);
if (p->cleanup)
if (p && p->cleanup)
p->cleanup(pdev);
kfree(priv);
@ -291,11 +316,18 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
.runtime_resume = tmio_mmc_host_runtime_resume,
};
static const struct of_device_id sh_mobile_sdhi_of_match[] = {
{ .compatible = "renesas,shmobile-sdhi" },
{ }
};
MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
static struct platform_driver sh_mobile_sdhi_driver = {
.driver = {
.name = "sh_mobile_sdhi",
.owner = THIS_MODULE,
.pm = &tmio_mmc_dev_pm_ops,
.of_match_table = sh_mobile_sdhi_of_match,
},
.probe = sh_mobile_sdhi_probe,
.remove = __devexit_p(sh_mobile_sdhi_remove),

View File

@ -34,8 +34,9 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/cd-gpio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/mmc/tmio.h>
#include <linux/module.h>
#include <linux/pagemap.h>
@ -305,8 +306,8 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
int c = cmd->opcode;
u32 irq_mask = TMIO_MASK_CMD;
/* Command 12 is handled by hardware */
if (cmd->opcode == 12 && !cmd->arg) {
/* CMD12 is handled by hardware */
if (cmd->opcode == MMC_STOP_TRANSMISSION && !cmd->arg) {
sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001);
return 0;
}
@ -449,7 +450,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
}
if (stop) {
if (stop->opcode == 12 && !stop->arg)
if (stop->opcode == MMC_STOP_TRANSMISSION && !stop->arg)
sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
else
BUG();
@ -751,6 +752,34 @@ fail:
mmc_request_done(mmc, mrq);
}
static int tmio_mmc_clk_update(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
struct tmio_mmc_data *pdata = host->pdata;
int ret;
if (!pdata->clk_enable)
return -ENOTSUPP;
ret = pdata->clk_enable(host->pdev, &mmc->f_max);
if (!ret)
mmc->f_min = mmc->f_max / 512;
return ret;
}
static void tmio_mmc_set_power(struct tmio_mmc_host *host, struct mmc_ios *ios)
{
struct mmc_host *mmc = host->mmc;
if (host->set_pwr)
host->set_pwr(host->pdev, ios->power_mode != MMC_POWER_OFF);
if (!IS_ERR(mmc->supply.vmmc))
/* Errors ignored... */
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
ios->power_mode ? ios->vdd : 0);
}
/* Set MMC clock / power.
* Note: This controller uses a simple divider scheme therefore it cannot
* run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
@ -797,32 +826,37 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
*/
if (ios->power_mode == MMC_POWER_ON && ios->clock) {
if (!host->power) {
tmio_mmc_clk_update(mmc);
pm_runtime_get_sync(dev);
host->power = true;
}
tmio_mmc_set_clock(host, ios->clock);
/* power up SD bus */
if (host->set_pwr)
host->set_pwr(host->pdev, 1);
tmio_mmc_set_power(host, ios);
/* start bus clock */
tmio_mmc_clk_start(host);
} else if (ios->power_mode != MMC_POWER_UP) {
if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
host->set_pwr(host->pdev, 0);
if (ios->power_mode == MMC_POWER_OFF)
tmio_mmc_set_power(host, ios);
if (host->power) {
struct tmio_mmc_data *pdata = host->pdata;
tmio_mmc_clk_stop(host);
host->power = false;
pm_runtime_put(dev);
if (pdata->clk_disable)
pdata->clk_disable(host->pdev);
}
tmio_mmc_clk_stop(host);
}
switch (ios->bus_width) {
case MMC_BUS_WIDTH_1:
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
break;
case MMC_BUS_WIDTH_4:
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
break;
if (host->power) {
switch (ios->bus_width) {
case MMC_BUS_WIDTH_1:
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
break;
case MMC_BUS_WIDTH_4:
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
break;
}
}
/* Let things settle. delay taken from winCE driver */
@ -841,6 +875,9 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
struct tmio_mmc_data *pdata = host->pdata;
int ret = mmc_gpio_get_ro(mmc);
if (ret >= 0)
return ret;
return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
@ -850,6 +887,9 @@ static int tmio_mmc_get_cd(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
struct tmio_mmc_data *pdata = host->pdata;
int ret = mmc_gpio_get_cd(mmc);
if (ret >= 0)
return ret;
if (!pdata->get_cd)
return -ENOSYS;
@ -865,6 +905,19 @@ static const struct mmc_host_ops tmio_mmc_ops = {
.enable_sdio_irq = tmio_mmc_enable_sdio_irq,
};
static void tmio_mmc_init_ocr(struct tmio_mmc_host *host)
{
struct tmio_mmc_data *pdata = host->pdata;
struct mmc_host *mmc = host->mmc;
mmc_regulator_get_supply(mmc);
if (!mmc->ocr_avail)
mmc->ocr_avail = pdata->ocr_mask ? : MMC_VDD_32_33 | MMC_VDD_33_34;
else if (pdata->ocr_mask)
dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
}
int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
struct platform_device *pdev,
struct tmio_mmc_data *pdata)
@ -904,18 +957,14 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
mmc->ops = &tmio_mmc_ops;
mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities;
mmc->f_max = pdata->hclk;
mmc->f_min = mmc->f_max / 512;
mmc->caps2 = pdata->capabilities2;
mmc->max_segs = 32;
mmc->max_blk_size = 512;
mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
mmc->max_segs;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;
if (pdata->ocr_mask)
mmc->ocr_avail = pdata->ocr_mask;
else
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
tmio_mmc_init_ocr(_host);
_host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
mmc->caps & MMC_CAP_NEEDS_POLL ||
@ -927,6 +976,11 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
if (ret < 0)
goto pm_disable;
if (tmio_mmc_clk_update(mmc) < 0) {
mmc->f_max = pdata->hclk;
mmc->f_min = mmc->f_max / 512;
}
/*
* There are 4 different scenarios for the card detection:
* 1) an external gpio irq handles the cd (best for power savings)
@ -937,7 +991,6 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
* While we increment the runtime PM counter for all scenarios when
* the mmc core activates us by calling an appropriate set_ios(), we
* must additionally ensure that in case 2) the tmio mmc hardware stays
* additionally ensure that in case 2) the tmio mmc hardware stays
* powered on during runtime for the card detection to work.
*/
if (_host->native_hotplug)
@ -948,6 +1001,17 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
_host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK);
tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
/* Unmask the IRQs we want to know about */
if (!_host->chan_rx)
irq_mask |= TMIO_MASK_READOP;
if (!_host->chan_tx)
irq_mask |= TMIO_MASK_WRITEOP;
if (!_host->native_hotplug)
irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
_host->sdcard_irq_mask &= ~irq_mask;
if (pdata->flags & TMIO_MMC_SDIO_IRQ)
tmio_mmc_enable_sdio_irq(mmc, 0);
@ -961,22 +1025,18 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
/* See if we also get DMA */
tmio_mmc_request_dma(_host, pdata);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (pdata->clk_disable)
pdata->clk_disable(pdev);
if (ret < 0) {
tmio_mmc_host_remove(_host);
return ret;
}
dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
/* Unmask the IRQs we want to know about */
if (!_host->chan_rx)
irq_mask |= TMIO_MASK_READOP;
if (!_host->chan_tx)
irq_mask |= TMIO_MASK_WRITEOP;
if (!_host->native_hotplug)
irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
tmio_mmc_enable_mmc_irqs(_host, irq_mask);
if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio);
ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio);
if (ret < 0) {
tmio_mmc_host_remove(_host);
return ret;
@ -1008,7 +1068,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
* This means we can miss a card-eject, but this is anyway
* possible, because of delayed processing of hotplug events.
*/
mmc_cd_gpio_free(mmc);
mmc_gpio_free_cd(mmc);
if (!host->native_hotplug)
pm_runtime_get_sync(&pdev->dev);

View File

@ -101,6 +101,7 @@ struct tmio_mmc_host;
struct tmio_mmc_data {
unsigned int hclk;
unsigned long capabilities;
unsigned long capabilities2;
unsigned long flags;
u32 ocr_mask; /* available voltages */
struct tmio_mmc_dma *dma;
@ -110,6 +111,9 @@ struct tmio_mmc_data {
void (*set_clk_div)(struct platform_device *host, int state);
int (*get_cd)(struct platform_device *host);
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
/* clock management callbacks */
int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
void (*clk_disable)(struct platform_device *pdev);
};
/*

View File

@ -149,6 +149,7 @@ struct sd_switch_caps {
#define SD_SET_CURRENT_LIMIT_400 1
#define SD_SET_CURRENT_LIMIT_600 2
#define SD_SET_CURRENT_LIMIT_800 3
#define SD_SET_CURRENT_NO_CHANGE (-1)
#define SD_MAX_CURRENT_200 (1 << SD_SET_CURRENT_LIMIT_200)
#define SD_MAX_CURRENT_400 (1 << SD_SET_CURRENT_LIMIT_400)

View File

@ -1,18 +0,0 @@
/*
* Generic GPIO card-detect helper header
*
* Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef MMC_CD_GPIO_H
#define MMC_CD_GPIO_H
struct mmc_host;
int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio);
void mmc_cd_gpio_free(struct mmc_host *host);
#endif

View File

@ -11,6 +11,7 @@
#define LINUX_MMC_HOST_H
#include <linux/leds.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/fault-inject.h>
@ -150,11 +151,31 @@ struct mmc_async_req {
int (*err_check) (struct mmc_card *, struct mmc_async_req *);
};
struct mmc_hotplug {
unsigned int irq;
/**
* struct mmc_slot - MMC slot functions
*
* @cd_irq: MMC/SD-card slot hotplug detection IRQ or -EINVAL
* @lock: protect the @handler_priv pointer
* @handler_priv: MMC/SD-card slot context
*
* Some MMC/SD host controllers implement slot-functions like card and
* write-protect detection natively. However, a large number of controllers
* leave these functions to the CPU. This struct provides a hook to attach
* such slot-function drivers.
*/
struct mmc_slot {
int cd_irq;
struct mutex lock;
void *handler_priv;
};
struct regulator;
struct mmc_supply {
struct regulator *vmmc; /* Card power supply */
struct regulator *vqmmc; /* Optional Vccq supply */
};
struct mmc_host {
struct device *parent;
struct device class_dev;
@ -168,6 +189,9 @@ struct mmc_host {
u32 ocr_avail_sd; /* SD-specific OCR */
u32 ocr_avail_mmc; /* MMC-specific OCR */
struct notifier_block pm_notify;
u32 max_current_330;
u32 max_current_300;
u32 max_current_180;
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
@ -211,16 +235,9 @@ struct mmc_host {
#define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */
#define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */
#define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */
#define MMC_CAP_SET_XPC_330 (1 << 20) /* Host supports >150mA current at 3.3V */
#define MMC_CAP_SET_XPC_300 (1 << 21) /* Host supports >150mA current at 3.0V */
#define MMC_CAP_SET_XPC_180 (1 << 22) /* Host supports >150mA current at 1.8V */
#define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
#define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
#define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */
#define MMC_CAP_MAX_CURRENT_200 (1 << 26) /* Host max current limit is 200mA */
#define MMC_CAP_MAX_CURRENT_400 (1 << 27) /* Host max current limit is 400mA */
#define MMC_CAP_MAX_CURRENT_600 (1 << 28) /* Host max current limit is 600mA */
#define MMC_CAP_MAX_CURRENT_800 (1 << 29) /* Host max current limit is 800mA */
#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
@ -238,6 +255,8 @@ struct mmc_host {
#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */
#define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */
#define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */
#define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */
#define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */
mmc_pm_flag_t pm_caps; /* supported pm features */
unsigned int power_notify_type;
@ -290,7 +309,7 @@ struct mmc_host {
struct delayed_work detect;
int detect_change; /* card detect flag */
struct mmc_hotplug hotplug;
struct mmc_slot slot;
const struct mmc_bus_ops *bus_ops; /* current bus driver */
unsigned int bus_refs; /* reference counter */
@ -309,6 +328,7 @@ struct mmc_host {
#ifdef CONFIG_REGULATOR
bool regulator_enabled; /* regulator state */
#endif
struct mmc_supply supply;
struct dentry *debugfs_root;
@ -357,13 +377,12 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
wake_up_process(host->sdio_irq_thread);
}
struct regulator;
#ifdef CONFIG_REGULATOR
int mmc_regulator_get_ocrmask(struct regulator *supply);
int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply,
unsigned short vdd_bit);
int mmc_regulator_get_supply(struct mmc_host *mmc);
#else
static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
{
@ -376,6 +395,11 @@ static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
{
return 0;
}
static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
{
return 0;
}
#endif
int mmc_card_awake(struct mmc_host *host);

View File

@ -122,6 +122,7 @@ struct sdhci_host {
#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
#define SDHCI_HS200_NEEDS_TUNING (1<<10) /* HS200 needs tuning */
#define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */
unsigned int version; /* SDHCI spec. version */
@ -155,7 +156,8 @@ struct sdhci_host {
struct timer_list timer; /* Timer for timeouts */
unsigned int caps; /* Alternative capabilities */
unsigned int caps; /* Alternative CAPABILITY_0 */
unsigned int caps1; /* Alternative CAPABILITY_1 */
unsigned int ocr_avail_sdio; /* OCR bit masks */
unsigned int ocr_avail_sd;

View File

@ -44,6 +44,8 @@ struct sh_mmcif_plat_data {
struct sh_mmcif_dma *dma; /* Deprecated. Instead */
unsigned int slave_id_tx; /* use embedded slave_id_[tr]x */
unsigned int slave_id_rx;
bool use_cd_gpio : 1;
unsigned int cd_gpio;
u8 sup_pclk; /* 1 :SH7757, 0: SH7724/SH7372 */
unsigned long caps;
u32 ocr;

View File

@ -23,6 +23,7 @@ struct sh_mobile_sdhi_info {
int dma_slave_rx;
unsigned long tmio_flags;
unsigned long tmio_caps;
unsigned long tmio_caps2;
u32 tmio_ocr_mask; /* available MMC voltages */
unsigned int cd_gpio;
struct tmio_mmc_data *pdata;

View File

@ -0,0 +1,24 @@
/*
* Generic GPIO card-detect helper header
*
* Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef MMC_SLOT_GPIO_H
#define MMC_SLOT_GPIO_H
struct mmc_host;
int mmc_gpio_get_ro(struct mmc_host *host);
int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio);
void mmc_gpio_free_ro(struct mmc_host *host);
int mmc_gpio_get_cd(struct mmc_host *host);
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio);
void mmc_gpio_free_cd(struct mmc_host *host);
#endif