1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org> 5 * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> 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 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/bus.h> 33 #include <sys/kernel.h> 34 #include <sys/lock.h> 35 #include <sys/module.h> 36 #include <sys/mutex.h> 37 #include <sys/rman.h> 38 #include <sys/resource.h> 39 #include <machine/bus.h> 40 41 #include <dev/ofw/ofw_bus.h> 42 #include <dev/ofw/ofw_bus_subr.h> 43 44 #include <dev/extres/clk/clk.h> 45 #include <dev/extres/hwreset/hwreset.h> 46 #include <dev/extres/regulator/regulator.h> 47 48 #include "syscon_if.h" 49 50 #include "opt_snd.h" 51 #include <dev/sound/pcm/sound.h> 52 #include <dev/sound/fdt/audio_dai.h> 53 #include "audio_dai_if.h" 54 #include "mixer_if.h" 55 56 #define A64_PR_CFG 0x00 57 #define A64_AC_PR_RST (1 << 28) 58 #define A64_AC_PR_RW (1 << 24) 59 #define A64_AC_PR_ADDR_MASK (0x1f << 16) 60 #define A64_AC_PR_ADDR(n) (((n) & 0x1f) << 16) 61 #define A64_ACDA_PR_WDAT_MASK (0xff << 8) 62 #define A64_ACDA_PR_WDAT(n) (((n) & 0xff) << 8) 63 #define A64_ACDA_PR_RDAT(n) ((n) & 0xff) 64 65 #define A64_HP_CTRL 0x00 66 #define A64_HPPA_EN (1 << 6) 67 #define A64_HPVOL_MASK 0x3f 68 #define A64_HPVOL(n) ((n) & 0x3f) 69 #define A64_OL_MIX_CTRL 0x01 70 #define A64_LMIXMUTE_LDAC (1 << 1) 71 #define A64_OR_MIX_CTRL 0x02 72 #define A64_RMIXMUTE_RDAC (1 << 1) 73 #define A64_LINEOUT_CTRL0 0x05 74 #define A64_LINEOUT_LEFT_EN (1 << 7) 75 #define A64_LINEOUT_RIGHT_EN (1 << 6) 76 #define A64_LINEOUT_EN (A64_LINEOUT_LEFT_EN|A64_LINEOUT_RIGHT_EN) 77 #define A64_LINEOUT_CTRL1 0x06 78 #define A64_LINEOUT_VOL __BITS(4,0) 79 #define A64_MIC1_CTRL 0x07 80 #define A64_MIC1G __BITS(6,4) 81 #define A64_MIC1AMPEN (1 << 3) 82 #define A64_MIC1BOOST __BITS(2,0) 83 #define A64_MIC2_CTRL 0x08 84 #define A64_MIC2_SEL (1 << 7) 85 #define A64_MIC2G_MASK (7 << 4) 86 #define A64_MIC2G(n) (((n) & 7) << 4) 87 #define A64_MIC2AMPEN (1 << 3) 88 #define A64_MIC2BOOST_MASK (7 << 0) 89 #define A64_MIC2BOOST(n) (((n) & 7) << 0) 90 #define A64_LINEIN_CTRL 0x09 91 #define A64_LINEING __BITS(6,4) 92 #define A64_MIX_DAC_CTRL 0x0a 93 #define A64_DACAREN (1 << 7) 94 #define A64_DACALEN (1 << 6) 95 #define A64_RMIXEN (1 << 5) 96 #define A64_LMIXEN (1 << 4) 97 #define A64_RHPPAMUTE (1 << 3) 98 #define A64_LHPPAMUTE (1 << 2) 99 #define A64_RHPIS (1 << 1) 100 #define A64_LHPIS (1 << 0) 101 #define A64_L_ADCMIX_SRC 0x0b 102 #define A64_R_ADCMIX_SRC 0x0c 103 #define A64_ADCMIX_SRC_MIC1 (1 << 6) 104 #define A64_ADCMIX_SRC_MIC2 (1 << 5) 105 #define A64_ADCMIX_SRC_LINEIN (1 << 2) 106 #define A64_ADCMIX_SRC_OMIXER (1 << 1) 107 #define A64_ADC_CTRL 0x0d 108 #define A64_ADCREN (1 << 7) 109 #define A64_ADCLEN (1 << 6) 110 #define A64_ADCG __BITS(2,0) 111 #define A64_JACK_MIC_CTRL 0x1d 112 #define A64_JACKDETEN (1 << 7) 113 #define A64_INNERRESEN (1 << 6) 114 #define A64_HMICBIASEN (1 << 5) 115 #define A64_AUTOPLEN (1 << 1) 116 117 #define A64CODEC_MIXER_DEVS ((1 << SOUND_MIXER_VOLUME) | \ 118 (1 << SOUND_MIXER_MIC)) 119 120 static struct ofw_compat_data compat_data[] = { 121 { "allwinner,sun50i-a64-codec-analog", 1}, 122 { NULL, 0 } 123 }; 124 125 struct a64codec_softc { 126 device_t dev; 127 struct resource *res; 128 struct mtx mtx; 129 u_int regaddr; /* address for the sysctl */ 130 }; 131 132 #define A64CODEC_LOCK(sc) mtx_lock(&(sc)->mtx) 133 #define A64CODEC_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 134 #define A64CODEC_READ(sc, reg) bus_read_4((sc)->res, (reg)) 135 #define A64CODEC_WRITE(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 136 137 static int a64codec_probe(device_t dev); 138 static int a64codec_attach(device_t dev); 139 static int a64codec_detach(device_t dev); 140 141 static u_int 142 a64_acodec_pr_read(struct a64codec_softc *sc, u_int addr) 143 { 144 uint32_t val; 145 146 /* Read current value */ 147 val = A64CODEC_READ(sc, A64_PR_CFG); 148 149 /* De-assert reset */ 150 val |= A64_AC_PR_RST; 151 A64CODEC_WRITE(sc, A64_PR_CFG, val); 152 153 /* Read mode */ 154 val &= ~A64_AC_PR_RW; 155 A64CODEC_WRITE(sc, A64_PR_CFG, val); 156 157 /* Set address */ 158 val &= ~A64_AC_PR_ADDR_MASK; 159 val |= A64_AC_PR_ADDR(addr); 160 A64CODEC_WRITE(sc, A64_PR_CFG, val); 161 162 /* Read data */ 163 val = A64CODEC_READ(sc, A64_PR_CFG); 164 return A64_ACDA_PR_RDAT(val); 165 } 166 167 static void 168 a64_acodec_pr_write(struct a64codec_softc *sc, u_int addr, u_int data) 169 { 170 uint32_t val; 171 172 /* Read current value */ 173 val = A64CODEC_READ(sc, A64_PR_CFG); 174 175 /* De-assert reset */ 176 val |= A64_AC_PR_RST; 177 A64CODEC_WRITE(sc, A64_PR_CFG, val); 178 179 /* Set address */ 180 val &= ~A64_AC_PR_ADDR_MASK; 181 val |= A64_AC_PR_ADDR(addr); 182 A64CODEC_WRITE(sc, A64_PR_CFG, val); 183 184 /* Write data */ 185 val &= ~A64_ACDA_PR_WDAT_MASK; 186 val |= A64_ACDA_PR_WDAT(data); 187 A64CODEC_WRITE(sc, A64_PR_CFG, val); 188 189 /* Write mode */ 190 val |= A64_AC_PR_RW; 191 A64CODEC_WRITE(sc, A64_PR_CFG, val); 192 193 /* Clear write mode */ 194 val &= ~A64_AC_PR_RW; 195 A64CODEC_WRITE(sc, A64_PR_CFG, val); 196 } 197 198 static void 199 a64_acodec_pr_set_clear(struct a64codec_softc *sc, u_int addr, u_int set, u_int clr) 200 { 201 u_int old, new; 202 203 old = a64_acodec_pr_read(sc, addr); 204 new = set | (old & ~clr); 205 a64_acodec_pr_write(sc, addr, new); 206 } 207 208 static int 209 a64codec_probe(device_t dev) 210 { 211 if (!ofw_bus_status_okay(dev)) 212 return (ENXIO); 213 214 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 215 return (ENXIO); 216 217 device_set_desc(dev, "Allwinner A64 Analog Codec"); 218 return (BUS_PROBE_DEFAULT); 219 } 220 221 static int 222 a64codec_attach(device_t dev) 223 { 224 struct a64codec_softc *sc; 225 int error, rid; 226 phandle_t node; 227 regulator_t reg; 228 229 sc = device_get_softc(dev); 230 sc->dev = dev; 231 232 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 233 234 rid = 0; 235 sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 236 if (!sc->res) { 237 device_printf(dev, "cannot allocate resource for device\n"); 238 error = ENXIO; 239 goto fail; 240 } 241 242 if (regulator_get_by_ofw_property(dev, 0, "cpvdd-supply", ®) == 0) { 243 error = regulator_enable(reg); 244 if (error != 0) { 245 device_printf(dev, "cannot enable PHY regulator\n"); 246 goto fail; 247 } 248 } 249 250 /* Right & Left Headphone PA enable */ 251 a64_acodec_pr_set_clear(sc, A64_HP_CTRL, 252 A64_HPPA_EN, 0); 253 254 /* Microphone BIAS enable */ 255 a64_acodec_pr_set_clear(sc, A64_JACK_MIC_CTRL, 256 A64_HMICBIASEN | A64_INNERRESEN, 0); 257 258 /* Unmute DAC to output mixer */ 259 a64_acodec_pr_set_clear(sc, A64_OL_MIX_CTRL, 260 A64_LMIXMUTE_LDAC, 0); 261 a64_acodec_pr_set_clear(sc, A64_OR_MIX_CTRL, 262 A64_RMIXMUTE_RDAC, 0); 263 264 /* For now we work only with headphones */ 265 a64_acodec_pr_set_clear(sc, A64_LINEOUT_CTRL0, 266 0, A64_LINEOUT_EN); 267 a64_acodec_pr_set_clear(sc, A64_HP_CTRL, 268 A64_HPPA_EN, 0); 269 270 u_int val = a64_acodec_pr_read(sc, A64_HP_CTRL); 271 val &= ~(0x3f); 272 val |= 0x25; 273 a64_acodec_pr_write(sc, A64_HP_CTRL, val); 274 275 a64_acodec_pr_set_clear(sc, A64_MIC2_CTRL, 276 A64_MIC2AMPEN | A64_MIC2_SEL | A64_MIC2G(0x3) | A64_MIC2BOOST(0x4), 277 A64_MIC2G_MASK | A64_MIC2BOOST_MASK); 278 279 a64_acodec_pr_write(sc, A64_L_ADCMIX_SRC, 280 A64_ADCMIX_SRC_MIC2); 281 a64_acodec_pr_write(sc, A64_R_ADCMIX_SRC, 282 A64_ADCMIX_SRC_MIC2); 283 284 /* Max out MIC2 gain */ 285 val = a64_acodec_pr_read(sc, A64_MIC2_CTRL); 286 val &= ~(0x7); 287 val |= (0x7); 288 val &= ~(7 << 4); 289 val |= (7 << 4); 290 a64_acodec_pr_write(sc, A64_MIC2_CTRL, val); 291 292 node = ofw_bus_get_node(dev); 293 OF_device_register_xref(OF_xref_from_node(node), dev); 294 295 return (0); 296 297 fail: 298 a64codec_detach(dev); 299 return (error); 300 } 301 302 static int 303 a64codec_detach(device_t dev) 304 { 305 struct a64codec_softc *sc; 306 307 sc = device_get_softc(dev); 308 309 if (sc->res) 310 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res); 311 mtx_destroy(&sc->mtx); 312 313 return (0); 314 } 315 316 static int 317 a64codec_mixer_init(struct snd_mixer *m) 318 { 319 320 mix_setdevs(m, A64CODEC_MIXER_DEVS); 321 322 return (0); 323 } 324 325 static int 326 a64codec_mixer_uninit(struct snd_mixer *m) 327 { 328 329 return (0); 330 } 331 332 static int 333 a64codec_mixer_reinit(struct snd_mixer *m) 334 { 335 336 return (0); 337 } 338 339 static int 340 a64codec_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 341 { 342 struct a64codec_softc *sc; 343 struct mtx *mixer_lock; 344 uint8_t do_unlock; 345 u_int val; 346 347 sc = device_get_softc(mix_getdevinfo(m)); 348 mixer_lock = mixer_get_lock(m); 349 350 if (mtx_owned(mixer_lock)) { 351 do_unlock = 0; 352 } else { 353 do_unlock = 1; 354 mtx_lock(mixer_lock); 355 } 356 357 right = left; 358 359 A64CODEC_LOCK(sc); 360 switch(dev) { 361 case SOUND_MIXER_VOLUME: 362 val = a64_acodec_pr_read(sc, A64_HP_CTRL); 363 val &= ~(A64_HPVOL_MASK); 364 val |= A64_HPVOL(left * 63 / 100); 365 a64_acodec_pr_write(sc, A64_HP_CTRL, val); 366 break; 367 368 case SOUND_MIXER_MIC: 369 val = a64_acodec_pr_read(sc, A64_MIC2_CTRL); 370 val &= ~(A64_MIC2BOOST_MASK); 371 val |= A64_MIC2BOOST(left * 7 / 100); 372 a64_acodec_pr_write(sc, A64_MIC2_CTRL, val); 373 break; 374 default: 375 break; 376 } 377 A64CODEC_UNLOCK(sc); 378 379 if (do_unlock) { 380 mtx_unlock(mixer_lock); 381 } 382 383 return (left | (right << 8)); 384 } 385 386 static unsigned 387 a64codec_mixer_setrecsrc(struct snd_mixer *m, unsigned src) 388 { 389 390 return (0); 391 } 392 393 static kobj_method_t a64codec_mixer_methods[] = { 394 KOBJMETHOD(mixer_init, a64codec_mixer_init), 395 KOBJMETHOD(mixer_uninit, a64codec_mixer_uninit), 396 KOBJMETHOD(mixer_reinit, a64codec_mixer_reinit), 397 KOBJMETHOD(mixer_set, a64codec_mixer_set), 398 KOBJMETHOD(mixer_setrecsrc, a64codec_mixer_setrecsrc), 399 KOBJMETHOD_END 400 }; 401 402 MIXER_DECLARE(a64codec_mixer); 403 404 static int 405 a64codec_dai_init(device_t dev, uint32_t format) 406 { 407 408 return (0); 409 } 410 411 static int 412 a64codec_dai_trigger(device_t dev, int go, int pcm_dir) 413 { 414 struct a64codec_softc *sc = device_get_softc(dev); 415 416 if ((pcm_dir != PCMDIR_PLAY) && (pcm_dir != PCMDIR_REC)) 417 return (EINVAL); 418 419 switch (go) { 420 case PCMTRIG_START: 421 if (pcm_dir == PCMDIR_PLAY) { 422 /* Enable DAC analog l/r channels, HP PA, and output mixer */ 423 a64_acodec_pr_set_clear(sc, A64_MIX_DAC_CTRL, 424 A64_DACAREN | A64_DACALEN | A64_RMIXEN | A64_LMIXEN | 425 A64_RHPPAMUTE | A64_LHPPAMUTE, 0); 426 } 427 else if (pcm_dir == PCMDIR_REC) { 428 /* Enable ADC analog l/r channels */ 429 a64_acodec_pr_set_clear(sc, A64_ADC_CTRL, 430 A64_ADCREN | A64_ADCLEN, 0); 431 } 432 break; 433 434 case PCMTRIG_STOP: 435 case PCMTRIG_ABORT: 436 if (pcm_dir == PCMDIR_PLAY) { 437 /* Disable DAC analog l/r channels, HP PA, and output mixer */ 438 a64_acodec_pr_set_clear(sc, A64_MIX_DAC_CTRL, 439 0, A64_DACAREN | A64_DACALEN | A64_RMIXEN | A64_LMIXEN | 440 A64_RHPPAMUTE | A64_LHPPAMUTE); 441 } 442 else if (pcm_dir == PCMDIR_REC) { 443 /* Disable ADC analog l/r channels */ 444 a64_acodec_pr_set_clear(sc, A64_ADC_CTRL, 445 0, A64_ADCREN | A64_ADCLEN); 446 } 447 break; 448 } 449 450 return (0); 451 } 452 453 static int 454 a64codec_dai_setup_mixer(device_t dev, device_t pcmdev) 455 { 456 457 mixer_init(pcmdev, &a64codec_mixer_class, dev); 458 459 return (0); 460 } 461 462 static device_method_t a64codec_methods[] = { 463 /* Device interface */ 464 DEVMETHOD(device_probe, a64codec_probe), 465 DEVMETHOD(device_attach, a64codec_attach), 466 DEVMETHOD(device_detach, a64codec_detach), 467 468 DEVMETHOD(audio_dai_init, a64codec_dai_init), 469 DEVMETHOD(audio_dai_setup_mixer, a64codec_dai_setup_mixer), 470 DEVMETHOD(audio_dai_trigger, a64codec_dai_trigger), 471 472 DEVMETHOD_END 473 }; 474 475 static driver_t a64codec_driver = { 476 "a64codec", 477 a64codec_methods, 478 sizeof(struct a64codec_softc), 479 }; 480 481 DRIVER_MODULE(a64codec, simplebus, a64codec_driver, 0, 0); 482 SIMPLEBUS_PNP_INFO(compat_data); 483