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