On Wed, May 5, 2010 at 8:53 AM, G, Manjunath Kondaiah <manjugk@xxxxxx> wrote: > > >> -----Original Message----- >> From: linux-omap-owner@xxxxxxxxxxxxxxx >> [mailto:linux-omap-owner@xxxxxxxxxxxxxxx] On Behalf Of >> kishore kadiyala >> Sent: Tuesday, May 04, 2010 9:32 PM >> To: linux-mmc@xxxxxxxxxxxxxxx; linux-omap@xxxxxxxxxxxxxxx >> Cc: tony@xxxxxxxxxxx; Chikkature Rajashekar, Madhusudhan; >> jarkko.lavinen@xxxxxxxxx; rmk@xxxxxxxxxxxxxxxx; paul@xxxxxxxxx >> Subject: [PATCH v2 3/5] OMAP4-HSMMC: Adding MMC-TWL regulator changes >> >> This patch adds PBIAS Configuration during POWER ON and OFF. >> Also it adds MMC1 Card detect configuration on Phoenix >> >> Signed-off-by: Kishore Kadiyala <kishore.kadiyala@xxxxxx> >> --- >> arch/arm/mach-omap2/hsmmc.c | 121 >> ++++++++++++++++++++++++++--- >> arch/arm/plat-omap/include/plat/control.h | 17 ++++ >> include/linux/i2c/twl.h | 42 +++++++++- >> 3 files changed, 166 insertions(+), 14 deletions(-) >> >> diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c >> index f5ca16c..a73f011 100644 >> --- a/arch/arm/mach-omap2/hsmmc.c >> +++ b/arch/arm/mach-omap2/hsmmc.c >> @@ -14,6 +14,7 @@ >> #include <linux/string.h> >> #include <linux/delay.h> >> #include <linux/i2c/twl.h> >> +#include <linux/platform_device.h> >> #include <mach/hardware.h> >> #include <plat/control.h> >> #include <plat/mmc.h> >> @@ -25,6 +26,7 @@ >> >> static u16 control_pbias_offset; >> static u16 control_devconf1_offset; >> +static u16 control_mmc1; >> >> #define HSMMC_NAME_LEN 9 >> >> @@ -43,7 +45,7 @@ static int hsmmc_get_context_loss(struct >> device *dev) >> #define hsmmc_get_context_loss NULL >> #endif >> >> -static void hsmmc1_before_set_reg(struct device *dev, int slot, >> +static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, >> int power_on, int vdd) >> { >> u32 reg, prog_io; >> @@ -96,7 +98,7 @@ static void hsmmc1_before_set_reg(struct >> device *dev, int slot, >> } >> } >> >> -static void hsmmc1_after_set_reg(struct device *dev, int slot, >> +static void omap_hsmmc1_after_set_reg(struct device *dev, int slot, >> int power_on, int vdd) >> { >> u32 reg; >> @@ -120,6 +122,61 @@ static void hsmmc1_after_set_reg(struct >> device *dev, int slot, >> } >> } >> >> +static void omap4_hsmmc1_before_set_reg(struct device *dev, int slot, >> + int power_on, int vdd) >> +{ >> + u32 reg; >> + >> + /* >> + * Assume we power both OMAP VMMC1 (for CMD, CLK, >> DAT0..3) and the >> + * card with Vcc regulator (from twl4030 or whatever). >> OMAP has both >> + * 1.8V and 3.0V modes, controlled by the PBIAS register. >> + * >> + * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a >> supply, which >> + * is most naturally TWL VSIM; those pins also use PBIAS. >> + * >> + * FIXME handle VMMC1A as needed ... >> + */ >> + if (power_on) { >> + reg = omap_ctrl_readl(control_pbias_offset); >> + reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ | >> OMAP4_MMC1_PWRDNZ); >> + omap_ctrl_writel(reg, control_pbias_offset); >> + } else { >> + reg = omap_ctrl_readl(control_pbias_offset); >> + reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ | >> OMAP4_MMC1_PWRDNZ); >> + omap_ctrl_writel(reg, control_pbias_offset); >> + } >> +} >> + >> +static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot, >> + int power_on, int vdd) >> +{ >> + u32 reg; >> + >> + /* 100ms delay required for PBIAS configuration */ >> + msleep(100); >> + >> + if (power_on) { >> + reg = omap_ctrl_readl(control_pbias_offset); >> + reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ; >> + if ((1 << vdd) <= MMC_VDD_165_195) { >> + reg &= ~OMAP4_MMC1_PBIASLITE_VMODE; >> + reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ | >> + OMAP4_MMC1_PWRDNZ); >> + } else { >> + reg |= (OMAP4_MMC1_PBIASLITE_VMODE | >> + OMAP4_MMC1_PBIASLITE_PWRDNZ | >> + OMAP4_MMC1_PWRDNZ); >> + } >> + omap_ctrl_writel(reg, control_pbias_offset); >> + } else { >> + reg = omap_ctrl_readl(control_pbias_offset); >> + reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ | >> + OMAP4_MMC1_PBIASLITE_VMODE | OMAP4_MMC1_PWRDNZ); >> + omap_ctrl_writel(reg, control_pbias_offset); >> + } >> +} >> + >> static void hsmmc23_before_set_reg(struct device *dev, int slot, >> int power_on, int vdd) >> { >> @@ -140,6 +197,24 @@ static void >> hsmmc23_before_set_reg(struct device *dev, int slot, >> } >> } >> >> +static int mmc_twl_late_init(struct device *dev) >> +{ >> + int ret = 0; >> + struct platform_device *pdev = container_of(dev, >> + struct platform_device, dev); >> + >> + if (cpu_is_omap44xx()) { >> + /* MMC1 Card detect Configuration */ >> + if (pdev->id == 0) { >> + ret = omap4_hsmmc1_card_detect_config(); >> + if (ret < 0) >> + pr_err("Unable to configure" >> + "Card detect for MMC1\n"); >> + } >> + } >> + return ret; >> +} >> + >> static struct omap_mmc_platform_data >> *hsmmc_data[OMAP34XX_NR_MMC] __initdata; >> >> void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) >> @@ -147,13 +222,28 @@ void __init omap2_hsmmc_init(struct >> omap2_hsmmc_info >> struct omap2_hsmmc_info *c; >> int nr_hsmmc = ARRAY_SIZE(hsmmc_data); >> int i; >> + u32 reg; >> >> - if (cpu_is_omap2430()) { >> - control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; >> - control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; >> + if (!cpu_is_omap44xx()) { >> + if (cpu_is_omap2430()) { >> + control_pbias_offset = >> OMAP243X_CONTROL_PBIAS_LITE; >> + control_devconf1_offset = >> OMAP243X_CONTROL_DEVCONF1; >> + } else { >> + control_pbias_offset = >> OMAP343X_CONTROL_PBIAS_LITE; >> + control_devconf1_offset = >> OMAP343X_CONTROL_DEVCONF1; >> + } >> } else { >> - control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; >> - control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; >> + control_pbias_offset = OMAP44XX_CONTROL_PBIAS_LITE; >> + control_mmc1 = OMAP44XX_CONTROL_MMC1; >> + reg = omap_ctrl_readl(control_mmc1); >> + reg |= (OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP0 | >> + OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP1); >> + reg &= ~(OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP2 | >> + OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP3); >> + reg |= (OMAP4_CONTROL_SDMMC1_DR0_SPEEDCTRL | >> + OMAP4_CONTROL_SDMMC1_DR1_SPEEDCTRL | >> + OMAP4_CONTROL_SDMMC1_DR2_SPEEDCTRL); >> + omap_ctrl_writel(reg, control_mmc1); >> } >> >> for (c = controllers; c->mmc; c++) { >> @@ -186,6 +276,7 @@ void __init omap2_hsmmc_init(struct >> omap2_hsmmc_info *controllers) >> mmc->slots[0].wires = c->wires; >> mmc->slots[0].internal_clock = !c->ext_clock; >> mmc->dma_mask = 0xffffffff; >> + mmc->init = mmc_twl_late_init; >> >> mmc->get_context_loss_count = hsmmc_get_context_loss; >> >> @@ -220,10 +311,18 @@ void __init omap2_hsmmc_init(struct >> omap2_hsmmc_info >> >> switch (c->mmc) { >> case 1: >> - /* on-chip level shifting via PBIAS0/PBIAS1 */ >> - mmc->slots[0].before_set_reg = >> hsmmc1_before_set_reg; >> - mmc->slots[0].after_set_reg = >> hsmmc1_after_set_reg; >> - >> + if (cpu_is_omap44xx()) { >> + /* on-chip level shifting via >> PBIAS0/PBIAS1 */ >> + 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->wires > 4) { >> c->wires = 4; >> diff --git a/arch/arm/plat-omap/include/plat/control.h >> b/arch/arm/plat-omap/include/plat/control.h >> index a56deee..6d17a61 100644 >> --- a/arch/arm/plat-omap/include/plat/control.h >> +++ b/arch/arm/plat-omap/include/plat/control.h >> @@ -207,6 +207,9 @@ >> /* 44xx control status register offset */ >> #define OMAP44XX_CONTROL_STATUS 0x2c4 >> >> +/* 44xx-only CONTROL_GENERAL register offsets */ >> +#define OMAP44XX_CONTROL_MMC1 0x628 >> +#define OMAP44XX_CONTROL_PBIAS_LITE 0x600 >> /* >> * REVISIT: This list of registers is not comprehensive - >> there are more >> * that should be added. >> @@ -252,6 +255,20 @@ >> #define OMAP2_PBIASLITEPWRDNZ0 (1 << 1) >> #define OMAP2_PBIASLITEVMODE0 (1 << 0) >> >> +/* CONTROL_PBIAS_LITE bits for OMAP4 */ >> +#define OMAP4_MMC1_PWRDNZ (1 << 26) >> +#define OMAP4_MMC1_PBIASLITE_HIZ_MODE (1 << 25) >> +#define OMAP4_MMC1_PBIASLITE_PWRDNZ (1 << 22) >> +#define OMAP4_MMC1_PBIASLITE_VMODE (1 << 21) >> + >> +#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP0 (1 << 31) >> +#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP1 (1 << 30) >> +#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP2 (1 << 29) >> +#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP3 (1 << 28) >> +#define OMAP4_CONTROL_SDMMC1_DR0_SPEEDCTRL (1 << 27) >> +#define OMAP4_CONTROL_SDMMC1_DR1_SPEEDCTRL (1 << 26) >> +#define OMAP4_CONTROL_SDMMC1_DR2_SPEEDCTRL (1 << 25) >> + >> /* CONTROL_PROG_IO1 bits */ >> #define OMAP3630_PRG_SDMMC1_SPEEDCTRL (1 << 20) >> >> diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h >> index eb198db..423a355 100644 >> --- a/include/linux/i2c/twl.h >> +++ b/include/linux/i2c/twl.h >> @@ -142,6 +142,13 @@ >> #define TWL6030_CHARGER_FAULT_INT_MASK 0x60 >> >> #define TWL6030_MMCCTRL 0xEE >> +#define VMMC_AUTO_OFF (0x1 << 3) >> +#define SW_FC (0x1 << 2) >> + >> +#define TWL6030_CFG_INPUT_PUPD3 0xF2 >> +#define MMC_PU (0x1 << 3) >> +#define MMC_PD (0x1 << 2) >> + >> >> #define TWL4030_CLASS_ID 0x4030 >> #define TWL6030_CLASS_ID 0x6030 >> @@ -174,11 +181,40 @@ int twl_i2c_read(u8 mod_no, u8 *value, >> u8 reg, unsigned >> int twl6030_interrupt_unmask(u8 bit_mask, u8 offset); >> int twl6030_interrupt_mask(u8 bit_mask, u8 offset); >> >> -/* >> - * MMC1 Controller on OMAP4 uses Phoenix Irq for Card detect. >> - */ >> +/* MMC1 Controller on OMAP4 uses Phoenix Irq for Card detect */ >> int twl6030_mmc_card_detect(struct device *dev, int slot); >> >> +/* Configuring Card Detect for MMC1 */ >> +static inline int omap4_hsmmc1_card_detect_config(void) >> +{ >> + int res = -1; >> + u8 reg_val = 0; >> + >> + /* Unmasking the Card detect Interrupt line for MMC1 >> from Phoenix */ >> + if (twl_class_is_6030()) { >> + twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, >> + >> REG_INT_MSK_LINE_B); >> + twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, >> + >> REG_INT_MSK_STS_B); >> + } >> + >> + /* >> + * Intially Configuring MMC_CTRL for receving interrupts & >> + * Card status on TWL6030 for MMC1 >> + */ >> + reg_val |= (SW_FC & ~VMMC_AUTO_OFF); >> + twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL); >> + res = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, >> + >> TWL6030_CFG_INPUT_PUPD3); >> + if (res < 0) >> + return -EINVAL; > > Use return res; since "twl_i2c_read_u8" will be handling all types of > Errors. Agree > >> + reg_val = 0; >> + reg_val &= ~(MMC_PU | MMC_PD); > > >> + twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, >> + >> TWL6030_CFG_INPUT_PUPD3); > > reg_val is always zero. > You can replace with "twl_i2c_write_u8(TWL6030_MODULE_ID0, 0, > TWL6030_CFG_INPUT_PUPD3); I think should read the value first using "twl_i2c_read_u8" and set/reset bits accordingly. > > -Manjunath > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html