cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wm8731.c (16933B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * wm8731.c  --  WM8731 ALSA SoC Audio driver
      4 *
      5 * Copyright 2005 Openedhand Ltd.
      6 * Copyright 2006-12 Wolfson Microelectronics, plc
      7 *
      8 * Author: Richard Purdie <richard@openedhand.com>
      9 *
     10 * Based on wm8753.c by Liam Girdwood
     11 */
     12
     13#include <linux/module.h>
     14#include <linux/moduleparam.h>
     15#include <linux/init.h>
     16#include <linux/delay.h>
     17#include <linux/pm.h>
     18#include <linux/slab.h>
     19#include <linux/regmap.h>
     20#include <linux/regulator/consumer.h>
     21#include <linux/clk.h>
     22#include <sound/core.h>
     23#include <sound/pcm.h>
     24#include <sound/pcm_params.h>
     25#include <sound/soc.h>
     26#include <sound/initval.h>
     27#include <sound/tlv.h>
     28
     29#include "wm8731.h"
     30
     31static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
     32	"AVDD",
     33	"HPVDD",
     34	"DCVDD",
     35	"DBVDD",
     36};
     37
     38/*
     39 * wm8731 register cache
     40 */
     41static const struct reg_default wm8731_reg_defaults[] = {
     42	{ 0, 0x0097 },
     43	{ 1, 0x0097 },
     44	{ 2, 0x0079 },
     45	{ 3, 0x0079 },
     46	{ 4, 0x000a },
     47	{ 5, 0x0008 },
     48	{ 6, 0x009f },
     49	{ 7, 0x000a },
     50	{ 8, 0x0000 },
     51	{ 9, 0x0000 },
     52};
     53
     54static bool wm8731_volatile(struct device *dev, unsigned int reg)
     55{
     56	return reg == WM8731_RESET;
     57}
     58
     59#define wm8731_reset(m)	regmap_write(m, WM8731_RESET, 0)
     60
     61static const char *wm8731_input_select[] = {"Line In", "Mic"};
     62
     63static SOC_ENUM_SINGLE_DECL(wm8731_insel_enum,
     64			    WM8731_APANA, 2, wm8731_input_select);
     65
     66static int wm8731_deemph[] = { 0, 32000, 44100, 48000 };
     67
     68static int wm8731_set_deemph(struct snd_soc_component *component)
     69{
     70	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
     71	int val, i, best;
     72
     73	/* If we're using deemphasis select the nearest available sample
     74	 * rate.
     75	 */
     76	if (wm8731->deemph) {
     77		best = 1;
     78		for (i = 2; i < ARRAY_SIZE(wm8731_deemph); i++) {
     79			if (abs(wm8731_deemph[i] - wm8731->playback_fs) <
     80			    abs(wm8731_deemph[best] - wm8731->playback_fs))
     81				best = i;
     82		}
     83
     84		val = best << 1;
     85	} else {
     86		best = 0;
     87		val = 0;
     88	}
     89
     90	dev_dbg(component->dev, "Set deemphasis %d (%dHz)\n",
     91		best, wm8731_deemph[best]);
     92
     93	return snd_soc_component_update_bits(component, WM8731_APDIGI, 0x6, val);
     94}
     95
     96static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
     97			     struct snd_ctl_elem_value *ucontrol)
     98{
     99	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    100	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
    101
    102	ucontrol->value.integer.value[0] = wm8731->deemph;
    103
    104	return 0;
    105}
    106
    107static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
    108			     struct snd_ctl_elem_value *ucontrol)
    109{
    110	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    111	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
    112	unsigned int deemph = ucontrol->value.integer.value[0];
    113	int ret = 0;
    114
    115	if (deemph > 1)
    116		return -EINVAL;
    117
    118	mutex_lock(&wm8731->lock);
    119	if (wm8731->deemph != deemph) {
    120		wm8731->deemph = deemph;
    121
    122		wm8731_set_deemph(component);
    123
    124		ret = 1;
    125	}
    126	mutex_unlock(&wm8731->lock);
    127
    128	return ret;
    129}
    130
    131static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0);
    132static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -1500, 300, 0);
    133static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
    134static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 2000, 0);
    135
    136static const struct snd_kcontrol_new wm8731_snd_controls[] = {
    137
    138SOC_DOUBLE_R_TLV("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
    139		 0, 127, 0, out_tlv),
    140SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V,
    141	7, 1, 0),
    142
    143SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0,
    144		 in_tlv),
    145SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
    146
    147SOC_SINGLE_TLV("Mic Boost Volume", WM8731_APANA, 0, 1, 0, mic_tlv),
    148SOC_SINGLE("Mic Capture Switch", WM8731_APANA, 1, 1, 1),
    149
    150SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1,
    151	       sidetone_tlv),
    152
    153SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
    154SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
    155
    156SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
    157		    wm8731_get_deemph, wm8731_put_deemph),
    158};
    159
    160/* Output Mixer */
    161static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = {
    162SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
    163SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
    164SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
    165};
    166
    167/* Input mux */
    168static const struct snd_kcontrol_new wm8731_input_mux_controls =
    169SOC_DAPM_ENUM("Input Select", wm8731_insel_enum);
    170
    171static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
    172SND_SOC_DAPM_SUPPLY("ACTIVE",WM8731_ACTIVE, 0, 0, NULL, 0),
    173SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
    174SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
    175	&wm8731_output_mixer_controls[0],
    176	ARRAY_SIZE(wm8731_output_mixer_controls)),
    177SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1),
    178SND_SOC_DAPM_OUTPUT("LOUT"),
    179SND_SOC_DAPM_OUTPUT("LHPOUT"),
    180SND_SOC_DAPM_OUTPUT("ROUT"),
    181SND_SOC_DAPM_OUTPUT("RHPOUT"),
    182SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1),
    183SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls),
    184SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0),
    185SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1),
    186SND_SOC_DAPM_INPUT("MICIN"),
    187SND_SOC_DAPM_INPUT("RLINEIN"),
    188SND_SOC_DAPM_INPUT("LLINEIN"),
    189};
    190
    191static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
    192			    struct snd_soc_dapm_widget *sink)
    193{
    194	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
    195	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
    196
    197	return wm8731->sysclk_type == WM8731_SYSCLK_XTAL;
    198}
    199
    200static const struct snd_soc_dapm_route wm8731_intercon[] = {
    201	{"DAC", NULL, "OSC", wm8731_check_osc},
    202	{"ADC", NULL, "OSC", wm8731_check_osc},
    203	{"DAC", NULL, "ACTIVE"},
    204	{"ADC", NULL, "ACTIVE"},
    205
    206	/* output mixer */
    207	{"Output Mixer", "Line Bypass Switch", "Line Input"},
    208	{"Output Mixer", "HiFi Playback Switch", "DAC"},
    209	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
    210
    211	/* outputs */
    212	{"RHPOUT", NULL, "Output Mixer"},
    213	{"ROUT", NULL, "Output Mixer"},
    214	{"LHPOUT", NULL, "Output Mixer"},
    215	{"LOUT", NULL, "Output Mixer"},
    216
    217	/* input mux */
    218	{"Input Mux", "Line In", "Line Input"},
    219	{"Input Mux", "Mic", "Mic Bias"},
    220	{"ADC", NULL, "Input Mux"},
    221
    222	/* inputs */
    223	{"Line Input", NULL, "LLINEIN"},
    224	{"Line Input", NULL, "RLINEIN"},
    225	{"Mic Bias", NULL, "MICIN"},
    226};
    227
    228struct _coeff_div {
    229	u32 mclk;
    230	u32 rate;
    231	u16 fs;
    232	u8 sr:4;
    233	u8 bosr:1;
    234	u8 usb:1;
    235};
    236
    237/* codec mclk clock divider coefficients */
    238static const struct _coeff_div coeff_div[] = {
    239	/* 48k */
    240	{12288000, 48000, 256, 0x0, 0x0, 0x0},
    241	{18432000, 48000, 384, 0x0, 0x1, 0x0},
    242	{12000000, 48000, 250, 0x0, 0x0, 0x1},
    243
    244	/* 32k */
    245	{12288000, 32000, 384, 0x6, 0x0, 0x0},
    246	{18432000, 32000, 576, 0x6, 0x1, 0x0},
    247	{12000000, 32000, 375, 0x6, 0x0, 0x1},
    248
    249	/* 8k */
    250	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
    251	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
    252	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
    253	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
    254	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
    255
    256	/* 96k */
    257	{12288000, 96000, 128, 0x7, 0x0, 0x0},
    258	{18432000, 96000, 192, 0x7, 0x1, 0x0},
    259	{12000000, 96000, 125, 0x7, 0x0, 0x1},
    260
    261	/* 44.1k */
    262	{11289600, 44100, 256, 0x8, 0x0, 0x0},
    263	{16934400, 44100, 384, 0x8, 0x1, 0x0},
    264	{12000000, 44100, 272, 0x8, 0x1, 0x1},
    265
    266	/* 88.2k */
    267	{11289600, 88200, 128, 0xf, 0x0, 0x0},
    268	{16934400, 88200, 192, 0xf, 0x1, 0x0},
    269	{12000000, 88200, 136, 0xf, 0x1, 0x1},
    270};
    271
    272/* rates constraints */
    273static const unsigned int wm8731_rates_12000000[] = {
    274	8000, 32000, 44100, 48000, 96000, 88200,
    275};
    276
    277static const unsigned int wm8731_rates_12288000_18432000[] = {
    278	8000, 32000, 48000, 96000,
    279};
    280
    281static const unsigned int wm8731_rates_11289600_16934400[] = {
    282	8000, 44100, 88200,
    283};
    284
    285static const struct snd_pcm_hw_constraint_list wm8731_constraints_12000000 = {
    286	.list = wm8731_rates_12000000,
    287	.count = ARRAY_SIZE(wm8731_rates_12000000),
    288};
    289
    290static const
    291struct snd_pcm_hw_constraint_list wm8731_constraints_12288000_18432000 = {
    292	.list = wm8731_rates_12288000_18432000,
    293	.count = ARRAY_SIZE(wm8731_rates_12288000_18432000),
    294};
    295
    296static const
    297struct snd_pcm_hw_constraint_list wm8731_constraints_11289600_16934400 = {
    298	.list = wm8731_rates_11289600_16934400,
    299	.count = ARRAY_SIZE(wm8731_rates_11289600_16934400),
    300};
    301
    302static inline int get_coeff(int mclk, int rate)
    303{
    304	int i;
    305
    306	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
    307		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
    308			return i;
    309	}
    310	return 0;
    311}
    312
    313static int wm8731_hw_params(struct snd_pcm_substream *substream,
    314			    struct snd_pcm_hw_params *params,
    315			    struct snd_soc_dai *dai)
    316{
    317	struct snd_soc_component *component = dai->component;
    318	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
    319	u16 iface = snd_soc_component_read(component, WM8731_IFACE) & 0xfff3;
    320	int i = get_coeff(wm8731->sysclk, params_rate(params));
    321	u16 srate = (coeff_div[i].sr << 2) |
    322		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
    323
    324	wm8731->playback_fs = params_rate(params);
    325
    326	snd_soc_component_write(component, WM8731_SRATE, srate);
    327
    328	/* bit size */
    329	switch (params_width(params)) {
    330	case 16:
    331		break;
    332	case 20:
    333		iface |= 0x0004;
    334		break;
    335	case 24:
    336		iface |= 0x0008;
    337		break;
    338	case 32:
    339		iface |= 0x000c;
    340		break;
    341	}
    342
    343	wm8731_set_deemph(component);
    344
    345	snd_soc_component_write(component, WM8731_IFACE, iface);
    346	return 0;
    347}
    348
    349static int wm8731_mute(struct snd_soc_dai *dai, int mute, int direction)
    350{
    351	struct snd_soc_component *component = dai->component;
    352	u16 mute_reg = snd_soc_component_read(component, WM8731_APDIGI) & 0xfff7;
    353
    354	if (mute)
    355		snd_soc_component_write(component, WM8731_APDIGI, mute_reg | 0x8);
    356	else
    357		snd_soc_component_write(component, WM8731_APDIGI, mute_reg);
    358	return 0;
    359}
    360
    361static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    362		int clk_id, unsigned int freq, int dir)
    363{
    364	struct snd_soc_component *component = codec_dai->component;
    365	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
    366	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
    367
    368	switch (clk_id) {
    369	case WM8731_SYSCLK_XTAL:
    370	case WM8731_SYSCLK_MCLK:
    371		if (wm8731->mclk && clk_set_rate(wm8731->mclk, freq))
    372			return -EINVAL;
    373		wm8731->sysclk_type = clk_id;
    374		break;
    375	default:
    376		return -EINVAL;
    377	}
    378
    379	switch (freq) {
    380	case 0:
    381		wm8731->constraints = NULL;
    382		break;
    383	case 12000000:
    384		wm8731->constraints = &wm8731_constraints_12000000;
    385		break;
    386	case 12288000:
    387	case 18432000:
    388		wm8731->constraints = &wm8731_constraints_12288000_18432000;
    389		break;
    390	case 16934400:
    391	case 11289600:
    392		wm8731->constraints = &wm8731_constraints_11289600_16934400;
    393		break;
    394	default:
    395		return -EINVAL;
    396	}
    397
    398	wm8731->sysclk = freq;
    399
    400	snd_soc_dapm_sync(dapm);
    401
    402	return 0;
    403}
    404
    405
    406static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
    407		unsigned int fmt)
    408{
    409	struct snd_soc_component *component = codec_dai->component;
    410	u16 iface = 0;
    411
    412	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
    413	case SND_SOC_DAIFMT_CBP_CFP:
    414		iface |= 0x0040;
    415		break;
    416	case SND_SOC_DAIFMT_CBC_CFC:
    417		break;
    418	default:
    419		return -EINVAL;
    420	}
    421
    422	/* interface format */
    423	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    424	case SND_SOC_DAIFMT_I2S:
    425		iface |= 0x0002;
    426		break;
    427	case SND_SOC_DAIFMT_RIGHT_J:
    428		break;
    429	case SND_SOC_DAIFMT_LEFT_J:
    430		iface |= 0x0001;
    431		break;
    432	case SND_SOC_DAIFMT_DSP_A:
    433		iface |= 0x0013;
    434		break;
    435	case SND_SOC_DAIFMT_DSP_B:
    436		iface |= 0x0003;
    437		break;
    438	default:
    439		return -EINVAL;
    440	}
    441
    442	/* clock inversion */
    443	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
    444	case SND_SOC_DAIFMT_NB_NF:
    445		break;
    446	case SND_SOC_DAIFMT_IB_IF:
    447		iface |= 0x0090;
    448		break;
    449	case SND_SOC_DAIFMT_IB_NF:
    450		iface |= 0x0080;
    451		break;
    452	case SND_SOC_DAIFMT_NB_IF:
    453		iface |= 0x0010;
    454		break;
    455	default:
    456		return -EINVAL;
    457	}
    458
    459	/* set iface */
    460	snd_soc_component_write(component, WM8731_IFACE, iface);
    461	return 0;
    462}
    463
    464static int wm8731_set_bias_level(struct snd_soc_component *component,
    465				 enum snd_soc_bias_level level)
    466{
    467	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
    468	int ret;
    469	u16 reg;
    470
    471	switch (level) {
    472	case SND_SOC_BIAS_ON:
    473		if (wm8731->mclk) {
    474			ret = clk_prepare_enable(wm8731->mclk);
    475			if (ret)
    476				return ret;
    477		}
    478		break;
    479	case SND_SOC_BIAS_PREPARE:
    480		break;
    481	case SND_SOC_BIAS_STANDBY:
    482		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
    483			ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
    484						    wm8731->supplies);
    485			if (ret != 0)
    486				return ret;
    487
    488			regcache_sync(wm8731->regmap);
    489		}
    490
    491		/* Clear PWROFF, gate CLKOUT, everything else as-is */
    492		reg = snd_soc_component_read(component, WM8731_PWR) & 0xff7f;
    493		snd_soc_component_write(component, WM8731_PWR, reg | 0x0040);
    494		break;
    495	case SND_SOC_BIAS_OFF:
    496		if (wm8731->mclk)
    497			clk_disable_unprepare(wm8731->mclk);
    498		snd_soc_component_write(component, WM8731_PWR, 0xffff);
    499		regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
    500				       wm8731->supplies);
    501		regcache_mark_dirty(wm8731->regmap);
    502		break;
    503	}
    504	return 0;
    505}
    506
    507static int wm8731_startup(struct snd_pcm_substream *substream,
    508	struct snd_soc_dai *dai)
    509{
    510	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(dai->component);
    511
    512	if (wm8731->constraints)
    513		snd_pcm_hw_constraint_list(substream->runtime, 0,
    514					   SNDRV_PCM_HW_PARAM_RATE,
    515					   wm8731->constraints);
    516
    517	return 0;
    518}
    519
    520#define WM8731_RATES SNDRV_PCM_RATE_8000_96000
    521
    522#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
    523	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
    524
    525static const struct snd_soc_dai_ops wm8731_dai_ops = {
    526	.startup	= wm8731_startup,
    527	.hw_params	= wm8731_hw_params,
    528	.mute_stream	= wm8731_mute,
    529	.set_sysclk	= wm8731_set_dai_sysclk,
    530	.set_fmt	= wm8731_set_dai_fmt,
    531	.no_capture_mute = 1,
    532};
    533
    534static struct snd_soc_dai_driver wm8731_dai = {
    535	.name = "wm8731-hifi",
    536	.playback = {
    537		.stream_name = "Playback",
    538		.channels_min = 1,
    539		.channels_max = 2,
    540		.rates = WM8731_RATES,
    541		.formats = WM8731_FORMATS,},
    542	.capture = {
    543		.stream_name = "Capture",
    544		.channels_min = 1,
    545		.channels_max = 2,
    546		.rates = WM8731_RATES,
    547		.formats = WM8731_FORMATS,},
    548	.ops = &wm8731_dai_ops,
    549	.symmetric_rate = 1,
    550};
    551
    552static const struct snd_soc_component_driver soc_component_dev_wm8731 = {
    553	.set_bias_level		= wm8731_set_bias_level,
    554	.controls		= wm8731_snd_controls,
    555	.num_controls		= ARRAY_SIZE(wm8731_snd_controls),
    556	.dapm_widgets		= wm8731_dapm_widgets,
    557	.num_dapm_widgets	= ARRAY_SIZE(wm8731_dapm_widgets),
    558	.dapm_routes		= wm8731_intercon,
    559	.num_dapm_routes	= ARRAY_SIZE(wm8731_intercon),
    560	.suspend_bias_off	= 1,
    561	.idle_bias_on		= 1,
    562	.use_pmdown_time	= 1,
    563	.endianness		= 1,
    564	.non_legacy_dai_naming	= 1,
    565};
    566
    567int wm8731_init(struct device *dev, struct wm8731_priv *wm8731)
    568{
    569	int ret = 0, i;
    570
    571	wm8731->mclk = devm_clk_get(dev, "mclk");
    572	if (IS_ERR(wm8731->mclk)) {
    573		ret = PTR_ERR(wm8731->mclk);
    574		if (ret == -ENOENT) {
    575			wm8731->mclk = NULL;
    576			dev_warn(dev, "Assuming static MCLK\n");
    577		} else {
    578			dev_err(dev, "Failed to get MCLK: %d\n", ret);
    579			return ret;
    580		}
    581	}
    582
    583	mutex_init(&wm8731->lock);
    584
    585	for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
    586		wm8731->supplies[i].supply = wm8731_supply_names[i];
    587
    588	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8731->supplies),
    589				 wm8731->supplies);
    590	if (ret != 0) {
    591		dev_err(dev, "Failed to request supplies: %d\n", ret);
    592		return ret;
    593	}
    594
    595	ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
    596				    wm8731->supplies);
    597	if (ret != 0) {
    598		dev_err(dev, "Failed to enable supplies: %d\n", ret);
    599		return ret;
    600	}
    601
    602	ret = wm8731_reset(wm8731->regmap);
    603	if (ret < 0) {
    604		dev_err(dev, "Failed to issue reset: %d\n", ret);
    605		goto err_regulator_enable;
    606	}
    607
    608	/* Clear POWEROFF, keep everything else disabled */
    609	regmap_write(wm8731->regmap, WM8731_PWR, 0x7f);
    610
    611	/* Latch the update bits */
    612	regmap_update_bits(wm8731->regmap, WM8731_LOUT1V, 0x100, 0);
    613	regmap_update_bits(wm8731->regmap, WM8731_ROUT1V, 0x100, 0);
    614	regmap_update_bits(wm8731->regmap, WM8731_LINVOL, 0x100, 0);
    615	regmap_update_bits(wm8731->regmap, WM8731_RINVOL, 0x100, 0);
    616
    617	/* Disable bypass path by default */
    618	regmap_update_bits(wm8731->regmap, WM8731_APANA, 0x8, 0);
    619
    620	regcache_mark_dirty(wm8731->regmap);
    621
    622	ret = devm_snd_soc_register_component(dev,
    623			&soc_component_dev_wm8731, &wm8731_dai, 1);
    624	if (ret != 0) {
    625		dev_err(dev, "Failed to register CODEC: %d\n", ret);
    626		goto err_regulator_enable;
    627	}
    628
    629	return 0;
    630
    631err_regulator_enable:
    632	/* Regulators will be enabled by bias management */
    633	regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
    634
    635	return ret;
    636}
    637EXPORT_SYMBOL_GPL(wm8731_init);
    638
    639const struct regmap_config wm8731_regmap = {
    640	.reg_bits = 7,
    641	.val_bits = 9,
    642
    643	.max_register = WM8731_RESET,
    644	.volatile_reg = wm8731_volatile,
    645
    646	.cache_type = REGCACHE_RBTREE,
    647	.reg_defaults = wm8731_reg_defaults,
    648	.num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults),
    649};
    650EXPORT_SYMBOL_GPL(wm8731_regmap);
    651
    652MODULE_DESCRIPTION("ASoC WM8731 driver");
    653MODULE_AUTHOR("Richard Purdie");
    654MODULE_LICENSE("GPL");