Commit ee60d015 authored by Mark Brown's avatar Mark Brown

ASoC: Convert wm8978 to direct regmap API usage

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: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent f98692ea
......@@ -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>
......@@ -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;
......@@ -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;
}
......@@ -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);
......@@ -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;
......@@ -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),
......@@ -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)
{
......@@ -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,
......@@ -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;
}
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment