sdhci: more complex quirks handling
[linux-2.6-block.git] / drivers / mmc / host / sdhci-pci.c
CommitLineData
b8c86fc5
PO
1/* 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>
17#include <linux/pci.h>
18#include <linux/dma-mapping.h>
19
20#include <linux/mmc/host.h>
21
22#include <asm/scatterlist.h>
23#include <asm/io.h>
24
25#include "sdhci.h"
26
27/*
28 * PCI registers
29 */
30
31#define PCI_SDHCI_IFPIO 0x00
32#define PCI_SDHCI_IFDMA 0x01
33#define PCI_SDHCI_IFVENDOR 0x02
34
35#define PCI_SLOT_INFO 0x40 /* 8 bits */
36#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7)
37#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07
38
39#define MAX_SLOTS 8
40
22606405
PO
41struct sdhci_pci_chip;
42
43struct sdhci_pci_fixes {
44 unsigned int quirks;
45
46 int (*probe)(struct sdhci_pci_chip*);
47};
48
49struct sdhci_pci_slot {
50 struct sdhci_pci_chip *chip;
51 struct sdhci_host *host;
b8c86fc5 52
22606405
PO
53 int pci_bar;
54};
55
56struct sdhci_pci_chip {
57 struct pci_dev *pdev;
58
59 unsigned int quirks;
60 const struct sdhci_pci_fixes *fixes;
61
62 int num_slots; /* Slots on controller */
63 struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */
64};
65
66
67/*****************************************************************************\
68 * *
69 * Hardware specific quirk handling *
70 * *
71\*****************************************************************************/
72
73static int ricoh_probe(struct sdhci_pci_chip *chip)
74{
75 if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
76 chip->quirks |= SDHCI_QUIRK_CLOCK_BEFORE_RESET;
77
78 if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)
79 chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET;
80
81 return 0;
82}
83
84static const struct sdhci_pci_fixes sdhci_ricoh = {
85 .probe = ricoh_probe,
86};
87
88static const struct sdhci_pci_fixes sdhci_ene_712 = {
89 .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
90 SDHCI_QUIRK_BROKEN_DMA,
91};
92
93static const struct sdhci_pci_fixes sdhci_ene_714 = {
94 .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
95 SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
96 SDHCI_QUIRK_BROKEN_DMA,
97};
98
99static const struct sdhci_pci_fixes sdhci_cafe = {
100 .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
101 SDHCI_QUIRK_INCR_TIMEOUT_CONTROL,
102};
103
104static const struct sdhci_pci_fixes sdhci_jmicron = {
105 .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
106 SDHCI_QUIRK_32BIT_DMA_SIZE |
107 SDHCI_QUIRK_RESET_AFTER_REQUEST,
108};
109
110static const struct pci_device_id pci_ids[] __devinitdata = {
b8c86fc5
PO
111 {
112 .vendor = PCI_VENDOR_ID_RICOH,
113 .device = PCI_DEVICE_ID_RICOH_R5C822,
22606405 114 .subvendor = PCI_ANY_ID,
b8c86fc5 115 .subdevice = PCI_ANY_ID,
22606405 116 .driver_data = (kernel_ulong_t)&sdhci_ricoh,
b8c86fc5
PO
117 },
118
119 {
120 .vendor = PCI_VENDOR_ID_ENE,
121 .device = PCI_DEVICE_ID_ENE_CB712_SD,
122 .subvendor = PCI_ANY_ID,
123 .subdevice = PCI_ANY_ID,
22606405 124 .driver_data = (kernel_ulong_t)&sdhci_ene_712,
b8c86fc5
PO
125 },
126
127 {
128 .vendor = PCI_VENDOR_ID_ENE,
129 .device = PCI_DEVICE_ID_ENE_CB712_SD_2,
130 .subvendor = PCI_ANY_ID,
131 .subdevice = PCI_ANY_ID,
22606405 132 .driver_data = (kernel_ulong_t)&sdhci_ene_712,
b8c86fc5
PO
133 },
134
135 {
136 .vendor = PCI_VENDOR_ID_ENE,
137 .device = PCI_DEVICE_ID_ENE_CB714_SD,
138 .subvendor = PCI_ANY_ID,
139 .subdevice = PCI_ANY_ID,
22606405 140 .driver_data = (kernel_ulong_t)&sdhci_ene_714,
b8c86fc5
PO
141 },
142
143 {
144 .vendor = PCI_VENDOR_ID_ENE,
145 .device = PCI_DEVICE_ID_ENE_CB714_SD_2,
146 .subvendor = PCI_ANY_ID,
147 .subdevice = PCI_ANY_ID,
22606405 148 .driver_data = (kernel_ulong_t)&sdhci_ene_714,
b8c86fc5
PO
149 },
150
151 {
152 .vendor = PCI_VENDOR_ID_MARVELL,
153 .device = PCI_DEVICE_ID_MARVELL_CAFE_SD,
154 .subvendor = PCI_ANY_ID,
155 .subdevice = PCI_ANY_ID,
22606405 156 .driver_data = (kernel_ulong_t)&sdhci_cafe,
b8c86fc5
PO
157 },
158
159 {
160 .vendor = PCI_VENDOR_ID_JMICRON,
161 .device = PCI_DEVICE_ID_JMICRON_JMB38X_SD,
162 .subvendor = PCI_ANY_ID,
163 .subdevice = PCI_ANY_ID,
22606405 164 .driver_data = (kernel_ulong_t)&sdhci_jmicron,
b8c86fc5
PO
165 },
166
167 { /* Generic SD host controller */
168 PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
169 },
170
171 { /* end: all zeroes */ },
172};
173
174MODULE_DEVICE_TABLE(pci, pci_ids);
175
b8c86fc5
PO
176/*****************************************************************************\
177 * *
178 * SDHCI core callbacks *
179 * *
180\*****************************************************************************/
181
182static int sdhci_pci_enable_dma(struct sdhci_host *host)
183{
184 struct sdhci_pci_slot *slot;
185 struct pci_dev *pdev;
186 int ret;
187
188 slot = sdhci_priv(host);
189 pdev = slot->chip->pdev;
190
191 if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) &&
192 ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
193 (host->flags & SDHCI_USE_DMA)) {
194 dev_warn(&pdev->dev, "Will use DMA mode even though HW "
195 "doesn't fully claim to support it.\n");
196 }
197
198 ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
199 if (ret)
200 return ret;
201
202 pci_set_master(pdev);
203
204 return 0;
205}
206
207static struct sdhci_ops sdhci_pci_ops = {
208 .enable_dma = sdhci_pci_enable_dma,
209};
210
211/*****************************************************************************\
212 * *
213 * Suspend/resume *
214 * *
215\*****************************************************************************/
216
217#ifdef CONFIG_PM
218
219static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
220{
221 struct sdhci_pci_chip *chip;
222 struct sdhci_pci_slot *slot;
223 int i, ret;
224
225 chip = pci_get_drvdata(pdev);
226 if (!chip)
227 return 0;
228
229 for (i = 0;i < chip->num_slots;i++) {
230 slot = chip->slots[i];
231 if (!slot)
232 continue;
233
234 ret = sdhci_suspend_host(slot->host, state);
235
236 if (ret) {
237 for (i--;i >= 0;i--)
238 sdhci_resume_host(chip->slots[i]->host);
239 return ret;
240 }
241 }
242
243 pci_save_state(pdev);
244 pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
245 pci_disable_device(pdev);
246 pci_set_power_state(pdev, pci_choose_state(pdev, state));
247
248 return 0;
249}
250
251static int sdhci_pci_resume (struct pci_dev *pdev)
252{
253 struct sdhci_pci_chip *chip;
254 struct sdhci_pci_slot *slot;
255 int i, ret;
256
257 chip = pci_get_drvdata(pdev);
258 if (!chip)
259 return 0;
260
261 pci_set_power_state(pdev, PCI_D0);
262 pci_restore_state(pdev);
263 ret = pci_enable_device(pdev);
264 if (ret)
265 return ret;
266
267 for (i = 0;i < chip->num_slots;i++) {
268 slot = chip->slots[i];
269 if (!slot)
270 continue;
271
272 ret = sdhci_resume_host(slot->host);
273 if (ret)
274 return ret;
275 }
276
277 return 0;
278}
279
280#else /* CONFIG_PM */
281
282#define sdhci_pci_suspend NULL
283#define sdhci_pci_resume NULL
284
285#endif /* CONFIG_PM */
286
287/*****************************************************************************\
288 * *
289 * Device probing/removal *
290 * *
291\*****************************************************************************/
292
293static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
294 struct pci_dev *pdev, struct sdhci_pci_chip *chip, int bar)
295{
296 struct sdhci_pci_slot *slot;
297 struct sdhci_host *host;
298
299 resource_size_t addr;
300
301 int ret;
302
303 if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
304 dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar);
305 return ERR_PTR(-ENODEV);
306 }
307
308 if (pci_resource_len(pdev, bar) != 0x100) {
309 dev_err(&pdev->dev, "Invalid iomem size. You may "
310 "experience problems.\n");
311 }
312
313 if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
314 dev_err(&pdev->dev, "Vendor specific interface. Aborting.\n");
315 return ERR_PTR(-ENODEV);
316 }
317
318 if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
319 dev_err(&pdev->dev, "Unknown interface. Aborting.\n");
320 return ERR_PTR(-ENODEV);
321 }
322
323 host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot));
324 if (IS_ERR(host)) {
325 ret = PTR_ERR(host);
326 goto unmap;
327 }
328
329 slot = sdhci_priv(host);
330
331 slot->chip = chip;
332 slot->host = host;
333 slot->pci_bar = bar;
334
335 host->hw_name = "PCI";
336 host->ops = &sdhci_pci_ops;
337 host->quirks = chip->quirks;
338
339 host->irq = pdev->irq;
340
341 ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc));
342 if (ret) {
343 dev_err(&pdev->dev, "cannot request region\n");
344 return ERR_PTR(ret);
345 }
346
347 addr = pci_resource_start(pdev, bar);
348 host->ioaddr = ioremap_nocache(addr, pci_resource_len(pdev, bar));
349 if (!host->ioaddr) {
350 dev_err(&pdev->dev, "failed to remap registers\n");
351 goto release;
352 }
353
354 ret = sdhci_add_host(host);
355 if (ret)
356 goto unmap;
357
358 return slot;
359
360unmap:
361 iounmap(host->ioaddr);
362
363release:
364 pci_release_region(pdev, bar);
365 sdhci_free_host(host);
366
367 return ERR_PTR(ret);
368}
369
370static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
371{
372 sdhci_remove_host(slot->host);
373 pci_release_region(slot->chip->pdev, slot->pci_bar);
374 sdhci_free_host(slot->host);
375}
376
377static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
378 const struct pci_device_id *ent)
379{
380 struct sdhci_pci_chip *chip;
381 struct sdhci_pci_slot *slot;
382
383 u8 slots, rev, first_bar;
384 int ret, i;
385
386 BUG_ON(pdev == NULL);
387 BUG_ON(ent == NULL);
388
389 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
390
391 dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n",
392 (int)pdev->vendor, (int)pdev->device, (int)rev);
393
394 ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
395 if (ret)
396 return ret;
397
398 slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
399 dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
400 if (slots == 0)
401 return -ENODEV;
402
403 BUG_ON(slots > MAX_SLOTS);
404
405 ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
406 if (ret)
407 return ret;
408
409 first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
410
411 if (first_bar > 5) {
412 dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n");
413 return -ENODEV;
414 }
415
416 ret = pci_enable_device(pdev);
417 if (ret)
418 return ret;
419
420 chip = kzalloc(sizeof(struct sdhci_pci_chip), GFP_KERNEL);
421 if (!chip) {
422 ret = -ENOMEM;
423 goto err;
424 }
425
426 chip->pdev = pdev;
22606405
PO
427 chip->fixes = (const struct sdhci_pci_fixes*)ent->driver_data;
428 if (chip->fixes)
429 chip->quirks = chip->fixes->quirks;
b8c86fc5
PO
430 chip->num_slots = slots;
431
432 pci_set_drvdata(pdev, chip);
433
22606405
PO
434 if (chip->fixes && chip->fixes->probe) {
435 ret = chip->fixes->probe(chip);
436 if (ret)
437 goto free;
438 }
439
b8c86fc5
PO
440 for (i = 0;i < slots;i++) {
441 slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
442 if (IS_ERR(slot)) {
443 for (i--;i >= 0;i--)
444 sdhci_pci_remove_slot(chip->slots[i]);
445 ret = PTR_ERR(slot);
446 goto free;
447 }
448
449 chip->slots[i] = slot;
450 }
451
452 return 0;
453
454free:
455 pci_set_drvdata(pdev, NULL);
456 kfree(chip);
457
458err:
459 pci_disable_device(pdev);
460 return ret;
461}
462
463static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
464{
465 int i;
466 struct sdhci_pci_chip *chip;
467
468 chip = pci_get_drvdata(pdev);
469
470 if (chip) {
471 for (i = 0;i < chip->num_slots; i++)
472 sdhci_pci_remove_slot(chip->slots[i]);
473
474 pci_set_drvdata(pdev, NULL);
475 kfree(chip);
476 }
477
478 pci_disable_device(pdev);
479}
480
481static struct pci_driver sdhci_driver = {
482 .name = "sdhci-pci",
483 .id_table = pci_ids,
484 .probe = sdhci_pci_probe,
485 .remove = __devexit_p(sdhci_pci_remove),
486 .suspend = sdhci_pci_suspend,
487 .resume = sdhci_pci_resume,
488};
489
490/*****************************************************************************\
491 * *
492 * Driver init/exit *
493 * *
494\*****************************************************************************/
495
496static int __init sdhci_drv_init(void)
497{
498 return pci_register_driver(&sdhci_driver);
499}
500
501static void __exit sdhci_drv_exit(void)
502{
503 pci_unregister_driver(&sdhci_driver);
504}
505
506module_init(sdhci_drv_init);
507module_exit(sdhci_drv_exit);
508
509MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
510MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver");
511MODULE_LICENSE("GPL");