xref: /openbmc/linux/sound/soc/codecs/wm8741.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2992bee40SIan Lartey /*
3992bee40SIan Lartey  * wm8741.c  --  WM8741 ALSA SoC Audio driver
4992bee40SIan Lartey  *
5656baaebSMark Brown  * Copyright 2010-1 Wolfson Microelectronics plc
6992bee40SIan Lartey  *
7992bee40SIan Lartey  * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
8992bee40SIan Lartey  */
9992bee40SIan Lartey 
10992bee40SIan Lartey #include <linux/module.h>
11992bee40SIan Lartey #include <linux/moduleparam.h>
12992bee40SIan Lartey #include <linux/init.h>
13992bee40SIan Lartey #include <linux/delay.h>
14992bee40SIan Lartey #include <linux/pm.h>
15992bee40SIan Lartey #include <linux/i2c.h>
1639e9b8d2SMark Brown #include <linux/spi/spi.h>
17fe98c0cfSMark Brown #include <linux/regmap.h>
18992bee40SIan Lartey #include <linux/regulator/consumer.h>
19992bee40SIan Lartey #include <linux/slab.h>
2080080ec5SMark Brown #include <linux/of_device.h>
21992bee40SIan Lartey #include <sound/core.h>
22992bee40SIan Lartey #include <sound/pcm.h>
23992bee40SIan Lartey #include <sound/pcm_params.h>
24992bee40SIan Lartey #include <sound/soc.h>
25992bee40SIan Lartey #include <sound/initval.h>
26992bee40SIan Lartey #include <sound/tlv.h>
27992bee40SIan Lartey 
28992bee40SIan Lartey #include "wm8741.h"
29992bee40SIan Lartey 
30992bee40SIan Lartey #define WM8741_NUM_SUPPLIES 2
31992bee40SIan Lartey static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
32992bee40SIan Lartey 	"AVDD",
33992bee40SIan Lartey 	"DVDD",
34992bee40SIan Lartey };
35992bee40SIan Lartey 
36992bee40SIan Lartey /* codec private data */
37992bee40SIan Lartey struct wm8741_priv {
38c354b54cSSergej Sawazki 	struct wm8741_platform_data pdata;
39fe98c0cfSMark Brown 	struct regmap *regmap;
40992bee40SIan Lartey 	struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
41992bee40SIan Lartey 	unsigned int sysclk;
4270bad2c7SLars-Peter Clausen 	const struct snd_pcm_hw_constraint_list *sysclk_constraints;
43992bee40SIan Lartey };
44992bee40SIan Lartey 
45fe98c0cfSMark Brown static const struct reg_default wm8741_reg_defaults[] = {
46fe98c0cfSMark Brown 	{  0, 0x0000 },     /* R0  - DACLLSB Attenuation */
47fe98c0cfSMark Brown 	{  1, 0x0000 },     /* R1  - DACLMSB Attenuation */
48fe98c0cfSMark Brown 	{  2, 0x0000 },     /* R2  - DACRLSB Attenuation */
49fe98c0cfSMark Brown 	{  3, 0x0000 },     /* R3  - DACRMSB Attenuation */
50fe98c0cfSMark Brown 	{  4, 0x0000 },     /* R4  - Volume Control */
51fe98c0cfSMark Brown 	{  5, 0x000A },     /* R5  - Format Control */
52fe98c0cfSMark Brown 	{  6, 0x0000 },     /* R6  - Filter Control */
53fe98c0cfSMark Brown 	{  7, 0x0000 },     /* R7  - Mode Control 1 */
54fe98c0cfSMark Brown 	{  8, 0x0002 },     /* R8  - Mode Control 2 */
55fe98c0cfSMark Brown 	{ 32, 0x0002 },     /* R32 - ADDITONAL_CONTROL_1 */
56992bee40SIan Lartey };
57992bee40SIan Lartey 
wm8741_reset(struct snd_soc_component * component)589b6a00f7SKuninori Morimoto static int wm8741_reset(struct snd_soc_component *component)
59992bee40SIan Lartey {
609b6a00f7SKuninori Morimoto 	return snd_soc_component_write(component, WM8741_RESET, 0);
61992bee40SIan Lartey }
62992bee40SIan Lartey 
63992bee40SIan Lartey static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0);
64992bee40SIan Lartey static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0);
65992bee40SIan Lartey 
66c354b54cSSergej Sawazki static const struct snd_kcontrol_new wm8741_snd_controls_stereo[] = {
67992bee40SIan Lartey SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
68992bee40SIan Lartey 		 WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine),
69992bee40SIan Lartey SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
70992bee40SIan Lartey 		 WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv),
71992bee40SIan Lartey };
72992bee40SIan Lartey 
73c354b54cSSergej Sawazki static const struct snd_kcontrol_new wm8741_snd_controls_mono_left[] = {
74c354b54cSSergej Sawazki SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
75c354b54cSSergej Sawazki 		 1, 255, 1, dac_tlv_fine),
76c354b54cSSergej Sawazki SOC_SINGLE_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
77c354b54cSSergej Sawazki 		 0, 511, 1, dac_tlv),
78c354b54cSSergej Sawazki };
79c354b54cSSergej Sawazki 
80c354b54cSSergej Sawazki static const struct snd_kcontrol_new wm8741_snd_controls_mono_right[] = {
81c354b54cSSergej Sawazki SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACRLSB_ATTENUATION,
82c354b54cSSergej Sawazki 		1, 255, 1, dac_tlv_fine),
83c354b54cSSergej Sawazki SOC_SINGLE_TLV("Playback Volume", WM8741_DACRMSB_ATTENUATION,
84c354b54cSSergej Sawazki 		0, 511, 1, dac_tlv),
85c354b54cSSergej Sawazki };
86c354b54cSSergej Sawazki 
87992bee40SIan Lartey static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = {
88992bee40SIan Lartey SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0),
89992bee40SIan Lartey SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0),
90992bee40SIan Lartey SND_SOC_DAPM_OUTPUT("VOUTLP"),
91992bee40SIan Lartey SND_SOC_DAPM_OUTPUT("VOUTLN"),
92992bee40SIan Lartey SND_SOC_DAPM_OUTPUT("VOUTRP"),
93992bee40SIan Lartey SND_SOC_DAPM_OUTPUT("VOUTRN"),
94992bee40SIan Lartey };
95992bee40SIan Lartey 
960e62780fSMark Brown static const struct snd_soc_dapm_route wm8741_dapm_routes[] = {
97992bee40SIan Lartey 	{ "VOUTLP", NULL, "DACL" },
98992bee40SIan Lartey 	{ "VOUTLN", NULL, "DACL" },
99992bee40SIan Lartey 	{ "VOUTRP", NULL, "DACR" },
100992bee40SIan Lartey 	{ "VOUTRN", NULL, "DACR" },
101992bee40SIan Lartey };
102992bee40SIan Lartey 
10370bad2c7SLars-Peter Clausen static const unsigned int rates_11289[] = {
1048787041dSSergej Sawazki 	44100, 88200,
1053fe4a5eeSIan Lartey };
1063fe4a5eeSIan Lartey 
10770bad2c7SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list constraints_11289 = {
1083fe4a5eeSIan Lartey 	.count	= ARRAY_SIZE(rates_11289),
1093fe4a5eeSIan Lartey 	.list	= rates_11289,
1103fe4a5eeSIan Lartey };
1113fe4a5eeSIan Lartey 
11270bad2c7SLars-Peter Clausen static const unsigned int rates_12288[] = {
1133fe4a5eeSIan Lartey 	32000, 48000, 96000,
1143fe4a5eeSIan Lartey };
1153fe4a5eeSIan Lartey 
11670bad2c7SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list constraints_12288 = {
1173fe4a5eeSIan Lartey 	.count	= ARRAY_SIZE(rates_12288),
1183fe4a5eeSIan Lartey 	.list	= rates_12288,
1193fe4a5eeSIan Lartey };
1203fe4a5eeSIan Lartey 
12170bad2c7SLars-Peter Clausen static const unsigned int rates_16384[] = {
1223fe4a5eeSIan Lartey 	32000,
1233fe4a5eeSIan Lartey };
1243fe4a5eeSIan Lartey 
12570bad2c7SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list constraints_16384 = {
1263fe4a5eeSIan Lartey 	.count	= ARRAY_SIZE(rates_16384),
1273fe4a5eeSIan Lartey 	.list	= rates_16384,
1283fe4a5eeSIan Lartey };
1293fe4a5eeSIan Lartey 
13070bad2c7SLars-Peter Clausen static const unsigned int rates_16934[] = {
1318787041dSSergej Sawazki 	44100, 88200,
1323fe4a5eeSIan Lartey };
1333fe4a5eeSIan Lartey 
13470bad2c7SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list constraints_16934 = {
1353fe4a5eeSIan Lartey 	.count	= ARRAY_SIZE(rates_16934),
1363fe4a5eeSIan Lartey 	.list	= rates_16934,
1373fe4a5eeSIan Lartey };
1383fe4a5eeSIan Lartey 
13970bad2c7SLars-Peter Clausen static const unsigned int rates_18432[] = {
1403fe4a5eeSIan Lartey 	48000, 96000,
1413fe4a5eeSIan Lartey };
1423fe4a5eeSIan Lartey 
14370bad2c7SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list constraints_18432 = {
1443fe4a5eeSIan Lartey 	.count	= ARRAY_SIZE(rates_18432),
1453fe4a5eeSIan Lartey 	.list	= rates_18432,
1463fe4a5eeSIan Lartey };
1473fe4a5eeSIan Lartey 
14870bad2c7SLars-Peter Clausen static const unsigned int rates_22579[] = {
1498787041dSSergej Sawazki 	44100, 88200, 176400
1503fe4a5eeSIan Lartey };
1513fe4a5eeSIan Lartey 
15270bad2c7SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list constraints_22579 = {
1533fe4a5eeSIan Lartey 	.count	= ARRAY_SIZE(rates_22579),
1543fe4a5eeSIan Lartey 	.list	= rates_22579,
1553fe4a5eeSIan Lartey };
1563fe4a5eeSIan Lartey 
15770bad2c7SLars-Peter Clausen static const unsigned int rates_24576[] = {
1583fe4a5eeSIan Lartey 	32000, 48000, 96000, 192000
1593fe4a5eeSIan Lartey };
1603fe4a5eeSIan Lartey 
16170bad2c7SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list constraints_24576 = {
1623fe4a5eeSIan Lartey 	.count	= ARRAY_SIZE(rates_24576),
1633fe4a5eeSIan Lartey 	.list	= rates_24576,
1643fe4a5eeSIan Lartey };
1653fe4a5eeSIan Lartey 
16670bad2c7SLars-Peter Clausen static const unsigned int rates_36864[] = {
1678787041dSSergej Sawazki 	48000, 96000, 192000
1683fe4a5eeSIan Lartey };
1693fe4a5eeSIan Lartey 
17070bad2c7SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list constraints_36864 = {
1713fe4a5eeSIan Lartey 	.count	= ARRAY_SIZE(rates_36864),
1723fe4a5eeSIan Lartey 	.list	= rates_36864,
173992bee40SIan Lartey };
174992bee40SIan Lartey 
wm8741_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)175992bee40SIan Lartey static int wm8741_startup(struct snd_pcm_substream *substream,
176992bee40SIan Lartey 			  struct snd_soc_dai *dai)
177992bee40SIan Lartey {
1789b6a00f7SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
1799b6a00f7SKuninori Morimoto 	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
180992bee40SIan Lartey 
181e369bd00SSergej Sawazki 	if (wm8741->sysclk)
182992bee40SIan Lartey 		snd_pcm_hw_constraint_list(substream->runtime, 0,
183992bee40SIan Lartey 				SNDRV_PCM_HW_PARAM_RATE,
1843fe4a5eeSIan Lartey 				wm8741->sysclk_constraints);
185992bee40SIan Lartey 
186992bee40SIan Lartey 	return 0;
187992bee40SIan Lartey }
188992bee40SIan Lartey 
wm8741_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)189992bee40SIan Lartey static int wm8741_hw_params(struct snd_pcm_substream *substream,
190992bee40SIan Lartey 			    struct snd_pcm_hw_params *params,
191992bee40SIan Lartey 			    struct snd_soc_dai *dai)
192992bee40SIan Lartey {
1939b6a00f7SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
1949b6a00f7SKuninori Morimoto 	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
195e9418629SSergej Sawazki 	unsigned int iface, mode;
196992bee40SIan Lartey 	int i;
197992bee40SIan Lartey 
198e369bd00SSergej Sawazki 	/* The set of sample rates that can be supported depends on the
199e369bd00SSergej Sawazki 	 * MCLK supplied to the CODEC - enforce this.
200e369bd00SSergej Sawazki 	 */
201e369bd00SSergej Sawazki 	if (!wm8741->sysclk) {
2029b6a00f7SKuninori Morimoto 		dev_err(component->dev,
203e369bd00SSergej Sawazki 			"No MCLK configured, call set_sysclk() on init or in hw_params\n");
204e369bd00SSergej Sawazki 		return -EINVAL;
205e369bd00SSergej Sawazki 	}
206e369bd00SSergej Sawazki 
207e369bd00SSergej Sawazki 	/* Find a supported LRCLK rate */
208e369bd00SSergej Sawazki 	for (i = 0; i < wm8741->sysclk_constraints->count; i++) {
209e369bd00SSergej Sawazki 		if (wm8741->sysclk_constraints->list[i] == params_rate(params))
210992bee40SIan Lartey 			break;
211992bee40SIan Lartey 	}
212992bee40SIan Lartey 
213e369bd00SSergej Sawazki 	if (i == wm8741->sysclk_constraints->count) {
2149b6a00f7SKuninori Morimoto 		dev_err(component->dev, "LRCLK %d unsupported with MCLK %d\n",
215e369bd00SSergej Sawazki 			params_rate(params), wm8741->sysclk);
216992bee40SIan Lartey 		return -EINVAL;
217992bee40SIan Lartey 	}
218992bee40SIan Lartey 
219992bee40SIan Lartey 	/* bit size */
22034967ad2SMark Brown 	switch (params_width(params)) {
22134967ad2SMark Brown 	case 16:
222eaf8abcfSCharles Keepax 		iface = 0x0;
223992bee40SIan Lartey 		break;
22434967ad2SMark Brown 	case 20:
225eaf8abcfSCharles Keepax 		iface = 0x1;
226992bee40SIan Lartey 		break;
22734967ad2SMark Brown 	case 24:
228eaf8abcfSCharles Keepax 		iface = 0x2;
229992bee40SIan Lartey 		break;
23034967ad2SMark Brown 	case 32:
231eaf8abcfSCharles Keepax 		iface = 0x3;
232992bee40SIan Lartey 		break;
233992bee40SIan Lartey 	default:
2349b6a00f7SKuninori Morimoto 		dev_dbg(component->dev, "wm8741_hw_params:    Unsupported bit size param = %d",
23534967ad2SMark Brown 			params_width(params));
236992bee40SIan Lartey 		return -EINVAL;
237992bee40SIan Lartey 	}
238992bee40SIan Lartey 
239e9418629SSergej Sawazki 	/* oversampling rate */
240e9418629SSergej Sawazki 	if (params_rate(params) > 96000)
241e9418629SSergej Sawazki 		mode = 0x40;
242e9418629SSergej Sawazki 	else if (params_rate(params) > 48000)
243e9418629SSergej Sawazki 		mode = 0x20;
244e9418629SSergej Sawazki 	else
245e9418629SSergej Sawazki 		mode = 0x00;
246e9418629SSergej Sawazki 
2479b6a00f7SKuninori Morimoto 	dev_dbg(component->dev, "wm8741_hw_params:    bit size param = %d, rate param = %d",
248e369bd00SSergej Sawazki 		params_width(params), params_rate(params));
249992bee40SIan Lartey 
2509b6a00f7SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8741_FORMAT_CONTROL, WM8741_IWL_MASK,
251eaf8abcfSCharles Keepax 			    iface);
252e9418629SSergej Sawazki 	snd_soc_component_update_bits(component, WM8741_MODE_CONTROL_1, WM8741_OSR_MASK,
253e9418629SSergej Sawazki 			    mode);
254eaf8abcfSCharles Keepax 
255992bee40SIan Lartey 	return 0;
256992bee40SIan Lartey }
257992bee40SIan Lartey 
wm8741_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)258992bee40SIan Lartey static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
259992bee40SIan Lartey 		int clk_id, unsigned int freq, int dir)
260992bee40SIan Lartey {
2619b6a00f7SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
2629b6a00f7SKuninori Morimoto 	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
263992bee40SIan Lartey 
2649b6a00f7SKuninori Morimoto 	dev_dbg(component->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
265992bee40SIan Lartey 
2663fe4a5eeSIan Lartey 	switch (freq) {
267e369bd00SSergej Sawazki 	case 0:
268e369bd00SSergej Sawazki 		wm8741->sysclk_constraints = NULL;
2696f55a041SAxel Lin 		break;
2703fe4a5eeSIan Lartey 	case 11289600:
2713fe4a5eeSIan Lartey 		wm8741->sysclk_constraints = &constraints_11289;
2726f55a041SAxel Lin 		break;
2733fe4a5eeSIan Lartey 	case 12288000:
2743fe4a5eeSIan Lartey 		wm8741->sysclk_constraints = &constraints_12288;
2756f55a041SAxel Lin 		break;
2763fe4a5eeSIan Lartey 	case 16384000:
2773fe4a5eeSIan Lartey 		wm8741->sysclk_constraints = &constraints_16384;
2786f55a041SAxel Lin 		break;
2793fe4a5eeSIan Lartey 	case 16934400:
2803fe4a5eeSIan Lartey 		wm8741->sysclk_constraints = &constraints_16934;
2816f55a041SAxel Lin 		break;
2823fe4a5eeSIan Lartey 	case 18432000:
2833fe4a5eeSIan Lartey 		wm8741->sysclk_constraints = &constraints_18432;
2846f55a041SAxel Lin 		break;
2853fe4a5eeSIan Lartey 	case 22579200:
2863fe4a5eeSIan Lartey 	case 33868800:
2873fe4a5eeSIan Lartey 		wm8741->sysclk_constraints = &constraints_22579;
2886f55a041SAxel Lin 		break;
2893fe4a5eeSIan Lartey 	case 24576000:
2903fe4a5eeSIan Lartey 		wm8741->sysclk_constraints = &constraints_24576;
2916f55a041SAxel Lin 		break;
2923fe4a5eeSIan Lartey 	case 36864000:
2933fe4a5eeSIan Lartey 		wm8741->sysclk_constraints = &constraints_36864;
2946f55a041SAxel Lin 		break;
2956f55a041SAxel Lin 	default:
2966f55a041SAxel Lin 		return -EINVAL;
2976f55a041SAxel Lin 	}
2986f55a041SAxel Lin 
2993fe4a5eeSIan Lartey 	wm8741->sysclk = freq;
3003fe4a5eeSIan Lartey 	return 0;
3013fe4a5eeSIan Lartey }
302992bee40SIan Lartey 
wm8741_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)303992bee40SIan Lartey static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
304992bee40SIan Lartey 		unsigned int fmt)
305992bee40SIan Lartey {
3069b6a00f7SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
307eaf8abcfSCharles Keepax 	unsigned int iface;
308992bee40SIan Lartey 
309992bee40SIan Lartey 	/* check master/slave audio interface */
310992bee40SIan Lartey 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
311992bee40SIan Lartey 	case SND_SOC_DAIFMT_CBS_CFS:
312992bee40SIan Lartey 		break;
313992bee40SIan Lartey 	default:
314992bee40SIan Lartey 		return -EINVAL;
315992bee40SIan Lartey 	}
316992bee40SIan Lartey 
317992bee40SIan Lartey 	/* interface format */
318992bee40SIan Lartey 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
319992bee40SIan Lartey 	case SND_SOC_DAIFMT_I2S:
320eaf8abcfSCharles Keepax 		iface = 0x08;
321992bee40SIan Lartey 		break;
322992bee40SIan Lartey 	case SND_SOC_DAIFMT_RIGHT_J:
323eaf8abcfSCharles Keepax 		iface = 0x00;
324992bee40SIan Lartey 		break;
325992bee40SIan Lartey 	case SND_SOC_DAIFMT_LEFT_J:
326eaf8abcfSCharles Keepax 		iface = 0x04;
327992bee40SIan Lartey 		break;
328992bee40SIan Lartey 	case SND_SOC_DAIFMT_DSP_A:
329eaf8abcfSCharles Keepax 		iface = 0x0C;
330992bee40SIan Lartey 		break;
331992bee40SIan Lartey 	case SND_SOC_DAIFMT_DSP_B:
332eaf8abcfSCharles Keepax 		iface = 0x1C;
333992bee40SIan Lartey 		break;
334992bee40SIan Lartey 	default:
335992bee40SIan Lartey 		return -EINVAL;
336992bee40SIan Lartey 	}
337992bee40SIan Lartey 
338992bee40SIan Lartey 	/* clock inversion */
339992bee40SIan Lartey 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
340992bee40SIan Lartey 	case SND_SOC_DAIFMT_NB_NF:
341992bee40SIan Lartey 		break;
34281b3cc55SSergej Sawazki 	case SND_SOC_DAIFMT_NB_IF:
343eaf8abcfSCharles Keepax 		iface |= 0x10;
344992bee40SIan Lartey 		break;
345992bee40SIan Lartey 	case SND_SOC_DAIFMT_IB_NF:
346eaf8abcfSCharles Keepax 		iface |= 0x20;
347992bee40SIan Lartey 		break;
34881b3cc55SSergej Sawazki 	case SND_SOC_DAIFMT_IB_IF:
349eaf8abcfSCharles Keepax 		iface |= 0x30;
350992bee40SIan Lartey 		break;
351992bee40SIan Lartey 	default:
352992bee40SIan Lartey 		return -EINVAL;
353992bee40SIan Lartey 	}
354992bee40SIan Lartey 
355992bee40SIan Lartey 
3569b6a00f7SKuninori Morimoto 	dev_dbg(component->dev, "wm8741_set_dai_fmt:    Format=%x, Clock Inv=%x\n",
357992bee40SIan Lartey 				fmt & SND_SOC_DAIFMT_FORMAT_MASK,
358992bee40SIan Lartey 				((fmt & SND_SOC_DAIFMT_INV_MASK)));
359992bee40SIan Lartey 
3609b6a00f7SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8741_FORMAT_CONTROL,
361eaf8abcfSCharles Keepax 			    WM8741_BCP_MASK | WM8741_LRP_MASK | WM8741_FMT_MASK,
362eaf8abcfSCharles Keepax 			    iface);
363eaf8abcfSCharles Keepax 
364992bee40SIan Lartey 	return 0;
365992bee40SIan Lartey }
366992bee40SIan Lartey 
wm8741_mute(struct snd_soc_dai * codec_dai,int mute,int direction)36726d3c16eSKuninori Morimoto static int wm8741_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
36836b15993SSergej Sawazki {
36936b15993SSergej Sawazki 	struct snd_soc_component *component = codec_dai->component;
37036b15993SSergej Sawazki 
37136b15993SSergej Sawazki 	snd_soc_component_update_bits(component, WM8741_VOLUME_CONTROL,
37236b15993SSergej Sawazki 			WM8741_SOFT_MASK, !!mute << WM8741_SOFT_SHIFT);
37336b15993SSergej Sawazki 	return 0;
37436b15993SSergej Sawazki }
37536b15993SSergej Sawazki 
376992bee40SIan Lartey #define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
377992bee40SIan Lartey 			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
378992bee40SIan Lartey 			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
379992bee40SIan Lartey 			SNDRV_PCM_RATE_192000)
380992bee40SIan Lartey 
381992bee40SIan Lartey #define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
382992bee40SIan Lartey 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
383992bee40SIan Lartey 
38485e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm8741_dai_ops = {
385992bee40SIan Lartey 	.startup	= wm8741_startup,
386992bee40SIan Lartey 	.hw_params	= wm8741_hw_params,
387992bee40SIan Lartey 	.set_sysclk	= wm8741_set_dai_sysclk,
388992bee40SIan Lartey 	.set_fmt	= wm8741_set_dai_fmt,
38926d3c16eSKuninori Morimoto 	.mute_stream	= wm8741_mute,
39026d3c16eSKuninori Morimoto 	.no_capture_mute = 1,
391992bee40SIan Lartey };
392992bee40SIan Lartey 
393f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm8741_dai = {
39430e2d368SIan Lartey 	.name = "wm8741",
395992bee40SIan Lartey 	.playback = {
396992bee40SIan Lartey 		.stream_name = "Playback",
397c354b54cSSergej Sawazki 		.channels_min = 2,
398992bee40SIan Lartey 		.channels_max = 2,
399992bee40SIan Lartey 		.rates = WM8741_RATES,
400992bee40SIan Lartey 		.formats = WM8741_FORMATS,
401992bee40SIan Lartey 	},
402992bee40SIan Lartey 	.ops = &wm8741_dai_ops,
403992bee40SIan Lartey };
404992bee40SIan Lartey 
405992bee40SIan Lartey #ifdef CONFIG_PM
wm8741_resume(struct snd_soc_component * component)4069b6a00f7SKuninori Morimoto static int wm8741_resume(struct snd_soc_component *component)
407992bee40SIan Lartey {
4089b6a00f7SKuninori Morimoto 	snd_soc_component_cache_sync(component);
409992bee40SIan Lartey 	return 0;
410992bee40SIan Lartey }
411992bee40SIan Lartey #else
412992bee40SIan Lartey #define wm8741_resume NULL
413992bee40SIan Lartey #endif
414992bee40SIan Lartey 
wm8741_configure(struct snd_soc_component * component)4159b6a00f7SKuninori Morimoto static int wm8741_configure(struct snd_soc_component *component)
416c354b54cSSergej Sawazki {
4179b6a00f7SKuninori Morimoto 	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
418c354b54cSSergej Sawazki 
419c354b54cSSergej Sawazki 	/* Configure differential mode */
420c354b54cSSergej Sawazki 	switch (wm8741->pdata.diff_mode) {
421c354b54cSSergej Sawazki 	case WM8741_DIFF_MODE_STEREO:
422c354b54cSSergej Sawazki 	case WM8741_DIFF_MODE_STEREO_REVERSED:
423c354b54cSSergej Sawazki 	case WM8741_DIFF_MODE_MONO_LEFT:
424c354b54cSSergej Sawazki 	case WM8741_DIFF_MODE_MONO_RIGHT:
4259b6a00f7SKuninori Morimoto 		snd_soc_component_update_bits(component, WM8741_MODE_CONTROL_2,
426c354b54cSSergej Sawazki 				WM8741_DIFF_MASK,
427c354b54cSSergej Sawazki 				wm8741->pdata.diff_mode << WM8741_DIFF_SHIFT);
428c354b54cSSergej Sawazki 		break;
429c354b54cSSergej Sawazki 	default:
430c354b54cSSergej Sawazki 		return -EINVAL;
431c354b54cSSergej Sawazki 	}
432c354b54cSSergej Sawazki 
433c354b54cSSergej Sawazki 	/* Change some default settings - latch VU */
4349b6a00f7SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8741_DACLLSB_ATTENUATION,
435c354b54cSSergej Sawazki 			WM8741_UPDATELL, WM8741_UPDATELL);
4369b6a00f7SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8741_DACLMSB_ATTENUATION,
437c354b54cSSergej Sawazki 			WM8741_UPDATELM, WM8741_UPDATELM);
4389b6a00f7SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8741_DACRLSB_ATTENUATION,
439c354b54cSSergej Sawazki 			WM8741_UPDATERL, WM8741_UPDATERL);
4409b6a00f7SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8741_DACRMSB_ATTENUATION,
441c354b54cSSergej Sawazki 			WM8741_UPDATERM, WM8741_UPDATERM);
442c354b54cSSergej Sawazki 
443c354b54cSSergej Sawazki 	return 0;
444c354b54cSSergej Sawazki }
445c354b54cSSergej Sawazki 
wm8741_add_controls(struct snd_soc_component * component)4469b6a00f7SKuninori Morimoto static int wm8741_add_controls(struct snd_soc_component *component)
447c354b54cSSergej Sawazki {
4489b6a00f7SKuninori Morimoto 	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
449c354b54cSSergej Sawazki 
450c354b54cSSergej Sawazki 	switch (wm8741->pdata.diff_mode) {
451c354b54cSSergej Sawazki 	case WM8741_DIFF_MODE_STEREO:
452c354b54cSSergej Sawazki 	case WM8741_DIFF_MODE_STEREO_REVERSED:
4539b6a00f7SKuninori Morimoto 		snd_soc_add_component_controls(component,
454c354b54cSSergej Sawazki 				wm8741_snd_controls_stereo,
455c354b54cSSergej Sawazki 				ARRAY_SIZE(wm8741_snd_controls_stereo));
456c354b54cSSergej Sawazki 		break;
457c354b54cSSergej Sawazki 	case WM8741_DIFF_MODE_MONO_LEFT:
4589b6a00f7SKuninori Morimoto 		snd_soc_add_component_controls(component,
459c354b54cSSergej Sawazki 				wm8741_snd_controls_mono_left,
460c354b54cSSergej Sawazki 				ARRAY_SIZE(wm8741_snd_controls_mono_left));
461c354b54cSSergej Sawazki 		break;
462c354b54cSSergej Sawazki 	case WM8741_DIFF_MODE_MONO_RIGHT:
4639b6a00f7SKuninori Morimoto 		snd_soc_add_component_controls(component,
464c354b54cSSergej Sawazki 				wm8741_snd_controls_mono_right,
465c354b54cSSergej Sawazki 				ARRAY_SIZE(wm8741_snd_controls_mono_right));
466c354b54cSSergej Sawazki 		break;
467c354b54cSSergej Sawazki 	default:
468c354b54cSSergej Sawazki 		return -EINVAL;
469c354b54cSSergej Sawazki 	}
470c354b54cSSergej Sawazki 
471c354b54cSSergej Sawazki 	return 0;
472c354b54cSSergej Sawazki }
473c354b54cSSergej Sawazki 
wm8741_probe(struct snd_soc_component * component)4749b6a00f7SKuninori Morimoto static int wm8741_probe(struct snd_soc_component *component)
475992bee40SIan Lartey {
4769b6a00f7SKuninori Morimoto 	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
477992bee40SIan Lartey 	int ret = 0;
478398575dbSMark Brown 
479398575dbSMark Brown 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
480398575dbSMark Brown 				    wm8741->supplies);
481398575dbSMark Brown 	if (ret != 0) {
4829b6a00f7SKuninori Morimoto 		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
483398575dbSMark Brown 		goto err_get;
484398575dbSMark Brown 	}
485992bee40SIan Lartey 
4869b6a00f7SKuninori Morimoto 	ret = wm8741_reset(component);
487992bee40SIan Lartey 	if (ret < 0) {
4889b6a00f7SKuninori Morimoto 		dev_err(component->dev, "Failed to issue reset\n");
489398575dbSMark Brown 		goto err_enable;
490992bee40SIan Lartey 	}
491992bee40SIan Lartey 
4929b6a00f7SKuninori Morimoto 	ret = wm8741_configure(component);
493c354b54cSSergej Sawazki 	if (ret < 0) {
4949b6a00f7SKuninori Morimoto 		dev_err(component->dev, "Failed to change default settings\n");
495c354b54cSSergej Sawazki 		goto err_enable;
496c354b54cSSergej Sawazki 	}
497c354b54cSSergej Sawazki 
4989b6a00f7SKuninori Morimoto 	ret = wm8741_add_controls(component);
499c354b54cSSergej Sawazki 	if (ret < 0) {
5009b6a00f7SKuninori Morimoto 		dev_err(component->dev, "Failed to add controls\n");
501c354b54cSSergej Sawazki 		goto err_enable;
502c354b54cSSergej Sawazki 	}
503992bee40SIan Lartey 
5049b6a00f7SKuninori Morimoto 	dev_dbg(component->dev, "Successful registration\n");
505f0fba2adSLiam Girdwood 	return ret;
506398575dbSMark Brown 
507398575dbSMark Brown err_enable:
508398575dbSMark Brown 	regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
509398575dbSMark Brown err_get:
510398575dbSMark Brown 	return ret;
511398575dbSMark Brown }
512398575dbSMark Brown 
wm8741_remove(struct snd_soc_component * component)5139b6a00f7SKuninori Morimoto static void wm8741_remove(struct snd_soc_component *component)
514398575dbSMark Brown {
5159b6a00f7SKuninori Morimoto 	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
516398575dbSMark Brown 
517398575dbSMark Brown 	regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
518f0fba2adSLiam Girdwood }
519f0fba2adSLiam Girdwood 
5209b6a00f7SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm8741 = {
521f0fba2adSLiam Girdwood 	.probe			= wm8741_probe,
522398575dbSMark Brown 	.remove			= wm8741_remove,
523f0fba2adSLiam Girdwood 	.resume			= wm8741_resume,
5240e62780fSMark Brown 	.dapm_widgets		= wm8741_dapm_widgets,
5250e62780fSMark Brown 	.num_dapm_widgets	= ARRAY_SIZE(wm8741_dapm_widgets),
5260e62780fSMark Brown 	.dapm_routes		= wm8741_dapm_routes,
5270e62780fSMark Brown 	.num_dapm_routes	= ARRAY_SIZE(wm8741_dapm_routes),
5289b6a00f7SKuninori Morimoto 	.idle_bias_on		= 1,
5299b6a00f7SKuninori Morimoto 	.use_pmdown_time	= 1,
5309b6a00f7SKuninori Morimoto 	.endianness		= 1,
531f0fba2adSLiam Girdwood };
532f0fba2adSLiam Girdwood 
53380080ec5SMark Brown static const struct of_device_id wm8741_of_match[] = {
53480080ec5SMark Brown 	{ .compatible = "wlf,wm8741", },
53580080ec5SMark Brown 	{ }
53680080ec5SMark Brown };
53780080ec5SMark Brown MODULE_DEVICE_TABLE(of, wm8741_of_match);
53880080ec5SMark Brown 
539fe98c0cfSMark Brown static const struct regmap_config wm8741_regmap = {
540fe98c0cfSMark Brown 	.reg_bits = 7,
541fe98c0cfSMark Brown 	.val_bits = 9,
542fe98c0cfSMark Brown 	.max_register = WM8741_MAX_REGISTER,
543fe98c0cfSMark Brown 
544fe98c0cfSMark Brown 	.reg_defaults = wm8741_reg_defaults,
545fe98c0cfSMark Brown 	.num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults),
546*5dd4dddeSMark Brown 	.cache_type = REGCACHE_MAPLE,
547fe98c0cfSMark Brown };
548fe98c0cfSMark Brown 
wm8741_set_pdata(struct device * dev,struct wm8741_priv * wm8741)549c354b54cSSergej Sawazki static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
550c354b54cSSergej Sawazki {
551c354b54cSSergej Sawazki 	const struct wm8741_platform_data *pdata = dev_get_platdata(dev);
552c354b54cSSergej Sawazki 	u32 diff_mode;
553c354b54cSSergej Sawazki 
554c354b54cSSergej Sawazki 	if (dev->of_node) {
555c354b54cSSergej Sawazki 		if (of_property_read_u32(dev->of_node, "diff-mode", &diff_mode)
556c354b54cSSergej Sawazki 				>= 0)
557c354b54cSSergej Sawazki 			wm8741->pdata.diff_mode = diff_mode;
558c354b54cSSergej Sawazki 	} else {
559c354b54cSSergej Sawazki 		if (pdata != NULL)
560c354b54cSSergej Sawazki 			memcpy(&wm8741->pdata, pdata, sizeof(wm8741->pdata));
561c354b54cSSergej Sawazki 	}
562c354b54cSSergej Sawazki 
563c354b54cSSergej Sawazki 	return 0;
564c354b54cSSergej Sawazki }
565c354b54cSSergej Sawazki 
56626090a83SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
wm8741_i2c_probe(struct i2c_client * i2c)56797b0b6e3SStephen Kitt static int wm8741_i2c_probe(struct i2c_client *i2c)
568f0fba2adSLiam Girdwood {
569f0fba2adSLiam Girdwood 	struct wm8741_priv *wm8741;
570d9780550SMark Brown 	int ret, i;
571f0fba2adSLiam Girdwood 
5725aefb306SMark Brown 	wm8741 = devm_kzalloc(&i2c->dev, sizeof(struct wm8741_priv),
5735aefb306SMark Brown 			      GFP_KERNEL);
574f0fba2adSLiam Girdwood 	if (wm8741 == NULL)
575f0fba2adSLiam Girdwood 		return -ENOMEM;
576f0fba2adSLiam Girdwood 
577d9780550SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
578d9780550SMark Brown 		wm8741->supplies[i].supply = wm8741_supply_names[i];
579d9780550SMark Brown 
580d9780550SMark Brown 	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
581d9780550SMark Brown 				      wm8741->supplies);
582d9780550SMark Brown 	if (ret != 0) {
583fe98c0cfSMark Brown 		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
584fe98c0cfSMark Brown 		return ret;
585fe98c0cfSMark Brown 	}
586fe98c0cfSMark Brown 
587fd64c455STushar Behera 	wm8741->regmap = devm_regmap_init_i2c(i2c, &wm8741_regmap);
588fe98c0cfSMark Brown 	if (IS_ERR(wm8741->regmap)) {
589fe98c0cfSMark Brown 		ret = PTR_ERR(wm8741->regmap);
590fe98c0cfSMark Brown 		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
591fe98c0cfSMark Brown 		return ret;
592d9780550SMark Brown 	}
593d9780550SMark Brown 
5942d52d172SDan Carpenter 	ret = wm8741_set_pdata(&i2c->dev, wm8741);
595c354b54cSSergej Sawazki 	if (ret != 0) {
596c354b54cSSergej Sawazki 		dev_err(&i2c->dev, "Failed to set pdata: %d\n", ret);
597c354b54cSSergej Sawazki 		return ret;
598c354b54cSSergej Sawazki 	}
599c354b54cSSergej Sawazki 
600f0fba2adSLiam Girdwood 	i2c_set_clientdata(i2c, wm8741);
601f0fba2adSLiam Girdwood 
6029b6a00f7SKuninori Morimoto 	ret = devm_snd_soc_register_component(&i2c->dev,
6039b6a00f7SKuninori Morimoto 				     &soc_component_dev_wm8741, &wm8741_dai, 1);
604398575dbSMark Brown 
605f0fba2adSLiam Girdwood 	return ret;
606992bee40SIan Lartey }
607992bee40SIan Lartey 
608992bee40SIan Lartey static const struct i2c_device_id wm8741_i2c_id[] = {
609992bee40SIan Lartey 	{ "wm8741", 0 },
610992bee40SIan Lartey 	{ }
611992bee40SIan Lartey };
612992bee40SIan Lartey MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
613992bee40SIan Lartey 
614992bee40SIan Lartey static struct i2c_driver wm8741_i2c_driver = {
615992bee40SIan Lartey 	.driver = {
6160473e61bSMark Brown 		.name = "wm8741",
61780080ec5SMark Brown 		.of_match_table = wm8741_of_match,
618992bee40SIan Lartey 	},
6199abcd240SUwe Kleine-König 	.probe = wm8741_i2c_probe,
620992bee40SIan Lartey 	.id_table = wm8741_i2c_id,
621992bee40SIan Lartey };
622992bee40SIan Lartey #endif
623992bee40SIan Lartey 
62439e9b8d2SMark Brown #if defined(CONFIG_SPI_MASTER)
wm8741_spi_probe(struct spi_device * spi)6257a79e94eSBill Pemberton static int wm8741_spi_probe(struct spi_device *spi)
62639e9b8d2SMark Brown {
62739e9b8d2SMark Brown 	struct wm8741_priv *wm8741;
628d9780550SMark Brown 	int ret, i;
62939e9b8d2SMark Brown 
6305aefb306SMark Brown 	wm8741 = devm_kzalloc(&spi->dev, sizeof(struct wm8741_priv),
6315aefb306SMark Brown 			     GFP_KERNEL);
63239e9b8d2SMark Brown 	if (wm8741 == NULL)
63339e9b8d2SMark Brown 		return -ENOMEM;
63439e9b8d2SMark Brown 
635d9780550SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
636d9780550SMark Brown 		wm8741->supplies[i].supply = wm8741_supply_names[i];
637d9780550SMark Brown 
638fe98c0cfSMark Brown 	ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8741->supplies),
639d9780550SMark Brown 				      wm8741->supplies);
640d9780550SMark Brown 	if (ret != 0) {
641d9780550SMark Brown 		dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
642fe98c0cfSMark Brown 		return ret;
643d9780550SMark Brown 	}
644d9780550SMark Brown 
645fd64c455STushar Behera 	wm8741->regmap = devm_regmap_init_spi(spi, &wm8741_regmap);
646fe98c0cfSMark Brown 	if (IS_ERR(wm8741->regmap)) {
647fe98c0cfSMark Brown 		ret = PTR_ERR(wm8741->regmap);
648fe98c0cfSMark Brown 		dev_err(&spi->dev, "Failed to init regmap: %d\n", ret);
649fe98c0cfSMark Brown 		return ret;
650fe98c0cfSMark Brown 	}
651fe98c0cfSMark Brown 
6522d52d172SDan Carpenter 	ret = wm8741_set_pdata(&spi->dev, wm8741);
653c354b54cSSergej Sawazki 	if (ret != 0) {
654c354b54cSSergej Sawazki 		dev_err(&spi->dev, "Failed to set pdata: %d\n", ret);
655c354b54cSSergej Sawazki 		return ret;
656c354b54cSSergej Sawazki 	}
657c354b54cSSergej Sawazki 
65839e9b8d2SMark Brown 	spi_set_drvdata(spi, wm8741);
65939e9b8d2SMark Brown 
6609b6a00f7SKuninori Morimoto 	ret = devm_snd_soc_register_component(&spi->dev,
6619b6a00f7SKuninori Morimoto 			&soc_component_dev_wm8741, &wm8741_dai, 1);
66239e9b8d2SMark Brown 	return ret;
66339e9b8d2SMark Brown }
66439e9b8d2SMark Brown 
66539e9b8d2SMark Brown static struct spi_driver wm8741_spi_driver = {
66639e9b8d2SMark Brown 	.driver = {
66739e9b8d2SMark Brown 		.name	= "wm8741",
66880080ec5SMark Brown 		.of_match_table = wm8741_of_match,
66939e9b8d2SMark Brown 	},
67039e9b8d2SMark Brown 	.probe		= wm8741_spi_probe,
67139e9b8d2SMark Brown };
67239e9b8d2SMark Brown #endif /* CONFIG_SPI_MASTER */
67339e9b8d2SMark Brown 
wm8741_modinit(void)674992bee40SIan Lartey static int __init wm8741_modinit(void)
675992bee40SIan Lartey {
676f0fba2adSLiam Girdwood 	int ret = 0;
677f0fba2adSLiam Girdwood 
67826090a83SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
679992bee40SIan Lartey 	ret = i2c_add_driver(&wm8741_i2c_driver);
6803fe4a5eeSIan Lartey 	if (ret != 0)
681f0fba2adSLiam Girdwood 		pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
682992bee40SIan Lartey #endif
68339e9b8d2SMark Brown #if defined(CONFIG_SPI_MASTER)
68439e9b8d2SMark Brown 	ret = spi_register_driver(&wm8741_spi_driver);
68539e9b8d2SMark Brown 	if (ret != 0) {
68639e9b8d2SMark Brown 		printk(KERN_ERR "Failed to register wm8741 SPI driver: %d\n",
68739e9b8d2SMark Brown 		       ret);
68839e9b8d2SMark Brown 	}
68939e9b8d2SMark Brown #endif
690f0fba2adSLiam Girdwood 
691f0fba2adSLiam Girdwood 	return ret;
692992bee40SIan Lartey }
693992bee40SIan Lartey module_init(wm8741_modinit);
694992bee40SIan Lartey 
wm8741_exit(void)695992bee40SIan Lartey static void __exit wm8741_exit(void)
696992bee40SIan Lartey {
69739e9b8d2SMark Brown #if defined(CONFIG_SPI_MASTER)
69839e9b8d2SMark Brown 	spi_unregister_driver(&wm8741_spi_driver);
69939e9b8d2SMark Brown #endif
70026090a83SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
701992bee40SIan Lartey 	i2c_del_driver(&wm8741_i2c_driver);
702992bee40SIan Lartey #endif
703992bee40SIan Lartey }
704992bee40SIan Lartey module_exit(wm8741_exit);
705992bee40SIan Lartey 
706992bee40SIan Lartey MODULE_DESCRIPTION("ASoC WM8741 driver");
707992bee40SIan Lartey MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>");
708992bee40SIan Lartey MODULE_LICENSE("GPL");
709