Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * wm8770.c  --  WM8770 ALSA SoC Audio driver
0004  *
0005  * Copyright 2010 Wolfson Microelectronics plc
0006  *
0007  * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/init.h>
0013 #include <linux/delay.h>
0014 #include <linux/of_device.h>
0015 #include <linux/pm.h>
0016 #include <linux/spi/spi.h>
0017 #include <linux/regmap.h>
0018 #include <linux/regulator/consumer.h>
0019 #include <linux/slab.h>
0020 #include <sound/core.h>
0021 #include <sound/pcm.h>
0022 #include <sound/pcm_params.h>
0023 #include <sound/soc.h>
0024 #include <sound/initval.h>
0025 #include <sound/tlv.h>
0026 
0027 #include "wm8770.h"
0028 
0029 #define WM8770_NUM_SUPPLIES 3
0030 static const char *wm8770_supply_names[WM8770_NUM_SUPPLIES] = {
0031     "AVDD1",
0032     "AVDD2",
0033     "DVDD"
0034 };
0035 
0036 static const struct reg_default wm8770_reg_defaults[] = {
0037     {  0, 0x7f },
0038     {  1, 0x7f },
0039     {  2, 0x7f },
0040     {  3, 0x7f },
0041     {  4, 0x7f },
0042     {  5, 0x7f },
0043     {  6, 0x7f },
0044     {  7, 0x7f },
0045     {  8, 0x7f },
0046     {  9, 0xff },
0047     { 10, 0xff },
0048     { 11, 0xff },
0049     { 12, 0xff },
0050     { 13, 0xff },
0051     { 14, 0xff },
0052     { 15, 0xff },
0053     { 16, 0xff },
0054     { 17, 0xff },
0055     { 18, 0    },
0056     { 19, 0x90 },
0057     { 20, 0    },
0058     { 21, 0    },
0059     { 22, 0x22 },
0060     { 23, 0x22 },
0061     { 24, 0x3e },
0062     { 25, 0xc  },
0063     { 26, 0xc  },
0064     { 27, 0x100 },
0065     { 28, 0x189 },
0066     { 29, 0x189 },
0067     { 30, 0x8770 },
0068 };
0069 
0070 static bool wm8770_volatile_reg(struct device *dev, unsigned int reg)
0071 {
0072     switch (reg) {
0073     case WM8770_RESET:
0074         return true;
0075     default:
0076         return false;
0077     }
0078 }
0079 
0080 struct wm8770_priv {
0081     struct regmap *regmap;
0082     struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES];
0083     struct notifier_block disable_nb[WM8770_NUM_SUPPLIES];
0084     struct snd_soc_component *component;
0085     int sysclk;
0086 };
0087 
0088 static int vout12supply_event(struct snd_soc_dapm_widget *w,
0089     struct snd_kcontrol *kcontrol, int event);
0090 static int vout34supply_event(struct snd_soc_dapm_widget *w,
0091     struct snd_kcontrol *kcontrol, int event);
0092 
0093 /*
0094  * We can't use the same notifier block for more than one supply and
0095  * there's no way I can see to get from a callback to the caller
0096  * except container_of().
0097  */
0098 #define WM8770_REGULATOR_EVENT(n) \
0099 static int wm8770_regulator_event_##n(struct notifier_block *nb, \
0100                       unsigned long event, void *data)    \
0101 { \
0102     struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \
0103                      disable_nb[n]); \
0104     if (event & REGULATOR_EVENT_DISABLE) { \
0105         regcache_mark_dirty(wm8770->regmap);    \
0106     } \
0107     return 0; \
0108 }
0109 
0110 WM8770_REGULATOR_EVENT(0)
0111 WM8770_REGULATOR_EVENT(1)
0112 WM8770_REGULATOR_EVENT(2)
0113 
0114 static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 100, 0);
0115 static const DECLARE_TLV_DB_SCALE(dac_dig_tlv, -12750, 50, 1);
0116 static const DECLARE_TLV_DB_SCALE(dac_alg_tlv, -12700, 100, 1);
0117 
0118 static const char *dac_phase_text[][2] = {
0119     { "DAC1 Normal", "DAC1 Inverted" },
0120     { "DAC2 Normal", "DAC2 Inverted" },
0121     { "DAC3 Normal", "DAC3 Inverted" },
0122     { "DAC4 Normal", "DAC4 Inverted" },
0123 };
0124 
0125 static const struct soc_enum dac_phase[] = {
0126     SOC_ENUM_DOUBLE(WM8770_DACPHASE, 0, 1, 2, dac_phase_text[0]),
0127     SOC_ENUM_DOUBLE(WM8770_DACPHASE, 2, 3, 2, dac_phase_text[1]),
0128     SOC_ENUM_DOUBLE(WM8770_DACPHASE, 4, 5, 2, dac_phase_text[2]),
0129     SOC_ENUM_DOUBLE(WM8770_DACPHASE, 6, 7, 2, dac_phase_text[3]),
0130 };
0131 
0132 static const struct snd_kcontrol_new wm8770_snd_controls[] = {
0133     /* global DAC playback controls */
0134     SOC_SINGLE_TLV("DAC Playback Volume", WM8770_MSDIGVOL, 0, 255, 0,
0135         dac_dig_tlv),
0136     SOC_SINGLE("DAC Playback Switch", WM8770_DACMUTE, 4, 1, 1),
0137     SOC_SINGLE("DAC Playback ZC Switch", WM8770_DACCTRL1, 0, 1, 0),
0138 
0139     /* global VOUT playback controls */
0140     SOC_SINGLE_TLV("VOUT Playback Volume", WM8770_MSALGVOL, 0, 127, 0,
0141         dac_alg_tlv),
0142     SOC_SINGLE("VOUT Playback ZC Switch", WM8770_MSALGVOL, 7, 1, 0),
0143 
0144     /* VOUT1/2/3/4 specific controls */
0145     SOC_DOUBLE_R_TLV("VOUT1 Playback Volume", WM8770_VOUT1LVOL,
0146         WM8770_VOUT1RVOL, 0, 127, 0, dac_alg_tlv),
0147     SOC_DOUBLE_R("VOUT1 Playback ZC Switch", WM8770_VOUT1LVOL,
0148         WM8770_VOUT1RVOL, 7, 1, 0),
0149     SOC_DOUBLE_R_TLV("VOUT2 Playback Volume", WM8770_VOUT2LVOL,
0150         WM8770_VOUT2RVOL, 0, 127, 0, dac_alg_tlv),
0151     SOC_DOUBLE_R("VOUT2 Playback ZC Switch", WM8770_VOUT2LVOL,
0152         WM8770_VOUT2RVOL, 7, 1, 0),
0153     SOC_DOUBLE_R_TLV("VOUT3 Playback Volume", WM8770_VOUT3LVOL,
0154         WM8770_VOUT3RVOL, 0, 127, 0, dac_alg_tlv),
0155     SOC_DOUBLE_R("VOUT3 Playback ZC Switch", WM8770_VOUT3LVOL,
0156         WM8770_VOUT3RVOL, 7, 1, 0),
0157     SOC_DOUBLE_R_TLV("VOUT4 Playback Volume", WM8770_VOUT4LVOL,
0158         WM8770_VOUT4RVOL, 0, 127, 0, dac_alg_tlv),
0159     SOC_DOUBLE_R("VOUT4 Playback ZC Switch", WM8770_VOUT4LVOL,
0160         WM8770_VOUT4RVOL, 7, 1, 0),
0161 
0162     /* DAC1/2/3/4 specific controls */
0163     SOC_DOUBLE_R_TLV("DAC1 Playback Volume", WM8770_DAC1LVOL,
0164         WM8770_DAC1RVOL, 0, 255, 0, dac_dig_tlv),
0165     SOC_SINGLE("DAC1 Deemphasis Switch", WM8770_DACCTRL2, 0, 1, 0),
0166     SOC_ENUM("DAC1 Phase", dac_phase[0]),
0167     SOC_DOUBLE_R_TLV("DAC2 Playback Volume", WM8770_DAC2LVOL,
0168         WM8770_DAC2RVOL, 0, 255, 0, dac_dig_tlv),
0169     SOC_SINGLE("DAC2 Deemphasis Switch", WM8770_DACCTRL2, 1, 1, 0),
0170     SOC_ENUM("DAC2 Phase", dac_phase[1]),
0171     SOC_DOUBLE_R_TLV("DAC3 Playback Volume", WM8770_DAC3LVOL,
0172         WM8770_DAC3RVOL, 0, 255, 0, dac_dig_tlv),
0173     SOC_SINGLE("DAC3 Deemphasis Switch", WM8770_DACCTRL2, 2, 1, 0),
0174     SOC_ENUM("DAC3 Phase", dac_phase[2]),
0175     SOC_DOUBLE_R_TLV("DAC4 Playback Volume", WM8770_DAC4LVOL,
0176         WM8770_DAC4RVOL, 0, 255, 0, dac_dig_tlv),
0177     SOC_SINGLE("DAC4 Deemphasis Switch", WM8770_DACCTRL2, 3, 1, 0),
0178     SOC_ENUM("DAC4 Phase", dac_phase[3]),
0179 
0180     /* ADC specific controls */
0181     SOC_DOUBLE_R_TLV("Capture Volume", WM8770_ADCLCTRL, WM8770_ADCRCTRL,
0182         0, 31, 0, adc_tlv),
0183     SOC_DOUBLE_R("Capture Switch", WM8770_ADCLCTRL, WM8770_ADCRCTRL,
0184         5, 1, 1),
0185 
0186     /* other controls */
0187     SOC_SINGLE("ADC 128x Oversampling Switch", WM8770_MSTRCTRL, 3, 1, 0),
0188     SOC_SINGLE("ADC Highpass Filter Switch", WM8770_IFACECTRL, 8, 1, 1)
0189 };
0190 
0191 static const char *ain_text[] = {
0192     "AIN1", "AIN2", "AIN3", "AIN4",
0193     "AIN5", "AIN6", "AIN7", "AIN8"
0194 };
0195 
0196 static SOC_ENUM_DOUBLE_DECL(ain_enum,
0197                 WM8770_ADCMUX, 0, 4, ain_text);
0198 
0199 static const struct snd_kcontrol_new ain_mux =
0200     SOC_DAPM_ENUM("Capture Mux", ain_enum);
0201 
0202 static const struct snd_kcontrol_new vout1_mix_controls[] = {
0203     SOC_DAPM_SINGLE("DAC1 Switch", WM8770_OUTMUX1, 0, 1, 0),
0204     SOC_DAPM_SINGLE("AUX1 Switch", WM8770_OUTMUX1, 1, 1, 0),
0205     SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 2, 1, 0)
0206 };
0207 
0208 static const struct snd_kcontrol_new vout2_mix_controls[] = {
0209     SOC_DAPM_SINGLE("DAC2 Switch", WM8770_OUTMUX1, 3, 1, 0),
0210     SOC_DAPM_SINGLE("AUX2 Switch", WM8770_OUTMUX1, 4, 1, 0),
0211     SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 5, 1, 0)
0212 };
0213 
0214 static const struct snd_kcontrol_new vout3_mix_controls[] = {
0215     SOC_DAPM_SINGLE("DAC3 Switch", WM8770_OUTMUX2, 0, 1, 0),
0216     SOC_DAPM_SINGLE("AUX3 Switch", WM8770_OUTMUX2, 1, 1, 0),
0217     SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 2, 1, 0)
0218 };
0219 
0220 static const struct snd_kcontrol_new vout4_mix_controls[] = {
0221     SOC_DAPM_SINGLE("DAC4 Switch", WM8770_OUTMUX2, 3, 1, 0),
0222     SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 4, 1, 0)
0223 };
0224 
0225 static const struct snd_soc_dapm_widget wm8770_dapm_widgets[] = {
0226     SND_SOC_DAPM_INPUT("AUX1"),
0227     SND_SOC_DAPM_INPUT("AUX2"),
0228     SND_SOC_DAPM_INPUT("AUX3"),
0229 
0230     SND_SOC_DAPM_INPUT("AIN1"),
0231     SND_SOC_DAPM_INPUT("AIN2"),
0232     SND_SOC_DAPM_INPUT("AIN3"),
0233     SND_SOC_DAPM_INPUT("AIN4"),
0234     SND_SOC_DAPM_INPUT("AIN5"),
0235     SND_SOC_DAPM_INPUT("AIN6"),
0236     SND_SOC_DAPM_INPUT("AIN7"),
0237     SND_SOC_DAPM_INPUT("AIN8"),
0238 
0239     SND_SOC_DAPM_MUX("Capture Mux", WM8770_ADCMUX, 8, 1, &ain_mux),
0240 
0241     SND_SOC_DAPM_ADC("ADC", "Capture", WM8770_PWDNCTRL, 1, 1),
0242 
0243     SND_SOC_DAPM_DAC("DAC1", "Playback", WM8770_PWDNCTRL, 2, 1),
0244     SND_SOC_DAPM_DAC("DAC2", "Playback", WM8770_PWDNCTRL, 3, 1),
0245     SND_SOC_DAPM_DAC("DAC3", "Playback", WM8770_PWDNCTRL, 4, 1),
0246     SND_SOC_DAPM_DAC("DAC4", "Playback", WM8770_PWDNCTRL, 5, 1),
0247 
0248     SND_SOC_DAPM_SUPPLY("VOUT12 Supply", SND_SOC_NOPM, 0, 0,
0249         vout12supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
0250     SND_SOC_DAPM_SUPPLY("VOUT34 Supply", SND_SOC_NOPM, 0, 0,
0251         vout34supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
0252 
0253     SND_SOC_DAPM_MIXER("VOUT1 Mixer", SND_SOC_NOPM, 0, 0,
0254         vout1_mix_controls, ARRAY_SIZE(vout1_mix_controls)),
0255     SND_SOC_DAPM_MIXER("VOUT2 Mixer", SND_SOC_NOPM, 0, 0,
0256         vout2_mix_controls, ARRAY_SIZE(vout2_mix_controls)),
0257     SND_SOC_DAPM_MIXER("VOUT3 Mixer", SND_SOC_NOPM, 0, 0,
0258         vout3_mix_controls, ARRAY_SIZE(vout3_mix_controls)),
0259     SND_SOC_DAPM_MIXER("VOUT4 Mixer", SND_SOC_NOPM, 0, 0,
0260         vout4_mix_controls, ARRAY_SIZE(vout4_mix_controls)),
0261 
0262     SND_SOC_DAPM_OUTPUT("VOUT1"),
0263     SND_SOC_DAPM_OUTPUT("VOUT2"),
0264     SND_SOC_DAPM_OUTPUT("VOUT3"),
0265     SND_SOC_DAPM_OUTPUT("VOUT4")
0266 };
0267 
0268 static const struct snd_soc_dapm_route wm8770_intercon[] = {
0269     { "Capture Mux", "AIN1", "AIN1" },
0270     { "Capture Mux", "AIN2", "AIN2" },
0271     { "Capture Mux", "AIN3", "AIN3" },
0272     { "Capture Mux", "AIN4", "AIN4" },
0273     { "Capture Mux", "AIN5", "AIN5" },
0274     { "Capture Mux", "AIN6", "AIN6" },
0275     { "Capture Mux", "AIN7", "AIN7" },
0276     { "Capture Mux", "AIN8", "AIN8" },
0277 
0278     { "ADC", NULL, "Capture Mux" },
0279 
0280     { "VOUT1 Mixer", NULL, "VOUT12 Supply" },
0281     { "VOUT1 Mixer", "DAC1 Switch", "DAC1" },
0282     { "VOUT1 Mixer", "AUX1 Switch", "AUX1" },
0283     { "VOUT1 Mixer", "Bypass Switch", "Capture Mux" },
0284 
0285     { "VOUT2 Mixer", NULL, "VOUT12 Supply" },
0286     { "VOUT2 Mixer", "DAC2 Switch", "DAC2" },
0287     { "VOUT2 Mixer", "AUX2 Switch", "AUX2" },
0288     { "VOUT2 Mixer", "Bypass Switch", "Capture Mux" },
0289 
0290     { "VOUT3 Mixer", NULL, "VOUT34 Supply" },
0291     { "VOUT3 Mixer", "DAC3 Switch", "DAC3" },
0292     { "VOUT3 Mixer", "AUX3 Switch", "AUX3" },
0293     { "VOUT3 Mixer", "Bypass Switch", "Capture Mux" },
0294 
0295     { "VOUT4 Mixer", NULL, "VOUT34 Supply" },
0296     { "VOUT4 Mixer", "DAC4 Switch", "DAC4" },
0297     { "VOUT4 Mixer", "Bypass Switch", "Capture Mux" },
0298 
0299     { "VOUT1", NULL, "VOUT1 Mixer" },
0300     { "VOUT2", NULL, "VOUT2 Mixer" },
0301     { "VOUT3", NULL, "VOUT3 Mixer" },
0302     { "VOUT4", NULL, "VOUT4 Mixer" }
0303 };
0304 
0305 static int vout12supply_event(struct snd_soc_dapm_widget *w,
0306     struct snd_kcontrol *kcontrol, int event)
0307 {
0308     struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
0309 
0310     switch (event) {
0311     case SND_SOC_DAPM_PRE_PMU:
0312         snd_soc_component_update_bits(component, WM8770_OUTMUX1, 0x180, 0);
0313         break;
0314     case SND_SOC_DAPM_POST_PMD:
0315         snd_soc_component_update_bits(component, WM8770_OUTMUX1, 0x180, 0x180);
0316         break;
0317     }
0318 
0319     return 0;
0320 }
0321 
0322 static int vout34supply_event(struct snd_soc_dapm_widget *w,
0323     struct snd_kcontrol *kcontrol, int event)
0324 {
0325     struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
0326 
0327     switch (event) {
0328     case SND_SOC_DAPM_PRE_PMU:
0329         snd_soc_component_update_bits(component, WM8770_OUTMUX2, 0x180, 0);
0330         break;
0331     case SND_SOC_DAPM_POST_PMD:
0332         snd_soc_component_update_bits(component, WM8770_OUTMUX2, 0x180, 0x180);
0333         break;
0334     }
0335 
0336     return 0;
0337 }
0338 
0339 static int wm8770_reset(struct snd_soc_component *component)
0340 {
0341     return snd_soc_component_write(component, WM8770_RESET, 0);
0342 }
0343 
0344 static int wm8770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0345 {
0346     struct snd_soc_component *component;
0347     int iface, master;
0348 
0349     component = dai->component;
0350 
0351     switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
0352     case SND_SOC_DAIFMT_CBM_CFM:
0353         master = 0x100;
0354         break;
0355     case SND_SOC_DAIFMT_CBS_CFS:
0356         master = 0;
0357         break;
0358     default:
0359         return -EINVAL;
0360     }
0361 
0362     iface = 0;
0363     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0364     case SND_SOC_DAIFMT_I2S:
0365         iface |= 0x2;
0366         break;
0367     case SND_SOC_DAIFMT_RIGHT_J:
0368         break;
0369     case SND_SOC_DAIFMT_LEFT_J:
0370         iface |= 0x1;
0371         break;
0372     default:
0373         return -EINVAL;
0374     }
0375 
0376     switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
0377     case SND_SOC_DAIFMT_NB_NF:
0378         break;
0379     case SND_SOC_DAIFMT_IB_IF:
0380         iface |= 0xc;
0381         break;
0382     case SND_SOC_DAIFMT_IB_NF:
0383         iface |= 0x8;
0384         break;
0385     case SND_SOC_DAIFMT_NB_IF:
0386         iface |= 0x4;
0387         break;
0388     default:
0389         return -EINVAL;
0390     }
0391 
0392     snd_soc_component_update_bits(component, WM8770_IFACECTRL, 0xf, iface);
0393     snd_soc_component_update_bits(component, WM8770_MSTRCTRL, 0x100, master);
0394 
0395     return 0;
0396 }
0397 
0398 static const int mclk_ratios[] = {
0399     128,
0400     192,
0401     256,
0402     384,
0403     512,
0404     768
0405 };
0406 
0407 static int wm8770_hw_params(struct snd_pcm_substream *substream,
0408                 struct snd_pcm_hw_params *params,
0409                 struct snd_soc_dai *dai)
0410 {
0411     struct snd_soc_component *component;
0412     struct wm8770_priv *wm8770;
0413     int i;
0414     int iface;
0415     int shift;
0416     int ratio;
0417 
0418     component = dai->component;
0419     wm8770 = snd_soc_component_get_drvdata(component);
0420 
0421     iface = 0;
0422     switch (params_width(params)) {
0423     case 16:
0424         break;
0425     case 20:
0426         iface |= 0x10;
0427         break;
0428     case 24:
0429         iface |= 0x20;
0430         break;
0431     case 32:
0432         iface |= 0x30;
0433         break;
0434     }
0435 
0436     switch (substream->stream) {
0437     case SNDRV_PCM_STREAM_PLAYBACK:
0438         i = 0;
0439         shift = 4;
0440         break;
0441     case SNDRV_PCM_STREAM_CAPTURE:
0442         i = 2;
0443         shift = 0;
0444         break;
0445     default:
0446         return -EINVAL;
0447     }
0448 
0449     /* Only need to set MCLK/LRCLK ratio if we're master */
0450     if (snd_soc_component_read(component, WM8770_MSTRCTRL) & 0x100) {
0451         for (; i < ARRAY_SIZE(mclk_ratios); ++i) {
0452             ratio = wm8770->sysclk / params_rate(params);
0453             if (ratio == mclk_ratios[i])
0454                 break;
0455         }
0456 
0457         if (i == ARRAY_SIZE(mclk_ratios)) {
0458             dev_err(component->dev,
0459                 "Unable to configure MCLK ratio %d/%d\n",
0460                 wm8770->sysclk, params_rate(params));
0461             return -EINVAL;
0462         }
0463 
0464         dev_dbg(component->dev, "MCLK is %dfs\n", mclk_ratios[i]);
0465 
0466         snd_soc_component_update_bits(component, WM8770_MSTRCTRL, 0x7 << shift,
0467                     i << shift);
0468     }
0469 
0470     snd_soc_component_update_bits(component, WM8770_IFACECTRL, 0x30, iface);
0471 
0472     return 0;
0473 }
0474 
0475 static int wm8770_mute(struct snd_soc_dai *dai, int mute, int direction)
0476 {
0477     struct snd_soc_component *component;
0478 
0479     component = dai->component;
0480     return snd_soc_component_update_bits(component, WM8770_DACMUTE, 0x10,
0481                    !!mute << 4);
0482 }
0483 
0484 static int wm8770_set_sysclk(struct snd_soc_dai *dai,
0485                  int clk_id, unsigned int freq, int dir)
0486 {
0487     struct snd_soc_component *component;
0488     struct wm8770_priv *wm8770;
0489 
0490     component = dai->component;
0491     wm8770 = snd_soc_component_get_drvdata(component);
0492     wm8770->sysclk = freq;
0493     return 0;
0494 }
0495 
0496 static int wm8770_set_bias_level(struct snd_soc_component *component,
0497                  enum snd_soc_bias_level level)
0498 {
0499     int ret;
0500     struct wm8770_priv *wm8770;
0501 
0502     wm8770 = snd_soc_component_get_drvdata(component);
0503 
0504     switch (level) {
0505     case SND_SOC_BIAS_ON:
0506         break;
0507     case SND_SOC_BIAS_PREPARE:
0508         break;
0509     case SND_SOC_BIAS_STANDBY:
0510         if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
0511             ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
0512                             wm8770->supplies);
0513             if (ret) {
0514                 dev_err(component->dev,
0515                     "Failed to enable supplies: %d\n",
0516                     ret);
0517                 return ret;
0518             }
0519 
0520             regcache_sync(wm8770->regmap);
0521 
0522             /* global powerup */
0523             snd_soc_component_write(component, WM8770_PWDNCTRL, 0);
0524         }
0525         break;
0526     case SND_SOC_BIAS_OFF:
0527         /* global powerdown */
0528         snd_soc_component_write(component, WM8770_PWDNCTRL, 1);
0529         regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies),
0530                        wm8770->supplies);
0531         break;
0532     }
0533 
0534     return 0;
0535 }
0536 
0537 #define WM8770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
0538             SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
0539 
0540 static const struct snd_soc_dai_ops wm8770_dai_ops = {
0541     .mute_stream = wm8770_mute,
0542     .hw_params = wm8770_hw_params,
0543     .set_fmt = wm8770_set_fmt,
0544     .set_sysclk = wm8770_set_sysclk,
0545     .no_capture_mute = 1,
0546 };
0547 
0548 static struct snd_soc_dai_driver wm8770_dai = {
0549     .name = "wm8770-hifi",
0550     .playback = {
0551         .stream_name = "Playback",
0552         .channels_min = 2,
0553         .channels_max = 2,
0554         .rates = SNDRV_PCM_RATE_8000_192000,
0555         .formats = WM8770_FORMATS
0556     },
0557     .capture = {
0558         .stream_name = "Capture",
0559         .channels_min = 2,
0560         .channels_max = 2,
0561         .rates = SNDRV_PCM_RATE_8000_96000,
0562         .formats = WM8770_FORMATS
0563     },
0564     .ops = &wm8770_dai_ops,
0565     .symmetric_rate = 1
0566 };
0567 
0568 static int wm8770_probe(struct snd_soc_component *component)
0569 {
0570     struct wm8770_priv *wm8770;
0571     int ret;
0572 
0573     wm8770 = snd_soc_component_get_drvdata(component);
0574     wm8770->component = component;
0575 
0576     ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
0577                     wm8770->supplies);
0578     if (ret) {
0579         dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
0580         return ret;
0581     }
0582 
0583     ret = wm8770_reset(component);
0584     if (ret < 0) {
0585         dev_err(component->dev, "Failed to issue reset: %d\n", ret);
0586         goto err_reg_enable;
0587     }
0588 
0589     /* latch the volume update bits */
0590     snd_soc_component_update_bits(component, WM8770_MSDIGVOL, 0x100, 0x100);
0591     snd_soc_component_update_bits(component, WM8770_MSALGVOL, 0x100, 0x100);
0592     snd_soc_component_update_bits(component, WM8770_VOUT1RVOL, 0x100, 0x100);
0593     snd_soc_component_update_bits(component, WM8770_VOUT2RVOL, 0x100, 0x100);
0594     snd_soc_component_update_bits(component, WM8770_VOUT3RVOL, 0x100, 0x100);
0595     snd_soc_component_update_bits(component, WM8770_VOUT4RVOL, 0x100, 0x100);
0596     snd_soc_component_update_bits(component, WM8770_DAC1RVOL, 0x100, 0x100);
0597     snd_soc_component_update_bits(component, WM8770_DAC2RVOL, 0x100, 0x100);
0598     snd_soc_component_update_bits(component, WM8770_DAC3RVOL, 0x100, 0x100);
0599     snd_soc_component_update_bits(component, WM8770_DAC4RVOL, 0x100, 0x100);
0600 
0601     /* mute all DACs */
0602     snd_soc_component_update_bits(component, WM8770_DACMUTE, 0x10, 0x10);
0603 
0604 err_reg_enable:
0605     regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
0606     return ret;
0607 }
0608 
0609 static const struct snd_soc_component_driver soc_component_dev_wm8770 = {
0610     .probe          = wm8770_probe,
0611     .set_bias_level     = wm8770_set_bias_level,
0612     .controls       = wm8770_snd_controls,
0613     .num_controls       = ARRAY_SIZE(wm8770_snd_controls),
0614     .dapm_widgets       = wm8770_dapm_widgets,
0615     .num_dapm_widgets   = ARRAY_SIZE(wm8770_dapm_widgets),
0616     .dapm_routes        = wm8770_intercon,
0617     .num_dapm_routes    = ARRAY_SIZE(wm8770_intercon),
0618     .use_pmdown_time    = 1,
0619     .endianness     = 1,
0620 };
0621 
0622 static const struct of_device_id wm8770_of_match[] = {
0623     { .compatible = "wlf,wm8770", },
0624     { }
0625 };
0626 MODULE_DEVICE_TABLE(of, wm8770_of_match);
0627 
0628 static const struct regmap_config wm8770_regmap = {
0629     .reg_bits = 7,
0630     .val_bits = 9,
0631     .max_register = WM8770_RESET,
0632 
0633     .reg_defaults = wm8770_reg_defaults,
0634     .num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults),
0635     .cache_type = REGCACHE_RBTREE,
0636 
0637     .volatile_reg = wm8770_volatile_reg,
0638 };
0639 
0640 static int wm8770_spi_probe(struct spi_device *spi)
0641 {
0642     struct wm8770_priv *wm8770;
0643     int ret, i;
0644 
0645     wm8770 = devm_kzalloc(&spi->dev, sizeof(struct wm8770_priv),
0646                   GFP_KERNEL);
0647     if (!wm8770)
0648         return -ENOMEM;
0649 
0650     for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++)
0651         wm8770->supplies[i].supply = wm8770_supply_names[i];
0652 
0653     ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8770->supplies),
0654                       wm8770->supplies);
0655     if (ret) {
0656         dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
0657         return ret;
0658     }
0659 
0660     wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0;
0661     wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1;
0662     wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2;
0663 
0664     /* This should really be moved into the regulator core */
0665     for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) {
0666         ret = devm_regulator_register_notifier(
0667                         wm8770->supplies[i].consumer,
0668                         &wm8770->disable_nb[i]);
0669         if (ret) {
0670             dev_err(&spi->dev,
0671                 "Failed to register regulator notifier: %d\n",
0672                 ret);
0673         }
0674     }
0675 
0676     wm8770->regmap = devm_regmap_init_spi(spi, &wm8770_regmap);
0677     if (IS_ERR(wm8770->regmap))
0678         return PTR_ERR(wm8770->regmap);
0679 
0680     spi_set_drvdata(spi, wm8770);
0681 
0682     ret = devm_snd_soc_register_component(&spi->dev,
0683                      &soc_component_dev_wm8770, &wm8770_dai, 1);
0684 
0685     return ret;
0686 }
0687 
0688 static struct spi_driver wm8770_spi_driver = {
0689     .driver = {
0690         .name = "wm8770",
0691         .of_match_table = wm8770_of_match,
0692     },
0693     .probe = wm8770_spi_probe,
0694 };
0695 
0696 module_spi_driver(wm8770_spi_driver);
0697 
0698 MODULE_DESCRIPTION("ASoC WM8770 driver");
0699 MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
0700 MODULE_LICENSE("GPL");