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