blob: af374771bed00c4862fd6dd9eef45d266e4d54c3 [file] [log] [blame]
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001/*
2 * drivers/mmc/host/omap_hsmmc.c
3 *
4 * Driver for OMAP2430/3430 MMC controller.
5 *
6 * Copyright (C) 2007 Texas Instruments.
7 *
8 * Authors:
9 * Syed Mohammed Khasim <x0khasim@ti.com>
10 * Madhusudhan <madhu.cr@ti.com>
11 * Mohit Jalori <mjalori@ti.com>
12 *
13 * This file is licensed under the terms of the GNU General Public License
14 * version 2. This program is licensed "as is" without any warranty of any
15 * kind, whether express or implied.
16 */
17
18#include <linux/module.h>
19#include <linux/init.h>
Denis Karpovd900f712009-09-22 16:44:38 -070020#include <linux/debugfs.h>
21#include <linux/seq_file.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010022#include <linux/interrupt.h>
23#include <linux/delay.h>
24#include <linux/dma-mapping.h>
25#include <linux/platform_device.h>
26#include <linux/workqueue.h>
27#include <linux/timer.h>
28#include <linux/clk.h>
29#include <linux/mmc/host.h>
Jarkko Lavinen13189e72009-09-22 16:44:53 -070030#include <linux/mmc/core.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010031#include <linux/io.h>
32#include <linux/semaphore.h>
Adrian Hunterdb0fefc2010-02-15 10:03:34 -080033#include <linux/gpio.h>
34#include <linux/regulator/consumer.h>
Tony Lindgrence491cf2009-10-20 09:40:47 -070035#include <plat/dma.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010036#include <mach/hardware.h>
Tony Lindgrence491cf2009-10-20 09:40:47 -070037#include <plat/board.h>
38#include <plat/mmc.h>
39#include <plat/cpu.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010040
41/* OMAP HSMMC Host Controller Registers */
42#define OMAP_HSMMC_SYSCONFIG 0x0010
Denis Karpov11dd62a2009-09-22 16:44:43 -070043#define OMAP_HSMMC_SYSSTATUS 0x0014
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010044#define OMAP_HSMMC_CON 0x002C
45#define OMAP_HSMMC_BLK 0x0104
46#define OMAP_HSMMC_ARG 0x0108
47#define OMAP_HSMMC_CMD 0x010C
48#define OMAP_HSMMC_RSP10 0x0110
49#define OMAP_HSMMC_RSP32 0x0114
50#define OMAP_HSMMC_RSP54 0x0118
51#define OMAP_HSMMC_RSP76 0x011C
52#define OMAP_HSMMC_DATA 0x0120
53#define OMAP_HSMMC_HCTL 0x0128
54#define OMAP_HSMMC_SYSCTL 0x012C
55#define OMAP_HSMMC_STAT 0x0130
56#define OMAP_HSMMC_IE 0x0134
57#define OMAP_HSMMC_ISE 0x0138
58#define OMAP_HSMMC_CAPA 0x0140
59
60#define VS18 (1 << 26)
61#define VS30 (1 << 25)
62#define SDVS18 (0x5 << 9)
63#define SDVS30 (0x6 << 9)
David Brownelleb250822009-02-17 14:49:01 -080064#define SDVS33 (0x7 << 9)
Kim Kyuwon1b331e62009-02-20 13:10:08 +010065#define SDVS_MASK 0x00000E00
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010066#define SDVSCLR 0xFFFFF1FF
67#define SDVSDET 0x00000400
68#define AUTOIDLE 0x1
69#define SDBP (1 << 8)
70#define DTO 0xe
71#define ICE 0x1
72#define ICS 0x2
73#define CEN (1 << 2)
74#define CLKD_MASK 0x0000FFC0
75#define CLKD_SHIFT 6
76#define DTO_MASK 0x000F0000
77#define DTO_SHIFT 16
78#define INT_EN_MASK 0x307F0033
Anand Gadiyarccdfe3a2009-09-22 16:44:21 -070079#define BWR_ENABLE (1 << 4)
80#define BRR_ENABLE (1 << 5)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010081#define INIT_STREAM (1 << 1)
82#define DP_SELECT (1 << 21)
83#define DDIR (1 << 4)
84#define DMA_EN 0x1
85#define MSBS (1 << 5)
86#define BCE (1 << 1)
87#define FOUR_BIT (1 << 1)
Jarkko Lavinen73153012008-11-21 16:49:54 +020088#define DW8 (1 << 5)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010089#define CC 0x1
90#define TC 0x02
91#define OD 0x1
92#define ERR (1 << 15)
93#define CMD_TIMEOUT (1 << 16)
94#define DATA_TIMEOUT (1 << 20)
95#define CMD_CRC (1 << 17)
96#define DATA_CRC (1 << 21)
97#define CARD_ERR (1 << 28)
98#define STAT_CLEAR 0xFFFFFFFF
99#define INIT_STREAM_CMD 0x00000000
100#define DUAL_VOLT_OCR_BIT 7
101#define SRC (1 << 25)
102#define SRD (1 << 26)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700103#define SOFTRESET (1 << 1)
104#define RESETDONE (1 << 0)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100105
106/*
107 * FIXME: Most likely all the data using these _DEVID defines should come
108 * from the platform_data, or implemented in controller and slot specific
109 * functions.
110 */
111#define OMAP_MMC1_DEVID 0
112#define OMAP_MMC2_DEVID 1
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +0000113#define OMAP_MMC3_DEVID 2
kishore kadiyala82cf8182009-09-22 16:45:25 -0700114#define OMAP_MMC4_DEVID 3
115#define OMAP_MMC5_DEVID 4
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100116
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100117#define MMC_TIMEOUT_MS 20
118#define OMAP_MMC_MASTER_CLOCK 96000000
119#define DRIVER_NAME "mmci-omap-hs"
120
Denis Karpovdd498ef2009-09-22 16:44:49 -0700121/* Timeouts for entering power saving states on inactivity, msec */
122#define OMAP_MMC_DISABLED_TIMEOUT 100
Jarkko Lavinen13189e72009-09-22 16:44:53 -0700123#define OMAP_MMC_SLEEP_TIMEOUT 1000
124#define OMAP_MMC_OFF_TIMEOUT 8000
Denis Karpovdd498ef2009-09-22 16:44:49 -0700125
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100126/*
127 * One controller can have multiple slots, like on some omap boards using
128 * omap.c controller driver. Luckily this is not currently done on any known
129 * omap_hsmmc.c device.
130 */
131#define mmc_slot(host) (host->pdata->slots[host->slot_id])
132
133/*
134 * MMC Host controller read/write API's
135 */
136#define OMAP_HSMMC_READ(base, reg) \
137 __raw_readl((base) + OMAP_HSMMC_##reg)
138
139#define OMAP_HSMMC_WRITE(base, reg, val) \
140 __raw_writel((val), (base) + OMAP_HSMMC_##reg)
141
Denis Karpov70a33412009-09-22 16:44:59 -0700142struct omap_hsmmc_host {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100143 struct device *dev;
144 struct mmc_host *mmc;
145 struct mmc_request *mrq;
146 struct mmc_command *cmd;
147 struct mmc_data *data;
148 struct clk *fclk;
149 struct clk *iclk;
150 struct clk *dbclk;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800151 /*
152 * vcc == configured supply
153 * vcc_aux == optional
154 * - MMC1, supply for DAT4..DAT7
155 * - MMC2/MMC2, external level shifter voltage supply, for
156 * chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
157 */
158 struct regulator *vcc;
159 struct regulator *vcc_aux;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100160 struct semaphore sem;
161 struct work_struct mmc_carddetect_work;
162 void __iomem *base;
163 resource_size_t mapbase;
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700164 spinlock_t irq_lock; /* Prevent races with irq handler */
165 unsigned long flags;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100166 unsigned int id;
167 unsigned int dma_len;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200168 unsigned int dma_sg_idx;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100169 unsigned char bus_mode;
Adrian Huntera3621462009-09-22 16:44:42 -0700170 unsigned char power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100171 u32 *buffer;
172 u32 bytesleft;
173 int suspended;
174 int irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100175 int use_dma, dma_ch;
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +0000176 int dma_line_tx, dma_line_rx;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100177 int slot_id;
Adrian Hunter2bec0892009-09-22 16:45:02 -0700178 int got_dbclk;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200179 int response_busy;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700180 int context_loss;
Denis Karpovdd498ef2009-09-22 16:44:49 -0700181 int dpm_state;
Adrian Hunter623821f2009-09-22 16:44:51 -0700182 int vdd;
Adrian Hunterb62f6222009-09-22 16:45:01 -0700183 int protect_card;
184 int reqs_blocked;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800185 int use_reg;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700186
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100187 struct omap_mmc_platform_data *pdata;
188};
189
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800190static int omap_hsmmc_card_detect(struct device *dev, int slot)
191{
192 struct omap_mmc_platform_data *mmc = dev->platform_data;
193
194 /* NOTE: assumes card detect signal is active-low */
195 return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
196}
197
198static int omap_hsmmc_get_wp(struct device *dev, int slot)
199{
200 struct omap_mmc_platform_data *mmc = dev->platform_data;
201
202 /* NOTE: assumes write protect signal is active-high */
203 return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
204}
205
206static int omap_hsmmc_get_cover_state(struct device *dev, int slot)
207{
208 struct omap_mmc_platform_data *mmc = dev->platform_data;
209
210 /* NOTE: assumes card detect signal is active-low */
211 return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
212}
213
214#ifdef CONFIG_PM
215
216static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)
217{
218 struct omap_mmc_platform_data *mmc = dev->platform_data;
219
220 disable_irq(mmc->slots[0].card_detect_irq);
221 return 0;
222}
223
224static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
225{
226 struct omap_mmc_platform_data *mmc = dev->platform_data;
227
228 enable_irq(mmc->slots[0].card_detect_irq);
229 return 0;
230}
231
232#else
233
234#define omap_hsmmc_suspend_cdirq NULL
235#define omap_hsmmc_resume_cdirq NULL
236
237#endif
238
239static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
240 int vdd)
241{
242 struct omap_hsmmc_host *host =
243 platform_get_drvdata(to_platform_device(dev));
244 int ret;
245
246 if (mmc_slot(host).before_set_reg)
247 mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
248
249 if (power_on)
250 ret = mmc_regulator_set_ocr(host->vcc, vdd);
251 else
252 ret = mmc_regulator_set_ocr(host->vcc, 0);
253
254 if (mmc_slot(host).after_set_reg)
255 mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
256
257 return ret;
258}
259
260static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
261 int vdd)
262{
263 struct omap_hsmmc_host *host =
264 platform_get_drvdata(to_platform_device(dev));
265 int ret = 0;
266
267 /*
268 * If we don't see a Vcc regulator, assume it's a fixed
269 * voltage always-on regulator.
270 */
271 if (!host->vcc)
272 return 0;
273
274 if (mmc_slot(host).before_set_reg)
275 mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
276
277 /*
278 * Assume Vcc regulator is used only to power the card ... OMAP
279 * VDDS is used to power the pins, optionally with a transceiver to
280 * support cards using voltages other than VDDS (1.8V nominal). When a
281 * transceiver is used, DAT3..7 are muxed as transceiver control pins.
282 *
283 * In some cases this regulator won't support enable/disable;
284 * e.g. it's a fixed rail for a WLAN chip.
285 *
286 * In other cases vcc_aux switches interface power. Example, for
287 * eMMC cards it represents VccQ. Sometimes transceivers or SDIO
288 * chips/cards need an interface voltage rail too.
289 */
290 if (power_on) {
291 ret = mmc_regulator_set_ocr(host->vcc, vdd);
292 /* Enable interface voltage rail, if needed */
293 if (ret == 0 && host->vcc_aux) {
294 ret = regulator_enable(host->vcc_aux);
295 if (ret < 0)
296 ret = mmc_regulator_set_ocr(host->vcc, 0);
297 }
298 } else {
Adrian Hunter6da20c82010-02-15 10:03:34 -0800299 if (host->vcc_aux)
300 ret = regulator_disable(host->vcc_aux);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800301 if (ret == 0)
302 ret = mmc_regulator_set_ocr(host->vcc, 0);
303 }
304
305 if (mmc_slot(host).after_set_reg)
306 mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
307
308 return ret;
309}
310
311static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
312 int vdd, int cardsleep)
313{
314 struct omap_hsmmc_host *host =
315 platform_get_drvdata(to_platform_device(dev));
316 int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
317
318 return regulator_set_mode(host->vcc, mode);
319}
320
321static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
322 int vdd, int cardsleep)
323{
324 struct omap_hsmmc_host *host =
325 platform_get_drvdata(to_platform_device(dev));
326 int err, mode;
327
328 /*
329 * If we don't see a Vcc regulator, assume it's a fixed
330 * voltage always-on regulator.
331 */
332 if (!host->vcc)
333 return 0;
334
335 mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
336
337 if (!host->vcc_aux)
338 return regulator_set_mode(host->vcc, mode);
339
340 if (cardsleep) {
341 /* VCC can be turned off if card is asleep */
342 if (sleep)
343 err = mmc_regulator_set_ocr(host->vcc, 0);
344 else
345 err = mmc_regulator_set_ocr(host->vcc, vdd);
346 } else
347 err = regulator_set_mode(host->vcc, mode);
348 if (err)
349 return err;
Adrian Huntere0eb2422010-02-15 10:03:34 -0800350
351 if (!mmc_slot(host).vcc_aux_disable_is_sleep)
352 return regulator_set_mode(host->vcc_aux, mode);
353
354 if (sleep)
355 return regulator_disable(host->vcc_aux);
356 else
357 return regulator_enable(host->vcc_aux);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800358}
359
360static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
361{
362 int ret;
363
364 if (gpio_is_valid(pdata->slots[0].switch_pin)) {
365 pdata->suspend = omap_hsmmc_suspend_cdirq;
366 pdata->resume = omap_hsmmc_resume_cdirq;
367 if (pdata->slots[0].cover)
368 pdata->slots[0].get_cover_state =
369 omap_hsmmc_get_cover_state;
370 else
371 pdata->slots[0].card_detect = omap_hsmmc_card_detect;
372 pdata->slots[0].card_detect_irq =
373 gpio_to_irq(pdata->slots[0].switch_pin);
374 ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd");
375 if (ret)
376 return ret;
377 ret = gpio_direction_input(pdata->slots[0].switch_pin);
378 if (ret)
379 goto err_free_sp;
380 } else
381 pdata->slots[0].switch_pin = -EINVAL;
382
383 if (gpio_is_valid(pdata->slots[0].gpio_wp)) {
384 pdata->slots[0].get_ro = omap_hsmmc_get_wp;
385 ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp");
386 if (ret)
387 goto err_free_cd;
388 ret = gpio_direction_input(pdata->slots[0].gpio_wp);
389 if (ret)
390 goto err_free_wp;
391 } else
392 pdata->slots[0].gpio_wp = -EINVAL;
393
394 return 0;
395
396err_free_wp:
397 gpio_free(pdata->slots[0].gpio_wp);
398err_free_cd:
399 if (gpio_is_valid(pdata->slots[0].switch_pin))
400err_free_sp:
401 gpio_free(pdata->slots[0].switch_pin);
402 return ret;
403}
404
405static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
406{
407 if (gpio_is_valid(pdata->slots[0].gpio_wp))
408 gpio_free(pdata->slots[0].gpio_wp);
409 if (gpio_is_valid(pdata->slots[0].switch_pin))
410 gpio_free(pdata->slots[0].switch_pin);
411}
412
413static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
414{
415 struct regulator *reg;
416 int ret = 0;
417
418 switch (host->id) {
419 case OMAP_MMC1_DEVID:
420 /* On-chip level shifting via PBIAS0/PBIAS1 */
421 mmc_slot(host).set_power = omap_hsmmc_1_set_power;
422 mmc_slot(host).set_sleep = omap_hsmmc_1_set_sleep;
423 break;
424 case OMAP_MMC2_DEVID:
425 case OMAP_MMC3_DEVID:
426 /* Off-chip level shifting, or none */
427 mmc_slot(host).set_power = omap_hsmmc_23_set_power;
428 mmc_slot(host).set_sleep = omap_hsmmc_23_set_sleep;
429 break;
430 default:
431 pr_err("MMC%d configuration not supported!\n", host->id);
432 return -EINVAL;
433 }
434
435 reg = regulator_get(host->dev, "vmmc");
436 if (IS_ERR(reg)) {
437 dev_dbg(host->dev, "vmmc regulator missing\n");
438 /*
439 * HACK: until fixed.c regulator is usable,
440 * we don't require a main regulator
441 * for MMC2 or MMC3
442 */
443 if (host->id == OMAP_MMC1_DEVID) {
444 ret = PTR_ERR(reg);
445 goto err;
446 }
447 } else {
448 host->vcc = reg;
449 mmc_slot(host).ocr_mask = mmc_regulator_get_ocrmask(reg);
450
451 /* Allow an aux regulator */
452 reg = regulator_get(host->dev, "vmmc_aux");
453 host->vcc_aux = IS_ERR(reg) ? NULL : reg;
454
455 /*
456 * UGLY HACK: workaround regulator framework bugs.
457 * When the bootloader leaves a supply active, it's
458 * initialized with zero usecount ... and we can't
459 * disable it without first enabling it. Until the
460 * framework is fixed, we need a workaround like this
461 * (which is safe for MMC, but not in general).
462 */
463 if (regulator_is_enabled(host->vcc) > 0) {
464 regulator_enable(host->vcc);
465 regulator_disable(host->vcc);
466 }
467 if (host->vcc_aux) {
468 if (regulator_is_enabled(reg) > 0) {
469 regulator_enable(reg);
470 regulator_disable(reg);
471 }
472 }
473 }
474
475 return 0;
476
477err:
478 mmc_slot(host).set_power = NULL;
479 mmc_slot(host).set_sleep = NULL;
480 return ret;
481}
482
483static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
484{
485 regulator_put(host->vcc);
486 regulator_put(host->vcc_aux);
487 mmc_slot(host).set_power = NULL;
488 mmc_slot(host).set_sleep = NULL;
489}
490
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100491/*
492 * Stop clock to the card
493 */
Denis Karpov70a33412009-09-22 16:44:59 -0700494static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100495{
496 OMAP_HSMMC_WRITE(host->base, SYSCTL,
497 OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
498 if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
499 dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
500}
501
Denis Karpov11dd62a2009-09-22 16:44:43 -0700502#ifdef CONFIG_PM
503
504/*
505 * Restore the MMC host context, if it was lost as result of a
506 * power state change.
507 */
Denis Karpov70a33412009-09-22 16:44:59 -0700508static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700509{
510 struct mmc_ios *ios = &host->mmc->ios;
511 struct omap_mmc_platform_data *pdata = host->pdata;
512 int context_loss = 0;
513 u32 hctl, capa, con;
514 u16 dsor = 0;
515 unsigned long timeout;
516
517 if (pdata->get_context_loss_count) {
518 context_loss = pdata->get_context_loss_count(host->dev);
519 if (context_loss < 0)
520 return 1;
521 }
522
523 dev_dbg(mmc_dev(host->mmc), "context was %slost\n",
524 context_loss == host->context_loss ? "not " : "");
525 if (host->context_loss == context_loss)
526 return 1;
527
528 /* Wait for hardware reset */
529 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
530 while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
531 && time_before(jiffies, timeout))
532 ;
533
534 /* Do software reset */
535 OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET);
536 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
537 while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
538 && time_before(jiffies, timeout))
539 ;
540
541 OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
542 OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
543
544 if (host->id == OMAP_MMC1_DEVID) {
545 if (host->power_mode != MMC_POWER_OFF &&
546 (1 << ios->vdd) <= MMC_VDD_23_24)
547 hctl = SDVS18;
548 else
549 hctl = SDVS30;
550 capa = VS30 | VS18;
551 } else {
552 hctl = SDVS18;
553 capa = VS18;
554 }
555
556 OMAP_HSMMC_WRITE(host->base, HCTL,
557 OMAP_HSMMC_READ(host->base, HCTL) | hctl);
558
559 OMAP_HSMMC_WRITE(host->base, CAPA,
560 OMAP_HSMMC_READ(host->base, CAPA) | capa);
561
562 OMAP_HSMMC_WRITE(host->base, HCTL,
563 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
564
565 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
566 while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP
567 && time_before(jiffies, timeout))
568 ;
569
570 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
571 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
572 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
573
574 /* Do not initialize card-specific things if the power is off */
575 if (host->power_mode == MMC_POWER_OFF)
576 goto out;
577
578 con = OMAP_HSMMC_READ(host->base, CON);
579 switch (ios->bus_width) {
580 case MMC_BUS_WIDTH_8:
581 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
582 break;
583 case MMC_BUS_WIDTH_4:
584 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
585 OMAP_HSMMC_WRITE(host->base, HCTL,
586 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
587 break;
588 case MMC_BUS_WIDTH_1:
589 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
590 OMAP_HSMMC_WRITE(host->base, HCTL,
591 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
592 break;
593 }
594
595 if (ios->clock) {
596 dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
597 if (dsor < 1)
598 dsor = 1;
599
600 if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
601 dsor++;
602
603 if (dsor > 250)
604 dsor = 250;
605 }
606
607 OMAP_HSMMC_WRITE(host->base, SYSCTL,
608 OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
609 OMAP_HSMMC_WRITE(host->base, SYSCTL, (dsor << 6) | (DTO << 16));
610 OMAP_HSMMC_WRITE(host->base, SYSCTL,
611 OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
612
613 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
614 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
615 && time_before(jiffies, timeout))
616 ;
617
618 OMAP_HSMMC_WRITE(host->base, SYSCTL,
619 OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
620
621 con = OMAP_HSMMC_READ(host->base, CON);
622 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
623 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
624 else
625 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
626out:
627 host->context_loss = context_loss;
628
629 dev_dbg(mmc_dev(host->mmc), "context is restored\n");
630 return 0;
631}
632
633/*
634 * Save the MMC host context (store the number of power state changes so far).
635 */
Denis Karpov70a33412009-09-22 16:44:59 -0700636static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700637{
638 struct omap_mmc_platform_data *pdata = host->pdata;
639 int context_loss;
640
641 if (pdata->get_context_loss_count) {
642 context_loss = pdata->get_context_loss_count(host->dev);
643 if (context_loss < 0)
644 return;
645 host->context_loss = context_loss;
646 }
647}
648
649#else
650
Denis Karpov70a33412009-09-22 16:44:59 -0700651static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700652{
653 return 0;
654}
655
Denis Karpov70a33412009-09-22 16:44:59 -0700656static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700657{
658}
659
660#endif
661
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100662/*
663 * Send init stream sequence to card
664 * before sending IDLE command
665 */
Denis Karpov70a33412009-09-22 16:44:59 -0700666static void send_init_stream(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100667{
668 int reg = 0;
669 unsigned long timeout;
670
Adrian Hunterb62f6222009-09-22 16:45:01 -0700671 if (host->protect_card)
672 return;
673
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100674 disable_irq(host->irq);
675 OMAP_HSMMC_WRITE(host->base, CON,
676 OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
677 OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
678
679 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
680 while ((reg != CC) && time_before(jiffies, timeout))
681 reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
682
683 OMAP_HSMMC_WRITE(host->base, CON,
684 OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
Adrian Hunterc653a6d2009-09-22 16:44:56 -0700685
686 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
687 OMAP_HSMMC_READ(host->base, STAT);
688
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100689 enable_irq(host->irq);
690}
691
692static inline
Denis Karpov70a33412009-09-22 16:44:59 -0700693int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100694{
695 int r = 1;
696
Denis Karpov191d1f12009-09-22 16:44:55 -0700697 if (mmc_slot(host).get_cover_state)
698 r = mmc_slot(host).get_cover_state(host->dev, host->slot_id);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100699 return r;
700}
701
702static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700703omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100704 char *buf)
705{
706 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700707 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100708
Denis Karpov70a33412009-09-22 16:44:59 -0700709 return sprintf(buf, "%s\n",
710 omap_hsmmc_cover_is_closed(host) ? "closed" : "open");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100711}
712
Denis Karpov70a33412009-09-22 16:44:59 -0700713static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100714
715static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700716omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100717 char *buf)
718{
719 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700720 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100721
Denis Karpov191d1f12009-09-22 16:44:55 -0700722 return sprintf(buf, "%s\n", mmc_slot(host).name);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100723}
724
Denis Karpov70a33412009-09-22 16:44:59 -0700725static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100726
727/*
728 * Configure the response type and send the cmd.
729 */
730static void
Denis Karpov70a33412009-09-22 16:44:59 -0700731omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100732 struct mmc_data *data)
733{
734 int cmdreg = 0, resptype = 0, cmdtype = 0;
735
736 dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
737 mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
738 host->cmd = cmd;
739
740 /*
741 * Clear status bits and enable interrupts
742 */
743 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
744 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
Anand Gadiyarccdfe3a2009-09-22 16:44:21 -0700745
746 if (host->use_dma)
747 OMAP_HSMMC_WRITE(host->base, IE,
748 INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
749 else
750 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100751
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200752 host->response_busy = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100753 if (cmd->flags & MMC_RSP_PRESENT) {
754 if (cmd->flags & MMC_RSP_136)
755 resptype = 1;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200756 else if (cmd->flags & MMC_RSP_BUSY) {
757 resptype = 3;
758 host->response_busy = 1;
759 } else
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100760 resptype = 2;
761 }
762
763 /*
764 * Unlike OMAP1 controller, the cmdtype does not seem to be based on
765 * ac, bc, adtc, bcr. Only commands ending an open ended transfer need
766 * a val of 0x3, rest 0x0.
767 */
768 if (cmd == host->mrq->stop)
769 cmdtype = 0x3;
770
771 cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
772
773 if (data) {
774 cmdreg |= DP_SELECT | MSBS | BCE;
775 if (data->flags & MMC_DATA_READ)
776 cmdreg |= DDIR;
777 else
778 cmdreg &= ~(DDIR);
779 }
780
781 if (host->use_dma)
782 cmdreg |= DMA_EN;
783
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700784 /*
785 * In an interrupt context (i.e. STOP command), the spinlock is unlocked
786 * by the interrupt handler, otherwise (i.e. for a new request) it is
787 * unlocked here.
788 */
789 if (!in_interrupt())
790 spin_unlock_irqrestore(&host->irq_lock, host->flags);
791
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100792 OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
793 OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
794}
795
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200796static int
Denis Karpov70a33412009-09-22 16:44:59 -0700797omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200798{
799 if (data->flags & MMC_DATA_WRITE)
800 return DMA_TO_DEVICE;
801 else
802 return DMA_FROM_DEVICE;
803}
804
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100805/*
806 * Notify the transfer complete to MMC core
807 */
808static void
Denis Karpov70a33412009-09-22 16:44:59 -0700809omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100810{
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200811 if (!data) {
812 struct mmc_request *mrq = host->mrq;
813
Adrian Hunter23050102009-09-22 16:44:57 -0700814 /* TC before CC from CMD6 - don't know why, but it happens */
815 if (host->cmd && host->cmd->opcode == 6 &&
816 host->response_busy) {
817 host->response_busy = 0;
818 return;
819 }
820
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200821 host->mrq = NULL;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200822 mmc_request_done(host->mmc, mrq);
823 return;
824 }
825
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100826 host->data = NULL;
827
828 if (host->use_dma && host->dma_ch != -1)
829 dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
Denis Karpov70a33412009-09-22 16:44:59 -0700830 omap_hsmmc_get_dma_dir(host, data));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100831
832 if (!data->error)
833 data->bytes_xfered += data->blocks * (data->blksz);
834 else
835 data->bytes_xfered = 0;
836
837 if (!data->stop) {
838 host->mrq = NULL;
839 mmc_request_done(host->mmc, data->mrq);
840 return;
841 }
Denis Karpov70a33412009-09-22 16:44:59 -0700842 omap_hsmmc_start_command(host, data->stop, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100843}
844
845/*
846 * Notify the core about command completion
847 */
848static void
Denis Karpov70a33412009-09-22 16:44:59 -0700849omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100850{
851 host->cmd = NULL;
852
853 if (cmd->flags & MMC_RSP_PRESENT) {
854 if (cmd->flags & MMC_RSP_136) {
855 /* response type 2 */
856 cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
857 cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
858 cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
859 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
860 } else {
861 /* response types 1, 1b, 3, 4, 5, 6 */
862 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
863 }
864 }
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200865 if ((host->data == NULL && !host->response_busy) || cmd->error) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100866 host->mrq = NULL;
867 mmc_request_done(host->mmc, cmd->mrq);
868 }
869}
870
871/*
872 * DMA clean up for command errors
873 */
Denis Karpov70a33412009-09-22 16:44:59 -0700874static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100875{
Jarkko Lavinen82788ff2008-12-05 12:31:46 +0200876 host->data->error = errno;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100877
878 if (host->use_dma && host->dma_ch != -1) {
879 dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
Denis Karpov70a33412009-09-22 16:44:59 -0700880 omap_hsmmc_get_dma_dir(host, host->data));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100881 omap_free_dma(host->dma_ch);
882 host->dma_ch = -1;
883 up(&host->sem);
884 }
885 host->data = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100886}
887
888/*
889 * Readable error output
890 */
891#ifdef CONFIG_MMC_DEBUG
Denis Karpov70a33412009-09-22 16:44:59 -0700892static void omap_hsmmc_report_irq(struct omap_hsmmc_host *host, u32 status)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100893{
894 /* --- means reserved bit without definition at documentation */
Denis Karpov70a33412009-09-22 16:44:59 -0700895 static const char *omap_hsmmc_status_bits[] = {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100896 "CC", "TC", "BGE", "---", "BWR", "BRR", "---", "---", "CIRQ",
897 "OBI", "---", "---", "---", "---", "---", "ERRI", "CTO", "CCRC",
898 "CEB", "CIE", "DTO", "DCRC", "DEB", "---", "ACE", "---",
899 "---", "---", "---", "CERR", "CERR", "BADA", "---", "---", "---"
900 };
901 char res[256];
902 char *buf = res;
903 int len, i;
904
905 len = sprintf(buf, "MMC IRQ 0x%x :", status);
906 buf += len;
907
Denis Karpov70a33412009-09-22 16:44:59 -0700908 for (i = 0; i < ARRAY_SIZE(omap_hsmmc_status_bits); i++)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100909 if (status & (1 << i)) {
Denis Karpov70a33412009-09-22 16:44:59 -0700910 len = sprintf(buf, " %s", omap_hsmmc_status_bits[i]);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100911 buf += len;
912 }
913
914 dev_dbg(mmc_dev(host->mmc), "%s\n", res);
915}
916#endif /* CONFIG_MMC_DEBUG */
917
Jean Pihet3ebf74b2009-02-06 16:42:51 +0100918/*
919 * MMC controller internal state machines reset
920 *
921 * Used to reset command or data internal state machines, using respectively
922 * SRC or SRD bit of SYSCTL register
923 * Can be called from interrupt context
924 */
Denis Karpov70a33412009-09-22 16:44:59 -0700925static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
926 unsigned long bit)
Jean Pihet3ebf74b2009-02-06 16:42:51 +0100927{
928 unsigned long i = 0;
929 unsigned long limit = (loops_per_jiffy *
930 msecs_to_jiffies(MMC_TIMEOUT_MS));
931
932 OMAP_HSMMC_WRITE(host->base, SYSCTL,
933 OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
934
935 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
936 (i++ < limit))
937 cpu_relax();
938
939 if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
940 dev_err(mmc_dev(host->mmc),
941 "Timeout waiting on controller reset in %s\n",
942 __func__);
943}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100944
945/*
946 * MMC controller IRQ handler
947 */
Denis Karpov70a33412009-09-22 16:44:59 -0700948static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100949{
Denis Karpov70a33412009-09-22 16:44:59 -0700950 struct omap_hsmmc_host *host = dev_id;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100951 struct mmc_data *data;
952 int end_cmd = 0, end_trans = 0, status;
953
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700954 spin_lock(&host->irq_lock);
955
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200956 if (host->mrq == NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100957 OMAP_HSMMC_WRITE(host->base, STAT,
958 OMAP_HSMMC_READ(host->base, STAT));
Kevin Hilman00adadc2009-04-06 15:01:19 +0300959 /* Flush posted write */
960 OMAP_HSMMC_READ(host->base, STAT);
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700961 spin_unlock(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100962 return IRQ_HANDLED;
963 }
964
965 data = host->data;
966 status = OMAP_HSMMC_READ(host->base, STAT);
967 dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
968
969 if (status & ERR) {
970#ifdef CONFIG_MMC_DEBUG
Denis Karpov70a33412009-09-22 16:44:59 -0700971 omap_hsmmc_report_irq(host, status);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100972#endif
973 if ((status & CMD_TIMEOUT) ||
974 (status & CMD_CRC)) {
975 if (host->cmd) {
976 if (status & CMD_TIMEOUT) {
Denis Karpov70a33412009-09-22 16:44:59 -0700977 omap_hsmmc_reset_controller_fsm(host,
978 SRC);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100979 host->cmd->error = -ETIMEDOUT;
980 } else {
981 host->cmd->error = -EILSEQ;
982 }
983 end_cmd = 1;
984 }
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200985 if (host->data || host->response_busy) {
986 if (host->data)
Denis Karpov70a33412009-09-22 16:44:59 -0700987 omap_hsmmc_dma_cleanup(host,
988 -ETIMEDOUT);
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200989 host->response_busy = 0;
Denis Karpov70a33412009-09-22 16:44:59 -0700990 omap_hsmmc_reset_controller_fsm(host, SRD);
Jean Pihetc232f452009-02-11 13:11:39 -0800991 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100992 }
993 if ((status & DATA_TIMEOUT) ||
994 (status & DATA_CRC)) {
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200995 if (host->data || host->response_busy) {
996 int err = (status & DATA_TIMEOUT) ?
997 -ETIMEDOUT : -EILSEQ;
998
999 if (host->data)
Denis Karpov70a33412009-09-22 16:44:59 -07001000 omap_hsmmc_dma_cleanup(host, err);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001001 else
Adrian Hunter4a694dc2009-01-12 16:13:08 +02001002 host->mrq->cmd->error = err;
1003 host->response_busy = 0;
Denis Karpov70a33412009-09-22 16:44:59 -07001004 omap_hsmmc_reset_controller_fsm(host, SRD);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001005 end_trans = 1;
1006 }
1007 }
1008 if (status & CARD_ERR) {
1009 dev_dbg(mmc_dev(host->mmc),
1010 "Ignoring card err CMD%d\n", host->cmd->opcode);
1011 if (host->cmd)
1012 end_cmd = 1;
1013 if (host->data)
1014 end_trans = 1;
1015 }
1016 }
1017
1018 OMAP_HSMMC_WRITE(host->base, STAT, status);
Kevin Hilman00adadc2009-04-06 15:01:19 +03001019 /* Flush posted write */
1020 OMAP_HSMMC_READ(host->base, STAT);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001021
Jarkko Lavinena8fe29d2009-04-08 11:18:32 +03001022 if (end_cmd || ((status & CC) && host->cmd))
Denis Karpov70a33412009-09-22 16:44:59 -07001023 omap_hsmmc_cmd_done(host, host->cmd);
Jarkko Lavinen0a40e642009-09-22 16:44:54 -07001024 if ((end_trans || (status & TC)) && host->mrq)
Denis Karpov70a33412009-09-22 16:44:59 -07001025 omap_hsmmc_xfer_done(host, data);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001026
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001027 spin_unlock(&host->irq_lock);
1028
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001029 return IRQ_HANDLED;
1030}
1031
Denis Karpov70a33412009-09-22 16:44:59 -07001032static void set_sd_bus_power(struct omap_hsmmc_host *host)
Adrian Huntere13bb302009-03-12 17:08:26 +02001033{
1034 unsigned long i;
1035
1036 OMAP_HSMMC_WRITE(host->base, HCTL,
1037 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
1038 for (i = 0; i < loops_per_jiffy; i++) {
1039 if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
1040 break;
1041 cpu_relax();
1042 }
1043}
1044
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001045/*
David Brownelleb250822009-02-17 14:49:01 -08001046 * Switch MMC interface voltage ... only relevant for MMC1.
1047 *
1048 * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
1049 * The MMC2 transceiver controls are used instead of DAT4..DAT7.
1050 * Some chips, like eMMC ones, use internal transceivers.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001051 */
Denis Karpov70a33412009-09-22 16:44:59 -07001052static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001053{
1054 u32 reg_val = 0;
1055 int ret;
1056
1057 /* Disable the clocks */
1058 clk_disable(host->fclk);
1059 clk_disable(host->iclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07001060 if (host->got_dbclk)
1061 clk_disable(host->dbclk);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001062
1063 /* Turn the power off */
1064 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001065
1066 /* Turn the power ON with given VDD 1.8 or 3.0v */
Adrian Hunter2bec0892009-09-22 16:45:02 -07001067 if (!ret)
1068 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1,
1069 vdd);
1070 clk_enable(host->iclk);
1071 clk_enable(host->fclk);
1072 if (host->got_dbclk)
1073 clk_enable(host->dbclk);
1074
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001075 if (ret != 0)
1076 goto err;
1077
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001078 OMAP_HSMMC_WRITE(host->base, HCTL,
1079 OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
1080 reg_val = OMAP_HSMMC_READ(host->base, HCTL);
David Brownelleb250822009-02-17 14:49:01 -08001081
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001082 /*
1083 * If a MMC dual voltage card is detected, the set_ios fn calls
1084 * this fn with VDD bit set for 1.8V. Upon card removal from the
Denis Karpov70a33412009-09-22 16:44:59 -07001085 * slot, omap_hsmmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001086 *
David Brownelleb250822009-02-17 14:49:01 -08001087 * Cope with a bit of slop in the range ... per data sheets:
1088 * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
1089 * but recommended values are 1.71V to 1.89V
1090 * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
1091 * but recommended values are 2.7V to 3.3V
1092 *
1093 * Board setup code shouldn't permit anything very out-of-range.
1094 * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
1095 * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001096 */
David Brownelleb250822009-02-17 14:49:01 -08001097 if ((1 << vdd) <= MMC_VDD_23_24)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001098 reg_val |= SDVS18;
David Brownelleb250822009-02-17 14:49:01 -08001099 else
1100 reg_val |= SDVS30;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001101
1102 OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
Adrian Huntere13bb302009-03-12 17:08:26 +02001103 set_sd_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001104
1105 return 0;
1106err:
1107 dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
1108 return ret;
1109}
1110
Adrian Hunterb62f6222009-09-22 16:45:01 -07001111/* Protect the card while the cover is open */
1112static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
1113{
1114 if (!mmc_slot(host).get_cover_state)
1115 return;
1116
1117 host->reqs_blocked = 0;
1118 if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
1119 if (host->protect_card) {
1120 printk(KERN_INFO "%s: cover is closed, "
1121 "card is now accessible\n",
1122 mmc_hostname(host->mmc));
1123 host->protect_card = 0;
1124 }
1125 } else {
1126 if (!host->protect_card) {
1127 printk(KERN_INFO "%s: cover is open, "
1128 "card is now inaccessible\n",
1129 mmc_hostname(host->mmc));
1130 host->protect_card = 1;
1131 }
1132 }
1133}
1134
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001135/*
1136 * Work Item to notify the core about card insertion/removal
1137 */
Denis Karpov70a33412009-09-22 16:44:59 -07001138static void omap_hsmmc_detect(struct work_struct *work)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001139{
Denis Karpov70a33412009-09-22 16:44:59 -07001140 struct omap_hsmmc_host *host =
1141 container_of(work, struct omap_hsmmc_host, mmc_carddetect_work);
David Brownell249d0fa2009-02-04 14:42:03 -08001142 struct omap_mmc_slot_data *slot = &mmc_slot(host);
Adrian Huntera6b22402009-09-22 16:44:45 -07001143 int carddetect;
David Brownell249d0fa2009-02-04 14:42:03 -08001144
Adrian Huntera6b22402009-09-22 16:44:45 -07001145 if (host->suspended)
1146 return;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001147
1148 sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
Adrian Huntera6b22402009-09-22 16:44:45 -07001149
Denis Karpov191d1f12009-09-22 16:44:55 -07001150 if (slot->card_detect)
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001151 carddetect = slot->card_detect(host->dev, host->slot_id);
Adrian Hunterb62f6222009-09-22 16:45:01 -07001152 else {
1153 omap_hsmmc_protect_card(host);
Adrian Huntera6b22402009-09-22 16:44:45 -07001154 carddetect = -ENOSYS;
Adrian Hunterb62f6222009-09-22 16:45:01 -07001155 }
Adrian Huntera6b22402009-09-22 16:44:45 -07001156
1157 if (carddetect) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001158 mmc_detect_change(host->mmc, (HZ * 200) / 1000);
1159 } else {
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001160 mmc_host_enable(host->mmc);
Denis Karpov70a33412009-09-22 16:44:59 -07001161 omap_hsmmc_reset_controller_fsm(host, SRD);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001162 mmc_host_lazy_disable(host->mmc);
Denis Karpov70a33412009-09-22 16:44:59 -07001163
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001164 mmc_detect_change(host->mmc, (HZ * 50) / 1000);
1165 }
1166}
1167
1168/*
1169 * ISR for handling card insertion and removal
1170 */
Denis Karpov70a33412009-09-22 16:44:59 -07001171static irqreturn_t omap_hsmmc_cd_handler(int irq, void *dev_id)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001172{
Denis Karpov70a33412009-09-22 16:44:59 -07001173 struct omap_hsmmc_host *host = (struct omap_hsmmc_host *)dev_id;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001174
Adrian Huntera6b22402009-09-22 16:44:45 -07001175 if (host->suspended)
1176 return IRQ_HANDLED;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001177 schedule_work(&host->mmc_carddetect_work);
1178
1179 return IRQ_HANDLED;
1180}
1181
Denis Karpov70a33412009-09-22 16:44:59 -07001182static int omap_hsmmc_get_dma_sync_dev(struct omap_hsmmc_host *host,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001183 struct mmc_data *data)
1184{
1185 int sync_dev;
1186
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +00001187 if (data->flags & MMC_DATA_WRITE)
1188 sync_dev = host->dma_line_tx;
1189 else
1190 sync_dev = host->dma_line_rx;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001191 return sync_dev;
1192}
1193
Denis Karpov70a33412009-09-22 16:44:59 -07001194static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001195 struct mmc_data *data,
1196 struct scatterlist *sgl)
1197{
1198 int blksz, nblk, dma_ch;
1199
1200 dma_ch = host->dma_ch;
1201 if (data->flags & MMC_DATA_WRITE) {
1202 omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
1203 (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
1204 omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
1205 sg_dma_address(sgl), 0, 0);
1206 } else {
1207 omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
Denis Karpov191d1f12009-09-22 16:44:55 -07001208 (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001209 omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
1210 sg_dma_address(sgl), 0, 0);
1211 }
1212
1213 blksz = host->data->blksz;
1214 nblk = sg_dma_len(sgl) / blksz;
1215
1216 omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32,
1217 blksz / 4, nblk, OMAP_DMA_SYNC_FRAME,
Denis Karpov70a33412009-09-22 16:44:59 -07001218 omap_hsmmc_get_dma_sync_dev(host, data),
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001219 !(data->flags & MMC_DATA_WRITE));
1220
1221 omap_start_dma(dma_ch);
1222}
1223
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001224/*
1225 * DMA call back function
1226 */
Denis Karpov70a33412009-09-22 16:44:59 -07001227static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001228{
Denis Karpov70a33412009-09-22 16:44:59 -07001229 struct omap_hsmmc_host *host = data;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001230
1231 if (ch_status & OMAP2_DMA_MISALIGNED_ERR_IRQ)
1232 dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n");
1233
1234 if (host->dma_ch < 0)
1235 return;
1236
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001237 host->dma_sg_idx++;
1238 if (host->dma_sg_idx < host->dma_len) {
1239 /* Fire up the next transfer. */
Denis Karpov70a33412009-09-22 16:44:59 -07001240 omap_hsmmc_config_dma_params(host, host->data,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001241 host->data->sg + host->dma_sg_idx);
1242 return;
1243 }
1244
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001245 omap_free_dma(host->dma_ch);
1246 host->dma_ch = -1;
1247 /*
1248 * DMA Callback: run in interrupt context.
Anand Gadiyar85b84322009-04-15 17:44:58 +05301249 * mutex_unlock will throw a kernel warning if used.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001250 */
1251 up(&host->sem);
1252}
1253
1254/*
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001255 * Routine to configure and start DMA for the MMC card
1256 */
Denis Karpov70a33412009-09-22 16:44:59 -07001257static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
1258 struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001259{
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001260 int dma_ch = 0, ret = 0, err = 1, i;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001261 struct mmc_data *data = req->data;
1262
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001263 /* Sanity check: all the SG entries must be aligned by block size. */
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001264 for (i = 0; i < data->sg_len; i++) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001265 struct scatterlist *sgl;
1266
1267 sgl = data->sg + i;
1268 if (sgl->length % data->blksz)
1269 return -EINVAL;
1270 }
1271 if ((data->blksz % 4) != 0)
1272 /* REVISIT: The MMC buffer increments only when MSB is written.
1273 * Return error for blksz which is non multiple of four.
1274 */
1275 return -EINVAL;
1276
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001277 /*
1278 * If for some reason the DMA transfer is still active,
1279 * we wait for timeout period and free the dma
1280 */
1281 if (host->dma_ch != -1) {
1282 set_current_state(TASK_UNINTERRUPTIBLE);
1283 schedule_timeout(100);
1284 if (down_trylock(&host->sem)) {
1285 omap_free_dma(host->dma_ch);
1286 host->dma_ch = -1;
1287 up(&host->sem);
1288 return err;
1289 }
1290 } else {
1291 if (down_trylock(&host->sem))
1292 return err;
1293 }
1294
Denis Karpov70a33412009-09-22 16:44:59 -07001295 ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data),
1296 "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001297 if (ret != 0) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001298 dev_err(mmc_dev(host->mmc),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001299 "%s: omap_request_dma() failed with %d\n",
1300 mmc_hostname(host->mmc), ret);
1301 return ret;
1302 }
1303
1304 host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
Denis Karpov70a33412009-09-22 16:44:59 -07001305 data->sg_len, omap_hsmmc_get_dma_dir(host, data));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001306 host->dma_ch = dma_ch;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001307 host->dma_sg_idx = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001308
Denis Karpov70a33412009-09-22 16:44:59 -07001309 omap_hsmmc_config_dma_params(host, data, data->sg);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001310
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001311 return 0;
1312}
1313
Denis Karpov70a33412009-09-22 16:44:59 -07001314static void set_data_timeout(struct omap_hsmmc_host *host,
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001315 unsigned int timeout_ns,
1316 unsigned int timeout_clks)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001317{
1318 unsigned int timeout, cycle_ns;
1319 uint32_t reg, clkd, dto = 0;
1320
1321 reg = OMAP_HSMMC_READ(host->base, SYSCTL);
1322 clkd = (reg & CLKD_MASK) >> CLKD_SHIFT;
1323 if (clkd == 0)
1324 clkd = 1;
1325
1326 cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001327 timeout = timeout_ns / cycle_ns;
1328 timeout += timeout_clks;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001329 if (timeout) {
1330 while ((timeout & 0x80000000) == 0) {
1331 dto += 1;
1332 timeout <<= 1;
1333 }
1334 dto = 31 - dto;
1335 timeout <<= 1;
1336 if (timeout && dto)
1337 dto += 1;
1338 if (dto >= 13)
1339 dto -= 13;
1340 else
1341 dto = 0;
1342 if (dto > 14)
1343 dto = 14;
1344 }
1345
1346 reg &= ~DTO_MASK;
1347 reg |= dto << DTO_SHIFT;
1348 OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
1349}
1350
1351/*
1352 * Configure block length for MMC/SD cards and initiate the transfer.
1353 */
1354static int
Denis Karpov70a33412009-09-22 16:44:59 -07001355omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001356{
1357 int ret;
1358 host->data = req->data;
1359
1360 if (req->data == NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001361 OMAP_HSMMC_WRITE(host->base, BLK, 0);
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001362 /*
1363 * Set an arbitrary 100ms data timeout for commands with
1364 * busy signal.
1365 */
1366 if (req->cmd->flags & MMC_RSP_BUSY)
1367 set_data_timeout(host, 100000000U, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001368 return 0;
1369 }
1370
1371 OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
1372 | (req->data->blocks << 16));
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001373 set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001374
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001375 if (host->use_dma) {
Denis Karpov70a33412009-09-22 16:44:59 -07001376 ret = omap_hsmmc_start_dma_transfer(host, req);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001377 if (ret != 0) {
1378 dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
1379 return ret;
1380 }
1381 }
1382 return 0;
1383}
1384
1385/*
1386 * Request function. for read/write operation
1387 */
Denis Karpov70a33412009-09-22 16:44:59 -07001388static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001389{
Denis Karpov70a33412009-09-22 16:44:59 -07001390 struct omap_hsmmc_host *host = mmc_priv(mmc);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001391 int err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001392
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001393 /*
1394 * Prevent races with the interrupt handler because of unexpected
1395 * interrupts, but not if we are already in interrupt context i.e.
1396 * retries.
1397 */
Adrian Hunterb62f6222009-09-22 16:45:01 -07001398 if (!in_interrupt()) {
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001399 spin_lock_irqsave(&host->irq_lock, host->flags);
Adrian Hunterb62f6222009-09-22 16:45:01 -07001400 /*
1401 * Protect the card from I/O if there is a possibility
1402 * it can be removed.
1403 */
1404 if (host->protect_card) {
1405 if (host->reqs_blocked < 3) {
1406 /*
1407 * Ensure the controller is left in a consistent
1408 * state by resetting the command and data state
1409 * machines.
1410 */
1411 omap_hsmmc_reset_controller_fsm(host, SRD);
1412 omap_hsmmc_reset_controller_fsm(host, SRC);
1413 host->reqs_blocked += 1;
1414 }
1415 req->cmd->error = -EBADF;
1416 if (req->data)
1417 req->data->error = -EBADF;
1418 spin_unlock_irqrestore(&host->irq_lock, host->flags);
1419 mmc_request_done(mmc, req);
1420 return;
1421 } else if (host->reqs_blocked)
1422 host->reqs_blocked = 0;
1423 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001424 WARN_ON(host->mrq != NULL);
1425 host->mrq = req;
Denis Karpov70a33412009-09-22 16:44:59 -07001426 err = omap_hsmmc_prepare_data(host, req);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001427 if (err) {
1428 req->cmd->error = err;
1429 if (req->data)
1430 req->data->error = err;
1431 host->mrq = NULL;
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001432 if (!in_interrupt())
1433 spin_unlock_irqrestore(&host->irq_lock, host->flags);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001434 mmc_request_done(mmc, req);
1435 return;
1436 }
1437
Denis Karpov70a33412009-09-22 16:44:59 -07001438 omap_hsmmc_start_command(host, req->cmd, req->data);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001439}
1440
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001441/* Routine to configure clock values. Exposed API to core */
Denis Karpov70a33412009-09-22 16:44:59 -07001442static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001443{
Denis Karpov70a33412009-09-22 16:44:59 -07001444 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001445 u16 dsor = 0;
1446 unsigned long regval;
1447 unsigned long timeout;
Jarkko Lavinen73153012008-11-21 16:49:54 +02001448 u32 con;
Adrian Huntera3621462009-09-22 16:44:42 -07001449 int do_send_init_stream = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001450
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001451 mmc_host_enable(host->mmc);
1452
Adrian Huntera3621462009-09-22 16:44:42 -07001453 if (ios->power_mode != host->power_mode) {
1454 switch (ios->power_mode) {
1455 case MMC_POWER_OFF:
1456 mmc_slot(host).set_power(host->dev, host->slot_id,
1457 0, 0);
Adrian Hunter623821f2009-09-22 16:44:51 -07001458 host->vdd = 0;
Adrian Huntera3621462009-09-22 16:44:42 -07001459 break;
1460 case MMC_POWER_UP:
1461 mmc_slot(host).set_power(host->dev, host->slot_id,
1462 1, ios->vdd);
Adrian Hunter623821f2009-09-22 16:44:51 -07001463 host->vdd = ios->vdd;
Adrian Huntera3621462009-09-22 16:44:42 -07001464 break;
1465 case MMC_POWER_ON:
1466 do_send_init_stream = 1;
1467 break;
1468 }
1469 host->power_mode = ios->power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001470 }
1471
Denis Karpovdd498ef2009-09-22 16:44:49 -07001472 /* FIXME: set registers based only on changes to ios */
1473
Jarkko Lavinen73153012008-11-21 16:49:54 +02001474 con = OMAP_HSMMC_READ(host->base, CON);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001475 switch (mmc->ios.bus_width) {
Jarkko Lavinen73153012008-11-21 16:49:54 +02001476 case MMC_BUS_WIDTH_8:
1477 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
1478 break;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001479 case MMC_BUS_WIDTH_4:
Jarkko Lavinen73153012008-11-21 16:49:54 +02001480 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001481 OMAP_HSMMC_WRITE(host->base, HCTL,
1482 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
1483 break;
1484 case MMC_BUS_WIDTH_1:
Jarkko Lavinen73153012008-11-21 16:49:54 +02001485 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001486 OMAP_HSMMC_WRITE(host->base, HCTL,
1487 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
1488 break;
1489 }
1490
1491 if (host->id == OMAP_MMC1_DEVID) {
David Brownelleb250822009-02-17 14:49:01 -08001492 /* Only MMC1 can interface at 3V without some flavor
1493 * of external transceiver; but they all handle 1.8V.
1494 */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001495 if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
1496 (ios->vdd == DUAL_VOLT_OCR_BIT)) {
1497 /*
1498 * The mmc_select_voltage fn of the core does
1499 * not seem to set the power_mode to
1500 * MMC_POWER_UP upon recalculating the voltage.
1501 * vdd 1.8v.
1502 */
Denis Karpov70a33412009-09-22 16:44:59 -07001503 if (omap_hsmmc_switch_opcond(host, ios->vdd) != 0)
1504 dev_dbg(mmc_dev(host->mmc),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001505 "Switch operation failed\n");
1506 }
1507 }
1508
1509 if (ios->clock) {
1510 dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
1511 if (dsor < 1)
1512 dsor = 1;
1513
1514 if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
1515 dsor++;
1516
1517 if (dsor > 250)
1518 dsor = 250;
1519 }
Denis Karpov70a33412009-09-22 16:44:59 -07001520 omap_hsmmc_stop_clock(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001521 regval = OMAP_HSMMC_READ(host->base, SYSCTL);
1522 regval = regval & ~(CLKD_MASK);
1523 regval = regval | (dsor << 6) | (DTO << 16);
1524 OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
1525 OMAP_HSMMC_WRITE(host->base, SYSCTL,
1526 OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
1527
1528 /* Wait till the ICS bit is set */
1529 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001530 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001531 && time_before(jiffies, timeout))
1532 msleep(1);
1533
1534 OMAP_HSMMC_WRITE(host->base, SYSCTL,
1535 OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
1536
Adrian Huntera3621462009-09-22 16:44:42 -07001537 if (do_send_init_stream)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001538 send_init_stream(host);
1539
Denis Karpovabb28e72009-09-22 16:44:44 -07001540 con = OMAP_HSMMC_READ(host->base, CON);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001541 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
Denis Karpovabb28e72009-09-22 16:44:44 -07001542 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
1543 else
1544 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001545
Denis Karpovdd498ef2009-09-22 16:44:49 -07001546 if (host->power_mode == MMC_POWER_OFF)
1547 mmc_host_disable(host->mmc);
1548 else
1549 mmc_host_lazy_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001550}
1551
1552static int omap_hsmmc_get_cd(struct mmc_host *mmc)
1553{
Denis Karpov70a33412009-09-22 16:44:59 -07001554 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001555
Denis Karpov191d1f12009-09-22 16:44:55 -07001556 if (!mmc_slot(host).card_detect)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001557 return -ENOSYS;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001558 return mmc_slot(host).card_detect(host->dev, host->slot_id);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001559}
1560
1561static int omap_hsmmc_get_ro(struct mmc_host *mmc)
1562{
Denis Karpov70a33412009-09-22 16:44:59 -07001563 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001564
Denis Karpov191d1f12009-09-22 16:44:55 -07001565 if (!mmc_slot(host).get_ro)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001566 return -ENOSYS;
Denis Karpov191d1f12009-09-22 16:44:55 -07001567 return mmc_slot(host).get_ro(host->dev, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001568}
1569
Denis Karpov70a33412009-09-22 16:44:59 -07001570static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001571{
1572 u32 hctl, capa, value;
1573
1574 /* Only MMC1 supports 3.0V */
1575 if (host->id == OMAP_MMC1_DEVID) {
1576 hctl = SDVS30;
1577 capa = VS30 | VS18;
1578 } else {
1579 hctl = SDVS18;
1580 capa = VS18;
1581 }
1582
1583 value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
1584 OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
1585
1586 value = OMAP_HSMMC_READ(host->base, CAPA);
1587 OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
1588
1589 /* Set the controller to AUTO IDLE mode */
1590 value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
1591 OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
1592
1593 /* Set SD bus power bit */
Adrian Huntere13bb302009-03-12 17:08:26 +02001594 set_sd_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001595}
1596
Denis Karpovdd498ef2009-09-22 16:44:49 -07001597/*
1598 * Dynamic power saving handling, FSM:
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001599 * ENABLED -> DISABLED -> CARDSLEEP / REGSLEEP -> OFF
1600 * ^___________| | |
1601 * |______________________|______________________|
Denis Karpovdd498ef2009-09-22 16:44:49 -07001602 *
1603 * ENABLED: mmc host is fully functional
1604 * DISABLED: fclk is off
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001605 * CARDSLEEP: fclk is off, card is asleep, voltage regulator is asleep
1606 * REGSLEEP: fclk is off, voltage regulator is asleep
1607 * OFF: fclk is off, voltage regulator is off
Denis Karpovdd498ef2009-09-22 16:44:49 -07001608 *
1609 * Transition handlers return the timeout for the next state transition
1610 * or negative error.
1611 */
1612
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001613enum {ENABLED = 0, DISABLED, CARDSLEEP, REGSLEEP, OFF};
Denis Karpovdd498ef2009-09-22 16:44:49 -07001614
1615/* Handler for [ENABLED -> DISABLED] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001616static int omap_hsmmc_enabled_to_disabled(struct omap_hsmmc_host *host)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001617{
Denis Karpov70a33412009-09-22 16:44:59 -07001618 omap_hsmmc_context_save(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001619 clk_disable(host->fclk);
1620 host->dpm_state = DISABLED;
1621
1622 dev_dbg(mmc_dev(host->mmc), "ENABLED -> DISABLED\n");
1623
1624 if (host->power_mode == MMC_POWER_OFF)
1625 return 0;
1626
Adrian Hunter4380eea2010-02-15 10:03:34 -08001627 return OMAP_MMC_SLEEP_TIMEOUT;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001628}
1629
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001630/* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001631static int omap_hsmmc_disabled_to_sleep(struct omap_hsmmc_host *host)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001632{
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001633 int err, new_state;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001634
1635 if (!mmc_try_claim_host(host->mmc))
1636 return 0;
1637
1638 clk_enable(host->fclk);
Denis Karpov70a33412009-09-22 16:44:59 -07001639 omap_hsmmc_context_restore(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001640 if (mmc_card_can_sleep(host->mmc)) {
1641 err = mmc_card_sleep(host->mmc);
1642 if (err < 0) {
1643 clk_disable(host->fclk);
1644 mmc_release_host(host->mmc);
1645 return err;
1646 }
1647 new_state = CARDSLEEP;
Denis Karpov70a33412009-09-22 16:44:59 -07001648 } else {
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001649 new_state = REGSLEEP;
Denis Karpov70a33412009-09-22 16:44:59 -07001650 }
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001651 if (mmc_slot(host).set_sleep)
1652 mmc_slot(host).set_sleep(host->dev, host->slot_id, 1, 0,
1653 new_state == CARDSLEEP);
1654 /* FIXME: turn off bus power and perhaps interrupts too */
1655 clk_disable(host->fclk);
1656 host->dpm_state = new_state;
1657
1658 mmc_release_host(host->mmc);
1659
1660 dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n",
1661 host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
Denis Karpovdd498ef2009-09-22 16:44:49 -07001662
Adrian Hunter1df58db2010-02-15 10:03:34 -08001663 if (mmc_slot(host).no_off)
1664 return 0;
1665
Denis Karpovdd498ef2009-09-22 16:44:49 -07001666 if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
1667 mmc_slot(host).card_detect ||
1668 (mmc_slot(host).get_cover_state &&
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001669 mmc_slot(host).get_cover_state(host->dev, host->slot_id)))
Adrian Hunter4380eea2010-02-15 10:03:34 -08001670 return OMAP_MMC_OFF_TIMEOUT;
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001671
1672 return 0;
1673}
1674
1675/* Handler for [REGSLEEP / CARDSLEEP -> OFF] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001676static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host)
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001677{
1678 if (!mmc_try_claim_host(host->mmc))
1679 return 0;
1680
Adrian Hunter1df58db2010-02-15 10:03:34 -08001681 if (mmc_slot(host).no_off)
1682 return 0;
1683
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001684 if (!((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
1685 mmc_slot(host).card_detect ||
1686 (mmc_slot(host).get_cover_state &&
1687 mmc_slot(host).get_cover_state(host->dev, host->slot_id)))) {
1688 mmc_release_host(host->mmc);
1689 return 0;
Adrian Hunter623821f2009-09-22 16:44:51 -07001690 }
Denis Karpovdd498ef2009-09-22 16:44:49 -07001691
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001692 mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
1693 host->vdd = 0;
1694 host->power_mode = MMC_POWER_OFF;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001695
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001696 dev_dbg(mmc_dev(host->mmc), "%s -> OFF\n",
1697 host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
Denis Karpovdd498ef2009-09-22 16:44:49 -07001698
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001699 host->dpm_state = OFF;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001700
1701 mmc_release_host(host->mmc);
1702
1703 return 0;
1704}
1705
1706/* Handler for [DISABLED -> ENABLED] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001707static int omap_hsmmc_disabled_to_enabled(struct omap_hsmmc_host *host)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001708{
1709 int err;
1710
1711 err = clk_enable(host->fclk);
1712 if (err < 0)
1713 return err;
1714
Denis Karpov70a33412009-09-22 16:44:59 -07001715 omap_hsmmc_context_restore(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001716 host->dpm_state = ENABLED;
1717
1718 dev_dbg(mmc_dev(host->mmc), "DISABLED -> ENABLED\n");
1719
1720 return 0;
1721}
1722
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001723/* Handler for [SLEEP -> ENABLED] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001724static int omap_hsmmc_sleep_to_enabled(struct omap_hsmmc_host *host)
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001725{
1726 if (!mmc_try_claim_host(host->mmc))
1727 return 0;
1728
1729 clk_enable(host->fclk);
Denis Karpov70a33412009-09-22 16:44:59 -07001730 omap_hsmmc_context_restore(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001731 if (mmc_slot(host).set_sleep)
1732 mmc_slot(host).set_sleep(host->dev, host->slot_id, 0,
1733 host->vdd, host->dpm_state == CARDSLEEP);
1734 if (mmc_card_can_sleep(host->mmc))
1735 mmc_card_awake(host->mmc);
1736
1737 dev_dbg(mmc_dev(host->mmc), "%s -> ENABLED\n",
1738 host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
1739
1740 host->dpm_state = ENABLED;
1741
1742 mmc_release_host(host->mmc);
1743
1744 return 0;
1745}
1746
Denis Karpovdd498ef2009-09-22 16:44:49 -07001747/* Handler for [OFF -> ENABLED] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001748static int omap_hsmmc_off_to_enabled(struct omap_hsmmc_host *host)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001749{
1750 clk_enable(host->fclk);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001751
Denis Karpov70a33412009-09-22 16:44:59 -07001752 omap_hsmmc_context_restore(host);
1753 omap_hsmmc_conf_bus_power(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001754 mmc_power_restore_host(host->mmc);
1755
1756 host->dpm_state = ENABLED;
1757
1758 dev_dbg(mmc_dev(host->mmc), "OFF -> ENABLED\n");
1759
1760 return 0;
1761}
1762
1763/*
1764 * Bring MMC host to ENABLED from any other PM state.
1765 */
Denis Karpov70a33412009-09-22 16:44:59 -07001766static int omap_hsmmc_enable(struct mmc_host *mmc)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001767{
Denis Karpov70a33412009-09-22 16:44:59 -07001768 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001769
1770 switch (host->dpm_state) {
1771 case DISABLED:
Denis Karpov70a33412009-09-22 16:44:59 -07001772 return omap_hsmmc_disabled_to_enabled(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001773 case CARDSLEEP:
Adrian Hunter623821f2009-09-22 16:44:51 -07001774 case REGSLEEP:
Denis Karpov70a33412009-09-22 16:44:59 -07001775 return omap_hsmmc_sleep_to_enabled(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001776 case OFF:
Denis Karpov70a33412009-09-22 16:44:59 -07001777 return omap_hsmmc_off_to_enabled(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001778 default:
1779 dev_dbg(mmc_dev(host->mmc), "UNKNOWN state\n");
1780 return -EINVAL;
1781 }
1782}
1783
1784/*
1785 * Bring MMC host in PM state (one level deeper).
1786 */
Denis Karpov70a33412009-09-22 16:44:59 -07001787static int omap_hsmmc_disable(struct mmc_host *mmc, int lazy)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001788{
Denis Karpov70a33412009-09-22 16:44:59 -07001789 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001790
1791 switch (host->dpm_state) {
1792 case ENABLED: {
1793 int delay;
1794
Denis Karpov70a33412009-09-22 16:44:59 -07001795 delay = omap_hsmmc_enabled_to_disabled(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001796 if (lazy || delay < 0)
1797 return delay;
1798 return 0;
1799 }
1800 case DISABLED:
Denis Karpov70a33412009-09-22 16:44:59 -07001801 return omap_hsmmc_disabled_to_sleep(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001802 case CARDSLEEP:
1803 case REGSLEEP:
Denis Karpov70a33412009-09-22 16:44:59 -07001804 return omap_hsmmc_sleep_to_off(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001805 default:
1806 dev_dbg(mmc_dev(host->mmc), "UNKNOWN state\n");
1807 return -EINVAL;
1808 }
1809}
1810
Denis Karpov70a33412009-09-22 16:44:59 -07001811static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001812{
Denis Karpov70a33412009-09-22 16:44:59 -07001813 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001814 int err;
1815
1816 err = clk_enable(host->fclk);
1817 if (err)
1818 return err;
1819 dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
Denis Karpov70a33412009-09-22 16:44:59 -07001820 omap_hsmmc_context_restore(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001821 return 0;
1822}
1823
Denis Karpov70a33412009-09-22 16:44:59 -07001824static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001825{
Denis Karpov70a33412009-09-22 16:44:59 -07001826 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001827
Denis Karpov70a33412009-09-22 16:44:59 -07001828 omap_hsmmc_context_save(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001829 clk_disable(host->fclk);
1830 dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n");
1831 return 0;
1832}
1833
Denis Karpov70a33412009-09-22 16:44:59 -07001834static const struct mmc_host_ops omap_hsmmc_ops = {
1835 .enable = omap_hsmmc_enable_fclk,
1836 .disable = omap_hsmmc_disable_fclk,
1837 .request = omap_hsmmc_request,
1838 .set_ios = omap_hsmmc_set_ios,
Denis Karpovdd498ef2009-09-22 16:44:49 -07001839 .get_cd = omap_hsmmc_get_cd,
1840 .get_ro = omap_hsmmc_get_ro,
1841 /* NYET -- enable_sdio_irq */
1842};
1843
Denis Karpov70a33412009-09-22 16:44:59 -07001844static const struct mmc_host_ops omap_hsmmc_ps_ops = {
1845 .enable = omap_hsmmc_enable,
1846 .disable = omap_hsmmc_disable,
1847 .request = omap_hsmmc_request,
1848 .set_ios = omap_hsmmc_set_ios,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001849 .get_cd = omap_hsmmc_get_cd,
1850 .get_ro = omap_hsmmc_get_ro,
1851 /* NYET -- enable_sdio_irq */
1852};
1853
Denis Karpovd900f712009-09-22 16:44:38 -07001854#ifdef CONFIG_DEBUG_FS
1855
Denis Karpov70a33412009-09-22 16:44:59 -07001856static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
Denis Karpovd900f712009-09-22 16:44:38 -07001857{
1858 struct mmc_host *mmc = s->private;
Denis Karpov70a33412009-09-22 16:44:59 -07001859 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001860 int context_loss = 0;
1861
Denis Karpov70a33412009-09-22 16:44:59 -07001862 if (host->pdata->get_context_loss_count)
1863 context_loss = host->pdata->get_context_loss_count(host->dev);
Denis Karpovd900f712009-09-22 16:44:38 -07001864
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001865 seq_printf(s, "mmc%d:\n"
1866 " enabled:\t%d\n"
Denis Karpovdd498ef2009-09-22 16:44:49 -07001867 " dpm_state:\t%d\n"
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001868 " nesting_cnt:\t%d\n"
Denis Karpov11dd62a2009-09-22 16:44:43 -07001869 " ctx_loss:\t%d:%d\n"
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001870 "\nregs:\n",
Denis Karpovdd498ef2009-09-22 16:44:49 -07001871 mmc->index, mmc->enabled ? 1 : 0,
1872 host->dpm_state, mmc->nesting_cnt,
Denis Karpov11dd62a2009-09-22 16:44:43 -07001873 host->context_loss, context_loss);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001874
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001875 if (host->suspended || host->dpm_state == OFF) {
Denis Karpovdd498ef2009-09-22 16:44:49 -07001876 seq_printf(s, "host suspended, can't read registers\n");
1877 return 0;
1878 }
1879
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001880 if (clk_enable(host->fclk) != 0) {
1881 seq_printf(s, "can't read the regs\n");
Denis Karpovdd498ef2009-09-22 16:44:49 -07001882 return 0;
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001883 }
Denis Karpovd900f712009-09-22 16:44:38 -07001884
1885 seq_printf(s, "SYSCONFIG:\t0x%08x\n",
1886 OMAP_HSMMC_READ(host->base, SYSCONFIG));
1887 seq_printf(s, "CON:\t\t0x%08x\n",
1888 OMAP_HSMMC_READ(host->base, CON));
1889 seq_printf(s, "HCTL:\t\t0x%08x\n",
1890 OMAP_HSMMC_READ(host->base, HCTL));
1891 seq_printf(s, "SYSCTL:\t\t0x%08x\n",
1892 OMAP_HSMMC_READ(host->base, SYSCTL));
1893 seq_printf(s, "IE:\t\t0x%08x\n",
1894 OMAP_HSMMC_READ(host->base, IE));
1895 seq_printf(s, "ISE:\t\t0x%08x\n",
1896 OMAP_HSMMC_READ(host->base, ISE));
1897 seq_printf(s, "CAPA:\t\t0x%08x\n",
1898 OMAP_HSMMC_READ(host->base, CAPA));
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001899
1900 clk_disable(host->fclk);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001901
Denis Karpovd900f712009-09-22 16:44:38 -07001902 return 0;
1903}
1904
Denis Karpov70a33412009-09-22 16:44:59 -07001905static int omap_hsmmc_regs_open(struct inode *inode, struct file *file)
Denis Karpovd900f712009-09-22 16:44:38 -07001906{
Denis Karpov70a33412009-09-22 16:44:59 -07001907 return single_open(file, omap_hsmmc_regs_show, inode->i_private);
Denis Karpovd900f712009-09-22 16:44:38 -07001908}
1909
1910static const struct file_operations mmc_regs_fops = {
Denis Karpov70a33412009-09-22 16:44:59 -07001911 .open = omap_hsmmc_regs_open,
Denis Karpovd900f712009-09-22 16:44:38 -07001912 .read = seq_read,
1913 .llseek = seq_lseek,
1914 .release = single_release,
1915};
1916
Denis Karpov70a33412009-09-22 16:44:59 -07001917static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001918{
1919 if (mmc->debugfs_root)
1920 debugfs_create_file("regs", S_IRUSR, mmc->debugfs_root,
1921 mmc, &mmc_regs_fops);
1922}
1923
1924#else
1925
Denis Karpov70a33412009-09-22 16:44:59 -07001926static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001927{
1928}
1929
1930#endif
1931
Denis Karpov70a33412009-09-22 16:44:59 -07001932static int __init omap_hsmmc_probe(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001933{
1934 struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
1935 struct mmc_host *mmc;
Denis Karpov70a33412009-09-22 16:44:59 -07001936 struct omap_hsmmc_host *host = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001937 struct resource *res;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001938 int ret, irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001939
1940 if (pdata == NULL) {
1941 dev_err(&pdev->dev, "Platform Data is missing\n");
1942 return -ENXIO;
1943 }
1944
1945 if (pdata->nr_slots == 0) {
1946 dev_err(&pdev->dev, "No Slots\n");
1947 return -ENXIO;
1948 }
1949
1950 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1951 irq = platform_get_irq(pdev, 0);
1952 if (res == NULL || irq < 0)
1953 return -ENXIO;
1954
1955 res = request_mem_region(res->start, res->end - res->start + 1,
1956 pdev->name);
1957 if (res == NULL)
1958 return -EBUSY;
1959
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001960 ret = omap_hsmmc_gpio_init(pdata);
1961 if (ret)
1962 goto err;
1963
Denis Karpov70a33412009-09-22 16:44:59 -07001964 mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001965 if (!mmc) {
1966 ret = -ENOMEM;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001967 goto err_alloc;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001968 }
1969
1970 host = mmc_priv(mmc);
1971 host->mmc = mmc;
1972 host->pdata = pdata;
1973 host->dev = &pdev->dev;
1974 host->use_dma = 1;
1975 host->dev->dma_mask = &pdata->dma_mask;
1976 host->dma_ch = -1;
1977 host->irq = irq;
1978 host->id = pdev->id;
1979 host->slot_id = 0;
1980 host->mapbase = res->start;
1981 host->base = ioremap(host->mapbase, SZ_4K);
Adrian Hunter6da20c82010-02-15 10:03:34 -08001982 host->power_mode = MMC_POWER_OFF;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001983
1984 platform_set_drvdata(pdev, host);
Denis Karpov70a33412009-09-22 16:44:59 -07001985 INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001986
Denis Karpov191d1f12009-09-22 16:44:55 -07001987 if (mmc_slot(host).power_saving)
Denis Karpov70a33412009-09-22 16:44:59 -07001988 mmc->ops = &omap_hsmmc_ps_ops;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001989 else
Denis Karpov70a33412009-09-22 16:44:59 -07001990 mmc->ops = &omap_hsmmc_ops;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001991
Adrian Huntere0eb2422010-02-15 10:03:34 -08001992 /*
1993 * If regulator_disable can only put vcc_aux to sleep then there is
1994 * no off state.
1995 */
1996 if (mmc_slot(host).vcc_aux_disable_is_sleep)
1997 mmc_slot(host).no_off = 1;
1998
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001999 mmc->f_min = 400000;
2000 mmc->f_max = 52000000;
2001
2002 sema_init(&host->sem, 1);
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07002003 spin_lock_init(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002004
Russell King6f7607c2009-01-28 10:22:50 +00002005 host->iclk = clk_get(&pdev->dev, "ick");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002006 if (IS_ERR(host->iclk)) {
2007 ret = PTR_ERR(host->iclk);
2008 host->iclk = NULL;
2009 goto err1;
2010 }
Russell King6f7607c2009-01-28 10:22:50 +00002011 host->fclk = clk_get(&pdev->dev, "fck");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002012 if (IS_ERR(host->fclk)) {
2013 ret = PTR_ERR(host->fclk);
2014 host->fclk = NULL;
2015 clk_put(host->iclk);
2016 goto err1;
2017 }
2018
Denis Karpov70a33412009-09-22 16:44:59 -07002019 omap_hsmmc_context_save(host);
Denis Karpov11dd62a2009-09-22 16:44:43 -07002020
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002021 mmc->caps |= MMC_CAP_DISABLE;
Denis Karpovdd498ef2009-09-22 16:44:49 -07002022 mmc_set_disable_delay(mmc, OMAP_MMC_DISABLED_TIMEOUT);
2023 /* we start off in DISABLED state */
2024 host->dpm_state = DISABLED;
2025
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002026 if (mmc_host_enable(host->mmc) != 0) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002027 clk_put(host->iclk);
2028 clk_put(host->fclk);
2029 goto err1;
2030 }
2031
2032 if (clk_enable(host->iclk) != 0) {
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002033 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002034 clk_put(host->iclk);
2035 clk_put(host->fclk);
2036 goto err1;
2037 }
2038
Adrian Hunter2bec0892009-09-22 16:45:02 -07002039 if (cpu_is_omap2430()) {
2040 host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
2041 /*
2042 * MMC can still work without debounce clock.
2043 */
2044 if (IS_ERR(host->dbclk))
2045 dev_warn(mmc_dev(host->mmc),
2046 "Failed to get debounce clock\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002047 else
Adrian Hunter2bec0892009-09-22 16:45:02 -07002048 host->got_dbclk = 1;
2049
2050 if (host->got_dbclk)
2051 if (clk_enable(host->dbclk) != 0)
2052 dev_dbg(mmc_dev(host->mmc), "Enabling debounce"
2053 " clk failed\n");
2054 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002055
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02002056 /* Since we do only SG emulation, we can have as many segs
2057 * as we want. */
2058 mmc->max_phys_segs = 1024;
2059 mmc->max_hw_segs = 1024;
2060
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002061 mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
2062 mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
2063 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2064 mmc->max_seg_size = mmc->max_req_size;
2065
Jarkko Lavinen13189e72009-09-22 16:44:53 -07002066 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
2067 MMC_CAP_WAIT_WHILE_BUSY;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002068
Denis Karpov191d1f12009-09-22 16:44:55 -07002069 if (mmc_slot(host).wires >= 8)
Jarkko Lavinen73153012008-11-21 16:49:54 +02002070 mmc->caps |= MMC_CAP_8_BIT_DATA;
Denis Karpov191d1f12009-09-22 16:44:55 -07002071 else if (mmc_slot(host).wires >= 4)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002072 mmc->caps |= MMC_CAP_4_BIT_DATA;
2073
Denis Karpov191d1f12009-09-22 16:44:55 -07002074 if (mmc_slot(host).nonremovable)
Adrian Hunter23d99bb2009-09-22 16:44:48 -07002075 mmc->caps |= MMC_CAP_NONREMOVABLE;
2076
Denis Karpov70a33412009-09-22 16:44:59 -07002077 omap_hsmmc_conf_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002078
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +00002079 /* Select DMA lines */
2080 switch (host->id) {
2081 case OMAP_MMC1_DEVID:
2082 host->dma_line_tx = OMAP24XX_DMA_MMC1_TX;
2083 host->dma_line_rx = OMAP24XX_DMA_MMC1_RX;
2084 break;
2085 case OMAP_MMC2_DEVID:
2086 host->dma_line_tx = OMAP24XX_DMA_MMC2_TX;
2087 host->dma_line_rx = OMAP24XX_DMA_MMC2_RX;
2088 break;
2089 case OMAP_MMC3_DEVID:
2090 host->dma_line_tx = OMAP34XX_DMA_MMC3_TX;
2091 host->dma_line_rx = OMAP34XX_DMA_MMC3_RX;
2092 break;
kishore kadiyala82cf8182009-09-22 16:45:25 -07002093 case OMAP_MMC4_DEVID:
2094 host->dma_line_tx = OMAP44XX_DMA_MMC4_TX;
2095 host->dma_line_rx = OMAP44XX_DMA_MMC4_RX;
2096 break;
2097 case OMAP_MMC5_DEVID:
2098 host->dma_line_tx = OMAP44XX_DMA_MMC5_TX;
2099 host->dma_line_rx = OMAP44XX_DMA_MMC5_RX;
2100 break;
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +00002101 default:
2102 dev_err(mmc_dev(host->mmc), "Invalid MMC id\n");
2103 goto err_irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002104 }
2105
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002106 /* Request IRQ for MMC operations */
Denis Karpov70a33412009-09-22 16:44:59 -07002107 ret = request_irq(host->irq, omap_hsmmc_irq, IRQF_DISABLED,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002108 mmc_hostname(mmc), host);
2109 if (ret) {
2110 dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
2111 goto err_irq;
2112 }
2113
2114 if (pdata->init != NULL) {
2115 if (pdata->init(&pdev->dev) != 0) {
Denis Karpov70a33412009-09-22 16:44:59 -07002116 dev_dbg(mmc_dev(host->mmc),
2117 "Unable to configure MMC IRQs\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002118 goto err_irq_cd_init;
2119 }
2120 }
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002121
2122 if (!mmc_slot(host).set_power) {
2123 ret = omap_hsmmc_reg_get(host);
2124 if (ret)
2125 goto err_reg;
2126 host->use_reg = 1;
2127 }
2128
David Brownellb583f262009-05-28 14:04:03 -07002129 mmc->ocr_avail = mmc_slot(host).ocr_mask;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002130
2131 /* Request IRQ for card detect */
Adrian Huntere1a55f52009-01-26 13:17:25 +02002132 if ((mmc_slot(host).card_detect_irq)) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002133 ret = request_irq(mmc_slot(host).card_detect_irq,
Denis Karpov70a33412009-09-22 16:44:59 -07002134 omap_hsmmc_cd_handler,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002135 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
2136 | IRQF_DISABLED,
2137 mmc_hostname(mmc), host);
2138 if (ret) {
2139 dev_dbg(mmc_dev(host->mmc),
2140 "Unable to grab MMC CD IRQ\n");
2141 goto err_irq_cd;
2142 }
2143 }
2144
2145 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
2146 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
2147
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002148 mmc_host_lazy_disable(host->mmc);
2149
Adrian Hunterb62f6222009-09-22 16:45:01 -07002150 omap_hsmmc_protect_card(host);
2151
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002152 mmc_add_host(mmc);
2153
Denis Karpov191d1f12009-09-22 16:44:55 -07002154 if (mmc_slot(host).name != NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002155 ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
2156 if (ret < 0)
2157 goto err_slot_name;
2158 }
Denis Karpov191d1f12009-09-22 16:44:55 -07002159 if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002160 ret = device_create_file(&mmc->class_dev,
2161 &dev_attr_cover_switch);
2162 if (ret < 0)
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002163 goto err_slot_name;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002164 }
2165
Denis Karpov70a33412009-09-22 16:44:59 -07002166 omap_hsmmc_debugfs(mmc);
Denis Karpovd900f712009-09-22 16:44:38 -07002167
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002168 return 0;
2169
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002170err_slot_name:
2171 mmc_remove_host(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002172 free_irq(mmc_slot(host).card_detect_irq, host);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002173err_irq_cd:
2174 if (host->use_reg)
2175 omap_hsmmc_reg_put(host);
2176err_reg:
2177 if (host->pdata->cleanup)
2178 host->pdata->cleanup(&pdev->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002179err_irq_cd_init:
2180 free_irq(host->irq, host);
2181err_irq:
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002182 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002183 clk_disable(host->iclk);
2184 clk_put(host->fclk);
2185 clk_put(host->iclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07002186 if (host->got_dbclk) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002187 clk_disable(host->dbclk);
2188 clk_put(host->dbclk);
2189 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002190err1:
2191 iounmap(host->base);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002192 platform_set_drvdata(pdev, NULL);
2193 mmc_free_host(mmc);
2194err_alloc:
2195 omap_hsmmc_gpio_free(pdata);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002196err:
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002197 release_mem_region(res->start, res->end - res->start + 1);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002198 return ret;
2199}
2200
Denis Karpov70a33412009-09-22 16:44:59 -07002201static int omap_hsmmc_remove(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002202{
Denis Karpov70a33412009-09-22 16:44:59 -07002203 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002204 struct resource *res;
2205
2206 if (host) {
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002207 mmc_host_enable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002208 mmc_remove_host(host->mmc);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002209 if (host->use_reg)
2210 omap_hsmmc_reg_put(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002211 if (host->pdata->cleanup)
2212 host->pdata->cleanup(&pdev->dev);
2213 free_irq(host->irq, host);
2214 if (mmc_slot(host).card_detect_irq)
2215 free_irq(mmc_slot(host).card_detect_irq, host);
2216 flush_scheduled_work();
2217
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002218 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002219 clk_disable(host->iclk);
2220 clk_put(host->fclk);
2221 clk_put(host->iclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07002222 if (host->got_dbclk) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002223 clk_disable(host->dbclk);
2224 clk_put(host->dbclk);
2225 }
2226
2227 mmc_free_host(host->mmc);
2228 iounmap(host->base);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002229 omap_hsmmc_gpio_free(pdev->dev.platform_data);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002230 }
2231
2232 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2233 if (res)
2234 release_mem_region(res->start, res->end - res->start + 1);
2235 platform_set_drvdata(pdev, NULL);
2236
2237 return 0;
2238}
2239
2240#ifdef CONFIG_PM
Denis Karpov70a33412009-09-22 16:44:59 -07002241static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002242{
2243 int ret = 0;
Denis Karpov70a33412009-09-22 16:44:59 -07002244 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002245
2246 if (host && host->suspended)
2247 return 0;
2248
2249 if (host) {
Adrian Huntera6b22402009-09-22 16:44:45 -07002250 host->suspended = 1;
2251 if (host->pdata->suspend) {
2252 ret = host->pdata->suspend(&pdev->dev,
2253 host->slot_id);
2254 if (ret) {
2255 dev_dbg(mmc_dev(host->mmc),
2256 "Unable to handle MMC board"
2257 " level suspend\n");
2258 host->suspended = 0;
2259 return ret;
2260 }
2261 }
2262 cancel_work_sync(&host->mmc_carddetect_work);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002263 mmc_host_enable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002264 ret = mmc_suspend_host(host->mmc, state);
2265 if (ret == 0) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002266 OMAP_HSMMC_WRITE(host->base, ISE, 0);
2267 OMAP_HSMMC_WRITE(host->base, IE, 0);
2268
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002269
Jarkko Lavinen0683af42009-03-12 15:30:58 +02002270 OMAP_HSMMC_WRITE(host->base, HCTL,
Denis Karpov191d1f12009-09-22 16:44:55 -07002271 OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002272 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002273 clk_disable(host->iclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07002274 if (host->got_dbclk)
2275 clk_disable(host->dbclk);
Adrian Huntera6b22402009-09-22 16:44:45 -07002276 } else {
2277 host->suspended = 0;
2278 if (host->pdata->resume) {
2279 ret = host->pdata->resume(&pdev->dev,
2280 host->slot_id);
2281 if (ret)
2282 dev_dbg(mmc_dev(host->mmc),
2283 "Unmask interrupt failed\n");
2284 }
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002285 mmc_host_disable(host->mmc);
Adrian Huntera6b22402009-09-22 16:44:45 -07002286 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002287
2288 }
2289 return ret;
2290}
2291
2292/* Routine to resume the MMC device */
Denis Karpov70a33412009-09-22 16:44:59 -07002293static int omap_hsmmc_resume(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002294{
2295 int ret = 0;
Denis Karpov70a33412009-09-22 16:44:59 -07002296 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002297
2298 if (host && !host->suspended)
2299 return 0;
2300
2301 if (host) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002302 ret = clk_enable(host->iclk);
Denis Karpov11dd62a2009-09-22 16:44:43 -07002303 if (ret)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002304 goto clk_en_err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002305
Denis Karpov11dd62a2009-09-22 16:44:43 -07002306 if (mmc_host_enable(host->mmc) != 0) {
2307 clk_disable(host->iclk);
2308 goto clk_en_err;
2309 }
2310
Adrian Hunter2bec0892009-09-22 16:45:02 -07002311 if (host->got_dbclk)
2312 clk_enable(host->dbclk);
2313
Denis Karpov70a33412009-09-22 16:44:59 -07002314 omap_hsmmc_conf_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01002315
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002316 if (host->pdata->resume) {
2317 ret = host->pdata->resume(&pdev->dev, host->slot_id);
2318 if (ret)
2319 dev_dbg(mmc_dev(host->mmc),
2320 "Unmask interrupt failed\n");
2321 }
2322
Adrian Hunterb62f6222009-09-22 16:45:01 -07002323 omap_hsmmc_protect_card(host);
2324
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002325 /* Notify the core to resume the host */
2326 ret = mmc_resume_host(host->mmc);
2327 if (ret == 0)
2328 host->suspended = 0;
Denis Karpov70a33412009-09-22 16:44:59 -07002329
Adrian Hunter5e2ea612009-09-22 16:44:39 -07002330 mmc_host_lazy_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002331 }
2332
2333 return ret;
2334
2335clk_en_err:
2336 dev_dbg(mmc_dev(host->mmc),
2337 "Failed to enable MMC clocks during resume\n");
2338 return ret;
2339}
2340
2341#else
Denis Karpov70a33412009-09-22 16:44:59 -07002342#define omap_hsmmc_suspend NULL
2343#define omap_hsmmc_resume NULL
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002344#endif
2345
Denis Karpov70a33412009-09-22 16:44:59 -07002346static struct platform_driver omap_hsmmc_driver = {
2347 .remove = omap_hsmmc_remove,
2348 .suspend = omap_hsmmc_suspend,
2349 .resume = omap_hsmmc_resume,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002350 .driver = {
2351 .name = DRIVER_NAME,
2352 .owner = THIS_MODULE,
2353 },
2354};
2355
Denis Karpov70a33412009-09-22 16:44:59 -07002356static int __init omap_hsmmc_init(void)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002357{
2358 /* Register the MMC driver */
Roger Quadros87532982009-10-26 16:49:38 -07002359 return platform_driver_probe(&omap_hsmmc_driver, omap_hsmmc_probe);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002360}
2361
Denis Karpov70a33412009-09-22 16:44:59 -07002362static void __exit omap_hsmmc_cleanup(void)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002363{
2364 /* Unregister MMC driver */
Denis Karpov70a33412009-09-22 16:44:59 -07002365 platform_driver_unregister(&omap_hsmmc_driver);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002366}
2367
Denis Karpov70a33412009-09-22 16:44:59 -07002368module_init(omap_hsmmc_init);
2369module_exit(omap_hsmmc_cleanup);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002370
2371MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
2372MODULE_LICENSE("GPL");
2373MODULE_ALIAS("platform:" DRIVER_NAME);
2374MODULE_AUTHOR("Texas Instruments Inc");