]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/mach-omap2/board-n800-mmc.c
ARM: OMAP: Clean up header file duplication
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap2 / board-n800-mmc.c
index b87c121821949d5cf15f55f6e5ed35145c60ebfa..bcee07d537e0f7e654384bce11a4b7d58e279071 100644 (file)
@@ -9,23 +9,32 @@
  * published by the Free Software Foundation.
  */
 
-#include <asm/arch/mmc.h>
-#include <asm/arch/menelaus.h>
-#include <asm/arch/gpio.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/menelaus.h>
 
-#ifdef CONFIG_MMC_OMAP
+#include <asm/mach-types.h>
+
+#include <mach/mmc.h>
+#include <mach/gpio.h>
+
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
 
 static const int slot_switch_gpio = 96;
-static const int slot1_wp_gpio = 23;
-static const int slot2_wp_gpio = 8;
-static int slot1_cover_closed;
-static int slot2_cover_closed;
+
+static const int n810_slot2_pw_vddf = 23;
+static const int n810_slot2_pw_vdd = 9;
+
+static int slot1_cover_open;
+static int slot2_cover_open;
 static struct device *mmc_device;
 
 /*
- * VMMC --> slot 1
- * VDCDC3_APE, VMCS2_APE --> slot 2
+ * VMMC   --> slot 1 (N800 & N810)
+ * VDCDC3_APE, VMCS2_APE --> slot 2 on N800
  * GPIO96 --> Menelaus GPIO2
+ * GPIO23 --> controls slot2 VSD    (N810 only)
+ * GPIO9  --> controls slot2 VIO_SD (N810 only)
  */
 
 static int n800_mmc_switch_slot(struct device *dev, int slot)
@@ -40,8 +49,8 @@ static int n800_mmc_switch_slot(struct device *dev, int slot)
        return 0;
 }
 
-static int n800_mmc_set_power(struct device *dev, int slot, int power_on,
-                               int vdd)
+static int n800_mmc_set_power_menelaus(struct device *dev, int slot,
+                                       int power_on, int vdd)
 {
        int mV;
 
@@ -109,14 +118,42 @@ static int n800_mmc_set_power(struct device *dev, int slot, int power_on,
        return 0;
 }
 
+static void nokia_mmc_set_power_internal(struct device *dev,
+                                        int power_on)
+{
+       dev_dbg(dev, "Set internal slot power %s\n",
+               power_on ? "on" : "off");
+
+       if (power_on) {
+               omap_set_gpio_dataout(n810_slot2_pw_vddf, 1);
+               udelay(30);
+               omap_set_gpio_dataout(n810_slot2_pw_vdd, 1);
+               udelay(100);
+       } else {
+               omap_set_gpio_dataout(n810_slot2_pw_vdd, 0);
+               msleep(50);
+               omap_set_gpio_dataout(n810_slot2_pw_vddf, 0);
+               msleep(50);
+       }
+}
+
+static int n800_mmc_set_power(struct device *dev, int slot, int power_on,
+                             int vdd)
+{
+       if (machine_is_nokia_n800() || slot == 0)
+               return n800_mmc_set_power_menelaus(dev, slot, power_on, vdd);
+
+       nokia_mmc_set_power_internal(dev, power_on);
+
+       return 0;
+}
+
 static int n800_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
 {
        int r;
 
-#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) {
@@ -135,55 +172,51 @@ static int n800_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
        return r;
 }
 
-#if 0
-static int n800_mmc_get_ro(struct device *dev, int slot)
-{
-       int ro;
-
-       slot++;
-       if (slot == 1)
-               ro = omap_get_gpio_datain(slot1_wp_gpio);
-       else
-               ro = omap_get_gpio_datain(slot2_wp_gpio);
-#ifdef CONFIG_MMC_DEBUG
-       dev_dbg(dev, "Get RO slot %d: %s\n",
-               slot, ro ? "read-only" : "read-write");
-#endif
-       return ro;
-}
-#endif
-
 static int n800_mmc_get_cover_state(struct device *dev, int slot)
 {
        slot++;
        BUG_ON(slot != 1 && slot != 2);
        if (slot == 1)
-               return slot1_cover_closed;
+               return slot1_cover_open;
        else
-               return slot2_cover_closed;
+               return slot2_cover_open;
 }
 
 static void n800_mmc_callback(void *data, u8 card_mask)
 {
-       if (card_mask & (1 << 1))
-               slot2_cover_closed = 0;
+       int bit, *openp, index;
+
+       if (machine_is_nokia_n800()) {
+               bit = 1 << 1;
+               openp = &slot2_cover_open;
+               index = 1;
+       } else {
+               bit = 1;
+               openp = &slot1_cover_open;
+               index = 0;
+       }
+
+       if (card_mask & bit)
+               *openp = 1;
        else
-               slot2_cover_closed = 1;
-        omap_mmc_notify_cover_event(mmc_device, 1, slot2_cover_closed);
+               *openp = 0;
+
+       omap_mmc_notify_cover_event(mmc_device, index, *openp);
 }
 
-void n800_mmc_slot1_cover_handler(void *arg, int state)
+void n800_mmc_slot1_cover_handler(void *arg, int closed_state)
 {
        if (mmc_device == NULL)
                return;
 
-       slot1_cover_closed = state;
-       omap_mmc_notify_cover_event(mmc_device, 0, state);
+       slot1_cover_open = !closed_state;
+       omap_mmc_notify_cover_event(mmc_device, 0, closed_state);
 }
 
 static int n800_mmc_late_init(struct device *dev)
 {
-       int r;
+       int r, bit, *openp;
+       int vs2sel;
 
        mmc_device = dev;
 
@@ -191,10 +224,22 @@ static int n800_mmc_late_init(struct device *dev)
        if (r < 0)
                return r;
 
+       if (machine_is_nokia_n800())
+               vs2sel = 0;
+       else
+               vs2sel = 2;
+
+       r = menelaus_set_mmc_slot(2, 0, vs2sel, 1);
+       if (r < 0)
+               return r;
+
+       n800_mmc_set_power(dev, 0, MMC_POWER_ON, 16); /* MMC_VDD_28_29 */
+       n800_mmc_set_power(dev, 1, MMC_POWER_ON, 16);
+
        r = menelaus_set_mmc_slot(1, 1, 0, 1);
        if (r < 0)
                return r;
-       r = menelaus_set_mmc_slot(2, 1, 0, 1);
+       r = menelaus_set_mmc_slot(2, 1, vs2sel, 1);
        if (r < 0)
                return r;
 
@@ -202,42 +247,78 @@ static int n800_mmc_late_init(struct device *dev)
        if (r < 0)
                return r;
 
-       if (r & (1 << 1))
-               slot2_cover_closed = 1;
+       if (machine_is_nokia_n800()) {
+               bit = 1 << 1;
+               openp = &slot2_cover_open;
+       } else {
+               bit = 1;
+               openp = &slot1_cover_open;
+               slot2_cover_open = 0;
+       }
+
+       /* All slot pin bits seem to be inversed until first swith change */
+       if (r == 0xf || r == (0xf & ~bit))
+               r = ~r;
+
+       if (r & bit)
+               *openp = 1;
        else
-               slot2_cover_closed = 0;
+               *openp = 0;
 
        r = menelaus_register_mmc_callback(n800_mmc_callback, NULL);
 
        return r;
 }
 
+static void n800_mmc_shutdown(struct device *dev)
+{
+       int vs2sel;
+
+       if (machine_is_nokia_n800())
+               vs2sel = 0;
+       else
+               vs2sel = 2;
+
+       menelaus_set_mmc_slot(1, 0, 0, 0);
+       menelaus_set_mmc_slot(2, 0, vs2sel, 0);
+}
+
 static void n800_mmc_cleanup(struct device *dev)
 {
        menelaus_unregister_mmc_callback();
+
+       omap_free_gpio(slot_switch_gpio);
+
+       if (machine_is_nokia_n810()) {
+               omap_free_gpio(n810_slot2_pw_vddf);
+               omap_free_gpio(n810_slot2_pw_vdd);
+       }
 }
 
-static struct omap_mmc_platform_data n800_mmc_data = {
-       .enabled                = 1,
+/*
+ * MMC controller1 has two slots that are multiplexed via I2C.
+ * MMC controller2 is not in use.
+ */
+static struct omap_mmc_platform_data mmc1_data = {
        .nr_slots               = 2,
-       .wire4                  = 1,
        .switch_slot            = n800_mmc_switch_slot,
        .init                   = n800_mmc_late_init,
        .cleanup                = n800_mmc_cleanup,
+       .shutdown               = n800_mmc_shutdown,
+       .max_freq               = 24000000,
+       .dma_mask               = 0xffffffff,
        .slots[0] = {
+               .wire4          = 1,
                .set_power      = n800_mmc_set_power,
                .set_bus_mode   = n800_mmc_set_bus_mode,
-               .get_ro         = NULL,
                .get_cover_state= n800_mmc_get_cover_state,
-               .ocr_mask       = MMC_VDD_165_195 |
-                                 MMC_VDD_28_29 | MMC_VDD_30_31 |
-                                 MMC_VDD_32_33 | MMC_VDD_33_34,
+               .ocr_mask       = MMC_VDD_165_195 | MMC_VDD_30_31 |
+                                 MMC_VDD_32_33   | MMC_VDD_33_34,
                .name           = "internal",
        },
        .slots[1] = {
                .set_power      = n800_mmc_set_power,
                .set_bus_mode   = n800_mmc_set_bus_mode,
-               .get_ro         = NULL,
                .get_cover_state= n800_mmc_get_cover_state,
                .ocr_mask       = MMC_VDD_165_195 | MMC_VDD_20_21 |
                                  MMC_VDD_21_22 | MMC_VDD_22_23 | MMC_VDD_23_24 |
@@ -248,21 +329,44 @@ static struct omap_mmc_platform_data n800_mmc_data = {
        },
 };
 
+static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
+
 void __init n800_mmc_init(void)
+
 {
-       omap_set_mmc_info(1, &n800_mmc_data);
+       if (machine_is_nokia_n810()) {
+               n800_mmc1_data.slots[0].name = "external";
+
+               /*
+                * Some Samsung Movinand chips do not like open-ended
+                * multi-block reads and fall to braind-dead state
+                * while doing so. Reducing the number of blocks in
+                * the transfer or delays in clock disable do not help
+                */
+               n800_mmc1_data.slots[1].name = "internal";
+               n800_mmc1_data.slots[1].ban_openended = 1;
+       }
+
        if (omap_request_gpio(slot_switch_gpio) < 0)
                BUG();
        omap_set_gpio_dataout(slot_switch_gpio, 0);
        omap_set_gpio_direction(slot_switch_gpio, 0);
-       if (omap_request_gpio(slot1_wp_gpio) < 0)
-               BUG();
-       if (omap_request_gpio(slot2_wp_gpio) < 0)
-               BUG();
-       omap_set_gpio_direction(slot1_wp_gpio, 1);
-       omap_set_gpio_direction(slot2_wp_gpio, 1);
-}
 
+       if (machine_is_nokia_n810()) {
+               if (omap_request_gpio(n810_slot2_pw_vddf) < 0)
+                       BUG();
+               omap_set_gpio_dataout(n810_slot2_pw_vddf, 0);
+               omap_set_gpio_direction(n810_slot2_pw_vddf, 0);
+
+               if (omap_request_gpio(n810_slot2_pw_vdd) < 0)
+                       BUG();
+               omap_set_gpio_dataout(n810_slot2_pw_vdd, 0);
+               omap_set_gpio_direction(n810_slot2_pw_vdd, 0);
+       }
+
+       mmc_data[0] = &mmc1_data;
+       omap2_init_mmc(mmc_data, OMAP24XX_NR_MMC);
+}
 #else
 
 void __init n800_mmc_init(void)