Blame view
drivers/mmc/host/sdhci-pxav3.c
15.4 KB
a702c8abb 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 mmc: sdhci-pxav3:... |
27 |
#include <linux/mmc/slot-gpio.h> |
bfed345ed mmc: sdhci-pxa: m... |
28 |
#include <linux/platform_data/pxa_sdhci.h> |
a702c8abb mmc: host: split ... |
29 30 |
#include <linux/slab.h> #include <linux/delay.h> |
88b476797 mmc: Add module.h... |
31 |
#include <linux/module.h> |
b650352dd mmc: sdhci-pxa: A... |
32 33 |
#include <linux/of.h> #include <linux/of_device.h> |
8f63795c6 mmc: sdhci-pxav3:... |
34 |
#include <linux/of_gpio.h> |
bb691ae46 mmc: sdhci-pxav3:... |
35 36 |
#include <linux/pm.h> #include <linux/pm_runtime.h> |
5491ce3f7 mmc: sdhci-pxav3:... |
37 |
#include <linux/mbus.h> |
b650352dd mmc: sdhci-pxa: A... |
38 |
|
a702c8abb mmc: host: split ... |
39 40 |
#include "sdhci.h" #include "sdhci-pltfm.h" |
bb691ae46 mmc: sdhci-pxav3:... |
41 |
#define PXAV3_RPM_DELAY_MS 50 |
a702c8abb 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 mmc: sdhci-pxav3:... |
58 |
struct sdhci_pxa { |
8afdc9cca mmc: sdhci-pxav3:... |
59 |
struct clk *clk_core; |
8c96a7a33 mmc: sdhci-pxav3:... |
60 |
struct clk *clk_io; |
cc9571e85 mmc: sdhci-pxav3:... |
61 |
u8 power_mode; |
1140011ee mmc: sdhci-pxav3:... |
62 |
void __iomem *sdio3_conf_reg; |
cc9571e85 mmc: sdhci-pxav3:... |
63 |
}; |
5491ce3f7 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 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 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 mmc: sdhci-pxav3:... |
126 127 |
static int armada_38x_quirks(struct platform_device *pdev, struct sdhci_host *host) |
d4b803c55 mmc: sdhci-pxav3:... |
128 |
{ |
a39128bcd mmc: sdhci-pxav3:... |
129 |
struct device_node *np = pdev->dev.of_node; |
1140011ee mmc: sdhci-pxav3:... |
130 |
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
f599da406 mmc: sdhci-pxav3:... |
131 |
struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); |
1140011ee mmc: sdhci-pxav3:... |
132 |
struct resource *res; |
a39128bcd mmc: sdhci-pxav3:... |
133 |
|
5de76bfcb mmc: sdhci-pxav3:... |
134 |
host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; |
d4b803c55 mmc: sdhci-pxav3:... |
135 |
host->quirks |= SDHCI_QUIRK_MISSING_CAPS; |
0ca33b4ad mmc: sdhci-pxav3:... |
136 137 138 |
host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); |
1140011ee 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 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 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 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 mmc: sdhci-pxav3:... |
171 172 |
return 0; } |
03231f9b7 mmc: sdhci: conve... |
173 |
static void pxav3_reset(struct sdhci_host *host, u8 mask) |
a702c8abb 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 mmc: sdhci: conve... |
177 |
sdhci_reset(host, mask); |
a702c8abb 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 mmc: sdhci-pxav3:... |
199 |
struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); |
a702c8abb 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 mmc: sdhci: set_u... |
246 |
static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) |
a702c8abb mmc: host: split ... |
247 |
{ |
1140011ee mmc: sdhci-pxav3:... |
248 |
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
f599da406 mmc: sdhci-pxav3:... |
249 |
struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); |
a702c8abb 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 mmc: sdhci-pxav3:... |
273 |
case MMC_TIMING_MMC_DDR52: |
a702c8abb mmc: host: split ... |
274 275 276 277 |
case MMC_TIMING_UHS_DDR50: ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; break; } |
1140011ee 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 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 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 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 mmc: host: split ... |
303 |
} |
1dceb0415 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 mmc: sdhci: Renam... |
309 |
sdhci_set_power_noreg(host, mode, vdd); |
1dceb0415 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 mmc: sdhci: Const... |
323 |
static const struct sdhci_ops pxav3_sdhci_ops = { |
1771059cf mmc: sdhci: conve... |
324 |
.set_clock = sdhci_set_clock, |
1dceb0415 mmc: sdhci: Fix r... |
325 |
.set_power = pxav3_set_power, |
a702c8abb mmc: host: split ... |
326 |
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks, |
d005d9435 mmc: sdhci-pltfm:... |
327 |
.get_max_clock = sdhci_pltfm_clk_get_max_clock, |
2317f56c0 mmc: sdhci: conve... |
328 |
.set_bus_width = sdhci_set_bus_width, |
03231f9b7 mmc: sdhci: conve... |
329 |
.reset = pxav3_reset, |
b31537657 mmc: sdhci-pxav3:... |
330 |
.set_uhs_signaling = pxav3_set_uhs_signaling, |
a702c8abb mmc: host: split ... |
331 |
}; |
73b7afb97 mmc: sdhci-pxav3:... |
332 |
static struct sdhci_pltfm_data sdhci_pxav3_pdata = { |
e065162ae mmc: sdhci-pxav3:... |
333 |
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
73b7afb97 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 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 mmc: sdhci-pxav3:... |
344 345 346 |
{ .compatible = "marvell,armada-380-sdhci", }, |
b650352dd 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 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 mmc: sdhci-pxav3:... |
360 361 |
if (!of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles)) |
b650352dd 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 mmc: remove use o... |
372 |
static int sdhci_pxav3_probe(struct platform_device *pdev) |
a702c8abb 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 mmc: sdhci-pxav3:... |
377 |
struct device_node *np = pdev->dev.of_node; |
a702c8abb mmc: host: split ... |
378 379 |
struct sdhci_host *host = NULL; struct sdhci_pxa *pxa = NULL; |
b650352dd mmc: sdhci-pxa: A... |
380 |
const struct of_device_id *match; |
a702c8abb mmc: host: split ... |
381 |
int ret; |
a702c8abb mmc: host: split ... |
382 |
|
f599da406 mmc: sdhci-pxav3:... |
383 |
host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, sizeof(*pxa)); |
3df5b2814 mmc: sdhci-pxav3:... |
384 |
if (IS_ERR(host)) |
a702c8abb mmc: host: split ... |
385 |
return PTR_ERR(host); |
5491ce3f7 mmc: sdhci-pxav3:... |
386 |
|
a702c8abb mmc: host: split ... |
387 |
pltfm_host = sdhci_priv(host); |
f599da406 mmc: sdhci-pxav3:... |
388 |
pxa = sdhci_pltfm_priv(pltfm_host); |
a702c8abb mmc: host: split ... |
389 |
|
01ae1070c 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 mmc: sdhci-pxav3:... |
393 |
if (IS_ERR(pxa->clk_io)) { |
a702c8abb mmc: host: split ... |
394 395 |
dev_err(dev, "failed to get io clock "); |
8c96a7a33 mmc: sdhci-pxav3:... |
396 |
ret = PTR_ERR(pxa->clk_io); |
a702c8abb mmc: host: split ... |
397 398 |
goto err_clk_get; } |
8c96a7a33 mmc: sdhci-pxav3:... |
399 400 |
pltfm_host->clk = pxa->clk_io; clk_prepare_enable(pxa->clk_io); |
a702c8abb mmc: host: split ... |
401 |
|
8afdc9cca 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 mmc: sdhci-pxav3:... |
405 406 |
/* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; |
aa8165f91 mmc: sdhci-pxav3:... |
407 |
if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) { |
a39128bcd mmc: sdhci-pxav3:... |
408 |
ret = armada_38x_quirks(pdev, host); |
d4b803c55 mmc: sdhci-pxav3:... |
409 |
if (ret < 0) |
2162d9f41 mmc: sdhci-pxav3:... |
410 |
goto err_mbus_win; |
aa8165f91 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 mmc: sdhci-pxa: A... |
415 |
match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); |
943647f6f mmc: sdhci-pxav3:... |
416 |
if (match) { |
d2cf6071c mmc: sdhci-pxav3:... |
417 418 419 |
ret = mmc_of_parse(host->mmc); if (ret) goto err_of_parse; |
943647f6f mmc: sdhci-pxav3:... |
420 |
sdhci_get_of_property(pdev); |
b650352dd mmc: sdhci-pxa: A... |
421 |
pdata = pxav3_get_mmc_pdata(dev); |
9cd76049f mmc: sdhci-pxav3:... |
422 |
pdev->dev.platform_data = pdata; |
943647f6f mmc: sdhci-pxav3:... |
423 |
} else if (pdata) { |
c844a46f1 mmc: sdhci-pxav3:... |
424 425 |
/* on-chip device */ if (pdata->flags & PXA_FLAG_CARD_PERMANENT) |
a702c8abb mmc: host: split ... |
426 |
host->mmc->caps |= MMC_CAP_NONREMOVABLE; |
a702c8abb 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 mmc: sdhci-pxav3:... |
434 435 |
if (pdata->quirks2) host->quirks2 |= pdata->quirks2; |
a702c8abb mmc: host: split ... |
436 437 |
if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; |
8f63795c6 mmc: sdhci-pxav3:... |
438 439 |
if (pdata->host_caps2) host->mmc->caps2 |= pdata->host_caps2; |
a702c8abb mmc: host: split ... |
440 441 |
if (pdata->pm_caps) host->mmc->pm_caps |= pdata->pm_caps; |
8f63795c6 mmc: sdhci-pxav3:... |
442 443 |
if (gpio_is_valid(pdata->ext_cd_gpio)) { |
214fc309d mmc: slot-gpio: A... |
444 445 |
ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio, 0); |
8f63795c6 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 mmc: host: split ... |
453 |
} |
62cf983ad mmc: sdhci-pxav3:... |
454 455 |
pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); |
bb691ae46 mmc: sdhci-pxav3:... |
456 457 |
pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); |
62cf983ad mmc: sdhci-pxav3:... |
458 |
pm_runtime_enable(&pdev->dev); |
bb691ae46 mmc: sdhci-pxav3:... |
459 |
pm_suspend_ignore_children(&pdev->dev, 1); |
bb691ae46 mmc: sdhci-pxav3:... |
460 |
|
a702c8abb 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 mmc: sdhci-pxav3:... |
469 |
if (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ) |
740b7a44a mmc: sdhci-pxav3:... |
470 |
device_init_wakeup(&pdev->dev, 1); |
740b7a44a mmc: sdhci-pxav3:... |
471 |
|
bb691ae46 mmc: sdhci-pxav3:... |
472 |
pm_runtime_put_autosuspend(&pdev->dev); |
a702c8abb mmc: host: split ... |
473 474 475 |
return 0; err_add_host: |
0dcaa2499 sdhci-pxav3: Fix ... |
476 |
pm_runtime_disable(&pdev->dev); |
62cf983ad mmc: sdhci-pxav3:... |
477 |
pm_runtime_put_noidle(&pdev->dev); |
87d2163da mmc: sdhci-pxav3:... |
478 479 |
err_of_parse: err_cd_req: |
aa8165f91 mmc: sdhci-pxav3:... |
480 |
err_mbus_win: |
8c96a7a33 mmc: sdhci-pxav3:... |
481 |
clk_disable_unprepare(pxa->clk_io); |
c25d9e1bd mmc: sdhci-pxav3:... |
482 |
clk_disable_unprepare(pxa->clk_core); |
a702c8abb mmc: host: split ... |
483 484 |
err_clk_get: sdhci_pltfm_free(pdev); |
a702c8abb mmc: host: split ... |
485 486 |
return ret; } |
6e0ee714f mmc: remove use o... |
487 |
static int sdhci_pxav3_remove(struct platform_device *pdev) |
a702c8abb mmc: host: split ... |
488 489 490 |
{ struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
f599da406 mmc: sdhci-pxav3:... |
491 |
struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); |
a702c8abb mmc: host: split ... |
492 |
|
bb691ae46 mmc: sdhci-pxav3:... |
493 |
pm_runtime_get_sync(&pdev->dev); |
bb691ae46 mmc: sdhci-pxav3:... |
494 |
pm_runtime_disable(&pdev->dev); |
20f1f2d7d mmc: sdhci-pxav3:... |
495 496 497 |
pm_runtime_put_noidle(&pdev->dev); sdhci_remove_host(host, 1); |
a702c8abb mmc: host: split ... |
498 |
|
8c96a7a33 mmc: sdhci-pxav3:... |
499 |
clk_disable_unprepare(pxa->clk_io); |
c25d9e1bd mmc: sdhci-pxav3:... |
500 |
clk_disable_unprepare(pxa->clk_core); |
8f63795c6 mmc: sdhci-pxav3:... |
501 |
|
a702c8abb mmc: host: split ... |
502 |
sdhci_pltfm_free(pdev); |
a702c8abb mmc: host: split ... |
503 |
|
a702c8abb mmc: host: split ... |
504 505 |
return 0; } |
bb691ae46 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 MMC / PM: Replace... |
533 |
#ifdef CONFIG_PM |
bb691ae46 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 mmc: sdhci-pxav3:... |
538 |
struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); |
3bb10f609 mmc: sdhci-pxav3:... |
539 |
int ret; |
bb691ae46 mmc: sdhci-pxav3:... |
540 |
|
3bb10f609 mmc: sdhci-pxav3:... |
541 542 543 |
ret = sdhci_runtime_suspend_host(host); if (ret) return ret; |
bb691ae46 mmc: sdhci-pxav3:... |
544 |
|
8c96a7a33 mmc: sdhci-pxav3:... |
545 |
clk_disable_unprepare(pxa->clk_io); |
8afdc9cca mmc: sdhci-pxav3:... |
546 547 |
if (!IS_ERR(pxa->clk_core)) clk_disable_unprepare(pxa->clk_core); |
bb691ae46 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 mmc: sdhci-pxav3:... |
556 |
struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); |
bb691ae46 mmc: sdhci-pxav3:... |
557 |
|
8c96a7a33 mmc: sdhci-pxav3:... |
558 |
clk_prepare_enable(pxa->clk_io); |
8afdc9cca mmc: sdhci-pxav3:... |
559 560 |
if (!IS_ERR(pxa->clk_core)) clk_prepare_enable(pxa->clk_core); |
bb691ae46 mmc: sdhci-pxav3:... |
561 |
|
3bb10f609 mmc: sdhci-pxav3:... |
562 |
return sdhci_runtime_resume_host(host); |
bb691ae46 mmc: sdhci-pxav3:... |
563 564 |
} #endif |
bb691ae46 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 mmc: host: split ... |
570 571 572 |
static struct platform_driver sdhci_pxav3_driver = { .driver = { .name = "sdhci-pxav3", |
59d22309c mmc: sdhci-{pxav2... |
573 |
.of_match_table = of_match_ptr(sdhci_pxav3_of_match), |
a81ce7723 mmc: sdhci-pxav3:... |
574 |
.pm = &sdhci_pxav3_pmops, |
a702c8abb mmc: host: split ... |
575 576 |
}, .probe = sdhci_pxav3_probe, |
0433c1435 mmc: remove use o... |
577 |
.remove = sdhci_pxav3_remove, |
a702c8abb mmc: host: split ... |
578 |
}; |
a702c8abb mmc: host: split ... |
579 |
|
d1f81a64a mmc: convert driv... |
580 |
module_platform_driver(sdhci_pxav3_driver); |
a702c8abb mmc: host: split ... |
581 582 583 584 |
MODULE_DESCRIPTION("SDHCI driver for pxav3"); MODULE_AUTHOR("Marvell International Ltd."); MODULE_LICENSE("GPL v2"); |