Commit 62ea6d80 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: (46 commits)
  mmc-omap: Clean up omap set_ios and make MMC_POWER_ON work
  mmc-omap: Fix omap to use MMC_POWER_ON
  mmc-omap: add missing '\n'
  mmc: make tifm_sd_set_dma_data() static
  mmc: remove old card states
  mmc: support unsafe resume of cards
  mmc: separate out reading EXT_CSD
  mmc: break apart switch function
  MMC: Fix handling of low-voltage cards
  MMC: Consolidate voltage definitions
  mmc: add bus handler
  wbsd: check for data opcode earlier
  mmc: Separate out protocol ops
  mmc: Move core functions to subdir
  mmc: deprecate mmc bus topology
  mmc: remove card upon suspend
  mmc: allow suspended block driver to be removed
  mmc: Flush pending detects on host removal
  mmc: Move host and card drivers to subdirs
  mmc: Move queue functions to mmc_block
  ...
parents fa24aa56 d3af5abe
This diff is collapsed.
This diff is collapsed.
......@@ -19,110 +19,10 @@ config MMC_DEBUG
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 && BLOCK
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.
config MMC_ARMMMCI
tristate "ARM AMBA Multimedia Card Interface support"
depends on ARM_AMBA && MMC
help
This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
Interface (PL180 and PL181) support. If you have an ARM(R)
platform with a Multimedia Card slot, say Y or M here.
If unsure, say N.
config MMC_PXA
tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
depends on ARCH_PXA && MMC
help
This selects the Intel(R) PXA(R) Multimedia card Interface.
If you have a PXA(R) platform with a Multimedia Card slot,
say Y or M here.
If unsure, say N.
config MMC_SDHCI
tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)"
depends on PCI && MMC && EXPERIMENTAL
help
This select the generic Secure Digital Host Controller Interface.
It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
and Toshiba(R). Most controllers found in laptops are of this type.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_OMAP
tristate "TI OMAP Multimedia Card Interface support"
depends on ARCH_OMAP && MMC
select TPS65010 if MACH_OMAP_H2
help
This selects the TI OMAP Multimedia card Interface.
If you have an OMAP board with a Multimedia Card slot,
say Y or M here.
If unsure, say N.
source "drivers/mmc/core/Kconfig"
config MMC_WBSD
tristate "Winbond W83L51xD SD/MMC Card Interface support"
depends on MMC && ISA_DMA_API
help
This selects the Winbond(R) W83L51xD Secure digital and
Multimedia card Interface.
If you have a machine with a integrated W83L518D or W83L519D
SD/MMC card reader, say Y or M here.
If unsure, say N.
config MMC_AU1X
tristate "Alchemy AU1XX0 MMC Card Interface support"
depends on MMC && SOC_AU1200
help
This selects the AMD Alchemy(R) Multimedia card interface.
If you have a Alchemy platform with a MMC slot, say Y or M here.
If unsure, say N.
config MMC_AT91
tristate "AT91 SD/MMC Card Interface support"
depends on ARCH_AT91 && MMC
help
This selects the AT91 MCI controller.
If unsure, say N.
config MMC_IMX
tristate "Motorola i.MX Multimedia Card Interface support"
depends on ARCH_IMX && MMC
help
This selects the Motorola i.MX Multimedia card Interface.
If you have a i.MX platform with a Multimedia Card slot,
say Y or M here.
If unsure, say N.
config MMC_TIFM_SD
tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
depends on MMC && EXPERIMENTAL && PCI
select TIFM_CORE
help
Say Y here if you want to be able to access MMC/SD cards with
the Texas Instruments(R) Flash Media card reader, found in many
laptops.
This option 'selects' (turns on, enables) 'TIFM_CORE', but you
probably also need appropriate card reader host adapter, such as
'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
(TIFM_7XX1)'.
source "drivers/mmc/card/Kconfig"
To compile this driver as a module, choose M here: the
module will be called tifm_sd.
source "drivers/mmc/host/Kconfig"
endmenu
......@@ -2,32 +2,11 @@
# 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
#
obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_IMX) += imxmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
mmc_core-y := mmc.o mmc_sysfs.o
mmc_core-$(CONFIG_BLOCK) += mmc_queue.o
ifeq ($(CONFIG_MMC_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
EXTRA_CFLAGS += -DDEBUG
endif
obj-$(CONFIG_MMC) += core/
obj-$(CONFIG_MMC) += card/
obj-$(CONFIG_MMC) += host/
#
# MMC/SD card drivers
#
comment "MMC/SD Card Drivers"
depends MMC
config MMC_BLOCK
tristate "MMC block device driver"
depends on MMC && BLOCK
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.
#
# Makefile for MMC/SD card drivers
#
ifeq ($(CONFIG_MMC_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
......@@ -2,6 +2,7 @@
* Block driver for media (i.e., flash cards)
*
* Copyright 2002 Hewlett-Packard Company
* Copyright 2005-2007 Pierre Ossman
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
......@@ -31,13 +32,13 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include "mmc_queue.h"
#include "queue.h"
/*
* max 8 partitions per card
......@@ -223,10 +224,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
struct mmc_blk_request brq;
int ret = 1;
int ret = 1, sg_pos, data_size;
if (mmc_card_claim_host(card))
goto flush_queue;
mmc_claim_host(card->host);
do {
struct mmc_command cmd;
......@@ -283,6 +283,20 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.sg = mq->sg;
brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
if (brq.data.blocks !=
(req->nr_sectors >> (md->block_bits - 9))) {
data_size = brq.data.blocks * brq.data.blksz;
for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) {
data_size -= mq->sg[sg_pos].length;
if (data_size <= 0) {
mq->sg[sg_pos].length += data_size;
sg_pos++;
break;
}
}
brq.data.sg_len = sg_pos;
}
mmc_wait_for_req(card->host, &brq.mrq);
if (brq.cmd.error) {
printk(KERN_ERR "%s: error %d sending read/write command\n",
......@@ -342,7 +356,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
} while (ret);
mmc_card_release_host(card);
mmc_release_host(card->host);
return 1;
......@@ -378,9 +392,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
}
flush_queue:
mmc_card_release_host(card);
mmc_release_host(card->host);
spin_lock_irq(&md->lock);
while (ret) {
......@@ -477,11 +489,20 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
/*
* The EXT_CSD sector count is in number or 512 byte
* sectors.
*/
set_capacity(md->disk, card->ext_csd.sectors);
} else {
/*
* The CSD capacity field is in units of read_blkbits.
* set_capacity takes units of 512 bytes.
*/
set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9));
set_capacity(md->disk,
card->csd.capacity << (card->csd.read_blkbits - 9));
}
return md;
err_putdisk:
......@@ -502,12 +523,12 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
if (mmc_card_blockaddr(card))
return 0;
mmc_card_claim_host(card);
mmc_claim_host(card->host);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
mmc_card_release_host(card);
mmc_release_host(card->host);
if (err) {
printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
......
/*
* linux/drivers/mmc/mmc_queue.c
* linux/drivers/mmc/queue.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2006-2007 Pierre Ossman
*
* 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
......@@ -14,7 +15,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include "mmc_queue.h"
#include "queue.h"
#define MMC_QUEUE_SUSPENDED (1 << 0)
......@@ -179,7 +180,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_cleanup_queue(mq->queue);
return ret;
}
EXPORT_SYMBOL(mmc_init_queue);
void mmc_cleanup_queue(struct mmc_queue *mq)
{
......@@ -191,6 +191,9 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
q->queuedata = NULL;
spin_unlock_irqrestore(q->queue_lock, flags);
/* Make sure the queue isn't suspended, as that will deadlock */
mmc_queue_resume(mq);
/* Then terminate our worker thread */
kthread_stop(mq->thread);
......@@ -226,7 +229,6 @@ void mmc_queue_suspend(struct mmc_queue *mq)
down(&mq->thread_sem);
}
}
EXPORT_SYMBOL(mmc_queue_suspend);
/**
* mmc_queue_resume - resume a previously suspended MMC request queue
......@@ -247,4 +249,4 @@ void mmc_queue_resume(struct mmc_queue *mq)
spin_unlock_irqrestore(q->queue_lock, flags);
}
}
EXPORT_SYMBOL(mmc_queue_resume);
#
# MMC core configuration
#
config MMC_UNSAFE_RESUME
bool "Allow unsafe resume (DANGEROUS)"
depends on MMC != n
help
If you say Y here, the MMC layer will assume that all cards
stayed in their respective slots during the suspend. The
normal behaviour is to remove them at suspend and
redetecting them at resume. Breaking this assumption will
in most cases result in data corruption.
This option is usually just for embedded systems which use
a MMC/SD card for rootfs. Most people should say N here.
#
# Makefile for the kernel mmc core.
#
ifeq ($(CONFIG_MMC_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
obj-$(CONFIG_MMC) += mmc_core.o
mmc_core-y := core.o sysfs.o mmc.o mmc_ops.o sd.o sd_ops.o
This diff is collapsed.
/*
* linux/drivers/mmc/core/core.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2007 Pierre Ossman
*
* 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_CORE_CORE_H
#define _MMC_CORE_CORE_H
#include <linux/delay.h>
#define MMC_CMD_RETRIES 3
struct mmc_bus_ops {
void (*remove)(struct mmc_host *);
void (*detect)(struct mmc_host *);
void (*suspend)(struct mmc_host *);
void (*resume)(struct mmc_host *);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
void mmc_detach_bus(struct mmc_host *host);
void __mmc_release_bus(struct mmc_host *host);
static inline void mmc_bus_get(struct mmc_host *host)
{
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
host->bus_refs++;
spin_unlock_irqrestore(&host->lock, flags);
}
static inline void mmc_bus_put(struct mmc_host *host)
{
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
host->bus_refs--;
if ((host->bus_refs == 0) && host->bus_ops)
__mmc_release_bus(host);
spin_unlock_irqrestore(&host->lock, flags);
}
void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
struct mmc_card *mmc_alloc_card(struct mmc_host *host);
static inline void mmc_delay(unsigned int ms)
{
if (ms < 1000 / HZ) {
cond_resched();
mdelay(ms);
} else {
msleep(ms);
}
}
#endif
This diff is collapsed.
/*
* linux/drivers/mmc/mmc_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
* 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.
*/
#include <linux/types.h>
#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include "core.h"
#include "mmc_ops.h"
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
int err;
struct mmc_command cmd;
BUG_ON(!host);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SELECT_CARD;
if (card) {
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
} else {
cmd.arg = 0;
cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
}
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
if (err != MMC_ERR_NONE)
return err;
return MMC_ERR_NONE;
}
int mmc_select_card(struct mmc_card *card)
{
BUG_ON(!card);
return _mmc_select_card(card->host, card);
}
int mmc_deselect_cards(struct mmc_host *host)
{
return _mmc_select_card(host, NULL);
}
int mmc_go_idle(struct mmc_host *host)
{
int err;
struct mmc_command cmd;
mmc_set_chip_select(host, MMC_CS_HIGH);
mmc_delay(1);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_GO_IDLE_STATE;
cmd.arg = 0;
cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
err = mmc_wait_for_cmd(host, &cmd, 0);
mmc_delay(1);
mmc_set_chip_select(host, MMC_CS_DONTCARE);
mmc_delay(1);
return err;
}
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
struct mmc_command cmd;
int i, err = 0;
BUG_ON(!host);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = ocr;
cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err != MMC_ERR_NONE)
break;
if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
break;
err = MMC_ERR_TIMEOUT;
mmc_delay(10);
}
if (rocr)
*rocr = cmd.resp[0];
return err;
}
int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
{
int err;
struct mmc_command cmd;
BUG_ON(!host);
BUG_ON(!cid);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0;
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
if (err != MMC_ERR_NONE)
return err;
memcpy(cid, cmd.resp, sizeof(u32) * 4);
return MMC_ERR_NONE;
}
int mmc_set_relative_addr(struct mmc_card *card)
{
int err;
struct mmc_command cmd;
BUG_ON(!card);
BUG_ON(!card->host);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err != MMC_ERR_NONE)
return err;
return MMC_ERR_NONE;
}
int mmc_send_csd(struct mmc_card *card, u32 *csd)
{
int err;
struct mmc_command cmd;
BUG_ON(!card);
BUG_ON(!card->host);
BUG_ON(!csd);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_CSD;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err != MMC_ERR_NONE)
return err;
memcpy(csd, cmd.resp, sizeof(u32) * 4);
return MMC_ERR_NONE;
}
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
{
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
struct scatterlist sg;
BUG_ON(!card);
BUG_ON(!card->host);
BUG_ON(!ext_csd);
memset(&mrq, 0, sizeof(struct mmc_request));
memset(&cmd, 0, sizeof(struct mmc_command));
memset(&data, 0, sizeof(struct mmc_data));
mrq.cmd = &cmd;
mrq.data = &data;
cmd.opcode = MMC_SEND_EXT_CSD;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 512;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, ext_csd, 512);
mmc_set_data_timeout(&data, card, 0);
mmc_wait_for_req(card->host, &mrq);
if (cmd.error != MMC_ERR_NONE)
return cmd.error;
if (data.error != MMC_ERR_NONE)
return data.error;
return MMC_ERR_NONE;
}
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
{
int err;
struct mmc_command cmd;
BUG_ON(!card);
BUG_ON(!card->host);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SWITCH;
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
(index << 16) |
(value << 8) |
set;
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err != MMC_ERR_NONE)
return err;
return MMC_ERR_NONE;
}
int mmc_send_status(struct mmc_card *card, u32 *status)
{
int err;
struct mmc_command cmd;
BUG_ON(!card);
BUG_ON(!card->host);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err != MMC_ERR_NONE)
return err;
if (status)
*status = cmd.resp[0];
return MMC_ERR_NONE;
}
/*
* linux/drivers/mmc/mmc_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
* 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.
*/
#ifndef _MMC_MMC_OPS_H
#define _MMC_MMC_OPS_H
int mmc_select_card(struct mmc_card *card);
int mmc_deselect_cards(struct mmc_host *host);
int mmc_go_idle(struct mmc_host *host);
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
int mmc_set_relative_addr(struct mmc_card *card);
int mmc_send_csd(struct mmc_card *card, u32 *csd);
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
int mmc_send_status(struct mmc_card *card, u32 *status);
#endif
This diff is collapsed.
/*
* linux/drivers/mmc/sd_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
* 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.
*/
#include <linux/types.h>
#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include "core.h"
#include "sd_ops.h"
/**
* mmc_wait_for_app_cmd - start an application command and wait for
completion
* @host: MMC host to start command
* @rca: RCA to send MMC_APP_CMD to
* @cmd: MMC command to start
* @retries: maximum number of retries
*
* Sends a MMC_APP_CMD, checks the card response, sends the command
* in the parameter and waits for it to complete. Return any error
* that occurred while the command was executing. Do not attempt to
* parse the response.
*/
int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
struct mmc_command *cmd, int retries)
{
struct mmc_request mrq;
int i, err;
BUG_ON(!cmd);
BUG_ON(retries < 0);
err = MMC_ERR_INVALID;
/*
* We have to resend MMC_APP_CMD for each attempt so
* we cannot use the retries field in mmc_command.
*/
for (i = 0;i <= retries;i++) {
memset(&mrq, 0, sizeof(struct mmc_request));
err = mmc_app_cmd(host, card);
if (err != MMC_ERR_NONE)
continue;
memset(&mrq, 0, sizeof(struct mmc_request));
memset(cmd->resp, 0, sizeof(cmd->resp));
cmd->retries = 0;
mrq.cmd = cmd;
cmd->data = NULL;
mmc_wait_for_req(host, &mrq);
err = cmd->error;
if (cmd->error == MMC_ERR_NONE)
break;
}
return err;
}
EXPORT_SYMBOL(mmc_wait_for_app_cmd);
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
int err;
struct mmc_command cmd;
BUG_ON(!host);
BUG_ON(card && (card->host != host));
cmd.opcode = MMC_APP_CMD;
if (card) {
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
} else {
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
}
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err != MMC_ERR_NONE)
return err;
/* Check that card supported application commands */
if (!(cmd.resp[0] & R1_APP_CMD))
return MMC_ERR_FAILED;
return MMC_ERR_NONE;
}
int mmc_app_set_bus_width(struct mmc_card *card, int width)
{
int err;
struct mmc_command cmd;
BUG_ON(!card);
BUG_ON(!card->host);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_SET_BUS_WIDTH;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
switch (width) {
case MMC_BUS_WIDTH_1:
cmd.arg = SD_BUS_WIDTH_1;
break;
case MMC_BUS_WIDTH_4:
cmd.arg = SD_BUS_WIDTH_4;
break;
default:
return MMC_ERR_INVALID;
}
err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
if (err != MMC_ERR_NONE)
return err;
return MMC_ERR_NONE;
}
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
struct mmc_command cmd;
int i, err = 0;
BUG_ON(!host);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_OP_COND;
cmd.arg = ocr;
cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
if (err != MMC_ERR_NONE)
break;
if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
break;
err = MMC_ERR_TIMEOUT;
mmc_delay(10);
}
if (rocr)
*rocr = cmd.resp[0];
return err;
}
int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
{
struct mmc_command cmd;
int err;
static const u8 test_pattern = 0xAA;
/*
* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
* before SD_APP_OP_COND. This command will harmlessly fail for
* SD 1.0 cards.
*/
cmd.opcode = SD_SEND_IF_COND;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err != MMC_ERR_NONE)
return err;
if ((cmd.resp[0] & 0xFF) != test_pattern)
return MMC_ERR_FAILED;
return MMC_ERR_NONE;
}
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
{
int err;
struct mmc_command cmd;
BUG_ON(!host);
BUG_ON(!rca);
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
if (err != MMC_ERR_NONE)
return err;
*rca = cmd.resp[0] >> 16;
return MMC_ERR_NONE;
}
int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
{
int err;
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
struct scatterlist sg;
BUG_ON(!card);
BUG_ON(!card->host);
BUG_ON(!scr);
err = mmc_app_cmd(card->host, card);
if (err != MMC_ERR_NONE)
return err;
memset(&mrq, 0, sizeof(struct mmc_request));
memset(&cmd, 0, sizeof(struct mmc_command));
memset(&data, 0, sizeof(struct mmc_data));
mrq.cmd = &cmd;
mrq.data = &data;
cmd.opcode = SD_APP_SEND_SCR;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 8;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, scr, 8);
mmc_set_data_timeout(&data, card, 0);
mmc_wait_for_req(card->host, &mrq);
if (cmd.error != MMC_ERR_NONE)
return cmd.error;
if (data.error != MMC_ERR_NONE)
return data.error;
scr[0] = ntohl(scr[0]);
scr[1] = ntohl(scr[1]);
return MMC_ERR_NONE;
}
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp)
{
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
struct scatterlist sg;
BUG_ON(!card);
BUG_ON(!card->host);
mode = !!mode;
value &= 0xF;
memset(&mrq, 0, sizeof(struct mmc_request));
memset(&cmd, 0, sizeof(struct mmc_command));
memset(&data, 0, sizeof(struct mmc_data));
mrq.cmd = &cmd;
mrq.data = &data;
cmd.opcode = SD_SWITCH;
cmd.arg = mode << 31 | 0x00FFFFFF;
cmd.arg &= ~(0xF << (group * 4));
cmd.arg |= value << (group * 4);
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 64;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, resp, 64);
mmc_set_data_timeout(&data, card, 0);
mmc_wait_for_req(card->host, &mrq);
if (cmd.error != MMC_ERR_NONE)
return cmd.error;
if (data.error != MMC_ERR_NONE)
return data.error;
return MMC_ERR_NONE;
}
/*
* linux/drivers/mmc/sd_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
* 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.
*/
#ifndef _MMC_SD_OPS_H
#define _MMC_SD_OPS_H
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp);
#endif
/*
* linux/drivers/mmc/mmc_sysfs.c
* linux/drivers/mmc/core/sysfs.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
*
......@@ -18,7 +18,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include "mmc.h"
#include "sysfs.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)
......@@ -72,12 +72,11 @@ static void mmc_release_card(struct device *dev)
/*
* This currently matches any MMC driver to any MMC card - drivers
* themselves make the decision whether to drive this card in their
* probe method. However, we force "bad" cards to fail.
* probe method.
*/
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
struct mmc_card *card = dev_to_mmc_card(dev);
return !mmc_card_bad(card);
return 1;
}
static int
......@@ -217,6 +216,8 @@ int mmc_register_card(struct mmc_card *card)
device_del(&card->dev);
}
}
if (ret == 0)
mmc_card_set_present(card);
return ret;
}
......
/*
* linux/drivers/mmc/mmc.h
* linux/drivers/mmc/core/sysfs.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2007 Pierre Ossman
*
* 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 */
#ifndef _MMC_CORE_SYSFS_H
#define _MMC_CORE_SYSFS_H
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);
......@@ -22,4 +23,5 @@ void mmc_free_host_sysfs(struct mmc_host *host);
int mmc_schedule_work(struct work_struct *work);
int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay);
void mmc_flush_scheduled_work(void);
#endif
#
# MMC/SD host controller drivers
#
comment "MMC/SD Host Controller Drivers"
depends on MMC
config MMC_ARMMMCI
tristate "ARM AMBA Multimedia Card Interface support"
depends on ARM_AMBA && MMC
help
This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
Interface (PL180 and PL181) support. If you have an ARM(R)
platform with a Multimedia Card slot, say Y or M here.
If unsure, say N.
config MMC_PXA
tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
depends on ARCH_PXA && MMC
help
This selects the Intel(R) PXA(R) Multimedia card Interface.
If you have a PXA(R) platform with a Multimedia Card slot,
say Y or M here.
If unsure, say N.
config MMC_SDHCI
tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)"
depends on PCI && MMC && EXPERIMENTAL
help
This select the generic Secure Digital Host Controller Interface.
It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
and Toshiba(R). Most controllers found in laptops are of this type.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_OMAP
tristate "TI OMAP Multimedia Card Interface support"
depends on ARCH_OMAP && MMC
select TPS65010 if MACH_OMAP_H2
help
This selects the TI OMAP Multimedia card Interface.
If you have an OMAP board with a Multimedia Card slot,
say Y or M here.
If unsure, say N.
config MMC_WBSD
tristate "Winbond W83L51xD SD/MMC Card Interface support"
depends on MMC && ISA_DMA_API
help
This selects the Winbond(R) W83L51xD Secure digital and
Multimedia card Interface.
If you have a machine with a integrated W83L518D or W83L519D
SD/MMC card reader, say Y or M here.
If unsure, say N.
config MMC_AU1X
tristate "Alchemy AU1XX0 MMC Card Interface support"
depends on MMC && SOC_AU1200
help
This selects the AMD Alchemy(R) Multimedia card interface.
If you have a Alchemy platform with a MMC slot, say Y or M here.
If unsure, say N.
config MMC_AT91
tristate "AT91 SD/MMC Card Interface support"
depends on ARCH_AT91 && MMC
help
This selects the AT91 MCI controller.
If unsure, say N.
config MMC_IMX
tristate "Motorola i.MX Multimedia Card Interface support"
depends on ARCH_IMX && MMC
help
This selects the Motorola i.MX Multimedia card Interface.
If you have a i.MX platform with a Multimedia Card slot,
say Y or M here.
If unsure, say N.
config MMC_TIFM_SD
tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
depends on MMC && EXPERIMENTAL && PCI
select TIFM_CORE
help
Say Y here if you want to be able to access MMC/SD cards with
the Texas Instruments(R) Flash Media card reader, found in many
laptops.
This option 'selects' (turns on, enables) 'TIFM_CORE', but you
probably also need appropriate card reader host adapter, such as
'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
(TIFM_7XX1)'.
To compile this driver as a module, choose M here: the
module will be called tifm_sd.
#
# Makefile for MMC/SD host controller drivers
#
ifeq ($(CONFIG_MMC_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_IMX) += imxmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
......@@ -67,7 +67,6 @@
#include <linux/atmel_pdc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
#include <asm/io.h>
#include <asm/irq.h>
......
......@@ -42,7 +42,6 @@
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
#include <asm/io.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
......
......@@ -41,7 +41,6 @@
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/protocol.h>
#include <linux/delay.h>
#include <asm/dma.h>
......
......@@ -17,7 +17,6 @@
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
......
......@@ -22,7 +22,6 @@
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
#include <linux/mmc/card.h>
#include <linux/clk.h>
......@@ -605,7 +604,7 @@ static void mmc_omap_switch_handler(struct work_struct *work)
}
if (mmc_omap_cover_is_open(host)) {
if (!complained) {
dev_info(mmc_dev(host->mmc), "cover is open");
dev_info(mmc_dev(host->mmc), "cover is open\n");
complained = 1;
}
if (mmc_omap_enable_poll)
......@@ -937,24 +936,20 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)
}
}
static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct mmc_omap_host *host = mmc_priv(mmc);
int func_clk_rate = clk_get_rate(host->fclk);
int dsor;
int realclock, i;
realclock = ios->clock;
if (ios->clock == 0)
dsor = 0;
else {
int func_clk_rate = clk_get_rate(host->fclk);
return 0;
dsor = func_clk_rate / realclock;
dsor = func_clk_rate / ios->clock;
if (dsor < 1)
dsor = 1;
if (func_clk_rate / dsor > realclock)
if (func_clk_rate / dsor > ios->clock)
dsor++;
if (dsor > 250)
......@@ -963,22 +958,33 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->bus_width == MMC_BUS_WIDTH_4)
dsor |= 1 << 15;
}
return dsor;
}
static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct mmc_omap_host *host = mmc_priv(mmc);
int dsor;
int i;
dsor = mmc_omap_calc_divisor(mmc, ios);
host->bus_mode = ios->bus_mode;
host->hw_bus_mode = host->bus_mode;
switch (ios->power_mode) {
case MMC_POWER_OFF:
mmc_omap_power(host, 0);
break;
case MMC_POWER_UP:
case MMC_POWER_ON:
/* Cannot touch dsor yet, just power up MMC */
mmc_omap_power(host, 1);
return;
case MMC_POWER_ON:
dsor |= 1 << 11;
break;
}
host->bus_mode = ios->bus_mode;
host->hw_bus_mode = host->bus_mode;
clk_enable(host->fclk);
/* On insanely high arm_per frequencies something sometimes
......@@ -987,7 +993,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
* Writing to the CON register twice seems to do the trick. */
for (i = 0; i < 2; i++)
OMAP_MMC_WRITE(host, CON, dsor);
if (ios->power_mode == MMC_POWER_UP) {
if (ios->power_mode == MMC_POWER_ON) {
/* Send clock cycles, poll completion */
OMAP_MMC_WRITE(host, IE, 0);
OMAP_MMC_WRITE(host, STAT, 0xffff);
......
......@@ -24,7 +24,6 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
#include <asm/dma.h>
#include <asm/io.h>
......
/*
* linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
*
* Copyright (C) 2005-2006 Pierre Ossman, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, 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
......@@ -15,7 +15,6 @@
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
#include <asm/scatterlist.h>
......@@ -247,14 +246,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
chunk_remain = min(blksize, 4);
}
size = min(host->size, host->remain);
size = min(size, chunk_remain);
size = min(host->remain, chunk_remain);
chunk_remain -= size;
blksize -= size;
host->offset += size;
host->remain -= size;
host->size -= size;
while (size) {
*buffer = data & 0xFF;
buffer++;
......@@ -289,14 +287,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
size = min(host->size, host->remain);
size = min(size, chunk_remain);
size = min(host->remain, chunk_remain);
chunk_remain -= size;
blksize -= size;
host->offset += size;
host->remain -= size;
host->size -= size;
while (size) {
data >>= 8;
data |= (u32)*buffer << 24;
......@@ -325,7 +322,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
BUG_ON(!host->data);
if (host->size == 0)
if (host->num_sg == 0)
return;
if (host->data->flags & MMC_DATA_READ)
......@@ -339,10 +336,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
else
sdhci_write_block_pio(host);
if (host->size == 0)
if (host->num_sg == 0)
break;
BUG_ON(host->num_sg == 0);
}
DBG("PIO transfer complete.\n");
......@@ -408,8 +403,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
} else {
host->size = data->blksz * data->blocks;
host->cur_sg = data->sg;
host->num_sg = data->sg_len;
......@@ -473,10 +466,6 @@ static void sdhci_finish_data(struct sdhci_host *host)
"though there were blocks left.\n",
mmc_hostname(host->mmc));
data->error = MMC_ERR_FAILED;
} else if (host->size != 0) {
printk(KERN_ERR "%s: %d bytes were left untransferred.\n",
mmc_hostname(host->mmc), host->size);
data->error = MMC_ERR_FAILED;
}
DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
......@@ -669,20 +658,16 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
pwr = SDHCI_POWER_ON;
switch (power) {
case MMC_VDD_170:
case MMC_VDD_180:
case MMC_VDD_190:
switch (1 << power) {
case MMC_VDD_165_195:
pwr |= SDHCI_POWER_180;
break;
case MMC_VDD_290:
case MMC_VDD_300:
case MMC_VDD_310:
case MMC_VDD_29_30:
case MMC_VDD_30_31:
pwr |= SDHCI_POWER_300;
break;
case MMC_VDD_320:
case MMC_VDD_330:
case MMC_VDD_340:
case MMC_VDD_32_33:
case MMC_VDD_33_34:
pwr |= SDHCI_POWER_330;
break;
default:
......@@ -1294,7 +1279,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
if (caps & SDHCI_CAN_VDD_300)
mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
mmc->ocr_avail |= MMC_VDD_165_195;
if (mmc->ocr_avail == 0) {
printk(KERN_ERR "%s: Hardware doesn't report any "
......
/*
* linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
*
* Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, 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
......@@ -187,8 +187,6 @@ struct sdhci_host {
int offset; /* Offset into current sg */
int remain; /* Bytes left in current */
int size; /* Remaining bytes in transfer */
char slot_descr[20]; /* Name for reservations */
int irq; /* Device IRQ */
......
/*
* linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver
*
* Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
* Copyright (C) 2004-2007 Pierre Ossman, 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
......@@ -46,10 +46,10 @@
#define WBSD_EINT_CARD 0x40
#define WBSD_EINT_FIFO_THRE 0x20
#define WBSD_EINT_CCRC 0x10
#define WBSD_EINT_CRC 0x10
#define WBSD_EINT_TIMEOUT 0x08
#define WBSD_EINT_PROGEND 0x04
#define WBSD_EINT_CRC 0x02
#define WBSD_EINT_BUSYEND 0x02
#define WBSD_EINT_TC 0x01
#define WBSD_INT_PENDING 0x80
......@@ -158,8 +158,6 @@ struct wbsd_host
unsigned int offset; /* Offset into current entry */
unsigned int remain; /* Data left in curren entry */
int size; /* Total size of transfer */
char* dma_buffer; /* ISA DMA buffer */
dma_addr_t dma_addr; /* Physical address for same */
......@@ -182,7 +180,6 @@ struct wbsd_host
struct tasklet_struct crc_tasklet;
struct tasklet_struct timeout_tasklet;
struct tasklet_struct finish_tasklet;
struct tasklet_struct block_tasklet;
struct timer_list ignore_timer; /* Ignore detection timer */
};
This diff is collapsed.
#ifndef ASMARM_ARCH_MMC_H
#define ASMARM_ARCH_MMC_H
#include <linux/mmc/protocol.h>
#include <linux/mmc/host.h>
struct imxmmc_platform_data {
int (*card_present)(void);
......
#ifndef ASMARM_ARCH_MMC_H
#define ASMARM_ARCH_MMC_H
#include <linux/mmc/protocol.h>
#include <linux/mmc/host.h>
#include <linux/interrupt.h>
struct device;
......
......@@ -4,7 +4,7 @@
#ifndef ASMARM_MACH_MMC_H
#define ASMARM_MACH_MMC_H
#include <linux/mmc/protocol.h>
#include <linux/mmc/host.h>
struct mmc_platform_data {
unsigned int ocr_mask; /* available voltages */
......
......@@ -10,7 +10,7 @@
#ifndef LINUX_MMC_CARD_H
#define LINUX_MMC_CARD_H
#include <linux/mmc/mmc.h>
#include <linux/mmc/core.h>
struct mmc_cid {
unsigned int manfid;
......@@ -41,6 +41,7 @@ struct mmc_csd {
struct mmc_ext_csd {
unsigned int hs_max_dtr;
unsigned int sectors;
};
struct sd_scr {
......@@ -60,18 +61,17 @@ 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 type; /* card type */
#define MMC_TYPE_MMC 0 /* MMC card */
#define MMC_TYPE_SD 1 /* SD card */
unsigned int state; /* (our) card state */
#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
#define MMC_STATE_DEAD (1<<1) /* device no longer in stack */
#define MMC_STATE_BAD (1<<2) /* unrecognised device */
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
#define MMC_STATE_READONLY (1<<4) /* card is read-only */
#define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */
#define MMC_STATE_BLOCKADDR (1<<6) /* card uses block-addressing */
#define MMC_STATE_READONLY (1<<1) /* card is read-only */
#define MMC_STATE_HIGHSPEED (1<<2) /* card is in high speed mode */
#define MMC_STATE_BLOCKADDR (1<<3) /* card uses block-addressing */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
......@@ -82,18 +82,15 @@ struct mmc_card {
struct sd_switch_caps sw_caps; /* switch (CMD6) caps */
};
#define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC)
#define mmc_card_sd(c) ((c)->type == MMC_TYPE_SD)
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD)
#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD)
#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD)
#define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD)
#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
......@@ -119,11 +116,4 @@ struct mmc_driver {
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/core.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 LINUX_MMC_CORE_H
#define LINUX_MMC_CORE_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_PRESENT (1 << 0)
#define MMC_RSP_136 (1 << 1) /* 136 bit response */
#define MMC_RSP_CRC (1 << 2) /* expect valid crc */
#define MMC_RSP_BUSY (1 << 3) /* card may send busy */
#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */
#define MMC_CMD_MASK (3 << 5) /* command type */
#define MMC_CMD_AC (0 << 5)
#define MMC_CMD_ADTC (1 << 5)
#define MMC_CMD_BC (2 << 5)
#define MMC_CMD_BCR (3 << 5)
/*
* These are the response types, and correspond to valid bit
* patterns of the above flags. One additional valid pattern
* is all zeros, which means we don't expect a response.
*/
#define MMC_RSP_NONE (0)
#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
/*
* These are the command types.
*/
#define mmc_cmd_type(cmd) ((cmd)->flags & MMC_CMD_MASK)
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 *mrq; /* associated 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; /* data block size */
unsigned int blocks; /* number of blocks */
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)
#define MMC_DATA_MULTI (1 << 11)
unsigned int bytes_xfered;
struct mmc_command *stop; /* stop command */
struct mmc_request *mrq; /* associated request */
unsigned int sg_len; /* size of scatter list */
struct scatterlist *sg; /* I/O scatter list */
};
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_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
struct mmc_command *, int);
extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *, int);
extern void mmc_claim_host(struct mmc_host *host);
extern void mmc_release_host(struct mmc_host *host);
#endif
......@@ -10,36 +10,13 @@
#ifndef LINUX_MMC_HOST_H
#define LINUX_MMC_HOST_H
#include <linux/mmc/mmc.h>
#include <linux/mmc/core.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
/* vdd stores the bit number of the selected voltage range from below. */
unsigned char bus_mode; /* command output mode */
......@@ -88,6 +65,24 @@ struct mmc_host {
unsigned int f_max;
u32 ocr_avail;
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
#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 */
unsigned long caps; /* Host capabilities */
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
......@@ -106,6 +101,8 @@ struct mmc_host {
unsigned int max_blk_count; /* maximum number of blocks in one req */
/* private data */
spinlock_t lock; /* lock for claim and bus ops */
struct mmc_ios ios; /* current io bus settings */
u32 ocr; /* the current OCR setting */
......@@ -113,15 +110,19 @@ struct mmc_host {
#define MMC_MODE_MMC 0
#define MMC_MODE_SD 1
struct list_head cards; /* devices attached to this host */
struct mmc_card *card; /* device attached to this host */
wait_queue_head_t wq;
spinlock_t lock; /* claimed lock */
unsigned int claimed:1; /* host exclusively claimed */
struct mmc_card *card_selected; /* the selected MMC card */
struct delayed_work detect;
#ifdef CONFIG_MMC_DEBUG
unsigned int removed:1; /* host is being removed */
#endif
const struct mmc_bus_ops *bus_ops; /* current bus driver */
unsigned int bus_refs; /* reference counter */
unsigned int bus_dead:1; /* bus has been released */
unsigned long private[0] ____cacheline_aligned;
};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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