xref: /linux/sound/pci/ice1712/wm8766.c (revision f7af616c632ee2ac3af0876fe33bf9e0232e665a)
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 const 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