blob: 305e5d26d7e7eab29882b81a80b135f587dedc68 [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>
33#include <mach/dma.h>
34#include <mach/hardware.h>
35#include <mach/board.h>
36#include <mach/mmc.h>
37#include <mach/cpu.h>
38
39/* OMAP HSMMC Host Controller Registers */
40#define OMAP_HSMMC_SYSCONFIG 0x0010
Denis Karpov11dd62a2009-09-22 16:44:43 -070041#define OMAP_HSMMC_SYSSTATUS 0x0014
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010042#define OMAP_HSMMC_CON 0x002C
43#define OMAP_HSMMC_BLK 0x0104
44#define OMAP_HSMMC_ARG 0x0108
45#define OMAP_HSMMC_CMD 0x010C
46#define OMAP_HSMMC_RSP10 0x0110
47#define OMAP_HSMMC_RSP32 0x0114
48#define OMAP_HSMMC_RSP54 0x0118
49#define OMAP_HSMMC_RSP76 0x011C
50#define OMAP_HSMMC_DATA 0x0120
51#define OMAP_HSMMC_HCTL 0x0128
52#define OMAP_HSMMC_SYSCTL 0x012C
53#define OMAP_HSMMC_STAT 0x0130
54#define OMAP_HSMMC_IE 0x0134
55#define OMAP_HSMMC_ISE 0x0138
56#define OMAP_HSMMC_CAPA 0x0140
57
58#define VS18 (1 << 26)
59#define VS30 (1 << 25)
60#define SDVS18 (0x5 << 9)
61#define SDVS30 (0x6 << 9)
David Brownelleb250822009-02-17 14:49:01 -080062#define SDVS33 (0x7 << 9)
Kim Kyuwon1b331e62009-02-20 13:10:08 +010063#define SDVS_MASK 0x00000E00
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010064#define SDVSCLR 0xFFFFF1FF
65#define SDVSDET 0x00000400
66#define AUTOIDLE 0x1
67#define SDBP (1 << 8)
68#define DTO 0xe
69#define ICE 0x1
70#define ICS 0x2
71#define CEN (1 << 2)
72#define CLKD_MASK 0x0000FFC0
73#define CLKD_SHIFT 6
74#define DTO_MASK 0x000F0000
75#define DTO_SHIFT 16
76#define INT_EN_MASK 0x307F0033
Anand Gadiyarccdfe3a2009-09-22 16:44:21 -070077#define BWR_ENABLE (1 << 4)
78#define BRR_ENABLE (1 << 5)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010079#define INIT_STREAM (1 << 1)
80#define DP_SELECT (1 << 21)
81#define DDIR (1 << 4)
82#define DMA_EN 0x1
83#define MSBS (1 << 5)
84#define BCE (1 << 1)
85#define FOUR_BIT (1 << 1)
Jarkko Lavinen73153012008-11-21 16:49:54 +020086#define DW8 (1 << 5)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010087#define CC 0x1
88#define TC 0x02
89#define OD 0x1
90#define ERR (1 << 15)
91#define CMD_TIMEOUT (1 << 16)
92#define DATA_TIMEOUT (1 << 20)
93#define CMD_CRC (1 << 17)
94#define DATA_CRC (1 << 21)
95#define CARD_ERR (1 << 28)
96#define STAT_CLEAR 0xFFFFFFFF
97#define INIT_STREAM_CMD 0x00000000
98#define DUAL_VOLT_OCR_BIT 7
99#define SRC (1 << 25)
100#define SRD (1 << 26)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700101#define SOFTRESET (1 << 1)
102#define RESETDONE (1 << 0)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100103
104/*
105 * FIXME: Most likely all the data using these _DEVID defines should come
106 * from the platform_data, or implemented in controller and slot specific
107 * functions.
108 */
109#define OMAP_MMC1_DEVID 0
110#define OMAP_MMC2_DEVID 1
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +0000111#define OMAP_MMC3_DEVID 2
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100112
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100113#define MMC_TIMEOUT_MS 20
114#define OMAP_MMC_MASTER_CLOCK 96000000
115#define DRIVER_NAME "mmci-omap-hs"
116
Denis Karpovdd498ef2009-09-22 16:44:49 -0700117/* Timeouts for entering power saving states on inactivity, msec */
118#define OMAP_MMC_DISABLED_TIMEOUT 100
Jarkko Lavinen13189e72009-09-22 16:44:53 -0700119#define OMAP_MMC_SLEEP_TIMEOUT 1000
120#define OMAP_MMC_OFF_TIMEOUT 8000
Denis Karpovdd498ef2009-09-22 16:44:49 -0700121
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100122/*
123 * One controller can have multiple slots, like on some omap boards using
124 * omap.c controller driver. Luckily this is not currently done on any known
125 * omap_hsmmc.c device.
126 */
127#define mmc_slot(host) (host->pdata->slots[host->slot_id])
128
129/*
130 * MMC Host controller read/write API's
131 */
132#define OMAP_HSMMC_READ(base, reg) \
133 __raw_readl((base) + OMAP_HSMMC_##reg)
134
135#define OMAP_HSMMC_WRITE(base, reg, val) \
136 __raw_writel((val), (base) + OMAP_HSMMC_##reg)
137
138struct mmc_omap_host {
139 struct device *dev;
140 struct mmc_host *mmc;
141 struct mmc_request *mrq;
142 struct mmc_command *cmd;
143 struct mmc_data *data;
144 struct clk *fclk;
145 struct clk *iclk;
146 struct clk *dbclk;
147 struct semaphore sem;
148 struct work_struct mmc_carddetect_work;
149 void __iomem *base;
150 resource_size_t mapbase;
151 unsigned int id;
152 unsigned int dma_len;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200153 unsigned int dma_sg_idx;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100154 unsigned char bus_mode;
Adrian Huntera3621462009-09-22 16:44:42 -0700155 unsigned char power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100156 u32 *buffer;
157 u32 bytesleft;
158 int suspended;
159 int irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100160 int use_dma, dma_ch;
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +0000161 int dma_line_tx, dma_line_rx;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100162 int slot_id;
163 int dbclk_enabled;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200164 int response_busy;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700165 int context_loss;
Denis Karpovdd498ef2009-09-22 16:44:49 -0700166 int dpm_state;
Adrian Hunter623821f2009-09-22 16:44:51 -0700167 int vdd;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700168
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100169 struct omap_mmc_platform_data *pdata;
170};
171
172/*
173 * Stop clock to the card
174 */
175static void omap_mmc_stop_clock(struct mmc_omap_host *host)
176{
177 OMAP_HSMMC_WRITE(host->base, SYSCTL,
178 OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
179 if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
180 dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
181}
182
Denis Karpov11dd62a2009-09-22 16:44:43 -0700183#ifdef CONFIG_PM
184
185/*
186 * Restore the MMC host context, if it was lost as result of a
187 * power state change.
188 */
189static int omap_mmc_restore_ctx(struct mmc_omap_host *host)
190{
191 struct mmc_ios *ios = &host->mmc->ios;
192 struct omap_mmc_platform_data *pdata = host->pdata;
193 int context_loss = 0;
194 u32 hctl, capa, con;
195 u16 dsor = 0;
196 unsigned long timeout;
197
198 if (pdata->get_context_loss_count) {
199 context_loss = pdata->get_context_loss_count(host->dev);
200 if (context_loss < 0)
201 return 1;
202 }
203
204 dev_dbg(mmc_dev(host->mmc), "context was %slost\n",
205 context_loss == host->context_loss ? "not " : "");
206 if (host->context_loss == context_loss)
207 return 1;
208
209 /* Wait for hardware reset */
210 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
211 while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
212 && time_before(jiffies, timeout))
213 ;
214
215 /* Do software reset */
216 OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET);
217 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
218 while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
219 && time_before(jiffies, timeout))
220 ;
221
222 OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
223 OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
224
225 if (host->id == OMAP_MMC1_DEVID) {
226 if (host->power_mode != MMC_POWER_OFF &&
227 (1 << ios->vdd) <= MMC_VDD_23_24)
228 hctl = SDVS18;
229 else
230 hctl = SDVS30;
231 capa = VS30 | VS18;
232 } else {
233 hctl = SDVS18;
234 capa = VS18;
235 }
236
237 OMAP_HSMMC_WRITE(host->base, HCTL,
238 OMAP_HSMMC_READ(host->base, HCTL) | hctl);
239
240 OMAP_HSMMC_WRITE(host->base, CAPA,
241 OMAP_HSMMC_READ(host->base, CAPA) | capa);
242
243 OMAP_HSMMC_WRITE(host->base, HCTL,
244 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
245
246 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
247 while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP
248 && time_before(jiffies, timeout))
249 ;
250
251 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
252 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
253 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
254
255 /* Do not initialize card-specific things if the power is off */
256 if (host->power_mode == MMC_POWER_OFF)
257 goto out;
258
259 con = OMAP_HSMMC_READ(host->base, CON);
260 switch (ios->bus_width) {
261 case MMC_BUS_WIDTH_8:
262 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
263 break;
264 case MMC_BUS_WIDTH_4:
265 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
266 OMAP_HSMMC_WRITE(host->base, HCTL,
267 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
268 break;
269 case MMC_BUS_WIDTH_1:
270 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
271 OMAP_HSMMC_WRITE(host->base, HCTL,
272 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
273 break;
274 }
275
276 if (ios->clock) {
277 dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
278 if (dsor < 1)
279 dsor = 1;
280
281 if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
282 dsor++;
283
284 if (dsor > 250)
285 dsor = 250;
286 }
287
288 OMAP_HSMMC_WRITE(host->base, SYSCTL,
289 OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
290 OMAP_HSMMC_WRITE(host->base, SYSCTL, (dsor << 6) | (DTO << 16));
291 OMAP_HSMMC_WRITE(host->base, SYSCTL,
292 OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
293
294 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
295 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
296 && time_before(jiffies, timeout))
297 ;
298
299 OMAP_HSMMC_WRITE(host->base, SYSCTL,
300 OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
301
302 con = OMAP_HSMMC_READ(host->base, CON);
303 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
304 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
305 else
306 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
307out:
308 host->context_loss = context_loss;
309
310 dev_dbg(mmc_dev(host->mmc), "context is restored\n");
311 return 0;
312}
313
314/*
315 * Save the MMC host context (store the number of power state changes so far).
316 */
317static void omap_mmc_save_ctx(struct mmc_omap_host *host)
318{
319 struct omap_mmc_platform_data *pdata = host->pdata;
320 int context_loss;
321
322 if (pdata->get_context_loss_count) {
323 context_loss = pdata->get_context_loss_count(host->dev);
324 if (context_loss < 0)
325 return;
326 host->context_loss = context_loss;
327 }
328}
329
330#else
331
332static int omap_mmc_restore_ctx(struct mmc_omap_host *host)
333{
334 return 0;
335}
336
337static void omap_mmc_save_ctx(struct mmc_omap_host *host)
338{
339}
340
341#endif
342
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100343/*
344 * Send init stream sequence to card
345 * before sending IDLE command
346 */
347static void send_init_stream(struct mmc_omap_host *host)
348{
349 int reg = 0;
350 unsigned long timeout;
351
352 disable_irq(host->irq);
353 OMAP_HSMMC_WRITE(host->base, CON,
354 OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
355 OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
356
357 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
358 while ((reg != CC) && time_before(jiffies, timeout))
359 reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
360
361 OMAP_HSMMC_WRITE(host->base, CON,
362 OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
363 enable_irq(host->irq);
364}
365
366static inline
367int mmc_omap_cover_is_closed(struct mmc_omap_host *host)
368{
369 int r = 1;
370
Denis Karpov191d1f12009-09-22 16:44:55 -0700371 if (mmc_slot(host).get_cover_state)
372 r = mmc_slot(host).get_cover_state(host->dev, host->slot_id);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100373 return r;
374}
375
376static ssize_t
377mmc_omap_show_cover_switch(struct device *dev, struct device_attribute *attr,
378 char *buf)
379{
380 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
381 struct mmc_omap_host *host = mmc_priv(mmc);
382
383 return sprintf(buf, "%s\n", mmc_omap_cover_is_closed(host) ? "closed" :
384 "open");
385}
386
387static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
388
389static ssize_t
390mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr,
391 char *buf)
392{
393 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
394 struct mmc_omap_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100395
Denis Karpov191d1f12009-09-22 16:44:55 -0700396 return sprintf(buf, "%s\n", mmc_slot(host).name);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100397}
398
399static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL);
400
401/*
402 * Configure the response type and send the cmd.
403 */
404static void
405mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd,
406 struct mmc_data *data)
407{
408 int cmdreg = 0, resptype = 0, cmdtype = 0;
409
410 dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
411 mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
412 host->cmd = cmd;
413
414 /*
415 * Clear status bits and enable interrupts
416 */
417 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
418 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
Anand Gadiyarccdfe3a2009-09-22 16:44:21 -0700419
420 if (host->use_dma)
421 OMAP_HSMMC_WRITE(host->base, IE,
422 INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
423 else
424 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100425
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200426 host->response_busy = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100427 if (cmd->flags & MMC_RSP_PRESENT) {
428 if (cmd->flags & MMC_RSP_136)
429 resptype = 1;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200430 else if (cmd->flags & MMC_RSP_BUSY) {
431 resptype = 3;
432 host->response_busy = 1;
433 } else
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100434 resptype = 2;
435 }
436
437 /*
438 * Unlike OMAP1 controller, the cmdtype does not seem to be based on
439 * ac, bc, adtc, bcr. Only commands ending an open ended transfer need
440 * a val of 0x3, rest 0x0.
441 */
442 if (cmd == host->mrq->stop)
443 cmdtype = 0x3;
444
445 cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
446
447 if (data) {
448 cmdreg |= DP_SELECT | MSBS | BCE;
449 if (data->flags & MMC_DATA_READ)
450 cmdreg |= DDIR;
451 else
452 cmdreg &= ~(DDIR);
453 }
454
455 if (host->use_dma)
456 cmdreg |= DMA_EN;
457
458 OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
459 OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
460}
461
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200462static int
463mmc_omap_get_dma_dir(struct mmc_omap_host *host, struct mmc_data *data)
464{
465 if (data->flags & MMC_DATA_WRITE)
466 return DMA_TO_DEVICE;
467 else
468 return DMA_FROM_DEVICE;
469}
470
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100471/*
472 * Notify the transfer complete to MMC core
473 */
474static void
475mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
476{
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200477 if (!data) {
478 struct mmc_request *mrq = host->mrq;
479
480 host->mrq = NULL;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200481 mmc_request_done(host->mmc, mrq);
482 return;
483 }
484
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100485 host->data = NULL;
486
487 if (host->use_dma && host->dma_ch != -1)
488 dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200489 mmc_omap_get_dma_dir(host, data));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100490
491 if (!data->error)
492 data->bytes_xfered += data->blocks * (data->blksz);
493 else
494 data->bytes_xfered = 0;
495
496 if (!data->stop) {
497 host->mrq = NULL;
498 mmc_request_done(host->mmc, data->mrq);
499 return;
500 }
501 mmc_omap_start_command(host, data->stop, NULL);
502}
503
504/*
505 * Notify the core about command completion
506 */
507static void
508mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
509{
510 host->cmd = NULL;
511
512 if (cmd->flags & MMC_RSP_PRESENT) {
513 if (cmd->flags & MMC_RSP_136) {
514 /* response type 2 */
515 cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
516 cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
517 cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
518 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
519 } else {
520 /* response types 1, 1b, 3, 4, 5, 6 */
521 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
522 }
523 }
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200524 if ((host->data == NULL && !host->response_busy) || cmd->error) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100525 host->mrq = NULL;
526 mmc_request_done(host->mmc, cmd->mrq);
527 }
528}
529
530/*
531 * DMA clean up for command errors
532 */
Jarkko Lavinen82788ff2008-12-05 12:31:46 +0200533static void mmc_dma_cleanup(struct mmc_omap_host *host, int errno)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100534{
Jarkko Lavinen82788ff2008-12-05 12:31:46 +0200535 host->data->error = errno;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100536
537 if (host->use_dma && host->dma_ch != -1) {
538 dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200539 mmc_omap_get_dma_dir(host, host->data));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100540 omap_free_dma(host->dma_ch);
541 host->dma_ch = -1;
542 up(&host->sem);
543 }
544 host->data = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100545}
546
547/*
548 * Readable error output
549 */
550#ifdef CONFIG_MMC_DEBUG
551static void mmc_omap_report_irq(struct mmc_omap_host *host, u32 status)
552{
553 /* --- means reserved bit without definition at documentation */
554 static const char *mmc_omap_status_bits[] = {
555 "CC", "TC", "BGE", "---", "BWR", "BRR", "---", "---", "CIRQ",
556 "OBI", "---", "---", "---", "---", "---", "ERRI", "CTO", "CCRC",
557 "CEB", "CIE", "DTO", "DCRC", "DEB", "---", "ACE", "---",
558 "---", "---", "---", "CERR", "CERR", "BADA", "---", "---", "---"
559 };
560 char res[256];
561 char *buf = res;
562 int len, i;
563
564 len = sprintf(buf, "MMC IRQ 0x%x :", status);
565 buf += len;
566
567 for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
568 if (status & (1 << i)) {
569 len = sprintf(buf, " %s", mmc_omap_status_bits[i]);
570 buf += len;
571 }
572
573 dev_dbg(mmc_dev(host->mmc), "%s\n", res);
574}
575#endif /* CONFIG_MMC_DEBUG */
576
Jean Pihet3ebf74b2009-02-06 16:42:51 +0100577/*
578 * MMC controller internal state machines reset
579 *
580 * Used to reset command or data internal state machines, using respectively
581 * SRC or SRD bit of SYSCTL register
582 * Can be called from interrupt context
583 */
584static inline void mmc_omap_reset_controller_fsm(struct mmc_omap_host *host,
585 unsigned long bit)
586{
587 unsigned long i = 0;
588 unsigned long limit = (loops_per_jiffy *
589 msecs_to_jiffies(MMC_TIMEOUT_MS));
590
591 OMAP_HSMMC_WRITE(host->base, SYSCTL,
592 OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
593
594 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
595 (i++ < limit))
596 cpu_relax();
597
598 if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
599 dev_err(mmc_dev(host->mmc),
600 "Timeout waiting on controller reset in %s\n",
601 __func__);
602}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100603
604/*
605 * MMC controller IRQ handler
606 */
607static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
608{
609 struct mmc_omap_host *host = dev_id;
610 struct mmc_data *data;
611 int end_cmd = 0, end_trans = 0, status;
612
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200613 if (host->mrq == NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100614 OMAP_HSMMC_WRITE(host->base, STAT,
615 OMAP_HSMMC_READ(host->base, STAT));
Kevin Hilman00adadc2009-04-06 15:01:19 +0300616 /* Flush posted write */
617 OMAP_HSMMC_READ(host->base, STAT);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100618 return IRQ_HANDLED;
619 }
620
621 data = host->data;
622 status = OMAP_HSMMC_READ(host->base, STAT);
623 dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
624
625 if (status & ERR) {
626#ifdef CONFIG_MMC_DEBUG
627 mmc_omap_report_irq(host, status);
628#endif
629 if ((status & CMD_TIMEOUT) ||
630 (status & CMD_CRC)) {
631 if (host->cmd) {
632 if (status & CMD_TIMEOUT) {
Denis Karpov191d1f12009-09-22 16:44:55 -0700633 mmc_omap_reset_controller_fsm(host,
634 SRC);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100635 host->cmd->error = -ETIMEDOUT;
636 } else {
637 host->cmd->error = -EILSEQ;
638 }
639 end_cmd = 1;
640 }
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200641 if (host->data || host->response_busy) {
642 if (host->data)
643 mmc_dma_cleanup(host, -ETIMEDOUT);
644 host->response_busy = 0;
Jean Pihet3ebf74b2009-02-06 16:42:51 +0100645 mmc_omap_reset_controller_fsm(host, SRD);
Jean Pihetc232f452009-02-11 13:11:39 -0800646 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100647 }
648 if ((status & DATA_TIMEOUT) ||
649 (status & DATA_CRC)) {
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200650 if (host->data || host->response_busy) {
651 int err = (status & DATA_TIMEOUT) ?
652 -ETIMEDOUT : -EILSEQ;
653
654 if (host->data)
655 mmc_dma_cleanup(host, err);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100656 else
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200657 host->mrq->cmd->error = err;
658 host->response_busy = 0;
Jean Pihet3ebf74b2009-02-06 16:42:51 +0100659 mmc_omap_reset_controller_fsm(host, SRD);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100660 end_trans = 1;
661 }
662 }
663 if (status & CARD_ERR) {
664 dev_dbg(mmc_dev(host->mmc),
665 "Ignoring card err CMD%d\n", host->cmd->opcode);
666 if (host->cmd)
667 end_cmd = 1;
668 if (host->data)
669 end_trans = 1;
670 }
671 }
672
673 OMAP_HSMMC_WRITE(host->base, STAT, status);
Kevin Hilman00adadc2009-04-06 15:01:19 +0300674 /* Flush posted write */
675 OMAP_HSMMC_READ(host->base, STAT);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100676
Jarkko Lavinena8fe29d2009-04-08 11:18:32 +0300677 if (end_cmd || ((status & CC) && host->cmd))
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100678 mmc_omap_cmd_done(host, host->cmd);
Jarkko Lavinen0a40e642009-09-22 16:44:54 -0700679 if ((end_trans || (status & TC)) && host->mrq)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100680 mmc_omap_xfer_done(host, data);
681
682 return IRQ_HANDLED;
683}
684
Adrian Huntere13bb302009-03-12 17:08:26 +0200685static void set_sd_bus_power(struct mmc_omap_host *host)
686{
687 unsigned long i;
688
689 OMAP_HSMMC_WRITE(host->base, HCTL,
690 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
691 for (i = 0; i < loops_per_jiffy; i++) {
692 if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
693 break;
694 cpu_relax();
695 }
696}
697
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100698/*
David Brownelleb250822009-02-17 14:49:01 -0800699 * Switch MMC interface voltage ... only relevant for MMC1.
700 *
701 * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
702 * The MMC2 transceiver controls are used instead of DAT4..DAT7.
703 * Some chips, like eMMC ones, use internal transceivers.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100704 */
705static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
706{
707 u32 reg_val = 0;
708 int ret;
709
710 /* Disable the clocks */
711 clk_disable(host->fclk);
712 clk_disable(host->iclk);
713 clk_disable(host->dbclk);
714
715 /* Turn the power off */
716 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
717 if (ret != 0)
718 goto err;
719
720 /* Turn the power ON with given VDD 1.8 or 3.0v */
721 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd);
722 if (ret != 0)
723 goto err;
724
725 clk_enable(host->fclk);
726 clk_enable(host->iclk);
727 clk_enable(host->dbclk);
728
729 OMAP_HSMMC_WRITE(host->base, HCTL,
730 OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
731 reg_val = OMAP_HSMMC_READ(host->base, HCTL);
David Brownelleb250822009-02-17 14:49:01 -0800732
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100733 /*
734 * If a MMC dual voltage card is detected, the set_ios fn calls
735 * this fn with VDD bit set for 1.8V. Upon card removal from the
736 * slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
737 *
David Brownelleb250822009-02-17 14:49:01 -0800738 * Cope with a bit of slop in the range ... per data sheets:
739 * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
740 * but recommended values are 1.71V to 1.89V
741 * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
742 * but recommended values are 2.7V to 3.3V
743 *
744 * Board setup code shouldn't permit anything very out-of-range.
745 * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
746 * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100747 */
David Brownelleb250822009-02-17 14:49:01 -0800748 if ((1 << vdd) <= MMC_VDD_23_24)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100749 reg_val |= SDVS18;
David Brownelleb250822009-02-17 14:49:01 -0800750 else
751 reg_val |= SDVS30;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100752
753 OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
Adrian Huntere13bb302009-03-12 17:08:26 +0200754 set_sd_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100755
756 return 0;
757err:
758 dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
759 return ret;
760}
761
762/*
763 * Work Item to notify the core about card insertion/removal
764 */
765static void mmc_omap_detect(struct work_struct *work)
766{
767 struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
768 mmc_carddetect_work);
David Brownell249d0fa2009-02-04 14:42:03 -0800769 struct omap_mmc_slot_data *slot = &mmc_slot(host);
Adrian Huntera6b22402009-09-22 16:44:45 -0700770 int carddetect;
David Brownell249d0fa2009-02-04 14:42:03 -0800771
Adrian Huntera6b22402009-09-22 16:44:45 -0700772 if (host->suspended)
773 return;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100774
775 sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
Adrian Huntera6b22402009-09-22 16:44:45 -0700776
Denis Karpov191d1f12009-09-22 16:44:55 -0700777 if (slot->card_detect)
Adrian Huntera6b22402009-09-22 16:44:45 -0700778 carddetect = slot->card_detect(slot->card_detect_irq);
779 else
780 carddetect = -ENOSYS;
781
782 if (carddetect) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100783 mmc_detect_change(host->mmc, (HZ * 200) / 1000);
784 } else {
Adrian Hunter5e2ea612009-09-22 16:44:39 -0700785 mmc_host_enable(host->mmc);
Jean Pihet3ebf74b2009-02-06 16:42:51 +0100786 mmc_omap_reset_controller_fsm(host, SRD);
Adrian Hunter5e2ea612009-09-22 16:44:39 -0700787 mmc_host_lazy_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100788 mmc_detect_change(host->mmc, (HZ * 50) / 1000);
789 }
790}
791
792/*
793 * ISR for handling card insertion and removal
794 */
795static irqreturn_t omap_mmc_cd_handler(int irq, void *dev_id)
796{
797 struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
798
Adrian Huntera6b22402009-09-22 16:44:45 -0700799 if (host->suspended)
800 return IRQ_HANDLED;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100801 schedule_work(&host->mmc_carddetect_work);
802
803 return IRQ_HANDLED;
804}
805
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200806static int mmc_omap_get_dma_sync_dev(struct mmc_omap_host *host,
807 struct mmc_data *data)
808{
809 int sync_dev;
810
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +0000811 if (data->flags & MMC_DATA_WRITE)
812 sync_dev = host->dma_line_tx;
813 else
814 sync_dev = host->dma_line_rx;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200815 return sync_dev;
816}
817
818static void mmc_omap_config_dma_params(struct mmc_omap_host *host,
819 struct mmc_data *data,
820 struct scatterlist *sgl)
821{
822 int blksz, nblk, dma_ch;
823
824 dma_ch = host->dma_ch;
825 if (data->flags & MMC_DATA_WRITE) {
826 omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
827 (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
828 omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
829 sg_dma_address(sgl), 0, 0);
830 } else {
831 omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
Denis Karpov191d1f12009-09-22 16:44:55 -0700832 (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200833 omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
834 sg_dma_address(sgl), 0, 0);
835 }
836
837 blksz = host->data->blksz;
838 nblk = sg_dma_len(sgl) / blksz;
839
840 omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32,
841 blksz / 4, nblk, OMAP_DMA_SYNC_FRAME,
842 mmc_omap_get_dma_sync_dev(host, data),
843 !(data->flags & MMC_DATA_WRITE));
844
845 omap_start_dma(dma_ch);
846}
847
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100848/*
849 * DMA call back function
850 */
851static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
852{
853 struct mmc_omap_host *host = data;
854
855 if (ch_status & OMAP2_DMA_MISALIGNED_ERR_IRQ)
856 dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n");
857
858 if (host->dma_ch < 0)
859 return;
860
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200861 host->dma_sg_idx++;
862 if (host->dma_sg_idx < host->dma_len) {
863 /* Fire up the next transfer. */
864 mmc_omap_config_dma_params(host, host->data,
865 host->data->sg + host->dma_sg_idx);
866 return;
867 }
868
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100869 omap_free_dma(host->dma_ch);
870 host->dma_ch = -1;
871 /*
872 * DMA Callback: run in interrupt context.
Anand Gadiyar85b84322009-04-15 17:44:58 +0530873 * mutex_unlock will throw a kernel warning if used.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100874 */
875 up(&host->sem);
876}
877
878/*
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100879 * Routine to configure and start DMA for the MMC card
880 */
881static int
882mmc_omap_start_dma_transfer(struct mmc_omap_host *host, struct mmc_request *req)
883{
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200884 int dma_ch = 0, ret = 0, err = 1, i;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100885 struct mmc_data *data = req->data;
886
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200887 /* Sanity check: all the SG entries must be aligned by block size. */
Jarkko Lavinena3f406f2009-09-22 16:44:46 -0700888 for (i = 0; i < data->sg_len; i++) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200889 struct scatterlist *sgl;
890
891 sgl = data->sg + i;
892 if (sgl->length % data->blksz)
893 return -EINVAL;
894 }
895 if ((data->blksz % 4) != 0)
896 /* REVISIT: The MMC buffer increments only when MSB is written.
897 * Return error for blksz which is non multiple of four.
898 */
899 return -EINVAL;
900
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100901 /*
902 * If for some reason the DMA transfer is still active,
903 * we wait for timeout period and free the dma
904 */
905 if (host->dma_ch != -1) {
906 set_current_state(TASK_UNINTERRUPTIBLE);
907 schedule_timeout(100);
908 if (down_trylock(&host->sem)) {
909 omap_free_dma(host->dma_ch);
910 host->dma_ch = -1;
911 up(&host->sem);
912 return err;
913 }
914 } else {
915 if (down_trylock(&host->sem))
916 return err;
917 }
918
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200919 ret = omap_request_dma(mmc_omap_get_dma_sync_dev(host, data), "MMC/SD",
Denis Karpov191d1f12009-09-22 16:44:55 -0700920 mmc_omap_dma_cb, host, &dma_ch);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100921 if (ret != 0) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200922 dev_err(mmc_dev(host->mmc),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100923 "%s: omap_request_dma() failed with %d\n",
924 mmc_hostname(host->mmc), ret);
925 return ret;
926 }
927
928 host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200929 data->sg_len, mmc_omap_get_dma_dir(host, data));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100930 host->dma_ch = dma_ch;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200931 host->dma_sg_idx = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100932
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200933 mmc_omap_config_dma_params(host, data, data->sg);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100934
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100935 return 0;
936}
937
938static void set_data_timeout(struct mmc_omap_host *host,
939 struct mmc_request *req)
940{
941 unsigned int timeout, cycle_ns;
942 uint32_t reg, clkd, dto = 0;
943
944 reg = OMAP_HSMMC_READ(host->base, SYSCTL);
945 clkd = (reg & CLKD_MASK) >> CLKD_SHIFT;
946 if (clkd == 0)
947 clkd = 1;
948
949 cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
950 timeout = req->data->timeout_ns / cycle_ns;
951 timeout += req->data->timeout_clks;
952 if (timeout) {
953 while ((timeout & 0x80000000) == 0) {
954 dto += 1;
955 timeout <<= 1;
956 }
957 dto = 31 - dto;
958 timeout <<= 1;
959 if (timeout && dto)
960 dto += 1;
961 if (dto >= 13)
962 dto -= 13;
963 else
964 dto = 0;
965 if (dto > 14)
966 dto = 14;
967 }
968
969 reg &= ~DTO_MASK;
970 reg |= dto << DTO_SHIFT;
971 OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
972}
973
974/*
975 * Configure block length for MMC/SD cards and initiate the transfer.
976 */
977static int
978mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
979{
980 int ret;
981 host->data = req->data;
982
983 if (req->data == NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100984 OMAP_HSMMC_WRITE(host->base, BLK, 0);
985 return 0;
986 }
987
988 OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
989 | (req->data->blocks << 16));
990 set_data_timeout(host, req);
991
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100992 if (host->use_dma) {
993 ret = mmc_omap_start_dma_transfer(host, req);
994 if (ret != 0) {
995 dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
996 return ret;
997 }
998 }
999 return 0;
1000}
1001
1002/*
1003 * Request function. for read/write operation
1004 */
1005static void omap_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
1006{
1007 struct mmc_omap_host *host = mmc_priv(mmc);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001008 int err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001009
1010 WARN_ON(host->mrq != NULL);
1011 host->mrq = req;
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001012 err = mmc_omap_prepare_data(host, req);
1013 if (err) {
1014 req->cmd->error = err;
1015 if (req->data)
1016 req->data->error = err;
1017 host->mrq = NULL;
1018 mmc_request_done(mmc, req);
1019 return;
1020 }
1021
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001022 mmc_omap_start_command(host, req->cmd, req->data);
1023}
1024
1025
1026/* Routine to configure clock values. Exposed API to core */
1027static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1028{
1029 struct mmc_omap_host *host = mmc_priv(mmc);
1030 u16 dsor = 0;
1031 unsigned long regval;
1032 unsigned long timeout;
Jarkko Lavinen73153012008-11-21 16:49:54 +02001033 u32 con;
Adrian Huntera3621462009-09-22 16:44:42 -07001034 int do_send_init_stream = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001035
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001036 mmc_host_enable(host->mmc);
1037
Adrian Huntera3621462009-09-22 16:44:42 -07001038 if (ios->power_mode != host->power_mode) {
1039 switch (ios->power_mode) {
1040 case MMC_POWER_OFF:
1041 mmc_slot(host).set_power(host->dev, host->slot_id,
1042 0, 0);
Adrian Hunter623821f2009-09-22 16:44:51 -07001043 host->vdd = 0;
Adrian Huntera3621462009-09-22 16:44:42 -07001044 break;
1045 case MMC_POWER_UP:
1046 mmc_slot(host).set_power(host->dev, host->slot_id,
1047 1, ios->vdd);
Adrian Hunter623821f2009-09-22 16:44:51 -07001048 host->vdd = ios->vdd;
Adrian Huntera3621462009-09-22 16:44:42 -07001049 break;
1050 case MMC_POWER_ON:
1051 do_send_init_stream = 1;
1052 break;
1053 }
1054 host->power_mode = ios->power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001055 }
1056
Denis Karpovdd498ef2009-09-22 16:44:49 -07001057 /* FIXME: set registers based only on changes to ios */
1058
Jarkko Lavinen73153012008-11-21 16:49:54 +02001059 con = OMAP_HSMMC_READ(host->base, CON);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001060 switch (mmc->ios.bus_width) {
Jarkko Lavinen73153012008-11-21 16:49:54 +02001061 case MMC_BUS_WIDTH_8:
1062 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
1063 break;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001064 case MMC_BUS_WIDTH_4:
Jarkko Lavinen73153012008-11-21 16:49:54 +02001065 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001066 OMAP_HSMMC_WRITE(host->base, HCTL,
1067 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
1068 break;
1069 case MMC_BUS_WIDTH_1:
Jarkko Lavinen73153012008-11-21 16:49:54 +02001070 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001071 OMAP_HSMMC_WRITE(host->base, HCTL,
1072 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
1073 break;
1074 }
1075
1076 if (host->id == OMAP_MMC1_DEVID) {
David Brownelleb250822009-02-17 14:49:01 -08001077 /* Only MMC1 can interface at 3V without some flavor
1078 * of external transceiver; but they all handle 1.8V.
1079 */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001080 if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
1081 (ios->vdd == DUAL_VOLT_OCR_BIT)) {
1082 /*
1083 * The mmc_select_voltage fn of the core does
1084 * not seem to set the power_mode to
1085 * MMC_POWER_UP upon recalculating the voltage.
1086 * vdd 1.8v.
1087 */
1088 if (omap_mmc_switch_opcond(host, ios->vdd) != 0)
1089 dev_dbg(mmc_dev(host->mmc),
1090 "Switch operation failed\n");
1091 }
1092 }
1093
1094 if (ios->clock) {
1095 dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
1096 if (dsor < 1)
1097 dsor = 1;
1098
1099 if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
1100 dsor++;
1101
1102 if (dsor > 250)
1103 dsor = 250;
1104 }
1105 omap_mmc_stop_clock(host);
1106 regval = OMAP_HSMMC_READ(host->base, SYSCTL);
1107 regval = regval & ~(CLKD_MASK);
1108 regval = regval | (dsor << 6) | (DTO << 16);
1109 OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
1110 OMAP_HSMMC_WRITE(host->base, SYSCTL,
1111 OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
1112
1113 /* Wait till the ICS bit is set */
1114 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001115 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001116 && time_before(jiffies, timeout))
1117 msleep(1);
1118
1119 OMAP_HSMMC_WRITE(host->base, SYSCTL,
1120 OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
1121
Adrian Huntera3621462009-09-22 16:44:42 -07001122 if (do_send_init_stream)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001123 send_init_stream(host);
1124
Denis Karpovabb28e72009-09-22 16:44:44 -07001125 con = OMAP_HSMMC_READ(host->base, CON);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001126 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
Denis Karpovabb28e72009-09-22 16:44:44 -07001127 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
1128 else
1129 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001130
Denis Karpovdd498ef2009-09-22 16:44:49 -07001131 if (host->power_mode == MMC_POWER_OFF)
1132 mmc_host_disable(host->mmc);
1133 else
1134 mmc_host_lazy_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001135}
1136
1137static int omap_hsmmc_get_cd(struct mmc_host *mmc)
1138{
1139 struct mmc_omap_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001140
Denis Karpov191d1f12009-09-22 16:44:55 -07001141 if (!mmc_slot(host).card_detect)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001142 return -ENOSYS;
Denis Karpov191d1f12009-09-22 16:44:55 -07001143 return mmc_slot(host).card_detect(mmc_slot(host).card_detect_irq);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001144}
1145
1146static int omap_hsmmc_get_ro(struct mmc_host *mmc)
1147{
1148 struct mmc_omap_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001149
Denis Karpov191d1f12009-09-22 16:44:55 -07001150 if (!mmc_slot(host).get_ro)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001151 return -ENOSYS;
Denis Karpov191d1f12009-09-22 16:44:55 -07001152 return mmc_slot(host).get_ro(host->dev, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001153}
1154
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001155static void omap_hsmmc_init(struct mmc_omap_host *host)
1156{
1157 u32 hctl, capa, value;
1158
1159 /* Only MMC1 supports 3.0V */
1160 if (host->id == OMAP_MMC1_DEVID) {
1161 hctl = SDVS30;
1162 capa = VS30 | VS18;
1163 } else {
1164 hctl = SDVS18;
1165 capa = VS18;
1166 }
1167
1168 value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
1169 OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
1170
1171 value = OMAP_HSMMC_READ(host->base, CAPA);
1172 OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
1173
1174 /* Set the controller to AUTO IDLE mode */
1175 value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
1176 OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
1177
1178 /* Set SD bus power bit */
Adrian Huntere13bb302009-03-12 17:08:26 +02001179 set_sd_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001180}
1181
Denis Karpovdd498ef2009-09-22 16:44:49 -07001182/*
1183 * Dynamic power saving handling, FSM:
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001184 * ENABLED -> DISABLED -> CARDSLEEP / REGSLEEP -> OFF
1185 * ^___________| | |
1186 * |______________________|______________________|
Denis Karpovdd498ef2009-09-22 16:44:49 -07001187 *
1188 * ENABLED: mmc host is fully functional
1189 * DISABLED: fclk is off
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001190 * CARDSLEEP: fclk is off, card is asleep, voltage regulator is asleep
1191 * REGSLEEP: fclk is off, voltage regulator is asleep
1192 * OFF: fclk is off, voltage regulator is off
Denis Karpovdd498ef2009-09-22 16:44:49 -07001193 *
1194 * Transition handlers return the timeout for the next state transition
1195 * or negative error.
1196 */
1197
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001198enum {ENABLED = 0, DISABLED, CARDSLEEP, REGSLEEP, OFF};
Denis Karpovdd498ef2009-09-22 16:44:49 -07001199
1200/* Handler for [ENABLED -> DISABLED] transition */
1201static int omap_mmc_enabled_to_disabled(struct mmc_omap_host *host)
1202{
1203 omap_mmc_save_ctx(host);
1204 clk_disable(host->fclk);
1205 host->dpm_state = DISABLED;
1206
1207 dev_dbg(mmc_dev(host->mmc), "ENABLED -> DISABLED\n");
1208
1209 if (host->power_mode == MMC_POWER_OFF)
1210 return 0;
1211
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001212 return msecs_to_jiffies(OMAP_MMC_SLEEP_TIMEOUT);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001213}
1214
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001215/* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */
1216static int omap_mmc_disabled_to_sleep(struct mmc_omap_host *host)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001217{
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001218 int err, new_state;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001219
1220 if (!mmc_try_claim_host(host->mmc))
1221 return 0;
1222
1223 clk_enable(host->fclk);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001224 omap_mmc_restore_ctx(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001225 if (mmc_card_can_sleep(host->mmc)) {
1226 err = mmc_card_sleep(host->mmc);
1227 if (err < 0) {
1228 clk_disable(host->fclk);
1229 mmc_release_host(host->mmc);
1230 return err;
1231 }
1232 new_state = CARDSLEEP;
1233 } else
1234 new_state = REGSLEEP;
1235 if (mmc_slot(host).set_sleep)
1236 mmc_slot(host).set_sleep(host->dev, host->slot_id, 1, 0,
1237 new_state == CARDSLEEP);
1238 /* FIXME: turn off bus power and perhaps interrupts too */
1239 clk_disable(host->fclk);
1240 host->dpm_state = new_state;
1241
1242 mmc_release_host(host->mmc);
1243
1244 dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n",
1245 host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
Denis Karpovdd498ef2009-09-22 16:44:49 -07001246
1247 if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
1248 mmc_slot(host).card_detect ||
1249 (mmc_slot(host).get_cover_state &&
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001250 mmc_slot(host).get_cover_state(host->dev, host->slot_id)))
1251 return msecs_to_jiffies(OMAP_MMC_OFF_TIMEOUT);
1252
1253 return 0;
1254}
1255
1256/* Handler for [REGSLEEP / CARDSLEEP -> OFF] transition */
1257static int omap_mmc_sleep_to_off(struct mmc_omap_host *host)
1258{
1259 if (!mmc_try_claim_host(host->mmc))
1260 return 0;
1261
1262 if (!((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
1263 mmc_slot(host).card_detect ||
1264 (mmc_slot(host).get_cover_state &&
1265 mmc_slot(host).get_cover_state(host->dev, host->slot_id)))) {
1266 mmc_release_host(host->mmc);
1267 return 0;
Adrian Hunter623821f2009-09-22 16:44:51 -07001268 }
Denis Karpovdd498ef2009-09-22 16:44:49 -07001269
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001270 mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
1271 host->vdd = 0;
1272 host->power_mode = MMC_POWER_OFF;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001273
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001274 dev_dbg(mmc_dev(host->mmc), "%s -> OFF\n",
1275 host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
Denis Karpovdd498ef2009-09-22 16:44:49 -07001276
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001277 host->dpm_state = OFF;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001278
1279 mmc_release_host(host->mmc);
1280
1281 return 0;
1282}
1283
1284/* Handler for [DISABLED -> ENABLED] transition */
1285static int omap_mmc_disabled_to_enabled(struct mmc_omap_host *host)
1286{
1287 int err;
1288
1289 err = clk_enable(host->fclk);
1290 if (err < 0)
1291 return err;
1292
1293 omap_mmc_restore_ctx(host);
1294
1295 host->dpm_state = ENABLED;
1296
1297 dev_dbg(mmc_dev(host->mmc), "DISABLED -> ENABLED\n");
1298
1299 return 0;
1300}
1301
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001302/* Handler for [SLEEP -> ENABLED] transition */
1303static int omap_mmc_sleep_to_enabled(struct mmc_omap_host *host)
1304{
1305 if (!mmc_try_claim_host(host->mmc))
1306 return 0;
1307
1308 clk_enable(host->fclk);
1309 omap_mmc_restore_ctx(host);
1310 if (mmc_slot(host).set_sleep)
1311 mmc_slot(host).set_sleep(host->dev, host->slot_id, 0,
1312 host->vdd, host->dpm_state == CARDSLEEP);
1313 if (mmc_card_can_sleep(host->mmc))
1314 mmc_card_awake(host->mmc);
1315
1316 dev_dbg(mmc_dev(host->mmc), "%s -> ENABLED\n",
1317 host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
1318
1319 host->dpm_state = ENABLED;
1320
1321 mmc_release_host(host->mmc);
1322
1323 return 0;
1324}
1325
Denis Karpovdd498ef2009-09-22 16:44:49 -07001326/* Handler for [OFF -> ENABLED] transition */
1327static int omap_mmc_off_to_enabled(struct mmc_omap_host *host)
1328{
1329 clk_enable(host->fclk);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001330
1331 omap_mmc_restore_ctx(host);
1332 omap_hsmmc_init(host);
1333 mmc_power_restore_host(host->mmc);
1334
1335 host->dpm_state = ENABLED;
1336
1337 dev_dbg(mmc_dev(host->mmc), "OFF -> ENABLED\n");
1338
1339 return 0;
1340}
1341
1342/*
1343 * Bring MMC host to ENABLED from any other PM state.
1344 */
1345static int omap_mmc_enable(struct mmc_host *mmc)
1346{
1347 struct mmc_omap_host *host = mmc_priv(mmc);
1348
1349 switch (host->dpm_state) {
1350 case DISABLED:
1351 return omap_mmc_disabled_to_enabled(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001352 case CARDSLEEP:
Adrian Hunter623821f2009-09-22 16:44:51 -07001353 case REGSLEEP:
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001354 return omap_mmc_sleep_to_enabled(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001355 case OFF:
1356 return omap_mmc_off_to_enabled(host);
1357 default:
1358 dev_dbg(mmc_dev(host->mmc), "UNKNOWN state\n");
1359 return -EINVAL;
1360 }
1361}
1362
1363/*
1364 * Bring MMC host in PM state (one level deeper).
1365 */
1366static int omap_mmc_disable(struct mmc_host *mmc, int lazy)
1367{
1368 struct mmc_omap_host *host = mmc_priv(mmc);
1369
1370 switch (host->dpm_state) {
1371 case ENABLED: {
1372 int delay;
1373
1374 delay = omap_mmc_enabled_to_disabled(host);
1375 if (lazy || delay < 0)
1376 return delay;
1377 return 0;
1378 }
1379 case DISABLED:
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001380 return omap_mmc_disabled_to_sleep(host);
1381 case CARDSLEEP:
1382 case REGSLEEP:
1383 return omap_mmc_sleep_to_off(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001384 default:
1385 dev_dbg(mmc_dev(host->mmc), "UNKNOWN state\n");
1386 return -EINVAL;
1387 }
1388}
1389
1390static int omap_mmc_enable_fclk(struct mmc_host *mmc)
1391{
1392 struct mmc_omap_host *host = mmc_priv(mmc);
1393 int err;
1394
1395 err = clk_enable(host->fclk);
1396 if (err)
1397 return err;
1398 dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
1399 omap_mmc_restore_ctx(host);
1400 return 0;
1401}
1402
1403static int omap_mmc_disable_fclk(struct mmc_host *mmc, int lazy)
1404{
1405 struct mmc_omap_host *host = mmc_priv(mmc);
1406
1407 omap_mmc_save_ctx(host);
1408 clk_disable(host->fclk);
1409 dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n");
1410 return 0;
1411}
1412
1413static const struct mmc_host_ops mmc_omap_ops = {
1414 .enable = omap_mmc_enable_fclk,
1415 .disable = omap_mmc_disable_fclk,
1416 .request = omap_mmc_request,
1417 .set_ios = omap_mmc_set_ios,
1418 .get_cd = omap_hsmmc_get_cd,
1419 .get_ro = omap_hsmmc_get_ro,
1420 /* NYET -- enable_sdio_irq */
1421};
1422
1423static const struct mmc_host_ops mmc_omap_ps_ops = {
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001424 .enable = omap_mmc_enable,
1425 .disable = omap_mmc_disable,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001426 .request = omap_mmc_request,
1427 .set_ios = omap_mmc_set_ios,
1428 .get_cd = omap_hsmmc_get_cd,
1429 .get_ro = omap_hsmmc_get_ro,
1430 /* NYET -- enable_sdio_irq */
1431};
1432
Denis Karpovd900f712009-09-22 16:44:38 -07001433#ifdef CONFIG_DEBUG_FS
1434
1435static int mmc_regs_show(struct seq_file *s, void *data)
1436{
1437 struct mmc_host *mmc = s->private;
1438 struct mmc_omap_host *host = mmc_priv(mmc);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001439 struct omap_mmc_platform_data *pdata = host->pdata;
1440 int context_loss = 0;
1441
1442 if (pdata->get_context_loss_count)
1443 context_loss = pdata->get_context_loss_count(host->dev);
Denis Karpovd900f712009-09-22 16:44:38 -07001444
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001445 seq_printf(s, "mmc%d:\n"
1446 " enabled:\t%d\n"
Denis Karpovdd498ef2009-09-22 16:44:49 -07001447 " dpm_state:\t%d\n"
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001448 " nesting_cnt:\t%d\n"
Denis Karpov11dd62a2009-09-22 16:44:43 -07001449 " ctx_loss:\t%d:%d\n"
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001450 "\nregs:\n",
Denis Karpovdd498ef2009-09-22 16:44:49 -07001451 mmc->index, mmc->enabled ? 1 : 0,
1452 host->dpm_state, mmc->nesting_cnt,
Denis Karpov11dd62a2009-09-22 16:44:43 -07001453 host->context_loss, context_loss);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001454
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001455 if (host->suspended || host->dpm_state == OFF) {
Denis Karpovdd498ef2009-09-22 16:44:49 -07001456 seq_printf(s, "host suspended, can't read registers\n");
1457 return 0;
1458 }
1459
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001460 if (clk_enable(host->fclk) != 0) {
1461 seq_printf(s, "can't read the regs\n");
Denis Karpovdd498ef2009-09-22 16:44:49 -07001462 return 0;
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001463 }
Denis Karpovd900f712009-09-22 16:44:38 -07001464
1465 seq_printf(s, "SYSCONFIG:\t0x%08x\n",
1466 OMAP_HSMMC_READ(host->base, SYSCONFIG));
1467 seq_printf(s, "CON:\t\t0x%08x\n",
1468 OMAP_HSMMC_READ(host->base, CON));
1469 seq_printf(s, "HCTL:\t\t0x%08x\n",
1470 OMAP_HSMMC_READ(host->base, HCTL));
1471 seq_printf(s, "SYSCTL:\t\t0x%08x\n",
1472 OMAP_HSMMC_READ(host->base, SYSCTL));
1473 seq_printf(s, "IE:\t\t0x%08x\n",
1474 OMAP_HSMMC_READ(host->base, IE));
1475 seq_printf(s, "ISE:\t\t0x%08x\n",
1476 OMAP_HSMMC_READ(host->base, ISE));
1477 seq_printf(s, "CAPA:\t\t0x%08x\n",
1478 OMAP_HSMMC_READ(host->base, CAPA));
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001479
1480 clk_disable(host->fclk);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001481
Denis Karpovd900f712009-09-22 16:44:38 -07001482 return 0;
1483}
1484
1485static int mmc_regs_open(struct inode *inode, struct file *file)
1486{
1487 return single_open(file, mmc_regs_show, inode->i_private);
1488}
1489
1490static const struct file_operations mmc_regs_fops = {
1491 .open = mmc_regs_open,
1492 .read = seq_read,
1493 .llseek = seq_lseek,
1494 .release = single_release,
1495};
1496
1497static void omap_mmc_debugfs(struct mmc_host *mmc)
1498{
1499 if (mmc->debugfs_root)
1500 debugfs_create_file("regs", S_IRUSR, mmc->debugfs_root,
1501 mmc, &mmc_regs_fops);
1502}
1503
1504#else
1505
1506static void omap_mmc_debugfs(struct mmc_host *mmc)
1507{
1508}
1509
1510#endif
1511
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001512static int __init omap_mmc_probe(struct platform_device *pdev)
1513{
1514 struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
1515 struct mmc_host *mmc;
1516 struct mmc_omap_host *host = NULL;
1517 struct resource *res;
1518 int ret = 0, irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001519
1520 if (pdata == NULL) {
1521 dev_err(&pdev->dev, "Platform Data is missing\n");
1522 return -ENXIO;
1523 }
1524
1525 if (pdata->nr_slots == 0) {
1526 dev_err(&pdev->dev, "No Slots\n");
1527 return -ENXIO;
1528 }
1529
1530 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1531 irq = platform_get_irq(pdev, 0);
1532 if (res == NULL || irq < 0)
1533 return -ENXIO;
1534
1535 res = request_mem_region(res->start, res->end - res->start + 1,
1536 pdev->name);
1537 if (res == NULL)
1538 return -EBUSY;
1539
1540 mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
1541 if (!mmc) {
1542 ret = -ENOMEM;
1543 goto err;
1544 }
1545
1546 host = mmc_priv(mmc);
1547 host->mmc = mmc;
1548 host->pdata = pdata;
1549 host->dev = &pdev->dev;
1550 host->use_dma = 1;
1551 host->dev->dma_mask = &pdata->dma_mask;
1552 host->dma_ch = -1;
1553 host->irq = irq;
1554 host->id = pdev->id;
1555 host->slot_id = 0;
1556 host->mapbase = res->start;
1557 host->base = ioremap(host->mapbase, SZ_4K);
Adrian Huntera3621462009-09-22 16:44:42 -07001558 host->power_mode = -1;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001559
1560 platform_set_drvdata(pdev, host);
1561 INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
1562
Denis Karpov191d1f12009-09-22 16:44:55 -07001563 if (mmc_slot(host).power_saving)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001564 mmc->ops = &mmc_omap_ps_ops;
1565 else
1566 mmc->ops = &mmc_omap_ops;
1567
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001568 mmc->f_min = 400000;
1569 mmc->f_max = 52000000;
1570
1571 sema_init(&host->sem, 1);
1572
Russell King6f7607c2009-01-28 10:22:50 +00001573 host->iclk = clk_get(&pdev->dev, "ick");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001574 if (IS_ERR(host->iclk)) {
1575 ret = PTR_ERR(host->iclk);
1576 host->iclk = NULL;
1577 goto err1;
1578 }
Russell King6f7607c2009-01-28 10:22:50 +00001579 host->fclk = clk_get(&pdev->dev, "fck");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001580 if (IS_ERR(host->fclk)) {
1581 ret = PTR_ERR(host->fclk);
1582 host->fclk = NULL;
1583 clk_put(host->iclk);
1584 goto err1;
1585 }
1586
Denis Karpov11dd62a2009-09-22 16:44:43 -07001587 omap_mmc_save_ctx(host);
1588
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001589 mmc->caps |= MMC_CAP_DISABLE;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001590 mmc_set_disable_delay(mmc, OMAP_MMC_DISABLED_TIMEOUT);
1591 /* we start off in DISABLED state */
1592 host->dpm_state = DISABLED;
1593
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001594 if (mmc_host_enable(host->mmc) != 0) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001595 clk_put(host->iclk);
1596 clk_put(host->fclk);
1597 goto err1;
1598 }
1599
1600 if (clk_enable(host->iclk) != 0) {
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001601 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001602 clk_put(host->iclk);
1603 clk_put(host->fclk);
1604 goto err1;
1605 }
1606
1607 host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
1608 /*
1609 * MMC can still work without debounce clock.
1610 */
1611 if (IS_ERR(host->dbclk))
1612 dev_warn(mmc_dev(host->mmc), "Failed to get debounce clock\n");
1613 else
1614 if (clk_enable(host->dbclk) != 0)
1615 dev_dbg(mmc_dev(host->mmc), "Enabling debounce"
1616 " clk failed\n");
1617 else
1618 host->dbclk_enabled = 1;
1619
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001620 /* Since we do only SG emulation, we can have as many segs
1621 * as we want. */
1622 mmc->max_phys_segs = 1024;
1623 mmc->max_hw_segs = 1024;
1624
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001625 mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
1626 mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
1627 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
1628 mmc->max_seg_size = mmc->max_req_size;
1629
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001630 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
1631 MMC_CAP_WAIT_WHILE_BUSY;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001632
Denis Karpov191d1f12009-09-22 16:44:55 -07001633 if (mmc_slot(host).wires >= 8)
Jarkko Lavinen73153012008-11-21 16:49:54 +02001634 mmc->caps |= MMC_CAP_8_BIT_DATA;
Denis Karpov191d1f12009-09-22 16:44:55 -07001635 else if (mmc_slot(host).wires >= 4)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001636 mmc->caps |= MMC_CAP_4_BIT_DATA;
1637
Denis Karpov191d1f12009-09-22 16:44:55 -07001638 if (mmc_slot(host).nonremovable)
Adrian Hunter23d99bb2009-09-22 16:44:48 -07001639 mmc->caps |= MMC_CAP_NONREMOVABLE;
1640
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001641 omap_hsmmc_init(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001642
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +00001643 /* Select DMA lines */
1644 switch (host->id) {
1645 case OMAP_MMC1_DEVID:
1646 host->dma_line_tx = OMAP24XX_DMA_MMC1_TX;
1647 host->dma_line_rx = OMAP24XX_DMA_MMC1_RX;
1648 break;
1649 case OMAP_MMC2_DEVID:
1650 host->dma_line_tx = OMAP24XX_DMA_MMC2_TX;
1651 host->dma_line_rx = OMAP24XX_DMA_MMC2_RX;
1652 break;
1653 case OMAP_MMC3_DEVID:
1654 host->dma_line_tx = OMAP34XX_DMA_MMC3_TX;
1655 host->dma_line_rx = OMAP34XX_DMA_MMC3_RX;
1656 break;
1657 default:
1658 dev_err(mmc_dev(host->mmc), "Invalid MMC id\n");
1659 goto err_irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001660 }
1661
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001662 /* Request IRQ for MMC operations */
1663 ret = request_irq(host->irq, mmc_omap_irq, IRQF_DISABLED,
1664 mmc_hostname(mmc), host);
1665 if (ret) {
1666 dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
1667 goto err_irq;
1668 }
1669
David Brownellb583f262009-05-28 14:04:03 -07001670 /* initialize power supplies, gpios, etc */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001671 if (pdata->init != NULL) {
1672 if (pdata->init(&pdev->dev) != 0) {
David Brownellb583f262009-05-28 14:04:03 -07001673 dev_dbg(mmc_dev(host->mmc), "late init error\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001674 goto err_irq_cd_init;
1675 }
1676 }
David Brownellb583f262009-05-28 14:04:03 -07001677 mmc->ocr_avail = mmc_slot(host).ocr_mask;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001678
1679 /* Request IRQ for card detect */
Adrian Huntere1a55f52009-01-26 13:17:25 +02001680 if ((mmc_slot(host).card_detect_irq)) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001681 ret = request_irq(mmc_slot(host).card_detect_irq,
1682 omap_mmc_cd_handler,
1683 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
1684 | IRQF_DISABLED,
1685 mmc_hostname(mmc), host);
1686 if (ret) {
1687 dev_dbg(mmc_dev(host->mmc),
1688 "Unable to grab MMC CD IRQ\n");
1689 goto err_irq_cd;
1690 }
1691 }
1692
1693 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
1694 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
1695
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001696 mmc_host_lazy_disable(host->mmc);
1697
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001698 mmc_add_host(mmc);
1699
Denis Karpov191d1f12009-09-22 16:44:55 -07001700 if (mmc_slot(host).name != NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001701 ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
1702 if (ret < 0)
1703 goto err_slot_name;
1704 }
Denis Karpov191d1f12009-09-22 16:44:55 -07001705 if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001706 ret = device_create_file(&mmc->class_dev,
1707 &dev_attr_cover_switch);
1708 if (ret < 0)
1709 goto err_cover_switch;
1710 }
1711
Denis Karpovd900f712009-09-22 16:44:38 -07001712 omap_mmc_debugfs(mmc);
1713
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001714 return 0;
1715
1716err_cover_switch:
1717 device_remove_file(&mmc->class_dev, &dev_attr_cover_switch);
1718err_slot_name:
1719 mmc_remove_host(mmc);
1720err_irq_cd:
1721 free_irq(mmc_slot(host).card_detect_irq, host);
1722err_irq_cd_init:
1723 free_irq(host->irq, host);
1724err_irq:
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001725 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001726 clk_disable(host->iclk);
1727 clk_put(host->fclk);
1728 clk_put(host->iclk);
1729 if (host->dbclk_enabled) {
1730 clk_disable(host->dbclk);
1731 clk_put(host->dbclk);
1732 }
1733
1734err1:
1735 iounmap(host->base);
1736err:
1737 dev_dbg(mmc_dev(host->mmc), "Probe Failed\n");
1738 release_mem_region(res->start, res->end - res->start + 1);
1739 if (host)
1740 mmc_free_host(mmc);
1741 return ret;
1742}
1743
1744static int omap_mmc_remove(struct platform_device *pdev)
1745{
1746 struct mmc_omap_host *host = platform_get_drvdata(pdev);
1747 struct resource *res;
1748
1749 if (host) {
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001750 mmc_host_enable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001751 mmc_remove_host(host->mmc);
1752 if (host->pdata->cleanup)
1753 host->pdata->cleanup(&pdev->dev);
1754 free_irq(host->irq, host);
1755 if (mmc_slot(host).card_detect_irq)
1756 free_irq(mmc_slot(host).card_detect_irq, host);
1757 flush_scheduled_work();
1758
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001759 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001760 clk_disable(host->iclk);
1761 clk_put(host->fclk);
1762 clk_put(host->iclk);
1763 if (host->dbclk_enabled) {
1764 clk_disable(host->dbclk);
1765 clk_put(host->dbclk);
1766 }
1767
1768 mmc_free_host(host->mmc);
1769 iounmap(host->base);
1770 }
1771
1772 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1773 if (res)
1774 release_mem_region(res->start, res->end - res->start + 1);
1775 platform_set_drvdata(pdev, NULL);
1776
1777 return 0;
1778}
1779
1780#ifdef CONFIG_PM
1781static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state)
1782{
1783 int ret = 0;
1784 struct mmc_omap_host *host = platform_get_drvdata(pdev);
1785
1786 if (host && host->suspended)
1787 return 0;
1788
1789 if (host) {
Adrian Huntera6b22402009-09-22 16:44:45 -07001790 host->suspended = 1;
1791 if (host->pdata->suspend) {
1792 ret = host->pdata->suspend(&pdev->dev,
1793 host->slot_id);
1794 if (ret) {
1795 dev_dbg(mmc_dev(host->mmc),
1796 "Unable to handle MMC board"
1797 " level suspend\n");
1798 host->suspended = 0;
1799 return ret;
1800 }
1801 }
1802 cancel_work_sync(&host->mmc_carddetect_work);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001803 mmc_host_enable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001804 ret = mmc_suspend_host(host->mmc, state);
1805 if (ret == 0) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001806 OMAP_HSMMC_WRITE(host->base, ISE, 0);
1807 OMAP_HSMMC_WRITE(host->base, IE, 0);
1808
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001809
Jarkko Lavinen0683af42009-03-12 15:30:58 +02001810 OMAP_HSMMC_WRITE(host->base, HCTL,
Denis Karpov191d1f12009-09-22 16:44:55 -07001811 OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001812 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001813 clk_disable(host->iclk);
1814 clk_disable(host->dbclk);
Adrian Huntera6b22402009-09-22 16:44:45 -07001815 } else {
1816 host->suspended = 0;
1817 if (host->pdata->resume) {
1818 ret = host->pdata->resume(&pdev->dev,
1819 host->slot_id);
1820 if (ret)
1821 dev_dbg(mmc_dev(host->mmc),
1822 "Unmask interrupt failed\n");
1823 }
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001824 mmc_host_disable(host->mmc);
Adrian Huntera6b22402009-09-22 16:44:45 -07001825 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001826
1827 }
1828 return ret;
1829}
1830
1831/* Routine to resume the MMC device */
1832static int omap_mmc_resume(struct platform_device *pdev)
1833{
1834 int ret = 0;
1835 struct mmc_omap_host *host = platform_get_drvdata(pdev);
1836
1837 if (host && !host->suspended)
1838 return 0;
1839
1840 if (host) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001841 ret = clk_enable(host->iclk);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001842 if (ret)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001843 goto clk_en_err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001844
1845 if (clk_enable(host->dbclk) != 0)
1846 dev_dbg(mmc_dev(host->mmc),
1847 "Enabling debounce clk failed\n");
1848
Denis Karpov11dd62a2009-09-22 16:44:43 -07001849 if (mmc_host_enable(host->mmc) != 0) {
1850 clk_disable(host->iclk);
1851 goto clk_en_err;
1852 }
1853
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001854 omap_hsmmc_init(host);
1855
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001856 if (host->pdata->resume) {
1857 ret = host->pdata->resume(&pdev->dev, host->slot_id);
1858 if (ret)
1859 dev_dbg(mmc_dev(host->mmc),
1860 "Unmask interrupt failed\n");
1861 }
1862
1863 /* Notify the core to resume the host */
1864 ret = mmc_resume_host(host->mmc);
1865 if (ret == 0)
1866 host->suspended = 0;
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001867 mmc_host_lazy_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001868 }
1869
1870 return ret;
1871
1872clk_en_err:
1873 dev_dbg(mmc_dev(host->mmc),
1874 "Failed to enable MMC clocks during resume\n");
1875 return ret;
1876}
1877
1878#else
1879#define omap_mmc_suspend NULL
1880#define omap_mmc_resume NULL
1881#endif
1882
1883static struct platform_driver omap_mmc_driver = {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001884 .remove = omap_mmc_remove,
1885 .suspend = omap_mmc_suspend,
1886 .resume = omap_mmc_resume,
1887 .driver = {
1888 .name = DRIVER_NAME,
1889 .owner = THIS_MODULE,
1890 },
1891};
1892
1893static int __init omap_mmc_init(void)
1894{
1895 /* Register the MMC driver */
Uwe Kleine-Königf400cd82009-09-22 16:44:26 -07001896 return platform_driver_probe(&omap_mmc_driver, omap_mmc_probe);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001897}
1898
1899static void __exit omap_mmc_cleanup(void)
1900{
1901 /* Unregister MMC driver */
1902 platform_driver_unregister(&omap_mmc_driver);
1903}
1904
1905module_init(omap_mmc_init);
1906module_exit(omap_mmc_cleanup);
1907
1908MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
1909MODULE_LICENSE("GPL");
1910MODULE_ALIAS("platform:" DRIVER_NAME);
1911MODULE_AUTHOR("Texas Instruments Inc");