Commit 90c62bf0 authored by Tony Lindgren's avatar Tony Lindgren
Browse files

omap mmc: Add low-level initialization for hsmmc controller



Add low-level initialization for hsmmc controller. Merged into
this patch patch are various improvments and board support by
Grazvydas Ignotas and David Brownell.

Also change wire4 to be wires, as some newer controllers support
8 data lines.

Cc: Pierre Ossman <drzeus-mmc@drzeus.cx>
Signed-off-by: default avatarGrazvydas Ignotas <notasas@gmail.com>
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>







parent d8874665
......@@ -385,7 +385,7 @@ static struct omap_mmc_platform_data mmc1_data = {
.nr_slots = 1,
.slots[0] = {
.set_power = mmc_set_power,
.wire4 = 1,
.wires = 4,
.name = "mmcblk",
},
};
......
......@@ -116,7 +116,7 @@ static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_cfg_reg(P19_1710_MMC_CMDDIR);
omap_cfg_reg(P20_1710_MMC_DATDIR0);
}
if (mmc_controller->slots[0].wire4) {
if (mmc_controller->slots[0].wires == 4) {
omap_cfg_reg(MMC_DAT1);
/* NOTE: DAT2 can be on W10 (here) or M15 */
if (!mmc_controller->slots[0].nomux)
......@@ -132,7 +132,7 @@ static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
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) {
if (mmc_controller->slots[1].wires == 4) {
omap_cfg_reg(V8_1610_MMC2_DAT1);
omap_cfg_reg(W15_1610_MMC2_DAT2);
omap_cfg_reg(R10_1610_MMC2_DAT3);
......
......@@ -27,10 +27,15 @@ obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o
obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o
obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o
obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o
obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o
obj-$(CONFIG_MACH_OVERO) += board-overo.o
obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o
obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OVERO) += board-overo.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o \
mmc-twl4030.o
......@@ -19,6 +19,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/i2c/twl4030.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
......@@ -35,6 +36,7 @@
#include <mach/common.h>
#include <mach/gpmc.h>
#include "mmc-twl4030.h"
#define SDP2430_FLASH_CS 0
#define SDP2430_SMC91X_CS 5
......@@ -197,12 +199,58 @@ static struct omap_board_config_kernel sdp2430_config[] = {
{OMAP_TAG_UART, &sdp2430_uart_config},
};
static struct twl4030_gpio_platform_data sdp2430_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
};
static struct twl4030_platform_data sdp2430_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.gpio = &sdp2430_gpio_data,
};
static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
.irq = INT_24XX_SYS_NIRQ,
.platform_data = &sdp2430_twldata,
},
};
static int __init omap2430_i2c_init(void)
{
omap_register_i2c_bus(1, 400, NULL, 0);
omap_register_i2c_bus(2, 2600, sdp2430_i2c_boardinfo,
ARRAY_SIZE(sdp2430_i2c_boardinfo));
return 0;
}
static struct twl4030_hsmmc_info mmc[] __initdata = {
{
.mmc = 1,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.ext_clock = 1,
},
{} /* Terminator */
};
static void __init omap_2430sdp_init(void)
{
omap2430_i2c_init();
platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
omap_board_config = sdp2430_config;
omap_board_config_size = ARRAY_SIZE(sdp2430_config);
omap_serial_init();
twl4030_mmc_init(mmc);
}
static void __init omap_2430sdp_map_io(void)
......
......@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/i2c/twl4030.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
......@@ -38,6 +39,8 @@
#include <asm/delay.h>
#include <mach/control.h>
#include "mmc-twl4030.h"
#define SDP3430_SMC91X_CS 3
static struct resource ldp_smc911x_resources[] = {
......@@ -109,14 +112,48 @@ static struct omap_board_config_kernel ldp_config[] __initdata = {
{ OMAP_TAG_UART, &ldp_uart_config },
};
static struct twl4030_gpio_platform_data ldp_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
};
static struct twl4030_platform_data ldp_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.gpio = &ldp_gpio_data,
};
static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
.irq = INT_34XX_SYS_NIRQ,
.platform_data = &ldp_twldata,
},
};
static int __init omap_i2c_init(void)
{
omap_register_i2c_bus(1, 2600, NULL, 0);
omap_register_i2c_bus(1, 2600, ldp_i2c_boardinfo,
ARRAY_SIZE(ldp_i2c_boardinfo));
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
}
static struct twl4030_hsmmc_info mmc[] __initdata = {
{
.mmc = 1,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{} /* Terminator */
};
static void __init omap_ldp_init(void)
{
omap_i2c_init();
......@@ -124,6 +161,7 @@ static void __init omap_ldp_init(void)
omap_board_config = ldp_config;
omap_board_config_size = ARRAY_SIZE(ldp_config);
omap_serial_init();
twl4030_mmc_init(mmc);
}
static void __init omap_ldp_map_io(void)
......
......@@ -38,7 +38,9 @@
#include <mach/common.h>
#include <mach/gpmc.h>
#include <mach/nand.h>
#include <mach/mux.h>
#include "mmc-twl4030.h"
#define GPMC_CS0_BASE 0x60
#define GPMC_CS_SIZE 0x30
......@@ -103,6 +105,78 @@ static struct omap_uart_config omap3_beagle_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
static struct twl4030_hsmmc_info mmc[] = {
{
.mmc = 1,
.wires = 8,
.gpio_wp = 29,
},
{} /* Terminator */
};
static struct gpio_led gpio_leds[];
static int beagle_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
/* REVISIT: need ehci-omap hooks for external VBUS
* power switch and overcurrent detect
*/
gpio_request(gpio + 1, "EHCI_nOC");
gpio_direction_input(gpio + 1);
/* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */
gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1);
/* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
return 0;
}
static struct twl4030_gpio_platform_data beagle_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
.use_leds = true,
.pullups = BIT(1),
.pulldowns = BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13)
| BIT(15) | BIT(16) | BIT(17),
.setup = beagle_twl_gpio_setup,
};
static struct twl4030_platform_data beagle_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.gpio = &beagle_gpio_data,
};
static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
.irq = INT_34XX_SYS_NIRQ,
.platform_data = &beagle_twldata,
},
};
static int __init omap3_beagle_i2c_init(void)
{
omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
ARRAY_SIZE(beagle_i2c_boardinfo));
#ifdef CONFIG_I2C2_OMAP_BEAGLE
omap_register_i2c_bus(2, 400, NULL, 0);
#endif
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
}
static void __init omap3_beagle_init_irq(void)
{
omap2_init_common_hw();
......@@ -130,6 +204,11 @@ static struct gpio_led gpio_leds[] = {
.default_trigger = "mmc0",
.gpio = 149,
},
{
.name = "beagleboard::pmu_stat",
.gpio = -EINVAL, /* gets replaced */
.active_low = true,
},
};
static struct gpio_led_platform_data gpio_led_info = {
......@@ -218,11 +297,22 @@ static void __init omap3beagle_flash_init(void)
static void __init omap3_beagle_init(void)
{
omap3_beagle_i2c_init();
platform_add_devices(omap3_beagle_devices,
ARRAY_SIZE(omap3_beagle_devices));
omap_board_config = omap3_beagle_config;
omap_board_config_size = ARRAY_SIZE(omap3_beagle_config);
omap_serial_init();
omap_cfg_reg(AH8_34XX_GPIO29);
mmc[0].gpio_cd = gpio + 0;
twl4030_mmc_init(mmc);
omap_cfg_reg(J25_34XX_GPIO170);
gpio_request(170, "DVI_nPD");
/* REVISIT leave DVI powered down until it's needed ... */
gpio_direction_output(170, true);
omap3beagle_flash_init();
}
......
......@@ -35,16 +35,48 @@
#include <mach/hardware.h>
#include <mach/mcspi.h>
#include "mmc-twl4030.h"
#define OMAP3_PANDORA_TS_GPIO 94
static struct twl4030_hsmmc_info omap3pandora_mmc[] = {
{
.mmc = 1,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = 126,
.ext_clock = 0,
},
{
.mmc = 2,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = 127,
.ext_clock = 1,
},
{} /* Terminator */
};
static struct omap_uart_config omap3pandora_uart_config __initdata = {
.enabled_uarts = (1 << 2), /* UART3 */
};
static int omap3pandora_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
/* gpio + {0,1} is "mmc{0,1}_cd" (input/IRQ) */
omap3pandora_mmc[0].gpio_cd = gpio + 0;
omap3pandora_mmc[1].gpio_cd = gpio + 1;
twl4030_mmc_init(omap3pandora_mmc);
return 0;
}
static struct twl4030_gpio_platform_data omap3pandora_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
.setup = omap3pandora_twl_gpio_setup,
};
static struct twl4030_usb_data omap3pandora_usb_data = {
......
......@@ -26,6 +26,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/i2c/twl4030.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
......@@ -44,6 +45,8 @@
#include <mach/hardware.h>
#include <mach/nand.h>
#include "mmc-twl4030.h"
#define NAND_BLOCK_SIZE SZ_128K
#define GPMC_CS0_BASE 0x60
#define GPMC_CS_SIZE 0x30
......@@ -139,8 +142,31 @@ static struct omap_uart_config overo_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
static struct twl4030_gpio_platform_data overo_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
};
static struct twl4030_platform_data overo_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
.gpio = &overo_gpio_data,
};
static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
.irq = INT_34XX_SYS_NIRQ,
.platform_data = &overo_twldata,
},
};
static int __init overo_i2c_init(void)
{
omap_register_i2c_bus(1, 2600, overo_i2c_boardinfo,
ARRAY_SIZE(overo_i2c_boardinfo));
/* i2c2 pins are used for gpio */
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
......@@ -171,6 +197,22 @@ static struct platform_device *overo_devices[] __initdata = {
&overo_lcd_device,
};
static struct twl4030_hsmmc_info mmc[] __initdata = {
{
.mmc = 1,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{
.mmc = 2,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{} /* Terminator */
};
static void __init overo_init(void)
{
overo_i2c_init();
......@@ -178,6 +220,7 @@ static void __init overo_init(void)
omap_board_config = overo_config;
omap_board_config_size = ARRAY_SIZE(overo_config);
omap_serial_init();
twl4030_mmc_init(mmc);
overo_flash_init();
if ((gpio_request(OVERO_GPIO_W2W_NRESET,
......
......@@ -19,6 +19,7 @@
#include <asm/mach-types.h>
#include <asm/mach/map.h>
#include <mach/control.h>
#include <mach/tc.h>
#include <mach/board.h>
#include <mach/mux.h>
......@@ -311,7 +312,7 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_cfg_reg(F20_24XX_MMC_DAT0);
omap_cfg_reg(F19_24XX_MMC_DAT_DIR0);
omap_cfg_reg(G18_24XX_MMC_CMD_DIR);
if (mmc_controller->slots[0].wire4) {
if (mmc_controller->slots[0].wires == 4) {
omap_cfg_reg(H14_24XX_MMC_DAT1);
omap_cfg_reg(E19_24XX_MMC_DAT2);
omap_cfg_reg(D19_24XX_MMC_DAT3);
......
<
/*
* linux/arch/arm/mach-omap2/mmc-twl4030.c
*
* Copyright (C) 2007-2008 Texas Instruments
* Copyright (C) 2008 Nokia Corporation
* Author: Texas Instruments
*
* 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.
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/i2c/twl4030.h>
#include <mach/hardware.h>
#include <mach/control.h>
#include <mach/mmc.h>
#include <mach/board.h>
#include "mmc-twl4030.h"
#if defined(CONFIG_TWL4030_CORE) && \
(defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
#define LDO_CLR 0x00
#define VSEL_S2_CLR 0x40
#define VMMC1_DEV_GRP 0x27
#define VMMC1_CLR 0x00
#define VMMC1_315V 0x03
#define VMMC1_300V 0x02
#define VMMC1_285V 0x01
#define VMMC1_185V 0x00
#define VMMC1_DEDICATED 0x2A
#define VMMC2_DEV_GRP 0x2B
#define VMMC2_CLR 0x40
#define VMMC2_315V 0x0c
#define VMMC2_300V 0x0b
#define VMMC2_285V 0x0a
#define VMMC2_260V 0x08
#define VMMC2_185V 0x06
#define VMMC2_DEDICATED 0x2E
#define VMMC_DEV_GRP_P1 0x20
static u16 control_pbias_offset;
static u16 control_devconf1_offset;
#define HSMMC_NAME_LEN 9
static struct twl_mmc_controller {
struct omap_mmc_platform_data *mmc;
u8 twl_vmmc_dev_grp;
u8 twl_mmc_dedicated;
char name[HSMMC_NAME_LEN];
} hsmmc[] = {
{
.twl_vmmc_dev_grp = VMMC1_DEV_GRP,
.twl_mmc_dedicated = VMMC1_DEDICATED,
},
{
.twl_vmmc_dev_grp = VMMC2_DEV_GRP,
.twl_mmc_dedicated = VMMC2_DEDICATED,
},
};
static int twl_mmc_card_detect(int irq)
{
unsigned i;
for (i = 0; i < ARRAY_SIZE(hsmmc); i++) {
struct omap_mmc_platform_data *mmc;
mmc = hsmmc[i].mmc;
if (!mmc)
continue;
if (irq != mmc->slots[0].card_detect_irq)
continue;
/* NOTE: assumes card detect signal is active-low */
return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
}
return -ENOSYS;
}
static int twl_mmc_get_ro(struct device *dev, int slot)
{
struct omap_mmc_platform_data *mmc = dev->platform_data;
/* NOTE: assumes write protect signal is active-high */
return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
}
/*
* MMC Slot Initialization.
*/
static int twl_mmc_late_init(struct device *dev)
{
struct omap_mmc_platform_data *mmc = dev->platform_data;
int ret = 0;
int i;
ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
if (ret)
goto done;
ret = gpio_direction_input(mmc->slots[0].switch_pin);
if (ret)
goto err;
for (i = 0; i < ARRAY_SIZE(hsmmc); i++) {
if (hsmmc[i].name == mmc->slots[0].name) {
hsmmc[i].mmc = mmc;
break;
}
}
return 0;
err:
gpio_free(mmc->slots[0].switch_pin);
done:
mmc->slots[0].card_detect_irq = 0;
mmc->slots[0].card_detect = NULL;
dev_err(dev, "err %d configuring card detect\n", ret);
return ret;
}
static void twl_mmc_cleanup(struct device *dev)
{
struct omap_mmc_platform_data *mmc = dev->platform_data;
gpio_free(mmc->slots[0].switch_pin);
}
#ifdef CONFIG_PM
static int twl_mmc_suspend(struct device *dev, int slot)
{
struct omap_mmc_platform_data *mmc = dev->platform_data;
disable_irq(mmc->slots[0].card_detect_irq);
return 0;
}
static int twl_mmc_resume(struct device *dev, int slot)
{
struct omap_mmc_platform_data *mmc = dev->platform_data;