From: "Shimoda, Yoshihiro" <yoshihiro.shimoda.uh@renesas.com>
To: cjb@laptop.org
Cc: linux-mmc@vger.kernel.org, SH-Linux <linux-sh@vger.kernel.org>,
Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Subject: [PATCH] mmc: sh_mmcif: add SET_BLOCK_COUNT support
Date: Thu, 13 Jun 2013 17:03:39 +0900 [thread overview]
Message-ID: <51B97CDB.7010207@renesas.com> (raw)
This patch adds SET_BLOCK_COUNT(CMD23) support to sh_mmcif driver.
If we add MMC_CAP_CMD23 to ".caps" of sh_mmcif_plat_data, the mmc
core driver will use CMD23. Then, the sh_mmcif driver can use
Reliable Write feature.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
This patch is based on the latest mmc-next branch of mmc.git.
drivers/mmc/host/sh_mmcif.c | 83 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 81 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 8ef5efa..14d4c81 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -244,6 +244,7 @@ struct sh_mmcif_host {
bool power;
bool card_present;
struct mutex thread_lock;
+ struct completion sbc_complete;
/* DMA support */
struct dma_chan *chan_rx;
@@ -802,7 +803,11 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
tmp |= CMD_SET_DWEN;
/* CMLTE/CMD12EN */
if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) {
- tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
+ /* If SBC, we don't use CMD12(STOP) */
+ if (mrq->sbc)
+ tmp |= CMD_SET_CMLTE;
+ else
+ tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET,
data->blocks << 16);
}
@@ -903,6 +908,43 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
host->wait_for = MMCIF_WAIT_FOR_STOP;
}
+static bool sh_mmcif_send_sbc(struct sh_mmcif_host *host,
+ struct mmc_request *mrq)
+{
+ struct mmc_request req_orig = *mrq;
+ long time;
+
+ /* Switch the commands around */
+ mrq->cmd = mrq->sbc;
+ mrq->sbc = NULL;
+ mrq->data = NULL;
+ mrq->stop = NULL;
+
+ /* Send SBC Cmd */
+ sh_mmcif_start_cmd(host, mrq);
+
+ /* Normal completion time is less than 1us */
+ time = wait_for_completion_interruptible_timeout(&host->sbc_complete,
+ host->timeout);
+
+ /* Restore */
+ mrq->cmd = req_orig.cmd;
+ mrq->sbc = req_orig.sbc;
+ mrq->data = req_orig.data;
+ mrq->stop = req_orig.stop;
+
+ if (mrq->sbc->error || host->sd_error || time <= 0) {
+ dev_dbg(&host->pd->dev, "%s(): failed!\n", __func__);
+ host->state = STATE_IDLE;
+ if (!time)
+ mrq->sbc->error = -ETIMEDOUT;
+ mmc_request_done(host->mmc, mrq);
+ return true;
+ }
+
+ return false;
+}
+
static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sh_mmcif_host *host = mmc_priv(mmc);
@@ -938,6 +980,11 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
+ if (mrq->sbc) {
+ if (sh_mmcif_send_sbc(host, mrq))
+ return;
+ }
+
sh_mmcif_start_cmd(host, mrq);
}
@@ -1074,6 +1121,9 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
sh_mmcif_get_response(host, cmd);
+ if (cmd->opcode == MMC_SET_BLOCK_COUNT)
+ complete(&host->sbc_complete);
+
if (!data)
return false;
@@ -1212,13 +1262,35 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+ if (mrq->sbc && (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) &&
+ (host->wait_for != MMCIF_WAIT_FOR_WRITE_END)) {
+ /* Wait for end of data phase */
+ host->wait_for = MMCIF_WAIT_FOR_WRITE_END;
+ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ mutex_unlock(&host->thread_lock);
+ return IRQ_HANDLED;
+ }
+
+ if (mrq->sbc && (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) &&
+ (host->wait_for != MMCIF_WAIT_FOR_READ_END)) {
+ /* Wait for end of data phase */
+ host->wait_for = MMCIF_WAIT_FOR_READ_END;
+ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ mutex_unlock(&host->thread_lock);
+ return IRQ_HANDLED;
+ }
+
if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
struct mmc_data *data = mrq->data;
if (!mrq->cmd->error && data && !data->error)
data->bytes_xfered =
data->blocks * data->blksz;
- if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) {
+ /* If SBC, we don't use CMD12(STOP) */
+ if (mrq->stop && !mrq->cmd->error && (!data || !data->error) &&
+ !mrq->sbc) {
sh_mmcif_stop_cmd(host, mrq);
if (!mrq->stop->error) {
schedule_delayed_work(&host->timeout_work, host->timeout);
@@ -1228,6 +1300,12 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
}
}
+ if ((mrq->cmd->opcode == MMC_SET_BLOCK_COUNT) && !mrq->cmd->error) {
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ mutex_unlock(&host->thread_lock);
+ return IRQ_HANDLED;
+ }
+
host->wait_for = MMCIF_WAIT_FOR_REQUEST;
host->state = STATE_IDLE;
host->mrq = NULL;
@@ -1379,6 +1457,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
host->pd = pdev;
spin_lock_init(&host->lock);
+ init_completion(&host->sbc_complete);
mmc->ops = &sh_mmcif_ops;
sh_mmcif_init_ocr(host);
--
1.7.1
WARNING: multiple messages have this Message-ID (diff)
From: "Shimoda, Yoshihiro" <yoshihiro.shimoda.uh@renesas.com>
To: cjb@laptop.org
Cc: linux-mmc@vger.kernel.org, SH-Linux <linux-sh@vger.kernel.org>,
Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Subject: [PATCH] mmc: sh_mmcif: add SET_BLOCK_COUNT support
Date: Thu, 13 Jun 2013 08:03:39 +0000 [thread overview]
Message-ID: <51B97CDB.7010207@renesas.com> (raw)
This patch adds SET_BLOCK_COUNT(CMD23) support to sh_mmcif driver.
If we add MMC_CAP_CMD23 to ".caps" of sh_mmcif_plat_data, the mmc
core driver will use CMD23. Then, the sh_mmcif driver can use
Reliable Write feature.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
This patch is based on the latest mmc-next branch of mmc.git.
drivers/mmc/host/sh_mmcif.c | 83 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 81 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 8ef5efa..14d4c81 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -244,6 +244,7 @@ struct sh_mmcif_host {
bool power;
bool card_present;
struct mutex thread_lock;
+ struct completion sbc_complete;
/* DMA support */
struct dma_chan *chan_rx;
@@ -802,7 +803,11 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
tmp |= CMD_SET_DWEN;
/* CMLTE/CMD12EN */
if (opc = MMC_READ_MULTIPLE_BLOCK || opc = MMC_WRITE_MULTIPLE_BLOCK) {
- tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
+ /* If SBC, we don't use CMD12(STOP) */
+ if (mrq->sbc)
+ tmp |= CMD_SET_CMLTE;
+ else
+ tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET,
data->blocks << 16);
}
@@ -903,6 +908,43 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
host->wait_for = MMCIF_WAIT_FOR_STOP;
}
+static bool sh_mmcif_send_sbc(struct sh_mmcif_host *host,
+ struct mmc_request *mrq)
+{
+ struct mmc_request req_orig = *mrq;
+ long time;
+
+ /* Switch the commands around */
+ mrq->cmd = mrq->sbc;
+ mrq->sbc = NULL;
+ mrq->data = NULL;
+ mrq->stop = NULL;
+
+ /* Send SBC Cmd */
+ sh_mmcif_start_cmd(host, mrq);
+
+ /* Normal completion time is less than 1us */
+ time = wait_for_completion_interruptible_timeout(&host->sbc_complete,
+ host->timeout);
+
+ /* Restore */
+ mrq->cmd = req_orig.cmd;
+ mrq->sbc = req_orig.sbc;
+ mrq->data = req_orig.data;
+ mrq->stop = req_orig.stop;
+
+ if (mrq->sbc->error || host->sd_error || time <= 0) {
+ dev_dbg(&host->pd->dev, "%s(): failed!\n", __func__);
+ host->state = STATE_IDLE;
+ if (!time)
+ mrq->sbc->error = -ETIMEDOUT;
+ mmc_request_done(host->mmc, mrq);
+ return true;
+ }
+
+ return false;
+}
+
static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sh_mmcif_host *host = mmc_priv(mmc);
@@ -938,6 +980,11 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
+ if (mrq->sbc) {
+ if (sh_mmcif_send_sbc(host, mrq))
+ return;
+ }
+
sh_mmcif_start_cmd(host, mrq);
}
@@ -1074,6 +1121,9 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
sh_mmcif_get_response(host, cmd);
+ if (cmd->opcode = MMC_SET_BLOCK_COUNT)
+ complete(&host->sbc_complete);
+
if (!data)
return false;
@@ -1212,13 +1262,35 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+ if (mrq->sbc && (mrq->cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK) &&
+ (host->wait_for != MMCIF_WAIT_FOR_WRITE_END)) {
+ /* Wait for end of data phase */
+ host->wait_for = MMCIF_WAIT_FOR_WRITE_END;
+ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ mutex_unlock(&host->thread_lock);
+ return IRQ_HANDLED;
+ }
+
+ if (mrq->sbc && (mrq->cmd->opcode = MMC_READ_MULTIPLE_BLOCK) &&
+ (host->wait_for != MMCIF_WAIT_FOR_READ_END)) {
+ /* Wait for end of data phase */
+ host->wait_for = MMCIF_WAIT_FOR_READ_END;
+ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ mutex_unlock(&host->thread_lock);
+ return IRQ_HANDLED;
+ }
+
if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
struct mmc_data *data = mrq->data;
if (!mrq->cmd->error && data && !data->error)
data->bytes_xfered data->blocks * data->blksz;
- if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) {
+ /* If SBC, we don't use CMD12(STOP) */
+ if (mrq->stop && !mrq->cmd->error && (!data || !data->error) &&
+ !mrq->sbc) {
sh_mmcif_stop_cmd(host, mrq);
if (!mrq->stop->error) {
schedule_delayed_work(&host->timeout_work, host->timeout);
@@ -1228,6 +1300,12 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
}
}
+ if ((mrq->cmd->opcode = MMC_SET_BLOCK_COUNT) && !mrq->cmd->error) {
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ mutex_unlock(&host->thread_lock);
+ return IRQ_HANDLED;
+ }
+
host->wait_for = MMCIF_WAIT_FOR_REQUEST;
host->state = STATE_IDLE;
host->mrq = NULL;
@@ -1379,6 +1457,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
host->pd = pdev;
spin_lock_init(&host->lock);
+ init_completion(&host->sbc_complete);
mmc->ops = &sh_mmcif_ops;
sh_mmcif_init_ocr(host);
--
1.7.1
next reply other threads:[~2013-06-13 8:03 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-06-13 8:03 Shimoda, Yoshihiro [this message]
2013-06-13 8:03 ` [PATCH] mmc: sh_mmcif: add SET_BLOCK_COUNT support Shimoda, Yoshihiro
2013-06-13 8:33 ` Guennadi Liakhovetski
2013-06-13 8:33 ` Guennadi Liakhovetski
2013-06-13 9:01 ` Shimoda, Yoshihiro
2013-06-13 9:01 ` Shimoda, Yoshihiro
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51B97CDB.7010207@renesas.com \
--to=yoshihiro.shimoda.uh@renesas.com \
--cc=cjb@laptop.org \
--cc=g.liakhovetski@gmx.de \
--cc=linux-mmc@vger.kernel.org \
--cc=linux-sh@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.