diff options
author | Tony Lindgren <tony@atomide.com> | 2008-12-11 01:37:16 (GMT) |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2008-12-11 01:37:16 (GMT) |
commit | d88746652b4d133284d1fdd05b5e999e8f44c998 (patch) | |
tree | 2a6cfd6fe175a18eb4b4f600e0a79444259c9a5d /arch/arm/mach-omap1 | |
parent | 652bcd8f72cc0cdf4499ce7d73990514e5e3e4b9 (diff) | |
download | linux-d88746652b4d133284d1fdd05b5e999e8f44c998.tar.xz |
omap mmc: Add better MMC low-level init
This will simplify the MMC low-level init, and make it more
flexible to add support for a newer MMC controller in the
following patches.
The patch rearranges platform data and gets rid of slot vs
controller confusion in the old data structures. Also fix
device id numbering in the clock code.
Some code snippets are based on an earlier patch by
Russell King <linux@arm.linux.org.uk>.
Cc: Pierre Ossman <drzeus-mmc@drzeus.cx>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap1')
-rw-r--r-- | arch/arm/mach-omap1/board-h2-mmc.c | 63 | ||||
-rw-r--r-- | arch/arm/mach-omap1/board-h2.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-omap1/board-h3-mmc.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-omap1/board-innovator.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-omap1/board-nokia770.c | 74 | ||||
-rw-r--r-- | arch/arm/mach-omap1/board-sx1-mmc.c | 31 | ||||
-rw-r--r-- | arch/arm/mach-omap1/clock.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap1/devices.c | 90 |
8 files changed, 329 insertions, 47 deletions
diff --git a/arch/arm/mach-omap1/board-h2-mmc.c b/arch/arm/mach-omap1/board-h2-mmc.c index 504ae88..409fa56 100644 --- a/arch/arm/mach-omap1/board-h2-mmc.c +++ b/arch/arm/mach-omap1/board-h2-mmc.c @@ -12,13 +12,74 @@ * published by the Free Software Foundation. */ +#include <linux/platform_device.h> + +#include <linux/i2c/tps65010.h> + #include <mach/mmc.h> #include <mach/gpio.h> +#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) + +static int mmc_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + if (power_on) + gpio_direction_output(H2_TPS_GPIO_MMC_PWR_EN, 1); + else + gpio_direction_output(H2_TPS_GPIO_MMC_PWR_EN, 0); + + return 0; +} + +static int mmc_late_init(struct device *dev) +{ + int ret; + + ret = gpio_request(H2_TPS_GPIO_MMC_PWR_EN, "MMC power"); + if (ret < 0) + return ret; + + gpio_direction_output(H2_TPS_GPIO_MMC_PWR_EN, 0); + + return ret; +} + +static void mmc_shutdown(struct device *dev) +{ + gpio_free(H2_TPS_GPIO_MMC_PWR_EN); +} + +/* + * H2 could use the following functions tested: + * - mmc_get_cover_state that uses OMAP_MPUIO(1) + * - mmc_get_wp that uses OMAP_MPUIO(3) + */ +static struct omap_mmc_platform_data mmc1_data = { + .nr_slots = 1, + .init = mmc_late_init, + .shutdown = mmc_shutdown, + .dma_mask = 0xffffffff, + .slots[0] = { + .set_power = mmc_set_power, + .ocr_mask = MMC_VDD_28_29 | MMC_VDD_30_31 | + MMC_VDD_32_33 | MMC_VDD_33_34, + .name = "mmcblk", + }, +}; + +static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC]; + void __init h2_mmc_init(void) { + mmc_data[0] = &mmc1_data; + omap1_init_mmc(mmc_data, OMAP16XX_NR_MMC); } -void h2_mmc_slot_cover_handler(void *arg, int state) +#else + +void __init h2_mmc_init(void) { } + +#endif diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 125d8e2..b240c5f 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -345,10 +345,25 @@ static void __init h2_init_smc91x(void) } } +static int tps_setup(struct i2c_client *client, void *context) +{ + tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | + TPS_LDO1_ENABLE | TPS_VLDO1_3_0V); + + return 0; +} + +static struct tps65010_board tps_board = { + .base = H2_TPS_GPIO_BASE, + .outmask = 0x0f, + .setup = tps_setup, +}; + static struct i2c_board_info __initdata h2_i2c_board_info[] = { { I2C_BOARD_INFO("tps65010", 0x48), .irq = OMAP_GPIO_IRQ(58), + .platform_data = &tps_board, }, { I2C_BOARD_INFO("isp1301_omap", 0x2d), .irq = OMAP_GPIO_IRQ(2), diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c index 0baba1c..fdfe793 100644 --- a/arch/arm/mach-omap1/board-h3-mmc.c +++ b/arch/arm/mach-omap1/board-h3-mmc.c @@ -12,13 +12,61 @@ * published by the Free Software Foundation. */ +#include <linux/platform_device.h> + +#include <linux/i2c/tps65010.h> + #include <mach/mmc.h> #include <mach/gpio.h> +#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) + +static int mmc_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + if (power_on) + gpio_direction_output(H3_TPS_GPIO_MMC_PWR_EN, 1); + else + gpio_direction_output(H3_TPS_GPIO_MMC_PWR_EN, 0); + + return 0; +} + +/* + * H3 could use the following functions tested: + * - mmc_get_cover_state that uses OMAP_MPUIO(1) + * - mmc_get_wp that maybe uses OMAP_MPUIO(3) + */ +static struct omap_mmc_platform_data mmc1_data = { + .nr_slots = 1, + .dma_mask = 0xffffffff, + .slots[0] = { + .set_power = mmc_set_power, + .ocr_mask = MMC_VDD_28_29 | MMC_VDD_30_31 | + MMC_VDD_32_33 | MMC_VDD_33_34, + .name = "mmcblk", + }, +}; + +static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC]; + void __init h3_mmc_init(void) { + int ret; + + ret = gpio_request(H3_TPS_GPIO_MMC_PWR_EN, "MMC power"); + if (ret < 0) + return; + gpio_direction_output(H3_TPS_GPIO_MMC_PWR_EN, 0); + + mmc_data[0] = &mmc1_data; + omap1_init_mmc(mmc_data, OMAP16XX_NR_MMC); } -void h3_mmc_slot_cover_handler(void *arg, int state) +#else + +void __init h3_mmc_init(void) { } + +#endif diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index a21e365..8ffb06f 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -39,6 +39,7 @@ #include <mach/common.h> #include <mach/mcbsp.h> #include <mach/omap-alsa.h> +#include <mach/mmc.h> static int innovator_keymap[] = { KEY(0, 0, KEY_F1), @@ -360,16 +361,49 @@ static struct omap_lcd_config innovator1610_lcd_config __initdata = { }; #endif -static struct omap_mmc_config innovator_mmc_config __initdata = { - .mmc [0] = { - .enabled = 1, - .wire4 = 1, - .wp_pin = OMAP_MPUIO(3), - .power_pin = -1, /* FPGA F3 UIO42 */ - .switch_pin = -1, /* FPGA F4 UIO43 */ +#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) + +static int mmc_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + if (power_on) + fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3), + OMAP1510_FPGA_POWER); + else + fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~(1 << 3), + OMAP1510_FPGA_POWER); + + return 0; +} + +/* + * Innovator could use the following functions tested: + * - mmc_get_wp that uses OMAP_MPUIO(3) + * - mmc_get_cover_state that uses FPGA F4 UIO43 + */ +static struct omap_mmc_platform_data mmc1_data = { + .nr_slots = 1, + .slots[0] = { + .set_power = mmc_set_power, + .wire4 = 1, + .name = "mmcblk", }, }; +static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC]; + +void __init innovator_mmc_init(void) +{ + mmc_data[0] = &mmc1_data; + omap1_init_mmc(mmc_data, OMAP15XX_NR_MMC); +} + +#else +static inline void innovator_mmc_init(void) +{ +} +#endif + static struct omap_uart_config innovator_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), }; @@ -377,7 +411,6 @@ static struct omap_uart_config innovator_uart_config __initdata = { static struct omap_board_config_kernel innovator_config[] = { { OMAP_TAG_USB, NULL }, { OMAP_TAG_LCD, NULL }, - { OMAP_TAG_MMC, &innovator_mmc_config }, { OMAP_TAG_UART, &innovator_uart_config }, }; @@ -412,6 +445,7 @@ static void __init innovator_init(void) omap_board_config_size = ARRAY_SIZE(innovator_config); omap_serial_init(); omap_register_i2c_bus(1, 100, NULL, 0); + innovator_mmc_init(); } static void __init innovator_map_io(void) diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index b267824..4970c40 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -35,6 +35,7 @@ #include <mach/aic23.h> #include <mach/omapfb.h> #include <mach/lcd_mipid.h> +#include <mach/mmc.h> #define ADS7846_PENDOWN_GPIO 15 @@ -173,26 +174,68 @@ static struct omap_usb_config nokia770_usb_config __initdata = { .pins[0] = 6, }; -static struct omap_mmc_config nokia770_mmc_config __initdata = { - .mmc[0] = { - .enabled = 0, - .wire4 = 0, - .wp_pin = -1, - .power_pin = -1, - .switch_pin = -1, - }, - .mmc[1] = { - .enabled = 0, - .wire4 = 0, - .wp_pin = -1, - .power_pin = -1, - .switch_pin = -1, +#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) + +#define NOKIA770_GPIO_MMC_POWER 41 +#define NOKIA770_GPIO_MMC_SWITCH 23 + +static int nokia770_mmc_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + if (power_on) + gpio_set_value(NOKIA770_GPIO_MMC_POWER, 1); + else + gpio_set_value(NOKIA770_GPIO_MMC_POWER, 0); + + return 0; +} + +static int nokia770_mmc_get_cover_state(struct device *dev, int slot) +{ + return gpio_get_value(NOKIA770_GPIO_MMC_SWITCH); +} + +static struct omap_mmc_platform_data nokia770_mmc2_data = { + .nr_slots = 1, + .dma_mask = 0xffffffff, + .slots[0] = { + .set_power = nokia770_mmc_set_power, + .get_cover_state = nokia770_mmc_get_cover_state, + .name = "mmcblk", }, }; +static struct omap_mmc_platform_data *nokia770_mmc_data[OMAP16XX_NR_MMC]; + +static void __init nokia770_mmc_init(void) +{ + int ret; + + ret = gpio_request(NOKIA770_GPIO_MMC_POWER, "MMC power"); + if (ret < 0) + return; + gpio_direction_output(NOKIA770_GPIO_MMC_POWER, 0); + + ret = gpio_request(NOKIA770_GPIO_MMC_SWITCH, "MMC cover"); + if (ret < 0) { + gpio_free(NOKIA770_GPIO_MMC_POWER); + return; + } + gpio_direction_input(NOKIA770_GPIO_MMC_SWITCH); + + /* Only the second MMC controller is used */ + nokia770_mmc_data[1] = &nokia770_mmc2_data; + omap1_init_mmc(nokia770_mmc_data, OMAP16XX_NR_MMC); +} + +#else +static inline void nokia770_mmc_init(void) +{ +} +#endif + static struct omap_board_config_kernel nokia770_config[] __initdata = { { OMAP_TAG_USB, NULL }, - { OMAP_TAG_MMC, &nokia770_mmc_config }, }; #if defined(CONFIG_OMAP_DSP) @@ -335,6 +378,7 @@ static void __init omap_nokia770_init(void) omap_dsp_init(); ads7846_dev_init(); mipid_dev_init(); + nokia770_mmc_init(); } static void __init omap_nokia770_map_io(void) diff --git a/arch/arm/mach-omap1/board-sx1-mmc.c b/arch/arm/mach-omap1/board-sx1-mmc.c index 0ece109..66a4d7d 100644 --- a/arch/arm/mach-omap1/board-sx1-mmc.c +++ b/arch/arm/mach-omap1/board-sx1-mmc.c @@ -12,30 +12,20 @@ * published by the Free Software Foundation. */ +#include <linux/platform_device.h> + #include <mach/hardware.h> #include <mach/mmc.h> #include <mach/gpio.h> -#ifdef CONFIG_MMC_OMAP -static int slot_cover_open; -static struct device *mmc_device; +#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) -static int sx1_mmc_set_power(struct device *dev, int slot, int power_on, +static int mmc_set_power(struct device *dev, int slot, int power_on, int vdd) { int err; u8 dat = 0; -#ifdef CONFIG_MMC_DEBUG - dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1, - power_on ? "on" : "off", vdd); -#endif - - if (slot != 0) { - dev_err(dev, "No such slot %d\n", slot + 1); - return -ENODEV; - } - err = sx1_i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, &dat); if (err < 0) return err; @@ -48,19 +38,23 @@ static int sx1_mmc_set_power(struct device *dev, int slot, int power_on, return sx1_i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, dat); } -static struct omap_mmc_platform_data sx1_mmc_data = { +/* Cover switch is at OMAP_MPUIO(3) */ +static struct omap_mmc_platform_data mmc1_data = { .nr_slots = 1, .slots[0] = { - .set_power = sx1_mmc_set_power, + .set_power = mmc_set_power, .ocr_mask = MMC_VDD_28_29 | MMC_VDD_30_31 | MMC_VDD_32_33 | MMC_VDD_33_34, .name = "mmcblk", }, }; +static struct omap_mmc_platform_data *mmc_data[OMAP15XX_NR_MMC]; + void __init sx1_mmc_init(void) { - omap_set_mmc_info(1, &sx1_mmc_data); + mmc_data[0] = &mmc1_data; + omap1_init_mmc(mmc_data, OMAP15XX_NR_MMC); } #else @@ -69,7 +63,4 @@ void __init sx1_mmc_init(void) { } -void sx1_mmc_slot_cover_handler(void *arg, int state) -{ -} #endif diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h index 5635b51..c1dcdf1 100644 --- a/arch/arm/mach-omap1/clock.h +++ b/arch/arm/mach-omap1/clock.h @@ -705,7 +705,6 @@ static struct clk bclk_16xx = { static struct clk mmc1_ck = { .name = "mmc_ck", - .id = 1, /* Functional clock is direct from ULPD, interface clock is ARMPER */ .parent = &armper_ck.clk, .rate = 48000000, @@ -720,7 +719,7 @@ static struct clk mmc1_ck = { static struct clk mmc2_ck = { .name = "mmc_ck", - .id = 2, + .id = 1, /* Functional clock is direct from ULPD, interface clock is ARMPER */ .parent = &armper_ck.clk, .rate = 48000000, diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index e382b43..024dab1 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -22,6 +22,7 @@ #include <mach/board.h> #include <mach/mux.h> #include <mach/gpio.h> +#include <mach/mmc.h> /*-------------------------------------------------------------------------*/ @@ -99,6 +100,95 @@ static inline void omap_init_mbox(void) static inline void omap_init_mbox(void) { } #endif +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) + +static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller, + int controller_nr) +{ + if (controller_nr == 0) { + 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 (mmc_controller->slots[0].wire4) { + omap_cfg_reg(MMC_DAT1); + /* NOTE: DAT2 can be on W10 (here) or M15 */ + if (!mmc_controller->slots[0].nomux) + omap_cfg_reg(MMC_DAT2); + omap_cfg_reg(MMC_DAT3); + } + } + + /* Block 2 is on newer chips, and has many pinout options */ + if (cpu_is_omap16xx() && controller_nr == 1) { + if (!mmc_controller->slots[1].nomux) { + 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 (mmc_controller->slots[1].wire4) { + 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); + } + + /* 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); + } +} + +void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, + int nr_controllers) +{ + int i; + + for (i = 0; i < nr_controllers; i++) { + unsigned long base, size; + unsigned int irq = 0; + + if (!mmc_data[i]) + continue; + + omap1_mmc_mux(mmc_data[i], i); + + switch (i) { + case 0: + base = OMAP1_MMC1_BASE; + irq = INT_MMC; + break; + case 1: + if (!cpu_is_omap16xx()) + return; + base = OMAP1_MMC2_BASE; + irq = INT_1610_MMC2; + break; + default: + continue; + } + size = OMAP1_MMC_SIZE; + + omap_mmc_add(i, base, size, irq, mmc_data[i]); + }; +} + +#endif + +/*-------------------------------------------------------------------------*/ + #if defined(CONFIG_OMAP_STI) #define OMAP1_STI_BASE 0xfffea000 |