summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-pxa/lubbock.c16
-rw-r--r--arch/arm/mach-pxa/mainstone.c58
-rw-r--r--drivers/mmc/pxamci.c35
-rw-r--r--drivers/mmc/pxamci.h30
4 files changed, 126 insertions, 13 deletions
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index dac8de8d3b6a..87fd729c35bb 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -33,6 +33,7 @@
#include <asm/arch/lubbock.h>
#include <asm/arch/udc.h>
#include <asm/arch/pxafb.h>
+#include <asm/arch/mmc.h>
#include <asm/hardware/sa1111.h>
#include "generic.h"
@@ -183,10 +184,25 @@ static struct pxafb_mach_info sharp_lm8v31 __initdata = {
.lccr3 = LCCR3_PCP | LCCR3_Acb(255),
};
+static int lubbock_mci_init(struct device *dev, irqreturn_t (*lubbock_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+ /* setup GPIO for PXA25x MMC controller */
+ pxa_gpio_mode(GPIO6_MMCCLK_MD);
+ pxa_gpio_mode(GPIO8_MMCCS0_MD);
+
+ return 0;
+}
+
+static struct pxamci_platform_data lubbock_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = lubbock_mci_init,
+};
+
static void __init lubbock_init(void)
{
pxa_set_udc_info(&udc_info);
set_pxa_fb_info(&sharp_lm8v31);
+ pxa_set_mci_info(&lubbock_mci_platform_data);
(void) platform_add_devices(devices, ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index d57920f58d69..2c8d7c826267 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -34,6 +34,7 @@
#include <asm/arch/pxa-regs.h>
#include <asm/arch/mainstone.h>
#include <asm/arch/pxafb.h>
+#include <asm/arch/mmc.h>
#include "generic.h"
@@ -170,6 +171,61 @@ static struct pxafb_mach_info toshiba_ltm035a776c __initdata = {
.pxafb_backlight_power = mainstone_backlight_power,
};
+static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+ int err;
+
+ /*
+ * setup GPIO for PXA27x MMC controller
+ */
+ pxa_gpio_mode(GPIO32_MMCCLK_MD);
+ pxa_gpio_mode(GPIO112_MMCCMD_MD);
+ pxa_gpio_mode(GPIO92_MMCDAT0_MD);
+ pxa_gpio_mode(GPIO109_MMCDAT1_MD);
+ pxa_gpio_mode(GPIO110_MMCDAT2_MD);
+ pxa_gpio_mode(GPIO111_MMCDAT3_MD);
+
+ /* make sure SD/Memory Stick multiplexer's signals
+ * are routed to MMC controller
+ */
+ MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL;
+
+ err = request_irq(MAINSTONE_MMC_IRQ, mstone_detect_int, SA_INTERRUPT,
+ "MMC card detect", data);
+ if (err) {
+ printk(KERN_ERR "mainstone_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void mainstone_mci_setpower(struct device *dev, unsigned int vdd)
+{
+ struct pxamci_platform_data* p_d = dev->platform_data;
+
+ if (( 1 << vdd) & p_d->ocr_mask) {
+ printk(KERN_DEBUG "%s: on\n", __FUNCTION__);
+ MST_MSCWR1 |= MST_MSCWR1_MMC_ON;
+ MST_MSCWR1 &= ~MST_MSCWR1_MS_SEL;
+ } else {
+ printk(KERN_DEBUG "%s: off\n", __FUNCTION__);
+ MST_MSCWR1 &= ~MST_MSCWR1_MMC_ON;
+ }
+}
+
+static void mainstone_mci_exit(struct device *dev, void *data)
+{
+ free_irq(MAINSTONE_MMC_IRQ, data);
+}
+
+static struct pxamci_platform_data mainstone_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = mainstone_mci_init,
+ .setpower = mainstone_mci_setpower,
+ .exit = mainstone_mci_exit,
+};
+
static void __init mainstone_init(void)
{
platform_device_register(&smc91x_device);
@@ -180,6 +236,8 @@ static void __init mainstone_init(void)
set_pxa_fb_info(&toshiba_ltm04c380k);
else
set_pxa_fb_info(&toshiba_ltm035a776c);
+
+ pxa_set_mci_info(&mainstone_mci_platform_data);
}
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index 78a5e5304a62..cadaa1efdab2 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -72,11 +72,6 @@ struct pxamci_host {
unsigned int dma_dir;
};
-/*
- * The base MMC clock rate
- */
-#define CLOCKRATE 20000000
-
static inline unsigned int ns_to_clocks(unsigned int ns)
{
return (ns * (CLOCKRATE / 1000000) + 999) / 1000;
@@ -244,7 +239,24 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
if (stat & STAT_TIME_OUT_RESPONSE) {
cmd->error = MMC_ERR_TIMEOUT;
} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
+#ifdef CONFIG_PXA27x
+ /*
+ * workaround for erratum #42:
+ * Intel PXA27x Family Processor Specification Update Rev 001
+ */
+ if (cmd->opcode == MMC_ALL_SEND_CID ||
+ cmd->opcode == MMC_SEND_CSD ||
+ cmd->opcode == MMC_SEND_CID) {
+ /* a bogus CRC error can appear if the msb of
+ the 15 byte response is a one */
+ if ((cmd->resp[0] & 0x80000000) == 0)
+ cmd->error = MMC_ERR_BADCRC;
+ } else {
+ DBG("ignoring CRC from command %d - *risky*\n",cmd->opcode);
+ }
+#else
cmd->error = MMC_ERR_BADCRC;
+#endif
}
pxamci_disable_irq(host, END_CMD_RES);
@@ -429,8 +441,8 @@ static int pxamci_probe(struct device *dev)
}
mmc->ops = &pxamci_ops;
- mmc->f_min = 312500;
- mmc->f_max = 20000000;
+ mmc->f_min = CLOCKRATE_MIN;
+ mmc->f_max = CLOCKRATE_MAX;
/*
* We can do SG-DMA, but we don't because we never know how much
@@ -460,8 +472,7 @@ static int pxamci_probe(struct device *dev)
spin_lock_init(&host->lock);
host->res = r;
host->irq = irq;
- host->imask = TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
- END_CMD_RES|PRG_DONE|DATA_TRAN_DONE;
+ host->imask = MMC_I_MASK_ALL;
host->base = ioremap(r->start, SZ_4K);
if (!host->base) {
@@ -478,10 +489,6 @@ static int pxamci_probe(struct device *dev)
writel(64, host->base + MMC_RESTO);
writel(host->imask, host->base + MMC_I_MASK);
- pxa_gpio_mode(GPIO6_MMCCLK_MD);
- pxa_gpio_mode(GPIO8_MMCCS0_MD);
- pxa_set_cken(CKEN12_MMC, 1);
-
host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
pxamci_dma_irq, host);
if (host->dma < 0) {
@@ -498,6 +505,8 @@ static int pxamci_probe(struct device *dev)
if (host->pdata && host->pdata->init)
host->pdata->init(dev, pxamci_detect_irq, mmc);
+ pxa_set_cken(CKEN12_MMC, 1);
+
mmc_add_host(mmc);
return 0;
diff --git a/drivers/mmc/pxamci.h b/drivers/mmc/pxamci.h
index a80b24db9734..1b163220df2b 100644
--- a/drivers/mmc/pxamci.h
+++ b/drivers/mmc/pxamci.h
@@ -70,6 +70,16 @@
#define BUF_PART_FULL (1 << 0)
#define MMC_I_MASK 0x0028
+
+/*PXA27x MMC interrupts*/
+#define SDIO_SUSPEND_ACK (1 << 12)
+#define SDIO_INT (1 << 11)
+#define RD_STALLED (1 << 10)
+#define RES_ERR (1 << 9)
+#define DAT_ERR (1 << 8)
+#define TINT (1 << 7)
+
+/*PXA2xx MMC interrupts*/
#define TXFIFO_WR_REQ (1 << 6)
#define RXFIFO_RD_REQ (1 << 5)
#define CLK_IS_OFF (1 << 4)
@@ -78,6 +88,12 @@
#define PRG_DONE (1 << 1)
#define DATA_TRAN_DONE (1 << 0)
+#ifdef CONFIG_PXA27x
+#define MMC_I_MASK_ALL 0x00001fff
+#else
+#define MMC_I_MASK_ALL 0x0000007f
+#endif
+
#define MMC_I_REG 0x002c
/* same as MMC_I_MASK */
@@ -92,3 +108,17 @@
#define MMC_RXFIFO 0x0040 /* 8 bit */
#define MMC_TXFIFO 0x0044 /* 8 bit */
+
+/*
+ * The base MMC clock rate
+ */
+#ifdef CONFIG_PXA27x
+#define CLOCKRATE_MIN 304688
+#define CLOCKRATE_MAX 19500000
+#else
+#define CLOCKRATE_MIN 312500
+#define CLOCKRATE_MAX 20000000
+#endif
+
+#define CLOCKRATE CLOCKRATE_MAX
+