/*
* linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver
*
* Copyright (c) 2005, Advanced Micro Devices, Inc.
*
* Developed with help from the 2.4.30 MMC AU1XXX controller including
* the following copyright notices:
* Copyright (c) 2003-2004 Embedded Edge, LLC.
* Portions Copyright (C) 2002 Embedix, Inc
* Copyright 2002 Hewlett-Packard Company
* 2.6 version of this driver inspired by:
* (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman,
* All Rights Reserved.
* (drivers/mmc/pxa.c) 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.
*/
/* Why don't we use the SD controllers' carddetect feature?
*
* From the AU1100 MMC application guide:
* If the Au1100-based design is intended to support both MultiMediaCards
* and 1- or 4-data bit SecureDigital cards, then the solution is to
* connect a weak (560KOhm) pull-up resistor to connector pin 1.
* In doing so, a MMC card never enters SPI-mode communications,
* but now the SecureDigital card-detect feature of CD/DAT3 is ineffective
* (the low to high transition will not occur).
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/leds.h>
#include <linux/mmc/host.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1100_mmc.h>
#define DRIVER_NAME "au1xxx-mmc"
/* Set this to enable special debugging macros */
/* #define DEBUG */
#ifdef DEBUG
#define DBG(fmt, idx, args...) \
printk(KERN_DEBUG "au1xmmc(%d): DEBUG: " fmt, idx, ##args)
#else
#define DBG(fmt, idx, args...) do {} while (0)
#endif
/* Hardware definitions */
#define AU1XMMC_DESCRIPTOR_COUNT 1
/* max DMA seg size: 64KB on Au1100, 4MB on Au1200 */
#ifdef CONFIG_SOC_AU1100
#define AU1XMMC_DESCRIPTOR_SIZE 0x0000ffff
#else /* Au1200 */
#define AU1XMMC_DESCRIPTOR_SIZE 0x003fffff
#endif
#define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \
MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \
MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
/* This gives us a hard value for the stop command that we can write directly
* to the command register.
*/
#define STOP_CMD \
(SD_CMD_RT_1B | SD_CMD_CT_7 | (0xC << SD_CMD_CI_SHIFT) | SD_CMD_GO)
/* This is the set of interrupts that we configure by default. */
#define AU1XMMC_INTERRUPTS \
(SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_RAT | \
SD_CONFIG_CR | SD_CONFIG_I)
/* The poll event (looking for insert/remove events runs twice a second. */
#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
struct au1xmmc_host {
struct mmc_host *mmc;
struct mmc_request *mrq;
u32 flags;
u32 iobase;
u32 clock;
u32 bus_width;
u32 power_mode;
int status;
struct {
int len;
int dir;
} dma;
struct {
int index;
int offset;
int len;
} pio;
u32 tx_chan;
u32 rx_chan;
int irq;
struct tasklet_struct finish_task;
struct tasklet_struct data_task;
struct au1xmmc_platform_data *platdata;
struct platform_device *pdev;
struct resource *ioarea;
};
/* Status flags used by the host structure */
#define HOST_F_XMIT 0x0001
#define HOST_F_RECV 0x0002
#define HOST_F_DMA 0x0010
#define HOST_F_ACTIVE 0x0100
#define HOST_F_STOP 0x1000
#define HOST_S_IDLE 0x0001
#define HOST_S_CMD 0x0002
#define HOST_S_DATA 0x0003
#define HOST_S_STOP 0x0004
/* Easy access macros */
#define HOST_STATUS(h) ((h)->iobase + SD_STATUS)
#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG)
#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE)
#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT)
#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT)
#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG)
#define HOST_BLKSIZE(h) ((h)->iobase + SD_BLKSIZE)
#define HOST_CMD(h) ((h)->iobase + SD_CMD)
#define HOST_CONFIG2(h) ((h)->iobase + SD_CONFIG2)
#define HOST_TIMEOUT(h) ((h)->iobase + SD_TIMEOUT)
#define HOST_DEBUG(h) ((h)->iobase + SD_DEBUG)
#define DMA_CHANNEL(h) \
(((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan)
static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
{
u32 val = au_readl(HOST_CONFIG(host));
val |= mask;
au_writel(val, HOST_CONFIG(host));
au_sync();
}
static inline void FLUSH_FIFO(struct au1xmmc_host *host)
{
u32 val = au_readl(HOST_CONFIG2(host));
au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
au_sync_delay(1);
/* SEND_STOP will turn off clock control - this re-enables it */
val &= ~SD_CONFIG2_DF;
au_writel(val, HOST_CONFIG2(host));
au_sync();
}
static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
{
u32 val = au_readl(HOST_CONFIG(host));
val