#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
-#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 VMMC1_DEV_GRP 0x27
#define VMMC1_CLR 0x00
u16 control_devconf_offset;
u32 devconf_loopback_clock;
int card_detect_gpio;
+ unsigned card_wp_gpio;
u8 twl_vmmc_dev_grp;
u8 twl_mmc_dedicated;
} hsmmc[] = {
{
.control_devconf_offset = OMAP2_CONTROL_DEVCONF0,
.devconf_loopback_clock = OMAP2_MMCSDIO1ADPCLKISEL,
- .card_detect_gpio = OMAP_MAX_GPIO_LINES,
+ .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)
{
- return gpio_get_value_cansleep(hsmmc[0].card_detect_gpio);
+ /* NOTE: assumes card detect signal is active-low */
+ return !gpio_get_value_cansleep(hsmmc[0].card_detect_gpio);
+}
+
+static int twl_mmc1_get_ro(struct device *dev, int slot)
+{
+ /* NOTE: assumes write protect signal is active-high */
+ return gpio_get_value_cansleep(hsmmc[0].card_wp_gpio);
}
/*
*/
static int twl_mmc1_late_init(struct device *dev)
{
+ struct omap_mmc_platform_data *mmc = dev->platform_data;
int ret = 0;
- /*
- * Configure TWL4030 GPIO parameters for MMC hotplug irq
- */
ret = gpio_request(hsmmc[0].card_detect_gpio, "mmc0_cd");
+ if (ret)
+ goto done;
+ ret = gpio_direction_input(hsmmc[0].card_detect_gpio);
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;
return ret;
err:
- dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
-
+ dev_err(dev, "Failed to configure TWL4030 card detect\n");
+done:
+ mmc->slots[0].card_detect_irq = 0;
+ mmc->slots[0].card_detect = NULL;
return ret;
}
#ifdef CONFIG_PM
-/*
- * Mask and unmask MMC Card Detect Interrupt
- * mask : 1
- * unmask : 0
- */
-static int twl_mmc_mask_cd_interrupt(int mask)
-{
- u8 reg = 0, ret = 0;
-
- ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, ®, TWL_GPIO_IMR1A);
- if (ret)
- 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)
- goto err;
-
- ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, ®, TWL_GPIO_ISR1A);
- if (ret)
- 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)
- goto err;
-
-err:
- return ret;
-}
-
-static int twl_mmc1_suspend(struct device *dev, int slot)
+static int twl_mmc_suspend(struct device *dev, int slot)
{
- int ret = 0;
+ struct omap_mmc_platform_data *mmc = dev->platform_data;
- disable_irq(hsmmc[0].card_detect_gpio);
- ret = twl_mmc_mask_cd_interrupt(1);
-
- return ret;
+ disable_irq(mmc->slots[0].card_detect_irq);
+ return 0;
}
-static int twl_mmc1_resume(struct device *dev, int slot)
+static int twl_mmc_resume(struct device *dev, int slot)
{
- int ret = 0;
-
- enable_irq(hsmmc[0].card_detect_gpio);
- ret = twl_mmc_mask_cd_interrupt(0);
+ struct omap_mmc_platform_data *mmc = dev->platform_data;
- return ret;
+ enable_irq(mmc->slots[0].card_detect_irq);
+ return 0;
}
#else
-#define twl_mmc1_suspend NULL
-#define twl_mmc1_resume NULL
+#define twl_mmc_suspend NULL
+#define twl_mmc_resume NULL
#endif
/*
MMC_VDD_29_30 |
MMC_VDD_30_31 | MMC_VDD_31_32;
mmc->slots[0].wires = c->wires;
- if (c->gpio_cd != -EINVAL)
- mmc->slots[0].card_detect_irq = c->gpio_cd;
mmc->dma_mask = 0xffffffff;
+ /* 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->init = twl_mmc1_late_init;
- mmc->cleanup = twl_mmc1_cleanup;
- mmc->suspend = twl_mmc1_suspend;
- mmc->resume = twl_mmc1_resume;
mmc->slots[0].set_power = twl_mmc1_set_power;
- mmc->slots[0].card_detect = twl_mmc1_card_detect;
+ 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("Unknown MMC configuration!\n");
+ pr_err("MMC%d configuration not supported!\n", c->mmc);
return;
}
}
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) | OD);
}
-/* NOTE: Read only switch not supported yet */
+
+static int omap_hsmmc_get_cd(struct mmc_host *mmc)
+{
+ struct mmc_omap_host *host = mmc_priv(mmc);
+ struct omap_mmc_platform_data *pdata = host->pdata;
+
+ if (!pdata->slots[0].card_detect)
+ return -ENOSYS;
+ return pdata->slots[0].card_detect(pdata->slots[0].card_detect_irq);
+}
+
+static int omap_hsmmc_get_ro(struct mmc_host *mmc)
+{
+ struct mmc_omap_host *host = mmc_priv(mmc);
+ struct omap_mmc_platform_data *pdata = host->pdata;
+
+ if (!pdata->slots[0].get_ro)
+ return -ENOSYS;
+ return pdata->slots[0].get_ro(host->dev, 0);
+}
+
static struct mmc_host_ops mmc_omap_ops = {
.request = omap_mmc_request,
.set_ios = omap_mmc_set_ios,
+ .get_cd = omap_hsmmc_get_cd,
+ .get_ro = omap_hsmmc_get_ro,
+ /* NYET -- enable_sdio_irq */
};
static int __init omap_mmc_probe(struct platform_device *pdev)
host->slot_id = 0;
host->mapbase = res->start;
host->base = ioremap(host->mapbase, SZ_4K);
+
+ platform_set_drvdata(pdev, host);
+ INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
+
mmc->ops = &mmc_omap_ops;
mmc->f_min = 400000;
mmc->f_max = 52000000;
goto err_irq;
}
+ if (pdata->init != NULL) {
+ if (pdata->init(&pdev->dev) != 0) {
+ dev_dbg(mmc_dev(host->mmc),
+ "Unable to configure MMC IRQs\n");
+ goto err_irq_cd_init;
+ }
+ }
+
/* Request IRQ for card detect */
if ((mmc_slot(host).card_detect_irq) && (mmc_slot(host).card_detect)) {
ret = request_irq(mmc_slot(host).card_detect_irq,
}
}
- INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
- if (pdata->init != NULL) {
- if (pdata->init(&pdev->dev) != 0) {
- dev_dbg(mmc_dev(host->mmc),
- "Unable to configure MMC IRQs\n");
- goto err_irq_cd_init;
- }
- }
-
OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
- platform_set_drvdata(pdev, host);
mmc_add_host(mmc);
if (host->pdata->slots[host->slot_id].name != NULL) {
device_remove_file(&mmc->class_dev, &dev_attr_cover_switch);
err_slot_name:
mmc_remove_host(mmc);
-err_irq_cd_init:
- free_irq(mmc_slot(host).card_detect_irq, host);
err_irq_cd:
+ free_irq(mmc_slot(host).card_detect_irq, host);
+err_irq_cd_init:
free_irq(host->irq, host);
err_irq:
clk_disable(host->fclk);