You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: (68 commits) sdio_uart: Fix SDIO break control to now return success or an error mmc: host driver for Ricoh Bay1Controllers sdio: sdio_io.c Fix sparse warnings sdio: fix the use of hard coded timeout value. mmc: OLPC: update vdd/powerup quirk comment mmc: fix spares errors of sdhci.c mmc: remove multiwrite capability wbsd: fix bad dma_addr_t conversion atmel-mci: Driver for Atmel on-chip MMC controllers mmc: fix sdio_io sparse errors mmc: wbsd.c fix shadowing of 'dma' variable MMC: S3C24XX: Refuse incorrectly aligned transfers MMC: S3C24XX: Add maintainer entry MMC: S3C24XX: Update error debugging. MMC: S3C24XX: Add media presence test to request handling. MMC: S3C24XX: Fix use of msecs where jiffies are needed MMC: S3C24XX: Add MODULE_ALIAS() entries for the platform devices MMC: S3C24XX: Fix s3c2410_dma_request() return code check. MMC: S3C24XX: Allow card-detect on non-IRQ capable pin MMC: S3C24XX: Ensure host->mrq->data is valid ... Manually fixed up bogus executable bits on drivers/mmc/core/sdio_io.c and include/linux/mmc/sdio_func.h when merging.
This commit is contained in:
+16
-1
@@ -348,7 +348,9 @@ W: http://www.linux-usb.org/SpeedTouch/
|
||||
S: Maintained
|
||||
|
||||
ALCHEMY AU1XX0 MMC DRIVER
|
||||
S: Orphan
|
||||
P: Manuel Lauss
|
||||
M: manuel.lauss@gmail.com
|
||||
S: Maintained
|
||||
|
||||
ALI1563 I2C DRIVER
|
||||
P: Rudolf Marek
|
||||
@@ -3559,6 +3561,13 @@ L: linux-s390@vger.kernel.org
|
||||
W: http://www.ibm.com/developerworks/linux/linux390/
|
||||
S: Supported
|
||||
|
||||
S3C24XX SD/MMC Driver
|
||||
P: Ben Dooks
|
||||
M: ben-linux@fluff.org
|
||||
L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
|
||||
SAA7146 VIDEO4LINUX-2 DRIVER
|
||||
P: Michael Hunold
|
||||
M: michael@mihu.de
|
||||
@@ -3631,6 +3640,12 @@ P: Jim Cromie
|
||||
M: jim.cromie@gmail.com
|
||||
S: Maintained
|
||||
|
||||
SDRICOH_CS MMC/SD HOST CONTROLLER INTERFACE DRIVER
|
||||
P: Sascha Sommer
|
||||
M: saschasommer@freenet.de
|
||||
L: sdricohcs-devel@lists.sourceforge.net (subscribers-only)
|
||||
S: Maintained
|
||||
|
||||
SECURITY CONTACT
|
||||
P: Security Officers
|
||||
M: security@kernel.org
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/leds.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <asm/atmel-mci.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
@@ -51,6 +52,11 @@ static struct spi_board_info spi0_board_info[] __initdata = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct mci_platform_data __initdata mci0_data = {
|
||||
.detect_pin = GPIO_PIN_PC(25),
|
||||
.wp_pin = GPIO_PIN_PE(0),
|
||||
};
|
||||
|
||||
/*
|
||||
* The next two functions should go away as the boot loader is
|
||||
* supposed to initialize the macb address registers with a valid
|
||||
@@ -170,6 +176,7 @@ static int __init atngw100_init(void)
|
||||
set_hw_addr(at32_add_device_eth(1, ð_data[1]));
|
||||
|
||||
at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
|
||||
at32_add_device_mci(0, &mci0_data);
|
||||
at32_add_device_usba(0, NULL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) {
|
||||
|
||||
@@ -234,6 +234,9 @@ static int __init atstk1002_init(void)
|
||||
#ifdef CONFIG_BOARD_ATSTK100X_SPI1
|
||||
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
|
||||
#endif
|
||||
#ifndef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
|
||||
at32_add_device_mci(0, NULL);
|
||||
#endif
|
||||
#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
|
||||
set_hw_addr(at32_add_device_eth(1, ð_data[1]));
|
||||
#else
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/usb/atmel_usba_udc.h>
|
||||
|
||||
#include <asm/atmel-mci.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
@@ -1278,20 +1279,32 @@ static struct clk atmel_mci0_pclk = {
|
||||
.index = 9,
|
||||
};
|
||||
|
||||
struct platform_device *__init at32_add_device_mci(unsigned int id)
|
||||
struct platform_device *__init
|
||||
at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct mci_platform_data _data;
|
||||
struct platform_device *pdev;
|
||||
struct dw_dma_slave *dws;
|
||||
|
||||
if (id != 0)
|
||||
return NULL;
|
||||
|
||||
pdev = platform_device_alloc("atmel_mci", id);
|
||||
if (!pdev)
|
||||
return NULL;
|
||||
goto fail;
|
||||
|
||||
if (platform_device_add_resources(pdev, atmel_mci0_resource,
|
||||
ARRAY_SIZE(atmel_mci0_resource)))
|
||||
goto err_add_resources;
|
||||
goto fail;
|
||||
|
||||
if (!data) {
|
||||
data = &_data;
|
||||
memset(data, 0, sizeof(struct mci_platform_data));
|
||||
}
|
||||
|
||||
if (platform_device_add_data(pdev, data,
|
||||
sizeof(struct mci_platform_data)))
|
||||
goto fail;
|
||||
|
||||
select_peripheral(PA(10), PERIPH_A, 0); /* CLK */
|
||||
select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
|
||||
@@ -1300,12 +1313,19 @@ struct platform_device *__init at32_add_device_mci(unsigned int id)
|
||||
select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
|
||||
select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
|
||||
|
||||
if (data) {
|
||||
if (data->detect_pin != GPIO_PIN_NONE)
|
||||
at32_select_gpio(data->detect_pin, 0);
|
||||
if (data->wp_pin != GPIO_PIN_NONE)
|
||||
at32_select_gpio(data->wp_pin, 0);
|
||||
}
|
||||
|
||||
atmel_mci0_pclk.dev = &pdev->dev;
|
||||
|
||||
platform_device_add(pdev);
|
||||
return pdev;
|
||||
|
||||
err_add_resources:
|
||||
fail:
|
||||
platform_device_put(pdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+27
-31
@@ -2,7 +2,7 @@
|
||||
* Block driver for media (i.e., flash cards)
|
||||
*
|
||||
* Copyright 2002 Hewlett-Packard Company
|
||||
* Copyright 2005-2007 Pierre Ossman
|
||||
* Copyright 2005-2008 Pierre Ossman
|
||||
*
|
||||
* Use consistent with the GNU GPL is permitted,
|
||||
* provided that this copyright notice is
|
||||
@@ -237,17 +237,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
||||
if (brq.data.blocks > card->host->max_blk_count)
|
||||
brq.data.blocks = card->host->max_blk_count;
|
||||
|
||||
/*
|
||||
* If the host doesn't support multiple block writes, force
|
||||
* block writes to single block. SD cards are excepted from
|
||||
* this rule as they support querying the number of
|
||||
* successfully written sectors.
|
||||
*/
|
||||
if (rq_data_dir(req) != READ &&
|
||||
!(card->host->caps & MMC_CAP_MULTIWRITE) &&
|
||||
!mmc_card_sd(card))
|
||||
brq.data.blocks = 1;
|
||||
|
||||
if (brq.data.blocks > 1) {
|
||||
/* SPI multiblock writes terminate using a special
|
||||
* token, not a STOP_TRANSMISSION request.
|
||||
@@ -296,22 +285,24 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
||||
|
||||
mmc_queue_bounce_post(mq);
|
||||
|
||||
/*
|
||||
* Check for errors here, but don't jump to cmd_err
|
||||
* until later as we need to wait for the card to leave
|
||||
* programming mode even when things go wrong.
|
||||
*/
|
||||
if (brq.cmd.error) {
|
||||
printk(KERN_ERR "%s: error %d sending read/write command\n",
|
||||
req->rq_disk->disk_name, brq.cmd.error);
|
||||
goto cmd_err;
|
||||
}
|
||||
|
||||
if (brq.data.error) {
|
||||
printk(KERN_ERR "%s: error %d transferring data\n",
|
||||
req->rq_disk->disk_name, brq.data.error);
|
||||
goto cmd_err;
|
||||
}
|
||||
|
||||
if (brq.stop.error) {
|
||||
printk(KERN_ERR "%s: error %d sending stop command\n",
|
||||
req->rq_disk->disk_name, brq.stop.error);
|
||||
goto cmd_err;
|
||||
}
|
||||
|
||||
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
|
||||
@@ -344,6 +335,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (brq.cmd.error || brq.data.error || brq.stop.error)
|
||||
goto cmd_err;
|
||||
|
||||
/*
|
||||
* A block was successfully transferred.
|
||||
*/
|
||||
@@ -362,30 +356,32 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
||||
* mark the known good sectors as ok.
|
||||
*
|
||||
* If the card is not SD, we can still ok written sectors
|
||||
* if the controller can do proper error reporting.
|
||||
* as reported by the controller (which might be less than
|
||||
* the real number of written sectors, but never more).
|
||||
*
|
||||
* For reads we just fail the entire chunk as that should
|
||||
* be safe in all cases.
|
||||
*/
|
||||
if (rq_data_dir(req) != READ && mmc_card_sd(card)) {
|
||||
u32 blocks;
|
||||
unsigned int bytes;
|
||||
if (rq_data_dir(req) != READ) {
|
||||
if (mmc_card_sd(card)) {
|
||||
u32 blocks;
|
||||
unsigned int bytes;
|
||||
|
||||
blocks = mmc_sd_num_wr_blocks(card);
|
||||
if (blocks != (u32)-1) {
|
||||
if (card->csd.write_partial)
|
||||
bytes = blocks << md->block_bits;
|
||||
else
|
||||
bytes = blocks << 9;
|
||||
blocks = mmc_sd_num_wr_blocks(card);
|
||||
if (blocks != (u32)-1) {
|
||||
if (card->csd.write_partial)
|
||||
bytes = blocks << md->block_bits;
|
||||
else
|
||||
bytes = blocks << 9;
|
||||
spin_lock_irq(&md->lock);
|
||||
ret = __blk_end_request(req, 0, bytes);
|
||||
spin_unlock_irq(&md->lock);
|
||||
}
|
||||
} else {
|
||||
spin_lock_irq(&md->lock);
|
||||
ret = __blk_end_request(req, 0, bytes);
|
||||
ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
|
||||
spin_unlock_irq(&md->lock);
|
||||
}
|
||||
} else if (rq_data_dir(req) != READ &&
|
||||
(card->host->caps & MMC_CAP_MULTIWRITE)) {
|
||||
spin_lock_irq(&md->lock);
|
||||
ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
|
||||
spin_unlock_irq(&md->lock);
|
||||
}
|
||||
|
||||
mmc_release_host(card->host);
|
||||
|
||||
+383
-200
File diff suppressed because it is too large
Load Diff
@@ -885,12 +885,14 @@ static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_t
|
||||
sdio_uart_release_func(port);
|
||||
}
|
||||
|
||||
static void sdio_uart_break_ctl(struct tty_struct *tty, int break_state)
|
||||
static int sdio_uart_break_ctl(struct tty_struct *tty, int break_state)
|
||||
{
|
||||
struct sdio_uart_port *port = tty->driver_data;
|
||||
int result;
|
||||
|
||||
if (sdio_uart_claim_func(port) != 0)
|
||||
return;
|
||||
result = sdio_uart_claim_func(port);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
if (break_state == -1)
|
||||
port->lcr |= UART_LCR_SBC;
|
||||
@@ -899,6 +901,7 @@ static void sdio_uart_break_ctl(struct tty_struct *tty, int break_state)
|
||||
sdio_out(port, UART_LCR, port->lcr);
|
||||
|
||||
sdio_uart_release_func(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdio_uart_tiocmget(struct tty_struct *tty, struct file *file)
|
||||
|
||||
+37
-4
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
|
||||
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
|
||||
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
|
||||
* Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
|
||||
* MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -294,6 +294,33 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_set_data_timeout);
|
||||
|
||||
/**
|
||||
* mmc_align_data_size - pads a transfer size to a more optimal value
|
||||
* @card: the MMC card associated with the data transfer
|
||||
* @sz: original transfer size
|
||||
*
|
||||
* Pads the original data size with a number of extra bytes in
|
||||
* order to avoid controller bugs and/or performance hits
|
||||
* (e.g. some controllers revert to PIO for certain sizes).
|
||||
*
|
||||
* Returns the improved size, which might be unmodified.
|
||||
*
|
||||
* Note that this function is only relevant when issuing a
|
||||
* single scatter gather entry.
|
||||
*/
|
||||
unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
|
||||
{
|
||||
/*
|
||||
* FIXME: We don't have a system for the controller to tell
|
||||
* the core about its problems yet, so for now we just 32-bit
|
||||
* align the size.
|
||||
*/
|
||||
sz = ((sz + 3) / 4) * 4;
|
||||
|
||||
return sz;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_align_data_size);
|
||||
|
||||
/**
|
||||
* __mmc_claim_host - exclusively claim a host
|
||||
* @host: mmc host to claim
|
||||
@@ -638,6 +665,9 @@ void mmc_rescan(struct work_struct *work)
|
||||
*/
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
|
||||
goto out;
|
||||
|
||||
mmc_claim_host(host);
|
||||
|
||||
mmc_power_up(host);
|
||||
@@ -652,7 +682,7 @@ void mmc_rescan(struct work_struct *work)
|
||||
if (!err) {
|
||||
if (mmc_attach_sdio(host, ocr))
|
||||
mmc_power_off(host);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -662,7 +692,7 @@ void mmc_rescan(struct work_struct *work)
|
||||
if (!err) {
|
||||
if (mmc_attach_sd(host, ocr))
|
||||
mmc_power_off(host);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -672,7 +702,7 @@ void mmc_rescan(struct work_struct *work)
|
||||
if (!err) {
|
||||
if (mmc_attach_mmc(host, ocr))
|
||||
mmc_power_off(host);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mmc_release_host(host);
|
||||
@@ -683,6 +713,9 @@ void mmc_rescan(struct work_struct *work)
|
||||
|
||||
mmc_bus_put(host);
|
||||
}
|
||||
out:
|
||||
if (host->caps & MMC_CAP_NEEDS_POLL)
|
||||
mmc_schedule_delayed_work(&host->detect, HZ);
|
||||
}
|
||||
|
||||
void mmc_start_host(struct mmc_host *host)
|
||||
|
||||
@@ -288,7 +288,7 @@ static struct device_type mmc_type = {
|
||||
/*
|
||||
* Handle the detection and initialisation of a card.
|
||||
*
|
||||
* In the case of a resume, "curcard" will contain the card
|
||||
* In the case of a resume, "oldcard" will contain the card
|
||||
* we're trying to reinitialise.
|
||||
*/
|
||||
static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
|
||||
@@ -326,7 +326,7 @@ static struct device_type sd_type = {
|
||||
/*
|
||||
* Handle the detection and initialisation of a card.
|
||||
*
|
||||
* In the case of a resume, "curcard" will contain the card
|
||||
* In the case of a resume, "oldcard" will contain the card
|
||||
* we're trying to reinitialise.
|
||||
*/
|
||||
static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
||||
@@ -494,13 +494,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
||||
* Check if read-only switch is active.
|
||||
*/
|
||||
if (!oldcard) {
|
||||
if (!host->ops->get_ro) {
|
||||
if (!host->ops->get_ro || host->ops->get_ro(host) < 0) {
|
||||
printk(KERN_WARNING "%s: host does not "
|
||||
"support reading read-only "
|
||||
"switch. assuming write-enable.\n",
|
||||
mmc_hostname(host));
|
||||
} else {
|
||||
if (host->ops->get_ro(host))
|
||||
if (host->ops->get_ro(host) > 0)
|
||||
mmc_card_set_readonly(card);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,12 @@ static int cistpl_funce_func(struct sdio_func *func,
|
||||
/* TPLFE_MAX_BLK_SIZE */
|
||||
func->max_blksize = buf[12] | (buf[13] << 8);
|
||||
|
||||
/* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */
|
||||
if (vsn > SDIO_SDIO_REV_1_00)
|
||||
func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10;
|
||||
else
|
||||
func->enable_timeout = jiffies_to_msecs(HZ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+128
-39
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/mmc/core/sdio_io.c
|
||||
*
|
||||
* Copyright 2007 Pierre Ossman
|
||||
* Copyright 2007-2008 Pierre Ossman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -76,11 +76,7 @@ int sdio_enable_func(struct sdio_func *func)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* FIXME: This should timeout based on information in the CIS,
|
||||
* but we don't have card to parse that yet.
|
||||
*/
|
||||
timeout = jiffies + HZ;
|
||||
timeout = jiffies + msecs_to_jiffies(func->enable_timeout);
|
||||
|
||||
while (1) {
|
||||
ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, ®);
|
||||
@@ -167,10 +163,8 @@ int sdio_set_block_size(struct sdio_func *func, unsigned blksz)
|
||||
return -EINVAL;
|
||||
|
||||
if (blksz == 0) {
|
||||
blksz = min(min(
|
||||
func->max_blksize,
|
||||
func->card->host->max_blk_size),
|
||||
512u);
|
||||
blksz = min(func->max_blksize, func->card->host->max_blk_size);
|
||||
blksz = min(blksz, 512u);
|
||||
}
|
||||
|
||||
ret = mmc_io_rw_direct(func->card, 1, 0,
|
||||
@@ -186,9 +180,116 @@ int sdio_set_block_size(struct sdio_func *func, unsigned blksz)
|
||||
func->cur_blksize = blksz;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(sdio_set_block_size);
|
||||
|
||||
/*
|
||||
* Calculate the maximum byte mode transfer size
|
||||
*/
|
||||
static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
|
||||
{
|
||||
unsigned mval = min(func->card->host->max_seg_size,
|
||||
func->card->host->max_blk_size);
|
||||
mval = min(mval, func->max_blksize);
|
||||
return min(mval, 512u); /* maximum size for byte mode */
|
||||
}
|
||||
|
||||
/**
|
||||
* sdio_align_size - pads a transfer size to a more optimal value
|
||||
* @func: SDIO function
|
||||
* @sz: original transfer size
|
||||
*
|
||||
* Pads the original data size with a number of extra bytes in
|
||||
* order to avoid controller bugs and/or performance hits
|
||||
* (e.g. some controllers revert to PIO for certain sizes).
|
||||
*
|
||||
* If possible, it will also adjust the size so that it can be
|
||||
* handled in just a single request.
|
||||
*
|
||||
* Returns the improved size, which might be unmodified.
|
||||
*/
|
||||
unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz)
|
||||
{
|
||||
unsigned int orig_sz;
|
||||
unsigned int blk_sz, byte_sz;
|
||||
unsigned chunk_sz;
|
||||
|
||||
orig_sz = sz;
|
||||
|
||||
/*
|
||||
* Do a first check with the controller, in case it
|
||||
* wants to increase the size up to a point where it
|
||||
* might need more than one block.
|
||||
*/
|
||||
sz = mmc_align_data_size(func->card, sz);
|
||||
|
||||
/*
|
||||
* If we can still do this with just a byte transfer, then
|
||||
* we're done.
|
||||
*/
|
||||
if (sz <= sdio_max_byte_size(func))
|
||||
return sz;
|
||||
|
||||
if (func->card->cccr.multi_block) {
|
||||
/*
|
||||
* Check if the transfer is already block aligned
|
||||
*/
|
||||
if ((sz % func->cur_blksize) == 0)
|
||||
return sz;
|
||||
|
||||
/*
|
||||
* Realign it so that it can be done with one request,
|
||||
* and recheck if the controller still likes it.
|
||||
*/
|
||||
blk_sz = ((sz + func->cur_blksize - 1) /
|
||||
func->cur_blksize) * func->cur_blksize;
|
||||
blk_sz = mmc_align_data_size(func->card, blk_sz);
|
||||
|
||||
/*
|
||||
* This value is only good if it is still just
|
||||
* one request.
|
||||
*/
|
||||
if ((blk_sz % func->cur_blksize) == 0)
|
||||
return blk_sz;
|
||||
|
||||
/*
|
||||
* We failed to do one request, but at least try to
|
||||
* pad the remainder properly.
|
||||
*/
|
||||
byte_sz = mmc_align_data_size(func->card,
|
||||
sz % func->cur_blksize);
|
||||
if (byte_sz <= sdio_max_byte_size(func)) {
|
||||
blk_sz = sz / func->cur_blksize;
|
||||
return blk_sz * func->cur_blksize + byte_sz;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We need multiple requests, so first check that the
|
||||
* controller can handle the chunk size;
|
||||
*/
|
||||
chunk_sz = mmc_align_data_size(func->card,
|
||||
sdio_max_byte_size(func));
|
||||
if (chunk_sz == sdio_max_byte_size(func)) {
|
||||
/*
|
||||
* Fix up the size of the remainder (if any)
|
||||
*/
|
||||
byte_sz = orig_sz % chunk_sz;
|
||||
if (byte_sz) {
|
||||
byte_sz = mmc_align_data_size(func->card,
|
||||
byte_sz);
|
||||
}
|
||||
|
||||
return (orig_sz / chunk_sz) * chunk_sz + byte_sz;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The controller is simply incapable of transferring the size
|
||||
* we want in decent manner, so just return the original size.
|
||||
*/
|
||||
return orig_sz;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdio_align_size);
|
||||
|
||||
/* Split an arbitrarily sized data transfer into several
|
||||
* IO_RW_EXTENDED commands. */
|
||||
static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
|
||||
@@ -199,14 +300,13 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
|
||||
int ret;
|
||||
|
||||
/* Do the bulk of the transfer using block mode (if supported). */
|
||||
if (func->card->cccr.multi_block) {
|
||||
if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
|
||||
/* Blocks per command is limited by host count, host transfer
|
||||
* size (we only use a single sg entry) and the maximum for
|
||||
* IO_RW_EXTENDED of 511 blocks. */
|
||||
max_blocks = min(min(
|
||||
func->card->host->max_blk_count,
|
||||
func->card->host->max_seg_size / func->cur_blksize),
|
||||
511u);
|
||||
max_blocks = min(func->card->host->max_blk_count,
|
||||
func->card->host->max_seg_size / func->cur_blksize);
|
||||
max_blocks = min(max_blocks, 511u);
|
||||
|
||||
while (remainder > func->cur_blksize) {
|
||||
unsigned blocks;
|
||||
@@ -231,11 +331,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
|
||||
|
||||
/* Write the remainder using byte mode. */
|
||||
while (remainder > 0) {
|
||||
size = remainder;
|
||||
if (size > func->cur_blksize)
|
||||
size = func->cur_blksize;
|
||||
if (size > 512)
|
||||
size = 512; /* maximum size for byte mode */
|
||||
size = min(remainder, sdio_max_byte_size(func));
|
||||
|
||||
ret = mmc_io_rw_extended(func->card, write, func->num, addr,
|
||||
incr_addr, buf, 1, size);
|
||||
@@ -260,11 +356,10 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
|
||||
* function. If there is a problem reading the address, 0xff
|
||||
* is returned and @err_ret will contain the error code.
|
||||
*/
|
||||
unsigned char sdio_readb(struct sdio_func *func, unsigned int addr,
|
||||
int *err_ret)
|
||||
u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret)
|
||||
{
|
||||
int ret;
|
||||
unsigned char val;
|
||||
u8 val;
|
||||
|
||||
BUG_ON(!func);
|
||||
|
||||
@@ -293,8 +388,7 @@ EXPORT_SYMBOL_GPL(sdio_readb);
|
||||
* function. @err_ret will contain the status of the actual
|
||||
* transfer.
|
||||
*/
|
||||
void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
|
||||
int *err_ret)
|
||||
void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -355,7 +449,6 @@ int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr,
|
||||
{
|
||||
return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(sdio_readsb);
|
||||
|
||||
/**
|
||||
@@ -385,8 +478,7 @@ EXPORT_SYMBOL_GPL(sdio_writesb);
|
||||
* function. If there is a problem reading the address, 0xffff
|
||||
* is returned and @err_ret will contain the error code.
|
||||
*/
|
||||
unsigned short sdio_readw(struct sdio_func *func, unsigned int addr,
|
||||
int *err_ret)
|
||||
u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -400,7 +492,7 @@ unsigned short sdio_readw(struct sdio_func *func, unsigned int addr,
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
return le16_to_cpu(*(u16*)func->tmpbuf);
|
||||
return le16_to_cpup((__le16 *)func->tmpbuf);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdio_readw);
|
||||
|
||||
@@ -415,12 +507,11 @@ EXPORT_SYMBOL_GPL(sdio_readw);
|
||||
* function. @err_ret will contain the status of the actual
|
||||
* transfer.
|
||||
*/
|
||||
void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr,
|
||||
int *err_ret)
|
||||
void sdio_writew(struct sdio_func *func, u16 b, unsigned int addr, int *err_ret)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*(u16*)func->tmpbuf = cpu_to_le16(b);
|
||||
*(__le16 *)func->tmpbuf = cpu_to_le16(b);
|
||||
|
||||
ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2);
|
||||
if (err_ret)
|
||||
@@ -439,8 +530,7 @@ EXPORT_SYMBOL_GPL(sdio_writew);
|
||||
* 0xffffffff is returned and @err_ret will contain the error
|
||||
* code.
|
||||
*/
|
||||
unsigned long sdio_readl(struct sdio_func *func, unsigned int addr,
|
||||
int *err_ret)
|
||||
u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -454,7 +544,7 @@ unsigned long sdio_readl(struct sdio_func *func, unsigned int addr,
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return le32_to_cpu(*(u32*)func->tmpbuf);
|
||||
return le32_to_cpup((__le32 *)func->tmpbuf);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdio_readl);
|
||||
|
||||
@@ -469,12 +559,11 @@ EXPORT_SYMBOL_GPL(sdio_readl);
|
||||
* function. @err_ret will contain the status of the actual
|
||||
* transfer.
|
||||
*/
|
||||
void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr,
|
||||
int *err_ret)
|
||||
void sdio_writel(struct sdio_func *func, u32 b, unsigned int addr, int *err_ret)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*(u32*)func->tmpbuf = cpu_to_le32(b);
|
||||
*(__le32 *)func->tmpbuf = cpu_to_le32(b);
|
||||
|
||||
ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4);
|
||||
if (err_ret)
|
||||
|
||||
@@ -26,18 +26,31 @@ config MMC_PXA
|
||||
|
||||
config MMC_SDHCI
|
||||
tristate "Secure Digital Host Controller Interface support"
|
||||
depends on PCI
|
||||
depends on HAS_DMA
|
||||
help
|
||||
This select the generic Secure Digital Host Controller Interface.
|
||||
This selects the generic Secure Digital Host Controller Interface.
|
||||
It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
|
||||
and Toshiba(R). Most controllers found in laptops are of this type.
|
||||
|
||||
If you have a controller with this interface, say Y or M here. You
|
||||
also need to enable an appropriate bus interface.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_SDHCI_PCI
|
||||
tristate "SDHCI support on PCI bus"
|
||||
depends on MMC_SDHCI && PCI
|
||||
help
|
||||
This selects the PCI Secure Digital Host Controller Interface.
|
||||
Most controllers found today are PCI devices.
|
||||
|
||||
If you have a controller with this interface, say Y or M here.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_RICOH_MMC
|
||||
tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
|
||||
depends on PCI && EXPERIMENTAL && MMC_SDHCI
|
||||
depends on MMC_SDHCI_PCI
|
||||
help
|
||||
This selects the disabler for the Ricoh MMC Controller. This
|
||||
proprietary controller is unnecessary because the SDHCI driver
|
||||
@@ -91,6 +104,16 @@ config MMC_AT91
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_ATMELMCI
|
||||
tristate "Atmel Multimedia Card Interface support"
|
||||
depends on AVR32
|
||||
help
|
||||
This selects the Atmel Multimedia Card Interface driver. If
|
||||
you have an AT32 (AVR32) platform with a Multimedia Card
|
||||
slot, say Y or M here.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_IMX
|
||||
tristate "Motorola i.MX Multimedia Card Interface support"
|
||||
depends on ARCH_IMX
|
||||
@@ -130,3 +153,24 @@ config MMC_SPI
|
||||
|
||||
If unsure, or if your system has no SPI master driver, say N.
|
||||
|
||||
config MMC_S3C
|
||||
tristate "Samsung S3C SD/MMC Card Interface support"
|
||||
depends on ARCH_S3C2410 && MMC
|
||||
help
|
||||
This selects a driver for the MCI interface found in
|
||||
Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
|
||||
If you have a board based on one of those and a MMC/SD
|
||||
slot, say Y or M here.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_SDRICOH_CS
|
||||
tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && MMC && PCI && PCMCIA
|
||||
help
|
||||
Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
|
||||
card whenever you insert a MMC or SD card into the card slot.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called sdricoh_cs.
|
||||
|
||||
|
||||
@@ -10,11 +10,15 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
|
||||
obj-$(CONFIG_MMC_PXA) += pxamci.o
|
||||
obj-$(CONFIG_MMC_IMX) += imxmmc.o
|
||||
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
|
||||
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
|
||||
obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o
|
||||
obj-$(CONFIG_MMC_WBSD) += wbsd.o
|
||||
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
|
||||
obj-$(CONFIG_MMC_OMAP) += omap.o
|
||||
obj-$(CONFIG_MMC_AT91) += at91_mci.o
|
||||
obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o
|
||||
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
|
||||
obj-$(CONFIG_MMC_SPI) += mmc_spi.o
|
||||
obj-$(CONFIG_MMC_S3C) += s3cmci.o
|
||||
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
|
||||
|
||||
|
||||
+208
-51
@@ -125,8 +125,71 @@ struct at91mci_host
|
||||
|
||||
/* Latest in the scatterlist that has been enabled for transfer */
|
||||
int transfer_index;
|
||||
|
||||
/* Timer for timeouts */
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
/*
|
||||
* Reset the controller and restore most of the state
|
||||
*/
|
||||
static void at91_reset_host(struct at91mci_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 mr;
|
||||
u32 sdcr;
|
||||
u32 dtor;
|
||||
u32 imr;
|
||||
|
||||
local_irq_save(flags);
|
||||
imr = at91_mci_read(host, AT91_MCI_IMR);
|
||||
|
||||
at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
|
||||
|
||||
/* save current state */
|
||||
mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;
|
||||
sdcr = at91_mci_read(host, AT91_MCI_SDCR);
|
||||
dtor = at91_mci_read(host, AT91_MCI_DTOR);
|
||||
|
||||
/* reset the controller */
|
||||
at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
|
||||
|
||||
/* restore state */
|
||||
at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
|
||||
at91_mci_write(host, AT91_MCI_MR, mr);
|
||||
at91_mci_write(host, AT91_MCI_SDCR, sdcr);
|
||||
at91_mci_write(host, AT91_MCI_DTOR, dtor);
|
||||
at91_mci_write(host, AT91_MCI_IER, imr);
|
||||
|
||||
/* make sure sdio interrupts will fire */
|
||||
at91_mci_read(host, AT91_MCI_SR);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void at91_timeout_timer(unsigned long data)
|
||||
{
|
||||
struct at91mci_host *host;
|
||||
|
||||
host = (struct at91mci_host *)data;
|
||||
|
||||
if (host->request) {
|
||||
dev_err(host->mmc->parent, "Timeout waiting end of packet\n");
|
||||
|
||||
if (host->cmd && host->cmd->data) {
|
||||
host->cmd->data->error = -ETIMEDOUT;
|
||||
} else {
|
||||
if (host->cmd)
|
||||
host->cmd->error = -ETIMEDOUT;
|
||||
else
|
||||
host->request->cmd->error = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
at91_reset_host(host);
|
||||
mmc_request_done(host->mmc, host->request);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy from sg to a dma block - used for transfers
|
||||
*/
|
||||
@@ -135,9 +198,14 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
|
||||
unsigned int len, i, size;
|
||||
unsigned *dmabuf = host->buffer;
|
||||
|
||||
size = host->total_length;
|
||||
size = data->blksz * data->blocks;
|
||||
len = data->sg_len;
|
||||
|
||||
/* AT91SAM926[0/3] Data Write Operation and number of bytes erratum */
|
||||
if (cpu_is_at91sam9260() || cpu_is_at91sam9263())
|
||||
if (host->total_length == 12)
|
||||
memset(dmabuf, 0, 12);
|
||||
|
||||
/*
|
||||
* Just loop through all entries. Size might not
|
||||
* be the entire list though so make sure that
|
||||
@@ -159,9 +227,10 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
|
||||
|
||||
for (index = 0; index < (amount / 4); index++)
|
||||
*dmabuf++ = swab32(sgbuffer[index]);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
memcpy(dmabuf, sgbuffer, amount);
|
||||
dmabuf += amount;
|
||||
}
|
||||
|
||||
kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
|
||||
|
||||
@@ -233,11 +302,11 @@ static void at91_mci_pre_dma_read(struct at91mci_host *host)
|
||||
|
||||
if (i == 0) {
|
||||
at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address);
|
||||
at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4);
|
||||
at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ? sg->length : sg->length / 4);
|
||||
}
|
||||
else {
|
||||
at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address);
|
||||
at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4);
|
||||
at91_mci_write(host, ATMEL_PDC_RNCR, (data->blksz & 0x3) ? sg->length : sg->length / 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,8 +346,6 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
|
||||
|
||||
dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
|
||||
|
||||
data->bytes_xfered += sg->length;
|
||||
|
||||
if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
|
||||
unsigned int *buffer;
|
||||
int index;
|
||||
@@ -294,6 +361,8 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
|
||||
}
|
||||
|
||||
flush_dcache_page(sg_page(sg));
|
||||
|
||||
data->bytes_xfered += sg->length;
|
||||
}
|
||||
|
||||
/* Is there another transfer to trigger? */
|
||||
@@ -334,10 +403,32 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
|
||||
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
|
||||
} else
|
||||
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
|
||||
|
||||
data->bytes_xfered = host->total_length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update bytes tranfered count during a write operation
|
||||
*/
|
||||
static void at91_mci_update_bytes_xfered(struct at91mci_host *host)
|
||||
{
|
||||
struct mmc_data *data;
|
||||
|
||||
/* always deal with the effective request (and not the current cmd) */
|
||||
|
||||
if (host->request->cmd && host->request->cmd->error != 0)
|
||||
return;
|
||||
|
||||
if (host->request->data) {
|
||||
data = host->request->data;
|
||||
if (data->flags & MMC_DATA_WRITE) {
|
||||
/* card is in IDLE mode now */
|
||||
pr_debug("-> bytes_xfered %d, total_length = %d\n",
|
||||
data->bytes_xfered, host->total_length);
|
||||
data->bytes_xfered = data->blksz * data->blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*Handle after command sent ready*/
|
||||
static int at91_mci_handle_cmdrdy(struct at91mci_host *host)
|
||||
{
|
||||
@@ -350,8 +441,7 @@ static int at91_mci_handle_cmdrdy(struct at91mci_host *host)
|
||||
} else return 1;
|
||||
} else if (host->cmd->data->flags & MMC_DATA_WRITE) {
|
||||
/*After sendding multi-block-write command, start DMA transfer*/
|
||||
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE);
|
||||
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
|
||||
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE | AT91_MCI_BLKE);
|
||||
at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
|
||||
}
|
||||
|
||||
@@ -430,11 +520,19 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
|
||||
|
||||
if (data) {
|
||||
|
||||
if ( data->blksz & 0x3 ) {
|
||||
pr_debug("Unsupported block size\n");
|
||||
cmd->error = -EINVAL;
|
||||
mmc_request_done(host->mmc, host->request);
|
||||
return;
|
||||
if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) {
|
||||
if (data->blksz & 0x3) {
|
||||
pr_debug("Unsupported block size\n");
|
||||
cmd->error = -EINVAL;
|
||||
mmc_request_done(host->mmc, host->request);
|
||||
return;
|
||||
}
|
||||
if (data->flags & MMC_DATA_STREAM) {
|
||||
pr_debug("Stream commands not supported\n");
|
||||
cmd->error = -EINVAL;
|
||||
mmc_request_done(host->mmc, host->request);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
block_length = data->blksz;
|
||||
@@ -481,8 +579,16 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
|
||||
ier = AT91_MCI_CMDRDY;
|
||||
} else {
|
||||
/* zero block length and PDC mode */
|
||||
mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;
|
||||
at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
|
||||
mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff;
|
||||
mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0;
|
||||
mr |= (block_length << 16);
|
||||
mr |= AT91_MCI_PDCMODE;
|
||||
at91_mci_write(host, AT91_MCI_MR, mr);
|
||||
|
||||
if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261()))
|
||||
at91_mci_write(host, AT91_MCI_BLKR,
|
||||
AT91_MCI_BLKR_BCNT(blocks) |
|
||||
AT91_MCI_BLKR_BLKLEN(block_length));
|
||||
|
||||
/*
|
||||
* Disable the PDC controller
|
||||
@@ -508,6 +614,13 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
|
||||
* Handle a write
|
||||
*/
|
||||
host->total_length = block_length * blocks;
|
||||
/*
|
||||
* AT91SAM926[0/3] Data Write Operation and
|
||||
* number of bytes erratum
|
||||
*/
|
||||
if (cpu_is_at91sam9260 () || cpu_is_at91sam9263())
|
||||
if (host->total_length < 12)
|
||||
host->total_length = 12;
|
||||
host->buffer = dma_alloc_coherent(NULL,
|
||||
host->total_length,
|
||||
&host->physical_address, GFP_KERNEL);
|
||||
@@ -517,7 +630,9 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
|
||||
pr_debug("Transmitting %d bytes\n", host->total_length);
|
||||
|
||||
at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
|
||||
at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);
|
||||
at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ?
|
||||
host->total_length : host->total_length / 4);
|
||||
|
||||
ier = AT91_MCI_CMDRDY;
|
||||
}
|
||||
}
|
||||
@@ -552,20 +667,26 @@ static void at91_mci_process_next(struct at91mci_host *host)
|
||||
else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
|
||||
host->flags |= FL_SENT_STOP;
|
||||
at91_mci_send_command(host, host->request->stop);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
del_timer(&host->timer);
|
||||
/* the at91rm9200 mci controller hangs after some transfers,
|
||||
* and the workaround is to reset it after each transfer.
|
||||
*/
|
||||
if (cpu_is_at91rm9200())
|
||||
at91_reset_host(host);
|
||||
mmc_request_done(host->mmc, host->request);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a command that has been completed
|
||||
*/
|
||||
static void at91_mci_completed_command(struct at91mci_host *host)
|
||||
static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status)
|
||||
{
|
||||
struct mmc_command *cmd = host->cmd;
|
||||
unsigned int status;
|
||||
struct mmc_data *data = cmd->data;
|
||||
|
||||
at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
|
||||
at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
|
||||
|
||||
cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
|
||||
cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
|
||||
@@ -577,25 +698,34 @@ static void at91_mci_completed_command(struct at91mci_host *host)
|
||||
host->buffer = NULL;
|
||||
}
|
||||
|
||||
status = at91_mci_read(host, AT91_MCI_SR);
|
||||
|
||||
pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
|
||||
status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
|
||||
pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n",
|
||||
status, at91_mci_read(host, AT91_MCI_SR),
|
||||
cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
|
||||
|
||||
if (status & AT91_MCI_ERRORS) {
|
||||
if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
|
||||
cmd->error = 0;
|
||||
}
|
||||
else {
|
||||
if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
|
||||
cmd->error = -ETIMEDOUT;
|
||||
else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
|
||||
cmd->error = -EILSEQ;
|
||||
else
|
||||
cmd->error = -EIO;
|
||||
if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) {
|
||||
if (data) {
|
||||
if (status & AT91_MCI_DTOE)
|
||||
data->error = -ETIMEDOUT;
|
||||
else if (status & AT91_MCI_DCRCE)
|
||||
data->error = -EILSEQ;
|
||||
}
|
||||
} else {
|
||||
if (status & AT91_MCI_RTOE)
|
||||
cmd->error = -ETIMEDOUT;
|
||||
else if (status & AT91_MCI_RCRCE)
|
||||
cmd->error = -EILSEQ;
|
||||
else
|
||||
cmd->error = -EIO;
|
||||
}
|
||||
|
||||
pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",
|
||||
cmd->error, cmd->opcode, cmd->retries);
|
||||
pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n",
|
||||
cmd->error, data ? data->error : 0,
|
||||
cmd->opcode, cmd->retries);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -613,6 +743,8 @@ static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
host->request = mrq;
|
||||
host->flags = 0;
|
||||
|
||||
mod_timer(&host->timer, jiffies + HZ);
|
||||
|
||||
at91_mci_process_next(host);
|
||||
}
|
||||
|
||||
@@ -736,6 +868,7 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
|
||||
|
||||
if (int_status & AT91_MCI_NOTBUSY) {
|
||||
pr_debug("Card is ready\n");
|
||||
at91_mci_update_bytes_xfered(host);
|
||||
completed = 1;
|
||||
}
|
||||
|
||||
@@ -744,9 +877,21 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
|
||||
|
||||
if (int_status & AT91_MCI_BLKE) {
|
||||
pr_debug("Block transfer has ended\n");
|
||||
completed = 1;
|
||||
if (host->request->data && host->request->data->blocks > 1) {
|
||||
/* multi block write : complete multi write
|
||||
* command and send stop */
|
||||
completed = 1;
|
||||
} else {
|
||||
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & AT91_MCI_SDIOIRQA)
|
||||
mmc_signal_sdio_irq(host->mmc);
|
||||
|
||||
if (int_status & AT91_MCI_SDIOIRQB)
|
||||
mmc_signal_sdio_irq(host->mmc);
|
||||
|
||||
if (int_status & AT91_MCI_TXRDY)
|
||||
pr_debug("Ready to transmit\n");
|
||||
|
||||
@@ -761,10 +906,10 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
|
||||
|
||||
if (completed) {
|
||||
pr_debug("Completed command\n");
|
||||
at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
|
||||
at91_mci_completed_command(host);
|
||||
at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
|
||||
at91_mci_completed_command(host, int_status);
|
||||
} else
|
||||
at91_mci_write(host, AT91_MCI_IDR, int_status);
|
||||
at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -793,25 +938,33 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
|
||||
|
||||
static int at91_mci_get_ro(struct mmc_host *mmc)
|
||||
{
|
||||
int read_only = 0;
|
||||
struct at91mci_host *host = mmc_priv(mmc);
|
||||
|
||||
if (host->board->wp_pin) {
|
||||
read_only = gpio_get_value(host->board->wp_pin);
|
||||
printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc),
|
||||
(read_only ? "read-only" : "read-write") );
|
||||
}
|
||||
else {
|
||||
printk(KERN_WARNING "%s: host does not support reading read-only "
|
||||
"switch. Assuming write-enable.\n", mmc_hostname(mmc));
|
||||
}
|
||||
return read_only;
|
||||
if (host->board->wp_pin)
|
||||
return !!gpio_get_value(host->board->wp_pin);
|
||||
/*
|
||||
* Board doesn't support read only detection; let the mmc core
|
||||
* decide what to do.
|
||||
*/
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static void at91_mci_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||||
{
|
||||
struct at91mci_host *host = mmc_priv(mmc);
|
||||
|
||||
pr_debug("%s: sdio_irq %c : %s\n", mmc_hostname(host->mmc),
|
||||
host->board->slot_b ? 'B':'A', enable ? "enable" : "disable");
|
||||
at91_mci_write(host, enable ? AT91_MCI_IER : AT91_MCI_IDR,
|
||||
host->board->slot_b ? AT91_MCI_SDIOIRQB : AT91_MCI_SDIOIRQA);
|
||||
|
||||
}
|
||||
|
||||
static const struct mmc_host_ops at91_mci_ops = {
|
||||
.request = at91_mci_request,
|
||||
.set_ios = at91_mci_set_ios,
|
||||
.get_ro = at91_mci_get_ro,
|
||||
.enable_sdio_irq = at91_mci_enable_sdio_irq,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -842,6 +995,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
|
||||
mmc->f_min = 375000;
|
||||
mmc->f_max = 25000000;
|
||||
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||
mmc->caps = MMC_CAP_SDIO_IRQ;
|
||||
|
||||
mmc->max_blk_size = 4095;
|
||||
mmc->max_blk_count = mmc->max_req_size;
|
||||
@@ -935,6 +1089,8 @@ static int __init at91_mci_probe(struct platform_device *pdev)
|
||||
|
||||
mmc_add_host(mmc);
|
||||
|
||||
setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host);
|
||||
|
||||
/*
|
||||
* monitor card insertion/removal if we can
|
||||
*/
|
||||
@@ -995,6 +1151,7 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
at91_mci_disable(host);
|
||||
del_timer_sync(&host->timer);
|
||||
mmc_remove_host(mmc);
|
||||
free_irq(host->irq, host);
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Atmel MultiMedia Card Interface driver
|
||||
*
|
||||
* Copyright (C) 2004-2006 Atmel Corporation
|
||||
*
|
||||
* 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 __DRIVERS_MMC_ATMEL_MCI_H__
|
||||
#define __DRIVERS_MMC_ATMEL_MCI_H__
|
||||
|
||||
/* MCI Register Definitions */
|
||||
#define MCI_CR 0x0000 /* Control */
|
||||
# define MCI_CR_MCIEN ( 1 << 0) /* MCI Enable */
|
||||
# define MCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */
|
||||
# define MCI_CR_SWRST ( 1 << 7) /* Software Reset */
|
||||
#define MCI_MR 0x0004 /* Mode */
|
||||
# define MCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */
|
||||
# define MCI_MR_RDPROOF ( 1 << 11) /* Read Proof */
|
||||
# define MCI_MR_WRPROOF ( 1 << 12) /* Write Proof */
|
||||
#define MCI_DTOR 0x0008 /* Data Timeout */
|
||||
# define MCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */
|
||||
# define MCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */
|
||||
#define MCI_SDCR 0x000c /* SD Card / SDIO */
|
||||
# define MCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */
|
||||
# define MCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */
|
||||
# define MCI_SDCBUS_1BIT ( 0 << 7) /* 1-bit data bus */
|
||||
# define MCI_SDCBUS_4BIT ( 1 << 7) /* 4-bit data bus */
|
||||
#define MCI_ARGR 0x0010 /* Command Argument */
|
||||
#define MCI_CMDR 0x0014 /* Command */
|
||||
# define MCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */
|
||||
# define MCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */
|
||||
# define MCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */
|
||||
# define MCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */
|
||||
# define MCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */
|
||||
# define MCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */
|
||||
# define MCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */
|
||||
# define MCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */
|
||||
# define MCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */
|
||||
# define MCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */
|
||||
# define MCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */
|
||||
# define MCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */
|
||||
# define MCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */
|
||||
# define MCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */
|
||||
# define MCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */
|
||||
# define MCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */
|
||||
# define MCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */
|
||||
# define MCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */
|
||||
# define MCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */
|
||||
# define MCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */
|
||||
# define MCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */
|
||||
# define MCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */
|
||||
#define MCI_BLKR 0x0018 /* Block */
|
||||
# define MCI_BCNT(x) ((x) << 0) /* Data Block Count */
|
||||
# define MCI_BLKLEN(x) ((x) << 16) /* Data Block Length */
|
||||
#define MCI_RSPR 0x0020 /* Response 0 */
|
||||
#define MCI_RSPR1 0x0024 /* Response 1 */
|
||||
#define MCI_RSPR2 0x0028 /* Response 2 */
|
||||
#define MCI_RSPR3 0x002c /* Response 3 */
|
||||
#define MCI_RDR 0x0030 /* Receive Data */
|
||||
#define MCI_TDR 0x0034 /* Transmit Data */
|
||||
#define MCI_SR 0x0040 /* Status */
|
||||
#define MCI_IER 0x0044 /* Interrupt Enable */
|
||||
#define MCI_IDR 0x0048 /* Interrupt Disable */
|
||||
#define MCI_IMR 0x004c /* Interrupt Mask */
|
||||
# define MCI_CMDRDY ( 1 << 0) /* Command Ready */
|
||||
# define MCI_RXRDY ( 1 << 1) /* Receiver Ready */
|
||||
# define MCI_TXRDY ( 1 << 2) /* Transmitter Ready */
|
||||
# define MCI_BLKE ( 1 << 3) /* Data Block Ended */
|
||||
# define MCI_DTIP ( 1 << 4) /* Data Transfer In Progress */
|
||||
# define MCI_NOTBUSY ( 1 << 5) /* Data Not Busy */
|
||||
# define MCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */
|
||||
# define MCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */
|
||||
# define MCI_RINDE ( 1 << 16) /* Response Index Error */
|
||||
# define MCI_RDIRE ( 1 << 17) /* Response Direction Error */
|
||||
# define MCI_RCRCE ( 1 << 18) /* Response CRC Error */
|
||||
# define MCI_RENDE ( 1 << 19) /* Response End Bit Error */
|
||||
# define MCI_RTOE ( 1 << 20) /* Response Time-Out Error */
|
||||
# define MCI_DCRCE ( 1 << 21) /* Data CRC Error */
|
||||
# define MCI_DTOE ( 1 << 22) /* Data Time-Out Error */
|
||||
# define MCI_OVRE ( 1 << 30) /* RX Overrun Error */
|
||||
# define MCI_UNRE ( 1 << 31) /* TX Underrun Error */
|
||||
|
||||
/* Register access macros */
|
||||
#define mci_readl(port,reg) \
|
||||
__raw_readl((port)->regs + MCI_##reg)
|
||||
#define mci_writel(port,reg,value) \
|
||||
__raw_writel((value), (port)->regs + MCI_##reg)
|
||||
|
||||
#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
+485
-339
File diff suppressed because it is too large
Load Diff
@@ -1,96 +0,0 @@
|
||||
#ifndef _AU1XMMC_H_
|
||||
#define _AU1XMMC_H_
|
||||
|
||||
/* Hardware definitions */
|
||||
|
||||
#define AU1XMMC_DESCRIPTOR_COUNT 1
|
||||
#define AU1XMMC_DESCRIPTOR_SIZE 2048
|
||||
|
||||
#define AU1XMMC_OCR ( MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \
|
||||
MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \
|
||||
MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
|
||||
|
||||
/* Easy access macros */
|
||||
|
||||
#define HOST_STATUS(h) ((h)->iobase + SD_STATUS)
|
||||
#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG)
|
||||
#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE)
|
||||
#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT)
|
||||
#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT)
|
||||
#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG)
|
||||
#define HOST_BLKSIZE(h) ((h)->iobase + SD_BLKSIZE)
|
||||
#define HOST_CMD(h) ((h)->iobase + SD_CMD)
|
||||
#define HOST_CONFIG2(h) ((h)->iobase + SD_CONFIG2)
|
||||
#define HOST_TIMEOUT(h) ((h)->iobase + SD_TIMEOUT)
|
||||
#define HOST_DEBUG(h) ((h)->iobase + SD_DEBUG)
|
||||
|
||||
#define DMA_CHANNEL(h) \
|
||||
( ((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan)
|
||||
|
||||
/* This gives us a hard value for the stop command that we can write directly
|
||||
* to the command register
|
||||
*/
|
||||
|
||||
#define STOP_CMD (SD_CMD_RT_1B|SD_CMD_CT_7|(0xC << SD_CMD_CI_SHIFT)|SD_CMD_GO)
|
||||
|
||||
/* This is the set of interrupts that we configure by default */
|
||||
|
||||
#if 0
|
||||
#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_DD | \
|
||||
SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
|
||||
#endif
|
||||
|
||||
#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | \
|
||||
SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
|
||||
/* The poll event (looking for insert/remove events runs twice a second */
|
||||
#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
|
||||
|
||||
struct au1xmmc_host {
|
||||
struct mmc_host *mmc;
|
||||
struct mmc_request *mrq;
|
||||
|
||||
u32 id;
|
||||
|
||||
u32 flags;
|
||||
u32 iobase;
|
||||
u32 clock;
|
||||
u32 bus_width;
|
||||
u32 power_mode;
|
||||
|
||||
int status;
|
||||
|
||||
struct {
|
||||
int len;
|
||||
int dir;
|
||||
} dma;
|
||||
|
||||
struct {
|
||||
int index;
|
||||
int offset;
|
||||
int len;
|
||||
} pio;
|
||||
|
||||
u32 tx_chan;
|
||||
u32 rx_chan;
|
||||
|
||||
struct timer_list timer;
|
||||
struct tasklet_struct finish_task;
|
||||
struct tasklet_struct data_task;
|
||||
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/* Status flags used by the host structure */
|
||||
|
||||
#define HOST_F_XMIT 0x0001
|
||||
#define HOST_F_RECV 0x0002
|
||||
#define HOST_F_DMA 0x0010
|
||||
#define HOST_F_ACTIVE 0x0100
|
||||
#define HOST_F_STOP 0x1000
|
||||
|
||||
#define HOST_S_IDLE 0x0001
|
||||
#define HOST_S_CMD 0x0002
|
||||
#define HOST_S_DATA 0x0003
|
||||
#define HOST_S_STOP 0x0004
|
||||
|
||||
#endif
|
||||
@@ -892,9 +892,12 @@ static int imxmci_get_ro(struct mmc_host *mmc)
|
||||
struct imxmci_host *host = mmc_priv(mmc);
|
||||
|
||||
if (host->pdata && host->pdata->get_ro)
|
||||
return host->pdata->get_ro(mmc_dev(mmc));
|
||||
/* Host doesn't support read only detection so assume writeable */
|
||||
return 0;
|
||||
return !!host->pdata->get_ro(mmc_dev(mmc));
|
||||
/*
|
||||
* Board doesn't support read only detection; let the mmc core
|
||||
* decide what to do.
|
||||
*/
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user