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