xref: /netbsd-src/sys/arch/evbarm/mini2440/audio_mini2440.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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/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