diff options
Diffstat (limited to 'packages/kexecboot/linux-kexecboot-2.6.24/tosa/0011-MMC-driver-for-TMIO-devices.patch')
-rw-r--r-- | packages/kexecboot/linux-kexecboot-2.6.24/tosa/0011-MMC-driver-for-TMIO-devices.patch | 891 |
1 files changed, 0 insertions, 891 deletions
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0011-MMC-driver-for-TMIO-devices.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0011-MMC-driver-for-TMIO-devices.patch deleted file mode 100644 index 6ff752d1ff..0000000000 --- a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0011-MMC-driver-for-TMIO-devices.patch +++ /dev/null @@ -1,891 +0,0 @@ -From b358a64c1fdd1eb80da57f919c893d910db95e37 Mon Sep 17 00:00:00 2001 -From: Ian Molton <spyro@f2s.com> -Date: Sat, 29 Dec 2007 15:26:19 +0000 -Subject: [PATCH 11/64] MMC driver for TMIO devices - ---- - drivers/mmc/host/Kconfig | 6 + - drivers/mmc/host/Makefile | 1 + - drivers/mmc/host/tmio_mmc.c | 633 +++++++++++++++++++++++++++++++++++++++++++ - drivers/mmc/host/tmio_mmc.h | 205 ++++++++++++++ - 4 files changed, 845 insertions(+), 0 deletions(-) - create mode 100644 drivers/mmc/host/tmio_mmc.c - create mode 100644 drivers/mmc/host/tmio_mmc.h - -diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 5fef678..f8f9b7e 100644 ---- a/drivers/mmc/host/Kconfig -+++ b/drivers/mmc/host/Kconfig -@@ -130,3 +130,9 @@ config MMC_SPI - - If unsure, or if your system has no SPI master driver, say N. - -+config MMC_TMIO -+ tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" -+ depends on MMC -+ help -+ This provides support for the SD/MMC cell found in TC6393XB, -+ T7L66XB and also ipaq ASIC3 -diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile -index 3877c87..7ac956b 100644 ---- a/drivers/mmc/host/Makefile -+++ b/drivers/mmc/host/Makefile -@@ -17,4 +17,5 @@ obj-$(CONFIG_MMC_OMAP) += omap.o - obj-$(CONFIG_MMC_AT91) += at91_mci.o - obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o - obj-$(CONFIG_MMC_SPI) += mmc_spi.o -+obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o - -diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c -new file mode 100644 -index 0000000..735c386 ---- /dev/null -+++ b/drivers/mmc/host/tmio_mmc.c -@@ -0,0 +1,633 @@ -+/* -+ * linux/drivers/mmc/tmio_mmc.c -+ * -+ * Copyright (C) 2004 Ian Molton -+ * Copyright (C) 2007 Ian Molton -+ * -+ * 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. -+ * -+ * Driver for the MMC / SD / SDIO cell found in: -+ * -+ * TC6393XB TC6391XB TC6387XB T7L66XB -+ * -+ * This driver draws mainly on scattered spec sheets, Reverse engineering -+ * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit -+ * support). (Further 4 bit support from a later datasheet). -+ * -+ * TODO: -+ * Investigate using a workqueue for PIO transfers -+ * Eliminate FIXMEs -+ * SDIO support -+ * Better Power management -+ * Handle MMC errors better -+ * double buffer support -+ * -+ */ -+#include <linux/module.h> -+#include <linux/irq.h> -+#include <linux/device.h> -+#include <linux/delay.h> -+#include <linux/mmc/mmc.h> -+#include <linux/mmc/host.h> -+#include <linux/mfd-core.h> -+#include <linux/mfd/tmio.h> -+ -+#include "tmio_mmc.h" -+ -+/* -+ * Fixme - documentation conflicts on what the clock values are for the -+ * various dividers. -+ * One document I have says that its a divisor of a 24MHz clock, another 33. -+ * This probably depends on HCLK for a given platform, so we may need to -+ * require HCLK be passed to us from the MFD core. -+ * -+ */ -+ -+static void tmio_mmc_set_clock (struct tmio_mmc_host *host, int new_clock) { -+ struct tmio_mmc_cnf __iomem *cnf = host->cnf; -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ u32 clk = 0, clock; -+ -+ if (new_clock) { -+ for(clock = 46875, clk = 0x100; new_clock >= (clock<<1); ){ -+ clock <<= 1; -+ clk >>= 1; -+ } -+ if(clk & 0x1) -+ clk = 0x20000; -+ -+ clk >>= 2; -+ if(clk & 0x8000) /* For full speed we disable the divider. */ -+ writeb(0, &cnf->sd_clk_mode); -+ else -+ writeb(1, &cnf->sd_clk_mode); -+ clk |= 0x100; -+ } -+ -+ writew(clk, &ctl->sd_card_clk_ctl); -+} -+ -+static void tmio_mmc_clk_stop (struct tmio_mmc_host *host) { -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ -+ writew(0x0000, &ctl->clk_and_wait_ctl); -+ msleep(10); -+ writew(readw(&ctl->sd_card_clk_ctl) & ~0x0100, &ctl->sd_card_clk_ctl); -+ msleep(10); -+} -+ -+static void tmio_mmc_clk_start (struct tmio_mmc_host *host) { -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ -+ writew(readw(&ctl->sd_card_clk_ctl) | 0x0100, &ctl->sd_card_clk_ctl); -+ msleep(10); -+ writew(0x0100, &ctl->clk_and_wait_ctl); -+ msleep(10); -+} -+ -+static void reset(struct tmio_mmc_host *host) { -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ -+ /* FIXME - should we set stop clock reg here */ -+ writew(0x0000, &ctl->reset_sd); -+ writew(0x0000, &ctl->reset_sdio); -+ msleep(10); -+ writew(0x0001, &ctl->reset_sd); -+ writew(0x0001, &ctl->reset_sdio); -+ msleep(10); -+} -+ -+static void -+tmio_mmc_finish_request(struct tmio_mmc_host *host) -+{ -+ struct mmc_request *mrq = host->mrq; -+ -+ host->mrq = NULL; -+ host->cmd = NULL; -+ host->data = NULL; -+ -+ mmc_request_done(host->mmc, mrq); -+} -+ -+/* These are the bitmasks the tmio chip requires to implement the MMC response -+ * types. Note that R1 and R6 are the same in this scheme. */ -+#define APP_CMD 0x0040 -+#define RESP_NONE 0x0300 -+#define RESP_R1 0x0400 -+#define RESP_R1B 0x0500 -+#define RESP_R2 0x0600 -+#define RESP_R3 0x0700 -+#define DATA_PRESENT 0x0800 -+#define TRANSFER_READ 0x1000 -+#define TRANSFER_MULTI 0x2000 -+#define SECURITY_CMD 0x4000 -+ -+static void -+tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) -+{ -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ struct mmc_data *data = host->data; -+ int c = cmd->opcode; -+ -+ if(cmd->opcode == MMC_STOP_TRANSMISSION) { -+ writew(0x001, &ctl->stop_internal_action); -+ return; -+ } -+ -+ switch(mmc_resp_type(cmd)) { -+ case MMC_RSP_NONE: c |= RESP_NONE; break; -+ case MMC_RSP_R1: c |= RESP_R1; break; -+ case MMC_RSP_R1B: c |= RESP_R1B; break; -+ case MMC_RSP_R2: c |= RESP_R2; break; -+ case MMC_RSP_R3: c |= RESP_R3; break; -+ default: -+ DBG("Unknown response type %d\n", mmc_resp_type(cmd)); -+ } -+ -+ host->cmd = cmd; -+ -+/* FIXME - this seems to be ok comented out but the spec suggest this bit should -+ * be set when issuing app commands. -+ * if(cmd->flags & MMC_FLAG_ACMD) -+ * c |= APP_CMD; -+ */ -+ if(data) { -+ c |= DATA_PRESENT; -+ if(data->blocks > 1) { -+ writew(0x100, &ctl->stop_internal_action); -+ c |= TRANSFER_MULTI; -+ } -+ if(data->flags & MMC_DATA_READ) -+ c |= TRANSFER_READ; -+ } -+ -+ enable_mmc_irqs(ctl, TMIO_MASK_CMD); -+ -+ /* Fire off the command */ -+ tmio_iowrite32(cmd->arg, ctl->arg_reg); -+ writew(c, &ctl->sd_cmd); -+} -+ -+/* This chip always returns (at least?) as much data as you ask for. -+ * Im unsure what happens if you ask for less than a block. This should be -+ * looked into to ensure that a funny length read doesnt hose the controller. -+ * -+ * FIXME - this chip cannot do 1 and 2 byte data requests in 4 bit mode -+ */ -+static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host) { -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ struct mmc_data *data = host->data; -+ unsigned short *buf; -+ unsigned int count; -+ unsigned long flags; -+ -+ if(!data){ -+ DBG("Spurious PIO IRQ\n"); -+ return; -+ } -+ -+ buf = (unsigned short *)(tmio_mmc_kmap_atomic(host, &flags) + -+ host->sg_off); -+ -+ /* Ensure we dont read more than one block. The chip will interrupt us -+ * When the next block is available. -+ * FIXME - this is probably not true now IRQ handling is fixed -+ */ -+ count = host->sg_ptr->length - host->sg_off; -+ if(count > data->blksz) -+ count = data->blksz; -+ -+ DBG("count: %08x offset: %08x flags %08x\n", -+ count, host->sg_off, data->flags); -+ -+ /* Transfer the data */ -+ if(data->flags & MMC_DATA_READ) -+ readsw(&ctl->sd_data_port[0], buf, count >> 1); -+ else -+ writesw(&ctl->sd_data_port[0], buf, count >> 1); -+ -+ host->sg_off += count; -+ -+ tmio_mmc_kunmap_atomic(host, &flags); -+ -+ if(host->sg_off == host->sg_ptr->length) -+ tmio_mmc_next_sg(host); -+ -+ return; -+} -+ -+static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host) { -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ struct mmc_data *data = host->data; -+ -+ host->data = NULL; -+ -+ if(!data){ -+ DBG("Spurious data end IRQ\n"); -+ return; -+ } -+ -+ /* FIXME - return correct transfer count on errors */ -+ if (!data->error) -+ data->bytes_xfered = data->blocks * data->blksz; -+ else -+ data->bytes_xfered = 0; -+ -+ DBG("Completed data request\n"); -+ -+ /*FIXME - other drivers allow an optional stop command of any given type -+ * which we dont do, as the chip can auto generate them. -+ * Perhaps we can be smarter about when to use auto CMD12 and -+ * only issue the auto request when we know this is the desired -+ * stop command, allowing fallback to the stop command the -+ * upper layers expect. For now, we do what works. -+ */ -+ -+ writew(0x000, &ctl->stop_internal_action); -+ -+ if(data->flags & MMC_DATA_READ) -+ disable_mmc_irqs(ctl, TMIO_MASK_READOP); -+ else -+ disable_mmc_irqs(ctl, TMIO_MASK_WRITEOP); -+ -+ tmio_mmc_finish_request(host); -+} -+ -+static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat) { -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ struct mmc_command *cmd = host->cmd; -+ -+ if(!host->cmd) { -+ DBG("Spurious CMD irq\n"); -+ return; -+ } -+ -+ host->cmd = NULL; -+ -+ /* This controller is sicker than the PXA one. not only do we need to -+ * drop the top 8 bits of the first response word, we also need to -+ * modify the order of the response for short response command types. -+ */ -+ -+ /* FIXME - this works but readl is wrong and will break on asic3... */ -+ cmd->resp[3] = tmio_ioread32(&ctl->response[0]); -+ cmd->resp[2] = tmio_ioread32(&ctl->response[2]); -+ cmd->resp[1] = tmio_ioread32(&ctl->response[4]); -+ cmd->resp[0] = tmio_ioread32(&ctl->response[6]); -+ -+ if(cmd->flags & MMC_RSP_136) { -+ cmd->resp[0] = (cmd->resp[0] <<8) | (cmd->resp[1] >>24); -+ cmd->resp[1] = (cmd->resp[1] <<8) | (cmd->resp[2] >>24); -+ cmd->resp[2] = (cmd->resp[2] <<8) | (cmd->resp[3] >>24); -+ cmd->resp[3] <<= 8; -+ } -+ else if(cmd->flags & MMC_RSP_R3) { -+ cmd->resp[0] = cmd->resp[3]; -+ } -+ -+ if (stat & TMIO_STAT_CMDTIMEOUT) -+ cmd->error = -ETIMEDOUT; -+ else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC) -+ cmd->error = -EILSEQ; -+ -+ /* If there is data to handle we enable data IRQs here, and -+ * we will ultimatley finish the request in the data_end handler. -+ * If theres no data or we encountered an error, finish now. -+ */ -+ if(host->data && !cmd->error){ -+ if(host->data->flags & MMC_DATA_READ) -+ enable_mmc_irqs(ctl, TMIO_MASK_READOP); -+ else -+ enable_mmc_irqs(ctl, TMIO_MASK_WRITEOP); -+ } -+ else { -+ tmio_mmc_finish_request(host); -+ } -+ -+ return; -+} -+ -+ -+static irqreturn_t tmio_mmc_irq(int irq, void *devid) -+{ -+ struct tmio_mmc_host *host = devid; -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ unsigned int ireg, irq_mask, status; -+ -+ DBG("MMC IRQ begin\n"); -+ -+ status = tmio_ioread32(ctl->status); -+ irq_mask = tmio_ioread32(ctl->irq_mask); -+ ireg = status & TMIO_MASK_IRQ & ~irq_mask; -+ -+#ifdef CONFIG_MMC_DEBUG -+ debug_status(status); -+ debug_status(ireg); -+#endif -+ if (!ireg) { -+ disable_mmc_irqs(ctl, status & ~irq_mask); -+#ifdef CONFIG_MMC_DEBUG -+ WARN("tmio_mmc: Spurious MMC irq, disabling! 0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); -+ debug_status(status); -+#endif -+ goto out; -+ } -+ -+ while (ireg) { -+ /* Card insert / remove attempts */ -+ if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)){ -+ ack_mmc_irqs(ctl, TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE); -+ mmc_detect_change(host->mmc,0); -+ } -+ -+ /* CRC and other errors */ -+/* if (ireg & TMIO_STAT_ERR_IRQ) -+ * handled |= tmio_error_irq(host, irq, stat); -+ */ -+ -+ /* Command completion */ -+ if (ireg & TMIO_MASK_CMD) { -+ tmio_mmc_cmd_irq(host, status); -+ ack_mmc_irqs(ctl, TMIO_MASK_CMD); -+ } -+ -+ /* Data transfer */ -+ if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { -+ ack_mmc_irqs(ctl, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); -+ tmio_mmc_pio_irq(host); -+ } -+ -+ /* Data transfer completion */ -+ if (ireg & TMIO_STAT_DATAEND) { -+ tmio_mmc_data_irq(host); -+ ack_mmc_irqs(ctl, TMIO_STAT_DATAEND); -+ } -+ -+ /* Check status - keep going until we've handled it all */ -+ status = tmio_ioread32(ctl->status); -+ irq_mask = tmio_ioread32(ctl->irq_mask); -+ ireg = status & TMIO_MASK_IRQ & ~irq_mask; -+ -+#ifdef CONFIG_MMC_DEBUG -+ DBG("Status at end of loop: %08x\n", status); -+ debug_status(status); -+#endif -+ } -+ DBG("MMC IRQ end\n"); -+ -+out: -+ return IRQ_HANDLED; -+} -+ -+static void tmio_mmc_start_data(struct tmio_mmc_host *host, struct mmc_data *data) -+{ -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ -+ DBG("setup data transfer: blocksize %08x nr_blocks %d\n", -+ data->blksz, data->blocks); -+ -+ tmio_mmc_init_sg(host, data); -+ host->data = data; -+ -+ /* Set transfer length / blocksize */ -+ writew(data->blksz, &ctl->sd_xfer_len); -+ writew(data->blocks, &ctl->xfer_blk_count); -+} -+ -+/* Process requests from the MMC layer */ -+static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct tmio_mmc_host *host = mmc_priv(mmc); -+ -+ WARN_ON(host->mrq != NULL); -+ -+ host->mrq = mrq; -+ -+ /* If we're performing a data request we need to setup some -+ extra information */ -+ if (mrq->data) -+ tmio_mmc_start_data(host, mrq->data); -+ -+ tmio_mmc_start_command(host, mrq->cmd); -+} -+ -+/* Set MMC clock / power. -+ * Note: This controller uses a simple divider scheme therefore it cannot -+ * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as -+ * MMC wont run that fast, it has to be clocked at 12MHz which is the next -+ * slowest setting. -+ */ -+static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -+{ -+ struct tmio_mmc_host *host = mmc_priv(mmc); -+ struct tmio_mmc_cnf __iomem *cnf = host->cnf; -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ -+ if(ios->clock) -+ tmio_mmc_set_clock (host, ios->clock); -+ -+ /* Power sequence - OFF -> ON -> UP */ -+ switch (ios->power_mode) { -+ case MMC_POWER_OFF: -+ writeb(0x00, &cnf->pwr_ctl[1]); /* power down SD bus */ -+ tmio_mmc_clk_stop(host); -+ break; -+ case MMC_POWER_ON: -+ writeb(0x02, &cnf->pwr_ctl[1]); /* power up SD bus */ -+ break; -+ case MMC_POWER_UP: -+ tmio_mmc_clk_start(host); /* start bus clock */ -+ break; -+ } -+ -+ switch (ios->bus_width) { -+ case MMC_BUS_WIDTH_1: -+ writew(0x80e0, &ctl->sd_mem_card_opt); -+ break; -+ case MMC_BUS_WIDTH_4: -+ writew(0x00e0, &ctl->sd_mem_card_opt); -+ break; -+ } -+ -+ /* Potentially we may need a 140us pause here. FIXME */ -+ udelay(140); -+} -+ -+static int tmio_mmc_get_ro(struct mmc_host *mmc) { -+ struct tmio_mmc_host *host = mmc_priv(mmc); -+ struct tmio_mmc_ctl __iomem *ctl = host->ctl; -+ -+ return (readw(&ctl->status[0]) & TMIO_STAT_WRPROTECT)?0:1; -+} -+ -+static struct mmc_host_ops tmio_mmc_ops = { -+ .request = tmio_mmc_request, -+ .set_ios = tmio_mmc_set_ios, -+ .get_ro = tmio_mmc_get_ro, -+}; -+ -+static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) { -+ struct mfd_cell *cell = mfd_get_cell(dev); -+ struct mmc_host *mmc = platform_get_drvdata(dev); -+ int ret; -+ -+ ret = mmc_suspend_host(mmc, state); -+ -+ /* Tell MFD core it can disable us now.*/ -+ if(!ret && cell->disable) -+ cell->disable(dev); -+ -+ return ret; -+} -+ -+static int tmio_mmc_resume(struct platform_device *dev) { -+ struct mfd_cell *cell = mfd_get_cell(dev); -+ struct mmc_host *mmc = platform_get_drvdata(dev); -+ struct tmio_mmc_host *host = mmc_priv(mmc); -+ struct tmio_mmc_cnf __iomem *cnf = host->cnf; -+ -+ /* Enable the MMC/SD Control registers */ -+ writew(SDCREN, &cnf->cmd); -+ writel(dev->resource[0].start & 0xfffe, &cnf->ctl_base); -+ -+ /* Tell the MFD core we are ready to be enabled */ -+ if(cell->enable) -+ cell->enable(dev); -+ -+ mmc_resume_host(mmc); -+ -+ return 0; -+} -+ -+static int __devinit tmio_mmc_probe(struct platform_device *dev) -+{ -+ struct mfd_cell *cell = mfd_get_cell(dev); -+ struct tmio_mmc_cnf __iomem *cnf; -+ struct tmio_mmc_ctl __iomem *ctl; -+ struct tmio_mmc_host *host; -+ struct mmc_host *mmc; -+ int ret = -ENOMEM; -+ -+ mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &dev->dev); -+ if (!mmc) { -+ goto out; -+ } -+ -+ host = mmc_priv(mmc); -+ host->mmc = mmc; -+ platform_set_drvdata(dev, mmc); /* Used so we can de-init safely. */ -+ -+ host->cnf = cnf = ioremap((unsigned long)dev->resource[1].start, -+ (unsigned long)dev->resource[1].end - -+ (unsigned long)dev->resource[1].start); -+ if(!host->cnf) -+ goto host_free; -+ -+ host->ctl = ctl = ioremap((unsigned long)dev->resource[0].start, -+ (unsigned long)dev->resource[0].end - -+ (unsigned long)dev->resource[0].start); -+ if (!host->ctl) { -+ goto unmap_cnf; -+ } -+ -+ mmc->ops = &tmio_mmc_ops; -+ mmc->caps = MMC_CAP_4_BIT_DATA; -+ mmc->f_min = 46875; -+ mmc->f_max = 24000000; -+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; -+ -+ /* Enable the MMC/SD Control registers */ -+ writew(SDCREN, &cnf->cmd); -+ writel(dev->resource[0].start & 0xfffe, &cnf->ctl_base); -+ -+ /* Tell the MFD core we are ready to be enabled */ -+ if(cell->enable) -+ cell->enable(dev); -+ -+ writeb(0x01,&cnf->pwr_ctl[2]); /* Disable SD power during suspend */ -+ writeb(0x1f, &cnf->stop_clk_ctl); /* Route clock to SDIO??? FIXME */ -+ writeb(0x0, &cnf->pwr_ctl[1]); /* Power down SD bus*/ -+ tmio_mmc_clk_stop(host); /* Stop bus clock */ -+ reset(host); /* Reset MMC HC */ -+ -+ host->irq = (unsigned long)dev->resource[2].start; -+ ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED, "tmio-mmc", host); -+ if (ret){ -+ ret = -ENODEV; -+ DBG("Failed to allocate IRQ.\n"); -+ goto unmap_ctl; -+ } -+ set_irq_type(host->irq, IRQT_FALLING); -+ -+ mmc_add_host(mmc); -+ -+ printk(KERN_INFO "%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), -+ (unsigned long)host->ctl, host->irq); -+ -+ /* Lets unmask the IRQs we want to know about */ -+ disable_mmc_irqs(ctl, TMIO_MASK_ALL); -+ enable_mmc_irqs(ctl, TMIO_MASK_IRQ); -+ -+ return 0; -+ -+unmap_ctl: -+ iounmap(host->ctl); -+unmap_cnf: -+ iounmap(host->cnf); -+host_free: -+ mmc_free_host(mmc); -+out: -+ return ret; -+} -+ -+static int __devexit tmio_mmc_remove(struct platform_device *dev) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(dev); -+ -+ platform_set_drvdata(dev, NULL); -+ -+ if (mmc) { -+ struct tmio_mmc_host *host = mmc_priv(mmc); -+ mmc_remove_host(mmc); -+ free_irq(host->irq, host); -+ /* FIXME - we might want to consider stopping the chip here. */ -+ iounmap(host->ctl); -+ iounmap(host->cnf); -+ mmc_free_host(mmc); /* FIXME - why does this call hang ? */ -+ } -+ return 0; -+} -+ -+/* ------------------- device registration ----------------------- */ -+ -+static struct platform_driver tmio_mmc_driver = { -+ .driver = { -+ .name = "tmio-mmc", -+ }, -+ .probe = tmio_mmc_probe, -+ .remove = __devexit_p(tmio_mmc_remove), -+#ifdef CONFIG_PM -+ .suspend = tmio_mmc_suspend, -+ .resume = tmio_mmc_resume, -+#endif -+}; -+ -+ -+static int __init tmio_mmc_init(void) -+{ -+ return platform_driver_register (&tmio_mmc_driver); -+} -+ -+static void __exit tmio_mmc_exit(void) -+{ -+ platform_driver_unregister (&tmio_mmc_driver); -+} -+ -+module_init(tmio_mmc_init); -+module_exit(tmio_mmc_exit); -+ -+MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver"); -+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); -+MODULE_LICENSE("GPLv2"); -diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h -new file mode 100644 -index 0000000..d4d9f8f ---- /dev/null -+++ b/drivers/mmc/host/tmio_mmc.h -@@ -0,0 +1,205 @@ -+/* Definitons for use with the tmio_mmc.c -+ * -+ * (c) 2005 Ian Molton <spyro@f2s.com> -+ * (c) 2007 Ian Molton <spyro@f2s.com> -+ * -+ * 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. -+ * -+ */ -+ -+struct tmio_mmc_cnf { -+ u8 x00[4]; -+ u16 cmd; -+ u8 x01[10]; -+ u32 ctl_base; -+ u8 x02[41]; -+ u8 int_pin; -+ u8 x03[2]; -+ u8 stop_clk_ctl; -+ u8 gclk_ctl; /* Gated Clock Control */ -+ u8 sd_clk_mode; /* 0x42 */ -+ u8 x04; -+ u16 pin_status; -+ u8 x05[2]; -+ u8 pwr_ctl[3]; -+ u8 x06; -+ u8 card_detect_mode; -+ u8 x07[3]; -+ u8 sd_slot; -+ u8 x08[159]; -+ u8 ext_gclk_ctl_1; /* Extended Gated Clock Control 1 */ -+ u8 ext_gclk_ctl_2; /* Extended Gated Clock Control 2 */ -+ u8 x09[7]; -+ u8 ext_gclk_ctl_3; /* Extended Gated Clock Control 3 */ -+ u8 sd_led_en_1; -+ u8 x10[3]; -+ u8 sd_led_en_2; -+ u8 x11; -+} __attribute__ ((packed)); -+ -+#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/ -+ -+struct tmio_mmc_ctl { -+ u16 sd_cmd; -+ u16 x00; -+ u16 arg_reg[2]; -+ u16 stop_internal_action; -+ u16 xfer_blk_count; -+ u16 response[8]; -+ u16 status[2]; -+ u16 irq_mask[2]; -+ u16 sd_card_clk_ctl; -+ u16 sd_xfer_len; -+ u16 sd_mem_card_opt; -+ u16 x01; -+ u16 sd_error_detail_status[2]; -+ u16 sd_data_port[2]; -+ u16 transaction_ctl; -+ u16 x02[85]; -+ u16 reset_sd; -+ u16 x03[15]; -+ u16 sdio_regs[28]; -+ u16 clk_and_wait_ctl; -+ u16 x04[83]; -+ u16 reset_sdio; -+ u16 x05[15]; -+} __attribute__ ((packed)); -+ -+/* Definitions for values the CTRL_STATUS register can take. */ -+#define TMIO_STAT_CMDRESPEND 0x00000001 -+#define TMIO_STAT_DATAEND 0x00000004 -+#define TMIO_STAT_CARD_REMOVE 0x00000008 -+#define TMIO_STAT_CARD_INSERT 0x00000010 -+#define TMIO_STAT_SIGSTATE 0x00000020 -+#define TMIO_STAT_WRPROTECT 0x00000080 -+#define TMIO_STAT_CARD_REMOVE_A 0x00000100 -+#define TMIO_STAT_CARD_INSERT_A 0x00000200 -+#define TMIO_STAT_SIGSTATE_A 0x00000400 -+#define TMIO_STAT_CMD_IDX_ERR 0x00010000 -+#define TMIO_STAT_CRCFAIL 0x00020000 -+#define TMIO_STAT_STOPBIT_ERR 0x00040000 -+#define TMIO_STAT_DATATIMEOUT 0x00080000 -+#define TMIO_STAT_RXOVERFLOW 0x00100000 -+#define TMIO_STAT_TXUNDERRUN 0x00200000 -+#define TMIO_STAT_CMDTIMEOUT 0x00400000 -+#define TMIO_STAT_RXRDY 0x01000000 -+#define TMIO_STAT_TXRQ 0x02000000 -+#define TMIO_STAT_ILL_FUNC 0x20000000 -+#define TMIO_STAT_CMD_BUSY 0x40000000 -+#define TMIO_STAT_ILL_ACCESS 0x80000000 -+ -+/* Define some IRQ masks */ -+/* This is the mask used at reset by the chip */ -+#define TMIO_MASK_ALL 0x837f031d -+#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND | \ -+ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) -+#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND | \ -+ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) -+#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ -+ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) -+#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) -+ -+#define enable_mmc_irqs(ctl, i) \ -+ do { \ -+ u32 mask;\ -+ mask = tmio_ioread32((ctl)->irq_mask); \ -+ mask &= ~((i) & TMIO_MASK_IRQ); \ -+ tmio_iowrite32(mask, (ctl)->irq_mask); \ -+ } while (0) -+ -+#define disable_mmc_irqs(ctl, i) \ -+ do { \ -+ u32 mask;\ -+ mask = tmio_ioread32((ctl)->irq_mask); \ -+ mask |= ((i) & TMIO_MASK_IRQ); \ -+ tmio_iowrite32(mask, (ctl)->irq_mask); \ -+ } while (0) -+ -+#define ack_mmc_irqs(ctl, i) \ -+ do { \ -+ u32 mask;\ -+ mask = tmio_ioread32((ctl)->status); \ -+ mask &= ~((i) & TMIO_MASK_IRQ); \ -+ tmio_iowrite32(mask, (ctl)->status); \ -+ } while (0) -+ -+ -+struct tmio_mmc_host { -+ struct tmio_mmc_cnf __iomem *cnf; -+ struct tmio_mmc_ctl __iomem *ctl; -+ struct mmc_command *cmd; -+ struct mmc_request *mrq; -+ struct mmc_data *data; -+ struct mmc_host *mmc; -+ int irq; -+ -+ /* pio related stuff */ -+ struct scatterlist *sg_ptr; -+ unsigned int sg_len; -+ unsigned int sg_off; -+}; -+ -+#include <linux/scatterlist.h> -+#include <linux/blkdev.h> -+ -+static inline void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data) -+{ -+ host->sg_len = data->sg_len; -+ host->sg_ptr = data->sg; -+ host->sg_off = 0; -+} -+ -+static inline int tmio_mmc_next_sg(struct tmio_mmc_host *host) -+{ -+ host->sg_ptr++; -+ host->sg_off = 0; -+ return --host->sg_len; -+} -+ -+static inline char *tmio_mmc_kmap_atomic(struct tmio_mmc_host *host, unsigned long *flags) -+{ -+ struct scatterlist *sg = host->sg_ptr; -+ -+ local_irq_save(*flags); -+ return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; -+} -+ -+static inline void tmio_mmc_kunmap_atomic(struct tmio_mmc_host *host, unsigned long *flags) -+{ -+ kunmap_atomic(sg_page(host->sg_ptr), KM_BIO_SRC_IRQ); -+ local_irq_restore(*flags); -+} -+ -+#ifdef CONFIG_MMC_DEBUG -+#define DBG(args...) printk(args) -+ -+void debug_status(u32 status){ -+ printk("status: %08x = ", status); -+ if(status & TMIO_STAT_CARD_REMOVE) printk("Card_removed "); -+ if(status & TMIO_STAT_CARD_INSERT) printk("Card_insert "); -+ if(status & TMIO_STAT_SIGSTATE) printk("Sigstate "); -+ if(status & TMIO_STAT_WRPROTECT) printk("Write_protect "); -+ if(status & TMIO_STAT_CARD_REMOVE_A) printk("Card_remove_A "); -+ if(status & TMIO_STAT_CARD_INSERT_A) printk("Card_insert_A "); -+ if(status & TMIO_STAT_SIGSTATE_A) printk("Sigstate_A "); -+ if(status & TMIO_STAT_CMD_IDX_ERR) printk("Cmd_IDX_Err "); -+ if(status & TMIO_STAT_STOPBIT_ERR) printk("Stopbit_ERR "); -+ if(status & TMIO_STAT_ILL_FUNC) printk("ILLEGAL_FUNC "); -+ if(status & TMIO_STAT_CMD_BUSY) printk("CMD_BUSY "); -+ if(status & TMIO_STAT_CMDRESPEND) printk("Response_end "); -+ if(status & TMIO_STAT_DATAEND) printk("Data_end "); -+ if(status & TMIO_STAT_CRCFAIL) printk("CRC_failure "); -+ if(status & TMIO_STAT_DATATIMEOUT) printk("Data_timeout "); -+ if(status & TMIO_STAT_CMDTIMEOUT) printk("Command_timeout "); -+ if(status & TMIO_STAT_RXOVERFLOW) printk("RX_OVF "); -+ if(status & TMIO_STAT_TXUNDERRUN) printk("TX_UND "); -+ if(status & TMIO_STAT_RXRDY) printk("RX_rdy "); -+ if(status & TMIO_STAT_TXRQ) printk("TX_req "); -+ if(status & TMIO_STAT_ILL_ACCESS) printk("ILLEGAL_ACCESS "); -+ printk("\n"); -+} -+#else -+#define DBG(fmt,args...) do { } while (0) -+#endif --- -1.5.3.8 - |