blob: 74e7aca271d45ee68418a1b9e0ca169f611adddc [file] [log] [blame]
Yusuke Godafdc50a92010-05-26 14:41:59 -07001/*
2 * MMCIF eMMC driver.
3 *
4 * Copyright (C) 2010 Renesas Solutions Corp.
5 * Yusuke Goda <yusuke.goda.sx@renesas.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License.
10 *
11 *
12 * TODO
13 * 1. DMA
14 * 2. Power management
15 * 3. Handle MMC errors better
16 *
17 */
18
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +000019#include <linux/clk.h>
20#include <linux/completion.h>
Yusuke Godafdc50a92010-05-26 14:41:59 -070021#include <linux/dma-mapping.h>
22#include <linux/mmc/host.h>
23#include <linux/mmc/card.h>
24#include <linux/mmc/core.h>
25#include <linux/mmc/mmc.h>
26#include <linux/mmc/sdio.h>
27#include <linux/delay.h>
28#include <linux/platform_device.h>
Yusuke Godafdc50a92010-05-26 14:41:59 -070029#include <linux/mmc/sh_mmcif.h>
30
31#define DRIVER_NAME "sh_mmcif"
32#define DRIVER_VERSION "2010-04-28"
33
Yusuke Godafdc50a92010-05-26 14:41:59 -070034/* CE_CMD_SET */
35#define CMD_MASK 0x3f000000
36#define CMD_SET_RTYP_NO ((0 << 23) | (0 << 22))
37#define CMD_SET_RTYP_6B ((0 << 23) | (1 << 22)) /* R1/R1b/R3/R4/R5 */
38#define CMD_SET_RTYP_17B ((1 << 23) | (0 << 22)) /* R2 */
39#define CMD_SET_RBSY (1 << 21) /* R1b */
40#define CMD_SET_CCSEN (1 << 20)
41#define CMD_SET_WDAT (1 << 19) /* 1: on data, 0: no data */
42#define CMD_SET_DWEN (1 << 18) /* 1: write, 0: read */
43#define CMD_SET_CMLTE (1 << 17) /* 1: multi block trans, 0: single */
44#define CMD_SET_CMD12EN (1 << 16) /* 1: CMD12 auto issue */
45#define CMD_SET_RIDXC_INDEX ((0 << 15) | (0 << 14)) /* index check */
46#define CMD_SET_RIDXC_BITS ((0 << 15) | (1 << 14)) /* check bits check */
47#define CMD_SET_RIDXC_NO ((1 << 15) | (0 << 14)) /* no check */
48#define CMD_SET_CRC7C ((0 << 13) | (0 << 12)) /* CRC7 check*/
49#define CMD_SET_CRC7C_BITS ((0 << 13) | (1 << 12)) /* check bits check*/
50#define CMD_SET_CRC7C_INTERNAL ((1 << 13) | (0 << 12)) /* internal CRC7 check*/
51#define CMD_SET_CRC16C (1 << 10) /* 0: CRC16 check*/
52#define CMD_SET_CRCSTE (1 << 8) /* 1: not receive CRC status */
53#define CMD_SET_TBIT (1 << 7) /* 1: tran mission bit "Low" */
54#define CMD_SET_OPDM (1 << 6) /* 1: open/drain */
55#define CMD_SET_CCSH (1 << 5)
56#define CMD_SET_DATW_1 ((0 << 1) | (0 << 0)) /* 1bit */
57#define CMD_SET_DATW_4 ((0 << 1) | (1 << 0)) /* 4bit */
58#define CMD_SET_DATW_8 ((1 << 1) | (0 << 0)) /* 8bit */
59
60/* CE_CMD_CTRL */
61#define CMD_CTRL_BREAK (1 << 0)
62
63/* CE_BLOCK_SET */
64#define BLOCK_SIZE_MASK 0x0000ffff
65
Yusuke Godafdc50a92010-05-26 14:41:59 -070066/* CE_INT */
67#define INT_CCSDE (1 << 29)
68#define INT_CMD12DRE (1 << 26)
69#define INT_CMD12RBE (1 << 25)
70#define INT_CMD12CRE (1 << 24)
71#define INT_DTRANE (1 << 23)
72#define INT_BUFRE (1 << 22)
73#define INT_BUFWEN (1 << 21)
74#define INT_BUFREN (1 << 20)
75#define INT_CCSRCV (1 << 19)
76#define INT_RBSYE (1 << 17)
77#define INT_CRSPE (1 << 16)
78#define INT_CMDVIO (1 << 15)
79#define INT_BUFVIO (1 << 14)
80#define INT_WDATERR (1 << 11)
81#define INT_RDATERR (1 << 10)
82#define INT_RIDXERR (1 << 9)
83#define INT_RSPERR (1 << 8)
84#define INT_CCSTO (1 << 5)
85#define INT_CRCSTO (1 << 4)
86#define INT_WDATTO (1 << 3)
87#define INT_RDATTO (1 << 2)
88#define INT_RBSYTO (1 << 1)
89#define INT_RSPTO (1 << 0)
90#define INT_ERR_STS (INT_CMDVIO | INT_BUFVIO | INT_WDATERR | \
91 INT_RDATERR | INT_RIDXERR | INT_RSPERR | \
92 INT_CCSTO | INT_CRCSTO | INT_WDATTO | \
93 INT_RDATTO | INT_RBSYTO | INT_RSPTO)
94
95/* CE_INT_MASK */
96#define MASK_ALL 0x00000000
97#define MASK_MCCSDE (1 << 29)
98#define MASK_MCMD12DRE (1 << 26)
99#define MASK_MCMD12RBE (1 << 25)
100#define MASK_MCMD12CRE (1 << 24)
101#define MASK_MDTRANE (1 << 23)
102#define MASK_MBUFRE (1 << 22)
103#define MASK_MBUFWEN (1 << 21)
104#define MASK_MBUFREN (1 << 20)
105#define MASK_MCCSRCV (1 << 19)
106#define MASK_MRBSYE (1 << 17)
107#define MASK_MCRSPE (1 << 16)
108#define MASK_MCMDVIO (1 << 15)
109#define MASK_MBUFVIO (1 << 14)
110#define MASK_MWDATERR (1 << 11)
111#define MASK_MRDATERR (1 << 10)
112#define MASK_MRIDXERR (1 << 9)
113#define MASK_MRSPERR (1 << 8)
114#define MASK_MCCSTO (1 << 5)
115#define MASK_MCRCSTO (1 << 4)
116#define MASK_MWDATTO (1 << 3)
117#define MASK_MRDATTO (1 << 2)
118#define MASK_MRBSYTO (1 << 1)
119#define MASK_MRSPTO (1 << 0)
120
121/* CE_HOST_STS1 */
122#define STS1_CMDSEQ (1 << 31)
123
124/* CE_HOST_STS2 */
125#define STS2_CRCSTE (1 << 31)
126#define STS2_CRC16E (1 << 30)
127#define STS2_AC12CRCE (1 << 29)
128#define STS2_RSPCRC7E (1 << 28)
129#define STS2_CRCSTEBE (1 << 27)
130#define STS2_RDATEBE (1 << 26)
131#define STS2_AC12REBE (1 << 25)
132#define STS2_RSPEBE (1 << 24)
133#define STS2_AC12IDXE (1 << 23)
134#define STS2_RSPIDXE (1 << 22)
135#define STS2_CCSTO (1 << 15)
136#define STS2_RDATTO (1 << 14)
137#define STS2_DATBSYTO (1 << 13)
138#define STS2_CRCSTTO (1 << 12)
139#define STS2_AC12BSYTO (1 << 11)
140#define STS2_RSPBSYTO (1 << 10)
141#define STS2_AC12RSPTO (1 << 9)
142#define STS2_RSPTO (1 << 8)
143#define STS2_CRC_ERR (STS2_CRCSTE | STS2_CRC16E | \
144 STS2_AC12CRCE | STS2_RSPCRC7E | STS2_CRCSTEBE)
145#define STS2_TIMEOUT_ERR (STS2_CCSTO | STS2_RDATTO | \
146 STS2_DATBSYTO | STS2_CRCSTTO | \
147 STS2_AC12BSYTO | STS2_RSPBSYTO | \
148 STS2_AC12RSPTO | STS2_RSPTO)
149
Yusuke Godafdc50a92010-05-26 14:41:59 -0700150#define CLKDEV_EMMC_DATA 52000000 /* 52MHz */
151#define CLKDEV_MMC_DATA 20000000 /* 20MHz */
152#define CLKDEV_INIT 400000 /* 400 KHz */
153
154struct sh_mmcif_host {
155 struct mmc_host *mmc;
156 struct mmc_data *data;
157 struct mmc_command *cmd;
158 struct platform_device *pd;
159 struct clk *hclk;
160 unsigned int clk;
161 int bus_width;
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000162 bool sd_error;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700163 long timeout;
164 void __iomem *addr;
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000165 struct completion intr_wait;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700166};
167
Yusuke Godafdc50a92010-05-26 14:41:59 -0700168
169static inline void sh_mmcif_bitset(struct sh_mmcif_host *host,
170 unsigned int reg, u32 val)
171{
Magnus Damm487d9fc2010-05-18 14:42:51 +0000172 writel(val | readl(host->addr + reg), host->addr + reg);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700173}
174
175static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
176 unsigned int reg, u32 val)
177{
Magnus Damm487d9fc2010-05-18 14:42:51 +0000178 writel(~val & readl(host->addr + reg), host->addr + reg);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700179}
180
181
182static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
183{
184 struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
185
186 sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
187 sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR);
188
189 if (!clk)
190 return;
191 if (p->sup_pclk && clk == host->clk)
192 sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
193 else
194 sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
195 (ilog2(__rounddown_pow_of_two(host->clk / clk)) << 16));
196
197 sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
198}
199
200static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
201{
202 u32 tmp;
203
Magnus Damm487d9fc2010-05-18 14:42:51 +0000204 tmp = 0x010f0000 & sh_mmcif_readl(host->addr, MMCIF_CE_CLK_CTRL);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700205
Magnus Damm487d9fc2010-05-18 14:42:51 +0000206 sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON);
207 sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700208 sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp |
209 SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29);
210 /* byte swap on */
211 sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP);
212}
213
214static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
215{
216 u32 state1, state2;
217 int ret, timeout = 10000000;
218
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000219 host->sd_error = false;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700220
Magnus Damm487d9fc2010-05-18 14:42:51 +0000221 state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1);
222 state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2);
223 pr_debug("%s: ERR HOST_STS1 = %08x\n", DRIVER_NAME, state1);
224 pr_debug("%s: ERR HOST_STS2 = %08x\n", DRIVER_NAME, state2);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700225
226 if (state1 & STS1_CMDSEQ) {
227 sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
228 sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
229 while (1) {
230 timeout--;
231 if (timeout < 0) {
232 pr_err(DRIVER_NAME": Forceed end of " \
233 "command sequence timeout err\n");
234 return -EIO;
235 }
Magnus Damm487d9fc2010-05-18 14:42:51 +0000236 if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
Yusuke Godafdc50a92010-05-26 14:41:59 -0700237 & STS1_CMDSEQ))
238 break;
239 mdelay(1);
240 }
241 sh_mmcif_sync_reset(host);
242 pr_debug(DRIVER_NAME": Forced end of command sequence\n");
243 return -EIO;
244 }
245
246 if (state2 & STS2_CRC_ERR) {
247 pr_debug(DRIVER_NAME": Happened CRC error\n");
248 ret = -EIO;
249 } else if (state2 & STS2_TIMEOUT_ERR) {
250 pr_debug(DRIVER_NAME": Happened Timeout error\n");
251 ret = -ETIMEDOUT;
252 } else {
253 pr_debug(DRIVER_NAME": Happened End/Index error\n");
254 ret = -EIO;
255 }
256 return ret;
257}
258
259static int sh_mmcif_single_read(struct sh_mmcif_host *host,
260 struct mmc_request *mrq)
261{
262 struct mmc_data *data = mrq->data;
263 long time;
264 u32 blocksize, i, *p = sg_virt(data->sg);
265
Yusuke Godafdc50a92010-05-26 14:41:59 -0700266 /* buf read enable */
267 sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000268 time = wait_for_completion_interruptible_timeout(&host->intr_wait,
269 host->timeout);
270 if (time <= 0 || host->sd_error)
Yusuke Godafdc50a92010-05-26 14:41:59 -0700271 return sh_mmcif_error_manage(host);
272
Yusuke Godafdc50a92010-05-26 14:41:59 -0700273 blocksize = (BLOCK_SIZE_MASK &
Magnus Damm487d9fc2010-05-18 14:42:51 +0000274 sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700275 for (i = 0; i < blocksize / 4; i++)
Magnus Damm487d9fc2010-05-18 14:42:51 +0000276 *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700277
278 /* buffer read end */
279 sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000280 time = wait_for_completion_interruptible_timeout(&host->intr_wait,
281 host->timeout);
282 if (time <= 0 || host->sd_error)
Yusuke Godafdc50a92010-05-26 14:41:59 -0700283 return sh_mmcif_error_manage(host);
284
Yusuke Godafdc50a92010-05-26 14:41:59 -0700285 return 0;
286}
287
288static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
289 struct mmc_request *mrq)
290{
291 struct mmc_data *data = mrq->data;
292 long time;
293 u32 blocksize, i, j, sec, *p;
294
Magnus Damm487d9fc2010-05-18 14:42:51 +0000295 blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
296 MMCIF_CE_BLOCK_SET);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700297 for (j = 0; j < data->sg_len; j++) {
298 p = sg_virt(data->sg);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700299 for (sec = 0; sec < data->sg->length / blocksize; sec++) {
300 sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
301 /* buf read enable */
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000302 time = wait_for_completion_interruptible_timeout(&host->intr_wait,
303 host->timeout);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700304
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000305 if (time <= 0 || host->sd_error)
Yusuke Godafdc50a92010-05-26 14:41:59 -0700306 return sh_mmcif_error_manage(host);
307
Yusuke Godafdc50a92010-05-26 14:41:59 -0700308 for (i = 0; i < blocksize / 4; i++)
Magnus Damm487d9fc2010-05-18 14:42:51 +0000309 *p++ = sh_mmcif_readl(host->addr,
310 MMCIF_CE_DATA);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700311 }
312 if (j < data->sg_len - 1)
313 data->sg++;
314 }
315 return 0;
316}
317
318static int sh_mmcif_single_write(struct sh_mmcif_host *host,
319 struct mmc_request *mrq)
320{
321 struct mmc_data *data = mrq->data;
322 long time;
323 u32 blocksize, i, *p = sg_virt(data->sg);
324
Yusuke Godafdc50a92010-05-26 14:41:59 -0700325 sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
326
327 /* buf write enable */
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000328 time = wait_for_completion_interruptible_timeout(&host->intr_wait,
329 host->timeout);
330 if (time <= 0 || host->sd_error)
Yusuke Godafdc50a92010-05-26 14:41:59 -0700331 return sh_mmcif_error_manage(host);
332
Yusuke Godafdc50a92010-05-26 14:41:59 -0700333 blocksize = (BLOCK_SIZE_MASK &
Magnus Damm487d9fc2010-05-18 14:42:51 +0000334 sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700335 for (i = 0; i < blocksize / 4; i++)
Magnus Damm487d9fc2010-05-18 14:42:51 +0000336 sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700337
338 /* buffer write end */
339 sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
340
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000341 time = wait_for_completion_interruptible_timeout(&host->intr_wait,
342 host->timeout);
343 if (time <= 0 || host->sd_error)
Yusuke Godafdc50a92010-05-26 14:41:59 -0700344 return sh_mmcif_error_manage(host);
345
Yusuke Godafdc50a92010-05-26 14:41:59 -0700346 return 0;
347}
348
349static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
350 struct mmc_request *mrq)
351{
352 struct mmc_data *data = mrq->data;
353 long time;
354 u32 i, sec, j, blocksize, *p;
355
Magnus Damm487d9fc2010-05-18 14:42:51 +0000356 blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
357 MMCIF_CE_BLOCK_SET);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700358
359 for (j = 0; j < data->sg_len; j++) {
360 p = sg_virt(data->sg);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700361 for (sec = 0; sec < data->sg->length / blocksize; sec++) {
362 sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
363 /* buf write enable*/
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000364 time = wait_for_completion_interruptible_timeout(&host->intr_wait,
365 host->timeout);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700366
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000367 if (time <= 0 || host->sd_error)
Yusuke Godafdc50a92010-05-26 14:41:59 -0700368 return sh_mmcif_error_manage(host);
369
Yusuke Godafdc50a92010-05-26 14:41:59 -0700370 for (i = 0; i < blocksize / 4; i++)
Magnus Damm487d9fc2010-05-18 14:42:51 +0000371 sh_mmcif_writel(host->addr,
372 MMCIF_CE_DATA, *p++);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700373 }
374 if (j < data->sg_len - 1)
375 data->sg++;
376 }
377 return 0;
378}
379
380static void sh_mmcif_get_response(struct sh_mmcif_host *host,
381 struct mmc_command *cmd)
382{
383 if (cmd->flags & MMC_RSP_136) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000384 cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP3);
385 cmd->resp[1] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP2);
386 cmd->resp[2] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP1);
387 cmd->resp[3] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700388 } else
Magnus Damm487d9fc2010-05-18 14:42:51 +0000389 cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700390}
391
392static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
393 struct mmc_command *cmd)
394{
Magnus Damm487d9fc2010-05-18 14:42:51 +0000395 cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP_CMD12);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700396}
397
398static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
399 struct mmc_request *mrq, struct mmc_command *cmd, u32 opc)
400{
401 u32 tmp = 0;
402
403 /* Response Type check */
404 switch (mmc_resp_type(cmd)) {
405 case MMC_RSP_NONE:
406 tmp |= CMD_SET_RTYP_NO;
407 break;
408 case MMC_RSP_R1:
409 case MMC_RSP_R1B:
410 case MMC_RSP_R3:
411 tmp |= CMD_SET_RTYP_6B;
412 break;
413 case MMC_RSP_R2:
414 tmp |= CMD_SET_RTYP_17B;
415 break;
416 default:
417 pr_err(DRIVER_NAME": Not support type response.\n");
418 break;
419 }
420 switch (opc) {
421 /* RBSY */
422 case MMC_SWITCH:
423 case MMC_STOP_TRANSMISSION:
424 case MMC_SET_WRITE_PROT:
425 case MMC_CLR_WRITE_PROT:
426 case MMC_ERASE:
427 case MMC_GEN_CMD:
428 tmp |= CMD_SET_RBSY;
429 break;
430 }
431 /* WDAT / DATW */
432 if (host->data) {
433 tmp |= CMD_SET_WDAT;
434 switch (host->bus_width) {
435 case MMC_BUS_WIDTH_1:
436 tmp |= CMD_SET_DATW_1;
437 break;
438 case MMC_BUS_WIDTH_4:
439 tmp |= CMD_SET_DATW_4;
440 break;
441 case MMC_BUS_WIDTH_8:
442 tmp |= CMD_SET_DATW_8;
443 break;
444 default:
445 pr_err(DRIVER_NAME": Not support bus width.\n");
446 break;
447 }
448 }
449 /* DWEN */
450 if (opc == MMC_WRITE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK)
451 tmp |= CMD_SET_DWEN;
452 /* CMLTE/CMD12EN */
453 if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) {
454 tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
455 sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET,
456 mrq->data->blocks << 16);
457 }
458 /* RIDXC[1:0] check bits */
459 if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID ||
460 opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
461 tmp |= CMD_SET_RIDXC_BITS;
462 /* RCRC7C[1:0] check bits */
463 if (opc == MMC_SEND_OP_COND)
464 tmp |= CMD_SET_CRC7C_BITS;
465 /* RCRC7C[1:0] internal CRC7 */
466 if (opc == MMC_ALL_SEND_CID ||
467 opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
468 tmp |= CMD_SET_CRC7C_INTERNAL;
469
470 return opc = ((opc << 24) | tmp);
471}
472
473static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
474 struct mmc_request *mrq, u32 opc)
475{
476 u32 ret;
477
478 switch (opc) {
479 case MMC_READ_MULTIPLE_BLOCK:
480 ret = sh_mmcif_multi_read(host, mrq);
481 break;
482 case MMC_WRITE_MULTIPLE_BLOCK:
483 ret = sh_mmcif_multi_write(host, mrq);
484 break;
485 case MMC_WRITE_BLOCK:
486 ret = sh_mmcif_single_write(host, mrq);
487 break;
488 case MMC_READ_SINGLE_BLOCK:
489 case MMC_SEND_EXT_CSD:
490 ret = sh_mmcif_single_read(host, mrq);
491 break;
492 default:
493 pr_err(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc);
494 ret = -EINVAL;
495 break;
496 }
497 return ret;
498}
499
500static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
501 struct mmc_request *mrq, struct mmc_command *cmd)
502{
503 long time;
504 int ret = 0, mask = 0;
505 u32 opc = cmd->opcode;
506
507 host->cmd = cmd;
508
509 switch (opc) {
510 /* respons busy check */
511 case MMC_SWITCH:
512 case MMC_STOP_TRANSMISSION:
513 case MMC_SET_WRITE_PROT:
514 case MMC_CLR_WRITE_PROT:
515 case MMC_ERASE:
516 case MMC_GEN_CMD:
517 mask = MASK_MRBSYE;
518 break;
519 default:
520 mask = MASK_MCRSPE;
521 break;
522 }
523 mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
524 MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
525 MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
526 MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
527
528 if (host->data) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000529 sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0);
530 sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET,
531 mrq->data->blksz);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700532 }
533 opc = sh_mmcif_set_cmd(host, mrq, cmd, opc);
534
Magnus Damm487d9fc2010-05-18 14:42:51 +0000535 sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0);
536 sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700537 /* set arg */
Magnus Damm487d9fc2010-05-18 14:42:51 +0000538 sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700539 /* set cmd */
Magnus Damm487d9fc2010-05-18 14:42:51 +0000540 sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700541
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000542 time = wait_for_completion_interruptible_timeout(&host->intr_wait,
543 host->timeout);
544 if (time <= 0) {
Yusuke Godafdc50a92010-05-26 14:41:59 -0700545 cmd->error = sh_mmcif_error_manage(host);
546 return;
547 }
548 if (host->sd_error) {
549 switch (cmd->opcode) {
550 case MMC_ALL_SEND_CID:
551 case MMC_SELECT_CARD:
552 case MMC_APP_CMD:
553 cmd->error = -ETIMEDOUT;
554 break;
555 default:
556 pr_debug("%s: Cmd(d'%d) err\n",
557 DRIVER_NAME, cmd->opcode);
558 cmd->error = sh_mmcif_error_manage(host);
559 break;
560 }
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000561 host->sd_error = false;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700562 return;
563 }
564 if (!(cmd->flags & MMC_RSP_PRESENT)) {
565 cmd->error = ret;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700566 return;
567 }
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000568 sh_mmcif_get_response(host, cmd);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700569 if (host->data) {
570 ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
571 if (ret < 0)
572 mrq->data->bytes_xfered = 0;
573 else
574 mrq->data->bytes_xfered =
575 mrq->data->blocks * mrq->data->blksz;
576 }
577 cmd->error = ret;
578}
579
580static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
581 struct mmc_request *mrq, struct mmc_command *cmd)
582{
583 long time;
584
585 if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK)
586 sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
587 else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
588 sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
589 else {
590 pr_err(DRIVER_NAME": not support stop cmd\n");
591 cmd->error = sh_mmcif_error_manage(host);
592 return;
593 }
594
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000595 time = wait_for_completion_interruptible_timeout(&host->intr_wait,
596 host->timeout);
597 if (time <= 0 || host->sd_error) {
Yusuke Godafdc50a92010-05-26 14:41:59 -0700598 cmd->error = sh_mmcif_error_manage(host);
599 return;
600 }
601 sh_mmcif_get_cmd12response(host, cmd);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700602 cmd->error = 0;
603}
604
605static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
606{
607 struct sh_mmcif_host *host = mmc_priv(mmc);
608
609 switch (mrq->cmd->opcode) {
610 /* MMCIF does not support SD/SDIO command */
611 case SD_IO_SEND_OP_COND:
612 case MMC_APP_CMD:
613 mrq->cmd->error = -ETIMEDOUT;
614 mmc_request_done(mmc, mrq);
615 return;
616 case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
617 if (!mrq->data) {
618 /* send_if_cond cmd (not support) */
619 mrq->cmd->error = -ETIMEDOUT;
620 mmc_request_done(mmc, mrq);
621 return;
622 }
623 break;
624 default:
625 break;
626 }
627 host->data = mrq->data;
628 sh_mmcif_start_cmd(host, mrq, mrq->cmd);
629 host->data = NULL;
630
631 if (mrq->cmd->error != 0) {
632 mmc_request_done(mmc, mrq);
633 return;
634 }
635 if (mrq->stop)
636 sh_mmcif_stop_cmd(host, mrq, mrq->stop);
637 mmc_request_done(mmc, mrq);
638}
639
640static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
641{
642 struct sh_mmcif_host *host = mmc_priv(mmc);
643 struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
644
645 if (ios->power_mode == MMC_POWER_OFF) {
646 /* clock stop */
647 sh_mmcif_clock_control(host, 0);
648 if (p->down_pwr)
649 p->down_pwr(host->pd);
650 return;
651 } else if (ios->power_mode == MMC_POWER_UP) {
652 if (p->set_pwr)
653 p->set_pwr(host->pd, ios->power_mode);
654 }
655
656 if (ios->clock)
657 sh_mmcif_clock_control(host, ios->clock);
658
659 host->bus_width = ios->bus_width;
660}
661
Arnd Hannemann777271d2010-08-24 17:27:01 +0200662static int sh_mmcif_get_cd(struct mmc_host *mmc)
663{
664 struct sh_mmcif_host *host = mmc_priv(mmc);
665 struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
666
667 if (!p->get_cd)
668 return -ENOSYS;
669 else
670 return p->get_cd(host->pd);
671}
672
Yusuke Godafdc50a92010-05-26 14:41:59 -0700673static struct mmc_host_ops sh_mmcif_ops = {
674 .request = sh_mmcif_request,
675 .set_ios = sh_mmcif_set_ios,
Arnd Hannemann777271d2010-08-24 17:27:01 +0200676 .get_cd = sh_mmcif_get_cd,
Yusuke Godafdc50a92010-05-26 14:41:59 -0700677};
678
679static void sh_mmcif_detect(struct mmc_host *mmc)
680{
681 mmc_detect_change(mmc, 0);
682}
683
684static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
685{
686 struct sh_mmcif_host *host = dev_id;
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000687 u32 state;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700688 int err = 0;
689
Magnus Damm487d9fc2010-05-18 14:42:51 +0000690 state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700691
692 if (state & INT_RBSYE) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000693 sh_mmcif_writel(host->addr, MMCIF_CE_INT,
694 ~(INT_RBSYE | INT_CRSPE));
Yusuke Godafdc50a92010-05-26 14:41:59 -0700695 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE);
696 } else if (state & INT_CRSPE) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000697 sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_CRSPE);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700698 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE);
699 } else if (state & INT_BUFREN) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000700 sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFREN);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700701 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
702 } else if (state & INT_BUFWEN) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000703 sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFWEN);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700704 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
705 } else if (state & INT_CMD12DRE) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000706 sh_mmcif_writel(host->addr, MMCIF_CE_INT,
Yusuke Godafdc50a92010-05-26 14:41:59 -0700707 ~(INT_CMD12DRE | INT_CMD12RBE |
708 INT_CMD12CRE | INT_BUFRE));
709 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
710 } else if (state & INT_BUFRE) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000711 sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700712 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
713 } else if (state & INT_DTRANE) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000714 sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_DTRANE);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700715 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
716 } else if (state & INT_CMD12RBE) {
Magnus Damm487d9fc2010-05-18 14:42:51 +0000717 sh_mmcif_writel(host->addr, MMCIF_CE_INT,
Yusuke Godafdc50a92010-05-26 14:41:59 -0700718 ~(INT_CMD12RBE | INT_CMD12CRE));
719 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
720 } else if (state & INT_ERR_STS) {
721 /* err interrupts */
Magnus Damm487d9fc2010-05-18 14:42:51 +0000722 sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700723 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
724 err = 1;
725 } else {
726 pr_debug("%s: Not support int\n", DRIVER_NAME);
Magnus Damm487d9fc2010-05-18 14:42:51 +0000727 sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700728 sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
729 err = 1;
730 }
731 if (err) {
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000732 host->sd_error = true;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700733 pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state);
734 }
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000735 if (state & ~(INT_CMD12RBE | INT_CMD12CRE))
736 complete(&host->intr_wait);
737 else
738 dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700739
740 return IRQ_HANDLED;
741}
742
743static int __devinit sh_mmcif_probe(struct platform_device *pdev)
744{
745 int ret = 0, irq[2];
746 struct mmc_host *mmc;
747 struct sh_mmcif_host *host = NULL;
748 struct sh_mmcif_plat_data *pd = NULL;
749 struct resource *res;
750 void __iomem *reg;
751 char clk_name[8];
752
753 irq[0] = platform_get_irq(pdev, 0);
754 irq[1] = platform_get_irq(pdev, 1);
755 if (irq[0] < 0 || irq[1] < 0) {
756 pr_err(DRIVER_NAME": Get irq error\n");
757 return -ENXIO;
758 }
759 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
760 if (!res) {
761 dev_err(&pdev->dev, "platform_get_resource error.\n");
762 return -ENXIO;
763 }
764 reg = ioremap(res->start, resource_size(res));
765 if (!reg) {
766 dev_err(&pdev->dev, "ioremap error.\n");
767 return -ENOMEM;
768 }
769 pd = (struct sh_mmcif_plat_data *)(pdev->dev.platform_data);
770 if (!pd) {
771 dev_err(&pdev->dev, "sh_mmcif plat data error.\n");
772 ret = -ENXIO;
773 goto clean_up;
774 }
775 mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev);
776 if (!mmc) {
777 ret = -ENOMEM;
778 goto clean_up;
779 }
780 host = mmc_priv(mmc);
781 host->mmc = mmc;
782 host->addr = reg;
783 host->timeout = 1000;
784
785 snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
786 host->hclk = clk_get(&pdev->dev, clk_name);
787 if (IS_ERR(host->hclk)) {
788 dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
789 ret = PTR_ERR(host->hclk);
790 goto clean_up1;
791 }
792 clk_enable(host->hclk);
793 host->clk = clk_get_rate(host->hclk);
794 host->pd = pdev;
795
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000796 init_completion(&host->intr_wait);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700797
798 mmc->ops = &sh_mmcif_ops;
799 mmc->f_max = host->clk;
800 /* close to 400KHz */
801 if (mmc->f_max < 51200000)
802 mmc->f_min = mmc->f_max / 128;
803 else if (mmc->f_max < 102400000)
804 mmc->f_min = mmc->f_max / 256;
805 else
806 mmc->f_min = mmc->f_max / 512;
807 if (pd->ocr)
808 mmc->ocr_avail = pd->ocr;
809 mmc->caps = MMC_CAP_MMC_HIGHSPEED;
810 if (pd->caps)
811 mmc->caps |= pd->caps;
Martin K. Petersena36274e2010-09-10 01:33:59 -0400812 mmc->max_segs = 128;
Yusuke Godafdc50a92010-05-26 14:41:59 -0700813 mmc->max_blk_size = 512;
814 mmc->max_blk_count = 65535;
815 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
816 mmc->max_seg_size = mmc->max_req_size;
817
818 sh_mmcif_sync_reset(host);
819 platform_set_drvdata(pdev, host);
820 mmc_add_host(mmc);
821
822 ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
823 if (ret) {
824 pr_err(DRIVER_NAME": request_irq error (sh_mmc:error)\n");
825 goto clean_up2;
826 }
827 ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
828 if (ret) {
829 free_irq(irq[0], host);
830 pr_err(DRIVER_NAME": request_irq error (sh_mmc:int)\n");
831 goto clean_up2;
832 }
833
Magnus Damm487d9fc2010-05-18 14:42:51 +0000834 sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700835 sh_mmcif_detect(host->mmc);
836
837 pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION);
838 pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME,
Magnus Damm487d9fc2010-05-18 14:42:51 +0000839 sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700840 return ret;
841
842clean_up2:
843 clk_disable(host->hclk);
844clean_up1:
845 mmc_free_host(mmc);
846clean_up:
847 if (reg)
848 iounmap(reg);
849 return ret;
850}
851
852static int __devexit sh_mmcif_remove(struct platform_device *pdev)
853{
854 struct sh_mmcif_host *host = platform_get_drvdata(pdev);
855 int irq[2];
856
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000857 mmc_remove_host(host->mmc);
858
859 if (host->addr)
860 iounmap(host->addr);
861
Magnus Damm487d9fc2010-05-18 14:42:51 +0000862 sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700863
864 irq[0] = platform_get_irq(pdev, 0);
865 irq[1] = platform_get_irq(pdev, 1);
866
Yusuke Godafdc50a92010-05-26 14:41:59 -0700867 free_irq(irq[0], host);
868 free_irq(irq[1], host);
869
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000870 platform_set_drvdata(pdev, NULL);
871
Yusuke Godafdc50a92010-05-26 14:41:59 -0700872 clk_disable(host->hclk);
873 mmc_free_host(host->mmc);
874
875 return 0;
876}
877
878static struct platform_driver sh_mmcif_driver = {
879 .probe = sh_mmcif_probe,
880 .remove = sh_mmcif_remove,
881 .driver = {
882 .name = DRIVER_NAME,
883 },
884};
885
886static int __init sh_mmcif_init(void)
887{
888 return platform_driver_register(&sh_mmcif_driver);
889}
890
891static void __exit sh_mmcif_exit(void)
892{
893 platform_driver_unregister(&sh_mmcif_driver);
894}
895
896module_init(sh_mmcif_init);
897module_exit(sh_mmcif_exit);
898
899
900MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
901MODULE_LICENSE("GPL");
Guennadi Liakhovetskiaa0787a2010-11-24 10:05:12 +0000902MODULE_ALIAS("platform:" DRIVER_NAME);
Yusuke Godafdc50a92010-05-26 14:41:59 -0700903MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");