Home | History | Annotate | Line # | Download | only in mini2440
audio_mini2440.c revision 1.1
      1 /*-
      2  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      3  * All rights reserved.
      4  *
      5  * This code is derived from software contributed to The NetBSD Foundation
      6  * by Paul Fleischer <paul (at) xpg.dk>
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27  * POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include <sys/cdefs.h>
     31 #include <sys/param.h>
     32 #include <sys/device.h>
     33 #include <sys/malloc.h>
     34 #include <sys/fcntl.h>
     35 #include <sys/audioio.h>
     36 
     37 #include <sys/bus.h>
     38 
     39 #include <dev/audio_if.h>
     40 
     41 
     42 #include <dev/ic/uda1341var.h>
     43 
     44 #include <arch/arm/s3c2xx0/s3c2440reg.h>
     45 #include <arch/arm/s3c2xx0/s3c2440var.h>
     46 
     47 #include <arch/arm/s3c2xx0/s3c2440_dma.h>
     48 #include <arch/arm/s3c2xx0/s3c2440_i2s.h>
     49 
     50 /*#define AUDIO_MINI2440_DEBUG*/
     51 
     52 #ifdef AUDIO_MINI2440_DEBUG
     53 #define DPRINTF(x) do {printf x; } while (/*CONSTCOND*/0)
     54 #else
     55 #define DPRINTF(s) do {} while (/*CONSTCOND*/0)
     56 #endif
     57 
     58 struct uda_softc {
     59 	device_t		sc_dev;
     60 	kmutex_t		sc_lock;
     61 	kmutex_t		sc_intr_lock;
     62 
     63 	struct uda1341_softc	sc_uda1341;
     64 
     65 	s3c2440_i2s_buf_t	sc_play_buf;
     66 	s3c2440_i2s_buf_t	sc_rec_buf;
     67 
     68 	void			*sc_i2s_handle;
     69 
     70 	bool			sc_open;
     71 };
     72 
     73 int	uda_ssio_open(void *, int);
     74 void	uda_ssio_close(void *);
     75 int	uda_ssio_set_params(void *, int, int, audio_params_t *, audio_params_t *,
     76 		       stream_filter_list_t *, stream_filter_list_t *);
     77 int	uda_ssio_round_blocksize(void *, int, int, const audio_params_t *);
     78 int	uda_ssio_start_output(void *, void *, int, void (*)(void *),
     79 			      void *);
     80 int	uda_ssio_start_input(void *, void *, int, void (*)(void *),
     81 			      void *);
     82 int	uda_ssio_halt_output(void *);
     83 int	uda_ssio_halt_input(void *);
     84 int	uda_ssio_getdev(void *, struct audio_device *ret);
     85 void*	uda_ssio_allocm(void *, int, size_t);
     86 void	uda_ssio_freem(void *, void *, size_t);
     87 size_t	uda_ssio_round_buffersize(void *, int, size_t);
     88 int	uda_ssio_getprops(void *);
     89 void	uda_ssio_get_locks(void *, kmutex_t**, kmutex_t**);
     90 
     91 struct audio_hw_if uda1341_hw_if = {
     92 	uda_ssio_open,
     93 	uda_ssio_close,
     94 	NULL,
     95 	uda1341_query_encodings,
     96 	uda_ssio_set_params,
     97 	uda_ssio_round_blocksize,
     98 	NULL,				/* commit_settings*/
     99 	NULL,
    100 	NULL,
    101 	uda_ssio_start_output,
    102 	uda_ssio_start_input,
    103 	uda_ssio_halt_output,
    104 	uda_ssio_halt_input,
    105 	NULL,
    106 	uda_ssio_getdev,
    107 	NULL,
    108 	uda1341_set_port,
    109 	uda1341_get_port,
    110 	uda1341_query_devinfo,
    111 	uda_ssio_allocm,
    112 	uda_ssio_freem,
    113 	uda_ssio_round_buffersize,
    114 	NULL,				/* mappage */
    115 	uda_ssio_getprops,
    116 	NULL,
    117 	NULL,
    118 	NULL,
    119 	uda_ssio_get_locks
    120 };
    121 
    122 static struct audio_device uda1341_device = {
    123 	"MINI2240-UDA1341",
    124 	"0.1",
    125 	"uda_ssio"
    126 };
    127 
    128 void uda_ssio_l3_write(void *,int mode, int value);
    129 
    130 int uda_ssio_match(device_t, cfdata_t, void*);
    131 void uda_ssio_attach(device_t, device_t, void*);
    132 
    133 CFATTACH_DECL_NEW(udassio, sizeof(struct uda_softc),
    134 	      uda_ssio_match, uda_ssio_attach, NULL, NULL);
    135 
    136 int
    137 uda_ssio_match(device_t parent, cfdata_t match, void *aux)
    138 {
    139 	DPRINTF(("%s\n", __func__));
    140 	/* Not quite sure how we can detect the UDA1341 chip */
    141 	return 1;
    142 }
    143 
    144 void
    145 uda_ssio_attach(device_t parent, device_t self, void *aux)
    146 {
    147 	/*	struct s3c2xx0_attach_args *sa = aux;*/
    148 	struct uda_softc *sc = device_private(self);
    149 	struct s3c2xx0_softc *s3sc = s3c2xx0_softc; /* Shortcut */
    150 	struct s3c2440_i2s_attach_args *aa = aux;
    151 	uint32_t reg;
    152 
    153 	sc->sc_dev = self;
    154 
    155 	sc->sc_play_buf = NULL;
    156 	sc->sc_i2s_handle = aa->i2sa_handle;
    157 	sc->sc_open = false;
    158 
    159 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    160 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
    161 
    162 	s3c2440_i2s_set_intr_lock(aa->i2sa_handle, &sc->sc_intr_lock);
    163 
    164 	/* arch/arm/s3c2xx0/s3c2440.c initializes the I2S subsystem for us */
    165 
    166 	/* Setup GPIO pins to output for L3 communication.
    167 	   GPB3 (L3DATA) will have to be switched to input when reading
    168 	   from the L3 bus.
    169 
    170 	   GPB2 - L3MODE
    171 	   GPB3 - L3DATA
    172 	   GPB4 - L3CLOCK
    173 	   TODO: Make this configurable
    174 	*/
    175 	reg = bus_space_read_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBCON);
    176 	reg = GPIO_SET_FUNC(reg, 2, 1);
    177 	reg = GPIO_SET_FUNC(reg, 3, 1);
    178 	reg = GPIO_SET_FUNC(reg, 4, 1);
    179 	bus_space_write_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBCON, reg);
    180 
    181 	reg = bus_space_read_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT);
    182 	reg = GPIO_SET_DATA(reg, 4, 1);
    183 	reg = GPIO_SET_DATA(reg, 3, 0);
    184 	reg = GPIO_SET_DATA(reg, 2, 1);
    185 	bus_space_write_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT, reg);
    186 
    187 	printf("\n");
    188 
    189 	/* uda1341_attach resets the uda1341 sc, so it has to be called before
    190 	   attributes are set on the sc.*/
    191 	uda1341_attach(&sc->sc_uda1341);
    192 
    193 	/* Configure the UDA1341 Codec */
    194 	sc->sc_uda1341.parent = sc;
    195 	sc->sc_uda1341.sc_l3_write = uda_ssio_l3_write;
    196 	sc->sc_uda1341.sc_bus_format = UDA1341_BUS_MSB;
    197 
    198 	/* Configure I2S controller */
    199 	s3c2440_i2s_set_bus_format(sc->sc_i2s_handle, S3C2440_I2S_BUS_MSB);
    200 	// Attach
    201 	audio_attach_mi(&uda1341_hw_if, &sc->sc_uda1341, self);
    202 }
    203 
    204 int
    205 uda_ssio_open(void *handle, int flags)
    206 {
    207 	struct uda1341_softc *uc = handle;
    208 	struct uda_softc *sc = uc->parent;
    209 	int retval;
    210 
    211 	DPRINTF(("%s\n", __func__));
    212 
    213 	if (sc->sc_open)
    214 		return EBUSY;
    215 
    216 	/* We only support write operations */
    217 	if (!(flags & FREAD) && !(flags & FWRITE))
    218 		return EINVAL;
    219 
    220 	/* We can't do much more at this point than to
    221 	   ask the UDA1341 codec to initialize itself
    222 	   (for an unknown system clock)
    223 	*/
    224 	retval = uda1341_open(handle, flags);
    225 	if (retval != 0) {
    226 		return retval;
    227 	}
    228 
    229 	sc->sc_open = true;
    230 
    231 	return 0; /* SUCCESS */
    232 }
    233 
    234 void
    235 uda_ssio_close(void *handle)
    236 {
    237 	struct uda1341_softc *uc = handle;
    238 	struct uda_softc *sc = uc->parent;
    239 	DPRINTF(("%s\n", __func__));
    240 
    241 	uda1341_close(handle);
    242 	sc->sc_open = false;
    243 }
    244 
    245 int
    246 uda_ssio_set_params(void *handle, int setmode, int usemode,
    247 		    audio_params_t *play, audio_params_t *rec,
    248 		    stream_filter_list_t *pfil, stream_filter_list_t *rfil)
    249 {
    250 	struct uda1341_softc *uc = handle;
    251 	struct uda_softc *sc = uc->parent;
    252 	const struct audio_format *selected_format;
    253 	audio_params_t *params;
    254 	stream_filter_list_t *fil;
    255 	int retval;
    256 
    257 	DPRINTF(("%s: setmode: %d\n", __func__, setmode));
    258 	DPRINTF(("%s: usemode: %d\n", __func__, usemode));
    259 
    260 	if (setmode == 0)
    261 		setmode = usemode;
    262 
    263 	if (setmode & AUMODE_PLAY) {
    264 		params = play;
    265 		fil = pfil;
    266 	} else if (setmode == AUMODE_RECORD) {
    267 		params = rec;
    268 		fil = rfil;
    269 	} else {
    270 		return EINVAL;
    271 	}
    272 
    273 	DPRINTF(("%s: %dHz, encoding: %d, precision: %d, channels: %d\n",
    274 		 __func__, params->sample_rate, params->encoding, play->precision,
    275 		 params->channels));
    276 
    277 	if (params->sample_rate != 8000 &&
    278 	    params->sample_rate != 11025 &&
    279 	    params->sample_rate != 22050 &&
    280 	    params->sample_rate != 32000 &&
    281 	    params->sample_rate != 44100 &&
    282 	    params->sample_rate != 48000) {
    283 		return EINVAL;
    284 	}
    285 
    286 	retval = auconv_set_converter(uda1341_formats, UDA1341_NFORMATS,
    287 				    setmode, params, true, fil);
    288 	if (retval < 0) {
    289 		printf("Could not find valid format\n");
    290 		return EINVAL;
    291 	}
    292 
    293 	selected_format = &uda1341_formats[retval];
    294 
    295 	if (setmode == AUMODE_PLAY) {
    296 		s3c2440_i2s_set_direction(sc->sc_i2s_handle,
    297 					  S3C2440_I2S_TRANSMIT);
    298 	} else {
    299 		s3c2440_i2s_set_direction(sc->sc_i2s_handle,
    300 					  S3C2440_I2S_RECEIVE);
    301 	}
    302 
    303 	s3c2440_i2s_set_sample_rate(sc->sc_i2s_handle, params->sample_rate);
    304 	s3c2440_i2s_set_sample_width(sc->sc_i2s_handle,
    305 				     selected_format->precision);
    306 
    307 	/* It is vital that sc_system_clock is set PRIOR to calling
    308 	   uda1341_set_params. */
    309 	switch (s3c2440_i2s_get_master_clock(sc->sc_i2s_handle)) {
    310 	case 384:
    311 		uc->sc_system_clock = UDA1341_CLOCK_384;
    312 		break;
    313 	case 256:
    314 		uc->sc_system_clock = UDA1341_CLOCK_256;
    315 		break;
    316 	default:
    317 		return EINVAL;
    318 	}
    319 
    320 	retval = uda1341_set_params(handle, setmode, usemode,
    321 				    play, rec, pfil, rfil);
    322 	if (retval != 0) {
    323 		return retval;
    324 	}
    325 
    326 	/* Setup and enable I2S controller */
    327 	retval = s3c2440_i2s_commit(sc->sc_i2s_handle);
    328 	if (retval != 0) {
    329 		printf("Failed to setup I2S controller\n");
    330 		return retval;
    331 	}
    332 
    333 	return 0;
    334 }
    335 
    336 int
    337 uda_ssio_round_blocksize(void *handle, int bs, int mode,
    338 			 const audio_params_t *param)
    339 {
    340 	int out_bs;
    341 	DPRINTF(("%s: %d\n", __func__, bs));
    342 
    343 	out_bs =  (bs + 0x03) & ~0x03;
    344 	DPRINTF(("%s: out_bs: %d\n", __func__, out_bs));
    345 	return out_bs;
    346 }
    347 
    348 int
    349 uda_ssio_start_output(void *handle, void *block, int bsize,
    350 		      void (*intr)(void *), void *intrarg)
    351 {
    352 	struct uda1341_softc *uc = handle;
    353 	struct uda_softc *sc = uc->parent;
    354 
    355 	return s3c2440_i2s_output(sc->sc_play_buf, block, bsize, intr, intrarg);
    356 }
    357 
    358 int
    359 uda_ssio_start_input(void *handle, void *block, int bsize,
    360 		     void (*intr)(void *), void *intrarg)
    361 {
    362 	struct uda1341_softc *uc = handle;
    363 	struct uda_softc *sc = uc->parent;
    364 
    365 	return s3c2440_i2s_input(sc->sc_rec_buf, block, bsize, intr, intrarg);
    366 }
    367 
    368 int
    369 uda_ssio_halt_output(void *handle)
    370 {
    371 	struct uda1341_softc *uc = handle;
    372 	struct uda_softc *sc = uc->parent;
    373 
    374 	return s3c2440_i2s_halt_output(sc->sc_play_buf);
    375 }
    376 
    377 int
    378 uda_ssio_halt_input(void *handle)
    379 {
    380 	DPRINTF(("%s\n", __func__));
    381 	return 0;
    382 }
    383 
    384 int
    385 uda_ssio_getdev(void *handle, struct audio_device *ret)
    386 {
    387 	*ret = uda1341_device;
    388 	return 0;
    389 }
    390 
    391 void *
    392 uda_ssio_allocm(void *handle, int direction, size_t size)
    393 {
    394 	struct uda1341_softc *uc = handle;
    395 	struct uda_softc *sc = uc->parent;
    396 	void *retval = NULL;
    397 
    398 	DPRINTF(("%s\n", __func__));
    399 
    400 	if (direction == AUMODE_PLAY ) {
    401 		if (sc->sc_play_buf != NULL)
    402 			return NULL;
    403 
    404 		s3c2440_i2s_alloc(sc->sc_i2s_handle, direction, size, 0x00, &sc->sc_play_buf);
    405 		DPRINTF(("%s: addr of ring buffer: %p\n", __func__, sc->sc_play_buf->i2b_addr));
    406 		retval = sc->sc_play_buf->i2b_addr;
    407 	} else if (direction == AUMODE_RECORD) {
    408 		if (sc->sc_rec_buf != NULL)
    409 			return NULL;
    410 
    411 		s3c2440_i2s_alloc(sc->sc_i2s_handle, direction, size, 0x00, &sc->sc_rec_buf);
    412 		DPRINTF(("%s: addr of ring buffer: %p\n", __func__, sc->sc_rec_buf->i2b_addr));
    413 		retval = sc->sc_rec_buf->i2b_addr;
    414 	}
    415 
    416 	DPRINTF(("buffer: %p", retval));
    417 
    418 	return retval;
    419 }
    420 
    421 void
    422 uda_ssio_freem(void *handle, void *ptr, size_t size)
    423 {
    424 	struct uda1341_softc *uc = handle;
    425 	struct uda_softc *sc = uc->parent;
    426 	DPRINTF(("%s\n", __func__));
    427 
    428 	if (ptr == sc->sc_play_buf->i2b_addr)
    429 		s3c2440_i2s_free(sc->sc_play_buf);
    430 	else if (ptr == sc->sc_rec_buf->i2b_addr)
    431 		s3c2440_i2s_free(sc->sc_rec_buf);
    432 }
    433 
    434 size_t
    435 uda_ssio_round_buffersize(void *handle, int direction, size_t bufsize)
    436 {
    437 	DPRINTF(("%s: %d\n", __func__, (int)bufsize));
    438 	return bufsize;
    439 }
    440 
    441 int
    442 uda_ssio_getprops(void *handle)
    443 {
    444 	return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE;
    445 }
    446 
    447 void
    448 uda_ssio_get_locks(void *handle, kmutex_t **intr, kmutex_t **thread)
    449 {
    450 	struct uda1341_softc *uc = handle;
    451 	struct uda_softc *sc = uc->parent;
    452 	//struct uda_softc *sc = handle;
    453 
    454 	*intr = &sc->sc_intr_lock;
    455 	*thread = &sc->sc_lock;
    456 }
    457 
    458 void
    459 uda_ssio_l3_write(void *cookie, int mode, int value)
    460 {
    461 	struct s3c2xx0_softc *s3sc = s3c2xx0_softc; /* Shortcut */
    462 	uint32_t reg;
    463 
    464 	/* GPB2: L3MODE
    465 	   GPB3: L2DATA
    466 	   GPB4: L3CLOCK */
    467 #define L3MODE	2
    468 #define L3DATA	3
    469 #define L3CLOCK 4
    470 #define READ_GPIO() bus_space_read_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT)
    471 #define WRITE_GPIO(val) bus_space_write_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT, val)
    472 
    473 #define DELAY_TIME 1
    474 
    475 	reg = READ_GPIO();
    476 	reg = GPIO_SET_DATA(reg, L3CLOCK, 1);
    477 	reg = GPIO_SET_DATA(reg, L3MODE, mode);
    478 	reg = GPIO_SET_DATA(reg, L3DATA, 0);
    479 	WRITE_GPIO(reg);
    480 
    481 	if (mode == 1 ) {
    482 		reg = READ_GPIO();
    483 		reg = GPIO_SET_DATA(reg, L3MODE, 1);
    484 		WRITE_GPIO(reg);
    485 	}
    486 
    487 	DELAY(1); /* L3MODE setup time: min 190ns */
    488 
    489 	for(int i = 0; i<8; i++) {
    490 		char bval = (value >> i) & 0x1;
    491 
    492 		reg = READ_GPIO();
    493 		reg = GPIO_SET_DATA(reg, L3CLOCK, 0);
    494 		reg = GPIO_SET_DATA(reg, L3DATA, bval);
    495 		WRITE_GPIO(reg);
    496 
    497 		DELAY(DELAY_TIME);
    498 
    499 		reg = READ_GPIO();
    500 		reg = GPIO_SET_DATA(reg, L3CLOCK, 1);
    501 		reg = GPIO_SET_DATA(reg, L3DATA, bval);
    502 		WRITE_GPIO(reg);
    503 
    504 		DELAY(DELAY_TIME);
    505 	}
    506 
    507 	reg = READ_GPIO();
    508 	reg = GPIO_SET_DATA(reg, L3MODE, 1);
    509 	reg = GPIO_SET_DATA(reg, L3CLOCK, 1);
    510 	reg = GPIO_SET_DATA(reg, L3DATA, 0);
    511 	WRITE_GPIO(reg);
    512 
    513 #undef L3MODE
    514 #undef L3DATA
    515 #undef L3CLOCK
    516 #undef DELAY_TIME
    517 #undef READ_GPIO
    518 #undef WRITE_GPIO
    519 }
    520