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