Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   ALSA driver for ICEnsemble VT17xx
0004  *
0005  *   Lowlevel functions for WM8766 codec
0006  *
0007  *  Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org>
0008  */
0009 
0010 #include <linux/delay.h>
0011 #include <sound/core.h>
0012 #include <sound/control.h>
0013 #include <sound/tlv.h>
0014 #include "wm8766.h"
0015 
0016 /* low-level access */
0017 
0018 static void snd_wm8766_write(struct snd_wm8766 *wm, u16 addr, u16 data)
0019 {
0020     if (addr < WM8766_REG_COUNT)
0021         wm->regs[addr] = data;
0022     wm->ops.write(wm, addr, data);
0023 }
0024 
0025 /* mixer controls */
0026 
0027 static const DECLARE_TLV_DB_SCALE(wm8766_tlv, -12750, 50, 1);
0028 
0029 static const struct snd_wm8766_ctl snd_wm8766_default_ctl[WM8766_CTL_COUNT] = {
0030     [WM8766_CTL_CH1_VOL] = {
0031         .name = "Channel 1 Playback Volume",
0032         .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
0033         .tlv = wm8766_tlv,
0034         .reg1 = WM8766_REG_DACL1,
0035         .reg2 = WM8766_REG_DACR1,
0036         .mask1 = WM8766_VOL_MASK,
0037         .mask2 = WM8766_VOL_MASK,
0038         .max = 0xff,
0039         .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE,
0040     },
0041     [WM8766_CTL_CH2_VOL] = {
0042         .name = "Channel 2 Playback Volume",
0043         .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
0044         .tlv = wm8766_tlv,
0045         .reg1 = WM8766_REG_DACL2,
0046         .reg2 = WM8766_REG_DACR2,
0047         .mask1 = WM8766_VOL_MASK,
0048         .mask2 = WM8766_VOL_MASK,
0049         .max = 0xff,
0050         .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE,
0051     },
0052     [WM8766_CTL_CH3_VOL] = {
0053         .name = "Channel 3 Playback Volume",
0054         .type = SNDRV_CTL_ELEM_TYPE_INTEGER,
0055         .tlv = wm8766_tlv,
0056         .reg1 = WM8766_REG_DACL3,
0057         .reg2 = WM8766_REG_DACR3,
0058         .mask1 = WM8766_VOL_MASK,
0059         .mask2 = WM8766_VOL_MASK,
0060         .max = 0xff,
0061         .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE,
0062     },
0063     [WM8766_CTL_CH1_SW] = {
0064         .name = "Channel 1 Playback Switch",
0065         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0066         .reg1 = WM8766_REG_DACCTRL2,
0067         .mask1 = WM8766_DAC2_MUTE1,
0068         .flags = WM8766_FLAG_INVERT,
0069     },
0070     [WM8766_CTL_CH2_SW] = {
0071         .name = "Channel 2 Playback Switch",
0072         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0073         .reg1 = WM8766_REG_DACCTRL2,
0074         .mask1 = WM8766_DAC2_MUTE2,
0075         .flags = WM8766_FLAG_INVERT,
0076     },
0077     [WM8766_CTL_CH3_SW] = {
0078         .name = "Channel 3 Playback Switch",
0079         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0080         .reg1 = WM8766_REG_DACCTRL2,
0081         .mask1 = WM8766_DAC2_MUTE3,
0082         .flags = WM8766_FLAG_INVERT,
0083     },
0084     [WM8766_CTL_PHASE1_SW] = {
0085         .name = "Channel 1 Phase Invert Playback Switch",
0086         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0087         .reg1 = WM8766_REG_IFCTRL,
0088         .mask1 = WM8766_PHASE_INVERT1,
0089     },
0090     [WM8766_CTL_PHASE2_SW] = {
0091         .name = "Channel 2 Phase Invert Playback Switch",
0092         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0093         .reg1 = WM8766_REG_IFCTRL,
0094         .mask1 = WM8766_PHASE_INVERT2,
0095     },
0096     [WM8766_CTL_PHASE3_SW] = {
0097         .name = "Channel 3 Phase Invert Playback Switch",
0098         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0099         .reg1 = WM8766_REG_IFCTRL,
0100         .mask1 = WM8766_PHASE_INVERT3,
0101     },
0102     [WM8766_CTL_DEEMPH1_SW] = {
0103         .name = "Channel 1 Deemphasis Playback Switch",
0104         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0105         .reg1 = WM8766_REG_DACCTRL2,
0106         .mask1 = WM8766_DAC2_DEEMP1,
0107     },
0108     [WM8766_CTL_DEEMPH2_SW] = {
0109         .name = "Channel 2 Deemphasis Playback Switch",
0110         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0111         .reg1 = WM8766_REG_DACCTRL2,
0112         .mask1 = WM8766_DAC2_DEEMP2,
0113     },
0114     [WM8766_CTL_DEEMPH3_SW] = {
0115         .name = "Channel 3 Deemphasis Playback Switch",
0116         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0117         .reg1 = WM8766_REG_DACCTRL2,
0118         .mask1 = WM8766_DAC2_DEEMP3,
0119     },
0120     [WM8766_CTL_IZD_SW] = {
0121         .name = "Infinite Zero Detect Playback Switch",
0122         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0123         .reg1 = WM8766_REG_DACCTRL1,
0124         .mask1 = WM8766_DAC_IZD,
0125     },
0126     [WM8766_CTL_ZC_SW] = {
0127         .name = "Zero Cross Detect Playback Switch",
0128         .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
0129         .reg1 = WM8766_REG_DACCTRL2,
0130         .mask1 = WM8766_DAC2_ZCD,
0131         .flags = WM8766_FLAG_INVERT,
0132     },
0133 };
0134 
0135 /* exported functions */
0136 
0137 void snd_wm8766_init(struct snd_wm8766 *wm)
0138 {
0139     int i;
0140     static const u16 default_values[] = {
0141         0x000, 0x100,
0142         0x120, 0x000,
0143         0x000, 0x100, 0x000, 0x100, 0x000,
0144         0x000, 0x080,
0145     };
0146 
0147     memcpy(wm->ctl, snd_wm8766_default_ctl, sizeof(wm->ctl));
0148 
0149     snd_wm8766_write(wm, WM8766_REG_RESET, 0x00); /* reset */
0150     udelay(10);
0151     /* load defaults */
0152     for (i = 0; i < ARRAY_SIZE(default_values); i++)
0153         snd_wm8766_write(wm, i, default_values[i]);
0154 }
0155 
0156 void snd_wm8766_resume(struct snd_wm8766 *wm)
0157 {
0158     int i;
0159 
0160     for (i = 0; i < WM8766_REG_COUNT; i++)
0161         snd_wm8766_write(wm, i, wm->regs[i]);
0162 }
0163 
0164 void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac)
0165 {
0166     u16 val = wm->regs[WM8766_REG_IFCTRL] & ~WM8766_IF_MASK;
0167 
0168     dac &= WM8766_IF_MASK;
0169     snd_wm8766_write(wm, WM8766_REG_IFCTRL, val | dac);
0170 }
0171 
0172 void snd_wm8766_volume_restore(struct snd_wm8766 *wm)
0173 {
0174     u16 val = wm->regs[WM8766_REG_DACR1];
0175     /* restore volume after MCLK stopped */
0176     snd_wm8766_write(wm, WM8766_REG_DACR1, val | WM8766_VOL_UPDATE);
0177 }
0178 
0179 /* mixer callbacks */
0180 
0181 static int snd_wm8766_volume_info(struct snd_kcontrol *kcontrol,
0182                    struct snd_ctl_elem_info *uinfo)
0183 {
0184     struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol);
0185     int n = kcontrol->private_value;
0186 
0187     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0188     uinfo->count = (wm->ctl[n].flags & WM8766_FLAG_STEREO) ? 2 : 1;
0189     uinfo->value.integer.min = wm->ctl[n].min;
0190     uinfo->value.integer.max = wm->ctl[n].max;
0191 
0192     return 0;
0193 }
0194 
0195 static int snd_wm8766_enum_info(struct snd_kcontrol *kcontrol,
0196                       struct snd_ctl_elem_info *uinfo)
0197 {
0198     struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol);
0199     int n = kcontrol->private_value;
0200 
0201     return snd_ctl_enum_info(uinfo, 1, wm->ctl[n].max,
0202                         wm->ctl[n].enum_names);
0203 }
0204 
0205 static int snd_wm8766_ctl_get(struct snd_kcontrol *kcontrol,
0206                   struct snd_ctl_elem_value *ucontrol)
0207 {
0208     struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol);
0209     int n = kcontrol->private_value;
0210     u16 val1, val2;
0211 
0212     if (wm->ctl[n].get)
0213         wm->ctl[n].get(wm, &val1, &val2);
0214     else {
0215         val1 = wm->regs[wm->ctl[n].reg1] & wm->ctl[n].mask1;
0216         val1 >>= __ffs(wm->ctl[n].mask1);
0217         if (wm->ctl[n].flags & WM8766_FLAG_STEREO) {
0218             val2 = wm->regs[wm->ctl[n].reg2] & wm->ctl[n].mask2;
0219             val2 >>= __ffs(wm->ctl[n].mask2);
0220             if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE)
0221                 val2 &= ~WM8766_VOL_UPDATE;
0222         }
0223     }
0224     if (wm->ctl[n].flags & WM8766_FLAG_INVERT) {
0225         val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min);
0226         if (wm->ctl[n].flags & WM8766_FLAG_STEREO)
0227             val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min);
0228     }
0229     ucontrol->value.integer.value[0] = val1;
0230     if (wm->ctl[n].flags & WM8766_FLAG_STEREO)
0231         ucontrol->value.integer.value[1] = val2;
0232 
0233     return 0;
0234 }
0235 
0236 static int snd_wm8766_ctl_put(struct snd_kcontrol *kcontrol,
0237                   struct snd_ctl_elem_value *ucontrol)
0238 {
0239     struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol);
0240     int n = kcontrol->private_value;
0241     u16 val, regval1, regval2;
0242 
0243     /* this also works for enum because value is a union */
0244     regval1 = ucontrol->value.integer.value[0];
0245     regval2 = ucontrol->value.integer.value[1];
0246     if (wm->ctl[n].flags & WM8766_FLAG_INVERT) {
0247         regval1 = wm->ctl[n].max - (regval1 - wm->ctl[n].min);
0248         regval2 = wm->ctl[n].max - (regval2 - wm->ctl[n].min);
0249     }
0250     if (wm->ctl[n].set)
0251         wm->ctl[n].set(wm, regval1, regval2);
0252     else {
0253         val = wm->regs[wm->ctl[n].reg1] & ~wm->ctl[n].mask1;
0254         val |= regval1 << __ffs(wm->ctl[n].mask1);
0255         /* both stereo controls in one register */
0256         if (wm->ctl[n].flags & WM8766_FLAG_STEREO &&
0257                 wm->ctl[n].reg1 == wm->ctl[n].reg2) {
0258             val &= ~wm->ctl[n].mask2;
0259             val |= regval2 << __ffs(wm->ctl[n].mask2);
0260         }
0261         snd_wm8766_write(wm, wm->ctl[n].reg1, val);
0262         /* stereo controls in different registers */
0263         if (wm->ctl[n].flags & WM8766_FLAG_STEREO &&
0264                 wm->ctl[n].reg1 != wm->ctl[n].reg2) {
0265             val = wm->regs[wm->ctl[n].reg2] & ~wm->ctl[n].mask2;
0266             val |= regval2 << __ffs(wm->ctl[n].mask2);
0267             if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE)
0268                 val |= WM8766_VOL_UPDATE;
0269             snd_wm8766_write(wm, wm->ctl[n].reg2, val);
0270         }
0271     }
0272 
0273     return 0;
0274 }
0275 
0276 static int snd_wm8766_add_control(struct snd_wm8766 *wm, int num)
0277 {
0278     struct snd_kcontrol_new cont;
0279     struct snd_kcontrol *ctl;
0280 
0281     memset(&cont, 0, sizeof(cont));
0282     cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
0283     cont.private_value = num;
0284     cont.name = wm->ctl[num].name;
0285     cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
0286     if (wm->ctl[num].flags & WM8766_FLAG_LIM ||
0287         wm->ctl[num].flags & WM8766_FLAG_ALC)
0288         cont.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
0289     cont.tlv.p = NULL;
0290     cont.get = snd_wm8766_ctl_get;
0291     cont.put = snd_wm8766_ctl_put;
0292 
0293     switch (wm->ctl[num].type) {
0294     case SNDRV_CTL_ELEM_TYPE_INTEGER:
0295         cont.info = snd_wm8766_volume_info;
0296         cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
0297         cont.tlv.p = wm->ctl[num].tlv;
0298         break;
0299     case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
0300         wm->ctl[num].max = 1;
0301         if (wm->ctl[num].flags & WM8766_FLAG_STEREO)
0302             cont.info = snd_ctl_boolean_stereo_info;
0303         else
0304             cont.info = snd_ctl_boolean_mono_info;
0305         break;
0306     case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
0307         cont.info = snd_wm8766_enum_info;
0308         break;
0309     default:
0310         return -EINVAL;
0311     }
0312     ctl = snd_ctl_new1(&cont, wm);
0313     if (!ctl)
0314         return -ENOMEM;
0315     wm->ctl[num].kctl = ctl;
0316 
0317     return snd_ctl_add(wm->card, ctl);
0318 }
0319 
0320 int snd_wm8766_build_controls(struct snd_wm8766 *wm)
0321 {
0322     int err, i;
0323 
0324     for (i = 0; i < WM8766_CTL_COUNT; i++)
0325         if (wm->ctl[i].name) {
0326             err = snd_wm8766_add_control(wm, i);
0327             if (err < 0)
0328                 return err;
0329         }
0330 
0331     return 0;
0332 }