Home | History | Annotate | Line # | Download | only in mini2440
audio_mini2440.c revision 1.4.4.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/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 
     71 int	uda_ssio_open(void *, int);
     72 void	uda_ssio_close(void *);
     73 int	uda_ssio_query_format(void *, audio_format_query_t *);
     74 int	uda_ssio_set_format(void *, int,
     75 		       const audio_params_t *, const audio_params_t *,
     76 		       audio_filter_reg_t *, audio_filter_reg_t *);
     77 int	uda_ssio_start_output(void *, void *, int, void (*)(void *),
     78 			      void *);
     79 int	uda_ssio_start_input(void *, void *, int, void (*)(void *),
     80 			      void *);
     81 int	uda_ssio_halt_output(void *);
     82 int	uda_ssio_halt_input(void *);
     83 int	uda_ssio_getdev(void *, struct audio_device *ret);
     84 void*	uda_ssio_allocm(void *, int, size_t);
     85 void	uda_ssio_freem(void *, void *, size_t);
     86 size_t	uda_ssio_round_buffersize(void *, int, size_t);
     87 int	uda_ssio_get_props(void *);
     88 void	uda_ssio_get_locks(void *, kmutex_t**, kmutex_t**);
     89 
     90 struct audio_hw_if uda1341_hw_if = {
     91 	.open			= uda_ssio_open,
     92 	.close			= uda_ssio_close,
     93 	.query_format		= uda_ssio_query_format,
     94 	.set_format		= uda_ssio_set_format,
     95 	.start_output		= uda_ssio_start_output,
     96 	.start_input		= uda_ssio_start_input,
     97 	.halt_output		= uda_ssio_halt_output,
     98 	.halt_input		= uda_ssio_halt_input,
     99 	.getdev			= uda_ssio_getdev,
    100 	.set_port		= uda1341_set_port,
    101 	.get_port		= uda1341_get_port,
    102 	.query_devinfo		= uda1341_query_devinfo,
    103 	.allocm			= uda_ssio_allocm,
    104 	.freem			= uda_ssio_freem,
    105 	.round_buffersize	= uda_ssio_round_buffersize,
    106 	.get_props		= uda_ssio_get_props,
    107 	.get_locks		= uda_ssio_get_locks
    108 };
    109 
    110 static struct audio_device uda1341_device = {
    111 	"MINI2240-UDA1341",
    112 	"0.1",
    113 	"uda_ssio"
    114 };
    115 
    116 static const struct audio_format uda_ssio_formats[] =
    117 {
    118 	{
    119 		.mode		= AUMODE_PLAY | AUMODE_RECORD,
    120 		.encoding	= AUDIO_ENCODING_SLINEAR_LE,
    121 		.validbits	= 16,
    122 		.precision	= 16,
    123 		.channels	= 2,
    124 		.channel_mask	= AUFMT_STEREO,
    125 		.frequency_type	= 6,
    126 		.frequency	= { 8000, 11025, 22050, 32000, 44100, 48000 },
    127 	}
    128 };
    129 #define UDA_SSIO_NFORMATS __arraycount(uda_ssio_formats)
    130 
    131 void uda_ssio_l3_write(void *,int mode, int value);
    132 
    133 int uda_ssio_match(device_t, cfdata_t, void*);
    134 void uda_ssio_attach(device_t, device_t, void*);
    135 
    136 CFATTACH_DECL_NEW(udassio, sizeof(struct uda_softc),
    137 	      uda_ssio_match, uda_ssio_attach, NULL, NULL);
    138 
    139 int
    140 uda_ssio_match(device_t parent, cfdata_t match, void *aux)
    141 {
    142 	DPRINTF(("%s\n", __func__));
    143 	/* Not quite sure how we can detect the UDA1341 chip */
    144 	return 1;
    145 }
    146 
    147 void
    148 uda_ssio_attach(device_t parent, device_t self, void *aux)
    149 {
    150 	/*	struct s3c2xx0_attach_args *sa = aux;*/
    151 	struct uda_softc *sc = device_private(self);
    152 	struct s3c2xx0_softc *s3sc = s3c2xx0_softc; /* Shortcut */
    153 	struct s3c2440_i2s_attach_args *aa = aux;
    154 	uint32_t reg;
    155 
    156 	sc->sc_dev = self;
    157 
    158 	sc->sc_play_buf = NULL;
    159 	sc->sc_i2s_handle = aa->i2sa_handle;
    160 
    161 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    162 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
    163 
    164 	s3c2440_i2s_set_intr_lock(aa->i2sa_handle, &sc->sc_intr_lock);
    165 
    166 	/* arch/arm/s3c2xx0/s3c2440.c initializes the I2S subsystem for us */
    167 
    168 	/* Setup GPIO pins to output for L3 communication.
    169 	   GPB3 (L3DATA) will have to be switched to input when reading
    170 	   from the L3 bus.
    171 
    172 	   GPB2 - L3MODE
    173 	   GPB3 - L3DATA
    174 	   GPB4 - L3CLOCK
    175 	   TODO: Make this configurable
    176 	*/
    177 	reg = bus_space_read_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBCON);
    178 	reg = GPIO_SET_FUNC(reg, 2, 1);
    179 	reg = GPIO_SET_FUNC(reg, 3, 1);
    180 	reg = GPIO_SET_FUNC(reg, 4, 1);
    181 	bus_space_write_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBCON, reg);
    182 
    183 	reg = bus_space_read_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT);
    184 	reg = GPIO_SET_DATA(reg, 4, 1);
    185 	reg = GPIO_SET_DATA(reg, 3, 0);
    186 	reg = GPIO_SET_DATA(reg, 2, 1);
    187 	bus_space_write_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT, reg);
    188 
    189 	printf("\n");
    190 
    191 	/* uda1341_attach resets the uda1341 sc, so it has to be called before
    192 	   attributes are set on the sc.*/
    193 	uda1341_attach(&sc->sc_uda1341);
    194 
    195 	/* Configure the UDA1341 Codec */
    196 	sc->sc_uda1341.parent = sc;
    197 	sc->sc_uda1341.sc_l3_write = uda_ssio_l3_write;
    198 	sc->sc_uda1341.sc_bus_format = UDA1341_BUS_MSB;
    199 
    200 	/* Configure I2S controller */
    201 	s3c2440_i2s_set_bus_format(sc->sc_i2s_handle, S3C2440_I2S_BUS_MSB);
    202 	// Attach
    203 	audio_attach_mi(&uda1341_hw_if, &sc->sc_uda1341, self);
    204 }
    205 
    206 int
    207 uda_ssio_open(void *handle, int flags)
    208 {
    209 	int retval;
    210 
    211 	DPRINTF(("%s\n", __func__));
    212 
    213 	/* We only support write operations */
    214 	if (!(flags & FREAD) && !(flags & FWRITE))
    215 		return EINVAL;
    216 
    217 	/* We can't do much more at this point than to
    218 	   ask the UDA1341 codec to initialize itself
    219 	   (for an unknown system clock)
    220 	*/
    221 	retval = uda1341_open(handle, flags);
    222 	if (retval != 0) {
    223 		return retval;
    224 	}
    225 
    226 	return 0; /* SUCCESS */
    227 }
    228 
    229 void
    230 uda_ssio_close(void *handle)
    231 {
    232 
    233 	DPRINTF(("%s\n", __func__));
    234 
    235 	uda1341_close(handle);
    236 }
    237 
    238 int
    239 uda_ssio_query_format(void *handle, audio_format_query_t *afp)
    240 {
    241 
    242 	return audio_query_format(uda_ssio_formats, UDA_SSIO_NFORMATS, afp);
    243 }
    244 
    245 int
    246 uda_ssio_set_format(void *handle, int setmode,
    247 		    const audio_params_t *play, const audio_params_t *rec,
    248 		    audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
    249 {
    250 	struct uda1341_softc *uc = handle;
    251 	struct uda_softc *sc = uc->parent;
    252 	int retval;
    253 
    254 	DPRINTF(("%s: setmode: %d\n", __func__, setmode));
    255 
    256 	/* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */
    257 
    258 	DPRINTF(("%s: %dHz, encoding: %d, precision: %d, channels: %d\n",
    259 		 __func__, play->sample_rate, play->encoding, play->precision,
    260 		 play->channels));
    261 
    262 	if (setmode == AUMODE_PLAY) {
    263 		s3c2440_i2s_set_direction(sc->sc_i2s_handle,
    264 					  S3C2440_I2S_TRANSMIT);
    265 	} else {
    266 		s3c2440_i2s_set_direction(sc->sc_i2s_handle,
    267 					  S3C2440_I2S_RECEIVE);
    268 	}
    269 
    270 	s3c2440_i2s_set_sample_rate(sc->sc_i2s_handle, play->sample_rate);
    271 	s3c2440_i2s_set_sample_width(sc->sc_i2s_handle, 16);
    272 
    273 	/* It is vital that sc_system_clock is set PRIOR to calling
    274 	   uda1341_set_format. */
    275 	switch (s3c2440_i2s_get_master_clock(sc->sc_i2s_handle)) {
    276 	case 384:
    277 		uc->sc_system_clock = UDA1341_CLOCK_384;
    278 		break;
    279 	case 256:
    280 		uc->sc_system_clock = UDA1341_CLOCK_256;
    281 		break;
    282 	default:
    283 		return EINVAL;
    284 	}
    285 
    286 	retval = uda1341_set_format(handle, setmode, play, rec, pfil, rfil);
    287 	if (retval != 0) {
    288 		return retval;
    289 	}
    290 
    291 	/* Setup and enable I2S controller */
    292 	retval = s3c2440_i2s_commit(sc->sc_i2s_handle);
    293 	if (retval != 0) {
    294 		printf("Failed to setup I2S controller\n");
    295 		return retval;
    296 	}
    297 
    298 	return 0;
    299 }
    300 
    301 int
    302 uda_ssio_start_output(void *handle, void *block, int bsize,
    303 		      void (*intr)(void *), void *intrarg)
    304 {
    305 	struct uda1341_softc *uc = handle;
    306 	struct uda_softc *sc = uc->parent;
    307 
    308 	return s3c2440_i2s_output(sc->sc_play_buf, block, bsize, intr, intrarg);
    309 }
    310 
    311 int
    312 uda_ssio_start_input(void *handle, void *block, int bsize,
    313 		     void (*intr)(void *), void *intrarg)
    314 {
    315 	struct uda1341_softc *uc = handle;
    316 	struct uda_softc *sc = uc->parent;
    317 
    318 	return s3c2440_i2s_input(sc->sc_rec_buf, block, bsize, intr, intrarg);
    319 }
    320 
    321 int
    322 uda_ssio_halt_output(void *handle)
    323 {
    324 	struct uda1341_softc *uc = handle;
    325 	struct uda_softc *sc = uc->parent;
    326 
    327 	return s3c2440_i2s_halt_output(sc->sc_play_buf);
    328 }
    329 
    330 int
    331 uda_ssio_halt_input(void *handle)
    332 {
    333 	DPRINTF(("%s\n", __func__));
    334 	return 0;
    335 }
    336 
    337 int
    338 uda_ssio_getdev(void *handle, struct audio_device *ret)
    339 {
    340 	*ret = uda1341_device;
    341 	return 0;
    342 }
    343 
    344 void *
    345 uda_ssio_allocm(void *handle, int direction, size_t size)
    346 {
    347 	struct uda1341_softc *uc = handle;
    348 	struct uda_softc *sc = uc->parent;
    349 	void *retval = NULL;
    350 
    351 	DPRINTF(("%s\n", __func__));
    352 
    353 	if (direction == AUMODE_PLAY ) {
    354 		if (sc->sc_play_buf != NULL)
    355 			return NULL;
    356 
    357 		s3c2440_i2s_alloc(sc->sc_i2s_handle, direction, size, 0x00, &sc->sc_play_buf);
    358 		DPRINTF(("%s: addr of ring buffer: %p\n", __func__, sc->sc_play_buf->i2b_addr));
    359 		retval = sc->sc_play_buf->i2b_addr;
    360 	} else if (direction == AUMODE_RECORD) {
    361 		if (sc->sc_rec_buf != NULL)
    362 			return NULL;
    363 
    364 		s3c2440_i2s_alloc(sc->sc_i2s_handle, direction, size, 0x00, &sc->sc_rec_buf);
    365 		DPRINTF(("%s: addr of ring buffer: %p\n", __func__, sc->sc_rec_buf->i2b_addr));
    366 		retval = sc->sc_rec_buf->i2b_addr;
    367 	}
    368 
    369 	DPRINTF(("buffer: %p", retval));
    370 
    371 	return retval;
    372 }
    373 
    374 void
    375 uda_ssio_freem(void *handle, void *ptr, size_t size)
    376 {
    377 	struct uda1341_softc *uc = handle;
    378 	struct uda_softc *sc = uc->parent;
    379 	DPRINTF(("%s\n", __func__));
    380 
    381 	if (ptr == sc->sc_play_buf->i2b_addr)
    382 		s3c2440_i2s_free(sc->sc_play_buf);
    383 	else if (ptr == sc->sc_rec_buf->i2b_addr)
    384 		s3c2440_i2s_free(sc->sc_rec_buf);
    385 }
    386 
    387 size_t
    388 uda_ssio_round_buffersize(void *handle, int direction, size_t bufsize)
    389 {
    390 	DPRINTF(("%s: %d\n", __func__, (int)bufsize));
    391 	return bufsize;
    392 }
    393 
    394 int
    395 uda_ssio_get_props(void *handle)
    396 {
    397 	return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE;
    398 }
    399 
    400 void
    401 uda_ssio_get_locks(void *handle, kmutex_t **intr, kmutex_t **thread)
    402 {
    403 	struct uda1341_softc *uc = handle;
    404 	struct uda_softc *sc = uc->parent;
    405 	//struct uda_softc *sc = handle;
    406 
    407 	*intr = &sc->sc_intr_lock;
    408 	*thread = &sc->sc_lock;
    409 }
    410 
    411 void
    412 uda_ssio_l3_write(void *cookie, int mode, int value)
    413 {
    414 	struct s3c2xx0_softc *s3sc = s3c2xx0_softc; /* Shortcut */
    415 	uint32_t reg;
    416 
    417 	/* GPB2: L3MODE
    418 	   GPB3: L2DATA
    419 	   GPB4: L3CLOCK */
    420 #define L3MODE	2
    421 #define L3DATA	3
    422 #define L3CLOCK 4
    423 #define READ_GPIO() bus_space_read_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT)
    424 #define WRITE_GPIO(val) bus_space_write_4(s3sc->sc_iot, s3sc->sc_gpio_ioh, GPIO_PBDAT, val)
    425 
    426 #define DELAY_TIME 1
    427 
    428 	reg = READ_GPIO();
    429 	reg = GPIO_SET_DATA(reg, L3CLOCK, 1);
    430 	reg = GPIO_SET_DATA(reg, L3MODE, mode);
    431 	reg = GPIO_SET_DATA(reg, L3DATA, 0);
    432 	WRITE_GPIO(reg);
    433 
    434 	if (mode == 1 ) {
    435 		reg = READ_GPIO();
    436 		reg = GPIO_SET_DATA(reg, L3MODE, 1);
    437 		WRITE_GPIO(reg);
    438 	}
    439 
    440 	DELAY(1); /* L3MODE setup time: min 190ns */
    441 
    442 	for(int i = 0; i<8; i++) {
    443 		char bval = (value >> i) & 0x1;
    444 
    445 		reg = READ_GPIO();
    446 		reg = GPIO_SET_DATA(reg, L3CLOCK, 0);
    447 		reg = GPIO_SET_DATA(reg, L3DATA, bval);
    448 		WRITE_GPIO(reg);
    449 
    450 		DELAY(DELAY_TIME);
    451 
    452 		reg = READ_GPIO();
    453 		reg = GPIO_SET_DATA(reg, L3CLOCK, 1);
    454 		reg = GPIO_SET_DATA(reg, L3DATA, bval);
    455 		WRITE_GPIO(reg);
    456 
    457 		DELAY(DELAY_TIME);
    458 	}
    459 
    460 	reg = READ_GPIO();
    461 	reg = GPIO_SET_DATA(reg, L3MODE, 1);
    462 	reg = GPIO_SET_DATA(reg, L3CLOCK, 1);
    463 	reg = GPIO_SET_DATA(reg, L3DATA, 0);
    464 	WRITE_GPIO(reg);
    465 
    466 #undef L3MODE
    467 #undef L3DATA
    468 #undef L3CLOCK
    469 #undef DELAY_TIME
    470 #undef READ_GPIO
    471 #undef WRITE_GPIO
    472 }
    473