diff options
Diffstat (limited to 'sound/soc/codecs/wm8753.c')
| -rw-r--r-- | sound/soc/codecs/wm8753.c | 773 |
1 files changed, 356 insertions, 417 deletions
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 8f679a13f2b..53e57b4049a 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1,7 +1,7 @@ /* * wm8753.c -- WM8753 ALSA Soc Audio driver * - * Copyright 2003 Wolfson Microelectronics PLC. + * Copyright 2003-11 Wolfson Microelectronics PLC. * Author: Liam Girdwood <lrg@slimlogic.co.uk> * * This program is free software; you can redistribute it and/or modify it @@ -38,14 +38,14 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> -#include <linux/platform_device.h> +#include <linux/of_device.h> +#include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> -#include <sound/soc-dapm.h> #include <sound/initval.h> #include <sound/tlv.h> #include <asm/div64.h> @@ -56,89 +56,106 @@ static int caps_charge = 2000; module_param(caps_charge, int, 0); MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); -static void wm8753_set_dai_mode(struct snd_soc_codec *codec, - struct snd_soc_dai *dai, unsigned int hifi); +static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec, + unsigned int fmt); +static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec, + unsigned int fmt); /* * wm8753 register cache * We can't read the WM8753 register space when we * are using 2 wire for device control, so we cache them instead. */ -static const u16 wm8753_reg[] = { - 0x0008, 0x0000, 0x000a, 0x000a, - 0x0033, 0x0000, 0x0007, 0x00ff, - 0x00ff, 0x000f, 0x000f, 0x007b, - 0x0000, 0x0032, 0x0000, 0x00c3, - 0x00c3, 0x00c0, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0055, - 0x0005, 0x0050, 0x0055, 0x0050, - 0x0055, 0x0050, 0x0055, 0x0079, - 0x0079, 0x0079, 0x0079, 0x0079, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0097, 0x0097, 0x0000, 0x0004, - 0x0000, 0x0083, 0x0024, 0x01ba, - 0x0000, 0x0083, 0x0024, 0x01ba, - 0x0000, 0x0000, 0x0000 +static const struct reg_default wm8753_reg_defaults[] = { + { 0x00, 0x0000 }, + { 0x01, 0x0008 }, + { 0x02, 0x0000 }, + { 0x03, 0x000a }, + { 0x04, 0x000a }, + { 0x05, 0x0033 }, + { 0x06, 0x0000 }, + { 0x07, 0x0007 }, + { 0x08, 0x00ff }, + { 0x09, 0x00ff }, + { 0x0a, 0x000f }, + { 0x0b, 0x000f }, + { 0x0c, 0x007b }, + { 0x0d, 0x0000 }, + { 0x0e, 0x0032 }, + { 0x0f, 0x0000 }, + { 0x10, 0x00c3 }, + { 0x11, 0x00c3 }, + { 0x12, 0x00c0 }, + { 0x13, 0x0000 }, + { 0x14, 0x0000 }, + { 0x15, 0x0000 }, + { 0x16, 0x0000 }, + { 0x17, 0x0000 }, + { 0x18, 0x0000 }, + { 0x19, 0x0000 }, + { 0x1a, 0x0000 }, + { 0x1b, 0x0000 }, + { 0x1c, 0x0000 }, + { 0x1d, 0x0000 }, + { 0x1e, 0x0000 }, + { 0x1f, 0x0000 }, + { 0x20, 0x0055 }, + { 0x21, 0x0005 }, + { 0x22, 0x0050 }, + { 0x23, 0x0055 }, + { 0x24, 0x0050 }, + { 0x25, 0x0055 }, + { 0x26, 0x0050 }, + { 0x27, 0x0055 }, + { 0x28, 0x0079 }, + { 0x29, 0x0079 }, + { 0x2a, 0x0079 }, + { 0x2b, 0x0079 }, + { 0x2c, 0x0079 }, + { 0x2d, 0x0000 }, + { 0x2e, 0x0000 }, + { 0x2f, 0x0000 }, + { 0x30, 0x0000 }, + { 0x31, 0x0097 }, + { 0x32, 0x0097 }, + { 0x33, 0x0000 }, + { 0x34, 0x0004 }, + { 0x35, 0x0000 }, + { 0x36, 0x0083 }, + { 0x37, 0x0024 }, + { 0x38, 0x01ba }, + { 0x39, 0x0000 }, + { 0x3a, 0x0083 }, + { 0x3b, 0x0024 }, + { 0x3c, 0x01ba }, + { 0x3d, 0x0000 }, + { 0x3e, 0x0000 }, + { 0x3f, 0x0000 }, }; -/* codec private data */ -struct wm8753_priv { - enum snd_soc_control_type control_type; - unsigned int sysclk; - unsigned int pcmclk; - u16 reg_cache[ARRAY_SIZE(wm8753_reg)]; - int dai_func; -}; - -/* - * read wm8753 register cache - */ -static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) +static bool wm8753_volatile(struct device *dev, unsigned int reg) { - u16 *cache = codec->reg_cache; - if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1)) - return -1; - return cache[reg - 1]; + return reg == WM8753_RESET; } -/* - * write wm8753 register cache - */ -static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) +static bool wm8753_writeable(struct device *dev, unsigned int reg) { - u16 *cache = codec->reg_cache; - if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1)) - return; - cache[reg - 1] = value; + return reg <= WM8753_ADCTL2; } -/* - * write to the WM8753 register space - */ -static int wm8753_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; +/* codec private data */ +struct wm8753_priv { + struct regmap *regmap; + unsigned int sysclk; + unsigned int pcmclk; - /* data is - * D15..D9 WM8753 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; + unsigned int voice_fmt; + unsigned int hifi_fmt; - wm8753_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} + int dai_func; +}; -#define wm8753_reset(c) wm8753_write(c, WM8753_RESET, 0) +#define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0) /* * WM8753 Controls @@ -217,27 +234,40 @@ SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase), static int wm8753_get_dai(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.integer.value[0] = (mode & 0xc) >> 2; + ucontrol->value.integer.value[0] = wm8753->dai_func; return 0; } static int wm8753_set_dai(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL); + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); + u16 ioctl; - if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0]) + if (wm8753->dai_func == ucontrol->value.integer.value[0]) return 0; - mode &= 0xfff3; - mode |= (ucontrol->value.integer.value[0] << 2); + if (snd_soc_codec_is_active(codec)) + return -EBUSY; + + ioctl = snd_soc_read(codec, WM8753_IOCTL); + + wm8753->dai_func = ucontrol->value.integer.value[0]; + + if (((ioctl >> 2) & 0x3) == wm8753->dai_func) + return 1; + + ioctl = (ioctl & 0x1f3) | (wm8753->dai_func << 2); + snd_soc_write(codec, WM8753_IOCTL, ioctl); + + + wm8753_hifi_write_dai_fmt(codec, wm8753->hifi_fmt); + wm8753_voice_write_dai_fmt(codec, wm8753->voice_fmt); - wm8753->dai_func = ucontrol->value.integer.value[0]; return 1; } @@ -514,7 +544,7 @@ SND_SOC_DAPM_INPUT("MIC2"), SND_SOC_DAPM_VMID("VREF"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8753_dapm_routes[] = { /* left mixer */ {"Left Mixer", "Left Playback Switch", "Left DAC"}, {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, @@ -668,16 +698,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"ACOP", NULL, "ALC Mixer"}, }; -static int wm8753_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, - ARRAY_SIZE(wm8753_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - return 0; -} - /* PLL divisors */ struct _pll_div { u32 div2:1; @@ -738,17 +758,17 @@ static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, if (pll_id == WM8753_PLL1) { offset = 0; enable = 0x10; - reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xffef; + reg = snd_soc_read(codec, WM8753_CLOCK) & 0xffef; } else { offset = 4; enable = 0x8; - reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfff7; + reg = snd_soc_read(codec, WM8753_CLOCK) & 0xfff7; } if (!freq_in || !freq_out) { /* disable PLL */ - wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0026); - wm8753_write(codec, WM8753_CLOCK, reg); + snd_soc_write(codec, WM8753_PLL1CTL1 + offset, 0x0026); + snd_soc_write(codec, WM8753_CLOCK, reg); return 0; } else { u16 value = 0; @@ -759,20 +779,20 @@ static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, /* set up N and K PLL divisor ratios */ /* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */ value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18); - wm8753_write(codec, WM8753_PLL1CTL2 + offset, value); + snd_soc_write(codec, WM8753_PLL1CTL2 + offset, value); /* bits 8:0 = PLL_K[17:9] */ value = (pll_div.k & 0x03fe00) >> 9; - wm8753_write(codec, WM8753_PLL1CTL3 + offset, value); + snd_soc_write(codec, WM8753_PLL1CTL3 + offset, value); /* bits 8:0 = PLL_K[8:0] */ value = pll_div.k & 0x0001ff; - wm8753_write(codec, WM8753_PLL1CTL4 + offset, value); + snd_soc_write(codec, WM8753_PLL1CTL4 + offset, value); /* set PLL as input and enable */ - wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 | + snd_soc_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 | (pll_div.div2 << 3)); - wm8753_write(codec, WM8753_CLOCK, reg | enable); + snd_soc_write(codec, WM8753_CLOCK, reg | enable); } return 0; } @@ -875,11 +895,10 @@ static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai, /* * Set's ADC and Voice DAC format. */ -static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec *codec, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; - u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01ec; + u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01ec; /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -901,14 +920,7 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8753_write(codec, WM8753_PCM, voice); - return 0; -} - -static int wm8753_pcm_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - wm8753_set_dai_mode(dai->codec, dai, 0); + snd_soc_write(codec, WM8753_PCM, voice); return 0; } @@ -919,11 +931,10 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_codec *codec = dai->codec; struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); - u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; - u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; + u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01f3; + u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x017f; /* bit size */ switch (params_format(params)) { @@ -943,23 +954,22 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, /* sample rate */ if (params_rate(params) * 384 == wm8753->pcmclk) srate |= 0x80; - wm8753_write(codec, WM8753_SRATE1, srate); + snd_soc_write(codec, WM8753_SRATE1, srate); - wm8753_write(codec, WM8753_PCM, voice); + snd_soc_write(codec, WM8753_PCM, voice); return 0; } /* * Set's PCM dai fmt and BCLK. */ -static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec *codec, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; u16 voice, ioctl; - voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x011f; - ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x015d; + voice = snd_soc_read(codec, WM8753_PCM) & 0x011f; + ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x015d; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -1013,8 +1023,8 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8753_write(codec, WM8753_PCM, voice); - wm8753_write(codec, WM8753_IOCTL, ioctl); + snd_soc_write(codec, WM8753_PCM, voice); + snd_soc_write(codec, WM8753_IOCTL, ioctl); return 0; } @@ -1026,16 +1036,16 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8753_PCMDIV: - reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0x003f; - wm8753_write(codec, WM8753_CLOCK, reg | div); + reg = snd_soc_read(codec, WM8753_CLOCK) & 0x003f; + snd_soc_write(codec, WM8753_CLOCK, reg | div); break; case WM8753_BCLKDIV: - reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x01c7; - wm8753_write(codec, WM8753_SRATE2, reg | div); + reg = snd_soc_read(codec, WM8753_SRATE2) & 0x01c7; + snd_soc_write(codec, WM8753_SRATE2, reg | div); break; case WM8753_VXCLKDIV: - reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x003f; - wm8753_write(codec, WM8753_SRATE2, reg | div); + reg = snd_soc_read(codec, WM8753_SRATE2) & 0x003f; + snd_soc_write(codec, WM8753_SRATE2, reg | div); break; default: return -EINVAL; @@ -1046,11 +1056,10 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, /* * Set's HiFi DAC format. */ -static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec *codec, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; - u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01e0; + u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01e0; /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -1072,21 +1081,20 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8753_write(codec, WM8753_HIFI, hifi); + snd_soc_write(codec, WM8753_HIFI, hifi); return 0; } /* * Set's I2S DAI format. */ -static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec *codec, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; u16 ioctl, hifi; - hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x011f; - ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x00ae; + hifi = snd_soc_read(codec, WM8753_HIFI) & 0x011f; + ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x00ae; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -1140,15 +1148,8 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8753_write(codec, WM8753_HIFI, hifi); - wm8753_write(codec, WM8753_IOCTL, ioctl); - return 0; -} - -static int wm8753_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - wm8753_set_dai_mode(dai->codec, dai, 1); + snd_soc_write(codec, WM8753_HIFI, hifi); + snd_soc_write(codec, WM8753_IOCTL, ioctl); return 0; } @@ -1159,11 +1160,10 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_codec *codec = dai->codec; struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); - u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; - u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; + u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x01c0; + u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01f3; int coeff; /* is digital filter coefficient valid ? */ @@ -1172,7 +1172,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, printk(KERN_ERR "wm8753 invalid MCLK or rate\n"); return coeff; } - wm8753_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) | + snd_soc_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); /* bit size */ @@ -1190,81 +1190,137 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, break; } - wm8753_write(codec, WM8753_HIFI, hifi); + snd_soc_write(codec, WM8753_HIFI, hifi); return 0; } -static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec *codec, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; u16 clock; /* set clk source as pcmclk */ - clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb; - wm8753_write(codec, WM8753_CLOCK, clock); + clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; + snd_soc_write(codec, WM8753_CLOCK, clock); - if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) - return -EINVAL; - return wm8753_pcm_set_dai_fmt(codec_dai, fmt); + return wm8753_vdac_adc_set_dai_fmt(codec, fmt); } -static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec *codec, unsigned int fmt) { - if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) - return -EINVAL; - return wm8753_i2s_set_dai_fmt(codec_dai, fmt); + return wm8753_hdac_set_dai_fmt(codec, fmt); } -static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec *codec, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; u16 clock; /* set clk source as pcmclk */ - clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb; - wm8753_write(codec, WM8753_CLOCK, clock); + clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; + snd_soc_write(codec, WM8753_CLOCK, clock); - if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) - return -EINVAL; - return wm8753_i2s_set_dai_fmt(codec_dai, fmt); + return wm8753_vdac_adc_set_dai_fmt(codec, fmt); } -static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, +static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec *codec, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; u16 clock; /* set clk source as mclk */ - clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb; - wm8753_write(codec, WM8753_CLOCK, clock | 0x4); + clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; + snd_soc_write(codec, WM8753_CLOCK, clock | 0x4); - if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) + if (wm8753_hdac_set_dai_fmt(codec, fmt) < 0) return -EINVAL; - if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) - return -EINVAL; - return wm8753_i2s_set_dai_fmt(codec_dai, fmt); + return wm8753_vdac_adc_set_dai_fmt(codec, fmt); } +static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec, + unsigned int fmt) +{ + struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + switch (wm8753->dai_func) { + case 0: + ret = wm8753_mode1h_set_dai_fmt(codec, fmt); + break; + case 1: + ret = wm8753_mode2_set_dai_fmt(codec, fmt); + break; + case 2: + case 3: + ret = wm8753_mode3_4_set_dai_fmt(codec, fmt); + break; + default: + break; + } + if (ret) + return ret; + + return wm8753_i2s_set_dai_fmt(codec, fmt); +} + +static int wm8753_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); + + wm8753->hifi_fmt = fmt; + + return wm8753_hifi_write_dai_fmt(codec, fmt); +}; + +static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec, + unsigned int fmt) +{ + struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + if (wm8753->dai_func != 0) + return 0; + + ret = wm8753_mode1v_set_dai_fmt(codec, fmt); + if (ret) + return ret; + ret = wm8753_pcm_set_dai_fmt(codec, fmt); + if (ret) + return ret; + + return 0; +}; + +static int wm8753_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); + + wm8753->voice_fmt = fmt; + + return wm8753_voice_write_dai_fmt(codec, fmt); +}; + static int wm8753_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; + u16 mute_reg = snd_soc_read(codec, WM8753_DAC) & 0xfff7; struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); /* the digital mute covers the HiFi and Voice DAC's on the WM8753. * make sure we check if they are not both active when we mute */ if (mute && wm8753->dai_func == 1) { - if (!codec->active) - wm8753_write(codec, WM8753_DAC, mute_reg | 0x8); + if (!snd_soc_codec_is_active(codec)) + snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8); } else { if (mute) - wm8753_write(codec, WM8753_DAC, mute_reg | 0x8); + snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8); else - wm8753_write(codec, WM8753_DAC, mute_reg); + snd_soc_write(codec, WM8753_DAC, mute_reg); } return 0; @@ -1273,26 +1329,26 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute) static int wm8753_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; + u16 pwr_reg = snd_soc_read(codec, WM8753_PWR1) & 0xfe3e; switch (level) { case SND_SOC_BIAS_ON: /* set vmid to 50k and unmute dac */ - wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); + snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); break; case SND_SOC_BIAS_PREPARE: /* set vmid to 5k for quick power up */ - wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); + snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); break; case SND_SOC_BIAS_STANDBY: /* mute dac and set vmid to 500k, enable VREF */ - wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); + snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141); break; case SND_SOC_BIAS_OFF: - wm8753_write(codec, WM8753_PWR1, 0x0001); + snd_soc_write(codec, WM8753_PWR1, 0x0001); break; } - codec->bias_level = level; + codec->dapm.bias_level = level; return 0; } @@ -1305,7 +1361,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_FMTBIT_S24_LE) /* - * The WM8753 supports upto 4 different and mutually exclusive DAI + * The WM8753 supports up to 4 different and mutually exclusive DAI * configurations. This gives 2 PCM's available for use, hifi and voice. * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI * is connected between the wm8753 and a BT codec or GSM modem. @@ -1315,57 +1371,25 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, * 3. Voice disabled - HIFI over HIFI * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture */ -static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { - .startup = wm8753_i2s_startup, +static const struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = { .hw_params = wm8753_i2s_hw_params, .digital_mute = wm8753_mute, - .set_fmt = wm8753_mode1h_set_dai_fmt, + .set_fmt = wm8753_hifi_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, .set_pll = wm8753_set_dai_pll, .set_sysclk = wm8753_set_dai_sysclk, }; -static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { - .startup = wm8753_pcm_startup, +static const struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = { .hw_params = wm8753_pcm_hw_params, .digital_mute = wm8753_mute, - .set_fmt = wm8753_mode1v_set_dai_fmt, + .set_fmt = wm8753_voice_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, .set_pll = wm8753_set_dai_pll, .set_sysclk = wm8753_set_dai_sysclk, }; -static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { - .startup = wm8753_pcm_startup, - .hw_params = wm8753_pcm_hw_params, - .digital_mute = wm8753_mute, - .set_fmt = wm8753_mode2_set_dai_fmt, - .set_clkdiv = wm8753_set_dai_clkdiv, - .set_pll = wm8753_set_dai_pll, - .set_sysclk = wm8753_set_dai_sysclk, -}; - -static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = { - .startup = wm8753_i2s_startup, - .hw_params = wm8753_i2s_hw_params, - .digital_mute = wm8753_mute, - .set_fmt = wm8753_mode3_4_set_dai_fmt, - .set_clkdiv = wm8753_set_dai_clkdiv, - .set_pll = wm8753_set_dai_pll, - .set_sysclk = wm8753_set_dai_sysclk, -}; - -static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = { - .startup = wm8753_i2s_startup, - .hw_params = wm8753_i2s_hw_params, - .digital_mute = wm8753_mute, - .set_fmt = wm8753_mode3_4_set_dai_fmt, - .set_clkdiv = wm8753_set_dai_clkdiv, - .set_pll = wm8753_set_dai_pll, - .set_sysclk = wm8753_set_dai_sysclk, -}; - -static struct snd_soc_dai_driver wm8753_all_dai[] = { +static struct snd_soc_dai_driver wm8753_dai[] = { /* DAI HiFi mode 1 */ { .name = "wm8753-hifi", .playback = { @@ -1373,14 +1397,16 @@ static struct snd_soc_dai_driver wm8753_all_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS}, + .formats = WM8753_FORMATS + }, .capture = { /* dummy for fast DAI switching */ .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS}, - .ops = &wm8753_dai_ops_hifi_mode1, + .formats = WM8753_FORMATS + }, + .ops = &wm8753_dai_ops_hifi_mode, }, /* DAI Voice mode 1 */ { .name = "wm8753-voice", @@ -1389,105 +1415,29 @@ static struct snd_soc_dai_driver wm8753_all_dai[] = { .channels_min = 1, .channels_max = 1, .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, - .ops = &wm8753_dai_ops_voice_mode1, -}, -/* DAI HiFi mode 2 - dummy */ -{ .name = "wm8753-hifi", -}, -/* DAI Voice mode 2 */ -{ .name = "wm8753-voice", - .playback = { - .stream_name = "Voice Playback", - .channels_min = 1, - .channels_max = 1, - .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, - .ops = &wm8753_dai_ops_voice_mode2, -}, -/* DAI HiFi mode 3 */ -{ .name = "wm8753-hifi", - .playback = { - .stream_name = "HiFi Playback", - .channels_min = 1, - .channels_max = 2, - .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, - .ops = &wm8753_dai_ops_hifi_mode3, -}, -/* DAI Voice mode 3 - dummy */ -{ .name = "wm8753-voice", -}, -/* DAI HiFi mode 4 */ -{ .name = "wm8753-hifi", - .playback = { - .stream_name = "HiFi Playback", - .channels_min = 1, - .channels_max = 2, - .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, + .formats = WM8753_FORMATS, + }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, - .ops = &wm8753_dai_ops_hifi_mode4, -}, -/* DAI Voice mode 4 - dummy */ -{ .name = "wm8753-voice", -}, -}; - -static struct snd_soc_dai_driver wm8753_dai[] = { - { - .name = "wm8753-aif0", - }, - { - .name = "wm8753-aif1", + .formats = WM8753_FORMATS, }, + .ops = &wm8753_dai_ops_voice_mode, +}, }; -static void wm8753_set_dai_mode(struct snd_soc_codec *codec, - struct snd_soc_dai *dai, unsigned int hifi) -{ - struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); - - if (wm8753->dai_func < 4) { - if (hifi) - dai->driver = &wm8753_all_dai[wm8753->dai_func << 1]; - else - dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1]; - } - wm8753_write(codec, WM8753_IOCTL, wm8753->dai_func); -} - static void wm8753_work(struct work_struct *work) { - struct snd_soc_codec *codec = - container_of(work, struct snd_soc_codec, delayed_work.work); - wm8753_set_bias_level(codec, codec->bias_level); + struct snd_soc_dapm_context *dapm = + container_of(work, struct snd_soc_dapm_context, + delayed_work.work); + struct snd_soc_codec *codec = dapm->codec; + wm8753_set_bias_level(codec, dapm->bias_level); } -static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state) +static int wm8753_suspend(struct snd_soc_codec *codec) { wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; @@ -1495,68 +1445,30 @@ static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state) static int wm8753_resume(struct snd_soc_codec *codec) { - int i; - u8 data[2]; - u16 *cache = codec->reg_cache; - - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { - if (i + 1 == WM8753_RESET) - continue; - - /* No point in writing hardware default values back */ - if (cache[i] == wm8753_reg[i]) - continue; + struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); - data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); - data[1] = cache[i] & 0x00ff; - codec->hw_write(codec->control_data, data, 2); - } + regcache_sync(wm8753->regmap); wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* charge wm8753 caps */ - if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { + if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - codec->bias_level = SND_SOC_BIAS_ON; - schedule_delayed_work(&codec->delayed_work, - msecs_to_jiffies(caps_charge)); + codec->dapm.bias_level = SND_SOC_BIAS_ON; + queue_delayed_work(system_power_efficient_wq, + &codec->dapm.delayed_work, + msecs_to_jiffies(caps_charge)); } return 0; } -/* - * This function forces any delayed work to be queued and run. - */ -static int run_delayed_work(struct delayed_work *dwork) -{ - int ret; - - /* cancel any work waiting to be queued. */ - ret = cancel_delayed_work(dwork); - - /* if there was any work waiting then we run it now and - * wait for it's completion */ - if (ret) { - schedule_delayed_work(dwork, 0); - flush_scheduled_work(); - } - return ret; -} - static int wm8753_probe(struct snd_soc_codec *codec) { struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); - int ret = 0, reg; - - INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); + int ret; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } + INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work); ret = wm8753_reset(codec); if (ret < 0) { @@ -1569,34 +1481,20 @@ static int wm8753_probe(struct snd_soc_codec *codec) /* charge output caps */ wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - schedule_delayed_work(&codec->delayed_work, + schedule_delayed_work(&codec->dapm.delayed_work, msecs_to_jiffies(caps_charge)); /* set the update bits */ - reg = wm8753_read_reg_cache(codec, WM8753_LDAC); - wm8753_write(codec, WM8753_LDAC, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_RDAC); - wm8753_write(codec, WM8753_RDAC, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_LADC); - wm8753_write(codec, WM8753_LADC, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_RADC); - wm8753_write(codec, WM8753_RADC, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_LOUT1V); - wm8753_write(codec, WM8753_LOUT1V, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_ROUT1V); - wm8753_write(codec, WM8753_ROUT1V, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_LOUT2V); - wm8753_write(codec, WM8753_LOUT2V, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_ROUT2V); - wm8753_write(codec, WM8753_ROUT2V, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_LINVOL); - wm8753_write(codec, WM8753_LINVOL, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); - wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); - - snd_soc_add_controls(codec, wm8753_snd_controls, - ARRAY_SIZE(wm8753_snd_controls)); - wm8753_add_widgets(codec); + snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100); + snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100); + snd_soc_update_bits(codec, WM8753_LADC, 0x0100, 0x0100); + snd_soc_update_bits(codec, WM8753_RADC, 0x0100, 0x0100); + snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100); + snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100); + snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100); + snd_soc_update_bits(codec, WM8753_ROUT2V, 0x0100, 0x0100); + snd_soc_update_bits(codec, WM8753_LINVOL, 0x0100, 0x0100); + snd_soc_update_bits(codec, WM8753_RINVOL, 0x0100, 0x0100); return 0; } @@ -1604,7 +1502,7 @@ static int wm8753_probe(struct snd_soc_codec *codec) /* power down chip */ static int wm8753_remove(struct snd_soc_codec *codec) { - run_delayed_work(&codec->delayed_work); + flush_delayed_work(&codec->dapm.delayed_work); wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; @@ -1616,73 +1514,113 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8753 = { .suspend = wm8753_suspend, .resume = wm8753_resume, .set_bias_level = wm8753_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8753_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8753_reg, + + .controls = wm8753_snd_controls, + .num_controls = ARRAY_SIZE(wm8753_snd_controls), + .dapm_widgets = wm8753_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8753_dapm_widgets), + .dapm_routes = wm8753_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8753_dapm_routes), +}; + +static const struct of_device_id wm8753_of_match[] = { + { .compatible = "wlf,wm8753", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8753_of_match); + +static const struct regmap_config wm8753_regmap = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = WM8753_ADCTL2, + .writeable_reg = wm8753_writeable, + .volatile_reg = wm8753_volatile, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wm8753_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults), }; #if defined(CONFIG_SPI_MASTER) -static int __devinit wm8753_spi_probe(struct spi_device *spi) +static int wm8753_spi_probe(struct spi_device *spi) { struct wm8753_priv *wm8753; int ret; - wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); + wm8753 = devm_kzalloc(&spi->dev, sizeof(struct wm8753_priv), + GFP_KERNEL); if (wm8753 == NULL) return -ENOMEM; - wm8753->control_type = SND_SOC_SPI; spi_set_drvdata(spi, wm8753); - ret = snd_soc_register_codec(&spi->dev, - &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); - if (ret < 0) - kfree(wm8753); + wm8753->regmap = devm_regmap_init_spi(spi, &wm8753_regmap); + if (IS_ERR(wm8753->regmap)) { + ret = PTR_ERR(wm8753->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8753, + wm8753_dai, ARRAY_SIZE(wm8753_dai)); + if (ret != 0) + dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret); + return ret; } -static int __devexit wm8753_spi_remove(struct spi_device *spi) +static int wm8753_spi_remove(struct spi_device *spi) { snd_soc_unregister_codec(&spi->dev); - kfree(spi_get_drvdata(spi)); return 0; } static struct spi_driver wm8753_spi_driver = { .driver = { - .name = "wm8753-codec", + .name = "wm8753", .owner = THIS_MODULE, + .of_match_table = wm8753_of_match, }, .probe = wm8753_spi_probe, - .remove = __devexit_p(wm8753_spi_remove), + .remove = wm8753_spi_remove, }; #endif /* CONFIG_SPI_MASTER */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static __devinit int wm8753_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +#if IS_ENABLED(CONFIG_I2C) +static int wm8753_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct wm8753_priv *wm8753; int ret; - wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); + wm8753 = devm_kzalloc(&i2c->dev, sizeof(struct wm8753_priv), + GFP_KERNEL); if (wm8753 == NULL) return -ENOMEM; i2c_set_clientdata(i2c, wm8753); - wm8753->control_type = SND_SOC_I2C; - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); - if (ret < 0) - kfree(wm8753); + wm8753->regmap = devm_regmap_init_i2c(i2c, &wm8753_regmap); + if (IS_ERR(wm8753->regmap)) { + ret = PTR_ERR(wm8753->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8753, + wm8753_dai, ARRAY_SIZE(wm8753_dai)); + if (ret != 0) + dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); + return ret; } -static __devexit int wm8753_i2c_remove(struct i2c_client *client) +static int wm8753_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); - kfree(i2c_get_clientdata(client)); return 0; } @@ -1694,11 +1632,12 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); static struct i2c_driver wm8753_i2c_driver = { .driver = { - .name = "wm8753-codec", + .name = "wm8753", .owner = THIS_MODULE, + .of_match_table = wm8753_of_match, }, .probe = wm8753_i2c_probe, - .remove = __devexit_p(wm8753_i2c_remove), + .remove = wm8753_i2c_remove, .id_table = wm8753_i2c_id, }; #endif @@ -1706,7 +1645,7 @@ static struct i2c_driver wm8753_i2c_driver = { static int __init wm8753_modinit(void) { int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C) ret = i2c_add_driver(&wm8753_i2c_driver); if (ret != 0) { printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n", @@ -1726,7 +1665,7 @@ module_init(wm8753_modinit); static void __exit wm8753_exit(void) { -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C) i2c_del_driver(&wm8753_i2c_driver); #endif #if defined(CONFIG_SPI_MASTER) |
