]> Pileus Git - ~andy/linux/blob - drivers/mmc/host/ricoh_mmc.c
at91_mci: use generic GPIO calls
[~andy/linux] / drivers / mmc / host / ricoh_mmc.c
1 /*
2  *  ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller.
3  *
4  *  Copyright (C) 2007 Philip Langdale, All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or (at
9  * your option) any later version.
10  */
11
12 /*
13  * This is a conceptually ridiculous driver, but it is required by the way
14  * the Ricoh multi-function R5C832 works. This chip implements firewire
15  * and four different memory card controllers. Two of those controllers are
16  * an SDHCI controller and a proprietary MMC controller. The linux SDHCI
17  * driver supports MMC cards but the chip detects MMC cards in hardware
18  * and directs them to the MMC controller - so the SDHCI driver never sees
19  * them. To get around this, we must disable the useless MMC controller.
20  * At that point, the SDHCI controller will start seeing them. As a bonus,
21  * a detection event occurs immediately, even if the MMC card is already
22  * in the reader.
23  *
24  * The relevant registers live on the firewire function, so this is unavoidably
25  * ugly. Such is life.
26  */
27
28 #include <linux/pci.h>
29
30 #define DRIVER_NAME "ricoh-mmc"
31
32 static const struct pci_device_id pci_ids[] __devinitdata = {
33         {
34                 .vendor         = PCI_VENDOR_ID_RICOH,
35                 .device         = PCI_DEVICE_ID_RICOH_R5C843,
36                 .subvendor      = PCI_ANY_ID,
37                 .subdevice      = PCI_ANY_ID,
38         },
39         { /* end: all zeroes */ },
40 };
41
42 MODULE_DEVICE_TABLE(pci, pci_ids);
43
44 static int ricoh_mmc_disable(struct pci_dev *fw_dev)
45 {
46         u8 write_enable;
47         u8 disable;
48
49         pci_read_config_byte(fw_dev, 0xCB, &disable);
50         if (disable & 0x02) {
51                 printk(KERN_INFO DRIVER_NAME
52                        ": Controller already disabled. Nothing to do.\n");
53                 return -ENODEV;
54         }
55
56         pci_read_config_byte(fw_dev, 0xCA, &write_enable);
57         pci_write_config_byte(fw_dev, 0xCA, 0x57);
58         pci_write_config_byte(fw_dev, 0xCB, disable | 0x02);
59         pci_write_config_byte(fw_dev, 0xCA, write_enable);
60
61         printk(KERN_INFO DRIVER_NAME
62                ": Controller is now disabled.\n");
63
64         return 0;
65 }
66
67 static int ricoh_mmc_enable(struct pci_dev *fw_dev)
68 {
69         u8 write_enable;
70         u8 disable;
71
72         pci_read_config_byte(fw_dev, 0xCA, &write_enable);
73         pci_read_config_byte(fw_dev, 0xCB, &disable);
74         pci_write_config_byte(fw_dev, 0xCA, 0x57);
75         pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02);
76         pci_write_config_byte(fw_dev, 0xCA, write_enable);
77
78         printk(KERN_INFO DRIVER_NAME
79                ": Controller is now re-enabled.\n");
80
81         return 0;
82 }
83
84 static int __devinit ricoh_mmc_probe(struct pci_dev *pdev,
85                                      const struct pci_device_id *ent)
86 {
87         u8 rev;
88
89         struct pci_dev *fw_dev = NULL;
90
91         BUG_ON(pdev == NULL);
92         BUG_ON(ent == NULL);
93
94         pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
95
96         printk(KERN_INFO DRIVER_NAME
97                 ": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n",
98                 pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
99                 (int)rev);
100
101         while ((fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) {
102                 if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&
103                     pdev->bus == fw_dev->bus) {
104                         if (ricoh_mmc_disable(fw_dev) != 0) {
105                                 return -ENODEV;
106                         }
107
108                         pci_set_drvdata(pdev, fw_dev);
109
110                         break;
111                 }
112         }
113
114         if (pci_get_drvdata(pdev) == NULL) {
115                 printk(KERN_WARNING DRIVER_NAME
116                        ": Main firewire function not found. Cannot disable controller.\n");
117                 return -ENODEV;
118         }
119
120         return 0;
121 }
122
123 static void __devexit ricoh_mmc_remove(struct pci_dev *pdev)
124 {
125         struct pci_dev *fw_dev = NULL;
126
127         fw_dev = pci_get_drvdata(pdev);
128         BUG_ON(fw_dev == NULL);
129
130         ricoh_mmc_enable(fw_dev);
131
132         pci_set_drvdata(pdev, NULL);
133 }
134
135 static int ricoh_mmc_suspend (struct pci_dev *pdev, pm_message_t state)
136 {
137         struct pci_dev *fw_dev = NULL;
138
139         fw_dev = pci_get_drvdata(pdev);
140         BUG_ON(fw_dev == NULL);
141
142         printk(KERN_INFO DRIVER_NAME ": Suspending.\n");
143
144         ricoh_mmc_enable(fw_dev);
145
146         return 0;
147 }
148
149 static int ricoh_mmc_resume (struct pci_dev *pdev)
150 {
151         struct pci_dev *fw_dev = NULL;
152
153         fw_dev = pci_get_drvdata(pdev);
154         BUG_ON(fw_dev == NULL);
155
156         printk(KERN_INFO DRIVER_NAME ": Resuming.\n");
157
158         ricoh_mmc_disable(fw_dev);
159
160         return 0;
161 }
162
163 static struct pci_driver ricoh_mmc_driver = {
164         .name =         DRIVER_NAME,
165         .id_table =     pci_ids,
166         .probe =        ricoh_mmc_probe,
167         .remove =       __devexit_p(ricoh_mmc_remove),
168         .suspend =      ricoh_mmc_suspend,
169         .resume =       ricoh_mmc_resume,
170 };
171
172 /*****************************************************************************\
173  *                                                                           *
174  * Driver init/exit                                                          *
175  *                                                                           *
176 \*****************************************************************************/
177
178 static int __init ricoh_mmc_drv_init(void)
179 {
180         printk(KERN_INFO DRIVER_NAME
181                 ": Ricoh MMC Controller disabling driver\n");
182         printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n");
183
184         return pci_register_driver(&ricoh_mmc_driver);
185 }
186
187 static void __exit ricoh_mmc_drv_exit(void)
188 {
189         pci_unregister_driver(&ricoh_mmc_driver);
190 }
191
192 module_init(ricoh_mmc_drv_init);
193 module_exit(ricoh_mmc_drv_exit);
194
195 MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>");
196 MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver");
197 MODULE_LICENSE("GPL");
198