File Index
Files and directories
Sign in
FILE

maya44.c

File preview with syntax highlighting.

linux-6.19.14/sound/pci/ice1712/maya44.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
  4 *
  5 *   Lowlevel functions for ESI Maya44 cards
  6 *
  7 *	Copyright (c) 2009 Takashi Iwai <tiwai@suse.de>
  8 *	Based on the patches by Rainer Zimmermann <mail@lightshed.de>
  9 */
 10
 11#include <linux/init.h>
 12#include <linux/slab.h>
 13#include <sound/core.h>
 14#include <sound/control.h>
 15#include <sound/pcm.h>
 16#include <sound/tlv.h>
 17
 18#include "ice1712.h"
 19#include "envy24ht.h"
 20#include "maya44.h"
 21
 22/* WM8776 register indexes */
 23#define WM8776_REG_HEADPHONE_L		0x00
 24#define WM8776_REG_HEADPHONE_R		0x01
 25#define WM8776_REG_HEADPHONE_MASTER	0x02
 26#define WM8776_REG_DAC_ATTEN_L		0x03
 27#define WM8776_REG_DAC_ATTEN_R		0x04
 28#define WM8776_REG_DAC_ATTEN_MASTER	0x05
 29#define WM8776_REG_DAC_PHASE		0x06
 30#define WM8776_REG_DAC_CONTROL		0x07
 31#define WM8776_REG_DAC_MUTE		0x08
 32#define WM8776_REG_DAC_DEEMPH		0x09
 33#define WM8776_REG_DAC_IF_CONTROL	0x0a
 34#define WM8776_REG_ADC_IF_CONTROL	0x0b
 35#define WM8776_REG_MASTER_MODE_CONTROL	0x0c
 36#define WM8776_REG_POWERDOWN		0x0d
 37#define WM8776_REG_ADC_ATTEN_L		0x0e
 38#define WM8776_REG_ADC_ATTEN_R		0x0f
 39#define WM8776_REG_ADC_ALC1		0x10
 40#define WM8776_REG_ADC_ALC2		0x11
 41#define WM8776_REG_ADC_ALC3		0x12
 42#define WM8776_REG_ADC_NOISE_GATE	0x13
 43#define WM8776_REG_ADC_LIMITER		0x14
 44#define WM8776_REG_ADC_MUX		0x15
 45#define WM8776_REG_OUTPUT_MUX		0x16
 46#define WM8776_REG_RESET		0x17
 47
 48#define WM8776_NUM_REGS			0x18
 49
 50/* clock ratio identifiers for snd_wm8776_set_rate() */
 51#define WM8776_CLOCK_RATIO_128FS	0
 52#define WM8776_CLOCK_RATIO_192FS	1
 53#define WM8776_CLOCK_RATIO_256FS	2
 54#define WM8776_CLOCK_RATIO_384FS	3
 55#define WM8776_CLOCK_RATIO_512FS	4
 56#define WM8776_CLOCK_RATIO_768FS	5
 57
 58enum { WM_VOL_HP, WM_VOL_DAC, WM_VOL_ADC, WM_NUM_VOLS };
 59enum { WM_SW_DAC, WM_SW_BYPASS, WM_NUM_SWITCHES };
 60
 61struct snd_wm8776 {
 62	unsigned char addr;
 63	unsigned short regs[WM8776_NUM_REGS];
 64	unsigned char volumes[WM_NUM_VOLS][2];
 65	unsigned int switch_bits;
 66};
 67
 68struct snd_maya44 {
 69	struct snd_ice1712 *ice;
 70	struct snd_wm8776 wm[2];
 71	struct mutex mutex;
 72};
 73
 74
 75/* write the given register and save the data to the cache */
 76static void wm8776_write(struct snd_ice1712 *ice, struct snd_wm8776 *wm,
 77			 unsigned char reg, unsigned short val)
 78{
 79	/*
 80	 * WM8776 registers are up to 9 bits wide, bit 8 is placed in the LSB
 81	 * of the address field
 82	 */
 83	snd_vt1724_write_i2c(ice, wm->addr,
 84			     (reg << 1) | ((val >> 8) & 1),
 85			     val & 0xff);
 86	wm->regs[reg] = val;
 87}
 88
 89/*
 90 * update the given register with and/or mask and save the data to the cache
 91 */
 92static int wm8776_write_bits(struct snd_ice1712 *ice, struct snd_wm8776 *wm,
 93			     unsigned char reg,
 94			     unsigned short mask, unsigned short val)
 95{
 96	val |= wm->regs[reg] & ~mask;
 97	if (val != wm->regs[reg]) {
 98		wm8776_write(ice, wm, reg, val);
 99		return 1;
100	}
101	return 0;
102}
103
104
105/*
106 * WM8776 volume controls
107 */
108
109struct maya_vol_info {
110	unsigned int maxval;		/* volume range: 0..maxval */
111	unsigned char regs[2];		/* left and right registers */
112	unsigned short mask;		/* value mask */
113	unsigned short offset;		/* zero-value offset */
114	unsigned short mute;		/* mute bit */
115	unsigned short update;		/* update bits */
116	unsigned char mux_bits[2];	/* extra bits for ADC mute */
117};
118
119static const struct maya_vol_info vol_info[WM_NUM_VOLS] = {
120	[WM_VOL_HP] = {
121		.maxval = 80,
122		.regs = { WM8776_REG_HEADPHONE_L, WM8776_REG_HEADPHONE_R },
123		.mask = 0x7f,
124		.offset = 0x30,
125		.mute = 0x00,
126		.update = 0x180,	/* update and zero-cross enable */
127	},
128	[WM_VOL_DAC] = {
129		.maxval = 255,
130		.regs = { WM8776_REG_DAC_ATTEN_L, WM8776_REG_DAC_ATTEN_R },
131		.mask = 0xff,
132		.offset = 0x01,
133		.mute = 0x00,
134		.update = 0x100,	/* zero-cross enable */
135	},
136	[WM_VOL_ADC] = {
137		.maxval = 91,
138		.regs = { WM8776_REG_ADC_ATTEN_L, WM8776_REG_ADC_ATTEN_R },
139		.mask = 0xff,
140		.offset = 0xa5,
141		.mute = 0xa5,
142		.update = 0x100,	/* update */
143		.mux_bits = { 0x80, 0x40 }, /* ADCMUX bits */
144	},
145};
146
147/*
148 * dB tables
149 */
150/* headphone output: mute, -73..+6db (1db step) */
151static const DECLARE_TLV_DB_SCALE(db_scale_hp, -7400, 100, 1);
152/* DAC output: mute, -127..0db (0.5db step) */
153static const DECLARE_TLV_DB_SCALE(db_scale_dac, -12750, 50, 1);
154/* ADC gain: mute, -21..+24db (0.5db step) */
155static const DECLARE_TLV_DB_SCALE(db_scale_adc, -2100, 50, 1);
156
157static int maya_vol_info(struct snd_kcontrol *kcontrol,
158			 struct snd_ctl_elem_info *uinfo)
159{
160	unsigned int idx = kcontrol->private_value;
161	const struct maya_vol_info *vol = &vol_info[idx];
162
163	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
164	uinfo->count = 2;
165	uinfo->value.integer.min = 0;
166	uinfo->value.integer.max = vol->maxval;
167	return 0;
168}
169
170static int maya_vol_get(struct snd_kcontrol *kcontrol,
171			struct snd_ctl_elem_value *ucontrol)
172{
173	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
174	struct snd_wm8776 *wm =
175		&chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
176	unsigned int idx = kcontrol->private_value;
177
178	guard(mutex)(&chip->mutex);
179	ucontrol->value.integer.value[0] = wm->volumes[idx][0];
180	ucontrol->value.integer.value[1] = wm->volumes[idx][1];
181	return 0;
182}
183
184static int maya_vol_put(struct snd_kcontrol *kcontrol,
185			struct snd_ctl_elem_value *ucontrol)
186{
187	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
188	struct snd_wm8776 *wm =
189		&chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
190	unsigned int idx = kcontrol->private_value;
191	const struct maya_vol_info *vol = &vol_info[idx];
192	unsigned int val, data;
193	int ch, changed = 0;
194
195	guard(mutex)(&chip->mutex);
196	for (ch = 0; ch < 2; ch++) {
197		val = ucontrol->value.integer.value[ch];
198		if (val > vol->maxval)
199			val = vol->maxval;
200		if (val == wm->volumes[idx][ch])
201			continue;
202		if (!val)
203			data = vol->mute;
204		else
205			data = (val - 1) + vol->offset;
206		data |= vol->update;
207		changed |= wm8776_write_bits(chip->ice, wm, vol->regs[ch],
208					     vol->mask | vol->update, data);
209		if (vol->mux_bits[ch])
210			wm8776_write_bits(chip->ice, wm, WM8776_REG_ADC_MUX,
211					  vol->mux_bits[ch],
212					  val ? 0 : vol->mux_bits[ch]);
213		wm->volumes[idx][ch] = val;
214	}
215	return changed;
216}
217
218/*
219 * WM8776 switch controls
220 */
221
222#define COMPOSE_SW_VAL(idx, reg, mask)	((idx) | ((reg) << 8) | ((mask) << 16))
223#define GET_SW_VAL_IDX(val)	((val) & 0xff)
224#define GET_SW_VAL_REG(val)	(((val) >> 8) & 0xff)
225#define GET_SW_VAL_MASK(val)	(((val) >> 16) & 0xff)
226
227#define maya_sw_info	snd_ctl_boolean_mono_info
228
229static int maya_sw_get(struct snd_kcontrol *kcontrol,
230		       struct snd_ctl_elem_value *ucontrol)
231{
232	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
233	struct snd_wm8776 *wm =
234		&chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
235	unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value);
236
237	ucontrol->value.integer.value[0] = (wm->switch_bits >> idx) & 1;
238	return 0;
239}
240
241static int maya_sw_put(struct snd_kcontrol *kcontrol,
242		       struct snd_ctl_elem_value *ucontrol)
243{
244	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
245	struct snd_wm8776 *wm =
246		&chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
247	unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value);
248	unsigned int mask, val;
249	int changed;
250
251	guard(mutex)(&chip->mutex);
252	mask = 1 << idx;
253	wm->switch_bits &= ~mask;
254	val = ucontrol->value.integer.value[0];
255	if (val)
256		wm->switch_bits |= mask;
257	mask = GET_SW_VAL_MASK(kcontrol->private_value);
258	changed = wm8776_write_bits(chip->ice, wm,
259				    GET_SW_VAL_REG(kcontrol->private_value),
260				    mask, val ? mask : 0);
261	return changed;
262}
263
264/*
265 * GPIO pins (known ones for maya44)
266 */
267#define GPIO_PHANTOM_OFF	2
268#define GPIO_MIC_RELAY		4
269#define GPIO_SPDIF_IN_INV	5
270#define GPIO_MUST_BE_0		7
271
272/*
273 * GPIO switch controls
274 */
275
276#define COMPOSE_GPIO_VAL(shift, inv)	((shift) | ((inv) << 8))
277#define GET_GPIO_VAL_SHIFT(val)		((val) & 0xff)
278#define GET_GPIO_VAL_INV(val)		(((val) >> 8) & 1)
279
280static int maya_set_gpio_bits(struct snd_ice1712 *ice, unsigned int mask,
281			      unsigned int bits)
282{
283	unsigned int data;
284	data = snd_ice1712_gpio_read(ice);
285	if ((data & mask) == bits)
286		return 0;
287	snd_ice1712_gpio_write(ice, (data & ~mask) | bits);
288	return 1;
289}
290
291#define maya_gpio_sw_info	snd_ctl_boolean_mono_info
292
293static int maya_gpio_sw_get(struct snd_kcontrol *kcontrol,
294			    struct snd_ctl_elem_value *ucontrol)
295{
296	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
297	unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value);
298	unsigned int val;
299
300	val = (snd_ice1712_gpio_read(chip->ice) >> shift) & 1;
301	if (GET_GPIO_VAL_INV(kcontrol->private_value))
302		val = !val;
303	ucontrol->value.integer.value[0] = val;
304	return 0;
305}
306
307static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol,
308			    struct snd_ctl_elem_value *ucontrol)
309{
310	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
311	unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value);
312	unsigned int val, mask;
313	int changed;
314
315	guard(mutex)(&chip->mutex);
316	mask = 1 << shift;
317	val = ucontrol->value.integer.value[0];
318	if (GET_GPIO_VAL_INV(kcontrol->private_value))
319		val = !val;
320	val = val ? mask : 0;
321	changed = maya_set_gpio_bits(chip->ice, mask, val);
322	return changed;
323}
324
325/*
326 * capture source selection
327 */
328
329/* known working input slots (0-4) */
330#define MAYA_LINE_IN	1	/* in-2 */
331#define MAYA_MIC_IN	3	/* in-4 */
332
333static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line)
334{
335	wm8776_write_bits(chip->ice, &chip->wm[idx], WM8776_REG_ADC_MUX,
336			  0x1f, 1 << line);
337}
338
339static int maya_rec_src_info(struct snd_kcontrol *kcontrol,
340			     struct snd_ctl_elem_info *uinfo)
341{
342	static const char * const texts[] = { "Line", "Mic" };
343
344	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
345}
346
347static int maya_rec_src_get(struct snd_kcontrol *kcontrol,
348			    struct snd_ctl_elem_value *ucontrol)
349{
350	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
351	int sel;
352
353	if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY))
354		sel = 1;
355	else
356		sel = 0;
357	ucontrol->value.enumerated.item[0] = sel;
358	return 0;
359}
360
361static int maya_rec_src_put(struct snd_kcontrol *kcontrol,
362			    struct snd_ctl_elem_value *ucontrol)
363{
364	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
365	int sel = ucontrol->value.enumerated.item[0];
366	int changed;
367
368	guard(mutex)(&chip->mutex);
369	changed = maya_set_gpio_bits(chip->ice, 1 << GPIO_MIC_RELAY,
370				     sel ? (1 << GPIO_MIC_RELAY) : 0);
371	wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN);
372	return changed;
373}
374
375/*
376 * Maya44 routing switch settings have different meanings than the standard
377 * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c).
378 */
379static int maya_pb_route_info(struct snd_kcontrol *kcontrol,
380			      struct snd_ctl_elem_info *uinfo)
381{
382	static const char * const texts[] = {
383		"PCM Out", /* 0 */
384		"Input 1", "Input 2", "Input 3", "Input 4"
385	};
386
387	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
388}
389
390static int maya_pb_route_shift(int idx)
391{
392	static const unsigned char shift[10] =
393		{ 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 };
394	return shift[idx % 10];
395}
396
397static int maya_pb_route_get(struct snd_kcontrol *kcontrol,
398			     struct snd_ctl_elem_value *ucontrol)
399{
400	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
401	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
402	ucontrol->value.enumerated.item[0] =
403		snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx));
404	return 0;
405}
406
407static int maya_pb_route_put(struct snd_kcontrol *kcontrol,
408			     struct snd_ctl_elem_value *ucontrol)
409{
410	struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol);
411	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
412	return snd_ice1724_put_route_val(chip->ice,
413					 ucontrol->value.enumerated.item[0],
414					 maya_pb_route_shift(idx));
415}
416
417
418/*
419 * controls to be added
420 */
421
422static const struct snd_kcontrol_new maya_controls[] = {
423	{
424		.name = "Crossmix Playback Volume",
425		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
426		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
427			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
428		.info = maya_vol_info,
429		.get = maya_vol_get,
430		.put = maya_vol_put,
431		.tlv = { .p = db_scale_hp },
432		.private_value = WM_VOL_HP,
433		.count = 2,
434	},
435	{
436		.name = "PCM Playback Volume",
437		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
438		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
439			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
440		.info = maya_vol_info,
441		.get = maya_vol_get,
442		.put = maya_vol_put,
443		.tlv = { .p = db_scale_dac },
444		.private_value = WM_VOL_DAC,
445		.count = 2,
446	},
447	{
448		.name = "Line Capture Volume",
449		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
450		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
451			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
452		.info = maya_vol_info,
453		.get = maya_vol_get,
454		.put = maya_vol_put,
455		.tlv = { .p = db_scale_adc },
456		.private_value = WM_VOL_ADC,
457		.count = 2,
458	},
459	{
460		.name = "PCM Playback Switch",
461		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
462		.info = maya_sw_info,
463		.get = maya_sw_get,
464		.put = maya_sw_put,
465		.private_value = COMPOSE_SW_VAL(WM_SW_DAC,
466						WM8776_REG_OUTPUT_MUX, 0x01),
467		.count = 2,
468	},
469	{
470		.name = "Bypass Playback Switch",
471		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
472		.info = maya_sw_info,
473		.get = maya_sw_get,
474		.put = maya_sw_put,
475		.private_value = COMPOSE_SW_VAL(WM_SW_BYPASS,
476						WM8776_REG_OUTPUT_MUX, 0x04),
477		.count = 2,
478	},
479	{
480		.name = "Capture Source",
481		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
482		.info = maya_rec_src_info,
483		.get = maya_rec_src_get,
484		.put = maya_rec_src_put,
485	},
486	{
487		.name = "Mic Phantom Power Switch",
488		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
489		.info = maya_gpio_sw_info,
490		.get = maya_gpio_sw_get,
491		.put = maya_gpio_sw_put,
492		.private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1),
493	},
494	{
495		.name = "SPDIF Capture Switch",
496		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
497		.info = maya_gpio_sw_info,
498		.get = maya_gpio_sw_get,
499		.put = maya_gpio_sw_put,
500		.private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1),
501	},
502	{
503		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
504		.name = "H/W Playback Route",
505		.info = maya_pb_route_info,
506		.get = maya_pb_route_get,
507		.put = maya_pb_route_put,
508		.count = 4,  /* FIXME: do controls 5-9 have any meaning? */
509	},
510};
511
512static int maya44_add_controls(struct snd_ice1712 *ice)
513{
514	int err, i;
515
516	for (i = 0; i < ARRAY_SIZE(maya_controls); i++) {
517		err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i],
518							  ice->spec));
519		if (err < 0)
520			return err;
521	}
522	return 0;
523}
524
525
526/*
527 * initialize a wm8776 chip
528 */
529static void wm8776_init(struct snd_ice1712 *ice,
530			struct snd_wm8776 *wm, unsigned int addr)
531{
532	static const unsigned short inits_wm8776[] = {
533		0x02, 0x100, /* R2: headphone L+R muted + update */
534		0x05, 0x100, /* R5: DAC output L+R muted + update */
535		0x06, 0x000, /* R6: DAC output phase normal */
536		0x07, 0x091, /* R7: DAC enable zero cross detection,
537				normal output */
538		0x08, 0x000, /* R8: DAC soft mute off */
539		0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */
540		0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */
541		0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit,
542				highpass filter enabled */
543		0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */
544		0x0d, 0x000, /* R13: all power up */
545		0x0e, 0x100, /* R14: ADC left muted,
546				enable zero cross detection */
547		0x0f, 0x100, /* R15: ADC right muted,
548				enable zero cross detection */
549			     /* R16: ALC...*/
550		0x11, 0x000, /* R17: disable ALC */
551			     /* R18: ALC...*/
552			     /* R19: noise gate...*/
553		0x15, 0x000, /* R21: ADC input mux init, mute all inputs */
554		0x16, 0x001, /* R22: output mux, select DAC */
555		0xff, 0xff
556	};
557
558	const unsigned short *ptr;
559	unsigned char reg;
560	unsigned short data;
561
562	wm->addr = addr;
563	/* enable DAC output; mute bypass, aux & all inputs */
564	wm->switch_bits = (1 << WM_SW_DAC);
565
566	ptr = inits_wm8776;
567	while (*ptr != 0xff) {
568		reg = *ptr++;
569		data = *ptr++;
570		wm8776_write(ice, wm, reg, data);
571	}
572}
573
574
575/*
576 * change the rate on the WM8776 codecs.
577 * this assumes that the VT17xx's rate is changed by the calling function.
578 * NOTE: even though the WM8776's are running in slave mode and rate
579 * selection is automatic, we need to call snd_wm8776_set_rate() here
580 * to make sure some flags are set correctly.
581 */
582static void set_rate(struct snd_ice1712 *ice, unsigned int rate)
583{
584	struct snd_maya44 *chip = ice->spec;
585	unsigned int ratio, adc_ratio, val;
586	int i;
587
588	switch (rate) {
589	case 192000:
590		ratio = WM8776_CLOCK_RATIO_128FS;
591		break;
592	case 176400:
593		ratio = WM8776_CLOCK_RATIO_128FS;
594		break;
595	case 96000:
596		ratio = WM8776_CLOCK_RATIO_256FS;
597		break;
598	case 88200:
599		ratio = WM8776_CLOCK_RATIO_384FS;
600		break;
601	case 48000:
602		ratio = WM8776_CLOCK_RATIO_512FS;
603		break;
604	case 44100:
605		ratio = WM8776_CLOCK_RATIO_512FS;
606		break;
607	case 32000:
608		ratio = WM8776_CLOCK_RATIO_768FS;
609		break;
610	case 0:
611		/* no hint - S/PDIF input is master, simply return */
612		return;
613	default:
614		snd_BUG();
615		return;
616	}
617
618	/*
619	 * this currently sets the same rate for ADC and DAC, but limits
620	 * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC
621	 * oversampling to 64x, as recommended by WM8776 datasheet.
622	 * Setting the rate is not really necessary in slave mode.
623	 */
624	adc_ratio = ratio;
625	if (adc_ratio < WM8776_CLOCK_RATIO_256FS)
626		adc_ratio = WM8776_CLOCK_RATIO_256FS;
627
628	val = adc_ratio;
629	if (adc_ratio == WM8776_CLOCK_RATIO_256FS)
630		val |= 8;
631	val |= ratio << 4;
632
633	guard(mutex)(&chip->mutex);
634	for (i = 0; i < 2; i++)
635		wm8776_write_bits(ice, &chip->wm[i],
636				  WM8776_REG_MASTER_MODE_CONTROL,
637				  0x180, val);
638}
639
640/*
641 * supported sample rates (to override the default one)
642 */
643
644static const unsigned int rates[] = {
645	32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000
646};
647
648/* playback rates: 32..192 kHz */
649static const struct snd_pcm_hw_constraint_list dac_rates = {
650	.count = ARRAY_SIZE(rates),
651	.list = rates,
652	.mask = 0
653};
654
655
656/*
657 * chip addresses on I2C bus
658 */
659static const unsigned char wm8776_addr[2] = {
660	0x34, 0x36, /* codec 0 & 1 */
661};
662
663/*
664 * initialize the chip
665 */
666static int maya44_init(struct snd_ice1712 *ice)
667{
668	int i;
669	struct snd_maya44 *chip;
670
671	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
672	if (!chip)
673		return -ENOMEM;
674	mutex_init(&chip->mutex);
675	chip->ice = ice;
676	ice->spec = chip;
677
678	/* initialise codecs */
679	ice->num_total_dacs = 4;
680	ice->num_total_adcs = 4;
681	ice->akm_codecs = 0;
682
683	for (i = 0; i < 2; i++) {
684		wm8776_init(ice, &chip->wm[i], wm8776_addr[i]);
685		wm8776_select_input(chip, i, MAYA_LINE_IN);
686	}
687
688	/* set card specific rates */
689	ice->hw_rates = &dac_rates;
690
691	/* register change rate notifier */
692	ice->gpio.set_pro_rate = set_rate;
693
694	/* RDMA1 (2nd input channel) is used for ADC by default */
695	ice->force_rdma1 = 1;
696
697	/* have an own routing control */
698	ice->own_routing = 1;
699
700	return 0;
701}
702
703
704/*
705 * Maya44 boards don't provide the EEPROM data except for the vendor IDs.
706 * hence the driver needs to sets up it properly.
707 */
708
709static const unsigned char maya44_eeprom[] = {
710	[ICE_EEP2_SYSCONF]     = 0x45,
711		/* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */
712	[ICE_EEP2_ACLINK]      = 0x80,
713		/* I2S */
714	[ICE_EEP2_I2S]         = 0xf8,
715		/* vol, 96k, 24bit, 192k */
716	[ICE_EEP2_SPDIF]       = 0xc3,
717		/* enable spdif out, spdif out supp, spdif-in, ext spdif out */
718	[ICE_EEP2_GPIO_DIR]    = 0xff,
719	[ICE_EEP2_GPIO_DIR1]   = 0xff,
720	[ICE_EEP2_GPIO_DIR2]   = 0xff,
721	[ICE_EEP2_GPIO_MASK]   = 0/*0x9f*/,
722	[ICE_EEP2_GPIO_MASK1]  = 0/*0xff*/,
723	[ICE_EEP2_GPIO_MASK2]  = 0/*0x7f*/,
724	[ICE_EEP2_GPIO_STATE]  = (1 << GPIO_PHANTOM_OFF) |
725			(1 << GPIO_SPDIF_IN_INV),
726	[ICE_EEP2_GPIO_STATE1] = 0x00,
727	[ICE_EEP2_GPIO_STATE2] = 0x00,
728};
729
730/* entry point */
731struct snd_ice1712_card_info snd_vt1724_maya44_cards[] = {
732	{
733		.subvendor = VT1724_SUBDEVICE_MAYA44,
734		.name = "ESI Maya44",
735		.model = "maya44",
736		.chip_init = maya44_init,
737		.build_controls = maya44_add_controls,
738		.eeprom_size = sizeof(maya44_eeprom),
739		.eeprom_data = maya44_eeprom,
740	},
741	{ } /* terminator */
742};
~/ Read-only file preview.