1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ALSA driver for ICEnsemble VT17xx 4 * 5 * Lowlevel functions for WM8766 codec 6 * 7 * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> 8 */ 9 10 #include <linux/delay.h> 11 #include <sound/core.h> 12 #include <sound/control.h> 13 #include <sound/tlv.h> 14 #include "wm8766.h" 15 16 /* low-level access */ 17 18 static void snd_wm8766_write(struct snd_wm8766 *wm, u16 addr, u16 data) 19 { 20 if (addr < WM8766_REG_COUNT) 21 wm->regs[addr] = data; 22 wm->ops.write(wm, addr, data); 23 } 24 25 /* mixer controls */ 26 27 static const DECLARE_TLV_DB_SCALE(wm8766_tlv, -12750, 50, 1); 28 29 static struct snd_wm8766_ctl snd_wm8766_default_ctl[WM8766_CTL_COUNT] = { 30 [WM8766_CTL_CH1_VOL] = { 31 .name = "Channel 1 Playback Volume", 32 .type = SNDRV_CTL_ELEM_TYPE_INTEGER, 33 .tlv = wm8766_tlv, 34 .reg1 = WM8766_REG_DACL1, 35 .reg2 = WM8766_REG_DACR1, 36 .mask1 = WM8766_VOL_MASK, 37 .mask2 = WM8766_VOL_MASK, 38 .max = 0xff, 39 .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE, 40 }, 41 [WM8766_CTL_CH2_VOL] = { 42 .name = "Channel 2 Playback Volume", 43 .type = SNDRV_CTL_ELEM_TYPE_INTEGER, 44 .tlv = wm8766_tlv, 45 .reg1 = WM8766_REG_DACL2, 46 .reg2 = WM8766_REG_DACR2, 47 .mask1 = WM8766_VOL_MASK, 48 .mask2 = WM8766_VOL_MASK, 49 .max = 0xff, 50 .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE, 51 }, 52 [WM8766_CTL_CH3_VOL] = { 53 .name = "Channel 3 Playback Volume", 54 .type = SNDRV_CTL_ELEM_TYPE_INTEGER, 55 .tlv = wm8766_tlv, 56 .reg1 = WM8766_REG_DACL3, 57 .reg2 = WM8766_REG_DACR3, 58 .mask1 = WM8766_VOL_MASK, 59 .mask2 = WM8766_VOL_MASK, 60 .max = 0xff, 61 .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE, 62 }, 63 [WM8766_CTL_CH1_SW] = { 64 .name = "Channel 1 Playback Switch", 65 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 66 .reg1 = WM8766_REG_DACCTRL2, 67 .mask1 = WM8766_DAC2_MUTE1, 68 .flags = WM8766_FLAG_INVERT, 69 }, 70 [WM8766_CTL_CH2_SW] = { 71 .name = "Channel 2 Playback Switch", 72 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 73 .reg1 = WM8766_REG_DACCTRL2, 74 .mask1 = WM8766_DAC2_MUTE2, 75 .flags = WM8766_FLAG_INVERT, 76 }, 77 [WM8766_CTL_CH3_SW] = { 78 .name = "Channel 3 Playback Switch", 79 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 80 .reg1 = WM8766_REG_DACCTRL2, 81 .mask1 = WM8766_DAC2_MUTE3, 82 .flags = WM8766_FLAG_INVERT, 83 }, 84 [WM8766_CTL_PHASE1_SW] = { 85 .name = "Channel 1 Phase Invert Playback Switch", 86 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 87 .reg1 = WM8766_REG_IFCTRL, 88 .mask1 = WM8766_PHASE_INVERT1, 89 }, 90 [WM8766_CTL_PHASE2_SW] = { 91 .name = "Channel 2 Phase Invert Playback Switch", 92 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 93 .reg1 = WM8766_REG_IFCTRL, 94 .mask1 = WM8766_PHASE_INVERT2, 95 }, 96 [WM8766_CTL_PHASE3_SW] = { 97 .name = "Channel 3 Phase Invert Playback Switch", 98 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 99 .reg1 = WM8766_REG_IFCTRL, 100 .mask1 = WM8766_PHASE_INVERT3, 101 }, 102 [WM8766_CTL_DEEMPH1_SW] = { 103 .name = "Channel 1 Deemphasis Playback Switch", 104 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 105 .reg1 = WM8766_REG_DACCTRL2, 106 .mask1 = WM8766_DAC2_DEEMP1, 107 }, 108 [WM8766_CTL_DEEMPH2_SW] = { 109 .name = "Channel 2 Deemphasis Playback Switch", 110 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 111 .reg1 = WM8766_REG_DACCTRL2, 112 .mask1 = WM8766_DAC2_DEEMP2, 113 }, 114 [WM8766_CTL_DEEMPH3_SW] = { 115 .name = "Channel 3 Deemphasis Playback Switch", 116 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 117 .reg1 = WM8766_REG_DACCTRL2, 118 .mask1 = WM8766_DAC2_DEEMP3, 119 }, 120 [WM8766_CTL_IZD_SW] = { 121 .name = "Infinite Zero Detect Playback Switch", 122 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 123 .reg1 = WM8766_REG_DACCTRL1, 124 .mask1 = WM8766_DAC_IZD, 125 }, 126 [WM8766_CTL_ZC_SW] = { 127 .name = "Zero Cross Detect Playback Switch", 128 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, 129 .reg1 = WM8766_REG_DACCTRL2, 130 .mask1 = WM8766_DAC2_ZCD, 131 .flags = WM8766_FLAG_INVERT, 132 }, 133 }; 134 135 /* exported functions */ 136 137 void snd_wm8766_init(struct snd_wm8766 *wm) 138 { 139 int i; 140 static const u16 default_values[] = { 141 0x000, 0x100, 142 0x120, 0x000, 143 0x000, 0x100, 0x000, 0x100, 0x000, 144 0x000, 0x080, 145 }; 146 147 memcpy(wm->ctl, snd_wm8766_default_ctl, sizeof(wm->ctl)); 148 149 snd_wm8766_write(wm, WM8766_REG_RESET, 0x00); /* reset */ 150 udelay(10); 151 /* load defaults */ 152 for (i = 0; i < ARRAY_SIZE(default_values); i++) 153 snd_wm8766_write(wm, i, default_values[i]); 154 } 155 156 void snd_wm8766_resume(struct snd_wm8766 *wm) 157 { 158 int i; 159 160 for (i = 0; i < WM8766_REG_COUNT; i++) 161 snd_wm8766_write(wm, i, wm->regs[i]); 162 } 163 164 void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac) 165 { 166 u16 val = wm->regs[WM8766_REG_IFCTRL] & ~WM8766_IF_MASK; 167 168 dac &= WM8766_IF_MASK; 169 snd_wm8766_write(wm, WM8766_REG_IFCTRL, val | dac); 170 } 171 172 void snd_wm8766_volume_restore(struct snd_wm8766 *wm) 173 { 174 u16 val = wm->regs[WM8766_REG_DACR1]; 175 /* restore volume after MCLK stopped */ 176 snd_wm8766_write(wm, WM8766_REG_DACR1, val | WM8766_VOL_UPDATE); 177 } 178 179 /* mixer callbacks */ 180 181 static int snd_wm8766_volume_info(struct snd_kcontrol *kcontrol, 182 struct snd_ctl_elem_info *uinfo) 183 { 184 struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); 185 int n = kcontrol->private_value; 186 187 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 188 uinfo->count = (wm->ctl[n].flags & WM8766_FLAG_STEREO) ? 2 : 1; 189 uinfo->value.integer.min = wm->ctl[n].min; 190 uinfo->value.integer.max = wm->ctl[n].max; 191 192 return 0; 193 } 194 195 static int snd_wm8766_enum_info(struct snd_kcontrol *kcontrol, 196 struct snd_ctl_elem_info *uinfo) 197 { 198 struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); 199 int n = kcontrol->private_value; 200 201 return snd_ctl_enum_info(uinfo, 1, wm->ctl[n].max, 202 wm->ctl[n].enum_names); 203 } 204 205 static int snd_wm8766_ctl_get(struct snd_kcontrol *kcontrol, 206 struct snd_ctl_elem_value *ucontrol) 207 { 208 struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); 209 int n = kcontrol->private_value; 210 u16 val1, val2; 211 212 if (wm->ctl[n].get) 213 wm->ctl[n].get(wm, &val1, &val2); 214 else { 215 val1 = wm->regs[wm->ctl[n].reg1] & wm->ctl[n].mask1; 216 val1 >>= __ffs(wm->ctl[n].mask1); 217 if (wm->ctl[n].flags & WM8766_FLAG_STEREO) { 218 val2 = wm->regs[wm->ctl[n].reg2] & wm->ctl[n].mask2; 219 val2 >>= __ffs(wm->ctl[n].mask2); 220 if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE) 221 val2 &= ~WM8766_VOL_UPDATE; 222 } 223 } 224 if (wm->ctl[n].flags & WM8766_FLAG_INVERT) { 225 val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min); 226 if (wm->ctl[n].flags & WM8766_FLAG_STEREO) 227 val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min); 228 } 229 ucontrol->value.integer.value[0] = val1; 230 if (wm->ctl[n].flags & WM8766_FLAG_STEREO) 231 ucontrol->value.integer.value[1] = val2; 232 233 return 0; 234 } 235 236 static int snd_wm8766_ctl_put(struct snd_kcontrol *kcontrol, 237 struct snd_ctl_elem_value *ucontrol) 238 { 239 struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); 240 int n = kcontrol->private_value; 241 u16 val, regval1, regval2; 242 243 /* this also works for enum because value is a union */ 244 regval1 = ucontrol->value.integer.value[0]; 245 regval2 = ucontrol->value.integer.value[1]; 246 if (wm->ctl[n].flags & WM8766_FLAG_INVERT) { 247 regval1 = wm->ctl[n].max - (regval1 - wm->ctl[n].min); 248 regval2 = wm->ctl[n].max - (regval2 - wm->ctl[n].min); 249 } 250 if (wm->ctl[n].set) 251 wm->ctl[n].set(wm, regval1, regval2); 252 else { 253 val = wm->regs[wm->ctl[n].reg1] & ~wm->ctl[n].mask1; 254 val |= regval1 << __ffs(wm->ctl[n].mask1); 255 /* both stereo controls in one register */ 256 if (wm->ctl[n].flags & WM8766_FLAG_STEREO && 257 wm->ctl[n].reg1 == wm->ctl[n].reg2) { 258 val &= ~wm->ctl[n].mask2; 259 val |= regval2 << __ffs(wm->ctl[n].mask2); 260 } 261 snd_wm8766_write(wm, wm->ctl[n].reg1, val); 262 /* stereo controls in different registers */ 263 if (wm->ctl[n].flags & WM8766_FLAG_STEREO && 264 wm->ctl[n].reg1 != wm->ctl[n].reg2) { 265 val = wm->regs[wm->ctl[n].reg2] & ~wm->ctl[n].mask2; 266 val |= regval2 << __ffs(wm->ctl[n].mask2); 267 if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE) 268 val |= WM8766_VOL_UPDATE; 269 snd_wm8766_write(wm, wm->ctl[n].reg2, val); 270 } 271 } 272 273 return 0; 274 } 275 276 static int snd_wm8766_add_control(struct snd_wm8766 *wm, int num) 277 { 278 struct snd_kcontrol_new cont; 279 struct snd_kcontrol *ctl; 280 281 memset(&cont, 0, sizeof(cont)); 282 cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 283 cont.private_value = num; 284 cont.name = wm->ctl[num].name; 285 cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; 286 if (wm->ctl[num].flags & WM8766_FLAG_LIM || 287 wm->ctl[num].flags & WM8766_FLAG_ALC) 288 cont.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; 289 cont.tlv.p = NULL; 290 cont.get = snd_wm8766_ctl_get; 291 cont.put = snd_wm8766_ctl_put; 292 293 switch (wm->ctl[num].type) { 294 case SNDRV_CTL_ELEM_TYPE_INTEGER: 295 cont.info = snd_wm8766_volume_info; 296 cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; 297 cont.tlv.p = wm->ctl[num].tlv; 298 break; 299 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 300 wm->ctl[num].max = 1; 301 if (wm->ctl[num].flags & WM8766_FLAG_STEREO) 302 cont.info = snd_ctl_boolean_stereo_info; 303 else 304 cont.info = snd_ctl_boolean_mono_info; 305 break; 306 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 307 cont.info = snd_wm8766_enum_info; 308 break; 309 default: 310 return -EINVAL; 311 } 312 ctl = snd_ctl_new1(&cont, wm); 313 if (!ctl) 314 return -ENOMEM; 315 wm->ctl[num].kctl = ctl; 316 317 return snd_ctl_add(wm->card, ctl); 318 } 319 320 int snd_wm8766_build_controls(struct snd_wm8766 *wm) 321 { 322 int err, i; 323 324 for (i = 0; i < WM8766_CTL_COUNT; i++) 325 if (wm->ctl[i].name) { 326 err = snd_wm8766_add_control(wm, i); 327 if (err < 0) 328 return err; 329 } 330 331 return 0; 332 } 333