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