Commit | Line | Data |
---|---|---|
f3d9478b JB |
1 | /* |
2 | * i2sbus driver | |
3 | * | |
45e513b6 | 4 | * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net> |
f3d9478b JB |
5 | * |
6 | * GPL v2, can be found in COPYING. | |
7 | */ | |
8 | ||
9 | #include <linux/module.h> | |
5a0e3ad6 | 10 | #include <linux/slab.h> |
f3d9478b JB |
11 | #include <linux/pci.h> |
12 | #include <linux/interrupt.h> | |
389ba795 | 13 | #include <linux/dma-mapping.h> |
5af50730 RH |
14 | #include <linux/of_address.h> |
15 | #include <linux/of_irq.h> | |
389ba795 | 16 | |
f3d9478b | 17 | #include <sound/core.h> |
389ba795 BH |
18 | |
19 | #include <asm/macio.h> | |
20 | #include <asm/dbdma.h> | |
21 | ||
f3d9478b JB |
22 | #include "../soundbus.h" |
23 | #include "i2sbus.h" | |
24 | ||
25 | MODULE_LICENSE("GPL"); | |
26 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | |
27 | MODULE_DESCRIPTION("Apple Soundbus: I2S support"); | |
f3d9478b | 28 | |
f9d08de5 BH |
29 | static int force; |
30 | module_param(force, int, 0444); | |
31 | MODULE_PARM_DESC(force, "Force loading i2sbus even when" | |
32 | " no layout-id property is present"); | |
33 | ||
f3d9478b JB |
34 | static struct of_device_id i2sbus_match[] = { |
35 | { .name = "i2s" }, | |
36 | { } | |
37 | }; | |
38 | ||
e3f9678c JB |
39 | MODULE_DEVICE_TABLE(of, i2sbus_match); |
40 | ||
f3d9478b JB |
41 | static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, |
42 | struct dbdma_command_mem *r, | |
43 | int numcmds) | |
44 | { | |
547ac2ae PM |
45 | /* one more for rounding, one for branch back, one for stop command */ |
46 | r->size = (numcmds + 3) * sizeof(struct dbdma_cmd); | |
f3d9478b JB |
47 | /* We use the PCI APIs for now until the generic one gets fixed |
48 | * enough or until we get some macio-specific versions | |
49 | */ | |
50 | r->space = dma_alloc_coherent( | |
51 | &macio_get_pci_dev(i2sdev->macio)->dev, | |
52 | r->size, | |
53 | &r->bus_addr, | |
54 | GFP_KERNEL); | |
55 | ||
56 | if (!r->space) return -ENOMEM; | |
57 | ||
58 | memset(r->space, 0, r->size); | |
59 | r->cmds = (void*)DBDMA_ALIGN(r->space); | |
60 | r->bus_cmd_start = r->bus_addr + | |
61 | (dma_addr_t)((char*)r->cmds - (char*)r->space); | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, | |
67 | struct dbdma_command_mem *r) | |
68 | { | |
69 | if (!r->space) return; | |
888dcb7c | 70 | |
f3d9478b JB |
71 | dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, |
72 | r->size, r->space, r->bus_addr); | |
73 | } | |
74 | ||
75 | static void i2sbus_release_dev(struct device *dev) | |
76 | { | |
77 | struct i2sbus_dev *i2sdev; | |
78 | int i; | |
79 | ||
80 | i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev); | |
81 | ||
82 | if (i2sdev->intfregs) iounmap(i2sdev->intfregs); | |
83 | if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma); | |
84 | if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma); | |
389ba795 | 85 | for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) |
f3d9478b JB |
86 | if (i2sdev->allocated_resource[i]) |
87 | release_and_free_resource(i2sdev->allocated_resource[i]); | |
88 | free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring); | |
89 | free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring); | |
389ba795 | 90 | for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) |
f3d9478b JB |
91 | free_irq(i2sdev->interrupts[i], i2sdev); |
92 | i2sbus_control_remove_dev(i2sdev->control, i2sdev); | |
93 | mutex_destroy(&i2sdev->lock); | |
94 | kfree(i2sdev); | |
95 | } | |
96 | ||
7d12e780 | 97 | static irqreturn_t i2sbus_bus_intr(int irq, void *devid) |
f3d9478b JB |
98 | { |
99 | struct i2sbus_dev *dev = devid; | |
100 | u32 intreg; | |
101 | ||
102 | spin_lock(&dev->low_lock); | |
103 | intreg = in_le32(&dev->intfregs->intr_ctl); | |
104 | ||
105 | /* acknowledge interrupt reasons */ | |
106 | out_le32(&dev->intfregs->intr_ctl, intreg); | |
107 | ||
108 | spin_unlock(&dev->low_lock); | |
109 | ||
110 | return IRQ_HANDLED; | |
111 | } | |
112 | ||
389ba795 BH |
113 | |
114 | /* | |
115 | * XXX FIXME: We test the layout_id's here to get the proper way of | |
116 | * mapping in various registers, thanks to bugs in Apple device-trees. | |
117 | * We could instead key off the machine model and the name of the i2s | |
118 | * node (i2s-a). This we'll do when we move it all to macio_asic.c | |
119 | * and have that export items for each sub-node too. | |
120 | */ | |
121 | static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index, | |
122 | int layout, struct resource *res) | |
123 | { | |
124 | struct device_node *parent; | |
125 | int pindex, rc = -ENXIO; | |
a7edd0e6 | 126 | const u32 *reg; |
389ba795 BH |
127 | |
128 | /* Machines with layout 76 and 36 (K2 based) have a weird device | |
129 | * tree what we need to special case. | |
130 | * Normal machines just fetch the resource from the i2s-X node. | |
131 | * Darwin further divides normal machines into old and new layouts | |
132 | * with a subtely different code path but that doesn't seem necessary | |
133 | * in practice, they just bloated it. In addition, even on our K2 | |
134 | * case the i2s-modem node, if we ever want to handle it, uses the | |
135 | * normal layout | |
136 | */ | |
137 | if (layout != 76 && layout != 36) | |
138 | return of_address_to_resource(np, index, res); | |
139 | ||
140 | parent = of_get_parent(np); | |
141 | pindex = (index == aoa_resource_i2smmio) ? 0 : 1; | |
142 | rc = of_address_to_resource(parent, pindex, res); | |
143 | if (rc) | |
144 | goto bail; | |
c4f55b39 | 145 | reg = of_get_property(np, "reg", NULL); |
389ba795 BH |
146 | if (reg == NULL) { |
147 | rc = -ENXIO; | |
148 | goto bail; | |
149 | } | |
150 | res->start += reg[index * 2]; | |
151 | res->end = res->start + reg[index * 2 + 1] - 1; | |
152 | bail: | |
153 | of_node_put(parent); | |
154 | return rc; | |
155 | } | |
156 | ||
f3d9478b JB |
157 | /* FIXME: look at device node refcounting */ |
158 | static int i2sbus_add_dev(struct macio_dev *macio, | |
159 | struct i2sbus_control *control, | |
160 | struct device_node *np) | |
161 | { | |
162 | struct i2sbus_dev *dev; | |
163 | struct device_node *child = NULL, *sound = NULL; | |
389ba795 | 164 | struct resource *r; |
9f50bbad | 165 | int i, layout = 0, rlen, ok = force; |
f3d9478b JB |
166 | static const char *rnames[] = { "i2sbus: %s (control)", |
167 | "i2sbus: %s (tx)", | |
168 | "i2sbus: %s (rx)" }; | |
7d12e780 | 169 | static irq_handler_t ints[] = { |
f3d9478b JB |
170 | i2sbus_bus_intr, |
171 | i2sbus_tx_intr, | |
172 | i2sbus_rx_intr | |
173 | }; | |
174 | ||
175 | if (strlen(np->name) != 5) | |
176 | return 0; | |
177 | if (strncmp(np->name, "i2s-", 4)) | |
178 | return 0; | |
179 | ||
f3d9478b JB |
180 | dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL); |
181 | if (!dev) | |
182 | return 0; | |
183 | ||
184 | i = 0; | |
185 | while ((child = of_get_next_child(np, child))) { | |
186 | if (strcmp(child->name, "sound") == 0) { | |
187 | i++; | |
188 | sound = child; | |
189 | } | |
190 | } | |
191 | if (i == 1) { | |
45e513b6 JB |
192 | const u32 *id = of_get_property(sound, "layout-id", NULL); |
193 | ||
194 | if (id) { | |
195 | layout = *id; | |
f3d9478b | 196 | snprintf(dev->sound.modalias, 32, |
389ba795 | 197 | "sound-layout-%d", layout); |
9f50bbad | 198 | ok = 1; |
45e513b6 JB |
199 | } else { |
200 | id = of_get_property(sound, "device-id", NULL); | |
201 | /* | |
202 | * We probably cannot handle all device-id machines, | |
203 | * so restrict to those we do handle for now. | |
204 | */ | |
08857861 ME |
205 | if (id && (*id == 22 || *id == 14 || *id == 35 || |
206 | *id == 44)) { | |
45e513b6 JB |
207 | snprintf(dev->sound.modalias, 32, |
208 | "aoa-device-id-%d", *id); | |
209 | ok = 1; | |
210 | layout = -1; | |
211 | } | |
f3d9478b JB |
212 | } |
213 | } | |
214 | /* for the time being, until we can handle non-layout-id | |
215 | * things in some fabric, refuse to attach if there is no | |
216 | * layout-id property or we haven't been forced to attach. | |
217 | * When there are two i2s busses and only one has a layout-id, | |
218 | * then this depends on the order, but that isn't important | |
219 | * either as the second one in that case is just a modem. */ | |
9f50bbad | 220 | if (!ok) { |
f3d9478b JB |
221 | kfree(dev); |
222 | return -ENODEV; | |
223 | } | |
224 | ||
225 | mutex_init(&dev->lock); | |
226 | spin_lock_init(&dev->low_lock); | |
cb6dc512 | 227 | dev->sound.ofdev.archdata.dma_mask = macio->ofdev.archdata.dma_mask; |
61c7a080 | 228 | dev->sound.ofdev.dev.of_node = np; |
cb6dc512 | 229 | dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.archdata.dma_mask; |
f3d9478b JB |
230 | dev->sound.ofdev.dev.parent = &macio->ofdev.dev; |
231 | dev->sound.ofdev.dev.release = i2sbus_release_dev; | |
232 | dev->sound.attach_codec = i2sbus_attach_codec; | |
233 | dev->sound.detach_codec = i2sbus_detach_codec; | |
234 | dev->sound.pcmid = -1; | |
235 | dev->macio = macio; | |
236 | dev->control = control; | |
237 | dev->bus_number = np->name[4] - 'a'; | |
238 | INIT_LIST_HEAD(&dev->sound.codec_list); | |
239 | ||
389ba795 | 240 | for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { |
f3d9478b | 241 | dev->interrupts[i] = -1; |
389ba795 BH |
242 | snprintf(dev->rnames[i], sizeof(dev->rnames[i]), |
243 | rnames[i], np->name); | |
f3d9478b | 244 | } |
389ba795 | 245 | for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { |
4a14cf45 AS |
246 | int irq = irq_of_parse_and_map(np, i); |
247 | if (request_irq(irq, ints[i], 0, dev->rnames[i], dev)) | |
f3d9478b | 248 | goto err; |
4a14cf45 | 249 | dev->interrupts[i] = irq; |
f3d9478b JB |
250 | } |
251 | ||
389ba795 BH |
252 | |
253 | /* Resource handling is problematic as some device-trees contain | |
254 | * useless crap (ugh ugh ugh). We work around that here by calling | |
255 | * specific functions for calculating the appropriate resources. | |
256 | * | |
257 | * This will all be moved to macio_asic.c at one point | |
258 | */ | |
259 | for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { | |
260 | if (i2sbus_get_and_fixup_rsrc(np,i,layout,&dev->resources[i])) | |
f3d9478b | 261 | goto err; |
389ba795 | 262 | /* If only we could use our resource dev->resources[i]... |
f3d9478b | 263 | * but request_resource doesn't know about parents and |
389ba795 BH |
264 | * contained resources... |
265 | */ | |
888dcb7c | 266 | dev->allocated_resource[i] = |
f3d9478b | 267 | request_mem_region(dev->resources[i].start, |
28f65c11 | 268 | resource_size(&dev->resources[i]), |
f3d9478b JB |
269 | dev->rnames[i]); |
270 | if (!dev->allocated_resource[i]) { | |
271 | printk(KERN_ERR "i2sbus: failed to claim resource %d!\n", i); | |
272 | goto err; | |
273 | } | |
274 | } | |
389ba795 BH |
275 | |
276 | r = &dev->resources[aoa_resource_i2smmio]; | |
28f65c11 | 277 | rlen = resource_size(r); |
389ba795 BH |
278 | if (rlen < sizeof(struct i2s_interface_regs)) |
279 | goto err; | |
280 | dev->intfregs = ioremap(r->start, rlen); | |
281 | ||
282 | r = &dev->resources[aoa_resource_txdbdma]; | |
28f65c11 | 283 | rlen = resource_size(r); |
389ba795 BH |
284 | if (rlen < sizeof(struct dbdma_regs)) |
285 | goto err; | |
286 | dev->out.dbdma = ioremap(r->start, rlen); | |
287 | ||
288 | r = &dev->resources[aoa_resource_rxdbdma]; | |
28f65c11 | 289 | rlen = resource_size(r); |
389ba795 BH |
290 | if (rlen < sizeof(struct dbdma_regs)) |
291 | goto err; | |
292 | dev->in.dbdma = ioremap(r->start, rlen); | |
293 | ||
f3d9478b JB |
294 | if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma) |
295 | goto err; | |
296 | ||
297 | if (alloc_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring, | |
298 | MAX_DBDMA_COMMANDS)) | |
299 | goto err; | |
300 | if (alloc_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring, | |
301 | MAX_DBDMA_COMMANDS)) | |
302 | goto err; | |
303 | ||
304 | if (i2sbus_control_add_dev(dev->control, dev)) { | |
305 | printk(KERN_ERR "i2sbus: control layer didn't like bus\n"); | |
306 | goto err; | |
307 | } | |
308 | ||
309 | if (soundbus_add_one(&dev->sound)) { | |
310 | printk(KERN_DEBUG "i2sbus: device registration error!\n"); | |
311 | goto err; | |
312 | } | |
313 | ||
314 | /* enable this cell */ | |
315 | i2sbus_control_cell(dev->control, dev, 1); | |
316 | i2sbus_control_enable(dev->control, dev); | |
317 | i2sbus_control_clock(dev->control, dev, 1); | |
318 | ||
319 | return 1; | |
320 | err: | |
321 | for (i=0;i<3;i++) | |
322 | if (dev->interrupts[i] != -1) | |
323 | free_irq(dev->interrupts[i], dev); | |
324 | free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring); | |
325 | free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring); | |
326 | if (dev->intfregs) iounmap(dev->intfregs); | |
327 | if (dev->out.dbdma) iounmap(dev->out.dbdma); | |
328 | if (dev->in.dbdma) iounmap(dev->in.dbdma); | |
329 | for (i=0;i<3;i++) | |
330 | if (dev->allocated_resource[i]) | |
331 | release_and_free_resource(dev->allocated_resource[i]); | |
332 | mutex_destroy(&dev->lock); | |
333 | kfree(dev); | |
334 | return 0; | |
335 | } | |
336 | ||
337 | static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match) | |
338 | { | |
339 | struct device_node *np = NULL; | |
340 | int got = 0, err; | |
341 | struct i2sbus_control *control = NULL; | |
342 | ||
343 | err = i2sbus_control_init(dev, &control); | |
344 | if (err) | |
345 | return err; | |
346 | if (!control) { | |
347 | printk(KERN_ERR "i2sbus_control_init API breakage\n"); | |
348 | return -ENODEV; | |
349 | } | |
350 | ||
61c7a080 | 351 | while ((np = of_get_next_child(dev->ofdev.dev.of_node, np))) { |
55b61fec SR |
352 | if (of_device_is_compatible(np, "i2sbus") || |
353 | of_device_is_compatible(np, "i2s-modem")) { | |
f3d9478b JB |
354 | got += i2sbus_add_dev(dev, control, np); |
355 | } | |
356 | } | |
357 | ||
358 | if (!got) { | |
359 | /* found none, clean up */ | |
360 | i2sbus_control_destroy(control); | |
361 | return -ENODEV; | |
362 | } | |
363 | ||
ae31c1fb | 364 | dev_set_drvdata(&dev->ofdev.dev, control); |
f3d9478b JB |
365 | |
366 | return 0; | |
367 | } | |
368 | ||
369 | static int i2sbus_remove(struct macio_dev* dev) | |
370 | { | |
ae31c1fb | 371 | struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); |
f3d9478b JB |
372 | struct i2sbus_dev *i2sdev, *tmp; |
373 | ||
374 | list_for_each_entry_safe(i2sdev, tmp, &control->list, item) | |
375 | soundbus_remove_one(&i2sdev->sound); | |
376 | ||
377 | return 0; | |
378 | } | |
379 | ||
380 | #ifdef CONFIG_PM | |
381 | static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) | |
382 | { | |
ae31c1fb | 383 | struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); |
f3d9478b JB |
384 | struct codec_info_item *cii; |
385 | struct i2sbus_dev* i2sdev; | |
386 | int err, ret = 0; | |
387 | ||
388 | list_for_each_entry(i2sdev, &control->list, item) { | |
389 | /* Notify Alsa */ | |
390 | if (i2sdev->sound.pcm) { | |
391 | /* Suspend PCM streams */ | |
392 | snd_pcm_suspend_all(i2sdev->sound.pcm); | |
f3d9478b | 393 | } |
547ac2ae | 394 | |
f3d9478b JB |
395 | /* Notify codecs */ |
396 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | |
397 | err = 0; | |
398 | if (cii->codec->suspend) | |
399 | err = cii->codec->suspend(cii, state); | |
400 | if (err) | |
401 | ret = err; | |
402 | } | |
547ac2ae PM |
403 | |
404 | /* wait until streams are stopped */ | |
405 | i2sbus_wait_for_stop_both(i2sdev); | |
f3d9478b | 406 | } |
547ac2ae | 407 | |
f3d9478b JB |
408 | return ret; |
409 | } | |
410 | ||
411 | static int i2sbus_resume(struct macio_dev* dev) | |
412 | { | |
ae31c1fb | 413 | struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); |
f3d9478b JB |
414 | struct codec_info_item *cii; |
415 | struct i2sbus_dev* i2sdev; | |
416 | int err, ret = 0; | |
417 | ||
418 | list_for_each_entry(i2sdev, &control->list, item) { | |
547ac2ae PM |
419 | /* reset i2s bus format etc. */ |
420 | i2sbus_pcm_prepare_both(i2sdev); | |
421 | ||
f3d9478b JB |
422 | /* Notify codecs so they can re-initialize */ |
423 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | |
424 | err = 0; | |
425 | if (cii->codec->resume) | |
426 | err = cii->codec->resume(cii); | |
427 | if (err) | |
428 | ret = err; | |
429 | } | |
f3d9478b JB |
430 | } |
431 | ||
432 | return ret; | |
433 | } | |
434 | #endif /* CONFIG_PM */ | |
435 | ||
436 | static int i2sbus_shutdown(struct macio_dev* dev) | |
437 | { | |
438 | return 0; | |
439 | } | |
440 | ||
441 | static struct macio_driver i2sbus_drv = { | |
c2cdf6ab BH |
442 | .driver = { |
443 | .name = "soundbus-i2s", | |
444 | .owner = THIS_MODULE, | |
445 | .of_match_table = i2sbus_match, | |
446 | }, | |
f3d9478b JB |
447 | .probe = i2sbus_probe, |
448 | .remove = i2sbus_remove, | |
449 | #ifdef CONFIG_PM | |
450 | .suspend = i2sbus_suspend, | |
451 | .resume = i2sbus_resume, | |
452 | #endif | |
453 | .shutdown = i2sbus_shutdown, | |
454 | }; | |
455 | ||
456 | static int __init soundbus_i2sbus_init(void) | |
457 | { | |
458 | return macio_register_driver(&i2sbus_drv); | |
459 | } | |
460 | ||
461 | static void __exit soundbus_i2sbus_exit(void) | |
462 | { | |
463 | macio_unregister_driver(&i2sbus_drv); | |
464 | } | |
465 | ||
466 | module_init(soundbus_i2sbus_init); | |
467 | module_exit(soundbus_i2sbus_exit); |