]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
MMC/SD board specific update for OMAP2430/3430
authorMadhusudhan Chikkature Rajashekar <madhu.cr@ti.com>
Thu, 20 Dec 2007 10:04:19 +0000 (15:34 +0530)
committerTony Lindgren <tony@atomide.com>
Thu, 24 Jan 2008 23:03:47 +0000 (15:03 -0800)
This patch adds OMAP2430/3430 MMC board specific file.

Signed-off-by: Madhusudhan Chikkature<madhu.cr@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-sdp-hsmmc.c [new file with mode: 0644]
include/asm-arm/arch-omap/board-2430sdp.h
include/asm-arm/arch-omap/board-3430sdp.h
include/asm-arm/arch-omap/mmc.h

index 519015f49d2eb4c6d80f92aa714c460a02888ef6..a15e59bf01cbfd17473c0a7881da87af2697e5ed 100644 (file)
@@ -355,10 +355,18 @@ struct omap_serial_console_config sdp2430_serial_console_config __initdata = {
        .console_speed = 115200,
 };
 
+static struct omap_mmc_config sdp2430_mmc_config __initdata = {
+       .mmc [0] = {
+               .enabled        = 1,
+               .wire4          = 1,
+       },
+};
+
 static struct omap_board_config_kernel sdp2430_config[] __initdata = {
        {OMAP_TAG_UART, &sdp2430_uart_config},
        {OMAP_TAG_LCD, &sdp2430_lcd_config},
        {OMAP_TAG_SERIAL_CONSOLE, &sdp2430_serial_console_config},
+       {OMAP_TAG_MMC,  &sdp2430_mmc_config},
 };
 
 static int __init omap2430_i2c_init(void)
@@ -381,6 +389,7 @@ static void __init omap_2430sdp_init(void)
        spi_register_board_info(sdp2430_spi_board_info,
                                ARRAY_SIZE(sdp2430_spi_board_info));
        ads7846_dev_init();
+       sdp_mmc_init();
 
        /* turn off secondary LCD backlight */
        omap_set_gpio_direction(SECONDARY_LCD_GPIO, 0);
index 0bc26e9fc6a1d64aec6fbc7d613da63f740fdfea..ae4c4f14ea0e8a20b5112ca60c083113842a6d24 100644 (file)
@@ -257,9 +257,17 @@ static struct omap_lcd_config sdp3430_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
 
+static struct omap_mmc_config sdp3430_mmc_config __initdata = {
+       .mmc [0] = {
+               .enabled        = 1,
+               .wire4          = 1,
+       },
+};
+
 static struct omap_board_config_kernel sdp3430_config[] __initdata = {
        { OMAP_TAG_UART,        &sdp3430_uart_config },
        {OMAP_TAG_LCD,          &sdp3430_lcd_config},
+       {OMAP_TAG_MMC,          &sdp3430_mmc_config },
 };
 
 static int __init omap3430_i2c_init(void)
@@ -283,6 +291,7 @@ static void __init omap_3430sdp_init(void)
        sdp3430_flash_init();
        omap_serial_init();
        sdp3430_usb_init();
+       sdp_mmc_init();
 }
 
 static void __init omap_3430sdp_map_io(void)
diff --git a/arch/arm/mach-omap2/board-sdp-hsmmc.c b/arch/arm/mach-omap2/board-sdp-hsmmc.c
new file mode 100644 (file)
index 0000000..4bf8165
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * linux/arch/arm/mach-omap2/board-sdp-hsmmc.c
+ *
+ * Copyright (C) 2007 Texas Instruments
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/hardware.h>
+#include <asm/arch/twl4030.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/board.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_MMC_OMAP_HS
+
+#define VMMC1_DEV_GRP          0x27
+#define P1_DEV_GRP             0x20
+#define VMMC1_DEDICATED                0x2A
+#define VSEL_3V                        0x02
+#define VSEL_18V               0x00
+#define TWL_GPIO_PUPDCTR1      0x13
+#define TWL_GPIO_IMR1A         0x1C
+#define TWL_GPIO_ISR1A         0x19
+#define LDO_CLR                        0x00
+#define VSEL_S2_CLR            0x40
+#define GPIO_0_BIT_POS         1 << 0
+#define MMC1_CD_IRQ            0
+#define MMC2_CD_IRQ            1
+
+static irqreturn_t mmc_omap_cd_handler(int irq, void *dev_id)
+{
+       int detect;
+
+       detect = twl4030_get_gpio_datain(MMC1_CD_IRQ);
+       omap_mmc_notify_card_detect(dev_id, 0, detect);
+       return IRQ_HANDLED;
+}
+
+/*
+ * MMC Slot Initialization.
+ */
+static int sdp_mmc_late_init(struct device *dev)
+{
+       int ret = 0;
+
+       /*
+        * Configure TWL4030 GPIO parameters for MMC hotplug irq
+        */
+       ret = twl4030_request_gpio(MMC1_CD_IRQ);
+       if (ret != 0)
+               goto err;
+
+       ret = twl4030_set_gpio_edge_ctrl(MMC1_CD_IRQ,
+                       TWL4030_GPIO_EDGE_RISING | TWL4030_GPIO_EDGE_FALLING);
+       if (ret != 0)
+               goto err;
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0x02,
+                                               TWL_GPIO_PUPDCTR1);
+       if (ret != 0)
+               goto err;
+
+       ret = twl4030_set_gpio_debounce(MMC1_CD_IRQ, TWL4030_GPIO_IS_ENABLE);
+       if (ret != 0)
+               goto err;
+
+       ret = request_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ),
+               mmc_omap_cd_handler, IRQF_DISABLED, "MMC1_CD_IRQ", dev);
+       if (ret < 0)
+               goto err;
+
+       return ret;
+err:
+       dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
+
+       return ret;
+}
+
+static void sdp_mmc_cleanup(struct device *dev)
+{
+       int ret = 0;
+
+       ret = twl4030_free_gpio(MMC1_CD_IRQ);
+       free_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ), dev);
+       if (ret != 0)
+               dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * To mask and unmask MMC Card Detect Interrupt
+ * mask : 1
+ * unmask : 0
+ */
+static int mask_cd_interrupt(int mask)
+{
+       u8 reg = 0, ret = 0;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &reg, TWL_GPIO_IMR1A);
+       if (ret != 0)
+               goto err;
+
+       reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_IMR1A);
+       if (ret != 0)
+               goto err;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &reg, TWL_GPIO_ISR1A);
+       if (ret != 0)
+               goto err;
+
+       reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_ISR1A);
+       if (ret != 0)
+               goto err;
+err:
+       return ret;
+}
+
+static int sdp_mmc_suspend(struct device *dev, int slot)
+{
+       int ret = 0;
+
+       disable_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ));
+       ret = mask_cd_interrupt(1);
+
+       return ret;
+}
+
+static int sdp_mmc_resume(struct device *dev, int slot)
+{
+       int ret = 0;
+
+       enable_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ));
+       ret = mask_cd_interrupt(0);
+
+       return ret;
+}
+
+#endif
+
+static int sdp_mmc_set_power(struct device *dev, int slot, int power_on,
+                               int vdd)
+{
+       u32 vdd_sel = 0, devconf = 0, reg = 0;
+       int ret = 0;
+
+       /* REVISIT: Using address directly till the control.h defines
+        * are settled.
+        */
+#if defined(CONFIG_ARCH_OMAP2430)
+       #define OMAP2_CONTROL_PBIAS 0x490024A0
+#else
+       #define OMAP2_CONTROL_PBIAS 0x48002520
+#endif
+
+       if (power_on == 1) {
+               if (cpu_is_omap24xx())
+                       devconf = omap_readl(0x490022E8);
+               else
+                       devconf = omap_readl(0x48002274);
+
+               switch (1 << vdd) {
+               case MMC_VDD_33_34:
+               case MMC_VDD_32_33:
+                       vdd_sel = VSEL_3V;
+                       if (cpu_is_omap24xx())
+                               devconf = (reg | (1 << 31));
+                       break;
+               case MMC_VDD_165_195:
+                       vdd_sel = VSEL_18V;
+                       if (cpu_is_omap24xx())
+                               devconf = (devconf & ~(1 << 31));
+               }
+
+               if (cpu_is_omap24xx())
+                       omap_writel(devconf, 0x490022E8);
+               else
+                       omap_writel(devconf | 1 << 24, 0x48002274);
+
+               omap_writel(omap_readl(OMAP2_CONTROL_PBIAS) | 1 << 2,
+                       OMAP2_CONTROL_PBIAS);
+               omap_writel(omap_readl(OMAP2_CONTROL_PBIAS) & ~(1 << 1),
+                       OMAP2_CONTROL_PBIAS);
+
+               ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                               P1_DEV_GRP, VMMC1_DEV_GRP);
+               if (ret != 0)
+                       goto err;
+
+               ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                               vdd_sel, VMMC1_DEDICATED);
+               if (ret != 0)
+                       goto err;
+
+               msleep(100);
+               reg = omap_readl(OMAP2_CONTROL_PBIAS);
+               reg = (vdd_sel == VSEL_18V) ? ((reg | 0x6) & ~0x1)
+                                               : (reg | 0x7);
+               omap_writel(reg, OMAP2_CONTROL_PBIAS);
+
+               return ret;
+
+       } else if (power_on == 0) {
+               /* Power OFF */
+
+               /* For MMC1, Toggle PBIAS before every power up sequence */
+               omap_writel(omap_readl(OMAP2_CONTROL_PBIAS) & ~(1 << 1),
+                                       OMAP2_CONTROL_PBIAS);
+               ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                               LDO_CLR, VMMC1_DEV_GRP);
+               if (ret != 0)
+                       goto err;
+
+               ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                               VSEL_S2_CLR, VMMC1_DEDICATED);
+               if (ret != 0)
+                       goto err;
+
+               /* 100ms delay required for PBIAS configuration */
+               msleep(100);
+               omap_writel(omap_readl(OMAP2_CONTROL_PBIAS) | 0x7,
+                       OMAP2_CONTROL_PBIAS);
+       } else {
+               ret = -1;
+               goto err;
+       }
+
+       return 0;
+err:
+       return 1;
+}
+
+static struct omap_mmc_platform_data sdp_mmc_data = {
+       .nr_slots                       = 1,
+       .switch_slot                    = NULL,
+       .init                           = sdp_mmc_late_init,
+       .cleanup                        = sdp_mmc_cleanup,
+#ifdef CONFIG_PM
+       .suspend                        = sdp_mmc_suspend,
+       .resume                         = sdp_mmc_resume,
+#endif
+       .slots[0] = {
+               .set_power              = sdp_mmc_set_power,
+               .set_bus_mode           = NULL,
+               .get_ro                 = NULL,
+               .get_cover_state        = NULL,
+               .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34 |
+                                               MMC_VDD_165_195,
+               .name                   = "first slot",
+       },
+};
+
+void __init sdp_mmc_init(void)
+{
+       omap_set_mmc_info(1, &sdp_mmc_data);
+}
+
+#else
+
+void __init sdp_mmc_init(void)
+{
+
+}
+
+#endif
index 3869182f87ba455877fad90c77bddd9c1ab3d9c9..186e9cc6d707d81f32d83f4fb052e66814882eb4 100644 (file)
@@ -48,5 +48,6 @@
 /* Function prototypes */
 extern void sdp2430_flash_init(void);
 extern void sdp2430_usb_init(void);
+extern void sdp_mmc_init(void);
 
 #endif /* __ASM_ARCH_OMAP_2430SDP_H */
index bc2bb3746168c7cc0e3d2d74b98ddf871be2cb49..61eb58701b1a3971d3e0055c20fc027f801b473e 100644 (file)
@@ -30,6 +30,7 @@
 #define __ASM_ARCH_OMAP_3430SDP_H
 
 extern void sdp3430_usb_init(void);
+extern void sdp_mmc_init(void);
 
 #define DEBUG_BASE                     0x08000000  /* debug board */
 
index 14e573f49d9e4e871edcf57659c5d3ad161e3b91..4d40db0a9a73cf4f17f68ece8cf753452a94992e 100644 (file)
@@ -36,6 +36,10 @@ struct omap_mmc_platform_data {
        int (* init)(struct device *dev);
        void (* cleanup)(struct device *dev);
 
+       /* To handle board related suspend/resume functionality for MMC */
+       int (*suspend)(struct device *dev, int slot);
+       int (*resume)(struct device *dev, int slot);
+
        struct omap_mmc_slot_data {
                int (* set_bus_mode)(struct device *dev, int slot, int bus_mode);
                int (* set_power)(struct device *dev, int slot, int power_on, int vdd);