#define GPIO_0_BIT_POS (1 << 0)
#define VMMC1_DEV_GRP 0x27
-#define VMMC1_DEV_GRP_P1 0x20
-#define VMMC1_DEDICATED 0x2A
#define VMMC1_CLR 0x00
#define VMMC1_315V 0x03
#define VMMC1_300V 0x02
#define VMMC1_285V 0x01
#define VMMC1_185V 0x00
+#define VMMC1_DEDICATED 0x2A
+
+#define VMMC2_DEV_GRP 0x2B
+#define VMMC2_CLR 0x40
+#define VMMC2_315V 0x0c
+#define VMMC2_300V 0x0b
+#define VMMC2_285V 0x0a
+#define VMMC2_260V 0x08
+#define VMMC2_185V 0x06
+#define VMMC2_DEDICATED 0x2E
+
+#define VMMC_DEV_GRP_P1 0x20
static u16 control_pbias_offset;
u16 control_devconf_offset;
u32 devconf_loopback_clock;
int card_detect_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,
+ .twl_vmmc_dev_grp = VMMC1_DEV_GRP,
+ .twl_mmc_dedicated = VMMC1_DEDICATED,
},
{
/* control_devconf_offset set dynamically */
.devconf_loopback_clock = OMAP2_MMCSDIO2ADPCLKISEL,
+ .twl_vmmc_dev_grp = VMMC2_DEV_GRP,
+ .twl_mmc_dedicated = VMMC2_DEDICATED,
},
-};
+ };
static int hsmmc1_card_detect(int irq)
{
#ifdef CONFIG_PM
/*
- * To mask and unmask MMC Card Detect Interrupt
+ * Mask and unmask MMC Card Detect Interrupt
* mask : 1
* unmask : 0
*/
#endif
+/*
+ * Sets the MMC voltage in twl4030
+ */
+static int hsmmc_twl_set_voltage(struct hsmmc_controller *c, int vdd)
+{
+ int ret;
+ u8 vmmc, dev_grp_val;
+
+ switch (1 << vdd) {
+ case MMC_VDD_35_36:
+ case MMC_VDD_34_35:
+ case MMC_VDD_33_34:
+ case MMC_VDD_32_33:
+ case MMC_VDD_31_32:
+ case MMC_VDD_30_31:
+ if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+ vmmc = VMMC1_315V;
+ else
+ vmmc = VMMC2_315V;
+ break;
+ case MMC_VDD_29_30:
+ if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+ vmmc = VMMC1_315V;
+ else
+ vmmc = VMMC2_300V;
+ break;
+ case MMC_VDD_27_28:
+ case MMC_VDD_26_27:
+ if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+ vmmc = VMMC1_285V;
+ else
+ vmmc = VMMC2_285V;
+ break;
+ case MMC_VDD_25_26:
+ case MMC_VDD_24_25:
+ case MMC_VDD_23_24:
+ case MMC_VDD_22_23:
+ case MMC_VDD_21_22:
+ case MMC_VDD_20_21:
+ if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+ vmmc = VMMC1_285V;
+ else
+ vmmc = VMMC2_260V;
+ break;
+ case MMC_VDD_165_195:
+ if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+ vmmc = VMMC1_185V;
+ else
+ vmmc = VMMC2_185V;
+ break;
+ default:
+ vmmc = 0;
+ break;
+ }
+
+ if (vmmc)
+ dev_grp_val = VMMC_DEV_GRP_P1; /* Power up */
+ else
+ dev_grp_val = LDO_CLR; /* Power down */
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ dev_grp_val, c->twl_vmmc_dev_grp);
+ if (ret)
+ return ret;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ vmmc, c->twl_mmc_dedicated);
+
+ return ret;
+}
+
static int hsmmc1_set_power(struct device *dev, int slot, int power_on,
int vdd)
{
u32 reg;
int ret = 0;
- u16 control_devconf_offset = hsmmc[0].control_devconf_offset;
+ struct hsmmc_controller *c = &hsmmc[0];
if (power_on) {
- u32 vdd_sel = 0;
-
- switch (1 << vdd) {
- case MMC_VDD_33_34:
- case MMC_VDD_32_33:
- case MMC_VDD_31_32:
- case MMC_VDD_30_31:
- vdd_sel = VMMC1_315V;
- break;
- case MMC_VDD_29_30:
- vdd_sel = VMMC1_300V;
- break;
- case MMC_VDD_165_195:
- vdd_sel = VMMC1_185V;
- }
-
if (cpu_is_omap2430()) {
reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1);
- if (vdd_sel >= VMMC1_300V)
+ if ((1 << vdd) >= MMC_VDD_30_31)
reg |= OMAP243X_MMC1_ACTIVE_OVERWRITE;
else
reg &= ~OMAP243X_MMC1_ACTIVE_OVERWRITE;
/* REVISIT: Loop back clock not needed for 2430? */
if (!cpu_is_omap2430()) {
- reg = omap_ctrl_readl(control_devconf_offset);
+ reg = omap_ctrl_readl(c->control_devconf_offset);
reg |= OMAP2_MMCSDIO1ADPCLKISEL;
- omap_ctrl_writel(reg, control_devconf_offset);
+ omap_ctrl_writel(reg, c->control_devconf_offset);
}
reg = omap_ctrl_readl(control_pbias_offset);
reg &= ~OMAP2_PBIASLITEPWRDNZ0;
omap_ctrl_writel(reg, control_pbias_offset);
- ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- VMMC1_DEV_GRP_P1, VMMC1_DEV_GRP);
- if (ret)
- goto err;
-
- ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- vdd_sel, VMMC1_DEDICATED);
- if (ret)
- goto err;
+ ret = hsmmc_twl_set_voltage(c, vdd);
/* 100ms delay required for PBIAS configuration */
msleep(100);
-
reg = omap_ctrl_readl(control_pbias_offset);
reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0);
- if (vdd_sel == VMMC1_185V)
+ if ((1 << vdd) <= MMC_VDD_165_195)
reg &= ~OMAP2_PBIASLITEVMODE0;
else
reg |= OMAP2_PBIASLITEVMODE0;
omap_ctrl_writel(reg, control_pbias_offset);
-
- return ret;
-
} else {
- /* Power OFF */
-
- /* For MMC1, Toggle PBIAS before every power up sequence */
reg = omap_ctrl_readl(control_pbias_offset);
reg &= ~OMAP2_PBIASLITEPWRDNZ0;
omap_ctrl_writel(reg, control_pbias_offset);
- ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- LDO_CLR, VMMC1_DEV_GRP);
- if (ret)
- goto err;
-
- ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- VSEL_S2_CLR, VMMC1_DEDICATED);
- if (ret)
- goto err;
+ ret = hsmmc_twl_set_voltage(c, 0);
/* 100ms delay required for PBIAS configuration */
msleep(100);
-
reg = omap_ctrl_readl(control_pbias_offset);
reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 |
OMAP2_PBIASLITEVMODE0);
omap_ctrl_writel(reg, control_pbias_offset);
}
- return 0;
+ return ret;
+}
-err:
- return 1;
+static int hsmmc2_set_power(struct device *dev, int slot, int power_on, int vdd)
+{
+ int ret;
+
+ struct hsmmc_controller *c = &hsmmc[1];
+
+ if (power_on) {
+ u32 reg;
+
+ reg = omap_ctrl_readl(c->control_devconf_offset);
+ reg |= OMAP2_MMCSDIO2ADPCLKISEL;
+ omap_ctrl_writel(reg, c->control_devconf_offset);
+ ret = hsmmc_twl_set_voltage(c, vdd);
+ } else {
+ ret = hsmmc_twl_set_voltage(c, 0);
+ }
+
+ return ret;
}
static struct omap_mmc_platform_data mmc1_data = {
},
};
+static struct omap_mmc_platform_data mmc2_data = {
+ .nr_slots = 1,
+ .slots[0] = {
+ .set_power = hsmmc2_set_power,
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 |
+ MMC_VDD_29_30 | MMC_VDD_30_31 |
+ MMC_VDD_31_32 | MMC_VDD_32_33,
+ .name = "second slot",
+ },
+};
+
static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC];
-void __init hsmmc_init(void)
+void __init hsmmc_init(int controller_mask)
{
if (cpu_is_omap2430()) {
control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE;
hsmmc[1].control_devconf_offset = OMAP343X_CONTROL_DEVCONF1;
}
- hsmmc_data[0] = &mmc1_data;
+ if (controller_mask & HSMMC1)
+ hsmmc_data[0] = &mmc1_data;
+ if (controller_mask & HSMMC2)
+ hsmmc_data[1] = &mmc2_data;
+ if (controller_mask & HSMMC3)
+ pr_err("HSMMC: Unknown configuration for controller 3\n");
omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);
}
+++ /dev/null
-/*
- * include/asm-arm/arch-omap/hsmmc.h
- *
- * Hardware definitions for SD/MMC Controller on OMAP243x and OMAP34xx
- *
- * Initial creation by Felipe Balbi.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __ASM_ARCH_OMAP_HSMMC_H
-#define __ASM_ARCH_OMAP_HSMMC_H
-
-extern void hsmmc_init(void);
-
-#endif /* __ASM_ARCH_OMAP_HSMMC_H */
-