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