am7930.c revision 1.40 1 1.40 pk /* $NetBSD: am7930.c,v 1.40 1998/08/28 08:59:14 pk Exp $ */
2 1.3 cgd
3 1.1 pk /*
4 1.1 pk * Copyright (c) 1995 Rolf Grossmann
5 1.1 pk * All rights reserved.
6 1.1 pk *
7 1.1 pk * Redistribution and use in source and binary forms, with or without
8 1.1 pk * modification, are permitted provided that the following conditions
9 1.1 pk * are met:
10 1.1 pk * 1. Redistributions of source code must retain the above copyright
11 1.1 pk * notice, this list of conditions and the following disclaimer.
12 1.1 pk * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 pk * notice, this list of conditions and the following disclaimer in the
14 1.1 pk * documentation and/or other materials provided with the distribution.
15 1.1 pk * 3. All advertising materials mentioning features or use of this software
16 1.1 pk * must display the following acknowledgement:
17 1.1 pk * This product includes software developed by Rolf Grossmann.
18 1.1 pk * 4. The name of the author may not be used to endorse or promote products
19 1.1 pk * derived from this software without specific prior written permission
20 1.1 pk *
21 1.1 pk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 1.1 pk * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 1.1 pk * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 1.1 pk * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 1.1 pk * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 1.1 pk * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 1.1 pk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 1.1 pk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 1.1 pk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 1.1 pk * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 1.1 pk */
32 1.1 pk
33 1.39 jonathan /*
34 1.39 jonathan * Front-end attachment independent layer for AMD 79c30
35 1.39 jonathan * audio driver. XXX isdn support??
36 1.39 jonathan */
37 1.39 jonathan
38 1.1 pk #include "audio.h"
39 1.1 pk #if NAUDIO > 0
40 1.1 pk
41 1.1 pk #include <sys/param.h>
42 1.1 pk #include <sys/systm.h>
43 1.1 pk #include <sys/errno.h>
44 1.1 pk #include <sys/ioctl.h>
45 1.1 pk #include <sys/device.h>
46 1.1 pk #include <sys/proc.h>
47 1.1 pk
48 1.36 pk #include <machine/bus.h>
49 1.1 pk #include <machine/autoconf.h>
50 1.1 pk #include <machine/cpu.h>
51 1.1 pk
52 1.1 pk #include <sys/audioio.h>
53 1.1 pk #include <dev/audio_if.h>
54 1.1 pk
55 1.3 cgd #include <dev/ic/am7930reg.h>
56 1.39 jonathan #include <dev/ic/am7930var.h>
57 1.1 pk
58 1.30 augustss #define AUDIO_ROM_NAME "audio"
59 1.30 augustss
60 1.4 brezak #ifdef AUDIO_DEBUG
61 1.39 jonathan int am7930debug = 0;
62 1.40 pk #define DPRINTF(x) if (am7930debug) printf x
63 1.1 pk #else
64 1.1 pk #define DPRINTF(x)
65 1.1 pk #endif
66 1.1 pk
67 1.39 jonathan /* forward declarations */
68 1.39 jonathan static void init_amd __P((volatile struct am7930 *));
69 1.39 jonathan
70 1.1 pk /*
71 1.39 jonathan * Audio device descriptor (attachment independent)
72 1.1 pk */
73 1.1 pk
74 1.39 jonathan struct audio_device am7930_device = {
75 1.1 pk "amd7930",
76 1.1 pk "x",
77 1.27 augustss "audioamd"
78 1.1 pk };
79 1.1 pk
80 1.1 pk /* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */
81 1.1 pk
82 1.1 pk /*
83 1.1 pk * gx, gr & stg gains. this table must contain 256 elements with
84 1.1 pk * the 0th being "infinity" (the magic value 9008). The remaining
85 1.1 pk * elements match sun's gain curve (but with higher resolution):
86 1.1 pk * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
87 1.1 pk */
88 1.1 pk static const u_short gx_coeff[256] = {
89 1.21 pk 0x9008, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33,
90 1.1 pk 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
91 1.1 pk 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
92 1.1 pk 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
93 1.1 pk 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
94 1.1 pk 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
95 1.1 pk 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
96 1.1 pk 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
97 1.1 pk 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
98 1.1 pk 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
99 1.1 pk 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
100 1.1 pk 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
101 1.1 pk 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
102 1.1 pk 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
103 1.1 pk 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
104 1.1 pk 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
105 1.1 pk 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
106 1.1 pk 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
107 1.1 pk 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
108 1.1 pk 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
109 1.1 pk 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
110 1.1 pk 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
111 1.1 pk 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
112 1.1 pk 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
113 1.1 pk 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
114 1.1 pk 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
115 1.1 pk 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
116 1.1 pk 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
117 1.1 pk 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
118 1.1 pk 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
119 1.1 pk 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
120 1.1 pk 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
121 1.1 pk };
122 1.1 pk
123 1.1 pk /*
124 1.1 pk * second stage play gain.
125 1.1 pk */
126 1.1 pk static const u_short ger_coeff[] = {
127 1.1 pk 0x431f, /* 5. dB */
128 1.1 pk 0x331f, /* 5.5 dB */
129 1.1 pk 0x40dd, /* 6. dB */
130 1.1 pk 0x11dd, /* 6.5 dB */
131 1.1 pk 0x440f, /* 7. dB */
132 1.1 pk 0x411f, /* 7.5 dB */
133 1.1 pk 0x311f, /* 8. dB */
134 1.1 pk 0x5520, /* 8.5 dB */
135 1.1 pk 0x10dd, /* 9. dB */
136 1.1 pk 0x4211, /* 9.5 dB */
137 1.1 pk 0x410f, /* 10. dB */
138 1.1 pk 0x111f, /* 10.5 dB */
139 1.1 pk 0x600b, /* 11. dB */
140 1.1 pk 0x00dd, /* 11.5 dB */
141 1.1 pk 0x4210, /* 12. dB */
142 1.1 pk 0x110f, /* 13. dB */
143 1.1 pk 0x7200, /* 14. dB */
144 1.1 pk 0x2110, /* 15. dB */
145 1.1 pk 0x2200, /* 15.9 dB */
146 1.1 pk 0x000b, /* 16.9 dB */
147 1.1 pk 0x000f /* 18. dB */
148 1.1 pk #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
149 1.1 pk };
150 1.1 pk
151 1.1 pk
152 1.1 pk /*
153 1.39 jonathan * Reset chip and set boot-time softc defaults.
154 1.1 pk */
155 1.1 pk void
156 1.39 jonathan am7930_init(sc)
157 1.39 jonathan struct am7930_softc *sc;
158 1.36 pk {
159 1.1 pk sc->sc_map.mr_mmr1 = AMD_MMR1_GX | AMD_MMR1_GER |
160 1.1 pk AMD_MMR1_GR | AMD_MMR1_STG;
161 1.39 jonathan
162 1.1 pk /* set boot defaults */
163 1.1 pk sc->sc_rlevel = 128;
164 1.1 pk sc->sc_plevel = 128;
165 1.1 pk sc->sc_mlevel = 0;
166 1.1 pk sc->sc_out_port = SUNAUDIO_SPEAKER;
167 1.39 jonathan init_amd(sc->sc_amd);
168 1.1 pk }
169 1.1 pk
170 1.1 pk static void
171 1.1 pk init_amd(amd)
172 1.39 jonathan register volatile struct am7930 *amd;
173 1.1 pk {
174 1.1 pk /* disable interrupts */
175 1.1 pk amd->cr = AMDR_INIT;
176 1.1 pk amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
177 1.1 pk
178 1.1 pk /*
179 1.1 pk * Initialize the mux unit. We use MCR3 to route audio (MAP)
180 1.1 pk * through channel Bb. MCR1 and MCR2 are unused.
181 1.1 pk * Setting the INT enable bit in MCR4 will generate an interrupt
182 1.1 pk * on each converted audio sample.
183 1.1 pk */
184 1.1 pk amd->cr = AMDR_MUX_1_4;
185 1.1 pk amd->dr = 0;
186 1.1 pk amd->dr = 0;
187 1.1 pk amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA;
188 1.1 pk amd->dr = AMD_MCR4_INT_ENABLE;
189 1.1 pk }
190 1.1 pk
191 1.1 pk int
192 1.39 jonathan am7930_open(addr, flags)
193 1.26 augustss void *addr;
194 1.1 pk int flags;
195 1.1 pk {
196 1.39 jonathan struct am7930_softc *sc = addr;
197 1.1 pk
198 1.26 augustss DPRINTF(("sa_open: unit %p\n", sc));
199 1.1 pk
200 1.1 pk if (sc->sc_open)
201 1.1 pk return (EBUSY);
202 1.1 pk sc->sc_open = 1;
203 1.1 pk sc->sc_locked = 0;
204 1.1 pk
205 1.39 jonathan /* tell attach layer about open */
206 1.39 jonathan sc->sc_onopen(sc);
207 1.1 pk
208 1.40 pk DPRINTF(("saopen: ok -> sc=%p\n", sc));
209 1.1 pk
210 1.1 pk return (0);
211 1.1 pk }
212 1.1 pk
213 1.1 pk void
214 1.39 jonathan am7930_close(addr)
215 1.1 pk void *addr;
216 1.1 pk {
217 1.39 jonathan register struct am7930_softc *sc = addr;
218 1.1 pk
219 1.40 pk DPRINTF(("sa_close: sc=%p\n", sc));
220 1.1 pk /*
221 1.1 pk * halt i/o, clear open flag, and done.
222 1.1 pk */
223 1.39 jonathan sc->sc_onclose(sc);
224 1.1 pk sc->sc_open = 0;
225 1.1 pk
226 1.1 pk DPRINTF(("sa_close: closed.\n"));
227 1.1 pk }
228 1.1 pk
229 1.1 pk int
230 1.39 jonathan am7930_set_params(addr, setmode, usemode, p, r)
231 1.1 pk void *addr;
232 1.28 augustss int setmode, usemode;
233 1.28 augustss struct audio_params *p, *r;
234 1.1 pk {
235 1.18 augustss if (p->sample_rate < 7500 || p->sample_rate > 8500 ||
236 1.18 augustss p->encoding != AUDIO_ENCODING_ULAW ||
237 1.18 augustss p->precision != 8 ||
238 1.18 augustss p->channels != 1)
239 1.1 pk return EINVAL;
240 1.20 augustss p->sample_rate = 8000; /* no other sampling rates supported by amd chip */
241 1.20 augustss
242 1.20 augustss return 0;
243 1.1 pk }
244 1.1 pk
245 1.1 pk int
246 1.39 jonathan am7930_query_encoding(addr, fp)
247 1.1 pk void *addr;
248 1.1 pk struct audio_encoding *fp;
249 1.1 pk {
250 1.1 pk switch (fp->index) { /* ??? */
251 1.1 pk case 0:
252 1.19 augustss strcpy(fp->name, AudioEmulaw);
253 1.19 augustss fp->encoding = AUDIO_ENCODING_ULAW;
254 1.19 augustss fp->precision = 8;
255 1.19 augustss fp->flags = 0;
256 1.1 pk break;
257 1.1 pk default:
258 1.1 pk return(EINVAL);
259 1.1 pk /*NOTREACHED*/
260 1.1 pk }
261 1.1 pk return(0);
262 1.1 pk }
263 1.1 pk
264 1.39 jonathan
265 1.1 pk int
266 1.39 jonathan am7930_round_blocksize(addr, blk)
267 1.1 pk void *addr;
268 1.1 pk int blk;
269 1.1 pk {
270 1.1 pk return(blk);
271 1.1 pk }
272 1.1 pk
273 1.1 pk int
274 1.39 jonathan am7930_commit_settings(addr)
275 1.1 pk void *addr;
276 1.1 pk {
277 1.39 jonathan register struct am7930_softc *sc = addr;
278 1.1 pk register struct mapreg *map;
279 1.39 jonathan register volatile struct am7930 *amd;
280 1.1 pk register int s, level;
281 1.10 pk
282 1.1 pk DPRINTF(("sa_commit.\n"));
283 1.1 pk
284 1.1 pk map = &sc->sc_map;
285 1.39 jonathan amd = sc->sc_amd;
286 1.1 pk
287 1.1 pk map->mr_gx = gx_coeff[sc->sc_rlevel];
288 1.1 pk map->mr_stgr = gx_coeff[sc->sc_mlevel];
289 1.10 pk
290 1.1 pk level = (sc->sc_plevel * (256 + NGER)) >> 8;
291 1.1 pk if (level >= 256) {
292 1.1 pk map->mr_ger = ger_coeff[level - 256];
293 1.1 pk map->mr_gr = gx_coeff[255];
294 1.1 pk } else {
295 1.1 pk map->mr_ger = ger_coeff[0];
296 1.1 pk map->mr_gr = gx_coeff[level];
297 1.1 pk }
298 1.1 pk
299 1.1 pk if (sc->sc_out_port == SUNAUDIO_SPEAKER)
300 1.1 pk map->mr_mmr2 |= AMD_MMR2_LS;
301 1.1 pk else
302 1.1 pk map->mr_mmr2 &= ~AMD_MMR2_LS;
303 1.10 pk
304 1.1 pk s = splaudio();
305 1.10 pk
306 1.1 pk amd->cr = AMDR_MAP_MMR1;
307 1.1 pk amd->dr = map->mr_mmr1;
308 1.1 pk amd->cr = AMDR_MAP_GX;
309 1.39 jonathan WAMD16(sc, amd, map->mr_gx);
310 1.1 pk amd->cr = AMDR_MAP_STG;
311 1.39 jonathan WAMD16(sc, amd, map->mr_stgr);
312 1.1 pk amd->cr = AMDR_MAP_GR;
313 1.39 jonathan WAMD16(sc, amd, map->mr_gr);
314 1.1 pk amd->cr = AMDR_MAP_GER;
315 1.39 jonathan WAMD16(sc, amd, map->mr_ger);
316 1.1 pk amd->cr = AMDR_MAP_MMR2;
317 1.1 pk amd->dr = map->mr_mmr2;
318 1.1 pk
319 1.1 pk splx(s);
320 1.1 pk return(0);
321 1.1 pk }
322 1.1 pk
323 1.1 pk int
324 1.39 jonathan am7930_halt_output(addr)
325 1.1 pk void *addr;
326 1.1 pk {
327 1.39 jonathan register struct am7930_softc *sc = addr;
328 1.39 jonathan register volatile struct am7930 *amd = sc->sc_amd;
329 1.1 pk
330 1.1 pk /* XXX only halt, if input is also halted ?? */
331 1.1 pk amd->cr = AMDR_INIT;
332 1.1 pk amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
333 1.1 pk sc->sc_locked = 0;
334 1.1 pk
335 1.1 pk return(0);
336 1.1 pk }
337 1.1 pk
338 1.1 pk int
339 1.39 jonathan am7930_halt_input(addr)
340 1.1 pk void *addr;
341 1.1 pk {
342 1.39 jonathan register struct am7930_softc *sc = addr;
343 1.39 jonathan register volatile struct am7930 *amd = sc->sc_amd;
344 1.1 pk
345 1.1 pk /* XXX only halt, if output is also halted ?? */
346 1.1 pk amd->cr = AMDR_INIT;
347 1.1 pk amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
348 1.1 pk sc->sc_locked = 0;
349 1.1 pk
350 1.1 pk return(0);
351 1.1 pk }
352 1.1 pk
353 1.1 pk int
354 1.39 jonathan am7930_getdev(addr, retp)
355 1.1 pk void *addr;
356 1.1 pk struct audio_device *retp;
357 1.1 pk {
358 1.39 jonathan *retp = am7930_device;
359 1.1 pk return 0;
360 1.1 pk }
361 1.1 pk
362 1.26 augustss
363 1.39 jonathan /*
364 1.39 jonathan * XXX chip is full-duplex, but really attach-dependent.
365 1.39 jonathan * For now we know of no half-duplex attachments.
366 1.39 jonathan */
367 1.26 augustss int
368 1.39 jonathan am7930_get_props(addr)
369 1.26 augustss void *addr;
370 1.26 augustss {
371 1.26 augustss return AUDIO_PROP_FULLDUPLEX;
372 1.1 pk }
373 1.39 jonathan #endif /* NAUDIO */
374