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_volume_restore(struct snd_wm8766 *wm) 187 { 188 u16 val = wm->regs[WM8766_REG_DACR1]; 189 /* restore volume after MCLK stopped */ 190 snd_wm8766_write(wm, WM8766_REG_DACR1, val | WM8766_VOL_UPDATE); 191 } 192 193 /* mixer callbacks */ 194 195 static int snd_wm8766_volume_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 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 202 uinfo->count = (wm->ctl[n].flags & WM8766_FLAG_STEREO) ? 2 : 1; 203 uinfo->value.integer.min = wm->ctl[n].min; 204 uinfo->value.integer.max = wm->ctl[n].max; 205 206 return 0; 207 } 208 209 static int snd_wm8766_enum_info(struct snd_kcontrol *kcontrol, 210 struct snd_ctl_elem_info *uinfo) 211 { 212 struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); 213 int n = kcontrol->private_value; 214 215 return snd_ctl_enum_info(uinfo, 1, wm->ctl[n].max, 216 wm->ctl[n].enum_names); 217 } 218 219 static int snd_wm8766_ctl_get(struct snd_kcontrol *kcontrol, 220 struct snd_ctl_elem_value *ucontrol) 221 { 222 struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); 223 int n = kcontrol->private_value; 224 u16 val1, val2; 225 226 if (wm->ctl[n].get) 227 wm->ctl[n].get(wm, &val1, &val2); 228 else { 229 val1 = wm->regs[wm->ctl[n].reg1] & wm->ctl[n].mask1; 230 val1 >>= __ffs(wm->ctl[n].mask1); 231 if (wm->ctl[n].flags & WM8766_FLAG_STEREO) { 232 val2 = wm->regs[wm->ctl[n].reg2] & wm->ctl[n].mask2; 233 val2 >>= __ffs(wm->ctl[n].mask2); 234 if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE) 235 val2 &= ~WM8766_VOL_UPDATE; 236 } 237 } 238 if (wm->ctl[n].flags & WM8766_FLAG_INVERT) { 239 val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min); 240 if (wm->ctl[n].flags & WM8766_FLAG_STEREO) 241 val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min); 242 } 243 ucontrol->value.integer.value[0] = val1; 244 if (wm->ctl[n].flags & WM8766_FLAG_STEREO) 245 ucontrol->value.integer.value[1] = val2; 246 247 return 0; 248 } 249 250 static int snd_wm8766_ctl_put(struct snd_kcontrol *kcontrol, 251 struct snd_ctl_elem_value *ucontrol) 252 { 253 struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); 254 int n = kcontrol->private_value; 255 u16 val, regval1, regval2; 256 257 /* this also works for enum because value is a union */ 258 regval1 = ucontrol->value.integer.value[0]; 259 regval2 = ucontrol->value.integer.value[1]; 260 if (wm->ctl[n].flags & WM8766_FLAG_INVERT) { 261 regval1 = wm->ctl[n].max - (regval1 - wm->ctl[n].min); 262 regval2 = wm->ctl[n].max - (regval2 - wm->ctl[n].min); 263 } 264 if (wm->ctl[n].set) 265 wm->ctl[n].set(wm, regval1, regval2); 266 else { 267 val = wm->regs[wm->ctl[n].reg1] & ~wm->ctl[n].mask1; 268 val |= regval1 << __ffs(wm->ctl[n].mask1); 269 /* both stereo controls in one register */ 270 if (wm->ctl[n].flags & WM8766_FLAG_STEREO && 271 wm->ctl[n].reg1 == wm->ctl[n].reg2) { 272 val &= ~wm->ctl[n].mask2; 273 val |= regval2 << __ffs(wm->ctl[n].mask2); 274 } 275 snd_wm8766_write(wm, wm->ctl[n].reg1, val); 276 /* stereo controls in different registers */ 277 if (wm->ctl[n].flags & WM8766_FLAG_STEREO && 278 wm->ctl[n].reg1 != wm->ctl[n].reg2) { 279 val = wm->regs[wm->ctl[n].reg2] & ~wm->ctl[n].mask2; 280 val |= regval2 << __ffs(wm->ctl[n].mask2); 281 if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE) 282 val |= WM8766_VOL_UPDATE; 283 snd_wm8766_write(wm, wm->ctl[n].reg2, val); 284 } 285 } 286 287 return 0; 288 } 289 290 static int snd_wm8766_add_control(struct snd_wm8766 *wm, int num) 291 { 292 struct snd_kcontrol_new cont; 293 struct snd_kcontrol *ctl; 294 295 memset(&cont, 0, sizeof(cont)); 296 cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 297 cont.private_value = num; 298 cont.name = wm->ctl[num].name; 299 cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; 300 if (wm->ctl[num].flags & WM8766_FLAG_LIM || 301 wm->ctl[num].flags & WM8766_FLAG_ALC) 302 cont.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; 303 cont.tlv.p = NULL; 304 cont.get = snd_wm8766_ctl_get; 305 cont.put = snd_wm8766_ctl_put; 306 307 switch (wm->ctl[num].type) { 308 case SNDRV_CTL_ELEM_TYPE_INTEGER: 309 cont.info = snd_wm8766_volume_info; 310 cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; 311 cont.tlv.p = wm->ctl[num].tlv; 312 break; 313 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 314 wm->ctl[num].max = 1; 315 if (wm->ctl[num].flags & WM8766_FLAG_STEREO) 316 cont.info = snd_ctl_boolean_stereo_info; 317 else 318 cont.info = snd_ctl_boolean_mono_info; 319 break; 320 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 321 cont.info = snd_wm8766_enum_info; 322 break; 323 default: 324 return -EINVAL; 325 } 326 ctl = snd_ctl_new1(&cont, wm); 327 if (!ctl) 328 return -ENOMEM; 329 wm->ctl[num].kctl = ctl; 330 331 return snd_ctl_add(wm->card, ctl); 332 } 333 334 int snd_wm8766_build_controls(struct snd_wm8766 *wm) 335 { 336 int err, i; 337 338 for (i = 0; i < WM8766_CTL_COUNT; i++) 339 if (wm->ctl[i].name) { 340 err = snd_wm8766_add_control(wm, i); 341 if (err < 0) 342 return err; 343 } 344 345 return 0; 346 } 347