summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/wbsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/wbsd.c')
-rw-r--r--drivers/mmc/host/wbsd.c150
1 files changed, 71 insertions, 79 deletions
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
index 1e54bbf13d75..c33a0223ce7f 100644
--- a/drivers/mmc/host/wbsd.c
+++ b/drivers/mmc/host/wbsd.c
@@ -1,14 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/host/wbsd.c - Winbond W83L51xD SD/MMC driver
*
* Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- *
* Warning!
*
* Changes to the FIFO system should be done with extreme care since
@@ -33,6 +28,8 @@
#include <linux/pnp.h>
#include <linux/highmem.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
@@ -270,7 +267,7 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
static inline char *wbsd_map_sg(struct wbsd_host *host)
{
- return kmap_atomic(sg_page(host->cur_sg)) + host->cur_sg->offset;
+ return kmap_local_page(sg_page(host->cur_sg)) + host->cur_sg->offset;
}
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@@ -442,7 +439,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
* End of scatter list entry?
*/
if (host->remain == 0) {
- kunmap_atomic(buffer);
+ kunmap_local(buffer);
/*
* Get next entry. Check if last.
*/
@@ -454,7 +451,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
}
}
}
- kunmap_atomic(buffer);
+ kunmap_local(buffer);
/*
* This is a very dirty hack to solve a
@@ -462,7 +459,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
* FIFO threshold interrupts properly.
*/
if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
- tasklet_schedule(&host->fifo_tasklet);
+ queue_work(system_bh_wq, &host->fifo_bh_work);
}
static void wbsd_fill_fifo(struct wbsd_host *host)
@@ -508,7 +505,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
* End of scatter list entry?
*/
if (host->remain == 0) {
- kunmap_atomic(buffer);
+ kunmap_local(buffer);
/*
* Get next entry. Check if last.
*/
@@ -520,14 +517,14 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
}
}
}
- kunmap_atomic(buffer);
+ kunmap_local(buffer);
/*
* The controller stops sending interrupts for
* 'FIFO empty' under certain conditions. So we
* need to be a bit more pro-active.
*/
- tasklet_schedule(&host->fifo_tasklet);
+ queue_work(system_bh_wq, &host->fifo_bh_work);
}
static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
@@ -749,7 +746,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
struct mmc_command *cmd;
/*
- * Disable tasklets to avoid a deadlock.
+ * Disable bh works to avoid a deadlock.
*/
spin_lock_bh(&host->lock);
@@ -775,22 +772,22 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
* interrupts.
*/
switch (cmd->opcode) {
- case 11:
- case 17:
- case 18:
- case 20:
- case 24:
- case 25:
- case 26:
- case 27:
- case 30:
- case 42:
- case 56:
+ case SD_SWITCH_VOLTAGE:
+ case MMC_READ_SINGLE_BLOCK:
+ case MMC_READ_MULTIPLE_BLOCK:
+ case MMC_WRITE_DAT_UNTIL_STOP:
+ case MMC_WRITE_BLOCK:
+ case MMC_WRITE_MULTIPLE_BLOCK:
+ case MMC_PROGRAM_CID:
+ case MMC_PROGRAM_CSD:
+ case MMC_SEND_WRITE_PROT:
+ case MMC_LOCK_UNLOCK:
+ case MMC_GEN_CMD:
break;
/* ACMDs. We don't keep track of state, so we just treat them
* like any other command. */
- case 51:
+ case SD_APP_SEND_SCR:
break;
default:
@@ -824,7 +821,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
* Dirty fix for hardware bug.
*/
if (host->dma == -1)
- tasklet_schedule(&host->fifo_tasklet);
+ queue_work(system_bh_wq, &host->fifo_bh_work);
spin_unlock_bh(&host->lock);
@@ -950,7 +947,7 @@ static const struct mmc_host_ops wbsd_ops = {
static void wbsd_reset_ignore(struct timer_list *t)
{
- struct wbsd_host *host = from_timer(host, t, ignore_timer);
+ struct wbsd_host *host = timer_container_of(host, t, ignore_timer);
BUG_ON(host == NULL);
@@ -964,13 +961,13 @@ static void wbsd_reset_ignore(struct timer_list *t)
* Card status might have changed during the
* blackout.
*/
- tasklet_schedule(&host->card_tasklet);
+ queue_work(system_bh_wq, &host->card_bh_work);
spin_unlock_bh(&host->lock);
}
/*
- * Tasklets
+ * BH Works
*/
static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
@@ -990,9 +987,9 @@ static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
return host->mrq->cmd->data;
}
-static void wbsd_tasklet_card(unsigned long param)
+static void wbsd_card_bh_work(struct work_struct *t)
{
- struct wbsd_host *host = (struct wbsd_host *)param;
+ struct wbsd_host *host = from_work(host, t, card_bh_work);
u8 csr;
int delay = -1;
@@ -1023,7 +1020,7 @@ static void wbsd_tasklet_card(unsigned long param)
wbsd_reset(host);
host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
+ queue_work(system_bh_wq, &host->finish_bh_work);
}
delay = 0;
@@ -1039,9 +1036,9 @@ static void wbsd_tasklet_card(unsigned long param)
mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
}
-static void wbsd_tasklet_fifo(unsigned long param)
+static void wbsd_fifo_bh_work(struct work_struct *t)
{
- struct wbsd_host *host = (struct wbsd_host *)param;
+ struct wbsd_host *host = from_work(host, t, fifo_bh_work);
struct mmc_data *data;
spin_lock(&host->lock);
@@ -1063,16 +1060,16 @@ static void wbsd_tasklet_fifo(unsigned long param)
*/
if (host->num_sg == 0) {
wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
- tasklet_schedule(&host->finish_tasklet);
+ queue_work(system_bh_wq, &host->finish_bh_work);
}
end:
spin_unlock(&host->lock);
}
-static void wbsd_tasklet_crc(unsigned long param)
+static void wbsd_crc_bh_work(struct work_struct *t)
{
- struct wbsd_host *host = (struct wbsd_host *)param;
+ struct wbsd_host *host = from_work(host, t, crc_bh_work);
struct mmc_data *data;
spin_lock(&host->lock);
@@ -1088,15 +1085,15 @@ static void wbsd_tasklet_crc(unsigned long param)
data->error = -EILSEQ;
- tasklet_schedule(&host->finish_tasklet);
+ queue_work(system_bh_wq, &host->finish_bh_work);
end:
spin_unlock(&host->lock);
}
-static void wbsd_tasklet_timeout(unsigned long param)
+static void wbsd_timeout_bh_work(struct work_struct *t)
{
- struct wbsd_host *host = (struct wbsd_host *)param;
+ struct wbsd_host *host = from_work(host, t, timeout_bh_work);
struct mmc_data *data;
spin_lock(&host->lock);
@@ -1112,15 +1109,15 @@ static void wbsd_tasklet_timeout(unsigned long param)
data->error = -ETIMEDOUT;
- tasklet_schedule(&host->finish_tasklet);
+ queue_work(system_bh_wq, &host->finish_bh_work);
end:
spin_unlock(&host->lock);
}
-static void wbsd_tasklet_finish(unsigned long param)
+static void wbsd_finish_bh_work(struct work_struct *t)
{
- struct wbsd_host *host = (struct wbsd_host *)param;
+ struct wbsd_host *host = from_work(host, t, finish_bh_work);
struct mmc_data *data;
spin_lock(&host->lock);
@@ -1159,18 +1156,18 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id)
host->isr |= isr;
/*
- * Schedule tasklets as needed.
+ * Schedule bh work as needed.
*/
if (isr & WBSD_INT_CARD)
- tasklet_schedule(&host->card_tasklet);
+ queue_work(system_bh_wq, &host->card_bh_work);
if (isr & WBSD_INT_FIFO_THRE)
- tasklet_schedule(&host->fifo_tasklet);
+ queue_work(system_bh_wq, &host->fifo_bh_work);
if (isr & WBSD_INT_CRC)
- tasklet_hi_schedule(&host->crc_tasklet);
+ queue_work(system_bh_highpri_wq, &host->crc_bh_work);
if (isr & WBSD_INT_TIMEOUT)
- tasklet_hi_schedule(&host->timeout_tasklet);
+ queue_work(system_bh_highpri_wq, &host->timeout_bh_work);
if (isr & WBSD_INT_TC)
- tasklet_schedule(&host->finish_tasklet);
+ queue_work(system_bh_wq, &host->finish_bh_work);
return IRQ_HANDLED;
}
@@ -1193,7 +1190,7 @@ static int wbsd_alloc_mmc(struct device *dev)
/*
* Allocate MMC structure.
*/
- mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
+ mmc = devm_mmc_alloc_host(dev, sizeof(*host));
if (!mmc)
return -ENOMEM;
@@ -1264,11 +1261,7 @@ static void wbsd_free_mmc(struct device *dev)
host = mmc_priv(mmc);
BUG_ON(host == NULL);
- del_timer_sync(&host->ignore_timer);
-
- mmc_free_host(mmc);
-
- dev_set_drvdata(dev, NULL);
+ timer_delete_sync(&host->ignore_timer);
}
/*
@@ -1289,8 +1282,6 @@ static int wbsd_scan(struct wbsd_host *host)
continue;
for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) {
- id = 0xFFFF;
-
host->config = config_ports[i];
host->unlock_code = unlock_codes[j];
@@ -1450,18 +1441,13 @@ static int wbsd_request_irq(struct wbsd_host *host, int irq)
int ret;
/*
- * Set up tasklets. Must be done before requesting interrupt.
+ * Set up bh works. Must be done before requesting interrupt.
*/
- tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
- (unsigned long)host);
- tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo,
- (unsigned long)host);
- tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc,
- (unsigned long)host);
- tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout,
- (unsigned long)host);
- tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
- (unsigned long)host);
+ INIT_WORK(&host->card_bh_work, wbsd_card_bh_work);
+ INIT_WORK(&host->fifo_bh_work, wbsd_fifo_bh_work);
+ INIT_WORK(&host->crc_bh_work, wbsd_crc_bh_work);
+ INIT_WORK(&host->timeout_bh_work, wbsd_timeout_bh_work);
+ INIT_WORK(&host->finish_bh_work, wbsd_finish_bh_work);
/*
* Allocate interrupt.
@@ -1484,11 +1470,11 @@ static void wbsd_release_irq(struct wbsd_host *host)
host->irq = 0;
- tasklet_kill(&host->card_tasklet);
- tasklet_kill(&host->fifo_tasklet);
- tasklet_kill(&host->crc_tasklet);
- tasklet_kill(&host->timeout_tasklet);
- tasklet_kill(&host->finish_tasklet);
+ cancel_work_sync(&host->card_bh_work);
+ cancel_work_sync(&host->fifo_bh_work);
+ cancel_work_sync(&host->crc_bh_work);
+ cancel_work_sync(&host->timeout_bh_work);
+ cancel_work_sync(&host->finish_bh_work);
}
/*
@@ -1706,7 +1692,15 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma,
*/
wbsd_init_device(host);
- mmc_add_host(mmc);
+ ret = mmc_add_host(mmc);
+ if (ret) {
+ if (!pnp)
+ wbsd_chip_poweroff(host);
+
+ wbsd_release_resources(host);
+ wbsd_free_mmc(dev);
+ return ret;
+ }
pr_info("%s: W83L51xD", mmc_hostname(mmc));
if (host->chip_id != 0)
@@ -1756,11 +1750,9 @@ static int wbsd_probe(struct platform_device *dev)
return wbsd_init(&dev->dev, param_io, param_irq, param_dma, 0);
}
-static int wbsd_remove(struct platform_device *dev)
+static void wbsd_remove(struct platform_device *dev)
{
wbsd_shutdown(&dev->dev, 0);
-
- return 0;
}
/*
@@ -1903,11 +1895,11 @@ static struct platform_device *wbsd_device;
static struct platform_driver wbsd_driver = {
.probe = wbsd_probe,
.remove = wbsd_remove,
-
.suspend = wbsd_platform_suspend,
.resume = wbsd_platform_resume,
.driver = {
.name = DRIVER_NAME,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};