/*
* MMCIF eMMC driver.
*
* Copyright (C) 2010 Renesas Solutions Corp.
* Yusuke Goda <yusuke.goda.sx@renesas.com>
*
* 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.
*
*
* TODO
* 1. DMA
* 2. Power management
* 3. Handle MMC errors better
*
*/
/*
* The MMCIF driver is now processing MMC requests asynchronously, according
* to the Linux MMC API requirement.
*
* The MMCIF driver processes MMC requests in up to 3 stages: command, optional
* data, and optional stop. To achieve asynchronous processing each of these
* stages is split into two halves: a top and a bottom half. The top half
* initialises the hardware, installs a timeout handler to handle completion
* timeouts, and returns. In case of the command stage this immediately returns
* control to the caller, leaving all further processing to run asynchronously.
* All further request processing is performed by the bottom halves.
*
* The bottom half further consists of a "hard" IRQ handler, an IRQ handler
* thread, a DMA completion callback, if DMA is used, a timeout work, and
* request- and stage-specific handler methods.
*
* Each bottom half run begins with either a hardware interrupt, a DMA callback
* invocation, or a timeout work run. In case of an error or a successful
* processing completion, the MMC core is informed and the request processing is
* finished. In case processing has to continue, i.e., if data has to be read
* from or written to the card, or if a stop command has to be sent, the next
* top half is called, which performs the necessary hardware handling and
* reschedules the timeout work. This returns the driver state machine into the
* bottom half waiting state.
*/
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sh_mmcif.h>
#include <linux/pagemap.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#define DRIVER_NAME "sh_mmcif"
#define DRIVER_VERSION "2010-04-28"
/* CE_CMD_SET */
#define CMD_MASK 0x3f000000
#define CMD_SET_RTYP_NO ((0 << 23) | (0 << 22))
#define CMD_SET_RTYP_6B ((0 << 23) | (1 << 22)) /* R1/R1b/R3/R4/R5 */
#define CMD_SET_RTYP_17B ((1 << 23) | (0 << 22)) /* R2 */
#define CMD_SET_RBSY (1 << 21) /* R1b */
#define CMD_SET_CCSEN (1 << 20)
#define CMD_SET_WDAT (1 << 19) /* 1: on data, 0: no data */
#define CMD_SET_DWEN (1 << 18) /* 1: write, 0: read */
#define CMD_SET_CMLTE (1 << 17) /* 1: multi block trans, 0: single */
#define CMD_SET_CMD12EN (1 << 16) /* 1: CMD12 auto issue */
#define CMD_SET_RIDXC_INDEX ((0 << 15) | (0 << 14)) /* index check */
#de