tifm_7xx1: Merge media insert and media remove functions
[linux-2.6.git] / drivers / misc / tifm_7xx1.c
1 /*
2  *  tifm_7xx1.c - TI FlashMedia driver
3  *
4  *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
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 version 2 as
8  * published by the Free Software Foundation.
9  *
10  */
11
12 #include <linux/tifm.h>
13 #include <linux/dma-mapping.h>
14
15 #define DRIVER_NAME "tifm_7xx1"
16 #define DRIVER_VERSION "0.7"
17
18 static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
19 {
20         unsigned long flags;
21
22         spin_lock_irqsave(&fm->lock, flags);
23         if (!fm->inhibit_new_cards) {
24                 fm->socket_change_set |= 1 << sock->socket_id;
25                 queue_work(fm->wq, &fm->media_switcher);
26         }
27         spin_unlock_irqrestore(&fm->lock, flags);
28 }
29
30 static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
31 {
32         struct tifm_adapter *fm = dev_id;
33         struct tifm_dev *sock;
34         unsigned int irq_status;
35         unsigned int sock_irq_status, cnt;
36
37         spin_lock(&fm->lock);
38         irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);
39         if (irq_status == 0 || irq_status == (~0)) {
40                 spin_unlock(&fm->lock);
41                 return IRQ_NONE;
42         }
43
44         if (irq_status & TIFM_IRQ_ENABLE) {
45                 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
46
47                 for (cnt = 0; cnt <  fm->num_sockets; cnt++) {
48                         sock = fm->sockets[cnt];
49                         sock_irq_status = (irq_status >> cnt)
50                                           & (TIFM_IRQ_FIFOMASK(1)
51                                              | TIFM_IRQ_CARDMASK(1));
52
53                         if (sock && sock_irq_status)
54                                 sock->signal_irq(sock, sock_irq_status);
55                 }
56
57                  fm->socket_change_set |= irq_status
58                                           & ((1 << fm->num_sockets) - 1);
59         }
60         writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
61
62         if (!fm->inhibit_new_cards) {
63                 if (!fm->socket_change_set) {
64                         writel(TIFM_IRQ_ENABLE,
65                                 fm->addr + FM_SET_INTERRUPT_ENABLE);
66                 } else {
67                         queue_work(fm->wq, &fm->media_switcher);
68                 }
69         }
70
71         spin_unlock(&fm->lock);
72         return IRQ_HANDLED;
73 }
74
75 static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
76 {
77         unsigned int s_state;
78         int cnt;
79
80         writel(0x0e00, sock_addr + SOCK_CONTROL);
81
82         for (cnt = 0; cnt < 100; cnt++) {
83                 if (!(TIFM_SOCK_STATE_POWERED &
84                                 readl(sock_addr + SOCK_PRESENT_STATE)))
85                         break;
86                 msleep(10);
87         }
88
89         s_state = readl(sock_addr + SOCK_PRESENT_STATE);
90         if (!(TIFM_SOCK_STATE_OCCUPIED & s_state))
91                 return FM_NULL;
92
93         if (is_x2) {
94                 writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
95         } else {
96                 // SmartMedia cards need extra 40 msec
97                 if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1)
98                         msleep(40);
99                 writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
100                        sock_addr + SOCK_CONTROL);
101                 msleep(10);
102                 writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED,
103                         sock_addr + SOCK_CONTROL);
104         }
105
106         for (cnt = 0; cnt < 100; cnt++) {
107                 if ((TIFM_SOCK_STATE_POWERED &
108                                 readl(sock_addr + SOCK_PRESENT_STATE)))
109                         break;
110                 msleep(10);
111         }
112
113         if (!is_x2)
114                 writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
115                        sock_addr + SOCK_CONTROL);
116
117         return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
118 }
119
120 inline static char __iomem *
121 tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
122 {
123         return base_addr + ((sock_num + 1) << 10);
124 }
125
126 static void tifm_7xx1_switch_media(struct work_struct *work)
127 {
128         struct tifm_adapter *fm =
129                 container_of(work, struct tifm_adapter, media_switcher);
130         unsigned long flags;
131         tifm_media_id media_id;
132         char *card_name = "xx";
133         int cnt;
134         struct tifm_dev *sock;
135         unsigned int socket_change_set;
136
137         if (!class_device_get(&fm->cdev))
138                 return;
139
140         while (1) {
141                 spin_lock_irqsave(&fm->lock, flags);
142                 socket_change_set = fm->socket_change_set;
143                 fm->socket_change_set = 0;
144
145                 dev_dbg(fm->dev, "checking media set %x\n",
146                         socket_change_set);
147
148                 if (fm->inhibit_new_cards)
149                         socket_change_set = (1 << fm->num_sockets) - 1;
150                 spin_unlock_irqrestore(&fm->lock, flags);
151
152                 if (!socket_change_set)
153                         break;
154
155                 spin_lock_irqsave(&fm->lock, flags);
156                 for (cnt = 0; cnt < fm->num_sockets; cnt++) {
157                         if (!(socket_change_set & (1 << cnt)))
158                                 continue;
159                         sock = fm->sockets[cnt];
160                         if (sock) {
161                                 printk(KERN_INFO DRIVER_NAME
162                                        ": demand removing card from socket %d\n",
163                                        cnt);
164                                 fm->sockets[cnt] = NULL;
165                                 spin_unlock_irqrestore(&fm->lock, flags);
166                                 device_unregister(&sock->dev);
167                                 spin_lock_irqsave(&fm->lock, flags);
168                                 writel(0x0e00,
169                                        tifm_7xx1_sock_addr(fm->addr, cnt)
170                                        + SOCK_CONTROL);
171                         }
172                         if (fm->inhibit_new_cards)
173                                 continue;
174
175                         spin_unlock_irqrestore(&fm->lock, flags);
176                         media_id = tifm_7xx1_toggle_sock_power(
177                                         tifm_7xx1_sock_addr(fm->addr, cnt),
178                                         fm->num_sockets == 2);
179                         if (media_id) {
180                                 sock = tifm_alloc_device(fm);
181                                 if (sock) {
182                                         sock->addr = tifm_7xx1_sock_addr(fm->addr,
183                                                                         cnt);
184                                         sock->media_id = media_id;
185                                         sock->socket_id = cnt;
186                                         switch (media_id) {
187                                         case 1:
188                                                 card_name = "xd";
189                                                 break;
190                                         case 2:
191                                                 card_name = "ms";
192                                                 break;
193                                         case 3:
194                                                 card_name = "sd";
195                                                 break;
196                                         default:
197                                                 tifm_free_device(&sock->dev);
198                                                 spin_lock_irqsave(&fm->lock, flags);
199                                                 continue;
200                                         }
201                                         snprintf(sock->dev.bus_id, BUS_ID_SIZE,
202                                                 "tifm_%s%u:%u", card_name, fm->id, cnt);
203                                         printk(KERN_INFO DRIVER_NAME
204                                                 ": %s card detected in socket %d\n",
205                                                 card_name, cnt);
206                                         if (!device_register(&sock->dev)) {
207                                                 spin_lock_irqsave(&fm->lock, flags);
208                                                 if (!fm->sockets[cnt]) {
209                                                         fm->sockets[cnt] = sock;
210                                                         sock = NULL;
211                                                 }
212                                                 spin_unlock_irqrestore(&fm->lock, flags);
213                                         }
214                                         if (sock)
215                                                 tifm_free_device(&sock->dev);
216                                 }
217                                 spin_lock_irqsave(&fm->lock, flags);
218                         }
219                 }
220
221                 if (!fm->inhibit_new_cards) {
222                         writel(TIFM_IRQ_FIFOMASK(socket_change_set)
223                                | TIFM_IRQ_CARDMASK(socket_change_set),
224                                fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
225                         writel(TIFM_IRQ_FIFOMASK(socket_change_set)
226                                | TIFM_IRQ_CARDMASK(socket_change_set),
227                                fm->addr + FM_SET_INTERRUPT_ENABLE);
228                         writel(TIFM_IRQ_ENABLE,
229                                fm->addr + FM_SET_INTERRUPT_ENABLE);
230                         spin_unlock_irqrestore(&fm->lock, flags);
231                         break;
232                 } else {
233                         for (cnt = 0; cnt < fm->num_sockets; cnt++) {
234                                 if (fm->sockets[cnt])
235                                         fm->socket_change_set |= 1 << cnt;
236                         }
237                         if (!fm->socket_change_set) {
238                                 spin_unlock_irqrestore(&fm->lock, flags);
239                                 break;
240                         } else {
241                                 spin_unlock_irqrestore(&fm->lock, flags);
242                         }
243                 }
244         }
245         class_device_put(&fm->cdev);
246 }
247
248 static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
249 {
250         struct tifm_adapter *fm = pci_get_drvdata(dev);
251         unsigned long flags;
252
253         spin_lock_irqsave(&fm->lock, flags);
254         fm->inhibit_new_cards = 1;
255         fm->socket_change_set = 0xf;
256         writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
257         spin_unlock_irqrestore(&fm->lock, flags);
258         flush_workqueue(fm->wq);
259
260         tifm_7xx1_switch_media(&fm->media_switcher);
261
262         pci_set_power_state(dev, PCI_D3hot);
263         pci_disable_device(dev);
264         pci_save_state(dev);
265         return 0;
266 }
267
268 static int tifm_7xx1_resume(struct pci_dev *dev)
269 {
270         struct tifm_adapter *fm = pci_get_drvdata(dev);
271         unsigned long flags;
272
273         pci_restore_state(dev);
274         pci_enable_device(dev);
275         pci_set_power_state(dev, PCI_D0);
276         pci_set_master(dev);
277
278         spin_lock_irqsave(&fm->lock, flags);
279         fm->inhibit_new_cards = 0;
280         writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
281         writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
282         writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
283                 fm->addr + FM_SET_INTERRUPT_ENABLE);
284         fm->socket_change_set = 0xf;
285         spin_unlock_irqrestore(&fm->lock, flags);
286         return 0;
287 }
288
289 static int tifm_7xx1_probe(struct pci_dev *dev,
290                         const struct pci_device_id *dev_id)
291 {
292         struct tifm_adapter *fm;
293         int pci_dev_busy = 0;
294         int rc;
295
296         rc = pci_set_dma_mask(dev, DMA_32BIT_MASK);
297         if (rc)
298                 return rc;
299
300         rc = pci_enable_device(dev);
301         if (rc)
302                 return rc;
303
304         pci_set_master(dev);
305
306         rc = pci_request_regions(dev, DRIVER_NAME);
307         if (rc) {
308                 pci_dev_busy = 1;
309                 goto err_out;
310         }
311
312         pci_intx(dev, 1);
313
314         fm = tifm_alloc_adapter();
315         if (!fm) {
316                 rc = -ENOMEM;
317                 goto err_out_int;
318         }
319
320         fm->dev = &dev->dev;
321         fm->num_sockets = (dev->device == 0x803B) ? 2 : 4;
322         fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
323                                 GFP_KERNEL);
324         if (!fm->sockets)
325                 goto err_out_free;
326
327         INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);
328         fm->eject = tifm_7xx1_eject;
329         pci_set_drvdata(dev, fm);
330
331         fm->addr = ioremap(pci_resource_start(dev, 0),
332                                 pci_resource_len(dev, 0));
333         if (!fm->addr)
334                 goto err_out_free;
335
336         rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
337         if (rc)
338                 goto err_out_unmap;
339
340         rc = tifm_add_adapter(fm);
341         if (rc)
342                 goto err_out_irq;
343
344         writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
345         writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
346                 fm->addr + FM_SET_INTERRUPT_ENABLE);
347
348         fm->socket_change_set = 0xf;
349
350         return 0;
351
352 err_out_irq:
353         free_irq(dev->irq, fm);
354 err_out_unmap:
355         iounmap(fm->addr);
356 err_out_free:
357         pci_set_drvdata(dev, NULL);
358         tifm_free_adapter(fm);
359 err_out_int:
360         pci_intx(dev, 0);
361         pci_release_regions(dev);
362 err_out:
363         if (!pci_dev_busy)
364                 pci_disable_device(dev);
365         return rc;
366 }
367
368 static void tifm_7xx1_remove(struct pci_dev *dev)
369 {
370         struct tifm_adapter *fm = pci_get_drvdata(dev);
371         unsigned long flags;
372
373         spin_lock_irqsave(&fm->lock, flags);
374         fm->inhibit_new_cards = 1;
375         fm->socket_change_set = 0xf;
376         writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
377         spin_unlock_irqrestore(&fm->lock, flags);
378
379         flush_workqueue(fm->wq);
380
381         tifm_7xx1_switch_media(&fm->media_switcher);
382
383         writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
384         free_irq(dev->irq, fm);
385
386         tifm_remove_adapter(fm);
387
388         pci_set_drvdata(dev, NULL);
389
390         iounmap(fm->addr);
391         pci_intx(dev, 0);
392         pci_release_regions(dev);
393
394         pci_disable_device(dev);
395         tifm_free_adapter(fm);
396 }
397
398 static struct pci_device_id tifm_7xx1_pci_tbl [] = {
399         { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
400           0 }, /* xx21 - the one I have */
401         { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
402           0 }, /* xx12 - should be also supported */
403         { }
404 };
405
406 static struct pci_driver tifm_7xx1_driver = {
407         .name = DRIVER_NAME,
408         .id_table = tifm_7xx1_pci_tbl,
409         .probe = tifm_7xx1_probe,
410         .remove = tifm_7xx1_remove,
411         .suspend = tifm_7xx1_suspend,
412         .resume = tifm_7xx1_resume,
413 };
414
415 static int __init tifm_7xx1_init(void)
416 {
417         return pci_register_driver(&tifm_7xx1_driver);
418 }
419
420 static void __exit tifm_7xx1_exit(void)
421 {
422         pci_unregister_driver(&tifm_7xx1_driver);
423 }
424
425 MODULE_AUTHOR("Alex Dubov");
426 MODULE_DESCRIPTION("TI FlashMedia host driver");
427 MODULE_LICENSE("GPL");
428 MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);
429 MODULE_VERSION(DRIVER_VERSION);
430
431 module_init(tifm_7xx1_init);
432 module_exit(tifm_7xx1_exit);