summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/atmel-mci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/atmel-mci.c')
-rw-r--r--drivers/mmc/host/atmel-mci.c1110
1 files changed, 594 insertions, 516 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index bdb84da74952..fdf6926ea468 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atmel MultiMedia Card Interface driver
*
* Copyright (C) 2004-2008 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/blkdev.h>
#include <linux/clk.h>
@@ -14,33 +11,168 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/types.h>
-#include <linux/platform_data/atmel.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio.h>
-#include <mach/atmel-mci.h>
-#include <linux/atmel-mci.h>
#include <linux/atmel_pdc.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/workqueue.h>
+#include <asm/cacheflush.h>
#include <asm/io.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
+#include <linux/string_choices.h>
+
+#define ATMCI_MAX_NR_SLOTS 2
+
+/*
+ * Superset of MCI IP registers integrated in Atmel AT91 Processor
+ * Registers and bitfields marked with [2] are only available in MCI2
+ */
-#include "atmel-mci-regs.h"
+/* MCI Register Definitions */
+#define ATMCI_CR 0x0000 /* Control */
+#define ATMCI_CR_MCIEN BIT(0) /* MCI Enable */
+#define ATMCI_CR_MCIDIS BIT(1) /* MCI Disable */
+#define ATMCI_CR_PWSEN BIT(2) /* Power Save Enable */
+#define ATMCI_CR_PWSDIS BIT(3) /* Power Save Disable */
+#define ATMCI_CR_SWRST BIT(7) /* Software Reset */
+#define ATMCI_MR 0x0004 /* Mode */
+#define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */
+#define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */
+#define ATMCI_MR_RDPROOF BIT(11) /* Read Proof */
+#define ATMCI_MR_WRPROOF BIT(12) /* Write Proof */
+#define ATMCI_MR_PDCFBYTE BIT(13) /* Force Byte Transfer */
+#define ATMCI_MR_PDCPADV BIT(14) /* Padding Value */
+#define ATMCI_MR_PDCMODE BIT(15) /* PDC-oriented Mode */
+#define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */
+#define ATMCI_DTOR 0x0008 /* Data Timeout */
+#define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */
+#define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */
+#define ATMCI_SDCR 0x000c /* SD Card / SDIO */
+#define ATMCI_SDCSEL_SLOT_A (0 << 0) /* Select SD slot A */
+#define ATMCI_SDCSEL_SLOT_B (1 << 0) /* Select SD slot A */
+#define ATMCI_SDCSEL_MASK (3 << 0)
+#define ATMCI_SDCBUS_1BIT (0 << 6) /* 1-bit data bus */
+#define ATMCI_SDCBUS_4BIT (2 << 6) /* 4-bit data bus */
+#define ATMCI_SDCBUS_8BIT (3 << 6) /* 8-bit data bus[2] */
+#define ATMCI_SDCBUS_MASK (3 << 6)
+#define ATMCI_ARGR 0x0010 /* Command Argument */
+#define ATMCI_CMDR 0x0014 /* Command */
+#define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */
+#define ATMCI_CMDR_RSPTYP_NONE (0 << 6) /* No response */
+#define ATMCI_CMDR_RSPTYP_48BIT (1 << 6) /* 48-bit response */
+#define ATMCI_CMDR_RSPTYP_136BIT (2 << 6) /* 136-bit response */
+#define ATMCI_CMDR_SPCMD_INIT (1 << 8) /* Initialization command */
+#define ATMCI_CMDR_SPCMD_SYNC (2 << 8) /* Synchronized command */
+#define ATMCI_CMDR_SPCMD_INT (4 << 8) /* Interrupt command */
+#define ATMCI_CMDR_SPCMD_INTRESP (5 << 8) /* Interrupt response */
+#define ATMCI_CMDR_OPDCMD (1 << 11) /* Open Drain */
+#define ATMCI_CMDR_MAXLAT_5CYC (0 << 12) /* Max latency 5 cycles */
+#define ATMCI_CMDR_MAXLAT_64CYC (1 << 12) /* Max latency 64 cycles */
+#define ATMCI_CMDR_START_XFER (1 << 16) /* Start data transfer */
+#define ATMCI_CMDR_STOP_XFER (2 << 16) /* Stop data transfer */
+#define ATMCI_CMDR_TRDIR_WRITE (0 << 18) /* Write data */
+#define ATMCI_CMDR_TRDIR_READ (1 << 18) /* Read data */
+#define ATMCI_CMDR_BLOCK (0 << 19) /* Single-block transfer */
+#define ATMCI_CMDR_MULTI_BLOCK (1 << 19) /* Multi-block transfer */
+#define ATMCI_CMDR_STREAM (2 << 19) /* MMC Stream transfer */
+#define ATMCI_CMDR_SDIO_BYTE (4 << 19) /* SDIO Byte transfer */
+#define ATMCI_CMDR_SDIO_BLOCK (5 << 19) /* SDIO Block transfer */
+#define ATMCI_CMDR_SDIO_SUSPEND (1 << 24) /* SDIO Suspend Command */
+#define ATMCI_CMDR_SDIO_RESUME (2 << 24) /* SDIO Resume Command */
+#define ATMCI_BLKR 0x0018 /* Block */
+#define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */
+#define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */
+#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */
+#define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */
+#define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */
+#define ATMCI_RSPR 0x0020 /* Response 0 */
+#define ATMCI_RSPR1 0x0024 /* Response 1 */
+#define ATMCI_RSPR2 0x0028 /* Response 2 */
+#define ATMCI_RSPR3 0x002c /* Response 3 */
+#define ATMCI_RDR 0x0030 /* Receive Data */
+#define ATMCI_TDR 0x0034 /* Transmit Data */
+#define ATMCI_SR 0x0040 /* Status */
+#define ATMCI_IER 0x0044 /* Interrupt Enable */
+#define ATMCI_IDR 0x0048 /* Interrupt Disable */
+#define ATMCI_IMR 0x004c /* Interrupt Mask */
+#define ATMCI_CMDRDY BIT(0) /* Command Ready */
+#define ATMCI_RXRDY BIT(1) /* Receiver Ready */
+#define ATMCI_TXRDY BIT(2) /* Transmitter Ready */
+#define ATMCI_BLKE BIT(3) /* Data Block Ended */
+#define ATMCI_DTIP BIT(4) /* Data Transfer In Progress */
+#define ATMCI_NOTBUSY BIT(5) /* Data Not Busy */
+#define ATMCI_ENDRX BIT(6) /* End of RX Buffer */
+#define ATMCI_ENDTX BIT(7) /* End of TX Buffer */
+#define ATMCI_SDIOIRQA BIT(8) /* SDIO IRQ in slot A */
+#define ATMCI_SDIOIRQB BIT(9) /* SDIO IRQ in slot B */
+#define ATMCI_SDIOWAIT BIT(12) /* SDIO Read Wait Operation Status */
+#define ATMCI_CSRCV BIT(13) /* CE-ATA Completion Signal Received */
+#define ATMCI_RXBUFF BIT(14) /* RX Buffer Full */
+#define ATMCI_TXBUFE BIT(15) /* TX Buffer Empty */
+#define ATMCI_RINDE BIT(16) /* Response Index Error */
+#define ATMCI_RDIRE BIT(17) /* Response Direction Error */
+#define ATMCI_RCRCE BIT(18) /* Response CRC Error */
+#define ATMCI_RENDE BIT(19) /* Response End Bit Error */
+#define ATMCI_RTOE BIT(20) /* Response Time-Out Error */
+#define ATMCI_DCRCE BIT(21) /* Data CRC Error */
+#define ATMCI_DTOE BIT(22) /* Data Time-Out Error */
+#define ATMCI_CSTOE BIT(23) /* Completion Signal Time-out Error */
+#define ATMCI_BLKOVRE BIT(24) /* DMA Block Overrun Error */
+#define ATMCI_DMADONE BIT(25) /* DMA Transfer Done */
+#define ATMCI_FIFOEMPTY BIT(26) /* FIFO Empty Flag */
+#define ATMCI_XFRDONE BIT(27) /* Transfer Done Flag */
+#define ATMCI_ACKRCV BIT(28) /* Boot Operation Acknowledge Received */
+#define ATMCI_ACKRCVE BIT(29) /* Boot Operation Acknowledge Error */
+#define ATMCI_OVRE BIT(30) /* RX Overrun Error */
+#define ATMCI_UNRE BIT(31) /* TX Underrun Error */
+#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */
+#define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */
+#define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */
+#define ATMCI_DMAEN BIT(8) /* DMA Hardware Handshaking Enable */
+#define ATMCI_CFG 0x0054 /* Configuration[2] */
+#define ATMCI_CFG_FIFOMODE_1DATA BIT(0) /* MCI Internal FIFO control mode */
+#define ATMCI_CFG_FERRCTRL_COR BIT(4) /* Flow Error flag reset control mode */
+#define ATMCI_CFG_HSMODE BIT(8) /* High Speed Mode */
+#define ATMCI_CFG_LSYNC BIT(12) /* Synchronize on the last block */
+#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */
+#define ATMCI_WP_EN BIT(0) /* WP Enable */
+#define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */
+#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */
+#define ATMCI_GET_WP_VS(x) ((x) & 0x0f)
+#define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff)
+#define ATMCI_VERSION 0x00FC /* Version */
+#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */
+
+/* This is not including the FIFO Aperture on MCI2 */
+#define ATMCI_REGS_SIZE 0x100
+
+/* Register access macros */
+#define atmci_readl(port, reg) \
+ __raw_readl((port)->regs + reg)
+#define atmci_writel(port, reg, value) \
+ __raw_writel((value), (port)->regs + reg)
+
+#define ATMCI_CMD_TIMEOUT_MS 2000
+#define AUTOSUSPEND_DELAY 50
#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
#define ATMCI_DMA_THRESHOLD 16
@@ -71,6 +203,29 @@ enum atmci_pdc_buf {
PDC_SECOND_BUF,
};
+/**
+ * struct mci_slot_pdata - board-specific per-slot configuration
+ * @bus_width: Number of data lines wired up the slot
+ * @detect_pin: GPIO pin wired to the card detect switch
+ * @wp_pin: GPIO pin wired to the write protect sensor
+ * @non_removable: The slot is not removable, only detect once
+ *
+ * If a given slot is not present on the board, @bus_width should be
+ * set to 0. The other fields are ignored in this case.
+ *
+ * Any pins that aren't available should be set to a negative value.
+ *
+ * Note that support for multiple slots is experimental -- some cards
+ * might get upset if we don't get the clock management exactly right.
+ * But in most cases, it should work just fine.
+ */
+struct mci_slot_pdata {
+ unsigned int bus_width;
+ struct gpio_desc *detect_pin;
+ struct gpio_desc *wp_pin;
+ bool non_removable;
+};
+
struct atmel_mci_caps {
bool has_dma_conf_reg;
bool has_pdc;
@@ -95,12 +250,13 @@ struct atmel_mci_dma {
* @lock: Spinlock protecting the queue and associated data.
* @regs: Pointer to MMIO registers.
* @sg: Scatterlist entry currently being processed by PIO or PDC code.
+ * @sg_len: Size of the scatterlist
* @pio_offset: Offset into the current scatterlist entry.
* @buffer: Buffer used if we don't have the r/w proof capability. We
* don't have the time to switch pdc buffers so we have to use only
* one buffer for the full transaction.
* @buf_size: size of the buffer.
- * @phys_buf_addr: buffer address needed for pdc.
+ * @buf_phys_addr: buffer address needed for pdc.
* @cur_slot: The slot which is currently using the controller.
* @mrq: The request currently being processed on @cur_slot,
* or NULL if the controller is idle.
@@ -110,6 +266,7 @@ struct atmel_mci_dma {
* @data_size: just data->blocks * data->blksz.
* @dma: DMA client state.
* @data_chan: DMA channel being used for the current data transfer.
+ * @dma_conf: Configuration for the DMA slave
* @cmd_status: Snapshot of SR taken upon completion of the current
* command. Only valid when EVENT_CMD_COMPLETE is pending.
* @data_status: Snapshot of SR taken upon completion of the current
@@ -117,12 +274,12 @@ struct atmel_mci_dma {
* EVENT_DATA_ERROR is pending.
* @stop_cmdr: Value to be loaded into CMDR when the stop command is
* to be sent.
- * @tasklet: Tasklet running the request state machine.
+ * @bh_work: Work running the request state machine.
* @pending_events: Bitmask of events flagged by the interrupt handler
- * to be processed by the tasklet.
+ * to be processed by the work.
* @completed_events: Bitmask of events which the state machine has
* processed.
- * @state: Tasklet state.
+ * @state: Work state.
* @queue: List of slots waiting for access to the controller.
* @need_clock_update: Update the clock rate before the next request.
* @need_reset: Reset controller before next request.
@@ -133,7 +290,8 @@ struct atmel_mci_dma {
* rate and timeout calculations.
* @mapbase: Physical address of the MMIO registers.
* @mck: The peripheral bus clock hooked up to the MMC controller.
- * @pdev: Platform device associated with the MMC controller.
+ * @dev: Device associated with the MMC controller.
+ * @pdata: Per-slot configuration data.
* @slot: Slots sharing this MMC controller.
* @caps: MCI capabilities depending on MCI version.
* @prepare_data: function to setup MCI before data transfer which
@@ -196,7 +354,7 @@ struct atmel_mci {
u32 data_status;
u32 stop_cmdr;
- struct tasklet_struct tasklet;
+ struct work_struct bh_work;
unsigned long pending_events;
unsigned long completed_events;
enum atmel_mci_state state;
@@ -210,8 +368,9 @@ struct atmel_mci {
unsigned long bus_hz;
unsigned long mapbase;
struct clk *mck;
- struct platform_device *pdev;
+ struct device *dev;
+ struct mci_slot_pdata pdata[ATMCI_MAX_NR_SLOTS];
struct atmel_mci_slot *slot[ATMCI_MAX_NR_SLOTS];
struct atmel_mci_caps caps;
@@ -237,7 +396,6 @@ struct atmel_mci {
* available.
* @wp_pin: GPIO pin used for card write protect sending, or negative
* if not available.
- * @detect_is_active_high: The state of the detect pin when it is active.
* @detect_timer: Timer used for debouncing @detect_pin interrupts.
*/
struct atmel_mci_slot {
@@ -255,11 +413,9 @@ struct atmel_mci_slot {
#define ATMCI_CARD_PRESENT 0
#define ATMCI_CARD_NEED_INIT 1
#define ATMCI_SHUTDOWN 2
-#define ATMCI_SUSPENDED 3
- int detect_pin;
- int wp_pin;
- bool detect_is_active_high;
+ struct gpio_desc *detect_pin;
+ struct gpio_desc *wp_pin;
struct timer_list detect_timer;
};
@@ -315,18 +471,7 @@ static int atmci_req_show(struct seq_file *s, void *v)
return 0;
}
-static int atmci_req_open(struct inode *inode, struct file *file)
-{
- return single_open(file, atmci_req_show, inode->i_private);
-}
-
-static const struct file_operations atmci_req_fops = {
- .owner = THIS_MODULE,
- .open = atmci_req_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(atmci_req);
static void atmci_show_status_reg(struct seq_file *s,
const char *regname, u32 value)
@@ -377,23 +522,28 @@ static void atmci_show_status_reg(struct seq_file *s,
static int atmci_regs_show(struct seq_file *s, void *v)
{
struct atmel_mci *host = s->private;
+ struct device *dev = host->dev;
u32 *buf;
+ int ret = 0;
+
buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
+ pm_runtime_get_sync(dev);
+
/*
* Grab a more or less consistent snapshot. Note that we're
* not disabling interrupts, so IMR and SR may not be
* consistent.
*/
spin_lock_bh(&host->lock);
- clk_enable(host->mck);
memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE);
- clk_disable(host->mck);
spin_unlock_bh(&host->lock);
+ pm_runtime_put_autosuspend(dev);
+
seq_printf(s, "MR:\t0x%08x%s%s ",
buf[ATMCI_MR / 4],
buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
@@ -444,65 +594,30 @@ static int atmci_regs_show(struct seq_file *s, void *v)
kfree(buf);
- return 0;
-}
-
-static int atmci_regs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, atmci_regs_show, inode->i_private);
+ return ret;
}
-static const struct file_operations atmci_regs_fops = {
- .owner = THIS_MODULE,
- .open = atmci_regs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(atmci_regs);
static void atmci_init_debugfs(struct atmel_mci_slot *slot)
{
struct mmc_host *mmc = slot->mmc;
struct atmel_mci *host = slot->host;
struct dentry *root;
- struct dentry *node;
root = mmc->debugfs_root;
if (!root)
return;
- node = debugfs_create_file("regs", S_IRUSR, root, host,
- &atmci_regs_fops);
- if (IS_ERR(node))
- return;
- if (!node)
- goto err;
-
- node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("pending_events", S_IRUSR, root,
- (u32 *)&host->pending_events);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("completed_events", S_IRUSR, root,
- (u32 *)&host->completed_events);
- if (!node)
- goto err;
-
- return;
-
-err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ debugfs_create_file("regs", 0400, root, host, &atmci_regs_fops);
+ debugfs_create_file("req", 0400, root, slot, &atmci_req_fops);
+ debugfs_create_u32("state", 0400, root, &host->state);
+ debugfs_create_xul("pending_events", 0400, root,
+ &host->pending_events);
+ debugfs_create_xul("completed_events", 0400, root,
+ &host->completed_events);
}
-#if defined(CONFIG_OF)
static const struct of_device_id atmci_dt_ids[] = {
{ .compatible = "atmel,hsmci" },
{ /* sentinel */ }
@@ -510,78 +625,110 @@ static const struct of_device_id atmci_dt_ids[] = {
MODULE_DEVICE_TABLE(of, atmci_dt_ids);
-static struct mci_platform_data*
-atmci_of_init(struct platform_device *pdev)
+static int atmci_of_init(struct atmel_mci *host)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = host->dev;
+ struct device_node *np = dev->of_node;
struct device_node *cnp;
- struct mci_platform_data *pdata;
u32 slot_id;
+ int err;
- if (!np) {
- dev_err(&pdev->dev, "device node not found\n");
- return ERR_PTR(-EINVAL);
- }
-
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "could not allocate memory for pdata\n");
- return ERR_PTR(-ENOMEM);
- }
+ if (!np)
+ return dev_err_probe(dev, -EINVAL, "device node not found\n");
for_each_child_of_node(np, cnp) {
if (of_property_read_u32(cnp, "reg", &slot_id)) {
- dev_warn(&pdev->dev, "reg property is missing for %s\n",
- cnp->full_name);
+ dev_warn(dev, "reg property is missing for %pOF\n", cnp);
continue;
}
if (slot_id >= ATMCI_MAX_NR_SLOTS) {
- dev_warn(&pdev->dev, "can't have more than %d slots\n",
+ dev_warn(dev, "can't have more than %d slots\n",
ATMCI_MAX_NR_SLOTS);
+ of_node_put(cnp);
break;
}
if (of_property_read_u32(cnp, "bus-width",
- &pdata->slot[slot_id].bus_width))
- pdata->slot[slot_id].bus_width = 1;
-
- pdata->slot[slot_id].detect_pin =
- of_get_named_gpio(cnp, "cd-gpios", 0);
-
- pdata->slot[slot_id].detect_is_active_high =
- of_property_read_bool(cnp, "cd-inverted");
+ &host->pdata[slot_id].bus_width))
+ host->pdata[slot_id].bus_width = 1;
+
+ host->pdata[slot_id].detect_pin =
+ devm_fwnode_gpiod_get(dev, of_fwnode_handle(cnp),
+ "cd", GPIOD_IN, "cd-gpios");
+ err = PTR_ERR_OR_ZERO(host->pdata[slot_id].detect_pin);
+ if (err) {
+ if (err != -ENOENT) {
+ of_node_put(cnp);
+ return err;
+ }
+ host->pdata[slot_id].detect_pin = NULL;
+ }
- pdata->slot[slot_id].wp_pin =
- of_get_named_gpio(cnp, "wp-gpios", 0);
+ host->pdata[slot_id].non_removable =
+ of_property_read_bool(cnp, "non-removable");
+
+ host->pdata[slot_id].wp_pin =
+ devm_fwnode_gpiod_get(dev, of_fwnode_handle(cnp),
+ "wp", GPIOD_IN, "wp-gpios");
+ err = PTR_ERR_OR_ZERO(host->pdata[slot_id].wp_pin);
+ if (err) {
+ if (err != -ENOENT) {
+ of_node_put(cnp);
+ return err;
+ }
+ host->pdata[slot_id].wp_pin = NULL;
+ }
}
- return pdata;
-}
-#else /* CONFIG_OF */
-static inline struct mci_platform_data*
-atmci_of_init(struct platform_device *dev)
-{
- return ERR_PTR(-EINVAL);
+ return 0;
}
-#endif
static inline unsigned int atmci_get_version(struct atmel_mci *host)
{
return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
}
-static void atmci_timeout_timer(unsigned long data)
+/*
+ * Fix sconfig's burst size according to atmel MCI. We need to convert them as:
+ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
+ * With version 0x600, we need to convert them as: 1 -> 0, 2 -> 1, 4 -> 2,
+ * 8 -> 3, 16 -> 4.
+ *
+ * This can be done by finding most significant bit set.
+ */
+static inline unsigned int atmci_convert_chksize(struct atmel_mci *host,
+ unsigned int maxburst)
{
- struct atmel_mci *host;
+ unsigned int version = atmci_get_version(host);
+ unsigned int offset = 2;
+
+ if (version >= 0x600)
+ offset = 1;
+
+ if (maxburst > 1)
+ return fls(maxburst) - offset;
+ else
+ return 0;
+}
- host = (struct atmel_mci *)data;
+static void atmci_timeout_timer(struct timer_list *t)
+{
+ struct atmel_mci *host = timer_container_of(host, t, timer);
+ struct device *dev = host->dev;
- dev_dbg(&host->pdev->dev, "software timeout\n");
+ dev_dbg(dev, "software timeout\n");
if (host->mrq->cmd->data) {
host->mrq->cmd->data->error = -ETIMEDOUT;
host->data = NULL;
+ /*
+ * With some SDIO modules, sometimes DMA transfer hangs. If
+ * stop_transfer() is not called then the DMA request is not
+ * removed, following ones are queued and never computed.
+ */
+ if (host->state == STATE_DATA_XFER)
+ host->stop_transfer(host);
} else {
host->mrq->cmd->error = -ETIMEDOUT;
host->cmd = NULL;
@@ -589,7 +736,7 @@ static void atmci_timeout_timer(unsigned long data)
host->need_reset = 1;
host->state = STATE_END_REQUEST;
smp_wmb();
- tasklet_schedule(&host->tasklet);
+ queue_work(system_bh_wq, &host->bh_work);
}
static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
@@ -672,9 +819,7 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,
if (cmd->opcode == SD_IO_RW_EXTENDED) {
cmdr |= ATMCI_CMDR_SDIO_BLOCK;
} else {
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= ATMCI_CMDR_STREAM;
- else if (data->blocks > 1)
+ if (data->blocks > 1)
cmdr |= ATMCI_CMDR_MULTI_BLOCK;
else
cmdr |= ATMCI_CMDR_BLOCK;
@@ -690,26 +835,32 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,
static void atmci_send_command(struct atmel_mci *host,
struct mmc_command *cmd, u32 cmd_flags)
{
+ struct device *dev = host->dev;
+ unsigned int timeout_ms = cmd->busy_timeout ? cmd->busy_timeout :
+ ATMCI_CMD_TIMEOUT_MS;
+
WARN_ON(host->cmd);
host->cmd = cmd;
- dev_vdbg(&host->pdev->dev,
- "start command: ARGR=0x%08x CMDR=0x%08x\n",
- cmd->arg, cmd_flags);
+ dev_vdbg(dev, "start command: ARGR=0x%08x CMDR=0x%08x\n", cmd->arg, cmd_flags);
atmci_writel(host, ATMCI_ARGR, cmd->arg);
atmci_writel(host, ATMCI_CMDR, cmd_flags);
+
+ mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout_ms));
}
static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
{
- dev_dbg(&host->pdev->dev, "send stop command\n");
+ struct device *dev = host->dev;
+
+ dev_dbg(dev, "send stop command\n");
atmci_send_command(host, data->stop, host->stop_cmdr);
atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
}
/*
- * Configure given PDC buffer taking care of alignement issues.
+ * Configure given PDC buffer taking care of alignment issues.
* Update host->data_size and host->sg.
*/
static void atmci_pdc_set_single_buf(struct atmel_mci *host,
@@ -776,12 +927,10 @@ static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir)
static void atmci_pdc_cleanup(struct atmel_mci *host)
{
struct mmc_data *data = host->data;
+ struct device *dev = host->dev;
if (data)
- dma_unmap_sg(&host->pdev->dev,
- data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ dma_unmap_sg(dev, data->sg, data->sg_len, mmc_get_dma_dir(data));
}
/*
@@ -791,6 +940,7 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
*/
static void atmci_pdc_complete(struct atmel_mci *host)
{
+ struct device *dev = host->dev;
int transfer_size = host->data->blocks * host->data->blksz;
int i;
@@ -807,16 +957,9 @@ static void atmci_pdc_complete(struct atmel_mci *host)
atmci_pdc_cleanup(host);
- /*
- * If the card was removed, data will be NULL. No point trying
- * to send the stop command or waiting for NBUSY in this case.
- */
- if (host->data) {
- dev_dbg(&host->pdev->dev,
- "(%s) set pending xfer complete\n", __func__);
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- tasklet_schedule(&host->tasklet);
- }
+ dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ queue_work(system_bh_wq, &host->bh_work);
}
static void atmci_dma_cleanup(struct atmel_mci *host)
@@ -826,19 +969,19 @@ static void atmci_dma_cleanup(struct atmel_mci *host)
if (data)
dma_unmap_sg(host->dma.chan->device->dev,
data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ mmc_get_dma_dir(data));
}
/*
- * This function is called by the DMA driver from tasklet context.
+ * This function is called by the DMA driver from bh context.
*/
static void atmci_dma_complete(void *arg)
{
struct atmel_mci *host = arg;
struct mmc_data *data = host->data;
+ struct device *dev = host->dev;
- dev_vdbg(&host->pdev->dev, "DMA complete\n");
+ dev_vdbg(dev, "DMA complete\n");
if (host->caps.has_dma_conf_reg)
/* Disable DMA hardware handshaking on MCI */
@@ -851,10 +994,9 @@ static void atmci_dma_complete(void *arg)
* to send the stop command or waiting for NBUSY in this case.
*/
if (data) {
- dev_dbg(&host->pdev->dev,
- "(%s) set pending xfer complete\n", __func__);
+ dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
atmci_set_pending(host, EVENT_XFER_COMPLETE);
- tasklet_schedule(&host->tasklet);
+ queue_work(system_bh_wq, &host->bh_work);
/*
* Regardless of what the documentation says, we have
@@ -867,7 +1009,7 @@ static void atmci_dma_complete(void *arg)
* haven't seen all the potential error bits yet.
*
* The interrupt handler will schedule a different
- * tasklet to finish things up when the data transfer
+ * bh work to finish things up when the data transfer
* is completely done.
*
* We may not complete the mmc request here anyway
@@ -926,9 +1068,8 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
static u32
atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
{
+ struct device *dev = host->dev;
u32 iflags, tmp;
- unsigned int sg_len;
- enum dma_data_direction dir;
int i;
data->error = -EINPROGRESS;
@@ -940,13 +1081,10 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
/* Enable pdc mode */
atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE);
- if (data->flags & MMC_DATA_READ) {
- dir = DMA_FROM_DEVICE;
+ if (data->flags & MMC_DATA_READ)
iflags |= ATMCI_ENDRX | ATMCI_RXBUFF;
- } else {
- dir = DMA_TO_DEVICE;
+ else
iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE;
- }
/* Set BLKLEN */
tmp = atmci_readl(host, ATMCI_MR);
@@ -956,7 +1094,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
/* Configure PDC */
host->data_size = data->blocks * data->blksz;
- sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
+ dma_map_sg(dev, data->sg, data->sg_len, mmc_get_dma_dir(data));
if ((!host->caps.has_rwproof)
&& (host->data->flags & MMC_DATA_WRITE)) {
@@ -968,9 +1106,8 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
}
if (host->data_size)
- atmci_pdc_set_both_buf(host,
- ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT));
-
+ atmci_pdc_set_both_buf(host, data->flags & MMC_DATA_READ ?
+ XFER_RECEIVE : XFER_TRANSMIT);
return iflags;
}
@@ -981,7 +1118,6 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
struct dma_async_tx_descriptor *desc;
struct scatterlist *sg;
unsigned int i;
- enum dma_data_direction direction;
enum dma_transfer_direction slave_dirn;
unsigned int sglen;
u32 maxburst;
@@ -1011,21 +1147,20 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
}
/* If we don't have a channel, we can't do DMA */
- chan = host->dma.chan;
- if (chan)
- host->data_chan = chan;
-
- if (!chan)
+ if (!host->dma.chan)
return -ENODEV;
+ chan = host->dma.chan;
+ host->data_chan = chan;
+
if (data->flags & MMC_DATA_READ) {
- direction = DMA_FROM_DEVICE;
host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
- maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst);
+ maxburst = atmci_convert_chksize(host,
+ host->dma_conf.src_maxburst);
} else {
- direction = DMA_TO_DEVICE;
host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
- maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst);
+ maxburst = atmci_convert_chksize(host,
+ host->dma_conf.dst_maxburst);
}
if (host->caps.has_dma_conf_reg)
@@ -1033,7 +1168,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
ATMCI_DMAEN);
sglen = dma_map_sg(chan->device->dev, data->sg,
- data->sg_len, direction);
+ data->sg_len, mmc_get_dma_dir(data));
dmaengine_slave_config(chan, &host->dma_conf);
desc = dmaengine_prep_slave_sg(chan,
@@ -1048,7 +1183,8 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
return iflags;
unmap_exit:
- dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction);
+ dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
return -ENOMEM;
}
@@ -1084,8 +1220,9 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
static void atmci_stop_transfer(struct atmel_mci *host)
{
- dev_dbg(&host->pdev->dev,
- "(%s) set pending xfer complete\n", __func__);
+ struct device *dev = host->dev;
+
+ dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
atmci_set_pending(host, EVENT_XFER_COMPLETE);
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
}
@@ -1101,14 +1238,14 @@ static void atmci_stop_transfer_pdc(struct atmel_mci *host)
static void atmci_stop_transfer_dma(struct atmel_mci *host)
{
struct dma_chan *chan = host->data_chan;
+ struct device *dev = host->dev;
if (chan) {
dmaengine_terminate_all(chan);
atmci_dma_cleanup(host);
} else {
/* Data transfer was stopped by the interrupt handler */
- dev_dbg(&host->pdev->dev,
- "(%s) set pending xfer complete\n", __func__);
+ dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
atmci_set_pending(host, EVENT_XFER_COMPLETE);
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
}
@@ -1121,6 +1258,7 @@ static void atmci_stop_transfer_dma(struct atmel_mci *host)
static void atmci_start_request(struct atmel_mci *host,
struct atmel_mci_slot *slot)
{
+ struct device *dev = host->dev;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
@@ -1136,7 +1274,7 @@ static void atmci_start_request(struct atmel_mci *host,
host->cmd_status = 0;
host->data_status = 0;
- dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode);
+ dev_dbg(dev, "start request: cmd %u\n", mrq->cmd->opcode);
if (host->need_reset || host->caps.need_reset_after_xfer) {
iflags = atmci_readl(host, ATMCI_IMR);
@@ -1179,20 +1317,28 @@ static void atmci_start_request(struct atmel_mci *host,
iflags |= ATMCI_CMDRDY;
cmd = mrq->cmd;
cmdflags = atmci_prepare_command(slot->mmc, cmd);
- atmci_send_command(host, cmd, cmdflags);
+
+ /*
+ * DMA transfer should be started before sending the command to avoid
+ * unexpected errors especially for read operations in SDIO mode.
+ * Unfortunately, in PDC mode, command has to be sent before starting
+ * the transfer.
+ */
+ if (host->submit_data != &atmci_submit_data_dma)
+ atmci_send_command(host, cmd, cmdflags);
if (data)
host->submit_data(host, data);
+ if (host->submit_data == &atmci_submit_data_dma)
+ atmci_send_command(host, cmd, cmdflags);
+
if (mrq->stop) {
host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
host->stop_cmdr |= ATMCI_CMDR_STOP_XFER;
if (!(data->flags & MMC_DATA_WRITE))
host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ;
- if (data->flags & MMC_DATA_STREAM)
- host->stop_cmdr |= ATMCI_CMDR_STREAM;
- else
- host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK;
+ host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK;
}
/*
@@ -1202,13 +1348,13 @@ static void atmci_start_request(struct atmel_mci *host,
* prepared yet.)
*/
atmci_writel(host, ATMCI_IER, iflags);
-
- mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000));
}
static void atmci_queue_request(struct atmel_mci *host,
struct atmel_mci_slot *slot, struct mmc_request *mrq)
{
+ struct device *dev = host->dev;
+
dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
host->state);
@@ -1218,7 +1364,7 @@ static void atmci_queue_request(struct atmel_mci *host,
host->state = STATE_SENDING_CMD;
atmci_start_request(host, slot);
} else {
- dev_dbg(&host->pdev->dev, "queue request\n");
+ dev_dbg(dev, "queue request\n");
list_add_tail(&slot->queue_node, &host->queue);
}
spin_unlock_bh(&host->lock);
@@ -1228,10 +1374,11 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct atmel_mci_slot *slot = mmc_priv(mmc);
struct atmel_mci *host = slot->host;
+ struct device *dev = host->dev;
struct mmc_data *data;
WARN_ON(slot->mrq);
- dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
+ dev_dbg(dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
/*
* We may "know" the card is gone even though there's still an
@@ -1271,15 +1418,17 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
case MMC_BUS_WIDTH_4:
slot->sdc_reg |= ATMCI_SDCBUS_4BIT;
break;
+ case MMC_BUS_WIDTH_8:
+ slot->sdc_reg |= ATMCI_SDCBUS_8BIT;
+ break;
}
if (ios->clock) {
unsigned int clock_min = ~0U;
- u32 clkdiv;
+ int clkdiv;
spin_lock_bh(&host->lock);
if (!host->mode_reg) {
- clk_enable(host->mck);
atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
if (host->caps.has_cfg_reg)
@@ -1300,7 +1449,12 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* Calculate clock divider */
if (host->caps.has_odd_clk_div) {
clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2;
- if (clkdiv > 511) {
+ if (clkdiv < 0) {
+ dev_warn(&mmc->class_dev,
+ "clock %u too fast; using %lu\n",
+ clock_min, host->bus_hz / 2);
+ clkdiv = 0;
+ } else if (clkdiv > 511) {
dev_warn(&mmc->class_dev,
"clock %u too slow; using %lu\n",
clock_min, host->bus_hz / (511 + 2));
@@ -1359,7 +1513,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
if (host->mode_reg) {
atmci_readl(host, ATMCI_MR);
- clk_disable(host->mck);
}
host->mode_reg = 0;
}
@@ -1367,22 +1520,16 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ if (!IS_ERR(mmc->supply.vmmc))
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+ break;
case MMC_POWER_UP:
set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
+ if (!IS_ERR(mmc->supply.vmmc))
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
break;
default:
- /*
- * TODO: None of the currently available AVR32-based
- * boards allow MMC power to be turned off. Implement
- * power control when this can be tested properly.
- *
- * We also need to hook this into the clock management
- * somehow so that newly inserted cards aren't
- * subjected to a fast clock before we have a chance
- * to figure out what the maximum rate is. Currently,
- * there's no way to avoid this, and there never will
- * be for boards that don't support power control.
- */
break;
}
}
@@ -1392,8 +1539,8 @@ static int atmci_get_ro(struct mmc_host *mmc)
int read_only = -ENOSYS;
struct atmel_mci_slot *slot = mmc_priv(mmc);
- if (gpio_is_valid(slot->wp_pin)) {
- read_only = gpio_get_value(slot->wp_pin);
+ if (slot->wp_pin) {
+ read_only = gpiod_get_value(slot->wp_pin);
dev_dbg(&mmc->class_dev, "card is %s\n",
read_only ? "read-only" : "read-write");
}
@@ -1406,9 +1553,8 @@ static int atmci_get_cd(struct mmc_host *mmc)
int present = -ENOSYS;
struct atmel_mci_slot *slot = mmc_priv(mmc);
- if (gpio_is_valid(slot->detect_pin)) {
- present = !(gpio_get_value(slot->detect_pin) ^
- slot->detect_is_active_high);
+ if (slot->detect_pin) {
+ present = gpiod_get_value_cansleep(slot->detect_pin);
dev_dbg(&mmc->class_dev, "card is %spresent\n",
present ? "" : "not ");
}
@@ -1442,9 +1588,12 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
{
struct atmel_mci_slot *slot = NULL;
struct mmc_host *prev_mmc = host->cur_slot->mmc;
+ struct device *dev = host->dev;
WARN_ON(host->cmd || host->data);
+ timer_delete(&host->timer);
+
/*
* Update the MMC clock rate if necessary. This may be
* necessary if set_ios() is called when a different slot is
@@ -1462,17 +1611,14 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
slot = list_entry(host->queue.next,
struct atmel_mci_slot, queue_node);
list_del(&slot->queue_node);
- dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
- mmc_hostname(slot->mmc));
+ dev_vdbg(dev, "list not empty: %s is next\n", mmc_hostname(slot->mmc));
host->state = STATE_SENDING_CMD;
atmci_start_request(host, slot);
} else {
- dev_vdbg(&host->pdev->dev, "list empty\n");
+ dev_vdbg(dev, "list empty\n");
host->state = STATE_IDLE;
}
- del_timer(&host->timer);
-
spin_unlock(&host->lock);
mmc_request_done(prev_mmc, mrq);
spin_lock(&host->lock);
@@ -1504,9 +1650,10 @@ static void atmci_command_complete(struct atmel_mci *host,
cmd->error = 0;
}
-static void atmci_detect_change(unsigned long data)
+static void atmci_detect_change(struct timer_list *t)
{
- struct atmel_mci_slot *slot = (struct atmel_mci_slot *)data;
+ struct atmel_mci_slot *slot = timer_container_of(slot, t,
+ detect_timer);
bool present;
bool present_old;
@@ -1520,9 +1667,8 @@ static void atmci_detect_change(unsigned long data)
if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
return;
- enable_irq(gpio_to_irq(slot->detect_pin));
- present = !(gpio_get_value(slot->detect_pin) ^
- slot->detect_is_active_high);
+ enable_irq(gpiod_to_irq(slot->detect_pin));
+ present = gpiod_get_value_cansleep(slot->detect_pin);
present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
@@ -1601,11 +1747,12 @@ static void atmci_detect_change(unsigned long data)
}
}
-static void atmci_tasklet_func(unsigned long priv)
+static void atmci_work_func(struct work_struct *t)
{
- struct atmel_mci *host = (struct atmel_mci *)priv;
+ struct atmel_mci *host = from_work(host, t, bh_work);
struct mmc_request *mrq = host->mrq;
struct mmc_data *data = host->data;
+ struct device *dev = host->dev;
enum atmel_mci_state state = host->state;
enum atmel_mci_state prev_state;
u32 status;
@@ -1614,14 +1761,13 @@ static void atmci_tasklet_func(unsigned long priv)
state = host->state;
- dev_vdbg(&host->pdev->dev,
- "tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
+ dev_vdbg(dev, "bh_work: state %u pending/completed/mask %lx/%lx/%x\n",
state, host->pending_events, host->completed_events,
atmci_readl(host, ATMCI_IMR));
do {
prev_state = state;
- dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state);
+ dev_dbg(dev, "FSM: state=%d\n", state);
switch (state) {
case STATE_IDLE:
@@ -1634,18 +1780,17 @@ static void atmci_tasklet_func(unsigned long priv)
* END_REQUEST by default, WAITING_NOTBUSY if it's a
* command needing it or DATA_XFER if there is data.
*/
- dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
+ dev_dbg(dev, "FSM: cmd ready?\n");
if (!atmci_test_and_clear_pending(host,
EVENT_CMD_RDY))
break;
- dev_dbg(&host->pdev->dev, "set completed cmd ready\n");
+ dev_dbg(dev, "set completed cmd ready\n");
host->cmd = NULL;
atmci_set_completed(host, EVENT_CMD_RDY);
atmci_command_complete(host, mrq->cmd);
if (mrq->data) {
- dev_dbg(&host->pdev->dev,
- "command with data transfer");
+ dev_dbg(dev, "command with data transfer\n");
/*
* If there is a command error don't start
* data transfer.
@@ -1660,8 +1805,7 @@ static void atmci_tasklet_func(unsigned long priv)
} else
state = STATE_DATA_XFER;
} else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) {
- dev_dbg(&host->pdev->dev,
- "command response need waiting notbusy");
+ dev_dbg(dev, "command response need waiting notbusy\n");
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
state = STATE_WAITING_NOTBUSY;
} else
@@ -1672,7 +1816,7 @@ static void atmci_tasklet_func(unsigned long priv)
case STATE_DATA_XFER:
if (atmci_test_and_clear_pending(host,
EVENT_DATA_ERROR)) {
- dev_dbg(&host->pdev->dev, "set completed data error\n");
+ dev_dbg(dev, "set completed data error\n");
atmci_set_completed(host, EVENT_DATA_ERROR);
state = STATE_END_REQUEST;
break;
@@ -1685,14 +1829,12 @@ static void atmci_tasklet_func(unsigned long priv)
* to the next step which is WAITING_NOTBUSY in write
* case and directly SENDING_STOP in read case.
*/
- dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n");
+ dev_dbg(dev, "FSM: xfer complete?\n");
if (!atmci_test_and_clear_pending(host,
EVENT_XFER_COMPLETE))
break;
- dev_dbg(&host->pdev->dev,
- "(%s) set completed xfer complete\n",
- __func__);
+ dev_dbg(dev, "(%s) set completed xfer complete\n", __func__);
atmci_set_completed(host, EVENT_XFER_COMPLETE);
if (host->caps.need_notbusy_for_read_ops ||
@@ -1700,7 +1842,6 @@ static void atmci_tasklet_func(unsigned long priv)
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
state = STATE_WAITING_NOTBUSY;
} else if (host->mrq->stop) {
- atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
atmci_send_stop_cmd(host, data);
state = STATE_SENDING_STOP;
} else {
@@ -1718,12 +1859,12 @@ static void atmci_tasklet_func(unsigned long priv)
* included) or a write operation. In the latest case,
* we need to send a stop command.
*/
- dev_dbg(&host->pdev->dev, "FSM: not busy?\n");
+ dev_dbg(dev, "FSM: not busy?\n");
if (!atmci_test_and_clear_pending(host,
EVENT_NOTBUSY))
break;
- dev_dbg(&host->pdev->dev, "set completed not busy\n");
+ dev_dbg(dev, "set completed not busy\n");
atmci_set_completed(host, EVENT_NOTBUSY);
if (host->data) {
@@ -1733,8 +1874,6 @@ static void atmci_tasklet_func(unsigned long priv)
* command to send.
*/
if (host->mrq->stop) {
- atmci_writel(host, ATMCI_IER,
- ATMCI_CMDRDY);
atmci_send_stop_cmd(host, data);
state = STATE_SENDING_STOP;
} else {
@@ -1755,12 +1894,12 @@ static void atmci_tasklet_func(unsigned long priv)
* in order to go to the end request state instead of
* sending stop again.
*/
- dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
+ dev_dbg(dev, "FSM: cmd ready?\n");
if (!atmci_test_and_clear_pending(host,
EVENT_CMD_RDY))
break;
- dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
+ dev_dbg(dev, "FSM: cmd ready\n");
host->cmd = NULL;
data->bytes_xfered = data->blocks * data->blksz;
data->error = 0;
@@ -1785,30 +1924,32 @@ static void atmci_tasklet_func(unsigned long priv)
if (unlikely(status)) {
host->stop_transfer(host);
host->data = NULL;
- if (status & ATMCI_DTOE) {
- data->error = -ETIMEDOUT;
- } else if (status & ATMCI_DCRCE) {
- data->error = -EILSEQ;
- } else {
- data->error = -EIO;
+ if (data) {
+ if (status & ATMCI_DTOE) {
+ data->error = -ETIMEDOUT;
+ } else if (status & ATMCI_DCRCE) {
+ data->error = -EILSEQ;
+ } else {
+ data->error = -EIO;
+ }
}
}
atmci_request_end(host, host->mrq);
- state = STATE_IDLE;
+ goto unlock; /* atmci_request_end() sets host->state */
break;
}
} while (state != prev_state);
host->state = state;
+unlock:
spin_unlock(&host->lock);
}
static void atmci_read_data_pio(struct atmel_mci *host)
{
struct scatterlist *sg = host->sg;
- void *buf = sg_virt(sg);
unsigned int offset = host->pio_offset;
struct mmc_data *data = host->data;
u32 value;
@@ -1818,7 +1959,7 @@ static void atmci_read_data_pio(struct atmel_mci *host)
do {
value = atmci_readl(host, ATMCI_RDR);
if (likely(offset + 4 <= sg->length)) {
- put_unaligned(value, (u32 *)(buf + offset));
+ sg_pcopy_from_buffer(sg, 1, &value, sizeof(u32), offset);
offset += 4;
nbytes += 4;
@@ -1831,11 +1972,11 @@ static void atmci_read_data_pio(struct atmel_mci *host)
goto done;
offset = 0;
- buf = sg_virt(sg);
}
} else {
unsigned int remaining = sg->length - offset;
- memcpy(buf + offset, &value, remaining);
+
+ sg_pcopy_from_buffer(sg, 1, &value, remaining, offset);
nbytes += remaining;
flush_dcache_page(sg_page(sg));
@@ -1845,8 +1986,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
goto done;
offset = 4 - remaining;
- buf = sg_virt(sg);
- memcpy(buf, (u8 *)&value + remaining, offset);
+ sg_pcopy_from_buffer(sg, 1, (u8 *)&value + remaining,
+ offset, 0);
nbytes += offset;
}
@@ -1876,7 +2017,6 @@ done:
static void atmci_write_data_pio(struct atmel_mci *host)
{
struct scatterlist *sg = host->sg;
- void *buf = sg_virt(sg);
unsigned int offset = host->pio_offset;
struct mmc_data *data = host->data;
u32 value;
@@ -1885,7 +2025,7 @@ static void atmci_write_data_pio(struct atmel_mci *host)
do {
if (likely(offset + 4 <= sg->length)) {
- value = get_unaligned((u32 *)(buf + offset));
+ sg_pcopy_to_buffer(sg, 1, &value, sizeof(u32), offset);
atmci_writel(host, ATMCI_TDR, value);
offset += 4;
@@ -1897,13 +2037,12 @@ static void atmci_write_data_pio(struct atmel_mci *host)
goto done;
offset = 0;
- buf = sg_virt(sg);
}
} else {
unsigned int remaining = sg->length - offset;
value = 0;
- memcpy(&value, buf + offset, remaining);
+ sg_pcopy_to_buffer(sg, 1, &value, remaining, offset);
nbytes += remaining;
host->sg = sg = sg_next(sg);
@@ -1914,8 +2053,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
}
offset = 4 - remaining;
- buf = sg_virt(sg);
- memcpy((u8 *)&value + remaining, buf, offset);
+ sg_pcopy_to_buffer(sg, 1, (u8 *)&value + remaining,
+ offset, 0);
atmci_writel(host, ATMCI_TDR, value);
nbytes += offset;
}
@@ -1959,6 +2098,7 @@ static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
static irqreturn_t atmci_interrupt(int irq, void *dev_id)
{
struct atmel_mci *host = dev_id;
+ struct device *dev = host->dev;
u32 status, mask, pending;
unsigned int pass_count = 0;
@@ -1970,21 +2110,21 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
break;
if (pending & ATMCI_DATA_ERROR_FLAGS) {
- dev_dbg(&host->pdev->dev, "IRQ: data error\n");
+ dev_dbg(dev, "IRQ: data error\n");
atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
| ATMCI_RXRDY | ATMCI_TXRDY
| ATMCI_ENDRX | ATMCI_ENDTX
| ATMCI_RXBUFF | ATMCI_TXBUFE);
host->data_status = status;
- dev_dbg(&host->pdev->dev, "set pending data error\n");
+ dev_dbg(dev, "set pending data error\n");
smp_wmb();
atmci_set_pending(host, EVENT_DATA_ERROR);
- tasklet_schedule(&host->tasklet);
+ queue_work(system_bh_wq, &host->bh_work);
}
if (pending & ATMCI_TXBUFE) {
- dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n");
+ dev_dbg(dev, "IRQ: tx buffer empty\n");
atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE);
atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
/*
@@ -2000,7 +2140,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
atmci_pdc_complete(host);
}
} else if (pending & ATMCI_ENDTX) {
- dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n");
+ dev_dbg(dev, "IRQ: end of tx buffer\n");
atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
if (host->data_size) {
@@ -2011,7 +2151,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
}
if (pending & ATMCI_RXBUFF) {
- dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n");
+ dev_dbg(dev, "IRQ: rx buffer full\n");
atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF);
atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
/*
@@ -2027,7 +2167,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
atmci_pdc_complete(host);
}
} else if (pending & ATMCI_ENDRX) {
- dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n");
+ dev_dbg(dev, "IRQ: end of rx buffer\n");
atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
if (host->data_size) {
@@ -2044,21 +2184,21 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
* The appropriate workaround is to use the BLKE signal.
*/
if (pending & ATMCI_BLKE) {
- dev_dbg(&host->pdev->dev, "IRQ: blke\n");
+ dev_dbg(dev, "IRQ: blke\n");
atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);
smp_wmb();
- dev_dbg(&host->pdev->dev, "set pending notbusy\n");
+ dev_dbg(dev, "set pending notbusy\n");
atmci_set_pending(host, EVENT_NOTBUSY);
- tasklet_schedule(&host->tasklet);
+ queue_work(system_bh_wq, &host->bh_work);
}
if (pending & ATMCI_NOTBUSY) {
- dev_dbg(&host->pdev->dev, "IRQ: not_busy\n");
+ dev_dbg(dev, "IRQ: not_busy\n");
atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY);
smp_wmb();
- dev_dbg(&host->pdev->dev, "set pending notbusy\n");
+ dev_dbg(dev, "set pending notbusy\n");
atmci_set_pending(host, EVENT_NOTBUSY);
- tasklet_schedule(&host->tasklet);
+ queue_work(system_bh_wq, &host->bh_work);
}
if (pending & ATMCI_RXRDY)
@@ -2067,13 +2207,13 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
atmci_write_data_pio(host);
if (pending & ATMCI_CMDRDY) {
- dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n");
+ dev_dbg(dev, "IRQ: cmd ready\n");
atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
host->cmd_status = status;
smp_wmb();
- dev_dbg(&host->pdev->dev, "set pending cmd rdy\n");
+ dev_dbg(dev, "set pending cmd rdy\n");
atmci_set_pending(host, EVENT_CMD_RDY);
- tasklet_schedule(&host->tasklet);
+ queue_work(system_bh_wq, &host->bh_work);
}
if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
@@ -2099,14 +2239,16 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int __init atmci_init_slot(struct atmel_mci *host,
+static int atmci_init_slot(struct atmel_mci *host,
struct mci_slot_pdata *slot_data, unsigned int id,
u32 sdc_reg, u32 sdio_irq)
{
+ struct device *dev = host->dev;
struct mmc_host *mmc;
struct atmel_mci_slot *slot;
+ int ret;
- mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
+ mmc = devm_mmc_alloc_host(dev, sizeof(*slot));
if (!mmc)
return -ENOMEM;
@@ -2115,16 +2257,15 @@ static int __init atmci_init_slot(struct atmel_mci *host,
slot->host = host;
slot->detect_pin = slot_data->detect_pin;
slot->wp_pin = slot_data->wp_pin;
- slot->detect_is_active_high = slot_data->detect_is_active_high;
slot->sdc_reg = sdc_reg;
slot->sdio_irq = sdio_irq;
dev_dbg(&mmc->class_dev,
"slot[%u]: bus_width=%u, detect_pin=%d, "
"detect_is_active_high=%s, wp_pin=%d\n",
- id, slot_data->bus_width, slot_data->detect_pin,
- slot_data->detect_is_active_high ? "true" : "false",
- slot_data->wp_pin);
+ id, slot_data->bus_width, desc_to_gpio(slot_data->detect_pin),
+ str_true_false(!gpiod_is_active_low(slot_data->detect_pin)),
+ desc_to_gpio(slot_data->wp_pin));
mmc->ops = &atmci_ops;
mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
@@ -2139,8 +2280,11 @@ static int __init atmci_init_slot(struct atmel_mci *host,
* use only one bit for data to prevent fifo underruns and overruns
* which will corrupt data.
*/
- if ((slot_data->bus_width >= 4) && host->caps.has_rwproof)
+ if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) {
mmc->caps |= MMC_CAP_4_BIT_DATA;
+ if (slot_data->bus_width >= 8)
+ mmc->caps |= MMC_CAP_8_BIT_DATA;
+ }
if (atmci_get_version(host) < 0x200) {
mmc->max_segs = 256;
@@ -2157,45 +2301,41 @@ static int __init atmci_init_slot(struct atmel_mci *host,
/* Assume card is present initially */
set_bit(ATMCI_CARD_PRESENT, &slot->flags);
- if (gpio_is_valid(slot->detect_pin)) {
- if (gpio_request(slot->detect_pin, "mmc_detect")) {
- dev_dbg(&mmc->class_dev, "no detect pin available\n");
- slot->detect_pin = -EBUSY;
- } else if (gpio_get_value(slot->detect_pin) ^
- slot->detect_is_active_high) {
+ if (slot->detect_pin) {
+ if (!gpiod_get_value_cansleep(slot->detect_pin))
clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
- }
+ } else {
+ dev_dbg(&mmc->class_dev, "no detect pin available\n");
}
- if (!gpio_is_valid(slot->detect_pin))
- mmc->caps |= MMC_CAP_NEEDS_POLL;
-
- if (gpio_is_valid(slot->wp_pin)) {
- if (gpio_request(slot->wp_pin, "mmc_wp")) {
- dev_dbg(&mmc->class_dev, "no WP pin available\n");
- slot->wp_pin = -EBUSY;
- }
+ if (!slot->detect_pin) {
+ if (slot_data->non_removable)
+ mmc->caps |= MMC_CAP_NONREMOVABLE;
+ else
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
}
- host->slot[id] = slot;
- mmc_add_host(mmc);
+ if (!slot->wp_pin)
+ dev_dbg(&mmc->class_dev, "no WP pin available\n");
- if (gpio_is_valid(slot->detect_pin)) {
- int ret;
+ host->slot[id] = slot;
+ mmc_regulator_get_supply(mmc);
+ ret = mmc_add_host(mmc);
+ if (ret)
+ return ret;
- setup_timer(&slot->detect_timer, atmci_detect_change,
- (unsigned long)slot);
+ if (slot->detect_pin) {
+ timer_setup(&slot->detect_timer, atmci_detect_change, 0);
- ret = request_irq(gpio_to_irq(slot->detect_pin),
- atmci_detect_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "mmc-detect", slot);
+ ret = request_irq(gpiod_to_irq(slot->detect_pin),
+ atmci_detect_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "mmc-detect", slot);
if (ret) {
dev_dbg(&mmc->class_dev,
"could not request IRQ %d for detect pin\n",
- gpio_to_irq(slot->detect_pin));
- gpio_free(slot->detect_pin);
- slot->detect_pin = -EBUSY;
+ gpiod_to_irq(slot->detect_pin));
+ slot->detect_pin = NULL;
}
}
@@ -2204,7 +2344,7 @@ static int __init atmci_init_slot(struct atmel_mci *host,
return 0;
}
-static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
+static void atmci_cleanup_slot(struct atmel_mci_slot *slot,
unsigned int id)
{
/* Debugfs stuff is cleaned up by mmc core */
@@ -2214,69 +2354,33 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
mmc_remove_host(slot->mmc);
- if (gpio_is_valid(slot->detect_pin)) {
- int pin = slot->detect_pin;
-
- free_irq(gpio_to_irq(pin), slot);
- del_timer_sync(&slot->detect_timer);
- gpio_free(pin);
+ if (slot->detect_pin) {
+ free_irq(gpiod_to_irq(slot->detect_pin), slot);
+ timer_delete_sync(&slot->detect_timer);
}
- if (gpio_is_valid(slot->wp_pin))
- gpio_free(slot->wp_pin);
slot->host->slot[id] = NULL;
- mmc_free_host(slot->mmc);
-}
-
-static bool atmci_filter(struct dma_chan *chan, void *pdata)
-{
- struct mci_platform_data *sl_pdata = pdata;
- struct mci_dma_data *sl;
-
- if (!sl_pdata)
- return false;
-
- sl = sl_pdata->dma_slave;
- if (sl && find_slave_dev(sl) == chan->device->dev) {
- chan->private = slave_data_ptr(sl);
- return true;
- } else {
- return false;
- }
}
-static bool atmci_configure_dma(struct atmel_mci *host)
+static int atmci_configure_dma(struct atmel_mci *host)
{
- struct mci_platform_data *pdata;
- dma_cap_mask_t mask;
+ struct device *dev = host->dev;
- if (host == NULL)
- return false;
+ host->dma.chan = dma_request_chan(dev, "rxtx");
+ if (IS_ERR(host->dma.chan))
+ return PTR_ERR(host->dma.chan);
- pdata = host->pdev->dev.platform_data;
+ dev_info(dev, "using %s for DMA transfers\n", dma_chan_name(host->dma.chan));
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
+ host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
+ host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_conf.src_maxburst = 1;
+ host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
+ host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_conf.dst_maxburst = 1;
+ host->dma_conf.device_fc = false;
- host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata,
- &host->pdev->dev, "rxtx");
- if (!host->dma.chan) {
- dev_warn(&host->pdev->dev, "no DMA channel available\n");
- return false;
- } else {
- dev_info(&host->pdev->dev,
- "using %s for DMA transfers\n",
- dma_chan_name(host->dma.chan));
-
- host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
- host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- host->dma_conf.src_maxburst = 1;
- host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
- host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- host->dma_conf.dst_maxburst = 1;
- host->dma_conf.device_fc = false;
- return true;
- }
+ return 0;
}
/*
@@ -2284,124 +2388,130 @@ static bool atmci_configure_dma(struct atmel_mci *host)
* HSMCI provides DMA support and a new config register but no more supports
* PDC.
*/
-static void __init atmci_get_cap(struct atmel_mci *host)
+static void atmci_get_cap(struct atmel_mci *host)
{
+ struct device *dev = host->dev;
unsigned int version;
version = atmci_get_version(host);
- dev_info(&host->pdev->dev,
- "version: 0x%x\n", version);
-
- host->caps.has_dma_conf_reg = 0;
- host->caps.has_pdc = ATMCI_PDC_CONNECTED;
- host->caps.has_cfg_reg = 0;
- host->caps.has_cstor_reg = 0;
- host->caps.has_highspeed = 0;
- host->caps.has_rwproof = 0;
- host->caps.has_odd_clk_div = 0;
- host->caps.has_bad_data_ordering = 1;
- host->caps.need_reset_after_xfer = 1;
- host->caps.need_blksz_mul_4 = 1;
- host->caps.need_notbusy_for_read_ops = 0;
+ dev_info(dev, "version: 0x%x\n", version);
+
+ host->caps.has_dma_conf_reg = false;
+ host->caps.has_pdc = true;
+ host->caps.has_cfg_reg = false;
+ host->caps.has_cstor_reg = false;
+ host->caps.has_highspeed = false;
+ host->caps.has_rwproof = false;
+ host->caps.has_odd_clk_div = false;
+ host->caps.has_bad_data_ordering = true;
+ host->caps.need_reset_after_xfer = true;
+ host->caps.need_blksz_mul_4 = true;
+ host->caps.need_notbusy_for_read_ops = false;
/* keep only major version number */
switch (version & 0xf00) {
+ case 0x600:
case 0x500:
- host->caps.has_odd_clk_div = 1;
+ host->caps.has_odd_clk_div = true;
+ fallthrough;
case 0x400:
case 0x300:
- host->caps.has_dma_conf_reg = 1;
- host->caps.has_pdc = 0;
- host->caps.has_cfg_reg = 1;
- host->caps.has_cstor_reg = 1;
- host->caps.has_highspeed = 1;
+ host->caps.has_dma_conf_reg = true;
+ host->caps.has_pdc = false;
+ host->caps.has_cfg_reg = true;
+ host->caps.has_cstor_reg = true;
+ host->caps.has_highspeed = true;
+ fallthrough;
case 0x200:
- host->caps.has_rwproof = 1;
- host->caps.need_blksz_mul_4 = 0;
- host->caps.need_notbusy_for_read_ops = 1;
+ host->caps.has_rwproof = true;
+ host->caps.need_blksz_mul_4 = false;
+ host->caps.need_notbusy_for_read_ops = true;
+ fallthrough;
case 0x100:
- host->caps.has_bad_data_ordering = 0;
- host->caps.need_reset_after_xfer = 0;
+ host->caps.has_bad_data_ordering = false;
+ host->caps.need_reset_after_xfer = false;
+ fallthrough;
case 0x0:
break;
default:
- host->caps.has_pdc = 0;
- dev_warn(&host->pdev->dev,
- "Unmanaged mci version, set minimum capabilities\n");
+ host->caps.has_pdc = false;
+ dev_warn(dev, "Unmanaged mci version, set minimum capabilities\n");
break;
}
}
-static int __init atmci_probe(struct platform_device *pdev)
+static int atmci_probe(struct platform_device *pdev)
{
- struct mci_platform_data *pdata;
+ struct device *dev = &pdev->dev;
struct atmel_mci *host;
struct resource *regs;
unsigned int nr_slots;
int irq;
- int ret;
+ int ret, i;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return -ENXIO;
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- pdata = atmci_of_init(pdev);
- if (IS_ERR(pdata)) {
- dev_err(&pdev->dev, "platform data not available\n");
- return PTR_ERR(pdata);
- }
- }
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host)
return -ENOMEM;
- host->pdev = pdev;
+ host->dev = dev;
spin_lock_init(&host->lock);
INIT_LIST_HEAD(&host->queue);
- host->mck = clk_get(&pdev->dev, "mci_clk");
- if (IS_ERR(host->mck)) {
- ret = PTR_ERR(host->mck);
- goto err_clk_get;
- }
+ ret = atmci_of_init(host);
+ if (ret)
+ return dev_err_probe(dev, ret, "Slot information not available\n");
- ret = -ENOMEM;
- host->regs = ioremap(regs->start, resource_size(regs));
+ host->mck = devm_clk_get(dev, "mci_clk");
+ if (IS_ERR(host->mck))
+ return PTR_ERR(host->mck);
+
+ host->regs = devm_ioremap(dev, regs->start, resource_size(regs));
if (!host->regs)
- goto err_ioremap;
+ return -ENOMEM;
+
+ ret = clk_prepare_enable(host->mck);
+ if (ret)
+ return ret;
- clk_enable(host->mck);
atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
host->bus_hz = clk_get_rate(host->mck);
- clk_disable(host->mck);
host->mapbase = regs->start;
- tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
+ INIT_WORK(&host->bh_work, atmci_work_func);
- ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
- if (ret)
- goto err_request_irq;
+ ret = request_irq(irq, atmci_interrupt, 0, dev_name(dev), host);
+ if (ret) {
+ clk_disable_unprepare(host->mck);
+ return ret;
+ }
/* Get MCI capabilities and set operations according to it */
atmci_get_cap(host);
- if (atmci_configure_dma(host)) {
+ ret = atmci_configure_dma(host);
+ if (ret == -EPROBE_DEFER) {
+ clk_disable_unprepare(host->mck);
+ goto err_dma_probe_defer;
+ }
+ if (ret == 0) {
host->prepare_data = &atmci_prepare_data_dma;
host->submit_data = &atmci_submit_data_dma;
host->stop_transfer = &atmci_stop_transfer_dma;
} else if (host->caps.has_pdc) {
- dev_info(&pdev->dev, "using PDC\n");
+ dev_info(dev, "using PDC\n");
host->prepare_data = &atmci_prepare_data_pdc;
host->submit_data = &atmci_submit_data_pdc;
host->stop_transfer = &atmci_stop_transfer_pdc;
} else {
- dev_info(&pdev->dev, "using PIO\n");
+ dev_info(dev, "using PIO\n");
host->prepare_data = &atmci_prepare_data;
host->submit_data = &atmci_submit_data;
host->stop_transfer = &atmci_stop_transfer;
@@ -2409,21 +2519,27 @@ static int __init atmci_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host);
- setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
+ timer_setup(&host->timer, atmci_timeout_timer, 0);
+
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_enable(dev);
/* We need at least one slot to succeed */
nr_slots = 0;
ret = -ENODEV;
- if (pdata->slot[0].bus_width) {
- ret = atmci_init_slot(host, &pdata->slot[0],
+ if (host->pdata[0].bus_width) {
+ ret = atmci_init_slot(host, &host->pdata[0],
0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA);
if (!ret) {
nr_slots++;
host->buf_size = host->slot[0]->mmc->max_req_size;
}
}
- if (pdata->slot[1].bus_width) {
- ret = atmci_init_slot(host, &pdata->slot[1],
+ if (host->pdata[1].bus_width) {
+ ret = atmci_init_slot(host, &host->pdata[1],
1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB);
if (!ret) {
nr_slots++;
@@ -2434,152 +2550,114 @@ static int __init atmci_probe(struct platform_device *pdev)
}
if (!nr_slots) {
- dev_err(&pdev->dev, "init failed: no slot defined\n");
+ dev_err_probe(dev, ret, "init failed: no slot defined\n");
goto err_init_slot;
}
if (!host->caps.has_rwproof) {
- host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size,
+ host->buffer = dma_alloc_coherent(dev, host->buf_size,
&host->buf_phys_addr,
GFP_KERNEL);
if (!host->buffer) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "buffer allocation failed\n");
- goto err_init_slot;
+ ret = dev_err_probe(dev, -ENOMEM, "buffer allocation failed\n");
+ goto err_dma_alloc;
}
}
- dev_info(&pdev->dev,
- "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
- host->mapbase, irq, nr_slots);
+ dev_info(dev, "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+ host->mapbase, irq, nr_slots);
+
+ pm_runtime_put_autosuspend(dev);
return 0;
+err_dma_alloc:
+ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+ if (host->slot[i])
+ atmci_cleanup_slot(host->slot[i], i);
+ }
err_init_slot:
- if (host->dma.chan)
+ clk_disable_unprepare(host->mck);
+
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+
+ timer_delete_sync(&host->timer);
+ if (!IS_ERR(host->dma.chan))
dma_release_channel(host->dma.chan);
+err_dma_probe_defer:
free_irq(irq, host);
-err_request_irq:
- iounmap(host->regs);
-err_ioremap:
- clk_put(host->mck);
-err_clk_get:
- kfree(host);
return ret;
}
-static int __exit atmci_remove(struct platform_device *pdev)
+static void atmci_remove(struct platform_device *pdev)
{
struct atmel_mci *host = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
unsigned int i;
+ pm_runtime_get_sync(dev);
+
if (host->buffer)
- dma_free_coherent(&pdev->dev, host->buf_size,
- host->buffer, host->buf_phys_addr);
+ dma_free_coherent(dev, host->buf_size, host->buffer, host->buf_phys_addr);
for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
if (host->slot[i])
atmci_cleanup_slot(host->slot[i], i);
}
- clk_enable(host->mck);
atmci_writel(host, ATMCI_IDR, ~0UL);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
atmci_readl(host, ATMCI_SR);
- clk_disable(host->mck);
- if (host->dma.chan)
+ timer_delete_sync(&host->timer);
+ if (!IS_ERR(host->dma.chan))
dma_release_channel(host->dma.chan);
free_irq(platform_get_irq(pdev, 0), host);
- iounmap(host->regs);
- clk_put(host->mck);
- kfree(host);
+ clk_disable_unprepare(host->mck);
- return 0;
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
}
-#ifdef CONFIG_PM_SLEEP
-static int atmci_suspend(struct device *dev)
+static int atmci_runtime_suspend(struct device *dev)
{
struct atmel_mci *host = dev_get_drvdata(dev);
- int i;
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- struct atmel_mci_slot *slot = host->slot[i];
- int ret;
+ clk_disable_unprepare(host->mck);
- if (!slot)
- continue;
- ret = mmc_suspend_host(slot->mmc);
- if (ret < 0) {
- while (--i >= 0) {
- slot = host->slot[i];
- if (slot
- && test_bit(ATMCI_SUSPENDED, &slot->flags)) {
- mmc_resume_host(host->slot[i]->mmc);
- clear_bit(ATMCI_SUSPENDED, &slot->flags);
- }
- }
- return ret;
- } else {
- set_bit(ATMCI_SUSPENDED, &slot->flags);
- }
- }
+ pinctrl_pm_select_sleep_state(dev);
return 0;
}
-static int atmci_resume(struct device *dev)
+static int atmci_runtime_resume(struct device *dev)
{
struct atmel_mci *host = dev_get_drvdata(dev);
- int i;
- int ret = 0;
-
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- struct atmel_mci_slot *slot = host->slot[i];
- int err;
- slot = host->slot[i];
- if (!slot)
- continue;
- if (!test_bit(ATMCI_SUSPENDED, &slot->flags))
- continue;
- err = mmc_resume_host(slot->mmc);
- if (err < 0)
- ret = err;
- else
- clear_bit(ATMCI_SUSPENDED, &slot->flags);
- }
+ pinctrl_select_default_state(dev);
- return ret;
+ return clk_prepare_enable(host->mck);
}
-#endif
-static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
+static const struct dev_pm_ops atmci_dev_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL)
+};
static struct platform_driver atmci_driver = {
- .remove = __exit_p(atmci_remove),
+ .probe = atmci_probe,
+ .remove = atmci_remove,
.driver = {
.name = "atmel_mci",
- .pm = &atmci_pm,
- .of_match_table = of_match_ptr(atmci_dt_ids),
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = atmci_dt_ids,
+ .pm = pm_ptr(&atmci_dev_pm_ops),
},
};
-
-static int __init atmci_init(void)
-{
- return platform_driver_probe(&atmci_driver, atmci_probe);
-}
-
-static void __exit atmci_exit(void)
-{
- platform_driver_unregister(&atmci_driver);
-}
-
-late_initcall(atmci_init); /* try to load after dma driver when built-in */
-module_exit(atmci_exit);
+module_platform_driver(atmci_driver);
MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");