Commit a6be1fcb authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 5b160bd4 30b87c60
...@@ -3,21 +3,22 @@ ...@@ -3,21 +3,22 @@
The Enhanced Secure Digital Host Controller provides an interface The Enhanced Secure Digital Host Controller provides an interface
for MMC, SD, and SDIO types of memory cards. 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: 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. - interrupt-parent : interrupt source phandle.
- clock-frequency : specifies eSDHC base clock frequency. - clock-frequency : specifies eSDHC base clock frequency.
- sdhci,wp-inverted : (optional) specifies that eSDHC controller
reports inverted write-protect state; New devices should use Optional properties:
the generic "wp-inverted" property. - sdhci,wp-inverted : specifies that eSDHC controller reports
- sdhci,1-bit-only : (optional) specifies that a controller can inverted write-protect state; New devices should use the generic
only handle 1-bit data transfers. New devices should use the "wp-inverted" property.
generic "bus-width = <1>" property. - sdhci,1-bit-only : specifies that a controller can only handle
- sdhci,auto-cmd12: (optional) specifies that a controller can 1-bit data transfers. New devices should use the generic
only handle auto CMD12. "bus-width = <1>" property.
- sdhci,auto-cmd12: specifies that a controller can only handle auto
CMD12.
Example: Example:
......
...@@ -3,17 +3,15 @@ ...@@ -3,17 +3,15 @@
The Enhanced Secure Digital Host Controller on Freescale i.MX family The Enhanced Secure Digital Host Controller on Freescale i.MX family
provides an interface for MMC, SD, and SDIO types of memory cards. 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: Required properties:
- compatible : Should be "fsl,<chip>-esdhc" - compatible : Should be "fsl,<chip>-esdhc"
- reg : Should contain eSDHC registers location and length
- interrupts : Should contain eSDHC interrupt
Optional properties: Optional properties:
- non-removable : Indicate the card is wired to host permanently
- fsl,cd-internal : Indicate to use controller internal card detection - fsl,cd-internal : Indicate to use controller internal card detection
- fsl,wp-internal : Indicate to use controller internal write protection - 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: Examples:
......
MMC/SD/SDIO slot directly connected to a SPI bus 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: 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). - spi-max-frequency : maximum frequency for this device (Hz).
- voltage-ranges : two cells are required, first cell specifies minimum - voltage-ranges : two cells are required, first cell specifies minimum
slot voltage (mV), second cell specifies maximum slot voltage (mV). slot voltage (mV), second cell specifies maximum slot voltage (mV).
...@@ -11,8 +12,7 @@ Required properties: ...@@ -11,8 +12,7 @@ Required properties:
Optional properties: Optional properties:
- gpios : may specify GPIOs in this order: Card-Detect GPIO, - gpios : may specify GPIOs in this order: Card-Detect GPIO,
Write-Protect GPIO. Note that this does not follow the Write-Protect GPIO. Note that this does not follow the
binding from mmc.txt, for historic reasons. binding from mmc.txt, for historical reasons.
- interrupts : the interrupt of a card detect interrupt.
- interrupt-parent : the phandle for the interrupt controller that - interrupt-parent : the phandle for the interrupt controller that
services interrupts for this device. services interrupts for this device.
......
...@@ -2,13 +2,17 @@ These properties are common to multiple MMC host controllers. Any host ...@@ -2,13 +2,17 @@ These properties are common to multiple MMC host controllers. Any host
that requires the respective functionality should implement them using that requires the respective functionality should implement them using
these definitions. these definitions.
Interpreted by the OF core:
- reg: Registers location and length.
- interrupts: Interrupts used by the MMC controller.
Required properties: Required properties:
- bus-width: Number of data lines, can be <1>, <4>, or <8> - bus-width: Number of data lines, can be <1>, <4>, or <8>
Optional properties: Optional properties:
- cd-gpios : Specify GPIOs for card detection, see gpio binding - cd-gpios: Specify GPIOs for card detection, see gpio binding
- wp-gpios : Specify GPIOs for write protection, 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-inverted: when present, polarity on the cd gpio line is inverted
- wp-inverted: when present, polarity on the wp gpio line is inverted - wp-inverted: when present, polarity on the wp gpio line is inverted
- non-removable: non-removable slot (like eMMC) - non-removable: non-removable slot (like eMMC)
- max-frequency: maximum operating clock frequency - max-frequency: maximum operating clock frequency
......
* ARM PrimeCell MultiMedia Card Interface (MMCI) PL180/1 * 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. 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: Required properties:
- compatible : contains "arm,pl18x", "arm,primecell". - 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. - arm,primecell-periphid : contains the PrimeCell Peripheral ID.
Optional properties: 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-mmc-highspeed : indicates whether MMC is high speed capable
- mmc-cap-sd-highspeed : indicates whether SD is high speed capable - mmc-cap-sd-highspeed : indicates whether SD is high speed capable
...@@ -3,16 +3,14 @@ ...@@ -3,16 +3,14 @@
The Freescale MXS Synchronous Serial Ports (SSP) can act as a MMC controller The Freescale MXS Synchronous Serial Ports (SSP) can act as a MMC controller
to support MMC, SD, and SDIO types of memory cards. 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: Required properties:
- compatible: Should be "fsl,<chip>-mmc". The supported chips include - compatible: Should be "fsl,<chip>-mmc". The supported chips include
imx23 and imx28. imx23 and imx28.
- reg: Should contain registers location and length
- interrupts: Should contain ERROR and DMA interrupts - interrupts: Should contain ERROR and DMA interrupts
- fsl,ssp-dma-channel: APBH DMA channel for the SSP - 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: Examples:
......
...@@ -3,15 +3,13 @@ ...@@ -3,15 +3,13 @@
This controller on Tegra family SoCs provides an interface for MMC, SD, This controller on Tegra family SoCs provides an interface for MMC, SD,
and SDIO types of memory cards. 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: Required properties:
- compatible : Should be "nvidia,<chip>-sdhci" - 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: Optional properties:
- cd-gpios : Specify GPIOs for card detection
- wp-gpios : Specify GPIOs for write protection
- power-gpios : Specify GPIOs for power control - power-gpios : Specify GPIOs for power control
Example: Example:
......
* 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>;
};
...@@ -3,21 +3,20 @@ ...@@ -3,21 +3,20 @@
The Highspeed MMC Host Controller on TI OMAP family The Highspeed MMC Host Controller on TI OMAP family
provides an interface for MMC, SD, and SDIO types of memory cards. 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: Required properties:
- compatible: - compatible:
Should be "ti,omap2-hsmmc", for OMAP2 controllers Should be "ti,omap2-hsmmc", for OMAP2 controllers
Should be "ti,omap3-hsmmc", for OMAP3 controllers Should be "ti,omap3-hsmmc", for OMAP3 controllers
Should be "ti,omap4-hsmmc", for OMAP4 controllers Should be "ti,omap4-hsmmc", for OMAP4 controllers
- ti,hwmods: Must be "mmc<n>", n is controller instance starting 1 - ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
- reg : should contain hsmmc registers location and length
Optional properties: Optional properties:
ti,dual-volt: boolean, supports dual voltage cards ti,dual-volt: boolean, supports dual voltage cards
<supply-name>-supply: phandle to the regulator device tree node <supply-name>-supply: phandle to the regulator device tree node
"supply-name" examples are "vmmc", "vmmc_aux" etc "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,non-removable: non-removable slot (like eMMC)
ti,needs-special-reset: Requires a special softreset sequence ti,needs-special-reset: Requires a special softreset sequence
......
...@@ -850,9 +850,7 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) ...@@ -850,9 +850,7 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
goto retry; goto retry;
if (!err) if (!err)
mmc_blk_reset_success(md, type); mmc_blk_reset_success(md, type);
spin_lock_irq(&md->lock); blk_end_request(req, err, blk_rq_bytes(req));
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
return err ? 0 : 1; return err ? 0 : 1;
} }
...@@ -934,9 +932,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, ...@@ -934,9 +932,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
if (!err) if (!err)
mmc_blk_reset_success(md, type); mmc_blk_reset_success(md, type);
out: out:
spin_lock_irq(&md->lock); blk_end_request(req, err, blk_rq_bytes(req));
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
return err ? 0 : 1; return err ? 0 : 1;
} }
...@@ -951,9 +947,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) ...@@ -951,9 +947,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
if (ret) if (ret)
ret = -EIO; ret = -EIO;
spin_lock_irq(&md->lock); blk_end_request_all(req, ret);
__blk_end_request_all(req, ret);
spin_unlock_irq(&md->lock);
return ret ? 0 : 1; return ret ? 0 : 1;
} }
...@@ -1252,14 +1246,10 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, ...@@ -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); blocks = mmc_sd_num_wr_blocks(card);
if (blocks != (u32)-1) { if (blocks != (u32)-1) {
spin_lock_irq(&md->lock); ret = blk_end_request(req, 0, blocks << 9);
ret = __blk_end_request(req, 0, blocks << 9);
spin_unlock_irq(&md->lock);
} }
} else { } else {
spin_lock_irq(&md->lock); ret = blk_end_request(req, 0, brq->data.bytes_xfered);
ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
spin_unlock_irq(&md->lock);
} }
return ret; return ret;
} }
...@@ -1311,10 +1301,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) ...@@ -1311,10 +1301,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
* A block was successfully transferred. * A block was successfully transferred.
*/ */
mmc_blk_reset_success(md, type); 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); brq->data.bytes_xfered);
spin_unlock_irq(&md->lock);
/* /*
* If the blk_end_request function returns non-zero even * If the blk_end_request function returns non-zero even
* though all data has been transferred and no errors * 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) ...@@ -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 * time, so we only reach here after trying to
* read a single sector. * read a single sector.
*/ */
spin_lock_irq(&md->lock); ret = blk_end_request(req, -EIO,
ret = __blk_end_request(req, -EIO,
brq->data.blksz); brq->data.blksz);
spin_unlock_irq(&md->lock);
if (!ret) if (!ret)
goto start_new_req; goto start_new_req;
break; break;
...@@ -1388,12 +1374,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) ...@@ -1388,12 +1374,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
return 1; return 1;
cmd_abort: cmd_abort:
spin_lock_irq(&md->lock);
if (mmc_card_removed(card)) if (mmc_card_removed(card))
req->cmd_flags |= REQ_QUIET; req->cmd_flags |= REQ_QUIET;
while (ret) while (ret)
ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); ret = blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
spin_unlock_irq(&md->lock);
start_new_req: start_new_req:
if (rqc) { if (rqc) {
...@@ -1417,9 +1401,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -1417,9 +1401,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
ret = mmc_blk_part_switch(card, md); ret = mmc_blk_part_switch(card, md);
if (ret) { if (ret) {
if (req) { if (req) {
spin_lock_irq(&md->lock); blk_end_request_all(req, -EIO);
__blk_end_request_all(req, -EIO);
spin_unlock_irq(&md->lock);
} }
ret = 0; ret = 0;
goto out; goto out;
......
...@@ -7,6 +7,6 @@ mmc_core-y := core.o bus.o host.o \ ...@@ -7,6 +7,6 @@ mmc_core-y := core.o bus.o host.o \
mmc.o mmc_ops.o sd.o sd_ops.o \ mmc.o mmc_ops.o sd.o sd_ops.o \
sdio.o sdio_ops.o sdio_bus.o \ sdio.o sdio_ops.o sdio_bus.o \
sdio_cis.o sdio_io.o sdio_irq.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 mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
/*
* 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);
...@@ -404,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card) ...@@ -404,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card)
{ {
int err; int err;
u32 status; u32 status;
unsigned long prg_wait;
BUG_ON(!card); BUG_ON(!card);
...@@ -419,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card) ...@@ -419,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card)
goto out; goto out;
} }
/* switch (R1_CURRENT_STATE(status)) {
* If the card status is in PRG-state, we can send the HPI command. case R1_STATE_IDLE:
*/ case R1_STATE_READY:
if (R1_CURRENT_STATE(status) == R1_STATE_PRG) { case R1_STATE_STBY:
do { /*
/* * In idle states, HPI is not needed and the caller
* We don't know when the HPI command will finish * can issue the next intended command immediately
* processing, so we need to resend HPI until out */
* of prg-state, and keep checking the card status goto out;
* with SEND_STATUS. If a timeout error occurs when case R1_STATE_PRG:
* sending the HPI command, we are already out of break;
* prg-state. default:
*/ /* In all other states, it's illegal to issue HPI */
err = mmc_send_hpi_cmd(card, &status); pr_debug("%s: HPI cannot be sent. Card state=%d\n",
if (err) mmc_hostname(card->host), R1_CURRENT_STATE(status));
pr_debug("%s: abort HPI (%d error)\n", err = -EINVAL;
mmc_hostname(card->host), err); goto out;
}
err = mmc_send_status(card, &status); err = mmc_send_hpi_cmd(card, &status);
if (err) if (err)
break; goto out;
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
} else prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time);
pr_debug("%s: Left prg-state\n", mmc_hostname(card->host)); 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: out:
mmc_release_host(card->host); mmc_release_host(card->host);
...@@ -941,7 +950,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply) ...@@ -941,7 +950,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
return result; 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 * mmc_regulator_set_ocr - set regulator to match host->ios voltage
...@@ -1011,7 +1020,30 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, ...@@ -1011,7 +1020,30 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
"could not set regulator OCR (%d)\n", result); "could not set regulator OCR (%d)\n", result);
return 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 */ #endif /* CONFIG_REGULATOR */
...@@ -1180,6 +1212,9 @@ static void mmc_power_up(struct mmc_host *host) ...@@ -1180,6 +1212,9 @@ static void mmc_power_up(struct mmc_host *host)
host->ios.timing = MMC_TIMING_LEGACY; host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host); 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 * This delay should be sufficient to allow the power supply
* to reach the minimum voltage. * to reach the minimum voltage.
...@@ -1931,9 +1966,6 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) ...@@ -1931,9 +1966,6 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
*/ */
mmc_hw_reset_for_init(host); 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 * sdio_reset sends CMD52 to reset card. Since we do not know
* if the card is being re-initialized, just send it. CMD52 * if the card is being re-initialized, just send it. CMD52
...@@ -2075,6 +2107,7 @@ void mmc_rescan(struct work_struct *work) ...@@ -2075,6 +2107,7 @@ void mmc_rescan(struct work_struct *work)
void mmc_start_host(struct mmc_host *host) void mmc_start_host(struct mmc_host *host)
{ {
host->f_init = max(freqs[0], host->f_min); host->f_init = max(freqs[0], host->f_min);
host->rescan_disable = 0;
mmc_power_up(host); mmc_power_up(host);
mmc_detect_change(host, 0); mmc_detect_change(host, 0);
} }
...@@ -2088,6 +2121,7 @@ void mmc_stop_host(struct mmc_host *host) ...@@ -2088,6 +2121,7 @@ void mmc_stop_host(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
#endif #endif
host->rescan_disable = 1;
cancel_delayed_work_sync(&host->detect); cancel_delayed_work_sync(&host->detect);
mmc_flush_scheduled_work(); mmc_flush_scheduled_work();
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
static void mmc_host_classdev_release(struct device *dev) static void mmc_host_classdev_release(struct device *dev)
{ {
struct mmc_host *host = cls_dev_to_mmc_host(dev); struct mmc_host *host = cls_dev_to_mmc_host(dev);
mutex_destroy(&host->slot.lock);
kfree(host); kfree(host);
} }
...@@ -312,6 +313,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) ...@@ -312,6 +313,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
if (!host) if (!host)
return NULL; return NULL;
/* scanning will be enabled when we're ready */
host->rescan_disable = 1;
spin_lock(&mmc_host_lock); spin_lock(&mmc_host_lock);
err = idr_get_new(&mmc_host_idr, host, &host->index); err = idr_get_new(&mmc_host_idr, host, &host->index);
spin_unlock(&mmc_host_lock); spin_unlock(&mmc_host_lock);
...@@ -327,6 +330,9 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) ...@@ -327,6 +330,9 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
mmc_host_clk_init(host); mmc_host_clk_init(host);
mutex_init(&host->slot.lock);
host->slot.cd_irq = -EINVAL;
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq); init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan); INIT_DELAYED_WORK(&host->detect, mmc_rescan);
......
...@@ -818,9 +818,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -818,9 +818,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!mmc_host_is_spi(host)) if (!mmc_host_is_spi(host))
mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); 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 * Since we're changing the OCR value, we seem to
* need to tell some cards to go back to the idle * need to tell some cards to go back to the idle
......
...@@ -569,7 +569,6 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) ...@@ -569,7 +569,6 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
cmd.opcode = opcode; cmd.opcode = opcode;
cmd.arg = card->rca << 16 | 1; 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); err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) { if (err) {
......
...@@ -244,7 +244,7 @@ static int mmc_read_ssr(struct mmc_card *card) ...@@ -244,7 +244,7 @@ static int mmc_read_ssr(struct mmc_card *card)
* bitfield positions accordingly. * bitfield positions accordingly.
*/ */
au = UNSTUFF_BITS(ssr, 428 - 384, 4); au = UNSTUFF_BITS(ssr, 428 - 384, 4);
if (au > 0 || au <= 9) { if (au > 0 && au <= 9) {
card->ssr.au = 1 << (au + 4); card->ssr.au = 1 << (au + 4);
es = UNSTUFF_BITS(ssr, 408 - 384, 16); es = UNSTUFF_BITS(ssr, 408 - 384, 16);
et = UNSTUFF_BITS(ssr, 402 - 384, 6); et = UNSTUFF_BITS(ssr, 402 - 384, 6);
...@@ -290,8 +290,12 @@ static int mmc_read_switch(struct mmc_card *card) ...@@ -290,8 +290,12 @@ static int mmc_read_switch(struct mmc_card *card)
return -ENOMEM; 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 (err) {
/* /*
* If the host or the card can't do the switch, * If the host or the card can't do the switch,
...@@ -312,46 +316,8 @@ static int mmc_read_switch(struct mmc_card *card) ...@@ -312,46 +316,8 @@ static int mmc_read_switch(struct mmc_card *card)
if (card->scr.sda_spec3) { if (card->scr.sda_spec3) {
card->sw_caps.sd3_bus_mode = status[13]; card->sw_caps.sd3_bus_mode = status[13];
/* Driver Strengths supported by the card */
/* 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;
}
card->sw_caps.sd3_drv_type = status[9]; 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: out:
...@@ -551,60 +517,80 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status) ...@@ -551,60 +517,80 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
return 0; 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) 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; int err;
u32 max_current;
/* /*
* Current limit switch is only defined for SDR50, SDR104, and DDR50 * Current limit switch is only defined for SDR50, SDR104, and DDR50
* bus speed modes. For other bus speed modes, we set the default * bus speed modes. For other bus speed modes, we do not change the
* current limit of 200mA. * current limit.
*/ */
if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) || if ((card->sd_bus_speed != UHS_SDR50_BUS_SPEED) &&
(card->sd_bus_speed == UHS_SDR104_BUS_SPEED) || (card->sd_bus_speed != UHS_SDR104_BUS_SPEED) &&
(card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) { (card->sd_bus_speed != UHS_DDR50_BUS_SPEED))
if (card->host->caps & MMC_CAP_MAX_CURRENT_800) { return 0;
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 & * Host has different current capabilities when operating at
SD_MAX_CURRENT_600) * different voltages, so find out its max current first.
current_limit = SD_SET_CURRENT_LIMIT_600; */
else if (card->sw_caps.sd3_curr_limit & max_current = sd_get_host_max_current(card->host);
SD_MAX_CURRENT_400)
current_limit = SD_SET_CURRENT_LIMIT_400; /*
else if (card->sw_caps.sd3_curr_limit & * We only check host's capability here, if we set a limit that is
SD_MAX_CURRENT_200) * higher than the card's maximum current, the card will be using its
current_limit = SD_SET_CURRENT_LIMIT_200; * maximum current, e.g. if the card's maximum current is 300ma, and
} else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) { * when we set current limit to 200ma, the card will draw 200ma, and
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600) * when we set current limit to 400/600/800ma, the card will draw its
current_limit = SD_SET_CURRENT_LIMIT_600; * maximum 300ma from the host.
else if (card->sw_caps.sd3_curr_limit & */
SD_MAX_CURRENT_400) if (max_current >= 800)
current_limit = SD_SET_CURRENT_LIMIT_400; current_limit = SD_SET_CURRENT_LIMIT_800;
else if (card->sw_caps.sd3_curr_limit & else if (max_current >= 600)
SD_MAX_CURRENT_200) current_limit = SD_SET_CURRENT_LIMIT_600;
current_limit = SD_SET_CURRENT_LIMIT_200; else if (max_current >= 400)
} else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) { current_limit = SD_SET_CURRENT_LIMIT_400;
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400) else if (max_current >= 200)
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
current_limit = SD_SET_CURRENT_LIMIT_200; current_limit = SD_SET_CURRENT_LIMIT_200;
err = mmc_sd_switch(card, 1, 3, current_limit, status); if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
if (err) err = mmc_sd_switch(card, 1, 3, current_limit, status);
return err; if (err)
return err;
if (((status[15] >> 4) & 0x0F) != current_limit) if (((status[15] >> 4) & 0x0F) != current_limit)
pr_warning("%s: Problem setting current limit!\n", pr_warning("%s: Problem setting current limit!\n",
mmc_hostname(card->host)); mmc_hostname(card->host));
}
return 0; return 0;
} }
...@@ -726,6 +712,7 @@ struct device_type sd_type = { ...@@ -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 mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
{ {
int err; int err;
u32 max_current;
/* /*
* Since we're changing the OCR value, we seem to * 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) ...@@ -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)) MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
ocr |= SD_OCR_S18R; 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 | * If the host can supply more than 150mA at current voltage,
MMC_CAP_SET_XPC_180)) * XPC should be set to 1.
*/
max_current = sd_get_host_max_current(host);
if (max_current > 150)
ocr |= SD_OCR_XPC; ocr |= SD_OCR_XPC;
try_again: try_again:
...@@ -911,9 +901,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, ...@@ -911,9 +901,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
BUG_ON(!host); BUG_ON(!host);
WARN_ON(!host->claimed); 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); err = mmc_sd_get_cid(host, ocr, cid, &rocr);
if (err) if (err)
return err; return err;
......
...@@ -591,9 +591,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -591,9 +591,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
* Inform the card of the voltage * Inform the card of the voltage
*/ */
if (!powered_resume) { 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); err = mmc_send_io_op_cond(host, host->ocr, &ocr);
if (err) if (err)
goto err; goto err;
...@@ -1006,10 +1003,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host) ...@@ -1006,10 +1003,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
* restore the correct voltage setting of the card. * 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); sdio_reset(host);
mmc_go_idle(host); mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail); mmc_send_if_cond(host, host->ocr_avail);
......
...@@ -313,7 +313,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) ...@@ -313,7 +313,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
if (ret == -ENOENT) { if (ret == -ENOENT) {
/* warn about unknown tuples */ /* warn about unknown tuples */
pr_warning("%s: queuing unknown" pr_warn_ratelimited("%s: queuing unknown"
" CIS tuple 0x%02x (%u bytes)\n", " CIS tuple 0x%02x (%u bytes)\n",
mmc_hostname(card->host), mmc_hostname(card->host),
tpl_code, tpl_link); tpl_code, tpl_link);
......
/*
* 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);
...@@ -391,11 +391,17 @@ static int atmci_regs_show(struct seq_file *s, void *v) ...@@ -391,11 +391,17 @@ static int atmci_regs_show(struct seq_file *s, void *v)
clk_disable(host->mck); clk_disable(host->mck);
spin_unlock_bh(&host->lock); 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],
buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "", buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "", buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "");
buf[ATMCI_MR / 4] & 0xff); 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, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]);
seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]); seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]);
seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]); seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]);
...@@ -1685,7 +1691,6 @@ static void atmci_tasklet_func(unsigned long priv) ...@@ -1685,7 +1691,6 @@ static void atmci_tasklet_func(unsigned long priv)
dev_dbg(&host->pdev->dev, "FSM: cmd ready\n"); dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
host->cmd = NULL; host->cmd = NULL;
host->data = NULL;
data->bytes_xfered = data->blocks * data->blksz; data->bytes_xfered = data->blocks * data->blksz;
data->error = 0; data->error = 0;
atmci_command_complete(host, mrq->stop); atmci_command_complete(host, mrq->stop);
...@@ -1699,6 +1704,7 @@ static void atmci_tasklet_func(unsigned long priv) ...@@ -1699,6 +1704,7 @@ static void atmci_tasklet_func(unsigned long priv)
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
state = STATE_WAITING_NOTBUSY; state = STATE_WAITING_NOTBUSY;
} }
host->data = NULL;
break; break;
case STATE_END_REQUEST: case STATE_END_REQUEST:
......
...@@ -405,11 +405,23 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) ...@@ -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) static int dw_mci_idmac_init(struct dw_mci *host)
{ {
struct idmac_desc *p; struct idmac_desc *p;
int i; int i, dma_support;
/* Number of descriptors in the ring buffer */ /* Number of descriptors in the ring buffer */
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); 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 */ /* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) 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)); 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) ...@@ -1876,7 +1888,6 @@ static void dw_mci_init_dma(struct dw_mci *host)
/* Determine which DMA interface to use */ /* Determine which DMA interface to use */
#ifdef CONFIG_MMC_DW_IDMAC #ifdef CONFIG_MMC_DW_IDMAC
host->dma_ops = &dw_mci_idmac_ops; host->dma_ops = &dw_mci_idmac_ops;
dev_info(&host->dev, "Using internal DMA controller.\n");
#endif #endif
if (!host->dma_ops) if (!host->dma_ops)
...@@ -2175,7 +2186,7 @@ int dw_mci_resume(struct dw_mci *host) ...@@ -2175,7 +2186,7 @@ int dw_mci_resume(struct dw_mci *host)
return ret; return ret;
} }
if (host->dma_ops->init) if (host->use_dma && host->dma_ops->init)
host->dma_ops->init(host); host->dma_ops->init(host);
/* Restore the old value at FIFOTH register */ /* Restore the old value at FIFOTH register */
......
...@@ -164,16 +164,23 @@ struct mxs_mmc_host { ...@@ -164,16 +164,23 @@ struct mxs_mmc_host {
spinlock_t lock; spinlock_t lock;
int sdio_irq_en; int sdio_irq_en;
int wp_gpio; int wp_gpio;
bool wp_inverted;
}; };
static int mxs_mmc_get_ro(struct mmc_host *mmc) static int mxs_mmc_get_ro(struct mmc_host *mmc)
{ {
struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_mmc_host *host = mmc_priv(mmc);
int ret;
if (!gpio_is_valid(host->wp_gpio)) if (!gpio_is_valid(host->wp_gpio))
return -EINVAL; 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) static int mxs_mmc_get_cd(struct mmc_host *mmc)
...@@ -707,6 +714,8 @@ static int mxs_mmc_probe(struct platform_device *pdev) ...@@ -707,6 +714,8 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct pinctrl *pinctrl; struct pinctrl *pinctrl;
int ret = 0, irq_err, irq_dma; int ret = 0, irq_err, irq_dma;
dma_cap_mask_t mask; dma_cap_mask_t mask;
struct regulator *reg_vmmc;
enum of_gpio_flags flags;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
...@@ -747,6 +756,16 @@ static int mxs_mmc_probe(struct platform_device *pdev) ...@@ -747,6 +756,16 @@ static int mxs_mmc_probe(struct platform_device *pdev)
host->mmc = mmc; host->mmc = mmc;
host->sdio_irq_en = 0; 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); pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) { if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl); ret = PTR_ERR(pinctrl);
...@@ -785,7 +804,10 @@ static int mxs_mmc_probe(struct platform_device *pdev) ...@@ -785,7 +804,10 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mmc->caps |= MMC_CAP_4_BIT_DATA; mmc->caps |= MMC_CAP_4_BIT_DATA;
else if (bus_width == 8) else if (bus_width == 8)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; 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 { } else {
if (pdata->flags & SLOTF_8_BIT_CAPABLE) if (pdata->flags & SLOTF_8_BIT_CAPABLE)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
......
...@@ -1089,7 +1089,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) ...@@ -1089,7 +1089,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
/* Disable the clocks */ /* Disable the clocks */
pm_runtime_put_sync(host->dev); pm_runtime_put_sync(host->dev);
if (host->dbclk) if (host->dbclk)
clk_disable(host->dbclk); clk_disable_unprepare(host->dbclk);
/* Turn the power off */ /* Turn the power off */
ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); 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) ...@@ -1100,7 +1100,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
vdd); vdd);
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
if (host->dbclk) if (host->dbclk)
clk_enable(host->dbclk); clk_prepare_enable(host->dbclk);
if (ret != 0) if (ret != 0)
goto err; goto err;
...@@ -1899,7 +1899,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1899,7 +1899,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
if (IS_ERR(host->dbclk)) { if (IS_ERR(host->dbclk)) {
dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n"); dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n");
host->dbclk = NULL; 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"); dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
clk_put(host->dbclk); clk_put(host->dbclk);
host->dbclk = NULL; host->dbclk = NULL;
...@@ -1931,6 +1931,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1931,6 +1931,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
if (!res) { if (!res) {
dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
ret = -ENXIO;
goto err_irq; goto err_irq;
} }
host->dma_line_tx = res->start; host->dma_line_tx = res->start;
...@@ -1938,6 +1939,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1938,6 +1939,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
if (!res) { if (!res) {
dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
ret = -ENXIO;
goto err_irq; goto err_irq;
} }
host->dma_line_rx = res->start; host->dma_line_rx = res->start;
...@@ -2023,7 +2025,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) ...@@ -2023,7 +2025,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
pm_runtime_disable(host->dev); pm_runtime_disable(host->dev);
clk_put(host->fclk); clk_put(host->fclk);
if (host->dbclk) { if (host->dbclk) {
clk_disable(host->dbclk); clk_disable_unprepare(host->dbclk);
clk_put(host->dbclk); clk_put(host->dbclk);
} }
err1: err1:
...@@ -2058,7 +2060,7 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev) ...@@ -2058,7 +2060,7 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
pm_runtime_disable(host->dev); pm_runtime_disable(host->dev);
clk_put(host->fclk); clk_put(host->fclk);
if (host->dbclk) { if (host->dbclk) {
clk_disable(host->dbclk); clk_disable_unprepare(host->dbclk);
clk_put(host->dbclk); clk_put(host->dbclk);
} }
...@@ -2116,7 +2118,7 @@ static int omap_hsmmc_suspend(struct device *dev) ...@@ -2116,7 +2118,7 @@ static int omap_hsmmc_suspend(struct device *dev)
} }
if (host->dbclk) if (host->dbclk)
clk_disable(host->dbclk); clk_disable_unprepare(host->dbclk);
err: err:
pm_runtime_put_sync(host->dev); pm_runtime_put_sync(host->dev);
return ret; return ret;
...@@ -2137,7 +2139,7 @@ static int omap_hsmmc_resume(struct device *dev) ...@@ -2137,7 +2139,7 @@ static int omap_hsmmc_resume(struct device *dev)
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
if (host->dbclk) if (host->dbclk)
clk_enable(host->dbclk); clk_prepare_enable(host->dbclk);
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
omap_hsmmc_conf_bus_power(host); omap_hsmmc_conf_bus_power(host);
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <mach/dma.h> #include <mach/dma.h>
#include <mach/regs-sdi.h> #include <mach/regs-sdi.h>
#include <mach/regs-gpio.h>
#include <plat/mci.h> #include <plat/mci.h>
...@@ -1237,12 +1236,9 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1237,12 +1236,9 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_ON: case MMC_POWER_ON:
case MMC_POWER_UP: case MMC_POWER_UP:
s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK); /* Configure GPE5...GPE10 pins in SD mode */
s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD); s3c_gpio_cfgall_range(S3C2410_GPE(5), 6, S3C_GPIO_SFN(2),
s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0); S3C_GPIO_PULL_NONE);
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);
if (host->pdata->set_power) if (host->pdata->set_power)
host->pdata->set_power(ios->power_mode, ios->vdd); host->pdata->set_power(ios->power_mode, ios->vdd);
......
...@@ -20,11 +20,17 @@ ...@@ -20,11 +20,17 @@
*/ */
#include <linux/io.h> #include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
struct sdhci_dove_priv {
struct clk *clk;
};
static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
{ {
u16 ret; u16 ret;
...@@ -66,16 +72,57 @@ static struct sdhci_pltfm_data sdhci_dove_pdata = { ...@@ -66,16 +72,57 @@ static struct sdhci_pltfm_data sdhci_dove_pdata = {
.quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_NO_BUSY_IRQ |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 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) 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) 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); return sdhci_pltfm_unregister(pdev);
} }
......
...@@ -299,6 +299,8 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) ...@@ -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) 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; u32 new_val;
switch (reg) { switch (reg) {
...@@ -315,8 +317,11 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) ...@@ -315,8 +317,11 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
SDHCI_CTRL_D3CD); SDHCI_CTRL_D3CD);
/* ensure the endianess */ /* ensure the endianess */
new_val |= ESDHC_HOST_CONTROL_LE; new_val |= ESDHC_HOST_CONTROL_LE;
/* DMA mode bits are shifted */ /* bits 8&9 are reserved on mx25 */
new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 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); esdhc_clrset_le(host, 0xffff, new_val, reg);
return; return;
......
...@@ -157,6 +157,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = { ...@@ -157,6 +157,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = {
static const struct sdhci_pci_fixes sdhci_cafe = { static const struct sdhci_pci_fixes sdhci_cafe = {
.quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_NO_BUSY_IRQ |
SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
}; };
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/platform_data/pxa_sdhci.h> #include <linux/platform_data/pxa_sdhci.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "sdhci.h" #include "sdhci.h"
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
...@@ -121,6 +124,48 @@ static struct sdhci_ops pxav2_sdhci_ops = { ...@@ -121,6 +124,48 @@ static struct sdhci_ops pxav2_sdhci_ops = {
.platform_8bit_width = pxav2_mmc_set_width, .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) static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
{ {
struct sdhci_pltfm_host *pltfm_host; struct sdhci_pltfm_host *pltfm_host;
...@@ -128,6 +173,8 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev) ...@@ -128,6 +173,8 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct sdhci_host *host = NULL; struct sdhci_host *host = NULL;
struct sdhci_pxa *pxa = NULL; struct sdhci_pxa *pxa = NULL;
const struct of_device_id *match;
int ret; int ret;
struct clk *clk; struct clk *clk;
...@@ -156,6 +203,10 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev) ...@@ -156,6 +203,10 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
| SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; | 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) {
if (pdata->flags & PXA_FLAG_CARD_PERMANENT) { if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
/* on-chip device */ /* on-chip device */
...@@ -218,6 +269,9 @@ static struct platform_driver sdhci_pxav2_driver = { ...@@ -218,6 +269,9 @@ static struct platform_driver sdhci_pxav2_driver = {
.driver = { .driver = {
.name = "sdhci-pxav2", .name = "sdhci-pxav2",
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = sdhci_pxav2_of_match,
#endif
.pm = SDHCI_PLTFM_PMOPS, .pm = SDHCI_PLTFM_PMOPS,
}, },
.probe = sdhci_pxav2_probe, .probe = sdhci_pxav2_probe,
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "sdhci.h" #include "sdhci.h"
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
...@@ -164,6 +167,46 @@ static struct sdhci_ops pxav3_sdhci_ops = { ...@@ -164,6 +167,46 @@ static struct sdhci_ops pxav3_sdhci_ops = {
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks, .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) static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
{ {
struct sdhci_pltfm_host *pltfm_host; struct sdhci_pltfm_host *pltfm_host;
...@@ -171,6 +214,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) ...@@ -171,6 +214,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct sdhci_host *host = NULL; struct sdhci_host *host = NULL;
struct sdhci_pxa *pxa = NULL; struct sdhci_pxa *pxa = NULL;
const struct of_device_id *match;
int ret; int ret;
struct clk *clk; struct clk *clk;
...@@ -202,6 +247,10 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) ...@@ -202,6 +247,10 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
/* enable 1/8V DDR capable */ /* enable 1/8V DDR capable */
host->mmc->caps |= MMC_CAP_1_8V_DDR; 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) {
if (pdata->flags & PXA_FLAG_CARD_PERMANENT) { if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
/* on-chip device */ /* on-chip device */
...@@ -263,6 +312,9 @@ static int __devexit sdhci_pxav3_remove(struct platform_device *pdev) ...@@ -263,6 +312,9 @@ static int __devexit sdhci_pxav3_remove(struct platform_device *pdev)
static struct platform_driver sdhci_pxav3_driver = { static struct platform_driver sdhci_pxav3_driver = {
.driver = { .driver = {
.name = "sdhci-pxav3", .name = "sdhci-pxav3",
#ifdef CONFIG_OF
.of_match_table = sdhci_pxav3_of_match,
#endif
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = SDHCI_PLTFM_PMOPS, .pm = SDHCI_PLTFM_PMOPS,
}, },
......
This diff is collapsed.
...@@ -205,6 +205,7 @@ ...@@ -205,6 +205,7 @@
#define SDHCI_CAPABILITIES_1 0x44 #define SDHCI_CAPABILITIES_1 0x44
#define SDHCI_MAX_CURRENT 0x48 #define SDHCI_MAX_CURRENT 0x48
#define SDHCI_MAX_CURRENT_LIMIT 0xFF
#define SDHCI_MAX_CURRENT_330_MASK 0x0000FF #define SDHCI_MAX_CURRENT_330_MASK 0x0000FF
#define SDHCI_MAX_CURRENT_330_SHIFT 0 #define SDHCI_MAX_CURRENT_330_SHIFT 0
#define SDHCI_MAX_CURRENT_300_MASK 0x00FF00 #define SDHCI_MAX_CURRENT_300_MASK 0x00FF00
......
This diff is collapsed.
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
...@@ -39,22 +40,39 @@ struct sh_mobile_sdhi { ...@@ -39,22 +40,39 @@ struct sh_mobile_sdhi {
struct tmio_mmc_dma dma_priv; 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) static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
{ {
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; 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) static int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
{ {
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
if (p && p->get_cd) return p->get_cd(pdev);
return p->get_cd(pdev);
else
return -ENOSYS;
} }
static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) 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) ...@@ -116,12 +134,14 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
} }
mmc_data = &priv->mmc_data; mmc_data = &priv->mmc_data;
p->pdata = mmc_data;
if (p->init) { if (p) {
ret = p->init(pdev, &sdhi_ops); p->pdata = mmc_data;
if (ret) if (p->init) {
goto einit; ret = p->init(pdev, &sdhi_ops);
if (ret)
goto einit;
}
} }
snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); 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) ...@@ -132,9 +152,8 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
goto eclkget; goto eclkget;
} }
mmc_data->hclk = clk_get_rate(priv->clk); mmc_data->clk_enable = sh_mobile_sdhi_clk_enable;
mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; mmc_data->clk_disable = sh_mobile_sdhi_clk_disable;
mmc_data->get_cd = sh_mobile_sdhi_get_cd;
mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
if (p) { if (p) {
mmc_data->flags = p->tmio_flags; mmc_data->flags = p->tmio_flags;
...@@ -142,7 +161,12 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -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->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->ocr_mask = p->tmio_ocr_mask; mmc_data->ocr_mask = p->tmio_ocr_mask;
mmc_data->capabilities |= p->tmio_caps; mmc_data->capabilities |= p->tmio_caps;
mmc_data->capabilities2 |= p->tmio_caps2;
mmc_data->cd_gpio = p->cd_gpio; 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) { if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
priv->param_tx.slave_id = p->dma_slave_tx; priv->param_tx.slave_id = p->dma_slave_tx;
...@@ -248,7 +272,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -248,7 +272,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
eprobe: eprobe:
clk_put(priv->clk); clk_put(priv->clk);
eclkget: eclkget:
if (p->cleanup) if (p && p->cleanup)
p->cleanup(pdev); p->cleanup(pdev);
einit: einit:
kfree(priv); kfree(priv);
...@@ -263,7 +287,8 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) ...@@ -263,7 +287,8 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
int i = 0, irq; int i = 0, irq;
p->pdata = NULL; if (p)
p->pdata = NULL;
tmio_mmc_host_remove(host); tmio_mmc_host_remove(host);
...@@ -276,7 +301,7 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) ...@@ -276,7 +301,7 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
clk_put(priv->clk); clk_put(priv->clk);
if (p->cleanup) if (p && p->cleanup)
p->cleanup(pdev); p->cleanup(pdev);
kfree(priv); kfree(priv);
...@@ -291,11 +316,18 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { ...@@ -291,11 +316,18 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
.runtime_resume = tmio_mmc_host_runtime_resume, .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 = { static struct platform_driver sh_mobile_sdhi_driver = {
.driver = { .driver = {
.name = "sh_mobile_sdhi", .name = "sh_mobile_sdhi",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &tmio_mmc_dev_pm_ops, .pm = &tmio_mmc_dev_pm_ops,
.of_match_table = sh_mobile_sdhi_of_match,
}, },
.probe = sh_mobile_sdhi_probe, .probe = sh_mobile_sdhi_probe,
.remove = __devexit_p(sh_mobile_sdhi_remove), .remove = __devexit_p(sh_mobile_sdhi_remove),
......
...@@ -34,8 +34,9 @@ ...@@ -34,8 +34,9 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/mfd/tmio.h> #include <linux/mfd/tmio.h>
#include <linux/mmc/cd-gpio.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/mmc/tmio.h> #include <linux/mmc/tmio.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
...@@ -305,8 +306,8 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command ...@@ -305,8 +306,8 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
int c = cmd->opcode; int c = cmd->opcode;
u32 irq_mask = TMIO_MASK_CMD; u32 irq_mask = TMIO_MASK_CMD;
/* Command 12 is handled by hardware */ /* CMD12 is handled by hardware */
if (cmd->opcode == 12 && !cmd->arg) { if (cmd->opcode == MMC_STOP_TRANSMISSION && !cmd->arg) {
sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001); sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001);
return 0; return 0;
} }
...@@ -449,7 +450,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) ...@@ -449,7 +450,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
} }
if (stop) { 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); sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
else else
BUG(); BUG();
...@@ -751,6 +752,34 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -751,6 +752,34 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
mmc_request_done(mmc, mrq); 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. /* Set MMC clock / power.
* Note: This controller uses a simple divider scheme therefore it cannot * 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 * 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) ...@@ -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 (ios->power_mode == MMC_POWER_ON && ios->clock) {
if (!host->power) { if (!host->power) {
tmio_mmc_clk_update(mmc);
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
host->power = true; host->power = true;
} }
tmio_mmc_set_clock(host, ios->clock); tmio_mmc_set_clock(host, ios->clock);
/* power up SD bus */ /* power up SD bus */
if (host->set_pwr) tmio_mmc_set_power(host, ios);
host->set_pwr(host->pdev, 1);
/* start bus clock */ /* start bus clock */
tmio_mmc_clk_start(host); tmio_mmc_clk_start(host);
} else if (ios->power_mode != MMC_POWER_UP) { } else if (ios->power_mode != MMC_POWER_UP) {
if (host->set_pwr && ios->power_mode == MMC_POWER_OFF) if (ios->power_mode == MMC_POWER_OFF)
host->set_pwr(host->pdev, 0); tmio_mmc_set_power(host, ios);
if (host->power) { if (host->power) {
struct tmio_mmc_data *pdata = host->pdata;
tmio_mmc_clk_stop(host);
host->power = false; host->power = false;
pm_runtime_put(dev); pm_runtime_put(dev);
if (pdata->clk_disable)
pdata->clk_disable(host->pdev);
} }
tmio_mmc_clk_stop(host);
} }
switch (ios->bus_width) { if (host->power) {
case MMC_BUS_WIDTH_1: switch (ios->bus_width) {
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); case MMC_BUS_WIDTH_1:
break; sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
case MMC_BUS_WIDTH_4: break;
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); case MMC_BUS_WIDTH_4:
break; sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
break;
}
} }
/* Let things settle. delay taken from winCE driver */ /* Let things settle. delay taken from winCE driver */
...@@ -841,6 +875,9 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) ...@@ -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_host *host = mmc_priv(mmc);
struct tmio_mmc_data *pdata = host->pdata; 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) || return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
...@@ -850,6 +887,9 @@ static int tmio_mmc_get_cd(struct mmc_host *mmc) ...@@ -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_host *host = mmc_priv(mmc);
struct tmio_mmc_data *pdata = host->pdata; struct tmio_mmc_data *pdata = host->pdata;
int ret = mmc_gpio_get_cd(mmc);
if (ret >= 0)
return ret;
if (!pdata->get_cd) if (!pdata->get_cd)
return -ENOSYS; return -ENOSYS;
...@@ -865,6 +905,19 @@ static const struct mmc_host_ops tmio_mmc_ops = { ...@@ -865,6 +905,19 @@ static const struct mmc_host_ops tmio_mmc_ops = {
.enable_sdio_irq = tmio_mmc_enable_sdio_irq, .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, int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
struct platform_device *pdev, struct platform_device *pdev,
struct tmio_mmc_data *pdata) struct tmio_mmc_data *pdata)
...@@ -904,18 +957,14 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, ...@@ -904,18 +957,14 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
mmc->ops = &tmio_mmc_ops; mmc->ops = &tmio_mmc_ops;
mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities;
mmc->f_max = pdata->hclk; mmc->caps2 = pdata->capabilities2;
mmc->f_min = mmc->f_max / 512;
mmc->max_segs = 32; mmc->max_segs = 32;
mmc->max_blk_size = 512; mmc->max_blk_size = 512;
mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) * mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
mmc->max_segs; mmc->max_segs;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size; mmc->max_seg_size = mmc->max_req_size;
if (pdata->ocr_mask) tmio_mmc_init_ocr(_host);
mmc->ocr_avail = pdata->ocr_mask;
else
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
_host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD || _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
mmc->caps & MMC_CAP_NEEDS_POLL || mmc->caps & MMC_CAP_NEEDS_POLL ||
...@@ -927,6 +976,11 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, ...@@ -927,6 +976,11 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
if (ret < 0) if (ret < 0)
goto pm_disable; 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: * There are 4 different scenarios for the card detection:
* 1) an external gpio irq handles the cd (best for power savings) * 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, ...@@ -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 * While we increment the runtime PM counter for all scenarios when
* the mmc core activates us by calling an appropriate set_ios(), we * the mmc core activates us by calling an appropriate set_ios(), we
* must additionally ensure that in case 2) the tmio mmc hardware stays * 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. * powered on during runtime for the card detection to work.
*/ */
if (_host->native_hotplug) if (_host->native_hotplug)
...@@ -948,6 +1001,17 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, ...@@ -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); _host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK);
tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); 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) if (pdata->flags & TMIO_MMC_SDIO_IRQ)
tmio_mmc_enable_sdio_irq(mmc, 0); tmio_mmc_enable_sdio_irq(mmc, 0);
...@@ -961,22 +1025,18 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, ...@@ -961,22 +1025,18 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
/* See if we also get DMA */ /* See if we also get DMA */
tmio_mmc_request_dma(_host, pdata); 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); 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) { 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) { if (ret < 0) {
tmio_mmc_host_remove(_host); tmio_mmc_host_remove(_host);
return ret; return ret;
...@@ -1008,7 +1068,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) ...@@ -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 * This means we can miss a card-eject, but this is anyway
* possible, because of delayed processing of hotplug events. * possible, because of delayed processing of hotplug events.
*/ */
mmc_cd_gpio_free(mmc); mmc_gpio_free_cd(mmc);
if (!host->native_hotplug) if (!host->native_hotplug)
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
......
...@@ -101,6 +101,7 @@ struct tmio_mmc_host; ...@@ -101,6 +101,7 @@ struct tmio_mmc_host;
struct tmio_mmc_data { struct tmio_mmc_data {
unsigned int hclk; unsigned int hclk;
unsigned long capabilities; unsigned long capabilities;
unsigned long capabilities2;
unsigned long flags; unsigned long flags;
u32 ocr_mask; /* available voltages */ u32 ocr_mask; /* available voltages */
struct tmio_mmc_dma *dma; struct tmio_mmc_dma *dma;
...@@ -110,6 +111,9 @@ struct tmio_mmc_data { ...@@ -110,6 +111,9 @@ struct tmio_mmc_data {
void (*set_clk_div)(struct platform_device *host, int state); void (*set_clk_div)(struct platform_device *host, int state);
int (*get_cd)(struct platform_device *host); int (*get_cd)(struct platform_device *host);
int (*write16_hook)(struct tmio_mmc_host *host, int addr); 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);
}; };
/* /*
......
...@@ -149,6 +149,7 @@ struct sd_switch_caps { ...@@ -149,6 +149,7 @@ struct sd_switch_caps {
#define SD_SET_CURRENT_LIMIT_400 1 #define SD_SET_CURRENT_LIMIT_400 1
#define SD_SET_CURRENT_LIMIT_600 2 #define SD_SET_CURRENT_LIMIT_600 2
#define SD_SET_CURRENT_LIMIT_800 3 #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_200 (1 << SD_SET_CURRENT_LIMIT_200)
#define SD_MAX_CURRENT_400 (1 << SD_SET_CURRENT_LIMIT_400) #define SD_MAX_CURRENT_400 (1 << SD_SET_CURRENT_LIMIT_400)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#define LINUX_MMC_HOST_H #define LINUX_MMC_HOST_H
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/mutex.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/fault-inject.h> #include <linux/fault-inject.h>
...@@ -150,11 +151,31 @@ struct mmc_async_req { ...@@ -150,11 +151,31 @@ struct mmc_async_req {
int (*err_check) (struct mmc_card *, 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; void *handler_priv;
}; };
struct regulator;
struct mmc_supply {
struct regulator *vmmc; /* Card power supply */
struct regulator *vqmmc; /* Optional Vccq supply */
};
struct mmc_host { struct mmc_host {
struct device *parent; struct device *parent;
struct device class_dev; struct device class_dev;
...@@ -168,6 +189,9 @@ struct mmc_host { ...@@ -168,6 +189,9 @@ struct mmc_host {
u32 ocr_avail_sd; /* SD-specific OCR */ u32 ocr_avail_sd; /* SD-specific OCR */
u32 ocr_avail_mmc; /* MMC-specific OCR */ u32 ocr_avail_mmc; /* MMC-specific OCR */
struct notifier_block pm_notify; 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_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ #define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
...@@ -211,16 +235,9 @@ struct mmc_host { ...@@ -211,16 +235,9 @@ struct mmc_host {
#define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */ #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_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */
#define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 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_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_C (1 << 24) /* Host supports Driver Type C */
#define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */ #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_CMD23 (1 << 30) /* CMD23 supported. */
#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */ #define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
...@@ -238,6 +255,8 @@ struct mmc_host { ...@@ -238,6 +255,8 @@ struct mmc_host {
#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */ #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_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_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 */ mmc_pm_flag_t pm_caps; /* supported pm features */
unsigned int power_notify_type; unsigned int power_notify_type;
...@@ -290,7 +309,7 @@ struct mmc_host { ...@@ -290,7 +309,7 @@ struct mmc_host {
struct delayed_work detect; struct delayed_work detect;
int detect_change; /* card detect flag */ int detect_change; /* card detect flag */
struct mmc_hotplug hotplug; struct mmc_slot slot;
const struct mmc_bus_ops *bus_ops; /* current bus driver */ const struct mmc_bus_ops *bus_ops; /* current bus driver */
unsigned int bus_refs; /* reference counter */ unsigned int bus_refs; /* reference counter */
...@@ -309,6 +328,7 @@ struct mmc_host { ...@@ -309,6 +328,7 @@ struct mmc_host {
#ifdef CONFIG_REGULATOR #ifdef CONFIG_REGULATOR
bool regulator_enabled; /* regulator state */ bool regulator_enabled; /* regulator state */
#endif #endif
struct mmc_supply supply;
struct dentry *debugfs_root; struct dentry *debugfs_root;
...@@ -357,13 +377,12 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host) ...@@ -357,13 +377,12 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
wake_up_process(host->sdio_irq_thread); wake_up_process(host->sdio_irq_thread);
} }
struct regulator;
#ifdef CONFIG_REGULATOR #ifdef CONFIG_REGULATOR
int mmc_regulator_get_ocrmask(struct regulator *supply); int mmc_regulator_get_ocrmask(struct regulator *supply);
int mmc_regulator_set_ocr(struct mmc_host *mmc, int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply, struct regulator *supply,
unsigned short vdd_bit); unsigned short vdd_bit);
int mmc_regulator_get_supply(struct mmc_host *mmc);
#else #else
static inline int mmc_regulator_get_ocrmask(struct regulator *supply) 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, ...@@ -376,6 +395,11 @@ static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
{ {
return 0; return 0;
} }
static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
{
return 0;
}
#endif #endif
int mmc_card_awake(struct mmc_host *host); int mmc_card_awake(struct mmc_host *host);
......
...@@ -122,6 +122,7 @@ struct sdhci_host { ...@@ -122,6 +122,7 @@ struct sdhci_host {
#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */ #define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
#define SDHCI_HS200_NEEDS_TUNING (1<<10) /* HS200 needs tuning */ #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 */ unsigned int version; /* SDHCI spec. version */
...@@ -155,7 +156,8 @@ struct sdhci_host { ...@@ -155,7 +156,8 @@ struct sdhci_host {
struct timer_list timer; /* Timer for timeouts */ 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_sdio; /* OCR bit masks */
unsigned int ocr_avail_sd; unsigned int ocr_avail_sd;
......
...@@ -44,6 +44,8 @@ struct sh_mmcif_plat_data { ...@@ -44,6 +44,8 @@ struct sh_mmcif_plat_data {
struct sh_mmcif_dma *dma; /* Deprecated. Instead */ struct sh_mmcif_dma *dma; /* Deprecated. Instead */
unsigned int slave_id_tx; /* use embedded slave_id_[tr]x */ unsigned int slave_id_tx; /* use embedded slave_id_[tr]x */
unsigned int slave_id_rx; unsigned int slave_id_rx;
bool use_cd_gpio : 1;
unsigned int cd_gpio;
u8 sup_pclk; /* 1 :SH7757, 0: SH7724/SH7372 */ u8 sup_pclk; /* 1 :SH7757, 0: SH7724/SH7372 */
unsigned long caps; unsigned long caps;
u32 ocr; u32 ocr;
......
...@@ -23,6 +23,7 @@ struct sh_mobile_sdhi_info { ...@@ -23,6 +23,7 @@ struct sh_mobile_sdhi_info {
int dma_slave_rx; int dma_slave_rx;
unsigned long tmio_flags; unsigned long tmio_flags;
unsigned long tmio_caps; unsigned long tmio_caps;
unsigned long tmio_caps2;
u32 tmio_ocr_mask; /* available MMC voltages */ u32 tmio_ocr_mask; /* available MMC voltages */
unsigned int cd_gpio; unsigned int cd_gpio;
struct tmio_mmc_data *pdata; struct tmio_mmc_data *pdata;
......
...@@ -8,11 +8,17 @@ ...@@ -8,11 +8,17 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#ifndef MMC_CD_GPIO_H #ifndef MMC_SLOT_GPIO_H
#define MMC_CD_GPIO_H #define MMC_SLOT_GPIO_H
struct mmc_host; struct mmc_host;
int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio);
void mmc_cd_gpio_free(struct mmc_host *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 #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment