summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/mxs-mmc.c
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2010-01-26 13:06:44 +0800
committerFrank Li <Frank.Li@freescale.com>2010-03-16 12:23:06 +0800
commit3a4d7c41486d30ce5cdda83b24e96316e1cbd965 (patch)
tree11c43b763b7a11b796519343ccf242e1baf50b75 /drivers/mmc/host/mxs-mmc.c
parent585b60556b28edbedff58f6781572018563c0da4 (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>
Diffstat (limited to 'drivers/mmc/host/mxs-mmc.c')
-rw-r--r--drivers/mmc/host/mxs-mmc.c518
1 files changed, 285 insertions, 233 deletions
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");