blob: 2eafd6f646768eaad6029e097356db11a4086a0f [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>
Russell Kingc5c98922012-04-13 12:14:39 +010022#include <linux/dmaengine.h>
Denis Karpovd900f712009-09-22 16:44:38 -070023#include <linux/seq_file.h>
Felipe Balbi031cd032013-07-11 16:09:05 +030024#include <linux/sizes.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010025#include <linux/interrupt.h>
26#include <linux/delay.h>
27#include <linux/dma-mapping.h>
28#include <linux/platform_device.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010029#include <linux/timer.h>
30#include <linux/clk.h>
Rajendra Nayak46856a62012-03-12 20:32:37 +053031#include <linux/of.h>
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +020032#include <linux/of_irq.h>
Rajendra Nayak46856a62012-03-12 20:32:37 +053033#include <linux/of_gpio.h>
34#include <linux/of_device.h>
Balaji T Kee526d52014-05-09 22:16:53 +053035#include <linux/omap-dmaengine.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010036#include <linux/mmc/host.h>
Jarkko Lavinen13189e72009-09-22 16:44:53 -070037#include <linux/mmc/core.h>
Adrian Hunter93caf8e692010-08-11 14:17:48 -070038#include <linux/mmc/mmc.h>
NeilBrown41afa3142015-01-13 08:23:18 +130039#include <linux/mmc/slot-gpio.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010040#include <linux/io.h>
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +020041#include <linux/irq.h>
Adrian Hunterdb0fefc2010-02-15 10:03:34 -080042#include <linux/gpio.h>
43#include <linux/regulator/consumer.h>
Daniel Mack46b76032012-10-15 21:35:05 +053044#include <linux/pinctrl/consumer.h>
Balaji T Kfa4aa2d2011-07-01 22:09:35 +053045#include <linux/pm_runtime.h>
Tony Lindgren5b83b222015-05-21 15:51:52 -070046#include <linux/pm_wakeirq.h>
Andreas Fenkart55143432014-11-08 15:33:09 +010047#include <linux/platform_data/hsmmc-omap.h>
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010048
49/* OMAP HSMMC Host Controller Registers */
Denis Karpov11dd62a2009-09-22 16:44:43 -070050#define OMAP_HSMMC_SYSSTATUS 0x0014
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010051#define OMAP_HSMMC_CON 0x002C
Balaji T Ka2e77152014-01-21 19:54:42 +053052#define OMAP_HSMMC_SDMASA 0x0100
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010053#define OMAP_HSMMC_BLK 0x0104
54#define OMAP_HSMMC_ARG 0x0108
55#define OMAP_HSMMC_CMD 0x010C
56#define OMAP_HSMMC_RSP10 0x0110
57#define OMAP_HSMMC_RSP32 0x0114
58#define OMAP_HSMMC_RSP54 0x0118
59#define OMAP_HSMMC_RSP76 0x011C
60#define OMAP_HSMMC_DATA 0x0120
Andreas Fenkartbb0635f2014-05-29 10:28:01 +020061#define OMAP_HSMMC_PSTATE 0x0124
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010062#define OMAP_HSMMC_HCTL 0x0128
63#define OMAP_HSMMC_SYSCTL 0x012C
64#define OMAP_HSMMC_STAT 0x0130
65#define OMAP_HSMMC_IE 0x0134
66#define OMAP_HSMMC_ISE 0x0138
Balaji T Ka2e77152014-01-21 19:54:42 +053067#define OMAP_HSMMC_AC12 0x013C
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010068#define OMAP_HSMMC_CAPA 0x0140
69
70#define VS18 (1 << 26)
71#define VS30 (1 << 25)
Hebbar, Gururajacd587092012-11-19 21:59:58 +053072#define HSS (1 << 21)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010073#define SDVS18 (0x5 << 9)
74#define SDVS30 (0x6 << 9)
David Brownelleb250822009-02-17 14:49:01 -080075#define SDVS33 (0x7 << 9)
Kim Kyuwon1b331e62009-02-20 13:10:08 +010076#define SDVS_MASK 0x00000E00
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010077#define SDVSCLR 0xFFFFF1FF
78#define SDVSDET 0x00000400
79#define AUTOIDLE 0x1
80#define SDBP (1 << 8)
81#define DTO 0xe
82#define ICE 0x1
83#define ICS 0x2
84#define CEN (1 << 2)
Balaji T Ked164182013-10-21 00:25:21 +053085#define CLKD_MAX 0x3FF /* max clock divisor: 1023 */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010086#define CLKD_MASK 0x0000FFC0
87#define CLKD_SHIFT 6
88#define DTO_MASK 0x000F0000
89#define DTO_SHIFT 16
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010090#define INIT_STREAM (1 << 1)
Balaji T Ka2e77152014-01-21 19:54:42 +053091#define ACEN_ACMD23 (2 << 2)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010092#define DP_SELECT (1 << 21)
93#define DDIR (1 << 4)
Venkatraman Sa7e96872012-11-19 22:00:01 +053094#define DMAE 0x1
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +010095#define MSBS (1 << 5)
96#define BCE (1 << 1)
97#define FOUR_BIT (1 << 1)
Hebbar, Gururajacd587092012-11-19 21:59:58 +053098#define HSPE (1 << 2)
Balaji T K5a52b082014-05-29 10:28:02 +020099#define IWE (1 << 24)
Balaji T K03b5d922012-04-09 12:08:33 +0530100#define DDR (1 << 19)
Balaji T K5a52b082014-05-29 10:28:02 +0200101#define CLKEXTFREE (1 << 16)
102#define CTPL (1 << 11)
Jarkko Lavinen73153012008-11-21 16:49:54 +0200103#define DW8 (1 << 5)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100104#define OD 0x1
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100105#define STAT_CLEAR 0xFFFFFFFF
106#define INIT_STREAM_CMD 0x00000000
107#define DUAL_VOLT_OCR_BIT 7
108#define SRC (1 << 25)
109#define SRD (1 << 26)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700110#define SOFTRESET (1 << 1)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100111
Andreas Fenkartf9459012014-05-29 10:28:03 +0200112/* PSTATE */
113#define DLEV_DAT(x) (1 << (20 + (x)))
114
Venkatraman Sa7e96872012-11-19 22:00:01 +0530115/* Interrupt masks for IE and ISE register */
116#define CC_EN (1 << 0)
117#define TC_EN (1 << 1)
118#define BWR_EN (1 << 4)
119#define BRR_EN (1 << 5)
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200120#define CIRQ_EN (1 << 8)
Venkatraman Sa7e96872012-11-19 22:00:01 +0530121#define ERR_EN (1 << 15)
122#define CTO_EN (1 << 16)
123#define CCRC_EN (1 << 17)
124#define CEB_EN (1 << 18)
125#define CIE_EN (1 << 19)
126#define DTO_EN (1 << 20)
127#define DCRC_EN (1 << 21)
128#define DEB_EN (1 << 22)
Balaji T Ka2e77152014-01-21 19:54:42 +0530129#define ACE_EN (1 << 24)
Venkatraman Sa7e96872012-11-19 22:00:01 +0530130#define CERR_EN (1 << 28)
131#define BADA_EN (1 << 29)
132
Balaji T Ka2e77152014-01-21 19:54:42 +0530133#define INT_EN_MASK (BADA_EN | CERR_EN | ACE_EN | DEB_EN | DCRC_EN |\
Venkatraman Sa7e96872012-11-19 22:00:01 +0530134 DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
135 BRR_EN | BWR_EN | TC_EN | CC_EN)
136
Balaji T Ka2e77152014-01-21 19:54:42 +0530137#define CNI (1 << 7)
138#define ACIE (1 << 4)
139#define ACEB (1 << 3)
140#define ACCE (1 << 2)
141#define ACTO (1 << 1)
142#define ACNE (1 << 0)
143
Balaji T Kfa4aa2d2011-07-01 22:09:35 +0530144#define MMC_AUTOSUSPEND_DELAY 100
Jianpeng Ma1e881782013-10-21 00:25:20 +0530145#define MMC_TIMEOUT_MS 20 /* 20 mSec */
146#define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */
Andy Shevchenko6b206ef2011-07-13 11:16:29 -0400147#define OMAP_MMC_MIN_CLOCK 400000
148#define OMAP_MMC_MAX_CLOCK 52000000
Kishore Kadiyala0005ae72011-02-28 20:48:05 +0530149#define DRIVER_NAME "omap_hsmmc"
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100150
Balaji T Ke99448f2014-02-19 20:26:40 +0530151#define VDD_1V8 1800000 /* 180000 uV */
152#define VDD_3V0 3000000 /* 300000 uV */
153#define VDD_165_195 (ffs(MMC_VDD_165_195) - 1)
154
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100155/*
156 * One controller can have multiple slots, like on some omap boards using
157 * omap.c controller driver. Luckily this is not currently done on any known
158 * omap_hsmmc.c device.
159 */
Andreas Fenkart326119c2014-11-08 15:33:14 +0100160#define mmc_pdata(host) host->pdata
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100161
162/*
163 * MMC Host controller read/write API's
164 */
165#define OMAP_HSMMC_READ(base, reg) \
166 __raw_readl((base) + OMAP_HSMMC_##reg)
167
168#define OMAP_HSMMC_WRITE(base, reg, val) \
169 __raw_writel((val), (base) + OMAP_HSMMC_##reg)
170
Per Forlin9782aff2011-07-01 18:55:23 +0200171struct omap_hsmmc_next {
172 unsigned int dma_len;
173 s32 cookie;
174};
175
Denis Karpov70a33412009-09-22 16:44:59 -0700176struct omap_hsmmc_host {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100177 struct device *dev;
178 struct mmc_host *mmc;
179 struct mmc_request *mrq;
180 struct mmc_command *cmd;
181 struct mmc_data *data;
182 struct clk *fclk;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100183 struct clk *dbclk;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800184 /*
185 * vcc == configured supply
186 * vcc_aux == optional
187 * - MMC1, supply for DAT4..DAT7
188 * - MMC2/MMC2, external level shifter voltage supply, for
189 * chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
190 */
191 struct regulator *vcc;
192 struct regulator *vcc_aux;
Balaji T Ke99448f2014-02-19 20:26:40 +0530193 struct regulator *pbias;
194 bool pbias_enabled;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100195 void __iomem *base;
196 resource_size_t mapbase;
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700197 spinlock_t irq_lock; /* Prevent races with irq handler */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100198 unsigned int dma_len;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200199 unsigned int dma_sg_idx;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100200 unsigned char bus_mode;
Adrian Huntera3621462009-09-22 16:44:42 -0700201 unsigned char power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100202 int suspended;
Tony Lindgren0a82e062013-10-21 00:25:19 +0530203 u32 con;
204 u32 hctl;
205 u32 sysctl;
206 u32 capa;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100207 int irq;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200208 int wake_irq;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100209 int use_dma, dma_ch;
Russell Kingc5c98922012-04-13 12:14:39 +0100210 struct dma_chan *tx_chan;
211 struct dma_chan *rx_chan;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200212 int response_busy;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700213 int context_loss;
Adrian Hunterb62f6222009-09-22 16:45:01 -0700214 int protect_card;
215 int reqs_blocked;
Adrian Hunterb4175772010-05-26 14:42:06 -0700216 int req_in_progress;
Balaji T K6e3076c2014-01-21 19:54:42 +0530217 unsigned long clk_rate;
Balaji T Ka2e77152014-01-21 19:54:42 +0530218 unsigned int flags;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200219#define AUTO_CMD23 (1 << 0) /* Auto CMD23 support */
220#define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */
Per Forlin9782aff2011-07-01 18:55:23 +0200221 struct omap_hsmmc_next next_data;
Andreas Fenkart55143432014-11-08 15:33:09 +0100222 struct omap_hsmmc_platform_data *pdata;
Andreas Fenkartb5cd43f2014-11-08 15:33:16 +0100223
Andreas Fenkartb5cd43f2014-11-08 15:33:16 +0100224 /* return MMC cover switch state, can be NULL if not supported.
225 *
226 * possible return values:
227 * 0 - closed
228 * 1 - open
229 */
Andreas Fenkart80412ca2014-11-08 15:33:17 +0100230 int (*get_cover_state)(struct device *dev);
Andreas Fenkartb5cd43f2014-11-08 15:33:16 +0100231
Andreas Fenkart80412ca2014-11-08 15:33:17 +0100232 int (*card_detect)(struct device *dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100233};
234
Nishanth Menon59445b12014-02-13 23:45:48 -0600235struct omap_mmc_of_data {
236 u32 reg_offset;
237 u8 controller_flags;
238};
239
Balaji T Kbf129e12014-01-21 19:54:42 +0530240static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host);
241
Andreas Fenkart80412ca2014-11-08 15:33:17 +0100242static int omap_hsmmc_card_detect(struct device *dev)
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800243{
Balaji T K9ea28ec2012-10-15 21:35:08 +0530244 struct omap_hsmmc_host *host = dev_get_drvdata(dev);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800245
NeilBrown41afa3142015-01-13 08:23:18 +1300246 return mmc_gpio_get_cd(host->mmc);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800247}
248
Andreas Fenkart80412ca2014-11-08 15:33:17 +0100249static int omap_hsmmc_get_cover_state(struct device *dev)
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800250{
Balaji T K9ea28ec2012-10-15 21:35:08 +0530251 struct omap_hsmmc_host *host = dev_get_drvdata(dev);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800252
NeilBrown41afa3142015-01-13 08:23:18 +1300253 return mmc_gpio_get_cd(host->mmc);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800254}
255
Adrian Hunterb702b102010-02-15 10:03:35 -0800256#ifdef CONFIG_REGULATOR
257
Andreas Fenkart80412ca2014-11-08 15:33:17 +0100258static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800259{
260 struct omap_hsmmc_host *host =
261 platform_get_drvdata(to_platform_device(dev));
262 int ret = 0;
263
Andreas Fenkartf7f0f032015-07-07 20:38:43 +0200264 if (mmc_pdata(host)->set_power)
265 return mmc_pdata(host)->set_power(dev, power_on, vdd);
266
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800267 /*
268 * If we don't see a Vcc regulator, assume it's a fixed
269 * voltage always-on regulator.
270 */
271 if (!host->vcc)
272 return 0;
273
Andreas Fenkart326119c2014-11-08 15:33:14 +0100274 if (mmc_pdata(host)->before_set_reg)
Andreas Fenkart80412ca2014-11-08 15:33:17 +0100275 mmc_pdata(host)->before_set_reg(dev, power_on, vdd);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800276
Balaji T Ke99448f2014-02-19 20:26:40 +0530277 if (host->pbias) {
278 if (host->pbias_enabled == 1) {
279 ret = regulator_disable(host->pbias);
280 if (!ret)
281 host->pbias_enabled = 0;
282 }
283 regulator_set_voltage(host->pbias, VDD_3V0, VDD_3V0);
284 }
285
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800286 /*
287 * Assume Vcc regulator is used only to power the card ... OMAP
288 * VDDS is used to power the pins, optionally with a transceiver to
289 * support cards using voltages other than VDDS (1.8V nominal). When a
290 * transceiver is used, DAT3..7 are muxed as transceiver control pins.
291 *
292 * In some cases this regulator won't support enable/disable;
293 * e.g. it's a fixed rail for a WLAN chip.
294 *
295 * In other cases vcc_aux switches interface power. Example, for
296 * eMMC cards it represents VccQ. Sometimes transceivers or SDIO
297 * chips/cards need an interface voltage rail too.
298 */
299 if (power_on) {
Balaji T K987fd492014-02-19 20:26:40 +0530300 if (host->vcc)
301 ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800302 /* Enable interface voltage rail, if needed */
303 if (ret == 0 && host->vcc_aux) {
304 ret = regulator_enable(host->vcc_aux);
Balaji T K987fd492014-02-19 20:26:40 +0530305 if (ret < 0 && host->vcc)
Linus Walleij99fc5132010-09-29 01:08:27 -0400306 ret = mmc_regulator_set_ocr(host->mmc,
307 host->vcc, 0);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800308 }
309 } else {
Linus Walleij99fc5132010-09-29 01:08:27 -0400310 /* Shut down the rail */
Adrian Hunter6da20c82010-02-15 10:03:34 -0800311 if (host->vcc_aux)
312 ret = regulator_disable(host->vcc_aux);
Balaji T K987fd492014-02-19 20:26:40 +0530313 if (host->vcc) {
Linus Walleij99fc5132010-09-29 01:08:27 -0400314 /* Then proceed to shut down the local regulator */
315 ret = mmc_regulator_set_ocr(host->mmc,
316 host->vcc, 0);
317 }
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800318 }
319
Balaji T Ke99448f2014-02-19 20:26:40 +0530320 if (host->pbias) {
321 if (vdd <= VDD_165_195)
322 ret = regulator_set_voltage(host->pbias, VDD_1V8,
323 VDD_1V8);
324 else
325 ret = regulator_set_voltage(host->pbias, VDD_3V0,
326 VDD_3V0);
327 if (ret < 0)
328 goto error_set_power;
329
330 if (host->pbias_enabled == 0) {
331 ret = regulator_enable(host->pbias);
332 if (!ret)
333 host->pbias_enabled = 1;
334 }
335 }
336
Andreas Fenkart326119c2014-11-08 15:33:14 +0100337 if (mmc_pdata(host)->after_set_reg)
Andreas Fenkart80412ca2014-11-08 15:33:17 +0100338 mmc_pdata(host)->after_set_reg(dev, power_on, vdd);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800339
Balaji T Ke99448f2014-02-19 20:26:40 +0530340error_set_power:
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800341 return ret;
342}
343
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800344static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
345{
346 struct regulator *reg;
kishore kadiyala64be9782010-10-01 16:35:28 -0700347 int ocr_value = 0;
Kishon Vijay Abraham I7d607f92015-08-27 14:43:53 +0530348 int ret;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800349
Andreas Fenkartf7f0f032015-07-07 20:38:43 +0200350 if (mmc_pdata(host)->set_power)
351 return 0;
352
Kishon Vijay Abraham I7d607f92015-08-27 14:43:53 +0530353 reg = devm_regulator_get_optional(host->dev, "vmmc");
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800354 if (IS_ERR(reg)) {
Kishon Vijay Abraham I7d607f92015-08-27 14:43:53 +0530355 ret = PTR_ERR(reg);
356 if (ret != -ENODEV)
357 return ret;
358 host->vcc = NULL;
359 dev_dbg(host->dev, "unable to get vmmc regulator %ld\n",
Balaji T K987fd492014-02-19 20:26:40 +0530360 PTR_ERR(reg));
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800361 } else {
362 host->vcc = reg;
kishore kadiyala64be9782010-10-01 16:35:28 -0700363 ocr_value = mmc_regulator_get_ocrmask(reg);
Andreas Fenkart326119c2014-11-08 15:33:14 +0100364 if (!mmc_pdata(host)->ocr_mask) {
365 mmc_pdata(host)->ocr_mask = ocr_value;
kishore kadiyala64be9782010-10-01 16:35:28 -0700366 } else {
Andreas Fenkart326119c2014-11-08 15:33:14 +0100367 if (!(mmc_pdata(host)->ocr_mask & ocr_value)) {
Rajendra Nayak2cecdf02012-02-23 17:02:20 +0530368 dev_err(host->dev, "ocrmask %x is not supported\n",
Andreas Fenkart326119c2014-11-08 15:33:14 +0100369 mmc_pdata(host)->ocr_mask);
370 mmc_pdata(host)->ocr_mask = 0;
kishore kadiyala64be9782010-10-01 16:35:28 -0700371 return -EINVAL;
372 }
373 }
Balaji T K987fd492014-02-19 20:26:40 +0530374 }
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800375
Balaji T K987fd492014-02-19 20:26:40 +0530376 /* Allow an aux regulator */
377 reg = devm_regulator_get_optional(host->dev, "vmmc_aux");
Kishon Vijay Abraham I6a9b2ff2015-08-27 14:43:54 +0530378 if (IS_ERR(reg)) {
379 ret = PTR_ERR(reg);
380 if (ret != -ENODEV)
381 return ret;
382 host->vcc_aux = NULL;
383 dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n",
384 PTR_ERR(reg));
385 } else {
386 host->vcc_aux = reg;
387 }
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800388
Balaji T Ke99448f2014-02-19 20:26:40 +0530389 reg = devm_regulator_get_optional(host->dev, "pbias");
Kishon Vijay Abraham I6a9b2ff2015-08-27 14:43:54 +0530390 if (IS_ERR(reg)) {
391 ret = PTR_ERR(reg);
392 if (ret != -ENODEV)
393 return ret;
394 host->pbias = NULL;
395 dev_dbg(host->dev, "unable to get pbias regulator %ld\n",
396 PTR_ERR(reg));
397 } else {
398 host->pbias = reg;
399 }
Balaji T Ke99448f2014-02-19 20:26:40 +0530400
Balaji T K987fd492014-02-19 20:26:40 +0530401 /* For eMMC do not power off when not in sleep state */
Andreas Fenkart326119c2014-11-08 15:33:14 +0100402 if (mmc_pdata(host)->no_regulator_off_init)
Balaji T K987fd492014-02-19 20:26:40 +0530403 return 0;
404 /*
405 * To disable boot_on regulator, enable regulator
406 * to increase usecount and then disable it.
407 */
408 if ((host->vcc && regulator_is_enabled(host->vcc) > 0) ||
409 (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
Andreas Fenkart326119c2014-11-08 15:33:14 +0100410 int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1;
Adrian Huntere840ce12011-05-06 12:14:10 +0300411
Andreas Fenkartf7f0f032015-07-07 20:38:43 +0200412 omap_hsmmc_set_power(host->dev, 1, vdd);
413 omap_hsmmc_set_power(host->dev, 0, 0);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800414 }
415
416 return 0;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800417}
418
Adrian Hunterb702b102010-02-15 10:03:35 -0800419static inline int omap_hsmmc_have_reg(void)
420{
421 return 1;
422}
423
424#else
425
Andreas Fenkartf7f0f032015-07-07 20:38:43 +0200426static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
427{
428 return 0;
429}
430
Adrian Hunterb702b102010-02-15 10:03:35 -0800431static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
432{
433 return -EINVAL;
434}
435
Adrian Hunterb702b102010-02-15 10:03:35 -0800436static inline int omap_hsmmc_have_reg(void)
437{
438 return 0;
439}
440
441#endif
442
Andreas Fenkartcde592c2015-03-03 13:28:15 +0100443static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id);
NeilBrown41afa3142015-01-13 08:23:18 +1300444
445static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
446 struct omap_hsmmc_host *host,
Andreas Fenkart1e363e32014-11-08 15:33:15 +0100447 struct omap_hsmmc_platform_data *pdata)
Adrian Hunterb702b102010-02-15 10:03:35 -0800448{
449 int ret;
450
Andreas Fenkartb7a56462015-03-20 15:53:54 +0100451 if (gpio_is_valid(pdata->gpio_cod)) {
452 ret = mmc_gpio_request_cd(mmc, pdata->gpio_cod, 0);
Adrian Hunterb702b102010-02-15 10:03:35 -0800453 if (ret)
454 return ret;
Andreas Fenkartcde592c2015-03-03 13:28:15 +0100455
456 host->get_cover_state = omap_hsmmc_get_cover_state;
457 mmc_gpio_set_cd_isr(mmc, omap_hsmmc_cover_irq);
Andreas Fenkartb7a56462015-03-20 15:53:54 +0100458 } else if (gpio_is_valid(pdata->gpio_cd)) {
459 ret = mmc_gpio_request_cd(mmc, pdata->gpio_cd, 0);
Andreas Fenkartcde592c2015-03-03 13:28:15 +0100460 if (ret)
461 return ret;
462
463 host->card_detect = omap_hsmmc_card_detect;
Andreas Fenkart326119c2014-11-08 15:33:14 +0100464 }
Adrian Hunterb702b102010-02-15 10:03:35 -0800465
Andreas Fenkart326119c2014-11-08 15:33:14 +0100466 if (gpio_is_valid(pdata->gpio_wp)) {
NeilBrown41afa3142015-01-13 08:23:18 +1300467 ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp);
Adrian Hunterb702b102010-02-15 10:03:35 -0800468 if (ret)
NeilBrown41afa3142015-01-13 08:23:18 +1300469 return ret;
Andreas Fenkart326119c2014-11-08 15:33:14 +0100470 }
Adrian Hunterb702b102010-02-15 10:03:35 -0800471
472 return 0;
Adrian Hunterb702b102010-02-15 10:03:35 -0800473}
474
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100475/*
Andy Shevchenkoe0c7f992011-05-06 12:14:05 +0300476 * Start clock to the card
477 */
478static void omap_hsmmc_start_clock(struct omap_hsmmc_host *host)
479{
480 OMAP_HSMMC_WRITE(host->base, SYSCTL,
481 OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
482}
483
484/*
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100485 * Stop clock to the card
486 */
Denis Karpov70a33412009-09-22 16:44:59 -0700487static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100488{
489 OMAP_HSMMC_WRITE(host->base, SYSCTL,
490 OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
491 if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
Masanari Iida7122bbb2012-08-05 23:25:40 +0900492 dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stopped\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100493}
494
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700495static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
496 struct mmc_command *cmd)
Adrian Hunterb4175772010-05-26 14:42:06 -0700497{
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200498 u32 irq_mask = INT_EN_MASK;
499 unsigned long flags;
Adrian Hunterb4175772010-05-26 14:42:06 -0700500
501 if (host->use_dma)
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200502 irq_mask &= ~(BRR_EN | BWR_EN);
Adrian Hunterb4175772010-05-26 14:42:06 -0700503
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700504 /* Disable timeout for erases */
505 if (cmd->opcode == MMC_ERASE)
Venkatraman Sa7e96872012-11-19 22:00:01 +0530506 irq_mask &= ~DTO_EN;
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700507
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200508 spin_lock_irqsave(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700509 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
510 OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200511
512 /* latch pending CIRQ, but don't signal MMC core */
513 if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
514 irq_mask |= CIRQ_EN;
Adrian Hunterb4175772010-05-26 14:42:06 -0700515 OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200516 spin_unlock_irqrestore(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700517}
518
519static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
520{
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200521 u32 irq_mask = 0;
522 unsigned long flags;
523
524 spin_lock_irqsave(&host->irq_lock, flags);
525 /* no transfer running but need to keep cirq if enabled */
526 if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
527 irq_mask |= CIRQ_EN;
528 OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
529 OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
Adrian Hunterb4175772010-05-26 14:42:06 -0700530 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200531 spin_unlock_irqrestore(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700532}
533
Andy Shevchenkoac330f42011-05-10 15:51:54 +0300534/* Calculate divisor for the given clock frequency */
Balaji TKd83b6e02011-12-20 15:12:00 +0530535static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios)
Andy Shevchenkoac330f42011-05-10 15:51:54 +0300536{
537 u16 dsor = 0;
538
539 if (ios->clock) {
Balaji TKd83b6e02011-12-20 15:12:00 +0530540 dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock);
Balaji T Ked164182013-10-21 00:25:21 +0530541 if (dsor > CLKD_MAX)
542 dsor = CLKD_MAX;
Andy Shevchenkoac330f42011-05-10 15:51:54 +0300543 }
544
545 return dsor;
546}
547
Andy Shevchenko5934df22011-05-06 12:14:06 +0300548static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
549{
550 struct mmc_ios *ios = &host->mmc->ios;
551 unsigned long regval;
552 unsigned long timeout;
Hebbar, Gururajacd587092012-11-19 21:59:58 +0530553 unsigned long clkdiv;
Andy Shevchenko5934df22011-05-06 12:14:06 +0300554
Venkatraman S8986d312012-08-07 19:10:38 +0530555 dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
Andy Shevchenko5934df22011-05-06 12:14:06 +0300556
557 omap_hsmmc_stop_clock(host);
558
559 regval = OMAP_HSMMC_READ(host->base, SYSCTL);
560 regval = regval & ~(CLKD_MASK | DTO_MASK);
Hebbar, Gururajacd587092012-11-19 21:59:58 +0530561 clkdiv = calc_divisor(host, ios);
562 regval = regval | (clkdiv << 6) | (DTO << 16);
Andy Shevchenko5934df22011-05-06 12:14:06 +0300563 OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
564 OMAP_HSMMC_WRITE(host->base, SYSCTL,
565 OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
566
567 /* Wait till the ICS bit is set */
568 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
569 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
570 && time_before(jiffies, timeout))
571 cpu_relax();
572
Hebbar, Gururajacd587092012-11-19 21:59:58 +0530573 /*
574 * Enable High-Speed Support
575 * Pre-Requisites
576 * - Controller should support High-Speed-Enable Bit
577 * - Controller should not be using DDR Mode
578 * - Controller should advertise that it supports High Speed
579 * in capabilities register
580 * - MMC/SD clock coming out of controller > 25MHz
581 */
Andreas Fenkart326119c2014-11-08 15:33:14 +0100582 if ((mmc_pdata(host)->features & HSMMC_HAS_HSPE_SUPPORT) &&
Seungwon Jeon5438ad92014-03-14 21:12:27 +0900583 (ios->timing != MMC_TIMING_MMC_DDR52) &&
Ulf Hansson903101a2014-11-25 13:05:13 +0100584 (ios->timing != MMC_TIMING_UHS_DDR50) &&
Hebbar, Gururajacd587092012-11-19 21:59:58 +0530585 ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
586 regval = OMAP_HSMMC_READ(host->base, HCTL);
587 if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
588 regval |= HSPE;
589 else
590 regval &= ~HSPE;
591
592 OMAP_HSMMC_WRITE(host->base, HCTL, regval);
593 }
594
Andy Shevchenko5934df22011-05-06 12:14:06 +0300595 omap_hsmmc_start_clock(host);
596}
597
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400598static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
599{
600 struct mmc_ios *ios = &host->mmc->ios;
601 u32 con;
602
603 con = OMAP_HSMMC_READ(host->base, CON);
Ulf Hansson903101a2014-11-25 13:05:13 +0100604 if (ios->timing == MMC_TIMING_MMC_DDR52 ||
605 ios->timing == MMC_TIMING_UHS_DDR50)
Balaji T K03b5d922012-04-09 12:08:33 +0530606 con |= DDR; /* configure in DDR mode */
607 else
608 con &= ~DDR;
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400609 switch (ios->bus_width) {
610 case MMC_BUS_WIDTH_8:
611 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
612 break;
613 case MMC_BUS_WIDTH_4:
614 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
615 OMAP_HSMMC_WRITE(host->base, HCTL,
616 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
617 break;
618 case MMC_BUS_WIDTH_1:
619 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
620 OMAP_HSMMC_WRITE(host->base, HCTL,
621 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
622 break;
623 }
624}
625
626static void omap_hsmmc_set_bus_mode(struct omap_hsmmc_host *host)
627{
628 struct mmc_ios *ios = &host->mmc->ios;
629 u32 con;
630
631 con = OMAP_HSMMC_READ(host->base, CON);
632 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
633 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
634 else
635 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
636}
637
Denis Karpov11dd62a2009-09-22 16:44:43 -0700638#ifdef CONFIG_PM
639
640/*
641 * Restore the MMC host context, if it was lost as result of a
642 * power state change.
643 */
Denis Karpov70a33412009-09-22 16:44:59 -0700644static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700645{
646 struct mmc_ios *ios = &host->mmc->ios;
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400647 u32 hctl, capa;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700648 unsigned long timeout;
649
Tony Lindgren0a82e062013-10-21 00:25:19 +0530650 if (host->con == OMAP_HSMMC_READ(host->base, CON) &&
651 host->hctl == OMAP_HSMMC_READ(host->base, HCTL) &&
652 host->sysctl == OMAP_HSMMC_READ(host->base, SYSCTL) &&
653 host->capa == OMAP_HSMMC_READ(host->base, CAPA))
654 return 0;
655
656 host->context_loss++;
657
Balaji T Kc2200ef2012-03-07 09:55:30 -0500658 if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
Denis Karpov11dd62a2009-09-22 16:44:43 -0700659 if (host->power_mode != MMC_POWER_OFF &&
660 (1 << ios->vdd) <= MMC_VDD_23_24)
661 hctl = SDVS18;
662 else
663 hctl = SDVS30;
664 capa = VS30 | VS18;
665 } else {
666 hctl = SDVS18;
667 capa = VS18;
668 }
669
Balaji T K5a52b082014-05-29 10:28:02 +0200670 if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
671 hctl |= IWE;
672
Denis Karpov11dd62a2009-09-22 16:44:43 -0700673 OMAP_HSMMC_WRITE(host->base, HCTL,
674 OMAP_HSMMC_READ(host->base, HCTL) | hctl);
675
676 OMAP_HSMMC_WRITE(host->base, CAPA,
677 OMAP_HSMMC_READ(host->base, CAPA) | capa);
678
679 OMAP_HSMMC_WRITE(host->base, HCTL,
680 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
681
682 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
683 while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP
684 && time_before(jiffies, timeout))
685 ;
686
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200687 OMAP_HSMMC_WRITE(host->base, ISE, 0);
688 OMAP_HSMMC_WRITE(host->base, IE, 0);
689 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700690
691 /* Do not initialize card-specific things if the power is off */
692 if (host->power_mode == MMC_POWER_OFF)
693 goto out;
694
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400695 omap_hsmmc_set_bus_width(host);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700696
Andy Shevchenko5934df22011-05-06 12:14:06 +0300697 omap_hsmmc_set_clock(host);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700698
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400699 omap_hsmmc_set_bus_mode(host);
700
Denis Karpov11dd62a2009-09-22 16:44:43 -0700701out:
Tony Lindgren0a82e062013-10-21 00:25:19 +0530702 dev_dbg(mmc_dev(host->mmc), "context is restored: restore count %d\n",
703 host->context_loss);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700704 return 0;
705}
706
707/*
708 * Save the MMC host context (store the number of power state changes so far).
709 */
Denis Karpov70a33412009-09-22 16:44:59 -0700710static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700711{
Tony Lindgren0a82e062013-10-21 00:25:19 +0530712 host->con = OMAP_HSMMC_READ(host->base, CON);
713 host->hctl = OMAP_HSMMC_READ(host->base, HCTL);
714 host->sysctl = OMAP_HSMMC_READ(host->base, SYSCTL);
715 host->capa = OMAP_HSMMC_READ(host->base, CAPA);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700716}
717
718#else
719
Denis Karpov70a33412009-09-22 16:44:59 -0700720static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700721{
722 return 0;
723}
724
Denis Karpov70a33412009-09-22 16:44:59 -0700725static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700726{
727}
728
729#endif
730
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100731/*
732 * Send init stream sequence to card
733 * before sending IDLE command
734 */
Denis Karpov70a33412009-09-22 16:44:59 -0700735static void send_init_stream(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100736{
737 int reg = 0;
738 unsigned long timeout;
739
Adrian Hunterb62f6222009-09-22 16:45:01 -0700740 if (host->protect_card)
741 return;
742
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100743 disable_irq(host->irq);
Adrian Hunterb4175772010-05-26 14:42:06 -0700744
745 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100746 OMAP_HSMMC_WRITE(host->base, CON,
747 OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
748 OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
749
750 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
Venkatraman Sa7e96872012-11-19 22:00:01 +0530751 while ((reg != CC_EN) && time_before(jiffies, timeout))
752 reg = OMAP_HSMMC_READ(host->base, STAT) & CC_EN;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100753
754 OMAP_HSMMC_WRITE(host->base, CON,
755 OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
Adrian Hunterc653a6d2009-09-22 16:44:56 -0700756
757 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
758 OMAP_HSMMC_READ(host->base, STAT);
759
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100760 enable_irq(host->irq);
761}
762
763static inline
Denis Karpov70a33412009-09-22 16:44:59 -0700764int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100765{
766 int r = 1;
767
Andreas Fenkartb5cd43f2014-11-08 15:33:16 +0100768 if (host->get_cover_state)
Andreas Fenkart80412ca2014-11-08 15:33:17 +0100769 r = host->get_cover_state(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100770 return r;
771}
772
773static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700774omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100775 char *buf)
776{
777 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700778 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100779
Denis Karpov70a33412009-09-22 16:44:59 -0700780 return sprintf(buf, "%s\n",
781 omap_hsmmc_cover_is_closed(host) ? "closed" : "open");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100782}
783
Denis Karpov70a33412009-09-22 16:44:59 -0700784static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100785
786static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700787omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100788 char *buf)
789{
790 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700791 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100792
Andreas Fenkart326119c2014-11-08 15:33:14 +0100793 return sprintf(buf, "%s\n", mmc_pdata(host)->name);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100794}
795
Denis Karpov70a33412009-09-22 16:44:59 -0700796static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100797
798/*
799 * Configure the response type and send the cmd.
800 */
801static void
Denis Karpov70a33412009-09-22 16:44:59 -0700802omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100803 struct mmc_data *data)
804{
805 int cmdreg = 0, resptype = 0, cmdtype = 0;
806
Venkatraman S8986d312012-08-07 19:10:38 +0530807 dev_vdbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100808 mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
809 host->cmd = cmd;
810
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700811 omap_hsmmc_enable_irq(host, cmd);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100812
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200813 host->response_busy = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100814 if (cmd->flags & MMC_RSP_PRESENT) {
815 if (cmd->flags & MMC_RSP_136)
816 resptype = 1;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200817 else if (cmd->flags & MMC_RSP_BUSY) {
818 resptype = 3;
819 host->response_busy = 1;
820 } else
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100821 resptype = 2;
822 }
823
824 /*
825 * Unlike OMAP1 controller, the cmdtype does not seem to be based on
826 * ac, bc, adtc, bcr. Only commands ending an open ended transfer need
827 * a val of 0x3, rest 0x0.
828 */
829 if (cmd == host->mrq->stop)
830 cmdtype = 0x3;
831
832 cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
833
Balaji T Ka2e77152014-01-21 19:54:42 +0530834 if ((host->flags & AUTO_CMD23) && mmc_op_multi(cmd->opcode) &&
835 host->mrq->sbc) {
836 cmdreg |= ACEN_ACMD23;
837 OMAP_HSMMC_WRITE(host->base, SDMASA, host->mrq->sbc->arg);
838 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100839 if (data) {
840 cmdreg |= DP_SELECT | MSBS | BCE;
841 if (data->flags & MMC_DATA_READ)
842 cmdreg |= DDIR;
843 else
844 cmdreg &= ~(DDIR);
845 }
846
847 if (host->use_dma)
Venkatraman Sa7e96872012-11-19 22:00:01 +0530848 cmdreg |= DMAE;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100849
Adrian Hunterb4175772010-05-26 14:42:06 -0700850 host->req_in_progress = 1;
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700851
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100852 OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
853 OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
854}
855
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200856static int
Denis Karpov70a33412009-09-22 16:44:59 -0700857omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200858{
859 if (data->flags & MMC_DATA_WRITE)
860 return DMA_TO_DEVICE;
861 else
862 return DMA_FROM_DEVICE;
863}
864
Russell Kingc5c98922012-04-13 12:14:39 +0100865static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host,
866 struct mmc_data *data)
867{
868 return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
869}
870
Adrian Hunterb4175772010-05-26 14:42:06 -0700871static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
872{
873 int dma_ch;
Venkatraman S31463b12012-04-09 12:08:34 +0530874 unsigned long flags;
Adrian Hunterb4175772010-05-26 14:42:06 -0700875
Venkatraman S31463b12012-04-09 12:08:34 +0530876 spin_lock_irqsave(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700877 host->req_in_progress = 0;
878 dma_ch = host->dma_ch;
Venkatraman S31463b12012-04-09 12:08:34 +0530879 spin_unlock_irqrestore(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700880
881 omap_hsmmc_disable_irq(host);
882 /* Do not complete the request if DMA is still in progress */
883 if (mrq->data && host->use_dma && dma_ch != -1)
884 return;
885 host->mrq = NULL;
886 mmc_request_done(host->mmc, mrq);
NeilBrownf57ba4c2015-03-26 12:18:23 +1100887 pm_runtime_mark_last_busy(host->dev);
888 pm_runtime_put_autosuspend(host->dev);
Adrian Hunterb4175772010-05-26 14:42:06 -0700889}
890
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100891/*
892 * Notify the transfer complete to MMC core
893 */
894static void
Denis Karpov70a33412009-09-22 16:44:59 -0700895omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100896{
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200897 if (!data) {
898 struct mmc_request *mrq = host->mrq;
899
Adrian Hunter23050102009-09-22 16:44:57 -0700900 /* TC before CC from CMD6 - don't know why, but it happens */
901 if (host->cmd && host->cmd->opcode == 6 &&
902 host->response_busy) {
903 host->response_busy = 0;
904 return;
905 }
906
Adrian Hunterb4175772010-05-26 14:42:06 -0700907 omap_hsmmc_request_done(host, mrq);
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200908 return;
909 }
910
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100911 host->data = NULL;
912
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100913 if (!data->error)
914 data->bytes_xfered += data->blocks * (data->blksz);
915 else
916 data->bytes_xfered = 0;
917
Balaji T Kbf129e12014-01-21 19:54:42 +0530918 if (data->stop && (data->error || !host->mrq->sbc))
919 omap_hsmmc_start_command(host, data->stop, NULL);
920 else
Adrian Hunterb4175772010-05-26 14:42:06 -0700921 omap_hsmmc_request_done(host, data->mrq);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100922}
923
924/*
925 * Notify the core about command completion
926 */
927static void
Denis Karpov70a33412009-09-22 16:44:59 -0700928omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100929{
Balaji T Kbf129e12014-01-21 19:54:42 +0530930 if (host->mrq->sbc && (host->cmd == host->mrq->sbc) &&
Balaji T Ka2e77152014-01-21 19:54:42 +0530931 !host->mrq->sbc->error && !(host->flags & AUTO_CMD23)) {
Balaji T K2177fa92014-05-09 22:16:52 +0530932 host->cmd = NULL;
Balaji T Kbf129e12014-01-21 19:54:42 +0530933 omap_hsmmc_start_dma_transfer(host);
934 omap_hsmmc_start_command(host, host->mrq->cmd,
935 host->mrq->data);
936 return;
937 }
938
Balaji T K2177fa92014-05-09 22:16:52 +0530939 host->cmd = NULL;
940
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100941 if (cmd->flags & MMC_RSP_PRESENT) {
942 if (cmd->flags & MMC_RSP_136) {
943 /* response type 2 */
944 cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
945 cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
946 cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
947 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
948 } else {
949 /* response types 1, 1b, 3, 4, 5, 6 */
950 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
951 }
952 }
Adrian Hunterb4175772010-05-26 14:42:06 -0700953 if ((host->data == NULL && !host->response_busy) || cmd->error)
Balaji T Kd4b2c372014-01-21 19:54:42 +0530954 omap_hsmmc_request_done(host, host->mrq);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100955}
956
957/*
958 * DMA clean up for command errors
959 */
Denis Karpov70a33412009-09-22 16:44:59 -0700960static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100961{
Adrian Hunterb4175772010-05-26 14:42:06 -0700962 int dma_ch;
Venkatraman S31463b12012-04-09 12:08:34 +0530963 unsigned long flags;
Adrian Hunterb4175772010-05-26 14:42:06 -0700964
Jarkko Lavinen82788ff2008-12-05 12:31:46 +0200965 host->data->error = errno;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100966
Venkatraman S31463b12012-04-09 12:08:34 +0530967 spin_lock_irqsave(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700968 dma_ch = host->dma_ch;
969 host->dma_ch = -1;
Venkatraman S31463b12012-04-09 12:08:34 +0530970 spin_unlock_irqrestore(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700971
972 if (host->use_dma && dma_ch != -1) {
Russell Kingc5c98922012-04-13 12:14:39 +0100973 struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host->data);
974
975 dmaengine_terminate_all(chan);
976 dma_unmap_sg(chan->device->dev,
977 host->data->sg, host->data->sg_len,
Denis Karpov70a33412009-09-22 16:44:59 -0700978 omap_hsmmc_get_dma_dir(host, host->data));
Russell Kingc5c98922012-04-13 12:14:39 +0100979
Per Forlin053bf342011-11-07 21:55:11 +0530980 host->data->host_cookie = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100981 }
982 host->data = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100983}
984
985/*
986 * Readable error output
987 */
988#ifdef CONFIG_MMC_DEBUG
Adrian Hunter699b9582011-05-06 12:14:01 +0300989static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100990{
991 /* --- means reserved bit without definition at documentation */
Denis Karpov70a33412009-09-22 16:44:59 -0700992 static const char *omap_hsmmc_status_bits[] = {
Adrian Hunter699b9582011-05-06 12:14:01 +0300993 "CC" , "TC" , "BGE", "---", "BWR" , "BRR" , "---" , "---" ,
994 "CIRQ", "OBI" , "---", "---", "---" , "---" , "---" , "ERRI",
995 "CTO" , "CCRC", "CEB", "CIE", "DTO" , "DCRC", "DEB" , "---" ,
996 "ACE" , "---" , "---", "---", "CERR", "BADA", "---" , "---"
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100997 };
998 char res[256];
999 char *buf = res;
1000 int len, i;
1001
1002 len = sprintf(buf, "MMC IRQ 0x%x :", status);
1003 buf += len;
1004
Denis Karpov70a33412009-09-22 16:44:59 -07001005 for (i = 0; i < ARRAY_SIZE(omap_hsmmc_status_bits); i++)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001006 if (status & (1 << i)) {
Denis Karpov70a33412009-09-22 16:44:59 -07001007 len = sprintf(buf, " %s", omap_hsmmc_status_bits[i]);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001008 buf += len;
1009 }
1010
Venkatraman S8986d312012-08-07 19:10:38 +05301011 dev_vdbg(mmc_dev(host->mmc), "%s\n", res);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001012}
Adrian Hunter699b9582011-05-06 12:14:01 +03001013#else
1014static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host,
1015 u32 status)
1016{
1017}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001018#endif /* CONFIG_MMC_DEBUG */
1019
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001020/*
1021 * MMC controller internal state machines reset
1022 *
1023 * Used to reset command or data internal state machines, using respectively
1024 * SRC or SRD bit of SYSCTL register
1025 * Can be called from interrupt context
1026 */
Denis Karpov70a33412009-09-22 16:44:59 -07001027static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
1028 unsigned long bit)
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001029{
1030 unsigned long i = 0;
Jianpeng Ma1e881782013-10-21 00:25:20 +05301031 unsigned long limit = MMC_TIMEOUT_US;
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001032
1033 OMAP_HSMMC_WRITE(host->base, SYSCTL,
1034 OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
1035
Madhusudhan Chikkature07ad64b2010-10-01 16:35:25 -07001036 /*
1037 * OMAP4 ES2 and greater has an updated reset logic.
1038 * Monitor a 0->1 transition first
1039 */
Andreas Fenkart326119c2014-11-08 15:33:14 +01001040 if (mmc_pdata(host)->features & HSMMC_HAS_UPDATED_RESET) {
kishore kadiyalab432b4b2010-11-17 22:35:32 -05001041 while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
Madhusudhan Chikkature07ad64b2010-10-01 16:35:25 -07001042 && (i++ < limit))
Jianpeng Ma1e881782013-10-21 00:25:20 +05301043 udelay(1);
Madhusudhan Chikkature07ad64b2010-10-01 16:35:25 -07001044 }
1045 i = 0;
1046
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001047 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
1048 (i++ < limit))
Jianpeng Ma1e881782013-10-21 00:25:20 +05301049 udelay(1);
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001050
1051 if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
1052 dev_err(mmc_dev(host->mmc),
1053 "Timeout waiting on controller reset in %s\n",
1054 __func__);
1055}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001056
Balaji T K25e18972012-11-19 21:59:55 +05301057static void hsmmc_command_incomplete(struct omap_hsmmc_host *host,
1058 int err, int end_cmd)
Venkatraman Sae4bf782012-08-09 20:36:07 +05301059{
Balaji T K25e18972012-11-19 21:59:55 +05301060 if (end_cmd) {
Balaji T K94d4f272012-11-19 21:59:56 +05301061 omap_hsmmc_reset_controller_fsm(host, SRC);
Balaji T K25e18972012-11-19 21:59:55 +05301062 if (host->cmd)
1063 host->cmd->error = err;
1064 }
Venkatraman Sae4bf782012-08-09 20:36:07 +05301065
1066 if (host->data) {
1067 omap_hsmmc_reset_controller_fsm(host, SRD);
1068 omap_hsmmc_dma_cleanup(host, err);
Balaji T Kdc7745b2012-11-19 21:59:57 +05301069 } else if (host->mrq && host->mrq->cmd)
1070 host->mrq->cmd->error = err;
Venkatraman Sae4bf782012-08-09 20:36:07 +05301071}
1072
Adrian Hunterb4175772010-05-26 14:42:06 -07001073static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001074{
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001075 struct mmc_data *data;
Adrian Hunterb4175772010-05-26 14:42:06 -07001076 int end_cmd = 0, end_trans = 0;
Balaji T Ka2e77152014-01-21 19:54:42 +05301077 int error = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001078
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001079 data = host->data;
Venkatraman S8986d312012-08-07 19:10:38 +05301080 dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001081
Venkatraman Sa7e96872012-11-19 22:00:01 +05301082 if (status & ERR_EN) {
Adrian Hunter699b9582011-05-06 12:14:01 +03001083 omap_hsmmc_dbg_report_irq(host, status);
Adrian Hunter4a694dc2009-01-12 16:13:08 +02001084
Venkatraman Sa7e96872012-11-19 22:00:01 +05301085 if (status & (CTO_EN | CCRC_EN))
Balaji T K25e18972012-11-19 21:59:55 +05301086 end_cmd = 1;
Kishon Vijay Abraham I408806f2015-06-16 16:07:17 +05301087 if (host->data || host->response_busy) {
1088 end_trans = !end_cmd;
1089 host->response_busy = 0;
1090 }
Venkatraman Sa7e96872012-11-19 22:00:01 +05301091 if (status & (CTO_EN | DTO_EN))
Balaji T K25e18972012-11-19 21:59:55 +05301092 hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd);
Vignesh R5027cd12015-06-16 16:07:18 +05301093 else if (status & (CCRC_EN | DCRC_EN | DEB_EN | CEB_EN |
1094 BADA_EN))
Balaji T K25e18972012-11-19 21:59:55 +05301095 hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
1096
Balaji T Ka2e77152014-01-21 19:54:42 +05301097 if (status & ACE_EN) {
1098 u32 ac12;
1099 ac12 = OMAP_HSMMC_READ(host->base, AC12);
1100 if (!(ac12 & ACNE) && host->mrq->sbc) {
1101 end_cmd = 1;
1102 if (ac12 & ACTO)
1103 error = -ETIMEDOUT;
1104 else if (ac12 & (ACCE | ACEB | ACIE))
1105 error = -EILSEQ;
1106 host->mrq->sbc->error = error;
1107 hsmmc_command_incomplete(host, error, end_cmd);
1108 }
1109 dev_dbg(mmc_dev(host->mmc), "AC12 err: 0x%x\n", ac12);
1110 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001111 }
1112
Francesco Lavra7472bab2013-06-29 08:25:12 +02001113 OMAP_HSMMC_WRITE(host->base, STAT, status);
Venkatraman Sa7e96872012-11-19 22:00:01 +05301114 if (end_cmd || ((status & CC_EN) && host->cmd))
Denis Karpov70a33412009-09-22 16:44:59 -07001115 omap_hsmmc_cmd_done(host, host->cmd);
Venkatraman Sa7e96872012-11-19 22:00:01 +05301116 if ((end_trans || (status & TC_EN)) && host->mrq)
Denis Karpov70a33412009-09-22 16:44:59 -07001117 omap_hsmmc_xfer_done(host, data);
Adrian Hunterb4175772010-05-26 14:42:06 -07001118}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001119
Adrian Hunterb4175772010-05-26 14:42:06 -07001120/*
1121 * MMC controller IRQ handler
1122 */
1123static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
1124{
1125 struct omap_hsmmc_host *host = dev_id;
1126 int status;
1127
1128 status = OMAP_HSMMC_READ(host->base, STAT);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001129 while (status & (INT_EN_MASK | CIRQ_EN)) {
1130 if (host->req_in_progress)
1131 omap_hsmmc_do_irq(host, status);
1132
1133 if (status & CIRQ_EN)
1134 mmc_signal_sdio_irq(host->mmc);
Venkatraman S1f6b9fa2012-08-08 15:44:29 +05301135
Adrian Hunterb4175772010-05-26 14:42:06 -07001136 /* Flush posted write */
1137 status = OMAP_HSMMC_READ(host->base, STAT);
Venkatraman S1f6b9fa2012-08-08 15:44:29 +05301138 }
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001139
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001140 return IRQ_HANDLED;
1141}
1142
Denis Karpov70a33412009-09-22 16:44:59 -07001143static void set_sd_bus_power(struct omap_hsmmc_host *host)
Adrian Huntere13bb302009-03-12 17:08:26 +02001144{
1145 unsigned long i;
1146
1147 OMAP_HSMMC_WRITE(host->base, HCTL,
1148 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
1149 for (i = 0; i < loops_per_jiffy; i++) {
1150 if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
1151 break;
1152 cpu_relax();
1153 }
1154}
1155
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001156/*
David Brownelleb250822009-02-17 14:49:01 -08001157 * Switch MMC interface voltage ... only relevant for MMC1.
1158 *
1159 * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
1160 * The MMC2 transceiver controls are used instead of DAT4..DAT7.
1161 * Some chips, like eMMC ones, use internal transceivers.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001162 */
Denis Karpov70a33412009-09-22 16:44:59 -07001163static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001164{
1165 u32 reg_val = 0;
1166 int ret;
1167
1168 /* Disable the clocks */
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301169 pm_runtime_put_sync(host->dev);
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05301170 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05301171 clk_disable_unprepare(host->dbclk);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001172
1173 /* Turn the power off */
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02001174 ret = omap_hsmmc_set_power(host->dev, 0, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001175
1176 /* Turn the power ON with given VDD 1.8 or 3.0v */
Adrian Hunter2bec0892009-09-22 16:45:02 -07001177 if (!ret)
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02001178 ret = omap_hsmmc_set_power(host->dev, 1, vdd);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301179 pm_runtime_get_sync(host->dev);
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05301180 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05301181 clk_prepare_enable(host->dbclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07001182
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001183 if (ret != 0)
1184 goto err;
1185
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001186 OMAP_HSMMC_WRITE(host->base, HCTL,
1187 OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
1188 reg_val = OMAP_HSMMC_READ(host->base, HCTL);
David Brownelleb250822009-02-17 14:49:01 -08001189
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001190 /*
1191 * If a MMC dual voltage card is detected, the set_ios fn calls
1192 * this fn with VDD bit set for 1.8V. Upon card removal from the
Denis Karpov70a33412009-09-22 16:44:59 -07001193 * slot, omap_hsmmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001194 *
David Brownelleb250822009-02-17 14:49:01 -08001195 * Cope with a bit of slop in the range ... per data sheets:
1196 * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
1197 * but recommended values are 1.71V to 1.89V
1198 * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
1199 * but recommended values are 2.7V to 3.3V
1200 *
1201 * Board setup code shouldn't permit anything very out-of-range.
1202 * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
1203 * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001204 */
David Brownelleb250822009-02-17 14:49:01 -08001205 if ((1 << vdd) <= MMC_VDD_23_24)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001206 reg_val |= SDVS18;
David Brownelleb250822009-02-17 14:49:01 -08001207 else
1208 reg_val |= SDVS30;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001209
1210 OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
Adrian Huntere13bb302009-03-12 17:08:26 +02001211 set_sd_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001212
1213 return 0;
1214err:
Venkatraman Sb1e056a2012-11-19 22:00:00 +05301215 dev_err(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001216 return ret;
1217}
1218
Adrian Hunterb62f6222009-09-22 16:45:01 -07001219/* Protect the card while the cover is open */
1220static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
1221{
Andreas Fenkartb5cd43f2014-11-08 15:33:16 +01001222 if (!host->get_cover_state)
Adrian Hunterb62f6222009-09-22 16:45:01 -07001223 return;
1224
1225 host->reqs_blocked = 0;
Andreas Fenkart80412ca2014-11-08 15:33:17 +01001226 if (host->get_cover_state(host->dev)) {
Adrian Hunterb62f6222009-09-22 16:45:01 -07001227 if (host->protect_card) {
Rajendra Nayak2cecdf02012-02-23 17:02:20 +05301228 dev_info(host->dev, "%s: cover is closed, "
Adrian Hunterb62f6222009-09-22 16:45:01 -07001229 "card is now accessible\n",
1230 mmc_hostname(host->mmc));
1231 host->protect_card = 0;
1232 }
1233 } else {
1234 if (!host->protect_card) {
Rajendra Nayak2cecdf02012-02-23 17:02:20 +05301235 dev_info(host->dev, "%s: cover is open, "
Adrian Hunterb62f6222009-09-22 16:45:01 -07001236 "card is now inaccessible\n",
1237 mmc_hostname(host->mmc));
1238 host->protect_card = 1;
1239 }
1240 }
1241}
1242
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001243/*
Andreas Fenkartcde592c2015-03-03 13:28:15 +01001244 * irq handler when (cell-phone) cover is mounted/removed
1245 */
1246static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id)
1247{
1248 struct omap_hsmmc_host *host = dev_id;
Andreas Fenkartcde592c2015-03-03 13:28:15 +01001249
1250 sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
1251
Andreas Fenkart11227d12015-03-03 13:28:17 +01001252 omap_hsmmc_protect_card(host);
1253 mmc_detect_change(host->mmc, (HZ * 200) / 1000);
Andreas Fenkartcde592c2015-03-03 13:28:15 +01001254 return IRQ_HANDLED;
1255}
1256
Russell Kingc5c98922012-04-13 12:14:39 +01001257static void omap_hsmmc_dma_callback(void *param)
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001258{
Russell Kingc5c98922012-04-13 12:14:39 +01001259 struct omap_hsmmc_host *host = param;
1260 struct dma_chan *chan;
Adrian Hunter770d7432011-05-06 12:14:11 +03001261 struct mmc_data *data;
Russell Kingc5c98922012-04-13 12:14:39 +01001262 int req_in_progress;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001263
Russell Kingc5c98922012-04-13 12:14:39 +01001264 spin_lock_irq(&host->irq_lock);
Adrian Hunterb4175772010-05-26 14:42:06 -07001265 if (host->dma_ch < 0) {
Russell Kingc5c98922012-04-13 12:14:39 +01001266 spin_unlock_irq(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001267 return;
Adrian Hunterb4175772010-05-26 14:42:06 -07001268 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001269
Adrian Hunter770d7432011-05-06 12:14:11 +03001270 data = host->mrq->data;
Russell Kingc5c98922012-04-13 12:14:39 +01001271 chan = omap_hsmmc_get_dma_chan(host, data);
Per Forlin9782aff2011-07-01 18:55:23 +02001272 if (!data->host_cookie)
Russell Kingc5c98922012-04-13 12:14:39 +01001273 dma_unmap_sg(chan->device->dev,
1274 data->sg, data->sg_len,
Per Forlin9782aff2011-07-01 18:55:23 +02001275 omap_hsmmc_get_dma_dir(host, data));
Adrian Hunterb4175772010-05-26 14:42:06 -07001276
1277 req_in_progress = host->req_in_progress;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001278 host->dma_ch = -1;
Russell Kingc5c98922012-04-13 12:14:39 +01001279 spin_unlock_irq(&host->irq_lock);
Adrian Hunterb4175772010-05-26 14:42:06 -07001280
1281 /* If DMA has finished after TC, complete the request */
1282 if (!req_in_progress) {
1283 struct mmc_request *mrq = host->mrq;
1284
1285 host->mrq = NULL;
1286 mmc_request_done(host->mmc, mrq);
NeilBrownf57ba4c2015-03-26 12:18:23 +11001287 pm_runtime_mark_last_busy(host->dev);
1288 pm_runtime_put_autosuspend(host->dev);
Adrian Hunterb4175772010-05-26 14:42:06 -07001289 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001290}
1291
Per Forlin9782aff2011-07-01 18:55:23 +02001292static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
1293 struct mmc_data *data,
Russell Kingc5c98922012-04-13 12:14:39 +01001294 struct omap_hsmmc_next *next,
Russell King26b88522012-04-13 12:27:37 +01001295 struct dma_chan *chan)
Per Forlin9782aff2011-07-01 18:55:23 +02001296{
1297 int dma_len;
1298
1299 if (!next && data->host_cookie &&
1300 data->host_cookie != host->next_data.cookie) {
Rajendra Nayak2cecdf02012-02-23 17:02:20 +05301301 dev_warn(host->dev, "[%s] invalid cookie: data->host_cookie %d"
Per Forlin9782aff2011-07-01 18:55:23 +02001302 " host->next_data.cookie %d\n",
1303 __func__, data->host_cookie, host->next_data.cookie);
1304 data->host_cookie = 0;
1305 }
1306
1307 /* Check if next job is already prepared */
Dan Carpenterb38313d2014-01-30 15:15:18 +03001308 if (next || data->host_cookie != host->next_data.cookie) {
Russell King26b88522012-04-13 12:27:37 +01001309 dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
Per Forlin9782aff2011-07-01 18:55:23 +02001310 omap_hsmmc_get_dma_dir(host, data));
1311
1312 } else {
1313 dma_len = host->next_data.dma_len;
1314 host->next_data.dma_len = 0;
1315 }
1316
1317
1318 if (dma_len == 0)
1319 return -EINVAL;
1320
1321 if (next) {
1322 next->dma_len = dma_len;
1323 data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
1324 } else
1325 host->dma_len = dma_len;
1326
1327 return 0;
1328}
1329
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001330/*
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001331 * Routine to configure and start DMA for the MMC card
1332 */
Balaji T K9d025332014-01-21 19:54:42 +05301333static int omap_hsmmc_setup_dma_transfer(struct omap_hsmmc_host *host,
Denis Karpov70a33412009-09-22 16:44:59 -07001334 struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001335{
Russell King26b88522012-04-13 12:27:37 +01001336 struct dma_slave_config cfg;
1337 struct dma_async_tx_descriptor *tx;
1338 int ret = 0, i;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001339 struct mmc_data *data = req->data;
Russell Kingc5c98922012-04-13 12:14:39 +01001340 struct dma_chan *chan;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001341
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001342 /* Sanity check: all the SG entries must be aligned by block size. */
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001343 for (i = 0; i < data->sg_len; i++) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001344 struct scatterlist *sgl;
1345
1346 sgl = data->sg + i;
1347 if (sgl->length % data->blksz)
1348 return -EINVAL;
1349 }
1350 if ((data->blksz % 4) != 0)
1351 /* REVISIT: The MMC buffer increments only when MSB is written.
1352 * Return error for blksz which is non multiple of four.
1353 */
1354 return -EINVAL;
1355
Adrian Hunterb4175772010-05-26 14:42:06 -07001356 BUG_ON(host->dma_ch != -1);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001357
Russell Kingc5c98922012-04-13 12:14:39 +01001358 chan = omap_hsmmc_get_dma_chan(host, data);
Russell Kingc5c98922012-04-13 12:14:39 +01001359
Russell King26b88522012-04-13 12:27:37 +01001360 cfg.src_addr = host->mapbase + OMAP_HSMMC_DATA;
1361 cfg.dst_addr = host->mapbase + OMAP_HSMMC_DATA;
1362 cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1363 cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1364 cfg.src_maxburst = data->blksz / 4;
1365 cfg.dst_maxburst = data->blksz / 4;
Russell Kingc5c98922012-04-13 12:14:39 +01001366
Russell King26b88522012-04-13 12:27:37 +01001367 ret = dmaengine_slave_config(chan, &cfg);
Per Forlin9782aff2011-07-01 18:55:23 +02001368 if (ret)
1369 return ret;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001370
Russell King26b88522012-04-13 12:27:37 +01001371 ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, chan);
1372 if (ret)
1373 return ret;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001374
Russell King26b88522012-04-13 12:27:37 +01001375 tx = dmaengine_prep_slave_sg(chan, data->sg, data->sg_len,
1376 data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
1377 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
1378 if (!tx) {
1379 dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
1380 /* FIXME: cleanup */
1381 return -1;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001382 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001383
Russell King26b88522012-04-13 12:27:37 +01001384 tx->callback = omap_hsmmc_dma_callback;
1385 tx->callback_param = host;
1386
1387 /* Does not fail */
1388 dmaengine_submit(tx);
1389
1390 host->dma_ch = 1;
1391
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001392 return 0;
1393}
1394
Denis Karpov70a33412009-09-22 16:44:59 -07001395static void set_data_timeout(struct omap_hsmmc_host *host,
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001396 unsigned int timeout_ns,
1397 unsigned int timeout_clks)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001398{
1399 unsigned int timeout, cycle_ns;
1400 uint32_t reg, clkd, dto = 0;
1401
1402 reg = OMAP_HSMMC_READ(host->base, SYSCTL);
1403 clkd = (reg & CLKD_MASK) >> CLKD_SHIFT;
1404 if (clkd == 0)
1405 clkd = 1;
1406
Balaji T K6e3076c2014-01-21 19:54:42 +05301407 cycle_ns = 1000000000 / (host->clk_rate / clkd);
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001408 timeout = timeout_ns / cycle_ns;
1409 timeout += timeout_clks;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001410 if (timeout) {
1411 while ((timeout & 0x80000000) == 0) {
1412 dto += 1;
1413 timeout <<= 1;
1414 }
1415 dto = 31 - dto;
1416 timeout <<= 1;
1417 if (timeout && dto)
1418 dto += 1;
1419 if (dto >= 13)
1420 dto -= 13;
1421 else
1422 dto = 0;
1423 if (dto > 14)
1424 dto = 14;
1425 }
1426
1427 reg &= ~DTO_MASK;
1428 reg |= dto << DTO_SHIFT;
1429 OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
1430}
1431
Balaji T K9d025332014-01-21 19:54:42 +05301432static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host)
1433{
1434 struct mmc_request *req = host->mrq;
1435 struct dma_chan *chan;
1436
1437 if (!req->data)
1438 return;
1439 OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
1440 | (req->data->blocks << 16));
1441 set_data_timeout(host, req->data->timeout_ns,
1442 req->data->timeout_clks);
1443 chan = omap_hsmmc_get_dma_chan(host, req->data);
1444 dma_async_issue_pending(chan);
1445}
1446
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001447/*
1448 * Configure block length for MMC/SD cards and initiate the transfer.
1449 */
1450static int
Denis Karpov70a33412009-09-22 16:44:59 -07001451omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001452{
1453 int ret;
1454 host->data = req->data;
1455
1456 if (req->data == NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001457 OMAP_HSMMC_WRITE(host->base, BLK, 0);
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001458 /*
1459 * Set an arbitrary 100ms data timeout for commands with
1460 * busy signal.
1461 */
1462 if (req->cmd->flags & MMC_RSP_BUSY)
1463 set_data_timeout(host, 100000000U, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001464 return 0;
1465 }
1466
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001467 if (host->use_dma) {
Balaji T K9d025332014-01-21 19:54:42 +05301468 ret = omap_hsmmc_setup_dma_transfer(host, req);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001469 if (ret != 0) {
Venkatraman Sb1e056a2012-11-19 22:00:00 +05301470 dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001471 return ret;
1472 }
1473 }
1474 return 0;
1475}
1476
Per Forlin9782aff2011-07-01 18:55:23 +02001477static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
1478 int err)
1479{
1480 struct omap_hsmmc_host *host = mmc_priv(mmc);
1481 struct mmc_data *data = mrq->data;
1482
Russell King26b88522012-04-13 12:27:37 +01001483 if (host->use_dma && data->host_cookie) {
Russell Kingc5c98922012-04-13 12:14:39 +01001484 struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data);
Russell Kingc5c98922012-04-13 12:14:39 +01001485
Russell King26b88522012-04-13 12:27:37 +01001486 dma_unmap_sg(c->device->dev, data->sg, data->sg_len,
1487 omap_hsmmc_get_dma_dir(host, data));
Per Forlin9782aff2011-07-01 18:55:23 +02001488 data->host_cookie = 0;
1489 }
1490}
1491
1492static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1493 bool is_first_req)
1494{
1495 struct omap_hsmmc_host *host = mmc_priv(mmc);
1496
1497 if (mrq->data->host_cookie) {
1498 mrq->data->host_cookie = 0;
1499 return ;
1500 }
1501
Russell Kingc5c98922012-04-13 12:14:39 +01001502 if (host->use_dma) {
1503 struct dma_chan *c = omap_hsmmc_get_dma_chan(host, mrq->data);
Russell Kingc5c98922012-04-13 12:14:39 +01001504
Per Forlin9782aff2011-07-01 18:55:23 +02001505 if (omap_hsmmc_pre_dma_transfer(host, mrq->data,
Russell King26b88522012-04-13 12:27:37 +01001506 &host->next_data, c))
Per Forlin9782aff2011-07-01 18:55:23 +02001507 mrq->data->host_cookie = 0;
Russell Kingc5c98922012-04-13 12:14:39 +01001508 }
Per Forlin9782aff2011-07-01 18:55:23 +02001509}
1510
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001511/*
1512 * Request function. for read/write operation
1513 */
Denis Karpov70a33412009-09-22 16:44:59 -07001514static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001515{
Denis Karpov70a33412009-09-22 16:44:59 -07001516 struct omap_hsmmc_host *host = mmc_priv(mmc);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001517 int err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001518
Adrian Hunterb4175772010-05-26 14:42:06 -07001519 BUG_ON(host->req_in_progress);
1520 BUG_ON(host->dma_ch != -1);
NeilBrownf57ba4c2015-03-26 12:18:23 +11001521 pm_runtime_get_sync(host->dev);
Adrian Hunterb4175772010-05-26 14:42:06 -07001522 if (host->protect_card) {
1523 if (host->reqs_blocked < 3) {
1524 /*
1525 * Ensure the controller is left in a consistent
1526 * state by resetting the command and data state
1527 * machines.
1528 */
1529 omap_hsmmc_reset_controller_fsm(host, SRD);
1530 omap_hsmmc_reset_controller_fsm(host, SRC);
1531 host->reqs_blocked += 1;
1532 }
1533 req->cmd->error = -EBADF;
1534 if (req->data)
1535 req->data->error = -EBADF;
1536 req->cmd->retries = 0;
1537 mmc_request_done(mmc, req);
NeilBrownf57ba4c2015-03-26 12:18:23 +11001538 pm_runtime_mark_last_busy(host->dev);
1539 pm_runtime_put_autosuspend(host->dev);
Adrian Hunterb4175772010-05-26 14:42:06 -07001540 return;
1541 } else if (host->reqs_blocked)
1542 host->reqs_blocked = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001543 WARN_ON(host->mrq != NULL);
1544 host->mrq = req;
Balaji T K6e3076c2014-01-21 19:54:42 +05301545 host->clk_rate = clk_get_rate(host->fclk);
Denis Karpov70a33412009-09-22 16:44:59 -07001546 err = omap_hsmmc_prepare_data(host, req);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001547 if (err) {
1548 req->cmd->error = err;
1549 if (req->data)
1550 req->data->error = err;
1551 host->mrq = NULL;
1552 mmc_request_done(mmc, req);
NeilBrownf57ba4c2015-03-26 12:18:23 +11001553 pm_runtime_mark_last_busy(host->dev);
1554 pm_runtime_put_autosuspend(host->dev);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001555 return;
1556 }
Balaji T Ka2e77152014-01-21 19:54:42 +05301557 if (req->sbc && !(host->flags & AUTO_CMD23)) {
Balaji T Kbf129e12014-01-21 19:54:42 +05301558 omap_hsmmc_start_command(host, req->sbc, NULL);
1559 return;
1560 }
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001561
Balaji T K9d025332014-01-21 19:54:42 +05301562 omap_hsmmc_start_dma_transfer(host);
Denis Karpov70a33412009-09-22 16:44:59 -07001563 omap_hsmmc_start_command(host, req->cmd, req->data);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001564}
1565
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001566/* Routine to configure clock values. Exposed API to core */
Denis Karpov70a33412009-09-22 16:44:59 -07001567static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001568{
Denis Karpov70a33412009-09-22 16:44:59 -07001569 struct omap_hsmmc_host *host = mmc_priv(mmc);
Adrian Huntera3621462009-09-22 16:44:42 -07001570 int do_send_init_stream = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001571
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301572 pm_runtime_get_sync(host->dev);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001573
Adrian Huntera3621462009-09-22 16:44:42 -07001574 if (ios->power_mode != host->power_mode) {
1575 switch (ios->power_mode) {
1576 case MMC_POWER_OFF:
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02001577 omap_hsmmc_set_power(host->dev, 0, 0);
Adrian Huntera3621462009-09-22 16:44:42 -07001578 break;
1579 case MMC_POWER_UP:
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02001580 omap_hsmmc_set_power(host->dev, 1, ios->vdd);
Adrian Huntera3621462009-09-22 16:44:42 -07001581 break;
1582 case MMC_POWER_ON:
1583 do_send_init_stream = 1;
1584 break;
1585 }
1586 host->power_mode = ios->power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001587 }
1588
Denis Karpovdd498ef2009-09-22 16:44:49 -07001589 /* FIXME: set registers based only on changes to ios */
1590
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -04001591 omap_hsmmc_set_bus_width(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001592
Kishore Kadiyala4621d5f2011-02-28 20:48:04 +05301593 if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
David Brownelleb250822009-02-17 14:49:01 -08001594 /* Only MMC1 can interface at 3V without some flavor
1595 * of external transceiver; but they all handle 1.8V.
1596 */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001597 if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
Balaji T K2cf171c2014-02-19 20:26:40 +05301598 (ios->vdd == DUAL_VOLT_OCR_BIT)) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001599 /*
1600 * The mmc_select_voltage fn of the core does
1601 * not seem to set the power_mode to
1602 * MMC_POWER_UP upon recalculating the voltage.
1603 * vdd 1.8v.
1604 */
Denis Karpov70a33412009-09-22 16:44:59 -07001605 if (omap_hsmmc_switch_opcond(host, ios->vdd) != 0)
1606 dev_dbg(mmc_dev(host->mmc),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001607 "Switch operation failed\n");
1608 }
1609 }
1610
Andy Shevchenko5934df22011-05-06 12:14:06 +03001611 omap_hsmmc_set_clock(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001612
Adrian Huntera3621462009-09-22 16:44:42 -07001613 if (do_send_init_stream)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001614 send_init_stream(host);
1615
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -04001616 omap_hsmmc_set_bus_mode(host);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001617
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301618 pm_runtime_put_autosuspend(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001619}
1620
1621static int omap_hsmmc_get_cd(struct mmc_host *mmc)
1622{
Denis Karpov70a33412009-09-22 16:44:59 -07001623 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001624
Andreas Fenkartb5cd43f2014-11-08 15:33:16 +01001625 if (!host->card_detect)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001626 return -ENOSYS;
Andreas Fenkart80412ca2014-11-08 15:33:17 +01001627 return host->card_detect(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001628}
1629
Grazvydas Ignotas48168582010-08-10 18:01:52 -07001630static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
1631{
1632 struct omap_hsmmc_host *host = mmc_priv(mmc);
1633
Andreas Fenkart326119c2014-11-08 15:33:14 +01001634 if (mmc_pdata(host)->init_card)
1635 mmc_pdata(host)->init_card(card);
Grazvydas Ignotas48168582010-08-10 18:01:52 -07001636}
1637
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001638static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
1639{
1640 struct omap_hsmmc_host *host = mmc_priv(mmc);
Balaji T K5a52b082014-05-29 10:28:02 +02001641 u32 irq_mask, con;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001642 unsigned long flags;
1643
1644 spin_lock_irqsave(&host->irq_lock, flags);
1645
Balaji T K5a52b082014-05-29 10:28:02 +02001646 con = OMAP_HSMMC_READ(host->base, CON);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001647 irq_mask = OMAP_HSMMC_READ(host->base, ISE);
1648 if (enable) {
1649 host->flags |= HSMMC_SDIO_IRQ_ENABLED;
1650 irq_mask |= CIRQ_EN;
Balaji T K5a52b082014-05-29 10:28:02 +02001651 con |= CTPL | CLKEXTFREE;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001652 } else {
1653 host->flags &= ~HSMMC_SDIO_IRQ_ENABLED;
1654 irq_mask &= ~CIRQ_EN;
Balaji T K5a52b082014-05-29 10:28:02 +02001655 con &= ~(CTPL | CLKEXTFREE);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001656 }
Balaji T K5a52b082014-05-29 10:28:02 +02001657 OMAP_HSMMC_WRITE(host->base, CON, con);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001658 OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
1659
1660 /*
1661 * if enable, piggy back detection on current request
1662 * but always disable immediately
1663 */
1664 if (!host->req_in_progress || !enable)
1665 OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
1666
1667 /* flush posted write */
1668 OMAP_HSMMC_READ(host->base, IE);
1669
1670 spin_unlock_irqrestore(&host->irq_lock, flags);
1671}
1672
1673static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host)
1674{
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001675 int ret;
1676
1677 /*
1678 * For omaps with wake-up path, wakeirq will be irq from pinctrl and
1679 * for other omaps, wakeirq will be from GPIO (dat line remuxed to
1680 * gpio). wakeirq is needed to detect sdio irq in runtime suspend state
1681 * with functional clock disabled.
1682 */
1683 if (!host->dev->of_node || !host->wake_irq)
1684 return -ENODEV;
1685
Tony Lindgren5b83b222015-05-21 15:51:52 -07001686 ret = dev_pm_set_dedicated_wake_irq(host->dev, host->wake_irq);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001687 if (ret) {
1688 dev_err(mmc_dev(host->mmc), "Unable to request wake IRQ\n");
1689 goto err;
1690 }
1691
1692 /*
1693 * Some omaps don't have wake-up path from deeper idle states
1694 * and need to remux SDIO DAT1 to GPIO for wake-up from idle.
1695 */
1696 if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING) {
Andreas Fenkart455e5cd2014-05-29 10:28:05 +02001697 struct pinctrl *p = devm_pinctrl_get(host->dev);
1698 if (!p) {
1699 ret = -ENODEV;
1700 goto err_free_irq;
1701 }
1702 if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT))) {
1703 dev_info(host->dev, "missing default pinctrl state\n");
1704 devm_pinctrl_put(p);
1705 ret = -EINVAL;
1706 goto err_free_irq;
1707 }
1708
1709 if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_IDLE))) {
1710 dev_info(host->dev, "missing idle pinctrl state\n");
1711 devm_pinctrl_put(p);
1712 ret = -EINVAL;
1713 goto err_free_irq;
1714 }
1715 devm_pinctrl_put(p);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001716 }
1717
Balaji T K5a52b082014-05-29 10:28:02 +02001718 OMAP_HSMMC_WRITE(host->base, HCTL,
1719 OMAP_HSMMC_READ(host->base, HCTL) | IWE);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001720 return 0;
1721
Andreas Fenkart455e5cd2014-05-29 10:28:05 +02001722err_free_irq:
Tony Lindgren5b83b222015-05-21 15:51:52 -07001723 dev_pm_clear_wake_irq(host->dev);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001724err:
1725 dev_warn(host->dev, "no SDIO IRQ support, falling back to polling\n");
1726 host->wake_irq = 0;
1727 return ret;
1728}
1729
Denis Karpov70a33412009-09-22 16:44:59 -07001730static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001731{
1732 u32 hctl, capa, value;
1733
1734 /* Only MMC1 supports 3.0V */
Kishore Kadiyala4621d5f2011-02-28 20:48:04 +05301735 if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001736 hctl = SDVS30;
1737 capa = VS30 | VS18;
1738 } else {
1739 hctl = SDVS18;
1740 capa = VS18;
1741 }
1742
1743 value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
1744 OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
1745
1746 value = OMAP_HSMMC_READ(host->base, CAPA);
1747 OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
1748
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001749 /* Set SD bus power bit */
Adrian Huntere13bb302009-03-12 17:08:26 +02001750 set_sd_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001751}
1752
Kuninori Morimotoafd8c292014-09-08 23:44:51 -07001753static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
1754 unsigned int direction, int blk_size)
1755{
1756 /* This controller can't do multiblock reads due to hw bugs */
1757 if (direction == MMC_DATA_READ)
1758 return 1;
1759
1760 return blk_size;
1761}
1762
1763static struct mmc_host_ops omap_hsmmc_ops = {
Per Forlin9782aff2011-07-01 18:55:23 +02001764 .post_req = omap_hsmmc_post_req,
1765 .pre_req = omap_hsmmc_pre_req,
Denis Karpov70a33412009-09-22 16:44:59 -07001766 .request = omap_hsmmc_request,
1767 .set_ios = omap_hsmmc_set_ios,
Denis Karpovdd498ef2009-09-22 16:44:49 -07001768 .get_cd = omap_hsmmc_get_cd,
Andreas Fenkarta49d8352015-03-03 13:28:14 +01001769 .get_ro = mmc_gpio_get_ro,
Grazvydas Ignotas48168582010-08-10 18:01:52 -07001770 .init_card = omap_hsmmc_init_card,
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001771 .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
Denis Karpovdd498ef2009-09-22 16:44:49 -07001772};
1773
Denis Karpovd900f712009-09-22 16:44:38 -07001774#ifdef CONFIG_DEBUG_FS
1775
Denis Karpov70a33412009-09-22 16:44:59 -07001776static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
Denis Karpovd900f712009-09-22 16:44:38 -07001777{
1778 struct mmc_host *mmc = s->private;
Denis Karpov70a33412009-09-22 16:44:59 -07001779 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001780
Andreas Fenkartbb0635f2014-05-29 10:28:01 +02001781 seq_printf(s, "mmc%d:\n", mmc->index);
1782 seq_printf(s, "sdio irq mode\t%s\n",
1783 (mmc->caps & MMC_CAP_SDIO_IRQ) ? "interrupt" : "polling");
1784
1785 if (mmc->caps & MMC_CAP_SDIO_IRQ) {
1786 seq_printf(s, "sdio irq \t%s\n",
1787 (host->flags & HSMMC_SDIO_IRQ_ENABLED) ? "enabled"
1788 : "disabled");
1789 }
1790 seq_printf(s, "ctx_loss:\t%d\n", host->context_loss);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001791
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301792 pm_runtime_get_sync(host->dev);
Andreas Fenkartbb0635f2014-05-29 10:28:01 +02001793 seq_puts(s, "\nregs:\n");
Denis Karpovd900f712009-09-22 16:44:38 -07001794 seq_printf(s, "CON:\t\t0x%08x\n",
1795 OMAP_HSMMC_READ(host->base, CON));
Andreas Fenkartbb0635f2014-05-29 10:28:01 +02001796 seq_printf(s, "PSTATE:\t\t0x%08x\n",
1797 OMAP_HSMMC_READ(host->base, PSTATE));
Denis Karpovd900f712009-09-22 16:44:38 -07001798 seq_printf(s, "HCTL:\t\t0x%08x\n",
1799 OMAP_HSMMC_READ(host->base, HCTL));
1800 seq_printf(s, "SYSCTL:\t\t0x%08x\n",
1801 OMAP_HSMMC_READ(host->base, SYSCTL));
1802 seq_printf(s, "IE:\t\t0x%08x\n",
1803 OMAP_HSMMC_READ(host->base, IE));
1804 seq_printf(s, "ISE:\t\t0x%08x\n",
1805 OMAP_HSMMC_READ(host->base, ISE));
1806 seq_printf(s, "CAPA:\t\t0x%08x\n",
1807 OMAP_HSMMC_READ(host->base, CAPA));
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001808
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301809 pm_runtime_mark_last_busy(host->dev);
1810 pm_runtime_put_autosuspend(host->dev);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001811
Denis Karpovd900f712009-09-22 16:44:38 -07001812 return 0;
1813}
1814
Denis Karpov70a33412009-09-22 16:44:59 -07001815static int omap_hsmmc_regs_open(struct inode *inode, struct file *file)
Denis Karpovd900f712009-09-22 16:44:38 -07001816{
Denis Karpov70a33412009-09-22 16:44:59 -07001817 return single_open(file, omap_hsmmc_regs_show, inode->i_private);
Denis Karpovd900f712009-09-22 16:44:38 -07001818}
1819
1820static const struct file_operations mmc_regs_fops = {
Denis Karpov70a33412009-09-22 16:44:59 -07001821 .open = omap_hsmmc_regs_open,
Denis Karpovd900f712009-09-22 16:44:38 -07001822 .read = seq_read,
1823 .llseek = seq_lseek,
1824 .release = single_release,
1825};
1826
Denis Karpov70a33412009-09-22 16:44:59 -07001827static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001828{
1829 if (mmc->debugfs_root)
1830 debugfs_create_file("regs", S_IRUSR, mmc->debugfs_root,
1831 mmc, &mmc_regs_fops);
1832}
1833
1834#else
1835
Denis Karpov70a33412009-09-22 16:44:59 -07001836static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001837{
1838}
1839
1840#endif
1841
Rajendra Nayak46856a62012-03-12 20:32:37 +05301842#ifdef CONFIG_OF
Nishanth Menon59445b12014-02-13 23:45:48 -06001843static const struct omap_mmc_of_data omap3_pre_es3_mmc_of_data = {
1844 /* See 35xx errata 2.1.1.128 in SPRZ278F */
1845 .controller_flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
1846};
1847
1848static const struct omap_mmc_of_data omap4_mmc_of_data = {
1849 .reg_offset = 0x100,
1850};
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001851static const struct omap_mmc_of_data am33xx_mmc_of_data = {
1852 .reg_offset = 0x100,
1853 .controller_flags = OMAP_HSMMC_SWAKEUP_MISSING,
1854};
Rajendra Nayak46856a62012-03-12 20:32:37 +05301855
1856static const struct of_device_id omap_mmc_of_match[] = {
1857 {
1858 .compatible = "ti,omap2-hsmmc",
1859 },
1860 {
Nishanth Menon59445b12014-02-13 23:45:48 -06001861 .compatible = "ti,omap3-pre-es3-hsmmc",
1862 .data = &omap3_pre_es3_mmc_of_data,
1863 },
1864 {
Rajendra Nayak46856a62012-03-12 20:32:37 +05301865 .compatible = "ti,omap3-hsmmc",
1866 },
1867 {
1868 .compatible = "ti,omap4-hsmmc",
Nishanth Menon59445b12014-02-13 23:45:48 -06001869 .data = &omap4_mmc_of_data,
Rajendra Nayak46856a62012-03-12 20:32:37 +05301870 },
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001871 {
1872 .compatible = "ti,am33xx-hsmmc",
1873 .data = &am33xx_mmc_of_data,
1874 },
Rajendra Nayak46856a62012-03-12 20:32:37 +05301875 {},
Chris Ballb6d085f2012-04-10 09:57:36 -04001876};
Rajendra Nayak46856a62012-03-12 20:32:37 +05301877MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
1878
Andreas Fenkart55143432014-11-08 15:33:09 +01001879static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
Rajendra Nayak46856a62012-03-12 20:32:37 +05301880{
Andreas Fenkart55143432014-11-08 15:33:09 +01001881 struct omap_hsmmc_platform_data *pdata;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301882 struct device_node *np = dev->of_node;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301883
1884 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
1885 if (!pdata)
Balaji T K19df45b2014-02-28 19:08:18 +05301886 return ERR_PTR(-ENOMEM); /* out of memory */
Rajendra Nayak46856a62012-03-12 20:32:37 +05301887
1888 if (of_find_property(np, "ti,dual-volt", NULL))
1889 pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
1890
Andreas Fenkartb7a56462015-03-20 15:53:54 +01001891 pdata->gpio_cd = -EINVAL;
1892 pdata->gpio_cod = -EINVAL;
NeilBrownfdb9de12015-01-13 08:23:18 +13001893 pdata->gpio_wp = -EINVAL;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301894
1895 if (of_find_property(np, "ti,non-removable", NULL)) {
Andreas Fenkart326119c2014-11-08 15:33:14 +01001896 pdata->nonremovable = true;
1897 pdata->no_regulator_off_init = true;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301898 }
Rajendra Nayak46856a62012-03-12 20:32:37 +05301899
1900 if (of_find_property(np, "ti,needs-special-reset", NULL))
Andreas Fenkart326119c2014-11-08 15:33:14 +01001901 pdata->features |= HSMMC_HAS_UPDATED_RESET;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301902
Hebbar, Gururajacd587092012-11-19 21:59:58 +05301903 if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
Andreas Fenkart326119c2014-11-08 15:33:14 +01001904 pdata->features |= HSMMC_HAS_HSPE_SUPPORT;
Hebbar, Gururajacd587092012-11-19 21:59:58 +05301905
Rajendra Nayak46856a62012-03-12 20:32:37 +05301906 return pdata;
1907}
1908#else
Andreas Fenkart55143432014-11-08 15:33:09 +01001909static inline struct omap_hsmmc_platform_data
Rajendra Nayak46856a62012-03-12 20:32:37 +05301910 *of_get_hsmmc_pdata(struct device *dev)
1911{
Balaji T K19df45b2014-02-28 19:08:18 +05301912 return ERR_PTR(-EINVAL);
Rajendra Nayak46856a62012-03-12 20:32:37 +05301913}
1914#endif
1915
Bill Pembertonc3be1ef2012-11-19 13:23:06 -05001916static int omap_hsmmc_probe(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001917{
Andreas Fenkart55143432014-11-08 15:33:09 +01001918 struct omap_hsmmc_platform_data *pdata = pdev->dev.platform_data;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001919 struct mmc_host *mmc;
Denis Karpov70a33412009-09-22 16:44:59 -07001920 struct omap_hsmmc_host *host = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001921 struct resource *res;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001922 int ret, irq;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301923 const struct of_device_id *match;
Russell King26b88522012-04-13 12:27:37 +01001924 dma_cap_mask_t mask;
1925 unsigned tx_req, rx_req;
Nishanth Menon59445b12014-02-13 23:45:48 -06001926 const struct omap_mmc_of_data *data;
Balaji T K77fae212014-05-09 22:16:51 +05301927 void __iomem *base;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301928
1929 match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
1930 if (match) {
1931 pdata = of_get_hsmmc_pdata(&pdev->dev);
Jan Luebbedc642c22013-01-30 10:07:17 +01001932
1933 if (IS_ERR(pdata))
1934 return PTR_ERR(pdata);
1935
Rajendra Nayak46856a62012-03-12 20:32:37 +05301936 if (match->data) {
Nishanth Menon59445b12014-02-13 23:45:48 -06001937 data = match->data;
1938 pdata->reg_offset = data->reg_offset;
1939 pdata->controller_flags |= data->controller_flags;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301940 }
1941 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001942
1943 if (pdata == NULL) {
1944 dev_err(&pdev->dev, "Platform Data is missing\n");
1945 return -ENXIO;
1946 }
1947
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001948 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1949 irq = platform_get_irq(pdev, 0);
1950 if (res == NULL || irq < 0)
1951 return -ENXIO;
1952
Balaji T K77fae212014-05-09 22:16:51 +05301953 base = devm_ioremap_resource(&pdev->dev, res);
1954 if (IS_ERR(base))
1955 return PTR_ERR(base);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001956
Denis Karpov70a33412009-09-22 16:44:59 -07001957 mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001958 if (!mmc) {
1959 ret = -ENOMEM;
Andreas Fenkart1e363e32014-11-08 15:33:15 +01001960 goto err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001961 }
1962
NeilBrownfdb9de12015-01-13 08:23:18 +13001963 ret = mmc_of_parse(mmc);
1964 if (ret)
1965 goto err1;
1966
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001967 host = mmc_priv(mmc);
1968 host->mmc = mmc;
1969 host->pdata = pdata;
1970 host->dev = &pdev->dev;
1971 host->use_dma = 1;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001972 host->dma_ch = -1;
1973 host->irq = irq;
Balaji T Kfc307df2012-04-02 12:26:47 +05301974 host->mapbase = res->start + pdata->reg_offset;
Balaji T K77fae212014-05-09 22:16:51 +05301975 host->base = base + pdata->reg_offset;
Adrian Hunter6da20c82010-02-15 10:03:34 -08001976 host->power_mode = MMC_POWER_OFF;
Per Forlin9782aff2011-07-01 18:55:23 +02001977 host->next_data.cookie = 1;
Balaji T Ke99448f2014-02-19 20:26:40 +05301978 host->pbias_enabled = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001979
NeilBrown41afa3142015-01-13 08:23:18 +13001980 ret = omap_hsmmc_gpio_init(mmc, host, pdata);
Andreas Fenkart1e363e32014-11-08 15:33:15 +01001981 if (ret)
1982 goto err_gpio;
1983
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001984 platform_set_drvdata(pdev, host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001985
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001986 if (pdev->dev.of_node)
1987 host->wake_irq = irq_of_parse_and_map(pdev->dev.of_node, 1);
1988
Balaji T K7a8c2ce2011-07-01 22:09:34 +05301989 mmc->ops = &omap_hsmmc_ops;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001990
Daniel Mackd418ed82012-02-19 13:20:33 +01001991 mmc->f_min = OMAP_MMC_MIN_CLOCK;
1992
1993 if (pdata->max_freq > 0)
1994 mmc->f_max = pdata->max_freq;
NeilBrownfdb9de12015-01-13 08:23:18 +13001995 else if (mmc->f_max == 0)
Daniel Mackd418ed82012-02-19 13:20:33 +01001996 mmc->f_max = OMAP_MMC_MAX_CLOCK;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001997
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001998 spin_lock_init(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001999
Balaji T K96181952014-05-09 22:16:48 +05302000 host->fclk = devm_clk_get(&pdev->dev, "fck");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002001 if (IS_ERR(host->fclk)) {
2002 ret = PTR_ERR(host->fclk);
2003 host->fclk = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002004 goto err1;
2005 }
2006
Paul Walmsley9b682562011-10-06 14:50:35 -06002007 if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) {
2008 dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n");
Kuninori Morimotoafd8c292014-09-08 23:44:51 -07002009 omap_hsmmc_ops.multi_io_quirk = omap_hsmmc_multi_io_quirk;
Paul Walmsley9b682562011-10-06 14:50:35 -06002010 }
Denis Karpovdd498ef2009-09-22 16:44:49 -07002011
Tony Lindgren5b83b222015-05-21 15:51:52 -07002012 device_init_wakeup(&pdev->dev, true);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302013 pm_runtime_enable(host->dev);
2014 pm_runtime_get_sync(host->dev);
2015 pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY);
2016 pm_runtime_use_autosuspend(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002017
Balaji T K92a3aeb2012-02-24 21:14:34 +05302018 omap_hsmmc_context_save(host);
2019
Balaji T K96181952014-05-09 22:16:48 +05302020 host->dbclk = devm_clk_get(&pdev->dev, "mmchsdb_fck");
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302021 /*
2022 * MMC can still work without debounce clock.
2023 */
2024 if (IS_ERR(host->dbclk)) {
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302025 host->dbclk = NULL;
Rajendra Nayak94c18142012-06-27 14:19:54 +05302026 } else if (clk_prepare_enable(host->dbclk) != 0) {
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302027 dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302028 host->dbclk = NULL;
Adrian Hunter2bec0892009-09-22 16:45:02 -07002029 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002030
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02002031 /* Since we do only SG emulation, we can have as many segs
2032 * as we want. */
Martin K. Petersena36274e2010-09-10 01:33:59 -04002033 mmc->max_segs = 1024;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02002034
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002035 mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
2036 mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
2037 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2038 mmc->max_seg_size = mmc->max_req_size;
2039
Jarkko Lavinen13189e72009-09-22 16:44:53 -07002040 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
Adrian Hunter93caf8e692010-08-11 14:17:48 -07002041 MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002042
Andreas Fenkart326119c2014-11-08 15:33:14 +01002043 mmc->caps |= mmc_pdata(host)->caps;
Sukumar Ghorai3a638332010-09-15 14:49:23 +00002044 if (mmc->caps & MMC_CAP_8_BIT_DATA)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002045 mmc->caps |= MMC_CAP_4_BIT_DATA;
2046
Andreas Fenkart326119c2014-11-08 15:33:14 +01002047 if (mmc_pdata(host)->nonremovable)
Adrian Hunter23d99bb2009-09-22 16:44:48 -07002048 mmc->caps |= MMC_CAP_NONREMOVABLE;
2049
NeilBrownfdb9de12015-01-13 08:23:18 +13002050 mmc->pm_caps |= mmc_pdata(host)->pm_caps;
Eliad Peller6fdc75d2011-11-22 16:02:18 +02002051
Denis Karpov70a33412009-09-22 16:44:59 -07002052 omap_hsmmc_conf_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002053
Santosh Shilimkar4a29b552013-05-10 17:42:35 +05302054 if (!pdev->dev.of_node) {
2055 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
2056 if (!res) {
2057 dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
2058 ret = -ENXIO;
2059 goto err_irq;
2060 }
2061 tx_req = res->start;
Balaji T Kb7bf7732012-03-07 09:55:30 -05002062
Santosh Shilimkar4a29b552013-05-10 17:42:35 +05302063 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
2064 if (!res) {
2065 dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
2066 ret = -ENXIO;
2067 goto err_irq;
2068 }
2069 rx_req = res->start;
Balaji T Kb7bf7732012-03-07 09:55:30 -05002070 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002071
Russell King26b88522012-04-13 12:27:37 +01002072 dma_cap_zero(mask);
2073 dma_cap_set(DMA_SLAVE, mask);
Russell Kingc5c98922012-04-13 12:14:39 +01002074
Matt Porterd272fbf2013-05-10 17:42:34 +05302075 host->rx_chan =
2076 dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
2077 &rx_req, &pdev->dev, "rx");
2078
Russell King26b88522012-04-13 12:27:37 +01002079 if (!host->rx_chan) {
2080 dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req);
Kevin Hilman04e8c7b2012-07-11 17:51:40 +01002081 ret = -ENXIO;
Russell King26b88522012-04-13 12:27:37 +01002082 goto err_irq;
2083 }
2084
Matt Porterd272fbf2013-05-10 17:42:34 +05302085 host->tx_chan =
2086 dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
2087 &tx_req, &pdev->dev, "tx");
2088
Russell King26b88522012-04-13 12:27:37 +01002089 if (!host->tx_chan) {
2090 dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req);
Kevin Hilman04e8c7b2012-07-11 17:51:40 +01002091 ret = -ENXIO;
Russell King26b88522012-04-13 12:27:37 +01002092 goto err_irq;
Russell Kingc5c98922012-04-13 12:14:39 +01002093 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002094
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002095 /* Request IRQ for MMC operations */
Balaji T Ke1538ed2014-05-09 22:16:49 +05302096 ret = devm_request_irq(&pdev->dev, host->irq, omap_hsmmc_irq, 0,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002097 mmc_hostname(mmc), host);
2098 if (ret) {
Venkatraman Sb1e056a2012-11-19 22:00:00 +05302099 dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002100 goto err_irq;
2101 }
2102
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02002103 if (omap_hsmmc_have_reg()) {
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002104 ret = omap_hsmmc_reg_get(host);
2105 if (ret)
Andreas Fenkartbb09d152014-11-08 15:33:11 +01002106 goto err_irq;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002107 }
2108
Andreas Fenkart326119c2014-11-08 15:33:14 +01002109 mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002110
Adrian Hunterb4175772010-05-26 14:42:06 -07002111 omap_hsmmc_disable_irq(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002112
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002113 /*
2114 * For now, only support SDIO interrupt if we have a separate
2115 * wake-up interrupt configured from device tree. This is because
2116 * the wake-up interrupt is needed for idle state and some
2117 * platforms need special quirks. And we don't want to add new
2118 * legacy mux platform init code callbacks any longer as we
2119 * are moving to DT based booting anyways.
2120 */
2121 ret = omap_hsmmc_configure_wake_irq(host);
2122 if (!ret)
2123 mmc->caps |= MMC_CAP_SDIO_IRQ;
2124
Adrian Hunterb62f6222009-09-22 16:45:01 -07002125 omap_hsmmc_protect_card(host);
2126
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002127 mmc_add_host(mmc);
2128
Andreas Fenkart326119c2014-11-08 15:33:14 +01002129 if (mmc_pdata(host)->name != NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002130 ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
2131 if (ret < 0)
2132 goto err_slot_name;
2133 }
Andreas Fenkartcde592c2015-03-03 13:28:15 +01002134 if (host->get_cover_state) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002135 ret = device_create_file(&mmc->class_dev,
Andreas Fenkartcde592c2015-03-03 13:28:15 +01002136 &dev_attr_cover_switch);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002137 if (ret < 0)
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002138 goto err_slot_name;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002139 }
2140
Denis Karpov70a33412009-09-22 16:44:59 -07002141 omap_hsmmc_debugfs(mmc);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302142 pm_runtime_mark_last_busy(host->dev);
2143 pm_runtime_put_autosuspend(host->dev);
Denis Karpovd900f712009-09-22 16:44:38 -07002144
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002145 return 0;
2146
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002147err_slot_name:
2148 mmc_remove_host(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002149err_irq:
Tony Lindgren5b83b222015-05-21 15:51:52 -07002150 device_init_wakeup(&pdev->dev, false);
Russell Kingc5c98922012-04-13 12:14:39 +01002151 if (host->tx_chan)
2152 dma_release_channel(host->tx_chan);
2153 if (host->rx_chan)
2154 dma_release_channel(host->rx_chan);
Balaji T Kd59d77e2012-02-24 21:14:33 +05302155 pm_runtime_put_sync(host->dev);
Tony Lindgren37f61902012-03-08 23:41:35 -05002156 pm_runtime_disable(host->dev);
Balaji T K96181952014-05-09 22:16:48 +05302157 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05302158 clk_disable_unprepare(host->dbclk);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002159err1:
Andreas Fenkart1e363e32014-11-08 15:33:15 +01002160err_gpio:
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002161 mmc_free_host(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002162err:
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002163 return ret;
2164}
2165
Bill Pemberton6e0ee712012-11-19 13:26:03 -05002166static int omap_hsmmc_remove(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002167{
Denis Karpov70a33412009-09-22 16:44:59 -07002168 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002169
Felipe Balbi927ce942012-03-14 11:18:27 +02002170 pm_runtime_get_sync(host->dev);
2171 mmc_remove_host(host->mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002172
Russell Kingc5c98922012-04-13 12:14:39 +01002173 if (host->tx_chan)
2174 dma_release_channel(host->tx_chan);
2175 if (host->rx_chan)
2176 dma_release_channel(host->rx_chan);
2177
Felipe Balbi927ce942012-03-14 11:18:27 +02002178 pm_runtime_put_sync(host->dev);
2179 pm_runtime_disable(host->dev);
Tony Lindgren5b83b222015-05-21 15:51:52 -07002180 device_init_wakeup(&pdev->dev, false);
Balaji T K96181952014-05-09 22:16:48 +05302181 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05302182 clk_disable_unprepare(host->dbclk);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002183
Balaji T K9d1f0282012-10-15 21:35:07 +05302184 mmc_free_host(host->mmc);
Felipe Balbi927ce942012-03-14 11:18:27 +02002185
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002186 return 0;
2187}
2188
Russ Dill3d3bbfb2015-02-27 13:24:34 +02002189#ifdef CONFIG_PM_SLEEP
Kevin Hilmana791daa2010-05-26 14:42:07 -07002190static int omap_hsmmc_suspend(struct device *dev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002191{
Felipe Balbi927ce942012-03-14 11:18:27 +02002192 struct omap_hsmmc_host *host = dev_get_drvdata(dev);
2193
2194 if (!host)
2195 return 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002196
Felipe Balbi927ce942012-03-14 11:18:27 +02002197 pm_runtime_get_sync(host->dev);
Felipe Balbi927ce942012-03-14 11:18:27 +02002198
2199 if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) {
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002200 OMAP_HSMMC_WRITE(host->base, ISE, 0);
2201 OMAP_HSMMC_WRITE(host->base, IE, 0);
2202 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
Felipe Balbi927ce942012-03-14 11:18:27 +02002203 OMAP_HSMMC_WRITE(host->base, HCTL,
2204 OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
2205 }
2206
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302207 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05302208 clk_disable_unprepare(host->dbclk);
Ulf Hansson3932afd2013-09-25 14:47:06 +02002209
Eliad Peller31f9d462011-11-22 16:02:17 +02002210 pm_runtime_put_sync(host->dev);
Ulf Hansson3932afd2013-09-25 14:47:06 +02002211 return 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002212}
2213
2214/* Routine to resume the MMC device */
Kevin Hilmana791daa2010-05-26 14:42:07 -07002215static int omap_hsmmc_resume(struct device *dev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002216{
Felipe Balbi927ce942012-03-14 11:18:27 +02002217 struct omap_hsmmc_host *host = dev_get_drvdata(dev);
2218
2219 if (!host)
2220 return 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002221
Felipe Balbi927ce942012-03-14 11:18:27 +02002222 pm_runtime_get_sync(host->dev);
Denis Karpov11dd62a2009-09-22 16:44:43 -07002223
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302224 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05302225 clk_prepare_enable(host->dbclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07002226
Felipe Balbi927ce942012-03-14 11:18:27 +02002227 if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
2228 omap_hsmmc_conf_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01002229
Felipe Balbi927ce942012-03-14 11:18:27 +02002230 omap_hsmmc_protect_card(host);
Felipe Balbi927ce942012-03-14 11:18:27 +02002231 pm_runtime_mark_last_busy(host->dev);
2232 pm_runtime_put_autosuspend(host->dev);
Ulf Hansson3932afd2013-09-25 14:47:06 +02002233 return 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002234}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002235#endif
2236
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302237static int omap_hsmmc_runtime_suspend(struct device *dev)
2238{
2239 struct omap_hsmmc_host *host;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002240 unsigned long flags;
Andreas Fenkartf9459012014-05-29 10:28:03 +02002241 int ret = 0;
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302242
2243 host = platform_get_drvdata(to_platform_device(dev));
2244 omap_hsmmc_context_save(host);
Felipe Balbi927ce942012-03-14 11:18:27 +02002245 dev_dbg(dev, "disabled\n");
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302246
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002247 spin_lock_irqsave(&host->irq_lock, flags);
2248 if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) &&
2249 (host->flags & HSMMC_SDIO_IRQ_ENABLED)) {
2250 /* disable sdio irq handling to prevent race */
2251 OMAP_HSMMC_WRITE(host->base, ISE, 0);
2252 OMAP_HSMMC_WRITE(host->base, IE, 0);
Andreas Fenkartf9459012014-05-29 10:28:03 +02002253
2254 if (!(OMAP_HSMMC_READ(host->base, PSTATE) & DLEV_DAT(1))) {
2255 /*
2256 * dat1 line low, pending sdio irq
2257 * race condition: possible irq handler running on
2258 * multi-core, abort
2259 */
2260 dev_dbg(dev, "pending sdio irq, abort suspend\n");
2261 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
2262 OMAP_HSMMC_WRITE(host->base, ISE, CIRQ_EN);
2263 OMAP_HSMMC_WRITE(host->base, IE, CIRQ_EN);
2264 pm_runtime_mark_last_busy(dev);
2265 ret = -EBUSY;
2266 goto abort;
2267 }
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002268
Andreas Fenkart97978a42014-05-29 10:28:04 +02002269 pinctrl_pm_select_idle_state(dev);
Andreas Fenkart97978a42014-05-29 10:28:04 +02002270 } else {
2271 pinctrl_pm_select_idle_state(dev);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002272 }
Andreas Fenkart97978a42014-05-29 10:28:04 +02002273
Andreas Fenkartf9459012014-05-29 10:28:03 +02002274abort:
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002275 spin_unlock_irqrestore(&host->irq_lock, flags);
Andreas Fenkartf9459012014-05-29 10:28:03 +02002276 return ret;
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302277}
2278
2279static int omap_hsmmc_runtime_resume(struct device *dev)
2280{
2281 struct omap_hsmmc_host *host;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002282 unsigned long flags;
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302283
2284 host = platform_get_drvdata(to_platform_device(dev));
2285 omap_hsmmc_context_restore(host);
Felipe Balbi927ce942012-03-14 11:18:27 +02002286 dev_dbg(dev, "enabled\n");
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302287
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002288 spin_lock_irqsave(&host->irq_lock, flags);
2289 if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) &&
2290 (host->flags & HSMMC_SDIO_IRQ_ENABLED)) {
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002291
Andreas Fenkart97978a42014-05-29 10:28:04 +02002292 pinctrl_pm_select_default_state(host->dev);
2293
2294 /* irq lost, if pinmux incorrect */
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002295 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
2296 OMAP_HSMMC_WRITE(host->base, ISE, CIRQ_EN);
2297 OMAP_HSMMC_WRITE(host->base, IE, CIRQ_EN);
Andreas Fenkart97978a42014-05-29 10:28:04 +02002298 } else {
2299 pinctrl_pm_select_default_state(host->dev);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002300 }
2301 spin_unlock_irqrestore(&host->irq_lock, flags);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302302 return 0;
2303}
2304
Kevin Hilmana791daa2010-05-26 14:42:07 -07002305static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
Russ Dill3d3bbfb2015-02-27 13:24:34 +02002306 SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume)
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302307 .runtime_suspend = omap_hsmmc_runtime_suspend,
2308 .runtime_resume = omap_hsmmc_runtime_resume,
Kevin Hilmana791daa2010-05-26 14:42:07 -07002309};
2310
2311static struct platform_driver omap_hsmmc_driver = {
Felipe Balbiefa25fd2012-03-14 11:18:28 +02002312 .probe = omap_hsmmc_probe,
Bill Pemberton0433c142012-11-19 13:20:26 -05002313 .remove = omap_hsmmc_remove,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002314 .driver = {
2315 .name = DRIVER_NAME,
Kevin Hilmana791daa2010-05-26 14:42:07 -07002316 .pm = &omap_hsmmc_dev_pm_ops,
Rajendra Nayak46856a62012-03-12 20:32:37 +05302317 .of_match_table = of_match_ptr(omap_mmc_of_match),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002318 },
2319};
2320
Felipe Balbib7964502012-03-14 11:18:32 +02002321module_platform_driver(omap_hsmmc_driver);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002322MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
2323MODULE_LICENSE("GPL");
2324MODULE_ALIAS("platform:" DRIVER_NAME);
2325MODULE_AUTHOR("Texas Instruments Inc");