Commit | Line | Data |
---|---|---|
a87d5638 MD |
1 | /* |
2 | * SuperH Mobile SDHI | |
3 | * | |
a72e8b17 WS |
4 | * Copyright (C) 2016 Sang Engineering, Wolfram Sang |
5 | * Copyright (C) 2015-16 Renesas Electronics Corporation | |
a87d5638 MD |
6 | * Copyright (C) 2009 Magnus Damm |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | * Based on "Compaq ASIC3 support": | |
13 | * | |
14 | * Copyright 2001 Compaq Computer Corporation. | |
15 | * Copyright 2004-2005 Phil Blundell | |
16 | * Copyright 2007-2008 OpenedHand Ltd. | |
17 | * | |
18 | * Authors: Phil Blundell <pb@handhelds.org>, | |
19 | * Samuel Ortiz <sameo@openedhand.com> | |
20 | * | |
21 | */ | |
22 | ||
23 | #include <linux/kernel.h> | |
24 | #include <linux/clk.h> | |
5a0e3ad6 | 25 | #include <linux/slab.h> |
c7bb4487 | 26 | #include <linux/mod_devicetable.h> |
88b47679 | 27 | #include <linux/module.h> |
5a00a971 | 28 | #include <linux/of_device.h> |
a87d5638 | 29 | #include <linux/platform_device.h> |
3c49e810 | 30 | #include <linux/mmc/host.h> |
a87d5638 | 31 | #include <linux/mfd/tmio.h> |
056676da | 32 | #include <linux/sh_dma.h> |
973ed3af | 33 | #include <linux/delay.h> |
057a4592 WS |
34 | #include <linux/pinctrl/consumer.h> |
35 | #include <linux/pinctrl/pinctrl-state.h> | |
36 | #include <linux/regulator/consumer.h> | |
a87d5638 | 37 | |
42051e8a GL |
38 | #include "tmio_mmc.h" |
39 | ||
e3c418f1 KM |
40 | #define EXT_ACC 0xe4 |
41 | ||
16935250 KM |
42 | #define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data) |
43 | ||
5a00a971 GL |
44 | struct sh_mobile_sdhi_of_data { |
45 | unsigned long tmio_flags; | |
b3a5d4ce | 46 | unsigned long capabilities; |
423f6c2e | 47 | unsigned long capabilities2; |
f45394d5 | 48 | enum dma_slave_buswidth dma_buswidth; |
384b2cbd | 49 | dma_addr_t dma_rx_offset; |
a72e8b17 | 50 | unsigned bus_shift; |
5a00a971 GL |
51 | }; |
52 | ||
13bbd8af WS |
53 | static const struct sh_mobile_sdhi_of_data of_default_cfg = { |
54 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, | |
5a00a971 GL |
55 | }; |
56 | ||
b3a5d4ce | 57 | static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = { |
da29fe2b SU |
58 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | |
59 | TMIO_MMC_CLK_ACTUAL, | |
b3a5d4ce KM |
60 | .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, |
61 | }; | |
62 | ||
423f6c2e | 63 | static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { |
da29fe2b | 64 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | |
3d376fb2 | 65 | TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, |
423f6c2e | 66 | .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, |
f45394d5 | 67 | .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, |
384b2cbd | 68 | .dma_rx_offset = 0x2000, |
423f6c2e KM |
69 | }; |
70 | ||
a72e8b17 WS |
71 | static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = { |
72 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | | |
3d376fb2 | 73 | TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, |
a72e8b17 WS |
74 | .capabilities = MMC_CAP_SD_HIGHSPEED, |
75 | .bus_shift = 2, | |
76 | }; | |
77 | ||
2772ef30 KM |
78 | static const struct of_device_id sh_mobile_sdhi_of_match[] = { |
79 | { .compatible = "renesas,sdhi-shmobile" }, | |
13bbd8af WS |
80 | { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, }, |
81 | { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, }, | |
82 | { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, }, | |
b3a5d4ce | 83 | { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, }, |
81bbbc72 | 84 | { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, }, |
423f6c2e | 85 | { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, }, |
81918d25 | 86 | { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, }, |
a6386403 GU |
87 | { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, }, |
88 | { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, }, | |
89 | { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, }, | |
a72e8b17 | 90 | { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, }, |
2772ef30 KM |
91 | {}, |
92 | }; | |
93 | MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); | |
94 | ||
a87d5638 MD |
95 | struct sh_mobile_sdhi { |
96 | struct clk *clk; | |
97 | struct tmio_mmc_data mmc_data; | |
056676da | 98 | struct tmio_mmc_dma dma_priv; |
057a4592 WS |
99 | struct pinctrl *pinctrl; |
100 | struct pinctrl_state *pins_default, *pins_uhs; | |
a87d5638 MD |
101 | }; |
102 | ||
f45394d5 KM |
103 | static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) |
104 | { | |
105 | u32 val; | |
106 | ||
107 | /* | |
108 | * see also | |
109 | * sh_mobile_sdhi_of_data :: dma_buswidth | |
110 | */ | |
111 | switch (sd_ctrl_read16(host, CTL_VERSION)) { | |
112 | case 0x490C: | |
113 | val = (width == 32) ? 0x0001 : 0x0000; | |
114 | break; | |
115 | case 0xCB0D: | |
116 | val = (width == 32) ? 0x0000 : 0x0001; | |
117 | break; | |
a72e8b17 WS |
118 | case 0xCC10: /* Gen3, SD only */ |
119 | case 0xCD10: /* Gen3, SD + MMC */ | |
120 | if (width == 64) | |
121 | val = 0x0000; | |
122 | else if (width == 32) | |
123 | val = 0x0101; | |
124 | else | |
125 | val = 0x0001; | |
126 | break; | |
f45394d5 KM |
127 | default: |
128 | /* nothing to do */ | |
129 | return; | |
130 | } | |
131 | ||
132 | sd_ctrl_write16(host, EXT_ACC, val); | |
133 | } | |
134 | ||
0ea28210 | 135 | static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host) |
56c49287 | 136 | { |
0ea28210 | 137 | struct mmc_host *mmc = host->mmc; |
16935250 | 138 | struct sh_mobile_sdhi *priv = host_to_priv(host); |
00fb3d2a | 139 | int ret = clk_prepare_enable(priv->clk); |
56c49287 GL |
140 | if (ret < 0) |
141 | return ret; | |
142 | ||
2fb55956 BH |
143 | /* |
144 | * The clock driver may not know what maximum frequency | |
145 | * actually works, so it should be set with the max-frequency | |
146 | * property which will already have been read to f_max. If it | |
147 | * was missing, assume the current frequency is the maximum. | |
148 | */ | |
149 | if (!mmc->f_max) | |
150 | mmc->f_max = clk_get_rate(priv->clk); | |
151 | ||
152 | /* | |
153 | * Minimum frequency is the minimum input clock frequency | |
154 | * divided by our maximum divider. | |
155 | */ | |
156 | mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L); | |
f45394d5 KM |
157 | |
158 | /* enable 16bit data access on SDBUF as default */ | |
159 | sh_mobile_sdhi_sdbuf_width(host, 16); | |
160 | ||
56c49287 GL |
161 | return 0; |
162 | } | |
163 | ||
2fb55956 BH |
164 | static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host, |
165 | unsigned int new_clock) | |
166 | { | |
167 | struct sh_mobile_sdhi *priv = host_to_priv(host); | |
3072ba8c | 168 | unsigned int freq, diff, best_freq = 0, diff_min = ~0; |
2fb55956 BH |
169 | int i; |
170 | ||
8fc00998 WS |
171 | /* tested only on RCar Gen2+ currently; may work for others */ |
172 | if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) | |
173 | return clk_get_rate(priv->clk); | |
174 | ||
2fb55956 BH |
175 | /* |
176 | * We want the bus clock to be as close as possible to, but no | |
177 | * greater than, new_clock. As we can divide by 1 << i for | |
178 | * any i in [0, 9] we want the input clock to be as close as | |
179 | * possible, but no greater than, new_clock << i. | |
180 | */ | |
181 | for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) { | |
182 | freq = clk_round_rate(priv->clk, new_clock << i); | |
183 | if (freq > (new_clock << i)) { | |
184 | /* Too fast; look for a slightly slower option */ | |
185 | freq = clk_round_rate(priv->clk, | |
186 | (new_clock << i) / 4 * 3); | |
187 | if (freq > (new_clock << i)) | |
188 | continue; | |
189 | } | |
190 | ||
191 | diff = new_clock - (freq >> i); | |
192 | if (diff <= diff_min) { | |
193 | best_freq = freq; | |
194 | diff_min = diff; | |
195 | } | |
196 | } | |
197 | ||
198 | clk_set_rate(priv->clk, best_freq); | |
199 | ||
200 | return best_freq; | |
201 | } | |
202 | ||
0ea28210 | 203 | static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host) |
56c49287 | 204 | { |
16935250 | 205 | struct sh_mobile_sdhi *priv = host_to_priv(host); |
0ea28210 | 206 | |
00fb3d2a | 207 | clk_disable_unprepare(priv->clk); |
56c49287 GL |
208 | } |
209 | ||
057a4592 WS |
210 | static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, |
211 | struct mmc_ios *ios) | |
212 | { | |
213 | struct tmio_mmc_host *host = mmc_priv(mmc); | |
214 | struct sh_mobile_sdhi *priv = host_to_priv(host); | |
215 | struct pinctrl_state *pin_state; | |
216 | int ret; | |
217 | ||
218 | switch (ios->signal_voltage) { | |
219 | case MMC_SIGNAL_VOLTAGE_330: | |
220 | pin_state = priv->pins_default; | |
221 | break; | |
222 | case MMC_SIGNAL_VOLTAGE_180: | |
223 | pin_state = priv->pins_uhs; | |
224 | break; | |
225 | default: | |
226 | return -EINVAL; | |
227 | } | |
228 | ||
229 | /* | |
230 | * If anything is missing, assume signal voltage is fixed at | |
231 | * 3.3V and succeed/fail accordingly. | |
232 | */ | |
233 | if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state)) | |
234 | return ios->signal_voltage == | |
235 | MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL; | |
236 | ||
237 | ret = mmc_regulator_set_vqmmc(host->mmc, ios); | |
238 | if (ret) | |
239 | return ret; | |
240 | ||
2272c841 | 241 | return pinctrl_select_state(priv->pinctrl, pin_state); |
057a4592 WS |
242 | } |
243 | ||
973ed3af SH |
244 | static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) |
245 | { | |
246 | int timeout = 1000; | |
247 | ||
a21553c9 WS |
248 | while (--timeout && !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) |
249 | & TMIO_STAT_SCLKDIVEN)) | |
973ed3af SH |
250 | udelay(1); |
251 | ||
252 | if (!timeout) { | |
94b110af | 253 | dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n"); |
973ed3af SH |
254 | return -EBUSY; |
255 | } | |
256 | ||
257 | return 0; | |
258 | } | |
259 | ||
260 | static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) | |
261 | { | |
262 | switch (addr) | |
263 | { | |
264 | case CTL_SD_CMD: | |
265 | case CTL_STOP_INTERNAL_ACTION: | |
266 | case CTL_XFER_BLK_COUNT: | |
267 | case CTL_SD_CARD_CLK_CTL: | |
268 | case CTL_SD_XFER_LEN: | |
269 | case CTL_SD_MEM_CARD_OPT: | |
270 | case CTL_TRANSACTION_CTL: | |
271 | case CTL_DMA_ENABLE: | |
ff741cfd | 272 | case EXT_ACC: |
973ed3af SH |
273 | return sh_mobile_sdhi_wait_idle(host); |
274 | } | |
275 | ||
276 | return 0; | |
277 | } | |
278 | ||
8b4efe2f KM |
279 | static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, |
280 | unsigned int direction, int blk_size) | |
281 | { | |
282 | /* | |
283 | * In Renesas controllers, when performing a | |
284 | * multiple block read of one or two blocks, | |
285 | * depending on the timing with which the | |
286 | * response register is read, the response | |
287 | * value may not be read properly. | |
288 | * Use single block read for this HW bug | |
289 | */ | |
290 | if ((direction == MMC_DATA_READ) && | |
291 | blk_size == 2) | |
292 | return 1; | |
293 | ||
294 | return blk_size; | |
295 | } | |
296 | ||
0c47f6ae KM |
297 | static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) |
298 | { | |
299 | sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); | |
f45394d5 KM |
300 | |
301 | /* enable 32bit access if DMA mode if possibile */ | |
302 | sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16); | |
0c47f6ae KM |
303 | } |
304 | ||
c3be1efd | 305 | static int sh_mobile_sdhi_probe(struct platform_device *pdev) |
a87d5638 | 306 | { |
5a00a971 GL |
307 | const struct of_device_id *of_id = |
308 | of_match_device(sh_mobile_sdhi_of_match, &pdev->dev); | |
a87d5638 | 309 | struct sh_mobile_sdhi *priv; |
056676da | 310 | struct tmio_mmc_data *mmc_data; |
f33c9d65 | 311 | struct tmio_mmc_data *mmd = pdev->dev.platform_data; |
42051e8a | 312 | struct tmio_mmc_host *host; |
3b159a6e | 313 | struct resource *res; |
d5098cb6 | 314 | int irq, ret, i = 0; |
87ae7bbe | 315 | struct tmio_mmc_dma *dma_priv; |
a87d5638 | 316 | |
3b159a6e KM |
317 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
318 | if (!res) | |
319 | return -EINVAL; | |
320 | ||
ac51b961 | 321 | priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL); |
2bf8ab6b | 322 | if (!priv) |
a87d5638 | 323 | return -ENOMEM; |
a87d5638 | 324 | |
056676da | 325 | mmc_data = &priv->mmc_data; |
87ae7bbe | 326 | dma_priv = &priv->dma_priv; |
056676da | 327 | |
ac51b961 | 328 | priv->clk = devm_clk_get(&pdev->dev, NULL); |
a87d5638 | 329 | if (IS_ERR(priv->clk)) { |
a87d5638 | 330 | ret = PTR_ERR(priv->clk); |
56ae1adc | 331 | dev_err(&pdev->dev, "cannot get clock: %d\n", ret); |
010f4aa7 | 332 | goto eprobe; |
a87d5638 MD |
333 | } |
334 | ||
057a4592 WS |
335 | priv->pinctrl = devm_pinctrl_get(&pdev->dev); |
336 | if (!IS_ERR(priv->pinctrl)) { | |
337 | priv->pins_default = pinctrl_lookup_state(priv->pinctrl, | |
338 | PINCTRL_STATE_DEFAULT); | |
339 | priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl, | |
340 | "state_uhs"); | |
341 | } | |
342 | ||
94b110af KM |
343 | host = tmio_mmc_host_alloc(pdev); |
344 | if (!host) { | |
345 | ret = -ENOMEM; | |
346 | goto eprobe; | |
347 | } | |
348 | ||
a72e8b17 WS |
349 | if (of_id && of_id->data) { |
350 | const struct sh_mobile_sdhi_of_data *of_data = of_id->data; | |
351 | ||
352 | mmc_data->flags |= of_data->tmio_flags; | |
353 | mmc_data->capabilities |= of_data->capabilities; | |
354 | mmc_data->capabilities2 |= of_data->capabilities2; | |
355 | mmc_data->dma_rx_offset = of_data->dma_rx_offset; | |
356 | dma_priv->dma_buswidth = of_data->dma_buswidth; | |
357 | host->bus_shift = of_data->bus_shift; | |
358 | } | |
359 | ||
7ecc09ba | 360 | host->dma = dma_priv; |
dfe9a229 | 361 | host->write16_hook = sh_mobile_sdhi_write16_hook; |
4fe2ec57 | 362 | host->clk_enable = sh_mobile_sdhi_clk_enable; |
2fb55956 | 363 | host->clk_update = sh_mobile_sdhi_clk_update; |
00452c11 | 364 | host->clk_disable = sh_mobile_sdhi_clk_disable; |
85c02ddd | 365 | host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; |
057a4592 | 366 | host->start_signal_voltage_switch = sh_mobile_sdhi_start_signal_voltage_switch; |
a72e8b17 WS |
367 | |
368 | /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ | |
369 | if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */ | |
95a7dc36 | 370 | host->bus_shift = 1; |
7ecc09ba | 371 | |
84f11d5b | 372 | if (mmd) |
f33c9d65 | 373 | *mmc_data = *mmd; |
84f11d5b | 374 | |
87ae7bbe | 375 | dma_priv->filter = shdma_chan_filter; |
0c47f6ae | 376 | dma_priv->enable = sh_mobile_sdhi_enable_dma; |
87ae7bbe | 377 | |
e471df0b | 378 | mmc_data->alignment_shift = 1; /* 2-byte alignment */ |
f33c9d65 | 379 | mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED; |
e471df0b | 380 | |
f1334fb3 YG |
381 | /* |
382 | * All SDHI blocks support 2-byte and larger block sizes in 4-bit | |
383 | * bus width mode. | |
384 | */ | |
385 | mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; | |
386 | ||
23b66071 AH |
387 | /* |
388 | * All SDHI blocks support SDIO IRQ signalling. | |
389 | */ | |
390 | mmc_data->flags |= TMIO_MMC_SDIO_IRQ; | |
391 | ||
b8d11962 SU |
392 | /* |
393 | * All SDHI have CMD12 controll bit | |
394 | */ | |
395 | mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL; | |
396 | ||
6b98757e SU |
397 | /* |
398 | * All SDHI need SDIO_INFO1 reserved bit | |
399 | */ | |
400 | mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK; | |
401 | ||
94b110af | 402 | ret = tmio_mmc_host_probe(host, mmc_data); |
42051e8a | 403 | if (ret < 0) |
94b110af | 404 | goto efree; |
a87d5638 | 405 | |
adcbc949 WS |
406 | while (1) { |
407 | irq = platform_get_irq(pdev, i); | |
408 | if (irq < 0) | |
409 | break; | |
410 | i++; | |
411 | ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, | |
d5098cb6 SH |
412 | dev_name(&pdev->dev), host); |
413 | if (ret) | |
ac51b961 | 414 | goto eirq; |
d5098cb6 SH |
415 | } |
416 | ||
adcbc949 WS |
417 | /* There must be at least one IRQ source */ |
418 | if (!i) { | |
d5098cb6 | 419 | ret = irq; |
ac51b961 | 420 | goto eirq; |
d5098cb6 SH |
421 | } |
422 | ||
2fb55956 | 423 | dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n", |
1f7d6819 | 424 | mmc_hostname(host->mmc), (unsigned long) |
58126c87 | 425 | (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), |
369213bd | 426 | host->mmc->f_max / 1000000); |
a87d5638 | 427 | |
42051e8a | 428 | return ret; |
a87d5638 | 429 | |
ac51b961 | 430 | eirq: |
8e7bfdb3 | 431 | tmio_mmc_host_remove(host); |
94b110af KM |
432 | efree: |
433 | tmio_mmc_host_free(host); | |
42051e8a | 434 | eprobe: |
a87d5638 MD |
435 | return ret; |
436 | } | |
437 | ||
438 | static int sh_mobile_sdhi_remove(struct platform_device *pdev) | |
439 | { | |
42051e8a GL |
440 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
441 | struct tmio_mmc_host *host = mmc_priv(mmc); | |
d6a1f863 | 442 | |
742a0c7c GL |
443 | tmio_mmc_host_remove(host); |
444 | ||
a87d5638 MD |
445 | return 0; |
446 | } | |
447 | ||
e6ee7182 | 448 | static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { |
753a688c UH |
449 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
450 | pm_runtime_force_resume) | |
6ed23b80 | 451 | SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, |
4e262d7f UH |
452 | tmio_mmc_host_runtime_resume, |
453 | NULL) | |
e6ee7182 GL |
454 | }; |
455 | ||
a87d5638 MD |
456 | static struct platform_driver sh_mobile_sdhi_driver = { |
457 | .driver = { | |
458 | .name = "sh_mobile_sdhi", | |
e6ee7182 | 459 | .pm = &tmio_mmc_dev_pm_ops, |
c7bb4487 | 460 | .of_match_table = sh_mobile_sdhi_of_match, |
a87d5638 MD |
461 | }, |
462 | .probe = sh_mobile_sdhi_probe, | |
0433c143 | 463 | .remove = sh_mobile_sdhi_remove, |
a87d5638 MD |
464 | }; |
465 | ||
d1f81a64 | 466 | module_platform_driver(sh_mobile_sdhi_driver); |
a87d5638 MD |
467 | |
468 | MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); | |
469 | MODULE_AUTHOR("Magnus Damm"); | |
470 | MODULE_LICENSE("GPL v2"); | |
42051e8a | 471 | MODULE_ALIAS("platform:sh_mobile_sdhi"); |