Blame view

drivers/mmc/host/sdhci-pxav3.c 15.4 KB
a702c8abb   Zhangfei Gao   mmc: host: split ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * Copyright (C) 2010 Marvell International Ltd.
   *		Zhangfei Gao <zhangfei.gao@marvell.com>
   *		Kevin Wang <dwang4@marvell.com>
   *		Mingwei Wang <mwwang@marvell.com>
   *		Philip Rakity <prakity@marvell.com>
   *		Mark Brown <markb@marvell.com>
   *
   * This software is licensed under the terms of the GNU General Public
   * License version 2, as published by the Free Software Foundation, and
   * may be copied, distributed, and modified under those terms.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   */
  #include <linux/err.h>
  #include <linux/init.h>
  #include <linux/platform_device.h>
  #include <linux/clk.h>
  #include <linux/io.h>
  #include <linux/gpio.h>
  #include <linux/mmc/card.h>
  #include <linux/mmc/host.h>
8f63795c6   Chris Ball   mmc: sdhci-pxav3:...
27
  #include <linux/mmc/slot-gpio.h>
bfed345ed   Zhangfei Gao   mmc: sdhci-pxa: m...
28
  #include <linux/platform_data/pxa_sdhci.h>
a702c8abb   Zhangfei Gao   mmc: host: split ...
29
30
  #include <linux/slab.h>
  #include <linux/delay.h>
88b476797   Paul Gortmaker   mmc: Add module.h...
31
  #include <linux/module.h>
b650352dd   Chris Ball   mmc: sdhci-pxa: A...
32
33
  #include <linux/of.h>
  #include <linux/of_device.h>
8f63795c6   Chris Ball   mmc: sdhci-pxav3:...
34
  #include <linux/of_gpio.h>
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
35
36
  #include <linux/pm.h>
  #include <linux/pm_runtime.h>
5491ce3f7   Marcin Wojtas   mmc: sdhci-pxav3:...
37
  #include <linux/mbus.h>
b650352dd   Chris Ball   mmc: sdhci-pxa: A...
38

a702c8abb   Zhangfei Gao   mmc: host: split ...
39
40
  #include "sdhci.h"
  #include "sdhci-pltfm.h"
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
41
  #define PXAV3_RPM_DELAY_MS     50
a702c8abb   Zhangfei Gao   mmc: host: split ...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  #define SD_CLOCK_BURST_SIZE_SETUP		0x10A
  #define SDCLK_SEL	0x100
  #define SDCLK_DELAY_SHIFT	9
  #define SDCLK_DELAY_MASK	0x1f
  
  #define SD_CFG_FIFO_PARAM       0x100
  #define SDCFG_GEN_PAD_CLK_ON	(1<<6)
  #define SDCFG_GEN_PAD_CLK_CNT_MASK	0xFF
  #define SDCFG_GEN_PAD_CLK_CNT_SHIFT	24
  
  #define SD_SPI_MODE          0x108
  #define SD_CE_ATA_1          0x10C
  
  #define SD_CE_ATA_2          0x10E
  #define SDCE_MISC_INT		(1<<2)
  #define SDCE_MISC_INT_EN	(1<<1)
cc9571e85   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
58
  struct sdhci_pxa {
8afdc9cca   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
59
  	struct clk *clk_core;
8c96a7a33   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
60
  	struct clk *clk_io;
cc9571e85   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
61
  	u8	power_mode;
1140011ee   Marcin Wojtas   mmc: sdhci-pxav3:...
62
  	void __iomem *sdio3_conf_reg;
cc9571e85   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
63
  };
5491ce3f7   Marcin Wojtas   mmc: sdhci-pxav3:...
64
65
66
67
68
69
70
  /*
   * These registers are relative to the second register region, for the
   * MBus bridge.
   */
  #define SDHCI_WINDOW_CTRL(i)	(0x80 + ((i) << 3))
  #define SDHCI_WINDOW_BASE(i)	(0x84 + ((i) << 3))
  #define SDHCI_MAX_WIN_NUM	8
1140011ee   Marcin Wojtas   mmc: sdhci-pxav3:...
71
72
73
74
75
76
77
  /*
   * Fields below belong to SDIO3 Configuration Register (third register
   * region for the Armada 38x flavor)
   */
  
  #define SDIO3_CONF_CLK_INV	BIT(0)
  #define SDIO3_CONF_SD_FB_CLK	BIT(2)
5491ce3f7   Marcin Wojtas   mmc: sdhci-pxav3:...
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  static int mv_conf_mbus_windows(struct platform_device *pdev,
  				const struct mbus_dram_target_info *dram)
  {
  	int i;
  	void __iomem *regs;
  	struct resource *res;
  
  	if (!dram) {
  		dev_err(&pdev->dev, "no mbus dram info
  ");
  		return -EINVAL;
  	}
  
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  	if (!res) {
  		dev_err(&pdev->dev, "cannot get mbus registers
  ");
  		return -EINVAL;
  	}
  
  	regs = ioremap(res->start, resource_size(res));
  	if (!regs) {
  		dev_err(&pdev->dev, "cannot map mbus registers
  ");
  		return -ENOMEM;
  	}
  
  	for (i = 0; i < SDHCI_MAX_WIN_NUM; i++) {
  		writel(0, regs + SDHCI_WINDOW_CTRL(i));
  		writel(0, regs + SDHCI_WINDOW_BASE(i));
  	}
  
  	for (i = 0; i < dram->num_cs; i++) {
  		const struct mbus_dram_window *cs = dram->cs + i;
  
  		/* Write size, attributes and target id to control register */
  		writel(((cs->size - 1) & 0xffff0000) |
  			(cs->mbus_attr << 8) |
  			(dram->mbus_dram_target_id << 4) | 1,
  			regs + SDHCI_WINDOW_CTRL(i));
  		/* Write base address to base register */
  		writel(cs->base, regs + SDHCI_WINDOW_BASE(i));
  	}
  
  	iounmap(regs);
  
  	return 0;
  }
a39128bcd   Marcin Wojtas   mmc: sdhci-pxav3:...
126
127
  static int armada_38x_quirks(struct platform_device *pdev,
  			     struct sdhci_host *host)
d4b803c55   Gregory CLEMENT   mmc: sdhci-pxav3:...
128
  {
a39128bcd   Marcin Wojtas   mmc: sdhci-pxav3:...
129
  	struct device_node *np = pdev->dev.of_node;
1140011ee   Marcin Wojtas   mmc: sdhci-pxav3:...
130
  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
f599da406   Jisheng Zhang   mmc: sdhci-pxav3:...
131
  	struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
1140011ee   Marcin Wojtas   mmc: sdhci-pxav3:...
132
  	struct resource *res;
a39128bcd   Marcin Wojtas   mmc: sdhci-pxav3:...
133

5de76bfcb   Nadav Haklai   mmc: sdhci-pxav3:...
134
  	host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
d4b803c55   Gregory CLEMENT   mmc: sdhci-pxav3:...
135
  	host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
0ca33b4ad   Russell King   mmc: sdhci-pxav3:...
136
137
138
  
  	host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
  	host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
1140011ee   Marcin Wojtas   mmc: sdhci-pxav3:...
139
140
141
142
143
144
145
146
147
148
149
150
151
  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
  					   "conf-sdio3");
  	if (res) {
  		pxa->sdio3_conf_reg = devm_ioremap_resource(&pdev->dev, res);
  		if (IS_ERR(pxa->sdio3_conf_reg))
  			return PTR_ERR(pxa->sdio3_conf_reg);
  	} else {
  		/*
  		 * According to erratum 'FE-2946959' both SDR50 and DDR50
  		 * modes require specific clock adjustments in SDIO3
  		 * Configuration register, if the adjustment is not done,
  		 * remove them from the capabilities.
  		 */
1140011ee   Marcin Wojtas   mmc: sdhci-pxav3:...
152
153
154
155
156
157
  		host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
  
  		dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.
  Consider updating your dtb
  ");
  	}
a39128bcd   Marcin Wojtas   mmc: sdhci-pxav3:...
158
159
160
161
162
163
  
  	/*
  	 * According to erratum 'ERR-7878951' Armada 38x SDHCI
  	 * controller has different capabilities than the ones shown
  	 * in its registers
  	 */
a39128bcd   Marcin Wojtas   mmc: sdhci-pxav3:...
164
165
166
167
168
169
170
  	if (of_property_read_bool(np, "no-1-8-v")) {
  		host->caps &= ~SDHCI_CAN_VDD_180;
  		host->mmc->caps &= ~MMC_CAP_1_8V_DDR;
  	} else {
  		host->caps &= ~SDHCI_CAN_VDD_330;
  	}
  	host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_USE_SDR50_TUNING);
d4b803c55   Gregory CLEMENT   mmc: sdhci-pxav3:...
171
172
  	return 0;
  }
03231f9b7   Russell King   mmc: sdhci: conve...
173
  static void pxav3_reset(struct sdhci_host *host, u8 mask)
a702c8abb   Zhangfei Gao   mmc: host: split ...
174
175
176
  {
  	struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
  	struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
03231f9b7   Russell King   mmc: sdhci: conve...
177
  	sdhci_reset(host, mask);
a702c8abb   Zhangfei Gao   mmc: host: split ...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  	if (mask == SDHCI_RESET_ALL) {
  		/*
  		 * tune timing of read data/command when crc error happen
  		 * no performance impact
  		 */
  		if (pdata && 0 != pdata->clk_delay_cycles) {
  			u16 tmp;
  
  			tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
  			tmp |= (pdata->clk_delay_cycles & SDCLK_DELAY_MASK)
  				<< SDCLK_DELAY_SHIFT;
  			tmp |= SDCLK_SEL;
  			writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
  		}
  	}
  }
  
  #define MAX_WAIT_COUNT 5
  static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
  {
  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
f599da406   Jisheng Zhang   mmc: sdhci-pxav3:...
199
  	struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
a702c8abb   Zhangfei Gao   mmc: host: split ...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  	u16 tmp;
  	int count;
  
  	if (pxa->power_mode == MMC_POWER_UP
  			&& power_mode == MMC_POWER_ON) {
  
  		dev_dbg(mmc_dev(host->mmc),
  				"%s: slot->power_mode = %d,"
  				"ios->power_mode = %d
  ",
  				__func__,
  				pxa->power_mode,
  				power_mode);
  
  		/* set we want notice of when 74 clocks are sent */
  		tmp = readw(host->ioaddr + SD_CE_ATA_2);
  		tmp |= SDCE_MISC_INT_EN;
  		writew(tmp, host->ioaddr + SD_CE_ATA_2);
  
  		/* start sending the 74 clocks */
  		tmp = readw(host->ioaddr + SD_CFG_FIFO_PARAM);
  		tmp |= SDCFG_GEN_PAD_CLK_ON;
  		writew(tmp, host->ioaddr + SD_CFG_FIFO_PARAM);
  
  		/* slowest speed is about 100KHz or 10usec per clock */
  		udelay(740);
  		count = 0;
  
  		while (count++ < MAX_WAIT_COUNT) {
  			if ((readw(host->ioaddr + SD_CE_ATA_2)
  						& SDCE_MISC_INT) == 0)
  				break;
  			udelay(10);
  		}
  
  		if (count == MAX_WAIT_COUNT)
  			dev_warn(mmc_dev(host->mmc), "74 clock interrupt not cleared
  ");
  
  		/* clear the interrupt bit if posted */
  		tmp = readw(host->ioaddr + SD_CE_ATA_2);
  		tmp |= SDCE_MISC_INT;
  		writew(tmp, host->ioaddr + SD_CE_ATA_2);
  	}
  	pxa->power_mode = power_mode;
  }
13e645012   Russell King   mmc: sdhci: set_u...
246
  static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
a702c8abb   Zhangfei Gao   mmc: host: split ...
247
  {
1140011ee   Marcin Wojtas   mmc: sdhci-pxav3:...
248
  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
f599da406   Jisheng Zhang   mmc: sdhci-pxav3:...
249
  	struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
a702c8abb   Zhangfei Gao   mmc: host: split ...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  	u16 ctrl_2;
  
  	/*
  	 * Set V18_EN -- UHS modes do not work without this.
  	 * does not change signaling voltage
  	 */
  	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
  
  	/* Select Bus Speed Mode for host */
  	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
  	switch (uhs) {
  	case MMC_TIMING_UHS_SDR12:
  		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
  		break;
  	case MMC_TIMING_UHS_SDR25:
  		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
  		break;
  	case MMC_TIMING_UHS_SDR50:
  		ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;
  		break;
  	case MMC_TIMING_UHS_SDR104:
  		ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
  		break;
668e84b20   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
273
  	case MMC_TIMING_MMC_DDR52:
a702c8abb   Zhangfei Gao   mmc: host: split ...
274
275
276
277
  	case MMC_TIMING_UHS_DDR50:
  		ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
  		break;
  	}
1140011ee   Marcin Wojtas   mmc: sdhci-pxav3:...
278
279
280
281
282
283
284
285
286
287
288
  	/*
  	 * Update SDIO3 Configuration register according to erratum
  	 * FE-2946959
  	 */
  	if (pxa->sdio3_conf_reg) {
  		u8 reg_val  = readb(pxa->sdio3_conf_reg);
  
  		if (uhs == MMC_TIMING_UHS_SDR50 ||
  		    uhs == MMC_TIMING_UHS_DDR50) {
  			reg_val &= ~SDIO3_CONF_CLK_INV;
  			reg_val |= SDIO3_CONF_SD_FB_CLK;
fa7964147   Nadav Haklai   mmc: sdhci-pxav3:...
289
290
291
  		} else if (uhs == MMC_TIMING_MMC_HS) {
  			reg_val &= ~SDIO3_CONF_CLK_INV;
  			reg_val &= ~SDIO3_CONF_SD_FB_CLK;
1140011ee   Marcin Wojtas   mmc: sdhci-pxav3:...
292
293
294
295
296
297
  		} else {
  			reg_val |= SDIO3_CONF_CLK_INV;
  			reg_val &= ~SDIO3_CONF_SD_FB_CLK;
  		}
  		writeb(reg_val, pxa->sdio3_conf_reg);
  	}
a702c8abb   Zhangfei Gao   mmc: host: split ...
298
299
300
301
302
  	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
  	dev_dbg(mmc_dev(host->mmc),
  		"%s uhs = %d, ctrl_2 = %04X
  ",
  		__func__, uhs, ctrl_2);
a702c8abb   Zhangfei Gao   mmc: host: split ...
303
  }
1dceb0415   Adrian Hunter   mmc: sdhci: Fix r...
304
305
306
307
308
  static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
  			    unsigned short vdd)
  {
  	struct mmc_host *mmc = host->mmc;
  	u8 pwr = host->pwr;
606d31312   Adrian Hunter   mmc: sdhci: Renam...
309
  	sdhci_set_power_noreg(host, mode, vdd);
1dceb0415   Adrian Hunter   mmc: sdhci: Fix r...
310
311
312
313
314
315
316
317
318
319
320
321
322
  
  	if (host->pwr == pwr)
  		return;
  
  	if (host->pwr == 0)
  		vdd = 0;
  
  	if (!IS_ERR(mmc->supply.vmmc)) {
  		spin_unlock_irq(&host->lock);
  		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
  		spin_lock_irq(&host->lock);
  	}
  }
c915568d9   Lars-Peter Clausen   mmc: sdhci: Const...
323
  static const struct sdhci_ops pxav3_sdhci_ops = {
1771059cf   Russell King   mmc: sdhci: conve...
324
  	.set_clock = sdhci_set_clock,
1dceb0415   Adrian Hunter   mmc: sdhci: Fix r...
325
  	.set_power = pxav3_set_power,
a702c8abb   Zhangfei Gao   mmc: host: split ...
326
  	.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
d005d9435   Lars-Peter Clausen   mmc: sdhci-pltfm:...
327
  	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
2317f56c0   Russell King   mmc: sdhci: conve...
328
  	.set_bus_width = sdhci_set_bus_width,
03231f9b7   Russell King   mmc: sdhci: conve...
329
  	.reset = pxav3_reset,
b31537657   Peter Griffin   mmc: sdhci-pxav3:...
330
  	.set_uhs_signaling = pxav3_set_uhs_signaling,
a702c8abb   Zhangfei Gao   mmc: host: split ...
331
  };
73b7afb97   Kevin Liu   mmc: sdhci-pxav3:...
332
  static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
e065162ae   Kevin Liu   mmc: sdhci-pxav3:...
333
  	.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
73b7afb97   Kevin Liu   mmc: sdhci-pxav3:...
334
335
336
337
338
  		| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
  		| SDHCI_QUIRK_32BIT_ADMA_SIZE
  		| SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
  	.ops = &pxav3_sdhci_ops,
  };
b650352dd   Chris Ball   mmc: sdhci-pxa: A...
339
340
341
342
343
  #ifdef CONFIG_OF
  static const struct of_device_id sdhci_pxav3_of_match[] = {
  	{
  		.compatible = "mrvl,pxav3-mmc",
  	},
5491ce3f7   Marcin Wojtas   mmc: sdhci-pxav3:...
344
345
346
  	{
  		.compatible = "marvell,armada-380-sdhci",
  	},
b650352dd   Chris Ball   mmc: sdhci-pxa: A...
347
348
349
350
351
352
353
354
  	{},
  };
  MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
  
  static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
  {
  	struct sdhci_pxa_platdata *pdata;
  	struct device_node *np = dev->of_node;
b650352dd   Chris Ball   mmc: sdhci-pxa: A...
355
356
357
358
359
  	u32 clk_delay_cycles;
  
  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
  	if (!pdata)
  		return NULL;
14460dbaf   Jisheng Zhang   mmc: sdhci-pxav3:...
360
361
  	if (!of_property_read_u32(np, "mrvl,clk-delay-cycles",
  				  &clk_delay_cycles))
b650352dd   Chris Ball   mmc: sdhci-pxa: A...
362
363
364
365
366
367
368
369
370
371
  		pdata->clk_delay_cycles = clk_delay_cycles;
  
  	return pdata;
  }
  #else
  static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
  {
  	return NULL;
  }
  #endif
c3be1efd4   Bill Pemberton   mmc: remove use o...
372
  static int sdhci_pxav3_probe(struct platform_device *pdev)
a702c8abb   Zhangfei Gao   mmc: host: split ...
373
374
375
376
  {
  	struct sdhci_pltfm_host *pltfm_host;
  	struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
  	struct device *dev = &pdev->dev;
5491ce3f7   Marcin Wojtas   mmc: sdhci-pxav3:...
377
  	struct device_node *np = pdev->dev.of_node;
a702c8abb   Zhangfei Gao   mmc: host: split ...
378
379
  	struct sdhci_host *host = NULL;
  	struct sdhci_pxa *pxa = NULL;
b650352dd   Chris Ball   mmc: sdhci-pxa: A...
380
  	const struct of_device_id *match;
a702c8abb   Zhangfei Gao   mmc: host: split ...
381
  	int ret;
a702c8abb   Zhangfei Gao   mmc: host: split ...
382

f599da406   Jisheng Zhang   mmc: sdhci-pxav3:...
383
  	host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, sizeof(*pxa));
3df5b2814   Laurent Pinchart   mmc: sdhci-pxav3:...
384
  	if (IS_ERR(host))
a702c8abb   Zhangfei Gao   mmc: host: split ...
385
  		return PTR_ERR(host);
5491ce3f7   Marcin Wojtas   mmc: sdhci-pxav3:...
386

a702c8abb   Zhangfei Gao   mmc: host: split ...
387
  	pltfm_host = sdhci_priv(host);
f599da406   Jisheng Zhang   mmc: sdhci-pxav3:...
388
  	pxa = sdhci_pltfm_priv(pltfm_host);
a702c8abb   Zhangfei Gao   mmc: host: split ...
389

01ae1070c   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
390
391
392
  	pxa->clk_io = devm_clk_get(dev, "io");
  	if (IS_ERR(pxa->clk_io))
  		pxa->clk_io = devm_clk_get(dev, NULL);
8c96a7a33   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
393
  	if (IS_ERR(pxa->clk_io)) {
a702c8abb   Zhangfei Gao   mmc: host: split ...
394
395
  		dev_err(dev, "failed to get io clock
  ");
8c96a7a33   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
396
  		ret = PTR_ERR(pxa->clk_io);
a702c8abb   Zhangfei Gao   mmc: host: split ...
397
398
  		goto err_clk_get;
  	}
8c96a7a33   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
399
400
  	pltfm_host->clk = pxa->clk_io;
  	clk_prepare_enable(pxa->clk_io);
a702c8abb   Zhangfei Gao   mmc: host: split ...
401

8afdc9cca   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
402
403
404
  	pxa->clk_core = devm_clk_get(dev, "core");
  	if (!IS_ERR(pxa->clk_core))
  		clk_prepare_enable(pxa->clk_core);
a39128bcd   Marcin Wojtas   mmc: sdhci-pxav3:...
405
406
  	/* enable 1/8V DDR capable */
  	host->mmc->caps |= MMC_CAP_1_8V_DDR;
aa8165f91   Thomas Petazzoni   mmc: sdhci-pxav3:...
407
  	if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) {
a39128bcd   Marcin Wojtas   mmc: sdhci-pxav3:...
408
  		ret = armada_38x_quirks(pdev, host);
d4b803c55   Gregory CLEMENT   mmc: sdhci-pxav3:...
409
  		if (ret < 0)
2162d9f41   Marcin Wojtas   mmc: sdhci-pxav3:...
410
  			goto err_mbus_win;
aa8165f91   Thomas Petazzoni   mmc: sdhci-pxav3:...
411
412
413
414
  		ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info());
  		if (ret < 0)
  			goto err_mbus_win;
  	}
b650352dd   Chris Ball   mmc: sdhci-pxa: A...
415
  	match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
943647f6f   Kevin Liu   mmc: sdhci-pxav3:...
416
  	if (match) {
d2cf6071c   Simon Baatz   mmc: sdhci-pxav3:...
417
418
419
  		ret = mmc_of_parse(host->mmc);
  		if (ret)
  			goto err_of_parse;
943647f6f   Kevin Liu   mmc: sdhci-pxav3:...
420
  		sdhci_get_of_property(pdev);
b650352dd   Chris Ball   mmc: sdhci-pxa: A...
421
  		pdata = pxav3_get_mmc_pdata(dev);
9cd76049f   Jingju Hou   mmc: sdhci-pxav3:...
422
  		pdev->dev.platform_data = pdata;
943647f6f   Kevin Liu   mmc: sdhci-pxav3:...
423
  	} else if (pdata) {
c844a46f1   Kevin Liu   mmc: sdhci-pxav3:...
424
425
  		/* on-chip device */
  		if (pdata->flags & PXA_FLAG_CARD_PERMANENT)
a702c8abb   Zhangfei Gao   mmc: host: split ...
426
  			host->mmc->caps |= MMC_CAP_NONREMOVABLE;
a702c8abb   Zhangfei Gao   mmc: host: split ...
427
428
429
430
431
432
433
  
  		/* If slot design supports 8 bit data, indicate this to MMC. */
  		if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
  			host->mmc->caps |= MMC_CAP_8_BIT_DATA;
  
  		if (pdata->quirks)
  			host->quirks |= pdata->quirks;
7c52d7bb8   Kevin Liu   mmc: sdhci-pxav3:...
434
435
  		if (pdata->quirks2)
  			host->quirks2 |= pdata->quirks2;
a702c8abb   Zhangfei Gao   mmc: host: split ...
436
437
  		if (pdata->host_caps)
  			host->mmc->caps |= pdata->host_caps;
8f63795c6   Chris Ball   mmc: sdhci-pxav3:...
438
439
  		if (pdata->host_caps2)
  			host->mmc->caps2 |= pdata->host_caps2;
a702c8abb   Zhangfei Gao   mmc: host: split ...
440
441
  		if (pdata->pm_caps)
  			host->mmc->pm_caps |= pdata->pm_caps;
8f63795c6   Chris Ball   mmc: sdhci-pxav3:...
442
443
  
  		if (gpio_is_valid(pdata->ext_cd_gpio)) {
214fc309d   Laurent Pinchart   mmc: slot-gpio: A...
444
445
  			ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio,
  						  0);
8f63795c6   Chris Ball   mmc: sdhci-pxav3:...
446
447
448
449
450
451
452
  			if (ret) {
  				dev_err(mmc_dev(host->mmc),
  					"failed to allocate card detect gpio
  ");
  				goto err_cd_req;
  			}
  		}
a702c8abb   Zhangfei Gao   mmc: host: split ...
453
  	}
62cf983ad   Jisheng Zhang   mmc: sdhci-pxav3:...
454
455
  	pm_runtime_get_noresume(&pdev->dev);
  	pm_runtime_set_active(&pdev->dev);
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
456
457
  	pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS);
  	pm_runtime_use_autosuspend(&pdev->dev);
62cf983ad   Jisheng Zhang   mmc: sdhci-pxav3:...
458
  	pm_runtime_enable(&pdev->dev);
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
459
  	pm_suspend_ignore_children(&pdev->dev, 1);
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
460

a702c8abb   Zhangfei Gao   mmc: host: split ...
461
462
463
464
465
466
467
468
  	ret = sdhci_add_host(host);
  	if (ret) {
  		dev_err(&pdev->dev, "failed to add host
  ");
  		goto err_add_host;
  	}
  
  	platform_set_drvdata(pdev, host);
83dc9fecd   Jisheng Zhang   mmc: sdhci-pxav3:...
469
  	if (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ)
740b7a44a   Kevin Liu   mmc: sdhci-pxav3:...
470
  		device_init_wakeup(&pdev->dev, 1);
740b7a44a   Kevin Liu   mmc: sdhci-pxav3:...
471

bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
472
  	pm_runtime_put_autosuspend(&pdev->dev);
a702c8abb   Zhangfei Gao   mmc: host: split ...
473
474
475
  	return 0;
  
  err_add_host:
0dcaa2499   Daniel Drake   sdhci-pxav3: Fix ...
476
  	pm_runtime_disable(&pdev->dev);
62cf983ad   Jisheng Zhang   mmc: sdhci-pxav3:...
477
  	pm_runtime_put_noidle(&pdev->dev);
87d2163da   Xiang Wang   mmc: sdhci-pxav3:...
478
479
  err_of_parse:
  err_cd_req:
aa8165f91   Thomas Petazzoni   mmc: sdhci-pxav3:...
480
  err_mbus_win:
8c96a7a33   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
481
  	clk_disable_unprepare(pxa->clk_io);
c25d9e1bd   Jisheng Zhang   mmc: sdhci-pxav3:...
482
  	clk_disable_unprepare(pxa->clk_core);
a702c8abb   Zhangfei Gao   mmc: host: split ...
483
484
  err_clk_get:
  	sdhci_pltfm_free(pdev);
a702c8abb   Zhangfei Gao   mmc: host: split ...
485
486
  	return ret;
  }
6e0ee714f   Bill Pemberton   mmc: remove use o...
487
  static int sdhci_pxav3_remove(struct platform_device *pdev)
a702c8abb   Zhangfei Gao   mmc: host: split ...
488
489
490
  {
  	struct sdhci_host *host = platform_get_drvdata(pdev);
  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
f599da406   Jisheng Zhang   mmc: sdhci-pxav3:...
491
  	struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
a702c8abb   Zhangfei Gao   mmc: host: split ...
492

bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
493
  	pm_runtime_get_sync(&pdev->dev);
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
494
  	pm_runtime_disable(&pdev->dev);
20f1f2d7d   Jisheng Zhang   mmc: sdhci-pxav3:...
495
496
497
  	pm_runtime_put_noidle(&pdev->dev);
  
  	sdhci_remove_host(host, 1);
a702c8abb   Zhangfei Gao   mmc: host: split ...
498

8c96a7a33   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
499
  	clk_disable_unprepare(pxa->clk_io);
c25d9e1bd   Jisheng Zhang   mmc: sdhci-pxav3:...
500
  	clk_disable_unprepare(pxa->clk_core);
8f63795c6   Chris Ball   mmc: sdhci-pxav3:...
501

a702c8abb   Zhangfei Gao   mmc: host: split ...
502
  	sdhci_pltfm_free(pdev);
a702c8abb   Zhangfei Gao   mmc: host: split ...
503

a702c8abb   Zhangfei Gao   mmc: host: split ...
504
505
  	return 0;
  }
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  #ifdef CONFIG_PM_SLEEP
  static int sdhci_pxav3_suspend(struct device *dev)
  {
  	int ret;
  	struct sdhci_host *host = dev_get_drvdata(dev);
  
  	pm_runtime_get_sync(dev);
  	ret = sdhci_suspend_host(host);
  	pm_runtime_mark_last_busy(dev);
  	pm_runtime_put_autosuspend(dev);
  
  	return ret;
  }
  
  static int sdhci_pxav3_resume(struct device *dev)
  {
  	int ret;
  	struct sdhci_host *host = dev_get_drvdata(dev);
  
  	pm_runtime_get_sync(dev);
  	ret = sdhci_resume_host(host);
  	pm_runtime_mark_last_busy(dev);
  	pm_runtime_put_autosuspend(dev);
  
  	return ret;
  }
  #endif
162d6f980   Rafael J. Wysocki   MMC / PM: Replace...
533
  #ifdef CONFIG_PM
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
534
535
536
537
  static int sdhci_pxav3_runtime_suspend(struct device *dev)
  {
  	struct sdhci_host *host = dev_get_drvdata(dev);
  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
f599da406   Jisheng Zhang   mmc: sdhci-pxav3:...
538
  	struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
3bb10f609   Jisheng Zhang   mmc: sdhci-pxav3:...
539
  	int ret;
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
540

3bb10f609   Jisheng Zhang   mmc: sdhci-pxav3:...
541
542
543
  	ret = sdhci_runtime_suspend_host(host);
  	if (ret)
  		return ret;
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
544

8c96a7a33   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
545
  	clk_disable_unprepare(pxa->clk_io);
8afdc9cca   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
546
547
  	if (!IS_ERR(pxa->clk_core))
  		clk_disable_unprepare(pxa->clk_core);
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
548
549
550
551
552
553
554
555
  
  	return 0;
  }
  
  static int sdhci_pxav3_runtime_resume(struct device *dev)
  {
  	struct sdhci_host *host = dev_get_drvdata(dev);
  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
f599da406   Jisheng Zhang   mmc: sdhci-pxav3:...
556
  	struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
557

8c96a7a33   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
558
  	clk_prepare_enable(pxa->clk_io);
8afdc9cca   Sebastian Hesselbarth   mmc: sdhci-pxav3:...
559
560
  	if (!IS_ERR(pxa->clk_core))
  		clk_prepare_enable(pxa->clk_core);
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
561

3bb10f609   Jisheng Zhang   mmc: sdhci-pxav3:...
562
  	return sdhci_runtime_resume_host(host);
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
563
564
  }
  #endif
bb691ae46   Kevin Liu   mmc: sdhci-pxav3:...
565
566
567
568
569
  static const struct dev_pm_ops sdhci_pxav3_pmops = {
  	SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume)
  	SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend,
  		sdhci_pxav3_runtime_resume, NULL)
  };
a702c8abb   Zhangfei Gao   mmc: host: split ...
570
571
572
  static struct platform_driver sdhci_pxav3_driver = {
  	.driver		= {
  		.name	= "sdhci-pxav3",
59d22309c   Axel Lin   mmc: sdhci-{pxav2...
573
  		.of_match_table = of_match_ptr(sdhci_pxav3_of_match),
a81ce7723   Ulf Hansson   mmc: sdhci-pxav3:...
574
  		.pm	= &sdhci_pxav3_pmops,
a702c8abb   Zhangfei Gao   mmc: host: split ...
575
576
  	},
  	.probe		= sdhci_pxav3_probe,
0433c1435   Bill Pemberton   mmc: remove use o...
577
  	.remove		= sdhci_pxav3_remove,
a702c8abb   Zhangfei Gao   mmc: host: split ...
578
  };
a702c8abb   Zhangfei Gao   mmc: host: split ...
579

d1f81a64a   Axel Lin   mmc: convert driv...
580
  module_platform_driver(sdhci_pxav3_driver);
a702c8abb   Zhangfei Gao   mmc: host: split ...
581
582
583
584
  
  MODULE_DESCRIPTION("SDHCI driver for pxav3");
  MODULE_AUTHOR("Marvell International Ltd.");
  MODULE_LICENSE("GPL v2");