| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 1 | /* | 
| Adrian Hunter | d02a900 | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 2 |  * linux/arch/arm/mach-omap2/hsmmc.c | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 3 |  * | 
 | 4 |  * Copyright (C) 2007-2008 Texas Instruments | 
 | 5 |  * Copyright (C) 2008 Nokia Corporation | 
 | 6 |  * Author: Texas Instruments | 
 | 7 |  * | 
 | 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. | 
 | 11 |  */ | 
| Adrian Hunter | db0fefc | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 12 | #include <linux/kernel.h> | 
 | 13 | #include <linux/slab.h> | 
 | 14 | #include <linux/string.h> | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 15 | #include <linux/delay.h> | 
| Silesh C V | 5e4698f | 2011-07-04 04:10:00 -0700 | [diff] [blame] | 16 | #include <linux/gpio.h> | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 17 | #include <mach/hardware.h> | 
| Tony Lindgren | ce491cf | 2009-10-20 09:40:47 -0700 | [diff] [blame] | 18 | #include <plat/mmc.h> | 
| Adrian Hunter | e3df0fb | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 19 | #include <plat/omap-pm.h> | 
| Kishore Kadiyala | d8d0a61 | 2011-02-28 20:48:03 +0530 | [diff] [blame] | 20 | #include <plat/mux.h> | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 21 | #include <plat/omap_device.h> | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 22 |  | 
| Kishore Kadiyala | d8d0a61 | 2011-02-28 20:48:03 +0530 | [diff] [blame] | 23 | #include "mux.h" | 
| Adrian Hunter | d02a900 | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 24 | #include "hsmmc.h" | 
| Paul Walmsley | 4814ced | 2010-10-08 11:40:20 -0600 | [diff] [blame] | 25 | #include "control.h" | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 26 |  | 
| Adrian Hunter | db0fefc | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 27 | #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 28 |  | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 29 | static u16 control_pbias_offset; | 
 | 30 | static u16 control_devconf1_offset; | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 31 | static u16 control_mmc1; | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 32 |  | 
 | 33 | #define HSMMC_NAME_LEN	9 | 
 | 34 |  | 
| Denis Karpov | 1887bde | 2009-09-22 16:44:40 -0700 | [diff] [blame] | 35 | #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) | 
 | 36 |  | 
| Adrian Hunter | 68ff042 | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 37 | static int hsmmc_get_context_loss(struct device *dev) | 
| Denis Karpov | 1887bde | 2009-09-22 16:44:40 -0700 | [diff] [blame] | 38 | { | 
| Adrian Hunter | e3df0fb | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 39 | 	return omap_pm_get_dev_context_loss_count(dev); | 
| Denis Karpov | 1887bde | 2009-09-22 16:44:40 -0700 | [diff] [blame] | 40 | } | 
 | 41 |  | 
 | 42 | #else | 
| Adrian Hunter | 68ff042 | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 43 | #define hsmmc_get_context_loss NULL | 
| Denis Karpov | 1887bde | 2009-09-22 16:44:40 -0700 | [diff] [blame] | 44 | #endif | 
 | 45 |  | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 46 | static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, | 
| Adrian Hunter | db0fefc | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 47 | 				  int power_on, int vdd) | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 48 | { | 
| Madhu | 555d503 | 2009-11-22 10:11:08 -0800 | [diff] [blame] | 49 | 	u32 reg, prog_io; | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 50 | 	struct omap_mmc_platform_data *mmc = dev->platform_data; | 
 | 51 |  | 
| Adrian Hunter | ce6f001 | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 52 | 	if (mmc->slots[0].remux) | 
 | 53 | 		mmc->slots[0].remux(dev, slot, power_on); | 
 | 54 |  | 
| David Brownell | 0329c37 | 2009-03-23 18:23:47 -0700 | [diff] [blame] | 55 | 	/* | 
 | 56 | 	 * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the | 
| David Brownell | b583f26 | 2009-05-28 14:04:03 -0700 | [diff] [blame] | 57 | 	 * card with Vcc regulator (from twl4030 or whatever).  OMAP has both | 
| David Brownell | 0329c37 | 2009-03-23 18:23:47 -0700 | [diff] [blame] | 58 | 	 * 1.8V and 3.0V modes, controlled by the PBIAS register. | 
 | 59 | 	 * | 
 | 60 | 	 * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which | 
 | 61 | 	 * is most naturally TWL VSIM; those pins also use PBIAS. | 
| David Brownell | b583f26 | 2009-05-28 14:04:03 -0700 | [diff] [blame] | 62 | 	 * | 
 | 63 | 	 * FIXME handle VMMC1A as needed ... | 
| David Brownell | 0329c37 | 2009-03-23 18:23:47 -0700 | [diff] [blame] | 64 | 	 */ | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 65 | 	if (power_on) { | 
 | 66 | 		if (cpu_is_omap2430()) { | 
 | 67 | 			reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1); | 
 | 68 | 			if ((1 << vdd) >= MMC_VDD_30_31) | 
 | 69 | 				reg |= OMAP243X_MMC1_ACTIVE_OVERWRITE; | 
 | 70 | 			else | 
 | 71 | 				reg &= ~OMAP243X_MMC1_ACTIVE_OVERWRITE; | 
 | 72 | 			omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1); | 
 | 73 | 		} | 
 | 74 |  | 
 | 75 | 		if (mmc->slots[0].internal_clock) { | 
 | 76 | 			reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); | 
 | 77 | 			reg |= OMAP2_MMCSDIO1ADPCLKISEL; | 
 | 78 | 			omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0); | 
 | 79 | 		} | 
 | 80 |  | 
 | 81 | 		reg = omap_ctrl_readl(control_pbias_offset); | 
| Madhu | 555d503 | 2009-11-22 10:11:08 -0800 | [diff] [blame] | 82 | 		if (cpu_is_omap3630()) { | 
 | 83 | 			/* Set MMC I/O to 52Mhz */ | 
 | 84 | 			prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1); | 
 | 85 | 			prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL; | 
 | 86 | 			omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1); | 
 | 87 | 		} else { | 
 | 88 | 			reg |= OMAP2_PBIASSPEEDCTRL0; | 
 | 89 | 		} | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 90 | 		reg &= ~OMAP2_PBIASLITEPWRDNZ0; | 
 | 91 | 		omap_ctrl_writel(reg, control_pbias_offset); | 
| Adrian Hunter | db0fefc | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 92 | 	} else { | 
 | 93 | 		reg = omap_ctrl_readl(control_pbias_offset); | 
 | 94 | 		reg &= ~OMAP2_PBIASLITEPWRDNZ0; | 
 | 95 | 		omap_ctrl_writel(reg, control_pbias_offset); | 
 | 96 | 	} | 
 | 97 | } | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 98 |  | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 99 | static void omap_hsmmc1_after_set_reg(struct device *dev, int slot, | 
| Adrian Hunter | db0fefc | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 100 | 				 int power_on, int vdd) | 
 | 101 | { | 
 | 102 | 	u32 reg; | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 103 |  | 
| Adrian Hunter | db0fefc | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 104 | 	/* 100ms delay required for PBIAS configuration */ | 
 | 105 | 	msleep(100); | 
 | 106 |  | 
 | 107 | 	if (power_on) { | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 108 | 		reg = omap_ctrl_readl(control_pbias_offset); | 
 | 109 | 		reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0); | 
 | 110 | 		if ((1 << vdd) <= MMC_VDD_165_195) | 
 | 111 | 			reg &= ~OMAP2_PBIASLITEVMODE0; | 
 | 112 | 		else | 
 | 113 | 			reg |= OMAP2_PBIASLITEVMODE0; | 
 | 114 | 		omap_ctrl_writel(reg, control_pbias_offset); | 
 | 115 | 	} else { | 
 | 116 | 		reg = omap_ctrl_readl(control_pbias_offset); | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 117 | 		reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 | | 
 | 118 | 			OMAP2_PBIASLITEVMODE0); | 
 | 119 | 		omap_ctrl_writel(reg, control_pbias_offset); | 
 | 120 | 	} | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 121 | } | 
 | 122 |  | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 123 | static void omap4_hsmmc1_before_set_reg(struct device *dev, int slot, | 
 | 124 | 				  int power_on, int vdd) | 
 | 125 | { | 
 | 126 | 	u32 reg; | 
 | 127 |  | 
 | 128 | 	/* | 
 | 129 | 	 * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the | 
 | 130 | 	 * card with Vcc regulator (from twl4030 or whatever).  OMAP has both | 
 | 131 | 	 * 1.8V and 3.0V modes, controlled by the PBIAS register. | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 132 | 	 */ | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 133 | 	reg = omap4_ctrl_pad_readl(control_pbias_offset); | 
 | 134 | 	reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK | | 
| Balaji T K | ff2beb1 | 2011-10-03 17:52:50 +0530 | [diff] [blame] | 135 | 		OMAP4_MMC1_PWRDNZ_MASK | | 
 | 136 | 		OMAP4_MMC1_PBIASLITE_VMODE_MASK); | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 137 | 	omap4_ctrl_pad_writel(reg, control_pbias_offset); | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 138 | } | 
 | 139 |  | 
 | 140 | static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot, | 
 | 141 | 				 int power_on, int vdd) | 
 | 142 | { | 
 | 143 | 	u32 reg; | 
| Balaji T K | 1fcecf2 | 2011-06-01 16:45:22 +0530 | [diff] [blame] | 144 | 	unsigned long timeout; | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 145 |  | 
 | 146 | 	if (power_on) { | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 147 | 		reg = omap4_ctrl_pad_readl(control_pbias_offset); | 
 | 148 | 		reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK; | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 149 | 		if ((1 << vdd) <= MMC_VDD_165_195) | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 150 | 			reg &= ~OMAP4_MMC1_PBIASLITE_VMODE_MASK; | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 151 | 		else | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 152 | 			reg |= OMAP4_MMC1_PBIASLITE_VMODE_MASK; | 
 | 153 | 		reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK | | 
| Bryan Buckley | 3696d30 | 2011-09-30 11:05:55 -0700 | [diff] [blame] | 154 | 			OMAP4_MMC1_PWRDNZ_MASK); | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 155 | 		omap4_ctrl_pad_writel(reg, control_pbias_offset); | 
| Balaji T K | 1fcecf2 | 2011-06-01 16:45:22 +0530 | [diff] [blame] | 156 |  | 
 | 157 | 		timeout = jiffies + msecs_to_jiffies(5); | 
 | 158 | 		do { | 
 | 159 | 			reg = omap4_ctrl_pad_readl(control_pbias_offset); | 
 | 160 | 			if (!(reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK)) | 
 | 161 | 				break; | 
 | 162 | 			usleep_range(100, 200); | 
 | 163 | 		} while (!time_after(jiffies, timeout)); | 
 | 164 |  | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 165 | 		if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK) { | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 166 | 			pr_err("Pbias Voltage is not same as LDO\n"); | 
 | 167 | 			/* Caution : On VMODE_ERROR Power Down MMC IO */ | 
| Bryan Buckley | 3696d30 | 2011-09-30 11:05:55 -0700 | [diff] [blame] | 168 | 			reg &= ~(OMAP4_MMC1_PWRDNZ_MASK); | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 169 | 			omap4_ctrl_pad_writel(reg, control_pbias_offset); | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 170 | 		} | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 171 | 	} | 
 | 172 | } | 
 | 173 |  | 
| Igor Grinberg | e62245b | 2011-11-29 11:37:48 +0200 | [diff] [blame] | 174 | static void hsmmc2_select_input_clk_src(struct omap_mmc_platform_data *mmc) | 
 | 175 | { | 
 | 176 | 	u32 reg; | 
 | 177 |  | 
| Grazvydas Ignotas | d82e519 | 2012-01-12 16:26:45 +0200 | [diff] [blame] | 178 | 	reg = omap_ctrl_readl(control_devconf1_offset); | 
 | 179 | 	if (mmc->slots[0].internal_clock) | 
| Igor Grinberg | e62245b | 2011-11-29 11:37:48 +0200 | [diff] [blame] | 180 | 		reg |= OMAP2_MMCSDIO2ADPCLKISEL; | 
| Grazvydas Ignotas | d82e519 | 2012-01-12 16:26:45 +0200 | [diff] [blame] | 181 | 	else | 
 | 182 | 		reg &= ~OMAP2_MMCSDIO2ADPCLKISEL; | 
 | 183 | 	omap_ctrl_writel(reg, control_devconf1_offset); | 
| Igor Grinberg | e62245b | 2011-11-29 11:37:48 +0200 | [diff] [blame] | 184 | } | 
 | 185 |  | 
| Grazvydas Ignotas | ffa1e4e | 2011-12-18 02:35:47 +0200 | [diff] [blame] | 186 | static void hsmmc2_before_set_reg(struct device *dev, int slot, | 
| Adrian Hunter | db0fefc | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 187 | 				   int power_on, int vdd) | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 188 | { | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 189 | 	struct omap_mmc_platform_data *mmc = dev->platform_data; | 
| Grazvydas Ignotas | 762ad3a4 | 2009-06-23 13:30:22 +0300 | [diff] [blame] | 190 |  | 
| Adrian Hunter | ce6f001 | 2010-02-15 10:03:34 -0800 | [diff] [blame] | 191 | 	if (mmc->slots[0].remux) | 
 | 192 | 		mmc->slots[0].remux(dev, slot, power_on); | 
 | 193 |  | 
| Igor Grinberg | e62245b | 2011-11-29 11:37:48 +0200 | [diff] [blame] | 194 | 	if (power_on) | 
 | 195 | 		hsmmc2_select_input_clk_src(mmc); | 
 | 196 | } | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 197 |  | 
| Igor Grinberg | e62245b | 2011-11-29 11:37:48 +0200 | [diff] [blame] | 198 | static int am35x_hsmmc2_set_power(struct device *dev, int slot, | 
 | 199 | 				  int power_on, int vdd) | 
 | 200 | { | 
 | 201 | 	struct omap_mmc_platform_data *mmc = dev->platform_data; | 
 | 202 |  | 
 | 203 | 	if (power_on) | 
 | 204 | 		hsmmc2_select_input_clk_src(mmc); | 
 | 205 |  | 
 | 206 | 	return 0; | 
| Adrian Hunter | 9b7c18e | 2009-09-22 16:44:50 -0700 | [diff] [blame] | 207 | } | 
 | 208 |  | 
| stanley.miao | 03e7e17 | 2010-05-13 12:39:31 +0000 | [diff] [blame] | 209 | static int nop_mmc_set_power(struct device *dev, int slot, int power_on, | 
 | 210 | 							int vdd) | 
 | 211 | { | 
 | 212 | 	return 0; | 
 | 213 | } | 
 | 214 |  | 
| Kishore Kadiyala | d8d0a61 | 2011-02-28 20:48:03 +0530 | [diff] [blame] | 215 | static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller, | 
 | 216 | 			int controller_nr) | 
 | 217 | { | 
| Thomas Weber | a15164f | 2011-11-17 22:39:40 +0100 | [diff] [blame] | 218 | 	if (gpio_is_valid(mmc_controller->slots[0].switch_pin) && | 
 | 219 | 		(mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES)) | 
| Kishore Kadiyala | d8d0a61 | 2011-02-28 20:48:03 +0530 | [diff] [blame] | 220 | 		omap_mux_init_gpio(mmc_controller->slots[0].switch_pin, | 
 | 221 | 					OMAP_PIN_INPUT_PULLUP); | 
| Thomas Weber | a15164f | 2011-11-17 22:39:40 +0100 | [diff] [blame] | 222 | 	if (gpio_is_valid(mmc_controller->slots[0].gpio_wp) && | 
 | 223 | 		(mmc_controller->slots[0].gpio_wp < OMAP_MAX_GPIO_LINES)) | 
| Kishore Kadiyala | d8d0a61 | 2011-02-28 20:48:03 +0530 | [diff] [blame] | 224 | 		omap_mux_init_gpio(mmc_controller->slots[0].gpio_wp, | 
 | 225 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 226 | 	if (cpu_is_omap34xx()) { | 
 | 227 | 		if (controller_nr == 0) { | 
 | 228 | 			omap_mux_init_signal("sdmmc1_clk", | 
 | 229 | 				OMAP_PIN_INPUT_PULLUP); | 
 | 230 | 			omap_mux_init_signal("sdmmc1_cmd", | 
 | 231 | 				OMAP_PIN_INPUT_PULLUP); | 
 | 232 | 			omap_mux_init_signal("sdmmc1_dat0", | 
 | 233 | 				OMAP_PIN_INPUT_PULLUP); | 
 | 234 | 			if (mmc_controller->slots[0].caps & | 
 | 235 | 				(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) { | 
 | 236 | 				omap_mux_init_signal("sdmmc1_dat1", | 
 | 237 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 238 | 				omap_mux_init_signal("sdmmc1_dat2", | 
 | 239 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 240 | 				omap_mux_init_signal("sdmmc1_dat3", | 
 | 241 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 242 | 			} | 
 | 243 | 			if (mmc_controller->slots[0].caps & | 
 | 244 | 						MMC_CAP_8_BIT_DATA) { | 
 | 245 | 				omap_mux_init_signal("sdmmc1_dat4", | 
 | 246 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 247 | 				omap_mux_init_signal("sdmmc1_dat5", | 
 | 248 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 249 | 				omap_mux_init_signal("sdmmc1_dat6", | 
 | 250 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 251 | 				omap_mux_init_signal("sdmmc1_dat7", | 
 | 252 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 253 | 			} | 
 | 254 | 		} | 
 | 255 | 		if (controller_nr == 1) { | 
 | 256 | 			/* MMC2 */ | 
 | 257 | 			omap_mux_init_signal("sdmmc2_clk", | 
 | 258 | 				OMAP_PIN_INPUT_PULLUP); | 
 | 259 | 			omap_mux_init_signal("sdmmc2_cmd", | 
 | 260 | 				OMAP_PIN_INPUT_PULLUP); | 
 | 261 | 			omap_mux_init_signal("sdmmc2_dat0", | 
 | 262 | 				OMAP_PIN_INPUT_PULLUP); | 
 | 263 |  | 
 | 264 | 			/* | 
 | 265 | 			 * For 8 wire configurations, Lines DAT4, 5, 6 and 7 | 
 | 266 | 			 * need to be muxed in the board-*.c files | 
 | 267 | 			 */ | 
 | 268 | 			if (mmc_controller->slots[0].caps & | 
 | 269 | 				(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) { | 
 | 270 | 				omap_mux_init_signal("sdmmc2_dat1", | 
 | 271 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 272 | 				omap_mux_init_signal("sdmmc2_dat2", | 
 | 273 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 274 | 				omap_mux_init_signal("sdmmc2_dat3", | 
 | 275 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 276 | 			} | 
 | 277 | 			if (mmc_controller->slots[0].caps & | 
 | 278 | 							MMC_CAP_8_BIT_DATA) { | 
 | 279 | 				omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4", | 
 | 280 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 281 | 				omap_mux_init_signal("sdmmc2_dat5.sdmmc2_dat5", | 
 | 282 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 283 | 				omap_mux_init_signal("sdmmc2_dat6.sdmmc2_dat6", | 
 | 284 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 285 | 				omap_mux_init_signal("sdmmc2_dat7.sdmmc2_dat7", | 
 | 286 | 					OMAP_PIN_INPUT_PULLUP); | 
 | 287 | 			} | 
 | 288 | 		} | 
 | 289 |  | 
 | 290 | 		/* | 
 | 291 | 		 * For MMC3 the pins need to be muxed in the board-*.c files | 
 | 292 | 		 */ | 
 | 293 | 	} | 
 | 294 | } | 
 | 295 |  | 
| Russell King | a98f77b | 2012-02-07 10:45:50 +0000 | [diff] [blame] | 296 | static int omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, | 
 | 297 | 				 struct omap_mmc_platform_data *mmc) | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 298 | { | 
 | 299 | 	char *hc_name; | 
 | 300 |  | 
 | 301 | 	hc_name = kzalloc(sizeof(char) * (HSMMC_NAME_LEN + 1), GFP_KERNEL); | 
 | 302 | 	if (!hc_name) { | 
 | 303 | 		pr_err("Cannot allocate memory for controller slot name\n"); | 
 | 304 | 		kfree(hc_name); | 
 | 305 | 		return -ENOMEM; | 
 | 306 | 	} | 
 | 307 |  | 
 | 308 | 	if (c->name) | 
 | 309 | 		strncpy(hc_name, c->name, HSMMC_NAME_LEN); | 
 | 310 | 	else | 
 | 311 | 		snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i", | 
 | 312 | 								c->mmc, 1); | 
 | 313 | 	mmc->slots[0].name = hc_name; | 
 | 314 | 	mmc->nr_slots = 1; | 
 | 315 | 	mmc->slots[0].caps = c->caps; | 
| Eliad Peller | 6fdc75d | 2011-11-22 16:02:18 +0200 | [diff] [blame] | 316 | 	mmc->slots[0].pm_caps = c->pm_caps; | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 317 | 	mmc->slots[0].internal_clock = !c->ext_clock; | 
 | 318 | 	mmc->dma_mask = 0xffffffff; | 
 | 319 | 	if (cpu_is_omap44xx()) | 
 | 320 | 		mmc->reg_offset = OMAP4_MMC_REG_OFFSET; | 
 | 321 | 	else | 
 | 322 | 		mmc->reg_offset = 0; | 
 | 323 |  | 
 | 324 | 	mmc->get_context_loss_count = hsmmc_get_context_loss; | 
 | 325 |  | 
 | 326 | 	mmc->slots[0].switch_pin = c->gpio_cd; | 
 | 327 | 	mmc->slots[0].gpio_wp = c->gpio_wp; | 
 | 328 |  | 
 | 329 | 	mmc->slots[0].remux = c->remux; | 
 | 330 | 	mmc->slots[0].init_card = c->init_card; | 
 | 331 |  | 
 | 332 | 	if (c->cover_only) | 
 | 333 | 		mmc->slots[0].cover = 1; | 
 | 334 |  | 
 | 335 | 	if (c->nonremovable) | 
 | 336 | 		mmc->slots[0].nonremovable = 1; | 
 | 337 |  | 
 | 338 | 	if (c->power_saving) | 
 | 339 | 		mmc->slots[0].power_saving = 1; | 
 | 340 |  | 
 | 341 | 	if (c->no_off) | 
 | 342 | 		mmc->slots[0].no_off = 1; | 
 | 343 |  | 
| Balaji T K | b1c1df7 | 2011-05-30 19:55:34 +0530 | [diff] [blame] | 344 | 	if (c->no_off_init) | 
 | 345 | 		mmc->slots[0].no_regulator_off_init = c->no_off_init; | 
 | 346 |  | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 347 | 	if (c->vcc_aux_disable_is_sleep) | 
 | 348 | 		mmc->slots[0].vcc_aux_disable_is_sleep = 1; | 
 | 349 |  | 
 | 350 | 	/* | 
 | 351 | 	 * NOTE:  MMC slots should have a Vcc regulator set up. | 
 | 352 | 	 * This may be from a TWL4030-family chip, another | 
 | 353 | 	 * controllable regulator, or a fixed supply. | 
 | 354 | 	 * | 
 | 355 | 	 * temporary HACK: ocr_mask instead of fixed supply | 
 | 356 | 	 */ | 
| Abhilash K V | e89715a | 2011-12-09 12:27:36 -0800 | [diff] [blame] | 357 | 	if (cpu_is_omap3505() || cpu_is_omap3517()) | 
 | 358 | 		mmc->slots[0].ocr_mask = MMC_VDD_165_195 | | 
 | 359 | 					 MMC_VDD_26_27 | | 
 | 360 | 					 MMC_VDD_27_28 | | 
 | 361 | 					 MMC_VDD_29_30 | | 
 | 362 | 					 MMC_VDD_30_31 | | 
 | 363 | 					 MMC_VDD_31_32; | 
 | 364 | 	else | 
 | 365 | 		mmc->slots[0].ocr_mask = c->ocr_mask; | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 366 |  | 
| Igor Grinberg | e62245b | 2011-11-29 11:37:48 +0200 | [diff] [blame] | 367 | 	if (!cpu_is_omap3517() && !cpu_is_omap3505()) | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 368 | 		mmc->slots[0].features |= HSMMC_HAS_PBIAS; | 
 | 369 |  | 
 | 370 | 	if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0)) | 
 | 371 | 		mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET; | 
 | 372 |  | 
 | 373 | 	switch (c->mmc) { | 
 | 374 | 	case 1: | 
 | 375 | 		if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { | 
 | 376 | 			/* on-chip level shifting via PBIAS0/PBIAS1 */ | 
 | 377 | 			if (cpu_is_omap44xx()) { | 
 | 378 | 				mmc->slots[0].before_set_reg = | 
 | 379 | 						omap4_hsmmc1_before_set_reg; | 
 | 380 | 				mmc->slots[0].after_set_reg = | 
 | 381 | 						omap4_hsmmc1_after_set_reg; | 
 | 382 | 			} else { | 
 | 383 | 				mmc->slots[0].before_set_reg = | 
 | 384 | 						omap_hsmmc1_before_set_reg; | 
 | 385 | 				mmc->slots[0].after_set_reg = | 
 | 386 | 						omap_hsmmc1_after_set_reg; | 
 | 387 | 			} | 
 | 388 | 		} | 
 | 389 |  | 
| Igor Grinberg | e62245b | 2011-11-29 11:37:48 +0200 | [diff] [blame] | 390 | 		if (cpu_is_omap3517() || cpu_is_omap3505()) | 
 | 391 | 			mmc->slots[0].set_power = nop_mmc_set_power; | 
 | 392 |  | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 393 | 		/* OMAP3630 HSMMC1 supports only 4-bit */ | 
 | 394 | 		if (cpu_is_omap3630() && | 
 | 395 | 				(c->caps & MMC_CAP_8_BIT_DATA)) { | 
 | 396 | 			c->caps &= ~MMC_CAP_8_BIT_DATA; | 
 | 397 | 			c->caps |= MMC_CAP_4_BIT_DATA; | 
 | 398 | 			mmc->slots[0].caps = c->caps; | 
 | 399 | 		} | 
 | 400 | 		break; | 
 | 401 | 	case 2: | 
| Igor Grinberg | e62245b | 2011-11-29 11:37:48 +0200 | [diff] [blame] | 402 | 		if (cpu_is_omap3517() || cpu_is_omap3505()) | 
 | 403 | 			mmc->slots[0].set_power = am35x_hsmmc2_set_power; | 
 | 404 |  | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 405 | 		if (c->ext_clock) | 
 | 406 | 			c->transceiver = 1; | 
 | 407 | 		if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) { | 
 | 408 | 			c->caps &= ~MMC_CAP_8_BIT_DATA; | 
 | 409 | 			c->caps |= MMC_CAP_4_BIT_DATA; | 
 | 410 | 		} | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 411 | 		if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { | 
 | 412 | 			/* off-chip level shifting, or none */ | 
| Grazvydas Ignotas | ffa1e4e | 2011-12-18 02:35:47 +0200 | [diff] [blame] | 413 | 			mmc->slots[0].before_set_reg = hsmmc2_before_set_reg; | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 414 | 			mmc->slots[0].after_set_reg = NULL; | 
 | 415 | 		} | 
 | 416 | 		break; | 
| Grazvydas Ignotas | ffa1e4e | 2011-12-18 02:35:47 +0200 | [diff] [blame] | 417 | 	case 3: | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 418 | 	case 4: | 
 | 419 | 	case 5: | 
 | 420 | 		mmc->slots[0].before_set_reg = NULL; | 
 | 421 | 		mmc->slots[0].after_set_reg = NULL; | 
 | 422 | 		break; | 
 | 423 | 	default: | 
 | 424 | 		pr_err("MMC%d configuration not supported!\n", c->mmc); | 
 | 425 | 		kfree(hc_name); | 
 | 426 | 		return -ENODEV; | 
 | 427 | 	} | 
 | 428 | 	return 0; | 
 | 429 | } | 
 | 430 |  | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 431 | #define MAX_OMAP_MMC_HWMOD_NAME_LEN		16 | 
 | 432 |  | 
| Russell King | a98f77b | 2012-02-07 10:45:50 +0000 | [diff] [blame] | 433 | void omap_init_hsmmc(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr) | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 434 | { | 
 | 435 | 	struct omap_hwmod *oh; | 
| Kevin Hilman | 3528c58 | 2011-07-21 13:48:45 -0700 | [diff] [blame] | 436 | 	struct platform_device *pdev; | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 437 | 	char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN]; | 
 | 438 | 	struct omap_mmc_platform_data *mmc_data; | 
 | 439 | 	struct omap_mmc_dev_attr *mmc_dev_attr; | 
 | 440 | 	char *name; | 
 | 441 | 	int l; | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 442 |  | 
 | 443 | 	mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL); | 
 | 444 | 	if (!mmc_data) { | 
 | 445 | 		pr_err("Cannot allocate memory for mmc device!\n"); | 
 | 446 | 		goto done; | 
 | 447 | 	} | 
 | 448 |  | 
 | 449 | 	if (omap_hsmmc_pdata_init(hsmmcinfo, mmc_data) < 0) { | 
 | 450 | 		pr_err("%s fails!\n", __func__); | 
 | 451 | 		goto done; | 
 | 452 | 	} | 
 | 453 | 	omap_hsmmc_mux(mmc_data, (ctrl_nr - 1)); | 
 | 454 |  | 
| Kishore Kadiyala | 0005ae7 | 2011-02-28 20:48:05 +0530 | [diff] [blame] | 455 | 	name = "omap_hsmmc"; | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 456 |  | 
 | 457 | 	l = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN, | 
 | 458 | 		     "mmc%d", ctrl_nr); | 
 | 459 | 	WARN(l >= MAX_OMAP_MMC_HWMOD_NAME_LEN, | 
 | 460 | 	     "String buffer overflow in MMC%d device setup\n", ctrl_nr); | 
 | 461 | 	oh = omap_hwmod_lookup(oh_name); | 
 | 462 | 	if (!oh) { | 
 | 463 | 		pr_err("Could not look up %s\n", oh_name); | 
 | 464 | 		kfree(mmc_data->slots[0].name); | 
 | 465 | 		goto done; | 
 | 466 | 	} | 
 | 467 |  | 
 | 468 | 	if (oh->dev_attr != NULL) { | 
 | 469 | 		mmc_dev_attr = oh->dev_attr; | 
 | 470 | 		mmc_data->controller_flags = mmc_dev_attr->flags; | 
 | 471 | 	} | 
 | 472 |  | 
| Kevin Hilman | 3528c58 | 2011-07-21 13:48:45 -0700 | [diff] [blame] | 473 | 	pdev = omap_device_build(name, ctrl_nr - 1, oh, mmc_data, | 
| Benoit Cousson | f718e2c | 2011-08-10 15:30:09 +0200 | [diff] [blame] | 474 | 		sizeof(struct omap_mmc_platform_data), NULL, 0, false); | 
| Kevin Hilman | 3528c58 | 2011-07-21 13:48:45 -0700 | [diff] [blame] | 475 | 	if (IS_ERR(pdev)) { | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 476 | 		WARN(1, "Can't build omap_device for %s:%s.\n", name, oh->name); | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 477 | 		kfree(mmc_data->slots[0].name); | 
 | 478 | 		goto done; | 
 | 479 | 	} | 
 | 480 | 	/* | 
 | 481 | 	 * return device handle to board setup code | 
 | 482 | 	 * required to populate for regulator framework structure | 
 | 483 | 	 */ | 
| Kevin Hilman | 3528c58 | 2011-07-21 13:48:45 -0700 | [diff] [blame] | 484 | 	hsmmcinfo->dev = &pdev->dev; | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 485 |  | 
 | 486 | done: | 
 | 487 | 	kfree(mmc_data); | 
 | 488 | } | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 489 |  | 
| Russell King | a98f77b | 2012-02-07 10:45:50 +0000 | [diff] [blame] | 490 | void omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 491 | { | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 492 | 	u32 reg; | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 493 |  | 
| kishore kadiyala | c83c8e6 | 2010-05-15 18:21:25 +0000 | [diff] [blame] | 494 | 	if (!cpu_is_omap44xx()) { | 
 | 495 | 		if (cpu_is_omap2430()) { | 
 | 496 | 			control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; | 
 | 497 | 			control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; | 
 | 498 | 		} else { | 
 | 499 | 			control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; | 
 | 500 | 			control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; | 
 | 501 | 		} | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 502 | 	} else { | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 503 | 		control_pbias_offset = | 
 | 504 | 			OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE; | 
 | 505 | 		control_mmc1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1; | 
 | 506 | 		reg = omap4_ctrl_pad_readl(control_mmc1); | 
 | 507 | 		reg |= (OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK | | 
 | 508 | 			OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK); | 
 | 509 | 		reg &= ~(OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK | | 
 | 510 | 			OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK); | 
| Balaji T K | c862dd7 | 2011-10-03 17:52:51 +0530 | [diff] [blame] | 511 | 		reg |= (OMAP4_SDMMC1_DR0_SPEEDCTRL_MASK | | 
| Santosh Shilimkar | dcf5ef3 | 2010-09-27 14:02:58 -0600 | [diff] [blame] | 512 | 			OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK | | 
 | 513 | 			OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK); | 
 | 514 | 		omap4_ctrl_pad_writel(reg, control_mmc1); | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 515 | 	} | 
 | 516 |  | 
| Kishore Kadiyala | 4621d5f | 2011-02-28 20:48:04 +0530 | [diff] [blame] | 517 | 	for (; controllers->mmc; controllers++) | 
 | 518 | 		omap_init_hsmmc(controllers, controllers->mmc); | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 519 |  | 
| Tony Lindgren | 90c62bf | 2008-12-10 17:37:17 -0800 | [diff] [blame] | 520 | } | 
 | 521 |  | 
 | 522 | #endif |