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