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