diff options
author | Tony Lindgren <tony@atomide.com> | 2008-12-10 20:37:16 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2008-12-10 20:37:16 -0500 |
commit | d88746652b4d133284d1fdd05b5e999e8f44c998 (patch) | |
tree | 2a6cfd6fe175a18eb4b4f600e0a79444259c9a5d /arch/arm/plat-omap/devices.c | |
parent | 652bcd8f72cc0cdf4499ce7d73990514e5e3e4b9 (diff) |
omap mmc: Add better MMC low-level init
This will simplify the MMC low-level init, and make it more
flexible to add support for a newer MMC controller in the
following patches.
The patch rearranges platform data and gets rid of slot vs
controller confusion in the old data structures. Also fix
device id numbering in the clock code.
Some code snippets are based on an earlier patch by
Russell King <linux@arm.linux.org.uk>.
Cc: Pierre Ossman <drzeus-mmc@drzeus.cx>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/plat-omap/devices.c')
-rw-r--r-- | arch/arm/plat-omap/devices.c | 225 |
1 files changed, 35 insertions, 190 deletions
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 0cb2b22388e9..ac15c23fd5da 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c | |||
@@ -192,202 +192,48 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config, | |||
192 | 192 | ||
193 | /*-------------------------------------------------------------------------*/ | 193 | /*-------------------------------------------------------------------------*/ |
194 | 194 | ||
195 | #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ | 195 | #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ |
196 | defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) | 196 | defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) |
197 | 197 | ||
198 | #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) | 198 | #define OMAP_MMC_NR_RES 2 |
199 | #define OMAP_MMC1_BASE 0x4809c000 | ||
200 | #define OMAP_MMC1_END (OMAP_MMC1_BASE + 0x1fc) | ||
201 | #define OMAP_MMC1_INT INT_24XX_MMC_IRQ | ||
202 | 199 | ||
203 | #define OMAP_MMC2_BASE 0x480b4000 | 200 | /* |
204 | #define OMAP_MMC2_END (OMAP_MMC2_BASE + 0x1fc) | 201 | * Register MMC devices. Called from mach-omap1 and mach-omap2 device init. |
205 | #define OMAP_MMC2_INT INT_24XX_MMC2_IRQ | 202 | */ |
206 | 203 | int __init omap_mmc_add(int id, unsigned long base, unsigned long size, | |
207 | #else | 204 | unsigned int irq, struct omap_mmc_platform_data *data) |
208 | |||
209 | #define OMAP_MMC1_BASE 0xfffb7800 | ||
210 | #define OMAP_MMC1_END (OMAP_MMC1_BASE + 0x7f) | ||
211 | #define OMAP_MMC1_INT INT_MMC | ||
212 | |||
213 | #define OMAP_MMC2_BASE 0xfffb7c00 /* omap16xx only */ | ||
214 | #define OMAP_MMC2_END (OMAP_MMC2_BASE + 0x7f) | ||
215 | #define OMAP_MMC2_INT INT_1610_MMC2 | ||
216 | |||
217 | #endif | ||
218 | |||
219 | static struct omap_mmc_platform_data mmc1_data; | ||
220 | |||
221 | static u64 mmc1_dmamask = 0xffffffff; | ||
222 | |||
223 | static struct resource mmc1_resources[] = { | ||
224 | { | ||
225 | .start = OMAP_MMC1_BASE, | ||
226 | .end = OMAP_MMC1_END, | ||
227 | .flags = IORESOURCE_MEM, | ||
228 | }, | ||
229 | { | ||
230 | .start = OMAP_MMC1_INT, | ||
231 | .flags = IORESOURCE_IRQ, | ||
232 | }, | ||
233 | }; | ||
234 | |||
235 | static struct platform_device mmc_omap_device1 = { | ||
236 | .name = "mmci-omap", | ||
237 | .id = 1, | ||
238 | .dev = { | ||
239 | .dma_mask = &mmc1_dmamask, | ||
240 | .platform_data = &mmc1_data, | ||
241 | }, | ||
242 | .num_resources = ARRAY_SIZE(mmc1_resources), | ||
243 | .resource = mmc1_resources, | ||
244 | }; | ||
245 | |||
246 | #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2430) || \ | ||
247 | defined(CONFIG_ARCH_OMAP34XX) | ||
248 | |||
249 | static struct omap_mmc_platform_data mmc2_data; | ||
250 | |||
251 | static u64 mmc2_dmamask = 0xffffffff; | ||
252 | |||
253 | static struct resource mmc2_resources[] = { | ||
254 | { | ||
255 | .start = OMAP_MMC2_BASE, | ||
256 | .end = OMAP_MMC2_END, | ||
257 | .flags = IORESOURCE_MEM, | ||
258 | }, | ||
259 | { | ||
260 | .start = OMAP_MMC2_INT, | ||
261 | .flags = IORESOURCE_IRQ, | ||
262 | }, | ||
263 | }; | ||
264 | |||
265 | static struct platform_device mmc_omap_device2 = { | ||
266 | .name = "mmci-omap", | ||
267 | .id = 2, | ||
268 | .dev = { | ||
269 | .dma_mask = &mmc2_dmamask, | ||
270 | .platform_data = &mmc2_data, | ||
271 | }, | ||
272 | .num_resources = ARRAY_SIZE(mmc2_resources), | ||
273 | .resource = mmc2_resources, | ||
274 | }; | ||
275 | #endif | ||
276 | |||
277 | static inline void omap_init_mmc_conf(const struct omap_mmc_config *mmc_conf) | ||
278 | { | ||
279 | if (cpu_is_omap2430() || cpu_is_omap34xx()) | ||
280 | return; | ||
281 | |||
282 | if (mmc_conf->mmc[0].enabled) { | ||
283 | if (cpu_is_omap24xx()) { | ||
284 | omap_cfg_reg(H18_24XX_MMC_CMD); | ||
285 | omap_cfg_reg(H15_24XX_MMC_CLKI); | ||
286 | omap_cfg_reg(G19_24XX_MMC_CLKO); | ||
287 | omap_cfg_reg(F20_24XX_MMC_DAT0); | ||
288 | omap_cfg_reg(F19_24XX_MMC_DAT_DIR0); | ||
289 | omap_cfg_reg(G18_24XX_MMC_CMD_DIR); | ||
290 | } else { | ||
291 | omap_cfg_reg(MMC_CMD); | ||
292 | omap_cfg_reg(MMC_CLK); | ||
293 | omap_cfg_reg(MMC_DAT0); | ||
294 | if (cpu_is_omap1710()) { | ||
295 | omap_cfg_reg(M15_1710_MMC_CLKI); | ||
296 | omap_cfg_reg(P19_1710_MMC_CMDDIR); | ||
297 | omap_cfg_reg(P20_1710_MMC_DATDIR0); | ||
298 | } | ||
299 | } | ||
300 | if (mmc_conf->mmc[0].wire4) { | ||
301 | if (cpu_is_omap24xx()) { | ||
302 | omap_cfg_reg(H14_24XX_MMC_DAT1); | ||
303 | omap_cfg_reg(E19_24XX_MMC_DAT2); | ||
304 | omap_cfg_reg(D19_24XX_MMC_DAT3); | ||
305 | omap_cfg_reg(E20_24XX_MMC_DAT_DIR1); | ||
306 | omap_cfg_reg(F18_24XX_MMC_DAT_DIR2); | ||
307 | omap_cfg_reg(E18_24XX_MMC_DAT_DIR3); | ||
308 | } else { | ||
309 | omap_cfg_reg(MMC_DAT1); | ||
310 | /* NOTE: DAT2 can be on W10 (here) or M15 */ | ||
311 | if (!mmc_conf->mmc[0].nomux) | ||
312 | omap_cfg_reg(MMC_DAT2); | ||
313 | omap_cfg_reg(MMC_DAT3); | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | |||
318 | #ifdef CONFIG_ARCH_OMAP16XX | ||
319 | /* block 2 is on newer chips, and has many pinout options */ | ||
320 | if (mmc_conf->mmc[1].enabled) { | ||
321 | if (!mmc_conf->mmc[1].nomux) { | ||
322 | omap_cfg_reg(Y8_1610_MMC2_CMD); | ||
323 | omap_cfg_reg(Y10_1610_MMC2_CLK); | ||
324 | omap_cfg_reg(R18_1610_MMC2_CLKIN); | ||
325 | omap_cfg_reg(W8_1610_MMC2_DAT0); | ||
326 | if (mmc_conf->mmc[1].wire4) { | ||
327 | omap_cfg_reg(V8_1610_MMC2_DAT1); | ||
328 | omap_cfg_reg(W15_1610_MMC2_DAT2); | ||
329 | omap_cfg_reg(R10_1610_MMC2_DAT3); | ||
330 | } | ||
331 | |||
332 | /* These are needed for the level shifter */ | ||
333 | omap_cfg_reg(V9_1610_MMC2_CMDDIR); | ||
334 | omap_cfg_reg(V5_1610_MMC2_DATDIR0); | ||
335 | omap_cfg_reg(W19_1610_MMC2_DATDIR1); | ||
336 | } | ||
337 | |||
338 | /* Feedback clock must be set on OMAP-1710 MMC2 */ | ||
339 | if (cpu_is_omap1710()) | ||
340 | omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24), | ||
341 | MOD_CONF_CTRL_1); | ||
342 | } | ||
343 | #endif | ||
344 | } | ||
345 | |||
346 | static void __init omap_init_mmc(void) | ||
347 | { | 205 | { |
348 | const struct omap_mmc_config *mmc_conf; | 206 | struct platform_device *pdev; |
349 | 207 | struct resource res[OMAP_MMC_NR_RES]; | |
350 | /* NOTE: assumes MMC was never (wrongly) enabled */ | 208 | int ret; |
351 | mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config); | 209 | |
352 | if (!mmc_conf) | 210 | pdev = platform_device_alloc("mmci-omap", id); |
353 | return; | 211 | if (!pdev) |
354 | 212 | return -ENOMEM; | |
355 | omap_init_mmc_conf(mmc_conf); | 213 | |
356 | 214 | memset(res, 0, OMAP_MMC_NR_RES * sizeof(struct resource)); | |
357 | if (mmc_conf->mmc[0].enabled) { | 215 | res[0].start = base; |
358 | mmc1_data.conf = mmc_conf->mmc[0]; | 216 | res[0].end = base + size - 1; |
359 | (void) platform_device_register(&mmc_omap_device1); | 217 | res[0].flags = IORESOURCE_MEM; |
360 | } | 218 | res[1].start = res[1].end = irq; |
361 | 219 | res[1].flags = IORESOURCE_IRQ; | |
362 | #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2430) || \ | 220 | |
363 | defined(CONFIG_ARCH_OMAP34XX) | 221 | ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); |
364 | if (mmc_conf->mmc[1].enabled) { | 222 | if (ret == 0) |
365 | mmc2_data.conf = mmc_conf->mmc[1]; | 223 | ret = platform_device_add_data(pdev, data, sizeof(*data)); |
366 | (void) platform_device_register(&mmc_omap_device2); | 224 | if (ret) |
367 | } | 225 | goto fail; |
368 | #endif | 226 | |
369 | } | 227 | ret = platform_device_add(pdev); |
228 | if (ret) | ||
229 | goto fail; | ||
230 | return 0; | ||
370 | 231 | ||
371 | void omap_set_mmc_info(int host, const struct omap_mmc_platform_data *info) | 232 | fail: |
372 | { | 233 | platform_device_put(pdev); |
373 | switch (host) { | 234 | return ret; |
374 | case 1: | ||
375 | mmc1_data = *info; | ||
376 | break; | ||
377 | #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2430) || \ | ||
378 | defined(CONFIG_ARCH_OMAP34XX) | ||
379 | case 2: | ||
380 | mmc2_data = *info; | ||
381 | break; | ||
382 | #endif | ||
383 | default: | ||
384 | BUG(); | ||
385 | } | ||
386 | } | 235 | } |
387 | 236 | ||
388 | #else | ||
389 | static inline void omap_init_mmc(void) {} | ||
390 | void omap_set_mmc_info(int host, const struct omap_mmc_platform_data *info) {} | ||
391 | #endif | 237 | #endif |
392 | 238 | ||
393 | /*-------------------------------------------------------------------------*/ | 239 | /*-------------------------------------------------------------------------*/ |
@@ -532,7 +378,6 @@ static int __init omap_init_devices(void) | |||
532 | */ | 378 | */ |
533 | omap_init_dsp(); | 379 | omap_init_dsp(); |
534 | omap_init_kp(); | 380 | omap_init_kp(); |
535 | omap_init_mmc(); | ||
536 | omap_init_uwire(); | 381 | omap_init_uwire(); |
537 | omap_init_wdt(); | 382 | omap_init_wdt(); |
538 | omap_init_rng(); | 383 | omap_init_rng(); |