2 * linux/arch/arm/mach-omap2/board-sdp-hsmmc.c
4 * Copyright (C) 2007-2008 Texas Instruments
5 * Copyright (C) 2008 Nokia Corporation
6 * Author: Texas Instruments
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 #include <linux/err.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/interrupt.h>
17 #include <linux/delay.h>
18 #include <linux/gpio.h>
19 #include <linux/i2c/twl4030.h>
21 #include <mach/hardware.h>
23 #include <mach/board.h>
24 #include <asm/mach-types.h>
26 #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
28 #define VMMC1_DEV_GRP 0x27
29 #define P1_DEV_GRP 0x20
30 #define VMMC1_DEDICATED 0x2A
32 #define VSEL_3V15 0x03
34 #define TWL_GPIO_IMR1A 0x1C
35 #define TWL_GPIO_ISR1A 0x19
37 #define VSEL_S2_CLR 0x40
38 #define GPIO_0_BIT_POS (1 << 0)
40 #define OMAP2_CONTROL_DEVCONF0 0x48002274
41 #if defined(CONFIG_ARCH_OMAP2430)
42 #define OMAP2_CONTROL_DEVCONF1 0x490022E8
44 #define OMAP2_CONTROL_DEVCONF1 0x480022D8
47 #define OMAP2_MMCSDIO2ADPCLKISEL (1 << 6)
48 #define OMAP2_CONTROL_DEVCONF0_LBCLK (1 << 24)
49 #define OMAP2_CONTROL_DEVCONF1_ACTOV (1 << 31)
51 #define OMAP2_CONTROL_PBIAS_VMODE (1 << 0)
52 #define OMAP2_CONTROL_PBIAS_PWRDNZ (1 << 1)
53 #define OMAP2_CONTROL_PBIAS_SCTRL (1 << 2)
56 static const int mmc1_cd_gpio = OMAP_MAX_GPIO_LINES; /* HACK!! */
58 static int hsmmc_card_detect(int irq)
60 return gpio_get_value_cansleep(mmc1_cd_gpio);
64 * MMC Slot Initialization.
66 static int hsmmc_late_init(struct device *dev)
71 * Configure TWL4030 GPIO parameters for MMC hotplug irq
73 ret = gpio_request(mmc1_cd_gpio, "mmc0_cd");
77 ret = twl4030_set_gpio_debounce(0, true);
84 dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
88 static void hsmmc_cleanup(struct device *dev)
90 gpio_free(mmc1_cd_gpio);
96 * To mask and unmask MMC Card Detect Interrupt
100 static int mask_cd_interrupt(int mask)
104 ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, ®, TWL_GPIO_IMR1A);
108 reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
110 ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_IMR1A);
114 ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, ®, TWL_GPIO_ISR1A);
118 reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
120 ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_ISR1A);
128 static int hsmmc_suspend(struct device *dev, int slot)
132 disable_irq(TWL4030_GPIO_IRQ_NO(0));
133 ret = mask_cd_interrupt(1);
138 static int hsmmc_resume(struct device *dev, int slot)
142 enable_irq(TWL4030_GPIO_IRQ_NO(0));
143 ret = mask_cd_interrupt(0);
150 static int hsmmc_set_power(struct device *dev, int slot, int power_on,
153 u32 vdd_sel = 0, devconf = 0, reg = 0;
156 dev_dbg(dev, "power %s, vdd %i\n", power_on ? "on" : "off", vdd);
158 /* REVISIT: Using address directly till the control.h defines
161 #if defined(CONFIG_ARCH_OMAP2430)
162 #define OMAP2_CONTROL_PBIAS 0x490024A0
164 #define OMAP2_CONTROL_PBIAS 0x48002520
168 if (cpu_is_omap24xx())
169 devconf = omap_readl(OMAP2_CONTROL_DEVCONF1);
171 devconf = omap_readl(OMAP2_CONTROL_DEVCONF0);
177 if (cpu_is_omap24xx())
178 devconf |= OMAP2_CONTROL_DEVCONF1_ACTOV;
180 case MMC_VDD_165_195:
182 if (cpu_is_omap24xx())
183 devconf &= ~OMAP2_CONTROL_DEVCONF1_ACTOV;
186 if (cpu_is_omap24xx())
187 omap_writel(devconf, OMAP2_CONTROL_DEVCONF1);
189 omap_writel(devconf | OMAP2_CONTROL_DEVCONF0_LBCLK,
190 OMAP2_CONTROL_DEVCONF0);
192 reg = omap_readl(OMAP2_CONTROL_PBIAS);
193 reg |= OMAP2_CONTROL_PBIAS_SCTRL;
194 omap_writel(reg, OMAP2_CONTROL_PBIAS);
196 reg = omap_readl(OMAP2_CONTROL_PBIAS);
197 reg &= ~OMAP2_CONTROL_PBIAS_PWRDNZ;
198 omap_writel(reg, OMAP2_CONTROL_PBIAS);
200 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
201 P1_DEV_GRP, VMMC1_DEV_GRP);
205 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
206 vdd_sel, VMMC1_DEDICATED);
211 reg = omap_readl(OMAP2_CONTROL_PBIAS);
212 reg |= (OMAP2_CONTROL_PBIAS_SCTRL |
213 OMAP2_CONTROL_PBIAS_PWRDNZ);
214 if (vdd_sel == VSEL_18V)
215 reg &= ~OMAP2_CONTROL_PBIAS_VMODE;
217 reg |= OMAP2_CONTROL_PBIAS_VMODE;
218 omap_writel(reg, OMAP2_CONTROL_PBIAS);
225 /* For MMC1, Toggle PBIAS before every power up sequence */
226 reg = omap_readl(OMAP2_CONTROL_PBIAS);
227 reg &= ~OMAP2_CONTROL_PBIAS_PWRDNZ;
228 omap_writel(reg, OMAP2_CONTROL_PBIAS);
230 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
231 LDO_CLR, VMMC1_DEV_GRP);
235 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
236 VSEL_S2_CLR, VMMC1_DEDICATED);
240 /* 100ms delay required for PBIAS configuration */
242 reg = omap_readl(OMAP2_CONTROL_PBIAS);
243 reg |= (OMAP2_CONTROL_PBIAS_VMODE |
244 OMAP2_CONTROL_PBIAS_PWRDNZ |
245 OMAP2_CONTROL_PBIAS_SCTRL);
246 omap_writel(reg, OMAP2_CONTROL_PBIAS);
255 static struct omap_mmc_platform_data mmc1_data = {
257 .init = hsmmc_late_init,
258 .cleanup = hsmmc_cleanup,
260 .suspend = hsmmc_suspend,
261 .resume = hsmmc_resume,
263 .dma_mask = 0xffffffff,
266 .set_power = hsmmc_set_power,
267 .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34 |
269 .name = "first slot",
271 .card_detect_irq = TWL4030_GPIO_IRQ_NO(0),
272 .card_detect = hsmmc_card_detect,
276 /* ************************************************************************* */
278 #define VMMC2_DEV_GRP 0x2B
279 #define VMMC2_DEDICATED 0x2E
281 #define mmc2_cd_gpio (mmc1_cd_gpio + 1)
283 static int hsmmc2_card_detect(int irq)
285 return gpio_get_value_cansleep(mmc2_cd_gpio);
288 static int hsmmc2_late_init(struct device *dev)
292 ret = gpio_request(mmc2_cd_gpio, "mmc1_cd");
296 ret = twl4030_set_gpio_debounce(1, true);
303 dev_err(dev, "Failed to configure TWL4030 GPIO IRQ for MMC2\n");
307 static void hsmmc2_cleanup(struct device *dev)
309 gpio_free(mmc2_cd_gpio);
312 static int hsmmc2_set_power(struct device *dev, int slot, int power_on,
315 u32 vdd_sel = 0, ret = 0;
317 dev_dbg(dev, "power %s, vdd %i\n", power_on ? "on" : "off", vdd);
320 if (machine_is_omap3_pandora()) {
321 u32 devconf = omap_readl(OMAP2_CONTROL_DEVCONF1);
322 devconf &= ~OMAP2_MMCSDIO2ADPCLKISEL;
323 omap_writel(devconf, OMAP2_CONTROL_DEVCONF1);
331 case MMC_VDD_165_195:
335 dev_err(dev, "Bad vdd request %i for MMC2\n", vdd);
339 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
340 P1_DEV_GRP, VMMC2_DEV_GRP);
344 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
345 vdd_sel, VMMC2_DEDICATED);
352 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
353 LDO_CLR, VMMC2_DEV_GRP);
357 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
358 VSEL_S2_CLR, VMMC2_DEDICATED);
369 static struct omap_mmc_platform_data mmc2_data = {
371 .init = hsmmc2_late_init,
372 .cleanup = hsmmc2_cleanup,
373 /* TODO: .suspend, .resume */
374 .dma_mask = 0xffffffff,
377 .set_power = hsmmc2_set_power,
378 .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34 |
380 .name = "second slot",
382 .card_detect_irq = TWL4030_GPIO_IRQ_NO(1),
383 .card_detect = hsmmc2_card_detect,
387 /* ************************************************************************* */
389 static int hsmmc3_set_power(struct device *dev, int slot, int power_on,
392 /* nothing to do for MMC3 */
397 * Hack: Hardcoded WL1251 embedded data for Pandora
398 * - passed up via a dirty hack to the MMC platform data.
401 #include <linux/mmc/host.h>
402 #include <linux/mmc/card.h>
403 #include <linux/mmc/sdio_func.h>
404 #include <linux/mmc/sdio_ids.h>
406 static struct sdio_embedded_func wifi_func = {
407 .f_class = SDIO_CLASS_WLAN,
411 static struct embedded_sdio_data pandora_wifi_emb_data = {
429 static struct omap_mmc_platform_data mmc3_data = {
431 .dma_mask = 0xffffffff,
432 .embedded_sdio = &pandora_wifi_emb_data,
435 .set_power = hsmmc3_set_power,
436 .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21,
437 .name = "third slot",
441 /* ************************************************************************* */
443 static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC];
445 void __init hsmmc_init(void)
447 hsmmc_data[0] = &mmc1_data;
448 hsmmc_data[1] = &mmc2_data;
449 hsmmc_data[2] = &mmc3_data;
450 omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);
455 void __init hsmmc_init(void)