blob: 1fad7c746bc3b6fbd1b4b2590e693975ab068b15 [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 Shevchenkoac330f442011-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 Fenkart551434382014-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 Fenkart551434382014-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;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800348
Andreas Fenkartf7f0f032015-07-07 20:38:43 +0200349 if (mmc_pdata(host)->set_power)
350 return 0;
351
Balaji T Kf2ddc1d2014-02-19 20:26:40 +0530352 reg = devm_regulator_get(host->dev, "vmmc");
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800353 if (IS_ERR(reg)) {
Balaji T K987fd492014-02-19 20:26:40 +0530354 dev_err(host->dev, "unable to get vmmc regulator %ld\n",
355 PTR_ERR(reg));
NeilBrown1fdc90f2012-08-08 00:06:00 -0400356 return PTR_ERR(reg);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800357 } else {
358 host->vcc = reg;
kishore kadiyala64be9782010-10-01 16:35:28 -0700359 ocr_value = mmc_regulator_get_ocrmask(reg);
Andreas Fenkart326119c2014-11-08 15:33:14 +0100360 if (!mmc_pdata(host)->ocr_mask) {
361 mmc_pdata(host)->ocr_mask = ocr_value;
kishore kadiyala64be9782010-10-01 16:35:28 -0700362 } else {
Andreas Fenkart326119c2014-11-08 15:33:14 +0100363 if (!(mmc_pdata(host)->ocr_mask & ocr_value)) {
Rajendra Nayak2cecdf02012-02-23 17:02:20 +0530364 dev_err(host->dev, "ocrmask %x is not supported\n",
Andreas Fenkart326119c2014-11-08 15:33:14 +0100365 mmc_pdata(host)->ocr_mask);
366 mmc_pdata(host)->ocr_mask = 0;
kishore kadiyala64be9782010-10-01 16:35:28 -0700367 return -EINVAL;
368 }
369 }
Balaji T K987fd492014-02-19 20:26:40 +0530370 }
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800371
Balaji T K987fd492014-02-19 20:26:40 +0530372 /* Allow an aux regulator */
373 reg = devm_regulator_get_optional(host->dev, "vmmc_aux");
374 host->vcc_aux = IS_ERR(reg) ? NULL : reg;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800375
Balaji T Ke99448f2014-02-19 20:26:40 +0530376 reg = devm_regulator_get_optional(host->dev, "pbias");
377 host->pbias = IS_ERR(reg) ? NULL : reg;
378
Balaji T K987fd492014-02-19 20:26:40 +0530379 /* For eMMC do not power off when not in sleep state */
Andreas Fenkart326119c2014-11-08 15:33:14 +0100380 if (mmc_pdata(host)->no_regulator_off_init)
Balaji T K987fd492014-02-19 20:26:40 +0530381 return 0;
382 /*
383 * To disable boot_on regulator, enable regulator
384 * to increase usecount and then disable it.
385 */
386 if ((host->vcc && regulator_is_enabled(host->vcc) > 0) ||
387 (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
Andreas Fenkart326119c2014-11-08 15:33:14 +0100388 int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1;
Adrian Huntere840ce12011-05-06 12:14:10 +0300389
Andreas Fenkartf7f0f032015-07-07 20:38:43 +0200390 omap_hsmmc_set_power(host->dev, 1, vdd);
391 omap_hsmmc_set_power(host->dev, 0, 0);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800392 }
393
394 return 0;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800395}
396
397static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
398{
Andreas Fenkartf7f0f032015-07-07 20:38:43 +0200399 if (mmc_pdata(host)->set_power)
400 return;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800401}
402
Adrian Hunterb702b102010-02-15 10:03:35 -0800403static inline int omap_hsmmc_have_reg(void)
404{
405 return 1;
406}
407
408#else
409
Andreas Fenkartf7f0f032015-07-07 20:38:43 +0200410static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
411{
412 return 0;
413}
414
Adrian Hunterb702b102010-02-15 10:03:35 -0800415static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
416{
417 return -EINVAL;
418}
419
420static inline void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
421{
422}
423
424static inline int omap_hsmmc_have_reg(void)
425{
426 return 0;
427}
428
429#endif
430
Andreas Fenkartcde592c2015-03-03 13:28:15 +0100431static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id);
NeilBrown41afa3142015-01-13 08:23:18 +1300432
433static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
434 struct omap_hsmmc_host *host,
Andreas Fenkart1e363e32014-11-08 15:33:15 +0100435 struct omap_hsmmc_platform_data *pdata)
Adrian Hunterb702b102010-02-15 10:03:35 -0800436{
437 int ret;
438
Andreas Fenkartb7a56462015-03-20 15:53:54 +0100439 if (gpio_is_valid(pdata->gpio_cod)) {
440 ret = mmc_gpio_request_cd(mmc, pdata->gpio_cod, 0);
Adrian Hunterb702b102010-02-15 10:03:35 -0800441 if (ret)
442 return ret;
Andreas Fenkartcde592c2015-03-03 13:28:15 +0100443
444 host->get_cover_state = omap_hsmmc_get_cover_state;
445 mmc_gpio_set_cd_isr(mmc, omap_hsmmc_cover_irq);
Andreas Fenkartb7a56462015-03-20 15:53:54 +0100446 } else if (gpio_is_valid(pdata->gpio_cd)) {
447 ret = mmc_gpio_request_cd(mmc, pdata->gpio_cd, 0);
Andreas Fenkartcde592c2015-03-03 13:28:15 +0100448 if (ret)
449 return ret;
450
451 host->card_detect = omap_hsmmc_card_detect;
Andreas Fenkart326119c2014-11-08 15:33:14 +0100452 }
Adrian Hunterb702b102010-02-15 10:03:35 -0800453
Andreas Fenkart326119c2014-11-08 15:33:14 +0100454 if (gpio_is_valid(pdata->gpio_wp)) {
NeilBrown41afa3142015-01-13 08:23:18 +1300455 ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp);
Adrian Hunterb702b102010-02-15 10:03:35 -0800456 if (ret)
NeilBrown41afa3142015-01-13 08:23:18 +1300457 return ret;
Andreas Fenkart326119c2014-11-08 15:33:14 +0100458 }
Adrian Hunterb702b102010-02-15 10:03:35 -0800459
460 return 0;
Adrian Hunterb702b102010-02-15 10:03:35 -0800461}
462
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100463/*
Andy Shevchenkoe0c7f992011-05-06 12:14:05 +0300464 * Start clock to the card
465 */
466static void omap_hsmmc_start_clock(struct omap_hsmmc_host *host)
467{
468 OMAP_HSMMC_WRITE(host->base, SYSCTL,
469 OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
470}
471
472/*
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100473 * Stop clock to the card
474 */
Denis Karpov70a33412009-09-22 16:44:59 -0700475static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100476{
477 OMAP_HSMMC_WRITE(host->base, SYSCTL,
478 OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
479 if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
Masanari Iida7122bbb2012-08-05 23:25:40 +0900480 dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stopped\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100481}
482
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700483static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
484 struct mmc_command *cmd)
Adrian Hunterb4175772010-05-26 14:42:06 -0700485{
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200486 u32 irq_mask = INT_EN_MASK;
487 unsigned long flags;
Adrian Hunterb4175772010-05-26 14:42:06 -0700488
489 if (host->use_dma)
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200490 irq_mask &= ~(BRR_EN | BWR_EN);
Adrian Hunterb4175772010-05-26 14:42:06 -0700491
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700492 /* Disable timeout for erases */
493 if (cmd->opcode == MMC_ERASE)
Venkatraman Sa7e96872012-11-19 22:00:01 +0530494 irq_mask &= ~DTO_EN;
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700495
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200496 spin_lock_irqsave(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700497 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
498 OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200499
500 /* latch pending CIRQ, but don't signal MMC core */
501 if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
502 irq_mask |= CIRQ_EN;
Adrian Hunterb4175772010-05-26 14:42:06 -0700503 OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200504 spin_unlock_irqrestore(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700505}
506
507static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
508{
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200509 u32 irq_mask = 0;
510 unsigned long flags;
511
512 spin_lock_irqsave(&host->irq_lock, flags);
513 /* no transfer running but need to keep cirq if enabled */
514 if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
515 irq_mask |= CIRQ_EN;
516 OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
517 OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
Adrian Hunterb4175772010-05-26 14:42:06 -0700518 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200519 spin_unlock_irqrestore(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700520}
521
Andy Shevchenkoac330f442011-05-10 15:51:54 +0300522/* Calculate divisor for the given clock frequency */
Balaji TKd83b6e02011-12-20 15:12:00 +0530523static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios)
Andy Shevchenkoac330f442011-05-10 15:51:54 +0300524{
525 u16 dsor = 0;
526
527 if (ios->clock) {
Balaji TKd83b6e02011-12-20 15:12:00 +0530528 dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock);
Balaji T Ked164182013-10-21 00:25:21 +0530529 if (dsor > CLKD_MAX)
530 dsor = CLKD_MAX;
Andy Shevchenkoac330f442011-05-10 15:51:54 +0300531 }
532
533 return dsor;
534}
535
Andy Shevchenko5934df22011-05-06 12:14:06 +0300536static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
537{
538 struct mmc_ios *ios = &host->mmc->ios;
539 unsigned long regval;
540 unsigned long timeout;
Hebbar, Gururajacd587092012-11-19 21:59:58 +0530541 unsigned long clkdiv;
Andy Shevchenko5934df22011-05-06 12:14:06 +0300542
Venkatraman S8986d312012-08-07 19:10:38 +0530543 dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
Andy Shevchenko5934df22011-05-06 12:14:06 +0300544
545 omap_hsmmc_stop_clock(host);
546
547 regval = OMAP_HSMMC_READ(host->base, SYSCTL);
548 regval = regval & ~(CLKD_MASK | DTO_MASK);
Hebbar, Gururajacd587092012-11-19 21:59:58 +0530549 clkdiv = calc_divisor(host, ios);
550 regval = regval | (clkdiv << 6) | (DTO << 16);
Andy Shevchenko5934df22011-05-06 12:14:06 +0300551 OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
552 OMAP_HSMMC_WRITE(host->base, SYSCTL,
553 OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
554
555 /* Wait till the ICS bit is set */
556 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
557 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
558 && time_before(jiffies, timeout))
559 cpu_relax();
560
Hebbar, Gururajacd587092012-11-19 21:59:58 +0530561 /*
562 * Enable High-Speed Support
563 * Pre-Requisites
564 * - Controller should support High-Speed-Enable Bit
565 * - Controller should not be using DDR Mode
566 * - Controller should advertise that it supports High Speed
567 * in capabilities register
568 * - MMC/SD clock coming out of controller > 25MHz
569 */
Andreas Fenkart326119c2014-11-08 15:33:14 +0100570 if ((mmc_pdata(host)->features & HSMMC_HAS_HSPE_SUPPORT) &&
Seungwon Jeon5438ad92014-03-14 21:12:27 +0900571 (ios->timing != MMC_TIMING_MMC_DDR52) &&
Ulf Hansson903101a2014-11-25 13:05:13 +0100572 (ios->timing != MMC_TIMING_UHS_DDR50) &&
Hebbar, Gururajacd587092012-11-19 21:59:58 +0530573 ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
574 regval = OMAP_HSMMC_READ(host->base, HCTL);
575 if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
576 regval |= HSPE;
577 else
578 regval &= ~HSPE;
579
580 OMAP_HSMMC_WRITE(host->base, HCTL, regval);
581 }
582
Andy Shevchenko5934df22011-05-06 12:14:06 +0300583 omap_hsmmc_start_clock(host);
584}
585
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400586static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
587{
588 struct mmc_ios *ios = &host->mmc->ios;
589 u32 con;
590
591 con = OMAP_HSMMC_READ(host->base, CON);
Ulf Hansson903101a2014-11-25 13:05:13 +0100592 if (ios->timing == MMC_TIMING_MMC_DDR52 ||
593 ios->timing == MMC_TIMING_UHS_DDR50)
Balaji T K03b5d922012-04-09 12:08:33 +0530594 con |= DDR; /* configure in DDR mode */
595 else
596 con &= ~DDR;
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400597 switch (ios->bus_width) {
598 case MMC_BUS_WIDTH_8:
599 OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
600 break;
601 case MMC_BUS_WIDTH_4:
602 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
603 OMAP_HSMMC_WRITE(host->base, HCTL,
604 OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
605 break;
606 case MMC_BUS_WIDTH_1:
607 OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
608 OMAP_HSMMC_WRITE(host->base, HCTL,
609 OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
610 break;
611 }
612}
613
614static void omap_hsmmc_set_bus_mode(struct omap_hsmmc_host *host)
615{
616 struct mmc_ios *ios = &host->mmc->ios;
617 u32 con;
618
619 con = OMAP_HSMMC_READ(host->base, CON);
620 if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
621 OMAP_HSMMC_WRITE(host->base, CON, con | OD);
622 else
623 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
624}
625
Denis Karpov11dd62a2009-09-22 16:44:43 -0700626#ifdef CONFIG_PM
627
628/*
629 * Restore the MMC host context, if it was lost as result of a
630 * power state change.
631 */
Denis Karpov70a33412009-09-22 16:44:59 -0700632static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700633{
634 struct mmc_ios *ios = &host->mmc->ios;
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400635 u32 hctl, capa;
Denis Karpov11dd62a2009-09-22 16:44:43 -0700636 unsigned long timeout;
637
Tony Lindgren0a82e062013-10-21 00:25:19 +0530638 if (host->con == OMAP_HSMMC_READ(host->base, CON) &&
639 host->hctl == OMAP_HSMMC_READ(host->base, HCTL) &&
640 host->sysctl == OMAP_HSMMC_READ(host->base, SYSCTL) &&
641 host->capa == OMAP_HSMMC_READ(host->base, CAPA))
642 return 0;
643
644 host->context_loss++;
645
Balaji T Kc2200ef2012-03-07 09:55:30 -0500646 if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
Denis Karpov11dd62a2009-09-22 16:44:43 -0700647 if (host->power_mode != MMC_POWER_OFF &&
648 (1 << ios->vdd) <= MMC_VDD_23_24)
649 hctl = SDVS18;
650 else
651 hctl = SDVS30;
652 capa = VS30 | VS18;
653 } else {
654 hctl = SDVS18;
655 capa = VS18;
656 }
657
Balaji T K5a52b082014-05-29 10:28:02 +0200658 if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
659 hctl |= IWE;
660
Denis Karpov11dd62a2009-09-22 16:44:43 -0700661 OMAP_HSMMC_WRITE(host->base, HCTL,
662 OMAP_HSMMC_READ(host->base, HCTL) | hctl);
663
664 OMAP_HSMMC_WRITE(host->base, CAPA,
665 OMAP_HSMMC_READ(host->base, CAPA) | capa);
666
667 OMAP_HSMMC_WRITE(host->base, HCTL,
668 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
669
670 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
671 while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP
672 && time_before(jiffies, timeout))
673 ;
674
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +0200675 OMAP_HSMMC_WRITE(host->base, ISE, 0);
676 OMAP_HSMMC_WRITE(host->base, IE, 0);
677 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700678
679 /* Do not initialize card-specific things if the power is off */
680 if (host->power_mode == MMC_POWER_OFF)
681 goto out;
682
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400683 omap_hsmmc_set_bus_width(host);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700684
Andy Shevchenko5934df22011-05-06 12:14:06 +0300685 omap_hsmmc_set_clock(host);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700686
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -0400687 omap_hsmmc_set_bus_mode(host);
688
Denis Karpov11dd62a2009-09-22 16:44:43 -0700689out:
Tony Lindgren0a82e062013-10-21 00:25:19 +0530690 dev_dbg(mmc_dev(host->mmc), "context is restored: restore count %d\n",
691 host->context_loss);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700692 return 0;
693}
694
695/*
696 * Save the MMC host context (store the number of power state changes so far).
697 */
Denis Karpov70a33412009-09-22 16:44:59 -0700698static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700699{
Tony Lindgren0a82e062013-10-21 00:25:19 +0530700 host->con = OMAP_HSMMC_READ(host->base, CON);
701 host->hctl = OMAP_HSMMC_READ(host->base, HCTL);
702 host->sysctl = OMAP_HSMMC_READ(host->base, SYSCTL);
703 host->capa = OMAP_HSMMC_READ(host->base, CAPA);
Denis Karpov11dd62a2009-09-22 16:44:43 -0700704}
705
706#else
707
Denis Karpov70a33412009-09-22 16:44:59 -0700708static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700709{
710 return 0;
711}
712
Denis Karpov70a33412009-09-22 16:44:59 -0700713static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
Denis Karpov11dd62a2009-09-22 16:44:43 -0700714{
715}
716
717#endif
718
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100719/*
720 * Send init stream sequence to card
721 * before sending IDLE command
722 */
Denis Karpov70a33412009-09-22 16:44:59 -0700723static void send_init_stream(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100724{
725 int reg = 0;
726 unsigned long timeout;
727
Adrian Hunterb62f6222009-09-22 16:45:01 -0700728 if (host->protect_card)
729 return;
730
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100731 disable_irq(host->irq);
Adrian Hunterb4175772010-05-26 14:42:06 -0700732
733 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100734 OMAP_HSMMC_WRITE(host->base, CON,
735 OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
736 OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
737
738 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
Venkatraman Sa7e96872012-11-19 22:00:01 +0530739 while ((reg != CC_EN) && time_before(jiffies, timeout))
740 reg = OMAP_HSMMC_READ(host->base, STAT) & CC_EN;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100741
742 OMAP_HSMMC_WRITE(host->base, CON,
743 OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
Adrian Hunterc653a6d2009-09-22 16:44:56 -0700744
745 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
746 OMAP_HSMMC_READ(host->base, STAT);
747
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100748 enable_irq(host->irq);
749}
750
751static inline
Denis Karpov70a33412009-09-22 16:44:59 -0700752int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100753{
754 int r = 1;
755
Andreas Fenkartb5cd43f2014-11-08 15:33:16 +0100756 if (host->get_cover_state)
Andreas Fenkart80412ca2014-11-08 15:33:17 +0100757 r = host->get_cover_state(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100758 return r;
759}
760
761static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700762omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100763 char *buf)
764{
765 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700766 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100767
Denis Karpov70a33412009-09-22 16:44:59 -0700768 return sprintf(buf, "%s\n",
769 omap_hsmmc_cover_is_closed(host) ? "closed" : "open");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100770}
771
Denis Karpov70a33412009-09-22 16:44:59 -0700772static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100773
774static ssize_t
Denis Karpov70a33412009-09-22 16:44:59 -0700775omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100776 char *buf)
777{
778 struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
Denis Karpov70a33412009-09-22 16:44:59 -0700779 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100780
Andreas Fenkart326119c2014-11-08 15:33:14 +0100781 return sprintf(buf, "%s\n", mmc_pdata(host)->name);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100782}
783
Denis Karpov70a33412009-09-22 16:44:59 -0700784static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100785
786/*
787 * Configure the response type and send the cmd.
788 */
789static void
Denis Karpov70a33412009-09-22 16:44:59 -0700790omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100791 struct mmc_data *data)
792{
793 int cmdreg = 0, resptype = 0, cmdtype = 0;
794
Venkatraman S8986d312012-08-07 19:10:38 +0530795 dev_vdbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100796 mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
797 host->cmd = cmd;
798
Adrian Hunter93caf8e692010-08-11 14:17:48 -0700799 omap_hsmmc_enable_irq(host, cmd);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100800
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200801 host->response_busy = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100802 if (cmd->flags & MMC_RSP_PRESENT) {
803 if (cmd->flags & MMC_RSP_136)
804 resptype = 1;
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200805 else if (cmd->flags & MMC_RSP_BUSY) {
806 resptype = 3;
807 host->response_busy = 1;
808 } else
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100809 resptype = 2;
810 }
811
812 /*
813 * Unlike OMAP1 controller, the cmdtype does not seem to be based on
814 * ac, bc, adtc, bcr. Only commands ending an open ended transfer need
815 * a val of 0x3, rest 0x0.
816 */
817 if (cmd == host->mrq->stop)
818 cmdtype = 0x3;
819
820 cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
821
Balaji T Ka2e77152014-01-21 19:54:42 +0530822 if ((host->flags & AUTO_CMD23) && mmc_op_multi(cmd->opcode) &&
823 host->mrq->sbc) {
824 cmdreg |= ACEN_ACMD23;
825 OMAP_HSMMC_WRITE(host->base, SDMASA, host->mrq->sbc->arg);
826 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100827 if (data) {
828 cmdreg |= DP_SELECT | MSBS | BCE;
829 if (data->flags & MMC_DATA_READ)
830 cmdreg |= DDIR;
831 else
832 cmdreg &= ~(DDIR);
833 }
834
835 if (host->use_dma)
Venkatraman Sa7e96872012-11-19 22:00:01 +0530836 cmdreg |= DMAE;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100837
Adrian Hunterb4175772010-05-26 14:42:06 -0700838 host->req_in_progress = 1;
Adrian Hunter4dffd7a2009-09-22 16:44:58 -0700839
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100840 OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
841 OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
842}
843
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200844static int
Denis Karpov70a33412009-09-22 16:44:59 -0700845omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
Juha Yrjola0ccd76d2008-11-14 15:22:00 +0200846{
847 if (data->flags & MMC_DATA_WRITE)
848 return DMA_TO_DEVICE;
849 else
850 return DMA_FROM_DEVICE;
851}
852
Russell Kingc5c98922012-04-13 12:14:39 +0100853static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host,
854 struct mmc_data *data)
855{
856 return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
857}
858
Adrian Hunterb4175772010-05-26 14:42:06 -0700859static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
860{
861 int dma_ch;
Venkatraman S31463b12012-04-09 12:08:34 +0530862 unsigned long flags;
Adrian Hunterb4175772010-05-26 14:42:06 -0700863
Venkatraman S31463b12012-04-09 12:08:34 +0530864 spin_lock_irqsave(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700865 host->req_in_progress = 0;
866 dma_ch = host->dma_ch;
Venkatraman S31463b12012-04-09 12:08:34 +0530867 spin_unlock_irqrestore(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700868
869 omap_hsmmc_disable_irq(host);
870 /* Do not complete the request if DMA is still in progress */
871 if (mrq->data && host->use_dma && dma_ch != -1)
872 return;
873 host->mrq = NULL;
874 mmc_request_done(host->mmc, mrq);
NeilBrownf57ba4c2015-03-26 12:18:23 +1100875 pm_runtime_mark_last_busy(host->dev);
876 pm_runtime_put_autosuspend(host->dev);
Adrian Hunterb4175772010-05-26 14:42:06 -0700877}
878
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100879/*
880 * Notify the transfer complete to MMC core
881 */
882static void
Denis Karpov70a33412009-09-22 16:44:59 -0700883omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100884{
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200885 if (!data) {
886 struct mmc_request *mrq = host->mrq;
887
Adrian Hunter23050102009-09-22 16:44:57 -0700888 /* TC before CC from CMD6 - don't know why, but it happens */
889 if (host->cmd && host->cmd->opcode == 6 &&
890 host->response_busy) {
891 host->response_busy = 0;
892 return;
893 }
894
Adrian Hunterb4175772010-05-26 14:42:06 -0700895 omap_hsmmc_request_done(host, mrq);
Adrian Hunter4a694dc2009-01-12 16:13:08 +0200896 return;
897 }
898
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100899 host->data = NULL;
900
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100901 if (!data->error)
902 data->bytes_xfered += data->blocks * (data->blksz);
903 else
904 data->bytes_xfered = 0;
905
Balaji T Kbf129e12014-01-21 19:54:42 +0530906 if (data->stop && (data->error || !host->mrq->sbc))
907 omap_hsmmc_start_command(host, data->stop, NULL);
908 else
Adrian Hunterb4175772010-05-26 14:42:06 -0700909 omap_hsmmc_request_done(host, data->mrq);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100910}
911
912/*
913 * Notify the core about command completion
914 */
915static void
Denis Karpov70a33412009-09-22 16:44:59 -0700916omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100917{
Balaji T Kbf129e12014-01-21 19:54:42 +0530918 if (host->mrq->sbc && (host->cmd == host->mrq->sbc) &&
Balaji T Ka2e77152014-01-21 19:54:42 +0530919 !host->mrq->sbc->error && !(host->flags & AUTO_CMD23)) {
Balaji T K2177fa92014-05-09 22:16:52 +0530920 host->cmd = NULL;
Balaji T Kbf129e12014-01-21 19:54:42 +0530921 omap_hsmmc_start_dma_transfer(host);
922 omap_hsmmc_start_command(host, host->mrq->cmd,
923 host->mrq->data);
924 return;
925 }
926
Balaji T K2177fa92014-05-09 22:16:52 +0530927 host->cmd = NULL;
928
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100929 if (cmd->flags & MMC_RSP_PRESENT) {
930 if (cmd->flags & MMC_RSP_136) {
931 /* response type 2 */
932 cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
933 cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
934 cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
935 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
936 } else {
937 /* response types 1, 1b, 3, 4, 5, 6 */
938 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
939 }
940 }
Adrian Hunterb4175772010-05-26 14:42:06 -0700941 if ((host->data == NULL && !host->response_busy) || cmd->error)
Balaji T Kd4b2c372014-01-21 19:54:42 +0530942 omap_hsmmc_request_done(host, host->mrq);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100943}
944
945/*
946 * DMA clean up for command errors
947 */
Denis Karpov70a33412009-09-22 16:44:59 -0700948static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100949{
Adrian Hunterb4175772010-05-26 14:42:06 -0700950 int dma_ch;
Venkatraman S31463b12012-04-09 12:08:34 +0530951 unsigned long flags;
Adrian Hunterb4175772010-05-26 14:42:06 -0700952
Jarkko Lavinen82788ff2008-12-05 12:31:46 +0200953 host->data->error = errno;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100954
Venkatraman S31463b12012-04-09 12:08:34 +0530955 spin_lock_irqsave(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700956 dma_ch = host->dma_ch;
957 host->dma_ch = -1;
Venkatraman S31463b12012-04-09 12:08:34 +0530958 spin_unlock_irqrestore(&host->irq_lock, flags);
Adrian Hunterb4175772010-05-26 14:42:06 -0700959
960 if (host->use_dma && dma_ch != -1) {
Russell Kingc5c98922012-04-13 12:14:39 +0100961 struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host->data);
962
963 dmaengine_terminate_all(chan);
964 dma_unmap_sg(chan->device->dev,
965 host->data->sg, host->data->sg_len,
Denis Karpov70a33412009-09-22 16:44:59 -0700966 omap_hsmmc_get_dma_dir(host, host->data));
Russell Kingc5c98922012-04-13 12:14:39 +0100967
Per Forlin053bf342011-11-07 21:55:11 +0530968 host->data->host_cookie = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100969 }
970 host->data = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100971}
972
973/*
974 * Readable error output
975 */
976#ifdef CONFIG_MMC_DEBUG
Adrian Hunter699b9582011-05-06 12:14:01 +0300977static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100978{
979 /* --- means reserved bit without definition at documentation */
Denis Karpov70a33412009-09-22 16:44:59 -0700980 static const char *omap_hsmmc_status_bits[] = {
Adrian Hunter699b9582011-05-06 12:14:01 +0300981 "CC" , "TC" , "BGE", "---", "BWR" , "BRR" , "---" , "---" ,
982 "CIRQ", "OBI" , "---", "---", "---" , "---" , "---" , "ERRI",
983 "CTO" , "CCRC", "CEB", "CIE", "DTO" , "DCRC", "DEB" , "---" ,
984 "ACE" , "---" , "---", "---", "CERR", "BADA", "---" , "---"
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100985 };
986 char res[256];
987 char *buf = res;
988 int len, i;
989
990 len = sprintf(buf, "MMC IRQ 0x%x :", status);
991 buf += len;
992
Denis Karpov70a33412009-09-22 16:44:59 -0700993 for (i = 0; i < ARRAY_SIZE(omap_hsmmc_status_bits); i++)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100994 if (status & (1 << i)) {
Denis Karpov70a33412009-09-22 16:44:59 -0700995 len = sprintf(buf, " %s", omap_hsmmc_status_bits[i]);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +0100996 buf += len;
997 }
998
Venkatraman S8986d312012-08-07 19:10:38 +0530999 dev_vdbg(mmc_dev(host->mmc), "%s\n", res);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001000}
Adrian Hunter699b9582011-05-06 12:14:01 +03001001#else
1002static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host,
1003 u32 status)
1004{
1005}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001006#endif /* CONFIG_MMC_DEBUG */
1007
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001008/*
1009 * MMC controller internal state machines reset
1010 *
1011 * Used to reset command or data internal state machines, using respectively
1012 * SRC or SRD bit of SYSCTL register
1013 * Can be called from interrupt context
1014 */
Denis Karpov70a33412009-09-22 16:44:59 -07001015static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
1016 unsigned long bit)
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001017{
1018 unsigned long i = 0;
Jianpeng Ma1e881782013-10-21 00:25:20 +05301019 unsigned long limit = MMC_TIMEOUT_US;
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001020
1021 OMAP_HSMMC_WRITE(host->base, SYSCTL,
1022 OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
1023
Madhusudhan Chikkature07ad64b2010-10-01 16:35:25 -07001024 /*
1025 * OMAP4 ES2 and greater has an updated reset logic.
1026 * Monitor a 0->1 transition first
1027 */
Andreas Fenkart326119c2014-11-08 15:33:14 +01001028 if (mmc_pdata(host)->features & HSMMC_HAS_UPDATED_RESET) {
kishore kadiyalab432b4b2010-11-17 22:35:32 -05001029 while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
Madhusudhan Chikkature07ad64b2010-10-01 16:35:25 -07001030 && (i++ < limit))
Jianpeng Ma1e881782013-10-21 00:25:20 +05301031 udelay(1);
Madhusudhan Chikkature07ad64b2010-10-01 16:35:25 -07001032 }
1033 i = 0;
1034
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001035 while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
1036 (i++ < limit))
Jianpeng Ma1e881782013-10-21 00:25:20 +05301037 udelay(1);
Jean Pihet3ebf74b2009-02-06 16:42:51 +01001038
1039 if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
1040 dev_err(mmc_dev(host->mmc),
1041 "Timeout waiting on controller reset in %s\n",
1042 __func__);
1043}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001044
Balaji T K25e18972012-11-19 21:59:55 +05301045static void hsmmc_command_incomplete(struct omap_hsmmc_host *host,
1046 int err, int end_cmd)
Venkatraman Sae4bf782012-08-09 20:36:07 +05301047{
Balaji T K25e18972012-11-19 21:59:55 +05301048 if (end_cmd) {
Balaji T K94d4f272012-11-19 21:59:56 +05301049 omap_hsmmc_reset_controller_fsm(host, SRC);
Balaji T K25e18972012-11-19 21:59:55 +05301050 if (host->cmd)
1051 host->cmd->error = err;
1052 }
Venkatraman Sae4bf782012-08-09 20:36:07 +05301053
1054 if (host->data) {
1055 omap_hsmmc_reset_controller_fsm(host, SRD);
1056 omap_hsmmc_dma_cleanup(host, err);
Balaji T Kdc7745b2012-11-19 21:59:57 +05301057 } else if (host->mrq && host->mrq->cmd)
1058 host->mrq->cmd->error = err;
Venkatraman Sae4bf782012-08-09 20:36:07 +05301059}
1060
Adrian Hunterb4175772010-05-26 14:42:06 -07001061static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001062{
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001063 struct mmc_data *data;
Adrian Hunterb4175772010-05-26 14:42:06 -07001064 int end_cmd = 0, end_trans = 0;
Balaji T Ka2e77152014-01-21 19:54:42 +05301065 int error = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001066
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001067 data = host->data;
Venkatraman S8986d312012-08-07 19:10:38 +05301068 dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001069
Venkatraman Sa7e96872012-11-19 22:00:01 +05301070 if (status & ERR_EN) {
Adrian Hunter699b9582011-05-06 12:14:01 +03001071 omap_hsmmc_dbg_report_irq(host, status);
Adrian Hunter4a694dc2009-01-12 16:13:08 +02001072
Venkatraman Sa7e96872012-11-19 22:00:01 +05301073 if (status & (CTO_EN | CCRC_EN))
Balaji T K25e18972012-11-19 21:59:55 +05301074 end_cmd = 1;
Kishon Vijay Abraham I408806f2015-06-16 16:07:17 +05301075 if (host->data || host->response_busy) {
1076 end_trans = !end_cmd;
1077 host->response_busy = 0;
1078 }
Venkatraman Sa7e96872012-11-19 22:00:01 +05301079 if (status & (CTO_EN | DTO_EN))
Balaji T K25e18972012-11-19 21:59:55 +05301080 hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd);
Vignesh R5027cd12015-06-16 16:07:18 +05301081 else if (status & (CCRC_EN | DCRC_EN | DEB_EN | CEB_EN |
1082 BADA_EN))
Balaji T K25e18972012-11-19 21:59:55 +05301083 hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
1084
Balaji T Ka2e77152014-01-21 19:54:42 +05301085 if (status & ACE_EN) {
1086 u32 ac12;
1087 ac12 = OMAP_HSMMC_READ(host->base, AC12);
1088 if (!(ac12 & ACNE) && host->mrq->sbc) {
1089 end_cmd = 1;
1090 if (ac12 & ACTO)
1091 error = -ETIMEDOUT;
1092 else if (ac12 & (ACCE | ACEB | ACIE))
1093 error = -EILSEQ;
1094 host->mrq->sbc->error = error;
1095 hsmmc_command_incomplete(host, error, end_cmd);
1096 }
1097 dev_dbg(mmc_dev(host->mmc), "AC12 err: 0x%x\n", ac12);
1098 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001099 }
1100
Francesco Lavra7472bab2013-06-29 08:25:12 +02001101 OMAP_HSMMC_WRITE(host->base, STAT, status);
Venkatraman Sa7e96872012-11-19 22:00:01 +05301102 if (end_cmd || ((status & CC_EN) && host->cmd))
Denis Karpov70a33412009-09-22 16:44:59 -07001103 omap_hsmmc_cmd_done(host, host->cmd);
Venkatraman Sa7e96872012-11-19 22:00:01 +05301104 if ((end_trans || (status & TC_EN)) && host->mrq)
Denis Karpov70a33412009-09-22 16:44:59 -07001105 omap_hsmmc_xfer_done(host, data);
Adrian Hunterb4175772010-05-26 14:42:06 -07001106}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001107
Adrian Hunterb4175772010-05-26 14:42:06 -07001108/*
1109 * MMC controller IRQ handler
1110 */
1111static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
1112{
1113 struct omap_hsmmc_host *host = dev_id;
1114 int status;
1115
1116 status = OMAP_HSMMC_READ(host->base, STAT);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001117 while (status & (INT_EN_MASK | CIRQ_EN)) {
1118 if (host->req_in_progress)
1119 omap_hsmmc_do_irq(host, status);
1120
1121 if (status & CIRQ_EN)
1122 mmc_signal_sdio_irq(host->mmc);
Venkatraman S1f6b9fa2012-08-08 15:44:29 +05301123
Adrian Hunterb4175772010-05-26 14:42:06 -07001124 /* Flush posted write */
1125 status = OMAP_HSMMC_READ(host->base, STAT);
Venkatraman S1f6b9fa2012-08-08 15:44:29 +05301126 }
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001127
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001128 return IRQ_HANDLED;
1129}
1130
Denis Karpov70a33412009-09-22 16:44:59 -07001131static void set_sd_bus_power(struct omap_hsmmc_host *host)
Adrian Huntere13bb302009-03-12 17:08:26 +02001132{
1133 unsigned long i;
1134
1135 OMAP_HSMMC_WRITE(host->base, HCTL,
1136 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
1137 for (i = 0; i < loops_per_jiffy; i++) {
1138 if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
1139 break;
1140 cpu_relax();
1141 }
1142}
1143
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001144/*
David Brownelleb250822009-02-17 14:49:01 -08001145 * Switch MMC interface voltage ... only relevant for MMC1.
1146 *
1147 * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
1148 * The MMC2 transceiver controls are used instead of DAT4..DAT7.
1149 * Some chips, like eMMC ones, use internal transceivers.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001150 */
Denis Karpov70a33412009-09-22 16:44:59 -07001151static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001152{
1153 u32 reg_val = 0;
1154 int ret;
1155
1156 /* Disable the clocks */
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301157 pm_runtime_put_sync(host->dev);
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05301158 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05301159 clk_disable_unprepare(host->dbclk);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001160
1161 /* Turn the power off */
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02001162 ret = omap_hsmmc_set_power(host->dev, 0, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001163
1164 /* Turn the power ON with given VDD 1.8 or 3.0v */
Adrian Hunter2bec0892009-09-22 16:45:02 -07001165 if (!ret)
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02001166 ret = omap_hsmmc_set_power(host->dev, 1, vdd);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301167 pm_runtime_get_sync(host->dev);
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05301168 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05301169 clk_prepare_enable(host->dbclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07001170
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001171 if (ret != 0)
1172 goto err;
1173
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001174 OMAP_HSMMC_WRITE(host->base, HCTL,
1175 OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
1176 reg_val = OMAP_HSMMC_READ(host->base, HCTL);
David Brownelleb250822009-02-17 14:49:01 -08001177
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001178 /*
1179 * If a MMC dual voltage card is detected, the set_ios fn calls
1180 * this fn with VDD bit set for 1.8V. Upon card removal from the
Denis Karpov70a33412009-09-22 16:44:59 -07001181 * slot, omap_hsmmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001182 *
David Brownelleb250822009-02-17 14:49:01 -08001183 * Cope with a bit of slop in the range ... per data sheets:
1184 * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
1185 * but recommended values are 1.71V to 1.89V
1186 * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
1187 * but recommended values are 2.7V to 3.3V
1188 *
1189 * Board setup code shouldn't permit anything very out-of-range.
1190 * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
1191 * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001192 */
David Brownelleb250822009-02-17 14:49:01 -08001193 if ((1 << vdd) <= MMC_VDD_23_24)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001194 reg_val |= SDVS18;
David Brownelleb250822009-02-17 14:49:01 -08001195 else
1196 reg_val |= SDVS30;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001197
1198 OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
Adrian Huntere13bb302009-03-12 17:08:26 +02001199 set_sd_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001200
1201 return 0;
1202err:
Venkatraman Sb1e056a2012-11-19 22:00:00 +05301203 dev_err(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001204 return ret;
1205}
1206
Adrian Hunterb62f6222009-09-22 16:45:01 -07001207/* Protect the card while the cover is open */
1208static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
1209{
Andreas Fenkartb5cd43f2014-11-08 15:33:16 +01001210 if (!host->get_cover_state)
Adrian Hunterb62f6222009-09-22 16:45:01 -07001211 return;
1212
1213 host->reqs_blocked = 0;
Andreas Fenkart80412ca2014-11-08 15:33:17 +01001214 if (host->get_cover_state(host->dev)) {
Adrian Hunterb62f6222009-09-22 16:45:01 -07001215 if (host->protect_card) {
Rajendra Nayak2cecdf02012-02-23 17:02:20 +05301216 dev_info(host->dev, "%s: cover is closed, "
Adrian Hunterb62f6222009-09-22 16:45:01 -07001217 "card is now accessible\n",
1218 mmc_hostname(host->mmc));
1219 host->protect_card = 0;
1220 }
1221 } else {
1222 if (!host->protect_card) {
Rajendra Nayak2cecdf02012-02-23 17:02:20 +05301223 dev_info(host->dev, "%s: cover is open, "
Adrian Hunterb62f6222009-09-22 16:45:01 -07001224 "card is now inaccessible\n",
1225 mmc_hostname(host->mmc));
1226 host->protect_card = 1;
1227 }
1228 }
1229}
1230
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001231/*
Andreas Fenkartcde592c2015-03-03 13:28:15 +01001232 * irq handler when (cell-phone) cover is mounted/removed
1233 */
1234static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id)
1235{
1236 struct omap_hsmmc_host *host = dev_id;
Andreas Fenkartcde592c2015-03-03 13:28:15 +01001237
1238 sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
1239
Andreas Fenkart11227d12015-03-03 13:28:17 +01001240 omap_hsmmc_protect_card(host);
1241 mmc_detect_change(host->mmc, (HZ * 200) / 1000);
Andreas Fenkartcde592c2015-03-03 13:28:15 +01001242 return IRQ_HANDLED;
1243}
1244
Russell Kingc5c98922012-04-13 12:14:39 +01001245static void omap_hsmmc_dma_callback(void *param)
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001246{
Russell Kingc5c98922012-04-13 12:14:39 +01001247 struct omap_hsmmc_host *host = param;
1248 struct dma_chan *chan;
Adrian Hunter770d7432011-05-06 12:14:11 +03001249 struct mmc_data *data;
Russell Kingc5c98922012-04-13 12:14:39 +01001250 int req_in_progress;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001251
Russell Kingc5c98922012-04-13 12:14:39 +01001252 spin_lock_irq(&host->irq_lock);
Adrian Hunterb4175772010-05-26 14:42:06 -07001253 if (host->dma_ch < 0) {
Russell Kingc5c98922012-04-13 12:14:39 +01001254 spin_unlock_irq(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001255 return;
Adrian Hunterb4175772010-05-26 14:42:06 -07001256 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001257
Adrian Hunter770d7432011-05-06 12:14:11 +03001258 data = host->mrq->data;
Russell Kingc5c98922012-04-13 12:14:39 +01001259 chan = omap_hsmmc_get_dma_chan(host, data);
Per Forlin9782aff2011-07-01 18:55:23 +02001260 if (!data->host_cookie)
Russell Kingc5c98922012-04-13 12:14:39 +01001261 dma_unmap_sg(chan->device->dev,
1262 data->sg, data->sg_len,
Per Forlin9782aff2011-07-01 18:55:23 +02001263 omap_hsmmc_get_dma_dir(host, data));
Adrian Hunterb4175772010-05-26 14:42:06 -07001264
1265 req_in_progress = host->req_in_progress;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001266 host->dma_ch = -1;
Russell Kingc5c98922012-04-13 12:14:39 +01001267 spin_unlock_irq(&host->irq_lock);
Adrian Hunterb4175772010-05-26 14:42:06 -07001268
1269 /* If DMA has finished after TC, complete the request */
1270 if (!req_in_progress) {
1271 struct mmc_request *mrq = host->mrq;
1272
1273 host->mrq = NULL;
1274 mmc_request_done(host->mmc, mrq);
NeilBrownf57ba4c2015-03-26 12:18:23 +11001275 pm_runtime_mark_last_busy(host->dev);
1276 pm_runtime_put_autosuspend(host->dev);
Adrian Hunterb4175772010-05-26 14:42:06 -07001277 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001278}
1279
Per Forlin9782aff2011-07-01 18:55:23 +02001280static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
1281 struct mmc_data *data,
Russell Kingc5c98922012-04-13 12:14:39 +01001282 struct omap_hsmmc_next *next,
Russell King26b88522012-04-13 12:27:37 +01001283 struct dma_chan *chan)
Per Forlin9782aff2011-07-01 18:55:23 +02001284{
1285 int dma_len;
1286
1287 if (!next && data->host_cookie &&
1288 data->host_cookie != host->next_data.cookie) {
Rajendra Nayak2cecdf02012-02-23 17:02:20 +05301289 dev_warn(host->dev, "[%s] invalid cookie: data->host_cookie %d"
Per Forlin9782aff2011-07-01 18:55:23 +02001290 " host->next_data.cookie %d\n",
1291 __func__, data->host_cookie, host->next_data.cookie);
1292 data->host_cookie = 0;
1293 }
1294
1295 /* Check if next job is already prepared */
Dan Carpenterb38313d2014-01-30 15:15:18 +03001296 if (next || data->host_cookie != host->next_data.cookie) {
Russell King26b88522012-04-13 12:27:37 +01001297 dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
Per Forlin9782aff2011-07-01 18:55:23 +02001298 omap_hsmmc_get_dma_dir(host, data));
1299
1300 } else {
1301 dma_len = host->next_data.dma_len;
1302 host->next_data.dma_len = 0;
1303 }
1304
1305
1306 if (dma_len == 0)
1307 return -EINVAL;
1308
1309 if (next) {
1310 next->dma_len = dma_len;
1311 data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
1312 } else
1313 host->dma_len = dma_len;
1314
1315 return 0;
1316}
1317
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001318/*
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001319 * Routine to configure and start DMA for the MMC card
1320 */
Balaji T K9d025332014-01-21 19:54:42 +05301321static int omap_hsmmc_setup_dma_transfer(struct omap_hsmmc_host *host,
Denis Karpov70a33412009-09-22 16:44:59 -07001322 struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001323{
Russell King26b88522012-04-13 12:27:37 +01001324 struct dma_slave_config cfg;
1325 struct dma_async_tx_descriptor *tx;
1326 int ret = 0, i;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001327 struct mmc_data *data = req->data;
Russell Kingc5c98922012-04-13 12:14:39 +01001328 struct dma_chan *chan;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001329
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001330 /* Sanity check: all the SG entries must be aligned by block size. */
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001331 for (i = 0; i < data->sg_len; i++) {
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02001332 struct scatterlist *sgl;
1333
1334 sgl = data->sg + i;
1335 if (sgl->length % data->blksz)
1336 return -EINVAL;
1337 }
1338 if ((data->blksz % 4) != 0)
1339 /* REVISIT: The MMC buffer increments only when MSB is written.
1340 * Return error for blksz which is non multiple of four.
1341 */
1342 return -EINVAL;
1343
Adrian Hunterb4175772010-05-26 14:42:06 -07001344 BUG_ON(host->dma_ch != -1);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001345
Russell Kingc5c98922012-04-13 12:14:39 +01001346 chan = omap_hsmmc_get_dma_chan(host, data);
Russell Kingc5c98922012-04-13 12:14:39 +01001347
Russell King26b88522012-04-13 12:27:37 +01001348 cfg.src_addr = host->mapbase + OMAP_HSMMC_DATA;
1349 cfg.dst_addr = host->mapbase + OMAP_HSMMC_DATA;
1350 cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1351 cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1352 cfg.src_maxburst = data->blksz / 4;
1353 cfg.dst_maxburst = data->blksz / 4;
Russell Kingc5c98922012-04-13 12:14:39 +01001354
Russell King26b88522012-04-13 12:27:37 +01001355 ret = dmaengine_slave_config(chan, &cfg);
Per Forlin9782aff2011-07-01 18:55:23 +02001356 if (ret)
1357 return ret;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001358
Russell King26b88522012-04-13 12:27:37 +01001359 ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, chan);
1360 if (ret)
1361 return ret;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001362
Russell King26b88522012-04-13 12:27:37 +01001363 tx = dmaengine_prep_slave_sg(chan, data->sg, data->sg_len,
1364 data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
1365 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
1366 if (!tx) {
1367 dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
1368 /* FIXME: cleanup */
1369 return -1;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001370 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001371
Russell King26b88522012-04-13 12:27:37 +01001372 tx->callback = omap_hsmmc_dma_callback;
1373 tx->callback_param = host;
1374
1375 /* Does not fail */
1376 dmaengine_submit(tx);
1377
1378 host->dma_ch = 1;
1379
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001380 return 0;
1381}
1382
Denis Karpov70a33412009-09-22 16:44:59 -07001383static void set_data_timeout(struct omap_hsmmc_host *host,
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001384 unsigned int timeout_ns,
1385 unsigned int timeout_clks)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001386{
1387 unsigned int timeout, cycle_ns;
1388 uint32_t reg, clkd, dto = 0;
1389
1390 reg = OMAP_HSMMC_READ(host->base, SYSCTL);
1391 clkd = (reg & CLKD_MASK) >> CLKD_SHIFT;
1392 if (clkd == 0)
1393 clkd = 1;
1394
Balaji T K6e3076c2014-01-21 19:54:42 +05301395 cycle_ns = 1000000000 / (host->clk_rate / clkd);
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001396 timeout = timeout_ns / cycle_ns;
1397 timeout += timeout_clks;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001398 if (timeout) {
1399 while ((timeout & 0x80000000) == 0) {
1400 dto += 1;
1401 timeout <<= 1;
1402 }
1403 dto = 31 - dto;
1404 timeout <<= 1;
1405 if (timeout && dto)
1406 dto += 1;
1407 if (dto >= 13)
1408 dto -= 13;
1409 else
1410 dto = 0;
1411 if (dto > 14)
1412 dto = 14;
1413 }
1414
1415 reg &= ~DTO_MASK;
1416 reg |= dto << DTO_SHIFT;
1417 OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
1418}
1419
Balaji T K9d025332014-01-21 19:54:42 +05301420static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host)
1421{
1422 struct mmc_request *req = host->mrq;
1423 struct dma_chan *chan;
1424
1425 if (!req->data)
1426 return;
1427 OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
1428 | (req->data->blocks << 16));
1429 set_data_timeout(host, req->data->timeout_ns,
1430 req->data->timeout_clks);
1431 chan = omap_hsmmc_get_dma_chan(host, req->data);
1432 dma_async_issue_pending(chan);
1433}
1434
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001435/*
1436 * Configure block length for MMC/SD cards and initiate the transfer.
1437 */
1438static int
Denis Karpov70a33412009-09-22 16:44:59 -07001439omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001440{
1441 int ret;
1442 host->data = req->data;
1443
1444 if (req->data == NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001445 OMAP_HSMMC_WRITE(host->base, BLK, 0);
Adrian Huntere2bf08d2009-09-22 16:45:03 -07001446 /*
1447 * Set an arbitrary 100ms data timeout for commands with
1448 * busy signal.
1449 */
1450 if (req->cmd->flags & MMC_RSP_BUSY)
1451 set_data_timeout(host, 100000000U, 0);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001452 return 0;
1453 }
1454
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001455 if (host->use_dma) {
Balaji T K9d025332014-01-21 19:54:42 +05301456 ret = omap_hsmmc_setup_dma_transfer(host, req);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001457 if (ret != 0) {
Venkatraman Sb1e056a2012-11-19 22:00:00 +05301458 dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001459 return ret;
1460 }
1461 }
1462 return 0;
1463}
1464
Per Forlin9782aff2011-07-01 18:55:23 +02001465static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
1466 int err)
1467{
1468 struct omap_hsmmc_host *host = mmc_priv(mmc);
1469 struct mmc_data *data = mrq->data;
1470
Russell King26b88522012-04-13 12:27:37 +01001471 if (host->use_dma && data->host_cookie) {
Russell Kingc5c98922012-04-13 12:14:39 +01001472 struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data);
Russell Kingc5c98922012-04-13 12:14:39 +01001473
Russell King26b88522012-04-13 12:27:37 +01001474 dma_unmap_sg(c->device->dev, data->sg, data->sg_len,
1475 omap_hsmmc_get_dma_dir(host, data));
Per Forlin9782aff2011-07-01 18:55:23 +02001476 data->host_cookie = 0;
1477 }
1478}
1479
1480static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
1481 bool is_first_req)
1482{
1483 struct omap_hsmmc_host *host = mmc_priv(mmc);
1484
1485 if (mrq->data->host_cookie) {
1486 mrq->data->host_cookie = 0;
1487 return ;
1488 }
1489
Russell Kingc5c98922012-04-13 12:14:39 +01001490 if (host->use_dma) {
1491 struct dma_chan *c = omap_hsmmc_get_dma_chan(host, mrq->data);
Russell Kingc5c98922012-04-13 12:14:39 +01001492
Per Forlin9782aff2011-07-01 18:55:23 +02001493 if (omap_hsmmc_pre_dma_transfer(host, mrq->data,
Russell King26b88522012-04-13 12:27:37 +01001494 &host->next_data, c))
Per Forlin9782aff2011-07-01 18:55:23 +02001495 mrq->data->host_cookie = 0;
Russell Kingc5c98922012-04-13 12:14:39 +01001496 }
Per Forlin9782aff2011-07-01 18:55:23 +02001497}
1498
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001499/*
1500 * Request function. for read/write operation
1501 */
Denis Karpov70a33412009-09-22 16:44:59 -07001502static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001503{
Denis Karpov70a33412009-09-22 16:44:59 -07001504 struct omap_hsmmc_host *host = mmc_priv(mmc);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001505 int err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001506
Adrian Hunterb4175772010-05-26 14:42:06 -07001507 BUG_ON(host->req_in_progress);
1508 BUG_ON(host->dma_ch != -1);
NeilBrownf57ba4c2015-03-26 12:18:23 +11001509 pm_runtime_get_sync(host->dev);
Adrian Hunterb4175772010-05-26 14:42:06 -07001510 if (host->protect_card) {
1511 if (host->reqs_blocked < 3) {
1512 /*
1513 * Ensure the controller is left in a consistent
1514 * state by resetting the command and data state
1515 * machines.
1516 */
1517 omap_hsmmc_reset_controller_fsm(host, SRD);
1518 omap_hsmmc_reset_controller_fsm(host, SRC);
1519 host->reqs_blocked += 1;
1520 }
1521 req->cmd->error = -EBADF;
1522 if (req->data)
1523 req->data->error = -EBADF;
1524 req->cmd->retries = 0;
1525 mmc_request_done(mmc, req);
NeilBrownf57ba4c2015-03-26 12:18:23 +11001526 pm_runtime_mark_last_busy(host->dev);
1527 pm_runtime_put_autosuspend(host->dev);
Adrian Hunterb4175772010-05-26 14:42:06 -07001528 return;
1529 } else if (host->reqs_blocked)
1530 host->reqs_blocked = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001531 WARN_ON(host->mrq != NULL);
1532 host->mrq = req;
Balaji T K6e3076c2014-01-21 19:54:42 +05301533 host->clk_rate = clk_get_rate(host->fclk);
Denis Karpov70a33412009-09-22 16:44:59 -07001534 err = omap_hsmmc_prepare_data(host, req);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001535 if (err) {
1536 req->cmd->error = err;
1537 if (req->data)
1538 req->data->error = err;
1539 host->mrq = NULL;
1540 mmc_request_done(mmc, req);
NeilBrownf57ba4c2015-03-26 12:18:23 +11001541 pm_runtime_mark_last_busy(host->dev);
1542 pm_runtime_put_autosuspend(host->dev);
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001543 return;
1544 }
Balaji T Ka2e77152014-01-21 19:54:42 +05301545 if (req->sbc && !(host->flags & AUTO_CMD23)) {
Balaji T Kbf129e12014-01-21 19:54:42 +05301546 omap_hsmmc_start_command(host, req->sbc, NULL);
1547 return;
1548 }
Jarkko Lavinena3f406f2009-09-22 16:44:46 -07001549
Balaji T K9d025332014-01-21 19:54:42 +05301550 omap_hsmmc_start_dma_transfer(host);
Denis Karpov70a33412009-09-22 16:44:59 -07001551 omap_hsmmc_start_command(host, req->cmd, req->data);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001552}
1553
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001554/* Routine to configure clock values. Exposed API to core */
Denis Karpov70a33412009-09-22 16:44:59 -07001555static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001556{
Denis Karpov70a33412009-09-22 16:44:59 -07001557 struct omap_hsmmc_host *host = mmc_priv(mmc);
Adrian Huntera3621462009-09-22 16:44:42 -07001558 int do_send_init_stream = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001559
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301560 pm_runtime_get_sync(host->dev);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001561
Adrian Huntera3621462009-09-22 16:44:42 -07001562 if (ios->power_mode != host->power_mode) {
1563 switch (ios->power_mode) {
1564 case MMC_POWER_OFF:
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02001565 omap_hsmmc_set_power(host->dev, 0, 0);
Adrian Huntera3621462009-09-22 16:44:42 -07001566 break;
1567 case MMC_POWER_UP:
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02001568 omap_hsmmc_set_power(host->dev, 1, ios->vdd);
Adrian Huntera3621462009-09-22 16:44:42 -07001569 break;
1570 case MMC_POWER_ON:
1571 do_send_init_stream = 1;
1572 break;
1573 }
1574 host->power_mode = ios->power_mode;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001575 }
1576
Denis Karpovdd498ef2009-09-22 16:44:49 -07001577 /* FIXME: set registers based only on changes to ios */
1578
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -04001579 omap_hsmmc_set_bus_width(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001580
Kishore Kadiyala4621d5f2011-02-28 20:48:04 +05301581 if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
David Brownelleb250822009-02-17 14:49:01 -08001582 /* Only MMC1 can interface at 3V without some flavor
1583 * of external transceiver; but they all handle 1.8V.
1584 */
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001585 if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
Balaji T K2cf171c2014-02-19 20:26:40 +05301586 (ios->vdd == DUAL_VOLT_OCR_BIT)) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001587 /*
1588 * The mmc_select_voltage fn of the core does
1589 * not seem to set the power_mode to
1590 * MMC_POWER_UP upon recalculating the voltage.
1591 * vdd 1.8v.
1592 */
Denis Karpov70a33412009-09-22 16:44:59 -07001593 if (omap_hsmmc_switch_opcond(host, ios->vdd) != 0)
1594 dev_dbg(mmc_dev(host->mmc),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001595 "Switch operation failed\n");
1596 }
1597 }
1598
Andy Shevchenko5934df22011-05-06 12:14:06 +03001599 omap_hsmmc_set_clock(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001600
Adrian Huntera3621462009-09-22 16:44:42 -07001601 if (do_send_init_stream)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001602 send_init_stream(host);
1603
Andy Shevchenko3796fb8a2011-07-13 11:31:15 -04001604 omap_hsmmc_set_bus_mode(host);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001605
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301606 pm_runtime_put_autosuspend(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001607}
1608
1609static int omap_hsmmc_get_cd(struct mmc_host *mmc)
1610{
Denis Karpov70a33412009-09-22 16:44:59 -07001611 struct omap_hsmmc_host *host = mmc_priv(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001612
Andreas Fenkartb5cd43f2014-11-08 15:33:16 +01001613 if (!host->card_detect)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001614 return -ENOSYS;
Andreas Fenkart80412ca2014-11-08 15:33:17 +01001615 return host->card_detect(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001616}
1617
Grazvydas Ignotas48168582010-08-10 18:01:52 -07001618static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
1619{
1620 struct omap_hsmmc_host *host = mmc_priv(mmc);
1621
Andreas Fenkart326119c2014-11-08 15:33:14 +01001622 if (mmc_pdata(host)->init_card)
1623 mmc_pdata(host)->init_card(card);
Grazvydas Ignotas48168582010-08-10 18:01:52 -07001624}
1625
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001626static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
1627{
1628 struct omap_hsmmc_host *host = mmc_priv(mmc);
Balaji T K5a52b082014-05-29 10:28:02 +02001629 u32 irq_mask, con;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001630 unsigned long flags;
1631
1632 spin_lock_irqsave(&host->irq_lock, flags);
1633
Balaji T K5a52b082014-05-29 10:28:02 +02001634 con = OMAP_HSMMC_READ(host->base, CON);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001635 irq_mask = OMAP_HSMMC_READ(host->base, ISE);
1636 if (enable) {
1637 host->flags |= HSMMC_SDIO_IRQ_ENABLED;
1638 irq_mask |= CIRQ_EN;
Balaji T K5a52b082014-05-29 10:28:02 +02001639 con |= CTPL | CLKEXTFREE;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001640 } else {
1641 host->flags &= ~HSMMC_SDIO_IRQ_ENABLED;
1642 irq_mask &= ~CIRQ_EN;
Balaji T K5a52b082014-05-29 10:28:02 +02001643 con &= ~(CTPL | CLKEXTFREE);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001644 }
Balaji T K5a52b082014-05-29 10:28:02 +02001645 OMAP_HSMMC_WRITE(host->base, CON, con);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001646 OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
1647
1648 /*
1649 * if enable, piggy back detection on current request
1650 * but always disable immediately
1651 */
1652 if (!host->req_in_progress || !enable)
1653 OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
1654
1655 /* flush posted write */
1656 OMAP_HSMMC_READ(host->base, IE);
1657
1658 spin_unlock_irqrestore(&host->irq_lock, flags);
1659}
1660
1661static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host)
1662{
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001663 int ret;
1664
1665 /*
1666 * For omaps with wake-up path, wakeirq will be irq from pinctrl and
1667 * for other omaps, wakeirq will be from GPIO (dat line remuxed to
1668 * gpio). wakeirq is needed to detect sdio irq in runtime suspend state
1669 * with functional clock disabled.
1670 */
1671 if (!host->dev->of_node || !host->wake_irq)
1672 return -ENODEV;
1673
Tony Lindgren5b83b222015-05-21 15:51:52 -07001674 ret = dev_pm_set_dedicated_wake_irq(host->dev, host->wake_irq);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001675 if (ret) {
1676 dev_err(mmc_dev(host->mmc), "Unable to request wake IRQ\n");
1677 goto err;
1678 }
1679
1680 /*
1681 * Some omaps don't have wake-up path from deeper idle states
1682 * and need to remux SDIO DAT1 to GPIO for wake-up from idle.
1683 */
1684 if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING) {
Andreas Fenkart455e5cd2014-05-29 10:28:05 +02001685 struct pinctrl *p = devm_pinctrl_get(host->dev);
1686 if (!p) {
1687 ret = -ENODEV;
1688 goto err_free_irq;
1689 }
1690 if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT))) {
1691 dev_info(host->dev, "missing default pinctrl state\n");
1692 devm_pinctrl_put(p);
1693 ret = -EINVAL;
1694 goto err_free_irq;
1695 }
1696
1697 if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_IDLE))) {
1698 dev_info(host->dev, "missing idle pinctrl state\n");
1699 devm_pinctrl_put(p);
1700 ret = -EINVAL;
1701 goto err_free_irq;
1702 }
1703 devm_pinctrl_put(p);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001704 }
1705
Balaji T K5a52b082014-05-29 10:28:02 +02001706 OMAP_HSMMC_WRITE(host->base, HCTL,
1707 OMAP_HSMMC_READ(host->base, HCTL) | IWE);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001708 return 0;
1709
Andreas Fenkart455e5cd2014-05-29 10:28:05 +02001710err_free_irq:
Tony Lindgren5b83b222015-05-21 15:51:52 -07001711 dev_pm_clear_wake_irq(host->dev);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001712err:
1713 dev_warn(host->dev, "no SDIO IRQ support, falling back to polling\n");
1714 host->wake_irq = 0;
1715 return ret;
1716}
1717
Denis Karpov70a33412009-09-22 16:44:59 -07001718static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001719{
1720 u32 hctl, capa, value;
1721
1722 /* Only MMC1 supports 3.0V */
Kishore Kadiyala4621d5f2011-02-28 20:48:04 +05301723 if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001724 hctl = SDVS30;
1725 capa = VS30 | VS18;
1726 } else {
1727 hctl = SDVS18;
1728 capa = VS18;
1729 }
1730
1731 value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
1732 OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
1733
1734 value = OMAP_HSMMC_READ(host->base, CAPA);
1735 OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
1736
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001737 /* Set SD bus power bit */
Adrian Huntere13bb302009-03-12 17:08:26 +02001738 set_sd_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01001739}
1740
Kuninori Morimotoafd8c292014-09-08 23:44:51 -07001741static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
1742 unsigned int direction, int blk_size)
1743{
1744 /* This controller can't do multiblock reads due to hw bugs */
1745 if (direction == MMC_DATA_READ)
1746 return 1;
1747
1748 return blk_size;
1749}
1750
1751static struct mmc_host_ops omap_hsmmc_ops = {
Per Forlin9782aff2011-07-01 18:55:23 +02001752 .post_req = omap_hsmmc_post_req,
1753 .pre_req = omap_hsmmc_pre_req,
Denis Karpov70a33412009-09-22 16:44:59 -07001754 .request = omap_hsmmc_request,
1755 .set_ios = omap_hsmmc_set_ios,
Denis Karpovdd498ef2009-09-22 16:44:49 -07001756 .get_cd = omap_hsmmc_get_cd,
Andreas Fenkarta49d8352015-03-03 13:28:14 +01001757 .get_ro = mmc_gpio_get_ro,
Grazvydas Ignotas48168582010-08-10 18:01:52 -07001758 .init_card = omap_hsmmc_init_card,
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001759 .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
Denis Karpovdd498ef2009-09-22 16:44:49 -07001760};
1761
Denis Karpovd900f712009-09-22 16:44:38 -07001762#ifdef CONFIG_DEBUG_FS
1763
Denis Karpov70a33412009-09-22 16:44:59 -07001764static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
Denis Karpovd900f712009-09-22 16:44:38 -07001765{
1766 struct mmc_host *mmc = s->private;
Denis Karpov70a33412009-09-22 16:44:59 -07001767 struct omap_hsmmc_host *host = mmc_priv(mmc);
Denis Karpov11dd62a2009-09-22 16:44:43 -07001768
Andreas Fenkartbb0635f2014-05-29 10:28:01 +02001769 seq_printf(s, "mmc%d:\n", mmc->index);
1770 seq_printf(s, "sdio irq mode\t%s\n",
1771 (mmc->caps & MMC_CAP_SDIO_IRQ) ? "interrupt" : "polling");
1772
1773 if (mmc->caps & MMC_CAP_SDIO_IRQ) {
1774 seq_printf(s, "sdio irq \t%s\n",
1775 (host->flags & HSMMC_SDIO_IRQ_ENABLED) ? "enabled"
1776 : "disabled");
1777 }
1778 seq_printf(s, "ctx_loss:\t%d\n", host->context_loss);
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001779
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301780 pm_runtime_get_sync(host->dev);
Andreas Fenkartbb0635f2014-05-29 10:28:01 +02001781 seq_puts(s, "\nregs:\n");
Denis Karpovd900f712009-09-22 16:44:38 -07001782 seq_printf(s, "CON:\t\t0x%08x\n",
1783 OMAP_HSMMC_READ(host->base, CON));
Andreas Fenkartbb0635f2014-05-29 10:28:01 +02001784 seq_printf(s, "PSTATE:\t\t0x%08x\n",
1785 OMAP_HSMMC_READ(host->base, PSTATE));
Denis Karpovd900f712009-09-22 16:44:38 -07001786 seq_printf(s, "HCTL:\t\t0x%08x\n",
1787 OMAP_HSMMC_READ(host->base, HCTL));
1788 seq_printf(s, "SYSCTL:\t\t0x%08x\n",
1789 OMAP_HSMMC_READ(host->base, SYSCTL));
1790 seq_printf(s, "IE:\t\t0x%08x\n",
1791 OMAP_HSMMC_READ(host->base, IE));
1792 seq_printf(s, "ISE:\t\t0x%08x\n",
1793 OMAP_HSMMC_READ(host->base, ISE));
1794 seq_printf(s, "CAPA:\t\t0x%08x\n",
1795 OMAP_HSMMC_READ(host->base, CAPA));
Adrian Hunter5e2ea612009-09-22 16:44:39 -07001796
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05301797 pm_runtime_mark_last_busy(host->dev);
1798 pm_runtime_put_autosuspend(host->dev);
Denis Karpovdd498ef2009-09-22 16:44:49 -07001799
Denis Karpovd900f712009-09-22 16:44:38 -07001800 return 0;
1801}
1802
Denis Karpov70a33412009-09-22 16:44:59 -07001803static int omap_hsmmc_regs_open(struct inode *inode, struct file *file)
Denis Karpovd900f712009-09-22 16:44:38 -07001804{
Denis Karpov70a33412009-09-22 16:44:59 -07001805 return single_open(file, omap_hsmmc_regs_show, inode->i_private);
Denis Karpovd900f712009-09-22 16:44:38 -07001806}
1807
1808static const struct file_operations mmc_regs_fops = {
Denis Karpov70a33412009-09-22 16:44:59 -07001809 .open = omap_hsmmc_regs_open,
Denis Karpovd900f712009-09-22 16:44:38 -07001810 .read = seq_read,
1811 .llseek = seq_lseek,
1812 .release = single_release,
1813};
1814
Denis Karpov70a33412009-09-22 16:44:59 -07001815static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001816{
1817 if (mmc->debugfs_root)
1818 debugfs_create_file("regs", S_IRUSR, mmc->debugfs_root,
1819 mmc, &mmc_regs_fops);
1820}
1821
1822#else
1823
Denis Karpov70a33412009-09-22 16:44:59 -07001824static void omap_hsmmc_debugfs(struct mmc_host *mmc)
Denis Karpovd900f712009-09-22 16:44:38 -07001825{
1826}
1827
1828#endif
1829
Rajendra Nayak46856a62012-03-12 20:32:37 +05301830#ifdef CONFIG_OF
Nishanth Menon59445b12014-02-13 23:45:48 -06001831static const struct omap_mmc_of_data omap3_pre_es3_mmc_of_data = {
1832 /* See 35xx errata 2.1.1.128 in SPRZ278F */
1833 .controller_flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
1834};
1835
1836static const struct omap_mmc_of_data omap4_mmc_of_data = {
1837 .reg_offset = 0x100,
1838};
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001839static const struct omap_mmc_of_data am33xx_mmc_of_data = {
1840 .reg_offset = 0x100,
1841 .controller_flags = OMAP_HSMMC_SWAKEUP_MISSING,
1842};
Rajendra Nayak46856a62012-03-12 20:32:37 +05301843
1844static const struct of_device_id omap_mmc_of_match[] = {
1845 {
1846 .compatible = "ti,omap2-hsmmc",
1847 },
1848 {
Nishanth Menon59445b12014-02-13 23:45:48 -06001849 .compatible = "ti,omap3-pre-es3-hsmmc",
1850 .data = &omap3_pre_es3_mmc_of_data,
1851 },
1852 {
Rajendra Nayak46856a62012-03-12 20:32:37 +05301853 .compatible = "ti,omap3-hsmmc",
1854 },
1855 {
1856 .compatible = "ti,omap4-hsmmc",
Nishanth Menon59445b12014-02-13 23:45:48 -06001857 .data = &omap4_mmc_of_data,
Rajendra Nayak46856a62012-03-12 20:32:37 +05301858 },
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001859 {
1860 .compatible = "ti,am33xx-hsmmc",
1861 .data = &am33xx_mmc_of_data,
1862 },
Rajendra Nayak46856a62012-03-12 20:32:37 +05301863 {},
Chris Ballb6d085f2012-04-10 09:57:36 -04001864};
Rajendra Nayak46856a62012-03-12 20:32:37 +05301865MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
1866
Andreas Fenkart551434382014-11-08 15:33:09 +01001867static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
Rajendra Nayak46856a62012-03-12 20:32:37 +05301868{
Andreas Fenkart551434382014-11-08 15:33:09 +01001869 struct omap_hsmmc_platform_data *pdata;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301870 struct device_node *np = dev->of_node;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301871
1872 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
1873 if (!pdata)
Balaji T K19df45b2014-02-28 19:08:18 +05301874 return ERR_PTR(-ENOMEM); /* out of memory */
Rajendra Nayak46856a62012-03-12 20:32:37 +05301875
1876 if (of_find_property(np, "ti,dual-volt", NULL))
1877 pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
1878
Andreas Fenkartb7a56462015-03-20 15:53:54 +01001879 pdata->gpio_cd = -EINVAL;
1880 pdata->gpio_cod = -EINVAL;
NeilBrownfdb9de12015-01-13 08:23:18 +13001881 pdata->gpio_wp = -EINVAL;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301882
1883 if (of_find_property(np, "ti,non-removable", NULL)) {
Andreas Fenkart326119c2014-11-08 15:33:14 +01001884 pdata->nonremovable = true;
1885 pdata->no_regulator_off_init = true;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301886 }
Rajendra Nayak46856a62012-03-12 20:32:37 +05301887
1888 if (of_find_property(np, "ti,needs-special-reset", NULL))
Andreas Fenkart326119c2014-11-08 15:33:14 +01001889 pdata->features |= HSMMC_HAS_UPDATED_RESET;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301890
Hebbar, Gururajacd587092012-11-19 21:59:58 +05301891 if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
Andreas Fenkart326119c2014-11-08 15:33:14 +01001892 pdata->features |= HSMMC_HAS_HSPE_SUPPORT;
Hebbar, Gururajacd587092012-11-19 21:59:58 +05301893
Rajendra Nayak46856a62012-03-12 20:32:37 +05301894 return pdata;
1895}
1896#else
Andreas Fenkart551434382014-11-08 15:33:09 +01001897static inline struct omap_hsmmc_platform_data
Rajendra Nayak46856a62012-03-12 20:32:37 +05301898 *of_get_hsmmc_pdata(struct device *dev)
1899{
Balaji T K19df45b2014-02-28 19:08:18 +05301900 return ERR_PTR(-EINVAL);
Rajendra Nayak46856a62012-03-12 20:32:37 +05301901}
1902#endif
1903
Bill Pembertonc3be1ef2012-11-19 13:23:06 -05001904static int omap_hsmmc_probe(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001905{
Andreas Fenkart551434382014-11-08 15:33:09 +01001906 struct omap_hsmmc_platform_data *pdata = pdev->dev.platform_data;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001907 struct mmc_host *mmc;
Denis Karpov70a33412009-09-22 16:44:59 -07001908 struct omap_hsmmc_host *host = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001909 struct resource *res;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08001910 int ret, irq;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301911 const struct of_device_id *match;
Russell King26b88522012-04-13 12:27:37 +01001912 dma_cap_mask_t mask;
1913 unsigned tx_req, rx_req;
Nishanth Menon59445b12014-02-13 23:45:48 -06001914 const struct omap_mmc_of_data *data;
Balaji T K77fae212014-05-09 22:16:51 +05301915 void __iomem *base;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301916
1917 match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
1918 if (match) {
1919 pdata = of_get_hsmmc_pdata(&pdev->dev);
Jan Luebbedc642c22013-01-30 10:07:17 +01001920
1921 if (IS_ERR(pdata))
1922 return PTR_ERR(pdata);
1923
Rajendra Nayak46856a62012-03-12 20:32:37 +05301924 if (match->data) {
Nishanth Menon59445b12014-02-13 23:45:48 -06001925 data = match->data;
1926 pdata->reg_offset = data->reg_offset;
1927 pdata->controller_flags |= data->controller_flags;
Rajendra Nayak46856a62012-03-12 20:32:37 +05301928 }
1929 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001930
1931 if (pdata == NULL) {
1932 dev_err(&pdev->dev, "Platform Data is missing\n");
1933 return -ENXIO;
1934 }
1935
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001936 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1937 irq = platform_get_irq(pdev, 0);
1938 if (res == NULL || irq < 0)
1939 return -ENXIO;
1940
Balaji T K77fae212014-05-09 22:16:51 +05301941 base = devm_ioremap_resource(&pdev->dev, res);
1942 if (IS_ERR(base))
1943 return PTR_ERR(base);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001944
Denis Karpov70a33412009-09-22 16:44:59 -07001945 mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001946 if (!mmc) {
1947 ret = -ENOMEM;
Andreas Fenkart1e363e32014-11-08 15:33:15 +01001948 goto err;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001949 }
1950
NeilBrownfdb9de12015-01-13 08:23:18 +13001951 ret = mmc_of_parse(mmc);
1952 if (ret)
1953 goto err1;
1954
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001955 host = mmc_priv(mmc);
1956 host->mmc = mmc;
1957 host->pdata = pdata;
1958 host->dev = &pdev->dev;
1959 host->use_dma = 1;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001960 host->dma_ch = -1;
1961 host->irq = irq;
Balaji T Kfc307df2012-04-02 12:26:47 +05301962 host->mapbase = res->start + pdata->reg_offset;
Balaji T K77fae212014-05-09 22:16:51 +05301963 host->base = base + pdata->reg_offset;
Adrian Hunter6da20c82010-02-15 10:03:34 -08001964 host->power_mode = MMC_POWER_OFF;
Per Forlin9782aff2011-07-01 18:55:23 +02001965 host->next_data.cookie = 1;
Balaji T Ke99448f2014-02-19 20:26:40 +05301966 host->pbias_enabled = 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001967
NeilBrown41afa3142015-01-13 08:23:18 +13001968 ret = omap_hsmmc_gpio_init(mmc, host, pdata);
Andreas Fenkart1e363e32014-11-08 15:33:15 +01001969 if (ret)
1970 goto err_gpio;
1971
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001972 platform_set_drvdata(pdev, host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001973
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02001974 if (pdev->dev.of_node)
1975 host->wake_irq = irq_of_parse_and_map(pdev->dev.of_node, 1);
1976
Balaji T K7a8c2ce2011-07-01 22:09:34 +05301977 mmc->ops = &omap_hsmmc_ops;
Denis Karpovdd498ef2009-09-22 16:44:49 -07001978
Daniel Mackd418ed82012-02-19 13:20:33 +01001979 mmc->f_min = OMAP_MMC_MIN_CLOCK;
1980
1981 if (pdata->max_freq > 0)
1982 mmc->f_max = pdata->max_freq;
NeilBrownfdb9de12015-01-13 08:23:18 +13001983 else if (mmc->f_max == 0)
Daniel Mackd418ed82012-02-19 13:20:33 +01001984 mmc->f_max = OMAP_MMC_MAX_CLOCK;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001985
Adrian Hunter4dffd7a2009-09-22 16:44:58 -07001986 spin_lock_init(&host->irq_lock);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001987
Balaji T K96181952014-05-09 22:16:48 +05301988 host->fclk = devm_clk_get(&pdev->dev, "fck");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001989 if (IS_ERR(host->fclk)) {
1990 ret = PTR_ERR(host->fclk);
1991 host->fclk = NULL;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01001992 goto err1;
1993 }
1994
Paul Walmsley9b682562011-10-06 14:50:35 -06001995 if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) {
1996 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 -07001997 omap_hsmmc_ops.multi_io_quirk = omap_hsmmc_multi_io_quirk;
Paul Walmsley9b682562011-10-06 14:50:35 -06001998 }
Denis Karpovdd498ef2009-09-22 16:44:49 -07001999
Tony Lindgren5b83b222015-05-21 15:51:52 -07002000 device_init_wakeup(&pdev->dev, true);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302001 pm_runtime_enable(host->dev);
2002 pm_runtime_get_sync(host->dev);
2003 pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY);
2004 pm_runtime_use_autosuspend(host->dev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002005
Balaji T K92a3aeb2012-02-24 21:14:34 +05302006 omap_hsmmc_context_save(host);
2007
Balaji T K96181952014-05-09 22:16:48 +05302008 host->dbclk = devm_clk_get(&pdev->dev, "mmchsdb_fck");
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302009 /*
2010 * MMC can still work without debounce clock.
2011 */
2012 if (IS_ERR(host->dbclk)) {
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302013 host->dbclk = NULL;
Rajendra Nayak94c18142012-06-27 14:19:54 +05302014 } else if (clk_prepare_enable(host->dbclk) != 0) {
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302015 dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302016 host->dbclk = NULL;
Adrian Hunter2bec0892009-09-22 16:45:02 -07002017 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002018
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02002019 /* Since we do only SG emulation, we can have as many segs
2020 * as we want. */
Martin K. Petersena36274e2010-09-10 01:33:59 -04002021 mmc->max_segs = 1024;
Juha Yrjola0ccd76d2008-11-14 15:22:00 +02002022
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002023 mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
2024 mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
2025 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2026 mmc->max_seg_size = mmc->max_req_size;
2027
Jarkko Lavinen13189e72009-09-22 16:44:53 -07002028 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
Adrian Hunter93caf8e692010-08-11 14:17:48 -07002029 MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002030
Andreas Fenkart326119c2014-11-08 15:33:14 +01002031 mmc->caps |= mmc_pdata(host)->caps;
Sukumar Ghorai3a638332010-09-15 14:49:23 +00002032 if (mmc->caps & MMC_CAP_8_BIT_DATA)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002033 mmc->caps |= MMC_CAP_4_BIT_DATA;
2034
Andreas Fenkart326119c2014-11-08 15:33:14 +01002035 if (mmc_pdata(host)->nonremovable)
Adrian Hunter23d99bb2009-09-22 16:44:48 -07002036 mmc->caps |= MMC_CAP_NONREMOVABLE;
2037
NeilBrownfdb9de12015-01-13 08:23:18 +13002038 mmc->pm_caps |= mmc_pdata(host)->pm_caps;
Eliad Peller6fdc75d2011-11-22 16:02:18 +02002039
Denis Karpov70a33412009-09-22 16:44:59 -07002040 omap_hsmmc_conf_bus_power(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002041
Santosh Shilimkar4a29b552013-05-10 17:42:35 +05302042 if (!pdev->dev.of_node) {
2043 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
2044 if (!res) {
2045 dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
2046 ret = -ENXIO;
2047 goto err_irq;
2048 }
2049 tx_req = res->start;
Balaji T Kb7bf7732012-03-07 09:55:30 -05002050
Santosh Shilimkar4a29b552013-05-10 17:42:35 +05302051 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
2052 if (!res) {
2053 dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
2054 ret = -ENXIO;
2055 goto err_irq;
2056 }
2057 rx_req = res->start;
Balaji T Kb7bf7732012-03-07 09:55:30 -05002058 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002059
Russell King26b88522012-04-13 12:27:37 +01002060 dma_cap_zero(mask);
2061 dma_cap_set(DMA_SLAVE, mask);
Russell Kingc5c98922012-04-13 12:14:39 +01002062
Matt Porterd272fbf2013-05-10 17:42:34 +05302063 host->rx_chan =
2064 dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
2065 &rx_req, &pdev->dev, "rx");
2066
Russell King26b88522012-04-13 12:27:37 +01002067 if (!host->rx_chan) {
2068 dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req);
Kevin Hilman04e8c7b2012-07-11 17:51:40 +01002069 ret = -ENXIO;
Russell King26b88522012-04-13 12:27:37 +01002070 goto err_irq;
2071 }
2072
Matt Porterd272fbf2013-05-10 17:42:34 +05302073 host->tx_chan =
2074 dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
2075 &tx_req, &pdev->dev, "tx");
2076
Russell King26b88522012-04-13 12:27:37 +01002077 if (!host->tx_chan) {
2078 dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req);
Kevin Hilman04e8c7b2012-07-11 17:51:40 +01002079 ret = -ENXIO;
Russell King26b88522012-04-13 12:27:37 +01002080 goto err_irq;
Russell Kingc5c98922012-04-13 12:14:39 +01002081 }
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002082
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002083 /* Request IRQ for MMC operations */
Balaji T Ke1538ed2014-05-09 22:16:49 +05302084 ret = devm_request_irq(&pdev->dev, host->irq, omap_hsmmc_irq, 0,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002085 mmc_hostname(mmc), host);
2086 if (ret) {
Venkatraman Sb1e056a2012-11-19 22:00:00 +05302087 dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002088 goto err_irq;
2089 }
2090
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02002091 if (omap_hsmmc_have_reg()) {
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002092 ret = omap_hsmmc_reg_get(host);
2093 if (ret)
Andreas Fenkartbb09d152014-11-08 15:33:11 +01002094 goto err_irq;
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002095 }
2096
Andreas Fenkart326119c2014-11-08 15:33:14 +01002097 mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002098
Adrian Hunterb4175772010-05-26 14:42:06 -07002099 omap_hsmmc_disable_irq(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002100
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002101 /*
2102 * For now, only support SDIO interrupt if we have a separate
2103 * wake-up interrupt configured from device tree. This is because
2104 * the wake-up interrupt is needed for idle state and some
2105 * platforms need special quirks. And we don't want to add new
2106 * legacy mux platform init code callbacks any longer as we
2107 * are moving to DT based booting anyways.
2108 */
2109 ret = omap_hsmmc_configure_wake_irq(host);
2110 if (!ret)
2111 mmc->caps |= MMC_CAP_SDIO_IRQ;
2112
Adrian Hunterb62f6222009-09-22 16:45:01 -07002113 omap_hsmmc_protect_card(host);
2114
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002115 mmc_add_host(mmc);
2116
Andreas Fenkart326119c2014-11-08 15:33:14 +01002117 if (mmc_pdata(host)->name != NULL) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002118 ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
2119 if (ret < 0)
2120 goto err_slot_name;
2121 }
Andreas Fenkartcde592c2015-03-03 13:28:15 +01002122 if (host->get_cover_state) {
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002123 ret = device_create_file(&mmc->class_dev,
Andreas Fenkartcde592c2015-03-03 13:28:15 +01002124 &dev_attr_cover_switch);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002125 if (ret < 0)
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002126 goto err_slot_name;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002127 }
2128
Denis Karpov70a33412009-09-22 16:44:59 -07002129 omap_hsmmc_debugfs(mmc);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302130 pm_runtime_mark_last_busy(host->dev);
2131 pm_runtime_put_autosuspend(host->dev);
Denis Karpovd900f712009-09-22 16:44:38 -07002132
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002133 return 0;
2134
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002135err_slot_name:
2136 mmc_remove_host(mmc);
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02002137 omap_hsmmc_reg_put(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002138err_irq:
Tony Lindgren5b83b222015-05-21 15:51:52 -07002139 device_init_wakeup(&pdev->dev, false);
Russell Kingc5c98922012-04-13 12:14:39 +01002140 if (host->tx_chan)
2141 dma_release_channel(host->tx_chan);
2142 if (host->rx_chan)
2143 dma_release_channel(host->rx_chan);
Balaji T Kd59d77e2012-02-24 21:14:33 +05302144 pm_runtime_put_sync(host->dev);
Tony Lindgren37f61902012-03-08 23:41:35 -05002145 pm_runtime_disable(host->dev);
Balaji T K96181952014-05-09 22:16:48 +05302146 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05302147 clk_disable_unprepare(host->dbclk);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002148err1:
Andreas Fenkart1e363e32014-11-08 15:33:15 +01002149err_gpio:
Adrian Hunterdb0fefc2010-02-15 10:03:34 -08002150 mmc_free_host(mmc);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002151err:
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002152 return ret;
2153}
2154
Bill Pemberton6e0ee712012-11-19 13:26:03 -05002155static int omap_hsmmc_remove(struct platform_device *pdev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002156{
Denis Karpov70a33412009-09-22 16:44:59 -07002157 struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002158
Felipe Balbi927ce942012-03-14 11:18:27 +02002159 pm_runtime_get_sync(host->dev);
2160 mmc_remove_host(host->mmc);
Andreas Fenkartf7f0f032015-07-07 20:38:43 +02002161 omap_hsmmc_reg_put(host);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002162
Russell Kingc5c98922012-04-13 12:14:39 +01002163 if (host->tx_chan)
2164 dma_release_channel(host->tx_chan);
2165 if (host->rx_chan)
2166 dma_release_channel(host->rx_chan);
2167
Felipe Balbi927ce942012-03-14 11:18:27 +02002168 pm_runtime_put_sync(host->dev);
2169 pm_runtime_disable(host->dev);
Tony Lindgren5b83b222015-05-21 15:51:52 -07002170 device_init_wakeup(&pdev->dev, false);
Balaji T K96181952014-05-09 22:16:48 +05302171 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05302172 clk_disable_unprepare(host->dbclk);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002173
Balaji T K9d1f0282012-10-15 21:35:07 +05302174 mmc_free_host(host->mmc);
Felipe Balbi927ce942012-03-14 11:18:27 +02002175
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002176 return 0;
2177}
2178
Russ Dill3d3bbfb2015-02-27 13:24:34 +02002179#ifdef CONFIG_PM_SLEEP
Kevin Hilmana791daa2010-05-26 14:42:07 -07002180static int omap_hsmmc_suspend(struct device *dev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002181{
Felipe Balbi927ce942012-03-14 11:18:27 +02002182 struct omap_hsmmc_host *host = dev_get_drvdata(dev);
2183
2184 if (!host)
2185 return 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002186
Felipe Balbi927ce942012-03-14 11:18:27 +02002187 pm_runtime_get_sync(host->dev);
Felipe Balbi927ce942012-03-14 11:18:27 +02002188
2189 if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) {
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002190 OMAP_HSMMC_WRITE(host->base, ISE, 0);
2191 OMAP_HSMMC_WRITE(host->base, IE, 0);
2192 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
Felipe Balbi927ce942012-03-14 11:18:27 +02002193 OMAP_HSMMC_WRITE(host->base, HCTL,
2194 OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
2195 }
2196
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302197 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05302198 clk_disable_unprepare(host->dbclk);
Ulf Hansson3932afd2013-09-25 14:47:06 +02002199
Eliad Peller31f9d462011-11-22 16:02:17 +02002200 pm_runtime_put_sync(host->dev);
Ulf Hansson3932afd2013-09-25 14:47:06 +02002201 return 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002202}
2203
2204/* Routine to resume the MMC device */
Kevin Hilmana791daa2010-05-26 14:42:07 -07002205static int omap_hsmmc_resume(struct device *dev)
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002206{
Felipe Balbi927ce942012-03-14 11:18:27 +02002207 struct omap_hsmmc_host *host = dev_get_drvdata(dev);
2208
2209 if (!host)
2210 return 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002211
Felipe Balbi927ce942012-03-14 11:18:27 +02002212 pm_runtime_get_sync(host->dev);
Denis Karpov11dd62a2009-09-22 16:44:43 -07002213
Rajendra Nayakcd03d9a2012-04-09 12:08:35 +05302214 if (host->dbclk)
Rajendra Nayak94c18142012-06-27 14:19:54 +05302215 clk_prepare_enable(host->dbclk);
Adrian Hunter2bec0892009-09-22 16:45:02 -07002216
Felipe Balbi927ce942012-03-14 11:18:27 +02002217 if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
2218 omap_hsmmc_conf_bus_power(host);
Kim Kyuwon1b331e62009-02-20 13:10:08 +01002219
Felipe Balbi927ce942012-03-14 11:18:27 +02002220 omap_hsmmc_protect_card(host);
Felipe Balbi927ce942012-03-14 11:18:27 +02002221 pm_runtime_mark_last_busy(host->dev);
2222 pm_runtime_put_autosuspend(host->dev);
Ulf Hansson3932afd2013-09-25 14:47:06 +02002223 return 0;
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002224}
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002225#endif
2226
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302227static int omap_hsmmc_runtime_suspend(struct device *dev)
2228{
2229 struct omap_hsmmc_host *host;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002230 unsigned long flags;
Andreas Fenkartf9459012014-05-29 10:28:03 +02002231 int ret = 0;
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302232
2233 host = platform_get_drvdata(to_platform_device(dev));
2234 omap_hsmmc_context_save(host);
Felipe Balbi927ce942012-03-14 11:18:27 +02002235 dev_dbg(dev, "disabled\n");
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302236
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002237 spin_lock_irqsave(&host->irq_lock, flags);
2238 if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) &&
2239 (host->flags & HSMMC_SDIO_IRQ_ENABLED)) {
2240 /* disable sdio irq handling to prevent race */
2241 OMAP_HSMMC_WRITE(host->base, ISE, 0);
2242 OMAP_HSMMC_WRITE(host->base, IE, 0);
Andreas Fenkartf9459012014-05-29 10:28:03 +02002243
2244 if (!(OMAP_HSMMC_READ(host->base, PSTATE) & DLEV_DAT(1))) {
2245 /*
2246 * dat1 line low, pending sdio irq
2247 * race condition: possible irq handler running on
2248 * multi-core, abort
2249 */
2250 dev_dbg(dev, "pending sdio irq, abort suspend\n");
2251 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
2252 OMAP_HSMMC_WRITE(host->base, ISE, CIRQ_EN);
2253 OMAP_HSMMC_WRITE(host->base, IE, CIRQ_EN);
2254 pm_runtime_mark_last_busy(dev);
2255 ret = -EBUSY;
2256 goto abort;
2257 }
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002258
Andreas Fenkart97978a42014-05-29 10:28:04 +02002259 pinctrl_pm_select_idle_state(dev);
Andreas Fenkart97978a42014-05-29 10:28:04 +02002260 } else {
2261 pinctrl_pm_select_idle_state(dev);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002262 }
Andreas Fenkart97978a42014-05-29 10:28:04 +02002263
Andreas Fenkartf9459012014-05-29 10:28:03 +02002264abort:
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002265 spin_unlock_irqrestore(&host->irq_lock, flags);
Andreas Fenkartf9459012014-05-29 10:28:03 +02002266 return ret;
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302267}
2268
2269static int omap_hsmmc_runtime_resume(struct device *dev)
2270{
2271 struct omap_hsmmc_host *host;
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002272 unsigned long flags;
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302273
2274 host = platform_get_drvdata(to_platform_device(dev));
2275 omap_hsmmc_context_restore(host);
Felipe Balbi927ce942012-03-14 11:18:27 +02002276 dev_dbg(dev, "enabled\n");
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302277
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002278 spin_lock_irqsave(&host->irq_lock, flags);
2279 if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) &&
2280 (host->flags & HSMMC_SDIO_IRQ_ENABLED)) {
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002281
Andreas Fenkart97978a42014-05-29 10:28:04 +02002282 pinctrl_pm_select_default_state(host->dev);
2283
2284 /* irq lost, if pinmux incorrect */
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002285 OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
2286 OMAP_HSMMC_WRITE(host->base, ISE, CIRQ_EN);
2287 OMAP_HSMMC_WRITE(host->base, IE, CIRQ_EN);
Andreas Fenkart97978a42014-05-29 10:28:04 +02002288 } else {
2289 pinctrl_pm_select_default_state(host->dev);
Andreas Fenkart2cd3a2a2014-05-29 10:28:00 +02002290 }
2291 spin_unlock_irqrestore(&host->irq_lock, flags);
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302292 return 0;
2293}
2294
Kevin Hilmana791daa2010-05-26 14:42:07 -07002295static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
Russ Dill3d3bbfb2015-02-27 13:24:34 +02002296 SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume)
Balaji T Kfa4aa2d2011-07-01 22:09:35 +05302297 .runtime_suspend = omap_hsmmc_runtime_suspend,
2298 .runtime_resume = omap_hsmmc_runtime_resume,
Kevin Hilmana791daa2010-05-26 14:42:07 -07002299};
2300
2301static struct platform_driver omap_hsmmc_driver = {
Felipe Balbiefa25fd2012-03-14 11:18:28 +02002302 .probe = omap_hsmmc_probe,
Bill Pemberton0433c142012-11-19 13:20:26 -05002303 .remove = omap_hsmmc_remove,
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002304 .driver = {
2305 .name = DRIVER_NAME,
Kevin Hilmana791daa2010-05-26 14:42:07 -07002306 .pm = &omap_hsmmc_dev_pm_ops,
Rajendra Nayak46856a62012-03-12 20:32:37 +05302307 .of_match_table = of_match_ptr(omap_mmc_of_match),
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002308 },
2309};
2310
Felipe Balbib7964502012-03-14 11:18:32 +02002311module_platform_driver(omap_hsmmc_driver);
Madhusudhan Chikkaturea45c6cb2009-01-23 01:05:23 +01002312MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
2313MODULE_LICENSE("GPL");
2314MODULE_ALIAS("platform:" DRIVER_NAME);
2315MODULE_AUTHOR("Texas Instruments Inc");