diff options
Diffstat (limited to 'sound/soc/codecs/wm8580.c')
| -rw-r--r-- | sound/soc/codecs/wm8580.c | 300 |
1 files changed, 165 insertions, 135 deletions
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 5e9c40fa7eb2..2be265bb0751 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1,21 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * wm8580.c -- WM8580 ALSA Soc Audio driver + * wm8580.c -- WM8580 and WM8581 ALSA Soc Audio driver * * Copyright 2008-12 Wolfson Microelectronics PLC. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * * Notes: * The WM8580 is a multichannel codec with S/PDIF support, featuring six * DAC channels and two ADC channels. * + * The WM8581 is a multichannel codec with S/PDIF support, featuring eight + * DAC channels and two ADC channels. + * * Currently only the primary audio interface is supported - S/PDIF and * the secondary audio interfaces are not. */ +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -26,7 +26,6 @@ #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> -#include <linux/of_device.h> #include <sound/core.h> #include <sound/pcm.h> @@ -65,6 +64,8 @@ #define WM8580_DIGITAL_ATTENUATION_DACR2 0x17 #define WM8580_DIGITAL_ATTENUATION_DACL3 0x18 #define WM8580_DIGITAL_ATTENUATION_DACR3 0x19 +#define WM8581_DIGITAL_ATTENUATION_DACL4 0x1A +#define WM8581_DIGITAL_ATTENUATION_DACR4 0x1B #define WM8580_MASTER_DIGITAL_ATTENUATION 0x1C #define WM8580_ADC_CONTROL1 0x1D #define WM8580_SPDTXCHAN0 0x1E @@ -236,12 +237,17 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = { "PVDD", }; +struct wm8580_driver_data { + int num_dacs; +}; + /* codec private data */ struct wm8580_priv { struct regmap *regmap; struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES]; struct pll_state a; struct pll_state b; + const struct wm8580_driver_data *drvdata; int sysclk[2]; }; @@ -252,8 +258,8 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component); unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; int ret; @@ -269,8 +275,8 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol, return ret; /* Now write again with the volume update bit set */ - snd_soc_update_bits(codec, reg, 0x100, 0x100); - snd_soc_update_bits(codec, reg2, 0x100, 0x100); + snd_soc_component_update_bits(component, reg, 0x100, 0x100); + snd_soc_component_update_bits(component, reg2, 0x100, 0x100); return 0; } @@ -306,6 +312,19 @@ SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1), SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), }; +static const struct snd_kcontrol_new wm8581_snd_controls[] = { +SOC_DOUBLE_R_EXT_TLV("DAC4 Playback Volume", + WM8581_DIGITAL_ATTENUATION_DACL4, + WM8581_DIGITAL_ATTENUATION_DACR4, + 0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv), + +SOC_SINGLE("DAC4 Deemphasis Switch", WM8580_DAC_CONTROL3, 3, 1, 0), + +SOC_DOUBLE("DAC4 Invert Switch", WM8580_DAC_CONTROL4, 8, 7, 1, 0), + +SOC_SINGLE("DAC4 Switch", WM8580_DAC_CONTROL5, 3, 1, 1), +}; + static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), @@ -324,6 +343,13 @@ SND_SOC_DAPM_INPUT("AINL"), SND_SOC_DAPM_INPUT("AINR"), }; +static const struct snd_soc_dapm_widget wm8581_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC4", "Playback", WM8580_PWRDN1, 5, 1), + +SND_SOC_DAPM_OUTPUT("VOUT4L"), +SND_SOC_DAPM_OUTPUT("VOUT4R"), +}; + static const struct snd_soc_dapm_route wm8580_dapm_routes[] = { { "VOUT1L", NULL, "DAC1" }, { "VOUT1R", NULL, "DAC1" }, @@ -338,6 +364,11 @@ static const struct snd_soc_dapm_route wm8580_dapm_routes[] = { { "ADC", NULL, "AINR" }, }; +static const struct snd_soc_dapm_route wm8581_dapm_routes[] = { + { "VOUT4L", NULL, "DAC4" }, + { "VOUT4R", NULL, "DAC4" }, +}; + /* PLL divisors */ struct _pll_div { u32 prescale:1; @@ -430,8 +461,8 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { int offset; - struct snd_soc_codec *codec = codec_dai->codec; - struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = codec_dai->component; + struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component); struct pll_state *state; struct _pll_div pll_div; unsigned int reg; @@ -470,25 +501,25 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, /* Always disable the PLL - it is not safe to leave it running * while reprogramming it. */ - snd_soc_update_bits(codec, WM8580_PWRDN2, pwr_mask, pwr_mask); + snd_soc_component_update_bits(component, WM8580_PWRDN2, pwr_mask, pwr_mask); if (!freq_in || !freq_out) return 0; - snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); - snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0x1ff); - snd_soc_write(codec, WM8580_PLLA3 + offset, + snd_soc_component_write(component, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); + snd_soc_component_write(component, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0x1ff); + snd_soc_component_write(component, WM8580_PLLA3 + offset, (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); - reg = snd_soc_read(codec, WM8580_PLLA4 + offset); + reg = snd_soc_component_read(component, WM8580_PLLA4 + offset); reg &= ~0x1b; reg |= pll_div.prescale | pll_div.postscale << 1 | pll_div.freqmode << 3; - snd_soc_write(codec, WM8580_PLLA4 + offset, reg); + snd_soc_component_write(component, WM8580_PLLA4 + offset, reg); /* All done, turn it on */ - snd_soc_update_bits(codec, WM8580_PWRDN2, pwr_mask, 0); + snd_soc_component_update_bits(component, WM8580_PWRDN2, pwr_mask, 0); return 0; } @@ -504,27 +535,26 @@ static int wm8580_paif_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 wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component); u16 paifa = 0; u16 paifb = 0; int i, ratio, osr; /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: paifa |= 0x8; break; - case SNDRV_PCM_FORMAT_S20_3LE: + case 20: paifa |= 0x0; paifb |= WM8580_AIF_LENGTH_20; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: paifa |= 0x0; paifb |= WM8580_AIF_LENGTH_24; break; - case SNDRV_PCM_FORMAT_S32_LE: + case 32: paifa |= 0x0; paifb |= WM8580_AIF_LENGTH_32; break; @@ -538,12 +568,12 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, if (ratio == wm8580_sysclk_ratios[i]) break; if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) { - dev_err(codec->dev, "Invalid clock ratio %d/%d\n", + dev_err(component->dev, "Invalid clock ratio %d/%d\n", wm8580->sysclk[dai->driver->id], params_rate(params)); return -EINVAL; } paifa |= i; - dev_dbg(codec->dev, "Running at %dfs with %dHz clock\n", + dev_dbg(component->dev, "Running at %dfs with %dHz clock\n", wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -551,21 +581,21 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, case 128: case 192: osr = WM8580_DACOSR; - dev_dbg(codec->dev, "Selecting 64x OSR\n"); + dev_dbg(component->dev, "Selecting 64x OSR\n"); break; default: osr = 0; - dev_dbg(codec->dev, "Selecting 128x OSR\n"); + dev_dbg(component->dev, "Selecting 128x OSR\n"); break; } - snd_soc_update_bits(codec, WM8580_PAIF3, WM8580_DACOSR, osr); + snd_soc_component_update_bits(component, WM8580_PAIF3, WM8580_DACOSR, osr); } - snd_soc_update_bits(codec, WM8580_PAIF1 + dai->driver->id, + snd_soc_component_update_bits(component, WM8580_PAIF1 + dai->driver->id, WM8580_AIF_RATE_MASK | WM8580_AIF_BCLKSEL_MASK, paifa); - snd_soc_update_bits(codec, WM8580_PAIF3 + dai->driver->id, + snd_soc_component_update_bits(component, WM8580_PAIF3 + dai->driver->id, WM8580_AIF_LENGTH_MASK, paifb); return 0; } @@ -573,21 +603,21 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_component *component = codec_dai->component; unsigned int aifa; unsigned int aifb; int can_invert_lrclk; - aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->driver->id); - aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->driver->id); + aifa = snd_soc_component_read(component, WM8580_PAIF1 + codec_dai->driver->id); + aifb = snd_soc_component_read(component, WM8580_PAIF3 + codec_dai->driver->id); aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: aifa &= ~WM8580_AIF_MS; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aifa |= WM8580_AIF_MS; break; default: @@ -645,8 +675,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8580_PAIF1 + codec_dai->driver->id, aifa); - snd_soc_write(codec, WM8580_PAIF3 + codec_dai->driver->id, aifb); + snd_soc_component_write(component, WM8580_PAIF1 + codec_dai->driver->id, aifa); + snd_soc_component_write(component, WM8580_PAIF3 + codec_dai->driver->id, aifb); return 0; } @@ -654,12 +684,12 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) { - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_component *component = codec_dai->component; unsigned int reg; switch (div_id) { case WM8580_MCLK: - reg = snd_soc_read(codec, WM8580_PLLB4); + reg = snd_soc_component_read(component, WM8580_PLLB4); reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK; switch (div) { @@ -681,11 +711,11 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - snd_soc_write(codec, WM8580_PLLB4, reg); + snd_soc_component_write(component, WM8580_PLLB4, reg); break; case WM8580_CLKOUTSRC: - reg = snd_soc_read(codec, WM8580_PLLB4); + reg = snd_soc_component_read(component, WM8580_PLLB4); reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK; switch (div) { @@ -707,7 +737,7 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - snd_soc_write(codec, WM8580_PLLB4, reg); + snd_soc_component_write(component, WM8580_PLLB4, reg); break; default: @@ -720,8 +750,8 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - struct snd_soc_codec *codec = dai->codec; - struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component); int ret, sel, sel_mask, sel_shift; switch (dai->driver->id) { @@ -736,7 +766,7 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id, break; default: - BUG_ON("Unknown DAI driver ID\n"); + WARN(1, "Unknown DAI driver ID\n"); return -EINVAL; } @@ -756,77 +786,90 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id, sel = 3 << sel_shift; break; default: - dev_err(codec->dev, "Unknown clock %d\n", clk_id); + dev_err(component->dev, "Unknown clock %d\n", clk_id); return -EINVAL; } /* We really should validate PLL settings but not yet */ wm8580->sysclk[dai->driver->id] = freq; - ret = snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel); + ret = snd_soc_component_update_bits(component, WM8580_CLKSEL, sel_mask, sel); if (ret < 0) return ret; return 0; } -static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) +static int wm8580_mute(struct snd_soc_dai *codec_dai, int mute, int direction) { - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_component *component = codec_dai->component; unsigned int reg; - reg = snd_soc_read(codec, WM8580_DAC_CONTROL5); + reg = snd_soc_component_read(component, WM8580_DAC_CONTROL5); if (mute) reg |= WM8580_DAC_CONTROL5_MUTEALL; else reg &= ~WM8580_DAC_CONTROL5_MUTEALL; - snd_soc_write(codec, WM8580_DAC_CONTROL5, reg); + snd_soc_component_write(component, WM8580_DAC_CONTROL5, reg); return 0; } -static int wm8580_set_bias_level(struct snd_soc_codec *codec, +static int wm8580_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + switch (level) { case SND_SOC_BIAS_ON: case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) { /* Power up and get individual control of the DACs */ - snd_soc_update_bits(codec, WM8580_PWRDN1, + snd_soc_component_update_bits(component, WM8580_PWRDN1, WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD, 0); /* Make VMID high impedance */ - snd_soc_update_bits(codec, WM8580_ADC_CONTROL1, + snd_soc_component_update_bits(component, WM8580_ADC_CONTROL1, 0x100, 0); } break; case SND_SOC_BIAS_OFF: - snd_soc_update_bits(codec, WM8580_PWRDN1, + snd_soc_component_update_bits(component, WM8580_PWRDN1, WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN); break; } - codec->dapm.bias_level = level; return 0; } +static int wm8580_playback_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component); + + return snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, 1, wm8580->drvdata->num_dacs * 2); +} + #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops wm8580_dai_ops_playback = { + .startup = wm8580_playback_startup, .set_sysclk = wm8580_set_sysclk, .hw_params = wm8580_paif_hw_params, .set_fmt = wm8580_set_paif_dai_fmt, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, - .digital_mute = wm8580_digital_mute, + .mute_stream = wm8580_mute, + .no_capture_mute = 1, }; static const struct snd_soc_dai_ops wm8580_dai_ops_capture = { @@ -844,7 +887,6 @@ static struct snd_soc_dai_driver wm8580_dai[] = { .playback = { .stream_name = "Playback", .channels_min = 1, - .channels_max = 6, .rates = SNDRV_PCM_RATE_8000_192000, .formats = WM8580_FORMATS, }, @@ -864,33 +906,39 @@ static struct snd_soc_dai_driver wm8580_dai[] = { }, }; -static int wm8580_probe(struct snd_soc_codec *codec) +static int wm8580_probe(struct snd_soc_component *component) { - struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); + struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); int ret = 0; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; + switch (wm8580->drvdata->num_dacs) { + case 4: + snd_soc_add_component_controls(component, wm8581_snd_controls, + ARRAY_SIZE(wm8581_snd_controls)); + snd_soc_dapm_new_controls(dapm, wm8581_dapm_widgets, + ARRAY_SIZE(wm8581_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, wm8581_dapm_routes, + ARRAY_SIZE(wm8581_dapm_routes)); + break; + default: + break; } ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); if (ret != 0) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + dev_err(component->dev, "Failed to enable supplies: %d\n", ret); goto err_regulator_get; } /* Get the codec into a known state */ - ret = snd_soc_write(codec, WM8580_RESET, 0); + ret = snd_soc_component_write(component, WM8580_RESET, 0); if (ret != 0) { - dev_err(codec->dev, "Failed to reset codec: %d\n", ret); + dev_err(component->dev, "Failed to reset component: %d\n", ret); goto err_regulator_enable; } - wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; err_regulator_enable: @@ -900,33 +948,26 @@ err_regulator_get: } /* power down chip */ -static int wm8580_remove(struct snd_soc_codec *codec) +static void wm8580_remove(struct snd_soc_component *component) { - struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); - - wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); + struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component); regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); - - return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8580 = { - .probe = wm8580_probe, - .remove = wm8580_remove, - .set_bias_level = wm8580_set_bias_level, - - .controls = wm8580_snd_controls, - .num_controls = ARRAY_SIZE(wm8580_snd_controls), - .dapm_widgets = wm8580_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm8580_dapm_widgets), - .dapm_routes = wm8580_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(wm8580_dapm_routes), -}; - -static const struct of_device_id wm8580_of_match[] = { - { .compatible = "wlf,wm8580" }, - { }, +static const struct snd_soc_component_driver soc_component_dev_wm8580 = { + .probe = wm8580_probe, + .remove = wm8580_remove, + .set_bias_level = wm8580_set_bias_level, + .controls = wm8580_snd_controls, + .num_controls = ARRAY_SIZE(wm8580_snd_controls), + .dapm_widgets = wm8580_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8580_dapm_widgets), + .dapm_routes = wm8580_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8580_dapm_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, }; static const struct regmap_config wm8580_regmap = { @@ -936,14 +977,20 @@ static const struct regmap_config wm8580_regmap = { .reg_defaults = wm8580_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8580_reg_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = wm8580_volatile, }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static int wm8580_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static const struct wm8580_driver_data wm8580_data = { + .num_dacs = 3, +}; + +static const struct wm8580_driver_data wm8581_data = { + .num_dacs = 4, +}; + +static int wm8580_i2c_probe(struct i2c_client *i2c) { struct wm8580_priv *wm8580; int ret, i; @@ -969,20 +1016,26 @@ static int wm8580_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8580); - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai)); + wm8580->drvdata = i2c_get_match_data(i2c); + if (!wm8580->drvdata) + return dev_err_probe(&i2c->dev, -EINVAL, "failed to find driver data\n"); + + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai)); return ret; } -static int wm8580_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - return 0; -} +static const struct of_device_id wm8580_of_match[] = { + { .compatible = "wlf,wm8580", .data = &wm8580_data }, + { .compatible = "wlf,wm8581", .data = &wm8581_data }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8580_of_match); static const struct i2c_device_id wm8580_i2c_id[] = { - { "wm8580", 0 }, + { "wm8580", (kernel_ulong_t)&wm8580_data }, + { "wm8581", (kernel_ulong_t)&wm8581_data }, { } }; MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); @@ -990,38 +1043,15 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); static struct i2c_driver wm8580_i2c_driver = { .driver = { .name = "wm8580", - .owner = THIS_MODULE, .of_match_table = wm8580_of_match, }, - .probe = wm8580_i2c_probe, - .remove = wm8580_i2c_remove, + .probe = wm8580_i2c_probe, .id_table = wm8580_i2c_id, }; -#endif -static int __init wm8580_modinit(void) -{ - int ret = 0; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&wm8580_i2c_driver); - if (ret != 0) { - pr_err("Failed to register WM8580 I2C driver: %d\n", ret); - } -#endif - - return ret; -} -module_init(wm8580_modinit); - -static void __exit wm8580_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8580_i2c_driver); -#endif -} -module_exit(wm8580_exit); +module_i2c_driver(wm8580_i2c_driver); MODULE_DESCRIPTION("ASoC WM8580 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>"); MODULE_LICENSE("GPL"); |
