diff options
author | Adrian Hunter <adrian.hunter@nokia.com> | 2010-02-15 13:03:34 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-02-15 13:03:34 -0500 |
commit | d02a900b5952597b6beebd709d92ab392fa3005a (patch) | |
tree | 0fcf2dc829872dac48bcdb98c02ca632159f9b11 /arch/arm/mach-omap2/hsmmc.c | |
parent | db0fefc5119e2cfaa8f57565331e0abe47f0801e (diff) |
omap: Rename mmc-twl4030 files to hsmmc
mmc-twl4030.[ch] no longer has any dependency on twl4030
and should be renamed to reflect that.
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/hsmmc.c')
-rw-r--r-- | arch/arm/mach-omap2/hsmmc.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c new file mode 100644 index 000000000000..df1cf7273317 --- /dev/null +++ b/arch/arm/mach-omap2/hsmmc.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap2/hsmmc.c | ||
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 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <mach/hardware.h> | ||
17 | #include <plat/control.h> | ||
18 | #include <plat/mmc.h> | ||
19 | |||
20 | #include "hsmmc.h" | ||
21 | |||
22 | #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) | ||
23 | |||
24 | static u16 control_pbias_offset; | ||
25 | static u16 control_devconf1_offset; | ||
26 | |||
27 | #define HSMMC_NAME_LEN 9 | ||
28 | |||
29 | static struct twl_mmc_controller { | ||
30 | char name[HSMMC_NAME_LEN + 1]; | ||
31 | } hsmmc[OMAP34XX_NR_MMC]; | ||
32 | |||
33 | #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) | ||
34 | |||
35 | static int twl4030_mmc_get_context_loss(struct device *dev) | ||
36 | { | ||
37 | /* FIXME: PM DPS not implemented yet */ | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | #else | ||
42 | #define twl4030_mmc_get_context_loss NULL | ||
43 | #endif | ||
44 | |||
45 | static void hsmmc1_before_set_reg(struct device *dev, int slot, | ||
46 | int power_on, int vdd) | ||
47 | { | ||
48 | u32 reg, prog_io; | ||
49 | struct omap_mmc_platform_data *mmc = dev->platform_data; | ||
50 | |||
51 | /* | ||
52 | * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the | ||
53 | * card with Vcc regulator (from twl4030 or whatever). OMAP has both | ||
54 | * 1.8V and 3.0V modes, controlled by the PBIAS register. | ||
55 | * | ||
56 | * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which | ||
57 | * is most naturally TWL VSIM; those pins also use PBIAS. | ||
58 | * | ||
59 | * FIXME handle VMMC1A as needed ... | ||
60 | */ | ||
61 | if (power_on) { | ||
62 | if (cpu_is_omap2430()) { | ||
63 | reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1); | ||
64 | if ((1 << vdd) >= MMC_VDD_30_31) | ||
65 | reg |= OMAP243X_MMC1_ACTIVE_OVERWRITE; | ||
66 | else | ||
67 | reg &= ~OMAP243X_MMC1_ACTIVE_OVERWRITE; | ||
68 | omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1); | ||
69 | } | ||
70 | |||
71 | if (mmc->slots[0].internal_clock) { | ||
72 | reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); | ||
73 | reg |= OMAP2_MMCSDIO1ADPCLKISEL; | ||
74 | omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0); | ||
75 | } | ||
76 | |||
77 | reg = omap_ctrl_readl(control_pbias_offset); | ||
78 | if (cpu_is_omap3630()) { | ||
79 | /* Set MMC I/O to 52Mhz */ | ||
80 | prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1); | ||
81 | prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL; | ||
82 | omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1); | ||
83 | } else { | ||
84 | reg |= OMAP2_PBIASSPEEDCTRL0; | ||
85 | } | ||
86 | reg &= ~OMAP2_PBIASLITEPWRDNZ0; | ||
87 | omap_ctrl_writel(reg, control_pbias_offset); | ||
88 | } else { | ||
89 | reg = omap_ctrl_readl(control_pbias_offset); | ||
90 | reg &= ~OMAP2_PBIASLITEPWRDNZ0; | ||
91 | omap_ctrl_writel(reg, control_pbias_offset); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | static void hsmmc1_after_set_reg(struct device *dev, int slot, | ||
96 | int power_on, int vdd) | ||
97 | { | ||
98 | u32 reg; | ||
99 | |||
100 | /* 100ms delay required for PBIAS configuration */ | ||
101 | msleep(100); | ||
102 | |||
103 | if (power_on) { | ||
104 | reg = omap_ctrl_readl(control_pbias_offset); | ||
105 | reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0); | ||
106 | if ((1 << vdd) <= MMC_VDD_165_195) | ||
107 | reg &= ~OMAP2_PBIASLITEVMODE0; | ||
108 | else | ||
109 | reg |= OMAP2_PBIASLITEVMODE0; | ||
110 | omap_ctrl_writel(reg, control_pbias_offset); | ||
111 | } else { | ||
112 | reg = omap_ctrl_readl(control_pbias_offset); | ||
113 | reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 | | ||
114 | OMAP2_PBIASLITEVMODE0); | ||
115 | omap_ctrl_writel(reg, control_pbias_offset); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static void hsmmc23_before_set_reg(struct device *dev, int slot, | ||
120 | int power_on, int vdd) | ||
121 | { | ||
122 | struct omap_mmc_platform_data *mmc = dev->platform_data; | ||
123 | |||
124 | if (power_on) { | ||
125 | /* Only MMC2 supports a CLKIN */ | ||
126 | if (mmc->slots[0].internal_clock) { | ||
127 | u32 reg; | ||
128 | |||
129 | reg = omap_ctrl_readl(control_devconf1_offset); | ||
130 | reg |= OMAP2_MMCSDIO2ADPCLKISEL; | ||
131 | omap_ctrl_writel(reg, control_devconf1_offset); | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; | ||
137 | |||
138 | void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) | ||
139 | { | ||
140 | struct twl4030_hsmmc_info *c; | ||
141 | int nr_hsmmc = ARRAY_SIZE(hsmmc_data); | ||
142 | int i; | ||
143 | |||
144 | if (cpu_is_omap2430()) { | ||
145 | control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; | ||
146 | control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; | ||
147 | } else { | ||
148 | control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; | ||
149 | control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; | ||
150 | } | ||
151 | |||
152 | for (c = controllers; c->mmc; c++) { | ||
153 | struct twl_mmc_controller *twl = hsmmc + c->mmc - 1; | ||
154 | struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1]; | ||
155 | |||
156 | if (!c->mmc || c->mmc > nr_hsmmc) { | ||
157 | pr_debug("MMC%d: no such controller\n", c->mmc); | ||
158 | continue; | ||
159 | } | ||
160 | if (mmc) { | ||
161 | pr_debug("MMC%d: already configured\n", c->mmc); | ||
162 | continue; | ||
163 | } | ||
164 | |||
165 | mmc = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL); | ||
166 | if (!mmc) { | ||
167 | pr_err("Cannot allocate memory for mmc device!\n"); | ||
168 | goto done; | ||
169 | } | ||
170 | |||
171 | if (c->name) | ||
172 | strncpy(twl->name, c->name, HSMMC_NAME_LEN); | ||
173 | else | ||
174 | snprintf(twl->name, ARRAY_SIZE(twl->name), | ||
175 | "mmc%islot%i", c->mmc, 1); | ||
176 | mmc->slots[0].name = twl->name; | ||
177 | mmc->nr_slots = 1; | ||
178 | mmc->slots[0].wires = c->wires; | ||
179 | mmc->slots[0].internal_clock = !c->ext_clock; | ||
180 | mmc->dma_mask = 0xffffffff; | ||
181 | |||
182 | mmc->get_context_loss_count = | ||
183 | twl4030_mmc_get_context_loss; | ||
184 | |||
185 | mmc->slots[0].switch_pin = c->gpio_cd; | ||
186 | mmc->slots[0].gpio_wp = c->gpio_wp; | ||
187 | |||
188 | if (c->cover_only) | ||
189 | mmc->slots[0].cover = 1; | ||
190 | |||
191 | if (c->nonremovable) | ||
192 | mmc->slots[0].nonremovable = 1; | ||
193 | |||
194 | if (c->power_saving) | ||
195 | mmc->slots[0].power_saving = 1; | ||
196 | |||
197 | /* NOTE: MMC slots should have a Vcc regulator set up. | ||
198 | * This may be from a TWL4030-family chip, another | ||
199 | * controllable regulator, or a fixed supply. | ||
200 | * | ||
201 | * temporary HACK: ocr_mask instead of fixed supply | ||
202 | */ | ||
203 | mmc->slots[0].ocr_mask = c->ocr_mask; | ||
204 | |||
205 | switch (c->mmc) { | ||
206 | case 1: | ||
207 | /* on-chip level shifting via PBIAS0/PBIAS1 */ | ||
208 | mmc->slots[0].before_set_reg = hsmmc1_before_set_reg; | ||
209 | mmc->slots[0].after_set_reg = hsmmc1_after_set_reg; | ||
210 | |||
211 | /* Omap3630 HSMMC1 supports only 4-bit */ | ||
212 | if (cpu_is_omap3630() && c->wires > 4) { | ||
213 | c->wires = 4; | ||
214 | mmc->slots[0].wires = c->wires; | ||
215 | } | ||
216 | break; | ||
217 | case 2: | ||
218 | if (c->ext_clock) | ||
219 | c->transceiver = 1; | ||
220 | if (c->transceiver && c->wires > 4) | ||
221 | c->wires = 4; | ||
222 | /* FALLTHROUGH */ | ||
223 | case 3: | ||
224 | /* off-chip level shifting, or none */ | ||
225 | mmc->slots[0].before_set_reg = hsmmc23_before_set_reg; | ||
226 | mmc->slots[0].after_set_reg = NULL; | ||
227 | break; | ||
228 | default: | ||
229 | pr_err("MMC%d configuration not supported!\n", c->mmc); | ||
230 | kfree(mmc); | ||
231 | continue; | ||
232 | } | ||
233 | hsmmc_data[c->mmc - 1] = mmc; | ||
234 | } | ||
235 | |||
236 | omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC); | ||
237 | |||
238 | /* pass the device nodes back to board setup code */ | ||
239 | for (c = controllers; c->mmc; c++) { | ||
240 | struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1]; | ||
241 | |||
242 | if (!c->mmc || c->mmc > nr_hsmmc) | ||
243 | continue; | ||
244 | c->dev = mmc->dev; | ||
245 | } | ||
246 | |||
247 | done: | ||
248 | for (i = 0; i < nr_hsmmc; i++) | ||
249 | kfree(hsmmc_data[i]); | ||
250 | } | ||
251 | |||
252 | #endif | ||