Skip to content

Commit

Permalink
ASoC: Convert wm8978 to direct regmap API usage
Browse files Browse the repository at this point in the history
Helps push the register cache code down out of ASoC and improves resume
times by using the more efficient regmap cache sync code.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
  • Loading branch information
Mark Brown committed Jan 20, 2012
1 parent f98692e commit ee60d01
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 22 deletions.
116 changes: 94 additions & 22 deletions sound/soc/codecs/wm8978.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
Expand All @@ -29,27 +30,74 @@

#include "wm8978.h"

/* wm8978 register cache. Note that register 0 is not included in the cache. */
static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */
0x0050, 0x0000, 0x0140, 0x0000, /* 0x04...0x07 */
0x0000, 0x0000, 0x0000, 0x00ff, /* 0x08...0x0b */
0x00ff, 0x0000, 0x0100, 0x00ff, /* 0x0c...0x0f */
0x00ff, 0x0000, 0x012c, 0x002c, /* 0x10...0x13 */
0x002c, 0x002c, 0x002c, 0x0000, /* 0x14...0x17 */
0x0032, 0x0000, 0x0000, 0x0000, /* 0x18...0x1b */
0x0000, 0x0000, 0x0000, 0x0000, /* 0x1c...0x1f */
0x0038, 0x000b, 0x0032, 0x0000, /* 0x20...0x23 */
0x0008, 0x000c, 0x0093, 0x00e9, /* 0x24...0x27 */
0x0000, 0x0000, 0x0000, 0x0000, /* 0x28...0x2b */
0x0033, 0x0010, 0x0010, 0x0100, /* 0x2c...0x2f */
0x0100, 0x0002, 0x0001, 0x0001, /* 0x30...0x33 */
0x0039, 0x0039, 0x0039, 0x0039, /* 0x34...0x37 */
0x0001, 0x0001, /* 0x38...0x3b */
static const struct reg_default wm8978_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, 0x00ff },
{ 13, 0x0000 },
{ 14, 0x0100 },
{ 15, 0x00ff },
{ 16, 0x00ff },
{ 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, 0x0033 },
{ 45, 0x0010 },
{ 46, 0x0010 },
{ 47, 0x0100 },
{ 48, 0x0100 },
{ 49, 0x0002 },
{ 50, 0x0001 },
{ 51, 0x0001 },
{ 52, 0x0039 },
{ 53, 0x0039 },
{ 54, 0x0039 },
{ 55, 0x0039 },
{ 56, 0x0001 },
{ 57, 0x0001 },
};

static bool wm8978_volatile(struct device *dev, unsigned int reg)
{
return reg == WM8978_RESET;
}

/* codec private data */
struct wm8978_priv {
struct regmap *regmap;
unsigned int f_pllout;
unsigned int f_mclk;
unsigned int f_256fs;
Expand Down Expand Up @@ -881,10 +929,14 @@ static struct snd_soc_dai_driver wm8978_dai = {

static int wm8978_suspend(struct snd_soc_codec *codec)
{
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);

wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
/* Also switch PLL off */
snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);

regcache_mark_dirty(wm8978->regmap);

return 0;
}

Expand All @@ -893,7 +945,7 @@ static int wm8978_resume(struct snd_soc_codec *codec)
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);

/* Sync reg_cache with the hardware */
snd_soc_cache_sync(codec);
regcache_sync(wm8978->regmap);

wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

Expand Down Expand Up @@ -933,7 +985,8 @@ static int wm8978_probe(struct snd_soc_codec *codec)
* default hardware setting
*/
wm8978->sysclk = WM8978_PLL;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
codec->control_data = wm8978->regmap;
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;
Expand Down Expand Up @@ -972,9 +1025,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
.suspend = wm8978_suspend,
.resume = wm8978_resume,
.set_bias_level = wm8978_set_bias_level,
.reg_cache_size = ARRAY_SIZE(wm8978_reg),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8978_reg,

.controls = wm8978_snd_controls,
.num_controls = ARRAY_SIZE(wm8978_snd_controls),
Expand All @@ -984,6 +1034,18 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
.num_dapm_routes = ARRAY_SIZE(wm8978_dapm_routes),
};

static const struct regmap_config wm8978_regmap_config = {
.reg_bits = 7,
.val_bits = 9,

.max_register = WM8978_MAX_REGISTER,
.volatile_reg = wm8978_volatile,

.cache_type = REGCACHE_RBTREE,
.reg_defaults = wm8978_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults),
};

static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
Expand All @@ -995,6 +1057,13 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
if (wm8978 == NULL)
return -ENOMEM;

wm8978->regmap = regmap_init_i2c(i2c, &wm8978_regmap_config);
if (IS_ERR(wm8978->regmap)) {
ret = PTR_ERR(wm8978->regmap);
dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
return ret;
}

i2c_set_clientdata(i2c, wm8978);

ret = snd_soc_register_codec(&i2c->dev,
Expand All @@ -1005,7 +1074,10 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,

static __devexit int wm8978_i2c_remove(struct i2c_client *client)
{
struct wm8978_priv *wm8978 = i2c_get_clientdata(client);

snd_soc_unregister_codec(&client->dev);
regmap_exit(wm8978->regmap);

return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/codecs/wm8978.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
#define WM8978_OUT3_MIXER_CONTROL 0x38
#define WM8978_OUT4_MIXER_CONTROL 0x39

#define WM8978_MAX_REGISTER 0x39

#define WM8978_CACHEREGNUM 58

/* Clock divider Id's */
Expand Down

0 comments on commit ee60d01

Please sign in to comment.