|
@@ -27,6 +27,7 @@
|
|
#include <linux/err.h>
|
|
#include <linux/err.h>
|
|
#include <linux/mmc/host.h>
|
|
#include <linux/mmc/host.h>
|
|
#include <linux/io.h>
|
|
#include <linux/io.h>
|
|
|
|
+#include <linux/regulator/consumer.h>
|
|
|
|
|
|
#include <asm/sizes.h>
|
|
#include <asm/sizes.h>
|
|
|
|
|
|
@@ -67,8 +68,42 @@ struct pxamci_host {
|
|
unsigned int dma_dir;
|
|
unsigned int dma_dir;
|
|
unsigned int dma_drcmrrx;
|
|
unsigned int dma_drcmrrx;
|
|
unsigned int dma_drcmrtx;
|
|
unsigned int dma_drcmrtx;
|
|
|
|
+
|
|
|
|
+ struct regulator *vcc;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static inline void pxamci_init_ocr(struct pxamci_host *host)
|
|
|
|
+{
|
|
|
|
+#ifdef CONFIG_REGULATOR
|
|
|
|
+ host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
|
|
|
|
+
|
|
|
|
+ if (IS_ERR(host->vcc))
|
|
|
|
+ host->vcc = NULL;
|
|
|
|
+ else {
|
|
|
|
+ host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
|
|
|
|
+ if (host->pdata && host->pdata->ocr_mask)
|
|
|
|
+ dev_warn(mmc_dev(host->mmc),
|
|
|
|
+ "ocr_mask/setpower will not be used\n");
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+ if (host->vcc == NULL) {
|
|
|
|
+ /* fall-back to platform data */
|
|
|
|
+ host->mmc->ocr_avail = host->pdata ?
|
|
|
|
+ host->pdata->ocr_mask :
|
|
|
|
+ MMC_VDD_32_33 | MMC_VDD_33_34;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
|
|
|
|
+{
|
|
|
|
+#ifdef CONFIG_REGULATOR
|
|
|
|
+ if (host->vcc)
|
|
|
|
+ mmc_regulator_set_ocr(host->vcc, vdd);
|
|
|
|
+#endif
|
|
|
|
+ if (!host->vcc && host->pdata && host->pdata->setpower)
|
|
|
|
+ host->pdata->setpower(mmc_dev(host->mmc), vdd);
|
|
|
|
+}
|
|
|
|
+
|
|
static void pxamci_stop_clock(struct pxamci_host *host)
|
|
static void pxamci_stop_clock(struct pxamci_host *host)
|
|
{
|
|
{
|
|
if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
|
|
if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
|
|
@@ -438,8 +473,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|
if (host->power_mode != ios->power_mode) {
|
|
if (host->power_mode != ios->power_mode) {
|
|
host->power_mode = ios->power_mode;
|
|
host->power_mode = ios->power_mode;
|
|
|
|
|
|
- if (host->pdata && host->pdata->setpower)
|
|
|
|
- host->pdata->setpower(mmc_dev(mmc), ios->vdd);
|
|
|
|
|
|
+ pxamci_set_power(host, ios->vdd);
|
|
|
|
|
|
if (ios->power_mode == MMC_POWER_ON)
|
|
if (ios->power_mode == MMC_POWER_ON)
|
|
host->cmdat |= CMDAT_INIT;
|
|
host->cmdat |= CMDAT_INIT;
|
|
@@ -562,9 +596,8 @@ static int pxamci_probe(struct platform_device *pdev)
|
|
mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000
|
|
mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000
|
|
: host->clkrate;
|
|
: host->clkrate;
|
|
|
|
|
|
- mmc->ocr_avail = host->pdata ?
|
|
|
|
- host->pdata->ocr_mask :
|
|
|
|
- MMC_VDD_32_33|MMC_VDD_33_34;
|
|
|
|
|
|
+ pxamci_init_ocr(host);
|
|
|
|
+
|
|
mmc->caps = 0;
|
|
mmc->caps = 0;
|
|
host->cmdat = 0;
|
|
host->cmdat = 0;
|
|
if (!cpu_is_pxa25x()) {
|
|
if (!cpu_is_pxa25x()) {
|
|
@@ -661,6 +694,9 @@ static int pxamci_remove(struct platform_device *pdev)
|
|
if (mmc) {
|
|
if (mmc) {
|
|
struct pxamci_host *host = mmc_priv(mmc);
|
|
struct pxamci_host *host = mmc_priv(mmc);
|
|
|
|
|
|
|
|
+ if (host->vcc)
|
|
|
|
+ regulator_put(host->vcc);
|
|
|
|
+
|
|
if (host->pdata && host->pdata->exit)
|
|
if (host->pdata && host->pdata->exit)
|
|
host->pdata->exit(&pdev->dev, mmc);
|
|
host->pdata->exit(&pdev->dev, mmc);
|
|
|
|
|