blob: 20746e4f00b3ff793bad94f6193f4adffe5b4a84 [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
Denis Karpov70a33412009-09-22 16:44:59 -0700138struct omap_hsmmc_host {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100139 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;
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700151 spinlock_t irq_lock; /* Prevent races with irq handler */
152 unsigned long flags;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100153 unsigned int id;
154 unsigned int dma_len;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200155 unsigned int dma_sg_idx;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100156 unsigned char bus_mode;
Adrian Huntera3621462009-09-22 16:44:42 -0700157 unsigned char power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100158 u32 *buffer;
159 u32 bytesleft;
160 int suspended;
161 int irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100162 int use_dma, dma_ch;
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +0000163 int dma_line_tx, dma_line_rx;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100164 int slot_id;
165 int dbclk_enabled;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200166 int response_busy;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700167 int context_loss;
Denis Karpovdd498ef2009-09-22 16:44:49 -0700168 int dpm_state;
Adrian Hunter623821f2009-09-22 16:44:51 -0700169 int vdd;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700170
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100171 struct omap_mmc_platform_data *pdata;
172};
173
174/*
175 * Stop clock to the card
176 */
Denis Karpov70a33412009-09-22 16:44:59 -0700177static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100178{
179 OMAP_HSMMC_WRITE(host->base, SYSCTL,
180 OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
181 if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
182 dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
183}
184
Denis Karpov11dd62a2009-09-22 16:44:43 -0700185#ifdef CONFIG_PM
186
187/*
188 * Restore the MMC host context, if it was lost as result of a
189 * power state change.
190 */
Denis Karpov70a33412009-09-22 16:44:59 -0700191static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700192{
193 struct mmc_ios *ios = &host->mmc->ios;
194 struct omap_mmc_platform_data *pdata = host->pdata;
195 int context_loss = 0;
196 u32 hctl, capa, con;
197 u16 dsor = 0;
198 unsigned long timeout;
199
200 if (pdata->get_context_loss_count) {
201 context_loss = pdata->get_context_loss_count(host->dev);
202 if (context_loss < 0)
203 return 1;
204 }
205
206 dev_dbg(mmc_dev(host->mmc), "context was %slost\n",
207 context_loss == host->context_loss ? "not " : "");
208 if (host->context_loss == context_loss)
209 return 1;
210
211 /* Wait for hardware reset */
212 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
213 while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
214 && time_before(jiffies, timeout))
215 ;
216
217 /* Do software reset */
218 OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET);
219 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
220 while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
221 && time_before(jiffies, timeout))
222 ;
223
224 OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
225 OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
226
227 if (host->id == OMAP_MMC1_DEVID) {
228 if (host->power_mode != MMC_POWER_OFF &&
229 (1 << ios->vdd) <= MMC_VDD_23_24)
230 hctl = SDVS18;
231 else
232 hctl = SDVS30;
233 capa = VS30 | VS18;
234 } else {
235 hctl = SDVS18;
236 capa = VS18;
237 }
238
239 OMAP_HSMMC_WRITE(host->base, HCTL,
240 OMAP_HSMMC_READ(host->base, HCTL) | hctl);
241
242 OMAP_HSMMC_WRITE(host->base, CAPA,
243 OMAP_HSMMC_READ(host->base, CAPA) | capa);
244
245 OMAP_HSMMC_WRITE(host->base, HCTL,
246 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
247
248 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
249 while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP
250 && time_before(jiffies, timeout))
251 ;
252
253 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
254 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
255 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
256
257 /* Do not initialize card-specific things if the power is off */
258 if (host->power_mode == MMC_POWER_OFF)
259 goto out;
260
261 con = OMAP_HSMMC_READ(host->base, CON);
262 switch (ios->bus_width) {
263 case MMC_BUS_WIDTH_8:
264 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
265 break;
266 case MMC_BUS_WIDTH_4:
267 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
268 OMAP_HSMMC_WRITE(host->base, HCTL,
269 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
270 break;
271 case MMC_BUS_WIDTH_1:
272 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
273 OMAP_HSMMC_WRITE(host->base, HCTL,
274 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
275 break;
276 }
277
278 if (ios->clock) {
279 dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
280 if (dsor < 1)
281 dsor = 1;
282
283 if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
284 dsor++;
285
286 if (dsor > 250)
287 dsor = 250;
288 }
289
290 OMAP_HSMMC_WRITE(host->base, SYSCTL,
291 OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
292 OMAP_HSMMC_WRITE(host->base, SYSCTL, (dsor << 6) | (DTO << 16));
293 OMAP_HSMMC_WRITE(host->base, SYSCTL,
294 OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
295
296 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
297 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
298 && time_before(jiffies, timeout))
299 ;
300
301 OMAP_HSMMC_WRITE(host->base, SYSCTL,
302 OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
303
304 con = OMAP_HSMMC_READ(host->base, CON);
305 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
306 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
307 else
308 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
309out:
310 host->context_loss = context_loss;
311
312 dev_dbg(mmc_dev(host->mmc), "context is restored\n");
313 return 0;
314}
315
316/*
317 * Save the MMC host context (store the number of power state changes so far).
318 */
Denis Karpov70a33412009-09-22 16:44:59 -0700319static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700320{
321 struct omap_mmc_platform_data *pdata = host->pdata;
322 int context_loss;
323
324 if (pdata->get_context_loss_count) {
325 context_loss = pdata->get_context_loss_count(host->dev);
326 if (context_loss < 0)
327 return;
328 host->context_loss = context_loss;
329 }
330}
331
332#else
333
Denis Karpov70a33412009-09-22 16:44:59 -0700334static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700335{
336 return 0;
337}
338
Denis Karpov70a33412009-09-22 16:44:59 -0700339static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700340{
341}
342
343#endif
344
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100345/*
346 * Send init stream sequence to card
347 * before sending IDLE command
348 */
Denis Karpov70a33412009-09-22 16:44:59 -0700349static void send_init_stream(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100350{
351 int reg = 0;
352 unsigned long timeout;
353
354 disable_irq(host->irq);
355 OMAP_HSMMC_WRITE(host->base, CON,
356 OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
357 OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
358
359 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
360 while ((reg != CC) && time_before(jiffies, timeout))
361 reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
362
363 OMAP_HSMMC_WRITE(host->base, CON,
364 OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
Adrian Hunterc653a6d2009-09-22 16:44:56 -0700365
366 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
367 OMAP_HSMMC_READ(host->base, STAT);
368
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100369 enable_irq(host->irq);
370}
371
372static inline
Denis Karpov70a33412009-09-22 16:44:59 -0700373int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100374{
375 int r = 1;
376
Denis Karpov191d1f12009-09-22 16:44:55 -0700377 if (mmc_slot(host).get_cover_state)
378 r = mmc_slot(host).get_cover_state(host->dev, host->slot_id);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100379 return r;
380}
381
382static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700383omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100384 char *buf)
385{
386 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700387 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100388
Denis Karpov70a33412009-09-22 16:44:59 -0700389 return sprintf(buf, "%s\n",
390 omap_hsmmc_cover_is_closed(host) ? "closed" : "open");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100391}
392
Denis Karpov70a33412009-09-22 16:44:59 -0700393static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100394
395static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700396omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100397 char *buf)
398{
399 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700400 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100401
Denis Karpov191d1f12009-09-22 16:44:55 -0700402 return sprintf(buf, "%s\n", mmc_slot(host).name);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100403}
404
Denis Karpov70a33412009-09-22 16:44:59 -0700405static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100406
407/*
408 * Configure the response type and send the cmd.
409 */
410static void
Denis Karpov70a33412009-09-22 16:44:59 -0700411omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100412 struct mmc_data *data)
413{
414 int cmdreg = 0, resptype = 0, cmdtype = 0;
415
416 dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
417 mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
418 host->cmd = cmd;
419
420 /*
421 * Clear status bits and enable interrupts
422 */
423 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
424 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
Anand Gadiyarccdfe3a2009-09-22 16:44:21 -0700425
426 if (host->use_dma)
427 OMAP_HSMMC_WRITE(host->base, IE,
428 INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
429 else
430 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100431
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200432 host->response_busy = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100433 if (cmd->flags & MMC_RSP_PRESENT) {
434 if (cmd->flags & MMC_RSP_136)
435 resptype = 1;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200436 else if (cmd->flags & MMC_RSP_BUSY) {
437 resptype = 3;
438 host->response_busy = 1;
439 } else
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100440 resptype = 2;
441 }
442
443 /*
444 * Unlike OMAP1 controller, the cmdtype does not seem to be based on
445 * ac, bc, adtc, bcr. Only commands ending an open ended transfer need
446 * a val of 0x3, rest 0x0.
447 */
448 if (cmd == host->mrq->stop)
449 cmdtype = 0x3;
450
451 cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
452
453 if (data) {
454 cmdreg |= DP_SELECT | MSBS | BCE;
455 if (data->flags & MMC_DATA_READ)
456 cmdreg |= DDIR;
457 else
458 cmdreg &= ~(DDIR);
459 }
460
461 if (host->use_dma)
462 cmdreg |= DMA_EN;
463
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700464 /*
465 * In an interrupt context (i.e. STOP command), the spinlock is unlocked
466 * by the interrupt handler, otherwise (i.e. for a new request) it is
467 * unlocked here.
468 */
469 if (!in_interrupt())
470 spin_unlock_irqrestore(&host->irq_lock, host->flags);
471
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100472 OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
473 OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
474}
475
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200476static int
Denis Karpov70a33412009-09-22 16:44:59 -0700477omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200478{
479 if (data->flags & MMC_DATA_WRITE)
480 return DMA_TO_DEVICE;
481 else
482 return DMA_FROM_DEVICE;
483}
484
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100485/*
486 * Notify the transfer complete to MMC core
487 */
488static void
Denis Karpov70a33412009-09-22 16:44:59 -0700489omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100490{
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200491 if (!data) {
492 struct mmc_request *mrq = host->mrq;
493
Adrian Hunter23050102009-09-22 16:44:57 -0700494 /* TC before CC from CMD6 - don't know why, but it happens */
495 if (host->cmd && host->cmd->opcode == 6 &&
496 host->response_busy) {
497 host->response_busy = 0;
498 return;
499 }
500
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200501 host->mrq = NULL;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200502 mmc_request_done(host->mmc, mrq);
503 return;
504 }
505
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100506 host->data = NULL;
507
508 if (host->use_dma && host->dma_ch != -1)
509 dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
Denis Karpov70a33412009-09-22 16:44:59 -0700510 omap_hsmmc_get_dma_dir(host, data));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100511
512 if (!data->error)
513 data->bytes_xfered += data->blocks * (data->blksz);
514 else
515 data->bytes_xfered = 0;
516
517 if (!data->stop) {
518 host->mrq = NULL;
519 mmc_request_done(host->mmc, data->mrq);
520 return;
521 }
Denis Karpov70a33412009-09-22 16:44:59 -0700522 omap_hsmmc_start_command(host, data->stop, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100523}
524
525/*
526 * Notify the core about command completion
527 */
528static void
Denis Karpov70a33412009-09-22 16:44:59 -0700529omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100530{
531 host->cmd = NULL;
532
533 if (cmd->flags & MMC_RSP_PRESENT) {
534 if (cmd->flags & MMC_RSP_136) {
535 /* response type 2 */
536 cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
537 cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
538 cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
539 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
540 } else {
541 /* response types 1, 1b, 3, 4, 5, 6 */
542 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
543 }
544 }
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200545 if ((host->data == NULL && !host->response_busy) || cmd->error) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100546 host->mrq = NULL;
547 mmc_request_done(host->mmc, cmd->mrq);
548 }
549}
550
551/*
552 * DMA clean up for command errors
553 */
Denis Karpov70a33412009-09-22 16:44:59 -0700554static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100555{
Jarkko Lavinen82788ff2008-12-05 12:31:46 +0200556 host->data->error = errno;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100557
558 if (host->use_dma && host->dma_ch != -1) {
559 dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
Denis Karpov70a33412009-09-22 16:44:59 -0700560 omap_hsmmc_get_dma_dir(host, host->data));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100561 omap_free_dma(host->dma_ch);
562 host->dma_ch = -1;
563 up(&host->sem);
564 }
565 host->data = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100566}
567
568/*
569 * Readable error output
570 */
571#ifdef CONFIG_MMC_DEBUG
Denis Karpov70a33412009-09-22 16:44:59 -0700572static void omap_hsmmc_report_irq(struct omap_hsmmc_host *host, u32 status)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100573{
574 /* --- means reserved bit without definition at documentation */
Denis Karpov70a33412009-09-22 16:44:59 -0700575 static const char *omap_hsmmc_status_bits[] = {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100576 "CC", "TC", "BGE", "---", "BWR", "BRR", "---", "---", "CIRQ",
577 "OBI", "---", "---", "---", "---", "---", "ERRI", "CTO", "CCRC",
578 "CEB", "CIE", "DTO", "DCRC", "DEB", "---", "ACE", "---",
579 "---", "---", "---", "CERR", "CERR", "BADA", "---", "---", "---"
580 };
581 char res[256];
582 char *buf = res;
583 int len, i;
584
585 len = sprintf(buf, "MMC IRQ 0x%x :", status);
586 buf += len;
587
Denis Karpov70a33412009-09-22 16:44:59 -0700588 for (i = 0; i < ARRAY_SIZE(omap_hsmmc_status_bits); i++)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100589 if (status & (1 << i)) {
Denis Karpov70a33412009-09-22 16:44:59 -0700590 len = sprintf(buf, " %s", omap_hsmmc_status_bits[i]);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100591 buf += len;
592 }
593
594 dev_dbg(mmc_dev(host->mmc), "%s\n", res);
595}
596#endif /* CONFIG_MMC_DEBUG */
597
Jean Pihet3ebf74b2009-02-06 16:42:51 +0100598/*
599 * MMC controller internal state machines reset
600 *
601 * Used to reset command or data internal state machines, using respectively
602 * SRC or SRD bit of SYSCTL register
603 * Can be called from interrupt context
604 */
Denis Karpov70a33412009-09-22 16:44:59 -0700605static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
606 unsigned long bit)
Jean Pihet3ebf74b2009-02-06 16:42:51 +0100607{
608 unsigned long i = 0;
609 unsigned long limit = (loops_per_jiffy *
610 msecs_to_jiffies(MMC_TIMEOUT_MS));
611
612 OMAP_HSMMC_WRITE(host->base, SYSCTL,
613 OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
614
615 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
616 (i++ < limit))
617 cpu_relax();
618
619 if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
620 dev_err(mmc_dev(host->mmc),
621 "Timeout waiting on controller reset in %s\n",
622 __func__);
623}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100624
625/*
626 * MMC controller IRQ handler
627 */
Denis Karpov70a33412009-09-22 16:44:59 -0700628static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100629{
Denis Karpov70a33412009-09-22 16:44:59 -0700630 struct omap_hsmmc_host *host = dev_id;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100631 struct mmc_data *data;
632 int end_cmd = 0, end_trans = 0, status;
633
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700634 spin_lock(&host->irq_lock);
635
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200636 if (host->mrq == NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100637 OMAP_HSMMC_WRITE(host->base, STAT,
638 OMAP_HSMMC_READ(host->base, STAT));
Kevin Hilman00adadc2009-04-06 15:01:19 +0300639 /* Flush posted write */
640 OMAP_HSMMC_READ(host->base, STAT);
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700641 spin_unlock(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100642 return IRQ_HANDLED;
643 }
644
645 data = host->data;
646 status = OMAP_HSMMC_READ(host->base, STAT);
647 dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
648
649 if (status & ERR) {
650#ifdef CONFIG_MMC_DEBUG
Denis Karpov70a33412009-09-22 16:44:59 -0700651 omap_hsmmc_report_irq(host, status);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100652#endif
653 if ((status & CMD_TIMEOUT) ||
654 (status & CMD_CRC)) {
655 if (host->cmd) {
656 if (status & CMD_TIMEOUT) {
Denis Karpov70a33412009-09-22 16:44:59 -0700657 omap_hsmmc_reset_controller_fsm(host,
658 SRC);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100659 host->cmd->error = -ETIMEDOUT;
660 } else {
661 host->cmd->error = -EILSEQ;
662 }
663 end_cmd = 1;
664 }
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200665 if (host->data || host->response_busy) {
666 if (host->data)
Denis Karpov70a33412009-09-22 16:44:59 -0700667 omap_hsmmc_dma_cleanup(host,
668 -ETIMEDOUT);
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200669 host->response_busy = 0;
Denis Karpov70a33412009-09-22 16:44:59 -0700670 omap_hsmmc_reset_controller_fsm(host, SRD);
Jean Pihetc232f452009-02-11 13:11:39 -0800671 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100672 }
673 if ((status & DATA_TIMEOUT) ||
674 (status & DATA_CRC)) {
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200675 if (host->data || host->response_busy) {
676 int err = (status & DATA_TIMEOUT) ?
677 -ETIMEDOUT : -EILSEQ;
678
679 if (host->data)
Denis Karpov70a33412009-09-22 16:44:59 -0700680 omap_hsmmc_dma_cleanup(host, err);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100681 else
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200682 host->mrq->cmd->error = err;
683 host->response_busy = 0;
Denis Karpov70a33412009-09-22 16:44:59 -0700684 omap_hsmmc_reset_controller_fsm(host, SRD);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100685 end_trans = 1;
686 }
687 }
688 if (status & CARD_ERR) {
689 dev_dbg(mmc_dev(host->mmc),
690 "Ignoring card err CMD%d\n", host->cmd->opcode);
691 if (host->cmd)
692 end_cmd = 1;
693 if (host->data)
694 end_trans = 1;
695 }
696 }
697
698 OMAP_HSMMC_WRITE(host->base, STAT, status);
Kevin Hilman00adadc2009-04-06 15:01:19 +0300699 /* Flush posted write */
700 OMAP_HSMMC_READ(host->base, STAT);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100701
Jarkko Lavinena8fe29d2009-04-08 11:18:32 +0300702 if (end_cmd || ((status & CC) && host->cmd))
Denis Karpov70a33412009-09-22 16:44:59 -0700703 omap_hsmmc_cmd_done(host, host->cmd);
Jarkko Lavinen0a40e642009-09-22 16:44:54 -0700704 if ((end_trans || (status & TC)) && host->mrq)
Denis Karpov70a33412009-09-22 16:44:59 -0700705 omap_hsmmc_xfer_done(host, data);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100706
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700707 spin_unlock(&host->irq_lock);
708
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100709 return IRQ_HANDLED;
710}
711
Denis Karpov70a33412009-09-22 16:44:59 -0700712static void set_sd_bus_power(struct omap_hsmmc_host *host)
Adrian Huntere13bb302009-03-12 17:08:26 +0200713{
714 unsigned long i;
715
716 OMAP_HSMMC_WRITE(host->base, HCTL,
717 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
718 for (i = 0; i < loops_per_jiffy; i++) {
719 if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
720 break;
721 cpu_relax();
722 }
723}
724
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100725/*
David Brownelleb250822009-02-17 14:49:01 -0800726 * Switch MMC interface voltage ... only relevant for MMC1.
727 *
728 * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
729 * The MMC2 transceiver controls are used instead of DAT4..DAT7.
730 * Some chips, like eMMC ones, use internal transceivers.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100731 */
Denis Karpov70a33412009-09-22 16:44:59 -0700732static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100733{
734 u32 reg_val = 0;
735 int ret;
736
737 /* Disable the clocks */
738 clk_disable(host->fclk);
739 clk_disable(host->iclk);
740 clk_disable(host->dbclk);
741
742 /* Turn the power off */
743 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
744 if (ret != 0)
745 goto err;
746
747 /* Turn the power ON with given VDD 1.8 or 3.0v */
748 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd);
749 if (ret != 0)
750 goto err;
751
752 clk_enable(host->fclk);
753 clk_enable(host->iclk);
754 clk_enable(host->dbclk);
755
756 OMAP_HSMMC_WRITE(host->base, HCTL,
757 OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
758 reg_val = OMAP_HSMMC_READ(host->base, HCTL);
David Brownelleb250822009-02-17 14:49:01 -0800759
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100760 /*
761 * If a MMC dual voltage card is detected, the set_ios fn calls
762 * this fn with VDD bit set for 1.8V. Upon card removal from the
Denis Karpov70a33412009-09-22 16:44:59 -0700763 * slot, omap_hsmmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100764 *
David Brownelleb250822009-02-17 14:49:01 -0800765 * Cope with a bit of slop in the range ... per data sheets:
766 * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
767 * but recommended values are 1.71V to 1.89V
768 * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
769 * but recommended values are 2.7V to 3.3V
770 *
771 * Board setup code shouldn't permit anything very out-of-range.
772 * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
773 * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100774 */
David Brownelleb250822009-02-17 14:49:01 -0800775 if ((1 << vdd) <= MMC_VDD_23_24)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100776 reg_val |= SDVS18;
David Brownelleb250822009-02-17 14:49:01 -0800777 else
778 reg_val |= SDVS30;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100779
780 OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
Adrian Huntere13bb302009-03-12 17:08:26 +0200781 set_sd_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100782
783 return 0;
784err:
785 dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
786 return ret;
787}
788
789/*
790 * Work Item to notify the core about card insertion/removal
791 */
Denis Karpov70a33412009-09-22 16:44:59 -0700792static void omap_hsmmc_detect(struct work_struct *work)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100793{
Denis Karpov70a33412009-09-22 16:44:59 -0700794 struct omap_hsmmc_host *host =
795 container_of(work, struct omap_hsmmc_host, mmc_carddetect_work);
David Brownell249d0fa2009-02-04 14:42:03 -0800796 struct omap_mmc_slot_data *slot = &mmc_slot(host);
Adrian Huntera6b22402009-09-22 16:44:45 -0700797 int carddetect;
David Brownell249d0fa2009-02-04 14:42:03 -0800798
Adrian Huntera6b22402009-09-22 16:44:45 -0700799 if (host->suspended)
800 return;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100801
802 sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
Adrian Huntera6b22402009-09-22 16:44:45 -0700803
Denis Karpov191d1f12009-09-22 16:44:55 -0700804 if (slot->card_detect)
Adrian Huntera6b22402009-09-22 16:44:45 -0700805 carddetect = slot->card_detect(slot->card_detect_irq);
806 else
807 carddetect = -ENOSYS;
808
809 if (carddetect) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100810 mmc_detect_change(host->mmc, (HZ * 200) / 1000);
811 } else {
Adrian Hunter5e2ea612009-09-22 16:44:39 -0700812 mmc_host_enable(host->mmc);
Denis Karpov70a33412009-09-22 16:44:59 -0700813 omap_hsmmc_reset_controller_fsm(host, SRD);
Adrian Hunter5e2ea612009-09-22 16:44:39 -0700814 mmc_host_lazy_disable(host->mmc);
Denis Karpov70a33412009-09-22 16:44:59 -0700815
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100816 mmc_detect_change(host->mmc, (HZ * 50) / 1000);
817 }
818}
819
820/*
821 * ISR for handling card insertion and removal
822 */
Denis Karpov70a33412009-09-22 16:44:59 -0700823static irqreturn_t omap_hsmmc_cd_handler(int irq, void *dev_id)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100824{
Denis Karpov70a33412009-09-22 16:44:59 -0700825 struct omap_hsmmc_host *host = (struct omap_hsmmc_host *)dev_id;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100826
Adrian Huntera6b22402009-09-22 16:44:45 -0700827 if (host->suspended)
828 return IRQ_HANDLED;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100829 schedule_work(&host->mmc_carddetect_work);
830
831 return IRQ_HANDLED;
832}
833
Denis Karpov70a33412009-09-22 16:44:59 -0700834static int omap_hsmmc_get_dma_sync_dev(struct omap_hsmmc_host *host,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200835 struct mmc_data *data)
836{
837 int sync_dev;
838
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +0000839 if (data->flags & MMC_DATA_WRITE)
840 sync_dev = host->dma_line_tx;
841 else
842 sync_dev = host->dma_line_rx;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200843 return sync_dev;
844}
845
Denis Karpov70a33412009-09-22 16:44:59 -0700846static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200847 struct mmc_data *data,
848 struct scatterlist *sgl)
849{
850 int blksz, nblk, dma_ch;
851
852 dma_ch = host->dma_ch;
853 if (data->flags & MMC_DATA_WRITE) {
854 omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
855 (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
856 omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
857 sg_dma_address(sgl), 0, 0);
858 } else {
859 omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
Denis Karpov191d1f12009-09-22 16:44:55 -0700860 (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200861 omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
862 sg_dma_address(sgl), 0, 0);
863 }
864
865 blksz = host->data->blksz;
866 nblk = sg_dma_len(sgl) / blksz;
867
868 omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32,
869 blksz / 4, nblk, OMAP_DMA_SYNC_FRAME,
Denis Karpov70a33412009-09-22 16:44:59 -0700870 omap_hsmmc_get_dma_sync_dev(host, data),
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200871 !(data->flags & MMC_DATA_WRITE));
872
873 omap_start_dma(dma_ch);
874}
875
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100876/*
877 * DMA call back function
878 */
Denis Karpov70a33412009-09-22 16:44:59 -0700879static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100880{
Denis Karpov70a33412009-09-22 16:44:59 -0700881 struct omap_hsmmc_host *host = data;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100882
883 if (ch_status & OMAP2_DMA_MISALIGNED_ERR_IRQ)
884 dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n");
885
886 if (host->dma_ch < 0)
887 return;
888
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200889 host->dma_sg_idx++;
890 if (host->dma_sg_idx < host->dma_len) {
891 /* Fire up the next transfer. */
Denis Karpov70a33412009-09-22 16:44:59 -0700892 omap_hsmmc_config_dma_params(host, host->data,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200893 host->data->sg + host->dma_sg_idx);
894 return;
895 }
896
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100897 omap_free_dma(host->dma_ch);
898 host->dma_ch = -1;
899 /*
900 * DMA Callback: run in interrupt context.
Anand Gadiyar85b84322009-04-15 17:44:58 +0530901 * mutex_unlock will throw a kernel warning if used.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100902 */
903 up(&host->sem);
904}
905
906/*
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100907 * Routine to configure and start DMA for the MMC card
908 */
Denis Karpov70a33412009-09-22 16:44:59 -0700909static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
910 struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100911{
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200912 int dma_ch = 0, ret = 0, err = 1, i;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100913 struct mmc_data *data = req->data;
914
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200915 /* Sanity check: all the SG entries must be aligned by block size. */
Jarkko Lavinena3f406f2009-09-22 16:44:46 -0700916 for (i = 0; i < data->sg_len; i++) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200917 struct scatterlist *sgl;
918
919 sgl = data->sg + i;
920 if (sgl->length % data->blksz)
921 return -EINVAL;
922 }
923 if ((data->blksz % 4) != 0)
924 /* REVISIT: The MMC buffer increments only when MSB is written.
925 * Return error for blksz which is non multiple of four.
926 */
927 return -EINVAL;
928
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100929 /*
930 * If for some reason the DMA transfer is still active,
931 * we wait for timeout period and free the dma
932 */
933 if (host->dma_ch != -1) {
934 set_current_state(TASK_UNINTERRUPTIBLE);
935 schedule_timeout(100);
936 if (down_trylock(&host->sem)) {
937 omap_free_dma(host->dma_ch);
938 host->dma_ch = -1;
939 up(&host->sem);
940 return err;
941 }
942 } else {
943 if (down_trylock(&host->sem))
944 return err;
945 }
946
Denis Karpov70a33412009-09-22 16:44:59 -0700947 ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data),
948 "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100949 if (ret != 0) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200950 dev_err(mmc_dev(host->mmc),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100951 "%s: omap_request_dma() failed with %d\n",
952 mmc_hostname(host->mmc), ret);
953 return ret;
954 }
955
956 host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
Denis Karpov70a33412009-09-22 16:44:59 -0700957 data->sg_len, omap_hsmmc_get_dma_dir(host, data));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100958 host->dma_ch = dma_ch;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200959 host->dma_sg_idx = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100960
Denis Karpov70a33412009-09-22 16:44:59 -0700961 omap_hsmmc_config_dma_params(host, data, data->sg);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100962
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100963 return 0;
964}
965
Denis Karpov70a33412009-09-22 16:44:59 -0700966static void set_data_timeout(struct omap_hsmmc_host *host,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100967 struct mmc_request *req)
968{
969 unsigned int timeout, cycle_ns;
970 uint32_t reg, clkd, dto = 0;
971
972 reg = OMAP_HSMMC_READ(host->base, SYSCTL);
973 clkd = (reg & CLKD_MASK) >> CLKD_SHIFT;
974 if (clkd == 0)
975 clkd = 1;
976
977 cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
978 timeout = req->data->timeout_ns / cycle_ns;
979 timeout += req->data->timeout_clks;
980 if (timeout) {
981 while ((timeout & 0x80000000) == 0) {
982 dto += 1;
983 timeout <<= 1;
984 }
985 dto = 31 - dto;
986 timeout <<= 1;
987 if (timeout && dto)
988 dto += 1;
989 if (dto >= 13)
990 dto -= 13;
991 else
992 dto = 0;
993 if (dto > 14)
994 dto = 14;
995 }
996
997 reg &= ~DTO_MASK;
998 reg |= dto << DTO_SHIFT;
999 OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
1000}
1001
1002/*
1003 * Configure block length for MMC/SD cards and initiate the transfer.
1004 */
1005static int
Denis Karpov70a33412009-09-22 16:44:59 -07001006omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001007{
1008 int ret;
1009 host->data = req->data;
1010
1011 if (req->data == NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001012 OMAP_HSMMC_WRITE(host->base, BLK, 0);
1013 return 0;
1014 }
1015
1016 OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
1017 | (req->data->blocks << 16));
1018 set_data_timeout(host, req);
1019
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001020 if (host->use_dma) {
Denis Karpov70a33412009-09-22 16:44:59 -07001021 ret = omap_hsmmc_start_dma_transfer(host, req);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001022 if (ret != 0) {
1023 dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
1024 return ret;
1025 }
1026 }
1027 return 0;
1028}
1029
1030/*
1031 * Request function. for read/write operation
1032 */
Denis Karpov70a33412009-09-22 16:44:59 -07001033static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001034{
Denis Karpov70a33412009-09-22 16:44:59 -07001035 struct omap_hsmmc_host *host = mmc_priv(mmc);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001036 int err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001037
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001038 /*
1039 * Prevent races with the interrupt handler because of unexpected
1040 * interrupts, but not if we are already in interrupt context i.e.
1041 * retries.
1042 */
1043 if (!in_interrupt())
1044 spin_lock_irqsave(&host->irq_lock, host->flags);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001045 WARN_ON(host->mrq != NULL);
1046 host->mrq = req;
Denis Karpov70a33412009-09-22 16:44:59 -07001047 err = omap_hsmmc_prepare_data(host, req);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001048 if (err) {
1049 req->cmd->error = err;
1050 if (req->data)
1051 req->data->error = err;
1052 host->mrq = NULL;
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001053 if (!in_interrupt())
1054 spin_unlock_irqrestore(&host->irq_lock, host->flags);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001055 mmc_request_done(mmc, req);
1056 return;
1057 }
1058
Denis Karpov70a33412009-09-22 16:44:59 -07001059 omap_hsmmc_start_command(host, req->cmd, req->data);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001060}
1061
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001062/* Routine to configure clock values. Exposed API to core */
Denis Karpov70a33412009-09-22 16:44:59 -07001063static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001064{
Denis Karpov70a33412009-09-22 16:44:59 -07001065 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001066 u16 dsor = 0;
1067 unsigned long regval;
1068 unsigned long timeout;
Jarkko Lavinen73153012008-11-21 16:49:54 +02001069 u32 con;
Adrian Huntera3621462009-09-22 16:44:42 -07001070 int do_send_init_stream = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001071
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001072 mmc_host_enable(host->mmc);
1073
Adrian Huntera3621462009-09-22 16:44:42 -07001074 if (ios->power_mode != host->power_mode) {
1075 switch (ios->power_mode) {
1076 case MMC_POWER_OFF:
1077 mmc_slot(host).set_power(host->dev, host->slot_id,
1078 0, 0);
Adrian Hunter623821f2009-09-22 16:44:51 -07001079 host->vdd = 0;
Adrian Huntera3621462009-09-22 16:44:42 -07001080 break;
1081 case MMC_POWER_UP:
1082 mmc_slot(host).set_power(host->dev, host->slot_id,
1083 1, ios->vdd);
Adrian Hunter623821f2009-09-22 16:44:51 -07001084 host->vdd = ios->vdd;
Adrian Huntera3621462009-09-22 16:44:42 -07001085 break;
1086 case MMC_POWER_ON:
1087 do_send_init_stream = 1;
1088 break;
1089 }
1090 host->power_mode = ios->power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001091 }
1092
Denis Karpovdd498ef2009-09-22 16:44:49 -07001093 /* FIXME: set registers based only on changes to ios */
1094
Jarkko Lavinen73153012008-11-21 16:49:54 +02001095 con = OMAP_HSMMC_READ(host->base, CON);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001096 switch (mmc->ios.bus_width) {
Jarkko Lavinen73153012008-11-21 16:49:54 +02001097 case MMC_BUS_WIDTH_8:
1098 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
1099 break;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001100 case MMC_BUS_WIDTH_4:
Jarkko Lavinen73153012008-11-21 16:49:54 +02001101 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001102 OMAP_HSMMC_WRITE(host->base, HCTL,
1103 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
1104 break;
1105 case MMC_BUS_WIDTH_1:
Jarkko Lavinen73153012008-11-21 16:49:54 +02001106 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001107 OMAP_HSMMC_WRITE(host->base, HCTL,
1108 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
1109 break;
1110 }
1111
1112 if (host->id == OMAP_MMC1_DEVID) {
David Brownelleb250822009-02-17 14:49:01 -08001113 /* Only MMC1 can interface at 3V without some flavor
1114 * of external transceiver; but they all handle 1.8V.
1115 */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001116 if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
1117 (ios->vdd == DUAL_VOLT_OCR_BIT)) {
1118 /*
1119 * The mmc_select_voltage fn of the core does
1120 * not seem to set the power_mode to
1121 * MMC_POWER_UP upon recalculating the voltage.
1122 * vdd 1.8v.
1123 */
Denis Karpov70a33412009-09-22 16:44:59 -07001124 if (omap_hsmmc_switch_opcond(host, ios->vdd) != 0)
1125 dev_dbg(mmc_dev(host->mmc),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001126 "Switch operation failed\n");
1127 }
1128 }
1129
1130 if (ios->clock) {
1131 dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
1132 if (dsor < 1)
1133 dsor = 1;
1134
1135 if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
1136 dsor++;
1137
1138 if (dsor > 250)
1139 dsor = 250;
1140 }
Denis Karpov70a33412009-09-22 16:44:59 -07001141 omap_hsmmc_stop_clock(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001142 regval = OMAP_HSMMC_READ(host->base, SYSCTL);
1143 regval = regval & ~(CLKD_MASK);
1144 regval = regval | (dsor << 6) | (DTO << 16);
1145 OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
1146 OMAP_HSMMC_WRITE(host->base, SYSCTL,
1147 OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
1148
1149 /* Wait till the ICS bit is set */
1150 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001151 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001152 && time_before(jiffies, timeout))
1153 msleep(1);
1154
1155 OMAP_HSMMC_WRITE(host->base, SYSCTL,
1156 OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
1157
Adrian Huntera3621462009-09-22 16:44:42 -07001158 if (do_send_init_stream)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001159 send_init_stream(host);
1160
Denis Karpovabb28e72009-09-22 16:44:44 -07001161 con = OMAP_HSMMC_READ(host->base, CON);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001162 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
Denis Karpovabb28e72009-09-22 16:44:44 -07001163 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
1164 else
1165 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001166
Denis Karpovdd498ef2009-09-22 16:44:49 -07001167 if (host->power_mode == MMC_POWER_OFF)
1168 mmc_host_disable(host->mmc);
1169 else
1170 mmc_host_lazy_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001171}
1172
1173static int omap_hsmmc_get_cd(struct mmc_host *mmc)
1174{
Denis Karpov70a33412009-09-22 16:44:59 -07001175 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001176
Denis Karpov191d1f12009-09-22 16:44:55 -07001177 if (!mmc_slot(host).card_detect)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001178 return -ENOSYS;
Denis Karpov191d1f12009-09-22 16:44:55 -07001179 return mmc_slot(host).card_detect(mmc_slot(host).card_detect_irq);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001180}
1181
1182static int omap_hsmmc_get_ro(struct mmc_host *mmc)
1183{
Denis Karpov70a33412009-09-22 16:44:59 -07001184 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001185
Denis Karpov191d1f12009-09-22 16:44:55 -07001186 if (!mmc_slot(host).get_ro)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001187 return -ENOSYS;
Denis Karpov191d1f12009-09-22 16:44:55 -07001188 return mmc_slot(host).get_ro(host->dev, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001189}
1190
Denis Karpov70a33412009-09-22 16:44:59 -07001191static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001192{
1193 u32 hctl, capa, value;
1194
1195 /* Only MMC1 supports 3.0V */
1196 if (host->id == OMAP_MMC1_DEVID) {
1197 hctl = SDVS30;
1198 capa = VS30 | VS18;
1199 } else {
1200 hctl = SDVS18;
1201 capa = VS18;
1202 }
1203
1204 value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
1205 OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
1206
1207 value = OMAP_HSMMC_READ(host->base, CAPA);
1208 OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
1209
1210 /* Set the controller to AUTO IDLE mode */
1211 value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
1212 OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
1213
1214 /* Set SD bus power bit */
Adrian Huntere13bb302009-03-12 17:08:26 +02001215 set_sd_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001216}
1217
Denis Karpovdd498ef2009-09-22 16:44:49 -07001218/*
1219 * Dynamic power saving handling, FSM:
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001220 * ENABLED -> DISABLED -> CARDSLEEP / REGSLEEP -> OFF
1221 * ^___________| | |
1222 * |______________________|______________________|
Denis Karpovdd498ef2009-09-22 16:44:49 -07001223 *
1224 * ENABLED: mmc host is fully functional
1225 * DISABLED: fclk is off
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001226 * CARDSLEEP: fclk is off, card is asleep, voltage regulator is asleep
1227 * REGSLEEP: fclk is off, voltage regulator is asleep
1228 * OFF: fclk is off, voltage regulator is off
Denis Karpovdd498ef2009-09-22 16:44:49 -07001229 *
1230 * Transition handlers return the timeout for the next state transition
1231 * or negative error.
1232 */
1233
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001234enum {ENABLED = 0, DISABLED, CARDSLEEP, REGSLEEP, OFF};
Denis Karpovdd498ef2009-09-22 16:44:49 -07001235
1236/* Handler for [ENABLED -> DISABLED] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001237static int omap_hsmmc_enabled_to_disabled(struct omap_hsmmc_host *host)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001238{
Denis Karpov70a33412009-09-22 16:44:59 -07001239 omap_hsmmc_context_save(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001240 clk_disable(host->fclk);
1241 host->dpm_state = DISABLED;
1242
1243 dev_dbg(mmc_dev(host->mmc), "ENABLED -> DISABLED\n");
1244
1245 if (host->power_mode == MMC_POWER_OFF)
1246 return 0;
1247
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001248 return msecs_to_jiffies(OMAP_MMC_SLEEP_TIMEOUT);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001249}
1250
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001251/* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001252static int omap_hsmmc_disabled_to_sleep(struct omap_hsmmc_host *host)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001253{
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001254 int err, new_state;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001255
1256 if (!mmc_try_claim_host(host->mmc))
1257 return 0;
1258
1259 clk_enable(host->fclk);
Denis Karpov70a33412009-09-22 16:44:59 -07001260 omap_hsmmc_context_restore(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001261 if (mmc_card_can_sleep(host->mmc)) {
1262 err = mmc_card_sleep(host->mmc);
1263 if (err < 0) {
1264 clk_disable(host->fclk);
1265 mmc_release_host(host->mmc);
1266 return err;
1267 }
1268 new_state = CARDSLEEP;
Denis Karpov70a33412009-09-22 16:44:59 -07001269 } else {
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001270 new_state = REGSLEEP;
Denis Karpov70a33412009-09-22 16:44:59 -07001271 }
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001272 if (mmc_slot(host).set_sleep)
1273 mmc_slot(host).set_sleep(host->dev, host->slot_id, 1, 0,
1274 new_state == CARDSLEEP);
1275 /* FIXME: turn off bus power and perhaps interrupts too */
1276 clk_disable(host->fclk);
1277 host->dpm_state = new_state;
1278
1279 mmc_release_host(host->mmc);
1280
1281 dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n",
1282 host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
Denis Karpovdd498ef2009-09-22 16:44:49 -07001283
1284 if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
1285 mmc_slot(host).card_detect ||
1286 (mmc_slot(host).get_cover_state &&
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001287 mmc_slot(host).get_cover_state(host->dev, host->slot_id)))
1288 return msecs_to_jiffies(OMAP_MMC_OFF_TIMEOUT);
1289
1290 return 0;
1291}
1292
1293/* Handler for [REGSLEEP / CARDSLEEP -> OFF] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001294static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host)
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001295{
1296 if (!mmc_try_claim_host(host->mmc))
1297 return 0;
1298
1299 if (!((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
1300 mmc_slot(host).card_detect ||
1301 (mmc_slot(host).get_cover_state &&
1302 mmc_slot(host).get_cover_state(host->dev, host->slot_id)))) {
1303 mmc_release_host(host->mmc);
1304 return 0;
Adrian Hunter623821f2009-09-22 16:44:51 -07001305 }
Denis Karpovdd498ef2009-09-22 16:44:49 -07001306
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001307 mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
1308 host->vdd = 0;
1309 host->power_mode = MMC_POWER_OFF;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001310
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001311 dev_dbg(mmc_dev(host->mmc), "%s -> OFF\n",
1312 host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
Denis Karpovdd498ef2009-09-22 16:44:49 -07001313
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001314 host->dpm_state = OFF;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001315
1316 mmc_release_host(host->mmc);
1317
1318 return 0;
1319}
1320
1321/* Handler for [DISABLED -> ENABLED] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001322static int omap_hsmmc_disabled_to_enabled(struct omap_hsmmc_host *host)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001323{
1324 int err;
1325
1326 err = clk_enable(host->fclk);
1327 if (err < 0)
1328 return err;
1329
Denis Karpov70a33412009-09-22 16:44:59 -07001330 omap_hsmmc_context_restore(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001331 host->dpm_state = ENABLED;
1332
1333 dev_dbg(mmc_dev(host->mmc), "DISABLED -> ENABLED\n");
1334
1335 return 0;
1336}
1337
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001338/* Handler for [SLEEP -> ENABLED] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001339static int omap_hsmmc_sleep_to_enabled(struct omap_hsmmc_host *host)
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001340{
1341 if (!mmc_try_claim_host(host->mmc))
1342 return 0;
1343
1344 clk_enable(host->fclk);
Denis Karpov70a33412009-09-22 16:44:59 -07001345 omap_hsmmc_context_restore(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001346 if (mmc_slot(host).set_sleep)
1347 mmc_slot(host).set_sleep(host->dev, host->slot_id, 0,
1348 host->vdd, host->dpm_state == CARDSLEEP);
1349 if (mmc_card_can_sleep(host->mmc))
1350 mmc_card_awake(host->mmc);
1351
1352 dev_dbg(mmc_dev(host->mmc), "%s -> ENABLED\n",
1353 host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
1354
1355 host->dpm_state = ENABLED;
1356
1357 mmc_release_host(host->mmc);
1358
1359 return 0;
1360}
1361
Denis Karpovdd498ef2009-09-22 16:44:49 -07001362/* Handler for [OFF -> ENABLED] transition */
Denis Karpov70a33412009-09-22 16:44:59 -07001363static int omap_hsmmc_off_to_enabled(struct omap_hsmmc_host *host)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001364{
1365 clk_enable(host->fclk);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001366
Denis Karpov70a33412009-09-22 16:44:59 -07001367 omap_hsmmc_context_restore(host);
1368 omap_hsmmc_conf_bus_power(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001369 mmc_power_restore_host(host->mmc);
1370
1371 host->dpm_state = ENABLED;
1372
1373 dev_dbg(mmc_dev(host->mmc), "OFF -> ENABLED\n");
1374
1375 return 0;
1376}
1377
1378/*
1379 * Bring MMC host to ENABLED from any other PM state.
1380 */
Denis Karpov70a33412009-09-22 16:44:59 -07001381static int omap_hsmmc_enable(struct mmc_host *mmc)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001382{
Denis Karpov70a33412009-09-22 16:44:59 -07001383 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001384
1385 switch (host->dpm_state) {
1386 case DISABLED:
Denis Karpov70a33412009-09-22 16:44:59 -07001387 return omap_hsmmc_disabled_to_enabled(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001388 case CARDSLEEP:
Adrian Hunter623821f2009-09-22 16:44:51 -07001389 case REGSLEEP:
Denis Karpov70a33412009-09-22 16:44:59 -07001390 return omap_hsmmc_sleep_to_enabled(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001391 case OFF:
Denis Karpov70a33412009-09-22 16:44:59 -07001392 return omap_hsmmc_off_to_enabled(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001393 default:
1394 dev_dbg(mmc_dev(host->mmc), "UNKNOWN state\n");
1395 return -EINVAL;
1396 }
1397}
1398
1399/*
1400 * Bring MMC host in PM state (one level deeper).
1401 */
Denis Karpov70a33412009-09-22 16:44:59 -07001402static int omap_hsmmc_disable(struct mmc_host *mmc, int lazy)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001403{
Denis Karpov70a33412009-09-22 16:44:59 -07001404 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001405
1406 switch (host->dpm_state) {
1407 case ENABLED: {
1408 int delay;
1409
Denis Karpov70a33412009-09-22 16:44:59 -07001410 delay = omap_hsmmc_enabled_to_disabled(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001411 if (lazy || delay < 0)
1412 return delay;
1413 return 0;
1414 }
1415 case DISABLED:
Denis Karpov70a33412009-09-22 16:44:59 -07001416 return omap_hsmmc_disabled_to_sleep(host);
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001417 case CARDSLEEP:
1418 case REGSLEEP:
Denis Karpov70a33412009-09-22 16:44:59 -07001419 return omap_hsmmc_sleep_to_off(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001420 default:
1421 dev_dbg(mmc_dev(host->mmc), "UNKNOWN state\n");
1422 return -EINVAL;
1423 }
1424}
1425
Denis Karpov70a33412009-09-22 16:44:59 -07001426static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001427{
Denis Karpov70a33412009-09-22 16:44:59 -07001428 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001429 int err;
1430
1431 err = clk_enable(host->fclk);
1432 if (err)
1433 return err;
1434 dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
Denis Karpov70a33412009-09-22 16:44:59 -07001435 omap_hsmmc_context_restore(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001436 return 0;
1437}
1438
Denis Karpov70a33412009-09-22 16:44:59 -07001439static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001440{
Denis Karpov70a33412009-09-22 16:44:59 -07001441 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001442
Denis Karpov70a33412009-09-22 16:44:59 -07001443 omap_hsmmc_context_save(host);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001444 clk_disable(host->fclk);
1445 dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n");
1446 return 0;
1447}
1448
Denis Karpov70a33412009-09-22 16:44:59 -07001449static const struct mmc_host_ops omap_hsmmc_ops = {
1450 .enable = omap_hsmmc_enable_fclk,
1451 .disable = omap_hsmmc_disable_fclk,
1452 .request = omap_hsmmc_request,
1453 .set_ios = omap_hsmmc_set_ios,
Denis Karpovdd498ef2009-09-22 16:44:49 -07001454 .get_cd = omap_hsmmc_get_cd,
1455 .get_ro = omap_hsmmc_get_ro,
1456 /* NYET -- enable_sdio_irq */
1457};
1458
Denis Karpov70a33412009-09-22 16:44:59 -07001459static const struct mmc_host_ops omap_hsmmc_ps_ops = {
1460 .enable = omap_hsmmc_enable,
1461 .disable = omap_hsmmc_disable,
1462 .request = omap_hsmmc_request,
1463 .set_ios = omap_hsmmc_set_ios,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001464 .get_cd = omap_hsmmc_get_cd,
1465 .get_ro = omap_hsmmc_get_ro,
1466 /* NYET -- enable_sdio_irq */
1467};
1468
Denis Karpovd900f712009-09-22 16:44:38 -07001469#ifdef CONFIG_DEBUG_FS
1470
Denis Karpov70a33412009-09-22 16:44:59 -07001471static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
Denis Karpovd900f712009-09-22 16:44:38 -07001472{
1473 struct mmc_host *mmc = s->private;
Denis Karpov70a33412009-09-22 16:44:59 -07001474 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001475 int context_loss = 0;
1476
Denis Karpov70a33412009-09-22 16:44:59 -07001477 if (host->pdata->get_context_loss_count)
1478 context_loss = host->pdata->get_context_loss_count(host->dev);
Denis Karpovd900f712009-09-22 16:44:38 -07001479
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001480 seq_printf(s, "mmc%d:\n"
1481 " enabled:\t%d\n"
Denis Karpovdd498ef2009-09-22 16:44:49 -07001482 " dpm_state:\t%d\n"
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001483 " nesting_cnt:\t%d\n"
Denis Karpov11dd62a2009-09-22 16:44:43 -07001484 " ctx_loss:\t%d:%d\n"
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001485 "\nregs:\n",
Denis Karpovdd498ef2009-09-22 16:44:49 -07001486 mmc->index, mmc->enabled ? 1 : 0,
1487 host->dpm_state, mmc->nesting_cnt,
Denis Karpov11dd62a2009-09-22 16:44:43 -07001488 host->context_loss, context_loss);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001489
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001490 if (host->suspended || host->dpm_state == OFF) {
Denis Karpovdd498ef2009-09-22 16:44:49 -07001491 seq_printf(s, "host suspended, can't read registers\n");
1492 return 0;
1493 }
1494
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001495 if (clk_enable(host->fclk) != 0) {
1496 seq_printf(s, "can't read the regs\n");
Denis Karpovdd498ef2009-09-22 16:44:49 -07001497 return 0;
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001498 }
Denis Karpovd900f712009-09-22 16:44:38 -07001499
1500 seq_printf(s, "SYSCONFIG:\t0x%08x\n",
1501 OMAP_HSMMC_READ(host->base, SYSCONFIG));
1502 seq_printf(s, "CON:\t\t0x%08x\n",
1503 OMAP_HSMMC_READ(host->base, CON));
1504 seq_printf(s, "HCTL:\t\t0x%08x\n",
1505 OMAP_HSMMC_READ(host->base, HCTL));
1506 seq_printf(s, "SYSCTL:\t\t0x%08x\n",
1507 OMAP_HSMMC_READ(host->base, SYSCTL));
1508 seq_printf(s, "IE:\t\t0x%08x\n",
1509 OMAP_HSMMC_READ(host->base, IE));
1510 seq_printf(s, "ISE:\t\t0x%08x\n",
1511 OMAP_HSMMC_READ(host->base, ISE));
1512 seq_printf(s, "CAPA:\t\t0x%08x\n",
1513 OMAP_HSMMC_READ(host->base, CAPA));
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001514
1515 clk_disable(host->fclk);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001516
Denis Karpovd900f712009-09-22 16:44:38 -07001517 return 0;
1518}
1519
Denis Karpov70a33412009-09-22 16:44:59 -07001520static int omap_hsmmc_regs_open(struct inode *inode, struct file *file)
Denis Karpovd900f712009-09-22 16:44:38 -07001521{
Denis Karpov70a33412009-09-22 16:44:59 -07001522 return single_open(file, omap_hsmmc_regs_show, inode->i_private);
Denis Karpovd900f712009-09-22 16:44:38 -07001523}
1524
1525static const struct file_operations mmc_regs_fops = {
Denis Karpov70a33412009-09-22 16:44:59 -07001526 .open = omap_hsmmc_regs_open,
Denis Karpovd900f712009-09-22 16:44:38 -07001527 .read = seq_read,
1528 .llseek = seq_lseek,
1529 .release = single_release,
1530};
1531
Denis Karpov70a33412009-09-22 16:44:59 -07001532static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001533{
1534 if (mmc->debugfs_root)
1535 debugfs_create_file("regs", S_IRUSR, mmc->debugfs_root,
1536 mmc, &mmc_regs_fops);
1537}
1538
1539#else
1540
Denis Karpov70a33412009-09-22 16:44:59 -07001541static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001542{
1543}
1544
1545#endif
1546
Denis Karpov70a33412009-09-22 16:44:59 -07001547static int __init omap_hsmmc_probe(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001548{
1549 struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
1550 struct mmc_host *mmc;
Denis Karpov70a33412009-09-22 16:44:59 -07001551 struct omap_hsmmc_host *host = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001552 struct resource *res;
1553 int ret = 0, irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001554
1555 if (pdata == NULL) {
1556 dev_err(&pdev->dev, "Platform Data is missing\n");
1557 return -ENXIO;
1558 }
1559
1560 if (pdata->nr_slots == 0) {
1561 dev_err(&pdev->dev, "No Slots\n");
1562 return -ENXIO;
1563 }
1564
1565 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1566 irq = platform_get_irq(pdev, 0);
1567 if (res == NULL || irq < 0)
1568 return -ENXIO;
1569
1570 res = request_mem_region(res->start, res->end - res->start + 1,
1571 pdev->name);
1572 if (res == NULL)
1573 return -EBUSY;
1574
Denis Karpov70a33412009-09-22 16:44:59 -07001575 mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001576 if (!mmc) {
1577 ret = -ENOMEM;
1578 goto err;
1579 }
1580
1581 host = mmc_priv(mmc);
1582 host->mmc = mmc;
1583 host->pdata = pdata;
1584 host->dev = &pdev->dev;
1585 host->use_dma = 1;
1586 host->dev->dma_mask = &pdata->dma_mask;
1587 host->dma_ch = -1;
1588 host->irq = irq;
1589 host->id = pdev->id;
1590 host->slot_id = 0;
1591 host->mapbase = res->start;
1592 host->base = ioremap(host->mapbase, SZ_4K);
Adrian Huntera3621462009-09-22 16:44:42 -07001593 host->power_mode = -1;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001594
1595 platform_set_drvdata(pdev, host);
Denis Karpov70a33412009-09-22 16:44:59 -07001596 INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001597
Denis Karpov191d1f12009-09-22 16:44:55 -07001598 if (mmc_slot(host).power_saving)
Denis Karpov70a33412009-09-22 16:44:59 -07001599 mmc->ops = &omap_hsmmc_ps_ops;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001600 else
Denis Karpov70a33412009-09-22 16:44:59 -07001601 mmc->ops = &omap_hsmmc_ops;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001602
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001603 mmc->f_min = 400000;
1604 mmc->f_max = 52000000;
1605
1606 sema_init(&host->sem, 1);
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001607 spin_lock_init(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001608
Russell King6f7607c2009-01-28 10:22:50 +00001609 host->iclk = clk_get(&pdev->dev, "ick");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001610 if (IS_ERR(host->iclk)) {
1611 ret = PTR_ERR(host->iclk);
1612 host->iclk = NULL;
1613 goto err1;
1614 }
Russell King6f7607c2009-01-28 10:22:50 +00001615 host->fclk = clk_get(&pdev->dev, "fck");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001616 if (IS_ERR(host->fclk)) {
1617 ret = PTR_ERR(host->fclk);
1618 host->fclk = NULL;
1619 clk_put(host->iclk);
1620 goto err1;
1621 }
1622
Denis Karpov70a33412009-09-22 16:44:59 -07001623 omap_hsmmc_context_save(host);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001624
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001625 mmc->caps |= MMC_CAP_DISABLE;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001626 mmc_set_disable_delay(mmc, OMAP_MMC_DISABLED_TIMEOUT);
1627 /* we start off in DISABLED state */
1628 host->dpm_state = DISABLED;
1629
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001630 if (mmc_host_enable(host->mmc) != 0) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001631 clk_put(host->iclk);
1632 clk_put(host->fclk);
1633 goto err1;
1634 }
1635
1636 if (clk_enable(host->iclk) != 0) {
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001637 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001638 clk_put(host->iclk);
1639 clk_put(host->fclk);
1640 goto err1;
1641 }
1642
1643 host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
1644 /*
1645 * MMC can still work without debounce clock.
1646 */
1647 if (IS_ERR(host->dbclk))
1648 dev_warn(mmc_dev(host->mmc), "Failed to get debounce clock\n");
1649 else
1650 if (clk_enable(host->dbclk) != 0)
1651 dev_dbg(mmc_dev(host->mmc), "Enabling debounce"
1652 " clk failed\n");
1653 else
1654 host->dbclk_enabled = 1;
1655
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001656 /* Since we do only SG emulation, we can have as many segs
1657 * as we want. */
1658 mmc->max_phys_segs = 1024;
1659 mmc->max_hw_segs = 1024;
1660
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001661 mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
1662 mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
1663 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
1664 mmc->max_seg_size = mmc->max_req_size;
1665
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001666 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
1667 MMC_CAP_WAIT_WHILE_BUSY;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001668
Denis Karpov191d1f12009-09-22 16:44:55 -07001669 if (mmc_slot(host).wires >= 8)
Jarkko Lavinen73153012008-11-21 16:49:54 +02001670 mmc->caps |= MMC_CAP_8_BIT_DATA;
Denis Karpov191d1f12009-09-22 16:44:55 -07001671 else if (mmc_slot(host).wires >= 4)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001672 mmc->caps |= MMC_CAP_4_BIT_DATA;
1673
Denis Karpov191d1f12009-09-22 16:44:55 -07001674 if (mmc_slot(host).nonremovable)
Adrian Hunter23d99bb2009-09-22 16:44:48 -07001675 mmc->caps |= MMC_CAP_NONREMOVABLE;
1676
Denis Karpov70a33412009-09-22 16:44:59 -07001677 omap_hsmmc_conf_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001678
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +00001679 /* Select DMA lines */
1680 switch (host->id) {
1681 case OMAP_MMC1_DEVID:
1682 host->dma_line_tx = OMAP24XX_DMA_MMC1_TX;
1683 host->dma_line_rx = OMAP24XX_DMA_MMC1_RX;
1684 break;
1685 case OMAP_MMC2_DEVID:
1686 host->dma_line_tx = OMAP24XX_DMA_MMC2_TX;
1687 host->dma_line_rx = OMAP24XX_DMA_MMC2_RX;
1688 break;
1689 case OMAP_MMC3_DEVID:
1690 host->dma_line_tx = OMAP34XX_DMA_MMC3_TX;
1691 host->dma_line_rx = OMAP34XX_DMA_MMC3_RX;
1692 break;
1693 default:
1694 dev_err(mmc_dev(host->mmc), "Invalid MMC id\n");
1695 goto err_irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001696 }
1697
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001698 /* Request IRQ for MMC operations */
Denis Karpov70a33412009-09-22 16:44:59 -07001699 ret = request_irq(host->irq, omap_hsmmc_irq, IRQF_DISABLED,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001700 mmc_hostname(mmc), host);
1701 if (ret) {
1702 dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
1703 goto err_irq;
1704 }
1705
David Brownellb583f262009-05-28 14:04:03 -07001706 /* initialize power supplies, gpios, etc */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001707 if (pdata->init != NULL) {
1708 if (pdata->init(&pdev->dev) != 0) {
Denis Karpov70a33412009-09-22 16:44:59 -07001709 dev_dbg(mmc_dev(host->mmc),
1710 "Unable to configure MMC IRQs\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001711 goto err_irq_cd_init;
1712 }
1713 }
David Brownellb583f262009-05-28 14:04:03 -07001714 mmc->ocr_avail = mmc_slot(host).ocr_mask;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001715
1716 /* Request IRQ for card detect */
Adrian Huntere1a55f52009-01-26 13:17:25 +02001717 if ((mmc_slot(host).card_detect_irq)) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001718 ret = request_irq(mmc_slot(host).card_detect_irq,
Denis Karpov70a33412009-09-22 16:44:59 -07001719 omap_hsmmc_cd_handler,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001720 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
1721 | IRQF_DISABLED,
1722 mmc_hostname(mmc), host);
1723 if (ret) {
1724 dev_dbg(mmc_dev(host->mmc),
1725 "Unable to grab MMC CD IRQ\n");
1726 goto err_irq_cd;
1727 }
1728 }
1729
1730 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
1731 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
1732
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001733 mmc_host_lazy_disable(host->mmc);
1734
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001735 mmc_add_host(mmc);
1736
Denis Karpov191d1f12009-09-22 16:44:55 -07001737 if (mmc_slot(host).name != NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001738 ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
1739 if (ret < 0)
1740 goto err_slot_name;
1741 }
Denis Karpov191d1f12009-09-22 16:44:55 -07001742 if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001743 ret = device_create_file(&mmc->class_dev,
1744 &dev_attr_cover_switch);
1745 if (ret < 0)
1746 goto err_cover_switch;
1747 }
1748
Denis Karpov70a33412009-09-22 16:44:59 -07001749 omap_hsmmc_debugfs(mmc);
Denis Karpovd900f712009-09-22 16:44:38 -07001750
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001751 return 0;
1752
1753err_cover_switch:
1754 device_remove_file(&mmc->class_dev, &dev_attr_cover_switch);
1755err_slot_name:
1756 mmc_remove_host(mmc);
1757err_irq_cd:
1758 free_irq(mmc_slot(host).card_detect_irq, host);
1759err_irq_cd_init:
1760 free_irq(host->irq, host);
1761err_irq:
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001762 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001763 clk_disable(host->iclk);
1764 clk_put(host->fclk);
1765 clk_put(host->iclk);
1766 if (host->dbclk_enabled) {
1767 clk_disable(host->dbclk);
1768 clk_put(host->dbclk);
1769 }
1770
1771err1:
1772 iounmap(host->base);
1773err:
1774 dev_dbg(mmc_dev(host->mmc), "Probe Failed\n");
1775 release_mem_region(res->start, res->end - res->start + 1);
1776 if (host)
1777 mmc_free_host(mmc);
1778 return ret;
1779}
1780
Denis Karpov70a33412009-09-22 16:44:59 -07001781static int omap_hsmmc_remove(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001782{
Denis Karpov70a33412009-09-22 16:44:59 -07001783 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001784 struct resource *res;
1785
1786 if (host) {
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001787 mmc_host_enable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001788 mmc_remove_host(host->mmc);
1789 if (host->pdata->cleanup)
1790 host->pdata->cleanup(&pdev->dev);
1791 free_irq(host->irq, host);
1792 if (mmc_slot(host).card_detect_irq)
1793 free_irq(mmc_slot(host).card_detect_irq, host);
1794 flush_scheduled_work();
1795
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001796 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001797 clk_disable(host->iclk);
1798 clk_put(host->fclk);
1799 clk_put(host->iclk);
1800 if (host->dbclk_enabled) {
1801 clk_disable(host->dbclk);
1802 clk_put(host->dbclk);
1803 }
1804
1805 mmc_free_host(host->mmc);
1806 iounmap(host->base);
1807 }
1808
1809 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1810 if (res)
1811 release_mem_region(res->start, res->end - res->start + 1);
1812 platform_set_drvdata(pdev, NULL);
1813
1814 return 0;
1815}
1816
1817#ifdef CONFIG_PM
Denis Karpov70a33412009-09-22 16:44:59 -07001818static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001819{
1820 int ret = 0;
Denis Karpov70a33412009-09-22 16:44:59 -07001821 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001822
1823 if (host && host->suspended)
1824 return 0;
1825
1826 if (host) {
Adrian Huntera6b22402009-09-22 16:44:45 -07001827 host->suspended = 1;
1828 if (host->pdata->suspend) {
1829 ret = host->pdata->suspend(&pdev->dev,
1830 host->slot_id);
1831 if (ret) {
1832 dev_dbg(mmc_dev(host->mmc),
1833 "Unable to handle MMC board"
1834 " level suspend\n");
1835 host->suspended = 0;
1836 return ret;
1837 }
1838 }
1839 cancel_work_sync(&host->mmc_carddetect_work);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001840 mmc_host_enable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001841 ret = mmc_suspend_host(host->mmc, state);
1842 if (ret == 0) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001843 OMAP_HSMMC_WRITE(host->base, ISE, 0);
1844 OMAP_HSMMC_WRITE(host->base, IE, 0);
1845
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001846
Jarkko Lavinen0683af42009-03-12 15:30:58 +02001847 OMAP_HSMMC_WRITE(host->base, HCTL,
Denis Karpov191d1f12009-09-22 16:44:55 -07001848 OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001849 mmc_host_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001850 clk_disable(host->iclk);
1851 clk_disable(host->dbclk);
Adrian Huntera6b22402009-09-22 16:44:45 -07001852 } else {
1853 host->suspended = 0;
1854 if (host->pdata->resume) {
1855 ret = host->pdata->resume(&pdev->dev,
1856 host->slot_id);
1857 if (ret)
1858 dev_dbg(mmc_dev(host->mmc),
1859 "Unmask interrupt failed\n");
1860 }
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001861 mmc_host_disable(host->mmc);
Adrian Huntera6b22402009-09-22 16:44:45 -07001862 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001863
1864 }
1865 return ret;
1866}
1867
1868/* Routine to resume the MMC device */
Denis Karpov70a33412009-09-22 16:44:59 -07001869static int omap_hsmmc_resume(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001870{
1871 int ret = 0;
Denis Karpov70a33412009-09-22 16:44:59 -07001872 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001873
1874 if (host && !host->suspended)
1875 return 0;
1876
1877 if (host) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001878 ret = clk_enable(host->iclk);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001879 if (ret)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001880 goto clk_en_err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001881
1882 if (clk_enable(host->dbclk) != 0)
1883 dev_dbg(mmc_dev(host->mmc),
1884 "Enabling debounce clk failed\n");
1885
Denis Karpov11dd62a2009-09-22 16:44:43 -07001886 if (mmc_host_enable(host->mmc) != 0) {
1887 clk_disable(host->iclk);
1888 goto clk_en_err;
1889 }
1890
Denis Karpov70a33412009-09-22 16:44:59 -07001891 omap_hsmmc_conf_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001892
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001893 if (host->pdata->resume) {
1894 ret = host->pdata->resume(&pdev->dev, host->slot_id);
1895 if (ret)
1896 dev_dbg(mmc_dev(host->mmc),
1897 "Unmask interrupt failed\n");
1898 }
1899
1900 /* Notify the core to resume the host */
1901 ret = mmc_resume_host(host->mmc);
1902 if (ret == 0)
1903 host->suspended = 0;
Denis Karpov70a33412009-09-22 16:44:59 -07001904
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001905 mmc_host_lazy_disable(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001906 }
1907
1908 return ret;
1909
1910clk_en_err:
1911 dev_dbg(mmc_dev(host->mmc),
1912 "Failed to enable MMC clocks during resume\n");
1913 return ret;
1914}
1915
1916#else
Denis Karpov70a33412009-09-22 16:44:59 -07001917#define omap_hsmmc_suspend NULL
1918#define omap_hsmmc_resume NULL
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001919#endif
1920
Denis Karpov70a33412009-09-22 16:44:59 -07001921static struct platform_driver omap_hsmmc_driver = {
1922 .remove = omap_hsmmc_remove,
1923 .suspend = omap_hsmmc_suspend,
1924 .resume = omap_hsmmc_resume,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001925 .driver = {
1926 .name = DRIVER_NAME,
1927 .owner = THIS_MODULE,
1928 },
1929};
1930
Denis Karpov70a33412009-09-22 16:44:59 -07001931static int __init omap_hsmmc_init(void)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001932{
1933 /* Register the MMC driver */
Denis Karpov70a33412009-09-22 16:44:59 -07001934 return platform_driver_register(&omap_hsmmc_driver);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001935}
1936
Denis Karpov70a33412009-09-22 16:44:59 -07001937static void __exit omap_hsmmc_cleanup(void)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001938{
1939 /* Unregister MMC driver */
Denis Karpov70a33412009-09-22 16:44:59 -07001940 platform_driver_unregister(&omap_hsmmc_driver);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001941}
1942
Denis Karpov70a33412009-09-22 16:44:59 -07001943module_init(omap_hsmmc_init);
1944module_exit(omap_hsmmc_cleanup);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001945
1946MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
1947MODULE_LICENSE("GPL");
1948MODULE_ALIAS("platform:" DRIVER_NAME);
1949MODULE_AUTHOR("Texas Instruments Inc");