blob: 3ea66971edfc25f76a92a927374d023e92f1396c [file] [log] [blame]
San Mehat9d2bd732009-09-22 16:44:22 -07001/*
2 * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
3 *
4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
San Mehat56a8b5b2009-11-21 12:29:46 -08006 * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved.
San Mehat9d2bd732009-09-22 16:44:22 -07007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Based on mmci.c
13 *
14 * Author: San Mehat (san@android.com)
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
22#include <linux/device.h>
23#include <linux/interrupt.h>
24#include <linux/delay.h>
25#include <linux/err.h>
26#include <linux/highmem.h>
27#include <linux/log2.h>
28#include <linux/mmc/host.h>
29#include <linux/mmc/card.h>
San Mehatb3fa5792009-11-02 18:46:09 -080030#include <linux/mmc/sdio.h>
San Mehat9d2bd732009-09-22 16:44:22 -070031#include <linux/clk.h>
32#include <linux/scatterlist.h>
33#include <linux/platform_device.h>
34#include <linux/dma-mapping.h>
35#include <linux/debugfs.h>
36#include <linux/io.h>
37#include <linux/memory.h>
38
39#include <asm/cacheflush.h>
40#include <asm/div64.h>
41#include <asm/sizes.h>
42
Pavel Machek3989d172009-12-08 11:11:36 -080043#include <mach/mmc.h>
San Mehat9d2bd732009-09-22 16:44:22 -070044#include <mach/msm_iomap.h>
45#include <mach/dma.h>
San Mehat9d2bd732009-09-22 16:44:22 -070046
San Mehat9d2bd732009-09-22 16:44:22 -070047#include "msm_sdcc.h"
48
49#define DRIVER_NAME "msm-sdcc"
50
San Mehatf4748492009-11-23 15:36:31 -080051#define BUSCLK_PWRSAVE 0
San Mehatc7fc9372009-11-22 17:19:07 -080052#define BUSCLK_TIMEOUT (HZ)
San Mehat9d2bd732009-09-22 16:44:22 -070053static unsigned int msmsdcc_fmin = 144000;
54static unsigned int msmsdcc_fmax = 50000000;
55static unsigned int msmsdcc_4bit = 1;
56static unsigned int msmsdcc_pwrsave = 1;
57static unsigned int msmsdcc_piopoll = 1;
58static unsigned int msmsdcc_sdioirq;
59
60#define PIO_SPINMAX 30
61#define CMD_SPINMAX 20
62
San Mehat865c80642009-11-13 13:42:06 -080063
San Mehatc7fc9372009-11-22 17:19:07 -080064static inline void
65msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr)
San Mehat865c80642009-11-13 13:42:06 -080066{
San Mehatc7fc9372009-11-22 17:19:07 -080067 WARN_ON(!host->clks_on);
San Mehat8b1c2ba2009-11-16 10:17:30 -080068
San Mehatf4748492009-11-23 15:36:31 -080069 BUG_ON(host->curr.mrq);
70
San Mehatc7fc9372009-11-22 17:19:07 -080071 if (deferr) {
72 mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT);
San Mehat865c80642009-11-13 13:42:06 -080073 } else {
San Mehatc7fc9372009-11-22 17:19:07 -080074 del_timer_sync(&host->busclk_timer);
75// dev_info(mmc_dev(host->mmc), "Immediate clock shutdown\n");
San Mehat865c80642009-11-13 13:42:06 -080076 clk_disable(host->clk);
77 clk_disable(host->pclk);
78 host->clks_on = 0;
79 }
San Mehatc7fc9372009-11-22 17:19:07 -080080}
81
82static inline int
83msmsdcc_enable_clocks(struct msmsdcc_host *host)
84{
85 int rc;
86
87 WARN_ON(host->clks_on);
88
89 del_timer_sync(&host->busclk_timer);
90
91 rc = clk_enable(host->pclk);
92 if (rc)
93 return rc;
94 rc = clk_enable(host->clk);
95 if (rc) {
96 clk_disable(host->pclk);
97 return rc;
98 }
99 udelay(1 + ((3 * USEC_PER_SEC) /
100 (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
101 host->clks_on = 1;
San Mehat865c80642009-11-13 13:42:06 -0800102 return 0;
103}
104
San Mehat8b1c2ba2009-11-16 10:17:30 -0800105static inline unsigned int
106msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg)
107{
108 return readl(host->base + reg);
109}
110
111static inline void
112msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg)
113{
114 writel(data, host->base + reg);
115 /* 3 clk delay required! */
116 udelay(1 + ((3 * USEC_PER_SEC) /
117 (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
118}
San Mehat865c80642009-11-13 13:42:06 -0800119
San Mehat9d2bd732009-09-22 16:44:22 -0700120static void
121msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
122 u32 c);
123
124static void
125msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
126{
San Mehat9d2bd732009-09-22 16:44:22 -0700127 BUG_ON(host->curr.data);
128
129 host->curr.mrq = NULL;
130 host->curr.cmd = NULL;
131
132 if (mrq->data)
133 mrq->data->bytes_xfered = host->curr.data_xfered;
134 if (mrq->cmd->error == -ETIMEDOUT)
135 mdelay(5);
136
San Mehatf4748492009-11-23 15:36:31 -0800137#if BUSCLK_PWRSAVE
San Mehatc7fc9372009-11-22 17:19:07 -0800138 msmsdcc_disable_clocks(host, 1);
San Mehatf4748492009-11-23 15:36:31 -0800139#endif
San Mehat9d2bd732009-09-22 16:44:22 -0700140 /*
141 * Need to drop the host lock here; mmc_request_done may call
142 * back into the driver...
143 */
144 spin_unlock(&host->lock);
145 mmc_request_done(host->mmc, mrq);
146 spin_lock(&host->lock);
147}
148
149static void
150msmsdcc_stop_data(struct msmsdcc_host *host)
151{
San Mehat9d2bd732009-09-22 16:44:22 -0700152 host->curr.data = NULL;
153 host->curr.got_dataend = host->curr.got_datablkend = 0;
154}
155
156uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
157{
Joe Perches75d14522009-09-22 16:44:24 -0700158 switch (host->pdev_id) {
159 case 1:
San Mehat9d2bd732009-09-22 16:44:22 -0700160 return MSM_SDC1_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700161 case 2:
San Mehat9d2bd732009-09-22 16:44:22 -0700162 return MSM_SDC2_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700163 case 3:
San Mehat9d2bd732009-09-22 16:44:22 -0700164 return MSM_SDC3_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700165 case 4:
San Mehat9d2bd732009-09-22 16:44:22 -0700166 return MSM_SDC4_PHYS + MMCIFIFO;
Joe Perches75d14522009-09-22 16:44:24 -0700167 }
168 BUG();
San Mehat9d2bd732009-09-22 16:44:22 -0700169 return 0;
170}
171
San Mehat56a8b5b2009-11-21 12:29:46 -0800172static inline void
173msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) {
174 msmsdcc_writel(host, arg, MMCIARGUMENT);
175 msmsdcc_writel(host, c, MMCICOMMAND);
176}
177
178static void
179msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
180{
181 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data;
182
183 writel(host->cmd_timeout, host->base + MMCIDATATIMER);
184 writel((unsigned int)host->curr.xfer_size, host->base + MMCIDATALENGTH);
185 writel(host->cmd_pio_irqmask, host->base + MMCIMASK1);
186 writel(host->cmd_datactrl, host->base + MMCIDATACTRL);
187
188 if (host->cmd_cmd) {
189 msmsdcc_start_command_exec(host,
190 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
191 }
192 host->dma.active = 1;
193}
194
San Mehat9d2bd732009-09-22 16:44:22 -0700195static void
196msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
197 unsigned int result,
198 struct msm_dmov_errdata *err)
199{
200 struct msmsdcc_dma_data *dma_data =
201 container_of(cmd, struct msmsdcc_dma_data, hdr);
202 struct msmsdcc_host *host = dma_data->host;
203 unsigned long flags;
204 struct mmc_request *mrq;
205
206 spin_lock_irqsave(&host->lock, flags);
San Mehat56a8b5b2009-11-21 12:29:46 -0800207 host->dma.active = 0;
208
San Mehat9d2bd732009-09-22 16:44:22 -0700209 mrq = host->curr.mrq;
210 BUG_ON(!mrq);
San Mehatb3b0ca82009-11-24 12:24:55 -0800211 WARN_ON(!mrq->data);
San Mehat9d2bd732009-09-22 16:44:22 -0700212
213 if (!(result & DMOV_RSLT_VALID)) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700214 pr_err("msmsdcc: Invalid DataMover result\n");
San Mehat9d2bd732009-09-22 16:44:22 -0700215 goto out;
216 }
217
218 if (result & DMOV_RSLT_DONE) {
219 host->curr.data_xfered = host->curr.xfer_size;
220 } else {
221 /* Error or flush */
222 if (result & DMOV_RSLT_ERROR)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700223 pr_err("%s: DMA error (0x%.8x)\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700224 mmc_hostname(host->mmc), result);
225 if (result & DMOV_RSLT_FLUSH)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700226 pr_err("%s: DMA channel flushed (0x%.8x)\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700227 mmc_hostname(host->mmc), result);
228 if (err)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700229 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
San Mehat9d2bd732009-09-22 16:44:22 -0700230 err->flush[0], err->flush[1], err->flush[2],
231 err->flush[3], err->flush[4], err->flush[5]);
232 if (!mrq->data->error)
233 mrq->data->error = -EIO;
234 }
San Mehat9d2bd732009-09-22 16:44:22 -0700235 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
236 host->dma.dir);
237
238 if (host->curr.user_pages) {
239 struct scatterlist *sg = host->dma.sg;
240 int i;
241
Joe Perches75d14522009-09-22 16:44:24 -0700242 for (i = 0; i < host->dma.num_ents; i++)
243 flush_dcache_page(sg_page(sg++));
San Mehat9d2bd732009-09-22 16:44:22 -0700244 }
245
246 host->dma.sg = NULL;
San Mehat56a8b5b2009-11-21 12:29:46 -0800247 host->dma.busy = 0;
San Mehat9d2bd732009-09-22 16:44:22 -0700248
249 if ((host->curr.got_dataend && host->curr.got_datablkend)
250 || mrq->data->error) {
251
252 /*
253 * If we've already gotten our DATAEND / DATABLKEND
254 * for this request, then complete it through here.
255 */
256 msmsdcc_stop_data(host);
257
258 if (!mrq->data->error)
259 host->curr.data_xfered = host->curr.xfer_size;
260 if (!mrq->data->stop || mrq->cmd->error) {
San Mehat9d2bd732009-09-22 16:44:22 -0700261 host->curr.mrq = NULL;
262 host->curr.cmd = NULL;
263 mrq->data->bytes_xfered = host->curr.data_xfered;
264
265 spin_unlock_irqrestore(&host->lock, flags);
San Mehatf4748492009-11-23 15:36:31 -0800266#if BUSCLK_PWRSAVE
San Mehatc7fc9372009-11-22 17:19:07 -0800267 msmsdcc_disable_clocks(host, 1);
San Mehatf4748492009-11-23 15:36:31 -0800268#endif
San Mehat9d2bd732009-09-22 16:44:22 -0700269 mmc_request_done(host->mmc, mrq);
270 return;
271 } else
272 msmsdcc_start_command(host, mrq->data->stop, 0);
273 }
274
275out:
276 spin_unlock_irqrestore(&host->lock, flags);
277 return;
278}
279
280static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data)
281{
282 if (host->dma.channel == -1)
283 return -ENOENT;
284
285 if ((data->blksz * data->blocks) < MCI_FIFOSIZE)
286 return -EINVAL;
287 if ((data->blksz * data->blocks) % MCI_FIFOSIZE)
288 return -EINVAL;
289 return 0;
290}
291
292static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
293{
294 struct msmsdcc_nc_dmadata *nc;
295 dmov_box *box;
296 uint32_t rows;
297 uint32_t crci;
298 unsigned int n;
299 int i, rc;
300 struct scatterlist *sg = data->sg;
301
302 rc = validate_dma(host, data);
303 if (rc)
304 return rc;
305
306 host->dma.sg = data->sg;
307 host->dma.num_ents = data->sg_len;
308
San Mehat56a8b5b2009-11-21 12:29:46 -0800309 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
310
San Mehat9d2bd732009-09-22 16:44:22 -0700311 nc = host->dma.nc;
312
Joe Perches75d14522009-09-22 16:44:24 -0700313 switch (host->pdev_id) {
314 case 1:
San Mehat9d2bd732009-09-22 16:44:22 -0700315 crci = MSMSDCC_CRCI_SDC1;
Joe Perches75d14522009-09-22 16:44:24 -0700316 break;
317 case 2:
San Mehat9d2bd732009-09-22 16:44:22 -0700318 crci = MSMSDCC_CRCI_SDC2;
Joe Perches75d14522009-09-22 16:44:24 -0700319 break;
320 case 3:
San Mehat9d2bd732009-09-22 16:44:22 -0700321 crci = MSMSDCC_CRCI_SDC3;
Joe Perches75d14522009-09-22 16:44:24 -0700322 break;
323 case 4:
San Mehat9d2bd732009-09-22 16:44:22 -0700324 crci = MSMSDCC_CRCI_SDC4;
Joe Perches75d14522009-09-22 16:44:24 -0700325 break;
326 default:
San Mehat9d2bd732009-09-22 16:44:22 -0700327 host->dma.sg = NULL;
328 host->dma.num_ents = 0;
329 return -ENOENT;
330 }
331
332 if (data->flags & MMC_DATA_READ)
333 host->dma.dir = DMA_FROM_DEVICE;
334 else
335 host->dma.dir = DMA_TO_DEVICE;
336
337 host->curr.user_pages = 0;
338
San Mehat9d2bd732009-09-22 16:44:22 -0700339 box = &nc->cmd[0];
340 for (i = 0; i < host->dma.num_ents; i++) {
341 box->cmd = CMD_MODE_BOX;
342
San Mehat56a8b5b2009-11-21 12:29:46 -0800343 /* Initialize sg dma address */
344 sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg))
345 + sg->offset;
346
347 if (i == (host->dma.num_ents - 1))
San Mehat9d2bd732009-09-22 16:44:22 -0700348 box->cmd |= CMD_LC;
349 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
350 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
351 (sg_dma_len(sg) / MCI_FIFOSIZE) ;
352
353 if (data->flags & MMC_DATA_READ) {
354 box->src_row_addr = msmsdcc_fifo_addr(host);
355 box->dst_row_addr = sg_dma_address(sg);
356
357 box->src_dst_len = (MCI_FIFOSIZE << 16) |
358 (MCI_FIFOSIZE);
359 box->row_offset = MCI_FIFOSIZE;
360
361 box->num_rows = rows * ((1 << 16) + 1);
362 box->cmd |= CMD_SRC_CRCI(crci);
363 } else {
364 box->src_row_addr = sg_dma_address(sg);
365 box->dst_row_addr = msmsdcc_fifo_addr(host);
366
367 box->src_dst_len = (MCI_FIFOSIZE << 16) |
368 (MCI_FIFOSIZE);
369 box->row_offset = (MCI_FIFOSIZE << 16);
370
371 box->num_rows = rows * ((1 << 16) + 1);
372 box->cmd |= CMD_DST_CRCI(crci);
373 }
374 box++;
375 sg++;
376 }
377
378 /* location of command block must be 64 bit aligned */
379 BUG_ON(host->dma.cmd_busaddr & 0x07);
380
381 nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
382 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
383 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
384 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
San Mehat56a8b5b2009-11-21 12:29:46 -0800385
386 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
387 host->dma.num_ents, host->dma.dir);
388/* dsb inside dma_map_sg will write nc out to mem as well */
389
390 if (n != host->dma.num_ents) {
391 printk(KERN_ERR "%s: Unable to map in all sg elements\n",
392 mmc_hostname(host->mmc));
393 host->dma.sg = NULL;
394 host->dma.num_ents = 0;
395 return -ENOMEM;
396 }
San Mehat9d2bd732009-09-22 16:44:22 -0700397
398 return 0;
399}
400
San Mehat56a8b5b2009-11-21 12:29:46 -0800401static int
402snoop_cccr_abort(struct mmc_command *cmd)
403{
404 if ((cmd->opcode == 52) &&
405 (cmd->arg & 0x80000000) &&
406 (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT))
407 return 1;
408 return 0;
409}
410
San Mehat9d2bd732009-09-22 16:44:22 -0700411static void
San Mehat56a8b5b2009-11-21 12:29:46 -0800412msmsdcc_start_command_deferred(struct msmsdcc_host *host,
413 struct mmc_command *cmd, u32 *c)
414{
415 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
416
417 if (cmd->flags & MMC_RSP_PRESENT) {
418 if (cmd->flags & MMC_RSP_136)
419 *c |= MCI_CPSM_LONGRSP;
420 *c |= MCI_CPSM_RESPONSE;
421 }
422
423 if (/*interrupt*/0)
424 *c |= MCI_CPSM_INTERRUPT;
425
426 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
427 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
428 (cmd->opcode == 53))
429 *c |= MCI_CSPM_DATCMD;
430
431 if (cmd == cmd->mrq->stop)
432 *c |= MCI_CSPM_MCIABORT;
433
434 if (snoop_cccr_abort(cmd))
435 *c |= MCI_CSPM_MCIABORT;
436
437 if (host->curr.cmd != NULL) {
438 printk(KERN_ERR "%s: Overlapping command requests\n",
439 mmc_hostname(host->mmc));
440 }
441 host->curr.cmd = cmd;
442}
443
444static void
445msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
446 struct mmc_command *cmd, u32 c)
San Mehat9d2bd732009-09-22 16:44:22 -0700447{
448 unsigned int datactrl, timeout;
449 unsigned long long clks;
San Mehat9d2bd732009-09-22 16:44:22 -0700450 unsigned int pio_irqmask = 0;
451
452 host->curr.data = data;
453 host->curr.xfer_size = data->blksz * data->blocks;
454 host->curr.xfer_remain = host->curr.xfer_size;
455 host->curr.data_xfered = 0;
456 host->curr.got_dataend = 0;
457 host->curr.got_datablkend = 0;
458
459 memset(&host->pio, 0, sizeof(host->pio));
460
San Mehat9d2bd732009-09-22 16:44:22 -0700461 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
462
463 if (!msmsdcc_config_dma(host, data))
464 datactrl |= MCI_DPSM_DMAENABLE;
465 else {
466 host->pio.sg = data->sg;
467 host->pio.sg_len = data->sg_len;
468 host->pio.sg_off = 0;
469
470 if (data->flags & MMC_DATA_READ) {
471 pio_irqmask = MCI_RXFIFOHALFFULLMASK;
472 if (host->curr.xfer_remain < MCI_FIFOSIZE)
473 pio_irqmask |= MCI_RXDATAAVLBLMASK;
474 } else
475 pio_irqmask = MCI_TXFIFOHALFEMPTYMASK;
476 }
477
478 if (data->flags & MMC_DATA_READ)
479 datactrl |= MCI_DPSM_DIRECTION;
480
San Mehat56a8b5b2009-11-21 12:29:46 -0800481 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
482 do_div(clks, NSEC_PER_SEC);
483 timeout = data->timeout_clks + (unsigned int)clks*2 ;
San Mehat9d2bd732009-09-22 16:44:22 -0700484
485 if (datactrl & MCI_DPSM_DMAENABLE) {
San Mehat56a8b5b2009-11-21 12:29:46 -0800486 /* Save parameters for the exec function */
487 host->cmd_timeout = timeout;
488 host->cmd_pio_irqmask = pio_irqmask;
489 host->cmd_datactrl = datactrl;
490 host->cmd_cmd = cmd;
San Mehat9d2bd732009-09-22 16:44:22 -0700491
San Mehat56a8b5b2009-11-21 12:29:46 -0800492 host->dma.hdr.execute_func = msmsdcc_dma_exec_func;
493 host->dma.hdr.data = (void *)host;
494 host->dma.busy = 1;
495
496 if (cmd) {
497 msmsdcc_start_command_deferred(host, cmd, &c);
498 host->cmd_c = c;
499 }
500 msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr);
501 } else {
502 msmsdcc_writel(host, timeout, MMCIDATATIMER);
503
504 msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH);
505
506 msmsdcc_writel(host, pio_irqmask, MMCIMASK1);
507 msmsdcc_writel(host, datactrl, MMCIDATACTRL);
508
509 if (cmd) {
510 /* Daisy-chain the command if requested */
511 msmsdcc_start_command(host, cmd, c);
512 }
513 }
San Mehatb3fa5792009-11-02 18:46:09 -0800514}
515
San Mehat9d2bd732009-09-22 16:44:22 -0700516static void
517msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
518{
San Mehat9d2bd732009-09-22 16:44:22 -0700519 if (cmd == cmd->mrq->stop)
520 c |= MCI_CSPM_MCIABORT;
521
San Mehat9d2bd732009-09-22 16:44:22 -0700522 host->stats.cmds++;
523
San Mehat56a8b5b2009-11-21 12:29:46 -0800524 msmsdcc_start_command_deferred(host, cmd, &c);
525 msmsdcc_start_command_exec(host, cmd->arg, c);
San Mehat9d2bd732009-09-22 16:44:22 -0700526}
527
528static void
529msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
530 unsigned int status)
531{
532 if (status & MCI_DATACRCFAIL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700533 pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc));
534 pr_err("%s: opcode 0x%.8x\n", __func__,
San Mehat9d2bd732009-09-22 16:44:22 -0700535 data->mrq->cmd->opcode);
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700536 pr_err("%s: blksz %d, blocks %d\n", __func__,
San Mehat9d2bd732009-09-22 16:44:22 -0700537 data->blksz, data->blocks);
538 data->error = -EILSEQ;
539 } else if (status & MCI_DATATIMEOUT) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700540 pr_err("%s: Data timeout\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700541 data->error = -ETIMEDOUT;
542 } else if (status & MCI_RXOVERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700543 pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700544 data->error = -EIO;
545 } else if (status & MCI_TXUNDERRUN) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700546 pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700547 data->error = -EIO;
548 } else {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700549 pr_err("%s: Unknown error (0x%.8x)\n",
550 mmc_hostname(host->mmc), status);
San Mehat9d2bd732009-09-22 16:44:22 -0700551 data->error = -EIO;
552 }
553}
554
555
556static int
557msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
558{
San Mehat9d2bd732009-09-22 16:44:22 -0700559 uint32_t *ptr = (uint32_t *) buffer;
560 int count = 0;
561
San Mehat8b1c2ba2009-11-16 10:17:30 -0800562 while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) {
563 *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE));
San Mehat9d2bd732009-09-22 16:44:22 -0700564 ptr++;
565 count += sizeof(uint32_t);
566
567 remain -= sizeof(uint32_t);
568 if (remain == 0)
569 break;
570 }
571 return count;
572}
573
574static int
575msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
576 unsigned int remain, u32 status)
577{
578 void __iomem *base = host->base;
579 char *ptr = buffer;
580
581 do {
582 unsigned int count, maxcnt;
583
584 maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE :
585 MCI_FIFOHALFSIZE;
586 count = min(remain, maxcnt);
587
588 writesl(base + MMCIFIFO, ptr, count >> 2);
589 ptr += count;
590 remain -= count;
591
592 if (remain == 0)
593 break;
594
San Mehat8b1c2ba2009-11-16 10:17:30 -0800595 status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700596 } while (status & MCI_TXFIFOHALFEMPTY);
597
598 return ptr - buffer;
599}
600
601static int
602msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin)
603{
604 while (maxspin) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800605 if ((msmsdcc_readl(host, MMCISTATUS) & mask))
San Mehat9d2bd732009-09-22 16:44:22 -0700606 return 0;
607 udelay(1);
608 --maxspin;
609 }
610 return -ETIMEDOUT;
611}
612
613static int
614msmsdcc_pio_irq(int irq, void *dev_id)
615{
616 struct msmsdcc_host *host = dev_id;
San Mehat9d2bd732009-09-22 16:44:22 -0700617 uint32_t status;
618
San Mehat8b1c2ba2009-11-16 10:17:30 -0800619 status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700620
621 do {
622 unsigned long flags;
623 unsigned int remain, len;
624 char *buffer;
625
626 if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) {
627 if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll)
628 break;
629
630 if (msmsdcc_spin_on_status(host,
631 (MCI_TXFIFOHALFEMPTY |
632 MCI_RXDATAAVLBL),
633 PIO_SPINMAX)) {
634 break;
635 }
636 }
637
638 /* Map the current scatter buffer */
639 local_irq_save(flags);
640 buffer = kmap_atomic(sg_page(host->pio.sg),
641 KM_BIO_SRC_IRQ) + host->pio.sg->offset;
642 buffer += host->pio.sg_off;
643 remain = host->pio.sg->length - host->pio.sg_off;
644 len = 0;
645 if (status & MCI_RXACTIVE)
646 len = msmsdcc_pio_read(host, buffer, remain);
647 if (status & MCI_TXACTIVE)
648 len = msmsdcc_pio_write(host, buffer, remain, status);
649
650 /* Unmap the buffer */
651 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
652 local_irq_restore(flags);
653
654 host->pio.sg_off += len;
655 host->curr.xfer_remain -= len;
656 host->curr.data_xfered += len;
657 remain -= len;
658
659 if (remain == 0) {
660 /* This sg page is full - do some housekeeping */
661 if (status & MCI_RXACTIVE && host->curr.user_pages)
662 flush_dcache_page(sg_page(host->pio.sg));
663
664 if (!--host->pio.sg_len) {
665 memset(&host->pio, 0, sizeof(host->pio));
666 break;
667 }
668
669 /* Advance to next sg */
670 host->pio.sg++;
671 host->pio.sg_off = 0;
672 }
673
San Mehat8b1c2ba2009-11-16 10:17:30 -0800674 status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700675 } while (1);
676
677 if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE)
San Mehat8b1c2ba2009-11-16 10:17:30 -0800678 msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1);
San Mehat9d2bd732009-09-22 16:44:22 -0700679
680 if (!host->curr.xfer_remain)
San Mehat8b1c2ba2009-11-16 10:17:30 -0800681 msmsdcc_writel(host, 0, MMCIMASK1);
San Mehat9d2bd732009-09-22 16:44:22 -0700682
683 return IRQ_HANDLED;
684}
685
686static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
687{
688 struct mmc_command *cmd = host->curr.cmd;
San Mehat9d2bd732009-09-22 16:44:22 -0700689
690 host->curr.cmd = NULL;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800691 cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0);
692 cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1);
693 cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2);
694 cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3);
San Mehat9d2bd732009-09-22 16:44:22 -0700695
San Mehat9d2bd732009-09-22 16:44:22 -0700696 if (status & MCI_CMDTIMEOUT) {
697 cmd->error = -ETIMEDOUT;
698 } else if (status & MCI_CMDCRCFAIL &&
699 cmd->flags & MMC_RSP_CRC) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700700 pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
San Mehat9d2bd732009-09-22 16:44:22 -0700701 cmd->error = -EILSEQ;
702 }
703
704 if (!cmd->data || cmd->error) {
705 if (host->curr.data && host->dma.sg)
706 msm_dmov_stop_cmd(host->dma.channel,
707 &host->dma.hdr, 0);
708 else if (host->curr.data) { /* Non DMA */
709 msmsdcc_stop_data(host);
710 msmsdcc_request_end(host, cmd->mrq);
711 } else /* host->data == NULL */
712 msmsdcc_request_end(host, cmd->mrq);
San Mehat56a8b5b2009-11-21 12:29:46 -0800713 } else if (cmd->data)
714 if (!(cmd->data->flags & MMC_DATA_READ))
715 msmsdcc_start_data(host, cmd->data,
716 NULL, 0);
San Mehat9d2bd732009-09-22 16:44:22 -0700717}
718
Joe Perchesb5a74d62009-09-22 16:44:25 -0700719static void
720msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
721 void __iomem *base)
722{
San Mehatb3b0ca82009-11-24 12:24:55 -0800723 struct mmc_data *data = host->curr.data;
Joe Perchesb5a74d62009-09-22 16:44:25 -0700724
San Mehat56a8b5b2009-11-21 12:29:46 -0800725 if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
726 MCI_CMDTIMEOUT) && host->curr.cmd) {
727 msmsdcc_do_cmdirq(host, status);
728 }
729
Joe Perchesb5a74d62009-09-22 16:44:25 -0700730 if (!data)
731 return;
732
733 /* Check for data errors */
734 if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT |
735 MCI_TXUNDERRUN | MCI_RXOVERRUN)) {
736 msmsdcc_data_err(host, data, status);
737 host->curr.data_xfered = 0;
738 if (host->dma.sg)
739 msm_dmov_stop_cmd(host->dma.channel,
740 &host->dma.hdr, 0);
741 else {
San Mehatb3b0ca82009-11-24 12:24:55 -0800742 if (host->curr.data)
743 msmsdcc_stop_data(host);
Joe Perchesb5a74d62009-09-22 16:44:25 -0700744 if (!data->stop)
745 msmsdcc_request_end(host, data->mrq);
746 else
747 msmsdcc_start_command(host, data->stop, 0);
748 }
749 }
750
751 /* Check for data done */
752 if (!host->curr.got_dataend && (status & MCI_DATAEND))
753 host->curr.got_dataend = 1;
754
755 if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND))
756 host->curr.got_datablkend = 1;
757
758 /*
759 * If DMA is still in progress, we complete via the completion handler
760 */
761 if (host->curr.got_dataend && host->curr.got_datablkend &&
762 !host->dma.busy) {
763 /*
764 * There appears to be an issue in the controller where
765 * if you request a small block transfer (< fifo size),
766 * you may get your DATAEND/DATABLKEND irq without the
767 * PIO data irq.
768 *
769 * Check to see if there is still data to be read,
770 * and simulate a PIO irq.
771 */
772 if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL)
773 msmsdcc_pio_irq(1, host);
774
775 msmsdcc_stop_data(host);
776 if (!data->error)
777 host->curr.data_xfered = host->curr.xfer_size;
778
779 if (!data->stop)
780 msmsdcc_request_end(host, data->mrq);
781 else
782 msmsdcc_start_command(host, data->stop, 0);
783 }
784}
785
San Mehat9d2bd732009-09-22 16:44:22 -0700786static irqreturn_t
787msmsdcc_irq(int irq, void *dev_id)
788{
789 struct msmsdcc_host *host = dev_id;
790 void __iomem *base = host->base;
791 u32 status;
792 int ret = 0;
793 int cardint = 0;
794
795 spin_lock(&host->lock);
796
797 do {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800798 struct mmc_data *data;
799 status = msmsdcc_readl(host, MMCISTATUS);
800 status &= (msmsdcc_readl(host, MMCIMASK0) |
801 MCI_DATABLOCKENDMASK);
802 msmsdcc_writel(host, status, MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -0700803
San Mehat865c80642009-11-13 13:42:06 -0800804 if (status & MCI_SDIOINTR)
805 status &= ~MCI_SDIOINTR;
806
807 if (!status)
808 break;
809
Joe Perchesb5a74d62009-09-22 16:44:25 -0700810 msmsdcc_handle_irq_data(host, status, base);
San Mehat9d2bd732009-09-22 16:44:22 -0700811
San Mehat9d2bd732009-09-22 16:44:22 -0700812 if (status & MCI_SDIOINTOPER) {
813 cardint = 1;
814 status &= ~MCI_SDIOINTOPER;
815 }
816 ret = 1;
817 } while (status);
818
819 spin_unlock(&host->lock);
820
821 /*
822 * We have to delay handling the card interrupt as it calls
823 * back into the driver.
824 */
825 if (cardint)
826 mmc_signal_sdio_irq(host->mmc);
827
828 return IRQ_RETVAL(ret);
829}
830
831static void
832msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
833{
834 struct msmsdcc_host *host = mmc_priv(mmc);
835 unsigned long flags;
836
837 WARN_ON(host->curr.mrq != NULL);
838 WARN_ON(host->pwr == 0);
839
840 spin_lock_irqsave(&host->lock, flags);
841
842 host->stats.reqs++;
843
844 if (host->eject) {
845 if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
846 mrq->cmd->error = 0;
847 mrq->data->bytes_xfered = mrq->data->blksz *
848 mrq->data->blocks;
849 } else
850 mrq->cmd->error = -ENOMEDIUM;
851
852 spin_unlock_irqrestore(&host->lock, flags);
853 mmc_request_done(mmc, mrq);
854 return;
855 }
856
857 host->curr.mrq = mrq;
San Mehatc7fc9372009-11-22 17:19:07 -0800858
859 /* Need to drop the host lock here in case
860 * the busclk wd fires
861 */
862 spin_unlock_irqrestore(&host->lock, flags);
San Mehat865c80642009-11-13 13:42:06 -0800863 if (!host->clks_on)
San Mehatc7fc9372009-11-22 17:19:07 -0800864 msmsdcc_enable_clocks(host);
865 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -0700866
867 if (mrq->data && mrq->data->flags & MMC_DATA_READ)
San Mehat56a8b5b2009-11-21 12:29:46 -0800868 /* Queue/read data, daisy-chain command when data starts */
869 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
870 else
871 msmsdcc_start_command(host, mrq->cmd, 0);
San Mehat9d2bd732009-09-22 16:44:22 -0700872
873 if (host->cmdpoll && !msmsdcc_spin_on_status(host,
874 MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT,
875 CMD_SPINMAX)) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800876 uint32_t status = msmsdcc_readl(host, MMCISTATUS);
San Mehat9d2bd732009-09-22 16:44:22 -0700877 msmsdcc_do_cmdirq(host, status);
San Mehat8b1c2ba2009-11-16 10:17:30 -0800878 msmsdcc_writel(host,
879 MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT,
880 MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -0700881 host->stats.cmdpoll_hits++;
882 } else {
883 host->stats.cmdpoll_misses++;
San Mehat9d2bd732009-09-22 16:44:22 -0700884 }
885 spin_unlock_irqrestore(&host->lock, flags);
886}
887
888static void
889msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
890{
891 struct msmsdcc_host *host = mmc_priv(mmc);
892 u32 clk = 0, pwr = 0;
893 int rc;
San Mehat4adbbcc2009-11-08 13:00:37 -0800894 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -0700895
San Mehat865c80642009-11-13 13:42:06 -0800896 if (!host->clks_on)
San Mehatc7fc9372009-11-22 17:19:07 -0800897 msmsdcc_enable_clocks(host);
898
899 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -0700900
San Mehat865c80642009-11-13 13:42:06 -0800901 if (ios->clock) {
San Mehat9d2bd732009-09-22 16:44:22 -0700902 if (ios->clock != host->clk_rate) {
903 rc = clk_set_rate(host->clk, ios->clock);
904 if (rc < 0)
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700905 pr_err("%s: Error setting clock rate (%d)\n",
906 mmc_hostname(host->mmc), rc);
San Mehat9d2bd732009-09-22 16:44:22 -0700907 else
908 host->clk_rate = ios->clock;
909 }
910 clk |= MCI_CLK_ENABLE;
911 }
912
913 if (ios->bus_width == MMC_BUS_WIDTH_4)
914 clk |= (2 << 10); /* Set WIDEBUS */
915
916 if (ios->clock > 400000 && msmsdcc_pwrsave)
917 clk |= (1 << 9); /* PWRSAVE */
918
919 clk |= (1 << 12); /* FLOW_ENA */
920 clk |= (1 << 15); /* feedback clock */
921
922 if (host->plat->translate_vdd)
923 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
924
925 switch (ios->power_mode) {
926 case MMC_POWER_OFF:
San Mehat9d2bd732009-09-22 16:44:22 -0700927 break;
928 case MMC_POWER_UP:
929 pwr |= MCI_PWR_UP;
930 break;
931 case MMC_POWER_ON:
San Mehat9d2bd732009-09-22 16:44:22 -0700932 pwr |= MCI_PWR_ON;
933 break;
934 }
935
936 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
937 pwr |= MCI_OD;
938
San Mehat8b1c2ba2009-11-16 10:17:30 -0800939 msmsdcc_writel(host, clk, MMCICLOCK);
San Mehat9d2bd732009-09-22 16:44:22 -0700940
941 if (host->pwr != pwr) {
942 host->pwr = pwr;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800943 msmsdcc_writel(host, pwr, MMCIPOWER);
San Mehat9d2bd732009-09-22 16:44:22 -0700944 }
San Mehatf4748492009-11-23 15:36:31 -0800945#if BUSCLK_PWRSAVE
San Mehatc7fc9372009-11-22 17:19:07 -0800946 msmsdcc_disable_clocks(host, 1);
San Mehatf4748492009-11-23 15:36:31 -0800947#endif
San Mehat4adbbcc2009-11-08 13:00:37 -0800948 spin_unlock_irqrestore(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -0700949}
950
951static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
952{
953 struct msmsdcc_host *host = mmc_priv(mmc);
954 unsigned long flags;
955 u32 status;
956
957 spin_lock_irqsave(&host->lock, flags);
958 if (msmsdcc_sdioirq == 1) {
San Mehat8b1c2ba2009-11-16 10:17:30 -0800959 status = msmsdcc_readl(host, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -0700960 if (enable)
961 status |= MCI_SDIOINTOPERMASK;
962 else
963 status &= ~MCI_SDIOINTOPERMASK;
964 host->saved_irq0mask = status;
San Mehat8b1c2ba2009-11-16 10:17:30 -0800965 msmsdcc_writel(host, status, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -0700966 }
967 spin_unlock_irqrestore(&host->lock, flags);
968}
969
970static const struct mmc_host_ops msmsdcc_ops = {
971 .request = msmsdcc_request,
972 .set_ios = msmsdcc_set_ios,
973 .enable_sdio_irq = msmsdcc_enable_sdio_irq,
974};
975
976static void
977msmsdcc_check_status(unsigned long data)
978{
979 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
980 unsigned int status;
981
982 if (!host->plat->status) {
983 mmc_detect_change(host->mmc, 0);
984 goto out;
985 }
986
987 status = host->plat->status(mmc_dev(host->mmc));
988 host->eject = !status;
989 if (status ^ host->oldstat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -0700990 pr_info("%s: Slot status change detected (%d -> %d)\n",
991 mmc_hostname(host->mmc), host->oldstat, status);
San Mehat9d2bd732009-09-22 16:44:22 -0700992 if (status)
993 mmc_detect_change(host->mmc, (5 * HZ) / 2);
994 else
995 mmc_detect_change(host->mmc, 0);
996 }
997
998 host->oldstat = status;
999
1000out:
1001 if (host->timer.function)
1002 mod_timer(&host->timer, jiffies + HZ);
1003}
1004
1005static irqreturn_t
1006msmsdcc_platform_status_irq(int irq, void *dev_id)
1007{
1008 struct msmsdcc_host *host = dev_id;
1009
1010 printk(KERN_DEBUG "%s: %d\n", __func__, irq);
1011 msmsdcc_check_status((unsigned long) host);
1012 return IRQ_HANDLED;
1013}
1014
1015static void
1016msmsdcc_status_notify_cb(int card_present, void *dev_id)
1017{
1018 struct msmsdcc_host *host = dev_id;
1019
1020 printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc),
1021 card_present);
1022 msmsdcc_check_status((unsigned long) host);
1023}
1024
San Mehat865c80642009-11-13 13:42:06 -08001025static void
1026msmsdcc_busclk_expired(unsigned long _data)
1027{
1028 struct msmsdcc_host *host = (struct msmsdcc_host *) _data;
1029 unsigned long flags;
1030
1031 spin_lock_irqsave(&host->lock, flags);
San Mehatc7fc9372009-11-22 17:19:07 -08001032 dev_info(mmc_dev(host->mmc), "Bus clock timer expired\n");
San Mehat865c80642009-11-13 13:42:06 -08001033 if (host->clks_on)
San Mehatc7fc9372009-11-22 17:19:07 -08001034 msmsdcc_disable_clocks(host, 0);
San Mehat865c80642009-11-13 13:42:06 -08001035 spin_unlock_irqrestore(&host->lock, flags);
1036}
1037
San Mehat9d2bd732009-09-22 16:44:22 -07001038static int
1039msmsdcc_init_dma(struct msmsdcc_host *host)
1040{
1041 memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
1042 host->dma.host = host;
1043 host->dma.channel = -1;
1044
1045 if (!host->dmares)
1046 return -ENODEV;
1047
1048 host->dma.nc = dma_alloc_coherent(NULL,
1049 sizeof(struct msmsdcc_nc_dmadata),
1050 &host->dma.nc_busaddr,
1051 GFP_KERNEL);
1052 if (host->dma.nc == NULL) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001053 pr_err("Unable to allocate DMA buffer\n");
San Mehat9d2bd732009-09-22 16:44:22 -07001054 return -ENOMEM;
1055 }
1056 memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
1057 host->dma.cmd_busaddr = host->dma.nc_busaddr;
1058 host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
1059 offsetof(struct msmsdcc_nc_dmadata, cmdptr);
1060 host->dma.channel = host->dmares->start;
1061
1062 return 0;
1063}
1064
1065#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ
1066static void
1067do_resume_work(struct work_struct *work)
1068{
1069 struct msmsdcc_host *host =
1070 container_of(work, struct msmsdcc_host, resume_task);
1071 struct mmc_host *mmc = host->mmc;
1072
1073 if (mmc) {
1074 mmc_resume_host(mmc);
1075 if (host->stat_irq)
1076 enable_irq(host->stat_irq);
1077 }
1078}
1079#endif
1080
1081static int
1082msmsdcc_probe(struct platform_device *pdev)
1083{
1084 struct mmc_platform_data *plat = pdev->dev.platform_data;
1085 struct msmsdcc_host *host;
1086 struct mmc_host *mmc;
1087 struct resource *cmd_irqres = NULL;
1088 struct resource *pio_irqres = NULL;
1089 struct resource *stat_irqres = NULL;
1090 struct resource *memres = NULL;
1091 struct resource *dmares = NULL;
1092 int ret;
1093
1094 /* must have platform data */
1095 if (!plat) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001096 pr_err("%s: Platform data not available\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07001097 ret = -EINVAL;
1098 goto out;
1099 }
1100
1101 if (pdev->id < 1 || pdev->id > 4)
1102 return -EINVAL;
1103
1104 if (pdev->resource == NULL || pdev->num_resources < 2) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001105 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07001106 return -ENXIO;
1107 }
1108
1109 memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1110 dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
1111 cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1112 "cmd_irq");
1113 pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1114 "pio_irq");
1115 stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1116 "status_irq");
1117
1118 if (!cmd_irqres || !pio_irqres || !memres) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001119 pr_err("%s: Invalid resource\n", __func__);
San Mehat9d2bd732009-09-22 16:44:22 -07001120 return -ENXIO;
1121 }
1122
1123 /*
1124 * Setup our host structure
1125 */
1126
1127 mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
1128 if (!mmc) {
1129 ret = -ENOMEM;
1130 goto out;
1131 }
1132
1133 host = mmc_priv(mmc);
1134 host->pdev_id = pdev->id;
1135 host->plat = plat;
1136 host->mmc = mmc;
San Mehat56a8b5b2009-11-21 12:29:46 -08001137 host->curr.cmd = NULL;
San Mehat9d2bd732009-09-22 16:44:22 -07001138
1139 host->cmdpoll = 1;
1140
1141 host->base = ioremap(memres->start, PAGE_SIZE);
1142 if (!host->base) {
1143 ret = -ENOMEM;
1144 goto out;
1145 }
1146
1147 host->cmd_irqres = cmd_irqres;
1148 host->pio_irqres = pio_irqres;
1149 host->memres = memres;
1150 host->dmares = dmares;
1151 spin_lock_init(&host->lock);
1152
1153 /*
1154 * Setup DMA
1155 */
1156 msmsdcc_init_dma(host);
1157
San Mehat4adbbcc2009-11-08 13:00:37 -08001158 /* Get our clocks */
San Mehat9d2bd732009-09-22 16:44:22 -07001159 host->pclk = clk_get(&pdev->dev, "sdc_pclk");
1160 if (IS_ERR(host->pclk)) {
1161 ret = PTR_ERR(host->pclk);
1162 goto host_free;
1163 }
1164
San Mehat9d2bd732009-09-22 16:44:22 -07001165 host->clk = clk_get(&pdev->dev, "sdc_clk");
1166 if (IS_ERR(host->clk)) {
1167 ret = PTR_ERR(host->clk);
San Mehat4adbbcc2009-11-08 13:00:37 -08001168 goto pclk_put;
San Mehat9d2bd732009-09-22 16:44:22 -07001169 }
1170
San Mehat4adbbcc2009-11-08 13:00:37 -08001171 /* Enable clocks */
San Mehatc7fc9372009-11-22 17:19:07 -08001172 ret = msmsdcc_enable_clocks(host);
San Mehat9d2bd732009-09-22 16:44:22 -07001173 if (ret)
1174 goto clk_put;
1175
1176 ret = clk_set_rate(host->clk, msmsdcc_fmin);
1177 if (ret) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001178 pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07001179 goto clk_disable;
1180 }
1181
San Mehat4adbbcc2009-11-08 13:00:37 -08001182 host->pclk_rate = clk_get_rate(host->pclk);
San Mehat9d2bd732009-09-22 16:44:22 -07001183 host->clk_rate = clk_get_rate(host->clk);
1184
San Mehat9d2bd732009-09-22 16:44:22 -07001185 /*
1186 * Setup MMC host structure
1187 */
1188 mmc->ops = &msmsdcc_ops;
1189 mmc->f_min = msmsdcc_fmin;
1190 mmc->f_max = msmsdcc_fmax;
1191 mmc->ocr_avail = plat->ocr_mask;
1192
1193 if (msmsdcc_4bit)
1194 mmc->caps |= MMC_CAP_4_BIT_DATA;
1195 if (msmsdcc_sdioirq)
1196 mmc->caps |= MMC_CAP_SDIO_IRQ;
1197 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
1198
1199 mmc->max_phys_segs = NR_SG;
1200 mmc->max_hw_segs = NR_SG;
1201 mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
1202 mmc->max_blk_count = 65536;
1203
1204 mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
1205 mmc->max_seg_size = mmc->max_req_size;
1206
San Mehat8b1c2ba2009-11-16 10:17:30 -08001207 msmsdcc_writel(host, 0, MMCIMASK0);
1208 msmsdcc_writel(host, 0x5e007ff, MMCICLEAR);
San Mehat9d2bd732009-09-22 16:44:22 -07001209
San Mehat8b1c2ba2009-11-16 10:17:30 -08001210 msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -07001211 host->saved_irq0mask = MCI_IRQENABLE;
1212
1213 /*
1214 * Setup card detect change
1215 */
1216
1217 memset(&host->timer, 0, sizeof(host->timer));
1218
1219 if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) {
1220 unsigned long irqflags = IRQF_SHARED |
1221 (stat_irqres->flags & IRQF_TRIGGER_MASK);
1222
1223 host->stat_irq = stat_irqres->start;
1224 ret = request_irq(host->stat_irq,
1225 msmsdcc_platform_status_irq,
1226 irqflags,
1227 DRIVER_NAME " (slot)",
1228 host);
1229 if (ret) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001230 pr_err("%s: Unable to get slot IRQ %d (%d)\n",
1231 mmc_hostname(mmc), host->stat_irq, ret);
San Mehat9d2bd732009-09-22 16:44:22 -07001232 goto clk_disable;
1233 }
1234 } else if (plat->register_status_notify) {
1235 plat->register_status_notify(msmsdcc_status_notify_cb, host);
1236 } else if (!plat->status)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001237 pr_err("%s: No card detect facilities available\n",
San Mehat9d2bd732009-09-22 16:44:22 -07001238 mmc_hostname(mmc));
1239 else {
1240 init_timer(&host->timer);
1241 host->timer.data = (unsigned long)host;
1242 host->timer.function = msmsdcc_check_status;
1243 host->timer.expires = jiffies + HZ;
1244 add_timer(&host->timer);
1245 }
1246
1247 if (plat->status) {
1248 host->oldstat = host->plat->status(mmc_dev(host->mmc));
1249 host->eject = !host->oldstat;
1250 }
1251
San Mehat865c80642009-11-13 13:42:06 -08001252 init_timer(&host->busclk_timer);
1253 host->busclk_timer.data = (unsigned long) host;
1254 host->busclk_timer.function = msmsdcc_busclk_expired;
1255
San Mehat9d2bd732009-09-22 16:44:22 -07001256 ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED,
1257 DRIVER_NAME " (cmd)", host);
1258 if (ret)
1259 goto stat_irq_free;
1260
1261 ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
1262 DRIVER_NAME " (pio)", host);
1263 if (ret)
1264 goto cmd_irq_free;
1265
1266 mmc_set_drvdata(pdev, mmc);
1267 mmc_add_host(mmc);
1268
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001269 pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n",
1270 mmc_hostname(mmc), (unsigned long long)memres->start,
1271 (unsigned int) cmd_irqres->start,
1272 (unsigned int) host->stat_irq, host->dma.channel);
1273 pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
1274 (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
1275 pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
1276 mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate);
1277 pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject);
1278 pr_info("%s: Power save feature enable = %d\n",
1279 mmc_hostname(mmc), msmsdcc_pwrsave);
San Mehat9d2bd732009-09-22 16:44:22 -07001280
1281 if (host->dma.channel != -1) {
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001282 pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
1283 mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
1284 pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
1285 mmc_hostname(mmc), host->dma.cmd_busaddr,
1286 host->dma.cmdptr_busaddr);
San Mehat9d2bd732009-09-22 16:44:22 -07001287 } else
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001288 pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001289 if (host->timer.function)
Joe Perches0a7ff7c2009-09-22 16:44:23 -07001290 pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
San Mehat9d2bd732009-09-22 16:44:22 -07001291
San Mehatf4748492009-11-23 15:36:31 -08001292#if BUSCLK_PWRSAVE
San Mehatc7fc9372009-11-22 17:19:07 -08001293 msmsdcc_disable_clocks(host, 1);
San Mehatf4748492009-11-23 15:36:31 -08001294#endif
San Mehat9d2bd732009-09-22 16:44:22 -07001295 return 0;
1296 cmd_irq_free:
1297 free_irq(cmd_irqres->start, host);
1298 stat_irq_free:
1299 if (host->stat_irq)
1300 free_irq(host->stat_irq, host);
1301 clk_disable:
San Mehatc7fc9372009-11-22 17:19:07 -08001302 msmsdcc_disable_clocks(host, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07001303 clk_put:
1304 clk_put(host->clk);
San Mehat9d2bd732009-09-22 16:44:22 -07001305 pclk_put:
1306 clk_put(host->pclk);
1307 host_free:
1308 mmc_free_host(mmc);
1309 out:
1310 return ret;
1311}
1312
1313static int
1314msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
1315{
1316 struct mmc_host *mmc = mmc_get_drvdata(dev);
1317 int rc = 0;
San Mehat56a8b5b2009-11-21 12:29:46 -08001318 unsigned long flags;
San Mehat9d2bd732009-09-22 16:44:22 -07001319
1320 if (mmc) {
1321 struct msmsdcc_host *host = mmc_priv(mmc);
1322
San Mehat56a8b5b2009-11-21 12:29:46 -08001323 spin_lock_irqsave(&host->lock, flags);
San Mehat9d2bd732009-09-22 16:44:22 -07001324 if (host->stat_irq)
1325 disable_irq(host->stat_irq);
1326
1327 if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
1328 rc = mmc_suspend_host(mmc, state);
1329 if (!rc) {
San Mehat8b1c2ba2009-11-16 10:17:30 -08001330 msmsdcc_writel(host, 0, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -07001331
San Mehat9d2bd732009-09-22 16:44:22 -07001332 }
San Mehat56a8b5b2009-11-21 12:29:46 -08001333 spin_unlock_irqrestore(&host->lock, flags);
San Mehatc7fc9372009-11-22 17:19:07 -08001334 if (host->clks_on)
1335 msmsdcc_disable_clocks(host, 0);
San Mehat9d2bd732009-09-22 16:44:22 -07001336 }
1337 return rc;
1338}
1339
1340static int
1341msmsdcc_resume(struct platform_device *dev)
1342{
1343 struct mmc_host *mmc = mmc_get_drvdata(dev);
San Mehat9d2bd732009-09-22 16:44:22 -07001344
1345 if (mmc) {
1346 struct msmsdcc_host *host = mmc_priv(mmc);
1347
San Mehatc7fc9372009-11-22 17:19:07 -08001348 msmsdcc_enable_clocks(host);
San Mehat56a8b5b2009-11-21 12:29:46 -08001349
San Mehat8b1c2ba2009-11-16 10:17:30 -08001350 msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0);
San Mehat9d2bd732009-09-22 16:44:22 -07001351
San Mehat9d2bd732009-09-22 16:44:22 -07001352 if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
1353 mmc_resume_host(mmc);
Roel Kluin5b8a2fb2010-01-17 20:25:36 +01001354 if (host->stat_irq)
San Mehat9d2bd732009-09-22 16:44:22 -07001355 enable_irq(host->stat_irq);
San Mehatf4748492009-11-23 15:36:31 -08001356#if BUSCLK_PWRSAVE
San Mehatc7fc9372009-11-22 17:19:07 -08001357 msmsdcc_disable_clocks(host, 1);
San Mehatf4748492009-11-23 15:36:31 -08001358#endif
San Mehat9d2bd732009-09-22 16:44:22 -07001359 }
1360 return 0;
1361}
1362
1363static struct platform_driver msmsdcc_driver = {
1364 .probe = msmsdcc_probe,
1365 .suspend = msmsdcc_suspend,
1366 .resume = msmsdcc_resume,
1367 .driver = {
1368 .name = "msm_sdcc",
1369 },
1370};
1371
1372static int __init msmsdcc_init(void)
1373{
1374 return platform_driver_register(&msmsdcc_driver);
1375}
1376
1377static void __exit msmsdcc_exit(void)
1378{
1379 platform_driver_unregister(&msmsdcc_driver);
1380}
1381
1382module_init(msmsdcc_init);
1383module_exit(msmsdcc_exit);
1384
1385MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver");
1386MODULE_LICENSE("GPL");