diff options
Diffstat (limited to 'drivers/sdio/hcd/s3c24xx/s3c24xx_hcd.c')
-rw-r--r-- | drivers/sdio/hcd/s3c24xx/s3c24xx_hcd.c | 1568 |
1 files changed, 0 insertions, 1568 deletions
diff --git a/drivers/sdio/hcd/s3c24xx/s3c24xx_hcd.c b/drivers/sdio/hcd/s3c24xx/s3c24xx_hcd.c deleted file mode 100644 index f56b85f1c85..00000000000 --- a/drivers/sdio/hcd/s3c24xx/s3c24xx_hcd.c +++ /dev/null @@ -1,1568 +0,0 @@ -/* - * s3c24xx_hcd.c - Samsung S3C MCI driver, Atheros SDIO API compatible. - * - * Copyright (C) 2007 by Openmoko, Inc. - * Written by Samuel Ortiz <sameo@openedhand.com> - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/list.h> -#include <linux/dma-mapping.h> -#include <linux/errno.h> -#include <linux/platform_device.h> -#include <linux/device.h> -#include <linux/clk.h> -#include <linux/fs.h> -#include <linux/ioport.h> -#include <linux/workqueue.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/seq_file.h> -#include <linux/debugfs.h> - -#include <linux/sdio/ctsystem.h> -#include <linux/sdio/sdio_busdriver.h> -#include <linux/sdio/sdio_lib.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include <asm/dma.h> -#include <asm/dma-mapping.h> - -#include <mach/regs-sdi.h> -#include <mach/regs-gpio.h> -#include <mach/mci.h> -#include <mach/gta02.h> - -#include "s3c24xx_hcd.h" - -#define DESCRIPTION "S3c24xx SDIO host controller" -#define AUTHOR "Samuel Ortiz <sameo@openedhand.com>" - -#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1) - -static struct s3c2410_dma_client s3c24xx_hcd_dma_client = { - .name = "s3c24xx_hcd", -}; - -extern struct platform_device s3c_device_sdi; - -static void dump_request(struct s3c24xx_hcd_context * context) -{ - if (context->hcd.pCurrentRequest != NULL) { - DBG_PRINT(SDDBG_ERROR, ("Current Request Command:%d, ARG:0x%8.8X flags: 0x%04x\n", - context->hcd.pCurrentRequest->Command, context->hcd.pCurrentRequest->Argument, - context->hcd.pCurrentRequest->Flags)); - if (IS_SDREQ_DATA_TRANS(context->hcd.pCurrentRequest->Flags)) { - DBG_PRINT(SDDBG_ERROR, ("Data %s, Blocks: %d, BlockLen:%d Remaining: %d \n", - IS_SDREQ_WRITE_DATA(context->hcd.pCurrentRequest->Flags) ? "WRITE":"READ", - context->hcd.pCurrentRequest->BlockCount, - context->hcd.pCurrentRequest->BlockLen, - context->hcd.pCurrentRequest->DataRemaining)); - } - } -} - -static void s3c24xx_dump_regs(struct s3c24xx_hcd_context * context) -{ - u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize; - u32 datcon, datcnt, datsta, fsta, imask; - - con = readl(context->base + S3C2410_SDICON); - pre = readl(context->base + S3C2410_SDIPRE); - cmdarg = readl(context->base + S3C2410_SDICMDARG); - cmdcon = readl(context->base + S3C2410_SDICMDCON); - cmdsta = readl(context->base + S3C2410_SDICMDSTAT); - r0 = readl(context->base + S3C2410_SDIRSP0); - r1 = readl(context->base + S3C2410_SDIRSP1); - r2 = readl(context->base + S3C2410_SDIRSP2); - r3 = readl(context->base + S3C2410_SDIRSP3); - timer = readl(context->base + S3C2410_SDITIMER); - bsize = readl(context->base + S3C2410_SDIBSIZE); - datcon = readl(context->base + S3C2410_SDIDCON); - datcnt = readl(context->base + S3C2410_SDIDCNT); - datsta = readl(context->base + S3C2410_SDIDSTA); - fsta = readl(context->base + S3C2410_SDIFSTA); - imask = readl(context->base + S3C2440_SDIIMSK); - - printk("SDICON: 0x%08x\n", con); - printk("SDIPRE: 0x%08x\n", pre); - printk("SDICmdArg: 0x%08x\n", cmdarg); - printk("SDICmdCon: 0x%08x\n", cmdcon); - printk("SDICmdSta: 0x%08x\n", cmdsta); - printk("SDIRSP0: 0x%08x\n", r0); - printk("SDIRSP1: 0x%08x\n", r1); - printk("SDIRSP2: 0x%08x\n", r2); - printk("SDIRSP3: 0x%08x\n", r3); - printk("SDIDTimer: 0x%08x\n", timer); - printk("SDIBSize: 0x%08x\n", bsize); - printk("SDIDatCon: 0x%08x\n", datcon); - printk("SDIDatCnt: 0x%08x\n", datcnt); - printk("SDIDatSta: 0x%08x\n", datsta); - printk("SDIFSta: 0x%08x\n", fsta); - printk("SDIIntMsk: 0x%08x\n", imask); -} - -static inline void s3c24xx_hcd_clear_imask(struct s3c24xx_hcd_context * context) -{ - if (context->int_sdio) { - writel(S3C2410_SDIIMSK_SDIOIRQ | S3C2410_SDIIMSK_READWAIT, - context->base + S3C2440_SDIIMSK); - } else { - writel(0, context->base + S3C2440_SDIIMSK); - } -} - -static inline void s3c24xx_hcd_set_imask(struct s3c24xx_hcd_context * context) -{ - writel(context->int_mask, context->base + S3C2440_SDIIMSK); -} - - -static inline void s3c24xx_hcd_clear_dsta(struct s3c24xx_hcd_context * context) -{ - u32 dsta; - - dsta = readl(context->base + S3C2410_SDIDSTA); - writel(dsta, context->base + S3C2410_SDIDSTA); -} - -static inline void s3c24xx_hcd_clear_csta(struct s3c24xx_hcd_context * context) -{ - u32 csta, csta_clear = 0; - - csta = readl(context->base + S3C2410_SDICMDSTAT); - - if (csta & S3C2410_SDICMDSTAT_CRCFAIL) - csta_clear |= S3C2410_SDICMDSTAT_CRCFAIL; - if (csta & S3C2410_SDICMDSTAT_CMDSENT) - csta_clear |= S3C2410_SDICMDSTAT_CMDSENT; - if (csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) - csta_clear |= S3C2410_SDICMDSTAT_CMDTIMEOUT; - if (csta & S3C2410_SDICMDSTAT_RSPFIN) - csta_clear |= S3C2410_SDICMDSTAT_RSPFIN; - - writel(csta_clear, context->base + S3C2410_SDICMDSTAT); -} - -static inline void s3c24xx_hcd_clear_sta(struct s3c24xx_hcd_context * context) -{ - u32 csta, dsta, csta_clear = 0, dsta_clear = 0; - - csta = readl(context->base + S3C2410_SDICMDSTAT); - dsta = readl(context->base + S3C2410_SDIDSTA); - - if (csta & S3C2410_SDICMDSTAT_CRCFAIL) - csta_clear |= S3C2410_SDICMDSTAT_CRCFAIL; - if (csta & S3C2410_SDICMDSTAT_CMDSENT) - csta_clear |= S3C2410_SDICMDSTAT_CMDSENT; - if (csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) - csta_clear |= S3C2410_SDICMDSTAT_CMDTIMEOUT; - if (csta & S3C2410_SDICMDSTAT_RSPFIN) - csta_clear |= S3C2410_SDICMDSTAT_RSPFIN; - - - if (dsta & S3C2410_SDIDSTA_RDYWAITREQ) - dsta_clear |= S3C2410_SDIDSTA_RDYWAITREQ; - if (dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) - dsta_clear |= S3C2410_SDIDSTA_SDIOIRQDETECT; - if (dsta & S3C2410_SDIDSTA_FIFOFAIL) - dsta_clear |= S3C2410_SDIDSTA_FIFOFAIL; - if (dsta & S3C2410_SDIDSTA_CRCFAIL) - dsta_clear |= S3C2410_SDIDSTA_CRCFAIL; - if (dsta & S3C2410_SDIDSTA_RXCRCFAIL) - dsta_clear |= S3C2410_SDIDSTA_RXCRCFAIL; - if (dsta & S3C2410_SDIDSTA_DATATIMEOUT) - dsta_clear |= S3C2410_SDIDSTA_DATATIMEOUT; - if (dsta & S3C2410_SDIDSTA_XFERFINISH) - dsta_clear |= S3C2410_SDIDSTA_XFERFINISH; - if (dsta & S3C2410_SDIDSTA_BUSYFINISH) - dsta_clear |= S3C2410_SDIDSTA_BUSYFINISH; - if (dsta & S3C2410_SDIDSTA_SBITERR) - dsta_clear |= S3C2410_SDIDSTA_SBITERR; - - writel(csta_clear, context->base + S3C2410_SDICMDSTAT); - writel(dsta_clear, context->base + S3C2410_SDIDSTA); -} - -static inline void s3c24xx_hcd_fifo_reset(struct s3c24xx_hcd_context * context) -{ - u32 fsta; - - fsta = readl(context->base + S3C2410_SDIFSTA); - fsta |= S3C2440_SDIFSTA_FIFORESET; - writel(fsta, context->base + S3C2410_SDIFSTA); -} - -#if 0 -static void s3c24xx_hcd_reset(struct s3c24xx_hcd_context * context) -{ - u32 con, counter; - unsigned long flags; - - spin_lock_irqsave(&context->lock, flags); - - con = readl(context->base + S3C2410_SDICON); - - con |= S3C2440_SDICON_SDRESET; - - writel(con, context->base + S3C2410_SDICON); - - counter = 1000; - while(counter) { - con = readl(context->base + S3C2410_SDICON); - if (!(con & S3C2440_SDICON_SDRESET)) - break; - counter--; - mdelay(1); - } - - spin_unlock_irqrestore(&context->lock, flags); -} -#endif - -static SDIO_STATUS s3c24xx_hcd_clock_enable(struct s3c24xx_hcd_context * context, - unsigned int clock_rate, - unsigned char enable) -{ - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - unsigned long flags; - u32 con; - - spin_lock_irqsave(&context->lock, flags); - - con = readl(context->base + S3C2410_SDICON); - - if (enable && clock_rate) { - con |= S3C2410_SDICON_CLOCKTYPE; - } else { - con &= ~S3C2410_SDICON_CLOCKTYPE; - } - - if (clock_rate) { - int prescaler; - - for (prescaler = 0; prescaler < 0xff; prescaler++) { - context->device.actual_clock_rate = - context->device.max_clock_rate / (prescaler + 1); - - if (context->device.actual_clock_rate <= clock_rate && - context->device.actual_clock_rate <= context->hcd.MaxClockRate) - break; - } - - if (prescaler == 0xff) - DBG_PRINT(SDDBG_ERROR , ("Using lowest clock rate\n")); - - writel(prescaler, context->base + S3C2410_SDIPRE); - } - - writel(con, context->base + S3C2410_SDICON); - - spin_unlock_irqrestore(&context->lock, flags); - - return SDIOErrorToOSError(status); -} - -static void s3c24xx_hcd_set_bus_mode(struct s3c24xx_hcd_context *context, - PSDCONFIG_BUS_MODE_DATA pMode) -{ - u32 datacon; - unsigned long flags; - - DBG_PRINT(SDDBG_TRACE , ("SetBusMode\n")); - - spin_lock_irqsave(&context->lock, flags); - datacon = readl(context->base + S3C2410_SDIDCON); - - switch (SDCONFIG_GET_BUSWIDTH(pMode->BusModeFlags)) { - case SDCONFIG_BUS_WIDTH_1_BIT: - context->bus_width = 1; - datacon &= S3C2410_SDIDCON_WIDEBUS; - break; - case SDCONFIG_BUS_WIDTH_4_BIT: - context->bus_width = 4; - datacon |= S3C2410_SDIDCON_WIDEBUS; - break; - default: - DBG_PRINT(SDDBG_TRACE , ("Unknown bus width: %d\n", SDCONFIG_GET_BUSWIDTH(pMode->BusModeFlags))); - break; - } - - writel(datacon, context->base + S3C2410_SDIDCON); - spin_unlock_irqrestore(&context->lock, flags); - - /* Set clock rate and enable clock */ - s3c24xx_hcd_clock_enable(context, pMode->ClockRate, 1); - pMode->ActualClockRate = context->device.actual_clock_rate; - - DBG_PRINT(SDDBG_TRACE , ("BUS mode: %d bits wide, actual clock rate: %d kHz (requested %d kHz)\n", - context->bus_width, pMode->ActualClockRate / 1000, pMode->ClockRate / 1000)); -} - - -static void s3c24xx_hcd_dma_complete(struct s3c24xx_hcd_context * context) -{ - u32 dsta, counter, i; - PSDREQUEST req; - SDIO_STATUS status = SDIO_STATUS_ERROR; - - req = GET_CURRENT_REQUEST(&context->hcd); - if (req == NULL) { - DBG_PRINT(SDDBG_ERROR, ("%s(): No current request\n", __FUNCTION__)); - return; - } - - if (context->complete == S3C24XX_HCD_DATA_READ) { - /* DMA READ completion */ - if (context->latest_xfer_size != req->DataRemaining) { - DBG_PRINT(SDDBG_ERROR, ("Unexpected read xfer size: %d <-> %d\n", - context->latest_xfer_size, req->DataRemaining)); - status = SDIO_STATUS_BUS_WRITE_ERROR; - } - - counter = 0; - dsta = readl(context->base + S3C2410_SDIDSTA); - while (!(dsta & S3C2410_SDIDSTA_XFERFINISH)) { - if (counter > 500) { - printk("read xfer timed out\n"); - s3c24xx_dump_regs(context); - memcpy(req->pDataBuffer, context->io_buffer, - req->BlockCount * req->BlockLen); - printk("Transfer: %dx%d\n", req->BlockCount, req->BlockLen); - for (i = 0; i < req->DataRemaining; i++) - printk("0x%x ", *(((char *)context->io_buffer) + i)); - printk("\n"); - status = SDIO_STATUS_BUS_READ_TIMEOUT; - goto out; - } - dsta = readl(context->base + S3C2410_SDIDSTA); - counter++; - mdelay(1); - }; - - dma_sync_single(NULL, context->io_buffer_dma, - req->BlockCount * req->BlockLen, DMA_BIDIRECTIONAL); - - writel(S3C2410_SDIDSTA_XFERFINISH, context->base + S3C2410_SDIDSTA); - - memcpy(req->pDataBuffer, context->io_buffer, - req->BlockCount * req->BlockLen); - - req->DataRemaining = 0; - status = SDIO_STATUS_SUCCESS; - - } else if (context->complete == S3C24XX_HCD_DATA_WRITE) { - /* DMA WRITE completion */ - if (context->latest_xfer_size != req->DataRemaining) { - DBG_PRINT(SDDBG_ERROR, ("Unexpected write xfer size: %d <-> %d\n", - context->latest_xfer_size, req->DataRemaining)); - status = SDIO_STATUS_BUS_WRITE_ERROR; - } - - dsta = readl(context->base + S3C2410_SDIDSTA); - counter = 0; - while (!(dsta & S3C2410_SDIDSTA_XFERFINISH)) { - if (counter > 500) { - printk("write xfer timed out\n"); - status = SDIO_STATUS_BUS_WRITE_ERROR; - goto out; - } - dsta = readl(context->base + S3C2410_SDIDSTA); - counter++; - mdelay(1); - }; - - writel(S3C2410_SDIDSTA_XFERFINISH, context->base + S3C2410_SDIDSTA); - req->DataRemaining = 0; - status = SDIO_STATUS_SUCCESS; - } - - out: - req->Status = status; -} - -static void s3c24xx_hcd_pio_complete(struct s3c24xx_hcd_context * context) -{ - u32 fsta, counter; - u8 *ptr; - int fifo_count; - PSDREQUEST req; - SDIO_STATUS status = SDIO_STATUS_ERROR; - - req = GET_CURRENT_REQUEST(&context->hcd); - if (req == NULL) { - DBG_PRINT(SDDBG_ERROR, ("%s(): No current request\n", __FUNCTION__)); - return; - } - - ptr = req->pDataBuffer; - - if (context->complete == S3C24XX_HCD_DATA_READ) { - counter = 0; - DBG_PRINT(SDDBG_TRACE, ("Data read...")); - do { - counter++; - fsta = readl(context->base + S3C2410_SDIFSTA); - mdelay(1); - if (counter > 1000) { - DBG_PRINT(SDDBG_ERROR, ("DATA read timeout\n")); - status = SDIO_STATUS_BUS_READ_TIMEOUT; - s3c24xx_dump_regs(context); - goto out; - } - } while(!(fsta & S3C2410_SDIFSTA_RFDET)); - DBG_PRINT(SDDBG_TRACE, ("RX detected\n")); - - while (1) { - counter = 0; - fifo_count = (readl(context->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK); - while (!fifo_count) { - counter++; - mdelay(1); - if (counter > 500) { - s3c24xx_dump_regs(context); - DBG_PRINT(SDDBG_ERROR, ("No more bytes in FIFO\n")); - goto out; - } - fifo_count = (readl(context->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK); - } - - if (fifo_count > req->DataRemaining) { - DBG_PRINT(SDDBG_ERROR, ("DATA read, fifo_count %d > expected %d\n", fifo_count, req->DataRemaining)); - fifo_count = req->DataRemaining; - } - - req->DataRemaining -= fifo_count; - while (fifo_count > 0) { - if (context->data_size == 4) - *(ptr) = readl(context->base + S3C2440_SDIDATA); - else if (context->data_size == 2) - *(ptr) = readw(context->base + S3C2440_SDIDATA); - else - *(ptr) = readb(context->base + S3C2440_SDIDATA); - - ptr += context->data_size; - fifo_count -= context->data_size; - - } - - if (!req->DataRemaining) { - /* We poll for xfer finish */ - counter = 0; - while (!(readl(context->base + S3C2410_SDIDSTA) - & S3C2410_SDIDSTA_XFERFINISH)) { - counter++; - mdelay(1); - if (counter > 500) { - DBG_PRINT(SDDBG_ERROR, ("RX XFERFINISH missing\n")); - s3c24xx_dump_regs(context); - break; - } - } - - status = SDIO_STATUS_SUCCESS; - goto out; - } - } - - } else if (context->complete == S3C24XX_HCD_DATA_WRITE) { - counter = 0; - DBG_PRINT(SDDBG_TRACE, ("Data write...")); - do { - counter++; - fsta = readl(context->base + S3C2410_SDIFSTA); - mdelay(1); - if (counter > 1000) { - DBG_PRINT(SDDBG_ERROR, ("DATA write timeout\n")); - status = SDIO_STATUS_BUS_WRITE_ERROR; - goto out; - break; - } - - } while(!(fsta & S3C2410_SDIFSTA_TFDET)); - DBG_PRINT(SDDBG_TRACE, ("TX detected\n")); - - while (1) { - counter = 0; - fifo_count = 63 - (readl(context->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK); - while (!fifo_count) { - counter++; - mdelay(1); - if (counter > 500) { - s3c24xx_dump_regs(context); - DBG_PRINT(SDDBG_ERROR, ("No more space in FIFO\n")); - goto out; - } - fifo_count = 63 - (readl(context->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK); - } - - if (fifo_count > req->DataRemaining) - fifo_count = req->DataRemaining; - - req->DataRemaining -= fifo_count; - - while (fifo_count > 0) { - if (context->data_size == 4) - writel(*(ptr), context->base + S3C2440_SDIDATA); - else if (context->data_size == 2) - writew(*(ptr), context->base + S3C2440_SDIDATA); - else - writeb(*(ptr), context->base + S3C2440_SDIDATA); - - ptr += context->data_size; - fifo_count -= context->data_size; - } - - if (!req->DataRemaining) { - /* We poll for xfer finish */ - counter = 0; - while (!(readl(context->base + S3C2410_SDIDSTA) - & S3C2410_SDIDSTA_XFERFINISH)) { - counter++; - mdelay(1); - if (counter > 500) { - DBG_PRINT(SDDBG_ERROR, ("RX XFERFINISH missing\n")); - s3c24xx_dump_regs(context); - break; - } - } - - status = SDIO_STATUS_SUCCESS; - goto out; - } - } - - } else { - DBG_PRINT(SDDBG_ERROR, ("Wrong context: %d\n", context->complete)); - } - - out: - req->Status = status; -} - -static void s3c24xx_hcd_io_work(struct work_struct *work) -{ - PSDREQUEST req; - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - struct s3c24xx_hcd_context * context = - container_of(work, struct s3c24xx_hcd_context, io_work); - - req = GET_CURRENT_REQUEST(&context->hcd); - if (req == NULL) { - DBG_PRINT(SDDBG_ERROR, ("%s(): No current request\n", __FUNCTION__)); - return; - } - - if (req->Status == SDIO_STATUS_BUS_RESP_TIMEOUT) { - DBG_PRINT(SDDBG_ERROR, ("### TIMEOUT ###\n")); - s3c24xx_dump_regs(context); - goto out; - } - - if (context->complete == S3C24XX_HCD_NO_RESPONSE && - req->Status == SDIO_STATUS_SUCCESS) { - DBG_PRINT(SDDBG_TRACE, ("CMD done, Status: %d\n", req->Status)); - printk("CMD done, Status: %d\n", req->Status); - goto out; - } - - if ((context->complete == S3C24XX_HCD_RESPONSE_SHORT || - context->complete == S3C24XX_HCD_RESPONSE_LONG || - context->complete == S3C24XX_HCD_DATA_READ || - context->complete == S3C24XX_HCD_DATA_WRITE) && - req->Status == SDIO_STATUS_SUCCESS) { - u32 resp[4]; - - /* We need to copy the response data and send it over */ - resp[0] = readl(context->base + S3C2410_SDIRSP0); - resp[1] = readl(context->base + S3C2410_SDIRSP1); - resp[2] = readl(context->base + S3C2410_SDIRSP2); - resp[3] = readl(context->base + S3C2410_SDIRSP3); - - if (GET_SDREQ_RESP_TYPE(req->Flags) != SDREQ_FLAGS_RESP_R2) { - DBG_PRINT(SDDBG_TRACE, ("SHORT response: 0x%08x\n", resp[0])); - memcpy(&req->Response[1], (u8*)resp, 4); - req->Response[5] = (readl(context->base + S3C2410_SDICMDSTAT) & 0xff); - } else { - printk("LONG response: 0x%08x\n", resp[0]); - DBG_PRINT(SDDBG_TRACE, ("LONG response: 0x%08x\n", resp[0])); - memcpy(&req->Response[1], (u8*)resp, 16); - //req->Response[17] = (readl(context->base + S3C2410_SDICMDSTAT) & 0xff); - } - - /* There is a data stage */ - if (context->complete == S3C24XX_HCD_DATA_READ || - context->complete == S3C24XX_HCD_DATA_WRITE) { - status = SDIO_CheckResponse(&context->hcd, req, - SDHCD_CHECK_DATA_TRANS_OK); - - if (!SDIO_SUCCESS(status)) { - DBG_PRINT(SDDBG_ERROR, - ("Target not ready for data xfer\n")); - return; - } - - if (context->dma_en) { - dma_sync_single(NULL, context->io_buffer_dma, - req->BlockCount * req->BlockLen, DMA_BIDIRECTIONAL); - - s3c2410_dma_ctrl(context->dma_channel, S3C2410_DMAOP_START); - - wait_for_completion(&context->dma_complete); - - s3c24xx_hcd_dma_complete(context); - } else { - s3c24xx_hcd_pio_complete(context); - } - } - } - - out: - s3c24xx_hcd_clear_sta(context); - s3c24xx_hcd_clear_imask(context); - - writel(0, context->base + S3C2410_SDICMDARG); - writel(0, context->base + S3C2410_SDICMDCON); - - SDIO_HandleHcdEvent(&context->hcd, EVENT_HCD_TRANSFER_DONE); -} - -static void s3c24xx_hcd_irq_work(struct work_struct *work) -{ - struct s3c24xx_hcd_context * context = - container_of(work, struct s3c24xx_hcd_context, irq_work); - - disable_irq(context->io_irq); - - writel(S3C2410_SDIDSTA_SDIOIRQDETECT, context->base + S3C2410_SDIDSTA); - - SDIO_HandleHcdEvent(&context->hcd, EVENT_HCD_SDIO_IRQ_PENDING); - - enable_irq(context->io_irq); -} - -void s3c24xx_hcd_dma_done(struct s3c2410_dma_chan *dma_ch, void *buf_id, - int size, enum s3c2410_dma_buffresult result) -{ - struct s3c24xx_hcd_context * context = - (struct s3c24xx_hcd_context *) buf_id; - - if (result != S3C2410_RES_OK) { - DBG_PRINT(SDDBG_ERROR, ("%s(): DMA xfer failed: %d\n", __FUNCTION__, result)); - s3c24xx_dump_regs(context); - } - - context->latest_xfer_size = size; - complete(&context->dma_complete); -} - -static int s3c24xx_hcd_prepare_dma(struct s3c24xx_hcd_context * context) -{ - PSDREQUEST req; - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - int read = 0, hwcfg = S3C2410_DISRCC_INC | S3C2410_DISRCC_APB; - enum s3c2410_dmasrc source = S3C2410_DMASRC_MEM; - - req = GET_CURRENT_REQUEST(&context->hcd); - if (req == NULL) { - DBG_PRINT(SDDBG_ERROR, ("%s(): No current request\n", __FUNCTION__)); - status = SDIO_STATUS_ERROR; - } - - if (!context->dma_en) { - DBG_PRINT(SDDBG_ERROR, ("%s(): DMA is disabled\n", __FUNCTION__)); - status = SDIO_STATUS_ERROR; - } - - if (!IS_SDREQ_DATA_TRANS(req->Flags)) { - DBG_PRINT(SDDBG_ERROR, ("%s(): No data to transfer\n", __FUNCTION__)); - status = SDIO_STATUS_ERROR; - } - - if(!IS_SDREQ_WRITE_DATA(req->Flags)) { - read = 1; - source = S3C2410_DMASRC_HW; - hwcfg = S3C2410_DISRCC_APB | 1; - } else { - memcpy(context->io_buffer, req->pDataBuffer, req->DataRemaining); - dma_sync_single(NULL, context->io_buffer_dma, - req->BlockCount * req->BlockLen, DMA_BIDIRECTIONAL); - - } - - s3c2410_dma_devconfig(context->dma_channel, source, hwcfg, - (unsigned long)context->mem->start + S3C2440_SDIDATA); - - s3c2410_dma_config(context->dma_channel, context->data_size, - S3C2410_DCON_CH0_SDI); - //(S3C2410_DCON_HWTRIG | S3C2410_DCON_CH0_SDI)); - - s3c2410_dma_set_buffdone_fn(context->dma_channel, s3c24xx_hcd_dma_done); - -// s3c2410_dma_setflags(context->dma_channel, S3C2410_DMAF_AUTOSTART); - - s3c2410_dma_ctrl(context->dma_channel, S3C2410_DMAOP_FLUSH); - - s3c2410_dma_enqueue(context->dma_channel, context, - context->io_buffer_dma, - req->DataRemaining); - - return 0; -} - - -static irqreturn_t s3c24xx_hcd_irq(int irq, void *dev_id) -{ - u32 cmdsta, dsta, fsta; - unsigned long flags, trace = 0; - PSDREQUEST req; - struct s3c24xx_hcd_context * context = - (struct s3c24xx_hcd_context *)dev_id; - - spin_lock_irqsave(&context->lock, flags); - - s3c24xx_hcd_clear_imask(context); - - cmdsta = readl(context->base + S3C2410_SDICMDSTAT); - dsta = readl(context->base + S3C2410_SDIDSTA); - fsta = readl(context->base + S3C2410_SDIFSTA); - - context->cmdsta = cmdsta; - context->dsta = dsta; - context->fsta = fsta; - - s3c24xx_hcd_clear_csta(context); - - if (dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) { - writel(S3C2410_SDIDSTA_SDIOIRQDETECT, context->base + S3C2410_SDIDSTA); - - if (context->int_sdio) { - u32 imask; - - context->int_sdio = 0; - - imask = readl(context->base + S3C2440_SDIIMSK); - imask &= ~S3C2410_SDIIMSK_SDIOIRQ; - writel(imask, context->base + S3C2440_SDIIMSK); - schedule_work(&context->irq_work); - } - } - - req = GET_CURRENT_REQUEST(&context->hcd); - if (req == NULL) { - DBG_PRINT(SDDBG_TRACE, ("%s(): No current request\n", __FUNCTION__)); - goto out; - } - - if (cmdsta & S3C2410_SDICMDSTAT_CMDTIMEOUT) { - DBG_PRINT(SDDBG_ERROR, ("TIMEOUT\n")); - printk("TIMEOUT\n"); - req->Status = SDIO_STATUS_BUS_RESP_TIMEOUT; - writel(S3C2410_SDICMDSTAT_CMDTIMEOUT, context->base + S3C2410_SDICMDSTAT); - schedule_work(&context->io_work); - } - - if (cmdsta & S3C2410_SDICMDSTAT_CRCFAIL) { - DBG_PRINT(SDDBG_ERROR, ("CRCFAIL 0x%x\n", cmdsta)); - printk("CRCFAIL 0x%x\n", cmdsta); - req->Status = SDIO_STATUS_BUS_RESP_CRC_ERR; - dump_request(context); - writel(S3C2410_SDICMDSTAT_CRCFAIL, context->base + S3C2410_SDICMDSTAT); - schedule_work(&context->io_work); - } - - - if (cmdsta & S3C2410_SDICMDSTAT_CMDSENT) { - writel(S3C2410_SDICMDSTAT_CMDSENT, context->base + S3C2410_SDICMDSTAT); - - if (context->complete == S3C24XX_HCD_NO_RESPONSE) { - req->Status = SDIO_STATUS_SUCCESS; - trace = 1; - schedule_work(&context->io_work); - } - } - - if (cmdsta & S3C2410_SDICMDSTAT_RSPFIN || - (IS_SDREQ_WRITE_DATA(req->Flags) && (fsta & S3C2410_SDIFSTA_TFDET)) || - (!IS_SDREQ_WRITE_DATA(req->Flags) && (fsta & S3C2410_SDIFSTA_RFDET))) { - - writel(S3C2410_SDICMDSTAT_RSPFIN, context->base + S3C2410_SDICMDSTAT); - - if (context->complete == S3C24XX_HCD_RESPONSE_SHORT || - context->complete == S3C24XX_HCD_RESPONSE_LONG || - context->complete == S3C24XX_HCD_DATA_READ || - context->complete == S3C24XX_HCD_DATA_WRITE) { - req->Status = SDIO_STATUS_SUCCESS; - if (trace) - printk("IO work already scheduled, cmdsta: 0x%x\n", cmdsta); - schedule_work(&context->io_work); - } - } - - out: - if (dsta & S3C2410_SDIDSTA_RDYWAITREQ) { - printk("S3C2410_SDIDSTA_RDYWAITREQ\n"); - //writel(S3C2410_SDIDSTA_RDYWAITREQ, context->base + S3C2410_SDIDSTA); - } - - if (dsta & S3C2410_SDIDSTA_FIFOFAIL) { - printk("S3C2410_SDIDSTA_FIFOFAIL\n"); - writel(S3C2410_SDIDSTA_FIFOFAIL, context->base + S3C2410_SDIDSTA); - } - - if (dsta & S3C2410_SDIDSTA_CRCFAIL) { - printk("S3C2410_SDIDSTA_CRCFAIL\n"); - writel(S3C2410_SDIDSTA_CRCFAIL, context->base + S3C2410_SDIDSTA); - } - - if (dsta & S3C2410_SDIDSTA_RXCRCFAIL) { - printk("S3C2410_SDIDSTA_RXCRCFAIL\n"); - writel(S3C2410_SDIDSTA_RXCRCFAIL, context->base + S3C2410_SDIDSTA); - } - - if (dsta & S3C2410_SDIDSTA_DATATIMEOUT) { - printk("S3C2410_SDIDSTA_DATATIMEOUT\n"); - writel(S3C2410_SDIDSTA_DATATIMEOUT, context->base + S3C2410_SDIDSTA); - } - - if (dsta & S3C2410_SDIDSTA_BUSYFINISH) { - printk("S3C2410_SDIDSTA_BUSYFINISH\n"); - writel(S3C2410_SDIDSTA_BUSYFINISH, context->base + S3C2410_SDIDSTA); - } - - if (dsta & S3C2410_SDIDSTA_SBITERR) { - printk("S3C2410_SDIDSTA_SBIERR\n"); - writel(S3C2410_SDIDSTA_SBITERR, context->base + S3C2410_SDIDSTA); - } - - spin_unlock_irqrestore(&context->lock, flags); - return IRQ_HANDLED; -} - - -SDIO_STATUS s3c24xx_hcd_config(PSDHCD hcd, PSDCONFIG config) -{ - u32 con, imsk; - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - PSDCONFIG_SDIO_INT_CTRL_DATA int_data; - struct s3c24xx_hcd_context * context = (struct s3c24xx_hcd_context *)hcd->pContext; - - switch (GET_SDCONFIG_CMD(config)){ - case SDCONFIG_GET_WP: - DBG_PRINT(SDDBG_TRACE, ("config GET_WP\n")); - *((SDCONFIG_WP_VALUE *)config->pData) = 0; - status = SDIO_STATUS_SUCCESS; - break; - case SDCONFIG_SEND_INIT_CLOCKS: - DBG_PRINT(SDDBG_TRACE, ("config SEND_INIT_CLOCKS\n")); - - /* We stop/start the clock */ - con = readl(context->base + S3C2410_SDICON); - - con &= ~S3C2410_SDICON_CLOCKTYPE; - writel(con, context->base + S3C2410_SDICON); - - mdelay(100); - - con |= S3C2410_SDICON_CLOCKTYPE; - writel(con, context->base + S3C2410_SDICON); - - mdelay(100); - - status = SDIO_STATUS_SUCCESS; - break; - case SDCONFIG_SDIO_INT_CTRL: - DBG_PRINT(SDDBG_TRACE, ("config SDIO_INT_CTRL\n")); - int_data = GET_SDCONFIG_CMD_DATA(PSDCONFIG_SDIO_INT_CTRL_DATA, config); - - if (int_data->SlotIRQEnable & - (IRQ_DETECT_1_BIT | IRQ_DETECT_4_BIT | IRQ_DETECT_MULTI_BLK) ) { - imsk = readl(context->base + S3C2440_SDIIMSK); - - if (int_data->SlotIRQEnable) { - printk("SDIO_INT_CTRL enable IRQ\n"); - DBG_PRINT(SDDBG_TRACE, ("SDIO_INT_CTRL enable IRQ\n")); - context->int_sdio = 1; - imsk |= S3C2410_SDIIMSK_SDIOIRQ; - writel(imsk, context->base + S3C2440_SDIIMSK); - } else { - printk("SDIO_INT_CTRL disable IRQ\n"); - DBG_PRINT(SDDBG_TRACE, ("SDIO_INT_CTRL disable IRQ\n")); - context->int_sdio = 0; - imsk &= ~S3C2410_SDIIMSK_SDIOIRQ; - writel(imsk, context->base + S3C2440_SDIIMSK); - } - } - status = SDIO_STATUS_SUCCESS; - break; - case SDCONFIG_SDIO_REARM_INT: - DBG_PRINT(SDDBG_TRACE, ("config SDIO_REARM_INT\n")); - - context->int_sdio = 1; - imsk = readl(context->base + S3C2440_SDIIMSK); - imsk |= S3C2410_SDIIMSK_SDIOIRQ; - writel(imsk, context->base + S3C2440_SDIIMSK); - - status = SDIO_STATUS_SUCCESS; - break; - case SDCONFIG_FUNC_CHANGE_BUS_MODE: - case SDCONFIG_BUS_MODE_CTRL: - s3c24xx_hcd_set_bus_mode(context, (PSDCONFIG_BUS_MODE_DATA)(config->pData)); - DBG_PRINT(SDDBG_TRACE, ("config BUS_MODE_CTRL\n")); - status = SDIO_STATUS_SUCCESS; - break; - case SDCONFIG_POWER_CTRL: - DBG_PRINT(SDDBG_TRACE, ("config POWER_CTRL\n")); - status = SDIO_STATUS_SUCCESS; - break; - case SDCONFIG_GET_HCD_DEBUG: - DBG_PRINT(SDDBG_TRACE, ("config GET_HCD_DEBUG\n")); - status = SDIO_STATUS_SUCCESS; - break; - case SDCONFIG_SET_HCD_DEBUG: - DBG_PRINT(SDDBG_TRACE, ("config SET_HCD_DEBUG\n")); - status = SDIO_STATUS_SUCCESS; - break; - default: - /* invalid request */ - DBG_PRINT(SDDBG_ERROR, ("%s() - unsupported command: 0x%X\n", - __FUNCTION__, GET_SDCONFIG_CMD(config))); - status = SDIO_STATUS_INVALID_PARAMETER; - } - - return SDIOErrorToOSError(status); -} - - -SDIO_STATUS s3c24xx_hcd_request(PSDHCD hcd) -{ - SDIO_STATUS status = SDIO_STATUS_PENDING; - PSDREQUEST req; - u32 cmdcon, imask; - unsigned long flags; - struct s3c24xx_hcd_context * context = - (struct s3c24xx_hcd_context *)hcd->pContext; - - req = GET_CURRENT_REQUEST(hcd); - DBG_ASSERT(req != NULL); - - if (req->Flags & SDREQ_FLAGS_DATA_SHORT_TRANSFER) - printk("### SHORT TRANSFER ###\n"); - - spin_lock_irqsave(&context->lock, flags); - - /* Clear command, data and fifo status registers */ - writel(0xFFFFFFFF, context->base + S3C2410_SDICMDSTAT); - writel(0xFFFFFFFF, context->base + S3C2410_SDIDSTA); - writel(0xFFFFFFFF, context->base + S3C2410_SDIFSTA); - - /* Enabling irqs */ - imask = S3C2410_SDIIMSK_READWAIT; - - cmdcon = readl(context->base + S3C2410_SDICMDCON); - - switch (GET_SDREQ_RESP_TYPE(req->Flags)) { - case SDREQ_FLAGS_NO_RESP: - cmdcon &= ~S3C2410_SDICMDCON_WAITRSP; - context->complete = S3C24XX_HCD_NO_RESPONSE; - imask |= S3C2410_SDIIMSK_CMDSENT; - break; - case SDREQ_FLAGS_RESP_R1: - case SDREQ_FLAGS_RESP_R1B: - case SDREQ_FLAGS_RESP_R3: - case SDREQ_FLAGS_RESP_SDIO_R4: - case SDREQ_FLAGS_RESP_SDIO_R5: - case SDREQ_FLAGS_RESP_R6: - cmdcon &= ~S3C2410_SDICMDCON_LONGRSP; - cmdcon |= S3C2410_SDICMDCON_WAITRSP; - context->complete = S3C24XX_HCD_RESPONSE_SHORT; - imask |= S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_RESPONSEND - | S3C2410_SDIIMSK_CMDTIMEOUT | S3C2410_SDIIMSK_RESPONSECRC; - break; - case SDREQ_FLAGS_RESP_R2: - cmdcon |= S3C2410_SDICMDCON_LONGRSP; - cmdcon |= S3C2410_SDICMDCON_WAITRSP; - context->complete = S3C24XX_HCD_RESPONSE_LONG; - imask |= S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_RESPONSEND - | S3C2410_SDIIMSK_CMDTIMEOUT | S3C2410_SDIIMSK_RESPONSECRC; - break; - - } - - /* There is a data part */ - if (IS_SDREQ_DATA_TRANS(req->Flags)) { - u32 dcon = 0; - - if (readl(context->base + S3C2410_SDIDSTA) & - (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) { - printk("##### DATA ON: 0x%x ######\n", readl(context->base + S3C2410_SDIDSTA)); - } - - /* Setting timer */ - writel(0x7fffff, context->base + S3C2410_SDITIMER); - - /* Block size */ - writel(req->BlockLen, context->base + S3C2410_SDIBSIZE); - /* Number of blocks */ - dcon |= (0xfff & req->BlockCount); - - if (context->bus_width == 4) - dcon |= S3C2410_SDIDCON_WIDEBUS; - - req->DataRemaining = req->BlockCount * req->BlockLen; - - /* Set data size, and start the transfer */ - dcon |= S3C2410_SDIDCON_IRQPERIOD; - if (!(req->DataRemaining % 4)) { - context->data_size = 4; - dcon |= S3C2440_SDIDCON_DS_WORD; - } else if (!(req->DataRemaining % 2)) { - context->data_size = 2; - dcon |= S3C2440_SDIDCON_DS_HALFWORD; - } else { - context->data_size = 1; - dcon |= S3C2440_SDIDCON_DS_BYTE; - } - -#ifdef CONFIG_SDIO_S3C24XX_DMA - if (req->DataRemaining > 16) { - context->dma_en = 1; - } else -#endif - { - context->dma_en = 0; - context->data_size = 1; - dcon |= S3C2440_SDIDCON_DS_BYTE; - } - - if (context->dma_en) { - dcon |= S3C2410_SDIDCON_DMAEN; - s3c24xx_hcd_prepare_dma(context); - } - - if (IS_SDREQ_WRITE_DATA(req->Flags)) { - /* Data write */ - DBG_PRINT(SDDBG_TRACE, ("Start data write, block count=%d, block size=%d\n", - req->BlockCount, req->BlockLen)); - - /* Data configuration: transmit after resp, block mode*/ - dcon |= S3C2410_SDIDCON_TXAFTERRESP | S3C2410_SDIDCON_BLOCKMODE; - - /* This is a write */ - dcon |= S3C2410_SDIDCON_XFER_TXSTART; - - imask |= S3C2410_SDIIMSK_TXFIFOHALF | S3C2410_SDIIMSK_TXFIFOEMPTY | - S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC | - S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH; - - context->complete = S3C24XX_HCD_DATA_WRITE; - } else { - /* Data read */ - DBG_PRINT(SDDBG_TRACE, ("Start data read, block count=%d, block size=%d\n", - req->BlockCount, req->BlockLen)); - - /* Data configuration: receive after cmd, block mode*/ - dcon |= S3C2410_SDIDCON_RXAFTERCMD | S3C2410_SDIDCON_BLOCKMODE; - - /* This is a read */ - dcon |= S3C2410_SDIDCON_XFER_RXSTART; - - imask |= S3C2410_SDIIMSK_RXFIFOHALF | S3C2410_SDIIMSK_RXFIFOLAST | - S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC | - S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH; - - context->complete = S3C24XX_HCD_DATA_READ; - } - - dcon |= S3C2440_SDIDCON_DATSTART; - - writel(dcon, context->base + S3C2410_SDIDCON); - - cmdcon |= S3C2410_SDICMDCON_WITHDATA; - - } else { - cmdcon &= ~S3C2410_SDICMDCON_WITHDATA; - } - - cmdcon |= req->Command & S3C2410_SDICMDCON_INDEX; - cmdcon |= S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART; - - req->Status = SDIO_STATUS_PENDING; - - if (context->int_sdio) - imask |= S3C2410_SDIIMSK_SDIOIRQ; - context->int_mask = imask; - writel(imask, context->base + S3C2440_SDIIMSK); - writel(req->Argument, context->base + S3C2410_SDICMDARG); - writel(cmdcon, context->base + S3C2410_SDICMDCON); - - spin_unlock_irqrestore(&context->lock, flags); - - return status; -} - -static int s3c24xx_hcd_hw_init(struct s3c24xx_hcd_context * context) -{ - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - u32 con, datacon; - - /* Clock */ - context->device.clock = clk_get(NULL, "sdi"); - if (IS_ERR(context->device.clock)) { - DBG_PRINT(SDDBG_ERROR, ("Couldn't get clock\n")); - status = PTR_ERR(context->device.clock); - context->device.clock = NULL; - return status; - } - - status = clk_enable(context->device.clock); - if (SDIO_IS_ERROR(status)) { - DBG_PRINT(SDDBG_ERROR, ("Couldn't get clock\n")); - return SDIOErrorToOSError(status); - } - - context->device.max_clock_rate = clk_get_rate(context->device.clock); - context->device.actual_clock_rate = context->device.max_clock_rate; - - /* I/O */ - context->mem = request_mem_region(context->mem->start, - RESSIZE(context->mem), context->description); - - if (!context->mem) { - DBG_PRINT(SDDBG_ERROR, ("Failed to request io memory region\n")); - status = -ENOENT; - goto out_disable_clock; - } - - context->base = ioremap(context->mem->start, RESSIZE(context->mem)); - if (context->base == 0) { - DBG_PRINT(SDDBG_ERROR, ("failed to ioremap() io memory region.\n")); - status = -EINVAL; - goto out_free_mem_region; - } - - /* IRQ */ -#if 0 - context->cd_irq = s3c2410_gpio_getirq(GTA02v1_GPIO_nSD_DETECT); - s3c2410_gpio_cfgpin(GTA02v1_GPIO_nSD_DETECT, S3C2410_GPIO_IRQ); - - if (request_irq(context->cd_irq, s3c24xx_hcd_cd_irq, 0, context->description, context)) { - DBG_PRINT(SDDBG_ERROR, ("failed to request card detect interrupt.\n")); - status = -ENOENT; - goto out_unmap_mem_region; - } -#endif - - if (request_irq(context->io_irq, s3c24xx_hcd_irq, 0, context->description, context)) { - DBG_PRINT(SDDBG_ERROR, ("failed to request mci interrupt.\n")); - status = -ENOENT; - goto out_unmap_mem_region; - } - - - /* DMA */ - context->io_buffer_size = 4 * 4096; - context->io_buffer = dma_alloc_writecombine(&context->pdev->dev, - context->io_buffer_size, - &context->io_buffer_dma, - GFP_KERNEL | GFP_DMA); - - if (context->io_buffer == NULL) { - DBG_PRINT(SDDBG_ERROR, ("failed to allocate DMA buffer\n")); - status = -ENOMEM; - goto out_free_irq; - - } - - if (s3c2410_dma_request(context->dma_channel, &s3c24xx_hcd_dma_client, - NULL) < 0) { - DBG_PRINT(SDDBG_ERROR, ("unable to get DMA channel.\n")); - status = -ENOENT; - goto out_free_dma; - } - - - /* Set multiplexing */ - s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD); - s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0); - s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1); - s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2); - s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3); - - con = readl(context->base + S3C2410_SDICON); - con |= S3C2410_SDICON_SDIOIRQ; - writel(con, context->base + S3C2410_SDICON); - - datacon = readl(context->base + S3C2410_SDIDCON); - datacon |= S3C2410_SDIDCON_WIDEBUS; - writel(datacon, context->base + S3C2410_SDIDCON); - - printk("S3c24xx SDIO: IRQ:%d Detect IRQ:%d DMA channel:%d base@0x%p PCLK@%ld kHz\n", - context->io_irq, context->cd_irq, context->dma_channel, context->base, - context->device.max_clock_rate/1000); - - return SDIOErrorToOSError(status); - - out_free_dma: - dma_free_writecombine(&context->pdev->dev,context->io_buffer_size, - context->io_buffer, context->io_buffer_dma); - - out_free_irq: - free_irq(context->io_irq, context); - - out_unmap_mem_region: - iounmap(context->base); - - out_free_mem_region: - release_mem_region(context->mem->start, RESSIZE(context->mem)); - - out_disable_clock: - clk_disable(context->device.clock); - - return SDIOErrorToOSError(status); -} - -static void s3c24xx_hcd_hw_cleanup(struct s3c24xx_hcd_context * context) -{ - clk_disable(context->device.clock); - free_irq(context->io_irq, context); - iounmap(context->base); - release_mem_region(context->mem->start, RESSIZE(context->mem)); - dma_free_writecombine(&context->pdev->dev,context->io_buffer_size, - context->io_buffer, context->io_buffer_dma); -} - -static int s3c24xx_hcd_pnp_probe(struct pnp_dev *pBusDevice, const struct pnp_device_id *pId) -{ - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - - status = s3c24xx_hcd_hw_init(&hcd_context); - if (SDIO_IS_ERROR(status)) { - DBG_PRINT(SDDBG_ERROR, ("HW Init failed\n")); - return SDIOErrorToOSError(status); - } - - status = SDIO_RegisterHostController(&hcd_context.hcd); - if (SDIO_IS_ERROR(status)) { - DBG_PRINT(SDDBG_ERROR, ("Host registration failed\n")); - s3c24xx_hcd_hw_cleanup(&hcd_context); - return SDIOErrorToOSError(status); - } - - /* Our card is built-in, we force the attachement event */ - SDIO_HandleHcdEvent(&hcd_context.hcd, EVENT_HCD_ATTACH); - - return 0; -} - -static void s3c24xx_hcd_pnp_remove(struct pnp_dev *pBusDevice) -{ -} - -/* the driver context data */ -struct s3c24xx_hcd_context hcd_context = { - .description = DESCRIPTION, - .hcd.pName = "sdio_s3c24xx", - .hcd.Version = CT_SDIO_STACK_VERSION_CODE, - .hcd.pModule = THIS_MODULE, - /* builtin card, 4 bits bus */ - .hcd.Attributes = SDHCD_ATTRIB_BUS_4BIT | SDHCD_ATTRIB_BUS_1BIT | SDHCD_ATTRIB_MULTI_BLK_IRQ, - .hcd.SlotNumber = 0, - .hcd.MaxSlotCurrent = 500, /* 1/2 amp */ - .hcd.SlotVoltageCaps = SLOT_POWER_3_3V, /* 3.3V */ - .hcd.SlotVoltagePreferred = SLOT_POWER_3_3V, /* 3.3V */ - .hcd.MaxClockRate = 25000000, - .hcd.MaxBytesPerBlock = 0xfff, /* 0 - 4095 */ - .hcd.MaxBlocksPerTrans = 0xfff, /* 0 - 4095 */ - .hcd.pContext = &hcd_context, - .hcd.pRequest = s3c24xx_hcd_request, - .hcd.pConfigure = s3c24xx_hcd_config, - .device.pnp_driver.name = "sdio_s3c24xx_hcd", - .device.pnp_driver.probe = s3c24xx_hcd_pnp_probe, - .device.pnp_driver.remove = s3c24xx_hcd_pnp_remove, -}; - -static int s3c24xx_hcd_probe(struct platform_device * pdev) -{ - SDIO_STATUS status = SDIO_STATUS_SUCCESS; - struct resource *r = NULL; - - printk("S3c2440 SDIO Host controller\n"); - - hcd_context.pdev = pdev; - - hcd_context.mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (hcd_context.mem == NULL) { - DBG_PRINT(SDDBG_ERROR, ("No memory region\n")); - status = SDIO_STATUS_NO_RESOURCES; - goto out; - } - - hcd_context.io_irq = platform_get_irq(pdev, 0); - if (hcd_context.io_irq == 0) { - DBG_PRINT(SDDBG_ERROR, ("No IRQ\n")); - status = SDIO_STATUS_NO_RESOURCES; - goto out; - } - - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (r == NULL) { - DBG_PRINT(SDDBG_ERROR, ("No DMA channel\n")); - status = SDIO_STATUS_NO_RESOURCES; - goto out; - } - hcd_context.dma_channel = r->start; - hcd_context.dma_en = 0; - - hcd_context.int_sdio = 0; - - spin_lock_init(&hcd_context.lock); - - init_completion(&hcd_context.dma_complete); - init_completion(&hcd_context.xfer_complete); - - INIT_WORK(&hcd_context.io_work, s3c24xx_hcd_io_work); - INIT_WORK(&hcd_context.irq_work, s3c24xx_hcd_irq_work); - - mdelay(100); - - status = SDIO_BusAddOSDevice(&hcd_context.device.dma, - &hcd_context.device.pnp_driver, - &hcd_context.device.pnp_device, "sdio_s3c24xx_hcd"); - - out: - - return SDIOErrorToOSError(status); -} - -/* - * module cleanup - */ -static int s3c24xx_hcd_remove(struct platform_device * pdev) { - printk("S3C2440 SDIO host controller unloaded\n"); - SDIO_BusRemoveOSDevice(&hcd_context.device.pnp_driver, hcd_context.device.pnp_device); - kfree(hcd_context.device.pnp_device); - - return 0; -} - -#ifdef CONFIG_PM - -static int s3c24xx_hcd_suspend(struct platform_device * pdev, pm_message_t state) -{ - struct s3c24xx_hcd_context * context = &hcd_context; - unsigned long flags; - - spin_lock_irqsave(&context->lock, flags); - - context->suspend_regs.con = readl(context->base + S3C2410_SDICON); - context->suspend_regs.pre = readl(context->base + S3C2410_SDIPRE); - context->suspend_regs.cmdarg = readl(context->base + S3C2410_SDICMDARG); - context->suspend_regs.cmdcon = readl(context->base + S3C2410_SDICMDCON); - context->suspend_regs.cmdsta = readl(context->base + S3C2410_SDICMDSTAT); - context->suspend_regs.r0 = readl(context->base + S3C2410_SDIRSP0); - context->suspend_regs.r1 = readl(context->base + S3C2410_SDIRSP1); - context->suspend_regs.r2 = readl(context->base + S3C2410_SDIRSP2); - context->suspend_regs.r3 = readl(context->base + S3C2410_SDIRSP3); - context->suspend_regs.timer = readl(context->base + S3C2410_SDITIMER); - context->suspend_regs.bsize = readl(context->base + S3C2410_SDIBSIZE); - context->suspend_regs.datcon = readl(context->base + S3C2410_SDIDCON); - context->suspend_regs.datcnt = readl(context->base + S3C2410_SDIDCNT); - context->suspend_regs.datsta = readl(context->base + S3C2410_SDIDSTA); - context->suspend_regs.fsta = readl(context->base + S3C2410_SDIFSTA); - context->suspend_regs.imask = readl(context->base + S3C2440_SDIIMSK); - - spin_unlock_irqrestore(&context->lock, flags); - return 0; -} - -static int s3c24xx_hcd_resume(struct platform_device * pdev) -{ - struct s3c24xx_hcd_context * context = &hcd_context; - unsigned long flags; - - spin_lock_irqsave(&context->lock, flags); - - writel(context->suspend_regs.con, context->base + S3C2410_SDICON); - writel(context->suspend_regs.pre, context->base + S3C2410_SDIPRE); - writel(context->suspend_regs.cmdarg, context->base + S3C2410_SDICMDARG); - writel(context->suspend_regs.cmdcon, context->base + S3C2410_SDICMDCON); - writel(context->suspend_regs.cmdsta, context->base + S3C2410_SDICMDSTAT); - writel(context->suspend_regs.r0, context->base + S3C2410_SDIRSP0); - writel(context->suspend_regs.r1, context->base + S3C2410_SDIRSP1); - writel(context->suspend_regs.r2, context->base + S3C2410_SDIRSP2); - writel(context->suspend_regs.r3, context->base + S3C2410_SDIRSP3); - writel(context->suspend_regs.timer, context->base + S3C2410_SDITIMER); - writel(context->suspend_regs.bsize, context->base + S3C2410_SDIBSIZE); - writel(context->suspend_regs.datcon, context->base + S3C2410_SDIDCON); - writel(context->suspend_regs.datcnt, context->base + S3C2410_SDIDCNT); - writel(context->suspend_regs.datsta, context->base + S3C2410_SDIDSTA); - writel(context->suspend_regs.fsta, context->base + S3C2410_SDIFSTA); - writel(context->suspend_regs.imask, context->base + S3C2440_SDIIMSK); - - spin_unlock_irqrestore(&context->lock, flags); - return 0; -} - -#else -#define s3c24xx_hcd_suspend = NULL -#define s3c24xx_hcd_resume = NULL -#endif - -static struct platform_driver s3c24xx_hcd_sdio = -{ - .driver.name = "s3c24xx-sdio", - .probe = s3c24xx_hcd_probe, - .remove = s3c24xx_hcd_remove, - .suspend = s3c24xx_hcd_suspend, - .resume = s3c24xx_hcd_resume, -}; - -#ifdef CONFIG_DEBUG_FS -static struct dentry *debugfs_dir; - -static int s3c24xx_hcd_debugfs_show(struct seq_file *s, void *data) -{ - PSDREQUEST req; - u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize; - u32 datcon, datcnt, datsta, fsta, imask; - struct s3c24xx_hcd_context * context = &hcd_context; - - - con = readl(context->base + S3C2410_SDICON); - pre = readl(context->base + S3C2410_SDIPRE); - cmdarg = readl(context->base + S3C2410_SDICMDARG); - cmdcon = readl(context->base + S3C2410_SDICMDCON); - cmdsta = readl(context->base + S3C2410_SDICMDSTAT); - r0 = readl(context->base + S3C2410_SDIRSP0); - r1 = readl(context->base + S3C2410_SDIRSP1); - r2 = readl(context->base + S3C2410_SDIRSP2); - r3 = readl(context->base + S3C2410_SDIRSP3); - timer = readl(context->base + S3C2410_SDITIMER); - bsize = readl(context->base + S3C2410_SDIBSIZE); - datcon = readl(context->base + S3C2410_SDIDCON); - datcnt = readl(context->base + S3C2410_SDIDCNT); - datsta = readl(context->base + S3C2410_SDIDSTA); - fsta = readl(context->base + S3C2410_SDIFSTA); - imask = readl(context->base + S3C2440_SDIIMSK); - - seq_printf(s, "SDICON: 0x%08x\n", con); - seq_printf(s, "SDIPRE: 0x%08x\n", pre); - seq_printf(s, "SDICmdArg: 0x%08x\n", cmdarg); - seq_printf(s, "SDICmdCon: 0x%08x\n", cmdcon); - seq_printf(s, "SDICmdSta: 0x%08x\n", cmdsta); - seq_printf(s, "SDIRSP0: 0x%08x\n", r0); - seq_printf(s, "SDIRSP1: 0x%08x\n", r1); - seq_printf(s, "SDIRSP2: 0x%08x\n", r2); - seq_printf(s, "SDIRSP3: 0x%08x\n", r3); - seq_printf(s, "SDIDTimer: 0x%08x\n", timer); - seq_printf(s, "SDIBSize: 0x%08x\n", bsize); - seq_printf(s, "SDIDatCon: 0x%08x\n", datcon); - seq_printf(s, "SDIDatCnt: 0x%08x\n", datcnt); - seq_printf(s, "SDIDatSta: 0x%08x\n", datsta); - seq_printf(s, "SDIFSta: 0x%08x\n", fsta); - seq_printf(s, "SDIIntMsk: 0x%08x\n", imask); - seq_printf(s, "\n"); - - seq_printf(s, "Current REQ: \n"); - req = GET_CURRENT_REQUEST(&context->hcd); - if (req == NULL) { - seq_printf(s, " No current request\n"); - } else { - seq_printf(s, " Command: %d\n", req->Command); - seq_printf(s, " Args: 0x%x\n", req->Argument); - seq_printf(s, " Flags: 0x%x\n", req->Flags); - seq_printf(s, " %d blocks x %d bytes\n", req->BlockCount, req->BlockLen); - seq_printf(s, " %d bytes remaining\n", req->DataRemaining); - } - - seq_printf(s, "Context: \n"); - seq_printf(s, " INT mask: 0x%x\n", context->int_mask); - seq_printf(s, " sdio INT: %d\n", context->int_sdio); - seq_printf(s, " cmdsta: 0x%x\n", context->cmdsta); - seq_printf(s, " dsta: 0x%x\n", context->dsta); - seq_printf(s, " fsta: 0x%x\n", context->fsta); - - return 0; -} - -static int s3c24xx_hcd_debugfs_open(struct inode *inode, - struct file *file) -{ - return single_open(file, s3c24xx_hcd_debugfs_show, NULL); -} - -static const struct file_operations s3c24xx_hcd_debugfs_fops = { - .open = s3c24xx_hcd_debugfs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - - -static int s3c24xx_debugfs_init(struct s3c24xx_hcd_context * context) -{ - debugfs_dir = debugfs_create_dir("s3c24xx_sdio", NULL); - - debugfs_create_file("registers", 0444, debugfs_dir, - (void *)context, - &s3c24xx_hcd_debugfs_fops); - - return 0; -} - -#else - -static int s3c24xx_debugfs_init(struct s3c24xx_hcd_context * context) -{ - return 0; -} - -#endif - -static int __init s3c24xx_hcd_init(void) -{ - int ret; - - ret = s3c24xx_debugfs_init(&hcd_context); - if (ret) { - printk("%s(): debugfs init failed\n", __FUNCTION__); - } - - platform_driver_register(&s3c24xx_hcd_sdio); - - return 0; -} - -static void __exit s3c24xx_hcd_exit(void) -{ - platform_driver_unregister(&s3c24xx_hcd_sdio); -} - - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DESCRIPTION); -MODULE_AUTHOR(AUTHOR); - -module_init(s3c24xx_hcd_init); -module_exit(s3c24xx_hcd_exit); |