1/* $NetBSD: es8316ac.c,v 1.6 2023/12/11 13:27:24 mlelstv Exp $ */ 2 3/*- 4 * Copyright (c) 2020 Jared McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: es8316ac.c,v 1.6 2023/12/11 13:27:24 mlelstv Exp $"); 31 32#include <sys/param.h> 33#include <sys/bus.h> 34#include <sys/device.h> 35#include <sys/intr.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38#include <sys/conf.h> 39#include <sys/bitops.h> 40 41#include <dev/audio/audio_dai.h> 42 43#include <dev/i2c/i2cvar.h> 44 45#include <dev/fdt/fdtvar.h> 46 47#define ESCODEC_RESET_REG 0x00 48#define RESET_ALL __BITS(5,0) 49#define RESET_CSM_ON __BIT(7) 50#define ESCODEC_CLKMAN1_REG 0x01 51#define CLKMAN1_MCLK_ON __BIT(6) 52#define CLKMAN1_BCLK_ON __BIT(5) 53#define CLKMAN1_CLK_CP_ON __BIT(4) 54#define CLKMAN1_CLK_DAC_ON __BIT(2) 55#define CLKMAN1_ANACLK_DAC_ON __BIT(0) 56#define ESCODEC_ADC_OSR_REG 0x03 57#define ESCODEC_SD_CLK_REG 0x09 58#define SD_CLK_MSC __BIT(7) 59#define SD_CLK_BCLK_INV __BIT(5) 60#define ESCODEC_SD_ADC_REG 0x0a 61#define ESCODEC_SD_DAC_REG 0x0b 62#define SD_FMT_LRP __BIT(5) 63#define SD_FMT_WL __BITS(4,2) 64#define SD_FMT_WL_16 3 65#define SD_FMT_MASK __BITS(1,0) 66#define SD_FMT_I2S 0 67#define ESCODEC_VMID_REG 0x0c 68#define ESCODEC_PDN_REG 0x0d 69#define ESCODEC_HPSEL_REG 0x13 70#define ESCODEC_HPMIXRT_REG 0x14 71#define HPMIXRT_LD2LHPMIX __BIT(7) 72#define HPMIXRT_RD2RHPMIX __BIT(3) 73#define ESCODEC_HPMIX_REG 0x15 74#define HPMIX_LHPMIX_MUTE __BIT(5) 75#define HPMIX_PDN_LHP_MIX __BIT(4) 76#define HPMIX_RHPMIX_MUTE __BIT(1) 77#define HPMIX_PDN_RHP_MIX __BIT(0) 78#define ESCODEC_HPMIXVOL_REG 0x16 79#define HPMIXVOL_LHPMIXVOL __BITS(7,4) 80#define HPMIXVOL_RHPMIXVOL __BITS(3,0) 81#define ESCODEC_HPOUTEN_REG 0x17 82#define HPOUTEN_EN_HPL __BIT(6) 83#define HPOUTEN_HPL_OUTEN __BIT(5) 84#define HPOUTEN_EN_HPR __BIT(2) 85#define HPOUTEN_HPR_OUTEN __BIT(1) 86#define ESCODEC_HPVOL_REG 0x18 87#define HPVOL_PDN_LICAL __BIT(7) 88#define HPVOL_HPLVOL __BITS(5,4) 89#define HPVOL_PDN_RICAL __BIT(3) 90#define HPVOL_HPRVOL __BITS(1,0) 91#define ESCODEC_HPPWR_REG 0x19 92#define HPPWR_PDN_CPHP __BIT(2) 93#define ESCODEC_CPPWR_REG 0x1a 94#define CPPWR_PDN_CP __BIT(5) 95#define ESCODEC_DACPWR_REG 0x2f 96#define DACPWR_PDN_DAC_L __BIT(4) 97#define DACPWR_PDN_DAC_R __BIT(0) 98#define ESCODEC_DACCTL1_REG 0x30 99#define DACCTL1_MUTE __BIT(5) 100#define ESCODEC_DACVOL_L_REG 0x33 101#define DACVOL_L_DACVOLUME __BITS(7,0) 102#define ESCODEC_DACVOL_R_REG 0x34 103#define DACVOL_R_DACVOLUME __BITS(7,0) 104 105static const struct device_compatible_entry compat_data[] = { 106 { .compat = "everest,es8316" }, 107 DEVICE_COMPAT_EOL 108}; 109 110struct escodec_softc { 111 device_t sc_dev; 112 i2c_tag_t sc_i2c; 113 i2c_addr_t sc_addr; 114 int sc_phandle; 115 struct clk *sc_clk; 116 117 struct audio_dai_device sc_dai; 118 audio_dai_tag_t sc_amplifier; 119 120 uint8_t sc_swvol; 121}; 122 123static void 124escodec_lock(struct escodec_softc *sc) 125{ 126 iic_acquire_bus(sc->sc_i2c, 0); 127} 128 129static void 130escodec_unlock(struct escodec_softc *sc) 131{ 132 iic_release_bus(sc->sc_i2c, 0); 133} 134 135static uint8_t 136escodec_read(struct escodec_softc *sc, uint8_t reg) 137{ 138 uint8_t val; 139 140 if (iic_smbus_read_byte(sc->sc_i2c, sc->sc_addr, reg, &val, 0) != 0) 141 val = 0xff; 142 143 return val; 144} 145 146static void 147escodec_write(struct escodec_softc *sc, uint8_t reg, uint8_t val) 148{ 149 (void)iic_smbus_write_byte(sc->sc_i2c, sc->sc_addr, reg, val, 0); 150} 151 152enum escodec_mixer_ctrl { 153 ESCODEC_OUTPUT_CLASS, 154 ESCODEC_INPUT_CLASS, 155 ESCODEC_OUTPUT_MASTER, 156 ESCODEC_INPUT_DAC, 157 ESCODEC_INPUT_DAC_MUTE, 158 ESCODEC_INPUT_HEADPHONE, 159 ESCODEC_INPUT_MIXEROUT, 160 ESCODEC_INPUT_MIXEROUT_MUTE, 161 162 ESCODEC_MIXER_CTRL_LAST 163}; 164 165enum escodec_mixer_type { 166 ESCODEC_MIXER_CLASS, 167 ESCODEC_MIXER_SWVOL, 168 ESCODEC_MIXER_AMPLIFIER, 169 ESCODEC_MIXER_ATTENUATOR, 170 ESCODEC_MIXER_MUTE, 171}; 172 173static const struct escodec_mixer { 174 const char * name; 175 int mixer_class; 176 int prev, next; 177 enum escodec_mixer_ctrl ctrl; 178 enum escodec_mixer_type type; 179 u_int reg[2]; 180 uint8_t mask[2]; 181 uint8_t maxval; 182} escodec_mixers[ESCODEC_MIXER_CTRL_LAST] = { 183 /* 184 * Mixer classes 185 */ 186 [ESCODEC_OUTPUT_CLASS] = { 187 .name = AudioCoutputs, 188 .type = ESCODEC_MIXER_CLASS, 189 }, 190 [ESCODEC_INPUT_CLASS] = { 191 .name = AudioCinputs, 192 .type = ESCODEC_MIXER_CLASS, 193 }, 194 195 /* 196 * Software master volume 197 */ 198 [ESCODEC_OUTPUT_MASTER] = { 199 .name = AudioNmaster, 200 .mixer_class = ESCODEC_OUTPUT_CLASS, 201 .prev = AUDIO_MIXER_LAST, 202 .next = AUDIO_MIXER_LAST, 203 .type = ESCODEC_MIXER_SWVOL, 204 }, 205 206 /* 207 * Stereo DAC 208 */ 209 [ESCODEC_INPUT_DAC] = { 210 .name = AudioNdac, 211 .mixer_class = ESCODEC_INPUT_CLASS, 212 .prev = AUDIO_MIXER_LAST, 213 .next = ESCODEC_INPUT_DAC_MUTE, 214 .type = ESCODEC_MIXER_ATTENUATOR, 215 .reg = { 216 [AUDIO_MIXER_LEVEL_LEFT] = ESCODEC_DACVOL_L_REG, 217 [AUDIO_MIXER_LEVEL_RIGHT] = ESCODEC_DACVOL_R_REG, 218 }, 219 .mask = { 220 [AUDIO_MIXER_LEVEL_LEFT] = DACVOL_L_DACVOLUME, 221 [AUDIO_MIXER_LEVEL_RIGHT] = DACVOL_R_DACVOLUME, 222 }, 223 .maxval = 0xc0, 224 }, 225 [ESCODEC_INPUT_DAC_MUTE] = { 226 .name = AudioNmute, 227 .mixer_class = ESCODEC_INPUT_CLASS, 228 .prev = ESCODEC_INPUT_DAC, 229 .next = AUDIO_MIXER_LAST, 230 .type = ESCODEC_MIXER_MUTE, 231 .reg = { 232 [AUDIO_MIXER_LEVEL_MONO] = ESCODEC_DACCTL1_REG, 233 }, 234 .mask = { 235 [AUDIO_MIXER_LEVEL_MONO] = DACCTL1_MUTE, 236 } 237 }, 238 239 /* 240 * Charge Pump Headphones 241 */ 242 [ESCODEC_INPUT_HEADPHONE] = { 243 .name = AudioNheadphone, 244 .mixer_class = ESCODEC_INPUT_CLASS, 245 .prev = AUDIO_MIXER_LAST, 246 .next = AUDIO_MIXER_LAST, 247 .type = ESCODEC_MIXER_ATTENUATOR, 248 .reg = { 249 [AUDIO_MIXER_LEVEL_LEFT] = ESCODEC_HPVOL_REG, 250 [AUDIO_MIXER_LEVEL_RIGHT] = ESCODEC_HPVOL_REG, 251 }, 252 .mask = { 253 [AUDIO_MIXER_LEVEL_LEFT] = HPVOL_HPLVOL, 254 [AUDIO_MIXER_LEVEL_RIGHT] = HPVOL_HPRVOL, 255 } 256 }, 257 258 /* 259 * Headphone mixer 260 */ 261 [ESCODEC_INPUT_MIXEROUT] = { 262 .name = AudioNmixerout, 263 .mixer_class = ESCODEC_INPUT_CLASS, 264 .prev = AUDIO_MIXER_LAST, 265 .next = ESCODEC_INPUT_MIXEROUT_MUTE, 266 .type = ESCODEC_MIXER_AMPLIFIER, 267 .reg = { 268 [AUDIO_MIXER_LEVEL_LEFT] = ESCODEC_HPMIXVOL_REG, 269 [AUDIO_MIXER_LEVEL_RIGHT] = ESCODEC_HPMIXVOL_REG, 270 }, 271 .mask = { 272 [AUDIO_MIXER_LEVEL_LEFT] = HPMIXVOL_LHPMIXVOL, 273 [AUDIO_MIXER_LEVEL_RIGHT] = HPMIXVOL_RHPMIXVOL 274 }, 275 /* 276 * Datasheet says this field goes up to 0xb, but values 277 * above 0x4 result in noisy output in practice. 278 */ 279 .maxval = 0x4, 280 }, 281 [ESCODEC_INPUT_MIXEROUT_MUTE] = { 282 .name = AudioNmute, 283 .mixer_class = ESCODEC_INPUT_CLASS, 284 .prev = ESCODEC_INPUT_MIXEROUT, 285 .next = AUDIO_MIXER_LAST, 286 .type = ESCODEC_MIXER_MUTE, 287 .reg = { 288 [AUDIO_MIXER_LEVEL_MONO] = ESCODEC_HPMIX_REG, 289 }, 290 .mask = { 291 [AUDIO_MIXER_LEVEL_MONO] = HPMIX_LHPMIX_MUTE | HPMIX_RHPMIX_MUTE, 292 } 293 }, 294}; 295 296static void 297escodec_swvol_codec(audio_filter_arg_t *arg) 298{ 299 struct escodec_softc * const sc = arg->context; 300 const aint_t *src; 301 int16_t *dst; 302 u_int sample_count; 303 u_int i; 304 305 src = arg->src; 306 dst = arg->dst; 307 sample_count = arg->count * arg->srcfmt->channels; 308 for (i = 0; i < sample_count; i++) { 309 aint2_t v = (aint2_t)(*src++); 310 v = v * sc->sc_swvol / 255; 311 *dst++ = (aint_t)v; 312 } 313} 314 315static const struct escodec_mixer * 316escodec_get_mixer(u_int index) 317{ 318 if (index >= ESCODEC_MIXER_CTRL_LAST) 319 return NULL; 320 321 return &escodec_mixers[index]; 322} 323 324static int 325escodec_set_format(void *priv, int setmode, 326 const audio_params_t *play, const audio_params_t *rec, 327 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 328{ 329 struct escodec_softc * const sc = priv; 330 331 pfil->codec = escodec_swvol_codec; 332 pfil->context = sc; 333 334 return 0; 335} 336 337static int 338escodec_set_port(void *priv, mixer_ctrl_t *mc) 339{ 340 struct escodec_softc * const sc = priv; 341 const struct escodec_mixer *mix; 342 int nvol, shift, ch; 343 uint8_t val; 344 345 if ((mix = escodec_get_mixer(mc->dev)) == NULL) 346 return ENXIO; 347 348 switch (mix->type) { 349 case ESCODEC_MIXER_SWVOL: 350 sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 351 return 0; 352 353 case ESCODEC_MIXER_AMPLIFIER: 354 case ESCODEC_MIXER_ATTENUATOR: 355 escodec_lock(sc); 356 for (ch = 0; ch < 2; ch++) { 357 val = escodec_read(sc, mix->reg[ch]); 358 shift = 8 - fls32(__SHIFTOUT_MASK(mix->mask[ch])); 359 nvol = mc->un.value.level[ch] >> shift; 360 if (mix->type == ESCODEC_MIXER_ATTENUATOR) 361 nvol = __SHIFTOUT_MASK(mix->mask[ch]) - nvol; 362 if (mix->maxval != 0 && nvol > mix->maxval) 363 nvol = mix->maxval; 364 365 val &= ~mix->mask[ch]; 366 val |= __SHIFTIN(nvol, mix->mask[ch]); 367 escodec_write(sc, mix->reg[ch], val); 368 } 369 escodec_unlock(sc); 370 return 0; 371 372 case ESCODEC_MIXER_MUTE: 373 if (mc->un.ord < 0 || mc->un.ord > 1) 374 return EINVAL; 375 escodec_lock(sc); 376 val = escodec_read(sc, mix->reg[0]); 377 if (mc->un.ord) 378 val |= mix->mask[0]; 379 else 380 val &= ~mix->mask[0]; 381 escodec_write(sc, mix->reg[0], val); 382 escodec_unlock(sc); 383 return 0; 384 385 default: 386 return ENXIO; 387 } 388} 389 390static int 391escodec_get_port(void *priv, mixer_ctrl_t *mc) 392{ 393 struct escodec_softc * const sc = priv; 394 const struct escodec_mixer *mix; 395 int nvol, shift, ch; 396 uint8_t val; 397 398 if ((mix = escodec_get_mixer(mc->dev)) == NULL) 399 return ENXIO; 400 401 switch (mix->type) { 402 case ESCODEC_MIXER_SWVOL: 403 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_swvol; 404 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = sc->sc_swvol; 405 return 0; 406 407 case ESCODEC_MIXER_AMPLIFIER: 408 case ESCODEC_MIXER_ATTENUATOR: 409 escodec_lock(sc); 410 for (ch = 0; ch < 2; ch++) { 411 val = escodec_read(sc, mix->reg[ch]); 412 shift = 8 - fls32(__SHIFTOUT_MASK(mix->mask[ch])); 413 nvol = __SHIFTOUT(val, mix->mask[ch]); 414 if (mix->type == ESCODEC_MIXER_ATTENUATOR) 415 nvol = __SHIFTOUT_MASK(mix->mask[ch]) - nvol; 416 nvol <<= shift; 417 mc->un.value.level[ch] = nvol; 418 } 419 escodec_unlock(sc); 420 return 0; 421 422 case ESCODEC_MIXER_MUTE: 423 escodec_lock(sc); 424 val = escodec_read(sc, mix->reg[0]); 425 mc->un.ord = (val & mix->mask[0]) != 0; 426 escodec_unlock(sc); 427 return 0; 428 429 default: 430 return ENXIO; 431 } 432} 433 434static int 435escodec_query_devinfo(void *priv, mixer_devinfo_t *di) 436{ 437 const struct escodec_mixer *mix; 438 439 if ((mix = escodec_get_mixer(di->index)) == NULL) 440 return ENXIO; 441 442 strcpy(di->label.name, mix->name); 443 di->mixer_class = mix->mixer_class; 444 di->next = mix->next; 445 di->prev = mix->prev; 446 447 switch (mix->type) { 448 case ESCODEC_MIXER_CLASS: 449 di->type = AUDIO_MIXER_CLASS; 450 return 0; 451 452 case ESCODEC_MIXER_SWVOL: 453 di->type = AUDIO_MIXER_VALUE; 454 di->un.v.delta = 1; 455 di->un.v.num_channels = 2; 456 strcpy(di->un.v.units.name, AudioNvolume); 457 return 0; 458 459 case ESCODEC_MIXER_AMPLIFIER: 460 case ESCODEC_MIXER_ATTENUATOR: 461 di->type = AUDIO_MIXER_VALUE; 462 di->un.v.delta = 463 256 / (__SHIFTOUT_MASK(mix->mask[0]) + 1); 464 di->un.v.num_channels = 2; 465 strcpy(di->un.v.units.name, AudioNvolume); 466 return 0; 467 468 case ESCODEC_MIXER_MUTE: 469 di->type = AUDIO_MIXER_ENUM; 470 di->un.e.num_mem = 2; 471 strcpy(di->un.e.member[0].label.name, AudioNoff); 472 di->un.e.member[0].ord = 0; 473 strcpy(di->un.e.member[1].label.name, AudioNon); 474 di->un.e.member[1].ord = 1; 475 return 0; 476 477 default: 478 return ENXIO; 479 } 480} 481 482static const struct audio_hw_if escodec_hw_if = { 483 .set_format = escodec_set_format, 484 .set_port = escodec_set_port, 485 .get_port = escodec_get_port, 486 .query_devinfo = escodec_query_devinfo, 487}; 488 489static int 490escodec_dai_set_sysclk(audio_dai_tag_t dai, u_int rate, int dir) 491{ 492 struct escodec_softc * const sc = audio_dai_private(dai); 493 int error; 494 495 error = clk_set_rate(sc->sc_clk, rate); 496 if (error != 0) 497 return error; 498 499 return 0; 500} 501 502static int 503escodec_dai_set_format(audio_dai_tag_t dai, u_int format) 504{ 505 struct escodec_softc * const sc = audio_dai_private(dai); 506 uint8_t sd_clk, sd_fmt, val; 507 508 const u_int fmt = __SHIFTOUT(format, AUDIO_DAI_FORMAT_MASK); 509 const u_int clk = __SHIFTOUT(format, AUDIO_DAI_CLOCK_MASK); 510 const u_int pol = __SHIFTOUT(format, AUDIO_DAI_POLARITY_MASK); 511 512 if (fmt != AUDIO_DAI_FORMAT_I2S) 513 return EINVAL; 514 515 if (clk != AUDIO_DAI_CLOCK_CBS_CFS) 516 return EINVAL; 517 518 switch (pol) { 519 case AUDIO_DAI_POLARITY_NB_NF: 520 sd_clk = 0; 521 sd_fmt = 0; 522 break; 523 case AUDIO_DAI_POLARITY_NB_IF: 524 sd_clk = 0; 525 sd_fmt = SD_FMT_LRP; 526 break; 527 case AUDIO_DAI_POLARITY_IB_NF: 528 sd_clk = SD_CLK_BCLK_INV; 529 sd_fmt = 0; 530 break; 531 case AUDIO_DAI_POLARITY_IB_IF: 532 sd_clk = SD_CLK_BCLK_INV; 533 sd_fmt = SD_FMT_LRP; 534 break; 535 } 536 537 escodec_lock(sc); 538 539 val = escodec_read(sc, ESCODEC_SD_CLK_REG); 540 val &= ~(SD_CLK_MSC|SD_CLK_BCLK_INV); 541 val |= sd_clk; 542 escodec_write(sc, ESCODEC_SD_CLK_REG, val); 543 544 val = escodec_read(sc, ESCODEC_SD_ADC_REG); 545 val &= ~SD_FMT_MASK; 546 val |= __SHIFTIN(SD_FMT_I2S, SD_FMT_MASK); 547 val &= ~SD_FMT_LRP; 548 val |= sd_fmt; 549 escodec_write(sc, ESCODEC_SD_ADC_REG, val); 550 551 val = escodec_read(sc, ESCODEC_SD_DAC_REG); 552 val &= ~SD_FMT_MASK; 553 val |= __SHIFTIN(SD_FMT_I2S, SD_FMT_MASK); 554 val &= ~SD_FMT_LRP; 555 val |= sd_fmt; 556 escodec_write(sc, ESCODEC_SD_DAC_REG, val); 557 558 val = escodec_read(sc, ESCODEC_CLKMAN1_REG); 559 val |= CLKMAN1_MCLK_ON; 560 val |= CLKMAN1_BCLK_ON; 561 val |= CLKMAN1_CLK_CP_ON; 562 val |= CLKMAN1_CLK_DAC_ON; 563 val |= CLKMAN1_ANACLK_DAC_ON; 564 escodec_write(sc, ESCODEC_CLKMAN1_REG, val); 565 566 escodec_unlock(sc); 567 568 return 0; 569} 570 571static int 572escodec_dai_add_device(audio_dai_tag_t dai, audio_dai_tag_t aux) 573{ 574 struct escodec_softc * const sc = audio_dai_private(dai); 575 576 if (sc->sc_amplifier != NULL) 577 return 0; 578 579 sc->sc_amplifier = aux; 580 581 return 0; 582} 583 584static audio_dai_tag_t 585escodec_dai_get_tag(device_t dev, const void *data, size_t len) 586{ 587 struct escodec_softc * const sc = device_private(dev); 588 589 if (len != 4) 590 return NULL; 591 592 return &sc->sc_dai; 593} 594 595static struct fdtbus_dai_controller_func escodec_dai_funcs = { 596 .get_tag = escodec_dai_get_tag 597}; 598 599static void 600escodec_init(struct escodec_softc *sc) 601{ 602 uint8_t val; 603 604 escodec_lock(sc); 605 606 escodec_write(sc, ESCODEC_RESET_REG, RESET_ALL); 607 delay(5000); 608 escodec_write(sc, ESCODEC_RESET_REG, RESET_CSM_ON); 609 delay(30000); 610 611 escodec_write(sc, ESCODEC_VMID_REG, 0xff); 612 escodec_write(sc, ESCODEC_ADC_OSR_REG, 0x32); 613 614 val = escodec_read(sc, ESCODEC_SD_ADC_REG); 615 val &= ~SD_FMT_WL; 616 val |= __SHIFTIN(SD_FMT_WL_16, SD_FMT_WL); 617 escodec_write(sc, ESCODEC_SD_ADC_REG, val); 618 619 val = escodec_read(sc, ESCODEC_SD_DAC_REG); 620 val &= ~SD_FMT_WL; 621 val |= __SHIFTIN(SD_FMT_WL_16, SD_FMT_WL); 622 escodec_write(sc, ESCODEC_SD_DAC_REG, val); 623 624 /* Power up */ 625 escodec_write(sc, ESCODEC_PDN_REG, 0); 626 627 /* Route DAC signal to HP mixer */ 628 val = HPMIXRT_LD2LHPMIX | HPMIXRT_RD2RHPMIX; 629 escodec_write(sc, ESCODEC_HPMIXRT_REG, val); 630 631 /* Power up DAC */ 632 escodec_write(sc, ESCODEC_DACPWR_REG, 0); 633 634 /* Power up HP mixer and unmute */ 635 escodec_write(sc, ESCODEC_HPMIX_REG, 0); 636 637 /* Power up HP output driver */ 638 val = escodec_read(sc, ESCODEC_HPPWR_REG); 639 val &= ~HPPWR_PDN_CPHP; 640 escodec_write(sc, ESCODEC_HPPWR_REG, val); 641 642 /* Power up HP charge pump circuits */ 643 val = escodec_read(sc, ESCODEC_CPPWR_REG); 644 val &= ~CPPWR_PDN_CP; 645 escodec_write(sc, ESCODEC_CPPWR_REG, val); 646 647 /* Set LIN1/RIN1 as inputs for HP mixer */ 648 escodec_write(sc, ESCODEC_HPSEL_REG, 0); 649 650 /* Power up HP output driver calibration */ 651 val = escodec_read(sc, ESCODEC_HPVOL_REG); 652 val &= ~HPVOL_PDN_LICAL; 653 val &= ~HPVOL_PDN_RICAL; 654 escodec_write(sc, ESCODEC_HPVOL_REG, val); 655 656 /* Set headphone mixer to -6dB */ 657 escodec_write(sc, ESCODEC_HPMIXVOL_REG, 0x44); 658 659 /* Set charge pump headphone to -48dB */ 660 escodec_write(sc, ESCODEC_HPVOL_REG, 0x33); 661 662 /* Set DAC to 0dB */ 663 escodec_write(sc, ESCODEC_DACVOL_L_REG, 0); 664 escodec_write(sc, ESCODEC_DACVOL_R_REG, 0); 665 666 /* Enable HP output */ 667 val = HPOUTEN_EN_HPL | HPOUTEN_EN_HPR | 668 HPOUTEN_HPL_OUTEN | HPOUTEN_HPR_OUTEN; 669 escodec_write(sc, ESCODEC_HPOUTEN_REG, val); 670 671 escodec_unlock(sc); 672} 673 674static int 675escodec_match(device_t parent, cfdata_t match, void *aux) 676{ 677 struct i2c_attach_args *ia = aux; 678 int match_result; 679 680 if (iic_use_direct_match(ia, match, compat_data, &match_result)) 681 return match_result; 682 683 /* This device is direct-config only */ 684 685 return 0; 686} 687 688static void 689escodec_attach(device_t parent, device_t self, void *aux) 690{ 691 struct escodec_softc * const sc = device_private(self); 692 struct i2c_attach_args * const ia = aux; 693 const int phandle = ia->ia_cookie; 694 695 sc->sc_dev = self; 696 sc->sc_i2c = ia->ia_tag; 697 sc->sc_addr = ia->ia_addr; 698 sc->sc_phandle = ia->ia_cookie; 699 sc->sc_swvol = 0xff; 700 701 sc->sc_clk = fdtbus_clock_get(phandle, "mclk"); 702 if (sc->sc_clk == NULL || clk_enable(sc->sc_clk) != 0) { 703 aprint_error(": couldn't enable mclk\n"); 704 return; 705 } 706 707 aprint_naive("\n"); 708 aprint_normal(": Everest Semi ES8316 Audio CODEC\n"); 709 710 escodec_init(sc); 711 712 sc->sc_dai.dai_set_sysclk = escodec_dai_set_sysclk; 713 sc->sc_dai.dai_set_format = escodec_dai_set_format; 714 sc->sc_dai.dai_add_device = escodec_dai_add_device; 715 sc->sc_dai.dai_hw_if = &escodec_hw_if; 716 sc->sc_dai.dai_dev = self; 717 sc->sc_dai.dai_priv = sc; 718 fdtbus_register_dai_controller(self, phandle, &escodec_dai_funcs); 719} 720 721CFATTACH_DECL_NEW(es8316ac, sizeof(struct escodec_softc), 722 escodec_match, escodec_attach, NULL, NULL); 723