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