OMAP: adapt hsmmc to hwmod framework
[deliverable/linux.git] / arch / arm / mach-omap2 / hsmmc.c
index 1348ac3d60e3580d5609ce2ac0193795cbfcc812..d492bc4d34289eb16d88eeb0f66908817a0cc72f 100644 (file)
@@ -17,6 +17,7 @@
 #include <plat/mmc.h>
 #include <plat/omap-pm.h>
 #include <plat/mux.h>
+#include <plat/omap_device.h>
 
 #include "mux.h"
 #include "hsmmc.h"
@@ -30,10 +31,6 @@ static u16 control_mmc1;
 
 #define HSMMC_NAME_LEN 9
 
-static struct hsmmc_controller {
-       char                            name[HSMMC_NAME_LEN + 1];
-} hsmmc[OMAP34XX_NR_MMC];
-
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
 
 static int hsmmc_get_context_loss(struct device *dev)
@@ -287,13 +284,203 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
        }
 }
 
-static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
+static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
+                                       struct omap_mmc_platform_data *mmc)
+{
+       char *hc_name;
+
+       hc_name = kzalloc(sizeof(char) * (HSMMC_NAME_LEN + 1), GFP_KERNEL);
+       if (!hc_name) {
+               pr_err("Cannot allocate memory for controller slot name\n");
+               kfree(hc_name);
+               return -ENOMEM;
+       }
+
+       if (c->name)
+               strncpy(hc_name, c->name, HSMMC_NAME_LEN);
+       else
+               snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i",
+                                                               c->mmc, 1);
+       mmc->slots[0].name = hc_name;
+       mmc->nr_slots = 1;
+       mmc->slots[0].caps = c->caps;
+       mmc->slots[0].internal_clock = !c->ext_clock;
+       mmc->dma_mask = 0xffffffff;
+       if (cpu_is_omap44xx())
+               mmc->reg_offset = OMAP4_MMC_REG_OFFSET;
+       else
+               mmc->reg_offset = 0;
+
+       mmc->get_context_loss_count = hsmmc_get_context_loss;
+
+       mmc->slots[0].switch_pin = c->gpio_cd;
+       mmc->slots[0].gpio_wp = c->gpio_wp;
+
+       mmc->slots[0].remux = c->remux;
+       mmc->slots[0].init_card = c->init_card;
+
+       if (c->cover_only)
+               mmc->slots[0].cover = 1;
+
+       if (c->nonremovable)
+               mmc->slots[0].nonremovable = 1;
+
+       if (c->power_saving)
+               mmc->slots[0].power_saving = 1;
+
+       if (c->no_off)
+               mmc->slots[0].no_off = 1;
+
+       if (c->vcc_aux_disable_is_sleep)
+               mmc->slots[0].vcc_aux_disable_is_sleep = 1;
+
+       /*
+        * NOTE:  MMC slots should have a Vcc regulator set up.
+        * This may be from a TWL4030-family chip, another
+        * controllable regulator, or a fixed supply.
+        *
+        * temporary HACK: ocr_mask instead of fixed supply
+        */
+       mmc->slots[0].ocr_mask = c->ocr_mask;
+
+       if (cpu_is_omap3517() || cpu_is_omap3505())
+               mmc->slots[0].set_power = nop_mmc_set_power;
+       else
+               mmc->slots[0].features |= HSMMC_HAS_PBIAS;
+
+       if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0))
+               mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+
+       switch (c->mmc) {
+       case 1:
+               if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
+                       /* on-chip level shifting via PBIAS0/PBIAS1 */
+                       if (cpu_is_omap44xx()) {
+                               mmc->slots[0].before_set_reg =
+                                               omap4_hsmmc1_before_set_reg;
+                               mmc->slots[0].after_set_reg =
+                                               omap4_hsmmc1_after_set_reg;
+                       } else {
+                               mmc->slots[0].before_set_reg =
+                                               omap_hsmmc1_before_set_reg;
+                               mmc->slots[0].after_set_reg =
+                                               omap_hsmmc1_after_set_reg;
+                       }
+               }
+
+               /* OMAP3630 HSMMC1 supports only 4-bit */
+               if (cpu_is_omap3630() &&
+                               (c->caps & MMC_CAP_8_BIT_DATA)) {
+                       c->caps &= ~MMC_CAP_8_BIT_DATA;
+                       c->caps |= MMC_CAP_4_BIT_DATA;
+                       mmc->slots[0].caps = c->caps;
+               }
+               break;
+       case 2:
+               if (c->ext_clock)
+                       c->transceiver = 1;
+               if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) {
+                       c->caps &= ~MMC_CAP_8_BIT_DATA;
+                       c->caps |= MMC_CAP_4_BIT_DATA;
+               }
+               /* FALLTHROUGH */
+       case 3:
+               if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
+                       /* off-chip level shifting, or none */
+                       mmc->slots[0].before_set_reg = hsmmc23_before_set_reg;
+                       mmc->slots[0].after_set_reg = NULL;
+               }
+               break;
+       case 4:
+       case 5:
+               mmc->slots[0].before_set_reg = NULL;
+               mmc->slots[0].after_set_reg = NULL;
+               break;
+       default:
+               pr_err("MMC%d configuration not supported!\n", c->mmc);
+               kfree(hc_name);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static struct omap_device_pm_latency omap_hsmmc_latency[] = {
+       [0] = {
+               .deactivate_func = omap_device_idle_hwmods,
+               .activate_func   = omap_device_enable_hwmods,
+               .flags           = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+       },
+       /*
+        * XXX There should also be an entry here to power off/on the
+        * MMC regulators/PBIAS cells, etc.
+        */
+};
+
+#define MAX_OMAP_MMC_HWMOD_NAME_LEN            16
+
+void __init omap_init_hsmmc(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr)
+{
+       struct omap_hwmod *oh;
+       struct omap_device *od;
+       struct omap_device_pm_latency *ohl;
+       char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN];
+       struct omap_mmc_platform_data *mmc_data;
+       struct omap_mmc_dev_attr *mmc_dev_attr;
+       char *name;
+       int l;
+       int ohl_cnt = 0;
+
+       mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL);
+       if (!mmc_data) {
+               pr_err("Cannot allocate memory for mmc device!\n");
+               goto done;
+       }
+
+       if (omap_hsmmc_pdata_init(hsmmcinfo, mmc_data) < 0) {
+               pr_err("%s fails!\n", __func__);
+               goto done;
+       }
+       omap_hsmmc_mux(mmc_data, (ctrl_nr - 1));
+
+       name = "mmci-omap-hs";
+       ohl = omap_hsmmc_latency;
+       ohl_cnt = ARRAY_SIZE(omap_hsmmc_latency);
+
+       l = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN,
+                    "mmc%d", ctrl_nr);
+       WARN(l >= MAX_OMAP_MMC_HWMOD_NAME_LEN,
+            "String buffer overflow in MMC%d device setup\n", ctrl_nr);
+       oh = omap_hwmod_lookup(oh_name);
+       if (!oh) {
+               pr_err("Could not look up %s\n", oh_name);
+               kfree(mmc_data->slots[0].name);
+               goto done;
+       }
+
+       if (oh->dev_attr != NULL) {
+               mmc_dev_attr = oh->dev_attr;
+               mmc_data->controller_flags = mmc_dev_attr->flags;
+       }
+
+       od = omap_device_build(name, ctrl_nr - 1, oh, mmc_data,
+               sizeof(struct omap_mmc_platform_data), ohl, ohl_cnt, false);
+       if (IS_ERR(od)) {
+               WARN(1, "Cant build omap_device for %s:%s.\n", name, oh->name);
+               kfree(mmc_data->slots[0].name);
+               goto done;
+       }
+       /*
+        * return device handle to board setup code
+        * required to populate for regulator framework structure
+        */
+       hsmmcinfo->dev = &od->pdev.dev;
+
+done:
+       kfree(mmc_data);
+}
 
 void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
 {
-       struct omap2_hsmmc_info *c;
-       int nr_hsmmc = ARRAY_SIZE(hsmmc_data);
-       int i;
        u32 reg;
 
        if (!cpu_is_omap44xx()) {
@@ -319,148 +506,9 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
                omap4_ctrl_pad_writel(reg, control_mmc1);
        }
 
-       for (c = controllers; c->mmc; c++) {
-               struct hsmmc_controller *hc = hsmmc + c->mmc - 1;
-               struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1];
-
-               if (!c->mmc || c->mmc > nr_hsmmc) {
-                       pr_debug("MMC%d: no such controller\n", c->mmc);
-                       continue;
-               }
-               if (mmc) {
-                       pr_debug("MMC%d: already configured\n", c->mmc);
-                       continue;
-               }
-
-               mmc = kzalloc(sizeof(struct omap_mmc_platform_data),
-                             GFP_KERNEL);
-               if (!mmc) {
-                       pr_err("Cannot allocate memory for mmc device!\n");
-                       goto done;
-               }
-
-               if (c->name)
-                       strncpy(hc->name, c->name, HSMMC_NAME_LEN);
-               else
-                       snprintf(hc->name, ARRAY_SIZE(hc->name),
-                               "mmc%islot%i", c->mmc, 1);
-               mmc->slots[0].name = hc->name;
-               mmc->nr_slots = 1;
-               mmc->slots[0].caps = c->caps;
-               mmc->slots[0].internal_clock = !c->ext_clock;
-               mmc->dma_mask = 0xffffffff;
-               if (cpu_is_omap44xx())
-                       mmc->reg_offset = OMAP4_MMC_REG_OFFSET;
-               else
-                       mmc->reg_offset = 0;
-
-               mmc->get_context_loss_count = hsmmc_get_context_loss;
-
-               mmc->slots[0].switch_pin = c->gpio_cd;
-               mmc->slots[0].gpio_wp = c->gpio_wp;
-
-               mmc->slots[0].remux = c->remux;
-               mmc->slots[0].init_card = c->init_card;
-
-               if (c->cover_only)
-                       mmc->slots[0].cover = 1;
-
-               if (c->nonremovable)
-                       mmc->slots[0].nonremovable = 1;
-
-               if (c->power_saving)
-                       mmc->slots[0].power_saving = 1;
-
-               if (c->no_off)
-                       mmc->slots[0].no_off = 1;
-
-               if (c->vcc_aux_disable_is_sleep)
-                       mmc->slots[0].vcc_aux_disable_is_sleep = 1;
-
-               /* NOTE:  MMC slots should have a Vcc regulator set up.
-                * This may be from a TWL4030-family chip, another
-                * controllable regulator, or a fixed supply.
-                *
-                * temporary HACK: ocr_mask instead of fixed supply
-                */
-               mmc->slots[0].ocr_mask = c->ocr_mask;
-
-               if (cpu_is_omap3517() || cpu_is_omap3505())
-                       mmc->slots[0].set_power = nop_mmc_set_power;
-               else
-                       mmc->slots[0].features |= HSMMC_HAS_PBIAS;
-
-               if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0))
-                       mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
-
-               switch (c->mmc) {
-               case 1:
-                       if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
-                               /* on-chip level shifting via PBIAS0/PBIAS1 */
-                               if (cpu_is_omap44xx()) {
-                                       mmc->slots[0].before_set_reg =
-                                               omap4_hsmmc1_before_set_reg;
-                                       mmc->slots[0].after_set_reg =
-                                               omap4_hsmmc1_after_set_reg;
-                               } else {
-                                       mmc->slots[0].before_set_reg =
-                                               omap_hsmmc1_before_set_reg;
-                                       mmc->slots[0].after_set_reg =
-                                               omap_hsmmc1_after_set_reg;
-                               }
-                       }
-
-                       /* Omap3630 HSMMC1 supports only 4-bit */
-                       if (cpu_is_omap3630() &&
-                                       (c->caps & MMC_CAP_8_BIT_DATA)) {
-                               c->caps &= ~MMC_CAP_8_BIT_DATA;
-                               c->caps |= MMC_CAP_4_BIT_DATA;
-                               mmc->slots[0].caps = c->caps;
-                       }
-                       break;
-               case 2:
-                       if (c->ext_clock)
-                               c->transceiver = 1;
-                       if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) {
-                               c->caps &= ~MMC_CAP_8_BIT_DATA;
-                               c->caps |= MMC_CAP_4_BIT_DATA;
-                       }
-                       /* FALLTHROUGH */
-               case 3:
-                       if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
-                               /* off-chip level shifting, or none */
-                               mmc->slots[0].before_set_reg = hsmmc23_before_set_reg;
-                               mmc->slots[0].after_set_reg = NULL;
-                       }
-                       break;
-               case 4:
-               case 5:
-                       mmc->slots[0].before_set_reg = NULL;
-                       mmc->slots[0].after_set_reg = NULL;
-                       break;
-               default:
-                       pr_err("MMC%d configuration not supported!\n", c->mmc);
-                       kfree(mmc);
-                       continue;
-               }
-               hsmmc_data[c->mmc - 1] = mmc;
-               omap_hsmmc_mux(hsmmc_data[c->mmc - 1], (c->mmc - 1));
-       }
-
-       omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);
-
-       /* pass the device nodes back to board setup code */
-       for (c = controllers; c->mmc; c++) {
-               struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1];
+       for (; controllers->mmc; controllers++)
+               omap_init_hsmmc(controllers, controllers->mmc);
 
-               if (!c->mmc || c->mmc > nr_hsmmc)
-                       continue;
-               c->dev = mmc->dev;
-       }
-
-done:
-       for (i = 0; i < nr_hsmmc; i++)
-               kfree(hsmmc_data[i]);
 }
 
 #endif
This page took 0.029223 seconds and 5 git commands to generate.