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