|
@@ -16,6 +16,8 @@
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+#include <linux/clk.h>
|
|
|
|
+#include <linux/completion.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/mmc/host.h>
|
|
#include <linux/mmc/host.h>
|
|
#include <linux/mmc/card.h>
|
|
#include <linux/mmc/card.h>
|
|
@@ -24,7 +26,6 @@
|
|
#include <linux/mmc/sdio.h>
|
|
#include <linux/mmc/sdio.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/platform_device.h>
|
|
-#include <linux/clk.h>
|
|
|
|
#include <linux/mmc/sh_mmcif.h>
|
|
#include <linux/mmc/sh_mmcif.h>
|
|
|
|
|
|
#define DRIVER_NAME "sh_mmcif"
|
|
#define DRIVER_NAME "sh_mmcif"
|
|
@@ -158,11 +159,10 @@ struct sh_mmcif_host {
|
|
struct clk *hclk;
|
|
struct clk *hclk;
|
|
unsigned int clk;
|
|
unsigned int clk;
|
|
int bus_width;
|
|
int bus_width;
|
|
- u16 wait_int;
|
|
|
|
- u16 sd_error;
|
|
|
|
|
|
+ bool sd_error;
|
|
long timeout;
|
|
long timeout;
|
|
void __iomem *addr;
|
|
void __iomem *addr;
|
|
- wait_queue_head_t intr_wait;
|
|
|
|
|
|
+ struct completion intr_wait;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -216,8 +216,7 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
|
|
u32 state1, state2;
|
|
u32 state1, state2;
|
|
int ret, timeout = 10000000;
|
|
int ret, timeout = 10000000;
|
|
|
|
|
|
- host->sd_error = 0;
|
|
|
|
- host->wait_int = 0;
|
|
|
|
|
|
+ host->sd_error = false;
|
|
|
|
|
|
state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1);
|
|
state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1);
|
|
state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2);
|
|
state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2);
|
|
@@ -264,17 +263,13 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host,
|
|
long time;
|
|
long time;
|
|
u32 blocksize, i, *p = sg_virt(data->sg);
|
|
u32 blocksize, i, *p = sg_virt(data->sg);
|
|
|
|
|
|
- host->wait_int = 0;
|
|
|
|
-
|
|
|
|
/* buf read enable */
|
|
/* buf read enable */
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
|
|
- time = wait_event_interruptible_timeout(host->intr_wait,
|
|
|
|
- host->wait_int == 1 ||
|
|
|
|
- host->sd_error == 1, host->timeout);
|
|
|
|
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
|
|
|
|
|
|
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
|
|
|
|
+ host->timeout);
|
|
|
|
+ if (time <= 0 || host->sd_error)
|
|
return sh_mmcif_error_manage(host);
|
|
return sh_mmcif_error_manage(host);
|
|
|
|
|
|
- host->wait_int = 0;
|
|
|
|
blocksize = (BLOCK_SIZE_MASK &
|
|
blocksize = (BLOCK_SIZE_MASK &
|
|
sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
|
|
sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
|
|
for (i = 0; i < blocksize / 4; i++)
|
|
for (i = 0; i < blocksize / 4; i++)
|
|
@@ -282,13 +277,11 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host,
|
|
|
|
|
|
/* buffer read end */
|
|
/* buffer read end */
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
|
|
- time = wait_event_interruptible_timeout(host->intr_wait,
|
|
|
|
- host->wait_int == 1 ||
|
|
|
|
- host->sd_error == 1, host->timeout);
|
|
|
|
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
|
|
|
|
|
|
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
|
|
|
|
+ host->timeout);
|
|
|
|
+ if (time <= 0 || host->sd_error)
|
|
return sh_mmcif_error_manage(host);
|
|
return sh_mmcif_error_manage(host);
|
|
|
|
|
|
- host->wait_int = 0;
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -303,19 +296,15 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
|
|
MMCIF_CE_BLOCK_SET);
|
|
MMCIF_CE_BLOCK_SET);
|
|
for (j = 0; j < data->sg_len; j++) {
|
|
for (j = 0; j < data->sg_len; j++) {
|
|
p = sg_virt(data->sg);
|
|
p = sg_virt(data->sg);
|
|
- host->wait_int = 0;
|
|
|
|
for (sec = 0; sec < data->sg->length / blocksize; sec++) {
|
|
for (sec = 0; sec < data->sg->length / blocksize; sec++) {
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
|
|
/* buf read enable */
|
|
/* buf read enable */
|
|
- time = wait_event_interruptible_timeout(host->intr_wait,
|
|
|
|
- host->wait_int == 1 ||
|
|
|
|
- host->sd_error == 1, host->timeout);
|
|
|
|
|
|
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
|
|
|
|
+ host->timeout);
|
|
|
|
|
|
- if (host->wait_int != 1 &&
|
|
|
|
- (time == 0 || host->sd_error != 0))
|
|
|
|
|
|
+ if (time <= 0 || host->sd_error)
|
|
return sh_mmcif_error_manage(host);
|
|
return sh_mmcif_error_manage(host);
|
|
|
|
|
|
- host->wait_int = 0;
|
|
|
|
for (i = 0; i < blocksize / 4; i++)
|
|
for (i = 0; i < blocksize / 4; i++)
|
|
*p++ = sh_mmcif_readl(host->addr,
|
|
*p++ = sh_mmcif_readl(host->addr,
|
|
MMCIF_CE_DATA);
|
|
MMCIF_CE_DATA);
|
|
@@ -333,17 +322,14 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host,
|
|
long time;
|
|
long time;
|
|
u32 blocksize, i, *p = sg_virt(data->sg);
|
|
u32 blocksize, i, *p = sg_virt(data->sg);
|
|
|
|
|
|
- host->wait_int = 0;
|
|
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
|
|
|
|
|
|
/* buf write enable */
|
|
/* buf write enable */
|
|
- time = wait_event_interruptible_timeout(host->intr_wait,
|
|
|
|
- host->wait_int == 1 ||
|
|
|
|
- host->sd_error == 1, host->timeout);
|
|
|
|
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
|
|
|
|
|
|
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
|
|
|
|
+ host->timeout);
|
|
|
|
+ if (time <= 0 || host->sd_error)
|
|
return sh_mmcif_error_manage(host);
|
|
return sh_mmcif_error_manage(host);
|
|
|
|
|
|
- host->wait_int = 0;
|
|
|
|
blocksize = (BLOCK_SIZE_MASK &
|
|
blocksize = (BLOCK_SIZE_MASK &
|
|
sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
|
|
sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
|
|
for (i = 0; i < blocksize / 4; i++)
|
|
for (i = 0; i < blocksize / 4; i++)
|
|
@@ -352,13 +338,11 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host,
|
|
/* buffer write end */
|
|
/* buffer write end */
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
|
|
|
|
|
|
- time = wait_event_interruptible_timeout(host->intr_wait,
|
|
|
|
- host->wait_int == 1 ||
|
|
|
|
- host->sd_error == 1, host->timeout);
|
|
|
|
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
|
|
|
|
|
|
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
|
|
|
|
+ host->timeout);
|
|
|
|
+ if (time <= 0 || host->sd_error)
|
|
return sh_mmcif_error_manage(host);
|
|
return sh_mmcif_error_manage(host);
|
|
|
|
|
|
- host->wait_int = 0;
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -374,19 +358,15 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
|
|
|
|
|
|
for (j = 0; j < data->sg_len; j++) {
|
|
for (j = 0; j < data->sg_len; j++) {
|
|
p = sg_virt(data->sg);
|
|
p = sg_virt(data->sg);
|
|
- host->wait_int = 0;
|
|
|
|
for (sec = 0; sec < data->sg->length / blocksize; sec++) {
|
|
for (sec = 0; sec < data->sg->length / blocksize; sec++) {
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
|
|
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
|
|
/* buf write enable*/
|
|
/* buf write enable*/
|
|
- time = wait_event_interruptible_timeout(host->intr_wait,
|
|
|
|
- host->wait_int == 1 ||
|
|
|
|
- host->sd_error == 1, host->timeout);
|
|
|
|
|
|
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
|
|
|
|
+ host->timeout);
|
|
|
|
|
|
- if (host->wait_int != 1 &&
|
|
|
|
- (time == 0 || host->sd_error != 0))
|
|
|
|
|
|
+ if (time <= 0 || host->sd_error)
|
|
return sh_mmcif_error_manage(host);
|
|
return sh_mmcif_error_manage(host);
|
|
|
|
|
|
- host->wait_int = 0;
|
|
|
|
for (i = 0; i < blocksize / 4; i++)
|
|
for (i = 0; i < blocksize / 4; i++)
|
|
sh_mmcif_writel(host->addr,
|
|
sh_mmcif_writel(host->addr,
|
|
MMCIF_CE_DATA, *p++);
|
|
MMCIF_CE_DATA, *p++);
|
|
@@ -556,13 +536,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
|
|
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
|
|
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
|
|
/* set arg */
|
|
/* set arg */
|
|
sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
|
|
sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
|
|
- host->wait_int = 0;
|
|
|
|
/* set cmd */
|
|
/* set cmd */
|
|
sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
|
|
sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
|
|
|
|
|
|
- time = wait_event_interruptible_timeout(host->intr_wait,
|
|
|
|
- host->wait_int == 1 || host->sd_error == 1, host->timeout);
|
|
|
|
- if (host->wait_int != 1 && time == 0) {
|
|
|
|
|
|
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
|
|
|
|
+ host->timeout);
|
|
|
|
+ if (time <= 0) {
|
|
cmd->error = sh_mmcif_error_manage(host);
|
|
cmd->error = sh_mmcif_error_manage(host);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -579,19 +558,14 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
|
|
cmd->error = sh_mmcif_error_manage(host);
|
|
cmd->error = sh_mmcif_error_manage(host);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- host->sd_error = 0;
|
|
|
|
- host->wait_int = 0;
|
|
|
|
|
|
+ host->sd_error = false;
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
if (!(cmd->flags & MMC_RSP_PRESENT)) {
|
|
if (!(cmd->flags & MMC_RSP_PRESENT)) {
|
|
cmd->error = ret;
|
|
cmd->error = ret;
|
|
- host->wait_int = 0;
|
|
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- if (host->wait_int == 1) {
|
|
|
|
- sh_mmcif_get_response(host, cmd);
|
|
|
|
- host->wait_int = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ sh_mmcif_get_response(host, cmd);
|
|
if (host->data) {
|
|
if (host->data) {
|
|
ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
|
|
ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
@@ -618,15 +592,13 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- time = wait_event_interruptible_timeout(host->intr_wait,
|
|
|
|
- host->wait_int == 1 ||
|
|
|
|
- host->sd_error == 1, host->timeout);
|
|
|
|
- if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) {
|
|
|
|
|
|
+ time = wait_for_completion_interruptible_timeout(&host->intr_wait,
|
|
|
|
+ host->timeout);
|
|
|
|
+ if (time <= 0 || host->sd_error) {
|
|
cmd->error = sh_mmcif_error_manage(host);
|
|
cmd->error = sh_mmcif_error_manage(host);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
sh_mmcif_get_cmd12response(host, cmd);
|
|
sh_mmcif_get_cmd12response(host, cmd);
|
|
- host->wait_int = 0;
|
|
|
|
cmd->error = 0;
|
|
cmd->error = 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -712,7 +684,7 @@ static void sh_mmcif_detect(struct mmc_host *mmc)
|
|
static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
|
|
static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
|
|
{
|
|
{
|
|
struct sh_mmcif_host *host = dev_id;
|
|
struct sh_mmcif_host *host = dev_id;
|
|
- u32 state = 0;
|
|
|
|
|
|
+ u32 state;
|
|
int err = 0;
|
|
int err = 0;
|
|
|
|
|
|
state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
|
|
state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
|
|
@@ -757,11 +729,13 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
|
|
err = 1;
|
|
err = 1;
|
|
}
|
|
}
|
|
if (err) {
|
|
if (err) {
|
|
- host->sd_error = 1;
|
|
|
|
|
|
+ host->sd_error = true;
|
|
pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state);
|
|
pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state);
|
|
}
|
|
}
|
|
- host->wait_int = 1;
|
|
|
|
- wake_up(&host->intr_wait);
|
|
|
|
|
|
+ if (state & ~(INT_CMD12RBE | INT_CMD12CRE))
|
|
|
|
+ complete(&host->intr_wait);
|
|
|
|
+ else
|
|
|
|
+ dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state);
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
}
|
|
}
|
|
@@ -819,7 +793,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
|
|
host->clk = clk_get_rate(host->hclk);
|
|
host->clk = clk_get_rate(host->hclk);
|
|
host->pd = pdev;
|
|
host->pd = pdev;
|
|
|
|
|
|
- init_waitqueue_head(&host->intr_wait);
|
|
|
|
|
|
+ init_completion(&host->intr_wait);
|
|
|
|
|
|
mmc->ops = &sh_mmcif_ops;
|
|
mmc->ops = &sh_mmcif_ops;
|
|
mmc->f_max = host->clk;
|
|
mmc->f_max = host->clk;
|
|
@@ -880,20 +854,21 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
|
|
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
|
|
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
|
|
int irq[2];
|
|
int irq[2];
|
|
|
|
|
|
- sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
|
|
|
|
-
|
|
|
|
- irq[0] = platform_get_irq(pdev, 0);
|
|
|
|
- irq[1] = platform_get_irq(pdev, 1);
|
|
|
|
|
|
+ mmc_remove_host(host->mmc);
|
|
|
|
|
|
if (host->addr)
|
|
if (host->addr)
|
|
iounmap(host->addr);
|
|
iounmap(host->addr);
|
|
|
|
|
|
- platform_set_drvdata(pdev, NULL);
|
|
|
|
- mmc_remove_host(host->mmc);
|
|
|
|
|
|
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
|
|
|
|
+
|
|
|
|
+ irq[0] = platform_get_irq(pdev, 0);
|
|
|
|
+ irq[1] = platform_get_irq(pdev, 1);
|
|
|
|
|
|
free_irq(irq[0], host);
|
|
free_irq(irq[0], host);
|
|
free_irq(irq[1], host);
|
|
free_irq(irq[1], host);
|
|
|
|
|
|
|
|
+ platform_set_drvdata(pdev, NULL);
|
|
|
|
+
|
|
clk_disable(host->hclk);
|
|
clk_disable(host->hclk);
|
|
mmc_free_host(host->mmc);
|
|
mmc_free_host(host->mmc);
|
|
|
|
|
|
@@ -924,5 +899,5 @@ module_exit(sh_mmcif_exit);
|
|
|
|
|
|
MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
|
|
MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_LICENSE("GPL");
|
|
-MODULE_ALIAS(DRIVER_NAME);
|
|
|
|
|
|
+MODULE_ALIAS("platform:" DRIVER_NAME);
|
|
MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");
|
|
MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");
|