aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/codecs/wm8510.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8510.c')
-rw-r--r--sound/soc/codecs/wm8510.c604
1 files changed, 236 insertions, 368 deletions
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 6a4cea09c45..1c1e328feeb 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -17,96 +17,101 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/platform_device.h>
#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/regmap.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 "wm8510.h"
-#define WM8510_VERSION "0.6"
-
-struct snd_soc_codec_device soc_codec_dev_wm8510;
-
/*
* wm8510 register cache
* We can't read the WM8510 register space when we are
* using 2 wire for device control, so we cache them instead.
*/
-static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0050, 0x0000, 0x0140, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x00ff,
- 0x0000, 0x0000, 0x0100, 0x00ff,
- 0x0000, 0x0000, 0x012c, 0x002c,
- 0x002c, 0x002c, 0x002c, 0x0000,
- 0x0032, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0038, 0x000b, 0x0032, 0x0000,
- 0x0008, 0x000c, 0x0093, 0x00e9,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0003, 0x0010, 0x0000, 0x0000,
- 0x0000, 0x0002, 0x0001, 0x0000,
- 0x0000, 0x0000, 0x0039, 0x0000,
- 0x0001,
+static const struct reg_default wm8510_reg_defaults[] = {
+ { 1, 0x0000 },
+ { 2, 0x0000 },
+ { 3, 0x0000 },
+ { 4, 0x0050 },
+ { 5, 0x0000 },
+ { 6, 0x0140 },
+ { 7, 0x0000 },
+ { 8, 0x0000 },
+ { 9, 0x0000 },
+ { 10, 0x0000 },
+ { 11, 0x00ff },
+ { 12, 0x0000 },
+ { 13, 0x0000 },
+ { 14, 0x0100 },
+ { 15, 0x00ff },
+ { 16, 0x0000 },
+ { 17, 0x0000 },
+ { 18, 0x012c },
+ { 19, 0x002c },
+ { 20, 0x002c },
+ { 21, 0x002c },
+ { 22, 0x002c },
+ { 23, 0x0000 },
+ { 24, 0x0032 },
+ { 25, 0x0000 },
+ { 26, 0x0000 },
+ { 27, 0x0000 },
+ { 28, 0x0000 },
+ { 29, 0x0000 },
+ { 30, 0x0000 },
+ { 31, 0x0000 },
+ { 32, 0x0038 },
+ { 33, 0x000b },
+ { 34, 0x0032 },
+ { 35, 0x0000 },
+ { 36, 0x0008 },
+ { 37, 0x000c },
+ { 38, 0x0093 },
+ { 39, 0x00e9 },
+ { 40, 0x0000 },
+ { 41, 0x0000 },
+ { 42, 0x0000 },
+ { 43, 0x0000 },
+ { 44, 0x0003 },
+ { 45, 0x0010 },
+ { 46, 0x0000 },
+ { 47, 0x0000 },
+ { 48, 0x0000 },
+ { 49, 0x0002 },
+ { 50, 0x0001 },
+ { 51, 0x0000 },
+ { 52, 0x0000 },
+ { 53, 0x0000 },
+ { 54, 0x0039 },
+ { 55, 0x0000 },
+ { 56, 0x0001 },
};
-#define WM8510_POWER1_BIASEN 0x08
-#define WM8510_POWER1_BUFIOEN 0x10
-
-/*
- * read wm8510 register cache
- */
-static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
+static bool wm8510_volatile(struct device *dev, unsigned int reg)
{
- u16 *cache = codec->reg_cache;
- if (reg == WM8510_RESET)
- return 0;
- if (reg >= WM8510_CACHEREGNUM)
- return -1;
- return cache[reg];
-}
-
-/*
- * write wm8510 register cache
- */
-static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec,
- u16 reg, unsigned int value)
-{
- u16 *cache = codec->reg_cache;
- if (reg >= WM8510_CACHEREGNUM)
- return;
- cache[reg] = value;
+ switch (reg) {
+ case WM8510_RESET:
+ return true;
+ default:
+ return false;
+ }
}
-/*
- * write to the WM8510 register space
- */
-static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u8 data[2];
-
- /* data is
- * D15..D9 WM8510 register offset
- * D8...D0 register data
- */
- data[0] = (reg << 1) | ((value >> 8) & 0x0001);
- data[1] = value & 0x00ff;
+#define WM8510_POWER1_BIASEN 0x08
+#define WM8510_POWER1_BUFIOEN 0x10
- wm8510_write_reg_cache(codec, reg, value);
- if (codec->hw_write(codec->control_data, data, 2) == 2)
- return 0;
- else
- return -EIO;
-}
+#define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0)
-#define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0)
+/* codec private data */
+struct wm8510_priv {
+ struct regmap *regmap;
+};
static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
@@ -228,7 +233,7 @@ SND_SOC_DAPM_OUTPUT("SPKOUTP"),
SND_SOC_DAPM_OUTPUT("SPKOUTN"),
};
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8510_dapm_routes[] = {
/* Mono output mixer */
{"Mono Mixer", "PCM Playback Switch", "DAC"},
{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
@@ -260,17 +265,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"ADC", NULL, "Boost Mixer"},
};
-static int wm8510_add_widgets(struct snd_soc_codec *codec)
-{
- snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets,
- ARRAY_SIZE(wm8510_dapm_widgets));
-
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
- snd_soc_dapm_new_widgets(codec);
- return 0;
-}
-
struct pll_ {
unsigned int pre_div:4; /* prescale - 1 */
unsigned int n:4;
@@ -298,7 +292,7 @@ static void pll_factors(unsigned int target, unsigned int source)
if ((Ndiv < 6) || (Ndiv > 12))
printk(KERN_WARNING
- "WM8510 N value %d outwith recommended range!d\n",
+ "WM8510 N value %u outwith recommended range!d\n",
Ndiv);
pll_div.n = Ndiv;
@@ -319,35 +313,35 @@ static void pll_factors(unsigned int target, unsigned int source)
pll_div.k = K;
}
-static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
u16 reg;
if (freq_in == 0 || freq_out == 0) {
/* Clock CODEC directly from MCLK */
- reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
- wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff);
+ reg = snd_soc_read(codec, WM8510_CLOCK);
+ snd_soc_write(codec, WM8510_CLOCK, reg & 0x0ff);
/* Turn off PLL */
- reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
- wm8510_write(codec, WM8510_POWER1, reg & 0x1df);
+ reg = snd_soc_read(codec, WM8510_POWER1);
+ snd_soc_write(codec, WM8510_POWER1, reg & 0x1df);
return 0;
}
pll_factors(freq_out*4, freq_in);
- wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
- wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18);
- wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
- wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
- reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
- wm8510_write(codec, WM8510_POWER1, reg | 0x020);
+ snd_soc_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
+ snd_soc_write(codec, WM8510_PLLK1, pll_div.k >> 18);
+ snd_soc_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
+ snd_soc_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
+ reg = snd_soc_read(codec, WM8510_POWER1);
+ snd_soc_write(codec, WM8510_POWER1, reg | 0x020);
/* Run CODEC from PLL instead of MCLK */
- reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
- wm8510_write(codec, WM8510_CLOCK, reg | 0x100);
+ reg = snd_soc_read(codec, WM8510_CLOCK);
+ snd_soc_write(codec, WM8510_CLOCK, reg | 0x100);
return 0;
}
@@ -363,24 +357,24 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) {
case WM8510_OPCLKDIV:
- reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf;
- wm8510_write(codec, WM8510_GPIO, reg | div);
+ reg = snd_soc_read(codec, WM8510_GPIO) & 0x1cf;
+ snd_soc_write(codec, WM8510_GPIO, reg | div);
break;
case WM8510_MCLKDIV:
- reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f;
- wm8510_write(codec, WM8510_CLOCK, reg | div);
+ reg = snd_soc_read(codec, WM8510_CLOCK) & 0x11f;
+ snd_soc_write(codec, WM8510_CLOCK, reg | div);
break;
case WM8510_ADCCLK:
- reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7;
- wm8510_write(codec, WM8510_ADC, reg | div);
+ reg = snd_soc_read(codec, WM8510_ADC) & 0x1f7;
+ snd_soc_write(codec, WM8510_ADC, reg | div);
break;
case WM8510_DACCLK:
- reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7;
- wm8510_write(codec, WM8510_DAC, reg | div);
+ reg = snd_soc_read(codec, WM8510_DAC) & 0x1f7;
+ snd_soc_write(codec, WM8510_DAC, reg | div);
break;
case WM8510_BCLKDIV:
- reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3;
- wm8510_write(codec, WM8510_CLOCK, reg | div);
+ reg = snd_soc_read(codec, WM8510_CLOCK) & 0x1e3;
+ snd_soc_write(codec, WM8510_CLOCK, reg | div);
break;
default:
return -EINVAL;
@@ -394,7 +388,7 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
{
struct snd_soc_codec *codec = codec_dai->codec;
u16 iface = 0;
- u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe;
+ u16 clk = snd_soc_read(codec, WM8510_CLOCK) & 0x1fe;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -441,8 +435,8 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
- wm8510_write(codec, WM8510_IFACE, iface);
- wm8510_write(codec, WM8510_CLOCK, clk);
+ snd_soc_write(codec, WM8510_IFACE, iface);
+ snd_soc_write(codec, WM8510_CLOCK, clk);
return 0;
}
@@ -450,11 +444,9 @@ static int wm8510_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_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f;
- u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1;
+ struct snd_soc_codec *codec = dai->codec;
+ u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
+ u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
/* bit size */
switch (params_format(params)) {
@@ -473,40 +465,40 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
/* filter coefficient */
switch (params_rate(params)) {
- case SNDRV_PCM_RATE_8000:
+ case 8000:
adn |= 0x5 << 1;
break;
- case SNDRV_PCM_RATE_11025:
+ case 11025:
adn |= 0x4 << 1;
break;
- case SNDRV_PCM_RATE_16000:
+ case 16000:
adn |= 0x3 << 1;
break;
- case SNDRV_PCM_RATE_22050:
+ case 22050:
adn |= 0x2 << 1;
break;
- case SNDRV_PCM_RATE_32000:
+ case 32000:
adn |= 0x1 << 1;
break;
- case SNDRV_PCM_RATE_44100:
- case SNDRV_PCM_RATE_48000:
+ case 44100:
+ case 48000:
break;
}
- wm8510_write(codec, WM8510_IFACE, iface);
- wm8510_write(codec, WM8510_ADD, adn);
+ snd_soc_write(codec, WM8510_IFACE, iface);
+ snd_soc_write(codec, WM8510_ADD, adn);
return 0;
}
static int wm8510_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf;
+ u16 mute_reg = snd_soc_read(codec, WM8510_DAC) & 0xffbf;
if (mute)
- wm8510_write(codec, WM8510_DAC, mute_reg | 0x40);
+ snd_soc_write(codec, WM8510_DAC, mute_reg | 0x40);
else
- wm8510_write(codec, WM8510_DAC, mute_reg);
+ snd_soc_write(codec, WM8510_DAC, mute_reg);
return 0;
}
@@ -514,36 +506,39 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
static int wm8510_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
+ struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
+ u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3;
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
power1 |= 0x1; /* VMID 50k */
- wm8510_write(codec, WM8510_POWER1, power1);
+ snd_soc_write(codec, WM8510_POWER1, power1);
break;
case SND_SOC_BIAS_STANDBY:
power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
- if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ regcache_sync(wm8510->regmap);
+
/* Initial cap charge at VMID 5k */
- wm8510_write(codec, WM8510_POWER1, power1 | 0x3);
+ snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
mdelay(100);
}
power1 |= 0x2; /* VMID 500k */
- wm8510_write(codec, WM8510_POWER1, power1);
+ snd_soc_write(codec, WM8510_POWER1, power1);
break;
case SND_SOC_BIAS_OFF:
- wm8510_write(codec, WM8510_POWER1, 0);
- wm8510_write(codec, WM8510_POWER2, 0);
- wm8510_write(codec, WM8510_POWER3, 0);
+ snd_soc_write(codec, WM8510_POWER1, 0);
+ snd_soc_write(codec, WM8510_POWER2, 0);
+ snd_soc_write(codec, WM8510_POWER3, 0);
break;
}
- codec->bias_level = level;
+ codec->dapm.bias_level = level;
return 0;
}
@@ -554,7 +549,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
#define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
-static struct snd_soc_dai_ops wm8510_dai_ops = {
+static const struct snd_soc_dai_ops wm8510_dai_ops = {
.hw_params = wm8510_pcm_hw_params,
.digital_mute = wm8510_mute,
.set_fmt = wm8510_set_dai_fmt,
@@ -562,8 +557,8 @@ static struct snd_soc_dai_ops wm8510_dai_ops = {
.set_pll = wm8510_set_dai_pll,
};
-struct snd_soc_dai wm8510_dai = {
- .name = "WM8510 HiFi",
+static struct snd_soc_dai_driver wm8510_dai = {
+ .name = "wm8510-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -577,314 +572,187 @@ struct snd_soc_dai wm8510_dai = {
.rates = WM8510_RATES,
.formats = WM8510_FORMATS,},
.ops = &wm8510_dai_ops,
+ .symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8510_dai);
-static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8510_suspend(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static int wm8510_resume(struct platform_device *pdev)
+static int wm8510_resume(struct snd_soc_codec *codec)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) {
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8510_set_bias_level(codec, codec->suspend_bias_level);
return 0;
}
-/*
- * initialise the WM8510 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8510_init(struct snd_soc_device *socdev)
+static int wm8510_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret = 0;
-
- codec->name = "WM8510";
- codec->owner = THIS_MODULE;
- codec->read = wm8510_read_reg_cache;
- codec->write = wm8510_write;
- codec->set_bias_level = wm8510_set_bias_level;
- codec->dai = &wm8510_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8510_reg);
- codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
-
wm8510_reset(codec);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
- if (ret < 0) {
- printk(KERN_ERR "wm8510: failed to create pcms\n");
- goto pcm_err;
- }
-
/* power on device */
- codec->bias_level = SND_SOC_BIAS_OFF;
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- snd_soc_add_controls(codec, wm8510_snd_controls,
- ARRAY_SIZE(wm8510_snd_controls));
- wm8510_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm8510: failed to register card\n");
- goto card_err;
- }
- return ret;
-
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-pcm_err:
- kfree(codec->reg_cache);
- return ret;
-}
-
-static struct snd_soc_device *wm8510_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM8510 2 wire address is 0x1a
- */
-
-static int wm8510_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct snd_soc_device *socdev = wm8510_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
- int ret;
-
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
-
- ret = wm8510_init(socdev);
- if (ret < 0)
- pr_err("failed to initialise WM8510\n");
- return ret;
+ return 0;
}
-static int wm8510_i2c_remove(struct i2c_client *client)
+/* power down chip */
+static int wm8510_remove(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
-static const struct i2c_device_id wm8510_i2c_id[] = {
- { "wm8510", 0 },
- { }
+static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
+ .probe = wm8510_probe,
+ .remove = wm8510_remove,
+ .suspend = wm8510_suspend,
+ .resume = wm8510_resume,
+ .set_bias_level = wm8510_set_bias_level,
+
+ .controls = wm8510_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8510_snd_controls),
+ .dapm_widgets = wm8510_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8510_dapm_widgets),
+ .dapm_routes = wm8510_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(wm8510_dapm_routes),
};
-MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
-static struct i2c_driver wm8510_i2c_driver = {
- .driver = {
- .name = "WM8510 I2C Codec",
- .owner = THIS_MODULE,
- },
- .probe = wm8510_i2c_probe,
- .remove = wm8510_i2c_remove,
- .id_table = wm8510_i2c_id,
+static const struct of_device_id wm8510_of_match[] = {
+ { .compatible = "wlf,wm8510" },
+ { },
};
-static int wm8510_add_i2c_device(struct platform_device *pdev,
- const struct wm8510_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&wm8510_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
+static const struct regmap_config wm8510_regmap = {
+ .reg_bits = 7,
+ .val_bits = 9,
+ .max_register = WM8510_MONOMIX,
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
+ .reg_defaults = wm8510_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm8510_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8510_i2c_driver);
- return -ENODEV;
-}
-#endif
+ .volatile_reg = wm8510_volatile,
+};
#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8510_spi_probe(struct spi_device *spi)
+static int wm8510_spi_probe(struct spi_device *spi)
{
- struct snd_soc_device *socdev = wm8510_socdev;
- struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8510_priv *wm8510;
int ret;
- codec->control_data = spi;
+ wm8510 = devm_kzalloc(&spi->dev, sizeof(struct wm8510_priv),
+ GFP_KERNEL);
+ if (wm8510 == NULL)
+ return -ENOMEM;
+
+ wm8510->regmap = devm_regmap_init_spi(spi, &wm8510_regmap);
+ if (IS_ERR(wm8510->regmap))
+ return PTR_ERR(wm8510->regmap);
- ret = wm8510_init(socdev);
- if (ret < 0)
- dev_err(&spi->dev, "failed to initialise WM8510\n");
+ spi_set_drvdata(spi, wm8510);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8510, &wm8510_dai, 1);
return ret;
}
-static int __devexit wm8510_spi_remove(struct spi_device *spi)
+static int wm8510_spi_remove(struct spi_device *spi)
{
+ snd_soc_unregister_codec(&spi->dev);
return 0;
}
static struct spi_driver wm8510_spi_driver = {
.driver = {
.name = "wm8510",
- .bus = &spi_bus_type,
.owner = THIS_MODULE,
+ .of_match_table = wm8510_of_match,
},
.probe = wm8510_spi_probe,
- .remove = __devexit_p(wm8510_spi_remove),
+ .remove = wm8510_spi_remove,
};
+#endif /* CONFIG_SPI_MASTER */
-static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8510_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
- struct spi_transfer t;
- struct spi_message m;
- u8 msg[2];
-
- if (len <= 0)
- return 0;
+ struct wm8510_priv *wm8510;
+ int ret;
- msg[0] = data[0];
- msg[1] = data[1];
+ wm8510 = devm_kzalloc(&i2c->dev, sizeof(struct wm8510_priv),
+ GFP_KERNEL);
+ if (wm8510 == NULL)
+ return -ENOMEM;
- spi_message_init(&m);
- memset(&t, 0, (sizeof t));
+ wm8510->regmap = devm_regmap_init_i2c(i2c, &wm8510_regmap);
+ if (IS_ERR(wm8510->regmap))
+ return PTR_ERR(wm8510->regmap);
- t.tx_buf = &msg[0];
- t.len = len;
+ i2c_set_clientdata(i2c, wm8510);
- spi_message_add_tail(&t, &m);
- spi_sync(spi, &m);
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8510, &wm8510_dai, 1);
- return len;
+ return ret;
}
-#endif /* CONFIG_SPI_MASTER */
-static int wm8510_probe(struct platform_device *pdev)
+static int wm8510_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8510_setup_data *setup;
- struct snd_soc_codec *codec;
- int ret = 0;
-
- pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
+static const struct i2c_device_id wm8510_i2c_id[] = {
+ { "wm8510", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
- socdev->card->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
+static struct i2c_driver wm8510_i2c_driver = {
+ .driver = {
+ .name = "wm8510",
+ .owner = THIS_MODULE,
+ .of_match_table = wm8510_of_match,
+ },
+ .probe = wm8510_i2c_probe,
+ .remove = wm8510_i2c_remove,
+ .id_table = wm8510_i2c_id,
+};
+#endif
- wm8510_socdev = socdev;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = wm8510_add_i2c_device(pdev, setup);
+static int __init wm8510_modinit(void)
+{
+ int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+ ret = i2c_add_driver(&wm8510_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
+ ret);
}
#endif
#if defined(CONFIG_SPI_MASTER)
- if (setup->spi) {
- codec->hw_write = (hw_write_t)wm8510_spi_write;
- ret = spi_register_driver(&wm8510_spi_driver);
- if (ret != 0)
- printk(KERN_ERR "can't add spi driver");
+ ret = spi_register_driver(&wm8510_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8510 SPI driver: %d\n",
+ ret);
}
#endif
-
- if (ret != 0)
- kfree(codec);
return ret;
}
+module_init(wm8510_modinit);
-/* power down chip */
-static int wm8510_remove(struct platform_device *pdev)
+static void __exit wm8510_exit(void)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->card->codec;
-
- if (codec->control_data)
- wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8510_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
spi_unregister_driver(&wm8510_spi_driver);
#endif
- kfree(codec);
-
- return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8510 = {
- .probe = wm8510_probe,
- .remove = wm8510_remove,
- .suspend = wm8510_suspend,
- .resume = wm8510_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510);
-
-static int __init wm8510_modinit(void)
-{
- return snd_soc_register_dai(&wm8510_dai);
-}
-module_init(wm8510_modinit);
-
-static void __exit wm8510_exit(void)
-{
- snd_soc_unregister_dai(&wm8510_dai);
}
module_exit(wm8510_exit);