]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/sound/macio/davbus.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / sound / macio / davbus.c
1 /*-
2  * Copyright 2008 by Marco Trillo. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
20  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 /*
29  *      Apple DAVbus audio controller.
30  */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40 #include <sys/rman.h>
41
42 #include <dev/ofw/ofw_bus.h>
43
44 #ifdef HAVE_KERNEL_OPTION_HEADERS
45 #include "opt_snd.h"
46 #endif
47
48 #include <dev/sound/pcm/sound.h>
49
50 #include <dev/sound/macio/aoa.h>
51 #include <dev/sound/macio/davbusreg.h>
52
53 #include <machine/intr_machdep.h>
54 #include <machine/resource.h>
55 #include <machine/bus.h>
56
57 #include "mixer_if.h"
58
59 struct davbus_softc {
60         struct aoa_softc         aoa;
61         phandle_t                node;
62         phandle_t                soundnode;
63         struct resource         *reg;
64         struct mtx               mutex;
65         int                      device_id;
66         u_int                    output_mask;
67         u_int                   (*read_status)(struct davbus_softc *, u_int);
68         void                    (*set_outputs)(struct davbus_softc *, u_int);
69 };
70
71 static int      davbus_probe(device_t);
72 static int      davbus_attach(device_t);
73 static void     davbus_cint(void *);
74
75 static device_method_t pcm_davbus_methods[] = {
76         /* Device interface. */
77         DEVMETHOD(device_probe,         davbus_probe),
78         DEVMETHOD(device_attach,        davbus_attach),
79
80         { 0, 0 }
81 };
82
83 static driver_t pcm_davbus_driver = {
84         "pcm",
85         pcm_davbus_methods,
86         PCM_SOFTC_SIZE
87 };
88
89 DRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, pcm_devclass, 0, 0);
90 MODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
91
92 /*****************************************************************************
93                         Probe and attachment routines.
94  *****************************************************************************/
95 static int
96 davbus_probe(device_t self)
97 {
98         const char              *name;
99
100         name = ofw_bus_get_name(self);
101         if (!name)
102                 return (ENXIO);
103
104         if (strcmp(name, "davbus") != 0)
105                 return (ENXIO);
106         
107         device_set_desc(self, "Apple DAVBus Audio Controller");
108
109         return (0);
110 }
111
112 /*
113  * Burgundy codec control
114  */
115
116 static int      burgundy_init(struct snd_mixer *m);
117 static int      burgundy_uninit(struct snd_mixer *m);
118 static int      burgundy_reinit(struct snd_mixer *m);
119 static void     burgundy_write_locked(struct davbus_softc *, u_int, u_int);
120 static void     burgundy_set_outputs(struct davbus_softc *d, u_int mask);
121 static u_int    burgundy_read_status(struct davbus_softc *d, u_int status);
122 static int      burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left,
123                     unsigned right);
124 static u_int32_t        burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src);
125
126 static kobj_method_t burgundy_mixer_methods[] = {
127         KOBJMETHOD(mixer_init,          burgundy_init),
128         KOBJMETHOD(mixer_uninit,        burgundy_uninit),
129         KOBJMETHOD(mixer_reinit,        burgundy_reinit),
130         KOBJMETHOD(mixer_set,           burgundy_set),
131         KOBJMETHOD(mixer_setrecsrc,     burgundy_setrecsrc),
132         KOBJMETHOD_END
133 };
134
135 MIXER_DECLARE(burgundy_mixer);
136
137 static int
138 burgundy_init(struct snd_mixer *m)
139 {
140         struct davbus_softc *d;
141
142         d = mix_getdevinfo(m);
143
144         d->read_status = burgundy_read_status;
145         d->set_outputs = burgundy_set_outputs;
146
147         /*
148          * We configure the Burgundy codec as follows:
149          *
150          *      o Input subframe 0 is connected to input digital
151          *        stream A (ISA).
152          *      o Stream A (ISA) is mixed in mixer 2 (MIX2).
153          *      o Output of mixer 2 (MIX2) is routed to output sources
154          *        OS0 and OS1 which can be converted to analog.
155          *
156          */
157         mtx_lock(&d->mutex);
158
159         burgundy_write_locked(d, 0x16700, 0x40);
160         
161         burgundy_write_locked(d, BURGUNDY_MIX0_REG, 0); 
162         burgundy_write_locked(d, BURGUNDY_MIX1_REG, 0);
163         burgundy_write_locked(d, BURGUNDY_MIX2_REG, BURGUNDY_MIX_ISA);
164         burgundy_write_locked(d, BURGUNDY_MIX3_REG, 0);
165
166         burgundy_write_locked(d, BURGUNDY_OS_REG, BURGUNDY_OS0_MIX2 | 
167             BURGUNDY_OS1_MIX2);
168
169         burgundy_write_locked(d, BURGUNDY_SDIN_REG, BURGUNDY_ISA_SF0);
170
171         /* Set several digital scalers to unity gain. */
172         burgundy_write_locked(d, BURGUNDY_MXS2L_REG, BURGUNDY_MXS_UNITY);
173         burgundy_write_locked(d, BURGUNDY_MXS2R_REG, BURGUNDY_MXS_UNITY);
174         burgundy_write_locked(d, BURGUNDY_OSS0L_REG, BURGUNDY_OSS_UNITY);
175         burgundy_write_locked(d, BURGUNDY_OSS0R_REG, BURGUNDY_OSS_UNITY);
176         burgundy_write_locked(d, BURGUNDY_OSS1L_REG, BURGUNDY_OSS_UNITY);
177         burgundy_write_locked(d, BURGUNDY_OSS1R_REG, BURGUNDY_OSS_UNITY);
178         burgundy_write_locked(d, BURGUNDY_ISSAL_REG, BURGUNDY_ISS_UNITY);
179         burgundy_write_locked(d, BURGUNDY_ISSAR_REG, BURGUNDY_ISS_UNITY);
180
181         burgundy_set_outputs(d, burgundy_read_status(d, 
182             bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
183
184         mtx_unlock(&d->mutex);
185
186         mix_setdevs(m, SOUND_MASK_VOLUME);
187
188         return (0);
189 }
190
191 static int
192 burgundy_uninit(struct snd_mixer *m)
193 {
194         return (0);
195 }
196
197 static int
198 burgundy_reinit(struct snd_mixer *m)
199 {
200         return (0);
201 }
202
203 static void
204 burgundy_write_locked(struct davbus_softc *d, u_int reg, u_int val)
205 {
206         u_int size, addr, offset, data, i;
207
208         size = (reg & 0x00FF0000) >> 16;
209         addr = (reg & 0x0000FF00) >> 8;
210         offset = reg & 0xFF;
211
212         for (i = offset; i < offset + size; ++i) {
213                 data = BURGUNDY_CTRL_WRITE | (addr << 12) | 
214                     ((size + offset - 1) << 10) | (i << 8) | (val & 0xFF);
215                 if (i == offset)
216                         data |= BURGUNDY_CTRL_RESET;
217
218                 bus_write_4(d->reg, DAVBUS_CODEC_CTRL, data);
219
220                 while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) &
221                     DAVBUS_CODEC_BUSY)
222                         DELAY(1);
223                 
224                 val >>= 8; /* next byte. */
225         }       
226 }
227
228 /* Must be called with d->mutex held. */
229 static void
230 burgundy_set_outputs(struct davbus_softc *d, u_int mask)
231 {
232         u_int   x = 0;
233
234         if (mask == d->output_mask)
235                 return;
236
237         /*
238          *      Bordeaux card wirings:
239          *              Port 15:        RCA out
240          *              Port 16:        Minijack out
241          *              Port 17:        Internal speaker
242          *
243          *      B&W G3 wirings:
244          *              Port 14:        Minijack out
245          *              Port 17:        Internal speaker
246          */
247
248         DPRINTF(("Enabled outputs:"));
249         if (mask & (1 << 0)) {
250                 DPRINTF((" SPEAKER"));
251                 x |= BURGUNDY_P17M_EN;
252         }
253         if (mask & (1 << 1)) {
254                 DPRINTF((" HEADPHONES"));
255                 x |= BURGUNDY_P14L_EN | BURGUNDY_P14R_EN;       
256         }
257         DPRINTF(("\n"));
258
259         burgundy_write_locked(d, BURGUNDY_MUTE_REG, x);
260         d->output_mask = mask;
261 }
262
263 static u_int
264 burgundy_read_status(struct davbus_softc *d, u_int status)
265 {
266         if (status & 0x4)
267                 return (1 << 1);
268         else
269                 return (1 << 0);
270 }
271
272 static int
273 burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
274 {
275         struct davbus_softc *d;
276         int lval, rval;
277
278         lval = ((100 - left) * 15 / 100) & 0xf;
279         rval = ((100 - right) * 15 / 100) & 0xf;
280         DPRINTF(("volume %d %d\n", lval, rval));
281
282         d = mix_getdevinfo(m);
283
284         switch (dev) {
285         case SOUND_MIXER_VOLUME:
286                 mtx_lock(&d->mutex);
287
288                 burgundy_write_locked(d, BURGUNDY_OL13_REG, lval);
289                 burgundy_write_locked(d, BURGUNDY_OL14_REG, (rval << 4) | lval);
290                 burgundy_write_locked(d, BURGUNDY_OL15_REG, (rval << 4) | lval);
291                 burgundy_write_locked(d, BURGUNDY_OL16_REG, (rval << 4) | lval);
292                 burgundy_write_locked(d, BURGUNDY_OL17_REG, lval);
293
294                 mtx_unlock(&d->mutex);
295
296                 return (left | (right << 8));
297         }
298
299         return (0);
300 }
301
302 static u_int32_t
303 burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src)
304 {
305         return (0);
306 }
307
308 /*
309  * Screamer Codec Control
310  */
311
312 static int      screamer_init(struct snd_mixer *m);
313 static int      screamer_uninit(struct snd_mixer *m);
314 static int      screamer_reinit(struct snd_mixer *m);
315 static void     screamer_write_locked(struct davbus_softc *, u_int, u_int);
316 static void     screamer_set_outputs(struct davbus_softc *d, u_int mask);
317 static u_int    screamer_read_status(struct davbus_softc *d, u_int status);
318 static int      screamer_set(struct snd_mixer *m, unsigned dev, unsigned left,
319                     unsigned right);
320 static u_int32_t        screamer_setrecsrc(struct snd_mixer *m, u_int32_t src);
321
322 static kobj_method_t screamer_mixer_methods[] = {
323         KOBJMETHOD(mixer_init,          screamer_init),
324         KOBJMETHOD(mixer_uninit,        screamer_uninit),
325         KOBJMETHOD(mixer_reinit,        screamer_reinit),
326         KOBJMETHOD(mixer_set,           screamer_set),
327         KOBJMETHOD(mixer_setrecsrc,     screamer_setrecsrc),
328         KOBJMETHOD_END
329 };
330
331 MIXER_DECLARE(screamer_mixer);
332
333 static int
334 screamer_init(struct snd_mixer *m)
335 {
336         struct davbus_softc *d;
337
338         d = mix_getdevinfo(m);
339
340         d->read_status = screamer_read_status;
341         d->set_outputs = screamer_set_outputs;
342
343         mtx_lock(&d->mutex);
344
345         screamer_write_locked(d, SCREAMER_CODEC_ADDR0, SCREAMER_INPUT_CD | 
346             SCREAMER_DEFAULT_CD_GAIN);
347
348         screamer_set_outputs(d, screamer_read_status(d, 
349             bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
350
351         screamer_write_locked(d, SCREAMER_CODEC_ADDR2, 0);
352         screamer_write_locked(d, SCREAMER_CODEC_ADDR4, 0);
353         screamer_write_locked(d, SCREAMER_CODEC_ADDR5, 0);
354         screamer_write_locked(d, SCREAMER_CODEC_ADDR6, 0);
355
356         mtx_unlock(&d->mutex);
357
358         mix_setdevs(m, SOUND_MASK_VOLUME);
359
360         return (0);
361 }
362
363 static int
364 screamer_uninit(struct snd_mixer *m)
365 {
366         return (0);
367 }
368
369 static int
370 screamer_reinit(struct snd_mixer *m)
371 {
372         return (0);
373 }
374
375
376 static void
377 screamer_write_locked(struct davbus_softc *d, u_int reg, u_int val)
378 {
379         u_int           x;
380
381         KASSERT(val == (val & 0xfff), ("bad val"));
382
383         while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY)
384                 DELAY(100);
385
386         x = reg;
387         x |= SCREAMER_CODEC_EMSEL0;
388         x |= val;
389         bus_write_4(d->reg, DAVBUS_CODEC_CTRL, x);
390
391         while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY)
392                 DELAY(100);
393 }
394
395 /* Must be called with d->mutex held. */
396 static void
397 screamer_set_outputs(struct davbus_softc *d, u_int mask)
398 {
399         u_int   x;
400
401         if (mask == d->output_mask) {
402                 return;
403         }
404
405         x = SCREAMER_MUTE_SPEAKER | SCREAMER_MUTE_HEADPHONES;
406
407         DPRINTF(("Enabled outputs: "));
408
409         if (mask & (1 << 0)) {
410                 DPRINTF(("SPEAKER "));
411                 x &= ~SCREAMER_MUTE_SPEAKER;
412         }
413         if (mask & (1 << 1)) {
414                 DPRINTF(("HEADPHONES "));
415                 x &= ~SCREAMER_MUTE_HEADPHONES;
416         }
417
418         DPRINTF(("\n"));
419
420         if (d->device_id == 5 || d->device_id == 11) {
421                 DPRINTF(("Enabling programmable output.\n"));
422                 x |= SCREAMER_PROG_OUTPUT0;
423         }
424         if (d->device_id == 8 || d->device_id == 11) {
425                 x &= ~SCREAMER_MUTE_SPEAKER;
426
427                 if (mask & (1 << 0))
428                         x |= SCREAMER_PROG_OUTPUT1; /* enable speaker. */
429         }
430
431         screamer_write_locked(d, SCREAMER_CODEC_ADDR1, x);
432         d->output_mask = mask;
433 }
434
435 static u_int
436 screamer_read_status(struct davbus_softc *d, u_int status)
437 {
438         int     headphones;
439
440         switch (d->device_id) {
441         case 5: /* Sawtooth */
442                 headphones = (status & 0x4);
443                 break;
444
445         case 8:
446         case 11: /* iMac DV */
447                 /* The iMac DV has 2 headphone outputs. */
448                 headphones = (status & 0x7);
449                 break;
450
451         default:
452                 headphones = (status & 0x8);
453         }
454
455         if (headphones)
456                 return (1 << 1);
457         else
458                 return (1 << 0);
459 }
460
461 static int
462 screamer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
463 {
464         struct davbus_softc *d;
465         int lval, rval;
466
467         lval = ((100 - left) * 15 / 100) & 0xf;
468         rval = ((100 - right) * 15 / 100) & 0xf;
469         DPRINTF(("volume %d %d\n", lval, rval));
470
471         d = mix_getdevinfo(m);
472
473         switch (dev) {
474         case SOUND_MIXER_VOLUME:
475                 mtx_lock(&d->mutex);
476                 screamer_write_locked(d, SCREAMER_CODEC_ADDR2, (lval << 6) |
477                     rval);
478                 screamer_write_locked(d, SCREAMER_CODEC_ADDR4, (lval << 6) | 
479                     rval);
480                 mtx_unlock(&d->mutex);
481
482                 return (left | (right << 8));
483         }
484
485         return (0);
486 }
487
488 static u_int32_t
489 screamer_setrecsrc(struct snd_mixer *m, u_int32_t src)
490 {
491         return (0);
492 }
493
494 static int
495 davbus_attach(device_t self)
496 {
497         struct davbus_softc     *sc;
498         struct resource         *dbdma_irq, *cintr;
499         void                    *cookie;
500         char                     compat[64];
501         int                      rid, oirq, err;
502
503         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
504
505         sc->aoa.sc_dev = self;
506         sc->node = ofw_bus_get_node(self);
507         sc->soundnode = OF_child(sc->node);
508
509         /* Map the controller register space. */
510         rid = 0;
511         sc->reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
512         if (sc->reg == NULL) 
513                 return (ENXIO);
514
515         /* Map the DBDMA channel register space. */
516         rid = 1;
517         sc->aoa.sc_odma = bus_alloc_resource_any(self, SYS_RES_MEMORY, 
518             &rid, RF_ACTIVE);
519         if (sc->aoa.sc_odma == NULL)
520                 return (ENXIO);
521
522         /* Establish the DBDMA channel edge-triggered interrupt. */
523         rid = 1;
524         dbdma_irq = bus_alloc_resource_any(self, SYS_RES_IRQ, 
525             &rid, RF_SHAREABLE | RF_ACTIVE);
526         if (dbdma_irq == NULL)
527                 return (ENXIO);
528
529         oirq = rman_get_start(dbdma_irq);
530         
531         DPRINTF(("interrupting at irq %d\n", oirq));
532
533         err = powerpc_config_intr(oirq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
534         if (err != 0)
535                 return (err);
536                 
537         snd_setup_intr(self, dbdma_irq, INTR_MPSAFE, aoa_interrupt,
538             sc, &cookie);
539
540         /* Now initialize the controller. */
541
542         bzero(compat, sizeof(compat));
543         OF_getprop(sc->soundnode, "compatible", compat, sizeof(compat));
544         OF_getprop(sc->soundnode, "device-id", &sc->device_id, sizeof(u_int));
545
546         mtx_init(&sc->mutex, "DAVbus", NULL, MTX_DEF);
547
548         device_printf(self, "codec: <%s>\n", compat);
549
550         /* Setup the control interrupt. */
551         rid = 0;
552         cintr = bus_alloc_resource_any(self, SYS_RES_IRQ, 
553              &rid, RF_SHAREABLE | RF_ACTIVE);
554         if (cintr != NULL) 
555                 bus_setup_intr(self, cintr, INTR_TYPE_MISC | INTR_MPSAFE,
556                     NULL, davbus_cint, sc, &cookie);
557         
558         /* Initialize controller registers. */
559         bus_write_4(sc->reg, DAVBUS_SOUND_CTRL, DAVBUS_INPUT_SUBFRAME0 | 
560             DAVBUS_OUTPUT_SUBFRAME0 | DAVBUS_RATE_44100 | DAVBUS_INTR_PORTCHG);
561
562         /* Attach DBDMA engine and PCM layer */
563         err = aoa_attach(sc);
564         if (err)
565                 return (err);
566
567         /* Install codec module */
568         if (strcmp(compat, "screamer") == 0)
569                 mixer_init(self, &screamer_mixer_class, sc);
570         else if (strcmp(compat, "burgundy") == 0)
571                 mixer_init(self, &burgundy_mixer_class, sc);
572
573         return (0);
574 }
575
576 static void 
577 davbus_cint(void *ptr)
578 {
579         struct davbus_softc *d = ptr;
580         u_int   reg, status, mask;
581
582         mtx_lock(&d->mutex);
583
584         reg = bus_read_4(d->reg, DAVBUS_SOUND_CTRL);
585         if (reg & DAVBUS_PORTCHG) {
586                 
587                 status = bus_read_4(d->reg, DAVBUS_CODEC_STATUS);
588                 
589                 if (d->read_status && d->set_outputs) {
590
591                         mask = (*d->read_status)(d, status);
592                         (*d->set_outputs)(d, mask);
593                 }
594
595                 /* Clear the interrupt. */
596                 bus_write_4(d->reg, DAVBUS_SOUND_CTRL, reg);
597         }
598
599         mtx_unlock(&d->mutex);
600 }
601