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 @@ ...@@ -3,7 +3,7 @@
# #
# Common support # 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 led-y := leds.o
# Specific board support # Specific board support
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/arch/gpio.h> #include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h> #include <asm/arch/tc.h>
#include <asm/arch/usb.h> #include <asm/arch/usb.h>
...@@ -151,9 +152,13 @@ static struct omap_usb_config h2_usb_config __initdata = { ...@@ -151,9 +152,13 @@ static struct omap_usb_config h2_usb_config __initdata = {
}; };
static struct omap_mmc_config h2_mmc_config __initdata = { static struct omap_mmc_config h2_mmc_config __initdata = {
.mmc_blocks = 1, .mmc [0] = {
.mmc1_power_pin = -1, /* tps65010 gpio3 */ .enabled = 1,
.mmc1_switch_pin = OMAP_MPUIO(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[] = { static struct omap_board_config_kernel h2_config[] = {
...@@ -169,6 +174,10 @@ static void __init h2_init(void) ...@@ -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 = h2_flash_resource.start = omap_cs3_phys();
h2_flash_resource.end += SZ_32M - 1; 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)); platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
omap_board_config = h2_config; omap_board_config = h2_config;
omap_board_config_size = ARRAY_SIZE(h2_config); omap_board_config_size = ARRAY_SIZE(h2_config);
......
...@@ -161,10 +161,12 @@ static struct omap_usb_config h3_usb_config __initdata = { ...@@ -161,10 +161,12 @@ static struct omap_usb_config h3_usb_config __initdata = {
.pins[1] = 3, .pins[1] = 3,
}; };
static struct omap_mmc_config h3_mmc_config __initdata_or_module = { static struct omap_mmc_config h3_mmc_config __initdata = {
.mmc_blocks = 1, .mmc[0] = {
.mmc1_power_pin = -1, /* tps65010 GPIO4 */ .enabled = 1,
.mmc1_switch_pin = OMAP_MPUIO(1), .power_pin = -1, /* tps65010 GPIO4 */
.switch_pin = OMAP_MPUIO(1),
},
}; };
static struct omap_board_config_kernel h3_config[] = { static struct omap_board_config_kernel h3_config[] = {
......
...@@ -144,9 +144,11 @@ static struct omap_usb_config voiceblue_usb_config __initdata = { ...@@ -144,9 +144,11 @@ static struct omap_usb_config voiceblue_usb_config __initdata = {
}; };
static struct omap_mmc_config voiceblue_mmc_config __initdata = { static struct omap_mmc_config voiceblue_mmc_config __initdata = {
.mmc_blocks = 1, .mmc[0] = {
.mmc1_power_pin = 2, .enabled = 1,
.mmc1_switch_pin = -1, .power_pin = 2,
.switch_pin = -1,
},
}; };
static struct omap_boot_reason_config voiceblue_boot_reason; static struct omap_boot_reason_config voiceblue_boot_reason;
......
...@@ -77,25 +77,6 @@ config MMC_OMAP ...@@ -77,25 +77,6 @@ config MMC_OMAP
If unsure, say N. 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 config MMC_WBSD
tristate "Winbond W83L51xD SD/MMC Card Interface support" tristate "Winbond W83L51xD SD/MMC Card Interface support"
depends on MMC && ISA_DMA_API depends on MMC && ISA_DMA_API
......
...@@ -44,8 +44,8 @@ ...@@ -44,8 +44,8 @@
#define DRIVER_NAME "mmci-omap" #define DRIVER_NAME "mmci-omap"
#ifdef CONFIG_MMC_DEBUG #ifdef CONFIG_MMC_DEBUG
//#define DBG(x...) printk(KERN_DEBUG x) #define DBG(x...) pr_debug(x)
#define DBG(x...) printk(x) //#define DBG(x...) printk(x)
#else #else
#define DBG(x...) do { } while (0) #define DBG(x...) do { } while (0)
#endif #endif
...@@ -54,11 +54,6 @@ ...@@ -54,11 +54,6 @@
* when the cover switch is open */ * when the cover switch is open */
#define OMAP_MMC_SWITCH_POLL_DELAY 500 #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; static int mmc_omap_enable_poll = 1;
struct mmc_omap_host { struct mmc_omap_host {
...@@ -81,17 +76,15 @@ struct mmc_omap_host { ...@@ -81,17 +76,15 @@ struct mmc_omap_host {
unsigned char datadir; unsigned char datadir;
u16 * buffer; u16 * buffer;
u32 bytesleft; u32 bytesleft;
int power_pin; short power_pin;
short wp_pin;
int use_dma, dma_ch; short use_dma, dma_ch;
struct completion dma_completion; struct completion dma_completion;
int switch_pin; int switch_pin;
struct work_struct switch_work; struct work_struct switch_work;
struct timer_list switch_timer; struct timer_list switch_timer;
int switch_last_state; int switch_last_state;
unsigned char sd_support;
}; };
static inline int static inline int
...@@ -394,11 +387,11 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -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) { if (status & OMAP_MMC_STAT_CMD_TOUT) {
// Command timeout /* Timeouts are routine with some commands */
if (host->cmd) { if (host->cmd) {
/* Timeouts are normal in case of MMC_SEND_STATUS */
if (host->cmd->opcode != MMC_ALL_SEND_CID && if (host->cmd->opcode != MMC_ALL_SEND_CID &&
host->cmd->opcode != MMC_SEND_OP_COND && host->cmd->opcode != MMC_SEND_OP_COND &&
host->cmd->opcode != MMC_APP_CMD &&
!mmc_omap_cover_is_open(host)) !mmc_omap_cover_is_open(host))
printk(KERN_ERR "MMC%d: Command timeout, CMD%d\n", printk(KERN_ERR "MMC%d: Command timeout, CMD%d\n",
host->id, host->cmd->opcode); host->id, host->cmd->opcode);
...@@ -417,10 +410,10 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -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) { if (status & OMAP_MMC_STAT_OCR_BUSY) {
// OCR Busy /* OCR Busy ... happens a lot */
if (host->cmd && host->cmd->opcode != MMC_SEND_OP_COND && if (host->cmd && host->cmd->opcode != MMC_SEND_OP_COND
host->cmd->opcode != MMC_SET_RELATIVE_ADDR) { && host->cmd->opcode != MMC_SET_RELATIVE_ADDR) {
printk(KERN_DEBUG "MMC%d: OCR busy error, CMD%d\n", DBG("MMC%d: OCR busy error, CMD%d\n",
host->id, host->cmd->opcode); host->id, host->cmd->opcode);
} }
} }
...@@ -849,6 +842,8 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -849,6 +842,8 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
dsor = 250; dsor = 250;
} }
/* REVISIT: if (ios->bus_width == MMC_BUS_WIDTH_4) dsor |= 1 << 15; */
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_OFF: case MMC_POWER_OFF:
mmc_omap_power(host, 0); mmc_omap_power(host, 0);
...@@ -887,6 +882,7 @@ static struct mmc_host_ops mmc_omap_ops = { ...@@ -887,6 +882,7 @@ static struct mmc_host_ops mmc_omap_ops = {
static int __init mmc_omap_probe(struct device *dev) static int __init mmc_omap_probe(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct omap_mmc_conf *minfo = dev->platform_data;
struct mmc_host *mmc; struct mmc_host *mmc;
struct mmc_omap_host *host = NULL; struct mmc_omap_host *host = NULL;
int ret = 0; int ret = 0;
...@@ -913,7 +909,7 @@ static int __init mmc_omap_probe(struct device *dev) ...@@ -913,7 +909,7 @@ static int __init mmc_omap_probe(struct device *dev)
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = 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"); host->clk = clk_get(dev, (host->id == 1) ? "mmc1_ck" : "mmc2_ck");
if (IS_ERR(host->clk)) { if (IS_ERR(host->clk)) {
...@@ -921,46 +917,15 @@ static int __init mmc_omap_probe(struct device *dev) ...@@ -921,46 +917,15 @@ static int __init mmc_omap_probe(struct device *dev)
goto out; goto out;
} }
if (host->id == 1) { /* REVISIT: SD-only support, when core merged
omap_cfg_reg(MMC_CMD); * - if (minfo->wire4) mmc->caps |= MMC_CAP_4_BIT_DATA;
omap_cfg_reg(MMC_CLK); * - mmc_omap_ops.get_ro uses wp_pin to sense slider
omap_cfg_reg(MMC_DAT0); * Also, use minfo->cover to decide how to manage
if (cpu_is_omap1710()) { * the card detect sensing.
omap_cfg_reg(M15_1710_MMC_CLKI); */
omap_cfg_reg(P19_1710_MMC_CMDDIR); host->power_pin = minfo->power_pin;
omap_cfg_reg(P20_1710_MMC_DATDIR0); host->switch_pin = minfo->switch_pin;
} host->wp_pin = minfo->wp_pin;
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);
}
host->use_dma = 1; host->use_dma = 1;
host->dma_ch = -1; host->dma_ch = -1;
...@@ -1122,60 +1087,6 @@ static int mmc_omap_resume(struct device *dev, u32 level) ...@@ -1122,60 +1087,6 @@ static int mmc_omap_resume(struct device *dev, u32 level)
#define mmc_omap_resume NULL #define mmc_omap_resume NULL
#endif #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 = { static struct device_driver mmc_omap_driver = {
.name = "mmci-omap", .name = "mmci-omap",
.bus = &platform_bus_type, .bus = &platform_bus_type,
...@@ -1185,72 +1096,14 @@ static struct device_driver mmc_omap_driver = { ...@@ -1185,72 +1096,14 @@ static struct device_driver mmc_omap_driver = {
.resume = mmc_omap_resume, .resume = mmc_omap_resume,
}; };
static int enable_blocks = 0;
static int __init mmc_omap_init(void) static int __init mmc_omap_init(void)
{ {
int ret; return driver_register(&mmc_omap_driver);
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;
} }
static void __exit mmc_omap_exit(void) static void __exit mmc_omap_exit(void)
{ {
driver_unregister(&mmc_omap_driver); 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); module_init(mmc_omap_init);
......
#ifndef DRIVERS_MEDIA_MMC_OMAP_H #ifndef DRIVERS_MEDIA_MMC_OMAP_H
#define 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_CMD 0x00
#define OMAP_MMC_REG_ARGL 0x04 #define OMAP_MMC_REG_ARGL 0x04
#define OMAP_MMC_REG_ARGH 0x08 #define OMAP_MMC_REG_ARGH 0x08
......
...@@ -30,10 +30,23 @@ struct omap_clock_config { ...@@ -30,10 +30,23 @@ struct omap_clock_config {
u8 system_clock_type; 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 { struct omap_mmc_config {
u8 mmc_blocks; struct omap_mmc_conf mmc[2];
s16 mmc1_power_pin, mmc2_power_pin;
s16 mmc1_switch_pin, mmc2_switch_pin;
}; };
struct omap_serial_console_config { 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