1 /* $OpenBSD: tascodec.c,v 1.6 2023/02/04 20:04:20 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/audioio.h> 21 #include <sys/device.h> 22 #include <sys/malloc.h> 23 24 #include <machine/bus.h> 25 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/ofw_gpio.h> 28 #include <dev/ofw/ofw_misc.h> 29 #include <dev/ofw/fdt.h> 30 31 #include <dev/i2c/i2cvar.h> 32 33 #include <dev/audio_if.h> 34 35 #define PWR_CTL 0x02 36 #define PWR_CTL_ISNS_PD (1 << 3) 37 #define PWR_CTL_VSNS_PD (1 << 2) 38 #define PWR_CTL_MODE_ACTIVE (0 << 0) 39 #define PWR_CTL_MODE_MUTE (1 << 0) 40 #define PWR_CTL_MODE_SHUTDOWN (2 << 0) 41 #define PB_CFG2 0x05 42 #define PB_CFG2_DVC_PCM_MIN 0xc9 43 #define PB_CFG2_DVC_PCM_30DB 0x3c 44 #define TDM_CFG0 0x0a 45 #define TDM_CFG0_FRAME_START (1 << 0) 46 #define TDM_CFG1 0x0b 47 #define TDM_CFG1_RX_JUSTIFY (1 << 6) 48 #define TDM_CFG1_RX_OFFSET_MASK (0x1f << 1) 49 #define TDM_CFG1_RX_OFFSET_SHIFT 1 50 #define TDM_CFG1_RX_EDGE (1 << 0) 51 #define TDM_CFG2 0x0c 52 #define TDM_CFG2_SCFG_MASK (3 << 4) 53 #define TDM_CFG2_SCFG_MONO_LEFT (1 << 4) 54 #define TDM_CFG2_SCFG_MONO_RIGHT (2 << 4) 55 #define TDM_CFG2_SCFG_STEREO_DOWNMIX (3 << 4) 56 #define TDM_CFG3 0x0d 57 #define TDM_CFG3_RX_SLOT_R_MASK 0xf0 58 #define TDM_CFG3_RX_SLOT_R_SHIFT 4 59 #define TDM_CFG3_RX_SLOT_L_MASK 0x0f 60 #define TDM_CFG3_RX_SLOT_L_SHIFT 0 61 62 struct tascodec_softc { 63 struct device sc_dev; 64 i2c_tag_t sc_tag; 65 i2c_addr_t sc_addr; 66 67 struct dai_device sc_dai; 68 uint8_t sc_dvc; 69 }; 70 71 int tascodec_match(struct device *, void *, void *); 72 void tascodec_attach(struct device *, struct device *, void *); 73 int tascodec_activate(struct device *, int); 74 75 const struct cfattach tascodec_ca = { 76 sizeof(struct tascodec_softc), tascodec_match, tascodec_attach, 77 NULL, tascodec_activate 78 }; 79 80 struct cfdriver tascodec_cd = { 81 NULL, "tascodec", DV_DULL 82 }; 83 84 int tascodec_set_format(void *, uint32_t, uint32_t, uint32_t); 85 int tascodec_set_tdm_slot(void *, int); 86 87 int tascodec_set_port(void *, mixer_ctrl_t *); 88 int tascodec_get_port(void *, mixer_ctrl_t *); 89 int tascodec_query_devinfo(void *, mixer_devinfo_t *); 90 int tascodec_trigger_output(void *, void *, void *, int, 91 void (*)(void *), void *, struct audio_params *); 92 int tascodec_halt_output(void *); 93 94 const struct audio_hw_if tascodec_hw_if = { 95 .set_port = tascodec_set_port, 96 .get_port = tascodec_get_port, 97 .query_devinfo = tascodec_query_devinfo, 98 .trigger_output = tascodec_trigger_output, 99 .halt_output = tascodec_halt_output, 100 }; 101 102 uint8_t tascodec_read(struct tascodec_softc *, int); 103 void tascodec_write(struct tascodec_softc *, int, uint8_t); 104 105 int 106 tascodec_match(struct device *parent, void *match, void *aux) 107 { 108 struct i2c_attach_args *ia = aux; 109 110 return iic_is_compatible(ia, "ti,tas2770"); 111 } 112 113 void 114 tascodec_attach(struct device *parent, struct device *self, void *aux) 115 { 116 struct tascodec_softc *sc = (struct tascodec_softc *)self; 117 struct i2c_attach_args *ia = aux; 118 int node = *(int *)ia->ia_cookie; 119 uint32_t *sdz_gpio; 120 int sdz_gpiolen; 121 uint8_t cfg2; 122 123 sc->sc_tag = ia->ia_tag; 124 sc->sc_addr = ia->ia_addr; 125 126 printf("\n"); 127 128 sdz_gpiolen = OF_getproplen(node, "shutdown-gpios"); 129 if (sdz_gpiolen > 0) { 130 sdz_gpio = malloc(sdz_gpiolen, M_TEMP, M_WAITOK); 131 OF_getpropintarray(node, "shutdown-gpios", 132 sdz_gpio, sdz_gpiolen); 133 gpio_controller_config_pin(sdz_gpio, GPIO_CONFIG_OUTPUT); 134 gpio_controller_set_pin(sdz_gpio, 1); 135 free(sdz_gpio, M_TEMP, sdz_gpiolen); 136 delay(1000); 137 } 138 139 /* Set volume to a reasonable level. */ 140 sc->sc_dvc = PB_CFG2_DVC_PCM_30DB; 141 tascodec_write(sc, PB_CFG2, sc->sc_dvc); 142 143 /* Default to stereo downmix mode for now. */ 144 cfg2 = tascodec_read(sc, TDM_CFG2); 145 cfg2 &= ~TDM_CFG2_SCFG_MASK; 146 cfg2 |= TDM_CFG2_SCFG_STEREO_DOWNMIX; 147 tascodec_write(sc, TDM_CFG2, cfg2); 148 149 sc->sc_dai.dd_node = node; 150 sc->sc_dai.dd_cookie = sc; 151 sc->sc_dai.dd_hw_if = &tascodec_hw_if; 152 sc->sc_dai.dd_set_format = tascodec_set_format; 153 sc->sc_dai.dd_set_tdm_slot = tascodec_set_tdm_slot; 154 dai_register(&sc->sc_dai); 155 } 156 157 int 158 tascodec_activate(struct device *self, int act) 159 { 160 struct tascodec_softc *sc = (struct tascodec_softc *)self; 161 162 switch (act) { 163 case DVACT_POWERDOWN: 164 tascodec_write(sc, PWR_CTL, 165 PWR_CTL_ISNS_PD | PWR_CTL_VSNS_PD | PWR_CTL_MODE_SHUTDOWN); 166 break; 167 } 168 169 return 0; 170 } 171 172 int 173 tascodec_set_format(void *cookie, uint32_t fmt, uint32_t pol, 174 uint32_t clk) 175 { 176 struct tascodec_softc *sc = cookie; 177 uint8_t cfg0, cfg1; 178 179 cfg0 = tascodec_read(sc, TDM_CFG0); 180 cfg1 = tascodec_read(sc, TDM_CFG1); 181 cfg1 &= ~TDM_CFG1_RX_OFFSET_MASK; 182 183 switch (fmt) { 184 case DAI_FORMAT_I2S: 185 cfg0 |= TDM_CFG0_FRAME_START; 186 cfg1 &= ~TDM_CFG1_RX_JUSTIFY; 187 cfg1 |= (1 << TDM_CFG1_RX_OFFSET_SHIFT); 188 cfg1 &= ~TDM_CFG1_RX_EDGE; 189 break; 190 case DAI_FORMAT_RJ: 191 cfg0 &= ~TDM_CFG0_FRAME_START; 192 cfg1 |= TDM_CFG1_RX_JUSTIFY; 193 cfg1 &= ~TDM_CFG1_RX_EDGE; 194 break; 195 case DAI_FORMAT_LJ: 196 cfg0 &= ~TDM_CFG0_FRAME_START; 197 cfg1 &= ~TDM_CFG1_RX_JUSTIFY; 198 cfg1 &= ~TDM_CFG1_RX_EDGE; 199 break; 200 default: 201 return EINVAL; 202 } 203 204 if (pol & DAI_POLARITY_IB) 205 cfg1 ^= TDM_CFG1_RX_EDGE; 206 if (pol & DAI_POLARITY_IF) 207 cfg0 ^= TDM_CFG0_FRAME_START; 208 209 if (!(clk & DAI_CLOCK_CBM) || !(clk & DAI_CLOCK_CFM)) 210 return EINVAL; 211 212 tascodec_write(sc, TDM_CFG0, cfg0); 213 tascodec_write(sc, TDM_CFG1, cfg1); 214 215 return 0; 216 } 217 218 int 219 tascodec_set_tdm_slot(void *cookie, int slot) 220 { 221 struct tascodec_softc *sc = cookie; 222 uint8_t cfg2, cfg3; 223 224 if (slot < 0 || slot >= 16) 225 return EINVAL; 226 227 cfg2 = tascodec_read(sc, TDM_CFG2); 228 cfg3 = tascodec_read(sc, TDM_CFG3); 229 cfg2 &= ~TDM_CFG2_SCFG_MASK; 230 cfg2 |= TDM_CFG2_SCFG_MONO_LEFT; 231 cfg3 &= ~TDM_CFG3_RX_SLOT_L_MASK; 232 cfg3 |= slot << TDM_CFG3_RX_SLOT_L_SHIFT; 233 tascodec_write(sc, TDM_CFG2, cfg2); 234 tascodec_write(sc, TDM_CFG3, cfg3); 235 236 return 0; 237 } 238 239 /* 240 * Mixer controls; the gain of the TAS2770 is determined by the 241 * amplifier gain and digital volume control setting, but we only 242 * expose the digital volume control setting through the mixer 243 * interface. 244 */ 245 enum { 246 TASCODEC_MASTER_VOL, 247 TASCODEC_OUTPUT_CLASS 248 }; 249 250 int 251 tascodec_set_port(void *priv, mixer_ctrl_t *mc) 252 { 253 struct tascodec_softc *sc = priv; 254 u_char level; 255 256 switch (mc->dev) { 257 case TASCODEC_MASTER_VOL: 258 level = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 259 sc->sc_dvc = (PB_CFG2_DVC_PCM_MIN * (255 - level)) / 255; 260 tascodec_write(sc, PB_CFG2, sc->sc_dvc); 261 return 0; 262 } 263 264 return EINVAL; 265 } 266 267 int 268 tascodec_get_port(void *priv, mixer_ctrl_t *mc) 269 { 270 struct tascodec_softc *sc = priv; 271 u_char level; 272 273 switch (mc->dev) { 274 case TASCODEC_MASTER_VOL: 275 mc->un.value.num_channels = 1; 276 level = 255 - ((255 * sc->sc_dvc) / PB_CFG2_DVC_PCM_MIN); 277 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = level; 278 return 0; 279 } 280 281 return EINVAL; 282 } 283 284 int 285 tascodec_query_devinfo(void *priv, mixer_devinfo_t *di) 286 { 287 switch (di->index) { 288 case TASCODEC_MASTER_VOL: 289 di->mixer_class = TASCODEC_OUTPUT_CLASS; 290 di->next = di->prev = AUDIO_MIXER_LAST; 291 strlcpy(di->label.name, AudioNmaster, sizeof(di->label.name)); 292 di->type = AUDIO_MIXER_VALUE; 293 di->un.v.num_channels = 1; 294 strlcpy(di->un.v.units.name, AudioNvolume, 295 sizeof(di->un.v.units.name)); 296 return 0; 297 298 case TASCODEC_OUTPUT_CLASS: 299 di->mixer_class = TASCODEC_OUTPUT_CLASS; 300 di->next = di->prev = AUDIO_MIXER_LAST; 301 strlcpy(di->label.name, AudioCoutputs, sizeof(di->label.name)); 302 di->type = AUDIO_MIXER_CLASS; 303 return 0; 304 } 305 306 return ENXIO; 307 } 308 309 int 310 tascodec_trigger_output(void *cookie, void *start, void *end, int blksize, 311 void (*intr)(void *), void *intrarg, struct audio_params *params) 312 { 313 struct tascodec_softc *sc = cookie; 314 315 tascodec_write(sc, PWR_CTL, 316 PWR_CTL_ISNS_PD | PWR_CTL_VSNS_PD | PWR_CTL_MODE_ACTIVE); 317 return 0; 318 } 319 320 int 321 tascodec_halt_output(void *cookie) 322 { 323 struct tascodec_softc *sc = cookie; 324 325 tascodec_write(sc, PWR_CTL, 326 PWR_CTL_ISNS_PD | PWR_CTL_VSNS_PD | PWR_CTL_MODE_SHUTDOWN); 327 return 0; 328 } 329 330 uint8_t 331 tascodec_read(struct tascodec_softc *sc, int reg) 332 { 333 uint8_t cmd = reg; 334 uint8_t val; 335 int error; 336 337 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 338 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 339 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 340 iic_release_bus(sc->sc_tag, I2C_F_POLL); 341 342 if (error) { 343 printf("%s: can't read register 0x%02x\n", 344 sc->sc_dev.dv_xname, reg); 345 val = 0xff; 346 } 347 348 return val; 349 } 350 351 void 352 tascodec_write(struct tascodec_softc *sc, int reg, uint8_t val) 353 { 354 uint8_t cmd = reg; 355 int error; 356 357 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 358 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 359 &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL); 360 iic_release_bus(sc->sc_tag, I2C_F_POLL); 361 362 if (error) { 363 printf("%s: can't write register 0x%02x\n", 364 sc->sc_dev.dv_xname, reg); 365 } 366 } 367