xref: /netbsd/sys/dev/ic/tms320av110.c (revision 6550d01e)
1 /*	$NetBSD: tms320av110.c,v 1.21 2008/04/28 20:23:51 martin Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Ignatios Souvatzis.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Machine independent part of TMS320AV110 driver.
34  *
35  * Currently, only minimum support for audio output. For audio/video
36  * synchronization, more is needed.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: tms320av110.c,v 1.21 2008/04/28 20:23:51 martin Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #include <sys/proc.h>
47 
48 #include <sys/audioio.h>
49 #include <dev/audio_if.h>
50 
51 #include <dev/ic/tms320av110reg.h>
52 #include <dev/ic/tms320av110var.h>
53 
54 #include <sys/bus.h>
55 
56 int tav_open(void *, int);
57 void tav_close(void *);
58 int tav_drain(void *);
59 int tav_query_encoding(void *, struct audio_encoding *);
60 int tav_set_params(void *, int, int, audio_params_t *, audio_params_t *,
61     stream_filter_list_t *, stream_filter_list_t *);
62 int tav_round_blocksize(void *, int, int, const audio_params_t *);
63 int tav_init_output(void *, void *, int);
64 int tav_start_output(void *, void *, int, void (*)(void *), void *);
65 int tav_start_input(void *, void *, int, void (*)(void *), void *);
66 int tav_halt_output(void *);
67 int tav_halt_input(void *);
68 int tav_speaker_ctl(void *, int);
69 int tav_getdev(void *, struct audio_device *);
70 int tav_setfd(void *, int);
71 int tav_set_port(void *, mixer_ctrl_t *);
72 int tav_get_port(void *, mixer_ctrl_t *);
73 int tav_query_devinfo(void *, mixer_devinfo_t *);
74 int tav_get_props(void *);
75 
76 const struct audio_hw_if tav_audio_if = {
77 	tav_open,
78 	tav_close,
79 	0 /* tav_drain*/,		/* optional */
80 	tav_query_encoding,
81 	tav_set_params,
82 	tav_round_blocksize,
83 	0 /* commit_settings */,	/* optional */
84 	tav_init_output,		/* optional */
85 	0 /* tav_init_input */,		/* optional */
86 	tav_start_output,
87 	tav_start_input,
88 	tav_halt_output,
89 	tav_halt_input,
90 	tav_speaker_ctl,		/* optional */
91 	tav_getdev,
92 	0 /* setfd */,			/* optional */
93 	tav_set_port,
94 	tav_get_port,
95 	tav_query_devinfo,
96 	0 /* alloc */,			/* optional */
97 	0 /* free */,			/* optional */
98 	0 /* round_buffersize */,	/* optional */
99 	0 /* mappage */,		/* optional */
100 	tav_get_props,
101 	0 /* dev_ioctl */		/* optional */
102 };
103 
104 void
105 tms320av110_attach_mi(struct tav_softc *sc)
106 {
107 	bus_space_tag_t iot;
108 	bus_space_handle_t ioh;
109 
110 	iot = sc->sc_iot;
111 	ioh = sc->sc_ioh;
112 	tav_write_byte(iot, ioh, TAV_RESET, 1);
113 	while (tav_read_byte(iot, ioh, TAV_RESET))
114 		delay(250);
115 
116 	tav_write_byte(iot, ioh, TAV_PCM_ORD, sc->sc_pcm_ord);
117 	tav_write_byte(iot, ioh, TAV_PCM_18, sc->sc_pcm_18);
118 	tav_write_byte(iot, ioh, TAV_DIF, sc->sc_dif);
119 	tav_write_byte(iot, ioh, TAV_PCM_DIV, sc->sc_pcm_div);
120 
121 	printf(": chip rev. %d, %d bytes buffer\n",
122 	    tav_read_byte(iot, ioh, TAV_VERSION),
123 	    TAV_DRAM_SIZE(tav_read_byte(iot, ioh, TAV_DRAM_EXT)));
124 
125 	tav_write_byte(iot, ioh, TAV_AUD_ID_EN, 0);
126 	tav_write_byte(iot, ioh, TAV_SKIP, 0);
127 	tav_write_byte(iot, ioh, TAV_REPEAT, 0);
128 	tav_write_byte(iot, ioh, TAV_MUTE, 0);
129 	tav_write_byte(iot, ioh, TAV_PLAY, 1);
130 	tav_write_byte(iot, ioh, TAV_SYNC_ECM, 0);
131 	tav_write_byte(iot, ioh, TAV_CRC_ECM, 0);
132 	tav_write_byte(iot, ioh, TAV_ATTEN_L, 0);
133 	tav_write_byte(iot, ioh, TAV_ATTEN_R, 0);
134 	tav_write_short(iot, ioh, TAV_FREE_FORM, 0);
135 	tav_write_byte(iot, ioh, TAV_SIN_EN, 0);
136 	tav_write_byte(iot, ioh, TAV_SYNC_ECM, TAV_ECM_REPEAT);
137 	tav_write_byte(iot, ioh, TAV_CRC_ECM, TAV_ECM_REPEAT);
138 
139 	audio_attach_mi(&tav_audio_if, sc, &sc->sc_dev);
140 }
141 
142 int
143 tms320av110_intr(void *p)
144 {
145 	struct tav_softc *sc;
146 	uint16_t intlist;
147 
148 	sc = p;
149 	intlist = tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR)
150 	    /* & tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR_EN)*/;
151 
152 	if (!intlist)
153 		return 0;
154 
155 	/* ack now, so that we don't miss later interrupts */
156 	if (sc->sc_intack)
157 		(sc->sc_intack)(sc);
158 
159 	if (intlist & TAV_INTR_LOWWATER) {
160 		(*sc->sc_intr)(sc->sc_intrarg);
161 	}
162 
163 	if (intlist & TAV_INTR_PCM_OUTPUT_UNDERFLOW) {
164 		 wakeup(sc);
165 	}
166 
167 	return 1;
168 }
169 
170 struct audio_encoding tav_encodings[] = {
171 	{0, AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM, 1, 0,},
172 	{1, AudioEmpeg_l2_packets, AUDIO_ENCODING_MPEG_L2_PACKETS, 1, 0,},
173 	{2, AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM, 1, 0,},
174 	{3, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0,},
175 };
176 
177 int
178 tav_open(void *hdl, int flags)
179 {
180 
181 	/* dummy */
182 	return 0;
183 }
184 
185 void
186 tav_close(void *hdl)
187 {
188 	struct tav_softc *sc;
189 	bus_space_tag_t iot;
190 	bus_space_handle_t ioh;
191 
192 	sc = hdl;
193 	iot = sc->sc_iot;
194 	ioh = sc->sc_ioh;
195 
196 	/* re"start" chip, also clears interrupts and interrupt enable */
197 	tav_write_short(iot, ioh, TAV_INTR_EN, 0);
198 	if (sc->sc_intack)
199 		(*sc->sc_intack)(sc);
200 }
201 
202 int
203 tav_drain(void *hdl)
204 {
205 	struct tav_softc *sc;
206 	bus_space_tag_t iot;
207 	bus_space_handle_t ioh;
208 	u_int16_t mask;
209 
210 	sc = hdl;
211 	iot = sc->sc_iot;
212 	ioh = sc->sc_ioh;
213 
214 	/*
215 	 * tsleep waiting for underflow interrupt.
216 	 */
217 	if (tav_read_short(iot, ioh, TAV_BUFF)) {
218 		mask = tav_read_short(iot, ioh, TAV_INTR_EN);
219 		tav_write_short(iot, ioh, TAV_INTR_EN,
220 		    mask|TAV_INTR_PCM_OUTPUT_UNDERFLOW);
221 
222 		/* still more than zero? */
223 		if (tav_read_short(iot, ioh, TAV_BUFF))
224 			(void)tsleep(sc, PCATCH, "tavdrain", 32*hz);
225 
226 		/* can be really that long for mpeg */
227 
228 		mask = tav_read_short(iot, ioh, TAV_INTR_EN);
229 		tav_write_short(iot, ioh, TAV_INTR_EN,
230 		    mask & ~TAV_INTR_PCM_OUTPUT_UNDERFLOW);
231 	}
232 
233 	return 0;
234 }
235 
236 int
237 tav_query_encoding(void *hdl, struct audio_encoding *ae)
238 {
239 	struct tav_softc *sc;
240 
241 	sc = hdl;
242 	if (ae->index >= sizeof(tav_encodings)/sizeof(*ae))
243 		return EINVAL;
244 
245 	*ae = tav_encodings[ae->index];
246 
247 	return 0;
248 }
249 
250 int
251 tav_start_input(void *hdl, void *block, int bsize,
252     void (*intr)(void *), void *intrarg)
253 {
254 
255 	return ENOTTY;
256 }
257 
258 int
259 tav_halt_input(void *hdl)
260 {
261 
262 	return ENOTTY;
263 }
264 
265 int
266 tav_start_output(void *hdl, void *block, int bsize,
267     void (*intr)(void *), void *intrarg)
268 {
269 	struct tav_softc *sc;
270 	bus_space_tag_t iot;
271 	bus_space_handle_t ioh;
272 	uint8_t *ptr;
273 	int count;
274 
275 	sc = hdl;
276 	iot = sc->sc_iot;
277 	ioh = sc->sc_ioh;
278 	ptr = block;
279 	count = bsize;
280 
281 	sc->sc_intr = intr;
282 	sc->sc_intrarg = intrarg;
283 
284 	bus_space_write_multi_1(iot, ioh, TAV_DATAIN, ptr, count);
285 	tav_write_short(iot, ioh, TAV_INTR_EN, TAV_INTR_LOWWATER);
286 
287 	return 0;
288 }
289 
290 int
291 tav_init_output(void *hdl, void *buffer, int size)
292 {
293 	struct tav_softc *sc;
294 	bus_space_tag_t iot;
295 	bus_space_handle_t ioh;
296 
297 	sc = hdl;
298 	iot = sc->sc_iot;
299 	ioh = sc->sc_ioh;
300 
301 	tav_write_byte(iot, ioh, TAV_PLAY, 1);
302 	tav_write_byte(iot, ioh, TAV_MUTE, 0);
303 
304 	return 0;
305 }
306 
307 int
308 tav_halt_output(void *hdl)
309 {
310 	struct tav_softc *sc;
311 	bus_space_tag_t iot;
312 	bus_space_handle_t ioh;
313 
314 	sc = hdl;
315 	iot = sc->sc_iot;
316 	ioh = sc->sc_ioh;
317 
318 	tav_write_byte(iot, ioh, TAV_PLAY, 0);
319 
320 	return 0;
321 }
322 
323 int
324 tav_getdev(void *hdl, struct audio_device *ret)
325 {
326 	struct tav_softc *sc;
327 	bus_space_tag_t iot;
328 	bus_space_handle_t ioh;
329 
330 	sc = hdl;
331 	iot = sc->sc_iot;
332 	ioh = sc->sc_ioh;
333 
334 	strlcpy(ret->name, "tms320av110", sizeof(ret->name));
335 	/* guaranteed to be <= 4 in length */
336 	snprintf(ret->version, sizeof(ret->version), "%u",
337 	    tav_read_byte(iot, ioh, TAV_VERSION));
338 	strlcpy(ret->config, device_xname(&sc->sc_dev), sizeof(ret->config));
339 
340 	return 0;
341 }
342 
343 int
344 tav_round_blocksize(void *hdl, int size, int mode, const audio_params_t *param)
345 {
346 	struct tav_softc *sc;
347 	bus_space_tag_t iot;
348 	bus_space_handle_t ioh;
349 	int maxhalf;
350 
351 	sc = hdl;
352 	iot = sc->sc_iot;
353 	ioh = sc->sc_ioh;
354 
355 	maxhalf = TAV_DRAM_HSIZE(tav_read_byte(iot, ioh, TAV_DRAM_EXT));
356 	if (size > maxhalf)
357 		size = maxhalf;
358 
359 	/* XXX should round to 128 bytes limits for audio bypass */
360 	size &= ~3;
361 
362 	tav_write_short(iot, ioh, TAV_BALE_LIM, size/8);
363 
364 	/* the buffer limits are in units of 4 bytes */
365 	return (size);
366 }
367 
368 int
369 tav_get_props(void *hdl)
370 {
371 	return 0;
372 }
373 
374 int
375 tav_set_params(void *hdl, int setmode, int usemode, audio_params_t *p,
376     audio_params_t *r, stream_filter_list_t *pfil, stream_filter_list_t *rfil)
377 {
378 	struct tav_softc *sc;
379 	bus_space_tag_t iot;
380 	bus_space_handle_t ioh;
381 
382 	sc = hdl;
383 	iot = sc->sc_iot;
384 	ioh = sc->sc_ioh;
385 
386 	if (!(setmode & AUMODE_PLAY))
387 		return 0;
388 
389 	if (p->encoding == AUDIO_ENCODING_ULAW)
390 		p->encoding = AUDIO_ENCODING_MPEG_L2_STREAM;
391 
392 	switch(p->encoding) {
393 	default:
394 		return EINVAL;
395 
396 	case AUDIO_ENCODING_SLINEAR_BE:
397 
398 		/* XXX: todo: add 8bit and mono using software */
399 		p->precision = 16;
400 		p->channels = 2;
401 
402 		/* XXX: this might depend on the specific board.
403 		   should be handled by the backend */
404 
405 		p->sample_rate = 44100;
406 
407 		bus_space_write_1(iot, ioh, TAV_STR_SEL,
408 		    TAV_STR_SEL_AUDIO_BYPASS);
409 		break;
410 
411 	/* XXX: later: add ULINEAR, and LE using software encoding */
412 
413 	case AUDIO_ENCODING_MPEG_L1_STREAM:
414 		/* FALLTHROUGH */
415 	case AUDIO_ENCODING_MPEG_L2_STREAM:
416 		bus_space_write_1(iot, ioh, TAV_STR_SEL,
417 		    TAV_STR_SEL_MPEG_AUDIO_STREAM);
418 		p->sample_rate = 44100;
419 		p->precision = 1;
420 		break;
421 
422 	case AUDIO_ENCODING_MPEG_L1_PACKETS:
423 		/* FALLTHROUGH */
424 	case AUDIO_ENCODING_MPEG_L2_PACKETS:
425 		bus_space_write_1(iot, ioh, TAV_STR_SEL,
426 		    TAV_STR_SEL_MPEG_AUDIO_PACKETS);
427 		p->sample_rate = 44100;
428 		p->precision = 1;
429 		break;
430 
431 	case AUDIO_ENCODING_MPEG_L1_SYSTEM:
432 		/* FALLTHROUGH */
433 	case AUDIO_ENCODING_MPEG_L2_SYSTEM:
434 		bus_space_write_1(iot, ioh, TAV_STR_SEL,
435 		    TAV_STR_SEL_MPEG_SYSTEM_STREAM);
436 		p->sample_rate = 44100;
437 		p->precision = 1;
438 		break;
439 	}
440 	tav_write_byte(iot, ioh, TAV_RESTART, 1);
441 	do {
442 		delay(10);
443 	} while (tav_read_byte(iot, ioh, TAV_RESTART));
444 
445 	return 0;
446 }
447 
448 int
449 tav_set_port(void *hdl, mixer_ctrl_t *mc)
450 {
451 	struct tav_softc *sc;
452 
453 	sc = hdl;
454 	/* dummy */
455 	return 0;
456 }
457 
458 int
459 tav_get_port(void *hdl, mixer_ctrl_t *mc)
460 {
461 	struct tav_softc *sc;
462 
463 	sc = hdl;
464 	/* dummy */
465 	return 0;
466 }
467 
468 int
469 tav_query_devinfo(void *hdl, mixer_devinfo_t *di)
470 {
471 	return ENXIO;
472 }
473 
474 int
475 tav_speaker_ctl(void *hdl, int value)
476 {
477 	struct tav_softc *sc;
478 	bus_space_tag_t iot;
479 	bus_space_handle_t ioh;
480 
481 	sc = hdl;
482 	iot = sc->sc_iot;
483 	ioh = sc->sc_ioh;
484 
485 	tav_write_byte(iot, ioh, TAV_MUTE, !value);
486 
487 	return 0;
488 }
489