03b4ece02f913278d8b3506374482c059a0c6b1f
[pandora-kernel.git] / drivers / staging / intel_sst / intelmid_ctrl.c
1 /*
2  *  intelmid_ctrl.c - Intel Sound card driver for MID
3  *
4  *  Copyright (C) 2008-10 Intel Corp
5  *  Authors:    Harsha Priya <priya.harsha@intel.com>
6  *              Vinod Koul <vinod.koul@intel.com>
7  *              Dharageswari R <dharageswari.r@intel.com>
8  *              KP Jeeja <jeeja.kp@intel.com>
9  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation version 2 of the License.
14  *
15  *  This program is distributed in the hope that it will be useful, but
16  *  WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License along
21  *  with this program; if not, write to the Free Software Foundation, Inc.,
22  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23  *
24  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25  *  ALSA driver handling mixer controls for Intel MAD chipset
26  */
27 #include <sound/core.h>
28 #include <sound/control.h>
29 #include "jack.h"
30 #include "intel_sst.h"
31 #include "intel_sst_ioctl.h"
32 #include "intelmid_snd_control.h"
33 #include "intelmid.h"
34
35 static char *out_names_mrst[] = {"Headphones",
36                                 "Internal speakers"};
37 static char *in_names_mrst[] = {"AMIC",
38                                 "DMIC",
39                                 "HS_MIC"};
40 static char *out_names_mfld[] = {"Headset ",
41                                 "EarPiece  "};
42 static char *in_names_mfld[] = {"AMIC",
43                                 "DMIC"};
44
45 struct snd_control_val intelmad_ctrl_val[MAX_VENDORS] = {
46         {
47                 .playback_vol_max = 63,
48                 .playback_vol_min = 0,
49                 .capture_vol_max = 63,
50                 .capture_vol_min = 0,
51         },
52         {
53                 .playback_vol_max = 0,
54                 .playback_vol_min = -31,
55                 .capture_vol_max = 0,
56                 .capture_vol_min = -20,
57         },
58         {
59                 .playback_vol_max = 0,
60                 .playback_vol_min = -126,
61                 .capture_vol_max = 0,
62                 .capture_vol_min = -31,
63         },
64 };
65
66 /* control path functionalities */
67
68 static inline int snd_intelmad_volume_info(struct snd_ctl_elem_info *uinfo,
69                                         int control_type, int max, int min)
70 {
71         WARN_ON(!uinfo);
72
73         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
74         uinfo->count = control_type;
75         uinfo->value.integer.min = min;
76         uinfo->value.integer.max = max;
77         return 0;
78 }
79
80 /**
81 * snd_intelmad_mute_info - provides information about the mute controls
82 *
83 * @kcontrol:    pointer to the control
84 * @uinfo:       pointer to the structure where the control's info need
85 *               to be filled
86 *
87 * This function is called when a mixer application requests for control's info
88 */
89 static int snd_intelmad_mute_info(struct snd_kcontrol *kcontrol,
90                                         struct snd_ctl_elem_info *uinfo)
91 {
92         WARN_ON(!uinfo);
93         WARN_ON(!kcontrol);
94
95         /* set up the mute as a boolean mono control with min-max values */
96         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
97         uinfo->count = MONO_CNTL;
98         uinfo->value.integer.min = MIN_MUTE;
99         uinfo->value.integer.max = MAX_MUTE;
100         return 0;
101 }
102
103 /**
104 * snd_intelmad_capture_volume_info - provides info about the volume control
105 *
106 * @kcontrol:    pointer to the control
107 * @uinfo:       pointer to the structure where the control's info need
108 *               to be filled
109 *
110 * This function is called when a mixer application requests for control's info
111 */
112 static int snd_intelmad_capture_volume_info(struct snd_kcontrol *kcontrol,
113                                         struct snd_ctl_elem_info *uinfo)
114 {
115         snd_intelmad_volume_info(uinfo, MONO_CNTL,
116                 intelmad_ctrl_val[sst_card_vendor_id].capture_vol_max,
117                 intelmad_ctrl_val[sst_card_vendor_id].capture_vol_min);
118         return 0;
119 }
120
121 /**
122 * snd_intelmad_playback_volume_info - provides info about the volume control
123 *
124 * @kcontrol:    pointer to the control
125 * @uinfo:       pointer to the structure where the control's info need
126 *               to be filled
127 *
128 * This function is called when a mixer application requests for control's info
129 */
130 static int snd_intelmad_playback_volume_info(struct snd_kcontrol *kcontrol,
131                                         struct snd_ctl_elem_info *uinfo)
132 {
133         snd_intelmad_volume_info(uinfo, STEREO_CNTL,
134                 intelmad_ctrl_val[sst_card_vendor_id].playback_vol_max,
135                 intelmad_ctrl_val[sst_card_vendor_id].playback_vol_min);
136         return 0;
137 }
138
139 /**
140 * snd_intelmad_device_info_mrst - provides information about the devices available
141 *
142 * @kcontrol:    pointer to the control
143 * @uinfo:       pointer to the structure where the devices's info need
144 *               to be filled
145 *
146 * This function is called when a mixer application requests for device's info
147 */
148 static int snd_intelmad_device_info_mrst(struct snd_kcontrol *kcontrol,
149                                         struct snd_ctl_elem_info *uinfo)
150 {
151
152         WARN_ON(!kcontrol);
153         WARN_ON(!uinfo);
154
155         /* setup device select as drop down controls with different values */
156         if (kcontrol->id.numid == OUTPUT_SEL)
157                 uinfo->value.enumerated.items = ARRAY_SIZE(out_names_mrst);
158         else
159                 uinfo->value.enumerated.items = ARRAY_SIZE(in_names_mrst);
160         uinfo->count = MONO_CNTL;
161         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
162
163         if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
164                 uinfo->value.enumerated.item = 1;
165         if (kcontrol->id.numid == OUTPUT_SEL)
166                 strncpy(uinfo->value.enumerated.name,
167                         out_names_mrst[uinfo->value.enumerated.item],
168                         sizeof(uinfo->value.enumerated.name)-1);
169         else
170                 strncpy(uinfo->value.enumerated.name,
171                         in_names_mrst[uinfo->value.enumerated.item],
172                         sizeof(uinfo->value.enumerated.name)-1);
173         return 0;
174 }
175
176 static int snd_intelmad_device_info_mfld(struct snd_kcontrol *kcontrol,
177                                         struct snd_ctl_elem_info *uinfo)
178 {
179         WARN_ON(!kcontrol);
180         WARN_ON(!uinfo);
181         /* setup device select as drop down controls with different values */
182         if (kcontrol->id.numid == OUTPUT_SEL)
183                 uinfo->value.enumerated.items = ARRAY_SIZE(out_names_mfld);
184         else
185                 uinfo->value.enumerated.items = ARRAY_SIZE(in_names_mfld);
186         uinfo->count = MONO_CNTL;
187         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
188
189         if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
190                 uinfo->value.enumerated.item = 1;
191         if (kcontrol->id.numid == OUTPUT_SEL)
192                 strncpy(uinfo->value.enumerated.name,
193                         out_names_mfld[uinfo->value.enumerated.item],
194                         sizeof(uinfo->value.enumerated.name)-1);
195         else
196                 strncpy(uinfo->value.enumerated.name,
197                         in_names_mfld[uinfo->value.enumerated.item],
198                         sizeof(uinfo->value.enumerated.name)-1);
199         return 0;
200 }
201
202 /**
203 * snd_intelmad_volume_get - gets the current volume for the control
204 *
205 * @kcontrol:    pointer to the control
206 * @uval:        pointer to the structure where the control's info need
207 *               to be filled
208 *
209 * This function is called when .get function of a control is invoked from app
210 */
211 static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol,
212                                 struct snd_ctl_elem_value *uval)
213 {
214         int ret_val = 0, cntl_list[2] = {0,};
215         int value = 0;
216         struct snd_intelmad *intelmaddata;
217         struct snd_pmic_ops *scard_ops;
218
219         pr_debug("sst: snd_intelmad_volume_get called\n");
220
221         WARN_ON(!uval);
222         WARN_ON(!kcontrol);
223
224         intelmaddata = kcontrol->private_data;
225
226         WARN_ON(!intelmaddata->sstdrv_ops);
227
228         scard_ops = intelmaddata->sstdrv_ops->scard_ops;
229
230         WARN_ON(!scard_ops);
231
232         switch (kcontrol->id.numid) {
233         case PLAYBACK_VOL:
234                 cntl_list[0] = PMIC_SND_RIGHT_PB_VOL;
235                 cntl_list[1] = PMIC_SND_LEFT_PB_VOL;
236                 break;
237
238         case CAPTURE_VOL:
239                 cntl_list[0] = PMIC_SND_CAPTURE_VOL;
240                 break;
241         default:
242                 return -EINVAL;
243         }
244
245         ret_val = scard_ops->get_vol(cntl_list[0], &value);
246         uval->value.integer.value[0] = value;
247
248         if (ret_val)
249                 return ret_val;
250
251         if (kcontrol->id.numid == PLAYBACK_VOL) {
252                 ret_val = scard_ops->get_vol(cntl_list[1], &value);
253                 uval->value.integer.value[1] = value;
254         }
255         return ret_val;
256 }
257
258 /**
259 * snd_intelmad_mute_get - gets the current mute status for the control
260 *
261 * @kcontrol:    pointer to the control
262 * @uval:        pointer to the structure where the control's info need
263 *               to be filled
264 *
265 * This function is called when .get function of a control is invoked from app
266 */
267 static int snd_intelmad_mute_get(struct snd_kcontrol *kcontrol,
268                                         struct snd_ctl_elem_value *uval)
269 {
270
271         int cntl_list = 0, ret_val = 0;
272         u8 value = 0;
273         struct snd_intelmad *intelmaddata;
274         struct snd_pmic_ops *scard_ops;
275
276         pr_debug("sst: Mute_get called\n");
277
278         WARN_ON(!uval);
279         WARN_ON(!kcontrol);
280
281         intelmaddata = kcontrol->private_data;
282
283         WARN_ON(!intelmaddata->sstdrv_ops);
284
285         scard_ops = intelmaddata->sstdrv_ops->scard_ops;
286
287         WARN_ON(!scard_ops);
288
289         switch (kcontrol->id.numid) {
290         case PLAYBACK_MUTE:
291                 if (intelmaddata->output_sel == STEREO_HEADPHONE)
292                         cntl_list = PMIC_SND_LEFT_HP_MUTE;
293                 else if ((intelmaddata->output_sel == INTERNAL_SPKR) ||
294                         (intelmaddata->output_sel == MONO_EARPIECE))
295                         cntl_list = PMIC_SND_LEFT_SPEAKER_MUTE;
296                 break;
297
298         case CAPTURE_MUTE:
299                 if (intelmaddata->input_sel == DMIC)
300                         cntl_list = PMIC_SND_DMIC_MUTE;
301                 else if (intelmaddata->input_sel == AMIC)
302                         cntl_list = PMIC_SND_AMIC_MUTE;
303                 else if (intelmaddata->input_sel == HS_MIC)
304                         cntl_list = PMIC_SND_HP_MIC_MUTE;
305                 break;
306         case MASTER_MUTE:
307                 uval->value.integer.value[0] = intelmaddata->master_mute;
308                 return 0;
309         default:
310                 return -EINVAL;
311         }
312
313         ret_val = scard_ops->get_mute(cntl_list, &value);
314         uval->value.integer.value[0] = value;
315         return ret_val;
316 }
317
318 /**
319 * snd_intelmad_volume_set - sets the volume control's info
320 *
321 * @kcontrol:    pointer to the control
322 * @uval:        pointer to the structure where the control's info is
323 *               available to be set
324 *
325 * This function is called when .set function of a control is invoked from app
326 */
327 static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol,
328                                         struct snd_ctl_elem_value *uval)
329 {
330
331         int ret_val, cntl_list[2] = {0,};
332         struct snd_intelmad *intelmaddata;
333         struct snd_pmic_ops *scard_ops;
334
335         pr_debug("sst: volume set called:%ld %ld\n",
336                         uval->value.integer.value[0],
337                         uval->value.integer.value[1]);
338
339         WARN_ON(!uval);
340         WARN_ON(!kcontrol);
341
342         intelmaddata = kcontrol->private_data;
343
344         WARN_ON(!intelmaddata->sstdrv_ops);
345
346         scard_ops = intelmaddata->sstdrv_ops->scard_ops;
347
348         WARN_ON(!scard_ops);
349
350         switch (kcontrol->id.numid) {
351         case PLAYBACK_VOL:
352                 cntl_list[0] = PMIC_SND_LEFT_PB_VOL;
353                 cntl_list[1] = PMIC_SND_RIGHT_PB_VOL;
354                 break;
355
356         case CAPTURE_VOL:
357                 cntl_list[0] = PMIC_SND_CAPTURE_VOL;
358                 break;
359         default:
360                 return -EINVAL;
361         }
362
363         ret_val = scard_ops->set_vol(cntl_list[0],
364                                 uval->value.integer.value[0]);
365         if (ret_val)
366                 return ret_val;
367
368         if (kcontrol->id.numid == PLAYBACK_VOL)
369                 ret_val = scard_ops->set_vol(cntl_list[1],
370                                 uval->value.integer.value[1]);
371         return ret_val;
372 }
373
374 /**
375 * snd_intelmad_mute_set - sets the mute control's info
376 *
377 * @kcontrol:    pointer to the control
378 * @uval:        pointer to the structure where the control's info is
379 *               available to be set
380 *
381 * This function is called when .set function of a control is invoked from app
382 */
383 static int snd_intelmad_mute_set(struct snd_kcontrol *kcontrol,
384                                         struct snd_ctl_elem_value *uval)
385 {
386         int cntl_list[2] = {0,}, ret_val;
387         struct snd_intelmad *intelmaddata;
388         struct snd_pmic_ops *scard_ops;
389
390         pr_debug("sst: snd_intelmad_mute_set called\n");
391
392         WARN_ON(!uval);
393         WARN_ON(!kcontrol);
394
395         intelmaddata = kcontrol->private_data;
396
397         WARN_ON(!intelmaddata->sstdrv_ops);
398
399         scard_ops = intelmaddata->sstdrv_ops->scard_ops;
400
401         WARN_ON(!scard_ops);
402
403         kcontrol->private_value = uval->value.integer.value[0];
404
405         switch (kcontrol->id.numid) {
406         case PLAYBACK_MUTE:
407                 if (intelmaddata->output_sel == STEREO_HEADPHONE) {
408                         cntl_list[0] = PMIC_SND_LEFT_HP_MUTE;
409                         cntl_list[1] = PMIC_SND_RIGHT_HP_MUTE;
410                 } else if ((intelmaddata->output_sel == INTERNAL_SPKR) ||
411                                 (intelmaddata->output_sel == MONO_EARPIECE)) {
412                         cntl_list[0] = PMIC_SND_LEFT_SPEAKER_MUTE;
413                         cntl_list[1] = PMIC_SND_RIGHT_SPEAKER_MUTE;
414                 }
415                 break;
416
417         case CAPTURE_MUTE:/*based on sel device mute the i/p dev*/
418                 if (intelmaddata->input_sel == DMIC)
419                         cntl_list[0] = PMIC_SND_DMIC_MUTE;
420                 else if (intelmaddata->input_sel == AMIC)
421                         cntl_list[0] = PMIC_SND_AMIC_MUTE;
422                 else if (intelmaddata->input_sel == HS_MIC)
423                         cntl_list[0] = PMIC_SND_HP_MIC_MUTE;
424                 break;
425         case MASTER_MUTE:
426                 cntl_list[0] = PMIC_SND_MUTE_ALL;
427                 intelmaddata->master_mute = uval->value.integer.value[0];
428                 break;
429         default:
430                 return -EINVAL;
431         }
432
433         ret_val = scard_ops->set_mute(cntl_list[0],
434                                 uval->value.integer.value[0]);
435         if (ret_val)
436                 return ret_val;
437
438         if (kcontrol->id.numid == PLAYBACK_MUTE)
439                 ret_val = scard_ops->set_mute(cntl_list[1],
440                                         uval->value.integer.value[0]);
441         return ret_val;
442 }
443
444 /**
445 * snd_intelmad_device_get - get the device select control's info
446 *
447 * @kcontrol:    pointer to the control
448 * @uval:        pointer to the structure where the control's info is
449 *               to be filled
450 *
451 * This function is called when .get function of a control is invoked from app
452 */
453 static int snd_intelmad_device_get(struct snd_kcontrol *kcontrol,
454                                         struct snd_ctl_elem_value *uval)
455 {
456         struct snd_intelmad *intelmaddata;
457         struct snd_pmic_ops *scard_ops;
458         pr_debug("sst: device_get called\n");
459
460         WARN_ON(!uval);
461         WARN_ON(!kcontrol);
462
463         intelmaddata = kcontrol->private_data;
464         if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
465                 scard_ops = intelmaddata->sstdrv_ops->scard_ops;
466                 if (kcontrol->id.numid == OUTPUT_SEL)
467                         uval->value.enumerated.item[0] =
468                                         scard_ops->output_dev_id;
469                 else if (kcontrol->id.numid == INPUT_SEL)
470                         uval->value.enumerated.item[0] =
471                                         scard_ops->input_dev_id;
472                 else
473                         return -EINVAL;
474         } else
475         uval->value.enumerated.item[0] = kcontrol->private_value;
476         return 0;
477 }
478
479 /**
480 * snd_intelmad_device_set - set the device select control's info
481 *
482 * @kcontrol:    pointer to the control
483 * @uval:        pointer to the structure where the control's info is
484 *               available to be set
485 *
486 * This function is called when .set function of a control is invoked from app
487 */
488 static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol,
489                                         struct snd_ctl_elem_value *uval)
490 {
491         struct snd_intelmad *intelmaddata;
492         struct snd_pmic_ops *scard_ops;
493         int ret_val = 0, vendor, status;
494
495         pr_debug("sst: snd_intelmad_device_set called\n");
496
497         WARN_ON(!uval);
498         WARN_ON(!kcontrol);
499         status = -1;
500
501         intelmaddata = kcontrol->private_data;
502
503         WARN_ON(!intelmaddata->sstdrv_ops);
504
505         scard_ops = intelmaddata->sstdrv_ops->scard_ops;
506
507         WARN_ON(!scard_ops);
508
509         /* store value with driver */
510         kcontrol->private_value = uval->value.enumerated.item[0];
511
512         switch (kcontrol->id.numid) {
513         case OUTPUT_SEL:
514                 ret_val = scard_ops->set_output_dev(
515                                 uval->value.enumerated.item[0]);
516                 intelmaddata->output_sel = uval->value.enumerated.item[0];
517                 break;
518         case INPUT_SEL:
519                 vendor = intelmaddata->sstdrv_ops->vendor_id;
520                 if ((vendor == SND_MX) || (vendor == SND_FS)) {
521                         if (uval->value.enumerated.item[0] == HS_MIC) {
522                                 status = 1;
523                                 intelmaddata->sstdrv_ops->
524                                 control_set(SST_ENABLE_RX_TIME_SLOT, &status);
525                         } else {
526                                 status = 0;
527                                 intelmaddata->sstdrv_ops->
528                                 control_set(SST_ENABLE_RX_TIME_SLOT, &status);
529                         }
530                 }
531                 ret_val = scard_ops->set_input_dev(
532                                 uval->value.enumerated.item[0]);
533                 intelmaddata->input_sel = uval->value.enumerated.item[0];
534                 break;
535         default:
536                 return -EINVAL;
537         }
538         kcontrol->private_value = uval->value.enumerated.item[0];
539         return ret_val;
540 }
541
542 struct snd_kcontrol_new snd_intelmad_controls_mrst[MAX_CTRL] __devinitdata = {
543 {
544         .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
545         .name           =       "PCM Playback Source",
546         .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
547         .info           =       snd_intelmad_device_info_mrst,
548         .get            =       snd_intelmad_device_get,
549         .put            =       snd_intelmad_device_set,
550         .private_value  =       0,
551 },
552 {
553         .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
554         .name           =       "PCM Capture Source",
555         .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
556         .info           =       snd_intelmad_device_info_mrst,
557         .get            =       snd_intelmad_device_get,
558         .put            =       snd_intelmad_device_set,
559         .private_value  =       0,
560 },
561 {
562         .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
563         .name           =       "PCM Playback Volume",
564         .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
565         .info           =       snd_intelmad_playback_volume_info,
566         .get            =       snd_intelmad_volume_get,
567         .put            =       snd_intelmad_volume_set,
568         .private_value  =       0,
569 },
570 {
571         .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
572         .name           =       "PCM Playback Switch",
573         .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
574         .info           =       snd_intelmad_mute_info,
575         .get            =       snd_intelmad_mute_get,
576         .put            =       snd_intelmad_mute_set,
577         .private_value  =       0,
578 },
579 {
580         .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
581         .name           =       "PCM Capture Volume",
582         .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
583         .info           =       snd_intelmad_capture_volume_info,
584         .get            =       snd_intelmad_volume_get,
585         .put            =       snd_intelmad_volume_set,
586         .private_value  =       0,
587 },
588 {
589         .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
590         .name           =       "PCM Capture Switch",
591         .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
592         .info           =       snd_intelmad_mute_info,
593         .get            =       snd_intelmad_mute_get,
594         .put            =       snd_intelmad_mute_set,
595         .private_value  =       0,
596 },
597 {
598         .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
599         .name           =       "Master Playback Switch",
600         .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
601         .info           =       snd_intelmad_mute_info,
602         .get            =       snd_intelmad_mute_get,
603         .put            =       snd_intelmad_mute_set,
604         .private_value  =       0,
605 },
606 };
607
608 struct snd_kcontrol_new
609 snd_intelmad_controls_mfld[MAX_CTRL_MFLD] __devinitdata = {
610 {
611         .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
612         .name           =       "PCM Playback Source",
613         .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
614         .info           =       snd_intelmad_device_info_mfld,
615         .get            =       snd_intelmad_device_get,
616         .put            =       snd_intelmad_device_set,
617         .private_value  =       0,
618 },
619 {
620         .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
621         .name           =       "PCM Capture Source",
622         .access         =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
623         .info           =       snd_intelmad_device_info_mfld,
624         .get            =       snd_intelmad_device_get,
625         .put            =       snd_intelmad_device_set,
626         .private_value  =       0,
627 },
628 };
629