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