#include <linux/mmc/sdhci-pltfm.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
+#include <linux/mmc/sd.h>
#include <mach/hardware.h>
#include <mach/esdhc.h>
#include "sdhci.h"
#define SDHCI_VENDOR_SPEC 0xC0
#define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002
#define SDHCI_MIX_CTRL 0x48
+#define SDHCI_TUNE_CTRL_STATUS 0x68
+#define SDHCI_TUNE_CTRL_STEP 0x1
+#define SDHCI_TUNE_CTRL_MIN 0x0
+#define SDHCI_TUNE_CTRL_MAX ((1 << 7) - 1)
+
+#define SDHCI_MIX_CTRL_EXE_TUNE (1 << 22)
+#define SDHCI_MIX_CTRL_SMPCLK_SEL (1 << 23)
+#define SDHCI_MIX_CTRL_FBCLK_SEL (1 << 25)
+
+#define SDHCI_VENDOR_SPEC_VSELECT (1 << 1)
+#define SDHCI_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8)
+
+#define SDHCI_PRESENT_STATE_CLSL (1 << 23)
+#define SDHCI_PRESENT_STATE_DLSL_L4 (0xF << 24)
+#define SDHCI_PRESENT_STATE_DLSL_H4 (0xF << 28)
#define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0)
/*
return readw(host->ioaddr + reg);
}
+void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
+{
+ u32 reg;
+
+ reg = sdhci_readl(host, SDHCI_MIX_CTRL);
+ reg |= SDHCI_MIX_CTRL_EXE_TUNE | \
+ SDHCI_MIX_CTRL_SMPCLK_SEL | \
+ SDHCI_MIX_CTRL_FBCLK_SEL;
+ sdhci_writel(host, reg, SDHCI_MIX_CTRL);
+ sdhci_writel(host, (val << 8), SDHCI_TUNE_CTRL_STATUS);
+}
+
+
static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
writel(0x08800880, host->ioaddr + SDHCI_CAPABILITIES_1);
if (cpu_is_mx6q()) {
+ imx_data->scratchpad |= \
+ (readl(host->ioaddr + SDHCI_MIX_CTRL) & (0xf << 22));
+
writel(imx_data->scratchpad,
host->ioaddr + SDHCI_MIX_CTRL);
writel(val << 16,
* FSL put some DMA bits here
* If your board has a regulator, code should be here
*/
+ if (val == (SDHCI_POWER_ON | SDHCI_POWER_180)) {
+ u32 reg;
+
+ /* switch to 1.8V */
+ reg = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
+ reg |= SDHCI_VENDOR_SPEC_VSELECT;
+ writel(reg, host->ioaddr + SDHCI_VENDOR_SPEC);
+
+ /* stop sd clock */
+ writel(reg & ~SDHCI_VENDOR_SPEC_FRC_SDCLK_ON, \
+ host->ioaddr + SDHCI_VENDOR_SPEC);
+
+ /* sleep at least 5ms */
+ mdelay(5);
+
+ /* restore sd clock status */
+ writel(reg, host->ioaddr + SDHCI_VENDOR_SPEC);
+ } else {
+ u32 reg;
+
+ reg = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
+ reg &= ~SDHCI_VENDOR_SPEC_VSELECT;
+ writel(reg, host->ioaddr + SDHCI_VENDOR_SPEC);
+ }
return;
case SDHCI_HOST_CONTROL:
/* FSL messed up here, so we can just keep those two */
.set_clock = esdhc_set_clock,
.get_max_clock = esdhc_pltfm_get_max_clock,
.get_min_clock = esdhc_pltfm_get_min_clock,
+ .pre_tuning = esdhc_prepare_tuning,
};
static irqreturn_t cd_irq(int irq, void *data)
{
struct sdhci_host *sdhost = (struct sdhci_host *)data;
+ sdhci_writel(sdhost, 0, SDHCI_MIX_CTRL);
+ sdhci_writel(sdhost, 0, SDHCI_TUNE_CTRL_STATUS);
tasklet_schedule(&sdhost->card_tasklet);
return IRQ_HANDLED;
};
/* write_protect can't be routed to controller, use gpio */
sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
- if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
+ if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51() || cpu_is_mx6q()))
imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
if (boarddata) {
/* Now we have a working card_detect again */
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
}
+ host->ocr_avail_sd = MMC_VDD_29_30 | MMC_VDD_30_31 | \
+ MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ if (boarddata->support_18v)
+ host->ocr_avail_sd |= MMC_VDD_165_195;
+
+ host->tuning_min = SDHCI_TUNE_CTRL_MIN;
+ host->tuning_max = SDHCI_TUNE_CTRL_MAX;
+ host->tuning_step = SDHCI_TUNE_CTRL_STEP;
return 0;
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
- | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+ | SDHCI_QUIRK_BROKEN_CARD_DETECTION
+ | SDHCI_QUIRK_NO_HISPD_BIT,
/* ADMA has issues. Might be fixable */
.ops = &sdhci_esdhc_ops,
.init = esdhc_pltfm_init,