summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2010-01-26 13:06:44 +0800
committerAlejandro Gonzalez <alex.gonzalez@digi.com>2010-05-25 11:09:57 +0200
commit45ed220caddf776585b71b32f9638f5d5bf3f91a (patch)
tree405db049730e5b4f4dfeb6c3747b963f9029e068
parenta912dcccaebdf8f877def4f81687674e7b41767a (diff)
ENGR00117737-2 MX28 SD/MMC/SDIO
Enable the ssp mmc port0~1, the set_rate, set_parent to refio.0 clock, and the HighSpeed mode, SD up to 4bits and 50MHz, MMC up to 8bits and 52MHz. Resolved the urgly IO bench and some cards unrecognization issues. The root cause is the clk unit of clock should be Hz, but not the KHz Signed-off-by: Richard Zhu <r65037@freescale.com> Signed-off-by: Alejandro Gonzalez <alex.gonzalez@digi.com>
-rw-r--r--arch/arm/configs/imx28evk_defconfig19
-rw-r--r--arch/arm/mach-mx28/clock.c73
-rw-r--r--arch/arm/mach-mx28/device.c244
-rw-r--r--arch/arm/mach-mx28/include/mach/regs-ssp.h474
-rw-r--r--arch/arm/mach-mx28/mx28evk_pins.c224
-rw-r--r--arch/arm/plat-mxs/device.c36
-rw-r--r--arch/arm/plat-mxs/include/mach/device.h17
-rw-r--r--drivers/mmc/core/mmc.c2
-rw-r--r--drivers/mmc/host/Kconfig8
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/mxs-mmc.c518
11 files changed, 1381 insertions, 235 deletions
diff --git a/arch/arm/configs/imx28evk_defconfig b/arch/arm/configs/imx28evk_defconfig
index 435360116915..6adbcfb1642b 100644
--- a/arch/arm/configs/imx28evk_defconfig
+++ b/arch/arm/configs/imx28evk_defconfig
@@ -685,7 +685,24 @@ CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
# CONFIG_HID_SUPPORT is not set
# CONFIG_USB_SUPPORT is not set
-# CONFIG_MMC is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_IMX_ESDHCI_PIO_MODE is not set
+CONFIG_MMC_MXS=y
# CONFIG_MEMSTICK is not set
# CONFIG_ACCESSIBILITY is not set
# CONFIG_NEW_LEDS is not set
diff --git a/arch/arm/mach-mx28/clock.c b/arch/arm/mach-mx28/clock.c
index 6c21cfb1ab9f..913a20d3523a 100644
--- a/arch/arm/mach-mx28/clock.c
+++ b/arch/arm/mach-mx28/clock.c
@@ -446,6 +446,63 @@ static struct clk emi_clk = {
static unsigned long ssp_get_rate(struct clk *clk);
+static int ssp_set_rate(struct clk *clk, unsigned long rate)
+{
+ int ret = -EINVAL;
+ int div = (clk_get_rate(clk->parent) + rate - 1) / rate;
+ u32 reg_frac;
+ const int mask = 0x1FF;
+ int try = 10;
+ int i = -1;
+
+ if (div == 0 || div > mask)
+ goto out;
+
+ reg_frac = __raw_readl(clk->scale_reg);
+ reg_frac &= ~(mask << clk->scale_bits);
+
+ while (try--) {
+ __raw_writel(reg_frac | (div << clk->scale_bits),
+ clk->scale_reg);
+
+ if (clk->busy_reg) {
+ for (i = 10000; i; i--)
+ if (!clk_is_busy(clk))
+ break;
+ }
+ if (i)
+ break;
+ }
+
+ if (!i)
+ ret = -ETIMEDOUT;
+ else
+ ret = 0;
+
+out:
+ if (ret != 0)
+ printk(KERN_ERR "%s: error %d\n", __func__, ret);
+ return ret;
+}
+
+static int ssp_set_parent(struct clk *clk, struct clk *parent)
+{
+ int ret = -EINVAL;
+
+ if (clk->bypass_reg) {
+ if (clk->parent == parent)
+ __raw_writel(1 << clk->bypass_bits,
+ clk->bypass_reg + SET_REGISTER);
+ else
+ __raw_writel(0 << clk->bypass_bits,
+ clk->bypass_reg + CLR_REGISTER);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
static struct clk ssp_clk[] = {
{
.parent = &ref_io_clk[0],
@@ -454,6 +511,14 @@ static struct clk ssp_clk[] = {
.disable = mx28_raw_disable,
.enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP0,
.enable_bits = BM_CLKCTRL_SSP0_CLKGATE,
+ .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP0,
+ .busy_bits = 29,
+ .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP0,
+ .scale_bits = 0,
+ .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ,
+ .bypass_bits = 3,
+ .set_rate = ssp_set_rate,
+ .set_parent = ssp_set_parent,
},
{
.parent = &ref_io_clk[0],
@@ -462,6 +527,14 @@ static struct clk ssp_clk[] = {
.disable = mx28_raw_disable,
.enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP1,
.enable_bits = BM_CLKCTRL_SSP1_CLKGATE,
+ .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP1,
+ .busy_bits = 29,
+ .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP1,
+ .scale_bits = 0,
+ .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ,
+ .bypass_bits = 4,
+ .set_rate = ssp_set_rate,
+ .set_parent = ssp_set_parent,
},
{
.parent = &ref_io_clk[1],
diff --git a/arch/arm/mach-mx28/device.c b/arch/arm/mach-mx28/device.c
index 133370ef5491..fb6ea416f6be 100644
--- a/arch/arm/mach-mx28/device.c
+++ b/arch/arm/mach-mx28/device.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
#include <asm/mach/map.h>
@@ -33,6 +34,7 @@
#include <mach/dma.h>
#include "device.h"
+#include "mx28_pins.h"
#if defined(CONFIG_SERIAL_MXS_DUART) || \
defined(CONFIG_SERIAL_MXS_DUART_MODULE)
@@ -117,10 +119,252 @@ static void mx28_init_dma(void)
}
#endif
+#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE)
+#if defined(CONFIG_MACH_MX28EVK)
+#define MMC0_POWER MXS_PIN_TO_GPIO(PINID_PWM3)
+#define MMC1_POWER MXS_PIN_TO_GPIO(PINID_PWM4)
+#define MMC0_WP MXS_PIN_TO_GPIO(PINID_SSP1_SCK)
+#define MMC1_WP MXS_PIN_TO_GPIO(PINID_GPMI_RESETN)
+#endif
+
+static int mxs_mmc_get_wp_ssp0(void)
+{
+ return gpio_get_value(MMC0_WP);
+}
+
+static int mxs_mmc_hw_init_ssp0(void)
+{
+ int ret = 0;
+
+ /* Configure write protect GPIO pin */
+ ret = gpio_request(MMC0_WP, "mmc0_wp");
+ if (ret)
+ goto out_wp;
+
+ gpio_set_value(MMC0_WP, 0);
+ gpio_direction_input(MMC0_WP);
+
+ /* Configure POWER pin as gpio to drive power to MMC slot */
+ ret = gpio_request(MMC0_POWER, "mmc0_power");
+ if (ret)
+ goto out_power;
+
+ gpio_direction_output(MMC0_POWER, 0);
+ mdelay(100);
+
+ return 0;
+
+out_power:
+ gpio_free(MMC0_WP);
+out_wp:
+ return ret;
+}
+
+static void mxs_mmc_hw_release_ssp0(void)
+{
+ gpio_free(MMC0_POWER);
+ gpio_free(MMC0_WP);
+
+}
+
+static void mxs_mmc_cmd_pullup_ssp0(int enable)
+{
+ mxs_set_pullup(PINID_SSP0_CMD, enable, "mmc0_cmd");
+}
+
+static unsigned long mxs_mmc_setclock_ssp0(unsigned long hz)
+{
+ struct clk *ssp = clk_get(NULL, "ssp.0"), *parent;
+
+ if (hz > 1000000)
+ parent = clk_get(NULL, "ref_io.0");
+ else
+ parent = clk_get(NULL, "xtal.0");
+
+ clk_set_parent(ssp, parent);
+ clk_set_rate(ssp, 2 * hz);
+ clk_put(parent);
+ clk_put(ssp);
+
+ return hz;
+}
+
+static int mxs_mmc_get_wp_ssp1(void)
+{
+ return gpio_get_value(MMC1_WP);
+}
+
+static int mxs_mmc_hw_init_ssp1(void)
+{
+ int ret = 0;
+
+ /* Configure write protect GPIO pin */
+ ret = gpio_request(MMC1_WP, "mmc1_wp");
+ if (ret)
+ goto out_wp;
+
+ gpio_set_value(MMC1_WP, 0);
+ gpio_direction_input(MMC1_WP);
+
+ /* Configure POWER pin as gpio to drive power to MMC slot */
+ ret = gpio_request(MMC1_POWER, "mmc1_power");
+ if (ret)
+ goto out_power;
+
+ gpio_direction_output(MMC1_POWER, 0);
+ mdelay(100);
+
+ return 0;
+
+out_power:
+ gpio_free(MMC1_WP);
+out_wp:
+ return ret;
+}
+
+static void mxs_mmc_hw_release_ssp1(void)
+{
+ gpio_free(MMC1_POWER);
+ gpio_free(MMC1_WP);
+}
+
+static void mxs_mmc_cmd_pullup_ssp1(int enable)
+{
+ mxs_set_pullup(PINID_GPMI_RDY1, enable, "mmc1_cmd");
+}
+
+static unsigned long mxs_mmc_setclock_ssp1(unsigned long hz)
+{
+ struct clk *ssp = clk_get(NULL, "ssp.1"), *parent;
+
+ if (hz > 1000000)
+ parent = clk_get(NULL, "ref_io.0");
+ else
+ parent = clk_get(NULL, "xtal.0");
+
+ clk_set_parent(ssp, parent);
+ clk_set_rate(ssp, 2 * hz);
+ clk_put(parent);
+ clk_put(ssp);
+
+ return hz;
+}
+
+static struct mxs_mmc_platform_data mmc0_data = {
+ .hw_init = mxs_mmc_hw_init_ssp0,
+ .hw_release = mxs_mmc_hw_release_ssp0,
+ .get_wp = mxs_mmc_get_wp_ssp0,
+ .cmd_pullup = mxs_mmc_cmd_pullup_ssp0,
+ .setclock = mxs_mmc_setclock_ssp0,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .min_clk = 400000,
+ .max_clk = 52000000,
+ .read_uA = 50000,
+ .write_uA = 70000,
+ .clock_mmc = "ssp.0",
+ .power_mmc = NULL,
+};
+
+static struct resource mmc0_resource[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .start = SSP0_PHYS_ADDR,
+ .end = SSP0_PHYS_ADDR + 0x2000 - 1,
+ },
+ {
+ .flags = IORESOURCE_DMA,
+ .start = MXS_DMA_CHANNEL_AHB_APBH_SSP0,
+ .end = MXS_DMA_CHANNEL_AHB_APBH_SSP0,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_SSP0_DMA,
+ .end = IRQ_SSP0_DMA,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_SSP0,
+ .end = IRQ_SSP0,
+ },
+};
+
+static struct mxs_mmc_platform_data mmc1_data = {
+ .hw_init = mxs_mmc_hw_init_ssp1,
+ .hw_release = mxs_mmc_hw_release_ssp1,
+ .get_wp = mxs_mmc_get_wp_ssp1,
+ .cmd_pullup = mxs_mmc_cmd_pullup_ssp1,
+ .setclock = mxs_mmc_setclock_ssp1,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .min_clk = 400000,
+ .max_clk = 52000000,
+ .read_uA = 50000,
+ .write_uA = 70000,
+ .clock_mmc = "ssp.1",
+ .power_mmc = NULL,
+};
+
+static struct resource mmc1_resource[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .start = SSP1_PHYS_ADDR,
+ .end = SSP1_PHYS_ADDR + 0x2000 - 1,
+ },
+ {
+ .flags = IORESOURCE_DMA,
+ .start = MXS_DMA_CHANNEL_AHB_APBH_SSP1,
+ .end = MXS_DMA_CHANNEL_AHB_APBH_SSP1,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_SSP1_DMA,
+ .end = IRQ_SSP1_DMA,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_SSP1,
+ .end = IRQ_SSP1,
+ },
+};
+
+static void __init mx28_init_mmc(void)
+{
+ int i;
+ struct mxs_dev_lookup *lookup;
+ struct platform_device *pdev;
+
+ lookup = mxs_get_devices("mxs-mmc");
+ if (lookup == NULL || IS_ERR(lookup))
+ return;
+ for (i = 0; i < lookup->size; i++) {
+ pdev = lookup->pdev + i;
+ switch (pdev->id) {
+ case 0:
+ pdev->resource = mmc0_resource;
+ pdev->num_resources = ARRAY_SIZE(mmc0_resource);
+ pdev->dev.platform_data = &mmc0_data;
+ break;
+ case 1:
+ pdev->resource = mmc1_resource;
+ pdev->num_resources = ARRAY_SIZE(mmc1_resource);
+ pdev->dev.platform_data = &mmc1_data;
+ break;
+ default:
+ return;
+ }
+ mxs_add_device(pdev, 2);
+ }
+}
+#else
+static void mx28_init_mmc(void)
+{
+}
+#endif
+
int __init mx28_device_init(void)
{
mx28_init_dma();
mx28_init_duart();
+ mx28_init_mmc();
return 0;
}
diff --git a/arch/arm/mach-mx28/include/mach/regs-ssp.h b/arch/arm/mach-mx28/include/mach/regs-ssp.h
new file mode 100644
index 000000000000..1d4793b25a3b
--- /dev/null
+++ b/arch/arm/mach-mx28/include/mach/regs-ssp.h
@@ -0,0 +1,474 @@
+/*
+ * Freescale SSP Register Definitions
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 4.0
+ * Template revision: 26195
+ */
+
+#ifndef __ARCH_ARM___SSP_H
+#define __ARCH_ARM___SSP_H
+
+#ifndef BF
+#define BF(value, field) (((value) << BP_##field) & BM_##field)
+#endif
+
+#define HW_SSP_CTRL0 (0x00000000)
+#define HW_SSP_CTRL0_SET (0x00000004)
+#define HW_SSP_CTRL0_CLR (0x00000008)
+#define HW_SSP_CTRL0_TOG (0x0000000c)
+
+#define BM_SSP_CTRL0_SFTRST 0x80000000
+#define BM_SSP_CTRL0_CLKGATE 0x40000000
+#define BM_SSP_CTRL0_RUN 0x20000000
+#define BM_SSP_CTRL0_SDIO_IRQ_CHECK 0x10000000
+#define BM_SSP_CTRL0_LOCK_CS 0x08000000
+#define BM_SSP_CTRL0_IGNORE_CRC 0x04000000
+#define BM_SSP_CTRL0_READ 0x02000000
+#define BM_SSP_CTRL0_DATA_XFER 0x01000000
+#define BP_SSP_CTRL0_BUS_WIDTH 22
+#define BM_SSP_CTRL0_BUS_WIDTH 0x00C00000
+#define BF_SSP_CTRL0_BUS_WIDTH(v) \
+ (((v) << 22) & BM_SSP_CTRL0_BUS_WIDTH)
+#define BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT 0x0
+#define BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT 0x1
+#define BV_SSP_CTRL0_BUS_WIDTH__EIGHT_BIT 0x2
+#define BM_SSP_CTRL0_WAIT_FOR_IRQ 0x00200000
+#define BM_SSP_CTRL0_WAIT_FOR_CMD 0x00100000
+#define BM_SSP_CTRL0_LONG_RESP 0x00080000
+#define BM_SSP_CTRL0_CHECK_RESP 0x00040000
+#define BM_SSP_CTRL0_GET_RESP 0x00020000
+#define BM_SSP_CTRL0_ENABLE 0x00010000
+#define BP_SSP_CTRL0_RSVD0 0
+#define BM_SSP_CTRL0_RSVD0 0x0000FFFF
+#define BF_SSP_CTRL0_RSVD0(v) \
+ (((v) << 0) & BM_SSP_CTRL0_RSVD0)
+
+#define HW_SSP_CMD0 (0x00000010)
+#define HW_SSP_CMD0_SET (0x00000014)
+#define HW_SSP_CMD0_CLR (0x00000018)
+#define HW_SSP_CMD0_TOG (0x0000001c)
+
+#define BP_SSP_CMD0_RSVD0 27
+#define BM_SSP_CMD0_RSVD0 0xF8000000
+#define BF_SSP_CMD0_RSVD0(v) \
+ (((v) << 27) & BM_SSP_CMD0_RSVD0)
+#define BM_SSP_CMD0_SOFT_TERMINATE 0x04000000
+#define BM_SSP_CMD0_DBL_DATA_RATE_EN 0x02000000
+#define BM_SSP_CMD0_PRIM_BOOT_OP_EN 0x01000000
+#define BM_SSP_CMD0_BOOT_ACK_EN 0x00800000
+#define BM_SSP_CMD0_SLOW_CLKING_EN 0x00400000
+#define BM_SSP_CMD0_CONT_CLKING_EN 0x00200000
+#define BM_SSP_CMD0_APPEND_8CYC 0x00100000
+#define BP_SSP_CMD0_RSVD1 8
+#define BM_SSP_CMD0_RSVD1 0x000FFF00
+#define BF_SSP_CMD0_RSVD1(v) \
+ (((v) << 8) & BM_SSP_CMD0_RSVD1)
+#define BP_SSP_CMD0_CMD 0
+#define BM_SSP_CMD0_CMD 0x000000FF
+#define BF_SSP_CMD0_CMD(v) \
+ (((v) << 0) & BM_SSP_CMD0_CMD)
+#define BV_SSP_CMD0_CMD__MMC_GO_IDLE_STATE 0x00
+#define BV_SSP_CMD0_CMD__MMC_SEND_OP_COND 0x01
+#define BV_SSP_CMD0_CMD__MMC_ALL_SEND_CID 0x02
+#define BV_SSP_CMD0_CMD__MMC_SET_RELATIVE_ADDR 0x03
+#define BV_SSP_CMD0_CMD__MMC_SET_DSR 0x04
+#define BV_SSP_CMD0_CMD__MMC_RESERVED_5 0x05
+#define BV_SSP_CMD0_CMD__MMC_SWITCH 0x06
+#define BV_SSP_CMD0_CMD__MMC_SELECT_DESELECT_CARD 0x07
+#define BV_SSP_CMD0_CMD__MMC_SEND_EXT_CSD 0x08
+#define BV_SSP_CMD0_CMD__MMC_SEND_CSD 0x09
+#define BV_SSP_CMD0_CMD__MMC_SEND_CID 0x0A
+#define BV_SSP_CMD0_CMD__MMC_READ_DAT_UNTIL_STOP 0x0B
+#define BV_SSP_CMD0_CMD__MMC_STOP_TRANSMISSION 0x0C
+#define BV_SSP_CMD0_CMD__MMC_SEND_STATUS 0x0D
+#define BV_SSP_CMD0_CMD__MMC_BUSTEST_R 0x0E
+#define BV_SSP_CMD0_CMD__MMC_GO_INACTIVE_STATE 0x0F
+#define BV_SSP_CMD0_CMD__MMC_SET_BLOCKLEN 0x10
+#define BV_SSP_CMD0_CMD__MMC_READ_SINGLE_BLOCK 0x11
+#define BV_SSP_CMD0_CMD__MMC_READ_MULTIPLE_BLOCK 0x12
+#define BV_SSP_CMD0_CMD__MMC_BUSTEST_W 0x13
+#define BV_SSP_CMD0_CMD__MMC_WRITE_DAT_UNTIL_STOP 0x14
+#define BV_SSP_CMD0_CMD__MMC_SET_BLOCK_COUNT 0x17
+#define BV_SSP_CMD0_CMD__MMC_WRITE_BLOCK 0x18
+#define BV_SSP_CMD0_CMD__MMC_WRITE_MULTIPLE_BLOCK 0x19
+#define BV_SSP_CMD0_CMD__MMC_PROGRAM_CID 0x1A
+#define BV_SSP_CMD0_CMD__MMC_PROGRAM_CSD 0x1B
+#define BV_SSP_CMD0_CMD__MMC_SET_WRITE_PROT 0x1C
+#define BV_SSP_CMD0_CMD__MMC_CLR_WRITE_PROT 0x1D
+#define BV_SSP_CMD0_CMD__MMC_SEND_WRITE_PROT 0x1E
+#define BV_SSP_CMD0_CMD__MMC_ERASE_GROUP_START 0x23
+#define BV_SSP_CMD0_CMD__MMC_ERASE_GROUP_END 0x24
+#define BV_SSP_CMD0_CMD__MMC_ERASE 0x26
+#define BV_SSP_CMD0_CMD__MMC_FAST_IO 0x27
+#define BV_SSP_CMD0_CMD__MMC_GO_IRQ_STATE 0x28
+#define BV_SSP_CMD0_CMD__MMC_LOCK_UNLOCK 0x2A
+#define BV_SSP_CMD0_CMD__MMC_APP_CMD 0x37
+#define BV_SSP_CMD0_CMD__MMC_GEN_CMD 0x38
+#define BV_SSP_CMD0_CMD__SD_GO_IDLE_STATE 0x00
+#define BV_SSP_CMD0_CMD__SD_ALL_SEND_CID 0x02
+#define BV_SSP_CMD0_CMD__SD_SEND_RELATIVE_ADDR 0x03
+#define BV_SSP_CMD0_CMD__SD_SET_DSR 0x04
+#define BV_SSP_CMD0_CMD__SD_IO_SEND_OP_COND 0x05
+#define BV_SSP_CMD0_CMD__SD_SELECT_DESELECT_CARD 0x07
+#define BV_SSP_CMD0_CMD__SD_SEND_CSD 0x09
+#define BV_SSP_CMD0_CMD__SD_SEND_CID 0x0A
+#define BV_SSP_CMD0_CMD__SD_STOP_TRANSMISSION 0x0C
+#define BV_SSP_CMD0_CMD__SD_SEND_STATUS 0x0D
+#define BV_SSP_CMD0_CMD__SD_GO_INACTIVE_STATE 0x0F
+#define BV_SSP_CMD0_CMD__SD_SET_BLOCKLEN 0x10
+#define BV_SSP_CMD0_CMD__SD_READ_SINGLE_BLOCK 0x11
+#define BV_SSP_CMD0_CMD__SD_READ_MULTIPLE_BLOCK 0x12
+#define BV_SSP_CMD0_CMD__SD_WRITE_BLOCK 0x18
+#define BV_SSP_CMD0_CMD__SD_WRITE_MULTIPLE_BLOCK 0x19
+#define BV_SSP_CMD0_CMD__SD_PROGRAM_CSD 0x1B
+#define BV_SSP_CMD0_CMD__SD_SET_WRITE_PROT 0x1C
+#define BV_SSP_CMD0_CMD__SD_CLR_WRITE_PROT 0x1D
+#define BV_SSP_CMD0_CMD__SD_SEND_WRITE_PROT 0x1E
+#define BV_SSP_CMD0_CMD__SD_ERASE_WR_BLK_START 0x20
+#define BV_SSP_CMD0_CMD__SD_ERASE_WR_BLK_END 0x21
+#define BV_SSP_CMD0_CMD__SD_ERASE_GROUP_START 0x23
+#define BV_SSP_CMD0_CMD__SD_ERASE_GROUP_END 0x24
+#define BV_SSP_CMD0_CMD__SD_ERASE 0x26
+#define BV_SSP_CMD0_CMD__SD_LOCK_UNLOCK 0x2A
+#define BV_SSP_CMD0_CMD__SD_IO_RW_DIRECT 0x34
+#define BV_SSP_CMD0_CMD__SD_IO_RW_EXTENDED 0x35
+#define BV_SSP_CMD0_CMD__SD_APP_CMD 0x37
+#define BV_SSP_CMD0_CMD__SD_GEN_CMD 0x38
+
+#define HW_SSP_CMD1 (0x00000020)
+
+#define BP_SSP_CMD1_CMD_ARG 0
+#define BM_SSP_CMD1_CMD_ARG 0xFFFFFFFF
+#define BF_SSP_CMD1_CMD_ARG(v) (v)
+
+#define HW_SSP_XFER_SIZE (0x00000030)
+
+#define BP_SSP_XFER_SIZE_XFER_COUNT 0
+#define BM_SSP_XFER_SIZE_XFER_COUNT 0xFFFFFFFF
+#define BF_SSP_XFER_SIZE_XFER_COUNT(v) (v)
+
+#define HW_SSP_BLOCK_SIZE (0x00000040)
+
+#define BP_SSP_BLOCK_SIZE_RSVD0 28
+#define BM_SSP_BLOCK_SIZE_RSVD0 0xF0000000
+#define BF_SSP_BLOCK_SIZE_RSVD0(v) \
+ (((v) << 28) & BM_SSP_BLOCK_SIZE_RSVD0)
+#define BP_SSP_BLOCK_SIZE_BLOCK_COUNT 4
+#define BM_SSP_BLOCK_SIZE_BLOCK_COUNT 0x0FFFFFF0
+#define BF_SSP_BLOCK_SIZE_BLOCK_COUNT(v) \
+ (((v) << 4) & BM_SSP_BLOCK_SIZE_BLOCK_COUNT)
+#define BP_SSP_BLOCK_SIZE_BLOCK_SIZE 0
+#define BM_SSP_BLOCK_SIZE_BLOCK_SIZE 0x0000000F
+#define BF_SSP_BLOCK_SIZE_BLOCK_SIZE(v) \
+ (((v) << 0) & BM_SSP_BLOCK_SIZE_BLOCK_SIZE)
+
+#define HW_SSP_COMPREF (0x00000050)
+
+#define BP_SSP_COMPREF_REFERENCE 0
+#define BM_SSP_COMPREF_REFERENCE 0xFFFFFFFF
+#define BF_SSP_COMPREF_REFERENCE(v) (v)
+
+#define HW_SSP_COMPMASK (0x00000060)
+
+#define BP_SSP_COMPMASK_MASK 0
+#define BM_SSP_COMPMASK_MASK 0xFFFFFFFF
+#define BF_SSP_COMPMASK_MASK(v) (v)
+
+#define HW_SSP_TIMING (0x00000070)
+
+#define BP_SSP_TIMING_TIMEOUT 16
+#define BM_SSP_TIMING_TIMEOUT 0xFFFF0000
+#define BF_SSP_TIMING_TIMEOUT(v) \
+ (((v) << 16) & BM_SSP_TIMING_TIMEOUT)
+#define BP_SSP_TIMING_CLOCK_DIVIDE 8
+#define BM_SSP_TIMING_CLOCK_DIVIDE 0x0000FF00
+#define BF_SSP_TIMING_CLOCK_DIVIDE(v) \
+ (((v) << 8) & BM_SSP_TIMING_CLOCK_DIVIDE)
+#define BP_SSP_TIMING_CLOCK_RATE 0
+#define BM_SSP_TIMING_CLOCK_RATE 0x000000FF
+#define BF_SSP_TIMING_CLOCK_RATE(v) \
+ (((v) << 0) & BM_SSP_TIMING_CLOCK_RATE)
+
+#define HW_SSP_CTRL1 (0x00000080)
+#define HW_SSP_CTRL1_SET (0x00000084)
+#define HW_SSP_CTRL1_CLR (0x00000088)
+#define HW_SSP_CTRL1_TOG (0x0000008c)
+
+#define BM_SSP_CTRL1_SDIO_IRQ 0x80000000
+#define BM_SSP_CTRL1_SDIO_IRQ_EN 0x40000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ 0x20000000
+#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN 0x10000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ 0x08000000
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN 0x04000000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ 0x02000000
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN 0x01000000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ 0x00800000
+#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN 0x00400000
+#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ 0x00200000
+#define BM_SSP_CTRL1_FIFO_UNDERRUN_EN 0x00100000
+#define BM_SSP_CTRL1_CEATA_CCS_ERR_IRQ 0x00080000
+#define BM_SSP_CTRL1_CEATA_CCS_ERR_IRQ_EN 0x00040000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ 0x00020000
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN 0x00010000
+#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ 0x00008000
+#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN 0x00004000
+#define BM_SSP_CTRL1_DMA_ENABLE 0x00002000
+#define BM_SSP_CTRL1_CEATA_CCS_ERR_EN 0x00001000
+#define BM_SSP_CTRL1_SLAVE_OUT_DISABLE 0x00000800
+#define BM_SSP_CTRL1_PHASE 0x00000400
+#define BM_SSP_CTRL1_POLARITY 0x00000200
+#define BM_SSP_CTRL1_SLAVE_MODE 0x00000100
+#define BP_SSP_CTRL1_WORD_LENGTH 4
+#define BM_SSP_CTRL1_WORD_LENGTH 0x000000F0
+#define BF_SSP_CTRL1_WORD_LENGTH(v) \
+ (((v) << 4) & BM_SSP_CTRL1_WORD_LENGTH)
+#define BV_SSP_CTRL1_WORD_LENGTH__RESERVED0 0x0
+#define BV_SSP_CTRL1_WORD_LENGTH__RESERVED1 0x1
+#define BV_SSP_CTRL1_WORD_LENGTH__RESERVED2 0x2
+#define BV_SSP_CTRL1_WORD_LENGTH__FOUR_BITS 0x3
+#define BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS 0x7
+#define BV_SSP_CTRL1_WORD_LENGTH__SIXTEEN_BITS 0xF
+#define BP_SSP_CTRL1_SSP_MODE 0
+#define BM_SSP_CTRL1_SSP_MODE 0x0000000F
+#define BF_SSP_CTRL1_SSP_MODE(v) \
+ (((v) << 0) & BM_SSP_CTRL1_SSP_MODE)
+#define BV_SSP_CTRL1_SSP_MODE__SPI 0x0
+#define BV_SSP_CTRL1_SSP_MODE__SSI 0x1
+#define BV_SSP_CTRL1_SSP_MODE__SD_MMC 0x3
+#define BV_SSP_CTRL1_SSP_MODE__MS 0x4
+
+#define HW_SSP_DATA (0x00000090)
+
+#define BP_SSP_DATA_DATA 0
+#define BM_SSP_DATA_DATA 0xFFFFFFFF
+#define BF_SSP_DATA_DATA(v) (v)
+
+#define HW_SSP_SDRESP0 (0x000000a0)
+
+#define BP_SSP_SDRESP0_RESP0 0
+#define BM_SSP_SDRESP0_RESP0 0xFFFFFFFF
+#define BF_SSP_SDRESP0_RESP0(v) (v)
+
+#define HW_SSP_SDRESP1 (0x000000b0)
+
+#define BP_SSP_SDRESP1_RESP1 0
+#define BM_SSP_SDRESP1_RESP1 0xFFFFFFFF
+#define BF_SSP_SDRESP1_RESP1(v) (v)
+
+#define HW_SSP_SDRESP2 (0x000000c0)
+
+#define BP_SSP_SDRESP2_RESP2 0
+#define BM_SSP_SDRESP2_RESP2 0xFFFFFFFF
+#define BF_SSP_SDRESP2_RESP2(v) (v)
+
+#define HW_SSP_SDRESP3 (0x000000d0)
+
+#define BP_SSP_SDRESP3_RESP3 0
+#define BM_SSP_SDRESP3_RESP3 0xFFFFFFFF
+#define BF_SSP_SDRESP3_RESP3(v) (v)
+
+#define HW_SSP_DDR_CTRL (0x000000e0)
+
+#define BP_SSP_DDR_CTRL_DMA_BURST_TYPE 30
+#define BM_SSP_DDR_CTRL_DMA_BURST_TYPE 0xC0000000
+#define BF_SSP_DDR_CTRL_DMA_BURST_TYPE(v) \
+ (((v) << 30) & BM_SSP_DDR_CTRL_DMA_BURST_TYPE)
+#define BP_SSP_DDR_CTRL_RSVD0 2
+#define BM_SSP_DDR_CTRL_RSVD0 0x3FFFFFFC
+#define BF_SSP_DDR_CTRL_RSVD0(v) \
+ (((v) << 2) & BM_SSP_DDR_CTRL_RSVD0)
+#define BM_SSP_DDR_CTRL_NIBBLE_POS 0x00000002
+#define BM_SSP_DDR_CTRL_TXCLK_DELAY_TYPE 0x00000001
+
+#define HW_SSP_DLL_CTRL (0x000000f0)
+
+#define BP_SSP_DLL_CTRL_REF_UPDATE_INT 28
+#define BM_SSP_DLL_CTRL_REF_UPDATE_INT 0xF0000000
+#define BF_SSP_DLL_CTRL_REF_UPDATE_INT(v) \
+ (((v) << 28) & BM_SSP_DLL_CTRL_REF_UPDATE_INT)
+#define BP_SSP_DLL_CTRL_SLV_UPDATE_INT 20
+#define BM_SSP_DLL_CTRL_SLV_UPDATE_INT 0x0FF00000
+#define BF_SSP_DLL_CTRL_SLV_UPDATE_INT(v) \
+ (((v) << 20) & BM_SSP_DLL_CTRL_SLV_UPDATE_INT)
+#define BP_SSP_DLL_CTRL_RSVD1 16
+#define BM_SSP_DLL_CTRL_RSVD1 0x000F0000
+#define BF_SSP_DLL_CTRL_RSVD1(v) \
+ (((v) << 16) & BM_SSP_DLL_CTRL_RSVD1)
+#define BP_SSP_DLL_CTRL_SLV_OVERRIDE_VAL 10
+#define BM_SSP_DLL_CTRL_SLV_OVERRIDE_VAL 0x0000FC00
+#define BF_SSP_DLL_CTRL_SLV_OVERRIDE_VAL(v) \
+ (((v) << 10) & BM_SSP_DLL_CTRL_SLV_OVERRIDE_VAL)
+#define BM_SSP_DLL_CTRL_SLV_OVERRIDE 0x00000200
+#define BM_SSP_DLL_CTRL_RSVD0 0x00000100
+#define BM_SSP_DLL_CTRL_GATE_UPDATE 0x00000080
+#define BP_SSP_DLL_CTRL_SLV_DLY_TARGET 3
+#define BM_SSP_DLL_CTRL_SLV_DLY_TARGET 0x00000078
+#define BF_SSP_DLL_CTRL_SLV_DLY_TARGET(v) \
+ (((v) << 3) & BM_SSP_DLL_CTRL_SLV_DLY_TARGET)
+#define BM_SSP_DLL_CTRL_SLV_FORCE_UPD 0x00000004
+#define BM_SSP_DLL_CTRL_RESET 0x00000002
+#define BM_SSP_DLL_CTRL_ENABLE 0x00000001
+
+#define HW_SSP_STATUS (0x00000100)
+
+#define BM_SSP_STATUS_PRESENT 0x80000000
+#define BM_SSP_STATUS_MS_PRESENT 0x40000000
+#define BM_SSP_STATUS_SD_PRESENT 0x20000000
+#define BM_SSP_STATUS_CARD_DETECT 0x10000000
+#define BP_SSP_STATUS_RSVD3 23
+#define BM_SSP_STATUS_RSVD3 0x0F800000
+#define BF_SSP_STATUS_RSVD3(v) \
+ (((v) << 23) & BM_SSP_STATUS_RSVD3)
+#define BM_SSP_STATUS_DMABURST 0x00400000
+#define BM_SSP_STATUS_DMASENSE 0x00200000
+#define BM_SSP_STATUS_DMATERM 0x00100000
+#define BM_SSP_STATUS_DMAREQ 0x00080000
+#define BM_SSP_STATUS_DMAEND 0x00040000
+#define BM_SSP_STATUS_SDIO_IRQ 0x00020000
+#define BM_SSP_STATUS_RESP_CRC_ERR 0x00010000
+#define BM_SSP_STATUS_RESP_ERR 0x00008000
+#define BM_SSP_STATUS_RESP_TIMEOUT 0x00004000
+#define BM_SSP_STATUS_DATA_CRC_ERR 0x00002000
+#define BM_SSP_STATUS_TIMEOUT 0x00001000
+#define BM_SSP_STATUS_RECV_TIMEOUT_STAT 0x00000800
+#define BM_SSP_STATUS_CEATA_CCS_ERR 0x00000400
+#define BM_SSP_STATUS_FIFO_OVRFLW 0x00000200
+#define BM_SSP_STATUS_FIFO_FULL 0x00000100
+#define BP_SSP_STATUS_RSVD1 6
+#define BM_SSP_STATUS_RSVD1 0x000000C0
+#define BF_SSP_STATUS_RSVD1(v) \
+ (((v) << 6) & BM_SSP_STATUS_RSVD1)
+#define BM_SSP_STATUS_FIFO_EMPTY 0x00000020
+#define BM_SSP_STATUS_FIFO_UNDRFLW 0x00000010
+#define BM_SSP_STATUS_CMD_BUSY 0x00000008
+#define BM_SSP_STATUS_DATA_BUSY 0x00000004
+#define BM_SSP_STATUS_RSVD0 0x00000002
+#define BM_SSP_STATUS_BUSY 0x00000001
+
+#define HW_SSP_DLL_STS (0x00000110)
+
+#define BP_SSP_DLL_STS_RSVD0 14
+#define BM_SSP_DLL_STS_RSVD0 0xFFFFC000
+#define BF_SSP_DLL_STS_RSVD0(v) \
+ (((v) << 14) & BM_SSP_DLL_STS_RSVD0)
+#define BP_SSP_DLL_STS_REF_SEL 8
+#define BM_SSP_DLL_STS_REF_SEL 0x00003F00
+#define BF_SSP_DLL_STS_REF_SEL(v) \
+ (((v) << 8) & BM_SSP_DLL_STS_REF_SEL)
+#define BP_SSP_DLL_STS_SLV_SEL 2
+#define BM_SSP_DLL_STS_SLV_SEL 0x000000FC
+#define BF_SSP_DLL_STS_SLV_SEL(v) \
+ (((v) << 2) & BM_SSP_DLL_STS_SLV_SEL)
+#define BM_SSP_DLL_STS_REF_LOCK 0x00000002
+#define BM_SSP_DLL_STS_SLV_LOCK 0x00000001
+
+#define HW_SSP_DEBUG (0x00000120)
+
+#define BP_SSP_DEBUG_DATACRC_ERR 28
+#define BM_SSP_DEBUG_DATACRC_ERR 0xF0000000
+#define BF_SSP_DEBUG_DATACRC_ERR(v) \
+ (((v) << 28) & BM_SSP_DEBUG_DATACRC_ERR)
+#define BM_SSP_DEBUG_DATA_STALL 0x08000000
+#define BP_SSP_DEBUG_DAT_SM 24
+#define BM_SSP_DEBUG_DAT_SM 0x07000000
+#define BF_SSP_DEBUG_DAT_SM(v) \
+ (((v) << 24) & BM_SSP_DEBUG_DAT_SM)
+#define BV_SSP_DEBUG_DAT_SM__DSM_IDLE 0x0
+#define BV_SSP_DEBUG_DAT_SM__DSM_WORD 0x2
+#define BV_SSP_DEBUG_DAT_SM__DSM_CRC1 0x3
+#define BV_SSP_DEBUG_DAT_SM__DSM_CRC2 0x4
+#define BV_SSP_DEBUG_DAT_SM__DSM_END 0x5
+#define BP_SSP_DEBUG_MSTK_SM 20
+#define BM_SSP_DEBUG_MSTK_SM 0x00F00000
+#define BF_SSP_DEBUG_MSTK_SM(v) \
+ (((v) << 20) & BM_SSP_DEBUG_MSTK_SM)
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_IDLE 0x0
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_CKON 0x1
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_BS1 0x2
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_TPC 0x3
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_BS2 0x4
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_HDSHK 0x5
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_BS3 0x6
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_RW 0x7
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_CRC1 0x8
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_CRC2 0x9
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_BS0 0xA
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_END1 0xB
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_END2W 0xC
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_END2R 0xD
+#define BV_SSP_DEBUG_MSTK_SM__MSTK_DONE 0xE
+#define BM_SSP_DEBUG_CMD_OE 0x00080000
+#define BP_SSP_DEBUG_DMA_SM 16
+#define BM_SSP_DEBUG_DMA_SM 0x00070000
+#define BF_SSP_DEBUG_DMA_SM(v) \
+ (((v) << 16) & BM_SSP_DEBUG_DMA_SM)
+#define BV_SSP_DEBUG_DMA_SM__DMA_IDLE 0x0
+#define BV_SSP_DEBUG_DMA_SM__DMA_DMAREQ 0x1
+#define BV_SSP_DEBUG_DMA_SM__DMA_DMAACK 0x2
+#define BV_SSP_DEBUG_DMA_SM__DMA_STALL 0x3
+#define BV_SSP_DEBUG_DMA_SM__DMA_BUSY 0x4
+#define BV_SSP_DEBUG_DMA_SM__DMA_DONE 0x5
+#define BV_SSP_DEBUG_DMA_SM__DMA_COUNT 0x6
+#define BP_SSP_DEBUG_MMC_SM 12
+#define BM_SSP_DEBUG_MMC_SM 0x0000F000
+#define BF_SSP_DEBUG_MMC_SM(v) \
+ (((v) << 12) & BM_SSP_DEBUG_MMC_SM)
+#define BV_SSP_DEBUG_MMC_SM__MMC_IDLE 0x0
+#define BV_SSP_DEBUG_MMC_SM__MMC_CMD 0x1
+#define BV_SSP_DEBUG_MMC_SM__MMC_TRC 0x2
+#define BV_SSP_DEBUG_MMC_SM__MMC_RESP 0x3
+#define BV_SSP_DEBUG_MMC_SM__MMC_RPRX 0x4
+#define BV_SSP_DEBUG_MMC_SM__MMC_TX 0x5
+#define BV_SSP_DEBUG_MMC_SM__MMC_CTOK 0x6
+#define BV_SSP_DEBUG_MMC_SM__MMC_RX 0x7
+#define BV_SSP_DEBUG_MMC_SM__MMC_CCS 0x8
+#define BV_SSP_DEBUG_MMC_SM__MMC_PUP 0x9
+#define BV_SSP_DEBUG_MMC_SM__MMC_WAIT 0xA
+#define BP_SSP_DEBUG_CMD_SM 10
+#define BM_SSP_DEBUG_CMD_SM 0x00000C00
+#define BF_SSP_DEBUG_CMD_SM(v) \
+ (((v) << 10) & BM_SSP_DEBUG_CMD_SM)
+#define BV_SSP_DEBUG_CMD_SM__CSM_IDLE 0x0
+#define BV_SSP_DEBUG_CMD_SM__CSM_INDEX 0x1
+#define BV_SSP_DEBUG_CMD_SM__CSM_ARG 0x2
+#define BV_SSP_DEBUG_CMD_SM__CSM_CRC 0x3
+#define BM_SSP_DEBUG_SSP_CMD 0x00000200
+#define BM_SSP_DEBUG_SSP_RESP 0x00000100
+#define BP_SSP_DEBUG_SSP_RXD 0
+#define BM_SSP_DEBUG_SSP_RXD 0x000000FF
+#define BF_SSP_DEBUG_SSP_RXD(v) \
+ (((v) << 0) & BM_SSP_DEBUG_SSP_RXD)
+
+#define HW_SSP_VERSION (0x00000130)
+
+#define BP_SSP_VERSION_MAJOR 24
+#define BM_SSP_VERSION_MAJOR 0xFF000000
+#define BF_SSP_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_SSP_VERSION_MAJOR)
+#define BP_SSP_VERSION_MINOR 16
+#define BM_SSP_VERSION_MINOR 0x00FF0000
+#define BF_SSP_VERSION_MINOR(v) \
+ (((v) << 16) & BM_SSP_VERSION_MINOR)
+#define BP_SSP_VERSION_STEP 0
+#define BM_SSP_VERSION_STEP 0x0000FFFF
+#define BF_SSP_VERSION_STEP(v) \
+ (((v) << 0) & BM_SSP_VERSION_STEP)
+#endif /* __ARCH_ARM___SSP_H */
diff --git a/arch/arm/mach-mx28/mx28evk_pins.c b/arch/arm/mach-mx28/mx28evk_pins.c
index 58d6ba6c3eb7..9c9ff4bfc411 100644
--- a/arch/arm/mach-mx28/mx28evk_pins.c
+++ b/arch/arm/mach-mx28/mx28evk_pins.c
@@ -37,6 +37,230 @@ static struct pin_desc mx28evk_fixed_pins[] = {
.id = PINID_PWM1,
.fun = PIN_FUN3,
},
+#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE)
+ /* Configurations of SSP0 SD/MMC port pins */
+ {
+ .name = "SSP0_DATA0",
+ .id = PINID_SSP0_DATA0,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP0_DATA1",
+ .id = PINID_SSP0_DATA1,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP0_DATA2",
+ .id = PINID_SSP0_DATA2,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP0_DATA3",
+ .id = PINID_SSP0_DATA3,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP0_DATA4",
+ .id = PINID_SSP0_DATA4,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP0_DATA5",
+ .id = PINID_SSP0_DATA5,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP0_DATA6",
+ .id = PINID_SSP0_DATA6,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP0_DATA7",
+ .id = PINID_SSP0_DATA7,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP0_CMD",
+ .id = PINID_SSP0_CMD,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP0_DETECT",
+ .id = PINID_SSP0_DETECT,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = 1,
+ .pull = 0,
+ },
+ {
+ .name = "SSP0_SCK",
+ .id = PINID_SSP0_SCK,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = 1,
+ .pull = 0,
+ },
+ /* Configurations of SSP1 SD/MMC port pins */
+ {
+ .name = "SSP1_DATA0",
+ .id = PINID_GPMI_D00,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA1",
+ .id = PINID_GPMI_D01,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA2",
+ .id = PINID_GPMI_D02,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA3",
+ .id = PINID_GPMI_D03,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA4",
+ .id = PINID_GPMI_D04,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA5",
+ .id = PINID_GPMI_D05,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA6",
+ .id = PINID_GPMI_D06,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA7",
+ .id = PINID_GPMI_D07,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_CMD",
+ .id = PINID_GPMI_RDY1,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DETECT",
+ .id = PINID_GPMI_RDY0,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = 1,
+ .pull = 0,
+ },
+ {
+ .name = "SSP1_SCK",
+ .id = PINID_GPMI_WRN,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = 1,
+ .pull = 0,
+ },
+#endif
};
void __init mx28evk_pins_init(void)
diff --git a/arch/arm/plat-mxs/device.c b/arch/arm/plat-mxs/device.c
index 9c9c6222127f..c0afc4a8e651 100644
--- a/arch/arm/plat-mxs/device.c
+++ b/arch/arm/plat-mxs/device.c
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <mach/device.h>
@@ -36,6 +37,8 @@ static struct list_head mxs_device_level[] = {
LIST_HEAD_INIT(mxs_device_level[3]),
};
+static u64 common_dmamask = DMA_BIT_MASK(32);
+
void mxs_nop_release(struct device *dev)
{
/* Nothing */
@@ -107,6 +110,30 @@ static struct platform_device mxs_dma[] = {
};
#endif
+#if defined(CONFIG_MMC_MXS) || \
+ defined(CONFIG_MMC_MXS_MODULE)
+static struct platform_device mxs_mmc[] = {
+ {
+ .name = "mxs-mmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &common_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .release = mxs_nop_release,
+ },
+ },
+ {
+ .name = "mxs-mmc",
+ .id = 1,
+ .dev = {
+ .dma_mask = &common_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .release = mxs_nop_release,
+ },
+ },
+};
+#endif
+
static struct mxs_dev_lookup dev_lookup[] = {
#if defined(CONFIG_SERIAL_MXS_DUART) || \
defined(CONFIG_SERIAL_MXS_DUART_MODULE)
@@ -123,6 +150,15 @@ static struct mxs_dev_lookup dev_lookup[] = {
.pdev = mxs_dma,
},
#endif
+
+#if defined(CONFIG_MMC_MXS) || \
+ defined(CONFIG_MMC_MXS_MODULE)
+ {
+ .name = "mxs-mmc",
+ .size = ARRAY_SIZE(mxs_mmc),
+ .pdev = mxs_mmc,
+ }
+#endif
};
struct platform_device *mxs_get_device(char *name, int id)
diff --git a/arch/arm/plat-mxs/include/mach/device.h b/arch/arm/plat-mxs/include/mach/device.h
index 2debcc89ffec..2e9d5968c31b 100644
--- a/arch/arm/plat-mxs/include/mach/device.h
+++ b/arch/arm/plat-mxs/include/mach/device.h
@@ -61,6 +61,23 @@ extern int mxs_add_device(struct platform_device *, int level);
extern struct platform_device *mxs_get_device(char *name, int id);
extern struct mxs_dev_lookup *mxs_get_devices(char *name);
+/* mxs ssp sd/mmc data definitons */
+struct mxs_mmc_platform_data {
+ int (*hw_init)(void);
+ void (*hw_release)(void);
+ void (*cmd_pullup)(int enable);
+ int (*get_wp)(void);
+ unsigned long (*setclock)(unsigned long hz);
+ unsigned int caps;
+ unsigned int min_clk;
+ unsigned int max_clk;
+ int read_uA;
+ int write_uA;
+ char *power_mmc;
+ char *clock_mmc;
+};
+/* end of mxs ssp sd/mmc data definitions */
+
#ifdef CONFIG_MXS_ICOLL
extern void __init avic_init_irq(void __iomem *base, int nr_irqs);
#endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 06084dbf1277..e207dcf9e754 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -208,7 +208,7 @@ static int mmc_read_ext_csd(struct mmc_card *card)
}
ext_csd_struct = ext_csd[EXT_CSD_REV];
- if (ext_csd_struct > 3) {
+ if (ext_csd_struct > 5) {
printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
"version %d\n", mmc_hostname(card->host),
ext_csd_struct);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ae501274f940..b96d6ccc2fbe 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -295,6 +295,14 @@ config MMC_STMP3XXX
If unsure, say N.
+config MMC_MXS
+ tristate "MXS MMC support"
+ depends on MMC && ARCH_MX28
+ help
+ Select Y if you would like to access MXS MMC support.
+
+ If unsure, say N.
+
config MMC_S3C
tristate "Samsung S3C SD/MMC Card Interface support"
depends on ARCH_S3C2410
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 035175610a46..fbef5ea2632b 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
obj-$(CONFIG_MMC_IMX_ESDHCI) += mx_sdhci.o
obj-$(CONFIG_MMC_STMP3XXX) += stmp3xxx_mmc.o
+obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 895a14291006..e47518f0567b 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -1,21 +1,25 @@
/*
- * Copyright (C) 2007 SigmaTel, Inc., Ioannis Kappas <ikappas@sigmatel.com>
- *
* Portions copyright (C) 2003 Russell King, PXA MMCI Driver
* Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver
*
- * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * Copyright 2008 Embedded Alley Solutions, Inc.
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ioport.h>
@@ -30,29 +34,24 @@
#include <linux/mmc/host.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
+
#include <mach/hardware.h>
-#include <mach/dma.h>
-#include <mach/regs-apbh.h>
+#include <mach/dmaengine.h>
#include <mach/regs-ssp.h>
-#include <mach/regs-clkctrl.h>
-#include <mach/stmp3xxx.h>
-#include <mach/mmc.h>
-#include <mach/platform.h>
+#include <mach/device.h>
+#include <mach/system.h>
-#define DRIVER_NAME "stmp3xxx-mmc"
-
-#define CLOCKRATE_MIN 400000
-#define CLOCKRATE_MAX 48000000
+#define DRIVER_NAME "mxs-mmc"
/*
* Card detect polling timeout
*/
-#define STMP37XX_MMC_DETECT_TIMEOUT (HZ/2)
+#define MXS_MMC_DETECT_TIMEOUT (HZ/2)
/* Max value supported for XFER_COUNT */
-#define SSP_BUFFER_SIZE (65536 - 512)
+#define SSP_BUFFER_SIZE (65536)
-struct stmp3xxx_mmc_host {
+struct mxs_mmc_host {
struct device *dev;
struct mmc_host *mmc;
@@ -63,8 +62,8 @@ struct stmp3xxx_mmc_host {
struct mmc_command *cmd;
struct mmc_data *data;
- /* Whether the card is capable of 4-bit data */
- int bus_width_4:1;
+ /* data bus width 0:1bit, 1:4bit, 2:8bit */
+ unsigned char bus_width;
/* Whether SD card is present */
unsigned present:1;
@@ -82,7 +81,7 @@ struct stmp3xxx_mmc_host {
int dmairq, errirq;
/* DMA descriptor to transfer data over SSP interface */
- struct stmp3xxx_dma_descriptor dma_desc;
+ struct mxs_dma_desc *dma_desc;
/* DMA buffer */
dma_addr_t dma_buf_phys;
@@ -92,44 +91,44 @@ struct stmp3xxx_mmc_host {
/* status on last interrupt */
u32 status;
int read_uA, write_uA;
- struct regulator *regulator;
+ struct regulator *regulator; /*! Regulator */
};
/* Return read only state of card */
-static int stmp3xxx_mmc_get_ro(struct mmc_host *mmc)
+static int mxs_mmc_get_ro(struct mmc_host *mmc)
{
- struct stmp3xxx_mmc_host *host = mmc_priv(mmc);
- struct stmp3xxxmmc_platform_data *pdata = host->dev->platform_data;
+ struct mxs_mmc_host *host = mmc_priv(mmc);
+ struct mxs_mmc_platform_data *mmc_data = host->dev->platform_data;
- if (pdata && pdata->get_wp)
- return pdata->get_wp();
+ if (mmc_data && mmc_data->get_wp)
+ return mmc_data->get_wp();
return 0;
}
/* Detect if card is plugged */
-static inline int stmp3xxx_mmc_is_plugged(struct stmp3xxx_mmc_host *host)
+static inline int mxs_mmc_is_plugged(struct mxs_mmc_host *host)
{
u32 status = __raw_readl(host->ssp_base + HW_SSP_STATUS);
return !(status & BM_SSP_STATUS_CARD_DETECT);
}
/* Card detection polling function */
-static void stmp3xxx_mmc_detect_poll(unsigned long arg)
+static void mxs_mmc_detect_poll(unsigned long arg)
{
- struct stmp3xxx_mmc_host *host = (struct stmp3xxx_mmc_host *)arg;
+ struct mxs_mmc_host *host = (struct mxs_mmc_host *)arg;
int card_status;
- card_status = stmp3xxx_mmc_is_plugged(host);
+ card_status = mxs_mmc_is_plugged(host);
if (card_status != host->present) {
host->present = card_status;
mmc_detect_change(host->mmc, 0);
}
- mod_timer(&host->timer, jiffies + STMP37XX_MMC_DETECT_TIMEOUT);
+ mod_timer(&host->timer, jiffies + MXS_MMC_DETECT_TIMEOUT);
}
-#define STMP3XXX_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \
+#define MXS_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \
BM_SSP_CTRL1_RESP_ERR_IRQ | \
BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \
BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \
@@ -141,14 +140,18 @@ static void stmp3xxx_mmc_detect_poll(unsigned long arg)
/* SSP DMA interrupt handler */
static irqreturn_t mmc_irq_handler(int irq, void *dev_id)
{
- struct stmp3xxx_mmc_host *host = dev_id;
+ struct mxs_mmc_host *host = dev_id;
u32 c1;
c1 = __raw_readl(host->ssp_base + HW_SSP_CTRL1);
- __raw_writel(c1 & STMP3XXX_MMC_IRQ_BITS,
+ __raw_writel(c1 & MXS_MMC_IRQ_BITS,
host->ssp_base + HW_SSP_CTRL1_CLR);
- if (irq == host->dmairq)
- stmp3xxx_dma_clear_interrupt(host->dmach);
+ if (irq == host->dmairq) {
+ dev_dbg(host->dev, "dma irq 0x%x and stop DMA.\n", irq);
+ mxs_dma_ack_irq(host->dmach);
+ /* STOP the dma transfer here. */
+ mxs_dma_cooked(host->dmach, NULL);
+ }
host->status =
__raw_readl(host->ssp_base + HW_SSP_STATUS);
@@ -162,7 +165,7 @@ static irqreturn_t mmc_irq_handler(int irq, void *dev_id)
* Check for MMC command errors
* Returns error code or zerro if no errors
*/
-static inline int stmp3xxx_mmc_cmd_error(u32 status)
+static inline int mxs_mmc_cmd_error(u32 status)
{
int err = 0;
@@ -179,40 +182,44 @@ static inline int stmp3xxx_mmc_cmd_error(u32 status)
}
/* Send the BC command to the device */
-static void stmp3xxx_mmc_bc(struct stmp3xxx_mmc_host *host)
+static void mxs_mmc_bc(struct mxs_mmc_host *host)
{
struct mmc_command *cmd = host->cmd;
- struct stmp3xxx_dma_descriptor *dma_desc = &host->dma_desc;
+ struct mxs_dma_desc *dma_desc = host->dma_desc;
- dma_desc->command->cmd = BM_APBH_CHn_CMD_WAIT4ENDCMD | BM_APBH_CHn_CMD_SEMAPHORE | BM_APBH_CHn_CMD_IRQONCMPLT | BF(0, APBH_CHn_CMD_XFER_COUNT) | BF(3, APBH_CHn_CMD_CMDWORDS) | BF(0, APBH_CHn_CMD_COMMAND); /* NO_DMA_XFER */
+ dma_desc->cmd.cmd.bits.command = NO_DMA_XFER;
+ dma_desc->cmd.cmd.bits.irq = 1;
+ dma_desc->cmd.cmd.bits.dec_sem = 1;
+ dma_desc->cmd.cmd.bits.wait4end = 1;
+ dma_desc->cmd.cmd.bits.pio_words = 3;
+ dma_desc->cmd.cmd.bits.bytes = 0;
- dma_desc->command->pio_words[0] = BM_SSP_CTRL0_ENABLE |
+ dma_desc->cmd.pio_words[0] = BM_SSP_CTRL0_ENABLE |
BM_SSP_CTRL0_IGNORE_CRC;
- dma_desc->command->pio_words[1] = BF(cmd->opcode, SSP_CMD0_CMD) |
+ dma_desc->cmd.pio_words[1] = BF(cmd->opcode, SSP_CMD0_CMD) |
BM_SSP_CMD0_APPEND_8CYC;
- dma_desc->command->pio_words[2] = BF(cmd->arg, SSP_CMD1_CMD_ARG);
+ dma_desc->cmd.pio_words[2] = BF(cmd->arg, SSP_CMD1_CMD_ARG);
init_completion(&host->dma_done);
- stmp3xxx_dma_reset_channel(host->dmach);
- stmp3xxx_dma_go(host->dmach, dma_desc, 1);
+ mxs_dma_reset(host->dmach);
+ mxs_dma_desc_append(host->dmach, host->dma_desc);
+ dev_dbg(host->dev, "%s start DMA.\n", __func__);
+ mxs_dma_enable(host->dmach);
wait_for_completion(&host->dma_done);
- cmd->error = stmp3xxx_mmc_cmd_error(host->status);
-
- if (stmp3xxx_dma_running(host->dmach))
- dev_dbg(host->dev, "DMA command not finished\n");
+ cmd->error = mxs_mmc_cmd_error(host->status);
if (cmd->error) {
dev_dbg(host->dev, "Command error 0x%x\n", cmd->error);
- stmp3xxx_dma_reset_channel(host->dmach);
+ mxs_dma_reset(host->dmach);
}
}
/* Send the ac command to the device */
-static void stmp3xxx_mmc_ac(struct stmp3xxx_mmc_host *host)
+static void mxs_mmc_ac(struct mxs_mmc_host *host)
{
struct mmc_command *cmd = host->cmd;
- struct stmp3xxx_dma_descriptor *dma_desc = &host->dma_desc;
+ struct mxs_dma_desc *dma_desc = host->dma_desc;
u32 ignore_crc, resp, long_resp;
u32 ssp_ctrl0;
u32 ssp_cmd0;
@@ -225,24 +232,26 @@ static void stmp3xxx_mmc_ac(struct stmp3xxx_mmc_host *host)
long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ?
BM_SSP_CTRL0_LONG_RESP : 0;
- dma_desc->command->cmd =
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_SEMAPHORE |
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(0, APBH_CHn_CMD_XFER_COUNT) |
- BF(3, APBH_CHn_CMD_CMDWORDS) | BF(0, APBH_CHn_CMD_COMMAND);
+ dma_desc->cmd.cmd.bits.command = NO_DMA_XFER;
+ dma_desc->cmd.cmd.bits.irq = 1;
+ dma_desc->cmd.cmd.bits.dec_sem = 1;
+ dma_desc->cmd.cmd.bits.wait4end = 1;
+ dma_desc->cmd.cmd.bits.pio_words = 3;
+ dma_desc->cmd.cmd.bits.bytes = 0;
ssp_ctrl0 = BM_SSP_CTRL0_ENABLE | ignore_crc | long_resp | resp;
ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD);
ssp_cmd1 = BF(cmd->arg, SSP_CMD1_CMD_ARG);
- dma_desc->command->pio_words[0] = ssp_ctrl0;
- dma_desc->command->pio_words[1] = ssp_cmd0;
- dma_desc->command->pio_words[2] = ssp_cmd1;
+ dma_desc->cmd.pio_words[0] = ssp_ctrl0;
+ dma_desc->cmd.pio_words[1] = ssp_cmd0;
+ dma_desc->cmd.pio_words[2] = ssp_cmd1;
- stmp3xxx_dma_reset_channel(host->dmach);
+ mxs_dma_reset(host->dmach);
init_completion(&host->dma_done);
- stmp3xxx_dma_go(host->dmach, dma_desc, 1);
+ mxs_dma_desc_append(host->dmach, host->dma_desc);
+ dev_dbg(host->dev, "%s start DMA.\n", __func__);
+ mxs_dma_enable(host->dmach);
wait_for_completion(&host->dma_done);
switch (mmc_resp_type(cmd)) {
@@ -274,19 +283,16 @@ static void stmp3xxx_mmc_ac(struct stmp3xxx_mmc_host *host)
break;
}
- cmd->error = stmp3xxx_mmc_cmd_error(host->status);
-
- if (stmp3xxx_dma_running(host->dmach))
- dev_dbg(host->dev, "DMA command not finished\n");
+ cmd->error = mxs_mmc_cmd_error(host->status);
if (cmd->error) {
dev_dbg(host->dev, "Command error 0x%x\n", cmd->error);
- stmp3xxx_dma_reset_channel(host->dmach);
+ mxs_dma_reset(host->dmach);
}
}
/* Copy data between sg list and dma buffer */
-static unsigned int stmp3xxx_sg_dma_copy(struct stmp3xxx_mmc_host *host,
+static unsigned int mxs_sg_dma_copy(struct mxs_mmc_host *host,
unsigned int size, int to_dma)
{
struct mmc_data *data = host->cmd->data;
@@ -327,7 +333,7 @@ static unsigned int stmp3xxx_sg_dma_copy(struct stmp3xxx_mmc_host *host,
}
/* Convert ns to tick count according to the current sclk speed */
-static unsigned short stmp3xxx_ns_to_ssp_ticks(unsigned clock_rate, unsigned ns)
+static unsigned short mxs_ns_to_ssp_ticks(unsigned clock_rate, unsigned ns)
{
const unsigned int ssp_timeout_mul = 4096;
/*
@@ -345,6 +351,8 @@ static unsigned short stmp3xxx_ns_to_ssp_ticks(unsigned clock_rate, unsigned ns)
static void __init_reg(struct device *dev, struct regulator **pp_reg)
{
+#if 0
+ /* Up to now, there is not pwr ctrl. Just keep it for future usage. */
struct regulator *reg = *pp_reg;
if (!reg) {
@@ -355,16 +363,18 @@ static void __init_reg(struct device *dev, struct regulator **pp_reg)
reg = NULL;
*pp_reg = reg;
}
+#endif
}
/* Send adtc command to the card */
-static void stmp3xxx_mmc_adtc(struct stmp3xxx_mmc_host *host)
+static void mxs_mmc_adtc(struct mxs_mmc_host *host)
{
struct mmc_command *cmd = host->cmd;
- struct stmp3xxx_dma_descriptor *dma_desc = &host->dma_desc;
+ struct mxs_dma_desc *dma_desc = host->dma_desc;
int ignore_crc, resp, long_resp;
int is_reading = 0;
unsigned int copy_size;
+ unsigned int ssp_ver_major;
u32 ssp_ctrl0;
u32 ssp_cmd0;
@@ -388,7 +398,7 @@ static void stmp3xxx_mmc_adtc(struct stmp3xxx_mmc_host *host)
if (cmd->data->flags & MMC_DATA_WRITE) {
dev_dbg(host->dev, "Data Write\n");
- copy_size = stmp3xxx_sg_dma_copy(host, data_size, 1);
+ copy_size = mxs_sg_dma_copy(host, data_size, 1);
BUG_ON(copy_size < data_size);
is_reading = 0;
if (!host->regulator)
@@ -415,61 +425,87 @@ static void stmp3xxx_mmc_adtc(struct stmp3xxx_mmc_host *host)
BUG_ON(cmd->data->flags & MMC_DATA_STREAM);
BUG_ON((data_size % 8) > 0);
- dma_desc->command->cmd =
- BM_APBH_CHn_CMD_WAIT4ENDCMD |
- BM_APBH_CHn_CMD_SEMAPHORE |
- BM_APBH_CHn_CMD_IRQONCMPLT |
- BF(data_size, APBH_CHn_CMD_XFER_COUNT) |
- BF(3, APBH_CHn_CMD_CMDWORDS);
-
/* when is_reading is set, DMA controller performs WRITE operation. */
- dma_desc->command->cmd |=
- BF(is_reading ? BV_APBH_CHn_CMD_COMMAND__DMA_WRITE :
- BV_APBH_CHn_CMD_COMMAND__DMA_READ,
- APBH_CHn_CMD_COMMAND);
- ssp_ctrl0 =
- (ignore_crc ? BM_SSP_CTRL0_IGNORE_CRC : 0) | (resp ?
- BM_SSP_CTRL0_GET_RESP
- : 0) | (long_resp ?
- BM_SSP_CTRL0_LONG_RESP
- : 0) |
- (is_reading ? BM_SSP_CTRL0_READ : 0) | BM_SSP_CTRL0_DATA_XFER |
- BM_SSP_CTRL0_WAIT_FOR_IRQ | BM_SSP_CTRL0_ENABLE | BF(data_size,
- SSP_CTRL0_XFER_COUNT)
- | BF(host->bus_width_4 ? BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT :
- BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT,
- SSP_CTRL0_BUS_WIDTH);
+ dma_desc->cmd.cmd.bits.command = is_reading ? DMA_WRITE : DMA_READ;
+ dma_desc->cmd.cmd.bits.irq = 1;
+ dma_desc->cmd.cmd.bits.dec_sem = 1;
+ dma_desc->cmd.cmd.bits.wait4end = 1;
+ dma_desc->cmd.cmd.bits.pio_words = 3;
+ dma_desc->cmd.cmd.bits.bytes = data_size;
+
+ ssp_ver_major = __raw_readl(host->ssp_base + HW_SSP_VERSION) >> 24;
+ dev_dbg(host->dev, "ssp ver major is 0x%x\n", ssp_ver_major);
+ if (ssp_ver_major > 3) {
+ __raw_writel(data_size, host->ssp_base + HW_SSP_XFER_SIZE);
+ ssp_ctrl0 = (ignore_crc ? BM_SSP_CTRL0_IGNORE_CRC : 0) |
+ (resp ? BM_SSP_CTRL0_GET_RESP : 0) |
+ (long_resp ? BM_SSP_CTRL0_LONG_RESP : 0) |
+ (is_reading ? BM_SSP_CTRL0_READ : 0) |
+ BM_SSP_CTRL0_DATA_XFER | BM_SSP_CTRL0_WAIT_FOR_IRQ |
+ BM_SSP_CTRL0_ENABLE;
+ if (host->bus_width == 2)
+ ssp_ctrl0 |= BF(BV_SSP_CTRL0_BUS_WIDTH__EIGHT_BIT,
+ SSP_CTRL0_BUS_WIDTH);
+ else if (host->bus_width == 1)
+ ssp_ctrl0 |= BF(BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT,
+ SSP_CTRL0_BUS_WIDTH);
+ else
+ ssp_ctrl0 |= BF(BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT,
+ SSP_CTRL0_BUS_WIDTH);
+ } else
+ ssp_ctrl0 = (ignore_crc ? BM_SSP_CTRL0_IGNORE_CRC : 0) |
+ (resp ? BM_SSP_CTRL0_GET_RESP : 0) |
+ (long_resp ? BM_SSP_CTRL0_LONG_RESP : 0) |
+ (is_reading ? BM_SSP_CTRL0_READ : 0) |
+ BM_SSP_CTRL0_DATA_XFER | BM_SSP_CTRL0_WAIT_FOR_IRQ |
+ BM_SSP_CTRL0_ENABLE |
+ BF(data_size, SSP_XFER_SIZE_XFER_COUNT) |
+ BF(host->bus_width ?
+ BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT :
+ BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT,
+ SSP_CTRL0_BUS_WIDTH);
/*
* We need to set the hardware register to the logarithm to base 2 of
* the block size.
*/
log2_block_size = ilog2(cmd->data->blksz);
-
- ssp_cmd0 =
- BF(log2_block_size, SSP_CMD0_BLOCK_SIZE) |
- BF(cmd->opcode, SSP_CMD0_CMD) |
- BF(cmd->data->blocks - 1, SSP_CMD0_BLOCK_COUNT);
+ dev_dbg(host->dev, "%s blksz is 0x%x.\n", __func__, log2_block_size);
+
+ if (ssp_ver_major > 3) {
+ /* Configure the BLOCK SIZE and BLOCK COUNT */
+ val = BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) |
+ BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT);
+ __raw_writel(val, host->ssp_base + HW_SSP_BLOCK_SIZE);
+ /* Configure the CMD0 */
+ ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD);
+ } else
+ ssp_cmd0 =
+ BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) |
+ BF(cmd->opcode, SSP_CMD0_CMD) |
+ BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT);
if (cmd->opcode == 12)
ssp_cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
ssp_cmd1 = BF(cmd->arg, SSP_CMD1_CMD_ARG);
- dma_desc->command->pio_words[0] = ssp_ctrl0;
- dma_desc->command->pio_words[1] = ssp_cmd0;
- dma_desc->command->pio_words[2] = ssp_cmd1;
+ dma_desc->cmd.pio_words[0] = ssp_ctrl0;
+ dma_desc->cmd.pio_words[1] = ssp_cmd0;
+ dma_desc->cmd.pio_words[2] = ssp_cmd1;
/* Set the timeout count */
- timeout = stmp3xxx_ns_to_ssp_ticks(host->clkrt, cmd->data->timeout_ns);
+ timeout = mxs_ns_to_ssp_ticks(host->clkrt, cmd->data->timeout_ns);
val = __raw_readl(host->ssp_base + HW_SSP_TIMING);
val &= ~(BM_SSP_TIMING_TIMEOUT);
val |= BF(timeout, SSP_TIMING_TIMEOUT);
__raw_writel(val, host->ssp_base + HW_SSP_TIMING);
init_completion(&host->dma_done);
- stmp3xxx_dma_reset_channel(host->dmach);
- stmp3xxx_dma_go(host->dmach, dma_desc, 1);
+ mxs_dma_reset(host->dmach);
+ mxs_dma_desc_append(host->dmach, host->dma_desc);
+ dev_dbg(host->dev, "%s start DMA.\n", __func__);
+ mxs_dma_enable(host->dmach);
wait_for_completion(&host->dma_done);
if (host->regulator)
regulator_set_current_limit(host->regulator, 0, 0);
@@ -499,19 +535,16 @@ static void stmp3xxx_mmc_adtc(struct stmp3xxx_mmc_host *host)
break;
}
- cmd->error = stmp3xxx_mmc_cmd_error(host->status);
-
- if (stmp3xxx_dma_running(host->dmach))
- dev_dbg(host->dev, "DMA command not finished\n");
+ cmd->error = mxs_mmc_cmd_error(host->status);
if (cmd->error) {
dev_dbg(host->dev, "Command error 0x%x\n", cmd->error);
- stmp3xxx_dma_reset_channel(host->dmach);
+ mxs_dma_reset(host->dmach);
} else {
- if (is_reading)
+ if (is_reading) {
cmd->data->bytes_xfered =
- stmp3xxx_sg_dma_copy(host, data_size, 0);
- else
+ mxs_sg_dma_copy(host, data_size, 0);
+ } else
cmd->data->bytes_xfered = data_size;
dev_dbg(host->dev, "Transferred %u bytes\n",
@@ -520,7 +553,7 @@ static void stmp3xxx_mmc_adtc(struct stmp3xxx_mmc_host *host)
}
/* Begin sedning a command to the card */
-static void stmp3xxx_mmc_start_cmd(struct stmp3xxx_mmc_host *host,
+static void mxs_mmc_start_cmd(struct mxs_mmc_host *host,
struct mmc_command *cmd)
{
dev_dbg(host->dev, "MMC command:\n"
@@ -532,16 +565,16 @@ static void stmp3xxx_mmc_start_cmd(struct stmp3xxx_mmc_host *host,
switch (mmc_cmd_type(cmd)) {
case MMC_CMD_BC:
- stmp3xxx_mmc_bc(host);
+ mxs_mmc_bc(host);
break;
case MMC_CMD_BCR:
- stmp3xxx_mmc_ac(host);
+ mxs_mmc_ac(host);
break;
case MMC_CMD_AC:
- stmp3xxx_mmc_ac(host);
+ mxs_mmc_ac(host);
break;
case MMC_CMD_ADTC:
- stmp3xxx_mmc_adtc(host);
+ mxs_mmc_adtc(host);
break;
default:
dev_warn(host->dev, "Unknown MMC command\n");
@@ -555,20 +588,20 @@ static void stmp3xxx_mmc_start_cmd(struct stmp3xxx_mmc_host *host,
}
/* Handle MMC request */
-static void stmp3xxx_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
- struct stmp3xxx_mmc_host *host = mmc_priv(mmc);
+ struct mxs_mmc_host *host = mmc_priv(mmc);
dev_dbg(host->dev, "MMC request\n");
host->mrq = mrq;
- stmp3xxx_mmc_start_cmd(host, mrq->cmd);
+ mxs_mmc_start_cmd(host, mrq->cmd);
if (mrq->data && mrq->data->stop) {
dev_dbg(host->dev, "Stop opcode is %u\n",
mrq->data->stop->opcode);
- stmp3xxx_mmc_start_cmd(host, mrq->data->stop);
+ mxs_mmc_start_cmd(host, mrq->data->stop);
}
host->mrq = NULL;
@@ -581,25 +614,28 @@ static void stmp3xxx_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
* SSP ports.
*/
static void
-stmp3xxx_set_sclk_speed(struct stmp3xxx_mmc_host *host, unsigned int hz)
+mxs_set_sclk_speed(struct mxs_mmc_host *host, unsigned int hz)
{
- unsigned long ssp;
+ unsigned long ssp, bus_clk = 0;
u32 div1, div2;
u32 val;
- struct stmp3xxxmmc_platform_data *pdata = host->dev->platform_data;
+ struct mxs_mmc_platform_data *mmc_data = host->dev->platform_data;
- if (get_evk_board_version() == 1) {
- /*EVK Ver1 max clock is 12M */
- if (hz > 12000000)
- hz = 12000000;
- }
+ if (mmc_data && mmc_data->setclock) {
+ /* using SSP1, no timeout, clock rate 1 */
+ __raw_writel(BF(0xFFFF, SSP_TIMING_TIMEOUT) |
+ BF(2, SSP_TIMING_CLOCK_DIVIDE) |
+ BF(0, SSP_TIMING_CLOCK_RATE),
+ host->ssp_base + HW_SSP_TIMING);
- if (pdata && pdata->setclock) {
/*
if the SSP is buggy and platform provides callback...
well, let it be.
*/
- host->clkrt = pdata->setclock(hz);
+ host->clkrt = mmc_data->setclock(hz);
+ dev_dbg(host->dev, "Setting clock rate to %d Hz"
+ "(requested %d)\n",
+ host->clkrt, hz);
return;
}
@@ -607,8 +643,6 @@ stmp3xxx_set_sclk_speed(struct stmp3xxx_mmc_host *host, unsigned int hz)
...but the RightIdea(tm) is to set divisors to match
the requested clock.
*/
- hz /= 1000;
-
ssp = clk_get_rate(host->clk);
for (div1 = 2; div1 < 254; div1 += 2) {
@@ -617,13 +651,18 @@ stmp3xxx_set_sclk_speed(struct stmp3xxx_mmc_host *host, unsigned int hz)
break;
}
if (div1 >= 254) {
- dev_err(host->dev, "Cannot set clock to %dkHz\n", hz);
+ dev_err(host->dev, "Cannot set clock to %dHz\n", hz);
return;
}
- dev_dbg(host->dev, "Setting clock rate to %ld kHz [%x+%x] "
+ if (div2 == 0)
+ bus_clk = ssp / div1;
+ else
+ bus_clk = ssp / div1 / div2;
+
+ dev_dbg(host->dev, "Setting clock rate to %ld Hz [%x+%x] "
"(requested %d), source %ldk\n",
- ssp / div1 / div2, div1, div2, hz, ssp);
+ bus_clk, div1, div2, hz, ssp);
val = __raw_readl(host->ssp_base + HW_SSP_TIMING);
val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE);
@@ -631,14 +670,14 @@ stmp3xxx_set_sclk_speed(struct stmp3xxx_mmc_host *host, unsigned int hz)
BF(div2 - 1, SSP_TIMING_CLOCK_RATE);
__raw_writel(val, host->ssp_base + HW_SSP_TIMING);
- host->clkrt = ssp / div1 / div2 * 1000;
+ host->clkrt = bus_clk;
}
/* Configure card */
-static void stmp3xxx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
- struct stmp3xxx_mmc_host *host = mmc_priv(mmc);
- struct stmp3xxxmmc_platform_data *pdata;
+ struct mxs_mmc_host *host = mmc_priv(mmc);
+ struct mxs_mmc_platform_data *mmc_data;
dev_dbg(host->dev, "MMC set ios:\n"
"Clock %u, vdd %u, bus_mode %u, chip_select %u, "
@@ -646,43 +685,46 @@ static void stmp3xxx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
ios->bus_mode, ios->chip_select, ios->power_mode,
ios->bus_width);
- pdata = host->dev->platform_data;
+ mmc_data = host->dev->platform_data;
- if (pdata->cmd_pullup) {
+ if (mmc_data->cmd_pullup) {
if (ios->bus_mode == MMC_BUSMODE_PUSHPULL)
- pdata->cmd_pullup(0);
+ mmc_data->cmd_pullup(0);
else
- pdata->cmd_pullup(1);
+ mmc_data->cmd_pullup(1);
} else
dev_warn(host->dev,
"Platform does not support CMD pin pullup control\n");
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- host->bus_width_4 = 1;
+ if (ios->bus_width == MMC_BUS_WIDTH_8)
+ host->bus_width = 2;
+ else if (ios->bus_width == MMC_BUS_WIDTH_4)
+ host->bus_width = 1;
else
- host->bus_width_4 = 0;
+ host->bus_width = 0;
+ dev_dbg(host->dev, "MMC bus_width %u\n", host->bus_width);
if (ios->clock > 0)
- stmp3xxx_set_sclk_speed(host, ios->clock);
+ mxs_set_sclk_speed(host, ios->clock);
}
-static const struct mmc_host_ops stmp3xxx_mmc_ops = {
- .request = stmp3xxx_mmc_request,
- .get_ro = stmp3xxx_mmc_get_ro,
- .set_ios = stmp3xxx_mmc_set_ios,
+static const struct mmc_host_ops mxs_mmc_ops = {
+ .request = mxs_mmc_request,
+ .get_ro = mxs_mmc_get_ro,
+ .set_ios = mxs_mmc_set_ios,
};
/*
- * STMP37XX MMC/SD driver initialization
+ * MXS MMC/SD driver initialization
*/
/* Reset ssp peripheral to default values */
-static void stmp3xxx_mmc_reset(struct stmp3xxx_mmc_host *host)
+static void mxs_mmc_reset(struct mxs_mmc_host *host)
{
u32 ssp_ctrl0;
u32 ssp_ctrl1;
- stmp3xxx_reset_block(host->ssp_base, 0);
+ mxs_reset_block(host->ssp_base, 0);
/* Configure SSP Control Register 0 */
ssp_ctrl0 =
@@ -711,13 +753,13 @@ static void stmp3xxx_mmc_reset(struct stmp3xxx_mmc_host *host)
__raw_writel(ssp_ctrl1, host->ssp_base + HW_SSP_CTRL1);
}
-static void stmp3xxx_mmc_irq_release(struct stmp3xxx_mmc_host *host)
+static void mxs_mmc_irq_release(struct mxs_mmc_host *host)
{
free_irq(host->dmairq, host);
free_irq(host->errirq, host);
}
-static int __init stmp3xxx_mmc_irq_init(struct stmp3xxx_mmc_host *host)
+static int __init mxs_mmc_irq_init(struct mxs_mmc_host *host)
{
int ret;
@@ -743,14 +785,14 @@ out0:
}
/* Allocate and initialise the DMA chains */
-static int stmp3xxx_mmc_dma_init(struct stmp3xxx_mmc_host *host, int reset)
+static int mxs_mmc_dma_init(struct mxs_mmc_host *host, int reset)
{
- int ret;
+ int ret = 0;
if (!reset) {
/* Allocate DMA channel */
- ret = stmp3xxx_dma_request(host->dmach,
- host->dev, "STMP37XX MMC/SD");
+ ret = mxs_dma_request(host->dmach,
+ host->dev, "MXS MMC/SD");
if (ret) {
dev_err(host->dev, "Unable to request DMA channel\n");
return ret;
@@ -765,25 +807,25 @@ static int stmp3xxx_mmc_dma_init(struct stmp3xxx_mmc_host *host, int reset)
goto out_mem;
}
- ret = stmp3xxx_dma_allocate_command(host->dmach,
- &host->dma_desc);
- if (ret) {
+ host->dma_desc = mxs_dma_alloc_desc();
+ if (host->dma_desc == NULL) {
dev_err(host->dev,
"Unable to allocate DMA descriptor\n");
+ ret = -ENOMEM;
goto out_cmd;
}
- host->dma_desc.command->next = (u32) host->dma_desc.handle;
- host->dma_desc.command->buf_ptr = (u32) host->dma_buf_phys;
- host->dma_desc.virtual_buf_ptr = host->dma_buf;
+ host->dma_desc->cmd.next = (u32) host->dma_desc->address;
+ host->dma_desc->cmd.address = (u32) host->dma_buf_phys;
+ host->dma_desc->buffer = host->dma_buf;
}
/* Reset DMA channel */
- stmp3xxx_dma_reset_channel(host->dmach);
+ mxs_dma_reset(host->dmach);
/* Enable DMA interrupt */
- stmp3xxx_dma_clear_interrupt(host->dmach);
- stmp3xxx_dma_enable_interrupt(host->dmach);
+ mxs_dma_ack_irq(host->dmach);
+ mxs_dma_enable_irq(host->dmach, 1);
return 0;
@@ -791,28 +833,32 @@ out_cmd:
dma_free_coherent(host->dev, SSP_BUFFER_SIZE, host->dma_buf,
host->dma_buf_phys);
out_mem:
- stmp3xxx_dma_release(host->dmach);
+ mxs_dma_release(host->dmach, host->dev);
return ret;
}
-static void stmp3xxx_mmc_dma_release(struct stmp3xxx_mmc_host *host)
+static void mxs_mmc_dma_release(struct mxs_mmc_host *host)
{
- stmp3xxx_dma_reset_channel(host->dmach);
+ mxs_dma_reset(host->dmach);
+
+ mxs_dma_enable_irq(host->dmach, 0);
+ mxs_dma_disable(host->dmach);
+ mxs_dma_get_cooked(host->dmach, NULL);
dma_free_coherent(host->dev, SSP_BUFFER_SIZE, host->dma_buf,
host->dma_buf_phys);
- stmp3xxx_dma_free_command(host->dmach, &host->dma_desc);
- stmp3xxx_dma_release(host->dmach);
+ mxs_dma_free_desc(host->dma_desc);
+ mxs_dma_release(host->dmach, host->dev);
}
/* Probe peripheral for connected cards */
-static int __init stmp3xxx_mmc_probe(struct platform_device *pdev)
+static int __init mxs_mmc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct stmp3xxxmmc_platform_data *mmc_data;
- struct stmp3xxx_mmc_host *host;
+ struct mxs_mmc_platform_data *mmc_data;
+ struct mxs_mmc_host *host;
struct mmc_host *mmc;
struct resource *r;
int err = 0;
@@ -825,7 +871,7 @@ static int __init stmp3xxx_mmc_probe(struct platform_device *pdev)
}
/* Allocate main MMC host structure */
- mmc = mmc_alloc_host(sizeof(struct stmp3xxx_mmc_host), dev);
+ mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), dev);
if (!mmc) {
dev_err(dev, "Unable to allocate MMC host\n");
err = -ENOMEM;
@@ -835,7 +881,8 @@ static int __init stmp3xxx_mmc_probe(struct platform_device *pdev)
host->read_uA = mmc_data->read_uA;
host->write_uA = mmc_data->write_uA;
- host->regulator = regulator_get(NULL, "mmc_ssp-1");
+ if (mmc_data->power_mmc != NULL)
+ host->regulator = regulator_get(NULL, mmc_data->power_mmc);
if (host->regulator && !IS_ERR(host->regulator))
regulator_set_mode(host->regulator, REGULATOR_MODE_NORMAL);
else
@@ -852,8 +899,7 @@ static int __init stmp3xxx_mmc_probe(struct platform_device *pdev)
err = -ENXIO;
goto out_res;
}
- host->ssp_base =
- r->start - STMP3XXX_REGS_PHBASE + STMP3XXX_REGS_BASE;
+ host->ssp_base = IO_ADDRESS(r->start);
/*
* 2. DMA channel
@@ -896,7 +942,7 @@ static int __init stmp3xxx_mmc_probe(struct platform_device *pdev)
host->dev = dev;
/* Set minimal clock rate */
- host->clk = clk_get(dev, "ssp");
+ host->clk = clk_get(dev, mmc_data->clock_mmc);
if (IS_ERR(host->clk)) {
err = PTR_ERR(host->clk);
dev_err(dev, "Clocks initialization failed\n");
@@ -904,39 +950,40 @@ static int __init stmp3xxx_mmc_probe(struct platform_device *pdev)
}
clk_enable(host->clk);
- stmp3xxx_set_sclk_speed(host, CLOCKRATE_MIN);
+ mxs_set_sclk_speed(host, mmc_data->min_clk);
/* Reset MMC block */
- stmp3xxx_mmc_reset(host);
+ mxs_mmc_reset(host);
/* Enable DMA */
- err = stmp3xxx_mmc_dma_init(host, 0);
+ err = mxs_mmc_dma_init(host, 0);
if (err) {
dev_err(dev, "DMA init failed\n");
goto out_dma;
}
/* Set up interrupt handlers */
- err = stmp3xxx_mmc_irq_init(host);
+ err = mxs_mmc_irq_init(host);
if (err) {
dev_err(dev, "IRQ initialization failed\n");
goto out_irq;
}
/* Get current card status for further cnanges tracking */
- host->present = stmp3xxx_mmc_is_plugged(host);
+ host->present = mxs_mmc_is_plugged(host);
/* Add a card detection polling timer */
init_timer(&host->timer);
- host->timer.function = stmp3xxx_mmc_detect_poll;
+ host->timer.function = mxs_mmc_detect_poll;
host->timer.data = (unsigned long)host;
- host->timer.expires = jiffies + STMP37XX_MMC_DETECT_TIMEOUT;
+ host->timer.expires = jiffies + MXS_MMC_DETECT_TIMEOUT;
add_timer(&host->timer);
- mmc->ops = &stmp3xxx_mmc_ops;
- mmc->f_min = CLOCKRATE_MIN;
- mmc->f_max = CLOCKRATE_MAX;
- mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->ops = &mxs_mmc_ops;
+ mmc->f_min = mmc_data->min_clk;
+ mmc->f_max = mmc_data->max_clk;
+ mmc->caps = mmc_data->caps;
+ mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
/* Maximum block count requests. */
mmc->max_blk_size = 512;
@@ -956,12 +1003,15 @@ static int __init stmp3xxx_mmc_probe(struct platform_device *pdev)
goto out_all;
}
+ dev_info(&pdev->dev, "%s: MXS SSP MMC DMAIRQ %d ERRIRQ %d \n",
+ mmc_hostname(mmc), host->dmairq, host->errirq);
+
return err;
out_all:
out_irq:
- stmp3xxx_mmc_dma_release(host);
+ mxs_mmc_dma_release(host);
out_dma:
clk_disable(host->clk);
out_clk:
@@ -973,10 +1023,10 @@ out:
return err;
}
-static int __exit stmp3xxx_mmc_remove(struct platform_device *pdev)
+static int __exit mxs_mmc_remove(struct platform_device *pdev)
{
- struct stmp3xxx_mmc_host *host;
- struct stmp3xxxmmc_platform_data *mmc_data;
+ struct mxs_mmc_host *host;
+ struct mxs_mmc_platform_data *mmc_data;
struct mmc_host *mmc;
dev_info(&pdev->dev, "Removing\n");
@@ -993,13 +1043,13 @@ static int __exit stmp3xxx_mmc_remove(struct platform_device *pdev)
clk_put(host->clk);
/* Release IRQs */
- stmp3xxx_mmc_irq_release(host);
+ mxs_mmc_irq_release(host);
/* Delete card detection timer */
del_timer(&host->timer);
/* Release DMA */
- stmp3xxx_mmc_dma_release(host);
+ mxs_mmc_dma_release(host);
if (host->regulator)
regulator_put(host->regulator);
@@ -1012,11 +1062,11 @@ static int __exit stmp3xxx_mmc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int stmp3xxx_mmc_suspend(struct platform_device *pdev,
+static int mxs_mmc_suspend(struct platform_device *pdev,
pm_message_t state)
{
- struct stmp3xxx_mmc_host *host;
- struct stmp3xxxmmc_platform_data *mmc_data;
+ struct mxs_mmc_host *host;
+ struct mxs_mmc_platform_data *mmc_data;
struct mmc_host *mmc;
int ret = 0;
@@ -1035,10 +1085,10 @@ static int stmp3xxx_mmc_suspend(struct platform_device *pdev,
return ret;
}
-static int stmp3xxx_mmc_resume(struct platform_device *pdev)
+static int mxs_mmc_resume(struct platform_device *pdev)
{
- struct stmp3xxx_mmc_host *host;
- struct stmp3xxxmmc_platform_data *mmc_data;
+ struct mxs_mmc_host *host;
+ struct mxs_mmc_platform_data *mmc_data;
struct mmc_host *mmc;
dev_dbg(&pdev->dev, "Resuming\n");
@@ -1051,45 +1101,47 @@ static int stmp3xxx_mmc_resume(struct platform_device *pdev)
if (mmc_data->hw_init)
mmc_data->hw_init();
- stmp3xxx_mmc_reset(host);
- stmp3xxx_mmc_dma_init(host, 1);
+ mxs_mmc_reset(host);
+ mxs_mmc_dma_init(host, 1);
return mmc_resume_host(mmc);
}
#else
-#define stmp3xxx_mmc_suspend NULL
-#define stmp3xxx_mmc_resume NULL
+#define mxs_mmc_suspend NULL
+#define mxs_mmc_resume NULL
#endif /* CONFIG_PM */
-static struct platform_driver stmp3xxx_mmc_driver = {
- .probe = stmp3xxx_mmc_probe,
- .remove = __exit_p(stmp3xxx_mmc_remove),
- .suspend = stmp3xxx_mmc_suspend,
- .resume = stmp3xxx_mmc_resume,
+static struct platform_driver mxs_mmc_driver = {
+ .probe = mxs_mmc_probe,
+ .remove = __exit_p(mxs_mmc_remove),
+ .suspend = mxs_mmc_suspend,
+ .resume = mxs_mmc_resume,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
-static int __init stmp3xxx_mmc_init(void)
+static int __init mxs_mmc_init(void)
{
int ret = 0;
- ret = platform_driver_register(&stmp3xxx_mmc_driver);
+ printk(KERN_INFO DRIVER_NAME
+ ": MXS SSP Controller MMC Interface driver\n");
+ ret = platform_driver_register(&mxs_mmc_driver);
if (ret < 0)
return ret;
return ret;
}
-static void __exit stmp3xxx_mmc_exit(void)
+static void __exit mxs_mmc_exit(void)
{
- platform_driver_unregister(&stmp3xxx_mmc_driver);
+ platform_driver_unregister(&mxs_mmc_driver);
}
-module_init(stmp3xxx_mmc_init);
-module_exit(stmp3xxx_mmc_exit);
+module_init(mxs_mmc_init);
+module_exit(mxs_mmc_exit);
-MODULE_DESCRIPTION("STMP37xx/378x MMC peripheral");
+MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral");
MODULE_LICENSE("GPL");