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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (66 commits)
  mmc: add new sdhci-pxa driver for Marvell SoCs
  mmc: make number of mmcblk minors configurable
  mmc_spi: Recover from CRC errors for r/w operation over SPI.
  mmc: sdhci-pltfm: add -pltfm driver for imx35/51
  mmc: sdhci-of-esdhc: factor out common stuff
  mmc: sdhci_pltfm: pass more data on custom init call
  mmc: sdhci: introduce get_ro private write-protect hook
  mmc: sdhci-pltfm: move .h file into appropriate subdir
  mmc: sdhci-pltfm: Add structure for host-specific data
  mmc: fix cb710 kconfig dependency warning
  mmc: cb710: remove debugging printk (info duplicated from mmc-core)
  mmc: cb710: clear irq handler on init() error path
  mmc: cb710: remove unnecessary msleep()
  mmc: cb710: implement get_cd() callback
  mmc: cb710: partially demystify clock selection
  mmc: add a file to debugfs for changing host clock at runtime
  mmc: sdhci: allow for eMMC 74 clock generation by controller
  mmc: sdhci: highspeed: check for mmc as well as sd cards
  mmc: sdhci: Add Moorestown device support
  mmc: sdhci: Intel Medfield support
  ...
This commit is contained in:
Linus Torvalds 2010-10-28 09:33:42 -07:00
commit 00ebb6382b
60 changed files with 2537 additions and 567 deletions

View File

@ -2520,6 +2520,12 @@ Your cooperation is appreciated.
8 = /dev/mmcblk1 Second SD/MMC card
...
The start of next SD/MMC card can be configured with
CONFIG_MMC_BLOCK_MINORS, or overridden at boot/modprobe
time using the mmcblk.perdev_minors option. That would
bump the offset between each card to be the configured
value instead of the default 8.
179 char CCube DVXChip-based PCI products
0 = /dev/dvxirq0 First DVX device
1 = /dev/dvxirq1 Second DVX device

View File

@ -0,0 +1,32 @@
/* linux/arch/arm/plat-pxa/include/plat/sdhci.h
*
* Copyright 2010 Marvell
* Zhangfei Gao <zhangfei.gao@marvell.com>
*
* PXA Platform - SDHCI platform data definitions
*
* 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 __PLAT_PXA_SDHCI_H
#define __PLAT_PXA_SDHCI_H
/* pxa specific flag */
/* Require clock free running */
#define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0)
/*
* struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI
* @max_speed: the maximum speed supported
* @quirks: quirks of specific device
* @flags: flags for platform requirement
*/
struct sdhci_pxa_platdata {
unsigned int max_speed;
unsigned int quirks;
unsigned int flags;
};
#endif /* __PLAT_PXA_SDHCI_H */

View File

@ -2,9 +2,7 @@
# Makefile for the kernel mmc device drivers.
#
ifeq ($(CONFIG_MMC_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG
obj-$(CONFIG_MMC) += core/
obj-$(CONFIG_MMC) += card/

View File

@ -14,6 +14,23 @@ config MMC_BLOCK
mount the filesystem. Almost everyone wishing MMC support
should say Y or M here.
config MMC_BLOCK_MINORS
int "Number of minors per block device"
range 4 256
default 8
help
Number of minors per block device. One is needed for every
partition on the disk (plus one for the whole disk).
Number of total MMC minors available is 256, so your number
of supported block devices will be limited to 256 divided
by this number.
Default is 8 to be backwards compatible with previous
hardwired device numbering.
If unsure, say 8 here.
config MMC_BLOCK_BOUNCE
bool "Use bounce buffer for simple hosts"
depends on MMC_BLOCK

View File

@ -2,10 +2,6 @@
# 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
obj-$(CONFIG_MMC_TEST) += mmc_test.o

View File

@ -43,15 +43,27 @@
#include "queue.h"
MODULE_ALIAS("mmc:block");
/*
* max 8 partitions per card
*/
#define MMC_SHIFT 3
#define MMC_NUM_MINORS (256 >> MMC_SHIFT)
#ifdef MODULE_PARAM_PREFIX
#undef MODULE_PARAM_PREFIX
#endif
#define MODULE_PARAM_PREFIX "mmcblk."
static DEFINE_MUTEX(block_mutex);
static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS);
/*
* The defaults come from config options but can be overriden by module
* or bootarg options.
*/
static int perdev_minors = CONFIG_MMC_BLOCK_MINORS;
/*
* We've only got one major, so number of mmcblk devices is
* limited to 256 / number of minors per device.
*/
static int max_devices;
/* 256 minors, so at most 256 separate devices */
static DECLARE_BITMAP(dev_use, 256);
/*
* There is one mmc_blk_data per slot.
@ -67,6 +79,9 @@ struct mmc_blk_data {
static DEFINE_MUTEX(open_lock);
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
@ -88,10 +103,10 @@ static void mmc_blk_put(struct mmc_blk_data *md)
md->usage--;
if (md->usage == 0) {
int devmaj = MAJOR(disk_devt(md->disk));
int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT;
int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
if (!devmaj)
devidx = md->disk->first_minor >> MMC_SHIFT;
devidx = md->disk->first_minor / perdev_minors;
blk_cleanup_queue(md->queue.queue);
@ -373,7 +388,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
readcmd = MMC_READ_SINGLE_BLOCK;
writecmd = MMC_WRITE_BLOCK;
}
if (rq_data_dir(req) == READ) {
brq.cmd.opcode = readcmd;
brq.data.flags |= MMC_DATA_READ;
@ -567,8 +581,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
struct mmc_blk_data *md;
int devidx, ret;
devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
if (devidx >= MMC_NUM_MINORS)
devidx = find_first_zero_bit(dev_use, max_devices);
if (devidx >= max_devices)
return ERR_PTR(-ENOSPC);
__set_bit(devidx, dev_use);
@ -585,7 +599,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
*/
md->read_only = mmc_blk_readonly(card);
md->disk = alloc_disk(1 << MMC_SHIFT);
md->disk = alloc_disk(perdev_minors);
if (md->disk == NULL) {
ret = -ENOMEM;
goto err_kfree;
@ -602,7 +616,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
md->queue.data = md;
md->disk->major = MMC_BLOCK_MAJOR;
md->disk->first_minor = devidx << MMC_SHIFT;
md->disk->first_minor = devidx * perdev_minors;
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
md->disk->queue = md->queue.queue;
@ -620,7 +634,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
* messages to tell when the card is present.
*/
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
"mmcblk%d", devidx);
blk_queue_logical_block_size(md->queue.queue, 512);
@ -651,23 +666,15 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
static int
mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
{
struct mmc_command cmd;
int err;
/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
if (mmc_card_blockaddr(card))
return 0;
mmc_claim_host(card->host);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 512;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
err = mmc_set_blocklen(card, 512);
mmc_release_host(card->host);
if (err) {
printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
md->disk->disk_name, cmd.arg, err);
printk(KERN_ERR "%s: unable to set block size to 512: %d\n",
md->disk->disk_name, err);
return -EINVAL;
}
@ -678,7 +685,6 @@ static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
int err;
char cap_str[10];
/*
@ -768,6 +774,11 @@ static int __init mmc_blk_init(void)
{
int res;
if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
pr_info("mmcblk: using %d minors per device\n", perdev_minors);
max_devices = 256 / perdev_minors;
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
if (res)
goto out;

View File

@ -17,6 +17,11 @@
#include <linux/scatterlist.h>
#include <linux/swap.h> /* For nr_free_buffer_pages() */
#include <linux/list.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/seq_file.h>
#define RESULT_OK 0
#define RESULT_FAIL 1
@ -56,7 +61,9 @@ struct mmc_test_mem {
* struct mmc_test_area - information for performance tests.
* @max_sz: test area size (in bytes)
* @dev_addr: address on card at which to do performance tests
* @max_segs: maximum segments in scatterlist @sg
* @max_tfr: maximum transfer size allowed by driver (in bytes)
* @max_segs: maximum segments allowed by driver in scatterlist @sg
* @max_seg_sz: maximum segment size allowed by driver
* @blocks: number of (512 byte) blocks currently mapped by @sg
* @sg_len: length of currently mapped scatterlist @sg
* @mem: allocated memory
@ -65,13 +72,59 @@ struct mmc_test_mem {
struct mmc_test_area {
unsigned long max_sz;
unsigned int dev_addr;
unsigned int max_tfr;
unsigned int max_segs;
unsigned int max_seg_sz;
unsigned int blocks;
unsigned int sg_len;
struct mmc_test_mem *mem;
struct scatterlist *sg;
};
/**
* struct mmc_test_transfer_result - transfer results for performance tests.
* @link: double-linked list
* @count: amount of group of sectors to check
* @sectors: amount of sectors to check in one group
* @ts: time values of transfer
* @rate: calculated transfer rate
*/
struct mmc_test_transfer_result {
struct list_head link;
unsigned int count;
unsigned int sectors;
struct timespec ts;
unsigned int rate;
};
/**
* struct mmc_test_general_result - results for tests.
* @link: double-linked list
* @card: card under test
* @testcase: number of test case
* @result: result of test run
* @tr_lst: transfer measurements if any as mmc_test_transfer_result
*/
struct mmc_test_general_result {
struct list_head link;
struct mmc_card *card;
int testcase;
int result;
struct list_head tr_lst;
};
/**
* struct mmc_test_dbgfs_file - debugfs related file.
* @link: double-linked list
* @card: card under test
* @file: file created under debugfs
*/
struct mmc_test_dbgfs_file {
struct list_head link;
struct mmc_card *card;
struct dentry *file;
};
/**
* struct mmc_test_card - test information.
* @card: card under test
@ -79,6 +132,7 @@ struct mmc_test_area {
* @buffer: transfer buffer
* @highmem: buffer for highmem tests
* @area: information for performance tests
* @gr: pointer to results of current testcase
*/
struct mmc_test_card {
struct mmc_card *card;
@ -88,7 +142,8 @@ struct mmc_test_card {
#ifdef CONFIG_HIGHMEM
struct page *highmem;
#endif
struct mmc_test_area area;
struct mmc_test_area area;
struct mmc_test_general_result *gr;
};
/*******************************************************************/
@ -100,17 +155,7 @@ struct mmc_test_card {
*/
static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
{
struct mmc_command cmd;
int ret;
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = size;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
if (ret)
return ret;
return 0;
return mmc_set_blocklen(test->card, size);
}
/*
@ -245,27 +290,38 @@ static void mmc_test_free_mem(struct mmc_test_mem *mem)
/*
* Allocate a lot of memory, preferrably max_sz but at least min_sz. In case
* there isn't much memory do not exceed 1/16th total lowmem pages.
* there isn't much memory do not exceed 1/16th total lowmem pages. Also do
* not exceed a maximum number of segments and try not to make segments much
* bigger than maximum segment size.
*/
static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
unsigned long max_sz)
unsigned long max_sz,
unsigned int max_segs,
unsigned int max_seg_sz)
{
unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE);
unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE);
unsigned long max_seg_page_cnt = DIV_ROUND_UP(max_seg_sz, PAGE_SIZE);
unsigned long page_cnt = 0;
unsigned long limit = nr_free_buffer_pages() >> 4;
struct mmc_test_mem *mem;
if (max_page_cnt > limit)
max_page_cnt = limit;
if (max_page_cnt < min_page_cnt)
max_page_cnt = min_page_cnt;
if (min_page_cnt > max_page_cnt)
min_page_cnt = max_page_cnt;
if (max_seg_page_cnt > max_page_cnt)
max_seg_page_cnt = max_page_cnt;
if (max_segs > max_page_cnt)
max_segs = max_page_cnt;
mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL);
if (!mem)
return NULL;
mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_page_cnt,
mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_segs,
GFP_KERNEL);
if (!mem->arr)
goto out_free;
@ -276,7 +332,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN |
__GFP_NORETRY;
order = get_order(max_page_cnt << PAGE_SHIFT);
order = get_order(max_seg_page_cnt << PAGE_SHIFT);
while (1) {
page = alloc_pages(flags, order);
if (page || !order)
@ -295,6 +351,11 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
break;
max_page_cnt -= 1UL << order;
page_cnt += 1UL << order;
if (mem->cnt >= max_segs) {
if (page_cnt < min_page_cnt)
goto out_free;
break;
}
}
return mem;
@ -310,7 +371,8 @@ out_free:
*/
static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
struct scatterlist *sglist, int repeat,
unsigned int max_segs, unsigned int *sg_len)
unsigned int max_segs, unsigned int max_seg_sz,
unsigned int *sg_len)
{
struct scatterlist *sg = NULL;
unsigned int i;
@ -322,8 +384,10 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
for (i = 0; i < mem->cnt; i++) {
unsigned long len = PAGE_SIZE << mem->arr[i].order;
if (sz < len)
if (len > sz)
len = sz;
if (len > max_seg_sz)
len = max_seg_sz;
if (sg)
sg = sg_next(sg);
else
@ -355,6 +419,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
unsigned long sz,
struct scatterlist *sglist,
unsigned int max_segs,
unsigned int max_seg_sz,
unsigned int *sg_len)
{
struct scatterlist *sg = NULL;
@ -365,7 +430,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
sg_init_table(sglist, max_segs);
*sg_len = 0;
while (sz && i) {
while (sz) {
base = page_address(mem->arr[--i].page);
cnt = 1 << mem->arr[i].order;
while (sz && cnt) {
@ -374,7 +439,9 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
continue;
last_addr = addr;
len = PAGE_SIZE;
if (sz < len)
if (len > max_seg_sz)
len = max_seg_sz;
if (len > sz)
len = sz;
if (sg)
sg = sg_next(sg);
@ -386,6 +453,8 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
sz -= len;
*sg_len += 1;
}
if (i == 0)
i = mem->cnt;
}
if (sg)
@ -420,6 +489,30 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
return bytes;
}
/*
* Save transfer results for future usage
*/
static void mmc_test_save_transfer_result(struct mmc_test_card *test,
unsigned int count, unsigned int sectors, struct timespec ts,
unsigned int rate)
{
struct mmc_test_transfer_result *tr;
if (!test->gr)
return;
tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL);
if (!tr)
return;
tr->count = count;
tr->sectors = sectors;
tr->ts = ts;
tr->rate = rate;
list_add_tail(&tr->link, &test->gr->tr_lst);
}
/*
* Print the transfer rate.
*/
@ -436,8 +529,10 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
"seconds (%u kB/s, %u KiB/s)\n",
mmc_hostname(test->card->host), sectors, sectors >> 1,
(sectors == 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
(sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
(unsigned long)ts.tv_nsec, rate / 1000, rate / 1024);
mmc_test_save_transfer_result(test, 1, sectors, ts, rate);
}
/*
@ -458,9 +553,11 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
"%lu.%09lu seconds (%u kB/s, %u KiB/s)\n",
mmc_hostname(test->card->host), count, sectors, count,
sectors >> 1, (sectors == 1 ? ".5" : ""),
sectors >> 1, (sectors & 1 ? ".5" : ""),
(unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
rate / 1000, rate / 1024);
mmc_test_save_transfer_result(test, count, sectors, ts, rate);
}
/*
@ -1215,16 +1312,22 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
int max_scatter)
{
struct mmc_test_area *t = &test->area;
int err;
t->blocks = sz >> 9;
if (max_scatter) {
return mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
t->max_segs, &t->sg_len);
} else {
return mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
t->max_segs, t->max_seg_sz,
&t->sg_len);
} else {
err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
t->max_seg_sz, &t->sg_len);
}
if (err)
printk(KERN_INFO "%s: Failed to map sg list\n",
mmc_hostname(test->card->host));
return err;
}
/*
@ -1249,6 +1352,22 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
struct timespec ts1, ts2;
int ret;
/*
* In the case of a maximally scattered transfer, the maximum transfer
* size is further limited by using PAGE_SIZE segments.
*/
if (max_scatter) {
struct mmc_test_area *t = &test->area;
unsigned long max_tfr;
if (t->max_seg_sz >= PAGE_SIZE)
max_tfr = t->max_segs * PAGE_SIZE;
else
max_tfr = t->max_segs * t->max_seg_sz;
if (sz > max_tfr)
sz = max_tfr;
}
ret = mmc_test_area_map(test, sz, max_scatter);
if (ret)
return ret;
@ -1274,7 +1393,7 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
*/
static int mmc_test_area_fill(struct mmc_test_card *test)
{
return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
1, 0, 0);
}
@ -1328,16 +1447,29 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
t->max_sz = TEST_AREA_MAX_SIZE;
else
t->max_sz = (unsigned long)test->card->pref_erase << 9;
t->max_segs = test->card->host->max_segs;
t->max_seg_sz = test->card->host->max_seg_size;
t->max_tfr = t->max_sz;
if (t->max_tfr >> 9 > test->card->host->max_blk_count)
t->max_tfr = test->card->host->max_blk_count << 9;
if (t->max_tfr > test->card->host->max_req_size)
t->max_tfr = test->card->host->max_req_size;
if (t->max_tfr / t->max_seg_sz > t->max_segs)
t->max_tfr = t->max_segs * t->max_seg_sz;
/*
* Try to allocate enough memory for the whole area. Less is OK
* Try to allocate enough memory for a max. sized transfer. Less is OK
* because the same memory can be mapped into the scatterlist more than
* once.
* once. Also, take into account the limits imposed on scatterlist
* segments by the host driver.
*/
t->mem = mmc_test_alloc_mem(min_sz, t->max_sz);
t->mem = mmc_test_alloc_mem(min_sz, t->max_tfr, t->max_segs,
t->max_seg_sz);
if (!t->mem)
return -ENOMEM;
t->max_segs = DIV_ROUND_UP(t->max_sz, PAGE_SIZE);
t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL);
if (!t->sg) {
ret = -ENOMEM;
@ -1401,7 +1533,7 @@ static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
static int mmc_test_best_performance(struct mmc_test_card *test, int write,
int max_scatter)
{
return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
write, max_scatter, 1);
}
@ -1446,12 +1578,13 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test)
unsigned int dev_addr;
int ret;
for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
dev_addr = test->area.dev_addr + (sz >> 9);
ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
if (ret)
return ret;
}
sz = test->area.max_tfr;
dev_addr = test->area.dev_addr;
return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
}
@ -1468,7 +1601,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
ret = mmc_test_area_erase(test);
if (ret)
return ret;
for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
dev_addr = test->area.dev_addr + (sz >> 9);
ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
if (ret)
@ -1477,6 +1610,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
ret = mmc_test_area_erase(test);
if (ret)
return ret;
sz = test->area.max_tfr;
dev_addr = test->area.dev_addr;
return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
}
@ -1516,29 +1650,63 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
return 0;
}
static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
{
unsigned int dev_addr, i, cnt;
struct timespec ts1, ts2;
int ret;
cnt = test->area.max_sz / sz;
dev_addr = test->area.dev_addr;
getnstimeofday(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
if (ret)
return ret;
dev_addr += (sz >> 9);
}
getnstimeofday(&ts2);
mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
return 0;
}
/*
* Consecutive read performance by transfer size.
*/
static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
{
unsigned long sz;
int ret;
for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
ret = mmc_test_seq_read_perf(test, sz);
if (ret)
return ret;
}
sz = test->area.max_tfr;
return mmc_test_seq_read_perf(test, sz);
}
static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
{
unsigned int dev_addr, i, cnt;
struct timespec ts1, ts2;
int ret;
for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
cnt = test->area.max_sz / sz;
dev_addr = test->area.dev_addr;
getnstimeofday(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
if (ret)
return ret;
dev_addr += (sz >> 9);
}
getnstimeofday(&ts2);
mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
ret = mmc_test_area_erase(test);
if (ret)
return ret;
cnt = test->area.max_sz / sz;
dev_addr = test->area.dev_addr;
getnstimeofday(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
if (ret)
return ret;
dev_addr += (sz >> 9);
}
getnstimeofday(&ts2);
mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
return 0;
}
@ -1548,27 +1716,15 @@ static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
{
unsigned long sz;
unsigned int dev_addr, i, cnt;
struct timespec ts1, ts2;
int ret;
for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
ret = mmc_test_area_erase(test);
for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
ret = mmc_test_seq_write_perf(test, sz);
if (ret)
return ret;
cnt = test->area.max_sz / sz;
dev_addr = test->area.dev_addr;
getnstimeofday(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
if (ret)
return ret;
dev_addr += (sz >> 9);
}
getnstimeofday(&ts2);
mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
}
return 0;
sz = test->area.max_tfr;
return mmc_test_seq_write_perf(test, sz);
}
/*
@ -1853,6 +2009,8 @@ static const struct mmc_test_case mmc_test_cases[] = {
static DEFINE_MUTEX(mmc_test_lock);
static LIST_HEAD(mmc_test_result);
static void mmc_test_run(struct mmc_test_card *test, int testcase)
{
int i, ret;
@ -1863,6 +2021,8 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
mmc_claim_host(test->card->host);
for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
struct mmc_test_general_result *gr;
if (testcase && ((i + 1) != testcase))
continue;
@ -1881,6 +2041,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
}
}
gr = kzalloc(sizeof(struct mmc_test_general_result),
GFP_KERNEL);
if (gr) {
INIT_LIST_HEAD(&gr->tr_lst);
/* Assign data what we know already */
gr->card = test->card;
gr->testcase = i;
/* Append container to global one */
list_add_tail(&gr->link, &mmc_test_result);
/*
* Save the pointer to created container in our private
* structure.
*/
test->gr = gr;
}
ret = mmc_test_cases[i].run(test);
switch (ret) {
case RESULT_OK:
@ -1906,6 +2085,10 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
mmc_hostname(test->card->host), ret);
}
/* Save the result */
if (gr)
gr->result = ret;
if (mmc_test_cases[i].cleanup) {
ret = mmc_test_cases[i].cleanup(test);
if (ret) {
@ -1923,30 +2106,95 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
mmc_hostname(test->card->host));
}
static ssize_t mmc_test_show(struct device *dev,
struct device_attribute *attr, char *buf)
static void mmc_test_free_result(struct mmc_card *card)
{
struct mmc_test_general_result *gr, *grs;
mutex_lock(&mmc_test_lock);
list_for_each_entry_safe(gr, grs, &mmc_test_result, link) {
struct mmc_test_transfer_result *tr, *trs;
if (card && gr->card != card)
continue;
list_for_each_entry_safe(tr, trs, &gr->tr_lst, link) {
list_del(&tr->link);
kfree(tr);
}
list_del(&gr->link);
kfree(gr);
}
mutex_unlock(&mmc_test_lock);
}
static LIST_HEAD(mmc_test_file_test);
static int mtf_test_show(struct seq_file *sf, void *data)
{
struct mmc_card *card = (struct mmc_card *)sf->private;
struct mmc_test_general_result *gr;
mutex_lock(&mmc_test_lock);
list_for_each_entry(gr, &mmc_test_result, link) {
struct mmc_test_transfer_result *tr;
if (gr->card != card)
continue;
seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result);
list_for_each_entry(tr, &gr->tr_lst, link) {
seq_printf(sf, "%u %d %lu.%09lu %u\n",
tr->count, tr->sectors,
(unsigned long)tr->ts.tv_sec,
(unsigned long)tr->ts.tv_nsec,
tr->rate);
}
}
mutex_unlock(&mmc_test_lock);
return 0;
}
static ssize_t mmc_test_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
static int mtf_test_open(struct inode *inode, struct file *file)
{
struct mmc_card *card;
return single_open(file, mtf_test_show, inode->i_private);
}
static ssize_t mtf_test_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
struct seq_file *sf = (struct seq_file *)file->private_data;
struct mmc_card *card = (struct mmc_card *)sf->private;
struct mmc_test_card *test;
int testcase;
char lbuf[12];
long testcase;
card = container_of(dev, struct mmc_card, dev);
if (count >= sizeof(lbuf))
return -EINVAL;
testcase = simple_strtol(buf, NULL, 10);
if (copy_from_user(lbuf, buf, count))
return -EFAULT;
lbuf[count] = '\0';
if (strict_strtol(lbuf, 10, &testcase))
return -EINVAL;
test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
if (!test)
return -ENOMEM;
/*
* Remove all test cases associated with given card. Thus we have only
* actual data of the last run.
*/
mmc_test_free_result(card);
test->card = card;
test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
@ -1973,16 +2221,78 @@ static ssize_t mmc_test_store(struct device *dev,
return count;
}
static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store);
static const struct file_operations mmc_test_fops_test = {
.open = mtf_test_open,
.read = seq_read,
.write = mtf_test_write,
.llseek = seq_lseek,
.release = single_release,
};
static void mmc_test_free_file_test(struct mmc_card *card)
{
struct mmc_test_dbgfs_file *df, *dfs;
mutex_lock(&mmc_test_lock);
list_for_each_entry_safe(df, dfs, &mmc_test_file_test, link) {
if (card && df->card != card)
continue;
debugfs_remove(df->file);
list_del(&df->link);
kfree(df);
}
mutex_unlock(&mmc_test_lock);
}
static int mmc_test_register_file_test(struct mmc_card *card)
{
struct dentry *file = NULL;
struct mmc_test_dbgfs_file *df;
int ret = 0;
mutex_lock(&mmc_test_lock);
if (card->debugfs_root)
file = debugfs_create_file("test", S_IWUSR | S_IRUGO,
card->debugfs_root, card, &mmc_test_fops_test);
if (IS_ERR_OR_NULL(file)) {
dev_err(&card->dev,
"Can't create file. Perhaps debugfs is disabled.\n");
ret = -ENODEV;
goto err;
}
df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL);
if (!df) {
debugfs_remove(file);
dev_err(&card->dev,
"Can't allocate memory for internal usage.\n");
ret = -ENOMEM;
goto err;
}
df->card = card;
df->file = file;
list_add(&df->link, &mmc_test_file_test);
err:
mutex_unlock(&mmc_test_lock);
return ret;
}
static int mmc_test_probe(struct mmc_card *card)
{
int ret;
if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
if (!mmc_card_mmc(card) && !mmc_card_sd(card))
return -ENODEV;
ret = device_create_file(&card->dev, &dev_attr_test);
ret = mmc_test_register_file_test(card);
if (ret)
return ret;
@ -1993,7 +2303,8 @@ static int mmc_test_probe(struct mmc_card *card)
static void mmc_test_remove(struct mmc_card *card)
{
device_remove_file(&card->dev, &dev_attr_test);
mmc_test_free_result(card);
mmc_test_free_file_test(card);
}
static struct mmc_driver mmc_driver = {
@ -2011,6 +2322,10 @@ static int __init mmc_test_init(void)
static void __exit mmc_test_exit(void)
{
/* Clear stalled data if card is still plugged */
mmc_test_free_result(NULL);
mmc_test_free_file_test(NULL);
mmc_unregister_driver(&mmc_driver);
}

View File

@ -146,7 +146,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
}
#ifdef CONFIG_MMC_BLOCK_BOUNCE
if (host->max_hw_segs == 1) {
if (host->max_segs == 1) {
unsigned int bouncesz;
bouncesz = MMC_QUEUE_BOUNCESZ;
@ -196,21 +196,23 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_bounce_limit(mq->queue, limit);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segments(mq->queue, host->max_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
mq->sg = kmalloc(sizeof(struct scatterlist) *
host->max_phys_segs, GFP_KERNEL);
host->max_segs, GFP_KERNEL);
if (!mq->sg) {
ret = -ENOMEM;
goto cleanup_queue;
}
sg_init_table(mq->sg, host->max_phys_segs);
sg_init_table(mq->sg, host->max_segs);
}
init_MUTEX(&mq->thread_sem);
sema_init(&mq->thread_sem, 1);
mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d",
host->index);
mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
if (IS_ERR(mq->thread)) {
ret = PTR_ERR(mq->thread);
goto free_bounce_sg;

View File

@ -2,10 +2,6 @@
# 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 bus.o host.o \
mmc.o mmc_ops.o sd.o sd_ops.o \

View File

@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@ -22,13 +23,12 @@
#include "sdio_cis.h"
#include "bus.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 ssize_t mmc_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mmc_card *card = dev_to_mmc_card(dev);
struct mmc_card *card = mmc_dev_to_card(dev);
switch (card->type) {
case MMC_TYPE_MMC:
@ -62,7 +62,7 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv)
static int
mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct mmc_card *card = dev_to_mmc_card(dev);
struct mmc_card *card = mmc_dev_to_card(dev);
const char *type;
int retval = 0;
@ -105,7 +105,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
static int mmc_bus_probe(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = dev_to_mmc_card(dev);
struct mmc_card *card = mmc_dev_to_card(dev);
return drv->probe(card);
}
@ -113,7 +113,7 @@ static int mmc_bus_probe(struct device *dev)
static int mmc_bus_remove(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = dev_to_mmc_card(dev);
struct mmc_card *card = mmc_dev_to_card(dev);
drv->remove(card);
@ -123,7 +123,7 @@ static int mmc_bus_remove(struct device *dev)
static int mmc_bus_suspend(struct device *dev, pm_message_t state)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = dev_to_mmc_card(dev);
struct mmc_card *card = mmc_dev_to_card(dev);
int ret = 0;
if (dev->driver && drv->suspend)
@ -134,7 +134,7 @@ static int mmc_bus_suspend(struct device *dev, pm_message_t state)
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);
struct mmc_card *card = mmc_dev_to_card(dev);
int ret = 0;
if (dev->driver && drv->resume)
@ -142,6 +142,41 @@ static int mmc_bus_resume(struct device *dev)
return ret;
}
#ifdef CONFIG_PM_RUNTIME
static int mmc_runtime_suspend(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
return mmc_power_save_host(card->host);
}
static int mmc_runtime_resume(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
return mmc_power_restore_host(card->host);
}
static int mmc_runtime_idle(struct device *dev)
{
return pm_runtime_suspend(dev);
}
static const struct dev_pm_ops mmc_bus_pm_ops = {
.runtime_suspend = mmc_runtime_suspend,
.runtime_resume = mmc_runtime_resume,
.runtime_idle = mmc_runtime_idle,
};
#define MMC_PM_OPS_PTR (&mmc_bus_pm_ops)
#else /* !CONFIG_PM_RUNTIME */
#define MMC_PM_OPS_PTR NULL
#endif /* !CONFIG_PM_RUNTIME */
static struct bus_type mmc_bus_type = {
.name = "mmc",
.dev_attrs = mmc_dev_attrs,
@ -151,6 +186,7 @@ static struct bus_type mmc_bus_type = {
.remove = mmc_bus_remove,
.suspend = mmc_bus_suspend,
.resume = mmc_bus_resume,
.pm = MMC_PM_OPS_PTR,
};
int mmc_register_bus(void)
@ -189,7 +225,7 @@ EXPORT_SYMBOL(mmc_unregister_driver);
static void mmc_release_card(struct device *dev)
{
struct mmc_card *card = dev_to_mmc_card(dev);
struct mmc_card *card = mmc_dev_to_card(dev);
sdio_free_common_cis(card);
@ -254,14 +290,16 @@ int mmc_add_card(struct mmc_card *card)
}
if (mmc_host_is_spi(card->host)) {
printk(KERN_INFO "%s: new %s%s card on SPI\n",
printk(KERN_INFO "%s: new %s%s%s card on SPI\n",
mmc_hostname(card->host),
mmc_card_highspeed(card) ? "high speed " : "",
mmc_card_ddr_mode(card) ? "DDR " : "",
type);
} else {
printk(KERN_INFO "%s: new %s%s card at address %04x\n",
printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
mmc_hostname(card->host),
mmc_card_highspeed(card) ? "high speed " : "",
mmc_card_ddr_mode(card) ? "DDR " : "",
type, card->rca);
}

View File

@ -14,7 +14,7 @@
#define MMC_DEV_ATTR(name, fmt, args...) \
static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct mmc_card *card = container_of(dev, struct mmc_card, dev); \
struct mmc_card *card = mmc_dev_to_card(dev); \
return sprintf(buf, fmt, args); \
} \
static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)

View File

@ -58,6 +58,7 @@ int mmc_assume_removable;
#else
int mmc_assume_removable = 1;
#endif
EXPORT_SYMBOL(mmc_assume_removable);
module_param_named(removable, mmc_assume_removable, bool, 0644);
MODULE_PARM_DESC(
removable,
@ -649,13 +650,23 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
mmc_set_ios(host);
}
/*
* Change data bus width and DDR mode of a host.
*/
void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
unsigned int ddr)
{
host->ios.bus_width = width;
host->ios.ddr = ddr;
mmc_set_ios(host);
}
/*
* Change data bus width of a host.
*/
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{
host->ios.bus_width = width;
mmc_set_ios(host);
mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
}
/**
@ -771,8 +782,9 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
/**
* mmc_regulator_set_ocr - set regulator to match host->ios voltage
* @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
* @mmc: the host to regulate
* @supply: regulator to use
* @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
*
* Returns zero on success, else negative errno.
*
@ -780,15 +792,12 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
* a particular supply voltage. This would normally be called from the
* set_ios() method.
*/
int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply,
unsigned short vdd_bit)
{
int result = 0;
int min_uV, max_uV;
int enabled;
enabled = regulator_is_enabled(supply);
if (enabled < 0)
return enabled;
if (vdd_bit) {
int tmp;
@ -819,17 +828,25 @@ int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
else
result = 0;
if (result == 0 && !enabled)
if (result == 0 && !mmc->regulator_enabled) {
result = regulator_enable(supply);
} else if (enabled) {
if (!result)
mmc->regulator_enabled = true;
}
} else if (mmc->regulator_enabled) {
result = regulator_disable(supply);
if (result == 0)
mmc->regulator_enabled = false;
}
if (result)
dev_err(mmc_dev(mmc),
"could not set regulator OCR (%d)\n", result);
return result;
}
EXPORT_SYMBOL(mmc_regulator_set_ocr);
#endif
#endif /* CONFIG_REGULATOR */
/*
* Mask off any voltages we don't support and select
@ -907,12 +924,7 @@ static void mmc_power_up(struct mmc_host *host)
*/
mmc_delay(10);
if (host->f_min > 400000) {
pr_warning("%s: Minimum clock frequency too high for "
"identification mode\n", mmc_hostname(host));
host->ios.clock = host->f_min;
} else
host->ios.clock = 400000;
host->ios.clock = host->f_init;
host->ios.power_mode = MMC_POWER_ON;
mmc_set_ios(host);
@ -1397,6 +1409,21 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
}
EXPORT_SYMBOL(mmc_erase_group_aligned);
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
struct mmc_command cmd;
if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
return 0;
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = blocklen;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
return mmc_wait_for_cmd(card->host, &cmd, 5);
}
EXPORT_SYMBOL(mmc_set_blocklen);
void mmc_rescan(struct work_struct *work)
{
struct mmc_host *host =
@ -1404,6 +1431,8 @@ void mmc_rescan(struct work_struct *work)
u32 ocr;
int err;
unsigned long flags;
int i;
const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
spin_lock_irqsave(&host->lock, flags);
@ -1443,55 +1472,71 @@ void mmc_rescan(struct work_struct *work)
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out;
mmc_claim_host(host);
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
mmc_claim_host(host);
mmc_power_up(host);
sdio_reset(host);
mmc_go_idle(host);
if (freqs[i] >= host->f_min)
host->f_init = freqs[i];
else if (!i || freqs[i-1] > host->f_min)
host->f_init = host->f_min;
else {
mmc_release_host(host);
goto out;
}
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init);
#endif
mmc_power_up(host);
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
mmc_send_if_cond(host, host->ocr_avail);
/*
* First we search for SDIO...
*/
err = mmc_send_io_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_sdio(host, ocr)) {
mmc_claim_host(host);
/* try SDMEM (but not MMC) even if SDIO is broken */
if (mmc_send_app_op_cond(host, 0, &ocr))
goto out_fail;
/*
* First we search for SDIO...
*/
err = mmc_send_io_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_sdio(host, ocr)) {
mmc_claim_host(host);
/*
* Try SDMEM (but not MMC) even if SDIO
* is broken.
*/
if (mmc_send_app_op_cond(host, 0, &ocr))
goto out_fail;
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
}
goto out;
}
/*
* ...then normal SD...
*/
err = mmc_send_app_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
goto out;
}
goto out;
}
/*
* ...then normal SD...
*/
err = mmc_send_app_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
goto out;
}
/*
* ...and finally MMC.
*/
err = mmc_send_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_mmc(host, ocr))
mmc_power_off(host);
goto out;
}
/*
* ...and finally MMC.
*/
err = mmc_send_op_cond(host, 0, &ocr);
if (!err) {
if (mmc_attach_mmc(host, ocr))
mmc_power_off(host);
goto out;
}
out_fail:
mmc_release_host(host);
mmc_power_off(host);
mmc_release_host(host);
mmc_power_off(host);
}
out:
if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ);
@ -1538,37 +1583,45 @@ void mmc_stop_host(struct mmc_host *host)
mmc_power_off(host);
}
void mmc_power_save_host(struct mmc_host *host)
int mmc_power_save_host(struct mmc_host *host)
{
int ret = 0;
mmc_bus_get(host);
if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
mmc_bus_put(host);
return;
return -EINVAL;
}
if (host->bus_ops->power_save)
host->bus_ops->power_save(host);
ret = host->bus_ops->power_save(host);
mmc_bus_put(host);
mmc_power_off(host);
return ret;
}
EXPORT_SYMBOL(mmc_power_save_host);
void mmc_power_restore_host(struct mmc_host *host)
int mmc_power_restore_host(struct mmc_host *host)
{
int ret;
mmc_bus_get(host);
if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
mmc_bus_put(host);
return;
return -EINVAL;
}
mmc_power_up(host);
host->bus_ops->power_restore(host);
ret = host->bus_ops->power_restore(host);
mmc_bus_put(host);
return ret;
}
EXPORT_SYMBOL(mmc_power_restore_host);

View File

@ -22,8 +22,8 @@ struct mmc_bus_ops {
void (*detect)(struct mmc_host *);
int (*suspend)(struct mmc_host *);
int (*resume)(struct mmc_host *);
void (*power_save)(struct mmc_host *);
void (*power_restore)(struct mmc_host *);
int (*power_save)(struct mmc_host *);
int (*power_restore)(struct mmc_host *);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@ -35,6 +35,8 @@ 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);
void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
unsigned int ddr);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
@ -58,7 +60,6 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
/* Module parameters */
extern int use_spi_crc;
extern int mmc_assume_removable;
/* Debugfs information for hosts and cards */
void mmc_add_host_debugfs(struct mmc_host *host);

View File

@ -134,6 +134,33 @@ static const struct file_operations mmc_ios_fops = {
.release = single_release,
};
static int mmc_clock_opt_get(void *data, u64 *val)
{
struct mmc_host *host = data;
*val = host->ios.clock;
return 0;
}
static int mmc_clock_opt_set(void *data, u64 val)
{
struct mmc_host *host = data;
/* We need this check due to input value is u64 */
if (val > host->f_max)
return -EINVAL;
mmc_claim_host(host);
mmc_set_clock(host, (unsigned int) val);
mmc_release_host(host);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
"%llu\n");
void mmc_add_host_debugfs(struct mmc_host *host)
{
struct dentry *root;
@ -150,11 +177,15 @@ void mmc_add_host_debugfs(struct mmc_host *host)
host->debugfs_root = root;
if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
goto err_ios;
goto err_node;
if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
&mmc_clock_fops))
goto err_node;
return;
err_ios:
err_node:
debugfs_remove_recursive(root);
host->debugfs_root = NULL;
err_root:

View File

@ -94,8 +94,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
* By default, hosts do not support SGIO or large requests.
* They have to set these according to their abilities.
*/
host->max_hw_segs = 1;
host->max_phys_segs = 1;
host->max_segs = 1;
host->max_seg_size = PAGE_CACHE_SIZE;
host->max_req_size = PAGE_CACHE_SIZE;

View File

@ -258,6 +258,21 @@ static int mmc_read_ext_csd(struct mmc_card *card)
}
switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
break;
case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
break;
case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
break;
case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
break;
@ -360,7 +375,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *oldcard)
{
struct mmc_card *card;
int err;
int err, ddr = MMC_SDR_MODE;
u32 cid[4];
unsigned int max_dtr;
@ -503,17 +518,35 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
mmc_set_clock(host, max_dtr);
/*
* Activate wide bus (if supported).
* Indicate DDR mode (if supported).
*/
if (mmc_card_highspeed(card)) {
if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
&& (host->caps & (MMC_CAP_1_8V_DDR)))
ddr = MMC_1_8V_DDR_MODE;
else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
&& (host->caps & (MMC_CAP_1_2V_DDR)))
ddr = MMC_1_2V_DDR_MODE;
}
/*
* Activate wide bus and DDR (if supported).
*/
if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
unsigned ext_csd_bit, bus_width;
if (host->caps & MMC_CAP_8_BIT_DATA) {
ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
if (ddr)
ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8;
else
ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
bus_width = MMC_BUS_WIDTH_8;
} else {
ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
if (ddr)
ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_4;
else
ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
bus_width = MMC_BUS_WIDTH_4;
}
@ -524,12 +557,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
goto free_card;
if (err) {
printk(KERN_WARNING "%s: switch to bus width %d "
printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
"failed\n", mmc_hostname(card->host),
1 << bus_width);
1 << bus_width, ddr);
err = 0;
} else {
mmc_set_bus_width(card->host, bus_width);
mmc_card_set_ddr_mode(card);
mmc_set_bus_width_ddr(card->host, bus_width, ddr);
}
}
@ -623,12 +657,16 @@ static int mmc_resume(struct mmc_host *host)
return err;
}
static void mmc_power_restore(struct mmc_host *host)
static int mmc_power_restore(struct mmc_host *host)
{
int ret;
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_claim_host(host);
mmc_init_card(host, host->ocr, host->card);
ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return ret;
}
static int mmc_sleep(struct mmc_host *host)
@ -685,7 +723,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
{
const struct mmc_bus_ops *bus_ops;
if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
if (!mmc_card_is_removable(host))
bus_ops = &mmc_ops_unsafe;
else
bus_ops = &mmc_ops;

View File

@ -722,12 +722,16 @@ static int mmc_sd_resume(struct mmc_host *host)
return err;
}
static void mmc_sd_power_restore(struct mmc_host *host)
static int mmc_sd_power_restore(struct mmc_host *host)
{
int ret;
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_claim_host(host);
mmc_sd_init_card(host, host->ocr, host->card);
ret = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return ret;
}
static const struct mmc_bus_ops mmc_sd_ops = {
@ -750,7 +754,7 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
{
const struct mmc_bus_ops *bus_ops;
if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
if (!mmc_card_is_removable(host))
bus_ops = &mmc_sd_ops_unsafe;
else
bus_ops = &mmc_sd_ops;

View File

@ -10,6 +10,7 @@
*/
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@ -456,7 +457,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
return -ENOENT;
card = oldcard;
return 0;
}
if (card->type == MMC_TYPE_SD_COMBO) {
@ -546,6 +546,11 @@ static void mmc_sdio_detect(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->card);
/* Make sure card is powered before detecting it */
err = pm_runtime_get_sync(&host->card->dev);
if (err < 0)
goto out;
mmc_claim_host(host);
/*
@ -555,6 +560,7 @@ static void mmc_sdio_detect(struct mmc_host *host)
mmc_release_host(host);
out:
if (err) {
mmc_sdio_remove(host);
@ -562,6 +568,9 @@ static void mmc_sdio_detect(struct mmc_host *host)
mmc_detach_bus(host);
mmc_release_host(host);
}
/* Tell PM core that we're done */
pm_runtime_put(&host->card->dev);
}
/*
@ -614,14 +623,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
mmc_claim_host(host);
err = mmc_sdio_init_card(host, host->ocr, host->card,
(host->pm_flags & MMC_PM_KEEP_POWER));
if (!err) {
/* We may have switched to 1-bit mode during suspend. */
err = sdio_enable_4bit_bus(host->card);
if (err > 0) {
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
err = 0;
}
}
if (!err && host->sdio_irqs)
mmc_signal_sdio_irq(host);
mmc_release_host(host);
@ -647,11 +648,29 @@ static int mmc_sdio_resume(struct mmc_host *host)
return err;
}
static int mmc_sdio_power_restore(struct mmc_host *host)
{
int ret;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
ret = mmc_sdio_init_card(host, host->ocr, host->card,
(host->pm_flags & MMC_PM_KEEP_POWER));
if (!ret && host->sdio_irqs)
mmc_signal_sdio_irq(host);
mmc_release_host(host);
return ret;
}
static const struct mmc_bus_ops mmc_sdio_ops = {
.remove = mmc_sdio_remove,
.detect = mmc_sdio_detect,
.suspend = mmc_sdio_suspend,
.resume = mmc_sdio_resume,
.power_restore = mmc_sdio_power_restore,
};
@ -698,6 +717,18 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
goto err;
card = host->card;
/*
* Let runtime PM core know our card is active
*/
err = pm_runtime_set_active(&card->dev);
if (err)
goto remove;
/*
* Enable runtime PM for this card
*/
pm_runtime_enable(&card->dev);
/*
* The number of functions on the card is encoded inside
* the ocr.
@ -712,6 +743,11 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
err = sdio_init_func(host->card, i + 1);
if (err)
goto remove;
/*
* Enable Runtime PM for this func
*/
pm_runtime_enable(&card->sdio_func[i]->dev);
}
mmc_release_host(host);

View File

@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
@ -125,21 +126,46 @@ static int sdio_bus_probe(struct device *dev)
if (!id)
return -ENODEV;
/* Unbound SDIO functions are always suspended.
* During probe, the function is set active and the usage count
* is incremented. If the driver supports runtime PM,
* it should call pm_runtime_put_noidle() in its probe routine and
* pm_runtime_get_noresume() in its remove routine.
*/
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto out;
/* Set the default block size so the driver is sure it's something
* sensible. */
sdio_claim_host(func);
ret = sdio_set_block_size(func, 0);
sdio_release_host(func);
if (ret)
return ret;
goto disable_runtimepm;
return drv->probe(func, id);
ret = drv->probe(func, id);
if (ret)
goto disable_runtimepm;
return 0;
disable_runtimepm:
pm_runtime_put_noidle(dev);
out:
return ret;
}
static int sdio_bus_remove(struct device *dev)
{
struct sdio_driver *drv = to_sdio_driver(dev->driver);
struct sdio_func *func = dev_to_sdio_func(dev);
int ret;
/* Make sure card is powered before invoking ->remove() */
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto out;
drv->remove(func);
@ -151,9 +177,63 @@ static int sdio_bus_remove(struct device *dev)
sdio_release_host(func);
}
/* First, undo the increment made directly above */
pm_runtime_put_noidle(dev);
/* Then undo the runtime PM settings in sdio_bus_probe() */
pm_runtime_put_noidle(dev);
out:
return ret;
}
#ifdef CONFIG_PM_RUNTIME
static int sdio_bus_pm_prepare(struct device *dev)
{
/*
* Resume an SDIO device which was suspended at run time at this
* point, in order to allow standard SDIO suspend/resume paths
* to keep working as usual.
*
* Ultimately, the SDIO driver itself will decide (in its
* suspend handler, or lack thereof) whether the card should be
* removed or kept, and if kept, at what power state.
*
* At this point, PM core have increased our use count, so it's
* safe to directly resume the device. After system is resumed
* again, PM core will drop back its runtime PM use count, and if
* needed device will be suspended again.
*
* The end result is guaranteed to be a power state that is
* coherent with the device's runtime PM use count.
*
* The return value of pm_runtime_resume is deliberately unchecked
* since there is little point in failing system suspend if a
* device can't be resumed.
*/
pm_runtime_resume(dev);
return 0;
}
static const struct dev_pm_ops sdio_bus_pm_ops = {
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
pm_generic_runtime_idle
)
.prepare = sdio_bus_pm_prepare,
};
#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops)
#else /* !CONFIG_PM_RUNTIME */
#define SDIO_PM_OPS_PTR NULL
#endif /* !CONFIG_PM_RUNTIME */
static struct bus_type sdio_bus_type = {
.name = "sdio",
.dev_attrs = sdio_dev_attrs,
@ -161,6 +241,7 @@ static struct bus_type sdio_bus_type = {
.uevent = sdio_bus_uevent,
.probe = sdio_bus_probe,
.remove = sdio_bus_remove,
.pm = SDIO_PM_OPS_PTR,
};
int sdio_register_bus(void)

View File

@ -130,6 +130,16 @@ config MMC_SDHCI_CNS3XXX
If unsure, say N.
config MMC_SDHCI_ESDHC_IMX
bool "SDHCI platform support for the Freescale eSDHC i.MX controller"
depends on MMC_SDHCI_PLTFM && (ARCH_MX25 || ARCH_MX35 || ARCH_MX5)
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Freescale eSDHC controller support on the platform
bus, found on platforms like mx35/51.
If unsure, say N.
config MMC_SDHCI_S3C
tristate "SDHCI support on Samsung S3C SoC"
depends on MMC_SDHCI && PLAT_SAMSUNG
@ -145,6 +155,18 @@ config MMC_SDHCI_S3C
If unsure, say N.
config MMC_SDHCI_PXA
tristate "Marvell PXA168/PXA910/MMP2 SD Host Controller support"
depends on ARCH_PXA || ARCH_MMP
select MMC_SDHCI
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Marvell(R) PXA168/PXA910/MMP2 SD Host Controller.
If you have a PXA168/PXA910/MMP2 platform with SD Host Controller
and a card slot, say Y or M here.
If unsure, say N.
config MMC_SDHCI_SPEAR
tristate "SDHCI support on ST SPEAr platform"
depends on MMC_SDHCI && PLAT_SPEAR
@ -395,6 +417,7 @@ config MMC_TMIO
config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
depends on PCI
select MISC_DEVICES
select CB710_CORE
help
This option enables support for MMC/SD part of ENE CB710/720 Flash
@ -451,3 +474,17 @@ config MMC_JZ4740
SoCs.
If you have a board based on such a SoC and with a SD/MMC slot,
say Y or M here.
config MMC_USHC
tristate "USB SD Host Controller (USHC) support"
depends on USB
help
This selects support for USB SD Host Controllers based on
the Cypress Astoria chip with firmware compliant with CSR's
USB SD Host Controller specification (CS-118793-SP).
CSR boards with this device include: USB<>SDIO (M1985v2),
and Ultrasira.
Note: These controllers only support SDIO cards and do not
support MMC or SD memory cards.

View File

@ -2,16 +2,13 @@
# 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_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
obj-$(CONFIG_MMC_SDHCI_PXA) += sdhci-pxa.o
obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
@ -36,10 +33,12 @@ obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_USHC) += ushc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o
sdhci-platform-y := sdhci-pltfm.o
sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
sdhci-of-y := sdhci-of-core.o

View File

@ -928,7 +928,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
if (!res)
return -ENXIO;
if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
return -EBUSY;
mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
@ -947,8 +947,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
mmc->max_blk_size = MCI_MAXBLKSIZE;
mmc->max_blk_count = MCI_BLKATONCE;
mmc->max_req_size = MCI_BUFSIZE;
mmc->max_phys_segs = MCI_BLKATONCE;
mmc->max_hw_segs = MCI_BLKATONCE;
mmc->max_segs = MCI_BLKATONCE;
mmc->max_seg_size = MCI_BUFSIZE;
host = mmc_priv(mmc);
@ -1017,7 +1016,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
/*
* Map I/O region
*/
host->baseaddr = ioremap(res->start, res->end - res->start + 1);
host->baseaddr = ioremap(res->start, resource_size(res));
if (!host->baseaddr) {
ret = -ENOMEM;
goto fail1;
@ -1093,7 +1092,7 @@ fail4b:
fail5:
mmc_free_host(mmc);
fail6:
release_mem_region(res->start, res->end - res->start + 1);
release_mem_region(res->start, resource_size(res));
dev_err(&pdev->dev, "probe failed, err %d\n", ret);
return ret;
}
@ -1138,7 +1137,7 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
iounmap(host->baseaddr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res->end - res->start + 1);
release_mem_region(res->start, resource_size(res));
mmc_free_host(mmc);
platform_set_drvdata(pdev, NULL);

View File

@ -1618,8 +1618,7 @@ static int __init atmci_init_slot(struct atmel_mci *host,
if (slot_data->bus_width >= 4)
mmc->caps |= MMC_CAP_4_BIT_DATA;
mmc->max_hw_segs = 64;
mmc->max_phys_segs = 64;
mmc->max_segs = 64;
mmc->max_req_size = 32768 * 512;
mmc->max_blk_size = 32768;
mmc->max_blk_count = 512;
@ -1777,7 +1776,7 @@ static int __init atmci_probe(struct platform_device *pdev)
}
ret = -ENOMEM;
host->regs = ioremap(regs->start, regs->end - regs->start + 1);
host->regs = ioremap(regs->start, resource_size(regs));
if (!host->regs)
goto err_ioremap;

View File

@ -964,7 +964,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
goto out1;
}
host->ioarea = request_mem_region(r->start, r->end - r->start + 1,
host->ioarea = request_mem_region(r->start, resource_size(r),
pdev->name);
if (!host->ioarea) {
dev_err(&pdev->dev, "mmio already in use\n");
@ -998,7 +998,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
mmc->f_max = 24000000;
mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;
mmc->max_blk_size = 2048;
mmc->max_blk_count = 512;

View File

@ -469,7 +469,7 @@ static int __devinit sdh_probe(struct platform_device *pdev)
}
mmc->ops = &sdh_ops;
mmc->max_phys_segs = 32;
mmc->max_segs = 32;
mmc->max_seg_size = 1 << 16;
mmc->max_blk_size = 1 << 11;
mmc->max_blk_count = 1 << 11;

View File

@ -25,7 +25,7 @@ static const u8 cb710_src_freq_mhz[16] = {
50, 55, 60, 65, 70, 75, 80, 85
};
static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
static void cb710_mmc_select_clock_divider(struct mmc_host *mmc, int hz)
{
struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
struct pci_dev *pdev = cb710_slot_to_chip(slot)->pdev;
@ -33,8 +33,11 @@ static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
u32 divider_idx;
int src_hz;
/* this is magic, unverifiable for me, unless I get
* MMC card with cables connected to bus signals */
/* on CB710 in HP nx9500:
* src_freq_idx == 0
* indexes 1-7 work as written in the table
* indexes 0,8-15 give no clock output
*/
pci_read_config_dword(pdev, 0x48, &src_freq_idx);
src_freq_idx = (src_freq_idx >> 16) & 0xF;
src_hz = cb710_src_freq_mhz[src_freq_idx] * 1000000;
@ -46,13 +49,15 @@ static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
if (src_freq_idx)
divider_idx |= 0x8;
else if (divider_idx == 0)
divider_idx = 1;
cb710_pci_update_config_reg(pdev, 0x40, ~0xF0000000, divider_idx << 28);
dev_dbg(cb710_slot_dev(slot),
"clock set to %d Hz, wanted %d Hz; flag = %d\n",
"clock set to %d Hz, wanted %d Hz; src_freq_idx = %d, divider_idx = %d|%d\n",
src_hz >> cb710_clock_divider_log2[divider_idx & 7],
hz, (divider_idx & 8) != 0);
hz, src_freq_idx, divider_idx & 7, divider_idx & 8);
}
static void __cb710_mmc_enable_irq(struct cb710_slot *slot,
@ -95,16 +100,8 @@ static void cb710_mmc_reset_events(struct cb710_slot *slot)
cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF);
}
static int cb710_mmc_is_card_inserted(struct cb710_slot *slot)
{
return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
& CB710_MMC_S3_CARD_DETECTED;
}
static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable)
{
dev_dbg(cb710_slot_dev(slot), "configuring %d-data-line%s mode\n",
enable ? 4 : 1, enable ? "s" : "");
if (enable)
cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
CB710_MMC_C1_4BIT_DATA_BUS, 0);
@ -494,13 +491,8 @@ static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
reader->mrq = mrq;
cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
if (cb710_mmc_is_card_inserted(slot)) {
if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
cb710_mmc_command(mmc, mrq->stop);
mdelay(1);
} else {
mrq->cmd->error = -ENOMEDIUM;
}
if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
cb710_mmc_command(mmc, mrq->stop);
tasklet_schedule(&reader->finish_req_tasklet);
}
@ -512,7 +504,7 @@ static int cb710_mmc_powerup(struct cb710_slot *slot)
#endif
int err;
/* a lot of magic; see comment in cb710_mmc_set_clock() */
/* a lot of magic for now */
dev_dbg(cb710_slot_dev(slot), "bus powerup\n");
cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
@ -572,13 +564,7 @@ static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct cb710_mmc_reader *reader = mmc_priv(mmc);
int err;
cb710_mmc_set_clock(mmc, ios->clock);
if (!cb710_mmc_is_card_inserted(slot)) {
dev_dbg(cb710_slot_dev(slot),
"no card inserted - ignoring bus powerup request\n");
ios->power_mode = MMC_POWER_OFF;
}
cb710_mmc_select_clock_divider(mmc, ios->clock);
if (ios->power_mode != reader->last_power_mode)
switch (ios->power_mode) {
@ -619,6 +605,14 @@ static int cb710_mmc_get_ro(struct mmc_host *mmc)
& CB710_MMC_S3_WRITE_PROTECTED;
}
static int cb710_mmc_get_cd(struct mmc_host *mmc)
{
struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
& CB710_MMC_S3_CARD_DETECTED;
}
static int cb710_mmc_irq_handler(struct cb710_slot *slot)
{
struct mmc_host *mmc = cb710_slot_to_mmc(slot);
@ -664,7 +658,8 @@ static void cb710_mmc_finish_request_tasklet(unsigned long data)
static const struct mmc_host_ops cb710_mmc_host = {
.request = cb710_mmc_request,
.set_ios = cb710_mmc_set_ios,
.get_ro = cb710_mmc_get_ro
.get_ro = cb710_mmc_get_ro,
.get_cd = cb710_mmc_get_cd,
};
#ifdef CONFIG_PM
@ -746,6 +741,7 @@ static int __devinit cb710_mmc_init(struct platform_device *pdev)
err_free_mmc:
dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err);
cb710_set_irq_handler(slot, NULL);
mmc_free_host(mmc);
return err;
}

View File

@ -138,7 +138,7 @@
/*
* One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
* and we handle up to MAX_NR_SG segments. MMC_BLOCK_BOUNCE kicks in only
* for drivers with max_hw_segs == 1, making the segments bigger (64KB)
* for drivers with max_segs == 1, making the segments bigger (64KB)
* than the page or two that's otherwise typical. nr_sg (passed from
* platform data) == 16 gives at least the same throughput boost, using
* EDMA transfer linkage instead of spending CPU time copying pages.
@ -1239,8 +1239,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
* Each hw_seg uses one EDMA parameter RAM slot, always one
* channel and then usually some linked slots.
*/
mmc->max_hw_segs = 1 + host->n_link;
mmc->max_phys_segs = mmc->max_hw_segs;
mmc->max_segs = 1 + host->n_link;
/* EDMA limit per hw segment (one or two MBytes) */
mmc->max_seg_size = MAX_CCNT * rw_threshold;
@ -1250,8 +1249,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
mmc->max_blk_count = 65535; /* NBLK is 16 bits */
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
dev_dbg(mmc_dev(host->mmc), "max_phys_segs=%d\n", mmc->max_phys_segs);
dev_dbg(mmc_dev(host->mmc), "max_hw_segs=%d\n", mmc->max_hw_segs);
dev_dbg(mmc_dev(host->mmc), "max_segs=%d\n", mmc->max_segs);
dev_dbg(mmc_dev(host->mmc), "max_blk_size=%d\n", mmc->max_blk_size);
dev_dbg(mmc_dev(host->mmc), "max_req_size=%d\n", mmc->max_req_size);
dev_dbg(mmc_dev(host->mmc), "max_seg_size=%d\n", mmc->max_seg_size);

View File

@ -966,8 +966,7 @@ static int __init imxmci_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_4_BIT_DATA;
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
mmc->max_phys_segs = 64;
mmc->max_segs = 64;
mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */
mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */
mmc->max_blk_size = 2048;

View File

@ -876,8 +876,7 @@ static int __devinit jz4740_mmc_probe(struct platform_device* pdev)
mmc->max_blk_count = (1 << 15) - 1;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_phys_segs = 128;
mmc->max_hw_segs = 128;
mmc->max_segs = 128;
mmc->max_seg_size = mmc->max_req_size;
host->mmc = mmc;

View File

@ -1055,6 +1055,8 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct mmc_spi_host *host = mmc_priv(mmc);
int status = -EINVAL;
int crc_retry = 5;
struct mmc_command stop;
#ifdef DEBUG
/* MMC core and layered drivers *MUST* issue SPI-aware commands */
@ -1087,10 +1089,29 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
/* request exclusive bus access */
spi_bus_lock(host->spi->master);
crc_recover:
/* issue command; then optionally data and stop */
status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
if (status == 0 && mrq->data) {
mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
/*
* The SPI bus is not always reliable for large data transfers.
* If an occasional crc error is reported by the SD device with
* data read/write over SPI, it may be recovered by repeating
* the last SD command again. The retry count is set to 5 to
* ensure the driver passes stress tests.
*/
if (mrq->data->error == -EILSEQ && crc_retry) {
stop.opcode = MMC_STOP_TRANSMISSION;
stop.arg = 0;
stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
status = mmc_spi_command_send(host, mrq, &stop, 0);
crc_retry--;
mrq->data->error = 0;
goto crc_recover;
}
if (mrq->stop)
status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
else
@ -1345,8 +1366,7 @@ static int mmc_spi_probe(struct spi_device *spi)
mmc->ops = &mmc_spi_ops;
mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
mmc->max_hw_segs = MMC_SPI_BLOCKSATONCE;
mmc->max_phys_segs = MMC_SPI_BLOCKSATONCE;
mmc->max_segs = MMC_SPI_BLOCKSATONCE;
mmc->max_req_size = MMC_SPI_BLOCKSATONCE * MMC_SPI_BLOCKSIZE;
mmc->max_blk_count = MMC_SPI_BLOCKSATONCE;

View File

@ -523,19 +523,27 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct mmci_host *host = mmc_priv(mmc);
u32 pwr = 0;
unsigned long flags;
int ret;
switch (ios->power_mode) {
case MMC_POWER_OFF:
if(host->vcc &&
regulator_is_enabled(host->vcc))
regulator_disable(host->vcc);
if (host->vcc)
ret = mmc_regulator_set_ocr(mmc, host->vcc, 0);
break;
case MMC_POWER_UP:
#ifdef CONFIG_REGULATOR
if (host->vcc)
/* This implicitly enables the regulator */
mmc_regulator_set_ocr(host->vcc, ios->vdd);
#endif
if (host->vcc) {
ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd);
if (ret) {
dev_err(mmc_dev(mmc), "unable to set OCR\n");
/*
* The .set_ios() function in the mmc_host_ops
* struct return void, and failing to set the
* power should be rare so we print an error
* and return here.
*/
return;
}
}
if (host->plat->vdd_handler)
pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
ios->power_mode);
@ -734,8 +742,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
/*
* We can do SGIO
*/
mmc->max_hw_segs = 16;
mmc->max_phys_segs = NR_SG;
mmc->max_segs = NR_SG;
/*
* Since only a certain number of bits are valid in the data length
@ -870,8 +877,8 @@ static int __devexit mmci_remove(struct amba_device *dev)
clk_disable(host->clk);
clk_put(host->clk);
if (regulator_is_enabled(host->vcc))
regulator_disable(host->vcc);
if (host->vcc)
mmc_regulator_set_ocr(mmc, host->vcc, 0);
regulator_put(host->vcc);
mmc_free_host(mmc);

View File

@ -1164,8 +1164,7 @@ msmsdcc_probe(struct platform_device *pdev)
mmc->caps |= MMC_CAP_SDIO_IRQ;
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
mmc->max_phys_segs = NR_SG;
mmc->max_hw_segs = NR_SG;
mmc->max_segs = NR_SG;
mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
mmc->max_blk_count = 65536;

View File

@ -742,8 +742,7 @@ static int __init mvsd_probe(struct platform_device *pdev)
mmc->max_blk_size = 2048;
mmc->max_blk_count = 65535;
mmc->max_hw_segs = 1;
mmc->max_phys_segs = 1;
mmc->max_segs = 1;
mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;

View File

@ -790,8 +790,7 @@ static int mxcmci_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
mmc->max_phys_segs = 64;
mmc->max_segs = 64;
mmc->max_blk_size = 2048;
mmc->max_blk_count = 65535;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;

View File

@ -1335,8 +1335,7 @@ static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id)
* NOTE max_seg_size assumption that small blocks aren't
* normally used (except e.g. for reading SD registers).
*/
mmc->max_phys_segs = 32;
mmc->max_hw_segs = 32;
mmc->max_segs = 32;
mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */
mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;

View File

@ -250,9 +250,9 @@ static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
if (power_on)
ret = mmc_regulator_set_ocr(host->vcc, vdd);
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
else
ret = mmc_regulator_set_ocr(host->vcc, 0);
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
if (mmc_slot(host).after_set_reg)
mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
@ -291,18 +291,23 @@ static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
* chips/cards need an interface voltage rail too.
*/
if (power_on) {
ret = mmc_regulator_set_ocr(host->vcc, vdd);
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
/* Enable interface voltage rail, if needed */
if (ret == 0 && host->vcc_aux) {
ret = regulator_enable(host->vcc_aux);
if (ret < 0)
ret = mmc_regulator_set_ocr(host->vcc, 0);
ret = mmc_regulator_set_ocr(host->mmc,
host->vcc, 0);
}
} else {
/* Shut down the rail */
if (host->vcc_aux)
ret = regulator_disable(host->vcc_aux);
if (ret == 0)
ret = mmc_regulator_set_ocr(host->vcc, 0);
if (!ret) {
/* Then proceed to shut down the local regulator */
ret = mmc_regulator_set_ocr(host->mmc,
host->vcc, 0);
}
}
if (mmc_slot(host).after_set_reg)
@ -343,9 +348,9 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
if (cardsleep) {
/* VCC can be turned off if card is asleep */
if (sleep)
err = mmc_regulator_set_ocr(host->vcc, 0);
err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
else
err = mmc_regulator_set_ocr(host->vcc, vdd);
err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
} else
err = regulator_set_mode(host->vcc, mode);
if (err)
@ -2130,8 +2135,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
/* Since we do only SG emulation, we can have as many segs
* as we want. */
mmc->max_phys_segs = 1024;
mmc->max_hw_segs = 1024;
mmc->max_segs = 1024;
mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */

View File

@ -99,14 +99,25 @@ static inline void pxamci_init_ocr(struct pxamci_host *host)
}
}
static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
static inline int pxamci_set_power(struct pxamci_host *host,
unsigned char power_mode,
unsigned int vdd)
{
int on;
#ifdef CONFIG_REGULATOR
if (host->vcc)
mmc_regulator_set_ocr(host->vcc, vdd);
#endif
if (host->vcc) {
int ret;
if (power_mode == MMC_POWER_UP) {
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
if (ret)
return ret;
} else if (power_mode == MMC_POWER_OFF) {
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
if (ret)
return ret;
}
}
if (!host->vcc && host->pdata &&
gpio_is_valid(host->pdata->gpio_power)) {
on = ((1 << vdd) & host->pdata->ocr_mask);
@ -115,6 +126,8 @@ static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
}
if (!host->vcc && host->pdata && host->pdata->setpower)
host->pdata->setpower(mmc_dev(host->mmc), vdd);
return 0;
}
static void pxamci_stop_clock(struct pxamci_host *host)
@ -490,9 +503,21 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
if (host->power_mode != ios->power_mode) {
int ret;
host->power_mode = ios->power_mode;
pxamci_set_power(host, ios->vdd);
ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
if (ret) {
dev_err(mmc_dev(mmc), "unable to set power\n");
/*
* The .set_ios() function in the mmc_host_ops
* struct return void, and failing to set the
* power should be rare so we print an error and
* return here.
*/
return;
}
if (ios->power_mode == MMC_POWER_ON)
host->cmdat |= CMDAT_INIT;
@ -503,8 +528,8 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
host->cmdat &= ~CMDAT_SD_4DAT;
pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
host->clkrt, host->cmdat);
dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
host->clkrt, host->cmdat);
}
static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
@ -576,7 +601,7 @@ static int pxamci_probe(struct platform_device *pdev)
* We can do SG-DMA, but we don't because we never know how much
* data we successfully wrote to the card.
*/
mmc->max_phys_segs = NR_SG;
mmc->max_segs = NR_SG;
/*
* Our hardware DMA can handle a maximum of one page per SG entry.

View File

@ -1736,8 +1736,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
mmc->max_req_size = 4095 * 512;
mmc->max_seg_size = mmc->max_req_size;
mmc->max_phys_segs = 128;
mmc->max_hw_segs = 128;
mmc->max_segs = 128;
dbg(host, dbg_debug,
"probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n",

View File

@ -15,7 +15,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mmc/host.h>
#include <linux/sdhci-pltfm.h>
#include <linux/mmc/sdhci-pltfm.h>
#include <mach/cns3xxx.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"

View File

@ -0,0 +1,143 @@
/*
* Freescale eSDHC i.MX controller driver for the platform bus.
*
* derived from the OF-version.
*
* Copyright (c) 2010 Pengutronix e.K.
* Author: Wolfram Sang <w.sang@pengutronix.de>
*
* 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.
*/
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdhci-pltfm.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
{
void __iomem *base = host->ioaddr + (reg & ~0x3);
u32 shift = (reg & 0x3) * 8;
writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
}
static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
{
if (unlikely(reg == SDHCI_HOST_VERSION))
reg ^= 2;
return readw(host->ioaddr + reg);
}
static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
switch (reg) {
case SDHCI_TRANSFER_MODE:
/*
* Postpone this write, we must do it together with a
* command write that is down below.
*/
pltfm_host->scratchpad = val;
return;
case SDHCI_COMMAND:
writel(val << 16 | pltfm_host->scratchpad,
host->ioaddr + SDHCI_TRANSFER_MODE);
return;
case SDHCI_BLOCK_SIZE:
val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
break;
}
esdhc_clrset_le(host, 0xffff, val, reg);
}
static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
{
u32 new_val;
switch (reg) {
case SDHCI_POWER_CONTROL:
/*
* FSL put some DMA bits here
* If your board has a regulator, code should be here
*/
return;
case SDHCI_HOST_CONTROL:
/* FSL messed up here, so we can just keep those two */
new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
/* ensure the endianess */
new_val |= ESDHC_HOST_CONTROL_LE;
/* DMA mode bits are shifted */
new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
esdhc_clrset_le(host, 0xffff, new_val, reg);
return;
}
esdhc_clrset_le(host, 0xff, val, reg);
}
static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
return clk_get_rate(pltfm_host->clk);
}
static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
return clk_get_rate(pltfm_host->clk) / 256 / 16;
}
static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct clk *clk;
clk = clk_get(mmc_dev(host->mmc), NULL);
if (IS_ERR(clk)) {
dev_err(mmc_dev(host->mmc), "clk err\n");
return PTR_ERR(clk);
}
clk_enable(clk);
pltfm_host->clk = clk;
return 0;
}
static void esdhc_pltfm_exit(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
}
static struct sdhci_ops sdhci_esdhc_ops = {
.read_w = esdhc_readw_le,
.write_w = esdhc_writew_le,
.write_b = esdhc_writeb_le,
.set_clock = esdhc_set_clock,
.get_max_clock = esdhc_pltfm_get_max_clock,
.get_min_clock = esdhc_pltfm_get_min_clock,
};
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK
| SDHCI_QUIRK_BROKEN_ADMA,
/* ADMA has issues. Might be fixable */
/* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */
.ops = &sdhci_esdhc_ops,
.init = esdhc_pltfm_init,
.exit = esdhc_pltfm_exit,
};

View File

@ -0,0 +1,83 @@
/*
* Freescale eSDHC controller driver generics for OF and pltfm.
*
* Copyright (c) 2007 Freescale Semiconductor, Inc.
* Copyright (c) 2009 MontaVista Software, Inc.
* Copyright (c) 2010 Pengutronix e.K.
* Author: Wolfram Sang <w.sang@pengutronix.de>
*
* 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.
*/
#ifndef _DRIVERS_MMC_SDHCI_ESDHC_H
#define _DRIVERS_MMC_SDHCI_ESDHC_H
/*
* Ops and quirks for the Freescale eSDHC controller.
*/
#define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
SDHCI_QUIRK_BROKEN_CARD_DETECTION | \
SDHCI_QUIRK_NO_BUSY_IRQ | \
SDHCI_QUIRK_NONSTANDARD_CLOCK | \
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
SDHCI_QUIRK_PIO_NEEDS_DELAY | \
SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | \
SDHCI_QUIRK_NO_CARD_NO_RESET)
#define ESDHC_SYSTEM_CONTROL 0x2c
#define ESDHC_CLOCK_MASK 0x0000fff0
#define ESDHC_PREDIV_SHIFT 8
#define ESDHC_DIVIDER_SHIFT 4
#define ESDHC_CLOCK_PEREN 0x00000004
#define ESDHC_CLOCK_HCKEN 0x00000002
#define ESDHC_CLOCK_IPGEN 0x00000001
/* pltfm-specific */
#define ESDHC_HOST_CONTROL_LE 0x20
/* OF-specific */
#define ESDHC_DMA_SYSCTL 0x40c
#define ESDHC_DMA_SNOOP 0x00000040
#define ESDHC_HOST_CONTROL_RES 0x05
static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
{
int pre_div = 2;
int div = 1;
u32 temp;
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
| ESDHC_CLOCK_MASK);
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
if (clock == 0)
goto out;
while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
pre_div *= 2;
while (host->max_clk / pre_div / div > clock && div < 16)
div++;
dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
clock, host->max_clk / pre_div / div);
pre_div >>= 1;
div--;
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
| (div << ESDHC_DIVIDER_SHIFT)
| (pre_div << ESDHC_PREDIV_SHIFT));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
mdelay(100);
out:
host->clock = clock;
}
#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */

View File

@ -18,23 +18,7 @@
#include <linux/mmc/host.h>
#include "sdhci-of.h"
#include "sdhci.h"
/*
* Ops and quirks for the Freescale eSDHC controller.
*/
#define ESDHC_DMA_SYSCTL 0x40c
#define ESDHC_DMA_SNOOP 0x00000040
#define ESDHC_SYSTEM_CONTROL 0x2c
#define ESDHC_CLOCK_MASK 0x0000fff0
#define ESDHC_PREDIV_SHIFT 8
#define ESDHC_DIVIDER_SHIFT 4
#define ESDHC_CLOCK_PEREN 0x00000004
#define ESDHC_CLOCK_HCKEN 0x00000002
#define ESDHC_CLOCK_IPGEN 0x00000001
#define ESDHC_HOST_CONTROL_RES 0x05
#include "sdhci-esdhc.h"
static u16 esdhc_readw(struct sdhci_host *host, int reg)
{
@ -68,51 +52,20 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
sdhci_be32bs_writeb(host, val, reg);
}
static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
{
int pre_div = 2;
int div = 1;
clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
if (clock == 0)
goto out;
while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
pre_div *= 2;
while (host->max_clk / pre_div / div > clock && div < 16)
div++;
dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
clock, host->max_clk / pre_div / div);
pre_div >>= 1;
div--;
setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
mdelay(100);
out:
host->clock = clock;
}
static int esdhc_enable_dma(struct sdhci_host *host)
static int esdhc_of_enable_dma(struct sdhci_host *host)
{
setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
return 0;
}
static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
{
struct sdhci_of_host *of_host = sdhci_priv(host);
return of_host->clock;
}
static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
{
struct sdhci_of_host *of_host = sdhci_priv(host);
@ -120,14 +73,7 @@ static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
}
struct sdhci_of_data sdhci_esdhc = {
.quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_NO_BUSY_IRQ |
SDHCI_QUIRK_NONSTANDARD_CLOCK |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_PIO_NEEDS_DELAY |
SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
SDHCI_QUIRK_NO_CARD_NO_RESET,
.quirks = ESDHC_DEFAULT_QUIRKS,
.ops = {
.read_l = sdhci_be32bs_readl,
.read_w = esdhc_readw,
@ -136,8 +82,8 @@ struct sdhci_of_data sdhci_esdhc = {
.write_w = esdhc_writew,
.write_b = esdhc_writeb,
.set_clock = esdhc_set_clock,
.enable_dma = esdhc_enable_dma,
.get_max_clock = esdhc_get_max_clock,
.get_min_clock = esdhc_get_min_clock,
.enable_dma = esdhc_of_enable_dma,
.get_max_clock = esdhc_of_get_max_clock,
.get_min_clock = esdhc_of_get_min_clock,
},
};

View File

@ -145,6 +145,37 @@ static const struct sdhci_pci_fixes sdhci_cafe = {
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
};
/*
* ADMA operation is disabled for Moorestown platform due to
* hardware bugs.
*/
static int mrst_hc1_probe(struct sdhci_pci_chip *chip)
{
/*
* slots number is fixed here for MRST as SDIO3 is never used and has
* hardware bugs.
*/
chip->num_slots = 1;
return 0;
}
static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
.quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
};
static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1 = {
.quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
.probe = mrst_hc1_probe,
};
static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
};
static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc_sdio = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
};
static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
{
u8 scratch;
@ -494,6 +525,62 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = (kernel_ulong_t)&sdhci_via,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MRST_SD0,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc0,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MRST_SD1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MFD_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MFD_SDIO1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MFD_SDIO2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MFD_EMMC0,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MFD_EMMC1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
},
{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@ -818,6 +905,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
goto free;
}
slots = chip->num_slots; /* Quirk may have changed this */
for (i = 0;i < slots;i++) {
slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
if (IS_ERR(slot)) {

View File

@ -30,7 +30,7 @@
#include <linux/mmc/host.h>
#include <linux/io.h>
#include <linux/sdhci-pltfm.h>
#include <linux/mmc/sdhci-pltfm.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
@ -52,14 +52,17 @@ static struct sdhci_ops sdhci_pltfm_ops = {
static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
{
struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
const struct platform_device_id *platid = platform_get_device_id(pdev);
struct sdhci_pltfm_data *pdata;
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct resource *iomem;
int ret;
if (!pdata && platid && platid->driver_data)
if (platid && platid->driver_data)
pdata = (void *)platid->driver_data;
else
pdata = pdev->dev.platform_data;
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iomem) {
@ -71,16 +74,19 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Invalid iomem size. You may "
"experience problems.\n");
if (pdev->dev.parent)
host = sdhci_alloc_host(pdev->dev.parent, 0);
/* Some PCI-based MFD need the parent here */
if (pdev->dev.parent != &platform_bus)
host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
else
host = sdhci_alloc_host(&pdev->dev, 0);
host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
if (IS_ERR(host)) {
ret = PTR_ERR(host);
goto err;
}
pltfm_host = sdhci_priv(host);
host->hw_name = "platform";
if (pdata && pdata->ops)
host->ops = pdata->ops;
@ -105,7 +111,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
}
if (pdata && pdata->init) {
ret = pdata->init(host);
ret = pdata->init(host, pdata);
if (ret)
goto err_plat_init;
}
@ -160,11 +166,33 @@ static const struct platform_device_id sdhci_pltfm_ids[] = {
{ "sdhci", },
#ifdef CONFIG_MMC_SDHCI_CNS3XXX
{ "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata },
#endif
#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
{ "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata },
#endif
{ },
};
MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
#ifdef CONFIG_PM
static int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state)
{
struct sdhci_host *host = platform_get_drvdata(dev);
return sdhci_suspend_host(host, state);
}
static int sdhci_pltfm_resume(struct platform_device *dev)
{
struct sdhci_host *host = platform_get_drvdata(dev);
return sdhci_resume_host(host);
}
#else
#define sdhci_pltfm_suspend NULL
#define sdhci_pltfm_resume NULL
#endif /* CONFIG_PM */
static struct platform_driver sdhci_pltfm_driver = {
.driver = {
.name = "sdhci",
@ -173,6 +201,8 @@ static struct platform_driver sdhci_pltfm_driver = {
.probe = sdhci_pltfm_probe,
.remove = __devexit_p(sdhci_pltfm_remove),
.id_table = sdhci_pltfm_ids,
.suspend = sdhci_pltfm_suspend,
.resume = sdhci_pltfm_resume,
};
/*****************************************************************************\

View File

@ -11,8 +11,16 @@
#ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
#define _DRIVERS_MMC_SDHCI_PLTFM_H
#include <linux/sdhci-pltfm.h>
#include <linux/clk.h>
#include <linux/types.h>
#include <linux/mmc/sdhci-pltfm.h>
struct sdhci_pltfm_host {
struct clk *clk;
u32 scratchpad; /* to handle quirks across io-accessor calls */
};
extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata;
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */

View File

@ -0,0 +1,253 @@
/* linux/drivers/mmc/host/sdhci-pxa.c
*
* Copyright (C) 2010 Marvell International Ltd.
* Zhangfei Gao <zhangfei.gao@marvell.com>
* Kevin Wang <dwang4@marvell.com>
* Mingwei Wang <mwwang@marvell.com>
* Philip Rakity <prakity@marvell.com>
* Mark Brown <markb@marvell.com>
*
* 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.
*/
/* Supports:
* SDHCI support for MMP2/PXA910/PXA168
*
* Refer to sdhci-s3c.c.
*/
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mmc/host.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/err.h>
#include <plat/sdhci.h>
#include "sdhci.h"
#define DRIVER_NAME "sdhci-pxa"
#define SD_FIFO_PARAM 0x104
#define DIS_PAD_SD_CLK_GATE 0x400
struct sdhci_pxa {
struct sdhci_host *host;
struct sdhci_pxa_platdata *pdata;
struct clk *clk;
struct resource *res;
u8 clk_enable;
};
/*****************************************************************************\
* *
* SDHCI core callbacks *
* *
\*****************************************************************************/
static void set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pxa *pxa = sdhci_priv(host);
u32 tmp = 0;
if (clock == 0) {
if (pxa->clk_enable) {
clk_disable(pxa->clk);
pxa->clk_enable = 0;
}
} else {
if (0 == pxa->clk_enable) {
if (pxa->pdata->flags & PXA_FLAG_DISABLE_CLOCK_GATING) {
tmp = readl(host->ioaddr + SD_FIFO_PARAM);
tmp |= DIS_PAD_SD_CLK_GATE;
writel(tmp, host->ioaddr + SD_FIFO_PARAM);
}
clk_enable(pxa->clk);
pxa->clk_enable = 1;
}
}
}
static struct sdhci_ops sdhci_pxa_ops = {
.set_clock = set_clock,
};
/*****************************************************************************\
* *
* Device probing/removal *
* *
\*****************************************************************************/
static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
{
struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
struct sdhci_host *host = NULL;
struct resource *iomem = NULL;
struct sdhci_pxa *pxa = NULL;
int ret, irq;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "no irq specified\n");
return irq;
}
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iomem) {
dev_err(dev, "no memory specified\n");
return -ENOENT;
}
host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pxa));
if (IS_ERR(host)) {
dev_err(dev, "failed to alloc host\n");
return PTR_ERR(host);
}
pxa = sdhci_priv(host);
pxa->host = host;
pxa->pdata = pdata;
pxa->clk_enable = 0;
pxa->clk = clk_get(dev, "PXA-SDHCLK");
if (IS_ERR(pxa->clk)) {
dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(pxa->clk);
goto out;
}
pxa->res = request_mem_region(iomem->start, resource_size(iomem),
mmc_hostname(host->mmc));
if (!pxa->res) {
dev_err(&pdev->dev, "cannot request region\n");
ret = -EBUSY;
goto out;
}
host->ioaddr = ioremap(iomem->start, resource_size(iomem));
if (!host->ioaddr) {
dev_err(&pdev->dev, "failed to remap registers\n");
ret = -ENOMEM;
goto out;
}
host->hw_name = "MMC";
host->ops = &sdhci_pxa_ops;
host->irq = irq;
host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
if (pdata->quirks)
host->quirks |= pdata->quirks;
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "failed to add host\n");
goto out;
}
if (pxa->pdata->max_speed)
host->mmc->f_max = pxa->pdata->max_speed;
platform_set_drvdata(pdev, host);
return 0;
out:
if (host) {
clk_put(pxa->clk);
if (host->ioaddr)
iounmap(host->ioaddr);
if (pxa->res)
release_mem_region(pxa->res->start,
resource_size(pxa->res));
sdhci_free_host(host);
}
return ret;
}
static int __devexit sdhci_pxa_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pxa *pxa = sdhci_priv(host);
int dead = 0;
u32 scratch;
if (host) {
scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
if (scratch == (u32)-1)
dead = 1;
sdhci_remove_host(host, dead);
if (host->ioaddr)
iounmap(host->ioaddr);
if (pxa->res)
release_mem_region(pxa->res->start,
resource_size(pxa->res));
if (pxa->clk_enable) {
clk_disable(pxa->clk);
pxa->clk_enable = 0;
}
clk_put(pxa->clk);
sdhci_free_host(host);
platform_set_drvdata(pdev, NULL);
}
return 0;
}
#ifdef CONFIG_PM
static int sdhci_pxa_suspend(struct platform_device *dev, pm_message_t state)
{
struct sdhci_host *host = platform_get_drvdata(dev);
return sdhci_suspend_host(host, state);
}
static int sdhci_pxa_resume(struct platform_device *dev)
{
struct sdhci_host *host = platform_get_drvdata(dev);
return sdhci_resume_host(host);
}
#else
#define sdhci_pxa_suspend NULL
#define sdhci_pxa_resume NULL
#endif
static struct platform_driver sdhci_pxa_driver = {
.probe = sdhci_pxa_probe,
.remove = __devexit_p(sdhci_pxa_remove),
.suspend = sdhci_pxa_suspend,
.resume = sdhci_pxa_resume,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
/*****************************************************************************\
* *
* Driver init/exit *
* *
\*****************************************************************************/
static int __init sdhci_pxa_init(void)
{
return platform_driver_register(&sdhci_pxa_driver);
}
static void __exit sdhci_pxa_exit(void)
{
platform_driver_unregister(&sdhci_pxa_driver);
}
module_init(sdhci_pxa_init);
module_exit(sdhci_pxa_exit);
MODULE_DESCRIPTION("SDH controller driver for PXA168/PXA910/MMP2");
MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>");
MODULE_LICENSE("GPL v2");

View File

@ -47,7 +47,8 @@ static void sdhci_finish_command(struct sdhci_host *);
static void sdhci_dumpregs(struct sdhci_host *host)
{
printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
mmc_hostname(host->mmc));
printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
sdhci_readl(host, SDHCI_DMA_ADDRESS),
@ -1001,13 +1002,28 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
if (clock == 0)
goto out;
for (div = 1;div < 256;div *= 2) {
if ((host->max_clk / div) <= clock)
break;
if (host->version >= SDHCI_SPEC_300) {
/* Version 3.00 divisors must be a multiple of 2. */
if (host->max_clk <= clock)
div = 1;
else {
for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
if ((host->max_clk / div) <= clock)
break;
}
}
} else {
/* Version 2.00 divisors must be a power of 2. */
for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
if ((host->max_clk / div) <= clock)
break;
}
}
div >>= 1;
clk = div << SDHCI_DIVIDER_SHIFT;
clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
<< SDHCI_DIVIDER_HI_SHIFT;
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
@ -1034,11 +1050,9 @@ out:
static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
{
u8 pwr;
u8 pwr = 0;
if (power == (unsigned short)-1)
pwr = 0;
else {
if (power != (unsigned short)-1) {
switch (1 << power) {
case MMC_VDD_165_195:
pwr = SDHCI_POWER_180;
@ -1168,6 +1182,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
sdhci_set_power(host, ios->vdd);
if (host->ops->platform_send_init_74_clocks)
host->ops->platform_send_init_74_clocks(host, ios->power_mode);
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if (ios->bus_width == MMC_BUS_WIDTH_8)
@ -1180,8 +1197,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
ctrl &= ~SDHCI_CTRL_4BITBUS;
if (ios->timing == MMC_TIMING_SD_HS &&
!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
if ((ios->timing == MMC_TIMING_SD_HS ||
ios->timing == MMC_TIMING_MMC_HS)
&& !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
ctrl |= SDHCI_CTRL_HISPD;
else
ctrl &= ~SDHCI_CTRL_HISPD;
@ -1205,22 +1223,25 @@ static int sdhci_get_ro(struct mmc_host *mmc)
{
struct sdhci_host *host;
unsigned long flags;
int present;
int is_readonly;
host = mmc_priv(mmc);
spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD)
present = 0;
is_readonly = 0;
else if (host->ops->get_ro)
is_readonly = host->ops->get_ro(host);
else
present = sdhci_readl(host, SDHCI_PRESENT_STATE);
is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
& SDHCI_WRITE_PROTECT);
spin_unlock_irqrestore(&host->lock, flags);
if (host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT)
return !!(present & SDHCI_WRITE_PROTECT);
return !(present & SDHCI_WRITE_PROTECT);
/* This quirk needs to be replaced by a callback-function later */
return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
!is_readonly : is_readonly;
}
static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
@ -1427,7 +1448,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
sdhci_finish_command(host);
}
#ifdef DEBUG
#ifdef CONFIG_MMC_DEBUG
static void sdhci_show_adma_error(struct sdhci_host *host)
{
const char *name = mmc_hostname(host->mmc);
@ -1708,7 +1729,7 @@ int sdhci_add_host(struct sdhci_host *host)
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
host->version = (host->version & SDHCI_SPEC_VER_MASK)
>> SDHCI_SPEC_VER_SHIFT;
if (host->version > SDHCI_SPEC_200) {
if (host->version > SDHCI_SPEC_300) {
printk(KERN_ERR "%s: Unknown controller version (%d). "
"You may experience problems.\n", mmc_hostname(mmc),
host->version);
@ -1779,8 +1800,13 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
}
host->max_clk =
(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
if (host->version >= SDHCI_SPEC_300)
host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK)
>> SDHCI_CLOCK_BASE_SHIFT;
else
host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK)
>> SDHCI_CLOCK_BASE_SHIFT;
host->max_clk *= 1000000;
if (host->max_clk == 0 || host->quirks &
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
@ -1815,18 +1841,21 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->ops = &sdhci_ops;
if (host->ops->get_min_clock)
mmc->f_min = host->ops->get_min_clock(host);
else if (host->version >= SDHCI_SPEC_300)
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
else
mmc->f_min = host->max_clk / 256;
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
mmc->f_max = host->max_clk;
mmc->caps |= MMC_CAP_SDIO_IRQ;
if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
mmc->caps |= MMC_CAP_4_BIT_DATA;
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
if (caps & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
mmc_card_is_removable(mmc))
mmc->caps |= MMC_CAP_NEEDS_POLL;
mmc->ocr_avail = 0;
@ -1850,12 +1879,11 @@ int sdhci_add_host(struct sdhci_host *host)
* can do scatter/gather or not.
*/
if (host->flags & SDHCI_USE_ADMA)
mmc->max_hw_segs = 128;
mmc->max_segs = 128;
else if (host->flags & SDHCI_USE_SDMA)
mmc->max_hw_segs = 1;
mmc->max_segs = 1;
else /* PIO */
mmc->max_hw_segs = 128;
mmc->max_phys_segs = 128;
mmc->max_segs = 128;
/*
* Maximum number of sectors in one transfer. Limited by DMA boundary

View File

@ -1,6 +1,8 @@
/*
* linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
*
* Header file for Host Controller registers and I/O accessors.
*
* Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@ -8,14 +10,16 @@
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*/
#ifndef __SDHCI_H
#define __SDHCI_H
#ifndef __SDHCI_HW_H
#define __SDHCI_HW_H
#include <linux/scatterlist.h>
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/mmc/sdhci.h>
/*
* Controller registers
*/
@ -86,6 +90,10 @@
#define SDHCI_CLOCK_CONTROL 0x2C
#define SDHCI_DIVIDER_SHIFT 8
#define SDHCI_DIVIDER_HI_SHIFT 6
#define SDHCI_DIV_MASK 0xFF
#define SDHCI_DIV_MASK_LEN 8
#define SDHCI_DIV_HI_MASK 0x300
#define SDHCI_CLOCK_CARD_EN 0x0004
#define SDHCI_CLOCK_INT_STABLE 0x0002
#define SDHCI_CLOCK_INT_EN 0x0001
@ -140,6 +148,7 @@
#define SDHCI_TIMEOUT_CLK_SHIFT 0
#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
#define SDHCI_CLOCK_BASE_MASK 0x00003F00
#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00
#define SDHCI_CLOCK_BASE_SHIFT 8
#define SDHCI_MAX_BLOCK_MASK 0x00030000
#define SDHCI_MAX_BLOCK_SHIFT 16
@ -178,134 +187,14 @@
#define SDHCI_SPEC_VER_SHIFT 0
#define SDHCI_SPEC_100 0
#define SDHCI_SPEC_200 1
#define SDHCI_SPEC_300 2
struct sdhci_ops;
struct sdhci_host {
/* Data set by hardware interface driver */
const char *hw_name; /* Hardware bus name */
unsigned int quirks; /* Deviations from spec. */
/* Controller doesn't honor resets unless we touch the clock register */
#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
/* Controller has bad caps bits, but really supports DMA */
#define SDHCI_QUIRK_FORCE_DMA (1<<1)
/* Controller doesn't like to be reset when there is no card inserted. */
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
/* Controller doesn't like clearing the power reg before a change */
#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
/* Controller has flaky internal state so reset it on each ios change */
#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4)
/* Controller has an unusable DMA engine */
#define SDHCI_QUIRK_BROKEN_DMA (1<<5)
/* Controller has an unusable ADMA engine */
#define SDHCI_QUIRK_BROKEN_ADMA (1<<6)
/* Controller can only DMA from 32-bit aligned addresses */
#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7)
/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8)
/* Controller can only ADMA chunks that are a multiple of 32 bits */
#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1<<9)
/* Controller needs to be reset after each request to stay stable */
#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<10)
/* Controller needs voltage and power writes to happen separately */
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11)
/* Controller provides an incorrect timeout value for transfers */
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12)
/* Controller has an issue with buffer bits for small transfers */
#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13)
/* Controller does not provide transfer-complete interrupt when not busy */
#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14)
/* Controller has unreliable card detection */
#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
/* Controller reports inverted write-protect state */
#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16)
/* Controller has nonstandard clock management */
#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<17)
/* Controller does not like fast PIO transfers */
#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)
/* Controller losing signal/interrupt enable states after reset */
#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19)
/* Controller has to be forced to use block size of 2048 bytes */
#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)
/* Controller cannot do multi-block transfers */
#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21)
/* Controller can only handle 1-bit data transfers */
#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22)
/* Controller needs 10ms delay between applying power and clock */
#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23)
/* Controller uses SDCLK instead of TMCLK for data timeouts */
#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24)
/* Controller reports wrong base clock capability */
#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25)
/* Controller cannot support End Attribute in NOP ADMA descriptor */
#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26)
/* Controller is missing device caps. Use caps provided by host */
#define SDHCI_QUIRK_MISSING_CAPS (1<<27)
/* Controller uses Auto CMD12 command to stop the transfer */
#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28)
/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29)
int irq; /* Device IRQ */
void __iomem * ioaddr; /* Mapped address */
const struct sdhci_ops *ops; /* Low level hw interface */
struct regulator *vmmc; /* Power regulator */
/* Internal data */
struct mmc_host *mmc; /* MMC structure */
u64 dma_mask; /* custom DMA mask */
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
struct led_classdev led; /* LED control */
char led_name[32];
#endif
spinlock_t lock; /* Mutex */
int flags; /* Host attributes */
#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */
#define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */
#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */
#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
unsigned int version; /* SDHCI spec. version */
unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int timeout_clk; /* Timeout freq (KHz) */
unsigned int clock; /* Current clock (MHz) */
u8 pwr; /* Current voltage */
struct mmc_request *mrq; /* Current request */
struct mmc_command *cmd; /* Current command */
struct mmc_data *data; /* Current data request */
unsigned int data_early:1; /* Data finished before cmd */
struct sg_mapping_iter sg_miter; /* SG state for PIO */
unsigned int blocks; /* remaining PIO blocks */
int sg_count; /* Mapped sg entries */
u8 *adma_desc; /* ADMA descriptor table */
u8 *align_buffer; /* Bounce buffer */
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */
struct tasklet_struct card_tasklet; /* Tasklet structures */
struct tasklet_struct finish_tasklet;
struct timer_list timer; /* Timer for timeouts */
unsigned int caps; /* Alternative capabilities */
unsigned long private[0] ____cacheline_aligned;
};
/*
* End of controller registers.
*/
#define SDHCI_MAX_DIV_SPEC_200 256
#define SDHCI_MAX_DIV_SPEC_300 2046
struct sdhci_ops {
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@ -323,6 +212,9 @@ struct sdhci_ops {
unsigned int (*get_max_clock)(struct sdhci_host *host);
unsigned int (*get_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
void (*platform_send_init_74_clocks)(struct sdhci_host *host,
u8 power_mode);
unsigned int (*get_ro)(struct sdhci_host *host);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@ -427,4 +319,4 @@ extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
extern int sdhci_resume_host(struct sdhci_host *host);
#endif
#endif /* __SDHCI_H */
#endif /* __SDHCI_HW_H */

View File

@ -846,8 +846,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_MMC_HIGHSPEED;
if (pd->caps)
mmc->caps |= pd->caps;
mmc->max_phys_segs = 128;
mmc->max_hw_segs = 128;
mmc->max_segs = 128;
mmc->max_blk_size = 512;
mmc->max_blk_count = 65535;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;

View File

@ -978,11 +978,10 @@ static int tifm_sd_probe(struct tifm_dev *sock)
mmc->f_max = 24000000;
mmc->max_blk_count = 2048;
mmc->max_hw_segs = mmc->max_blk_count;
mmc->max_segs = mmc->max_blk_count;
mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);
mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
mmc->max_req_size = mmc->max_seg_size;
mmc->max_phys_segs = mmc->max_hw_segs;
sock->card_event = tifm_sd_card_event;
sock->data_event = tifm_sd_data_event;

566
drivers/mmc/host/ushc.c Normal file
View File

@ -0,0 +1,566 @@
/*
* USB SD Host Controller (USHC) controller driver.
*
* Copyright (C) 2010 Cambridge Silicon Radio Ltd.
*
* 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.
*
* Notes:
* - Only version 2 devices are supported.
* - Version 2 devices only support SDIO cards/devices (R2 response is
* unsupported).
*
* References:
* [USHC] USB SD Host Controller specification (CS-118793-SP)
*/
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
enum ushc_request {
USHC_GET_CAPS = 0x00,
USHC_HOST_CTRL = 0x01,
USHC_PWR_CTRL = 0x02,
USHC_CLK_FREQ = 0x03,
USHC_EXEC_CMD = 0x04,
USHC_READ_RESP = 0x05,
USHC_RESET = 0x06,
};
enum ushc_request_type {
USHC_GET_CAPS_TYPE = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
USHC_HOST_CTRL_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
USHC_PWR_CTRL_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
USHC_CLK_FREQ_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
USHC_EXEC_CMD_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
USHC_READ_RESP_TYPE = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
USHC_RESET_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
};
#define USHC_GET_CAPS_VERSION_MASK 0xff
#define USHC_GET_CAPS_3V3 (1 << 8)
#define USHC_GET_CAPS_3V0 (1 << 9)
#define USHC_GET_CAPS_1V8 (1 << 10)
#define USHC_GET_CAPS_HIGH_SPD (1 << 16)
#define USHC_HOST_CTRL_4BIT (1 << 1)
#define USHC_HOST_CTRL_HIGH_SPD (1 << 0)
#define USHC_PWR_CTRL_OFF 0x00
#define USHC_PWR_CTRL_3V3 0x01
#define USHC_PWR_CTRL_3V0 0x02
#define USHC_PWR_CTRL_1V8 0x03
#define USHC_READ_RESP_BUSY (1 << 4)
#define USHC_READ_RESP_ERR_TIMEOUT (1 << 3)
#define USHC_READ_RESP_ERR_CRC (1 << 2)
#define USHC_READ_RESP_ERR_DAT (1 << 1)
#define USHC_READ_RESP_ERR_CMD (1 << 0)
#define USHC_READ_RESP_ERR_MASK 0x0f
struct ushc_cbw {
__u8 signature;
__u8 cmd_idx;
__le16 block_size;
__le32 arg;
} __attribute__((packed));
#define USHC_CBW_SIGNATURE 'C'
struct ushc_csw {
__u8 signature;
__u8 status;
__le32 response;
} __attribute__((packed));
#define USHC_CSW_SIGNATURE 'S'
struct ushc_int_data {
u8 status;
u8 reserved[3];
};
#define USHC_INT_STATUS_SDIO_INT (1 << 1)
#define USHC_INT_STATUS_CARD_PRESENT (1 << 0)
struct ushc_data {
struct usb_device *usb_dev;
struct mmc_host *mmc;
struct urb *int_urb;
struct ushc_int_data *int_data;
struct urb *cbw_urb;
struct ushc_cbw *cbw;
struct urb *data_urb;
struct urb *csw_urb;
struct ushc_csw *csw;
spinlock_t lock;
struct mmc_request *current_req;
u32 caps;
u16 host_ctrl;
unsigned long flags;
u8 last_status;
int clock_freq;
};
#define DISCONNECTED 0
#define INT_EN 1
#define IGNORE_NEXT_INT 2
static void data_callback(struct urb *urb);
static int ushc_hw_reset(struct ushc_data *ushc)
{
return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
USHC_RESET, USHC_RESET_TYPE,
0, 0, NULL, 0, 100);
}
static int ushc_hw_get_caps(struct ushc_data *ushc)
{
int ret;
int version;
ret = usb_control_msg(ushc->usb_dev, usb_rcvctrlpipe(ushc->usb_dev, 0),
USHC_GET_CAPS, USHC_GET_CAPS_TYPE,
0, 0, &ushc->caps, sizeof(ushc->caps), 100);
if (ret < 0)
return ret;
ushc->caps = le32_to_cpu(ushc->caps);
version = ushc->caps & USHC_GET_CAPS_VERSION_MASK;
if (version != 0x02) {
dev_err(&ushc->usb_dev->dev, "controller version %d is not supported\n", version);
return -EINVAL;
}
return 0;
}
static int ushc_hw_set_host_ctrl(struct ushc_data *ushc, u16 mask, u16 val)
{
u16 host_ctrl;
int ret;
host_ctrl = (ushc->host_ctrl & ~mask) | val;
ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
USHC_HOST_CTRL, USHC_HOST_CTRL_TYPE,
host_ctrl, 0, NULL, 0, 100);
if (ret < 0)
return ret;
ushc->host_ctrl = host_ctrl;
return 0;
}
static void int_callback(struct urb *urb)
{
struct ushc_data *ushc = urb->context;
u8 status, last_status;
if (urb->status < 0)
return;
status = ushc->int_data->status;
last_status = ushc->last_status;
ushc->last_status = status;
/*
* Ignore the card interrupt status on interrupt transfers that
* were submitted while card interrupts where disabled.
*
* This avoid occasional spurious interrupts when enabling
* interrupts immediately after clearing the source on the card.
*/
if (!test_and_clear_bit(IGNORE_NEXT_INT, &ushc->flags)
&& test_bit(INT_EN, &ushc->flags)
&& status & USHC_INT_STATUS_SDIO_INT) {
mmc_signal_sdio_irq(ushc->mmc);
}
if ((status ^ last_status) & USHC_INT_STATUS_CARD_PRESENT)
mmc_detect_change(ushc->mmc, msecs_to_jiffies(100));
if (!test_bit(INT_EN, &ushc->flags))
set_bit(IGNORE_NEXT_INT, &ushc->flags);
usb_submit_urb(ushc->int_urb, GFP_ATOMIC);
}
static void cbw_callback(struct urb *urb)
{
struct ushc_data *ushc = urb->context;
if (urb->status != 0) {
usb_unlink_urb(ushc->data_urb);
usb_unlink_urb(ushc->csw_urb);
}
}
static void data_callback(struct urb *urb)
{
struct ushc_data *ushc = urb->context;
if (urb->status != 0)
usb_unlink_urb(ushc->csw_urb);
}
static void csw_callback(struct urb *urb)
{
struct ushc_data *ushc = urb->context;
struct mmc_request *req = ushc->current_req;
int status;
status = ushc->csw->status;
if (urb->status != 0) {
req->cmd->error = urb->status;
} else if (status & USHC_READ_RESP_ERR_CMD) {
if (status & USHC_READ_RESP_ERR_CRC)
req->cmd->error = -EIO;
else
req->cmd->error = -ETIMEDOUT;
}
if (req->data) {
if (status & USHC_READ_RESP_ERR_DAT) {
if (status & USHC_READ_RESP_ERR_CRC)
req->data->error = -EIO;
else
req->data->error = -ETIMEDOUT;
req->data->bytes_xfered = 0;
} else {
req->data->bytes_xfered = req->data->blksz * req->data->blocks;
}
}
req->cmd->resp[0] = le32_to_cpu(ushc->csw->response);
mmc_request_done(ushc->mmc, req);
}
static void ushc_request(struct mmc_host *mmc, struct mmc_request *req)
{
struct ushc_data *ushc = mmc_priv(mmc);
int ret;
unsigned long flags;
spin_lock_irqsave(&ushc->lock, flags);
if (test_bit(DISCONNECTED, &ushc->flags)) {
ret = -ENODEV;
goto out;
}
/* Version 2 firmware doesn't support the R2 response format. */
if (req->cmd->flags & MMC_RSP_136) {
ret = -EINVAL;
goto out;
}
/* The Astoria's data FIFOs don't work with clock speeds < 5MHz so
limit commands with data to 6MHz or more. */
if (req->data && ushc->clock_freq < 6000000) {
ret = -EINVAL;
goto out;
}
ushc->current_req = req;
/* Start cmd with CBW. */
ushc->cbw->cmd_idx = cpu_to_le16(req->cmd->opcode);
if (req->data)
ushc->cbw->block_size = cpu_to_le16(req->data->blksz);
else
ushc->cbw->block_size = 0;
ushc->cbw->arg = cpu_to_le32(req->cmd->arg);
ret = usb_submit_urb(ushc->cbw_urb, GFP_ATOMIC);
if (ret < 0)
goto out;
/* Submit data (if any). */
if (req->data) {
struct mmc_data *data = req->data;
int pipe;
if (data->flags & MMC_DATA_READ)
pipe = usb_rcvbulkpipe(ushc->usb_dev, 6);
else
pipe = usb_sndbulkpipe(ushc->usb_dev, 2);
usb_fill_bulk_urb(ushc->data_urb, ushc->usb_dev, pipe,
sg_virt(data->sg), data->sg->length,
data_callback, ushc);
ret = usb_submit_urb(ushc->data_urb, GFP_ATOMIC);
if (ret < 0)
goto out;
}
/* Submit CSW. */
ret = usb_submit_urb(ushc->csw_urb, GFP_ATOMIC);
if (ret < 0)
goto out;
out:
spin_unlock_irqrestore(&ushc->lock, flags);
if (ret < 0) {
usb_unlink_urb(ushc->cbw_urb);
usb_unlink_urb(ushc->data_urb);
req->cmd->error = ret;
mmc_request_done(mmc, req);
}
}
static int ushc_set_power(struct ushc_data *ushc, unsigned char power_mode)
{
u16 voltage;
switch (power_mode) {
case MMC_POWER_OFF:
voltage = USHC_PWR_CTRL_OFF;
break;
case MMC_POWER_UP:
case MMC_POWER_ON:
voltage = USHC_PWR_CTRL_3V3;
break;
default:
return -EINVAL;
}
return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
USHC_PWR_CTRL, USHC_PWR_CTRL_TYPE,
voltage, 0, NULL, 0, 100);
}
static int ushc_set_bus_width(struct ushc_data *ushc, int bus_width)
{
return ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_4BIT,
bus_width == 4 ? USHC_HOST_CTRL_4BIT : 0);
}
static int ushc_set_bus_freq(struct ushc_data *ushc, int clk, bool enable_hs)
{
int ret;
/* Hardware can't detect interrupts while the clock is off. */
if (clk == 0)
clk = 400000;
ret = ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_HIGH_SPD,
enable_hs ? USHC_HOST_CTRL_HIGH_SPD : 0);
if (ret < 0)
return ret;
ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
USHC_CLK_FREQ, USHC_CLK_FREQ_TYPE,
clk & 0xffff, (clk >> 16) & 0xffff, NULL, 0, 100);
if (ret < 0)
return ret;
ushc->clock_freq = clk;
return 0;
}
static void ushc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct ushc_data *ushc = mmc_priv(mmc);
ushc_set_power(ushc, ios->power_mode);
ushc_set_bus_width(ushc, 1 << ios->bus_width);
ushc_set_bus_freq(ushc, ios->clock, ios->timing == MMC_TIMING_SD_HS);
}
static int ushc_get_cd(struct mmc_host *mmc)
{
struct ushc_data *ushc = mmc_priv(mmc);
return !!(ushc->last_status & USHC_INT_STATUS_CARD_PRESENT);
}
static void ushc_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct ushc_data *ushc = mmc_priv(mmc);
if (enable)
set_bit(INT_EN, &ushc->flags);
else
clear_bit(INT_EN, &ushc->flags);
}
static void ushc_clean_up(struct ushc_data *ushc)
{
usb_free_urb(ushc->int_urb);
usb_free_urb(ushc->csw_urb);
usb_free_urb(ushc->data_urb);
usb_free_urb(ushc->cbw_urb);
kfree(ushc->int_data);
kfree(ushc->cbw);
kfree(ushc->csw);
mmc_free_host(ushc->mmc);
}
static const struct mmc_host_ops ushc_ops = {
.request = ushc_request,
.set_ios = ushc_set_ios,
.get_cd = ushc_get_cd,
.enable_sdio_irq = ushc_enable_sdio_irq,
};
static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct mmc_host *mmc;
struct ushc_data *ushc;
int ret = -ENOMEM;
mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
if (mmc == NULL)
return -ENOMEM;
ushc = mmc_priv(mmc);
usb_set_intfdata(intf, ushc);
ushc->usb_dev = usb_dev;
ushc->mmc = mmc;
spin_lock_init(&ushc->lock);
ret = ushc_hw_reset(ushc);
if (ret < 0)
goto err;
/* Read capabilities. */
ret = ushc_hw_get_caps(ushc);
if (ret < 0)
goto err;
mmc->ops = &ushc_ops;
mmc->f_min = 400000;
mmc->f_max = 50000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
mmc->caps |= (ushc->caps & USHC_GET_CAPS_HIGH_SPD) ? MMC_CAP_SD_HIGHSPEED : 0;
mmc->max_seg_size = 512*511;
mmc->max_segs = 1;
mmc->max_req_size = 512*511;
mmc->max_blk_size = 512;
mmc->max_blk_count = 511;
ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL);
if (ushc->int_urb == NULL)
goto err;
ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL);
if (ushc->int_data == NULL)
goto err;
usb_fill_int_urb(ushc->int_urb, ushc->usb_dev,
usb_rcvintpipe(usb_dev,
intf->cur_altsetting->endpoint[0].desc.bEndpointAddress),
ushc->int_data, sizeof(struct ushc_int_data),
int_callback, ushc,
intf->cur_altsetting->endpoint[0].desc.bInterval);
ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL);
if (ushc->cbw_urb == NULL)
goto err;
ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
if (ushc->cbw == NULL)
goto err;
ushc->cbw->signature = USHC_CBW_SIGNATURE;
usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2),
ushc->cbw, sizeof(struct ushc_cbw),
cbw_callback, ushc);
ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL);
if (ushc->data_urb == NULL)
goto err;
ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL);
if (ushc->csw_urb == NULL)
goto err;
ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
if (ushc->csw == NULL)
goto err;
usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6),
ushc->csw, sizeof(struct ushc_csw),
csw_callback, ushc);
ret = mmc_add_host(ushc->mmc);
if (ret)
goto err;
ret = usb_submit_urb(ushc->int_urb, GFP_KERNEL);
if (ret < 0) {
mmc_remove_host(ushc->mmc);
goto err;
}
return 0;
err:
ushc_clean_up(ushc);
return ret;
}
static void ushc_disconnect(struct usb_interface *intf)
{
struct ushc_data *ushc = usb_get_intfdata(intf);
spin_lock_irq(&ushc->lock);
set_bit(DISCONNECTED, &ushc->flags);
spin_unlock_irq(&ushc->lock);
usb_kill_urb(ushc->int_urb);
usb_kill_urb(ushc->cbw_urb);
usb_kill_urb(ushc->data_urb);
usb_kill_urb(ushc->csw_urb);
mmc_remove_host(ushc->mmc);
ushc_clean_up(ushc);
}
static struct usb_device_id ushc_id_table[] = {
/* CSR USB SD Host Controller */
{ USB_DEVICE(0x0a12, 0x5d10) },
{ },
};
MODULE_DEVICE_TABLE(usb, ushc_id_table);
static struct usb_driver ushc_driver = {
.name = "ushc",
.id_table = ushc_id_table,
.probe = ushc_probe,
.disconnect = ushc_disconnect,
};
static int __init ushc_init(void)
{
return usb_register(&ushc_driver);
}
module_init(ushc_init);
static void __exit ushc_exit(void)
{
usb_deregister(&ushc_driver);
}
module_exit(ushc_exit);
MODULE_DESCRIPTION("USB SD Host Controller driver");
MODULE_AUTHOR("David Vrabel <david.vrabel@csr.com>");
MODULE_LICENSE("GPL");

View File

@ -1050,8 +1050,7 @@ static void via_init_mmc_host(struct via_crdr_mmc_host *host)
mmc->ops = &via_sdc_ops;
/*Hardware cannot do scatter lists*/
mmc->max_hw_segs = 1;
mmc->max_phys_segs = 1;
mmc->max_segs = 1;
mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH;
mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT;

View File

@ -1235,8 +1235,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
* Maximum number of segments. Worst case is one sector per segment
* so this will be 64kB/512.
*/
mmc->max_hw_segs = 128;
mmc->max_phys_segs = 128;
mmc->max_segs = 128;
/*
* Maximum request size. Also limited by 64KiB buffer.

View File

@ -48,6 +48,7 @@ struct mmc_ext_csd {
unsigned int sa_timeout; /* Units: 100ns */
unsigned int hs_max_dtr;
unsigned int sectors;
unsigned int card_type;
unsigned int hc_erase_size; /* In sectors */
unsigned int hc_erase_timeout; /* In milliseconds */
unsigned int sec_trim_mult; /* Secure trim multiplier */
@ -113,6 +114,7 @@ struct mmc_card {
#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 */
#define MMC_STATE_HIGHSPEED_DDR (1<<4) /* card is in high speed mode */
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@ -154,11 +156,13 @@ struct mmc_card {
#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_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#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)
#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
{
@ -173,6 +177,8 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
#define mmc_card_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) (dev_name(&(c)->dev))
#define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev)
#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)

View File

@ -153,6 +153,8 @@ extern int mmc_can_secure_erase_trim(struct mmc_card *card);
extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
unsigned int nr);
extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);

View File

@ -50,6 +50,12 @@ struct mmc_ios {
#define MMC_TIMING_LEGACY 0
#define MMC_TIMING_MMC_HS 1
#define MMC_TIMING_SD_HS 2
unsigned char ddr; /* dual data rate used */
#define MMC_SDR_MODE 0
#define MMC_1_2V_DDR_MODE 1
#define MMC_1_8V_DDR_MODE 2
};
struct mmc_host_ops {
@ -123,6 +129,7 @@ struct mmc_host {
const struct mmc_host_ops *ops;
unsigned int f_min;
unsigned int f_max;
unsigned int f_init;
u32 ocr_avail;
struct notifier_block pm_notify;
@ -157,13 +164,16 @@ struct mmc_host {
#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */
#define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */
#define MMC_CAP_1_8V_DDR (1 << 11) /* can support */
/* DDR mode at 1.8V */
#define MMC_CAP_1_2V_DDR (1 << 12) /* can support */
/* DDR mode at 1.2V */
mmc_pm_flag_t pm_caps; /* supported pm features */
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */
unsigned short max_phys_segs; /* see blk_queue_max_phys_segments */
unsigned short max_segs; /* see blk_queue_max_segments */
unsigned short unused;
unsigned int max_req_size; /* maximum number of bytes in one req */
unsigned int max_blk_size; /* maximum size of one mmc block */
@ -212,6 +222,10 @@ struct mmc_host {
struct led_trigger *led; /* activity led */
#endif
#ifdef CONFIG_REGULATOR
bool regulator_enabled; /* regulator state */
#endif
struct dentry *debugfs_root;
unsigned long private[0] ____cacheline_aligned;
@ -236,8 +250,8 @@ static inline void *mmc_priv(struct mmc_host *host)
extern int mmc_suspend_host(struct mmc_host *);
extern int mmc_resume_host(struct mmc_host *);
extern void mmc_power_save_host(struct mmc_host *host);
extern void mmc_power_restore_host(struct mmc_host *host);
extern int mmc_power_save_host(struct mmc_host *host);
extern int mmc_power_restore_host(struct mmc_host *host);
extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
@ -250,8 +264,24 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
struct regulator;
#ifdef CONFIG_REGULATOR
int mmc_regulator_get_ocrmask(struct regulator *supply);
int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply,
unsigned short vdd_bit);
#else
static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
{
return 0;
}
static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply,
unsigned short vdd_bit)
{
return 0;
}
#endif
int mmc_card_awake(struct mmc_host *host);
int mmc_card_sleep(struct mmc_host *host);
@ -268,5 +298,13 @@ static inline void mmc_set_disable_delay(struct mmc_host *host,
host->disable_delay = disable_delay;
}
/* Module parameter */
extern int mmc_assume_removable;
static inline int mmc_card_is_removable(struct mmc_host *host)
{
return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable;
}
#endif

View File

@ -277,11 +277,19 @@ struct _mmc_csd {
#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
#define EXT_CSD_CARD_TYPE_MASK 0x3 /* Mask out reserved and DDR bits */
#define EXT_CSD_CARD_TYPE_MASK 0xF /* Mask out reserved bits */
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
/* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_SEC_ER_EN BIT(0)
#define EXT_CSD_SEC_BD_BLK_EN BIT(2)

View File

@ -28,7 +28,7 @@ struct sdhci_host;
struct sdhci_pltfm_data {
struct sdhci_ops *ops;
unsigned int quirks;
int (*init)(struct sdhci_host *host);
int (*init)(struct sdhci_host *host, struct sdhci_pltfm_data *pdata);
void (*exit)(struct sdhci_host *host);
};

144
include/linux/mmc/sdhci.h Normal file
View File

@ -0,0 +1,144 @@
/*
* linux/include/linux/mmc/sdhci.h - Secure Digital Host Controller Interface
*
* Copyright (C) 2005-2008 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
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*/
#ifndef __SDHCI_H
#define __SDHCI_H
#include <linux/scatterlist.h>
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/mmc/host.h>
struct sdhci_host {
/* Data set by hardware interface driver */
const char *hw_name; /* Hardware bus name */
unsigned int quirks; /* Deviations from spec. */
/* Controller doesn't honor resets unless we touch the clock register */
#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
/* Controller has bad caps bits, but really supports DMA */
#define SDHCI_QUIRK_FORCE_DMA (1<<1)
/* Controller doesn't like to be reset when there is no card inserted. */
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
/* Controller doesn't like clearing the power reg before a change */
#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
/* Controller has flaky internal state so reset it on each ios change */
#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4)
/* Controller has an unusable DMA engine */
#define SDHCI_QUIRK_BROKEN_DMA (1<<5)
/* Controller has an unusable ADMA engine */
#define SDHCI_QUIRK_BROKEN_ADMA (1<<6)
/* Controller can only DMA from 32-bit aligned addresses */
#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7)
/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8)
/* Controller can only ADMA chunks that are a multiple of 32 bits */
#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1<<9)
/* Controller needs to be reset after each request to stay stable */
#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<10)
/* Controller needs voltage and power writes to happen separately */
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11)
/* Controller provides an incorrect timeout value for transfers */
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12)
/* Controller has an issue with buffer bits for small transfers */
#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13)
/* Controller does not provide transfer-complete interrupt when not busy */
#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14)
/* Controller has unreliable card detection */
#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
/* Controller reports inverted write-protect state */
#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16)
/* Controller has nonstandard clock management */
#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<17)
/* Controller does not like fast PIO transfers */
#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)
/* Controller losing signal/interrupt enable states after reset */
#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19)
/* Controller has to be forced to use block size of 2048 bytes */
#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)
/* Controller cannot do multi-block transfers */
#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21)
/* Controller can only handle 1-bit data transfers */
#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22)
/* Controller needs 10ms delay between applying power and clock */
#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23)
/* Controller uses SDCLK instead of TMCLK for data timeouts */
#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24)
/* Controller reports wrong base clock capability */
#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25)
/* Controller cannot support End Attribute in NOP ADMA descriptor */
#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26)
/* Controller is missing device caps. Use caps provided by host */
#define SDHCI_QUIRK_MISSING_CAPS (1<<27)
/* Controller uses Auto CMD12 command to stop the transfer */
#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28)
/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
const struct sdhci_ops *ops; /* Low level hw interface */
struct regulator *vmmc; /* Power regulator */
/* Internal data */
struct mmc_host *mmc; /* MMC structure */
u64 dma_mask; /* custom DMA mask */
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
struct led_classdev led; /* LED control */
char led_name[32];
#endif
spinlock_t lock; /* Mutex */
int flags; /* Host attributes */
#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */
#define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */
#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */
#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
unsigned int version; /* SDHCI spec. version */
unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int timeout_clk; /* Timeout freq (KHz) */
unsigned int clock; /* Current clock (MHz) */
u8 pwr; /* Current voltage */
struct mmc_request *mrq; /* Current request */
struct mmc_command *cmd; /* Current command */
struct mmc_data *data; /* Current data request */
unsigned int data_early:1; /* Data finished before cmd */
struct sg_mapping_iter sg_miter; /* SG state for PIO */
unsigned int blocks; /* remaining PIO blocks */
int sg_count; /* Mapped sg entries */
u8 *adma_desc; /* ADMA descriptor table */
u8 *align_buffer; /* Bounce buffer */
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */
struct tasklet_struct card_tasklet; /* Tasklet structures */
struct tasklet_struct finish_tasklet;
struct timer_list timer; /* Timer for timeouts */
unsigned int caps; /* Alternative capabilities */
unsigned long private[0] ____cacheline_aligned;
};
#endif /* __SDHCI_H */

View File

@ -2430,6 +2430,13 @@
#define PCI_DEVICE_ID_INTEL_82375 0x0482
#define PCI_DEVICE_ID_INTEL_82424 0x0483
#define PCI_DEVICE_ID_INTEL_82378 0x0484
#define PCI_DEVICE_ID_INTEL_MRST_SD0 0x0807
#define PCI_DEVICE_ID_INTEL_MRST_SD1 0x0808
#define PCI_DEVICE_ID_INTEL_MFD_SD 0x0820
#define PCI_DEVICE_ID_INTEL_MFD_SDIO1 0x0821
#define PCI_DEVICE_ID_INTEL_MFD_SDIO2 0x0822
#define PCI_DEVICE_ID_INTEL_MFD_EMMC0 0x0823
#define PCI_DEVICE_ID_INTEL_MFD_EMMC1 0x0824
#define PCI_DEVICE_ID_INTEL_I960 0x0960
#define PCI_DEVICE_ID_INTEL_I960RM 0x0962
#define PCI_DEVICE_ID_INTEL_8257X_SOL 0x1062