static u16 control_pbias_offset;
+#define HSMMC_NAME_LEN 9
+
static struct twl_mmc_controller {
- u16 control_devconf_offset;
+ struct omap_mmc_platform_data *mmc;
u32 devconf_loopback_clock;
- int card_detect_gpio;
- unsigned card_wp_gpio;
+ u16 control_devconf_offset;
u8 twl_vmmc_dev_grp;
u8 twl_mmc_dedicated;
+ char name[HSMMC_NAME_LEN];
} hsmmc[] = {
{
.control_devconf_offset = OMAP2_CONTROL_DEVCONF0,
.devconf_loopback_clock = OMAP2_MMCSDIO1ADPCLKISEL,
- .card_detect_gpio = -EINVAL,
.twl_vmmc_dev_grp = VMMC1_DEV_GRP,
.twl_mmc_dedicated = VMMC1_DEDICATED,
},
{
/* control_devconf_offset set dynamically */
.devconf_loopback_clock = OMAP2_MMCSDIO2ADPCLKISEL,
- .card_detect_gpio = -EINVAL,
.twl_vmmc_dev_grp = VMMC2_DEV_GRP,
.twl_mmc_dedicated = VMMC2_DEDICATED,
},
};
-static int twl_mmc1_card_detect(int irq)
+static int twl_mmc_card_detect(int irq)
{
- /* NOTE: assumes card detect signal is active-low */
- return !gpio_get_value_cansleep(hsmmc[0].card_detect_gpio);
+ 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_mmc1_get_ro(struct device *dev, int slot)
+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(hsmmc[0].card_wp_gpio);
+ return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
}
/*
* MMC Slot Initialization.
*/
-static int twl_mmc1_late_init(struct device *dev)
+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(hsmmc[0].card_detect_gpio, "mmc0_cd");
+ ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
if (ret)
goto done;
- ret = gpio_direction_input(hsmmc[0].card_detect_gpio);
+ ret = gpio_direction_input(mmc->slots[0].switch_pin);
if (ret)
goto err;
- /* FIXME assumes this uses (a) TWL4030 and (b) GPIO-0 ...
- * but that's not actually required.
- */
- ret = twl4030_set_gpio_debounce(0, true);
- 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 ret;
+ return 0;
err:
- dev_err(dev, "Failed to configure TWL4030 card detect\n");
+ 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_mmc1_cleanup(struct device *dev)
+static void twl_mmc_cleanup(struct device *dev)
{
- gpio_free(hsmmc[0].card_detect_gpio);
+ struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+ gpio_free(mmc->slots[0].switch_pin);
}
#ifdef CONFIG_PM
return ret;
}
-static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC];
-
-#define HSMMC_NAME_LEN 9
+static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
void __init hsmmc_init(struct twl4030_hsmmc_info *controllers)
{
struct twl4030_hsmmc_info *c;
+ int nr_hsmmc = ARRAY_SIZE(hsmmc_data);
if (cpu_is_omap2430()) {
control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE;
hsmmc[1].control_devconf_offset = OMAP243X_CONTROL_DEVCONF1;
+ nr_hsmmc = 2;
} else {
control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE;
hsmmc[1].control_devconf_offset = OMAP343X_CONTROL_DEVCONF1;
}
for (c = controllers; c->mmc; c++) {
- struct omap_mmc_platform_data *mmc;
- char *name;
+ struct twl_mmc_controller *twl = 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) {
return;
}
- name = kzalloc(HSMMC_NAME_LEN, GFP_KERNEL);
- if (!name) {
- kfree(mmc);
- pr_err("Cannot allocate memory for mmc name!\n");
- return;
- }
-
- sprintf(name, "mmc%islot%i", c->mmc, 1);
- mmc->slots[0].name = name;
+ sprintf(twl->name, "mmc%islot%i", c->mmc, 1);
+ mmc->slots[0].name = twl->name;
mmc->nr_slots = 1;
mmc->slots[0].ocr_mask = MMC_VDD_165_195 |
MMC_VDD_26_27 | MMC_VDD_27_28 |
mmc->slots[0].wires = c->wires;
mmc->dma_mask = 0xffffffff;
+ /* note: twl4030 card detect GPIOs normally switch VMMCx ... */
+ if (gpio_is_valid(c->gpio_cd)) {
+ mmc->init = twl_mmc_late_init;
+ mmc->cleanup = twl_mmc_cleanup;
+ mmc->suspend = twl_mmc_suspend;
+ mmc->resume = twl_mmc_resume;
+
+ mmc->slots[0].switch_pin = c->gpio_cd;
+ mmc->slots[0].card_detect_irq = gpio_to_irq(c->gpio_cd);
+ mmc->slots[0].card_detect = twl_mmc_card_detect;
+ } else
+ mmc->slots[0].switch_pin = -EINVAL;
+
+ /* write protect normally uses an OMAP gpio */
+ if (gpio_is_valid(c->gpio_wp)) {
+ gpio_request(c->gpio_wp, "mmc_wp");
+ gpio_direction_input(c->gpio_wp);
+
+ mmc->slots[0].gpio_wp = c->gpio_wp;
+ mmc->slots[0].get_ro = twl_mmc_get_ro;
+ } else
+ mmc->slots[0].gpio_wp = -EINVAL;
+
/* NOTE: we assume OMAP's MMC1 and MMC2 use
* the TWL4030's VMMC1 and VMMC2, respectively;
* and that OMAP's MMC3 isn't used.
switch (c->mmc) {
case 1:
mmc->slots[0].set_power = twl_mmc1_set_power;
- if (gpio_is_valid(c->gpio_cd)) {
- mmc->slots[0].card_detect_irq =
- gpio_to_irq(c->gpio_cd);
- mmc->suspend = twl_mmc_suspend;
- mmc->resume = twl_mmc_resume;
-
- /* NOTE: hsmmc[0] is hard-wired ... */
- hsmmc[0].card_detect_gpio = c->gpio_cd;
- mmc->init = twl_mmc1_late_init;
- mmc->cleanup = twl_mmc1_cleanup;
- mmc->slots[0].card_detect =
- twl_mmc1_card_detect;
- }
- if (gpio_is_valid(c->gpio_wp)) {
- gpio_request(c->gpio_wp, "mmc0_wp");
- gpio_direction_input(c->gpio_wp);
-
- /* NOTE: hsmmc[0] is hard-wired ... */
- hsmmc[0].card_wp_gpio = c->gpio_wp;
- mmc->slots[0].get_ro = twl_mmc1_get_ro;
- }
- hsmmc_data[0] = mmc;
break;
case 2:
- /* FIXME rework interfaces so that mmc2 (and mmc3) can
- * be fully functional... hsmmc[] shouldn't hold gpios.
- */
mmc->slots[0].set_power = twl_mmc2_set_power;
- if (gpio_is_valid(c->gpio_cd))
- pr_warning("MMC2 detect nyet supported!\n");
- if (gpio_is_valid(c->gpio_wp))
- pr_warning("MMC2 WP nyet supported!\n");
- hsmmc_data[1] = mmc;
break;
default:
pr_err("MMC%d configuration not supported!\n", c->mmc);
- return;
+ continue;
}
+ hsmmc_data[c->mmc - 1] = mmc;
}
omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);