2 * ALSA driver for ICEnsemble VT17xx
4 * Lowlevel functions for WM8766 codec
6 * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org>
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.
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.
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
24 #include <linux/delay.h>
25 #include <sound/core.h>
26 #include <sound/control.h>
27 #include <sound/tlv.h>
30 /* low-level access */
32 static void snd_wm8766_write(struct snd_wm8766
*wm
, u16 addr
, u16 data
)
34 if (addr
< WM8766_REG_COUNT
)
35 wm
->regs
[addr
] = data
;
36 wm
->ops
.write(wm
, addr
, data
);
41 static const DECLARE_TLV_DB_SCALE(wm8766_tlv
, -12750, 50, 1);
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
,
48 .reg1
= WM8766_REG_DACL1
,
49 .reg2
= WM8766_REG_DACR1
,
50 .mask1
= WM8766_VOL_MASK
,
51 .mask2
= WM8766_VOL_MASK
,
53 .flags
= WM8766_FLAG_STEREO
| WM8766_FLAG_VOL_UPDATE
,
55 [WM8766_CTL_CH2_VOL
] = {
56 .name
= "Channel 2 Playback Volume",
57 .type
= SNDRV_CTL_ELEM_TYPE_INTEGER
,
59 .reg1
= WM8766_REG_DACL2
,
60 .reg2
= WM8766_REG_DACR2
,
61 .mask1
= WM8766_VOL_MASK
,
62 .mask2
= WM8766_VOL_MASK
,
64 .flags
= WM8766_FLAG_STEREO
| WM8766_FLAG_VOL_UPDATE
,
66 [WM8766_CTL_CH3_VOL
] = {
67 .name
= "Channel 3 Playback Volume",
68 .type
= SNDRV_CTL_ELEM_TYPE_INTEGER
,
70 .reg1
= WM8766_REG_DACL3
,
71 .reg2
= WM8766_REG_DACR3
,
72 .mask1
= WM8766_VOL_MASK
,
73 .mask2
= WM8766_VOL_MASK
,
75 .flags
= WM8766_FLAG_STEREO
| WM8766_FLAG_VOL_UPDATE
,
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
,
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
,
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
,
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
,
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
,
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
,
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
,
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
,
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
,
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
,
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
,
149 /* exported functions */
151 void snd_wm8766_init(struct snd_wm8766
*wm
)
154 static const u16 default_values
[] = {
157 0x000, 0x100, 0x000, 0x100, 0x000,
161 memcpy(wm
->ctl
, snd_wm8766_default_ctl
, sizeof(wm
->ctl
));
163 snd_wm8766_write(wm
, WM8766_REG_RESET
, 0x00); /* reset */
166 for (i
= 0; i
< ARRAY_SIZE(default_values
); i
++)
167 snd_wm8766_write(wm
, i
, default_values
[i
]);
170 void snd_wm8766_resume(struct snd_wm8766
*wm
)
174 for (i
= 0; i
< WM8766_REG_COUNT
; i
++)
175 snd_wm8766_write(wm
, i
, wm
->regs
[i
]);
178 void snd_wm8766_set_if(struct snd_wm8766
*wm
, u16 dac
)
180 u16 val
= wm
->regs
[WM8766_REG_IFCTRL
] & ~WM8766_IF_MASK
;
182 dac
&= WM8766_IF_MASK
;
183 snd_wm8766_write(wm
, WM8766_REG_IFCTRL
, val
| dac
);
186 void snd_wm8766_volume_restore(struct snd_wm8766
*wm
)
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
);
193 /* mixer callbacks */
195 static int snd_wm8766_volume_info(struct snd_kcontrol
*kcontrol
,
196 struct snd_ctl_elem_info
*uinfo
)
198 struct snd_wm8766
*wm
= snd_kcontrol_chip(kcontrol
);
199 int n
= kcontrol
->private_value
;
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
;
209 static int snd_wm8766_enum_info(struct snd_kcontrol
*kcontrol
,
210 struct snd_ctl_elem_info
*uinfo
)
212 struct snd_wm8766
*wm
= snd_kcontrol_chip(kcontrol
);
213 int n
= kcontrol
->private_value
;
215 return snd_ctl_enum_info(uinfo
, 1, wm
->ctl
[n
].max
,
216 wm
->ctl
[n
].enum_names
);
219 static int snd_wm8766_ctl_get(struct snd_kcontrol
*kcontrol
,
220 struct snd_ctl_elem_value
*ucontrol
)
222 struct snd_wm8766
*wm
= snd_kcontrol_chip(kcontrol
);
223 int n
= kcontrol
->private_value
;
227 wm
->ctl
[n
].get(wm
, &val1
, &val2
);
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
;
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
);
243 ucontrol
->value
.integer
.value
[0] = val1
;
244 if (wm
->ctl
[n
].flags
& WM8766_FLAG_STEREO
)
245 ucontrol
->value
.integer
.value
[1] = val2
;
250 static int snd_wm8766_ctl_put(struct snd_kcontrol
*kcontrol
,
251 struct snd_ctl_elem_value
*ucontrol
)
253 struct snd_wm8766
*wm
= snd_kcontrol_chip(kcontrol
);
254 int n
= kcontrol
->private_value
;
255 u16 val
, regval1
, regval2
;
257 /* this also works for enum because value is an 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
);
265 wm
->ctl
[n
].set(wm
, regval1
, regval2
);
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
);
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
);
290 static int snd_wm8766_add_control(struct snd_wm8766
*wm
, int num
)
292 struct snd_kcontrol_new cont
;
293 struct snd_kcontrol
*ctl
;
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
;
304 cont
.get
= snd_wm8766_ctl_get
;
305 cont
.put
= snd_wm8766_ctl_put
;
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
;
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
;
318 cont
.info
= snd_ctl_boolean_mono_info
;
320 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
321 cont
.info
= snd_wm8766_enum_info
;
326 ctl
= snd_ctl_new1(&cont
, wm
);
329 wm
->ctl
[num
].kctl
= ctl
;
331 return snd_ctl_add(wm
->card
, ctl
);
334 int snd_wm8766_build_controls(struct snd_wm8766
*wm
)
338 for (i
= 0; i
< WM8766_CTL_COUNT
; i
++)
339 if (wm
->ctl
[i
].name
) {
340 err
= snd_wm8766_add_control(wm
, i
);