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

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

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ 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.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /sound/pci/ice1712/wm8776.c (Version linux-6.12-rc7) and /sound/pci/ice1712/wm8776.c (Version linux-4.20.17)


  1 // SPDX-License-Identifier: GPL-2.0-or-later   << 
  2 /*                                                  1 /*
  3  *   ALSA driver for ICEnsemble VT17xx              2  *   ALSA driver for ICEnsemble VT17xx
  4  *                                                  3  *
  5  *   Lowlevel functions for WM8776 codec            4  *   Lowlevel functions for WM8776 codec
  6  *                                                  5  *
  7  *      Copyright (c) 2012 Ondrej Zary <linux@      6  *      Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org>
                                                   >>   7  *
                                                   >>   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.
                                                   >>  12  *
                                                   >>  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.
                                                   >>  17  *
                                                   >>  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
                                                   >>  21  *
  8  */                                                22  */
  9                                                    23 
 10 #include <linux/delay.h>                           24 #include <linux/delay.h>
 11 #include <sound/core.h>                            25 #include <sound/core.h>
 12 #include <sound/control.h>                         26 #include <sound/control.h>
 13 #include <sound/tlv.h>                             27 #include <sound/tlv.h>
 14 #include "wm8776.h"                                28 #include "wm8776.h"
 15                                                    29 
 16 /* low-level access */                             30 /* low-level access */
 17                                                    31 
 18 static void snd_wm8776_write(struct snd_wm8776     32 static void snd_wm8776_write(struct snd_wm8776 *wm, u16 addr, u16 data)
 19 {                                                  33 {
 20         u8 bus_addr = addr << 1 | data >> 8;       34         u8 bus_addr = addr << 1 | data >> 8;    /* addr + 9th data bit */
 21         u8 bus_data = data & 0xff;                 35         u8 bus_data = data & 0xff;              /* remaining 8 data bits */
 22                                                    36 
 23         if (addr < WM8776_REG_RESET)               37         if (addr < WM8776_REG_RESET)
 24                 wm->regs[addr] = data;             38                 wm->regs[addr] = data;
 25         wm->ops.write(wm, bus_addr, bus_data);     39         wm->ops.write(wm, bus_addr, bus_data);
 26 }                                                  40 }
 27                                                    41 
 28 /* register-level functions */                     42 /* register-level functions */
 29                                                    43 
 30 static void snd_wm8776_activate_ctl(struct snd     44 static void snd_wm8776_activate_ctl(struct snd_wm8776 *wm,
 31                                     const char     45                                     const char *ctl_name,
 32                                     bool activ     46                                     bool active)
 33 {                                                  47 {
 34         struct snd_card *card = wm->card;          48         struct snd_card *card = wm->card;
 35         struct snd_kcontrol *kctl;                 49         struct snd_kcontrol *kctl;
 36         struct snd_kcontrol_volatile *vd;          50         struct snd_kcontrol_volatile *vd;
                                                   >>  51         struct snd_ctl_elem_id elem_id;
 37         unsigned int index_offset;                 52         unsigned int index_offset;
 38                                                    53 
 39         kctl = snd_ctl_find_id_mixer(card, ctl !!  54         memset(&elem_id, 0, sizeof(elem_id));
                                                   >>  55         strlcpy(elem_id.name, ctl_name, sizeof(elem_id.name));
                                                   >>  56         elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
                                                   >>  57         kctl = snd_ctl_find_id(card, &elem_id);
 40         if (!kctl)                                 58         if (!kctl)
 41                 return;                            59                 return;
 42         index_offset = snd_ctl_get_ioff(kctl,      60         index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
 43         vd = &kctl->vd[index_offset];              61         vd = &kctl->vd[index_offset];
 44         if (active)                                62         if (active)
 45                 vd->access &= ~SNDRV_CTL_ELEM_     63                 vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
 46         else                                       64         else
 47                 vd->access |= SNDRV_CTL_ELEM_A     65                 vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
 48         snd_ctl_notify(card, SNDRV_CTL_EVENT_M     66         snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
 49 }                                                  67 }
 50                                                    68 
 51 static void snd_wm8776_update_agc_ctl(struct s     69 static void snd_wm8776_update_agc_ctl(struct snd_wm8776 *wm)
 52 {                                                  70 {
 53         int i, flags_on = 0, flags_off = 0;        71         int i, flags_on = 0, flags_off = 0;
 54                                                    72 
 55         switch (wm->agc_mode) {                    73         switch (wm->agc_mode) {
 56         case WM8776_AGC_OFF:                       74         case WM8776_AGC_OFF:
 57                 flags_off = WM8776_FLAG_LIM |      75                 flags_off = WM8776_FLAG_LIM | WM8776_FLAG_ALC;
 58                 break;                             76                 break;
 59         case WM8776_AGC_LIM:                       77         case WM8776_AGC_LIM:
 60                 flags_off = WM8776_FLAG_ALC;       78                 flags_off = WM8776_FLAG_ALC;
 61                 flags_on = WM8776_FLAG_LIM;        79                 flags_on = WM8776_FLAG_LIM;
 62                 break;                             80                 break;
 63         case WM8776_AGC_ALC_R:                     81         case WM8776_AGC_ALC_R:
 64         case WM8776_AGC_ALC_L:                     82         case WM8776_AGC_ALC_L:
 65         case WM8776_AGC_ALC_STEREO:                83         case WM8776_AGC_ALC_STEREO:
 66                 flags_off = WM8776_FLAG_LIM;       84                 flags_off = WM8776_FLAG_LIM;
 67                 flags_on = WM8776_FLAG_ALC;        85                 flags_on = WM8776_FLAG_ALC;
 68                 break;                             86                 break;
 69         }                                          87         }
 70                                                    88 
 71         for (i = 0; i < WM8776_CTL_COUNT; i++)     89         for (i = 0; i < WM8776_CTL_COUNT; i++)
 72                 if (wm->ctl[i].flags & flags_o     90                 if (wm->ctl[i].flags & flags_off)
 73                         snd_wm8776_activate_ct     91                         snd_wm8776_activate_ctl(wm, wm->ctl[i].name, false);
 74                 else if (wm->ctl[i].flags & fl     92                 else if (wm->ctl[i].flags & flags_on)
 75                         snd_wm8776_activate_ct     93                         snd_wm8776_activate_ctl(wm, wm->ctl[i].name, true);
 76 }                                                  94 }
 77                                                    95 
 78 static void snd_wm8776_set_agc(struct snd_wm87     96 static void snd_wm8776_set_agc(struct snd_wm8776 *wm, u16 agc, u16 nothing)
 79 {                                                  97 {
 80         u16 alc1 = wm->regs[WM8776_REG_ALCCTRL     98         u16 alc1 = wm->regs[WM8776_REG_ALCCTRL1] & ~WM8776_ALC1_LCT_MASK;
 81         u16 alc2 = wm->regs[WM8776_REG_ALCCTRL     99         u16 alc2 = wm->regs[WM8776_REG_ALCCTRL2] & ~WM8776_ALC2_LCEN;
 82                                                   100 
 83         switch (agc) {                            101         switch (agc) {
 84         case 0: /* Off */                         102         case 0: /* Off */
 85                 wm->agc_mode = WM8776_AGC_OFF;    103                 wm->agc_mode = WM8776_AGC_OFF;
 86                 break;                            104                 break;
 87         case 1: /* Limiter */                     105         case 1: /* Limiter */
 88                 alc2 |= WM8776_ALC2_LCEN;         106                 alc2 |= WM8776_ALC2_LCEN;
 89                 wm->agc_mode = WM8776_AGC_LIM;    107                 wm->agc_mode = WM8776_AGC_LIM;
 90                 break;                            108                 break;
 91         case 2: /* ALC Right */                   109         case 2: /* ALC Right */
 92                 alc1 |= WM8776_ALC1_LCSEL_ALCR    110                 alc1 |= WM8776_ALC1_LCSEL_ALCR;
 93                 alc2 |= WM8776_ALC2_LCEN;         111                 alc2 |= WM8776_ALC2_LCEN;
 94                 wm->agc_mode = WM8776_AGC_ALC_    112                 wm->agc_mode = WM8776_AGC_ALC_R;
 95                 break;                            113                 break;
 96         case 3: /* ALC Left */                    114         case 3: /* ALC Left */
 97                 alc1 |= WM8776_ALC1_LCSEL_ALCL    115                 alc1 |= WM8776_ALC1_LCSEL_ALCL;
 98                 alc2 |= WM8776_ALC2_LCEN;         116                 alc2 |= WM8776_ALC2_LCEN;
 99                 wm->agc_mode = WM8776_AGC_ALC_    117                 wm->agc_mode = WM8776_AGC_ALC_L;
100                 break;                            118                 break;
101         case 4: /* ALC Stereo */                  119         case 4: /* ALC Stereo */
102                 alc1 |= WM8776_ALC1_LCSEL_ALCS    120                 alc1 |= WM8776_ALC1_LCSEL_ALCSTEREO;
103                 alc2 |= WM8776_ALC2_LCEN;         121                 alc2 |= WM8776_ALC2_LCEN;
104                 wm->agc_mode = WM8776_AGC_ALC_    122                 wm->agc_mode = WM8776_AGC_ALC_STEREO;
105                 break;                            123                 break;
106         }                                         124         }
107         snd_wm8776_write(wm, WM8776_REG_ALCCTR    125         snd_wm8776_write(wm, WM8776_REG_ALCCTRL1, alc1);
108         snd_wm8776_write(wm, WM8776_REG_ALCCTR    126         snd_wm8776_write(wm, WM8776_REG_ALCCTRL2, alc2);
109         snd_wm8776_update_agc_ctl(wm);            127         snd_wm8776_update_agc_ctl(wm);
110 }                                                 128 }
111                                                   129 
112 static void snd_wm8776_get_agc(struct snd_wm87    130 static void snd_wm8776_get_agc(struct snd_wm8776 *wm, u16 *mode, u16 *nothing)
113 {                                                 131 {
114         *mode = wm->agc_mode;                     132         *mode = wm->agc_mode;
115 }                                                 133 }
116                                                   134 
117 /* mixer controls */                              135 /* mixer controls */
118                                                   136 
119 static const DECLARE_TLV_DB_SCALE(wm8776_hp_tl    137 static const DECLARE_TLV_DB_SCALE(wm8776_hp_tlv, -7400, 100, 1);
120 static const DECLARE_TLV_DB_SCALE(wm8776_dac_t    138 static const DECLARE_TLV_DB_SCALE(wm8776_dac_tlv, -12750, 50, 1);
121 static const DECLARE_TLV_DB_SCALE(wm8776_adc_t    139 static const DECLARE_TLV_DB_SCALE(wm8776_adc_tlv, -10350, 50, 1);
122 static const DECLARE_TLV_DB_SCALE(wm8776_lct_t    140 static const DECLARE_TLV_DB_SCALE(wm8776_lct_tlv, -1600, 100, 0);
123 static const DECLARE_TLV_DB_SCALE(wm8776_maxga    141 static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_tlv, 0, 400, 0);
124 static const DECLARE_TLV_DB_SCALE(wm8776_ngth_    142 static const DECLARE_TLV_DB_SCALE(wm8776_ngth_tlv, -7800, 600, 0);
125 static const DECLARE_TLV_DB_SCALE(wm8776_maxat    143 static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_tlv, -1200, 100, 0);
126 static const DECLARE_TLV_DB_SCALE(wm8776_maxat    144 static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_tlv, -2100, 400, 0);
127                                                   145 
128 static const struct snd_wm8776_ctl snd_wm8776_ !! 146 static struct snd_wm8776_ctl snd_wm8776_default_ctl[WM8776_CTL_COUNT] = {
129         [WM8776_CTL_DAC_VOL] = {                  147         [WM8776_CTL_DAC_VOL] = {
130                 .name = "Master Playback Volum    148                 .name = "Master Playback Volume",
131                 .type = SNDRV_CTL_ELEM_TYPE_IN    149                 .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
132                 .tlv = wm8776_dac_tlv,            150                 .tlv = wm8776_dac_tlv,
133                 .reg1 = WM8776_REG_DACLVOL,       151                 .reg1 = WM8776_REG_DACLVOL,
134                 .reg2 = WM8776_REG_DACRVOL,       152                 .reg2 = WM8776_REG_DACRVOL,
135                 .mask1 = WM8776_DACVOL_MASK,      153                 .mask1 = WM8776_DACVOL_MASK,
136                 .mask2 = WM8776_DACVOL_MASK,      154                 .mask2 = WM8776_DACVOL_MASK,
137                 .max = 0xff,                      155                 .max = 0xff,
138                 .flags = WM8776_FLAG_STEREO |     156                 .flags = WM8776_FLAG_STEREO | WM8776_FLAG_VOL_UPDATE,
139         },                                        157         },
140         [WM8776_CTL_DAC_SW] = {                   158         [WM8776_CTL_DAC_SW] = {
141                 .name = "Master Playback Switc    159                 .name = "Master Playback Switch",
142                 .type = SNDRV_CTL_ELEM_TYPE_BO    160                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
143                 .reg1 = WM8776_REG_DACCTRL1,      161                 .reg1 = WM8776_REG_DACCTRL1,
144                 .reg2 = WM8776_REG_DACCTRL1,      162                 .reg2 = WM8776_REG_DACCTRL1,
145                 .mask1 = WM8776_DAC_PL_LL,        163                 .mask1 = WM8776_DAC_PL_LL,
146                 .mask2 = WM8776_DAC_PL_RR,        164                 .mask2 = WM8776_DAC_PL_RR,
147                 .flags = WM8776_FLAG_STEREO,      165                 .flags = WM8776_FLAG_STEREO,
148         },                                        166         },
149         [WM8776_CTL_DAC_ZC_SW] = {                167         [WM8776_CTL_DAC_ZC_SW] = {
150                 .name = "Master Zero Cross Det    168                 .name = "Master Zero Cross Detect Playback Switch",
151                 .type = SNDRV_CTL_ELEM_TYPE_BO    169                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
152                 .reg1 = WM8776_REG_DACCTRL1,      170                 .reg1 = WM8776_REG_DACCTRL1,
153                 .mask1 = WM8776_DAC_DZCEN,        171                 .mask1 = WM8776_DAC_DZCEN,
154         },                                        172         },
155         [WM8776_CTL_HP_VOL] = {                   173         [WM8776_CTL_HP_VOL] = {
156                 .name = "Headphone Playback Vo    174                 .name = "Headphone Playback Volume",
157                 .type = SNDRV_CTL_ELEM_TYPE_IN    175                 .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
158                 .tlv = wm8776_hp_tlv,             176                 .tlv = wm8776_hp_tlv,
159                 .reg1 = WM8776_REG_HPLVOL,        177                 .reg1 = WM8776_REG_HPLVOL,
160                 .reg2 = WM8776_REG_HPRVOL,        178                 .reg2 = WM8776_REG_HPRVOL,
161                 .mask1 = WM8776_HPVOL_MASK,       179                 .mask1 = WM8776_HPVOL_MASK,
162                 .mask2 = WM8776_HPVOL_MASK,       180                 .mask2 = WM8776_HPVOL_MASK,
163                 .min = 0x2f,                      181                 .min = 0x2f,
164                 .max = 0x7f,                      182                 .max = 0x7f,
165                 .flags = WM8776_FLAG_STEREO |     183                 .flags = WM8776_FLAG_STEREO | WM8776_FLAG_VOL_UPDATE,
166         },                                        184         },
167         [WM8776_CTL_HP_SW] = {                    185         [WM8776_CTL_HP_SW] = {
168                 .name = "Headphone Playback Sw    186                 .name = "Headphone Playback Switch",
169                 .type = SNDRV_CTL_ELEM_TYPE_BO    187                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
170                 .reg1 = WM8776_REG_PWRDOWN,       188                 .reg1 = WM8776_REG_PWRDOWN,
171                 .mask1 = WM8776_PWR_HPPD,         189                 .mask1 = WM8776_PWR_HPPD,
172                 .flags = WM8776_FLAG_INVERT,      190                 .flags = WM8776_FLAG_INVERT,
173         },                                        191         },
174         [WM8776_CTL_HP_ZC_SW] = {                 192         [WM8776_CTL_HP_ZC_SW] = {
175                 .name = "Headphone Zero Cross     193                 .name = "Headphone Zero Cross Detect Playback Switch",
176                 .type = SNDRV_CTL_ELEM_TYPE_BO    194                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
177                 .reg1 = WM8776_REG_HPLVOL,        195                 .reg1 = WM8776_REG_HPLVOL,
178                 .reg2 = WM8776_REG_HPRVOL,        196                 .reg2 = WM8776_REG_HPRVOL,
179                 .mask1 = WM8776_VOL_HPZCEN,       197                 .mask1 = WM8776_VOL_HPZCEN,
180                 .mask2 = WM8776_VOL_HPZCEN,       198                 .mask2 = WM8776_VOL_HPZCEN,
181                 .flags = WM8776_FLAG_STEREO,      199                 .flags = WM8776_FLAG_STEREO,
182         },                                        200         },
183         [WM8776_CTL_AUX_SW] = {                   201         [WM8776_CTL_AUX_SW] = {
184                 .name = "AUX Playback Switch",    202                 .name = "AUX Playback Switch",
185                 .type = SNDRV_CTL_ELEM_TYPE_BO    203                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
186                 .reg1 = WM8776_REG_OUTMUX,        204                 .reg1 = WM8776_REG_OUTMUX,
187                 .mask1 = WM8776_OUTMUX_AUX,       205                 .mask1 = WM8776_OUTMUX_AUX,
188         },                                        206         },
189         [WM8776_CTL_BYPASS_SW] = {                207         [WM8776_CTL_BYPASS_SW] = {
190                 .name = "Bypass Playback Switc    208                 .name = "Bypass Playback Switch",
191                 .type = SNDRV_CTL_ELEM_TYPE_BO    209                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
192                 .reg1 = WM8776_REG_OUTMUX,        210                 .reg1 = WM8776_REG_OUTMUX,
193                 .mask1 = WM8776_OUTMUX_BYPASS,    211                 .mask1 = WM8776_OUTMUX_BYPASS,
194         },                                        212         },
195         [WM8776_CTL_DAC_IZD_SW] = {               213         [WM8776_CTL_DAC_IZD_SW] = {
196                 .name = "Infinite Zero Detect     214                 .name = "Infinite Zero Detect Playback Switch",
197                 .type = SNDRV_CTL_ELEM_TYPE_BO    215                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
198                 .reg1 = WM8776_REG_DACCTRL1,      216                 .reg1 = WM8776_REG_DACCTRL1,
199                 .mask1 = WM8776_DAC_IZD,          217                 .mask1 = WM8776_DAC_IZD,
200         },                                        218         },
201         [WM8776_CTL_PHASE_SW] = {                 219         [WM8776_CTL_PHASE_SW] = {
202                 .name = "Phase Invert Playback    220                 .name = "Phase Invert Playback Switch",
203                 .type = SNDRV_CTL_ELEM_TYPE_BO    221                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
204                 .reg1 = WM8776_REG_PHASESWAP,     222                 .reg1 = WM8776_REG_PHASESWAP,
205                 .reg2 = WM8776_REG_PHASESWAP,     223                 .reg2 = WM8776_REG_PHASESWAP,
206                 .mask1 = WM8776_PHASE_INVERTL,    224                 .mask1 = WM8776_PHASE_INVERTL,
207                 .mask2 = WM8776_PHASE_INVERTR,    225                 .mask2 = WM8776_PHASE_INVERTR,
208                 .flags = WM8776_FLAG_STEREO,      226                 .flags = WM8776_FLAG_STEREO,
209         },                                        227         },
210         [WM8776_CTL_DEEMPH_SW] = {                228         [WM8776_CTL_DEEMPH_SW] = {
211                 .name = "Deemphasis Playback S    229                 .name = "Deemphasis Playback Switch",
212                 .type = SNDRV_CTL_ELEM_TYPE_BO    230                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
213                 .reg1 = WM8776_REG_DACCTRL2,      231                 .reg1 = WM8776_REG_DACCTRL2,
214                 .mask1 = WM8776_DAC2_DEEMPH,      232                 .mask1 = WM8776_DAC2_DEEMPH,
215         },                                        233         },
216         [WM8776_CTL_ADC_VOL] = {                  234         [WM8776_CTL_ADC_VOL] = {
217                 .name = "Input Capture Volume"    235                 .name = "Input Capture Volume",
218                 .type = SNDRV_CTL_ELEM_TYPE_IN    236                 .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
219                 .tlv = wm8776_adc_tlv,            237                 .tlv = wm8776_adc_tlv,
220                 .reg1 = WM8776_REG_ADCLVOL,       238                 .reg1 = WM8776_REG_ADCLVOL,
221                 .reg2 = WM8776_REG_ADCRVOL,       239                 .reg2 = WM8776_REG_ADCRVOL,
222                 .mask1 = WM8776_ADC_GAIN_MASK,    240                 .mask1 = WM8776_ADC_GAIN_MASK,
223                 .mask2 = WM8776_ADC_GAIN_MASK,    241                 .mask2 = WM8776_ADC_GAIN_MASK,
224                 .max = 0xff,                      242                 .max = 0xff,
225                 .flags = WM8776_FLAG_STEREO |     243                 .flags = WM8776_FLAG_STEREO | WM8776_FLAG_VOL_UPDATE,
226         },                                        244         },
227         [WM8776_CTL_ADC_SW] = {                   245         [WM8776_CTL_ADC_SW] = {
228                 .name = "Input Capture Switch"    246                 .name = "Input Capture Switch",
229                 .type = SNDRV_CTL_ELEM_TYPE_BO    247                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
230                 .reg1 = WM8776_REG_ADCMUX,        248                 .reg1 = WM8776_REG_ADCMUX,
231                 .reg2 = WM8776_REG_ADCMUX,        249                 .reg2 = WM8776_REG_ADCMUX,
232                 .mask1 = WM8776_ADC_MUTEL,        250                 .mask1 = WM8776_ADC_MUTEL,
233                 .mask2 = WM8776_ADC_MUTER,        251                 .mask2 = WM8776_ADC_MUTER,
234                 .flags = WM8776_FLAG_STEREO |     252                 .flags = WM8776_FLAG_STEREO | WM8776_FLAG_INVERT,
235         },                                        253         },
236         [WM8776_CTL_INPUT1_SW] = {                254         [WM8776_CTL_INPUT1_SW] = {
237                 .name = "AIN1 Capture Switch",    255                 .name = "AIN1 Capture Switch",
238                 .type = SNDRV_CTL_ELEM_TYPE_BO    256                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
239                 .reg1 = WM8776_REG_ADCMUX,        257                 .reg1 = WM8776_REG_ADCMUX,
240                 .mask1 = WM8776_ADC_MUX_AIN1,     258                 .mask1 = WM8776_ADC_MUX_AIN1,
241         },                                        259         },
242         [WM8776_CTL_INPUT2_SW] = {                260         [WM8776_CTL_INPUT2_SW] = {
243                 .name = "AIN2 Capture Switch",    261                 .name = "AIN2 Capture Switch",
244                 .type = SNDRV_CTL_ELEM_TYPE_BO    262                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
245                 .reg1 = WM8776_REG_ADCMUX,        263                 .reg1 = WM8776_REG_ADCMUX,
246                 .mask1 = WM8776_ADC_MUX_AIN2,     264                 .mask1 = WM8776_ADC_MUX_AIN2,
247         },                                        265         },
248         [WM8776_CTL_INPUT3_SW] = {                266         [WM8776_CTL_INPUT3_SW] = {
249                 .name = "AIN3 Capture Switch",    267                 .name = "AIN3 Capture Switch",
250                 .type = SNDRV_CTL_ELEM_TYPE_BO    268                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
251                 .reg1 = WM8776_REG_ADCMUX,        269                 .reg1 = WM8776_REG_ADCMUX,
252                 .mask1 = WM8776_ADC_MUX_AIN3,     270                 .mask1 = WM8776_ADC_MUX_AIN3,
253         },                                        271         },
254         [WM8776_CTL_INPUT4_SW] = {                272         [WM8776_CTL_INPUT4_SW] = {
255                 .name = "AIN4 Capture Switch",    273                 .name = "AIN4 Capture Switch",
256                 .type = SNDRV_CTL_ELEM_TYPE_BO    274                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
257                 .reg1 = WM8776_REG_ADCMUX,        275                 .reg1 = WM8776_REG_ADCMUX,
258                 .mask1 = WM8776_ADC_MUX_AIN4,     276                 .mask1 = WM8776_ADC_MUX_AIN4,
259         },                                        277         },
260         [WM8776_CTL_INPUT5_SW] = {                278         [WM8776_CTL_INPUT5_SW] = {
261                 .name = "AIN5 Capture Switch",    279                 .name = "AIN5 Capture Switch",
262                 .type = SNDRV_CTL_ELEM_TYPE_BO    280                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
263                 .reg1 = WM8776_REG_ADCMUX,        281                 .reg1 = WM8776_REG_ADCMUX,
264                 .mask1 = WM8776_ADC_MUX_AIN5,     282                 .mask1 = WM8776_ADC_MUX_AIN5,
265         },                                        283         },
266         [WM8776_CTL_AGC_SEL] = {                  284         [WM8776_CTL_AGC_SEL] = {
267                 .name = "AGC Select Capture En    285                 .name = "AGC Select Capture Enum",
268                 .type = SNDRV_CTL_ELEM_TYPE_EN    286                 .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED,
269                 .enum_names = { "Off", "Limite    287                 .enum_names = { "Off", "Limiter", "ALC Right", "ALC Left",
270                                 "ALC Stereo" }    288                                 "ALC Stereo" },
271                 .max = 5,       /* .enum_names    289                 .max = 5,       /* .enum_names item count */
272                 .set = snd_wm8776_set_agc,        290                 .set = snd_wm8776_set_agc,
273                 .get = snd_wm8776_get_agc,        291                 .get = snd_wm8776_get_agc,
274         },                                        292         },
275         [WM8776_CTL_LIM_THR] = {                  293         [WM8776_CTL_LIM_THR] = {
276                 .name = "Limiter Threshold Cap    294                 .name = "Limiter Threshold Capture Volume",
277                 .type = SNDRV_CTL_ELEM_TYPE_IN    295                 .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
278                 .tlv = wm8776_lct_tlv,            296                 .tlv = wm8776_lct_tlv,
279                 .reg1 = WM8776_REG_ALCCTRL1,      297                 .reg1 = WM8776_REG_ALCCTRL1,
280                 .mask1 = WM8776_ALC1_LCT_MASK,    298                 .mask1 = WM8776_ALC1_LCT_MASK,
281                 .max = 15,                        299                 .max = 15,
282                 .flags = WM8776_FLAG_LIM,         300                 .flags = WM8776_FLAG_LIM,
283         },                                        301         },
284         [WM8776_CTL_LIM_ATK] = {                  302         [WM8776_CTL_LIM_ATK] = {
285                 .name = "Limiter Attack Time C    303                 .name = "Limiter Attack Time Capture Enum",
286                 .type = SNDRV_CTL_ELEM_TYPE_EN    304                 .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED,
287                 .enum_names = { "0.25 ms", "0.    305                 .enum_names = { "0.25 ms", "0.5 ms", "1 ms", "2 ms", "4 ms",
288                         "8 ms", "16 ms", "32 m    306                         "8 ms", "16 ms", "32 ms", "64 ms", "128 ms", "256 ms" },
289                 .max = 11,      /* .enum_names    307                 .max = 11,      /* .enum_names item count */
290                 .reg1 = WM8776_REG_ALCCTRL3,      308                 .reg1 = WM8776_REG_ALCCTRL3,
291                 .mask1 = WM8776_ALC3_ATK_MASK,    309                 .mask1 = WM8776_ALC3_ATK_MASK,
292                 .flags = WM8776_FLAG_LIM,         310                 .flags = WM8776_FLAG_LIM,
293         },                                        311         },
294         [WM8776_CTL_LIM_DCY] = {                  312         [WM8776_CTL_LIM_DCY] = {
295                 .name = "Limiter Decay Time Ca    313                 .name = "Limiter Decay Time Capture Enum",
296                 .type = SNDRV_CTL_ELEM_TYPE_EN    314                 .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED,
297                 .enum_names = { "1.2 ms", "2.4    315                 .enum_names = { "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms",
298                         "19.2 ms", "38.4 ms",     316                         "19.2 ms", "38.4 ms", "76.8 ms", "154 ms", "307 ms",
299                         "614 ms", "1.23 s" },     317                         "614 ms", "1.23 s" },
300                 .max = 11,      /* .enum_names    318                 .max = 11,      /* .enum_names item count */
301                 .reg1 = WM8776_REG_ALCCTRL3,      319                 .reg1 = WM8776_REG_ALCCTRL3,
302                 .mask1 = WM8776_ALC3_DCY_MASK,    320                 .mask1 = WM8776_ALC3_DCY_MASK,
303                 .flags = WM8776_FLAG_LIM,         321                 .flags = WM8776_FLAG_LIM,
304         },                                        322         },
305         [WM8776_CTL_LIM_TRANWIN] = {              323         [WM8776_CTL_LIM_TRANWIN] = {
306                 .name = "Limiter Transient Win    324                 .name = "Limiter Transient Window Capture Enum",
307                 .type = SNDRV_CTL_ELEM_TYPE_EN    325                 .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED,
308                 .enum_names = { "0 us", "62.5     326                 .enum_names = { "0 us", "62.5 us", "125 us", "250 us", "500 us",
309                         "1 ms", "2 ms", "4 ms"    327                         "1 ms", "2 ms", "4 ms" },
310                 .max = 8,       /* .enum_names    328                 .max = 8,       /* .enum_names item count */
311                 .reg1 = WM8776_REG_LIMITER,       329                 .reg1 = WM8776_REG_LIMITER,
312                 .mask1 = WM8776_LIM_TRANWIN_MA    330                 .mask1 = WM8776_LIM_TRANWIN_MASK,
313                 .flags = WM8776_FLAG_LIM,         331                 .flags = WM8776_FLAG_LIM,
314         },                                        332         },
315         [WM8776_CTL_LIM_MAXATTN] = {              333         [WM8776_CTL_LIM_MAXATTN] = {
316                 .name = "Limiter Maximum Atten    334                 .name = "Limiter Maximum Attenuation Capture Volume",
317                 .type = SNDRV_CTL_ELEM_TYPE_IN    335                 .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
318                 .tlv = wm8776_maxatten_lim_tlv    336                 .tlv = wm8776_maxatten_lim_tlv,
319                 .reg1 = WM8776_REG_LIMITER,       337                 .reg1 = WM8776_REG_LIMITER,
320                 .mask1 = WM8776_LIM_MAXATTEN_M    338                 .mask1 = WM8776_LIM_MAXATTEN_MASK,
321                 .min = 3,                         339                 .min = 3,
322                 .max = 12,                        340                 .max = 12,
323                 .flags = WM8776_FLAG_LIM | WM8    341                 .flags = WM8776_FLAG_LIM | WM8776_FLAG_INVERT,
324         },                                        342         },
325         [WM8776_CTL_ALC_TGT] = {                  343         [WM8776_CTL_ALC_TGT] = {
326                 .name = "ALC Target Level Capt    344                 .name = "ALC Target Level Capture Volume",
327                 .type = SNDRV_CTL_ELEM_TYPE_IN    345                 .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
328                 .tlv = wm8776_lct_tlv,            346                 .tlv = wm8776_lct_tlv,
329                 .reg1 = WM8776_REG_ALCCTRL1,      347                 .reg1 = WM8776_REG_ALCCTRL1,
330                 .mask1 = WM8776_ALC1_LCT_MASK,    348                 .mask1 = WM8776_ALC1_LCT_MASK,
331                 .max = 15,                        349                 .max = 15,
332                 .flags = WM8776_FLAG_ALC,         350                 .flags = WM8776_FLAG_ALC,
333         },                                        351         },
334         [WM8776_CTL_ALC_ATK] = {                  352         [WM8776_CTL_ALC_ATK] = {
335                 .name = "ALC Attack Time Captu    353                 .name = "ALC Attack Time Capture Enum",
336                 .type = SNDRV_CTL_ELEM_TYPE_EN    354                 .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED,
337                 .enum_names = { "8.40 ms", "16    355                 .enum_names = { "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms",
338                         "134 ms", "269 ms", "5    356                         "134 ms", "269 ms", "538 ms", "1.08 s", "2.15 s",
339                         "4.3 s", "8.6 s" },       357                         "4.3 s", "8.6 s" },
340                 .max = 11,      /* .enum_names    358                 .max = 11,      /* .enum_names item count */
341                 .reg1 = WM8776_REG_ALCCTRL3,      359                 .reg1 = WM8776_REG_ALCCTRL3,
342                 .mask1 = WM8776_ALC3_ATK_MASK,    360                 .mask1 = WM8776_ALC3_ATK_MASK,
343                 .flags = WM8776_FLAG_ALC,         361                 .flags = WM8776_FLAG_ALC,
344         },                                        362         },
345         [WM8776_CTL_ALC_DCY] = {                  363         [WM8776_CTL_ALC_DCY] = {
346                 .name = "ALC Decay Time Captur    364                 .name = "ALC Decay Time Capture Enum",
347                 .type = SNDRV_CTL_ELEM_TYPE_EN    365                 .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED,
348                 .enum_names = { "33.5 ms", "67    366                 .enum_names = { "33.5 ms", "67.0 ms", "134 ms", "268 ms",
349                         "536 ms", "1.07 s", "2    367                         "536 ms", "1.07 s", "2.14 s", "4.29 s", "8.58 s",
350                         "17.2 s", "34.3 s" },     368                         "17.2 s", "34.3 s" },
351                 .max = 11,      /* .enum_names    369                 .max = 11,      /* .enum_names item count */
352                 .reg1 = WM8776_REG_ALCCTRL3,      370                 .reg1 = WM8776_REG_ALCCTRL3,
353                 .mask1 = WM8776_ALC3_DCY_MASK,    371                 .mask1 = WM8776_ALC3_DCY_MASK,
354                 .flags = WM8776_FLAG_ALC,         372                 .flags = WM8776_FLAG_ALC,
355         },                                        373         },
356         [WM8776_CTL_ALC_MAXGAIN] = {              374         [WM8776_CTL_ALC_MAXGAIN] = {
357                 .name = "ALC Maximum Gain Capt    375                 .name = "ALC Maximum Gain Capture Volume",
358                 .type = SNDRV_CTL_ELEM_TYPE_IN    376                 .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
359                 .tlv = wm8776_maxgain_tlv,        377                 .tlv = wm8776_maxgain_tlv,
360                 .reg1 = WM8776_REG_ALCCTRL1,      378                 .reg1 = WM8776_REG_ALCCTRL1,
361                 .mask1 = WM8776_ALC1_MAXGAIN_M    379                 .mask1 = WM8776_ALC1_MAXGAIN_MASK,
362                 .min = 1,                         380                 .min = 1,
363                 .max = 7,                         381                 .max = 7,
364                 .flags = WM8776_FLAG_ALC,         382                 .flags = WM8776_FLAG_ALC,
365         },                                        383         },
366         [WM8776_CTL_ALC_MAXATTN] = {              384         [WM8776_CTL_ALC_MAXATTN] = {
367                 .name = "ALC Maximum Attenuati    385                 .name = "ALC Maximum Attenuation Capture Volume",
368                 .type = SNDRV_CTL_ELEM_TYPE_IN    386                 .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
369                 .tlv = wm8776_maxatten_alc_tlv    387                 .tlv = wm8776_maxatten_alc_tlv,
370                 .reg1 = WM8776_REG_LIMITER,       388                 .reg1 = WM8776_REG_LIMITER,
371                 .mask1 = WM8776_LIM_MAXATTEN_M    389                 .mask1 = WM8776_LIM_MAXATTEN_MASK,
372                 .min = 10,                        390                 .min = 10,
373                 .max = 15,                        391                 .max = 15,
374                 .flags = WM8776_FLAG_ALC | WM8    392                 .flags = WM8776_FLAG_ALC | WM8776_FLAG_INVERT,
375         },                                        393         },
376         [WM8776_CTL_ALC_HLD] = {                  394         [WM8776_CTL_ALC_HLD] = {
377                 .name = "ALC Hold Time Capture    395                 .name = "ALC Hold Time Capture Enum",
378                 .type = SNDRV_CTL_ELEM_TYPE_EN    396                 .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED,
379                 .enum_names = { "0 ms", "2.67     397                 .enum_names = { "0 ms", "2.67 ms", "5.33 ms", "10.6 ms",
380                         "21.3 ms", "42.7 ms",     398                         "21.3 ms", "42.7 ms", "85.3 ms", "171 ms", "341 ms",
381                         "683 ms", "1.37 s", "2    399                         "683 ms", "1.37 s", "2.73 s", "5.46 s", "10.9 s",
382                         "21.8 s", "43.7 s" },     400                         "21.8 s", "43.7 s" },
383                 .max = 16,      /* .enum_names    401                 .max = 16,      /* .enum_names item count */
384                 .reg1 = WM8776_REG_ALCCTRL2,      402                 .reg1 = WM8776_REG_ALCCTRL2,
385                 .mask1 = WM8776_ALC2_HOLD_MASK    403                 .mask1 = WM8776_ALC2_HOLD_MASK,
386                 .flags = WM8776_FLAG_ALC,         404                 .flags = WM8776_FLAG_ALC,
387         },                                        405         },
388         [WM8776_CTL_NGT_SW] = {                   406         [WM8776_CTL_NGT_SW] = {
389                 .name = "Noise Gate Capture Sw    407                 .name = "Noise Gate Capture Switch",
390                 .type = SNDRV_CTL_ELEM_TYPE_BO    408                 .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
391                 .reg1 = WM8776_REG_NOISEGATE,     409                 .reg1 = WM8776_REG_NOISEGATE,
392                 .mask1 = WM8776_NGAT_ENABLE,      410                 .mask1 = WM8776_NGAT_ENABLE,
393                 .flags = WM8776_FLAG_ALC,         411                 .flags = WM8776_FLAG_ALC,
394         },                                        412         },
395         [WM8776_CTL_NGT_THR] = {                  413         [WM8776_CTL_NGT_THR] = {
396                 .name = "Noise Gate Threshold     414                 .name = "Noise Gate Threshold Capture Volume",
397                 .type = SNDRV_CTL_ELEM_TYPE_IN    415                 .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
398                 .tlv = wm8776_ngth_tlv,           416                 .tlv = wm8776_ngth_tlv,
399                 .reg1 = WM8776_REG_NOISEGATE,     417                 .reg1 = WM8776_REG_NOISEGATE,
400                 .mask1 = WM8776_NGAT_THR_MASK,    418                 .mask1 = WM8776_NGAT_THR_MASK,
401                 .max = 7,                         419                 .max = 7,
402                 .flags = WM8776_FLAG_ALC,         420                 .flags = WM8776_FLAG_ALC,
403         },                                        421         },
404 };                                                422 };
405                                                   423 
406 /* exported functions */                          424 /* exported functions */
407                                                   425 
408 void snd_wm8776_init(struct snd_wm8776 *wm)       426 void snd_wm8776_init(struct snd_wm8776 *wm)
409 {                                                 427 {
410         int i;                                    428         int i;
411         static const u16 default_values[] = {     429         static const u16 default_values[] = {
412                 0x000, 0x100, 0x000,              430                 0x000, 0x100, 0x000,
413                 0x000, 0x100, 0x000,              431                 0x000, 0x100, 0x000,
414                 0x000, 0x090, 0x000, 0x000,       432                 0x000, 0x090, 0x000, 0x000,
415                 0x022, 0x022, 0x022,              433                 0x022, 0x022, 0x022,
416                 0x008, 0x0cf, 0x0cf, 0x07b, 0x    434                 0x008, 0x0cf, 0x0cf, 0x07b, 0x000,
417                 0x032, 0x000, 0x0a6, 0x001, 0x    435                 0x032, 0x000, 0x0a6, 0x001, 0x001
418         };                                        436         };
419                                                   437 
420         memcpy(wm->ctl, snd_wm8776_default_ctl    438         memcpy(wm->ctl, snd_wm8776_default_ctl, sizeof(wm->ctl));
421                                                   439 
422         snd_wm8776_write(wm, WM8776_REG_RESET,    440         snd_wm8776_write(wm, WM8776_REG_RESET, 0x00); /* reset */
423         udelay(10);                               441         udelay(10);
424         /* load defaults */                       442         /* load defaults */
425         for (i = 0; i < ARRAY_SIZE(default_val    443         for (i = 0; i < ARRAY_SIZE(default_values); i++)
426                 snd_wm8776_write(wm, i, defaul    444                 snd_wm8776_write(wm, i, default_values[i]);
427 }                                                 445 }
428                                                   446 
429 void snd_wm8776_resume(struct snd_wm8776 *wm)     447 void snd_wm8776_resume(struct snd_wm8776 *wm)
430 {                                                 448 {
431         int i;                                    449         int i;
432                                                   450 
433         for (i = 0; i < WM8776_REG_COUNT; i++)    451         for (i = 0; i < WM8776_REG_COUNT; i++)
434                 snd_wm8776_write(wm, i, wm->re    452                 snd_wm8776_write(wm, i, wm->regs[i]);
435 }                                                 453 }
436                                                   454 
437 void snd_wm8776_set_power(struct snd_wm8776 *w    455 void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power)
438 {                                                 456 {
439         snd_wm8776_write(wm, WM8776_REG_PWRDOW    457         snd_wm8776_write(wm, WM8776_REG_PWRDOWN, power);
440 }                                                 458 }
441                                                   459 
442 void snd_wm8776_volume_restore(struct snd_wm87    460 void snd_wm8776_volume_restore(struct snd_wm8776 *wm)
443 {                                                 461 {
444         u16 val = wm->regs[WM8776_REG_DACRVOL]    462         u16 val = wm->regs[WM8776_REG_DACRVOL];
445         /* restore volume after MCLK stopped *    463         /* restore volume after MCLK stopped */
446         snd_wm8776_write(wm, WM8776_REG_DACRVO    464         snd_wm8776_write(wm, WM8776_REG_DACRVOL, val | WM8776_VOL_UPDATE);
447 }                                                 465 }
448                                                   466 
449 /* mixer callbacks */                             467 /* mixer callbacks */
450                                                   468 
451 static int snd_wm8776_volume_info(struct snd_k    469 static int snd_wm8776_volume_info(struct snd_kcontrol *kcontrol,
452                                    struct snd_    470                                    struct snd_ctl_elem_info *uinfo)
453 {                                                 471 {
454         struct snd_wm8776 *wm = snd_kcontrol_c    472         struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol);
455         int n = kcontrol->private_value;          473         int n = kcontrol->private_value;
456                                                   474 
457         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTE    475         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
458         uinfo->count = (wm->ctl[n].flags & WM8    476         uinfo->count = (wm->ctl[n].flags & WM8776_FLAG_STEREO) ? 2 : 1;
459         uinfo->value.integer.min = wm->ctl[n].    477         uinfo->value.integer.min = wm->ctl[n].min;
460         uinfo->value.integer.max = wm->ctl[n].    478         uinfo->value.integer.max = wm->ctl[n].max;
461                                                   479 
462         return 0;                                 480         return 0;
463 }                                                 481 }
464                                                   482 
465 static int snd_wm8776_enum_info(struct snd_kco    483 static int snd_wm8776_enum_info(struct snd_kcontrol *kcontrol,
466                                       struct s    484                                       struct snd_ctl_elem_info *uinfo)
467 {                                                 485 {
468         struct snd_wm8776 *wm = snd_kcontrol_c    486         struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol);
469         int n = kcontrol->private_value;          487         int n = kcontrol->private_value;
470                                                   488 
471         return snd_ctl_enum_info(uinfo, 1, wm-    489         return snd_ctl_enum_info(uinfo, 1, wm->ctl[n].max,
472                                                   490                                                 wm->ctl[n].enum_names);
473 }                                                 491 }
474                                                   492 
475 static int snd_wm8776_ctl_get(struct snd_kcont    493 static int snd_wm8776_ctl_get(struct snd_kcontrol *kcontrol,
476                                   struct snd_c    494                                   struct snd_ctl_elem_value *ucontrol)
477 {                                                 495 {
478         struct snd_wm8776 *wm = snd_kcontrol_c    496         struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol);
479         int n = kcontrol->private_value;          497         int n = kcontrol->private_value;
480         u16 val1, val2;                           498         u16 val1, val2;
481                                                   499 
482         if (wm->ctl[n].get)                       500         if (wm->ctl[n].get)
483                 wm->ctl[n].get(wm, &val1, &val    501                 wm->ctl[n].get(wm, &val1, &val2);
484         else {                                    502         else {
485                 val1 = wm->regs[wm->ctl[n].reg    503                 val1 = wm->regs[wm->ctl[n].reg1] & wm->ctl[n].mask1;
486                 val1 >>= __ffs(wm->ctl[n].mask    504                 val1 >>= __ffs(wm->ctl[n].mask1);
487                 if (wm->ctl[n].flags & WM8776_    505                 if (wm->ctl[n].flags & WM8776_FLAG_STEREO) {
488                         val2 = wm->regs[wm->ct    506                         val2 = wm->regs[wm->ctl[n].reg2] & wm->ctl[n].mask2;
489                         val2 >>= __ffs(wm->ctl    507                         val2 >>= __ffs(wm->ctl[n].mask2);
490                         if (wm->ctl[n].flags &    508                         if (wm->ctl[n].flags & WM8776_FLAG_VOL_UPDATE)
491                                 val2 &= ~WM877    509                                 val2 &= ~WM8776_VOL_UPDATE;
492                 }                                 510                 }
493         }                                         511         }
494         if (wm->ctl[n].flags & WM8776_FLAG_INV    512         if (wm->ctl[n].flags & WM8776_FLAG_INVERT) {
495                 val1 = wm->ctl[n].max - (val1     513                 val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min);
496                 if (wm->ctl[n].flags & WM8776_    514                 if (wm->ctl[n].flags & WM8776_FLAG_STEREO)
497                         val2 = wm->ctl[n].max     515                         val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min);
498         }                                         516         }
499         ucontrol->value.integer.value[0] = val    517         ucontrol->value.integer.value[0] = val1;
500         if (wm->ctl[n].flags & WM8776_FLAG_STE    518         if (wm->ctl[n].flags & WM8776_FLAG_STEREO)
501                 ucontrol->value.integer.value[    519                 ucontrol->value.integer.value[1] = val2;
502                                                   520 
503         return 0;                                 521         return 0;
504 }                                                 522 }
505                                                   523 
506 static int snd_wm8776_ctl_put(struct snd_kcont    524 static int snd_wm8776_ctl_put(struct snd_kcontrol *kcontrol,
507                                   struct snd_c    525                                   struct snd_ctl_elem_value *ucontrol)
508 {                                                 526 {
509         struct snd_wm8776 *wm = snd_kcontrol_c    527         struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol);
510         int n = kcontrol->private_value;          528         int n = kcontrol->private_value;
511         u16 val, regval1, regval2;                529         u16 val, regval1, regval2;
512                                                   530 
513         /* this also works for enum because va    531         /* this also works for enum because value is a union */
514         regval1 = ucontrol->value.integer.valu    532         regval1 = ucontrol->value.integer.value[0];
515         regval2 = ucontrol->value.integer.valu    533         regval2 = ucontrol->value.integer.value[1];
516         if (wm->ctl[n].flags & WM8776_FLAG_INV    534         if (wm->ctl[n].flags & WM8776_FLAG_INVERT) {
517                 regval1 = wm->ctl[n].max - (re    535                 regval1 = wm->ctl[n].max - (regval1 - wm->ctl[n].min);
518                 regval2 = wm->ctl[n].max - (re    536                 regval2 = wm->ctl[n].max - (regval2 - wm->ctl[n].min);
519         }                                         537         }
520         if (wm->ctl[n].set)                       538         if (wm->ctl[n].set)
521                 wm->ctl[n].set(wm, regval1, re    539                 wm->ctl[n].set(wm, regval1, regval2);
522         else {                                    540         else {
523                 val = wm->regs[wm->ctl[n].reg1    541                 val = wm->regs[wm->ctl[n].reg1] & ~wm->ctl[n].mask1;
524                 val |= regval1 << __ffs(wm->ct    542                 val |= regval1 << __ffs(wm->ctl[n].mask1);
525                 /* both stereo controls in one    543                 /* both stereo controls in one register */
526                 if (wm->ctl[n].flags & WM8776_    544                 if (wm->ctl[n].flags & WM8776_FLAG_STEREO &&
527                                 wm->ctl[n].reg    545                                 wm->ctl[n].reg1 == wm->ctl[n].reg2) {
528                         val &= ~wm->ctl[n].mas    546                         val &= ~wm->ctl[n].mask2;
529                         val |= regval2 << __ff    547                         val |= regval2 << __ffs(wm->ctl[n].mask2);
530                 }                                 548                 }
531                 snd_wm8776_write(wm, wm->ctl[n    549                 snd_wm8776_write(wm, wm->ctl[n].reg1, val);
532                 /* stereo controls in differen    550                 /* stereo controls in different registers */
533                 if (wm->ctl[n].flags & WM8776_    551                 if (wm->ctl[n].flags & WM8776_FLAG_STEREO &&
534                                 wm->ctl[n].reg    552                                 wm->ctl[n].reg1 != wm->ctl[n].reg2) {
535                         val = wm->regs[wm->ctl    553                         val = wm->regs[wm->ctl[n].reg2] & ~wm->ctl[n].mask2;
536                         val |= regval2 << __ff    554                         val |= regval2 << __ffs(wm->ctl[n].mask2);
537                         if (wm->ctl[n].flags &    555                         if (wm->ctl[n].flags & WM8776_FLAG_VOL_UPDATE)
538                                 val |= WM8776_    556                                 val |= WM8776_VOL_UPDATE;
539                         snd_wm8776_write(wm, w    557                         snd_wm8776_write(wm, wm->ctl[n].reg2, val);
540                 }                                 558                 }
541         }                                         559         }
542                                                   560 
543         return 0;                                 561         return 0;
544 }                                                 562 }
545                                                   563 
546 static int snd_wm8776_add_control(struct snd_w    564 static int snd_wm8776_add_control(struct snd_wm8776 *wm, int num)
547 {                                                 565 {
548         struct snd_kcontrol_new cont;             566         struct snd_kcontrol_new cont;
549         struct snd_kcontrol *ctl;                 567         struct snd_kcontrol *ctl;
550                                                   568 
551         memset(&cont, 0, sizeof(cont));           569         memset(&cont, 0, sizeof(cont));
552         cont.iface = SNDRV_CTL_ELEM_IFACE_MIXE    570         cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
553         cont.private_value = num;                 571         cont.private_value = num;
554         cont.name = wm->ctl[num].name;            572         cont.name = wm->ctl[num].name;
555         cont.access = SNDRV_CTL_ELEM_ACCESS_RE    573         cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
556         if (wm->ctl[num].flags & WM8776_FLAG_L    574         if (wm->ctl[num].flags & WM8776_FLAG_LIM ||
557             wm->ctl[num].flags & WM8776_FLAG_A    575             wm->ctl[num].flags & WM8776_FLAG_ALC)
558                 cont.access |= SNDRV_CTL_ELEM_    576                 cont.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
559         cont.tlv.p = NULL;                        577         cont.tlv.p = NULL;
560         cont.get = snd_wm8776_ctl_get;            578         cont.get = snd_wm8776_ctl_get;
561         cont.put = snd_wm8776_ctl_put;            579         cont.put = snd_wm8776_ctl_put;
562                                                   580 
563         switch (wm->ctl[num].type) {              581         switch (wm->ctl[num].type) {
564         case SNDRV_CTL_ELEM_TYPE_INTEGER:         582         case SNDRV_CTL_ELEM_TYPE_INTEGER:
565                 cont.info = snd_wm8776_volume_    583                 cont.info = snd_wm8776_volume_info;
566                 cont.access |= SNDRV_CTL_ELEM_    584                 cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
567                 cont.tlv.p = wm->ctl[num].tlv;    585                 cont.tlv.p = wm->ctl[num].tlv;
568                 break;                            586                 break;
569         case SNDRV_CTL_ELEM_TYPE_BOOLEAN:         587         case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
570                 wm->ctl[num].max = 1;             588                 wm->ctl[num].max = 1;
571                 if (wm->ctl[num].flags & WM877    589                 if (wm->ctl[num].flags & WM8776_FLAG_STEREO)
572                         cont.info = snd_ctl_bo    590                         cont.info = snd_ctl_boolean_stereo_info;
573                 else                              591                 else
574                         cont.info = snd_ctl_bo    592                         cont.info = snd_ctl_boolean_mono_info;
575                 break;                            593                 break;
576         case SNDRV_CTL_ELEM_TYPE_ENUMERATED:      594         case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
577                 cont.info = snd_wm8776_enum_in    595                 cont.info = snd_wm8776_enum_info;
578                 break;                            596                 break;
579         default:                                  597         default:
580                 return -EINVAL;                   598                 return -EINVAL;
581         }                                         599         }
582         ctl = snd_ctl_new1(&cont, wm);            600         ctl = snd_ctl_new1(&cont, wm);
583         if (!ctl)                                 601         if (!ctl)
584                 return -ENOMEM;                   602                 return -ENOMEM;
585                                                   603 
586         return snd_ctl_add(wm->card, ctl);        604         return snd_ctl_add(wm->card, ctl);
587 }                                                 605 }
588                                                   606 
589 int snd_wm8776_build_controls(struct snd_wm877    607 int snd_wm8776_build_controls(struct snd_wm8776 *wm)
590 {                                                 608 {
591         int err, i;                               609         int err, i;
592                                                   610 
593         for (i = 0; i < WM8776_CTL_COUNT; i++)    611         for (i = 0; i < WM8776_CTL_COUNT; i++)
594                 if (wm->ctl[i].name) {            612                 if (wm->ctl[i].name) {
595                         err = snd_wm8776_add_c    613                         err = snd_wm8776_add_control(wm, i);
596                         if (err < 0)              614                         if (err < 0)
597                                 return err;       615                                 return err;
598                 }                                 616                 }
599                                                   617 
600         return 0;                                 618         return 0;
601 }                                                 619 }
602                                                   620 

~ [ 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