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