blob: 9952535671f2fb54f1024816d8254410e830061f [file] [log] [blame]
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001/* linux/drivers/mmc/host/sdhci-pci.c - SDHCI on PCI bus interface
2 *
3 * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * Thanks to the following companies for their support:
11 *
12 * - JMicron (hardware and technical support)
13 */
14
15#include <linux/delay.h>
16#include <linux/highmem.h>
Paul Gortmaker88b47672011-07-03 15:15:51 -040017#include <linux/module.h>
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +010018#include <linux/pci.h>
19#include <linux/dma-mapping.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090020#include <linux/slab.h>
Maxim Levitskyccc92c22010-08-10 18:01:42 -070021#include <linux/device.h>
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +010022#include <linux/mmc/host.h>
Ameya Palandeb177bc92011-04-05 21:13:13 +030023#include <linux/scatterlist.h>
24#include <linux/io.h>
Adrian Hunter0f201652011-08-29 16:42:13 +030025#include <linux/gpio.h>
Adrian Hunter66fd8ad2011-10-03 15:33:34 +030026#include <linux/pm_runtime.h>
Adrian Hunter52c506f2011-12-27 15:48:43 +020027#include <linux/mmc/sdhci-pci-data.h>
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +010028
29#include "sdhci.h"
30
31/*
32 * PCI registers
33 */
34
35#define PCI_SDHCI_IFPIO 0x00
36#define PCI_SDHCI_IFDMA 0x01
37#define PCI_SDHCI_IFVENDOR 0x02
38
39#define PCI_SLOT_INFO 0x40 /* 8 bits */
40#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7)
41#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07
42
43#define MAX_SLOTS 8
44
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +010045struct sdhci_pci_chip;
Pierre Ossman44894282008-04-04 19:36:59 +020046struct sdhci_pci_slot;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +010047
Pierre Ossman22606402008-03-23 19:33:23 +010048struct sdhci_pci_fixes {
49 unsigned int quirks;
Adrian Hunterc43fd772011-10-17 10:52:44 +030050 bool allow_runtime_pm;
Pierre Ossman22606402008-03-23 19:33:23 +010051
Ameya Palandeb177bc92011-04-05 21:13:13 +030052 int (*probe) (struct sdhci_pci_chip *);
Pierre Ossman45211e22008-03-24 13:09:09 +010053
Ameya Palandeb177bc92011-04-05 21:13:13 +030054 int (*probe_slot) (struct sdhci_pci_slot *);
55 void (*remove_slot) (struct sdhci_pci_slot *, int);
Pierre Ossman44894282008-04-04 19:36:59 +020056
Manuel Lauss29495aa2011-11-03 11:09:45 +010057 int (*suspend) (struct sdhci_pci_chip *);
Ameya Palandeb177bc92011-04-05 21:13:13 +030058 int (*resume) (struct sdhci_pci_chip *);
Pierre Ossman22606402008-03-23 19:33:23 +010059};
60
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +010061struct sdhci_pci_slot {
62 struct sdhci_pci_chip *chip;
63 struct sdhci_host *host;
Adrian Hunter52c506f2011-12-27 15:48:43 +020064 struct sdhci_pci_data *data;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +010065
66 int pci_bar;
Adrian Hunter0f201652011-08-29 16:42:13 +030067 int rst_n_gpio;
Adrian Hunter66fd8ad2011-10-03 15:33:34 +030068 int cd_gpio;
69 int cd_irq;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +010070};
71
72struct sdhci_pci_chip {
73 struct pci_dev *pdev;
Pierre Ossman22606402008-03-23 19:33:23 +010074
75 unsigned int quirks;
Adrian Hunterc43fd772011-10-17 10:52:44 +030076 bool allow_runtime_pm;
Pierre Ossman22606402008-03-23 19:33:23 +010077 const struct sdhci_pci_fixes *fixes;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +010078
79 int num_slots; /* Slots on controller */
80 struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */
81};
82
Pierre Ossman22606402008-03-23 19:33:23 +010083
84/*****************************************************************************\
85 * *
86 * Hardware specific quirk handling *
87 * *
88\*****************************************************************************/
89
90static int ricoh_probe(struct sdhci_pci_chip *chip)
91{
Chris Ballc99436f2009-09-22 16:45:22 -070092 if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG ||
93 chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY)
Pierre Ossman22606402008-03-23 19:33:23 +010094 chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET;
Maxim Levitskyccc92c22010-08-10 18:01:42 -070095 return 0;
96}
Pierre Ossman22606402008-03-23 19:33:23 +010097
Maxim Levitskyccc92c22010-08-10 18:01:42 -070098static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
99{
100 slot->host->caps =
101 ((0x21 << SDHCI_TIMEOUT_CLK_SHIFT)
102 & SDHCI_TIMEOUT_CLK_MASK) |
103
104 ((0x21 << SDHCI_CLOCK_BASE_SHIFT)
105 & SDHCI_CLOCK_BASE_MASK) |
106
107 SDHCI_TIMEOUT_CLK_UNIT |
108 SDHCI_CAN_VDD_330 |
109 SDHCI_CAN_DO_SDMA;
110 return 0;
111}
112
113static int ricoh_mmc_resume(struct sdhci_pci_chip *chip)
114{
115 /* Apply a delay to allow controller to settle */
116 /* Otherwise it becomes confused if card state changed
117 during suspend */
118 msleep(500);
Pierre Ossman22606402008-03-23 19:33:23 +0100119 return 0;
120}
121
122static const struct sdhci_pci_fixes sdhci_ricoh = {
123 .probe = ricoh_probe,
Vasily Khoruzhick84938292010-03-05 13:43:46 -0800124 .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
125 SDHCI_QUIRK_FORCE_DMA |
126 SDHCI_QUIRK_CLOCK_BEFORE_RESET,
Pierre Ossman22606402008-03-23 19:33:23 +0100127};
128
Maxim Levitskyccc92c22010-08-10 18:01:42 -0700129static const struct sdhci_pci_fixes sdhci_ricoh_mmc = {
130 .probe_slot = ricoh_mmc_probe_slot,
131 .resume = ricoh_mmc_resume,
132 .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
133 SDHCI_QUIRK_CLOCK_BEFORE_RESET |
134 SDHCI_QUIRK_NO_CARD_NO_RESET |
135 SDHCI_QUIRK_MISSING_CAPS
136};
137
Pierre Ossman22606402008-03-23 19:33:23 +0100138static const struct sdhci_pci_fixes sdhci_ene_712 = {
139 .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
140 SDHCI_QUIRK_BROKEN_DMA,
141};
142
143static const struct sdhci_pci_fixes sdhci_ene_714 = {
144 .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
145 SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
146 SDHCI_QUIRK_BROKEN_DMA,
147};
148
149static const struct sdhci_pci_fixes sdhci_cafe = {
150 .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
Andres Salomona0874892009-03-02 21:48:20 +0100151 SDHCI_QUIRK_NO_BUSY_IRQ |
Pierre Ossmanee53ab52008-07-05 00:25:15 +0200152 SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
Pierre Ossman22606402008-03-23 19:33:23 +0100153};
154
Major Lee68077b02011-06-29 14:23:46 +0300155static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot)
156{
157 slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
158 return 0;
159}
160
Alan Coxf9ee3ea2010-10-04 15:25:11 +0100161/*
162 * ADMA operation is disabled for Moorestown platform due to
163 * hardware bugs.
164 */
Jacob Pan35ac6f02010-11-09 13:57:29 +0000165static int mrst_hc_probe(struct sdhci_pci_chip *chip)
Alan Coxf9ee3ea2010-10-04 15:25:11 +0100166{
167 /*
Jacob Pan35ac6f02010-11-09 13:57:29 +0000168 * slots number is fixed here for MRST as SDIO3/5 are never used and
169 * have hardware bugs.
Alan Coxf9ee3ea2010-10-04 15:25:11 +0100170 */
171 chip->num_slots = 1;
172 return 0;
173}
174
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300175#ifdef CONFIG_PM_RUNTIME
176
Adrian Hunterc5e027a2011-12-27 15:48:44 +0200177static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300178{
179 struct sdhci_pci_slot *slot = dev_id;
180 struct sdhci_host *host = slot->host;
181
182 mmc_detect_change(host->mmc, msecs_to_jiffies(200));
183 return IRQ_HANDLED;
184}
185
Adrian Hunterc5e027a2011-12-27 15:48:44 +0200186static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300187{
Adrian Hunterc5e027a2011-12-27 15:48:44 +0200188 int err, irq, gpio = slot->cd_gpio;
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300189
190 slot->cd_gpio = -EINVAL;
191 slot->cd_irq = -EINVAL;
192
Adrian Hunterc5e027a2011-12-27 15:48:44 +0200193 if (!gpio_is_valid(gpio))
194 return;
195
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300196 err = gpio_request(gpio, "sd_cd");
197 if (err < 0)
198 goto out;
199
200 err = gpio_direction_input(gpio);
201 if (err < 0)
202 goto out_free;
203
204 irq = gpio_to_irq(gpio);
205 if (irq < 0)
206 goto out_free;
207
Adrian Hunterc5e027a2011-12-27 15:48:44 +0200208 err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING |
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300209 IRQF_TRIGGER_FALLING, "sd_cd", slot);
210 if (err)
211 goto out_free;
212
213 slot->cd_gpio = gpio;
214 slot->cd_irq = irq;
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300215
Adrian Hunterc5e027a2011-12-27 15:48:44 +0200216 return;
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300217
218out_free:
219 gpio_free(gpio);
220out:
221 dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n");
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300222}
223
Adrian Hunterc5e027a2011-12-27 15:48:44 +0200224static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300225{
226 if (slot->cd_irq >= 0)
227 free_irq(slot->cd_irq, slot);
Adrian Hunterc5e027a2011-12-27 15:48:44 +0200228 if (gpio_is_valid(slot->cd_gpio))
229 gpio_free(slot->cd_gpio);
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300230}
231
232#else
233
Adrian Hunterc5e027a2011-12-27 15:48:44 +0200234static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
235{
236}
237
238static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
239{
240}
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300241
242#endif
243
Adrian Hunter0d013bc2011-06-29 14:23:47 +0300244static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
245{
Adrian Hunter66fd8ad2011-10-03 15:33:34 +0300246 slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
Adrian Hunterda721cf2012-02-07 14:48:53 +0200247 slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC |
248 MMC_CAP2_HC_ERASE_SZ;
Adrian Hunter0d013bc2011-06-29 14:23:47 +0300249 return 0;
250}
251
Adrian Hunter93933502011-12-27 15:48:47 +0200252static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot)
253{
Adrian Hunter012e4672012-01-30 14:27:18 +0200254 slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
Adrian Hunter93933502011-12-27 15:48:47 +0200255 return 0;
256}
257
Alan Coxf9ee3ea2010-10-04 15:25:11 +0100258static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
259 .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
Major Lee68077b02011-06-29 14:23:46 +0300260 .probe_slot = mrst_hc_probe_slot,
Alan Coxf9ee3ea2010-10-04 15:25:11 +0100261};
262
Jacob Pan35ac6f02010-11-09 13:57:29 +0000263static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = {
Alan Coxf9ee3ea2010-10-04 15:25:11 +0100264 .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
Jacob Pan35ac6f02010-11-09 13:57:29 +0000265 .probe = mrst_hc_probe,
Alan Coxf9ee3ea2010-10-04 15:25:11 +0100266};
267
Xiaochen Shen29229052010-10-04 15:24:52 +0100268static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
269 .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
Adrian Hunterc43fd772011-10-17 10:52:44 +0300270 .allow_runtime_pm = true,
Xiaochen Shen29229052010-10-04 15:24:52 +0100271};
272
Adrian Hunter0d013bc2011-06-29 14:23:47 +0300273static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
Xiaochen Shen29229052010-10-04 15:24:52 +0100274 .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
Adrian Hunterc43fd772011-10-17 10:52:44 +0300275 .allow_runtime_pm = true,
Adrian Hunter93933502011-12-27 15:48:47 +0200276 .probe_slot = mfd_sdio_probe_slot,
Xiaochen Shen29229052010-10-04 15:24:52 +0100277};
278
Adrian Hunter0d013bc2011-06-29 14:23:47 +0300279static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = {
280 .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
Adrian Hunterc43fd772011-10-17 10:52:44 +0300281 .allow_runtime_pm = true,
Adrian Hunter0d013bc2011-06-29 14:23:47 +0300282 .probe_slot = mfd_emmc_probe_slot,
283};
284
Jennifer Li26daa1e2010-11-17 23:01:59 -0500285/* O2Micro extra registers */
286#define O2_SD_LOCK_WP 0xD3
287#define O2_SD_MULTI_VCC3V 0xEE
288#define O2_SD_CLKREQ 0xEC
289#define O2_SD_CAPS 0xE0
290#define O2_SD_ADMA1 0xE2
291#define O2_SD_ADMA2 0xE7
292#define O2_SD_INF_MOD 0xF1
293
294static int o2_probe(struct sdhci_pci_chip *chip)
295{
296 int ret;
297 u8 scratch;
298
299 switch (chip->pdev->device) {
300 case PCI_DEVICE_ID_O2_8220:
301 case PCI_DEVICE_ID_O2_8221:
302 case PCI_DEVICE_ID_O2_8320:
303 case PCI_DEVICE_ID_O2_8321:
304 /* This extra setup is required due to broken ADMA. */
305 ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
306 if (ret)
307 return ret;
308 scratch &= 0x7f;
309 pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
310
311 /* Set Multi 3 to VCC3V# */
312 pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08);
313
314 /* Disable CLK_REQ# support after media DET */
315 ret = pci_read_config_byte(chip->pdev, O2_SD_CLKREQ, &scratch);
316 if (ret)
317 return ret;
318 scratch |= 0x20;
319 pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch);
320
321 /* Choose capabilities, enable SDMA. We have to write 0x01
322 * to the capabilities register first to unlock it.
323 */
324 ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch);
325 if (ret)
326 return ret;
327 scratch |= 0x01;
328 pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch);
329 pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73);
330
331 /* Disable ADMA1/2 */
332 pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39);
333 pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08);
334
335 /* Disable the infinite transfer mode */
336 ret = pci_read_config_byte(chip->pdev, O2_SD_INF_MOD, &scratch);
337 if (ret)
338 return ret;
339 scratch |= 0x08;
340 pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch);
341
342 /* Lock WP */
343 ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
344 if (ret)
345 return ret;
346 scratch |= 0x80;
347 pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
348 }
349
350 return 0;
351}
352
Pierre Ossman45211e22008-03-24 13:09:09 +0100353static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
354{
355 u8 scratch;
356 int ret;
357
358 ret = pci_read_config_byte(chip->pdev, 0xAE, &scratch);
359 if (ret)
360 return ret;
361
362 /*
363 * Turn PMOS on [bit 0], set over current detection to 2.4 V
364 * [bit 1:2] and enable over current debouncing [bit 6].
365 */
366 if (on)
367 scratch |= 0x47;
368 else
369 scratch &= ~0x47;
370
371 ret = pci_write_config_byte(chip->pdev, 0xAE, scratch);
372 if (ret)
373 return ret;
374
375 return 0;
376}
377
378static int jmicron_probe(struct sdhci_pci_chip *chip)
379{
380 int ret;
Takashi Iwai8f230f42010-12-08 10:04:30 +0100381 u16 mmcdev = 0;
Pierre Ossman45211e22008-03-24 13:09:09 +0100382
Pierre Ossman93fc48c2008-06-28 18:21:41 +0200383 if (chip->pdev->revision == 0) {
384 chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
385 SDHCI_QUIRK_32BIT_DMA_SIZE |
Pierre Ossman2134a922008-06-28 18:28:51 +0200386 SDHCI_QUIRK_32BIT_ADMA_SIZE |
Pierre Ossman4a3cba32008-07-29 00:11:16 +0200387 SDHCI_QUIRK_RESET_AFTER_REQUEST |
Pierre Ossman86a6a872009-02-02 21:13:49 +0100388 SDHCI_QUIRK_BROKEN_SMALL_PIO;
Pierre Ossman93fc48c2008-06-28 18:21:41 +0200389 }
390
Pierre Ossman45211e22008-03-24 13:09:09 +0100391 /*
Pierre Ossman44894282008-04-04 19:36:59 +0200392 * JMicron chips can have two interfaces to the same hardware
393 * in order to work around limitations in Microsoft's driver.
394 * We need to make sure we only bind to one of them.
395 *
396 * This code assumes two things:
397 *
398 * 1. The PCI code adds subfunctions in order.
399 *
400 * 2. The MMC interface has a lower subfunction number
401 * than the SD interface.
402 */
Takashi Iwai8f230f42010-12-08 10:04:30 +0100403 if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD)
404 mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC;
405 else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD)
406 mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD;
407
408 if (mmcdev) {
Pierre Ossman44894282008-04-04 19:36:59 +0200409 struct pci_dev *sd_dev;
410
411 sd_dev = NULL;
412 while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON,
Takashi Iwai8f230f42010-12-08 10:04:30 +0100413 mmcdev, sd_dev)) != NULL) {
Pierre Ossman44894282008-04-04 19:36:59 +0200414 if ((PCI_SLOT(chip->pdev->devfn) ==
415 PCI_SLOT(sd_dev->devfn)) &&
416 (chip->pdev->bus == sd_dev->bus))
417 break;
418 }
419
420 if (sd_dev) {
421 pci_dev_put(sd_dev);
422 dev_info(&chip->pdev->dev, "Refusing to bind to "
423 "secondary interface.\n");
424 return -ENODEV;
425 }
426 }
427
428 /*
Pierre Ossman45211e22008-03-24 13:09:09 +0100429 * JMicron chips need a bit of a nudge to enable the power
430 * output pins.
431 */
432 ret = jmicron_pmos(chip, 1);
433 if (ret) {
434 dev_err(&chip->pdev->dev, "Failure enabling card power\n");
435 return ret;
436 }
437
Takashi Iwai82b0e232011-04-21 20:26:38 +0200438 /* quirk for unsable RO-detection on JM388 chips */
439 if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD ||
440 chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
441 chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT;
442
Pierre Ossman45211e22008-03-24 13:09:09 +0100443 return 0;
444}
445
Pierre Ossman44894282008-04-04 19:36:59 +0200446static void jmicron_enable_mmc(struct sdhci_host *host, int on)
447{
448 u8 scratch;
449
450 scratch = readb(host->ioaddr + 0xC0);
451
452 if (on)
453 scratch |= 0x01;
454 else
455 scratch &= ~0x01;
456
457 writeb(scratch, host->ioaddr + 0xC0);
458}
459
460static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
461{
Pierre Ossman2134a922008-06-28 18:28:51 +0200462 if (slot->chip->pdev->revision == 0) {
463 u16 version;
464
465 version = readl(slot->host->ioaddr + SDHCI_HOST_VERSION);
466 version = (version & SDHCI_VENDOR_VER_MASK) >>
467 SDHCI_VENDOR_VER_SHIFT;
468
469 /*
470 * Older versions of the chip have lots of nasty glitches
471 * in the ADMA engine. It's best just to avoid it
472 * completely.
473 */
474 if (version < 0xAC)
475 slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
476 }
477
Takashi Iwai8f230f42010-12-08 10:04:30 +0100478 /* JM388 MMC doesn't support 1.8V while SD supports it */
479 if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
480 slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 |
481 MMC_VDD_29_30 | MMC_VDD_30_31 |
482 MMC_VDD_165_195; /* allow 1.8V */
483 slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 |
484 MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */
485 }
486
Pierre Ossman44894282008-04-04 19:36:59 +0200487 /*
488 * The secondary interface requires a bit set to get the
489 * interrupts.
490 */
Takashi Iwai8f230f42010-12-08 10:04:30 +0100491 if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
492 slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
Pierre Ossman44894282008-04-04 19:36:59 +0200493 jmicron_enable_mmc(slot->host, 1);
494
Takashi Iwaid75c1082010-12-16 17:54:14 +0100495 slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST;
496
Pierre Ossman44894282008-04-04 19:36:59 +0200497 return 0;
498}
499
Pierre Ossman1e728592008-04-16 19:13:13 +0200500static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead)
Pierre Ossman44894282008-04-04 19:36:59 +0200501{
Pierre Ossman1e728592008-04-16 19:13:13 +0200502 if (dead)
503 return;
504
Takashi Iwai8f230f42010-12-08 10:04:30 +0100505 if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
506 slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
Pierre Ossman44894282008-04-04 19:36:59 +0200507 jmicron_enable_mmc(slot->host, 0);
508}
509
Manuel Lauss29495aa2011-11-03 11:09:45 +0100510static int jmicron_suspend(struct sdhci_pci_chip *chip)
Pierre Ossman44894282008-04-04 19:36:59 +0200511{
512 int i;
513
Takashi Iwai8f230f42010-12-08 10:04:30 +0100514 if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
515 chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
Ameya Palandeb177bc92011-04-05 21:13:13 +0300516 for (i = 0; i < chip->num_slots; i++)
Pierre Ossman44894282008-04-04 19:36:59 +0200517 jmicron_enable_mmc(chip->slots[i]->host, 0);
518 }
519
520 return 0;
521}
522
Pierre Ossman45211e22008-03-24 13:09:09 +0100523static int jmicron_resume(struct sdhci_pci_chip *chip)
524{
Pierre Ossman44894282008-04-04 19:36:59 +0200525 int ret, i;
526
Takashi Iwai8f230f42010-12-08 10:04:30 +0100527 if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
528 chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
Ameya Palandeb177bc92011-04-05 21:13:13 +0300529 for (i = 0; i < chip->num_slots; i++)
Pierre Ossman44894282008-04-04 19:36:59 +0200530 jmicron_enable_mmc(chip->slots[i]->host, 1);
531 }
Pierre Ossman45211e22008-03-24 13:09:09 +0100532
533 ret = jmicron_pmos(chip, 1);
534 if (ret) {
535 dev_err(&chip->pdev->dev, "Failure enabling card power\n");
536 return ret;
537 }
538
539 return 0;
540}
541
Jennifer Li26daa1e2010-11-17 23:01:59 -0500542static const struct sdhci_pci_fixes sdhci_o2 = {
543 .probe = o2_probe,
544};
545
Pierre Ossman22606402008-03-23 19:33:23 +0100546static const struct sdhci_pci_fixes sdhci_jmicron = {
Pierre Ossman45211e22008-03-24 13:09:09 +0100547 .probe = jmicron_probe,
548
Pierre Ossman44894282008-04-04 19:36:59 +0200549 .probe_slot = jmicron_probe_slot,
550 .remove_slot = jmicron_remove_slot,
551
552 .suspend = jmicron_suspend,
Pierre Ossman45211e22008-03-24 13:09:09 +0100553 .resume = jmicron_resume,
Pierre Ossman22606402008-03-23 19:33:23 +0100554};
555
Nicolas Pitrea7a61862009-12-14 18:01:26 -0800556/* SysKonnect CardBus2SDIO extra registers */
557#define SYSKT_CTRL 0x200
558#define SYSKT_RDFIFO_STAT 0x204
559#define SYSKT_WRFIFO_STAT 0x208
560#define SYSKT_POWER_DATA 0x20c
561#define SYSKT_POWER_330 0xef
562#define SYSKT_POWER_300 0xf8
563#define SYSKT_POWER_184 0xcc
564#define SYSKT_POWER_CMD 0x20d
565#define SYSKT_POWER_START (1 << 7)
566#define SYSKT_POWER_STATUS 0x20e
567#define SYSKT_POWER_STATUS_OK (1 << 0)
568#define SYSKT_BOARD_REV 0x210
569#define SYSKT_CHIP_REV 0x211
570#define SYSKT_CONF_DATA 0x212
571#define SYSKT_CONF_DATA_1V8 (1 << 2)
572#define SYSKT_CONF_DATA_2V5 (1 << 1)
573#define SYSKT_CONF_DATA_3V3 (1 << 0)
574
575static int syskt_probe(struct sdhci_pci_chip *chip)
576{
577 if ((chip->pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
578 chip->pdev->class &= ~0x0000FF;
579 chip->pdev->class |= PCI_SDHCI_IFDMA;
580 }
581 return 0;
582}
583
584static int syskt_probe_slot(struct sdhci_pci_slot *slot)
585{
586 int tm, ps;
587
588 u8 board_rev = readb(slot->host->ioaddr + SYSKT_BOARD_REV);
589 u8 chip_rev = readb(slot->host->ioaddr + SYSKT_CHIP_REV);
590 dev_info(&slot->chip->pdev->dev, "SysKonnect CardBus2SDIO, "
591 "board rev %d.%d, chip rev %d.%d\n",
592 board_rev >> 4, board_rev & 0xf,
593 chip_rev >> 4, chip_rev & 0xf);
594 if (chip_rev >= 0x20)
595 slot->host->quirks |= SDHCI_QUIRK_FORCE_DMA;
596
597 writeb(SYSKT_POWER_330, slot->host->ioaddr + SYSKT_POWER_DATA);
598 writeb(SYSKT_POWER_START, slot->host->ioaddr + SYSKT_POWER_CMD);
599 udelay(50);
600 tm = 10; /* Wait max 1 ms */
601 do {
602 ps = readw(slot->host->ioaddr + SYSKT_POWER_STATUS);
603 if (ps & SYSKT_POWER_STATUS_OK)
604 break;
605 udelay(100);
606 } while (--tm);
607 if (!tm) {
608 dev_err(&slot->chip->pdev->dev,
609 "power regulator never stabilized");
610 writeb(0, slot->host->ioaddr + SYSKT_POWER_CMD);
611 return -ENODEV;
612 }
613
614 return 0;
615}
616
617static const struct sdhci_pci_fixes sdhci_syskt = {
618 .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER,
619 .probe = syskt_probe,
620 .probe_slot = syskt_probe_slot,
621};
622
Harald Welte557b0692009-06-18 16:53:38 +0200623static int via_probe(struct sdhci_pci_chip *chip)
624{
625 if (chip->pdev->revision == 0x10)
626 chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER;
627
628 return 0;
629}
630
631static const struct sdhci_pci_fixes sdhci_via = {
632 .probe = via_probe,
633};
634
Pierre Ossman22606402008-03-23 19:33:23 +0100635static const struct pci_device_id pci_ids[] __devinitdata = {
636 {
637 .vendor = PCI_VENDOR_ID_RICOH,
638 .device = PCI_DEVICE_ID_RICOH_R5C822,
639 .subvendor = PCI_ANY_ID,
640 .subdevice = PCI_ANY_ID,
641 .driver_data = (kernel_ulong_t)&sdhci_ricoh,
642 },
643
644 {
Maxim Levitskyccc92c22010-08-10 18:01:42 -0700645 .vendor = PCI_VENDOR_ID_RICOH,
646 .device = 0x843,
647 .subvendor = PCI_ANY_ID,
648 .subdevice = PCI_ANY_ID,
649 .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
650 },
651
652 {
Pablo Castillo568133e2010-08-10 18:02:01 -0700653 .vendor = PCI_VENDOR_ID_RICOH,
654 .device = 0xe822,
655 .subvendor = PCI_ANY_ID,
656 .subdevice = PCI_ANY_ID,
657 .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
658 },
659
660 {
Manoj Iyer5fd11c02011-02-11 16:25:31 -0600661 .vendor = PCI_VENDOR_ID_RICOH,
662 .device = 0xe823,
663 .subvendor = PCI_ANY_ID,
664 .subdevice = PCI_ANY_ID,
665 .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
666 },
667
668 {
Pierre Ossman22606402008-03-23 19:33:23 +0100669 .vendor = PCI_VENDOR_ID_ENE,
670 .device = PCI_DEVICE_ID_ENE_CB712_SD,
671 .subvendor = PCI_ANY_ID,
672 .subdevice = PCI_ANY_ID,
673 .driver_data = (kernel_ulong_t)&sdhci_ene_712,
674 },
675
676 {
677 .vendor = PCI_VENDOR_ID_ENE,
678 .device = PCI_DEVICE_ID_ENE_CB712_SD_2,
679 .subvendor = PCI_ANY_ID,
680 .subdevice = PCI_ANY_ID,
681 .driver_data = (kernel_ulong_t)&sdhci_ene_712,
682 },
683
684 {
685 .vendor = PCI_VENDOR_ID_ENE,
686 .device = PCI_DEVICE_ID_ENE_CB714_SD,
687 .subvendor = PCI_ANY_ID,
688 .subdevice = PCI_ANY_ID,
689 .driver_data = (kernel_ulong_t)&sdhci_ene_714,
690 },
691
692 {
693 .vendor = PCI_VENDOR_ID_ENE,
694 .device = PCI_DEVICE_ID_ENE_CB714_SD_2,
695 .subvendor = PCI_ANY_ID,
696 .subdevice = PCI_ANY_ID,
697 .driver_data = (kernel_ulong_t)&sdhci_ene_714,
698 },
699
700 {
701 .vendor = PCI_VENDOR_ID_MARVELL,
David Woodhouse8c5eb882008-09-03 09:45:57 +0100702 .device = PCI_DEVICE_ID_MARVELL_88ALP01_SD,
Pierre Ossman22606402008-03-23 19:33:23 +0100703 .subvendor = PCI_ANY_ID,
704 .subdevice = PCI_ANY_ID,
705 .driver_data = (kernel_ulong_t)&sdhci_cafe,
706 },
707
708 {
709 .vendor = PCI_VENDOR_ID_JMICRON,
710 .device = PCI_DEVICE_ID_JMICRON_JMB38X_SD,
711 .subvendor = PCI_ANY_ID,
712 .subdevice = PCI_ANY_ID,
713 .driver_data = (kernel_ulong_t)&sdhci_jmicron,
714 },
715
Pierre Ossman44894282008-04-04 19:36:59 +0200716 {
717 .vendor = PCI_VENDOR_ID_JMICRON,
718 .device = PCI_DEVICE_ID_JMICRON_JMB38X_MMC,
719 .subvendor = PCI_ANY_ID,
720 .subdevice = PCI_ANY_ID,
721 .driver_data = (kernel_ulong_t)&sdhci_jmicron,
722 },
723
Harald Welte557b0692009-06-18 16:53:38 +0200724 {
Takashi Iwai8f230f42010-12-08 10:04:30 +0100725 .vendor = PCI_VENDOR_ID_JMICRON,
726 .device = PCI_DEVICE_ID_JMICRON_JMB388_SD,
727 .subvendor = PCI_ANY_ID,
728 .subdevice = PCI_ANY_ID,
729 .driver_data = (kernel_ulong_t)&sdhci_jmicron,
730 },
731
732 {
733 .vendor = PCI_VENDOR_ID_JMICRON,
734 .device = PCI_DEVICE_ID_JMICRON_JMB388_ESD,
735 .subvendor = PCI_ANY_ID,
736 .subdevice = PCI_ANY_ID,
737 .driver_data = (kernel_ulong_t)&sdhci_jmicron,
738 },
739
740 {
Nicolas Pitrea7a61862009-12-14 18:01:26 -0800741 .vendor = PCI_VENDOR_ID_SYSKONNECT,
742 .device = 0x8000,
743 .subvendor = PCI_ANY_ID,
744 .subdevice = PCI_ANY_ID,
745 .driver_data = (kernel_ulong_t)&sdhci_syskt,
746 },
747
748 {
Harald Welte557b0692009-06-18 16:53:38 +0200749 .vendor = PCI_VENDOR_ID_VIA,
750 .device = 0x95d0,
751 .subvendor = PCI_ANY_ID,
752 .subdevice = PCI_ANY_ID,
753 .driver_data = (kernel_ulong_t)&sdhci_via,
754 },
755
Xiaochen Shen29229052010-10-04 15:24:52 +0100756 {
757 .vendor = PCI_VENDOR_ID_INTEL,
Alan Coxf9ee3ea2010-10-04 15:25:11 +0100758 .device = PCI_DEVICE_ID_INTEL_MRST_SD0,
759 .subvendor = PCI_ANY_ID,
760 .subdevice = PCI_ANY_ID,
761 .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc0,
762 },
763
764 {
765 .vendor = PCI_VENDOR_ID_INTEL,
766 .device = PCI_DEVICE_ID_INTEL_MRST_SD1,
767 .subvendor = PCI_ANY_ID,
768 .subdevice = PCI_ANY_ID,
Jacob Pan35ac6f02010-11-09 13:57:29 +0000769 .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2,
770 },
771
772 {
773 .vendor = PCI_VENDOR_ID_INTEL,
774 .device = PCI_DEVICE_ID_INTEL_MRST_SD2,
775 .subvendor = PCI_ANY_ID,
776 .subdevice = PCI_ANY_ID,
777 .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2,
Alan Coxf9ee3ea2010-10-04 15:25:11 +0100778 },
779
780 {
781 .vendor = PCI_VENDOR_ID_INTEL,
Xiaochen Shen29229052010-10-04 15:24:52 +0100782 .device = PCI_DEVICE_ID_INTEL_MFD_SD,
783 .subvendor = PCI_ANY_ID,
784 .subdevice = PCI_ANY_ID,
785 .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd,
786 },
787
788 {
789 .vendor = PCI_VENDOR_ID_INTEL,
790 .device = PCI_DEVICE_ID_INTEL_MFD_SDIO1,
791 .subvendor = PCI_ANY_ID,
792 .subdevice = PCI_ANY_ID,
Adrian Hunter0d013bc2011-06-29 14:23:47 +0300793 .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
Xiaochen Shen29229052010-10-04 15:24:52 +0100794 },
795
796 {
797 .vendor = PCI_VENDOR_ID_INTEL,
798 .device = PCI_DEVICE_ID_INTEL_MFD_SDIO2,
799 .subvendor = PCI_ANY_ID,
800 .subdevice = PCI_ANY_ID,
Adrian Hunter0d013bc2011-06-29 14:23:47 +0300801 .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
Xiaochen Shen29229052010-10-04 15:24:52 +0100802 },
803
804 {
805 .vendor = PCI_VENDOR_ID_INTEL,
806 .device = PCI_DEVICE_ID_INTEL_MFD_EMMC0,
807 .subvendor = PCI_ANY_ID,
808 .subdevice = PCI_ANY_ID,
Adrian Hunter0d013bc2011-06-29 14:23:47 +0300809 .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
Xiaochen Shen29229052010-10-04 15:24:52 +0100810 },
811
812 {
813 .vendor = PCI_VENDOR_ID_INTEL,
814 .device = PCI_DEVICE_ID_INTEL_MFD_EMMC1,
815 .subvendor = PCI_ANY_ID,
816 .subdevice = PCI_ANY_ID,
Adrian Hunter0d013bc2011-06-29 14:23:47 +0300817 .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
Xiaochen Shen29229052010-10-04 15:24:52 +0100818 },
819
Jennifer Li26daa1e2010-11-17 23:01:59 -0500820 {
821 .vendor = PCI_VENDOR_ID_O2,
822 .device = PCI_DEVICE_ID_O2_8120,
823 .subvendor = PCI_ANY_ID,
824 .subdevice = PCI_ANY_ID,
825 .driver_data = (kernel_ulong_t)&sdhci_o2,
826 },
827
828 {
829 .vendor = PCI_VENDOR_ID_O2,
830 .device = PCI_DEVICE_ID_O2_8220,
831 .subvendor = PCI_ANY_ID,
832 .subdevice = PCI_ANY_ID,
833 .driver_data = (kernel_ulong_t)&sdhci_o2,
834 },
835
836 {
837 .vendor = PCI_VENDOR_ID_O2,
838 .device = PCI_DEVICE_ID_O2_8221,
839 .subvendor = PCI_ANY_ID,
840 .subdevice = PCI_ANY_ID,
841 .driver_data = (kernel_ulong_t)&sdhci_o2,
842 },
843
844 {
845 .vendor = PCI_VENDOR_ID_O2,
846 .device = PCI_DEVICE_ID_O2_8320,
847 .subvendor = PCI_ANY_ID,
848 .subdevice = PCI_ANY_ID,
849 .driver_data = (kernel_ulong_t)&sdhci_o2,
850 },
851
852 {
853 .vendor = PCI_VENDOR_ID_O2,
854 .device = PCI_DEVICE_ID_O2_8321,
855 .subvendor = PCI_ANY_ID,
856 .subdevice = PCI_ANY_ID,
857 .driver_data = (kernel_ulong_t)&sdhci_o2,
858 },
859
Pierre Ossman22606402008-03-23 19:33:23 +0100860 { /* Generic SD host controller */
861 PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
862 },
863
864 { /* end: all zeroes */ },
865};
866
867MODULE_DEVICE_TABLE(pci, pci_ids);
868
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100869/*****************************************************************************\
870 * *
871 * SDHCI core callbacks *
872 * *
873\*****************************************************************************/
874
875static int sdhci_pci_enable_dma(struct sdhci_host *host)
876{
877 struct sdhci_pci_slot *slot;
878 struct pci_dev *pdev;
879 int ret;
880
881 slot = sdhci_priv(host);
882 pdev = slot->chip->pdev;
883
884 if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) &&
885 ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
Richard Röjforsa13abc72009-09-22 16:45:30 -0700886 (host->flags & SDHCI_USE_SDMA)) {
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100887 dev_warn(&pdev->dev, "Will use DMA mode even though HW "
888 "doesn't fully claim to support it.\n");
889 }
890
Yang Hongyang284901a2009-04-06 19:01:15 -0700891 ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100892 if (ret)
893 return ret;
894
895 pci_set_master(pdev);
896
897 return 0;
898}
899
Major Lee68077b02011-06-29 14:23:46 +0300900static int sdhci_pci_8bit_width(struct sdhci_host *host, int width)
901{
902 u8 ctrl;
903
904 ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
905
906 switch (width) {
907 case MMC_BUS_WIDTH_8:
908 ctrl |= SDHCI_CTRL_8BITBUS;
909 ctrl &= ~SDHCI_CTRL_4BITBUS;
910 break;
911 case MMC_BUS_WIDTH_4:
912 ctrl |= SDHCI_CTRL_4BITBUS;
913 ctrl &= ~SDHCI_CTRL_8BITBUS;
914 break;
915 default:
916 ctrl &= ~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_4BITBUS);
917 break;
918 }
919
920 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
921
922 return 0;
923}
924
Adrian Hunter0f201652011-08-29 16:42:13 +0300925static void sdhci_pci_hw_reset(struct sdhci_host *host)
926{
927 struct sdhci_pci_slot *slot = sdhci_priv(host);
928 int rst_n_gpio = slot->rst_n_gpio;
929
930 if (!gpio_is_valid(rst_n_gpio))
931 return;
932 gpio_set_value_cansleep(rst_n_gpio, 0);
933 /* For eMMC, minimum is 1us but give it 10us for good measure */
934 udelay(10);
935 gpio_set_value_cansleep(rst_n_gpio, 1);
936 /* For eMMC, minimum is 200us but give it 300us for good measure */
937 usleep_range(300, 1000);
938}
939
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100940static struct sdhci_ops sdhci_pci_ops = {
941 .enable_dma = sdhci_pci_enable_dma,
Major Lee68077b02011-06-29 14:23:46 +0300942 .platform_8bit_width = sdhci_pci_8bit_width,
Adrian Hunter0f201652011-08-29 16:42:13 +0300943 .hw_reset = sdhci_pci_hw_reset,
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100944};
945
946/*****************************************************************************\
947 * *
948 * Suspend/resume *
949 * *
950\*****************************************************************************/
951
952#ifdef CONFIG_PM
953
Manuel Lauss29495aa2011-11-03 11:09:45 +0100954static int sdhci_pci_suspend(struct device *dev)
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100955{
Manuel Lauss29495aa2011-11-03 11:09:45 +0100956 struct pci_dev *pdev = to_pci_dev(dev);
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100957 struct sdhci_pci_chip *chip;
958 struct sdhci_pci_slot *slot;
Daniel Drake5f619702010-11-04 22:20:39 +0000959 mmc_pm_flag_t slot_pm_flags;
Nicolas Pitre2f4cbb32010-03-05 13:43:32 -0800960 mmc_pm_flag_t pm_flags = 0;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100961 int i, ret;
962
963 chip = pci_get_drvdata(pdev);
964 if (!chip)
965 return 0;
966
Ameya Palandeb177bc92011-04-05 21:13:13 +0300967 for (i = 0; i < chip->num_slots; i++) {
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100968 slot = chip->slots[i];
969 if (!slot)
970 continue;
971
Manuel Lauss29495aa2011-11-03 11:09:45 +0100972 ret = sdhci_suspend_host(slot->host);
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100973
Axel Linb678b912011-12-03 15:28:05 +0800974 if (ret)
975 goto err_pci_suspend;
Nicolas Pitre2f4cbb32010-03-05 13:43:32 -0800976
Daniel Drake5f619702010-11-04 22:20:39 +0000977 slot_pm_flags = slot->host->mmc->pm_flags;
978 if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ)
979 sdhci_enable_irq_wakeups(slot->host);
980
981 pm_flags |= slot_pm_flags;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100982 }
983
Pierre Ossman44894282008-04-04 19:36:59 +0200984 if (chip->fixes && chip->fixes->suspend) {
Manuel Lauss29495aa2011-11-03 11:09:45 +0100985 ret = chip->fixes->suspend(chip);
Axel Linb678b912011-12-03 15:28:05 +0800986 if (ret)
987 goto err_pci_suspend;
Pierre Ossman44894282008-04-04 19:36:59 +0200988 }
989
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +0100990 pci_save_state(pdev);
Nicolas Pitre2f4cbb32010-03-05 13:43:32 -0800991 if (pm_flags & MMC_PM_KEEP_POWER) {
Daniel Drake5f619702010-11-04 22:20:39 +0000992 if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
993 pci_pme_active(pdev, true);
Nicolas Pitre2f4cbb32010-03-05 13:43:32 -0800994 pci_enable_wake(pdev, PCI_D3hot, 1);
Daniel Drake5f619702010-11-04 22:20:39 +0000995 }
Nicolas Pitre2f4cbb32010-03-05 13:43:32 -0800996 pci_set_power_state(pdev, PCI_D3hot);
997 } else {
Manuel Lauss29495aa2011-11-03 11:09:45 +0100998 pci_enable_wake(pdev, PCI_D3hot, 0);
Nicolas Pitre2f4cbb32010-03-05 13:43:32 -0800999 pci_disable_device(pdev);
Manuel Lauss29495aa2011-11-03 11:09:45 +01001000 pci_set_power_state(pdev, PCI_D3hot);
Nicolas Pitre2f4cbb32010-03-05 13:43:32 -08001001 }
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001002
1003 return 0;
Axel Linb678b912011-12-03 15:28:05 +08001004
1005err_pci_suspend:
1006 while (--i >= 0)
1007 sdhci_resume_host(chip->slots[i]->host);
1008 return ret;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001009}
1010
Manuel Lauss29495aa2011-11-03 11:09:45 +01001011static int sdhci_pci_resume(struct device *dev)
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001012{
Manuel Lauss29495aa2011-11-03 11:09:45 +01001013 struct pci_dev *pdev = to_pci_dev(dev);
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001014 struct sdhci_pci_chip *chip;
1015 struct sdhci_pci_slot *slot;
1016 int i, ret;
1017
1018 chip = pci_get_drvdata(pdev);
1019 if (!chip)
1020 return 0;
1021
1022 pci_set_power_state(pdev, PCI_D0);
1023 pci_restore_state(pdev);
1024 ret = pci_enable_device(pdev);
1025 if (ret)
1026 return ret;
1027
Pierre Ossman45211e22008-03-24 13:09:09 +01001028 if (chip->fixes && chip->fixes->resume) {
1029 ret = chip->fixes->resume(chip);
1030 if (ret)
1031 return ret;
1032 }
1033
Ameya Palandeb177bc92011-04-05 21:13:13 +03001034 for (i = 0; i < chip->num_slots; i++) {
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001035 slot = chip->slots[i];
1036 if (!slot)
1037 continue;
1038
1039 ret = sdhci_resume_host(slot->host);
1040 if (ret)
1041 return ret;
1042 }
1043
1044 return 0;
1045}
1046
1047#else /* CONFIG_PM */
1048
1049#define sdhci_pci_suspend NULL
1050#define sdhci_pci_resume NULL
1051
1052#endif /* CONFIG_PM */
1053
Adrian Hunter66fd8ad2011-10-03 15:33:34 +03001054#ifdef CONFIG_PM_RUNTIME
1055
1056static int sdhci_pci_runtime_suspend(struct device *dev)
1057{
1058 struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
1059 struct sdhci_pci_chip *chip;
1060 struct sdhci_pci_slot *slot;
Adrian Hunter66fd8ad2011-10-03 15:33:34 +03001061 int i, ret;
1062
1063 chip = pci_get_drvdata(pdev);
1064 if (!chip)
1065 return 0;
1066
1067 for (i = 0; i < chip->num_slots; i++) {
1068 slot = chip->slots[i];
1069 if (!slot)
1070 continue;
1071
1072 ret = sdhci_runtime_suspend_host(slot->host);
1073
Axel Linb678b912011-12-03 15:28:05 +08001074 if (ret)
1075 goto err_pci_runtime_suspend;
Adrian Hunter66fd8ad2011-10-03 15:33:34 +03001076 }
1077
1078 if (chip->fixes && chip->fixes->suspend) {
Manuel Lauss29495aa2011-11-03 11:09:45 +01001079 ret = chip->fixes->suspend(chip);
Axel Linb678b912011-12-03 15:28:05 +08001080 if (ret)
1081 goto err_pci_runtime_suspend;
Adrian Hunter66fd8ad2011-10-03 15:33:34 +03001082 }
1083
1084 return 0;
Axel Linb678b912011-12-03 15:28:05 +08001085
1086err_pci_runtime_suspend:
1087 while (--i >= 0)
1088 sdhci_runtime_resume_host(chip->slots[i]->host);
1089 return ret;
Adrian Hunter66fd8ad2011-10-03 15:33:34 +03001090}
1091
1092static int sdhci_pci_runtime_resume(struct device *dev)
1093{
1094 struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
1095 struct sdhci_pci_chip *chip;
1096 struct sdhci_pci_slot *slot;
1097 int i, ret;
1098
1099 chip = pci_get_drvdata(pdev);
1100 if (!chip)
1101 return 0;
1102
1103 if (chip->fixes && chip->fixes->resume) {
1104 ret = chip->fixes->resume(chip);
1105 if (ret)
1106 return ret;
1107 }
1108
1109 for (i = 0; i < chip->num_slots; i++) {
1110 slot = chip->slots[i];
1111 if (!slot)
1112 continue;
1113
1114 ret = sdhci_runtime_resume_host(slot->host);
1115 if (ret)
1116 return ret;
1117 }
1118
1119 return 0;
1120}
1121
1122static int sdhci_pci_runtime_idle(struct device *dev)
1123{
1124 return 0;
1125}
1126
1127#else
1128
1129#define sdhci_pci_runtime_suspend NULL
1130#define sdhci_pci_runtime_resume NULL
1131#define sdhci_pci_runtime_idle NULL
1132
1133#endif
1134
1135static const struct dev_pm_ops sdhci_pci_pm_ops = {
Manuel Lauss29495aa2011-11-03 11:09:45 +01001136 .suspend = sdhci_pci_suspend,
1137 .resume = sdhci_pci_resume,
Adrian Hunter66fd8ad2011-10-03 15:33:34 +03001138 .runtime_suspend = sdhci_pci_runtime_suspend,
1139 .runtime_resume = sdhci_pci_runtime_resume,
1140 .runtime_idle = sdhci_pci_runtime_idle,
1141};
1142
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001143/*****************************************************************************\
1144 * *
1145 * Device probing/removal *
1146 * *
1147\*****************************************************************************/
1148
1149static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
Adrian Hunter52c506f2011-12-27 15:48:43 +02001150 struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar,
1151 int slotno)
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001152{
1153 struct sdhci_pci_slot *slot;
1154 struct sdhci_host *host;
Adrian Hunter52c506f2011-12-27 15:48:43 +02001155 int ret, bar = first_bar + slotno;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001156
1157 if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
1158 dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar);
1159 return ERR_PTR(-ENODEV);
1160 }
1161
1162 if (pci_resource_len(pdev, bar) != 0x100) {
1163 dev_err(&pdev->dev, "Invalid iomem size. You may "
1164 "experience problems.\n");
1165 }
1166
1167 if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
1168 dev_err(&pdev->dev, "Vendor specific interface. Aborting.\n");
1169 return ERR_PTR(-ENODEV);
1170 }
1171
1172 if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
1173 dev_err(&pdev->dev, "Unknown interface. Aborting.\n");
1174 return ERR_PTR(-ENODEV);
1175 }
1176
1177 host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot));
1178 if (IS_ERR(host)) {
Dan Carpenterc60a32c2009-04-10 23:31:10 +02001179 dev_err(&pdev->dev, "cannot allocate host\n");
Julia Lawalldc0fd7b2010-05-26 14:42:11 -07001180 return ERR_CAST(host);
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001181 }
1182
1183 slot = sdhci_priv(host);
1184
1185 slot->chip = chip;
1186 slot->host = host;
1187 slot->pci_bar = bar;
Adrian Hunter0f201652011-08-29 16:42:13 +03001188 slot->rst_n_gpio = -EINVAL;
Adrian Hunterc5e027a2011-12-27 15:48:44 +02001189 slot->cd_gpio = -EINVAL;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001190
Adrian Hunter52c506f2011-12-27 15:48:43 +02001191 /* Retrieve platform data if there is any */
1192 if (*sdhci_pci_get_data)
1193 slot->data = sdhci_pci_get_data(pdev, slotno);
1194
1195 if (slot->data) {
1196 if (slot->data->setup) {
1197 ret = slot->data->setup(slot->data);
1198 if (ret) {
1199 dev_err(&pdev->dev, "platform setup failed\n");
1200 goto free;
1201 }
1202 }
Adrian Hunterc5e027a2011-12-27 15:48:44 +02001203 slot->rst_n_gpio = slot->data->rst_n_gpio;
1204 slot->cd_gpio = slot->data->cd_gpio;
Adrian Hunter52c506f2011-12-27 15:48:43 +02001205 }
1206
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001207 host->hw_name = "PCI";
1208 host->ops = &sdhci_pci_ops;
1209 host->quirks = chip->quirks;
1210
1211 host->irq = pdev->irq;
1212
1213 ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc));
1214 if (ret) {
1215 dev_err(&pdev->dev, "cannot request region\n");
Adrian Hunter52c506f2011-12-27 15:48:43 +02001216 goto cleanup;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001217 }
1218
Arjan van de Ven092f82e2008-09-28 16:15:56 -07001219 host->ioaddr = pci_ioremap_bar(pdev, bar);
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001220 if (!host->ioaddr) {
1221 dev_err(&pdev->dev, "failed to remap registers\n");
Chris Ball9fdcdbb2011-03-29 00:46:12 -04001222 ret = -ENOMEM;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001223 goto release;
1224 }
1225
Pierre Ossman44894282008-04-04 19:36:59 +02001226 if (chip->fixes && chip->fixes->probe_slot) {
1227 ret = chip->fixes->probe_slot(slot);
1228 if (ret)
1229 goto unmap;
1230 }
1231
Adrian Hunterc5e027a2011-12-27 15:48:44 +02001232 if (gpio_is_valid(slot->rst_n_gpio)) {
1233 if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) {
1234 gpio_direction_output(slot->rst_n_gpio, 1);
1235 slot->host->mmc->caps |= MMC_CAP_HW_RESET;
1236 } else {
1237 dev_warn(&pdev->dev, "failed to request rst_n_gpio\n");
1238 slot->rst_n_gpio = -EINVAL;
1239 }
1240 }
1241
Nicolas Pitre2f4cbb32010-03-05 13:43:32 -08001242 host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
1243
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001244 ret = sdhci_add_host(host);
1245 if (ret)
Pierre Ossman44894282008-04-04 19:36:59 +02001246 goto remove;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001247
Adrian Hunterc5e027a2011-12-27 15:48:44 +02001248 sdhci_pci_add_own_cd(slot);
1249
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001250 return slot;
1251
Pierre Ossman44894282008-04-04 19:36:59 +02001252remove:
Adrian Hunterc5e027a2011-12-27 15:48:44 +02001253 if (gpio_is_valid(slot->rst_n_gpio))
1254 gpio_free(slot->rst_n_gpio);
1255
Pierre Ossman44894282008-04-04 19:36:59 +02001256 if (chip->fixes && chip->fixes->remove_slot)
Pierre Ossman1e728592008-04-16 19:13:13 +02001257 chip->fixes->remove_slot(slot, 0);
Pierre Ossman44894282008-04-04 19:36:59 +02001258
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001259unmap:
1260 iounmap(host->ioaddr);
1261
1262release:
1263 pci_release_region(pdev, bar);
Dan Carpenterc60a32c2009-04-10 23:31:10 +02001264
Adrian Hunter52c506f2011-12-27 15:48:43 +02001265cleanup:
1266 if (slot->data && slot->data->cleanup)
1267 slot->data->cleanup(slot->data);
1268
Dan Carpenterc60a32c2009-04-10 23:31:10 +02001269free:
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001270 sdhci_free_host(host);
1271
1272 return ERR_PTR(ret);
1273}
1274
1275static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
1276{
Pierre Ossman1e728592008-04-16 19:13:13 +02001277 int dead;
1278 u32 scratch;
1279
Adrian Hunterc5e027a2011-12-27 15:48:44 +02001280 sdhci_pci_remove_own_cd(slot);
1281
Pierre Ossman1e728592008-04-16 19:13:13 +02001282 dead = 0;
1283 scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS);
1284 if (scratch == (u32)-1)
1285 dead = 1;
1286
1287 sdhci_remove_host(slot->host, dead);
Pierre Ossman44894282008-04-04 19:36:59 +02001288
Adrian Hunterc5e027a2011-12-27 15:48:44 +02001289 if (gpio_is_valid(slot->rst_n_gpio))
1290 gpio_free(slot->rst_n_gpio);
1291
Pierre Ossman44894282008-04-04 19:36:59 +02001292 if (slot->chip->fixes && slot->chip->fixes->remove_slot)
Pierre Ossman1e728592008-04-16 19:13:13 +02001293 slot->chip->fixes->remove_slot(slot, dead);
Pierre Ossman44894282008-04-04 19:36:59 +02001294
Adrian Hunter52c506f2011-12-27 15:48:43 +02001295 if (slot->data && slot->data->cleanup)
1296 slot->data->cleanup(slot->data);
1297
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001298 pci_release_region(slot->chip->pdev, slot->pci_bar);
Pierre Ossman44894282008-04-04 19:36:59 +02001299
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001300 sdhci_free_host(slot->host);
1301}
1302
Adrian Hunter66fd8ad2011-10-03 15:33:34 +03001303static void __devinit sdhci_pci_runtime_pm_allow(struct device *dev)
1304{
1305 pm_runtime_put_noidle(dev);
1306 pm_runtime_allow(dev);
1307 pm_runtime_set_autosuspend_delay(dev, 50);
1308 pm_runtime_use_autosuspend(dev);
1309 pm_suspend_ignore_children(dev, 1);
1310}
1311
1312static void __devexit sdhci_pci_runtime_pm_forbid(struct device *dev)
1313{
1314 pm_runtime_forbid(dev);
1315 pm_runtime_get_noresume(dev);
1316}
1317
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001318static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
1319 const struct pci_device_id *ent)
1320{
1321 struct sdhci_pci_chip *chip;
1322 struct sdhci_pci_slot *slot;
1323
Sergei Shtylyovcf5e23e2011-03-17 16:46:17 -04001324 u8 slots, first_bar;
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001325 int ret, i;
1326
1327 BUG_ON(pdev == NULL);
1328 BUG_ON(ent == NULL);
1329
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001330 dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n",
Sergei Shtylyovcf5e23e2011-03-17 16:46:17 -04001331 (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001332
1333 ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
1334 if (ret)
1335 return ret;
1336
1337 slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
1338 dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
1339 if (slots == 0)
1340 return -ENODEV;
1341
1342 BUG_ON(slots > MAX_SLOTS);
1343
1344 ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
1345 if (ret)
1346 return ret;
1347
1348 first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
1349
1350 if (first_bar > 5) {
1351 dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n");
1352 return -ENODEV;
1353 }
1354
1355 ret = pci_enable_device(pdev);
1356 if (ret)
1357 return ret;
1358
1359 chip = kzalloc(sizeof(struct sdhci_pci_chip), GFP_KERNEL);
1360 if (!chip) {
1361 ret = -ENOMEM;
1362 goto err;
1363 }
1364
1365 chip->pdev = pdev;
Ameya Palandeb177bc92011-04-05 21:13:13 +03001366 chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
Adrian Hunterc43fd772011-10-17 10:52:44 +03001367 if (chip->fixes) {
Pierre Ossman22606402008-03-23 19:33:23 +01001368 chip->quirks = chip->fixes->quirks;
Adrian Hunterc43fd772011-10-17 10:52:44 +03001369 chip->allow_runtime_pm = chip->fixes->allow_runtime_pm;
1370 }
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001371 chip->num_slots = slots;
1372
1373 pci_set_drvdata(pdev, chip);
1374
Pierre Ossman22606402008-03-23 19:33:23 +01001375 if (chip->fixes && chip->fixes->probe) {
1376 ret = chip->fixes->probe(chip);
1377 if (ret)
1378 goto free;
1379 }
1380
Alan Cox225d85f2010-10-04 15:24:21 +01001381 slots = chip->num_slots; /* Quirk may have changed this */
1382
Ameya Palandeb177bc92011-04-05 21:13:13 +03001383 for (i = 0; i < slots; i++) {
Adrian Hunter52c506f2011-12-27 15:48:43 +02001384 slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001385 if (IS_ERR(slot)) {
Ameya Palandeb177bc92011-04-05 21:13:13 +03001386 for (i--; i >= 0; i--)
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001387 sdhci_pci_remove_slot(chip->slots[i]);
1388 ret = PTR_ERR(slot);
1389 goto free;
1390 }
1391
1392 chip->slots[i] = slot;
1393 }
1394
Adrian Hunterc43fd772011-10-17 10:52:44 +03001395 if (chip->allow_runtime_pm)
1396 sdhci_pci_runtime_pm_allow(&pdev->dev);
Adrian Hunter66fd8ad2011-10-03 15:33:34 +03001397
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001398 return 0;
1399
1400free:
1401 pci_set_drvdata(pdev, NULL);
1402 kfree(chip);
1403
1404err:
1405 pci_disable_device(pdev);
1406 return ret;
1407}
1408
1409static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
1410{
1411 int i;
1412 struct sdhci_pci_chip *chip;
1413
1414 chip = pci_get_drvdata(pdev);
1415
1416 if (chip) {
Adrian Hunterc43fd772011-10-17 10:52:44 +03001417 if (chip->allow_runtime_pm)
1418 sdhci_pci_runtime_pm_forbid(&pdev->dev);
1419
Ameya Palandeb177bc92011-04-05 21:13:13 +03001420 for (i = 0; i < chip->num_slots; i++)
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001421 sdhci_pci_remove_slot(chip->slots[i]);
1422
1423 pci_set_drvdata(pdev, NULL);
1424 kfree(chip);
1425 }
1426
1427 pci_disable_device(pdev);
1428}
1429
1430static struct pci_driver sdhci_driver = {
Ameya Palandeb177bc92011-04-05 21:13:13 +03001431 .name = "sdhci-pci",
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001432 .id_table = pci_ids,
Ameya Palandeb177bc92011-04-05 21:13:13 +03001433 .probe = sdhci_pci_probe,
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001434 .remove = __devexit_p(sdhci_pci_remove),
Adrian Hunter66fd8ad2011-10-03 15:33:34 +03001435 .driver = {
1436 .pm = &sdhci_pci_pm_ops
1437 },
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001438};
1439
1440/*****************************************************************************\
1441 * *
1442 * Driver init/exit *
1443 * *
1444\*****************************************************************************/
1445
1446static int __init sdhci_drv_init(void)
1447{
1448 return pci_register_driver(&sdhci_driver);
1449}
1450
1451static void __exit sdhci_drv_exit(void)
1452{
1453 pci_unregister_driver(&sdhci_driver);
1454}
1455
1456module_init(sdhci_drv_init);
1457module_exit(sdhci_drv_exit);
1458
Pierre Ossman32710e82009-04-08 20:14:54 +02001459MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
Pierre Ossmanb8c86fc2008-03-18 17:35:49 +01001460MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver");
1461MODULE_LICENSE("GPL");