Home | History | Annotate | Line # | Download | only in ic
tms320av110.c revision 1.21
      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