diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/mmc.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mmc/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/host/mxs-mmc.c | 518 |
4 files changed, 295 insertions, 234 deletions
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"); |