Commit 4014a6be authored by David Brownell's avatar David Brownell Committed by Tony Lindgren

[PATCH] ARM: OMAP: MMC initialization

This updates the MMC initialization:

  - OMAP_TAG_MMC updates:
      * Re-factor contents into one struct per silicon block
      * Provide information that's useful for SD support, like whether
	the board is wired for 4-wire transfers and what gpio (if any)
	is used to sense the writeprotect slider.
      * Allows for "nonstandard" muxing options, which would mostly
	affect boards using MMC2.
      * Report whether the MMC switch should use the card detect model,
	or the cover switch model.
      * Updated/tested board config only for H2 (not H3 or VoiceBlue).

  - MMC device initialization moved into mach-omap/omap1/device.c and
    out of the MMC driver itself.

  - Removed the "what MMC blocks to configure" option from Kconfig;
    the board-specific MMC tag holds this info (and more).

This new device init hook should be easy to reuse to set up any of the
other integrated devices.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
parent 958fb2d8
......@@ -3,7 +3,7 @@
#
# Common support
obj-y := io.o id.o irq.o time.o serial.o
obj-y := io.o id.o irq.o time.o serial.o devices.o
led-y := leds.o
# Specific board support
......
......@@ -33,6 +33,7 @@
#include <asm/mach/map.h>
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
#include <asm/arch/usb.h>
......@@ -151,9 +152,13 @@ static struct omap_usb_config h2_usb_config __initdata = {
};
static struct omap_mmc_config h2_mmc_config __initdata = {
.mmc_blocks = 1,
.mmc1_power_pin = -1, /* tps65010 gpio3 */
.mmc1_switch_pin = OMAP_MPUIO(1),
.mmc [0] = {
.enabled = 1,
.wire4 = 1,
.wp_pin = OMAP_MPUIO(3),
.power_pin = -1, /* tps65010 gpio3 */
.switch_pin = OMAP_MPUIO(1),
},
};
static struct omap_board_config_kernel h2_config[] = {
......@@ -169,6 +174,10 @@ static void __init h2_init(void)
h2_flash_resource.end = h2_flash_resource.start = omap_cs3_phys();
h2_flash_resource.end += SZ_32M - 1;
/* MMC: card detect and WP */
// omap_cfg_reg(U19_ARMIO1); /* CD */
omap_cfg_reg(BALLOUT_V8_ARMIO3); /* WP */
platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
omap_board_config = h2_config;
omap_board_config_size = ARRAY_SIZE(h2_config);
......
......@@ -161,10 +161,12 @@ static struct omap_usb_config h3_usb_config __initdata = {
.pins[1] = 3,
};
static struct omap_mmc_config h3_mmc_config __initdata_or_module = {
.mmc_blocks = 1,
.mmc1_power_pin = -1, /* tps65010 GPIO4 */
.mmc1_switch_pin = OMAP_MPUIO(1),
static struct omap_mmc_config h3_mmc_config __initdata = {
.mmc[0] = {
.enabled = 1,
.power_pin = -1, /* tps65010 GPIO4 */
.switch_pin = OMAP_MPUIO(1),
},
};
static struct omap_board_config_kernel h3_config[] = {
......
......@@ -144,9 +144,11 @@ static struct omap_usb_config voiceblue_usb_config __initdata = {
};
static struct omap_mmc_config voiceblue_mmc_config __initdata = {
.mmc_blocks = 1,
.mmc1_power_pin = 2,
.mmc1_switch_pin = -1,
.mmc[0] = {
.enabled = 1,
.power_pin = 2,
.switch_pin = -1,
},
};
static struct omap_boot_reason_config voiceblue_boot_reason;
......
......@@ -77,25 +77,6 @@ config MMC_OMAP
If unsure, say N.
config MMC_OMAP16XX_BLOCK1
boolean "First MMC block on OMAP16XX"
depends on ARCH_OMAP16XX && MMC_OMAP
default y if MACH_OMAP_H2 || MACH_OMAP_H3
help
This enables the first of two MMC blocks on OMAP1610 multimedia
processor. You need to enable the correct block to activate your
MMC slot.
config MMC_OMAP16XX_BLOCK2
boolean "Second MMC block on OMAP16XX"
depends on ARCH_OMAP16XX && MMC_OMAP
default n if MACH_OMAP_H2 || MACH_OMAP_H3
default y
help
This enables the second of two MMC blocks on OMAP1610 multimedia
processor. You need to enable the correct block to activate your
MMC slot.
config MMC_WBSD
tristate "Winbond W83L51xD SD/MMC Card Interface support"
depends on MMC && ISA_DMA_API
......
......@@ -44,8 +44,8 @@
#define DRIVER_NAME "mmci-omap"
#ifdef CONFIG_MMC_DEBUG
//#define DBG(x...) printk(KERN_DEBUG x)
#define DBG(x...) printk(x)
#define DBG(x...) pr_debug(x)
//#define DBG(x...) printk(x)
#else
#define DBG(x...) do { } while (0)
#endif
......@@ -54,11 +54,6 @@
* when the cover switch is open */
#define OMAP_MMC_SWITCH_POLL_DELAY 500
static s16 mmc1_power_pin = -1,
mmc2_power_pin = -1;
static s16 mmc1_switch_pin = -1,
mmc2_switch_pin = -1;
static int mmc_omap_enable_poll = 1;
struct mmc_omap_host {
......@@ -81,17 +76,15 @@ struct mmc_omap_host {
unsigned char datadir;
u16 * buffer;
u32 bytesleft;
int power_pin;
int use_dma, dma_ch;
short power_pin;
short wp_pin;
short use_dma, dma_ch;
struct completion dma_completion;
int switch_pin;
struct work_struct switch_work;
struct timer_list switch_timer;
int switch_last_state;
unsigned char sd_support;
};
static inline int
......@@ -394,11 +387,11 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs)
}
if (status & OMAP_MMC_STAT_CMD_TOUT) {
// Command timeout
/* Timeouts are routine with some commands */
if (host->cmd) {
/* Timeouts are normal in case of MMC_SEND_STATUS */
if (host->cmd->opcode != MMC_ALL_SEND_CID &&
host->cmd->opcode != MMC_SEND_OP_COND &&
host->cmd->opcode != MMC_APP_CMD &&
!mmc_omap_cover_is_open(host))
printk(KERN_ERR "MMC%d: Command timeout, CMD%d\n",
host->id, host->cmd->opcode);
......@@ -417,10 +410,10 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs)
}
if (status & OMAP_MMC_STAT_OCR_BUSY) {
// OCR Busy
if (host->cmd && host->cmd->opcode != MMC_SEND_OP_COND &&
host->cmd->opcode != MMC_SET_RELATIVE_ADDR) {
printk(KERN_DEBUG "MMC%d: OCR busy error, CMD%d\n",
/* OCR Busy ... happens a lot */
if (host->cmd && host->cmd->opcode != MMC_SEND_OP_COND
&& host->cmd->opcode != MMC_SET_RELATIVE_ADDR) {
DBG("MMC%d: OCR busy error, CMD%d\n",
host->id, host->cmd->opcode);
}
}
......@@ -849,6 +842,8 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
dsor = 250;
}
/* REVISIT: if (ios->bus_width == MMC_BUS_WIDTH_4) dsor |= 1 << 15; */
switch (ios->power_mode) {
case MMC_POWER_OFF:
mmc_omap_power(host, 0);
......@@ -887,6 +882,7 @@ static struct mmc_host_ops mmc_omap_ops = {
static int __init mmc_omap_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct omap_mmc_conf *minfo = dev->platform_data;
struct mmc_host *mmc;
struct mmc_omap_host *host = NULL;
int ret = 0;
......@@ -913,7 +909,7 @@ static int __init mmc_omap_probe(struct device *dev)
host = mmc_priv(mmc);
host->mmc = mmc;
host->id = (pdev->resource[0].start == IO_ADDRESS(OMAP_MMC1_BASE)) ? 1 : 2;
host->id = pdev->id;
host->clk = clk_get(dev, (host->id == 1) ? "mmc1_ck" : "mmc2_ck");
if (IS_ERR(host->clk)) {
......@@ -921,46 +917,15 @@ static int __init mmc_omap_probe(struct device *dev)
goto out;
}
if (host->id == 1) {
omap_cfg_reg(MMC_CMD);
omap_cfg_reg(MMC_CLK);
omap_cfg_reg(MMC_DAT0);
if (cpu_is_omap1710()) {
omap_cfg_reg(M15_1710_MMC_CLKI);
omap_cfg_reg(P19_1710_MMC_CMDDIR);
omap_cfg_reg(P20_1710_MMC_DATDIR0);
}
if (host->sd_support) {
omap_cfg_reg(MMC_DAT1);
omap_cfg_reg(MMC_DAT2);
omap_cfg_reg(MMC_DAT3);
}
host->power_pin = mmc1_power_pin;
host->switch_pin = mmc1_switch_pin;
} else {
omap_cfg_reg(Y8_1610_MMC2_CMD);
omap_cfg_reg(Y10_1610_MMC2_CLK);
omap_cfg_reg(R18_1610_MMC2_CLKIN);
omap_cfg_reg(W8_1610_MMC2_DAT0);
if (host->sd_support) {
omap_cfg_reg(V8_1610_MMC2_DAT1);
omap_cfg_reg(W15_1610_MMC2_DAT2);
omap_cfg_reg(R10_1610_MMC2_DAT3);
}
/* These are needed for the level shifter */
omap_cfg_reg(V9_1610_MMC2_CMDDIR);
omap_cfg_reg(V5_1610_MMC2_DATDIR0);
omap_cfg_reg(W19_1610_MMC2_DATDIR1);
host->power_pin = mmc2_power_pin;
host->switch_pin = mmc2_switch_pin;
/* Feedback clock must be set on OMAP-1710 MMC2 */
if (cpu_is_omap1710())
omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
MOD_CONF_CTRL_1);
}
/* REVISIT: SD-only support, when core merged
* - if (minfo->wire4) mmc->caps |= MMC_CAP_4_BIT_DATA;
* - mmc_omap_ops.get_ro uses wp_pin to sense slider
* Also, use minfo->cover to decide how to manage
* the card detect sensing.
*/
host->power_pin = minfo->power_pin;
host->switch_pin = minfo->switch_pin;
host->wp_pin = minfo->wp_pin;
host->use_dma = 1;
host->dma_ch = -1;
......@@ -1122,60 +1087,6 @@ static int mmc_omap_resume(struct device *dev, u32 level)
#define mmc_omap_resume NULL
#endif
static void mmc_release(struct device *dev)
{
/* Nothing to release? */
}
static struct resource mmc1_resources[] = {
{
.start = IO_ADDRESS(OMAP_MMC1_BASE),
.end = IO_ADDRESS(OMAP_MMC1_BASE) + 0x7f,
.flags = IORESOURCE_MEM,
},
{
.start = INT_MMC,
.flags = IORESOURCE_IRQ,
},
};
static struct resource mmc2_resources[] = {
{
.start = IO_ADDRESS(OMAP_MMC2_BASE),
.end = IO_ADDRESS(OMAP_MMC2_BASE) + 0x7f,
.flags = IORESOURCE_MEM,
},
{
.start = INT_1610_MMC2,
.flags = IORESOURCE_IRQ,
},
};
static u64 mmc_dmamask = 0xffffffff;
static struct platform_device mmc_omap_device1 = {
.name = "mmci-omap",
.id = 1,
.dev = {
.release = mmc_release,
.dma_mask = &mmc_dmamask,
},
.num_resources = ARRAY_SIZE(mmc1_resources),
.resource = mmc1_resources,
};
static struct platform_device mmc_omap_device2 = {
.name = "mmci-omap",
.id = 2,
.dev = {
.release = mmc_release,
.dma_mask = &mmc_dmamask,
},
.num_resources = ARRAY_SIZE(mmc2_resources),
.resource = mmc2_resources,
};
static struct device_driver mmc_omap_driver = {
.name = "mmci-omap",
.bus = &platform_bus_type,
......@@ -1185,72 +1096,14 @@ static struct device_driver mmc_omap_driver = {
.resume = mmc_omap_resume,
};
static int enable_blocks = 0;
static int __init mmc_omap_init(void)
{
int ret;
const struct omap_mmc_config *minfo;
minfo = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config);
if (minfo != NULL) {
enable_blocks = minfo->mmc_blocks;
if (enable_blocks & 1) {
mmc1_power_pin = minfo->mmc1_power_pin;
mmc1_switch_pin = minfo->mmc1_switch_pin;
}
if (enable_blocks & 2) {
mmc2_power_pin = minfo->mmc2_power_pin;
mmc2_switch_pin = minfo->mmc2_switch_pin;
}
} else {
#if defined(CONFIG_ARCH_OMAP1510) || defined(CONFIG_MMC_OMAP16XX_BLOCK1)
enable_blocks |= 1;
#endif
#if defined(CONFIG_MMC_OMAP16XX_BLOCK2)
enable_blocks |= 2;
#endif
}
if (enable_blocks == 0) {
printk(KERN_INFO "OMAP MMC driver not loaded\n");
return -ENODEV;
}
if (enable_blocks & 1) {
ret = platform_device_register(&mmc_omap_device1);
if (ret != 0)
return -ENODEV;
}
if (enable_blocks & 2) {
ret = platform_device_register(&mmc_omap_device2);
if (ret != 0)
goto free1;
}
ret = driver_register(&mmc_omap_driver);
if (ret == 0)
return 0;
if (enable_blocks & 2)
platform_device_unregister(&mmc_omap_device2);
free1:
if (enable_blocks & 1)
platform_device_unregister(&mmc_omap_device1);
return -ENODEV;
return driver_register(&mmc_omap_driver);
}
static void __exit mmc_omap_exit(void)
{
driver_unregister(&mmc_omap_driver);
if (enable_blocks & 2)
platform_device_unregister(&mmc_omap_device2);
if (enable_blocks & 1)
platform_device_unregister(&mmc_omap_device1);
}
module_init(mmc_omap_init);
......
#ifndef DRIVERS_MEDIA_MMC_OMAP_H
#define DRIVERS_MEDIA_MMC_OMAP_H
#define OMAP_MMC1_BASE 0xfffb7800
#define OMAP_MMC2_BASE 0xfffb7c00
#define OMAP_MMC_REG_CMD 0x00
#define OMAP_MMC_REG_ARGL 0x04
#define OMAP_MMC_REG_ARGH 0x08
......
......@@ -30,10 +30,23 @@ struct omap_clock_config {
u8 system_clock_type;
};
struct omap_mmc_conf {
unsigned enabled:1;
/* nomux means "standard" muxing is wrong on this board, and that
* board-specific code handled it before common init logic.
*/
unsigned nomux:1;
/* switch pin can be for card detect (default) or card cover */
unsigned cover:1;
/* 4 wire signaling is optional, and is only used for SD/SDIO */
unsigned wire4:1;
s16 power_pin;
s16 switch_pin;
s16 wp_pin;
};
struct omap_mmc_config {
u8 mmc_blocks;
s16 mmc1_power_pin, mmc2_power_pin;
s16 mmc1_switch_pin, mmc2_switch_pin;
struct omap_mmc_conf mmc[2];
};
struct omap_serial_console_config {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment