@@ -25,13 +25,21 @@
#include <linux/io.h>
#include <linux/err.h>
#include <plat/sdhci.h>
+#include <mach/cputype.h>
#include "sdhci.h"
#define DRIVER_NAME "sdhci-pxa"
+#define SD_CFG_FIFO_PARAM 0x100
+#define SDCFG_GEN_PAD_CLK_ON (1<<6)
+
#define SD_FIFO_PARAM 0x104
#define DIS_PAD_SD_CLK_GATE 0x400
+#define SD_CE_ATA_2 0x10E
+#define SDCE_MISC_INT_EN (1<<1)
+#define SDCE_MISC_INT (1<<2)
+
struct sdhci_pxa {
struct sdhci_host *host;
struct sdhci_pxa_platdata *pdata;
@@ -39,6 +47,11 @@ struct sdhci_pxa {
struct resource *res;
u8 clk_enable;
+ u8 power_mode;
+};
+
+static struct sdhci_ops sdhci_mmc_ops = {
+ .platform_send_init_74_clocks = NULL,
};
/*****************************************************************************\
@@ -73,6 +86,60 @@ static struct sdhci_ops sdhci_pxa_ops = {
.set_clock = set_clock,
};
+/*
+ * MMC spec calls for the host to send 74 clocks to the card
+ * during initialization, right after voltage stabilization.
+ * the mmp2 controller does not start the clock when the clock
+ * is enabled but does provide a way to generate the clocks by
+ * programming the hardware.
+ */
+static void generate_init_clocks_mmp2(struct sdhci_host *host, u8 power_mode)
+{
+ struct sdhci_pxa *pxa = sdhci_priv(host);
+ u16 tmp;
+ int count;
+
+ if (pxa->power_mode == MMC_POWER_UP
+ && power_mode == MMC_POWER_ON) {
+
+ /*
+ * set we want notice of when 74 clocks are sent
+ * (NOT an interrupt -- just a h/w flag that flips)
+ */
+ tmp = readw(host->ioaddr + SD_CE_ATA_2);
+ tmp |= SDCE_MISC_INT_EN;
+ writew(tmp, host->ioaddr + SD_CE_ATA_2);
+
+ /* start sending the 74 clocks */
+ tmp = readw(host->ioaddr + SD_CFG_FIFO_PARAM);
+ tmp |= SDCFG_GEN_PAD_CLK_ON;
+ writew(tmp, host->ioaddr + SD_CFG_FIFO_PARAM);
+
+ /* slowest speed is about 100KHz or 10usec per clock */
+ udelay (740);
+ count = 0;
+#define MAX_WAIT_COUNT 5
+ while (count++ < MAX_WAIT_COUNT)
+ {
+ /* check if hardware has indicated clocks sent */
+ if ((readw(host->ioaddr + SD_CE_ATA_2) & SDCE_MISC_INT) == 0)
+ break;
+ udelay(10);
+ }
+
+ /* keep going if error -- could be okay */
+ if (count == MAX_WAIT_COUNT)
+ printk (KERN_WARNING "%s: %s: 74 clock interrupt not"
+ "cleared\n",
+ __func__,
+ mmc_hostname(host->mmc));
+ /* clear the interrupt bit if posted */
+ tmp = readw(host->ioaddr + SD_CE_ATA_2);
+ tmp |= SDCE_MISC_INT;
+ writew(tmp, host->ioaddr + SD_CE_ATA_2);
+ }
+ pxa->power_mode = power_mode;
+}
/*****************************************************************************\
* *
* Device probing/removal *
@@ -145,6 +212,10 @@ static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+ if (cpu_is_mmp2())
+ sdhci_mmc_ops.platform_send_init_74_clocks =
+ generate_init_clocks_mmp2;
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "failed to add host\n");--