1 1.2 isaki /* $NetBSD: sun6i_a31_codec.c,v 1.2 2019/05/08 13:40:14 isaki Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2014-2017 Jared McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 14 1.1 jmcneill * documentation and/or other materials provided with the distribution. 15 1.1 jmcneill * 16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 jmcneill * SUCH DAMAGE. 27 1.1 jmcneill */ 28 1.1 jmcneill 29 1.1 jmcneill #include <sys/cdefs.h> 30 1.2 isaki __KERNEL_RCSID(0, "$NetBSD: sun6i_a31_codec.c,v 1.2 2019/05/08 13:40:14 isaki Exp $"); 31 1.1 jmcneill 32 1.1 jmcneill #include <sys/param.h> 33 1.1 jmcneill #include <sys/bus.h> 34 1.1 jmcneill #include <sys/cpu.h> 35 1.1 jmcneill #include <sys/device.h> 36 1.1 jmcneill #include <sys/kmem.h> 37 1.1 jmcneill #include <sys/bitops.h> 38 1.1 jmcneill 39 1.1 jmcneill #include <sys/audioio.h> 40 1.2 isaki #include <dev/audio/audio_if.h> 41 1.1 jmcneill 42 1.1 jmcneill #include <arm/sunxi/sunxi_codec.h> 43 1.1 jmcneill 44 1.1 jmcneill #define A31_DEFAULT_HPVOL 0x20 45 1.1 jmcneill 46 1.1 jmcneill #define OMIXER_DACA_CTRL 0x20 47 1.1 jmcneill #define DACAREN __BIT(31) 48 1.1 jmcneill #define DACALEN __BIT(30) 49 1.1 jmcneill #define RMIXEN __BIT(29) 50 1.1 jmcneill #define LMIXEN __BIT(28) 51 1.1 jmcneill #define RMIXMUTE __BITS(23,17) 52 1.1 jmcneill #define RMIXMUTE_MIC1 __BIT(23) 53 1.1 jmcneill #define RMIXMUTE_MIC2 __BIT(22) 54 1.1 jmcneill #define RMIXMUTE_PHONEP_PHONEN __BIT(21) 55 1.1 jmcneill #define RMIXMUTE_PHONEP __BIT(20) 56 1.1 jmcneill #define RMIXMUTE_LINEINR __BIT(19) 57 1.1 jmcneill #define RMIXMUTE_DACR __BIT(18) 58 1.1 jmcneill #define RMIXMUTE_DACL __BIT(17) 59 1.1 jmcneill #define LMIXMUTE __BITS(16,10) 60 1.1 jmcneill #define LMIXMUTE_MIC1 __BIT(16) 61 1.1 jmcneill #define LMIXMUTE_MIC2 __BIT(15) 62 1.1 jmcneill #define LMIXMUTE_PHONEP_PHONEN __BIT(14) 63 1.1 jmcneill #define LMIXMUTE_PHONEN __BIT(13) 64 1.1 jmcneill #define LMIXMUTE_LINEINL __BIT(12) 65 1.1 jmcneill #define LMIXMUTE_DACL __BIT(11) 66 1.1 jmcneill #define LMIXMUTE_DACR __BIT(10) 67 1.1 jmcneill #define RHPIS __BIT(9) 68 1.1 jmcneill #define LHPIS __BIT(8) 69 1.1 jmcneill #define RHPPAMUTE __BIT(7) 70 1.1 jmcneill #define LHPPAMUTE __BIT(6) 71 1.1 jmcneill #define HPVOL __BITS(5,0) 72 1.1 jmcneill 73 1.1 jmcneill #define OMIXER_PA_CTRL 0x24 74 1.1 jmcneill #define HPPAEN __BIT(31) 75 1.1 jmcneill #define HPCOM_CTL __BITS(30,29) 76 1.1 jmcneill #define COMPTEN __BIT(28) 77 1.1 jmcneill #define PA_ANTI_POP_CTRL __BITS(27,26) 78 1.1 jmcneill #define MIC1G __BITS(17,15) 79 1.1 jmcneill #define MIC2G __BITS(14,12) 80 1.1 jmcneill #define LINEING __BITS(11,9) 81 1.1 jmcneill #define PHONEG __BITS(8,6) 82 1.1 jmcneill #define PHONEPG __BITS(5,3) 83 1.1 jmcneill #define PHONENG __BITS(2,0) 84 1.1 jmcneill 85 1.1 jmcneill #define AC_MIC_CTRL 0x28 86 1.1 jmcneill #define HBIASEN __BIT(31) 87 1.1 jmcneill #define MBIASEN __BIT(30) 88 1.1 jmcneill #define HBIASADCEN __BIT(29) 89 1.1 jmcneill #define MIC1AMPEN __BIT(28) 90 1.1 jmcneill #define MIC1BOOST __BITS(27,25) 91 1.1 jmcneill #define MIC2AMPEN __BIT(24) 92 1.1 jmcneill #define MIC2BOOST __BITS(23,21) 93 1.1 jmcneill #define MIC2SLT __BIT(20) 94 1.1 jmcneill #define LINEOUTLEN __BIT(19) 95 1.1 jmcneill #define LINEOUTREN __BIT(18) 96 1.1 jmcneill #define LINEOUTLSRC __BIT(17) 97 1.1 jmcneill #define LINEOUTRSRC __BIT(16) 98 1.1 jmcneill #define LINEOUTVC __BITS(15,11) 99 1.1 jmcneill #define PHONEPREG __BITS(10,8) 100 1.1 jmcneill #define PHONEOUTG __BITS(7,5) 101 1.1 jmcneill #define PHONEOUTEN __BIT(4) 102 1.1 jmcneill #define PHONEOUTS0 __BIT(3) 103 1.1 jmcneill #define PHONEOUTS1 __BIT(2) 104 1.1 jmcneill #define PHONEOUTS2 __BIT(1) 105 1.1 jmcneill #define PHONEOUTS3 __BIT(0) 106 1.1 jmcneill 107 1.1 jmcneill #define AC_ADCA_CTRL 0x2c 108 1.1 jmcneill #define ADCREN __BIT(31) 109 1.1 jmcneill #define ADCLEN __BIT(30) 110 1.1 jmcneill #define ADCRG __BITS(29,27) 111 1.1 jmcneill #define ADCLG __BITS(26,24) 112 1.1 jmcneill #define RADCMIXMUTE __BITS(13,7) 113 1.1 jmcneill #define RADCMIXMUTE_MIC1 __BIT(13) 114 1.1 jmcneill #define RADCMIXMUTE_MIC2 __BIT(12) 115 1.1 jmcneill #define RADCMIXMUTE_PHONEP_PHONEN __BIT(11) 116 1.1 jmcneill #define RADCMIXMUTE_PHONEP __BIT(10) 117 1.1 jmcneill #define RADCMIXMUTE_LINEINR __BIT(9) 118 1.1 jmcneill #define RADCMIXMUTE_ROM __BIT(8) 119 1.1 jmcneill #define RADCMIXMUTE_LOM __BIT(7) 120 1.1 jmcneill #define LADCMIXMUTE __BITS(6,0) 121 1.1 jmcneill #define LADCMIXMUTE_MIC1 __BIT(6) 122 1.1 jmcneill #define LADCMIXMUTE_MIC2 __BIT(5) 123 1.1 jmcneill #define LADCMIXMUTE_PHONEP_PHONEN __BIT(4) 124 1.1 jmcneill #define LADCMIXMUTE_PHONEN __BIT(3) 125 1.1 jmcneill #define LADCMIXMUTE_LINEINL __BIT(2) 126 1.1 jmcneill #define LADCMIXMUTE_LOM __BIT(1) 127 1.1 jmcneill #define LADCMIXMUTE_ROM __BIT(0) 128 1.1 jmcneill 129 1.1 jmcneill enum a31_codec_mixer_ctrl { 130 1.1 jmcneill A31_CODEC_OUTPUT_CLASS, 131 1.1 jmcneill A31_CODEC_INPUT_CLASS, 132 1.1 jmcneill 133 1.1 jmcneill A31_CODEC_OUTPUT_MASTER_VOLUME, 134 1.1 jmcneill A31_CODEC_INPUT_DAC_VOLUME, 135 1.1 jmcneill 136 1.1 jmcneill A31_CODEC_MIXER_CTRL_LAST 137 1.1 jmcneill }; 138 1.1 jmcneill 139 1.1 jmcneill static const struct a31_codec_mixer { 140 1.1 jmcneill const char * name; 141 1.1 jmcneill enum a31_codec_mixer_ctrl mixer_class; 142 1.1 jmcneill u_int reg; 143 1.1 jmcneill u_int mask; 144 1.1 jmcneill } a31_codec_mixers[A31_CODEC_MIXER_CTRL_LAST] = { 145 1.1 jmcneill [A31_CODEC_OUTPUT_MASTER_VOLUME] = { AudioNmaster, 146 1.1 jmcneill A31_CODEC_OUTPUT_CLASS, OMIXER_DACA_CTRL, HPVOL }, 147 1.1 jmcneill [A31_CODEC_INPUT_DAC_VOLUME] = { AudioNdac, 148 1.1 jmcneill A31_CODEC_INPUT_CLASS, OMIXER_DACA_CTRL, HPVOL }, 149 1.1 jmcneill }; 150 1.1 jmcneill 151 1.1 jmcneill #define RD4(sc, reg) \ 152 1.1 jmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 153 1.1 jmcneill #define WR4(sc, reg, val) \ 154 1.1 jmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 155 1.1 jmcneill #define SET4(sc, reg, mask) \ 156 1.1 jmcneill WR4((sc), (reg), RD4((sc), (reg)) | (mask)) 157 1.1 jmcneill #define CLR4(sc, reg, mask) \ 158 1.1 jmcneill WR4((sc), (reg), RD4((sc), (reg)) & ~(mask)) 159 1.1 jmcneill 160 1.1 jmcneill static int 161 1.1 jmcneill a31_codec_init(struct sunxi_codec_softc *sc) 162 1.1 jmcneill { 163 1.1 jmcneill 164 1.1 jmcneill /* Disable HPCOM and HPCOM output protection */ 165 1.1 jmcneill CLR4(sc, OMIXER_PA_CTRL, HPCOM_CTL | COMPTEN); 166 1.1 jmcneill /* Enable headphone power amp */ 167 1.1 jmcneill SET4(sc, OMIXER_PA_CTRL, HPPAEN); 168 1.1 jmcneill 169 1.1 jmcneill /* Set headphone PA input to DAC */ 170 1.1 jmcneill CLR4(sc, OMIXER_DACA_CTRL, RHPIS | LHPIS); 171 1.1 jmcneill /* Mute inputs to headphone PA */ 172 1.1 jmcneill CLR4(sc, OMIXER_DACA_CTRL, RHPPAMUTE | LHPPAMUTE); 173 1.1 jmcneill /* Set initial volume */ 174 1.1 jmcneill CLR4(sc, OMIXER_DACA_CTRL, HPVOL); 175 1.1 jmcneill SET4(sc, OMIXER_DACA_CTRL, __SHIFTIN(A31_DEFAULT_HPVOL, HPVOL)); 176 1.1 jmcneill 177 1.1 jmcneill /* Disable lineout */ 178 1.1 jmcneill CLR4(sc, AC_MIC_CTRL, LINEOUTLEN | LINEOUTREN | LINEOUTVC); 179 1.1 jmcneill /* Enable headset microphone bias, current sensor, and ADC */ 180 1.1 jmcneill SET4(sc, AC_MIC_CTRL, HBIASEN | HBIASADCEN); 181 1.1 jmcneill 182 1.1 jmcneill return 0; 183 1.1 jmcneill } 184 1.1 jmcneill 185 1.1 jmcneill static void 186 1.1 jmcneill a31_codec_mute(struct sunxi_codec_softc *sc, int mute, u_int mode) 187 1.1 jmcneill { 188 1.1 jmcneill if (mode == AUMODE_PLAY) { 189 1.1 jmcneill if (sc->sc_pin_pa != NULL) 190 1.1 jmcneill fdtbus_gpio_write(sc->sc_pin_pa, !mute); 191 1.1 jmcneill 192 1.1 jmcneill if (mute) { 193 1.1 jmcneill CLR4(sc, OMIXER_DACA_CTRL, DACAREN | DACALEN); 194 1.1 jmcneill } else { 195 1.1 jmcneill CLR4(sc, OMIXER_DACA_CTRL, RMIXMUTE | LMIXMUTE); 196 1.1 jmcneill SET4(sc, OMIXER_DACA_CTRL, 197 1.1 jmcneill LHPIS | RHPIS | LHPPAMUTE | RHPPAMUTE | 198 1.1 jmcneill DACAREN | DACALEN | RMIXEN | LMIXEN | 199 1.1 jmcneill RMIXMUTE_DACR | LMIXMUTE_DACL); 200 1.1 jmcneill } 201 1.1 jmcneill } else { 202 1.1 jmcneill if (mute) { 203 1.1 jmcneill CLR4(sc, AC_ADCA_CTRL, ADCREN | ADCLEN); 204 1.1 jmcneill } else { 205 1.1 jmcneill SET4(sc, AC_ADCA_CTRL, ADCREN | ADCLEN); 206 1.1 jmcneill } 207 1.1 jmcneill } 208 1.1 jmcneill } 209 1.1 jmcneill 210 1.1 jmcneill static int 211 1.1 jmcneill a31_codec_set_port(struct sunxi_codec_softc *sc, mixer_ctrl_t *mc) 212 1.1 jmcneill { 213 1.1 jmcneill const struct a31_codec_mixer *mix; 214 1.1 jmcneill u_int val, shift; 215 1.1 jmcneill int nvol; 216 1.1 jmcneill 217 1.1 jmcneill switch (mc->dev) { 218 1.1 jmcneill case A31_CODEC_OUTPUT_MASTER_VOLUME: 219 1.1 jmcneill case A31_CODEC_INPUT_DAC_VOLUME: 220 1.1 jmcneill mix = &a31_codec_mixers[mc->dev]; 221 1.1 jmcneill val = RD4(sc, mix->reg); 222 1.1 jmcneill shift = 8 - fls32(__SHIFTOUT_MASK(mix->mask)); 223 1.1 jmcneill nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] >> shift; 224 1.1 jmcneill val &= ~mix->mask; 225 1.1 jmcneill val |= __SHIFTIN(nvol, mix->mask); 226 1.1 jmcneill WR4(sc, mix->reg, val); 227 1.1 jmcneill return 0; 228 1.1 jmcneill } 229 1.1 jmcneill 230 1.1 jmcneill return ENXIO; 231 1.1 jmcneill } 232 1.1 jmcneill 233 1.1 jmcneill static int 234 1.1 jmcneill a31_codec_get_port(struct sunxi_codec_softc *sc, mixer_ctrl_t *mc) 235 1.1 jmcneill { 236 1.1 jmcneill const struct a31_codec_mixer *mix; 237 1.1 jmcneill u_int val, shift; 238 1.1 jmcneill int nvol; 239 1.1 jmcneill 240 1.1 jmcneill switch (mc->dev) { 241 1.1 jmcneill case A31_CODEC_OUTPUT_MASTER_VOLUME: 242 1.1 jmcneill case A31_CODEC_INPUT_DAC_VOLUME: 243 1.1 jmcneill mix = &a31_codec_mixers[mc->dev]; 244 1.1 jmcneill val = RD4(sc, mix->reg); 245 1.1 jmcneill shift = 8 - fls32(__SHIFTOUT_MASK(mix->mask)); 246 1.1 jmcneill nvol = __SHIFTOUT(val, mix->mask) << shift; 247 1.1 jmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = nvol; 248 1.1 jmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = nvol; 249 1.1 jmcneill return 0; 250 1.1 jmcneill } 251 1.1 jmcneill 252 1.1 jmcneill return ENXIO; 253 1.1 jmcneill } 254 1.1 jmcneill 255 1.1 jmcneill static int 256 1.1 jmcneill a31_codec_query_devinfo(struct sunxi_codec_softc *sc, mixer_devinfo_t *di) 257 1.1 jmcneill { 258 1.1 jmcneill const struct a31_codec_mixer *mix; 259 1.1 jmcneill 260 1.1 jmcneill switch (di->index) { 261 1.1 jmcneill case A31_CODEC_OUTPUT_CLASS: 262 1.1 jmcneill di->mixer_class = di->index; 263 1.1 jmcneill strcpy(di->label.name, AudioCoutputs); 264 1.1 jmcneill di->type = AUDIO_MIXER_CLASS; 265 1.1 jmcneill di->next = di->prev = AUDIO_MIXER_LAST; 266 1.1 jmcneill return 0; 267 1.1 jmcneill 268 1.1 jmcneill case A31_CODEC_INPUT_CLASS: 269 1.1 jmcneill di->mixer_class = di->index; 270 1.1 jmcneill strcpy(di->label.name, AudioCinputs); 271 1.1 jmcneill di->type = AUDIO_MIXER_CLASS; 272 1.1 jmcneill di->next = di->prev = AUDIO_MIXER_LAST; 273 1.1 jmcneill return 0; 274 1.1 jmcneill 275 1.1 jmcneill case A31_CODEC_OUTPUT_MASTER_VOLUME: 276 1.1 jmcneill case A31_CODEC_INPUT_DAC_VOLUME: 277 1.1 jmcneill mix = &a31_codec_mixers[di->index]; 278 1.1 jmcneill di->mixer_class = mix->mixer_class; 279 1.1 jmcneill strcpy(di->label.name, mix->name); 280 1.1 jmcneill di->un.v.delta = 281 1.1 jmcneill 256 / (__SHIFTOUT_MASK(mix->mask) + 1); 282 1.1 jmcneill di->type = AUDIO_MIXER_VALUE; 283 1.1 jmcneill di->next = di->prev = AUDIO_MIXER_LAST; 284 1.1 jmcneill di->un.v.num_channels = 2; 285 1.1 jmcneill strcpy(di->un.v.units.name, AudioNvolume); 286 1.1 jmcneill return 0; 287 1.1 jmcneill } 288 1.1 jmcneill 289 1.1 jmcneill return ENXIO; 290 1.1 jmcneill } 291 1.1 jmcneill 292 1.1 jmcneill const struct sunxi_codec_conf sun6i_a31_codecconf = { 293 1.1 jmcneill .name = "A31 Audio Codec", 294 1.1 jmcneill 295 1.1 jmcneill .init = a31_codec_init, 296 1.1 jmcneill .mute = a31_codec_mute, 297 1.1 jmcneill .set_port = a31_codec_set_port, 298 1.1 jmcneill .get_port = a31_codec_get_port, 299 1.1 jmcneill .query_devinfo = a31_codec_query_devinfo, 300 1.1 jmcneill 301 1.1 jmcneill .DPC = 0x00, 302 1.1 jmcneill .DAC_FIFOC = 0x04, 303 1.1 jmcneill .DAC_FIFOS = 0x08, 304 1.1 jmcneill .DAC_TXDATA = 0x0c, 305 1.1 jmcneill .ADC_FIFOC = 0x10, 306 1.1 jmcneill .ADC_FIFOS = 0x14, 307 1.1 jmcneill .ADC_RXDATA = 0x18, 308 1.1 jmcneill .DAC_CNT = 0x40, 309 1.1 jmcneill .ADC_CNT = 0x44, 310 1.1 jmcneill }; 311