]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
OMAP: MMC: Add MMC multislot support for TI OMAP H4 2420 boards.
authorDavid Cohen <david.cohen@indt.org.br>
Fri, 25 Jan 2008 18:59:36 +0000 (14:59 -0400)
committerTony Lindgren <tony@atomide.com>
Fri, 25 Jan 2008 22:56:44 +0000 (14:56 -0800)
This patch adds MMC multislot support for TI OMAP H4 2420 boards.

Signed-off-by: David Cohen <david.cohen@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Acked-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Tony Lindgren <tony@atomide.com>
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-h4-mmc.c [new file with mode: 0644]
arch/arm/mach-omap2/board-h4.c
include/asm-arm/arch-omap/board-h4.h

index 45b85fc3688c4393fa6238a8073292fe882d9d2d..842f9fb79675dc481daf57aba752daac2ffb4af3 100644 (file)
@@ -21,7 +21,7 @@ mmu_mach-objs                 := mmu.o
 
 # Specific board support
 obj-$(CONFIG_MACH_OMAP_GENERIC)                += board-generic.o
-obj-$(CONFIG_MACH_OMAP_H4)             += board-h4.o
+obj-$(CONFIG_MACH_OMAP_H4)             += board-h4.o board-h4-mmc.o
 obj-$(CONFIG_MACH_OMAP_2430SDP)                += board-2430sdp.o \
                                           board-2430sdp-flash.o \
                                           board-sdp-hsmmc.o \
diff --git a/arch/arm/mach-omap2/board-h4-mmc.c b/arch/arm/mach-omap2/board-h4-mmc.c
new file mode 100644 (file)
index 0000000..9cdb00f
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * linux/arch/arm/mach-omap2/board-h4-mmc.c
+ *
+ * Copyright (C) 2007 Instituto Nokia de Tecnologia - INdT
+ * Authors: David Cohen <david.cohen@indt.org.br>
+ *          Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
+ *
+ * This code is based on linux/arch/arm/mach-omap2/board-n800-mmc.c, which is:
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrjola
+ *
+ * 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 <asm/arch/mmc.h>
+#include <asm/arch/menelaus.h>
+
+#include <asm/mach-types.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_MMC_OMAP
+
+/* Bit mask for slots detection interrupts */
+#define SD1_CD_ST      (1 << 0)
+#define SD2_CD_ST      (1 << 1)
+
+static int slot1_cover_open;
+static int slot2_cover_open;
+static struct device *mmc_device;
+
+/*
+ * VMMC --> slot 1
+ * VDCDC3_APE, VMCS2_APE --> slot 2
+ */
+
+static int h4_mmc_switch_slot(struct device *dev, int slot)
+{
+       int r = 0;
+
+#ifdef CONFIG_MMC_DEBUG
+       dev_dbg(dev, "Choose slot %d\n", slot + 1);
+#endif
+       if (slot == 0) {
+               r = menelaus_enable_slot(2, 0);
+               r |= menelaus_enable_slot(1, 1);
+       } else {
+               r = menelaus_enable_slot(1, 0);
+               r |= menelaus_enable_slot(2, 1);
+       }
+
+       return r ? -ENODEV : 0;
+}
+
+static int h4_mmc_set_power(struct device *dev, int slot, int power_on,
+                               int vdd)
+{
+       int mV = 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) {
+               if (!power_on)
+                       return menelaus_set_vmmc(3000);
+               switch (1 << vdd) {
+                       case MMC_VDD_33_34:
+                       case MMC_VDD_32_33:
+                       case MMC_VDD_31_32:
+                               mV = 3100;
+                               break;
+                       case MMC_VDD_30_31:
+                               mV = 3000;
+                               break;
+                       case MMC_VDD_28_29:
+                               mV = 2800;
+                               break;
+                       case MMC_VDD_165_195:
+                               mV = 1850;
+                               break;
+                       default:
+                               BUG();
+               }
+               return menelaus_set_vmmc(mV);
+       } else {
+               if (!power_on)
+                       return menelaus_set_vdcdc(3, 3000);
+               switch (1 << vdd) {
+                       case MMC_VDD_33_34:
+                       case MMC_VDD_32_33:
+                               mV = 3300;
+                               break;
+                       case MMC_VDD_30_31:
+                       case MMC_VDD_29_30:
+                               mV = 3000;
+                               break;
+                       case MMC_VDD_28_29:
+                       case MMC_VDD_27_28:
+                               mV = 2800;
+                               break;
+                       case MMC_VDD_24_25:
+                       case MMC_VDD_23_24:
+                               mV = 2400;
+                               break;
+                       case MMC_VDD_22_23:
+                       case MMC_VDD_21_22:
+                               mV = 2200;
+                               break;
+                       case MMC_VDD_20_21:
+                               mV = 2000;
+                               break;
+                       case MMC_VDD_165_195:
+                               mV = 1800;
+                               break;
+                       default:
+                               BUG();
+               }
+               return menelaus_set_vdcdc(3, mV);
+       }
+       return 0;
+}
+
+static int h4_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
+{
+       int r = 0;
+
+#ifdef CONFIG_MMC_DEBUG
+       dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1,
+               bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
+#endif
+       BUG_ON(slot != 0 && slot != 1);
+       slot++;
+       switch (bus_mode) {
+       case MMC_BUSMODE_OPENDRAIN:
+               r = menelaus_set_mmc_opendrain(slot, 1);
+               break;
+       case MMC_BUSMODE_PUSHPULL:
+               r = menelaus_set_mmc_opendrain(slot, 0);
+               break;
+       default:
+               BUG();
+       }
+       if (r != 0 && printk_ratelimit()) {
+               dev_err(dev, "MMC: unable to set bus mode for slot %d\n",
+                       slot);
+       }
+       return r;
+}
+
+static int h4_mmc_slot1_cover_state(struct device *dev, int slot)
+{
+       BUG_ON(slot != 0);
+       return slot1_cover_open;
+}
+
+static int h4_mmc_slot2_cover_state(struct device *dev, int slot)
+{
+       BUG_ON(slot != 1);
+       return slot2_cover_open;
+}
+
+static void h4_mmc_slot_callback(void *data, u8 card_mask)
+{
+       int cover_open;
+
+       cover_open = (card_mask & SD1_CD_ST) ? 0 : 1;
+       if (cover_open != slot1_cover_open) {
+               slot1_cover_open = cover_open;
+               omap_mmc_notify_cover_event(mmc_device, 0, slot1_cover_open);
+       }
+
+       cover_open = (card_mask & SD2_CD_ST) ? 0 : 1;
+       if (cover_open != slot2_cover_open) {
+               slot2_cover_open = cover_open;
+               omap_mmc_notify_cover_event(mmc_device, 1, slot2_cover_open);
+       }
+}
+
+static int h4_mmc_late_init(struct device *dev)
+{
+       int r;
+
+       mmc_device = dev;
+
+       r = menelaus_set_mmc_slot(1, 0, 0, 1);
+       if (r < 0)
+               goto out;
+       r = menelaus_set_mmc_slot(2, 0, 0, 1);
+       if (r < 0)
+               goto out;
+
+       r = menelaus_get_slot_pin_states();
+       if (r < 0)
+               goto out;
+
+       if (r & SD1_CD_ST)
+               slot1_cover_open = 1;
+       else
+               slot1_cover_open = 0;
+
+       /* Slot pin bits seem to be inversed until first swith change,
+        * but just for slot 2
+        */
+       if ((r == 0xf) || (r == (0xf & ~SD2_CD_ST)))
+               r = ~r;
+
+       if (r & SD2_CD_ST)
+               slot2_cover_open = 1;
+       else
+               slot2_cover_open = 0;
+
+       r = menelaus_register_mmc_callback(h4_mmc_slot_callback, NULL);
+
+out:
+       return r;
+}
+
+static void h4_mmc_cleanup(struct device *dev)
+{
+       menelaus_unregister_mmc_callback();
+}
+
+static struct omap_mmc_platform_data h4_mmc_data = {
+       .nr_slots               = 2,
+       .switch_slot            = h4_mmc_switch_slot,
+       .init                   = h4_mmc_late_init,
+       .cleanup                = h4_mmc_cleanup,
+       .slots[0] = {
+               .set_power      = h4_mmc_set_power,
+               .set_bus_mode   = h4_mmc_set_bus_mode,
+               .get_ro         = NULL,
+               .get_cover_state= h4_mmc_slot1_cover_state,
+               .ocr_mask       = MMC_VDD_165_195 |
+                                 MMC_VDD_28_29 | MMC_VDD_30_31 |
+                                 MMC_VDD_32_33 | MMC_VDD_33_34,
+               .name           = "slot1",
+       },
+       .slots[1] = {
+               .set_power      = h4_mmc_set_power,
+               .set_bus_mode   = h4_mmc_set_bus_mode,
+               .get_ro         = NULL,
+               .get_cover_state= h4_mmc_slot2_cover_state,
+               .ocr_mask       = MMC_VDD_165_195 | MMC_VDD_20_21 |
+                                 MMC_VDD_21_22 | MMC_VDD_22_23 | MMC_VDD_23_24 |
+                                 MMC_VDD_24_25 | MMC_VDD_27_28 | MMC_VDD_28_29 |
+                                 MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_32_33 |
+                                 MMC_VDD_33_34,
+               .name           = "slot2",
+       },
+};
+
+void __init h4_mmc_init(void)
+{
+       omap_set_mmc_info(1, &h4_mmc_data);
+}
+
+#else
+
+void __init h4_mmc_init(void)
+{
+}
+
+#endif
+
index ef91d21c5d8c5bcc4e2e8dfdd29d6b8321b626c8..9b494d00831a3981fa06581faf02b1c38215ef73 100644 (file)
@@ -385,12 +385,15 @@ static struct omap_mmc_config h4_mmc_config __initdata = {
        .mmc [0] = {
                .enabled        = 1,
                .wire4          = 1,
-               .wp_pin         = -1,
-               .power_pin      = -1,
-               .switch_pin     = -1,
+       },
+       .mmc [1] = {
+               .enabled        = 1,
+               .wire4          = 1,
        },
 };
 
+extern struct omap_mmc_platform_data h4_mmc_data;
+
 static struct omap_lcd_config h4_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
@@ -688,6 +691,7 @@ static void __init omap_h4_init(void)
        omap_board_config = h4_config;
        omap_board_config_size = ARRAY_SIZE(h4_config);
        omap_serial_init();
+       h4_mmc_init();
        omap_register_i2c_bus(1, 100, h4_i2c_board_info,
                              ARRAY_SIZE(h4_i2c_board_info));
 
index 23b5ac6e2822689ff148c4cf722a72475908999c..9cc2ff7e40ade8f133232db88509f86a91a33ad5 100644 (file)
@@ -29,6 +29,9 @@
 #ifndef __ASM_ARCH_OMAP_H4_H
 #define __ASM_ARCH_OMAP_H4_H
 
+/* MMC Prototypes */
+extern void h4_mmc_init(void);
+
 /* Placeholder for H4 specific defines */
 #define OMAP24XX_ETHR_GPIO_IRQ         92
 #endif /*  __ASM_ARCH_OMAP_H4_H */