1 /*
2 * Sunxi SD/MMC host driver
3 *
4 * Copyright (C) 2015 AllWinnertech Ltd.
5 * Author: lixiang <lixiang@allwinnertech>
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 version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
12 * kind, whether express or implied; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17
18 #ifdef CONFIG_ARCH_SUN50IW1P1
19
20 #include <linux/clk.h>
21 #include <sunxi-clk.h>
22
23 #include <linux/gpio.h>
24 #include <linux/platform_device.h>
25 #include <linux/spinlock.h>
26 #include <linux/scatterlist.h>
27 #include <linux/dma-mapping.h>
28 #include <linux/slab.h>
29 #include <linux/reset.h>
30
31 #include <linux/of_address.h>
32 #include <linux/of_gpio.h>
33 #include <linux/of_platform.h>
34
35 #include <linux/mmc/host.h>
36 #include <linux/mmc/sd.h>
37 #include <linux/mmc/sdio.h>
38 #include <linux/mmc/mmc.h>
39 #include <linux/mmc/core.h>
40 #include <linux/mmc/card.h>
41 #include <linux/mmc/slot-gpio.h>
42
43 #include "sunxi-mmc.h"
44 #include "sunxi-mmc-sun50iw1p1-1.h"
45
46 /*reg*/
47 /*SMHC eMMC4.5 DDR Start Bit Detection Control Register */
48 /*SMHC CRC Status Detect Control Register */
49 /*SMHC Card Threshold Control Register */
50 /*SMHC Drive Delay Control Register */
51 /*SMHC Sample Delay Control Register */
52 /*SMHC Data Strobe Delay Control Register */
53 /*SMHC NewTiming Set Register */
54 #define SDXC_REG_EDSD (0x010C)
55 #define SDXC_REG_CSDC (0x0054)
56 #define SDXC_REG_THLD (0x0100)
57 #define SDXC_REG_DRV_DL (0x0140)
58 #define SDXC_REG_SAMP_DL (0x0144)
59 #define SDXC_REG_DS_DL (0x0148)
60 #define SDXC_REG_SD_NTSR (0x005C)
61
62 /*bit*/
63 #define SDXC_HS400_MD_EN (1U<<31)
64 #define SDXC_CARD_WR_THLD_ENB (1U<<2)
65 #define SDXC_CARD_RD_THLD_ENB (1U)
66
67 #define SDXC_DAT_DRV_PH_SEL (1U<<17)
68 #define SDXC_CMD_DRV_PH_SEL (1U<<16)
69 #define SDXC_SAMP_DL_SW_EN (1u<<7)
70 #define SDXC_DS_DL_SW_EN (1u<<7)
71
72 #define SDXC_2X_TIMING_MODE (1U<<31)
73
74 /*mask*/
75 #define SDXC_CRC_DET_PARA_MASK (0xf)
76 #define SDXC_CARD_RD_THLD_MASK (0x0FFF0000)
77 #define SDXC_TX_TL_MASK (0xff)
78 #define SDXC_RX_TL_MASK (0x00FF0000)
79
80 #define SDXC_SAMP_DL_SW_MASK (0x0000003F)
81 #define SDXC_DS_DL_SW_MASK (0x0000003F)
82
83 #define SDXC_SAM_TIMING_PH_MASK (0x00000030)
84
85 /*value*/
86 #define SDXC_CRC_DET_PARA_HS400 (6)
87 #define SDXC_CRC_DET_PARA_OTHER (3)
88 #define SDXC_FIFO_DETH (1024>>2)
89
90 /*size*/
91 #define SDXC_CARD_RD_THLD_SIZE (0x00000FFF)
92
93 /*shit*/
94 #define SDXC_CARD_RD_THLD_SIZE_SHIFT (16)
95
96 #define SDXC_SAM_TIMING_PH_SHIFT (4)
97
98 enum sunxi_mmc_clk_mode {
99 mmc_clk_400k = 0,
100 mmc_clk_26M,
101 mmc_clk_52M,
102 mmc_clk_52M_DDR4,
103 mmc_clk_52M_DDR8,
104 mmc_clk_104M,
105 mmc_clk_208M,
106 mmc_clk_104M_DDR,
107 mmc_clk_208M_DDR,
108 mmc_clk_mod_num,
109 };
110
111 struct sunxi_mmc_clk_dly {
112 enum sunxi_mmc_clk_mode cmod;
113 char *mod_str;
114 u32 cmd_drv_ph;
115 u32 dat_drv_ph;
116 u32 sam_dly;
117 u32 ds_dly;
118 u32 sam_ph;
119 };
120
121 /*sample delay and output deley setting */
122 static struct sunxi_mmc_clk_dly mmc_clk_dly[mmc_clk_mod_num] = {
123 [mmc_clk_400k] = {
124 .cmod = mmc_clk_400k,
125 .mod_str = "sunxi-dly-400k",
126 .cmd_drv_ph = 1,
127 .dat_drv_ph = 0,
128 .sam_dly = 0,
129 .ds_dly = 0,
130 .sam_ph = 0,
131 },
132 [mmc_clk_26M] = {
133 .cmod = mmc_clk_26M,
134 .mod_str = "sunxi-dly-26M",
135 .cmd_drv_ph = 1,
136 .dat_drv_ph = 0,
137 .sam_dly = 0,
138 .ds_dly = 0,
139 .sam_ph = 0,
140 },
141 [mmc_clk_52M] = {
142 .cmod = mmc_clk_52M,
143 .mod_str = "sunxi-dly-52M",
144 .cmd_drv_ph = 1,
145 .dat_drv_ph = 0,
146 .sam_dly = 0,
147 .ds_dly = 0,
148 .sam_ph = 0,
149 },
150 [mmc_clk_52M_DDR4] = {
151 .cmod = mmc_clk_52M_DDR4,
152 .mod_str = "sunxi-dly-52M-ddr4",
153 .cmd_drv_ph = 1,
154 .dat_drv_ph = 0,
155 .sam_dly = 0,
156 .ds_dly = 0,
157 .sam_ph = 0,
158 },
159 [mmc_clk_52M_DDR8] = {
160 .cmod = mmc_clk_52M_DDR8,
161 .mod_str = "sunxi-dly-52M-ddr8",
162 .cmd_drv_ph = 1,
163 .dat_drv_ph = 0,
164 .sam_dly = 0,
165 .ds_dly = 0,
166 .sam_ph = 0,
167 },
168 [mmc_clk_104M] = {
169 .cmod = mmc_clk_104M,
170 .mod_str = "sunxi-dly-104M",
171 .cmd_drv_ph = 1,
172 .dat_drv_ph = 0,
173 .sam_dly = 0,
174 .ds_dly = 0,
175 .sam_ph = 0,
176
177 },
178 [mmc_clk_208M] = {
179 .cmod = mmc_clk_208M,
180 .mod_str = "sunxi-dly-208M",
181 .cmd_drv_ph = 1,
182 .dat_drv_ph = 0,
183 .sam_dly = 0,
184 .ds_dly = 0,
185 .sam_ph = 0,
186 },
187 [mmc_clk_104M_DDR] = {
188 .cmod = mmc_clk_104M_DDR,
189 .mod_str = "sunxi-dly-104M-ddr",
190 .cmd_drv_ph = 1,
191 .dat_drv_ph = 0,
192 .sam_dly = 0,
193 .ds_dly = 0,
194 .sam_ph = 0,
195 },
196 [mmc_clk_208M_DDR] = {
197 .cmod = mmc_clk_208M_DDR,
198 .mod_str = "sunxi-dly-208M-ddr",
199 .cmd_drv_ph = 1,
200 .dat_drv_ph = 0,
201 .sam_dly = 0,
202 .ds_dly = 0,
203 .sam_ph = 0,
204 },
205 };
206
207 struct sunxi_mmc_spec_regs {
208 u32 drv_dl; /*REG_DRV_DL */
209 u32 samp_dl; /*REG_SAMP_DL */
210 u32 ds_dl; /*REG_DS_DL */
211 u32 sd_ntsr; /*REG_SD_NTSR */
212 };
213
214 static struct sunxi_mmc_spec_regs bak_spec_regs;
215
sunxi_mmc_set_clk_dly(struct sunxi_mmc_host * host,int clk,int bus_width,int timing)216 static void sunxi_mmc_set_clk_dly(struct sunxi_mmc_host *host, int clk,
217 int bus_width, int timing)
218 {
219 struct mmc_host *mhost = host->mmc;
220 u32 rval = 0;
221 enum sunxi_mmc_clk_mode cmod = mmc_clk_400k;
222 u32 in_clk_dly[5] = { 0 };
223 int ret = 0;
224 struct device_node *np = NULL;
225
226 if (!mhost->parent || !mhost->parent->of_node) {
227 SM_ERR(mmc_dev(host->mmc),
228 "no dts to parse clk dly,use default\n");
229 return;
230 }
231
232 np = mhost->parent->of_node;
233
234 if (clk <= 400 * 1000) {
235 cmod = mmc_clk_400k;
236 } else if (clk <= 26 * 1000 * 1000) {
237 cmod = mmc_clk_26M;
238 } else if (clk <= 52 * 1000 * 1000) {
239 if ((bus_width == MMC_BUS_WIDTH_4)
240 && sunxi_mmc_ddr_timing(timing)) {
241 cmod = mmc_clk_52M_DDR4;
242 } else if ((bus_width == MMC_BUS_WIDTH_8)
243 && (timing == MMC_TIMING_MMC_DDR52)) {
244 cmod = mmc_clk_52M_DDR8;
245 } else {
246 cmod = mmc_clk_52M;
247 }
248 } else if (clk <= 104 * 1000 * 1000) {
249 if ((bus_width == MMC_BUS_WIDTH_8)
250 && (timing == MMC_TIMING_MMC_HS400)) {
251 cmod = mmc_clk_104M_DDR;
252 } else {
253 cmod = mmc_clk_104M;
254 }
255 } else if (clk <= 208 * 1000 * 1000) {
256 if ((bus_width == MMC_BUS_WIDTH_8)
257 && (timing == MMC_TIMING_MMC_HS400)) {
258 cmod = mmc_clk_208M_DDR;
259 } else {
260 cmod = mmc_clk_208M;
261 }
262 } else {
263 SM_ERR(mmc_dev(mhost), "clk %d is out of range\n", clk);
264 return;
265 }
266
267 ret = of_property_read_u32_array(np, mmc_clk_dly[cmod].mod_str,
268 in_clk_dly, ARRAY_SIZE(in_clk_dly));
269 if (ret) {
270 SM_DBG(mmc_dev(host->mmc), "failded to get %s used default\n",
271 mmc_clk_dly[cmod].mod_str);
272 } else {
273 mmc_clk_dly[cmod].cmd_drv_ph = in_clk_dly[0];
274 mmc_clk_dly[cmod].dat_drv_ph = in_clk_dly[1];
275 /*mmc_clk_dly[cmod].sam_dly = in_clk_dly[2]; */
276 /*mmc_clk_dly[cmod].ds_dly = in_clk_dly[3]; */
277 mmc_clk_dly[cmod].sam_ph = in_clk_dly[4];
278 SM_DBG(mmc_dev(host->mmc), "Get %s clk dly ok\n",
279 mmc_clk_dly[cmod].mod_str);
280
281 }
282
283 SM_DBG(mmc_dev(host->mmc), "Try set %s clk dly ok\n",
284 mmc_clk_dly[cmod].mod_str);
285 SM_DBG(mmc_dev(host->mmc), "cmd_drv_ph %d\n",
286 mmc_clk_dly[cmod].cmd_drv_ph);
287 SM_DBG(mmc_dev(host->mmc), "dat_drv_ph %d\n",
288 mmc_clk_dly[cmod].dat_drv_ph);
289 SM_DBG(mmc_dev(host->mmc), "sam_ph %d\n",
290 mmc_clk_dly[cmod].sam_ph);
291
292 rval = mmc_readl(host, REG_DRV_DL);
293 if (mmc_clk_dly[cmod].cmd_drv_ph)
294 rval |= SDXC_CMD_DRV_PH_SEL; /*180 phase */
295 else
296 rval &= ~SDXC_CMD_DRV_PH_SEL; /*90 phase */
297
298
299 if (mmc_clk_dly[cmod].dat_drv_ph)
300 rval |= SDXC_DAT_DRV_PH_SEL; /*180 phase */
301 else
302 rval &= ~SDXC_DAT_DRV_PH_SEL; /*90 phase */
303
304 sunxi_r_op(host, mmc_writel(host, REG_DRV_DL, rval));
305
306 /*
307 * rval = mmc_readl(host,REG_SAMP_DL);
308 * rval &= ~SDXC_SAMP_DL_SW_MASK;
309 * rval |= mmc_clk_dly[cmod].sam_dly & SDXC_SAMP_DL_SW_MASK;
310 * rval |= SDXC_SAMP_DL_SW_EN;
311 * mmc_writel(host,REG_SAMP_DL,rval);
312 *
313 * rval = mmc_readl(host,REG_DS_DL);
314 * rval &= ~SDXC_DS_DL_SW_MASK;
315 * rval |= mmc_clk_dly[cmod].ds_dly & SDXC_DS_DL_SW_MASK;
316 * rval |= SDXC_DS_DL_SW_EN;
317 * mmc_writel(host,REG_DS_DL,rval);
318 */
319 rval = mmc_readl(host, REG_SD_NTSR);
320 rval &= ~SDXC_SAM_TIMING_PH_MASK;
321 rval |=
322 (mmc_clk_dly[cmod].
323 sam_ph << SDXC_SAM_TIMING_PH_SHIFT) & SDXC_SAM_TIMING_PH_MASK;
324 mmc_writel(host, REG_SD_NTSR, rval);
325
326 SM_DBG(mmc_dev(host->mmc), " REG_DRV_DL %08x\n",
327 mmc_readl(host, REG_DRV_DL));
328 SM_DBG(mmc_dev(host->mmc), " REG_SAMP_DL %08x\n",
329 mmc_readl(host, REG_SAMP_DL));
330 SM_DBG(mmc_dev(host->mmc), " REG_DS_DL %08x\n",
331 mmc_readl(host, REG_DS_DL));
332
333 }
334
__sunxi_mmc_do_oclk_onoff(struct sunxi_mmc_host * host,u32 oclk_en,u32 pwr_save,u32 ignore_dat0)335 static int __sunxi_mmc_do_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en,
336 u32 pwr_save, u32 ignore_dat0)
337 {
338 unsigned long expire = jiffies + msecs_to_jiffies(250);
339 u32 rval;
340
341 rval = mmc_readl(host, REG_CLKCR);
342 rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON | SDXC_MASK_DATA0);
343
344 if (oclk_en)
345 rval |= SDXC_CARD_CLOCK_ON;
346 if (pwr_save)
347 rval |= SDXC_LOW_POWER_ON;
348 if (ignore_dat0)
349 rval |= SDXC_MASK_DATA0;
350
351 mmc_writel(host, REG_CLKCR, rval);
352
353 SM_DBG(mmc_dev(host->mmc), "%s REG_CLKCR:%x\n", __func__,
354 mmc_readl(host, REG_CLKCR));
355
356 rval = SDXC_START | SDXC_UPCLK_ONLY | SDXC_WAIT_PRE_OVER;
357 mmc_writel(host, REG_CMDR, rval);
358
359 do {
360 rval = mmc_readl(host, REG_CMDR);
361 } while (time_before(jiffies, expire) && (rval & SDXC_START));
362
363 /* clear irq status bits set by the command */
364 /*? */
365 mmc_writel(host, REG_RINTR,
366 mmc_readl(host, REG_RINTR) & ~SDXC_SDIO_INTERRUPT);
367
368 if (rval & SDXC_START) {
369 SM_ERR(mmc_dev(host->mmc), "fatal err update clk timeout\n");
370 return -EIO;
371 }
372
373 /*only use mask data0 when update clk,clear it when not update clk */
374 if (ignore_dat0)
375 mmc_writel(host, REG_CLKCR,
376 mmc_readl(host, REG_CLKCR) & ~SDXC_MASK_DATA0);
377
378 return 0;
379 }
380
sunxi_mmc_oclk_onoff(struct sunxi_mmc_host * host,u32 oclk_en)381 static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
382 {
383 struct device_node *np = NULL;
384 struct mmc_host *mmc = host->mmc;
385 int pwr_save = 0;
386 int len = 0;
387
388 if (!mmc->parent || !mmc->parent->of_node) {
389 SM_ERR(mmc_dev(host->mmc),
390 "no dts to parse power save mode\n");
391 return -EIO;
392 }
393
394 np = mmc->parent->of_node;
395 if (of_find_property(np, "sunxi-power-save-mode", &len))
396 pwr_save = 1;
397 return __sunxi_mmc_do_oclk_onoff(host, oclk_en, pwr_save, 1);
398 }
399
sunxi_mmc_oclk_onoff_sdmmc1(struct sunxi_mmc_host * host,u32 oclk_en)400 int sunxi_mmc_oclk_onoff_sdmmc1(struct sunxi_mmc_host *host, u32 oclk_en)
401 {
402 return sunxi_mmc_oclk_onoff(host, oclk_en);
403 }
404
sunxi_mmc_2xmod_onoff(struct sunxi_mmc_host * host,u32 newmode_en)405 static void sunxi_mmc_2xmod_onoff(struct sunxi_mmc_host *host, u32 newmode_en)
406 {
407 u32 rval = mmc_readl(host, REG_SD_NTSR);
408
409 if (newmode_en)
410 rval |= SDXC_2X_TIMING_MODE;
411 else
412 rval &= ~SDXC_2X_TIMING_MODE;
413
414 mmc_writel(host, REG_SD_NTSR, rval);
415
416 SM_DBG(mmc_dev(host->mmc), "REG_SD_NTSR: 0x%08x ,val %x\n",
417 mmc_readl(host, REG_SD_NTSR), rval);
418 }
419
sunxi_mmc_clk_set_rate_for_sdmmc1(struct sunxi_mmc_host * host,struct mmc_ios * ios)420 int sunxi_mmc_clk_set_rate_for_sdmmc1(struct sunxi_mmc_host *host,
421 struct mmc_ios *ios)
422 {
423 u32 mod_clk = 0;
424 u32 src_clk = 0;
425 u32 rval = 0;
426 s32 err = 0;
427 u32 rate = 0;
428 char *sclk_name = NULL;
429 struct clk *mclk = host->clk_mmc;
430 struct clk *sclk = NULL;
431 struct device *dev = mmc_dev(host->mmc);
432 int div = 0;
433
434 if (ios->clock == 0) {
435 __sunxi_mmc_do_oclk_onoff(host, 0, 0, 1);
436 return 0;
437 }
438
439 if (sunxi_mmc_ddr_timing(ios->timing)) {
440 mod_clk = ios->clock << 2;
441 div = 1;
442 } else {
443 mod_clk = ios->clock << 1;
444 div = 0;
445 }
446
447 if (ios->clock <= 400000) {
448 sclk = clk_get(dev, "osc24m");
449 sclk_name = "osc24m";
450 } else {
451 sclk = clk_get(dev, "pll_periph");
452 sclk_name = "pll_periph";
453 }
454
455 if (IS_ERR(sclk)) {
456 SM_ERR(mmc_dev(host->mmc), "Error to get source clock %s\n",
457 sclk_name);
458 return -1;
459 }
460
461 sunxi_mmc_oclk_onoff(host, 0);
462
463 err = clk_set_parent(mclk, sclk);
464 if (err) {
465 SM_ERR(mmc_dev(host->mmc), "set parent failed\n");
466 clk_put(sclk);
467 return -1;
468 }
469
470 rate = clk_round_rate(mclk, mod_clk);
471
472 SM_DBG(mmc_dev(host->mmc), "get round rate %d\n", rate);
473
474 clk_disable_unprepare(host->clk_mmc);
475
476 err = clk_set_rate(mclk, rate);
477 if (err) {
478 SM_ERR(mmc_dev(host->mmc), "set mclk rate error, rate %dHz\n",
479 rate);
480 clk_put(sclk);
481 return -1;
482 }
483
484 rval = clk_prepare_enable(host->clk_mmc);
485 if (rval) {
486 SM_ERR(mmc_dev(host->mmc), "Enable mmc clk err %d\n", rval);
487 return -1;
488 }
489
490 src_clk = clk_get_rate(sclk);
491 clk_put(sclk);
492
493 SM_DBG(mmc_dev(host->mmc), "set round clock %d, soure clk is %d\n",
494 rate, src_clk);
495
496 #ifdef MMC_FPGA
497 if (sunxi_mmc_ddr_timing(ios->timing)) {
498 /* clear internal divider */
499 rval = mmc_readl(host, REG_CLKCR);
500 rval &= ~0xff;
501 rval |= 1;
502 } else {
503 /* support internal divide clock under fpga environment */
504 rval = mmc_readl(host, REG_CLKCR);
505 rval &= ~0xff;
506 rval |= 24000000 / mod_clk / 2; /* =24M/400K/2=0x1E*/
507 }
508 mmc_writel(host, REG_CLKCR, rval);
509 SM_INFO(mmc_dev(host->mmc), "FPGA REG_CLKCR: 0x%08x\n",
510 mmc_readl(host, REG_CLKCR));
511 #else
512 /* clear internal divider */
513 rval = mmc_readl(host, REG_CLKCR);
514 rval &= ~0xff;
515 rval |= div;
516 mmc_writel(host, REG_CLKCR, rval);
517 #endif
518
519 /*sunxi_of_parse_clk_dly(host);*/
520 sunxi_mmc_2xmod_onoff(host, 1);
521
522 if (sunxi_mmc_ddr_timing(ios->timing))
523 ios->clock = rate >> 2;
524 else
525 ios->clock = rate >> 1;
526
527
528 sunxi_mmc_set_clk_dly(host, ios->clock, ios->bus_width, ios->timing);
529
530 return sunxi_mmc_oclk_onoff(host, 1);
531 }
532
sunxi_mmc_thld_ctl_for_sdmmc1(struct sunxi_mmc_host * host,struct mmc_ios * ios,struct mmc_data * data)533 void sunxi_mmc_thld_ctl_for_sdmmc1(struct sunxi_mmc_host *host,
534 struct mmc_ios *ios, struct mmc_data *data)
535 {
536 u32 bsz = data->blksz;
537 /*unit:byte */
538 u32 rdtl = ((host->dma_tl & SDXC_RX_TL_MASK) >> 16) << 2;
539 u32 rval = 0;
540
541 if ((data->flags & MMC_DATA_READ)
542 && (bsz <= SDXC_CARD_RD_THLD_SIZE)
543 /*((SDXC_FIFO_DETH<<2)-bsz) >= (rdtl)*/
544 && ((SDXC_FIFO_DETH << 2) >= (rdtl + bsz))
545 && ((ios->timing == MMC_TIMING_MMC_HS200)
546 || (ios->timing == MMC_TIMING_UHS_SDR50)
547 || (ios->timing == MMC_TIMING_UHS_SDR104))) {
548 rval = mmc_readl(host, REG_THLD);
549 rval &= ~SDXC_CARD_RD_THLD_MASK;
550 rval |= data->blksz << SDXC_CARD_RD_THLD_SIZE_SHIFT;
551 rval |= SDXC_CARD_RD_THLD_ENB;
552 mmc_writel(host, REG_THLD, rval);
553 } else {
554 rval = mmc_readl(host, REG_THLD);
555 rval &= ~SDXC_CARD_RD_THLD_ENB;
556 mmc_writel(host, REG_THLD, rval);
557 }
558
559 SM_DBG(mmc_dev(host->mmc), "SDXC_REG_THLD: 0x%08x\n",
560 mmc_readl(host, REG_THLD));
561
562 }
563
sunxi_mmc_save_spec_reg1(struct sunxi_mmc_host * host)564 void sunxi_mmc_save_spec_reg1(struct sunxi_mmc_host *host)
565 {
566 bak_spec_regs.drv_dl = mmc_readl(host, REG_DRV_DL);
567 bak_spec_regs.samp_dl = mmc_readl(host, REG_SAMP_DL);
568 bak_spec_regs.ds_dl = mmc_readl(host, REG_DS_DL);
569 bak_spec_regs.sd_ntsr = mmc_readl(host, REG_SD_NTSR);
570 }
571
sunxi_mmc_restore_spec_reg1(struct sunxi_mmc_host * host)572 void sunxi_mmc_restore_spec_reg1(struct sunxi_mmc_host *host)
573 {
574 sunxi_r_op(host, mmc_writel(host, REG_DRV_DL, bak_spec_regs.drv_dl));
575 mmc_writel(host, REG_SAMP_DL, bak_spec_regs.samp_dl);
576 mmc_writel(host, REG_DS_DL, bak_spec_regs.ds_dl);
577 mmc_writel(host, REG_SD_NTSR, bak_spec_regs.sd_ntsr);
578 }
579
580 #endif
581