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