~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/pci/ice1712/maya44.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php