Commit bbb6b218 authored by Russell King's avatar Russell King

[MMC] Add MMC core support

This patch adds core support to the Linux kernel for driving MMC
interfaces found on embedded devices, such as found in the Intel
PXA and ARM MMCI primecell.  This patch does _not_ add support
for SD or SDIO cards.
                                                                                
It is vaguely based upon the handhelds.org MMC code, but the bulk
of the core has been rewritten from scratch.
parent 472bca81
#
# MMC subsystem configuration
#
menu "MMC/SD Card support"
config MMC
tristate "MMC support"
help
MMC is the "multi-media card" bus protocol.
If you want MMC support, you should say Y here and also
to the specific driver for your MMC interface.
config MMC_DEBUG
bool "MMC debugging"
depends on MMC != n
help
This is an option for use by developers; most people should
say N here. This enables MMC core and driver debugging.
config MMC_BLOCK
tristate "MMC block device driver"
depends on MMC
default y
help
Say Y here to enable the MMC block device driver support.
This provides a block device driver, which you can use to
mount the filesystem. Almost everyone wishing MMC support
should say Y or M here.
endmenu
#
# Makefile for the kernel mmc device drivers.
#
#
# Core
#
obj-$(CONFIG_MMC) += mmc_core.o
#
# Media drivers
#
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
#
# Host drivers
#
mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
This diff is collapsed.
/*
* linux/drivers/mmc/mmc.h
*
* 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.
*/
#ifndef _MMC_H
#define _MMC_H
/* core-internal functions */
void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
int mmc_register_card(struct mmc_card *card);
void mmc_remove_card(struct mmc_card *card);
#endif
This diff is collapsed.
/*
* linux/drivers/mmc/mmc_queue.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.
*
*/
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include "mmc_queue.h"
/*
* Prepare a MMC request. Essentially, this means passing the
* preparation off to the media driver. The media driver will
* create a mmc_io_request in req->special.
*/
static int mmc_prep_request(struct request_queue *q, struct request *req)
{
struct mmc_queue *mq = q->queuedata;
int ret = BLKPREP_KILL;
if (req->flags & REQ_SPECIAL) {
/*
* Special commands already have the command
* blocks already setup in req->special.
*/
BUG_ON(!req->special);
ret = BLKPREP_OK;
} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
/*
* Block I/O requests need translating according
* to the protocol.
*/
ret = mq->prep_fn(mq, req);
} else {
/*
* Everything else is invalid.
*/
blk_dump_rq_flags(req, "MMC bad request");
}
if (ret == BLKPREP_OK)
req->flags |= REQ_DONTPREP;
return ret;
}
static int mmc_queue_thread(void *d)
{
struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
DECLARE_WAITQUEUE(wait, current);
int ret;
/*
* Set iothread to ensure that we aren't put to sleep by
* the process freezing. We handle suspension ourselves.
*/
current->flags |= PF_MEMALLOC|PF_NOFREEZE;
daemonize("mmcqd");
spin_lock_irq(&current->sighand->siglock);
sigfillset(&current->blocked);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
mq->thread = current;
complete(&mq->thread_complete);
add_wait_queue(&mq->thread_wq, &wait);
spin_lock_irq(q->queue_lock);
do {
struct request *req = NULL;
set_current_state(TASK_INTERRUPTIBLE);
if (!blk_queue_plugged(q))
mq->req = req = elv_next_request(q);
spin_unlock(q->queue_lock);
if (!req) {
if (!mq->thread)
break;
schedule();
continue;
}
set_current_state(TASK_RUNNING);
ret = mq->issue_fn(mq, req);
spin_lock_irq(q->queue_lock);
end_request(req, ret);
} while (1);
remove_wait_queue(&mq->thread_wq, &wait);
complete_and_exit(&mq->thread_complete, 0);
return 0;
}
/*
* Generic MMC request handler. This is called for any queue on a
* particular host. When the host is not busy, we look for a request
* on any queue on this host, and attempt to issue it. This may
* not be the queue we were asked to process.
*/
static void mmc_request(request_queue_t *q)
{
struct mmc_queue *mq = q->queuedata;
if (!mq->req && !blk_queue_plugged(q))
wake_up(&mq->thread_wq);
}
/**
* mmc_init_queue - initialise a queue structure.
* @mq: mmc queue
* @card: mmc card to attach this queue
* @lock: queue lock
*
* Initialise a MMC card request queue.
*/
int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
{
u64 limit = BLK_BOUNCE_HIGH;
int ret;
if (card->host->dev->dma_mask)
limit = *card->host->dev->dma_mask;
mq->card = card;
mq->queue = blk_init_queue(mmc_request, lock);
if (!mq->queue)
return -ENOMEM;
blk_queue_prep_rq(mq->queue, mmc_prep_request);
blk_queue_bounce_limit(mq->queue, limit);
mq->queue->queuedata = mq;
mq->req = NULL;
init_completion(&mq->thread_complete);
init_waitqueue_head(&mq->thread_wq);
ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL);
if (ret < 0) {
blk_cleanup_queue(mq->queue);
} else {
wait_for_completion(&mq->thread_complete);
init_completion(&mq->thread_complete);
ret = 0;
}
return ret;
}
EXPORT_SYMBOL(mmc_init_queue);
void mmc_cleanup_queue(struct mmc_queue *mq)
{
mq->thread = NULL;
wake_up(&mq->thread_wq);
wait_for_completion(&mq->thread_complete);
blk_cleanup_queue(mq->queue);
mq->card = NULL;
}
EXPORT_SYMBOL(mmc_cleanup_queue);
#ifndef MMC_QUEUE_H
#define MMC_QUEUE_H
struct request;
struct task_struct;
struct mmc_queue {
struct mmc_card *card;
struct completion thread_complete;
wait_queue_head_t thread_wq;
struct task_struct *thread;
struct request *req;
int (*prep_fn)(struct mmc_queue *, struct request *);
int (*issue_fn)(struct mmc_queue *, struct request *);
void *data;
struct request_queue *queue;
};
struct mmc_io_request {
struct request *rq;
int num;
struct mmc_command selcmd; /* mmc_queue private */
struct mmc_command cmd[4]; /* max 4 commands */
};
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
extern void mmc_cleanup_queue(struct mmc_queue *);
#endif
/*
* linux/drivers/mmc/mmc_sysfs.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.
*
* MMC sysfs/driver model support.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include "mmc.h"
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
static void mmc_release_card(struct device *dev)
{
struct mmc_card *card = dev_to_mmc_card(dev);
kfree(card);
}
/*
* This currently matches any MMC driver to any MMC card - drivers
* themselves make the decision whether to drive this card in their
* probe method.
*/
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
static int
mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf,
int buf_size)
{
struct mmc_card *card = dev_to_mmc_card(dev);
char ccc[13];
int i = 0;
#define add_env(fmt,val) \
({ \
int len, ret = -ENOMEM; \
if (i < num_envp) { \
envp[i++] = buf; \
len = snprintf(buf, buf_size, fmt, val) + 1; \
buf_size -= len; \
buf += len; \
if (buf_size >= 0) \
ret = 0; \
} \
ret; \
})
for (i = 0; i < 12; i++)
ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
ccc[12] = '\0';
i = 0;
add_env("MMC_CCC=%s", ccc);
add_env("MMC_MANFID=%03x", card->cid.manfid);
add_env("MMC_SLOT_NAME=%s", card->dev.bus_id);
return 0;
}
static int mmc_bus_suspend(struct device *dev, u32 state)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = dev_to_mmc_card(dev);
int ret = 0;
if (dev->driver && drv->suspend)
ret = drv->suspend(card, state);
return ret;
}
static int mmc_bus_resume(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = dev_to_mmc_card(dev);
int ret = 0;
if (dev->driver && drv->resume)
ret = drv->resume(card);
return ret;
}
static struct bus_type mmc_bus_type = {
.name = "mmc",
.match = mmc_bus_match,
.hotplug = mmc_bus_hotplug,
.suspend = mmc_bus_suspend,
.resume = mmc_bus_resume,
};
static int mmc_drv_probe(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = dev_to_mmc_card(dev);
return drv->probe(card);
}
static int mmc_drv_remove(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = dev_to_mmc_card(dev);
drv->remove(card);
return 0;
}
/**
* mmc_register_driver - register a media driver
* @drv: MMC media driver
*/
int mmc_register_driver(struct mmc_driver *drv)
{
drv->drv.bus = &mmc_bus_type;
drv->drv.probe = mmc_drv_probe;
drv->drv.remove = mmc_drv_remove;
return driver_register(&drv->drv);
}
EXPORT_SYMBOL(mmc_register_driver);
/**
* mmc_unregister_driver - unregister a media driver
* @drv: MMC media driver
*/
void mmc_unregister_driver(struct mmc_driver *drv)
{
drv->drv.bus = &mmc_bus_type;
driver_unregister(&drv->drv);
}
EXPORT_SYMBOL(mmc_unregister_driver);
#define MMC_ATTR(name, fmt, args...) \
static ssize_t mmc_dev_show_##name (struct device *dev, char *buf) \
{ \
struct mmc_card *card = dev_to_mmc_card(dev); \
return sprintf(buf, fmt, args); \
} \
static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL)
MMC_ATTR(date, "%02d/%04d\n", card->cid.month, 1997 + card->cid.year);
MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_ATTR(manfid, "0x%03x\n", card->cid.manfid);
MMC_ATTR(serial, "0x%06x\n", card->cid.serial);
MMC_ATTR(name, "%s\n", card->cid.prod_name);
static struct device_attribute *mmc_dev_attributes[] = {
&dev_attr_date,
&dev_attr_fwrev,
&dev_attr_hwrev,
&dev_attr_manfid,
&dev_attr_serial,
&dev_attr_name,
};
/*
* Internal function. Initialise a MMC card structure.
*/
void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
{
memset(card, 0, sizeof(struct mmc_card));
card->host = host;
device_initialize(&card->dev);
card->dev.parent = card->host->dev;
card->dev.bus = &mmc_bus_type;
card->dev.release = mmc_release_card;
}
/*
* Internal function. Register a new MMC card with the driver model.
*/
int mmc_register_card(struct mmc_card *card)
{
int ret, i;
snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
"%s:%04x", card->host->host_name, card->rca);
ret = device_add(&card->dev);
if (ret == 0)
for (i = 0; i < ARRAY_SIZE(mmc_dev_attributes); i++)
device_create_file(&card->dev, mmc_dev_attributes[i]);
return ret;
}
/*
* Internal function. Unregister a new MMC card with the
* driver model, and (eventually) free it.
*/
void mmc_remove_card(struct mmc_card *card)
{
if (mmc_card_present(card))
device_del(&card->dev);
put_device(&card->dev);
}
static int __init mmc_init(void)
{
return bus_register(&mmc_bus_type);
}
static void __exit mmc_exit(void)
{
bus_unregister(&mmc_bus_type);
}
module_init(mmc_init);
module_exit(mmc_exit);
/*
* linux/include/linux/mmc/card.h
*
* 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.
*
* Card driver specific definitions.
*/
#ifndef LINUX_MMC_CARD_H
#define LINUX_MMC_CARD_H
#include <linux/mmc/mmc.h>
struct mmc_cid {
unsigned int manfid;
unsigned int serial;
char prod_name[8];
unsigned char hwrev;
unsigned char fwrev;
unsigned char month;
unsigned char year;
};
struct mmc_csd {
unsigned char mmc_prot;
unsigned short cmdclass;
unsigned short tacc_clks;
unsigned int tacc_ns;
unsigned int max_dtr;
unsigned int read_blkbits;
unsigned int capacity;
};
struct mmc_host;
/*
* MMC device
*/
struct mmc_card {
struct list_head node; /* node in hosts devices list */
struct mmc_host *host; /* the host this device belongs to */
struct device dev; /* the device */
unsigned int rca; /* relative card address of device */
unsigned int state; /* (our) card state */
#define MMC_STATE_PRESENT (1<<0)
#define MMC_STATE_DEAD (1<<1)
struct mmc_cid cid; /* card identification */
struct mmc_csd csd; /* card specific */
};
#define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD)
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) ((c)->dev.bus_id)
#define mmc_list_to_card(l) container_of(l, struct mmc_card, node)
#define mmc_get_drvdata(c) dev_get_drvdata(&(c)->dev)
#define mmc_set_drvdata(c,d) dev_set_drvdata(&(c)->dev, d)
/*
* MMC device driver (e.g., Flash card, I/O card...)
*/
struct mmc_driver {
struct device_driver drv;
int (*probe)(struct mmc_card *);
void (*remove)(struct mmc_card *);
int (*suspend)(struct mmc_card *, u32);
int (*resume)(struct mmc_card *);
};
extern int mmc_register_driver(struct mmc_driver *);
extern void mmc_unregister_driver(struct mmc_driver *);
static inline int mmc_card_claim_host(struct mmc_card *card)
{
return __mmc_claim_host(card->host, card);
}
#define mmc_card_release_host(c) mmc_release_host((c)->host)
#endif
/*
* linux/include/linux/mmc/host.h
*
* 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.
*
* Host driver specific definitions.
*/
#ifndef LINUX_MMC_HOST_H
#define LINUX_MMC_HOST_H
#include <linux/mmc/mmc.h>
struct mmc_ios {
unsigned int clock; /* clock rate */
unsigned short vdd;
#define MMC_VDD_150 0
#define MMC_VDD_155 1
#define MMC_VDD_160 2
#define MMC_VDD_165 3
#define MMC_VDD_170 4
#define MMC_VDD_180 5
#define MMC_VDD_190 6
#define MMC_VDD_200 7
#define MMC_VDD_210 8
#define MMC_VDD_220 9
#define MMC_VDD_230 10
#define MMC_VDD_240 11
#define MMC_VDD_250 12
#define MMC_VDD_260 13
#define MMC_VDD_270 14
#define MMC_VDD_280 15
#define MMC_VDD_290 16
#define MMC_VDD_300 17
#define MMC_VDD_310 18
#define MMC_VDD_320 19
#define MMC_VDD_330 20
#define MMC_VDD_340 21
#define MMC_VDD_350 22
#define MMC_VDD_360 23
unsigned char bus_mode; /* command output mode */
#define MMC_BUSMODE_OPENDRAIN 1
#define MMC_BUSMODE_PUSHPULL 2
unsigned char power_mode; /* power supply mode */
#define MMC_POWER_OFF 0
#define MMC_POWER_UP 1
#define MMC_POWER_ON 2
};
struct mmc_host_ops {
void (*request)(struct mmc_host *host, struct mmc_request *req);
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
};
struct mmc_card;
struct device;
struct mmc_host {
struct device *dev;
struct mmc_host_ops *ops;
void *priv;
unsigned int f_min;
unsigned int f_max;
u32 ocr_avail;
char host_name[8];
/* private data */
struct mmc_ios ios; /* current io bus settings */
u32 ocr; /* the current OCR setting */
struct list_head cards; /* devices attached to this host */
wait_queue_head_t wq;
spinlock_t lock; /* card_busy lock */
struct mmc_card *card_busy; /* the MMC card claiming host */
struct mmc_card *card_selected; /* the selected MMC card */
struct work_struct detect;
};
extern struct mmc_host *mmc_alloc_host(int extra, struct device *);
extern int mmc_add_host(struct mmc_host *);
extern void mmc_remove_host(struct mmc_host *);
extern void mmc_free_host(struct mmc_host *);
#define mmc_priv(x) ((void *)((x) + 1))
#define mmc_dev(x) ((x)->dev)
extern int mmc_suspend_host(struct mmc_host *, u32);
extern int mmc_resume_host(struct mmc_host *);
extern void mmc_detect_change(struct mmc_host *);
extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
#endif
/*
* linux/include/linux/mmc/mmc.h
*
* 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.
*/
#ifndef MMC_H
#define MMC_H
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/device.h>
struct request;
struct mmc_data;
struct mmc_request;
struct mmc_command {
u32 opcode;
u32 arg;
u32 resp[4];
unsigned int flags; /* expected response type */
#define MMC_RSP_NONE (0 << 0)
#define MMC_RSP_SHORT (1 << 0)
#define MMC_RSP_LONG (2 << 0)
#define MMC_RSP_MASK (3 << 0)
#define MMC_RSP_CRC (1 << 3) /* expect valid crc */
#define MMC_RSP_BUSY (1 << 4) /* card may send busy */
unsigned int retries; /* max number of retries */
unsigned int error; /* command error */
#define MMC_ERR_NONE 0
#define MMC_ERR_TIMEOUT 1
#define MMC_ERR_BADCRC 2
#define MMC_ERR_FIFO 3
#define MMC_ERR_FAILED 4
#define MMC_ERR_INVALID 5
struct mmc_data *data; /* data segment associated with cmd */
struct mmc_request *req; /* assoicated request */
};
struct mmc_data {
unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */
unsigned int timeout_clks; /* data timeout (in clocks) */
unsigned int blksz_bits; /* data block size */
unsigned int blocks; /* number of blocks */
struct request *rq; /* request structure */
unsigned int error; /* data error */
unsigned int flags;
#define MMC_DATA_WRITE (1 << 8)
#define MMC_DATA_READ (1 << 9)
#define MMC_DATA_STREAM (1 << 10)
unsigned int bytes_xfered;
struct mmc_command *stop; /* stop command */
struct mmc_request *req; /* assoicated request */
};
struct mmc_request {
struct mmc_command *cmd;
struct mmc_data *data;
struct mmc_command *stop;
void *done_data; /* completion data */
void (*done)(struct mmc_request *);/* completion function */
};
struct mmc_host;
struct mmc_card;
extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
static inline void mmc_claim_host(struct mmc_host *host)
{
__mmc_claim_host(host, (struct mmc_card *)-1);
}
extern void mmc_release_host(struct mmc_host *host);
#endif
/*
* Header for MultiMediaCard (MMC)
*
* Copyright 2002 Hewlett-Packard Company
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
* FITNESS FOR ANY PARTICULAR PURPOSE.
*
* Many thanks to Alessandro Rubini and Jonathan Corbet!
*
* Based strongly on code by:
*
* Author: Yong-iL Joh <tolkien@mizi.com>
* Date : $Date: 2002/06/18 12:37:30 $
*
* Author: Andrew Christian
* 15 May 2002
*/
#ifndef MMC_MMC_PROTOCOL_H
#define MMC_MMC_PROTOCOL_H
/* Standard MMC commands (3.1) type argument response */
/* class 1 */
#define MMC_GO_IDLE_STATE 0 /* bc */
#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
#define MMC_ALL_SEND_CID 2 /* bcr R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define MMC_SET_DSR 4 /* bc [31:16] RCA */
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
/* class 2 */
#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
/* class 3 */
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
/* class 4 */
#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
#define MMC_PROGRAM_CID 26 /* adtc R1 */
#define MMC_PROGRAM_CSD 27 /* adtc R1 */
/* class 6 */
#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
/* class 5 */
#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
#define MMC_ERASE 37 /* ac R1b */
/* class 9 */
#define MMC_FAST_IO 39 /* ac <Complex> R4 */
#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
/* class 7 */
#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
/* class 8 */
#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1b */
/*
MMC status in R1
Type
e : error bit
s : status bit
r : detected and set for the actual command response
x : detected and set during command execution. the host must poll
the card by sending status command in order to read these bits.
Clear condition
a : according to the card state
b : always related to the previous command. Reception of
a valid command will clear it (with a delay of one command)
c : clear by read
*/
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
#define R1_ERASE_PARAM (1 << 27) /* ex, c */
#define R1_WP_VIOLATION (1 << 26) /* erx, c */
#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
#define R1_CC_ERROR (1 << 20) /* erx, c */
#define R1_ERROR (1 << 19) /* erx, c */
#define R1_UNDERRUN (1 << 18) /* ex, c */
#define R1_OVERRUN (1 << 17) /* ex, c */
#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
#define R1_ERASE_RESET (1 << 13) /* sr, c */
#define R1_STATUS(x) (x & 0xFFFFE000)
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_APP_CMD (1 << 7) /* sr, c */
/* These are unpacked versions of the actual responses */
struct _mmc_csd {
u8 csd_structure;
u8 spec_vers;
u8 taac;
u8 nsac;
u8 tran_speed;
u16 ccc;
u8 read_bl_len;
u8 read_bl_partial;
u8 write_blk_misalign;
u8 read_blk_misalign;
u8 dsr_imp;
u16 c_size;
u8 vdd_r_curr_min;
u8 vdd_r_curr_max;
u8 vdd_w_curr_min;
u8 vdd_w_curr_max;
u8 c_size_mult;
union {
struct { /* MMC system specification version 3.1 */
u8 erase_grp_size;
u8 erase_grp_mult;
} v31;
struct { /* MMC system specification version 2.2 */
u8 sector_size;
u8 erase_grp_size;
} v22;
} erase;
u8 wp_grp_size;
u8 wp_grp_enable;
u8 default_ecc;
u8 r2w_factor;
u8 write_bl_len;
u8 write_bl_partial;
u8 file_format_grp;
u8 copy;
u8 perm_write_protect;
u8 tmp_write_protect;
u8 file_format;
u8 ecc;
};
#define MMC_VDD_145_150 0x00000001 /* VDD voltage 1.45 - 1.50 */
#define MMC_VDD_150_155 0x00000002 /* VDD voltage 1.50 - 1.55 */
#define MMC_VDD_155_160 0x00000004 /* VDD voltage 1.55 - 1.60 */
#define MMC_VDD_160_165 0x00000008 /* VDD voltage 1.60 - 1.65 */
#define MMC_VDD_165_170 0x00000010 /* VDD voltage 1.65 - 1.70 */
#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */
#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */
#define MMC_VDD_19_20 0x00000080 /* VDD voltage 1.9 - 2.0 */
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
/*
* CSD field definitions
*/
#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */
#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */
#endif /* MMC_MMC_PROTOCOL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment