diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2007-02-11 19:57:36 +0100 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-05-01 13:04:17 +0200 |
commit | 1c6a0718f0bfdab0d9b7da5f7b74f38a0058c03a (patch) | |
tree | 5e7f2a26d5d1782d87c596b40f874c6c0b8b8e1a /drivers/mmc/pxamci.c | |
parent | 98ac2162699f7e9880683cb954891817f20b607c (diff) |
mmc: Move host and card drivers to subdirs
Clean up the drivers/mmc directory by moving card and host drivers
into subdirectories.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/pxamci.c')
-rw-r--r-- | drivers/mmc/pxamci.c | 616 |
1 files changed, 0 insertions, 616 deletions
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c deleted file mode 100644 index a98ff98fa56..00000000000 --- a/drivers/mmc/pxamci.c +++ /dev/null @@ -1,616 +0,0 @@ -/* - * linux/drivers/mmc/pxa.c - PXA MMCI driver - * - * Copyright (C) 2003 Russell King, 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 version 2 as - * published by the Free Software Foundation. - * - * This hardware is really sick: - * - No way to clear interrupts. - * - Have to turn off the clock whenever we touch the device. - * - Doesn't tell you how many data blocks were transferred. - * Yuck! - * - * 1 and 3 byte data transfers not supported - * max block length up to 1023 - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/mmc/host.h> - -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/scatterlist.h> -#include <asm/sizes.h> - -#include <asm/arch/pxa-regs.h> -#include <asm/arch/mmc.h> - -#include "pxamci.h" - -#define DRIVER_NAME "pxa2xx-mci" - -#define NR_SG 1 - -struct pxamci_host { - struct mmc_host *mmc; - spinlock_t lock; - struct resource *res; - void __iomem *base; - int irq; - int dma; - unsigned int clkrt; - unsigned int cmdat; - unsigned int imask; - unsigned int power_mode; - struct pxamci_platform_data *pdata; - - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - - dma_addr_t sg_dma; - struct pxa_dma_desc *sg_cpu; - unsigned int dma_len; - - unsigned int dma_dir; -}; - -static void pxamci_stop_clock(struct pxamci_host *host) -{ - if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { - unsigned long timeout = 10000; - unsigned int v; - - writel(STOP_CLOCK, host->base + MMC_STRPCL); - - do { - v = readl(host->base + MMC_STAT); - if (!(v & STAT_CLK_EN)) - break; - udelay(1); - } while (timeout--); - - if (v & STAT_CLK_EN) - dev_err(mmc_dev(host->mmc), "unable to stop clock\n"); - } -} - -static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - host->imask &= ~mask; - writel(host->imask, host->base + MMC_I_MASK); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - host->imask |= mask; - writel(host->imask, host->base + MMC_I_MASK); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) -{ - unsigned int nob = data->blocks; - unsigned long long clks; - unsigned int timeout; - u32 dcmd; - int i; - - host->data = data; - - if (data->flags & MMC_DATA_STREAM) - nob = 0xffff; - - writel(nob, host->base + MMC_NOB); - writel(data->blksz, host->base + MMC_BLKLEN); - - clks = (unsigned long long)data->timeout_ns * CLOCKRATE; - do_div(clks, 1000000000UL); - timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); - writel((timeout + 255) / 256, host->base + MMC_RDTO); - - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; - DRCMRTXMMC = 0; - DRCMRRXMMC = host->dma | DRCMR_MAPVLD; - } else { - host->dma_dir = DMA_TO_DEVICE; - dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; - DRCMRRXMMC = 0; - DRCMRTXMMC = host->dma | DRCMR_MAPVLD; - } - - dcmd |= DCMD_BURST32 | DCMD_WIDTH1; - - host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - host->dma_dir); - - for (i = 0; i < host->dma_len; i++) { - if (data->flags & MMC_DATA_READ) { - host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; - host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); - } else { - host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); - host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; - } - host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]); - host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * - sizeof(struct pxa_dma_desc); - } - host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP; - wmb(); - - DDADR(host->dma) = host->sg_dma; - DCSR(host->dma) = DCSR_RUN; -} - -static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) -{ - WARN_ON(host->cmd != NULL); - host->cmd = cmd; - - if (cmd->flags & MMC_RSP_BUSY) - cmdat |= CMDAT_BUSY; - -#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) - switch (RSP_TYPE(mmc_resp_type(cmd))) { - case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ - cmdat |= CMDAT_RESP_SHORT; - break; - case RSP_TYPE(MMC_RSP_R3): - cmdat |= CMDAT_RESP_R3; - break; - case RSP_TYPE(MMC_RSP_R2): - cmdat |= CMDAT_RESP_R2; - break; - default: - break; - } - - writel(cmd->opcode, host->base + MMC_CMD); - writel(cmd->arg >> 16, host->base + MMC_ARGH); - writel(cmd->arg & 0xffff, host->base + MMC_ARGL); - writel(cmdat, host->base + MMC_CMDAT); - writel(host->clkrt, host->base + MMC_CLKRT); - - writel(START_CLOCK, host->base + MMC_STRPCL); - - pxamci_enable_irq(host, END_CMD_RES); -} - -static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) -{ - host->mrq = NULL; - host->cmd = NULL; - host->data = NULL; - mmc_request_done(host->mmc, mrq); -} - -static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) -{ - struct mmc_command *cmd = host->cmd; - int i; - u32 v; - - if (!cmd) - return 0; - - host->cmd = NULL; - - /* - * Did I mention this is Sick. We always need to - * discard the upper 8 bits of the first 16-bit word. - */ - v = readl(host->base + MMC_RES) & 0xffff; - for (i = 0; i < 4; i++) { - u32 w1 = readl(host->base + MMC_RES) & 0xffff; - u32 w2 = readl(host->base + MMC_RES) & 0xffff; - cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; - v = w2; - } - - if (stat & STAT_TIME_OUT_RESPONSE) { - cmd->error = MMC_ERR_TIMEOUT; - } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { -#ifdef CONFIG_PXA27x - /* - * workaround for erratum #42: - * Intel PXA27x Family Processor Specification Update Rev 001 - */ - if (cmd->opcode == MMC_ALL_SEND_CID || - cmd->opcode == MMC_SEND_CSD || - cmd->opcode == MMC_SEND_CID) { - /* a bogus CRC error can appear if the msb of - the 15 byte response is a one */ - if ((cmd->resp[0] & 0x80000000) == 0) - cmd->error = MMC_ERR_BADCRC; - } else { - pr_debug("ignoring CRC from command %d - *risky*\n",cmd->opcode); - } -#else - cmd->error = MMC_ERR_BADCRC; -#endif - } - - pxamci_disable_irq(host, END_CMD_RES); - if (host->data && cmd->error == MMC_ERR_NONE) { - pxamci_enable_irq(host, DATA_TRAN_DONE); - } else { - pxamci_finish_request(host, host->mrq); - } - - return 1; -} - -static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - - if (!data) - return 0; - - DCSR(host->dma) = 0; - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, - host->dma_dir); - - if (stat & STAT_READ_TIME_OUT) - data->error = MMC_ERR_TIMEOUT; - else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) - data->error = MMC_ERR_BADCRC; - - /* - * There appears to be a hardware design bug here. There seems to - * be no way to find out how much data was transferred to the card. - * This means that if there was an error on any block, we mark all - * data blocks as being in error. - */ - if (data->error == MMC_ERR_NONE) - data->bytes_xfered = data->blocks * data->blksz; - else - data->bytes_xfered = 0; - - pxamci_disable_irq(host, DATA_TRAN_DONE); - - host->data = NULL; - if (host->mrq->stop) { - pxamci_stop_clock(host); - pxamci_start_cmd(host, host->mrq->stop, 0); - } else { - pxamci_finish_request(host, host->mrq); - } - - return 1; -} - -static irqreturn_t pxamci_irq(int irq, void *devid) -{ - struct pxamci_host *host = devid; - unsigned int ireg; - int handled = 0; - - ireg = readl(host->base + MMC_I_REG); - - if (ireg) { - unsigned stat = readl(host->base + MMC_STAT); - - pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); - - if (ireg & END_CMD_RES) - handled |= pxamci_cmd_done(host, stat); - if (ireg & DATA_TRAN_DONE) - handled |= pxamci_data_done(host, stat); - } - - return IRQ_RETVAL(handled); -} - -static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct pxamci_host *host = mmc_priv(mmc); - unsigned int cmdat; - - WARN_ON(host->mrq != NULL); - - host->mrq = mrq; - - pxamci_stop_clock(host); - - cmdat = host->cmdat; - host->cmdat &= ~CMDAT_INIT; - - if (mrq->data) { - pxamci_setup_data(host, mrq->data); - - cmdat &= ~CMDAT_BUSY; - cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; - if (mrq->data->flags & MMC_DATA_WRITE) - cmdat |= CMDAT_WRITE; - - if (mrq->data->flags & MMC_DATA_STREAM) - cmdat |= CMDAT_STREAM; - } - - pxamci_start_cmd(host, mrq->cmd, cmdat); -} - -static int pxamci_get_ro(struct mmc_host *mmc) -{ - struct pxamci_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->get_ro) - return host->pdata->get_ro(mmc_dev(mmc)); - /* Host doesn't support read only detection so assume writeable */ - return 0; -} - -static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct pxamci_host *host = mmc_priv(mmc); - - if (ios->clock) { - unsigned int clk = CLOCKRATE / ios->clock; - if (CLOCKRATE / clk > ios->clock) - clk <<= 1; - host->clkrt = fls(clk) - 1; - pxa_set_cken(CKEN12_MMC, 1); - - /* - * we write clkrt on the next command - */ - } else { - pxamci_stop_clock(host); - pxa_set_cken(CKEN12_MMC, 0); - } - - if (host->power_mode != ios->power_mode) { - host->power_mode = ios->power_mode; - - if (host->pdata && host->pdata->setpower) - host->pdata->setpower(mmc_dev(mmc), ios->vdd); - - if (ios->power_mode == MMC_POWER_ON) - host->cmdat |= CMDAT_INIT; - } - - pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", - host->clkrt, host->cmdat); -} - -static const struct mmc_host_ops pxamci_ops = { - .request = pxamci_request, - .get_ro = pxamci_get_ro, - .set_ios = pxamci_set_ios, -}; - -static void pxamci_dma_irq(int dma, void *devid) -{ - printk(KERN_ERR "DMA%d: IRQ???\n", dma); - DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; -} - -static irqreturn_t pxamci_detect_irq(int irq, void *devid) -{ - struct pxamci_host *host = mmc_priv(devid); - - mmc_detect_change(devid, host->pdata->detect_delay); - return IRQ_HANDLED; -} - -static int pxamci_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct pxamci_host *host = NULL; - struct resource *r; - int ret, irq; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!r || irq < 0) - return -ENXIO; - - r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); - if (!r) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } - - mmc->ops = &pxamci_ops; - mmc->f_min = CLOCKRATE_MIN; - mmc->f_max = CLOCKRATE_MAX; - - /* - * We can do SG-DMA, but we don't because we never know how much - * data we successfully wrote to the card. - */ - mmc->max_phys_segs = NR_SG; - - /* - * Our hardware DMA can handle a maximum of one page per SG entry. - */ - mmc->max_seg_size = PAGE_SIZE; - - /* - * Block length register is 10 bits. - */ - mmc->max_blk_size = 1023; - - /* - * Block count register is 16 bits. - */ - mmc->max_blk_count = 65535; - - host = mmc_priv(mmc); - host->mmc = mmc; - host->dma = -1; - host->pdata = pdev->dev.platform_data; - mmc->ocr_avail = host->pdata ? - host->pdata->ocr_mask : - MMC_VDD_32_33|MMC_VDD_33_34; - - host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); - if (!host->sg_cpu) { - ret = -ENOMEM; - goto out; - } - - spin_lock_init(&host->lock); - host->res = r; - host->irq = irq; - host->imask = MMC_I_MASK_ALL; - - host->base = ioremap(r->start, SZ_4K); - if (!host->base) { - ret = -ENOMEM; - goto out; - } - - /* - * Ensure that the host controller is shut down, and setup - * with our defaults. - */ - pxamci_stop_clock(host); - writel(0, host->base + MMC_SPI); - writel(64, host->base + MMC_RESTO); - writel(host->imask, host->base + MMC_I_MASK); - - host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW, - pxamci_dma_irq, host); - if (host->dma < 0) { - ret = -EBUSY; - goto out; - } - - ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host); - if (ret) - goto out; - - platform_set_drvdata(pdev, mmc); - - if (host->pdata && host->pdata->init) - host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); - - mmc_add_host(mmc); - - return 0; - - out: - if (host) { - if (host->dma >= 0) - pxa_free_dma(host->dma); - if (host->base) - iounmap(host->base); - if (host->sg_cpu) - dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); - } - if (mmc) - mmc_free_host(mmc); - release_resource(r); - return ret; -} - -static int pxamci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (mmc) { - struct pxamci_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->exit) - host->pdata->exit(&pdev->dev, mmc); - - mmc_remove_host(mmc); - - pxamci_stop_clock(host); - writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| - END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, - host->base + MMC_I_MASK); - - DRCMRRXMMC = 0; - DRCMRTXMMC = 0; - - free_irq(host->irq, host); - pxa_free_dma(host->dma); - iounmap(host->base); - dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); - - release_resource(host->res); - - mmc_free_host(mmc); - } - return 0; -} - -#ifdef CONFIG_PM -static int pxamci_suspend(struct platform_device *dev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc, state); - - return ret; -} - -static int pxamci_resume(struct platform_device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_resume_host(mmc); - - return ret; -} -#else -#define pxamci_suspend NULL -#define pxamci_resume NULL -#endif - -static struct platform_driver pxamci_driver = { - .probe = pxamci_probe, - .remove = pxamci_remove, - .suspend = pxamci_suspend, - .resume = pxamci_resume, - .driver = { - .name = DRIVER_NAME, - }, -}; - -static int __init pxamci_init(void) -{ - return platform_driver_register(&pxamci_driver); -} - -static void __exit pxamci_exit(void) -{ - platform_driver_unregister(&pxamci_driver); -} - -module_init(pxamci_init); -module_exit(pxamci_exit); - -MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); -MODULE_LICENSE("GPL"); |