Annotation of sys/arch/macppc/dev/tumbler.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: tumbler.c,v 1.4 2007/04/23 16:27:20 deraadt Exp $ */
2:
3: /*-
4: * Copyright (c) 2001,2003 Tsubai Masanari. All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: * 3. The name of the author may not be used to endorse or promote products
15: * derived from this software without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: /*
30: * Datasheet is available from
31: * http://focus.ti.com/docs/prod/folders/print/tas3001.html
32: */
33:
34: #include <sys/param.h>
35: #include <sys/audioio.h>
36: #include <sys/device.h>
37: #include <sys/systm.h>
38:
39: #include <dev/audio_if.h>
40: #include <dev/ofw/openfirm.h>
41: #include <macppc/dev/dbdma.h>
42:
43: #include <machine/autoconf.h>
44:
45: #include <macppc/dev/i2svar.h>
46:
47: #ifdef TUMBLER_DEBUG
48: # define DPRINTF printf
49: #else
50: # define DPRINTF while (0) printf
51: #endif
52:
53: /* XXX */
54: #define tumbler_softc i2s_softc
55:
56: /* XXX */
57: int kiic_write(struct device *, int, int, const void *, int);
58: int kiic_writereg(struct device *, int, u_int);
59:
60: void tumbler_init(struct tumbler_softc *);
61: int tumbler_getdev(void *, struct audio_device *);
62: int tumbler_match(struct device *, void *, void *);
63: void tumbler_attach(struct device *, struct device *, void *);
64: void tumbler_defer(struct device *);
65: void tumbler_set_volume(struct tumbler_softc *, int, int);
66: void tumbler_set_bass(struct tumbler_softc *, int);
67: void tumbler_set_treble(struct tumbler_softc *, int);
68:
69: int tas3001_write(struct tumbler_softc *, u_int, const void *);
70: int tas3001_init(struct tumbler_softc *);
71:
72: struct cfattach tumbler_ca = {
73: sizeof(struct tumbler_softc), tumbler_match, tumbler_attach
74: };
75: struct cfdriver tumbler_cd = {
76: NULL, "tumbler", DV_DULL
77: };
78:
79: struct audio_hw_if tumbler_hw_if = {
80: i2s_open,
81: i2s_close,
82: NULL,
83: i2s_query_encoding,
84: i2s_set_params,
85: i2s_round_blocksize,
86: NULL,
87: NULL,
88: NULL,
89: NULL,
90: NULL,
91: i2s_halt_output,
92: i2s_halt_input,
93: NULL,
94: tumbler_getdev,
95: NULL,
96: i2s_set_port,
97: i2s_get_port,
98: i2s_query_devinfo,
99: i2s_allocm, /* allocm */
100: NULL,
101: i2s_round_buffersize,
102: i2s_mappage,
103: i2s_get_props,
104: i2s_trigger_output,
105: i2s_trigger_input,
106: };
107:
108: struct audio_device tumbler_device = {
109: "TUMBLER",
110: "",
111: "tumbler"
112: };
113:
114: const uint8_t tumbler_trebletab[] = {
115: 0x96, /* -18dB */
116: 0x94, /* -17dB */
117: 0x92, /* -16dB */
118: 0x90, /* -15dB */
119: 0x8e, /* -14dB */
120: 0x8c, /* -13dB */
121: 0x8a, /* -12dB */
122: 0x88, /* -11dB */
123: 0x86, /* -10dB */
124: 0x84, /* -9dB */
125: 0x82, /* -8dB */
126: 0x80, /* -7dB */
127: 0x7e, /* -6dB */
128: 0x7c, /* -5dB */
129: 0x7a, /* -4dB */
130: 0x78, /* -3dB */
131: 0x76, /* -2dB */
132: 0x74, /* -1dB */
133: 0x72, /* 0dB */
134: 0x70, /* 1dB */
135: 0x6d, /* 2dB */
136: 0x6b, /* 3dB */
137: 0x68, /* 4dB */
138: 0x65, /* 5dB */
139: 0x62, /* 6dB */
140: 0x5e, /* 7dB */
141: 0x59, /* 8dB */
142: 0x5a, /* 9dB */
143: 0x4f, /* 10dB */
144: 0x49, /* 11dB */
145: 0x42, /* 12dB */
146: 0x3a, /* 13dB */
147: 0x32, /* 14dB */
148: 0x28, /* 15dB */
149: 0x1c, /* 16dB */
150: 0x10, /* 17dB */
151: 0x01, /* 18dB */
152: };
153:
154: const uint8_t tumbler_basstab[] = {
155: 0x86, /* -18dB */
156: 0x7f, /* -17dB */
157: 0x7a, /* -16dB */
158: 0x76, /* -15dB */
159: 0x72, /* -14dB */
160: 0x6e, /* -13dB */
161: 0x6b, /* -12dB */
162: 0x66, /* -11dB */
163: 0x61, /* -10dB */
164: 0x5d, /* -9dB */
165: 0x5a, /* -8dB */
166: 0x58, /* -7dB */
167: 0x55, /* -6dB */
168: 0x53, /* -5dB */
169: 0x4f, /* -4dB */
170: 0x4b, /* -3dB */
171: 0x46, /* -2dB */
172: 0x42, /* -1dB */
173: 0x3e, /* 0dB */
174: 0x3b, /* 1dB */
175: 0x38, /* 2dB */
176: 0x35, /* 3dB */
177: 0x31, /* 4dB */
178: 0x2e, /* 5dB */
179: 0x2b, /* 6dB */
180: 0x28, /* 7dB */
181: 0x25, /* 8dB */
182: 0x21, /* 9dB */
183: 0x1c, /* 10dB */
184: 0x18, /* 11dB */
185: 0x16, /* 12dB */
186: 0x13, /* 13dB */
187: 0x10, /* 14dB */
188: 0x0d, /* 15dB */
189: 0x0a, /* 16dB */
190: 0x06, /* 17dB */
191: 0x01, /* 18dB */
192: };
193:
194: /* TAS3001 registers */
195: #define DEQ_MCR 0x01 /* Main Control Register (1byte) */
196: #define DEQ_DRC 0x02 /* Dynamic Range Compression (2bytes) */
197: #define DEQ_VOLUME 0x04 /* Volume (6bytes) */
198: #define DEQ_TREBLE 0x05 /* Treble Control Register (1byte) */
199: #define DEQ_BASS 0x06 /* Bass Control Register (1byte) */
200: #define DEQ_MIXER1 0x07 /* Mixer 1 (3bytes) */
201: #define DEQ_MIXER2 0x08 /* Mixer 2 (3bytes) */
202: #define DEQ_LB0 0x0a /* Left Biquad 0 (15bytes) */
203: #define DEQ_LB1 0x0b /* Left Biquad 1 (15bytes) */
204: #define DEQ_LB2 0x0c /* Left Biquad 2 (15bytes) */
205: #define DEQ_LB3 0x0d /* Left Biquad 3 (15bytes) */
206: #define DEQ_LB4 0x0e /* Left Biquad 4 (15bytes) */
207: #define DEQ_LB5 0x0f /* Left Biquad 5 (15bytes) */
208: #define DEQ_RB0 0x13 /* Right Biquad 0 (15bytes) */
209: #define DEQ_RB1 0x14 /* Right Biquad 1 (15bytes) */
210: #define DEQ_RB2 0x15 /* Right Biquad 2 (15bytes) */
211: #define DEQ_RB3 0x16 /* Right Biquad 3 (15bytes) */
212: #define DEQ_RB4 0x17 /* Right Biquad 4 (15bytes) */
213: #define DEQ_RB5 0x18 /* Right Biquad 5 (15bytes) */
214:
215: #define DEQ_MCR_FL 0x80 /* Fast load */
216: #define DEQ_MCR_SC 0x40 /* SCLK frequency */
217: #define DEQ_MCR_SC_32 0x00 /* 32fs */
218: #define DEQ_MCR_SC_64 0x40 /* 64fs */
219: #define DEQ_MCR_OM 0x30 /* Output serial port mode */
220: #define DEQ_MCR_OM_L 0x00 /* Left justified */
221: #define DEQ_MCR_OM_R 0x10 /* Right justified */
222: #define DEQ_MCR_OM_I2S 0x20 /* I2S */
223: #define DEQ_MCR_IM 0x0c /* Input serial port mode */
224: #define DEQ_MCR_IM_L 0x00 /* Left justified */
225: #define DEQ_MCR_IM_R 0x04 /* Right justified */
226: #define DEQ_MCR_IM_I2S 0x08 /* I2S */
227: #define DEQ_MCR_W 0x03 /* Serial port word length */
228: #define DEQ_MCR_W_16 0x00 /* 16 bit */
229: #define DEQ_MCR_W_18 0x01 /* 18 bit */
230: #define DEQ_MCR_W_20 0x02 /* 20 bit */
231:
232: #define DEQ_DRC_CR 0xc0 /* Compression ratio */
233: #define DEQ_DRC_CR_31 0xc0 /* 3:1 */
234: #define DEQ_DRC_EN 0x01 /* Enable DRC */
235:
236: #define DEQ_MCR_I2S (DEQ_MCR_OM_I2S | DEQ_MCR_IM_I2S)
237:
238: struct tas3001_reg {
239: u_char MCR[1];
240: u_char DRC[2];
241: u_char VOLUME[6];
242: u_char TREBLE[1];
243: u_char BASS[1];
244: u_char MIXER1[3];
245: u_char MIXER2[3];
246: u_char LB0[15];
247: u_char LB1[15];
248: u_char LB2[15];
249: u_char LB3[15];
250: u_char LB4[15];
251: u_char LB5[15];
252: u_char RB0[15];
253: u_char RB1[15];
254: u_char RB2[15];
255: u_char RB3[15];
256: u_char RB4[15];
257: u_char RB5[15];
258: };
259:
260: int
261: tumbler_match(struct device *parent, void *match, void *aux)
262: {
263: struct confargs *ca = aux;
264: int soundbus, soundchip;
265: char compat[32];
266:
267: if (strcmp(ca->ca_name, "i2s") != 0)
268: return (0);
269:
270: if ((soundbus = OF_child(ca->ca_node)) == 0 ||
271: (soundchip = OF_child(soundbus)) == 0)
272: return (0);
273:
274: bzero(compat, sizeof compat);
275: OF_getprop(soundchip, "compatible", compat, sizeof compat);
276:
277: if (strcmp(compat, "tumbler") != 0)
278: return (0);
279:
280: return (1);
281: }
282:
283: void
284: tumbler_attach(struct device *parent, struct device *self, void *aux)
285: {
286: struct tumbler_softc *sc = (struct tumbler_softc *)self;
287:
288: sc->sc_setvolume = tumbler_set_volume;
289: sc->sc_setbass = tumbler_set_bass;
290: sc->sc_settreble = tumbler_set_treble;
291:
292: i2s_attach(parent, sc, aux);
293: config_defer(self, tumbler_defer);
294: }
295:
296: void
297: tumbler_defer(struct device *dev)
298: {
299: struct tumbler_softc *sc = (struct tumbler_softc *)dev;
300: struct device *dv;
301:
302: TAILQ_FOREACH(dv, &alldevs, dv_list)
303: if (strncmp(dv->dv_xname, "kiic", 4) == 0 &&
304: strncmp(dv->dv_parent->dv_xname, "macobio", 7) == 0)
305: sc->sc_i2c = dv;
306: if (sc->sc_i2c == NULL) {
307: printf("%s: unable to find i2c\n", sc->sc_dev.dv_xname);
308: return;
309: }
310:
311: /* XXX If i2c has failed to attach, what should we do? */
312:
313: audio_attach_mi(&tumbler_hw_if, sc, &sc->sc_dev);
314:
315: tumbler_init(sc);
316: }
317:
318: void
319: tumbler_set_volume(struct tumbler_softc *sc, int left, int right)
320: {
321: u_char vol[6];
322:
323: sc->sc_vol_l = left;
324: sc->sc_vol_r = right;
325:
326: left <<= 6; /* XXX for now */
327: right <<= 6;
328:
329: vol[0] = left >> 16;
330: vol[1] = left >> 8;
331: vol[2] = left;
332: vol[3] = right >> 16;
333: vol[4] = right >> 8;
334: vol[5] = right;
335:
336: tas3001_write(sc, DEQ_VOLUME, vol);
337: }
338:
339: void
340: tumbler_set_treble(struct tumbler_softc *sc, int value)
341: {
342: uint8_t reg;
343:
344: if ((value >= 0) && (value <= 255) && (value != sc->sc_treble)) {
345: reg = tumbler_trebletab[(value >> 3) + 2];
346: if (tas3001_write(sc, DEQ_TREBLE, ®) < 0)
347: return;
348: sc->sc_treble = value;
349: }
350: }
351:
352: void
353: tumbler_set_bass(struct tumbler_softc *sc, int value)
354: {
355: uint8_t reg;
356:
357: if ((value >= 0) && (value <= 255) && (value != sc->sc_bass)) {
358: reg = tumbler_basstab[(value >> 3) + 2];
359: if (tas3001_write(sc, DEQ_BASS, ®) < 0)
360: return;
361: sc->sc_bass = value;
362: }
363: }
364:
365: const struct tas3001_reg tas3001_initdata = {
366: { DEQ_MCR_SC_64 | DEQ_MCR_I2S | DEQ_MCR_W_20 }, /* MCR */
367: { DEQ_DRC_CR_31, 0xa0 }, /* DRC */
368: { 0, 0, 0, 0, 0, 0 }, /* VOLUME */
369: { 0x72 }, /* TREBLE */
370: { 0x3e }, /* BASS */
371: { 0x10, 0x00, 0x00 }, /* MIXER1 */
372: { 0x00, 0x00, 0x00 }, /* MIXER2 */
373: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
374: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
375: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
376: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
377: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
378: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
379: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
380: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
381: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
382: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
383: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
384: { 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* BIQUAD */
385: };
386:
387: const char tas3001_regsize[] = {
388: 0, /* 0x00 */
389: sizeof tas3001_initdata.MCR, /* 0x01 */
390: sizeof tas3001_initdata.DRC, /* 0x02 */
391: 0, /* 0x03 */
392: sizeof tas3001_initdata.VOLUME, /* 0x04 */
393: sizeof tas3001_initdata.TREBLE, /* 0x05 */
394: sizeof tas3001_initdata.BASS, /* 0x06 */
395: sizeof tas3001_initdata.MIXER1, /* 0x07 */
396: sizeof tas3001_initdata.MIXER2, /* 0x08 */
397: 0, /* 0x09 */
398: sizeof tas3001_initdata.LB0, /* 0x0a */
399: sizeof tas3001_initdata.LB1, /* 0x0b */
400: sizeof tas3001_initdata.LB2, /* 0x0c */
401: sizeof tas3001_initdata.LB3, /* 0x0d */
402: sizeof tas3001_initdata.LB4, /* 0x0e */
403: sizeof tas3001_initdata.LB5, /* 0x0f */
404: 0, /* 0x10 */
405: 0, /* 0x11 */
406: 0, /* 0x12 */
407: sizeof tas3001_initdata.RB0, /* 0x13 */
408: sizeof tas3001_initdata.RB1, /* 0x14 */
409: sizeof tas3001_initdata.RB2, /* 0x15 */
410: sizeof tas3001_initdata.RB3, /* 0x16 */
411: sizeof tas3001_initdata.RB4, /* 0x17 */
412: sizeof tas3001_initdata.RB5 /* 0x18 */
413: };
414:
415: #define DEQaddr 0x68
416:
417: int
418: tas3001_write(struct tumbler_softc *sc, u_int reg, const void *data)
419: {
420: int size;
421:
422: KASSERT(reg < sizeof tas3001_regsize);
423: size = tas3001_regsize[reg];
424: KASSERT(size > 0);
425:
426: if (kiic_write(sc->sc_i2c, DEQaddr, reg, data, size))
427: return (-1);
428:
429: return (0);
430: }
431:
432: #define DEQ_WRITE(sc, reg, addr) \
433: if (tas3001_write(sc, reg, addr)) goto err
434:
435: int
436: tas3001_init(struct tumbler_softc *sc)
437: {
438: deq_reset(sc);
439:
440: /* Initialize TAS3001 registers. */
441: DEQ_WRITE(sc, DEQ_LB0, tas3001_initdata.LB0);
442: DEQ_WRITE(sc, DEQ_LB1, tas3001_initdata.LB1);
443: DEQ_WRITE(sc, DEQ_LB2, tas3001_initdata.LB2);
444: DEQ_WRITE(sc, DEQ_LB3, tas3001_initdata.LB3);
445: DEQ_WRITE(sc, DEQ_LB4, tas3001_initdata.LB4);
446: DEQ_WRITE(sc, DEQ_LB5, tas3001_initdata.LB5);
447: DEQ_WRITE(sc, DEQ_RB0, tas3001_initdata.RB0);
448: DEQ_WRITE(sc, DEQ_RB1, tas3001_initdata.RB1);
449: DEQ_WRITE(sc, DEQ_RB1, tas3001_initdata.RB1);
450: DEQ_WRITE(sc, DEQ_RB2, tas3001_initdata.RB2);
451: DEQ_WRITE(sc, DEQ_RB3, tas3001_initdata.RB3);
452: DEQ_WRITE(sc, DEQ_RB4, tas3001_initdata.RB4);
453: DEQ_WRITE(sc, DEQ_MCR, tas3001_initdata.MCR);
454: DEQ_WRITE(sc, DEQ_DRC, tas3001_initdata.DRC);
455: DEQ_WRITE(sc, DEQ_VOLUME, tas3001_initdata.VOLUME);
456: DEQ_WRITE(sc, DEQ_TREBLE, tas3001_initdata.TREBLE);
457: DEQ_WRITE(sc, DEQ_BASS, tas3001_initdata.BASS);
458: DEQ_WRITE(sc, DEQ_MIXER1, tas3001_initdata.MIXER1);
459: DEQ_WRITE(sc, DEQ_MIXER2, tas3001_initdata.MIXER2);
460:
461: return (0);
462: err:
463: printf("%s: tas3001_init: error\n", sc->sc_dev.dv_xname);
464: return (-1);
465: }
466:
467: void
468: tumbler_init(struct tumbler_softc *sc)
469: {
470:
471: /* "sample-rates" (44100, 48000) */
472: i2s_set_rate(sc, 44100);
473:
474: #if 1
475: /* Enable I2C interrupts. */
476: #define IER 4
477: #define I2C_INT_DATA 0x01
478: #define I2C_INT_ADDR 0x02
479: #define I2C_INT_STOP 0x04
480: kiic_writereg(sc->sc_i2c, IER,I2C_INT_DATA|I2C_INT_ADDR|I2C_INT_STOP);
481: #endif
482:
483: if (tas3001_init(sc))
484: return;
485:
486: tumbler_set_volume(sc, 80, 80);
487: }
488:
489: int
490: tumbler_getdev(void *h, struct audio_device *retp)
491: {
492: *retp = tumbler_device;
493: return (0);
494: }
CVSweb