blob: bda284ba1303998aba7705be14eeda8d8c68c382 [file] [log] [blame]
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001/*
2 * drivers/mmc/host/omap_hsmmc.c
3 *
4 * Driver for OMAP2430/3430 MMC controller.
5 *
6 * Copyright (C) 2007 Texas Instruments.
7 *
8 * Authors:
9 * Syed Mohammed Khasim <x0khasim@ti.com>
10 * Madhusudhan <madhu.cr@ti.com>
11 * Mohit Jalori <mjalori@ti.com>
12 *
13 * This file is licensed under the terms of the GNU General Public License
14 * version 2. This program is licensed "as is" without any warranty of any
15 * kind, whether express or implied.
16 */
17
18#include <linux/module.h>
19#include <linux/init.h>
Andy Shevchenkoac330f42011-05-10 15:51:54 +030020#include <linux/kernel.h>
Denis Karpovd900f712009-09-22 16:44:38 -070021#include <linux/debugfs.h>
22#include <linux/seq_file.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010023#include <linux/interrupt.h>
24#include <linux/delay.h>
25#include <linux/dma-mapping.h>
26#include <linux/platform_device.h>
27#include <linux/workqueue.h>
28#include <linux/timer.h>
29#include <linux/clk.h>
30#include <linux/mmc/host.h>
Jarkko Lavinen13189e72009-09-22 16:44:53 -070031#include <linux/mmc/core.h>
Adrian Hunter93caf8e692010-08-11 14:17:48 -070032#include <linux/mmc/mmc.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010033#include <linux/io.h>
34#include <linux/semaphore.h>
Adrian Hunterdb0fefc2010-02-15 10:03:34 -080035#include <linux/gpio.h>
36#include <linux/regulator/consumer.h>
Balaji T Kfa4aa2d2011-07-01 22:09:35 +053037#include <linux/pm_runtime.h>
Tony Lindgrence491cf2009-10-20 09:40:47 -070038#include <plat/dma.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010039#include <mach/hardware.h>
Tony Lindgrence491cf2009-10-20 09:40:47 -070040#include <plat/board.h>
41#include <plat/mmc.h>
42#include <plat/cpu.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010043
44/* OMAP HSMMC Host Controller Registers */
45#define OMAP_HSMMC_SYSCONFIG 0x0010
Denis Karpov11dd62a2009-09-22 16:44:43 -070046#define OMAP_HSMMC_SYSSTATUS 0x0014
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010047#define OMAP_HSMMC_CON 0x002C
48#define OMAP_HSMMC_BLK 0x0104
49#define OMAP_HSMMC_ARG 0x0108
50#define OMAP_HSMMC_CMD 0x010C
51#define OMAP_HSMMC_RSP10 0x0110
52#define OMAP_HSMMC_RSP32 0x0114
53#define OMAP_HSMMC_RSP54 0x0118
54#define OMAP_HSMMC_RSP76 0x011C
55#define OMAP_HSMMC_DATA 0x0120
56#define OMAP_HSMMC_HCTL 0x0128
57#define OMAP_HSMMC_SYSCTL 0x012C
58#define OMAP_HSMMC_STAT 0x0130
59#define OMAP_HSMMC_IE 0x0134
60#define OMAP_HSMMC_ISE 0x0138
61#define OMAP_HSMMC_CAPA 0x0140
62
63#define VS18 (1 << 26)
64#define VS30 (1 << 25)
65#define SDVS18 (0x5 << 9)
66#define SDVS30 (0x6 << 9)
David Brownelleb250822009-02-17 14:49:01 -080067#define SDVS33 (0x7 << 9)
Kim Kyuwon1b331e62009-02-20 13:10:08 +010068#define SDVS_MASK 0x00000E00
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010069#define SDVSCLR 0xFFFFF1FF
70#define SDVSDET 0x00000400
71#define AUTOIDLE 0x1
72#define SDBP (1 << 8)
73#define DTO 0xe
74#define ICE 0x1
75#define ICS 0x2
76#define CEN (1 << 2)
77#define CLKD_MASK 0x0000FFC0
78#define CLKD_SHIFT 6
79#define DTO_MASK 0x000F0000
80#define DTO_SHIFT 16
81#define INT_EN_MASK 0x307F0033
Anand Gadiyarccdfe3a2009-09-22 16:44:21 -070082#define BWR_ENABLE (1 << 4)
83#define BRR_ENABLE (1 << 5)
Adrian Hunter93caf8e692010-08-11 14:17:48 -070084#define DTO_ENABLE (1 << 20)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010085#define INIT_STREAM (1 << 1)
86#define DP_SELECT (1 << 21)
87#define DDIR (1 << 4)
88#define DMA_EN 0x1
89#define MSBS (1 << 5)
90#define BCE (1 << 1)
91#define FOUR_BIT (1 << 1)
Jarkko Lavinen73153012008-11-21 16:49:54 +020092#define DW8 (1 << 5)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010093#define CC 0x1
94#define TC 0x02
95#define OD 0x1
96#define ERR (1 << 15)
97#define CMD_TIMEOUT (1 << 16)
98#define DATA_TIMEOUT (1 << 20)
99#define CMD_CRC (1 << 17)
100#define DATA_CRC (1 << 21)
101#define CARD_ERR (1 << 28)
102#define STAT_CLEAR 0xFFFFFFFF
103#define INIT_STREAM_CMD 0x00000000
104#define DUAL_VOLT_OCR_BIT 7
105#define SRC (1 << 25)
106#define SRD (1 << 26)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700107#define SOFTRESET (1 << 1)
108#define RESETDONE (1 << 0)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100109
110/*
111 * FIXME: Most likely all the data using these _DEVID defines should come
112 * from the platform_data, or implemented in controller and slot specific
113 * functions.
114 */
115#define OMAP_MMC1_DEVID 0
116#define OMAP_MMC2_DEVID 1
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +0000117#define OMAP_MMC3_DEVID 2
kishore kadiyala82cf8182009-09-22 16:45:25 -0700118#define OMAP_MMC4_DEVID 3
119#define OMAP_MMC5_DEVID 4
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100120
Balaji T Kfa4aa2d2011-07-01 22:09:35 +0530121#define MMC_AUTOSUSPEND_DELAY 100
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100122#define MMC_TIMEOUT_MS 20
123#define OMAP_MMC_MASTER_CLOCK 96000000
Andy Shevchenko6b206ef2011-07-13 11:16:29 -0400124#define OMAP_MMC_MIN_CLOCK 400000
125#define OMAP_MMC_MAX_CLOCK 52000000
Kishore Kadiyala0005ae72011-02-28 20:48:05 +0530126#define DRIVER_NAME "omap_hsmmc"
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100127
128/*
129 * One controller can have multiple slots, like on some omap boards using
130 * omap.c controller driver. Luckily this is not currently done on any known
131 * omap_hsmmc.c device.
132 */
133#define mmc_slot(host) (host->pdata->slots[host->slot_id])
134
135/*
136 * MMC Host controller read/write API's
137 */
138#define OMAP_HSMMC_READ(base, reg) \
139 __raw_readl((base) + OMAP_HSMMC_##reg)
140
141#define OMAP_HSMMC_WRITE(base, reg, val) \
142 __raw_writel((val), (base) + OMAP_HSMMC_##reg)
143
Per Forlin9782aff2011-07-01 18:55:23 +0200144struct omap_hsmmc_next {
145 unsigned int dma_len;
146 s32 cookie;
147};
148
Denis Karpov70a33412009-09-22 16:44:59 -0700149struct omap_hsmmc_host {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100150 struct device *dev;
151 struct mmc_host *mmc;
152 struct mmc_request *mrq;
153 struct mmc_command *cmd;
154 struct mmc_data *data;
155 struct clk *fclk;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100156 struct clk *dbclk;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800157 /*
158 * vcc == configured supply
159 * vcc_aux == optional
160 * - MMC1, supply for DAT4..DAT7
161 * - MMC2/MMC2, external level shifter voltage supply, for
162 * chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
163 */
164 struct regulator *vcc;
165 struct regulator *vcc_aux;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100166 struct work_struct mmc_carddetect_work;
167 void __iomem *base;
168 resource_size_t mapbase;
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700169 spinlock_t irq_lock; /* Prevent races with irq handler */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100170 unsigned int id;
171 unsigned int dma_len;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200172 unsigned int dma_sg_idx;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100173 unsigned char bus_mode;
Adrian Huntera3621462009-09-22 16:44:42 -0700174 unsigned char power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100175 u32 *buffer;
176 u32 bytesleft;
177 int suspended;
178 int irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100179 int use_dma, dma_ch;
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +0000180 int dma_line_tx, dma_line_rx;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100181 int slot_id;
Adrian Hunter2bec0892009-09-22 16:45:02 -0700182 int got_dbclk;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200183 int response_busy;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700184 int context_loss;
Denis Karpovdd498ef2009-09-22 16:44:49 -0700185 int dpm_state;
Adrian Hunter623821f2009-09-22 16:44:51 -0700186 int vdd;
Adrian Hunterb62f6222009-09-22 16:45:01 -0700187 int protect_card;
188 int reqs_blocked;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800189 int use_reg;
Adrian Hunterb4175772010-05-26 14:42:06 -0700190 int req_in_progress;
Per Forlin9782aff2011-07-01 18:55:23 +0200191 struct omap_hsmmc_next next_data;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700192
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100193 struct omap_mmc_platform_data *pdata;
194};
195
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800196static int omap_hsmmc_card_detect(struct device *dev, int slot)
197{
198 struct omap_mmc_platform_data *mmc = dev->platform_data;
199
200 /* NOTE: assumes card detect signal is active-low */
201 return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
202}
203
204static int omap_hsmmc_get_wp(struct device *dev, int slot)
205{
206 struct omap_mmc_platform_data *mmc = dev->platform_data;
207
208 /* NOTE: assumes write protect signal is active-high */
209 return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
210}
211
212static int omap_hsmmc_get_cover_state(struct device *dev, int slot)
213{
214 struct omap_mmc_platform_data *mmc = dev->platform_data;
215
216 /* NOTE: assumes card detect signal is active-low */
217 return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
218}
219
220#ifdef CONFIG_PM
221
222static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)
223{
224 struct omap_mmc_platform_data *mmc = dev->platform_data;
225
226 disable_irq(mmc->slots[0].card_detect_irq);
227 return 0;
228}
229
230static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
231{
232 struct omap_mmc_platform_data *mmc = dev->platform_data;
233
234 enable_irq(mmc->slots[0].card_detect_irq);
235 return 0;
236}
237
238#else
239
240#define omap_hsmmc_suspend_cdirq NULL
241#define omap_hsmmc_resume_cdirq NULL
242
243#endif
244
Adrian Hunterb702b102010-02-15 10:03:35 -0800245#ifdef CONFIG_REGULATOR
246
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800247static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
248 int vdd)
249{
250 struct omap_hsmmc_host *host =
251 platform_get_drvdata(to_platform_device(dev));
252 int ret;
253
254 if (mmc_slot(host).before_set_reg)
255 mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
256
257 if (power_on)
Linus Walleij99fc5132010-09-29 01:08:27 -0400258 ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800259 else
Linus Walleij99fc5132010-09-29 01:08:27 -0400260 ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800261
262 if (mmc_slot(host).after_set_reg)
263 mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
264
265 return ret;
266}
267
Kishore Kadiyala7715db52011-02-15 03:40:36 -0500268static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800269 int vdd)
270{
271 struct omap_hsmmc_host *host =
272 platform_get_drvdata(to_platform_device(dev));
273 int ret = 0;
274
275 /*
276 * If we don't see a Vcc regulator, assume it's a fixed
277 * voltage always-on regulator.
278 */
279 if (!host->vcc)
280 return 0;
281
282 if (mmc_slot(host).before_set_reg)
283 mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
284
285 /*
286 * Assume Vcc regulator is used only to power the card ... OMAP
287 * VDDS is used to power the pins, optionally with a transceiver to
288 * support cards using voltages other than VDDS (1.8V nominal). When a
289 * transceiver is used, DAT3..7 are muxed as transceiver control pins.
290 *
291 * In some cases this regulator won't support enable/disable;
292 * e.g. it's a fixed rail for a WLAN chip.
293 *
294 * In other cases vcc_aux switches interface power. Example, for
295 * eMMC cards it represents VccQ. Sometimes transceivers or SDIO
296 * chips/cards need an interface voltage rail too.
297 */
298 if (power_on) {
Linus Walleij99fc5132010-09-29 01:08:27 -0400299 ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800300 /* Enable interface voltage rail, if needed */
301 if (ret == 0 && host->vcc_aux) {
302 ret = regulator_enable(host->vcc_aux);
303 if (ret < 0)
Linus Walleij99fc5132010-09-29 01:08:27 -0400304 ret = mmc_regulator_set_ocr(host->mmc,
305 host->vcc, 0);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800306 }
307 } else {
Linus Walleij99fc5132010-09-29 01:08:27 -0400308 /* Shut down the rail */
Adrian Hunter6da20c82010-02-15 10:03:34 -0800309 if (host->vcc_aux)
310 ret = regulator_disable(host->vcc_aux);
Linus Walleij99fc5132010-09-29 01:08:27 -0400311 if (!ret) {
312 /* Then proceed to shut down the local regulator */
313 ret = mmc_regulator_set_ocr(host->mmc,
314 host->vcc, 0);
315 }
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800316 }
317
318 if (mmc_slot(host).after_set_reg)
319 mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
320
321 return ret;
322}
323
Kishore Kadiyala7715db52011-02-15 03:40:36 -0500324static int omap_hsmmc_4_set_power(struct device *dev, int slot, int power_on,
325 int vdd)
326{
327 return 0;
328}
329
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800330static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
331 int vdd, int cardsleep)
332{
333 struct omap_hsmmc_host *host =
334 platform_get_drvdata(to_platform_device(dev));
335 int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
336
337 return regulator_set_mode(host->vcc, mode);
338}
339
Kishore Kadiyala7715db52011-02-15 03:40:36 -0500340static int omap_hsmmc_235_set_sleep(struct device *dev, int slot, int sleep,
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800341 int vdd, int cardsleep)
342{
343 struct omap_hsmmc_host *host =
344 platform_get_drvdata(to_platform_device(dev));
345 int err, mode;
346
347 /*
348 * If we don't see a Vcc regulator, assume it's a fixed
349 * voltage always-on regulator.
350 */
351 if (!host->vcc)
352 return 0;
353
354 mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
355
356 if (!host->vcc_aux)
357 return regulator_set_mode(host->vcc, mode);
358
359 if (cardsleep) {
360 /* VCC can be turned off if card is asleep */
361 if (sleep)
Linus Walleij99fc5132010-09-29 01:08:27 -0400362 err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800363 else
Linus Walleij99fc5132010-09-29 01:08:27 -0400364 err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800365 } else
366 err = regulator_set_mode(host->vcc, mode);
367 if (err)
368 return err;
Adrian Huntere0eb2422010-02-15 10:03:34 -0800369
370 if (!mmc_slot(host).vcc_aux_disable_is_sleep)
371 return regulator_set_mode(host->vcc_aux, mode);
372
373 if (sleep)
374 return regulator_disable(host->vcc_aux);
375 else
376 return regulator_enable(host->vcc_aux);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800377}
378
Kishore Kadiyala7715db52011-02-15 03:40:36 -0500379static int omap_hsmmc_4_set_sleep(struct device *dev, int slot, int sleep,
380 int vdd, int cardsleep)
381{
382 return 0;
383}
384
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800385static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
386{
387 struct regulator *reg;
388 int ret = 0;
kishore kadiyala64be9782010-10-01 16:35:28 -0700389 int ocr_value = 0;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800390
391 switch (host->id) {
392 case OMAP_MMC1_DEVID:
393 /* On-chip level shifting via PBIAS0/PBIAS1 */
394 mmc_slot(host).set_power = omap_hsmmc_1_set_power;
395 mmc_slot(host).set_sleep = omap_hsmmc_1_set_sleep;
396 break;
397 case OMAP_MMC2_DEVID:
398 case OMAP_MMC3_DEVID:
Kishore Kadiyala7715db52011-02-15 03:40:36 -0500399 case OMAP_MMC5_DEVID:
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800400 /* Off-chip level shifting, or none */
Kishore Kadiyala7715db52011-02-15 03:40:36 -0500401 mmc_slot(host).set_power = omap_hsmmc_235_set_power;
402 mmc_slot(host).set_sleep = omap_hsmmc_235_set_sleep;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800403 break;
Kishore Kadiyala7715db52011-02-15 03:40:36 -0500404 case OMAP_MMC4_DEVID:
405 mmc_slot(host).set_power = omap_hsmmc_4_set_power;
406 mmc_slot(host).set_sleep = omap_hsmmc_4_set_sleep;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800407 default:
408 pr_err("MMC%d configuration not supported!\n", host->id);
409 return -EINVAL;
410 }
411
412 reg = regulator_get(host->dev, "vmmc");
413 if (IS_ERR(reg)) {
414 dev_dbg(host->dev, "vmmc regulator missing\n");
415 /*
416 * HACK: until fixed.c regulator is usable,
417 * we don't require a main regulator
418 * for MMC2 or MMC3
419 */
420 if (host->id == OMAP_MMC1_DEVID) {
421 ret = PTR_ERR(reg);
422 goto err;
423 }
424 } else {
425 host->vcc = reg;
kishore kadiyala64be9782010-10-01 16:35:28 -0700426 ocr_value = mmc_regulator_get_ocrmask(reg);
427 if (!mmc_slot(host).ocr_mask) {
428 mmc_slot(host).ocr_mask = ocr_value;
429 } else {
430 if (!(mmc_slot(host).ocr_mask & ocr_value)) {
431 pr_err("MMC%d ocrmask %x is not supported\n",
432 host->id, mmc_slot(host).ocr_mask);
433 mmc_slot(host).ocr_mask = 0;
434 return -EINVAL;
435 }
436 }
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800437
438 /* Allow an aux regulator */
439 reg = regulator_get(host->dev, "vmmc_aux");
440 host->vcc_aux = IS_ERR(reg) ? NULL : reg;
441
Balaji T Kb1c1df72011-05-30 19:55:34 +0530442 /* For eMMC do not power off when not in sleep state */
443 if (mmc_slot(host).no_regulator_off_init)
444 return 0;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800445 /*
446 * UGLY HACK: workaround regulator framework bugs.
447 * When the bootloader leaves a supply active, it's
448 * initialized with zero usecount ... and we can't
449 * disable it without first enabling it. Until the
450 * framework is fixed, we need a workaround like this
451 * (which is safe for MMC, but not in general).
452 */
453 if (regulator_is_enabled(host->vcc) > 0) {
454 regulator_enable(host->vcc);
455 regulator_disable(host->vcc);
456 }
457 if (host->vcc_aux) {
458 if (regulator_is_enabled(reg) > 0) {
459 regulator_enable(reg);
460 regulator_disable(reg);
461 }
462 }
463 }
464
465 return 0;
466
467err:
468 mmc_slot(host).set_power = NULL;
469 mmc_slot(host).set_sleep = NULL;
470 return ret;
471}
472
473static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
474{
475 regulator_put(host->vcc);
476 regulator_put(host->vcc_aux);
477 mmc_slot(host).set_power = NULL;
478 mmc_slot(host).set_sleep = NULL;
479}
480
Adrian Hunterb702b102010-02-15 10:03:35 -0800481static inline int omap_hsmmc_have_reg(void)
482{
483 return 1;
484}
485
486#else
487
488static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
489{
490 return -EINVAL;
491}
492
493static inline void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
494{
495}
496
497static inline int omap_hsmmc_have_reg(void)
498{
499 return 0;
500}
501
502#endif
503
504static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
505{
506 int ret;
507
508 if (gpio_is_valid(pdata->slots[0].switch_pin)) {
Adrian Hunterb702b102010-02-15 10:03:35 -0800509 if (pdata->slots[0].cover)
510 pdata->slots[0].get_cover_state =
511 omap_hsmmc_get_cover_state;
512 else
513 pdata->slots[0].card_detect = omap_hsmmc_card_detect;
514 pdata->slots[0].card_detect_irq =
515 gpio_to_irq(pdata->slots[0].switch_pin);
516 ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd");
517 if (ret)
518 return ret;
519 ret = gpio_direction_input(pdata->slots[0].switch_pin);
520 if (ret)
521 goto err_free_sp;
522 } else
523 pdata->slots[0].switch_pin = -EINVAL;
524
525 if (gpio_is_valid(pdata->slots[0].gpio_wp)) {
526 pdata->slots[0].get_ro = omap_hsmmc_get_wp;
527 ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp");
528 if (ret)
529 goto err_free_cd;
530 ret = gpio_direction_input(pdata->slots[0].gpio_wp);
531 if (ret)
532 goto err_free_wp;
533 } else
534 pdata->slots[0].gpio_wp = -EINVAL;
535
536 return 0;
537
538err_free_wp:
539 gpio_free(pdata->slots[0].gpio_wp);
540err_free_cd:
541 if (gpio_is_valid(pdata->slots[0].switch_pin))
542err_free_sp:
543 gpio_free(pdata->slots[0].switch_pin);
544 return ret;
545}
546
547static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
548{
549 if (gpio_is_valid(pdata->slots[0].gpio_wp))
550 gpio_free(pdata->slots[0].gpio_wp);
551 if (gpio_is_valid(pdata->slots[0].switch_pin))
552 gpio_free(pdata->slots[0].switch_pin);
553}
554
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100555/*
Andy Shevchenkoe0c7f992011-05-06 12:14:05 +0300556 * Start clock to the card
557 */
558static void omap_hsmmc_start_clock(struct omap_hsmmc_host *host)
559{
560 OMAP_HSMMC_WRITE(host->base, SYSCTL,
561 OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
562}
563
564/*
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100565 * Stop clock to the card
566 */
Denis Karpov70a33412009-09-22 16:44:59 -0700567static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100568{
569 OMAP_HSMMC_WRITE(host->base, SYSCTL,
570 OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
571 if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
572 dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
573}
574
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700575static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
576 struct mmc_command *cmd)
Adrian Hunterb4175772010-05-26 14:42:06 -0700577{
578 unsigned int irq_mask;
579
580 if (host->use_dma)
581 irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
582 else
583 irq_mask = INT_EN_MASK;
584
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700585 /* Disable timeout for erases */
586 if (cmd->opcode == MMC_ERASE)
587 irq_mask &= ~DTO_ENABLE;
588
Adrian Hunterb4175772010-05-26 14:42:06 -0700589 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
590 OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
591 OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
592}
593
594static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
595{
596 OMAP_HSMMC_WRITE(host->base, ISE, 0);
597 OMAP_HSMMC_WRITE(host->base, IE, 0);
598 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
599}
600
Andy Shevchenkoac330f42011-05-10 15:51:54 +0300601/* Calculate divisor for the given clock frequency */
602static u16 calc_divisor(struct mmc_ios *ios)
603{
604 u16 dsor = 0;
605
606 if (ios->clock) {
607 dsor = DIV_ROUND_UP(OMAP_MMC_MASTER_CLOCK, ios->clock);
608 if (dsor > 250)
609 dsor = 250;
610 }
611
612 return dsor;
613}
614
Andy Shevchenko5934df22011-05-06 12:14:06 +0300615static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
616{
617 struct mmc_ios *ios = &host->mmc->ios;
618 unsigned long regval;
619 unsigned long timeout;
620
621 dev_dbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
622
623 omap_hsmmc_stop_clock(host);
624
625 regval = OMAP_HSMMC_READ(host->base, SYSCTL);
626 regval = regval & ~(CLKD_MASK | DTO_MASK);
627 regval = regval | (calc_divisor(ios) << 6) | (DTO << 16);
628 OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
629 OMAP_HSMMC_WRITE(host->base, SYSCTL,
630 OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
631
632 /* Wait till the ICS bit is set */
633 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
634 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
635 && time_before(jiffies, timeout))
636 cpu_relax();
637
638 omap_hsmmc_start_clock(host);
639}
640
Denis Karpov11dd62a2009-09-22 16:44:43 -0700641#ifdef CONFIG_PM
642
643/*
644 * Restore the MMC host context, if it was lost as result of a
645 * power state change.
646 */
Denis Karpov70a33412009-09-22 16:44:59 -0700647static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700648{
649 struct mmc_ios *ios = &host->mmc->ios;
650 struct omap_mmc_platform_data *pdata = host->pdata;
651 int context_loss = 0;
652 u32 hctl, capa, con;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700653 unsigned long timeout;
654
655 if (pdata->get_context_loss_count) {
656 context_loss = pdata->get_context_loss_count(host->dev);
657 if (context_loss < 0)
658 return 1;
659 }
660
661 dev_dbg(mmc_dev(host->mmc), "context was %slost\n",
662 context_loss == host->context_loss ? "not " : "");
663 if (host->context_loss == context_loss)
664 return 1;
665
666 /* Wait for hardware reset */
667 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
668 while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
669 && time_before(jiffies, timeout))
670 ;
671
672 /* Do software reset */
673 OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET);
674 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
675 while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
676 && time_before(jiffies, timeout))
677 ;
678
679 OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
680 OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
681
682 if (host->id == OMAP_MMC1_DEVID) {
683 if (host->power_mode != MMC_POWER_OFF &&
684 (1 << ios->vdd) <= MMC_VDD_23_24)
685 hctl = SDVS18;
686 else
687 hctl = SDVS30;
688 capa = VS30 | VS18;
689 } else {
690 hctl = SDVS18;
691 capa = VS18;
692 }
693
694 OMAP_HSMMC_WRITE(host->base, HCTL,
695 OMAP_HSMMC_READ(host->base, HCTL) | hctl);
696
697 OMAP_HSMMC_WRITE(host->base, CAPA,
698 OMAP_HSMMC_READ(host->base, CAPA) | capa);
699
700 OMAP_HSMMC_WRITE(host->base, HCTL,
701 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
702
703 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
704 while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP
705 && time_before(jiffies, timeout))
706 ;
707
Adrian Hunterb4175772010-05-26 14:42:06 -0700708 omap_hsmmc_disable_irq(host);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700709
710 /* Do not initialize card-specific things if the power is off */
711 if (host->power_mode == MMC_POWER_OFF)
712 goto out;
713
714 con = OMAP_HSMMC_READ(host->base, CON);
715 switch (ios->bus_width) {
716 case MMC_BUS_WIDTH_8:
717 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
718 break;
719 case MMC_BUS_WIDTH_4:
720 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
721 OMAP_HSMMC_WRITE(host->base, HCTL,
722 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
723 break;
724 case MMC_BUS_WIDTH_1:
725 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
726 OMAP_HSMMC_WRITE(host->base, HCTL,
727 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
728 break;
729 }
730
Andy Shevchenko5934df22011-05-06 12:14:06 +0300731 omap_hsmmc_set_clock(host);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700732
733 con = OMAP_HSMMC_READ(host->base, CON);
734 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
735 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
736 else
737 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
738out:
739 host->context_loss = context_loss;
740
741 dev_dbg(mmc_dev(host->mmc), "context is restored\n");
742 return 0;
743}
744
745/*
746 * Save the MMC host context (store the number of power state changes so far).
747 */
Denis Karpov70a33412009-09-22 16:44:59 -0700748static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700749{
750 struct omap_mmc_platform_data *pdata = host->pdata;
751 int context_loss;
752
753 if (pdata->get_context_loss_count) {
754 context_loss = pdata->get_context_loss_count(host->dev);
755 if (context_loss < 0)
756 return;
757 host->context_loss = context_loss;
758 }
759}
760
761#else
762
Denis Karpov70a33412009-09-22 16:44:59 -0700763static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700764{
765 return 0;
766}
767
Denis Karpov70a33412009-09-22 16:44:59 -0700768static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700769{
770}
771
772#endif
773
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100774/*
775 * Send init stream sequence to card
776 * before sending IDLE command
777 */
Denis Karpov70a33412009-09-22 16:44:59 -0700778static void send_init_stream(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100779{
780 int reg = 0;
781 unsigned long timeout;
782
Adrian Hunterb62f6222009-09-22 16:45:01 -0700783 if (host->protect_card)
784 return;
785
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100786 disable_irq(host->irq);
Adrian Hunterb4175772010-05-26 14:42:06 -0700787
788 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100789 OMAP_HSMMC_WRITE(host->base, CON,
790 OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
791 OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
792
793 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
794 while ((reg != CC) && time_before(jiffies, timeout))
795 reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
796
797 OMAP_HSMMC_WRITE(host->base, CON,
798 OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
Adrian Hunterc653a6d2009-09-22 16:44:56 -0700799
800 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
801 OMAP_HSMMC_READ(host->base, STAT);
802
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100803 enable_irq(host->irq);
804}
805
806static inline
Denis Karpov70a33412009-09-22 16:44:59 -0700807int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100808{
809 int r = 1;
810
Denis Karpov191d1f12009-09-22 16:44:55 -0700811 if (mmc_slot(host).get_cover_state)
812 r = mmc_slot(host).get_cover_state(host->dev, host->slot_id);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100813 return r;
814}
815
816static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700817omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100818 char *buf)
819{
820 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700821 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100822
Denis Karpov70a33412009-09-22 16:44:59 -0700823 return sprintf(buf, "%s\n",
824 omap_hsmmc_cover_is_closed(host) ? "closed" : "open");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100825}
826
Denis Karpov70a33412009-09-22 16:44:59 -0700827static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100828
829static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700830omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100831 char *buf)
832{
833 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700834 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100835
Denis Karpov191d1f12009-09-22 16:44:55 -0700836 return sprintf(buf, "%s\n", mmc_slot(host).name);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100837}
838
Denis Karpov70a33412009-09-22 16:44:59 -0700839static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100840
841/*
842 * Configure the response type and send the cmd.
843 */
844static void
Denis Karpov70a33412009-09-22 16:44:59 -0700845omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100846 struct mmc_data *data)
847{
848 int cmdreg = 0, resptype = 0, cmdtype = 0;
849
850 dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
851 mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
852 host->cmd = cmd;
853
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700854 omap_hsmmc_enable_irq(host, cmd);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100855
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200856 host->response_busy = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100857 if (cmd->flags & MMC_RSP_PRESENT) {
858 if (cmd->flags & MMC_RSP_136)
859 resptype = 1;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200860 else if (cmd->flags & MMC_RSP_BUSY) {
861 resptype = 3;
862 host->response_busy = 1;
863 } else
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100864 resptype = 2;
865 }
866
867 /*
868 * Unlike OMAP1 controller, the cmdtype does not seem to be based on
869 * ac, bc, adtc, bcr. Only commands ending an open ended transfer need
870 * a val of 0x3, rest 0x0.
871 */
872 if (cmd == host->mrq->stop)
873 cmdtype = 0x3;
874
875 cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
876
877 if (data) {
878 cmdreg |= DP_SELECT | MSBS | BCE;
879 if (data->flags & MMC_DATA_READ)
880 cmdreg |= DDIR;
881 else
882 cmdreg &= ~(DDIR);
883 }
884
885 if (host->use_dma)
886 cmdreg |= DMA_EN;
887
Adrian Hunterb4175772010-05-26 14:42:06 -0700888 host->req_in_progress = 1;
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700889
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100890 OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
891 OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
892}
893
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200894static int
Denis Karpov70a33412009-09-22 16:44:59 -0700895omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200896{
897 if (data->flags & MMC_DATA_WRITE)
898 return DMA_TO_DEVICE;
899 else
900 return DMA_FROM_DEVICE;
901}
902
Adrian Hunterb4175772010-05-26 14:42:06 -0700903static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
904{
905 int dma_ch;
906
907 spin_lock(&host->irq_lock);
908 host->req_in_progress = 0;
909 dma_ch = host->dma_ch;
910 spin_unlock(&host->irq_lock);
911
912 omap_hsmmc_disable_irq(host);
913 /* Do not complete the request if DMA is still in progress */
914 if (mrq->data && host->use_dma && dma_ch != -1)
915 return;
916 host->mrq = NULL;
917 mmc_request_done(host->mmc, mrq);
918}
919
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100920/*
921 * Notify the transfer complete to MMC core
922 */
923static void
Denis Karpov70a33412009-09-22 16:44:59 -0700924omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100925{
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200926 if (!data) {
927 struct mmc_request *mrq = host->mrq;
928
Adrian Hunter23050102009-09-22 16:44:57 -0700929 /* TC before CC from CMD6 - don't know why, but it happens */
930 if (host->cmd && host->cmd->opcode == 6 &&
931 host->response_busy) {
932 host->response_busy = 0;
933 return;
934 }
935
Adrian Hunterb4175772010-05-26 14:42:06 -0700936 omap_hsmmc_request_done(host, mrq);
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200937 return;
938 }
939
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100940 host->data = NULL;
941
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100942 if (!data->error)
943 data->bytes_xfered += data->blocks * (data->blksz);
944 else
945 data->bytes_xfered = 0;
946
947 if (!data->stop) {
Adrian Hunterb4175772010-05-26 14:42:06 -0700948 omap_hsmmc_request_done(host, data->mrq);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100949 return;
950 }
Denis Karpov70a33412009-09-22 16:44:59 -0700951 omap_hsmmc_start_command(host, data->stop, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100952}
953
954/*
955 * Notify the core about command completion
956 */
957static void
Denis Karpov70a33412009-09-22 16:44:59 -0700958omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100959{
960 host->cmd = NULL;
961
962 if (cmd->flags & MMC_RSP_PRESENT) {
963 if (cmd->flags & MMC_RSP_136) {
964 /* response type 2 */
965 cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
966 cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
967 cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
968 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
969 } else {
970 /* response types 1, 1b, 3, 4, 5, 6 */
971 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
972 }
973 }
Adrian Hunterb4175772010-05-26 14:42:06 -0700974 if ((host->data == NULL && !host->response_busy) || cmd->error)
975 omap_hsmmc_request_done(host, cmd->mrq);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100976}
977
978/*
979 * DMA clean up for command errors
980 */
Denis Karpov70a33412009-09-22 16:44:59 -0700981static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100982{
Adrian Hunterb4175772010-05-26 14:42:06 -0700983 int dma_ch;
984
Jarkko Lavinen82788ff2008-12-05 12:31:46 +0200985 host->data->error = errno;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100986
Adrian Hunterb4175772010-05-26 14:42:06 -0700987 spin_lock(&host->irq_lock);
988 dma_ch = host->dma_ch;
989 host->dma_ch = -1;
990 spin_unlock(&host->irq_lock);
991
992 if (host->use_dma && dma_ch != -1) {
Per Forlina9120c32011-06-17 20:14:21 +0200993 dma_unmap_sg(mmc_dev(host->mmc), host->data->sg,
994 host->data->sg_len,
Denis Karpov70a33412009-09-22 16:44:59 -0700995 omap_hsmmc_get_dma_dir(host, host->data));
Adrian Hunterb4175772010-05-26 14:42:06 -0700996 omap_free_dma(dma_ch);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100997 }
998 host->data = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100999}
1000
1001/*
1002 * Readable error output
1003 */
1004#ifdef CONFIG_MMC_DEBUG
Adrian Hunter699b9582011-05-06 12:14:01 +03001005static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001006{
1007 /* --- means reserved bit without definition at documentation */
Denis Karpov70a33412009-09-22 16:44:59 -07001008 static const char *omap_hsmmc_status_bits[] = {
Adrian Hunter699b9582011-05-06 12:14:01 +03001009 "CC" , "TC" , "BGE", "---", "BWR" , "BRR" , "---" , "---" ,
1010 "CIRQ", "OBI" , "---", "---", "---" , "---" , "---" , "ERRI",
1011 "CTO" , "CCRC", "CEB", "CIE", "DTO" , "DCRC", "DEB" , "---" ,
1012 "ACE" , "---" , "---", "---", "CERR", "BADA", "---" , "---"
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001013 };
1014 char res[256];
1015 char *buf = res;
1016 int len, i;
1017
1018 len = sprintf(buf, "MMC IRQ 0x%x :", status);
1019 buf += len;
1020
Denis Karpov70a33412009-09-22 16:44:59 -07001021 for (i = 0; i < ARRAY_SIZE(omap_hsmmc_status_bits); i++)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001022 if (status & (1 << i)) {
Denis Karpov70a33412009-09-22 16:44:59 -07001023 len = sprintf(buf, " %s", omap_hsmmc_status_bits[i]);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001024 buf += len;
1025 }
1026
1027 dev_dbg(mmc_dev(host->mmc), "%s\n", res);
1028}
Adrian Hunter699b9582011-05-06 12:14:01 +03001029#else
1030static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host,
1031 u32 status)
1032{
1033}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001034#endif /* CONFIG_MMC_DEBUG */
1035
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001036/*
1037 * MMC controller internal state machines reset
1038 *
1039 * Used to reset command or data internal state machines, using respectively
1040 * SRC or SRD bit of SYSCTL register
1041 * Can be called from interrupt context
1042 */
Denis Karpov70a33412009-09-22 16:44:59 -07001043static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
1044 unsigned long bit)
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001045{
1046 unsigned long i = 0;
1047 unsigned long limit = (loops_per_jiffy *
1048 msecs_to_jiffies(MMC_TIMEOUT_MS));
1049
1050 OMAP_HSMMC_WRITE(host->base, SYSCTL,
1051 OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
1052
Madhusudhan Chikkature07ad64b2010-10-01 16:35:25 -07001053 /*
1054 * OMAP4 ES2 and greater has an updated reset logic.
1055 * Monitor a 0->1 transition first
1056 */
1057 if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
kishore kadiyalab432b4b2010-11-17 22:35:32 -05001058 while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
Madhusudhan Chikkature07ad64b2010-10-01 16:35:25 -07001059 && (i++ < limit))
1060 cpu_relax();
1061 }
1062 i = 0;
1063
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001064 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
1065 (i++ < limit))
1066 cpu_relax();
1067
1068 if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
1069 dev_err(mmc_dev(host->mmc),
1070 "Timeout waiting on controller reset in %s\n",
1071 __func__);
1072}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001073
Adrian Hunterb4175772010-05-26 14:42:06 -07001074static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001075{
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001076 struct mmc_data *data;
Adrian Hunterb4175772010-05-26 14:42:06 -07001077 int end_cmd = 0, end_trans = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001078
Adrian Hunterb4175772010-05-26 14:42:06 -07001079 if (!host->req_in_progress) {
1080 do {
1081 OMAP_HSMMC_WRITE(host->base, STAT, status);
1082 /* Flush posted write */
1083 status = OMAP_HSMMC_READ(host->base, STAT);
1084 } while (status & INT_EN_MASK);
1085 return;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001086 }
1087
1088 data = host->data;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001089 dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
1090
1091 if (status & ERR) {
Adrian Hunter699b9582011-05-06 12:14:01 +03001092 omap_hsmmc_dbg_report_irq(host, status);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001093 if ((status & CMD_TIMEOUT) ||
1094 (status & CMD_CRC)) {
1095 if (host->cmd) {
1096 if (status & CMD_TIMEOUT) {
Denis Karpov70a33412009-09-22 16:44:59 -07001097 omap_hsmmc_reset_controller_fsm(host,
1098 SRC);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001099 host->cmd->error = -ETIMEDOUT;
1100 } else {
1101 host->cmd->error = -EILSEQ;
1102 }
1103 end_cmd = 1;
1104 }
Adrian Hunter4a694dc2009-01-12 16:13:08 +02001105 if (host->data || host->response_busy) {
1106 if (host->data)
Denis Karpov70a33412009-09-22 16:44:59 -07001107 omap_hsmmc_dma_cleanup(host,
1108 -ETIMEDOUT);
Adrian Hunter4a694dc2009-01-12 16:13:08 +02001109 host->response_busy = 0;
Denis Karpov70a33412009-09-22 16:44:59 -07001110 omap_hsmmc_reset_controller_fsm(host, SRD);
Jean Pihetc232f452009-02-11 13:11:39 -08001111 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001112 }
1113 if ((status & DATA_TIMEOUT) ||
1114 (status & DATA_CRC)) {
Adrian Hunter4a694dc2009-01-12 16:13:08 +02001115 if (host->data || host->response_busy) {
1116 int err = (status & DATA_TIMEOUT) ?
1117 -ETIMEDOUT : -EILSEQ;
1118
1119 if (host->data)
Denis Karpov70a33412009-09-22 16:44:59 -07001120 omap_hsmmc_dma_cleanup(host, err);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001121 else
Adrian Hunter4a694dc2009-01-12 16:13:08 +02001122 host->mrq->cmd->error = err;
1123 host->response_busy = 0;
Denis Karpov70a33412009-09-22 16:44:59 -07001124 omap_hsmmc_reset_controller_fsm(host, SRD);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001125 end_trans = 1;
1126 }
1127 }
1128 if (status & CARD_ERR) {
1129 dev_dbg(mmc_dev(host->mmc),
1130 "Ignoring card err CMD%d\n", host->cmd->opcode);
1131 if (host->cmd)
1132 end_cmd = 1;
1133 if (host->data)
1134 end_trans = 1;
1135 }
1136 }
1137
1138 OMAP_HSMMC_WRITE(host->base, STAT, status);
1139
Jarkko Lavinena8fe29d2009-04-08 11:18:32 +03001140 if (end_cmd || ((status & CC) && host->cmd))
Denis Karpov70a33412009-09-22 16:44:59 -07001141 omap_hsmmc_cmd_done(host, host->cmd);
Jarkko Lavinen0a40e642009-09-22 16:44:54 -07001142 if ((end_trans || (status & TC)) && host->mrq)
Denis Karpov70a33412009-09-22 16:44:59 -07001143 omap_hsmmc_xfer_done(host, data);
Adrian Hunterb4175772010-05-26 14:42:06 -07001144}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001145
Adrian Hunterb4175772010-05-26 14:42:06 -07001146/*
1147 * MMC controller IRQ handler
1148 */
1149static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
1150{
1151 struct omap_hsmmc_host *host = dev_id;
1152 int status;
1153
1154 status = OMAP_HSMMC_READ(host->base, STAT);
1155 do {
1156 omap_hsmmc_do_irq(host, status);
1157 /* Flush posted write */
1158 status = OMAP_HSMMC_READ(host->base, STAT);
1159 } while (status & INT_EN_MASK);
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001160
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001161 return IRQ_HANDLED;
1162}
1163
Denis Karpov70a33412009-09-22 16:44:59 -07001164static void set_sd_bus_power(struct omap_hsmmc_host *host)
Adrian Huntere13bb302009-03-12 17:08:26 +02001165{
1166 unsigned long i;
1167
1168 OMAP_HSMMC_WRITE(host->base, HCTL,
1169 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
1170 for (i = 0; i < loops_per_jiffy; i++) {
1171 if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
1172 break;
1173 cpu_relax();
1174 }
1175}
1176
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001177/*
David Brownelleb250822009-02-17 14:49:01 -08001178 * Switch MMC interface voltage ... only relevant for MMC1.
1179 *
1180 * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
1181 * The MMC2 transceiver controls are used instead of DAT4..DAT7.
1182 * Some chips, like eMMC ones, use internal transceivers.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001183 */
Denis Karpov70a33412009-09-22 16:44:59 -07001184static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001185{
1186 u32 reg_val = 0;
1187 int ret;
1188
1189 /* Disable the clocks */
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301190 pm_runtime_put_sync(host->dev);
Adrian Hunter2bec0892009-09-22 16:45:02 -07001191 if (host->got_dbclk)
1192 clk_disable(host->dbclk);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001193
1194 /* Turn the power off */
1195 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001196
1197 /* Turn the power ON with given VDD 1.8 or 3.0v */
Adrian Hunter2bec0892009-09-22 16:45:02 -07001198 if (!ret)
1199 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1,
1200 vdd);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301201 pm_runtime_get_sync(host->dev);
Adrian Hunter2bec0892009-09-22 16:45:02 -07001202 if (host->got_dbclk)
1203 clk_enable(host->dbclk);
1204
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001205 if (ret != 0)
1206 goto err;
1207
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001208 OMAP_HSMMC_WRITE(host->base, HCTL,
1209 OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
1210 reg_val = OMAP_HSMMC_READ(host->base, HCTL);
David Brownelleb250822009-02-17 14:49:01 -08001211
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001212 /*
1213 * If a MMC dual voltage card is detected, the set_ios fn calls
1214 * this fn with VDD bit set for 1.8V. Upon card removal from the
Denis Karpov70a33412009-09-22 16:44:59 -07001215 * slot, omap_hsmmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001216 *
David Brownelleb250822009-02-17 14:49:01 -08001217 * Cope with a bit of slop in the range ... per data sheets:
1218 * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
1219 * but recommended values are 1.71V to 1.89V
1220 * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
1221 * but recommended values are 2.7V to 3.3V
1222 *
1223 * Board setup code shouldn't permit anything very out-of-range.
1224 * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
1225 * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001226 */
David Brownelleb250822009-02-17 14:49:01 -08001227 if ((1 << vdd) <= MMC_VDD_23_24)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001228 reg_val |= SDVS18;
David Brownelleb250822009-02-17 14:49:01 -08001229 else
1230 reg_val |= SDVS30;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001231
1232 OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
Adrian Huntere13bb302009-03-12 17:08:26 +02001233 set_sd_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001234
1235 return 0;
1236err:
1237 dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
1238 return ret;
1239}
1240
Adrian Hunterb62f6222009-09-22 16:45:01 -07001241/* Protect the card while the cover is open */
1242static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
1243{
1244 if (!mmc_slot(host).get_cover_state)
1245 return;
1246
1247 host->reqs_blocked = 0;
1248 if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
1249 if (host->protect_card) {
1250 printk(KERN_INFO "%s: cover is closed, "
1251 "card is now accessible\n",
1252 mmc_hostname(host->mmc));
1253 host->protect_card = 0;
1254 }
1255 } else {
1256 if (!host->protect_card) {
1257 printk(KERN_INFO "%s: cover is open, "
1258 "card is now inaccessible\n",
1259 mmc_hostname(host->mmc));
1260 host->protect_card = 1;
1261 }
1262 }
1263}
1264
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001265/*
1266 * Work Item to notify the core about card insertion/removal
1267 */
Denis Karpov70a33412009-09-22 16:44:59 -07001268static void omap_hsmmc_detect(struct work_struct *work)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001269{
Denis Karpov70a33412009-09-22 16:44:59 -07001270 struct omap_hsmmc_host *host =
1271 container_of(work, struct omap_hsmmc_host, mmc_carddetect_work);
David Brownell249d0fa2009-02-04 14:42:03 -08001272 struct omap_mmc_slot_data *slot = &mmc_slot(host);
Adrian Huntera6b22402009-09-22 16:44:45 -07001273 int carddetect;
David Brownell249d0fa2009-02-04 14:42:03 -08001274
Adrian Huntera6b22402009-09-22 16:44:45 -07001275 if (host->suspended)
1276 return;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001277
1278 sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
Adrian Huntera6b22402009-09-22 16:44:45 -07001279
Denis Karpov191d1f12009-09-22 16:44:55 -07001280 if (slot->card_detect)
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001281 carddetect = slot->card_detect(host->dev, host->slot_id);
Adrian Hunterb62f6222009-09-22 16:45:01 -07001282 else {
1283 omap_hsmmc_protect_card(host);
Adrian Huntera6b22402009-09-22 16:44:45 -07001284 carddetect = -ENOSYS;
Adrian Hunterb62f6222009-09-22 16:45:01 -07001285 }
Adrian Huntera6b22402009-09-22 16:44:45 -07001286
Madhusudhan Chikkaturecdeebad2010-04-06 14:34:49 -07001287 if (carddetect)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001288 mmc_detect_change(host->mmc, (HZ * 200) / 1000);
Madhusudhan Chikkaturecdeebad2010-04-06 14:34:49 -07001289 else
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001290 mmc_detect_change(host->mmc, (HZ * 50) / 1000);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001291}
1292
1293/*
1294 * ISR for handling card insertion and removal
1295 */
Denis Karpov70a33412009-09-22 16:44:59 -07001296static irqreturn_t omap_hsmmc_cd_handler(int irq, void *dev_id)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001297{
Denis Karpov70a33412009-09-22 16:44:59 -07001298 struct omap_hsmmc_host *host = (struct omap_hsmmc_host *)dev_id;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001299
Adrian Huntera6b22402009-09-22 16:44:45 -07001300 if (host->suspended)
1301 return IRQ_HANDLED;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001302 schedule_work(&host->mmc_carddetect_work);
1303
1304 return IRQ_HANDLED;
1305}
1306
Denis Karpov70a33412009-09-22 16:44:59 -07001307static int omap_hsmmc_get_dma_sync_dev(struct omap_hsmmc_host *host,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001308 struct mmc_data *data)
1309{
1310 int sync_dev;
1311
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +00001312 if (data->flags & MMC_DATA_WRITE)
1313 sync_dev = host->dma_line_tx;
1314 else
1315 sync_dev = host->dma_line_rx;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001316 return sync_dev;
1317}
1318
Denis Karpov70a33412009-09-22 16:44:59 -07001319static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host,
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001320 struct mmc_data *data,
1321 struct scatterlist *sgl)
1322{
1323 int blksz, nblk, dma_ch;
1324
1325 dma_ch = host->dma_ch;
1326 if (data->flags & MMC_DATA_WRITE) {
1327 omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
1328 (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
1329 omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
1330 sg_dma_address(sgl), 0, 0);
1331 } else {
1332 omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
Denis Karpov191d1f12009-09-22 16:44:55 -07001333 (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001334 omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
1335 sg_dma_address(sgl), 0, 0);
1336 }
1337
1338 blksz = host->data->blksz;
1339 nblk = sg_dma_len(sgl) / blksz;
1340
1341 omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32,
1342 blksz / 4, nblk, OMAP_DMA_SYNC_FRAME,
Denis Karpov70a33412009-09-22 16:44:59 -07001343 omap_hsmmc_get_dma_sync_dev(host, data),
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001344 !(data->flags & MMC_DATA_WRITE));
1345
1346 omap_start_dma(dma_ch);
1347}
1348
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001349/*
1350 * DMA call back function
1351 */
Adrian Hunterb4175772010-05-26 14:42:06 -07001352static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001353{
Adrian Hunterb4175772010-05-26 14:42:06 -07001354 struct omap_hsmmc_host *host = cb_data;
1355 struct mmc_data *data = host->mrq->data;
1356 int dma_ch, req_in_progress;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001357
Venkatraman Sf3584e52010-08-10 18:01:54 -07001358 if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
1359 dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n",
1360 ch_status);
1361 return;
1362 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001363
Adrian Hunterb4175772010-05-26 14:42:06 -07001364 spin_lock(&host->irq_lock);
1365 if (host->dma_ch < 0) {
1366 spin_unlock(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001367 return;
Adrian Hunterb4175772010-05-26 14:42:06 -07001368 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001369
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001370 host->dma_sg_idx++;
1371 if (host->dma_sg_idx < host->dma_len) {
1372 /* Fire up the next transfer. */
Adrian Hunterb4175772010-05-26 14:42:06 -07001373 omap_hsmmc_config_dma_params(host, data,
1374 data->sg + host->dma_sg_idx);
1375 spin_unlock(&host->irq_lock);
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001376 return;
1377 }
1378
Per Forlin9782aff2011-07-01 18:55:23 +02001379 if (!data->host_cookie)
1380 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1381 omap_hsmmc_get_dma_dir(host, data));
Adrian Hunterb4175772010-05-26 14:42:06 -07001382
1383 req_in_progress = host->req_in_progress;
1384 dma_ch = host->dma_ch;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001385 host->dma_ch = -1;
Adrian Hunterb4175772010-05-26 14:42:06 -07001386 spin_unlock(&host->irq_lock);
1387
1388 omap_free_dma(dma_ch);
1389
1390 /* If DMA has finished after TC, complete the request */
1391 if (!req_in_progress) {
1392 struct mmc_request *mrq = host->mrq;
1393
1394 host->mrq = NULL;
1395 mmc_request_done(host->mmc, mrq);
1396 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001397}
1398
Per Forlin9782aff2011-07-01 18:55:23 +02001399static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
1400 struct mmc_data *data,
1401 struct omap_hsmmc_next *next)
1402{
1403 int dma_len;
1404
1405 if (!next && data->host_cookie &&
1406 data->host_cookie != host->next_data.cookie) {
1407 printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d"
1408 " host->next_data.cookie %d\n",
1409 __func__, data->host_cookie, host->next_data.cookie);
1410 data->host_cookie = 0;
1411 }
1412
1413 /* Check if next job is already prepared */
1414 if (next ||
1415 (!next && data->host_cookie != host->next_data.cookie)) {
1416 dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
1417 data->sg_len,
1418 omap_hsmmc_get_dma_dir(host, data));
1419
1420 } else {
1421 dma_len = host->next_data.dma_len;
1422 host->next_data.dma_len = 0;
1423 }
1424
1425
1426 if (dma_len == 0)
1427 return -EINVAL;
1428
1429 if (next) {
1430 next->dma_len = dma_len;
1431 data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
1432 } else
1433 host->dma_len = dma_len;
1434
1435 return 0;
1436}
1437
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001438/*
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001439 * Routine to configure and start DMA for the MMC card
1440 */
Denis Karpov70a33412009-09-22 16:44:59 -07001441static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
1442 struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001443{
Adrian Hunterb4175772010-05-26 14:42:06 -07001444 int dma_ch = 0, ret = 0, i;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001445 struct mmc_data *data = req->data;
1446
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001447 /* Sanity check: all the SG entries must be aligned by block size. */
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001448 for (i = 0; i < data->sg_len; i++) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001449 struct scatterlist *sgl;
1450
1451 sgl = data->sg + i;
1452 if (sgl->length % data->blksz)
1453 return -EINVAL;
1454 }
1455 if ((data->blksz % 4) != 0)
1456 /* REVISIT: The MMC buffer increments only when MSB is written.
1457 * Return error for blksz which is non multiple of four.
1458 */
1459 return -EINVAL;
1460
Adrian Hunterb4175772010-05-26 14:42:06 -07001461 BUG_ON(host->dma_ch != -1);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001462
Denis Karpov70a33412009-09-22 16:44:59 -07001463 ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data),
1464 "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001465 if (ret != 0) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001466 dev_err(mmc_dev(host->mmc),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001467 "%s: omap_request_dma() failed with %d\n",
1468 mmc_hostname(host->mmc), ret);
1469 return ret;
1470 }
Per Forlin9782aff2011-07-01 18:55:23 +02001471 ret = omap_hsmmc_pre_dma_transfer(host, data, NULL);
1472 if (ret)
1473 return ret;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001474
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001475 host->dma_ch = dma_ch;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001476 host->dma_sg_idx = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001477
Denis Karpov70a33412009-09-22 16:44:59 -07001478 omap_hsmmc_config_dma_params(host, data, data->sg);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001479
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001480 return 0;
1481}
1482
Denis Karpov70a33412009-09-22 16:44:59 -07001483static void set_data_timeout(struct omap_hsmmc_host *host,
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001484 unsigned int timeout_ns,
1485 unsigned int timeout_clks)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001486{
1487 unsigned int timeout, cycle_ns;
1488 uint32_t reg, clkd, dto = 0;
1489
1490 reg = OMAP_HSMMC_READ(host->base, SYSCTL);
1491 clkd = (reg & CLKD_MASK) >> CLKD_SHIFT;
1492 if (clkd == 0)
1493 clkd = 1;
1494
1495 cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001496 timeout = timeout_ns / cycle_ns;
1497 timeout += timeout_clks;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001498 if (timeout) {
1499 while ((timeout & 0x80000000) == 0) {
1500 dto += 1;
1501 timeout <<= 1;
1502 }
1503 dto = 31 - dto;
1504 timeout <<= 1;
1505 if (timeout && dto)
1506 dto += 1;
1507 if (dto >= 13)
1508 dto -= 13;
1509 else
1510 dto = 0;
1511 if (dto > 14)
1512 dto = 14;
1513 }
1514
1515 reg &= ~DTO_MASK;
1516 reg |= dto << DTO_SHIFT;
1517 OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
1518}
1519
1520/*
1521 * Configure block length for MMC/SD cards and initiate the transfer.
1522 */
1523static int
Denis Karpov70a33412009-09-22 16:44:59 -07001524omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001525{
1526 int ret;
1527 host->data = req->data;
1528
1529 if (req->data == NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001530 OMAP_HSMMC_WRITE(host->base, BLK, 0);
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001531 /*
1532 * Set an arbitrary 100ms data timeout for commands with
1533 * busy signal.
1534 */
1535 if (req->cmd->flags & MMC_RSP_BUSY)
1536 set_data_timeout(host, 100000000U, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001537 return 0;
1538 }
1539
1540 OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
1541 | (req->data->blocks << 16));
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001542 set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001543
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001544 if (host->use_dma) {
Denis Karpov70a33412009-09-22 16:44:59 -07001545 ret = omap_hsmmc_start_dma_transfer(host, req);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001546 if (ret != 0) {
1547 dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
1548 return ret;
1549 }
1550 }
1551 return 0;
1552}
1553
Per Forlin9782aff2011-07-01 18:55:23 +02001554static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
1555 int err)
1556{
1557 struct omap_hsmmc_host *host = mmc_priv(mmc);
1558 struct mmc_data *data = mrq->data;
1559
1560 if (host->use_dma) {
1561 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1562 omap_hsmmc_get_dma_dir(host, data));
1563 data->host_cookie = 0;
1564 }
1565}
1566
1567static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1568 bool is_first_req)
1569{
1570 struct omap_hsmmc_host *host = mmc_priv(mmc);
1571
1572 if (mrq->data->host_cookie) {
1573 mrq->data->host_cookie = 0;
1574 return ;
1575 }
1576
1577 if (host->use_dma)
1578 if (omap_hsmmc_pre_dma_transfer(host, mrq->data,
1579 &host->next_data))
1580 mrq->data->host_cookie = 0;
1581}
1582
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001583/*
1584 * Request function. for read/write operation
1585 */
Denis Karpov70a33412009-09-22 16:44:59 -07001586static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001587{
Denis Karpov70a33412009-09-22 16:44:59 -07001588 struct omap_hsmmc_host *host = mmc_priv(mmc);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001589 int err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001590
Adrian Hunterb4175772010-05-26 14:42:06 -07001591 BUG_ON(host->req_in_progress);
1592 BUG_ON(host->dma_ch != -1);
1593 if (host->protect_card) {
1594 if (host->reqs_blocked < 3) {
1595 /*
1596 * Ensure the controller is left in a consistent
1597 * state by resetting the command and data state
1598 * machines.
1599 */
1600 omap_hsmmc_reset_controller_fsm(host, SRD);
1601 omap_hsmmc_reset_controller_fsm(host, SRC);
1602 host->reqs_blocked += 1;
1603 }
1604 req->cmd->error = -EBADF;
1605 if (req->data)
1606 req->data->error = -EBADF;
1607 req->cmd->retries = 0;
1608 mmc_request_done(mmc, req);
1609 return;
1610 } else if (host->reqs_blocked)
1611 host->reqs_blocked = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001612 WARN_ON(host->mrq != NULL);
1613 host->mrq = req;
Denis Karpov70a33412009-09-22 16:44:59 -07001614 err = omap_hsmmc_prepare_data(host, req);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001615 if (err) {
1616 req->cmd->error = err;
1617 if (req->data)
1618 req->data->error = err;
1619 host->mrq = NULL;
1620 mmc_request_done(mmc, req);
1621 return;
1622 }
1623
Denis Karpov70a33412009-09-22 16:44:59 -07001624 omap_hsmmc_start_command(host, req->cmd, req->data);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001625}
1626
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001627/* Routine to configure clock values. Exposed API to core */
Denis Karpov70a33412009-09-22 16:44:59 -07001628static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001629{
Denis Karpov70a33412009-09-22 16:44:59 -07001630 struct omap_hsmmc_host *host = mmc_priv(mmc);
Jarkko Lavinen73153012008-11-21 16:49:54 +02001631 u32 con;
Adrian Huntera3621462009-09-22 16:44:42 -07001632 int do_send_init_stream = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001633
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301634 pm_runtime_get_sync(host->dev);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001635
Adrian Huntera3621462009-09-22 16:44:42 -07001636 if (ios->power_mode != host->power_mode) {
1637 switch (ios->power_mode) {
1638 case MMC_POWER_OFF:
1639 mmc_slot(host).set_power(host->dev, host->slot_id,
1640 0, 0);
Adrian Hunter623821f2009-09-22 16:44:51 -07001641 host->vdd = 0;
Adrian Huntera3621462009-09-22 16:44:42 -07001642 break;
1643 case MMC_POWER_UP:
1644 mmc_slot(host).set_power(host->dev, host->slot_id,
1645 1, ios->vdd);
Adrian Hunter623821f2009-09-22 16:44:51 -07001646 host->vdd = ios->vdd;
Adrian Huntera3621462009-09-22 16:44:42 -07001647 break;
1648 case MMC_POWER_ON:
1649 do_send_init_stream = 1;
1650 break;
1651 }
1652 host->power_mode = ios->power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001653 }
1654
Denis Karpovdd498ef2009-09-22 16:44:49 -07001655 /* FIXME: set registers based only on changes to ios */
1656
Jarkko Lavinen73153012008-11-21 16:49:54 +02001657 con = OMAP_HSMMC_READ(host->base, CON);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001658 switch (mmc->ios.bus_width) {
Jarkko Lavinen73153012008-11-21 16:49:54 +02001659 case MMC_BUS_WIDTH_8:
1660 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
1661 break;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001662 case MMC_BUS_WIDTH_4:
Jarkko Lavinen73153012008-11-21 16:49:54 +02001663 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001664 OMAP_HSMMC_WRITE(host->base, HCTL,
1665 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
1666 break;
1667 case MMC_BUS_WIDTH_1:
Jarkko Lavinen73153012008-11-21 16:49:54 +02001668 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001669 OMAP_HSMMC_WRITE(host->base, HCTL,
1670 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
1671 break;
1672 }
1673
Kishore Kadiyala4621d5f2011-02-28 20:48:04 +05301674 if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
David Brownelleb250822009-02-17 14:49:01 -08001675 /* Only MMC1 can interface at 3V without some flavor
1676 * of external transceiver; but they all handle 1.8V.
1677 */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001678 if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
1679 (ios->vdd == DUAL_VOLT_OCR_BIT)) {
1680 /*
1681 * The mmc_select_voltage fn of the core does
1682 * not seem to set the power_mode to
1683 * MMC_POWER_UP upon recalculating the voltage.
1684 * vdd 1.8v.
1685 */
Denis Karpov70a33412009-09-22 16:44:59 -07001686 if (omap_hsmmc_switch_opcond(host, ios->vdd) != 0)
1687 dev_dbg(mmc_dev(host->mmc),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001688 "Switch operation failed\n");
1689 }
1690 }
1691
Andy Shevchenko5934df22011-05-06 12:14:06 +03001692 omap_hsmmc_set_clock(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001693
Adrian Huntera3621462009-09-22 16:44:42 -07001694 if (do_send_init_stream)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001695 send_init_stream(host);
1696
Denis Karpovabb28e72009-09-22 16:44:44 -07001697 con = OMAP_HSMMC_READ(host->base, CON);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001698 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
Denis Karpovabb28e72009-09-22 16:44:44 -07001699 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
1700 else
1701 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001702
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301703 pm_runtime_put_autosuspend(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001704}
1705
1706static int omap_hsmmc_get_cd(struct mmc_host *mmc)
1707{
Denis Karpov70a33412009-09-22 16:44:59 -07001708 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001709
Denis Karpov191d1f12009-09-22 16:44:55 -07001710 if (!mmc_slot(host).card_detect)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001711 return -ENOSYS;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001712 return mmc_slot(host).card_detect(host->dev, host->slot_id);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001713}
1714
1715static int omap_hsmmc_get_ro(struct mmc_host *mmc)
1716{
Denis Karpov70a33412009-09-22 16:44:59 -07001717 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001718
Denis Karpov191d1f12009-09-22 16:44:55 -07001719 if (!mmc_slot(host).get_ro)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001720 return -ENOSYS;
Denis Karpov191d1f12009-09-22 16:44:55 -07001721 return mmc_slot(host).get_ro(host->dev, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001722}
1723
Grazvydas Ignotas48168582010-08-10 18:01:52 -07001724static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
1725{
1726 struct omap_hsmmc_host *host = mmc_priv(mmc);
1727
1728 if (mmc_slot(host).init_card)
1729 mmc_slot(host).init_card(card);
1730}
1731
Denis Karpov70a33412009-09-22 16:44:59 -07001732static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001733{
1734 u32 hctl, capa, value;
1735
1736 /* Only MMC1 supports 3.0V */
Kishore Kadiyala4621d5f2011-02-28 20:48:04 +05301737 if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001738 hctl = SDVS30;
1739 capa = VS30 | VS18;
1740 } else {
1741 hctl = SDVS18;
1742 capa = VS18;
1743 }
1744
1745 value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
1746 OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
1747
1748 value = OMAP_HSMMC_READ(host->base, CAPA);
1749 OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
1750
1751 /* Set the controller to AUTO IDLE mode */
1752 value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
1753 OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
1754
1755 /* Set SD bus power bit */
Adrian Huntere13bb302009-03-12 17:08:26 +02001756 set_sd_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001757}
1758
Denis Karpov70a33412009-09-22 16:44:59 -07001759static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001760{
Denis Karpov70a33412009-09-22 16:44:59 -07001761 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001762
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301763 pm_runtime_get_sync(host->dev);
1764
Denis Karpovdd498ef2009-09-22 16:44:49 -07001765 return 0;
1766}
1767
Denis Karpov70a33412009-09-22 16:44:59 -07001768static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy)
Denis Karpovdd498ef2009-09-22 16:44:49 -07001769{
Denis Karpov70a33412009-09-22 16:44:59 -07001770 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001771
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301772 pm_runtime_mark_last_busy(host->dev);
1773 pm_runtime_put_autosuspend(host->dev);
1774
Denis Karpovdd498ef2009-09-22 16:44:49 -07001775 return 0;
1776}
1777
Denis Karpov70a33412009-09-22 16:44:59 -07001778static const struct mmc_host_ops omap_hsmmc_ops = {
1779 .enable = omap_hsmmc_enable_fclk,
1780 .disable = omap_hsmmc_disable_fclk,
Per Forlin9782aff2011-07-01 18:55:23 +02001781 .post_req = omap_hsmmc_post_req,
1782 .pre_req = omap_hsmmc_pre_req,
Denis Karpov70a33412009-09-22 16:44:59 -07001783 .request = omap_hsmmc_request,
1784 .set_ios = omap_hsmmc_set_ios,
Denis Karpovdd498ef2009-09-22 16:44:49 -07001785 .get_cd = omap_hsmmc_get_cd,
1786 .get_ro = omap_hsmmc_get_ro,
Grazvydas Ignotas48168582010-08-10 18:01:52 -07001787 .init_card = omap_hsmmc_init_card,
Denis Karpovdd498ef2009-09-22 16:44:49 -07001788 /* NYET -- enable_sdio_irq */
1789};
1790
Denis Karpovd900f712009-09-22 16:44:38 -07001791#ifdef CONFIG_DEBUG_FS
1792
Denis Karpov70a33412009-09-22 16:44:59 -07001793static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
Denis Karpovd900f712009-09-22 16:44:38 -07001794{
1795 struct mmc_host *mmc = s->private;
Denis Karpov70a33412009-09-22 16:44:59 -07001796 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001797 int context_loss = 0;
1798
Denis Karpov70a33412009-09-22 16:44:59 -07001799 if (host->pdata->get_context_loss_count)
1800 context_loss = host->pdata->get_context_loss_count(host->dev);
Denis Karpovd900f712009-09-22 16:44:38 -07001801
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001802 seq_printf(s, "mmc%d:\n"
1803 " enabled:\t%d\n"
Denis Karpovdd498ef2009-09-22 16:44:49 -07001804 " dpm_state:\t%d\n"
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001805 " nesting_cnt:\t%d\n"
Denis Karpov11dd62a2009-09-22 16:44:43 -07001806 " ctx_loss:\t%d:%d\n"
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001807 "\nregs:\n",
Denis Karpovdd498ef2009-09-22 16:44:49 -07001808 mmc->index, mmc->enabled ? 1 : 0,
1809 host->dpm_state, mmc->nesting_cnt,
Denis Karpov11dd62a2009-09-22 16:44:43 -07001810 host->context_loss, context_loss);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001811
Balaji T K7a8c2ce2011-07-01 22:09:34 +05301812 if (host->suspended) {
Denis Karpovdd498ef2009-09-22 16:44:49 -07001813 seq_printf(s, "host suspended, can't read registers\n");
1814 return 0;
1815 }
1816
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301817 pm_runtime_get_sync(host->dev);
Denis Karpovd900f712009-09-22 16:44:38 -07001818
1819 seq_printf(s, "SYSCONFIG:\t0x%08x\n",
1820 OMAP_HSMMC_READ(host->base, SYSCONFIG));
1821 seq_printf(s, "CON:\t\t0x%08x\n",
1822 OMAP_HSMMC_READ(host->base, CON));
1823 seq_printf(s, "HCTL:\t\t0x%08x\n",
1824 OMAP_HSMMC_READ(host->base, HCTL));
1825 seq_printf(s, "SYSCTL:\t\t0x%08x\n",
1826 OMAP_HSMMC_READ(host->base, SYSCTL));
1827 seq_printf(s, "IE:\t\t0x%08x\n",
1828 OMAP_HSMMC_READ(host->base, IE));
1829 seq_printf(s, "ISE:\t\t0x%08x\n",
1830 OMAP_HSMMC_READ(host->base, ISE));
1831 seq_printf(s, "CAPA:\t\t0x%08x\n",
1832 OMAP_HSMMC_READ(host->base, CAPA));
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001833
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301834 pm_runtime_mark_last_busy(host->dev);
1835 pm_runtime_put_autosuspend(host->dev);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001836
Denis Karpovd900f712009-09-22 16:44:38 -07001837 return 0;
1838}
1839
Denis Karpov70a33412009-09-22 16:44:59 -07001840static int omap_hsmmc_regs_open(struct inode *inode, struct file *file)
Denis Karpovd900f712009-09-22 16:44:38 -07001841{
Denis Karpov70a33412009-09-22 16:44:59 -07001842 return single_open(file, omap_hsmmc_regs_show, inode->i_private);
Denis Karpovd900f712009-09-22 16:44:38 -07001843}
1844
1845static const struct file_operations mmc_regs_fops = {
Denis Karpov70a33412009-09-22 16:44:59 -07001846 .open = omap_hsmmc_regs_open,
Denis Karpovd900f712009-09-22 16:44:38 -07001847 .read = seq_read,
1848 .llseek = seq_lseek,
1849 .release = single_release,
1850};
1851
Denis Karpov70a33412009-09-22 16:44:59 -07001852static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001853{
1854 if (mmc->debugfs_root)
1855 debugfs_create_file("regs", S_IRUSR, mmc->debugfs_root,
1856 mmc, &mmc_regs_fops);
1857}
1858
1859#else
1860
Denis Karpov70a33412009-09-22 16:44:59 -07001861static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001862{
1863}
1864
1865#endif
1866
Denis Karpov70a33412009-09-22 16:44:59 -07001867static int __init omap_hsmmc_probe(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001868{
1869 struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
1870 struct mmc_host *mmc;
Denis Karpov70a33412009-09-22 16:44:59 -07001871 struct omap_hsmmc_host *host = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001872 struct resource *res;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001873 int ret, irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001874
1875 if (pdata == NULL) {
1876 dev_err(&pdev->dev, "Platform Data is missing\n");
1877 return -ENXIO;
1878 }
1879
1880 if (pdata->nr_slots == 0) {
1881 dev_err(&pdev->dev, "No Slots\n");
1882 return -ENXIO;
1883 }
1884
1885 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1886 irq = platform_get_irq(pdev, 0);
1887 if (res == NULL || irq < 0)
1888 return -ENXIO;
1889
kishore kadiyala91a0b082010-10-01 16:35:28 -07001890 res->start += pdata->reg_offset;
1891 res->end += pdata->reg_offset;
Chris Ball984b2032011-03-22 16:34:42 -07001892 res = request_mem_region(res->start, resource_size(res), pdev->name);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001893 if (res == NULL)
1894 return -EBUSY;
1895
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001896 ret = omap_hsmmc_gpio_init(pdata);
1897 if (ret)
1898 goto err;
1899
Denis Karpov70a33412009-09-22 16:44:59 -07001900 mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001901 if (!mmc) {
1902 ret = -ENOMEM;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001903 goto err_alloc;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001904 }
1905
1906 host = mmc_priv(mmc);
1907 host->mmc = mmc;
1908 host->pdata = pdata;
1909 host->dev = &pdev->dev;
1910 host->use_dma = 1;
1911 host->dev->dma_mask = &pdata->dma_mask;
1912 host->dma_ch = -1;
1913 host->irq = irq;
1914 host->id = pdev->id;
1915 host->slot_id = 0;
1916 host->mapbase = res->start;
1917 host->base = ioremap(host->mapbase, SZ_4K);
Adrian Hunter6da20c82010-02-15 10:03:34 -08001918 host->power_mode = MMC_POWER_OFF;
Per Forlin9782aff2011-07-01 18:55:23 +02001919 host->next_data.cookie = 1;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001920
1921 platform_set_drvdata(pdev, host);
Denis Karpov70a33412009-09-22 16:44:59 -07001922 INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001923
Balaji T K7a8c2ce2011-07-01 22:09:34 +05301924 mmc->ops = &omap_hsmmc_ops;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001925
Adrian Huntere0eb2422010-02-15 10:03:34 -08001926 /*
1927 * If regulator_disable can only put vcc_aux to sleep then there is
1928 * no off state.
1929 */
1930 if (mmc_slot(host).vcc_aux_disable_is_sleep)
1931 mmc_slot(host).no_off = 1;
1932
Andy Shevchenko6b206ef2011-07-13 11:16:29 -04001933 mmc->f_min = OMAP_MMC_MIN_CLOCK;
1934 mmc->f_max = OMAP_MMC_MAX_CLOCK;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001935
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001936 spin_lock_init(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001937
Russell King6f7607c2009-01-28 10:22:50 +00001938 host->fclk = clk_get(&pdev->dev, "fck");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001939 if (IS_ERR(host->fclk)) {
1940 ret = PTR_ERR(host->fclk);
1941 host->fclk = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001942 goto err1;
1943 }
1944
Denis Karpov70a33412009-09-22 16:44:59 -07001945 omap_hsmmc_context_save(host);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001946
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001947 mmc->caps |= MMC_CAP_DISABLE;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001948
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301949 pm_runtime_enable(host->dev);
1950 pm_runtime_get_sync(host->dev);
1951 pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY);
1952 pm_runtime_use_autosuspend(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001953
Adrian Hunter2bec0892009-09-22 16:45:02 -07001954 if (cpu_is_omap2430()) {
1955 host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
1956 /*
1957 * MMC can still work without debounce clock.
1958 */
1959 if (IS_ERR(host->dbclk))
1960 dev_warn(mmc_dev(host->mmc),
1961 "Failed to get debounce clock\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001962 else
Adrian Hunter2bec0892009-09-22 16:45:02 -07001963 host->got_dbclk = 1;
1964
1965 if (host->got_dbclk)
1966 if (clk_enable(host->dbclk) != 0)
1967 dev_dbg(mmc_dev(host->mmc), "Enabling debounce"
1968 " clk failed\n");
1969 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001970
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001971 /* Since we do only SG emulation, we can have as many segs
1972 * as we want. */
Martin K. Petersena36274e2010-09-10 01:33:59 -04001973 mmc->max_segs = 1024;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001974
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001975 mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
1976 mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
1977 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
1978 mmc->max_seg_size = mmc->max_req_size;
1979
Jarkko Lavinen13189e72009-09-22 16:44:53 -07001980 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
Adrian Hunter93caf8e692010-08-11 14:17:48 -07001981 MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001982
Sukumar Ghorai3a638332010-09-15 14:49:23 +00001983 mmc->caps |= mmc_slot(host).caps;
1984 if (mmc->caps & MMC_CAP_8_BIT_DATA)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001985 mmc->caps |= MMC_CAP_4_BIT_DATA;
1986
Denis Karpov191d1f12009-09-22 16:44:55 -07001987 if (mmc_slot(host).nonremovable)
Adrian Hunter23d99bb2009-09-22 16:44:48 -07001988 mmc->caps |= MMC_CAP_NONREMOVABLE;
1989
Denis Karpov70a33412009-09-22 16:44:59 -07001990 omap_hsmmc_conf_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001991
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +00001992 /* Select DMA lines */
1993 switch (host->id) {
1994 case OMAP_MMC1_DEVID:
1995 host->dma_line_tx = OMAP24XX_DMA_MMC1_TX;
1996 host->dma_line_rx = OMAP24XX_DMA_MMC1_RX;
1997 break;
1998 case OMAP_MMC2_DEVID:
1999 host->dma_line_tx = OMAP24XX_DMA_MMC2_TX;
2000 host->dma_line_rx = OMAP24XX_DMA_MMC2_RX;
2001 break;
2002 case OMAP_MMC3_DEVID:
2003 host->dma_line_tx = OMAP34XX_DMA_MMC3_TX;
2004 host->dma_line_rx = OMAP34XX_DMA_MMC3_RX;
2005 break;
kishore kadiyala82cf8182009-09-22 16:45:25 -07002006 case OMAP_MMC4_DEVID:
2007 host->dma_line_tx = OMAP44XX_DMA_MMC4_TX;
2008 host->dma_line_rx = OMAP44XX_DMA_MMC4_RX;
2009 break;
2010 case OMAP_MMC5_DEVID:
2011 host->dma_line_tx = OMAP44XX_DMA_MMC5_TX;
2012 host->dma_line_rx = OMAP44XX_DMA_MMC5_RX;
2013 break;
Grazvydas Ignotasf3e2f1d2009-01-03 10:36:13 +00002014 default:
2015 dev_err(mmc_dev(host->mmc), "Invalid MMC id\n");
2016 goto err_irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002017 }
2018
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002019 /* Request IRQ for MMC operations */
Denis Karpov70a33412009-09-22 16:44:59 -07002020 ret = request_irq(host->irq, omap_hsmmc_irq, IRQF_DISABLED,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002021 mmc_hostname(mmc), host);
2022 if (ret) {
2023 dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
2024 goto err_irq;
2025 }
2026
2027 if (pdata->init != NULL) {
2028 if (pdata->init(&pdev->dev) != 0) {
Denis Karpov70a33412009-09-22 16:44:59 -07002029 dev_dbg(mmc_dev(host->mmc),
2030 "Unable to configure MMC IRQs\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002031 goto err_irq_cd_init;
2032 }
2033 }
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002034
Adrian Hunterb702b102010-02-15 10:03:35 -08002035 if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) {
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002036 ret = omap_hsmmc_reg_get(host);
2037 if (ret)
2038 goto err_reg;
2039 host->use_reg = 1;
2040 }
2041
David Brownellb583f262009-05-28 14:04:03 -07002042 mmc->ocr_avail = mmc_slot(host).ocr_mask;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002043
2044 /* Request IRQ for card detect */
Adrian Huntere1a55f52009-01-26 13:17:25 +02002045 if ((mmc_slot(host).card_detect_irq)) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002046 ret = request_irq(mmc_slot(host).card_detect_irq,
Denis Karpov70a33412009-09-22 16:44:59 -07002047 omap_hsmmc_cd_handler,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002048 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
2049 | IRQF_DISABLED,
2050 mmc_hostname(mmc), host);
2051 if (ret) {
2052 dev_dbg(mmc_dev(host->mmc),
2053 "Unable to grab MMC CD IRQ\n");
2054 goto err_irq_cd;
2055 }
kishore kadiyala72f2e2c2010-09-24 17:13:20 +00002056 pdata->suspend = omap_hsmmc_suspend_cdirq;
2057 pdata->resume = omap_hsmmc_resume_cdirq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002058 }
2059
Adrian Hunterb4175772010-05-26 14:42:06 -07002060 omap_hsmmc_disable_irq(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002061
Adrian Hunterb62f6222009-09-22 16:45:01 -07002062 omap_hsmmc_protect_card(host);
2063
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002064 mmc_add_host(mmc);
2065
Denis Karpov191d1f12009-09-22 16:44:55 -07002066 if (mmc_slot(host).name != NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002067 ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
2068 if (ret < 0)
2069 goto err_slot_name;
2070 }
Denis Karpov191d1f12009-09-22 16:44:55 -07002071 if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002072 ret = device_create_file(&mmc->class_dev,
2073 &dev_attr_cover_switch);
2074 if (ret < 0)
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002075 goto err_slot_name;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002076 }
2077
Denis Karpov70a33412009-09-22 16:44:59 -07002078 omap_hsmmc_debugfs(mmc);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302079 pm_runtime_mark_last_busy(host->dev);
2080 pm_runtime_put_autosuspend(host->dev);
Denis Karpovd900f712009-09-22 16:44:38 -07002081
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002082 return 0;
2083
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002084err_slot_name:
2085 mmc_remove_host(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002086 free_irq(mmc_slot(host).card_detect_irq, host);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002087err_irq_cd:
2088 if (host->use_reg)
2089 omap_hsmmc_reg_put(host);
2090err_reg:
2091 if (host->pdata->cleanup)
2092 host->pdata->cleanup(&pdev->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002093err_irq_cd_init:
2094 free_irq(host->irq, host);
2095err_irq:
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302096 pm_runtime_mark_last_busy(host->dev);
2097 pm_runtime_put_autosuspend(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002098 clk_put(host->fclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07002099 if (host->got_dbclk) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002100 clk_disable(host->dbclk);
2101 clk_put(host->dbclk);
2102 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002103err1:
2104 iounmap(host->base);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002105 platform_set_drvdata(pdev, NULL);
2106 mmc_free_host(mmc);
2107err_alloc:
2108 omap_hsmmc_gpio_free(pdata);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002109err:
Chris Ball984b2032011-03-22 16:34:42 -07002110 release_mem_region(res->start, resource_size(res));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002111 return ret;
2112}
2113
Denis Karpov70a33412009-09-22 16:44:59 -07002114static int omap_hsmmc_remove(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002115{
Denis Karpov70a33412009-09-22 16:44:59 -07002116 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002117 struct resource *res;
2118
2119 if (host) {
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302120 pm_runtime_get_sync(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002121 mmc_remove_host(host->mmc);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002122 if (host->use_reg)
2123 omap_hsmmc_reg_put(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002124 if (host->pdata->cleanup)
2125 host->pdata->cleanup(&pdev->dev);
2126 free_irq(host->irq, host);
2127 if (mmc_slot(host).card_detect_irq)
2128 free_irq(mmc_slot(host).card_detect_irq, host);
Tejun Heo0d9ee5b2010-12-24 16:00:17 +01002129 flush_work_sync(&host->mmc_carddetect_work);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002130
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302131 pm_runtime_put_sync(host->dev);
2132 pm_runtime_disable(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002133 clk_put(host->fclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07002134 if (host->got_dbclk) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002135 clk_disable(host->dbclk);
2136 clk_put(host->dbclk);
2137 }
2138
2139 mmc_free_host(host->mmc);
2140 iounmap(host->base);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002141 omap_hsmmc_gpio_free(pdev->dev.platform_data);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002142 }
2143
2144 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2145 if (res)
Chris Ball984b2032011-03-22 16:34:42 -07002146 release_mem_region(res->start, resource_size(res));
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002147 platform_set_drvdata(pdev, NULL);
2148
2149 return 0;
2150}
2151
2152#ifdef CONFIG_PM
Kevin Hilmana791daa2010-05-26 14:42:07 -07002153static int omap_hsmmc_suspend(struct device *dev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002154{
2155 int ret = 0;
Kevin Hilmana791daa2010-05-26 14:42:07 -07002156 struct platform_device *pdev = to_platform_device(dev);
Denis Karpov70a33412009-09-22 16:44:59 -07002157 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002158
2159 if (host && host->suspended)
2160 return 0;
2161
2162 if (host) {
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302163 pm_runtime_get_sync(host->dev);
Adrian Huntera6b22402009-09-22 16:44:45 -07002164 host->suspended = 1;
2165 if (host->pdata->suspend) {
2166 ret = host->pdata->suspend(&pdev->dev,
2167 host->slot_id);
2168 if (ret) {
2169 dev_dbg(mmc_dev(host->mmc),
2170 "Unable to handle MMC board"
2171 " level suspend\n");
2172 host->suspended = 0;
2173 return ret;
2174 }
2175 }
2176 cancel_work_sync(&host->mmc_carddetect_work);
Matt Fleming1a13f8f2010-05-26 14:42:08 -07002177 ret = mmc_suspend_host(host->mmc);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302178
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002179 if (ret == 0) {
Adrian Hunterb4175772010-05-26 14:42:06 -07002180 omap_hsmmc_disable_irq(host);
Jarkko Lavinen0683af42009-03-12 15:30:58 +02002181 OMAP_HSMMC_WRITE(host->base, HCTL,
Denis Karpov191d1f12009-09-22 16:44:55 -07002182 OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
Adrian Hunter2bec0892009-09-22 16:45:02 -07002183 if (host->got_dbclk)
2184 clk_disable(host->dbclk);
Adrian Huntera6b22402009-09-22 16:44:45 -07002185 } else {
2186 host->suspended = 0;
2187 if (host->pdata->resume) {
2188 ret = host->pdata->resume(&pdev->dev,
2189 host->slot_id);
2190 if (ret)
2191 dev_dbg(mmc_dev(host->mmc),
2192 "Unmask interrupt failed\n");
2193 }
Adrian Huntera6b22402009-09-22 16:44:45 -07002194 }
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302195 pm_runtime_put_sync(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002196 }
2197 return ret;
2198}
2199
2200/* Routine to resume the MMC device */
Kevin Hilmana791daa2010-05-26 14:42:07 -07002201static int omap_hsmmc_resume(struct device *dev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002202{
2203 int ret = 0;
Kevin Hilmana791daa2010-05-26 14:42:07 -07002204 struct platform_device *pdev = to_platform_device(dev);
Denis Karpov70a33412009-09-22 16:44:59 -07002205 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002206
2207 if (host && !host->suspended)
2208 return 0;
2209
2210 if (host) {
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302211 pm_runtime_get_sync(host->dev);
Denis Karpov11dd62a2009-09-22 16:44:43 -07002212
Adrian Hunter2bec0892009-09-22 16:45:02 -07002213 if (host->got_dbclk)
2214 clk_enable(host->dbclk);
2215
Denis Karpov70a33412009-09-22 16:44:59 -07002216 omap_hsmmc_conf_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01002217
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002218 if (host->pdata->resume) {
2219 ret = host->pdata->resume(&pdev->dev, host->slot_id);
2220 if (ret)
2221 dev_dbg(mmc_dev(host->mmc),
2222 "Unmask interrupt failed\n");
2223 }
2224
Adrian Hunterb62f6222009-09-22 16:45:01 -07002225 omap_hsmmc_protect_card(host);
2226
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002227 /* Notify the core to resume the host */
2228 ret = mmc_resume_host(host->mmc);
2229 if (ret == 0)
2230 host->suspended = 0;
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302231
2232 pm_runtime_mark_last_busy(host->dev);
2233 pm_runtime_put_autosuspend(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002234 }
2235
2236 return ret;
2237
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002238}
2239
2240#else
Denis Karpov70a33412009-09-22 16:44:59 -07002241#define omap_hsmmc_suspend NULL
2242#define omap_hsmmc_resume NULL
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002243#endif
2244
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302245static int omap_hsmmc_runtime_suspend(struct device *dev)
2246{
2247 struct omap_hsmmc_host *host;
2248
2249 host = platform_get_drvdata(to_platform_device(dev));
2250 omap_hsmmc_context_save(host);
2251 dev_dbg(mmc_dev(host->mmc), "disabled\n");
2252
2253 return 0;
2254}
2255
2256static int omap_hsmmc_runtime_resume(struct device *dev)
2257{
2258 struct omap_hsmmc_host *host;
2259
2260 host = platform_get_drvdata(to_platform_device(dev));
2261 omap_hsmmc_context_restore(host);
2262 dev_dbg(mmc_dev(host->mmc), "enabled\n");
2263
2264 return 0;
2265}
2266
Kevin Hilmana791daa2010-05-26 14:42:07 -07002267static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
Denis Karpov70a33412009-09-22 16:44:59 -07002268 .suspend = omap_hsmmc_suspend,
2269 .resume = omap_hsmmc_resume,
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302270 .runtime_suspend = omap_hsmmc_runtime_suspend,
2271 .runtime_resume = omap_hsmmc_runtime_resume,
Kevin Hilmana791daa2010-05-26 14:42:07 -07002272};
2273
2274static struct platform_driver omap_hsmmc_driver = {
2275 .remove = omap_hsmmc_remove,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002276 .driver = {
2277 .name = DRIVER_NAME,
2278 .owner = THIS_MODULE,
Kevin Hilmana791daa2010-05-26 14:42:07 -07002279 .pm = &omap_hsmmc_dev_pm_ops,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002280 },
2281};
2282
Denis Karpov70a33412009-09-22 16:44:59 -07002283static int __init omap_hsmmc_init(void)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002284{
2285 /* Register the MMC driver */
Roger Quadros87532982009-10-26 16:49:38 -07002286 return platform_driver_probe(&omap_hsmmc_driver, omap_hsmmc_probe);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002287}
2288
Denis Karpov70a33412009-09-22 16:44:59 -07002289static void __exit omap_hsmmc_cleanup(void)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002290{
2291 /* Unregister MMC driver */
Denis Karpov70a33412009-09-22 16:44:59 -07002292 platform_driver_unregister(&omap_hsmmc_driver);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002293}
2294
Denis Karpov70a33412009-09-22 16:44:59 -07002295module_init(omap_hsmmc_init);
2296module_exit(omap_hsmmc_cleanup);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002297
2298MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
2299MODULE_LICENSE("GPL");
2300MODULE_ALIAS("platform:" DRIVER_NAME);
2301MODULE_AUTHOR("Texas Instruments Inc");