From: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
To: Mark Brown <broonie@opensource.wolfsonmicro.com>,
Liam Girdwood <lrg@slimlogic.co.uk>
Cc: alsa-devel@alsa-project.org, patches@opensource.wolfsonmicro.com
Subject: [PATCH 2/4] ASoC: soc-cache: Add support for standard register caching
Date: Fri, 22 Oct 2010 15:28:20 +0100 [thread overview]
Message-ID: <1287757702-9573-3-git-send-email-dp@opensource.wolfsonmicro.com> (raw)
In-Reply-To: <1287757702-9573-1-git-send-email-dp@opensource.wolfsonmicro.com>
This patch adds support for normal caching (no compression). One
can still access codec->reg_cache directly but this is not advised
as that will not be portable across different caching strategies.
Signed-off-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
---
sound/soc/soc-cache.c | 267 +++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 236 insertions(+), 31 deletions(-)
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index d214f02..a8ec23a 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -18,7 +18,8 @@
static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- u16 *cache = codec->reg_cache;
+ int ret;
+ unsigned int val;
if (reg >= codec->driver->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg)) {
@@ -28,13 +29,15 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
return codec->hw_read(codec, reg);
}
- return cache[reg];
+ ret = snd_soc_cache_read(codec, reg, &val);
+ if (ret < 0)
+ return -1;
+ return val;
}
static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- u16 *cache = codec->reg_cache;
u8 data[2];
int ret;
@@ -42,8 +45,11 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
data[1] = value & 0x00ff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size)
- cache[reg] = value;
+ reg < codec->driver->reg_cache_size) {
+ ret = snd_soc_cache_write(codec, reg, value);
+ if (ret < 0)
+ return -1;
+ }
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -94,7 +100,8 @@ static int snd_soc_4_12_spi_write(void *control_data, const char *data,
static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- u16 *cache = codec->reg_cache;
+ int ret;
+ unsigned int val;
if (reg >= codec->driver->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg)) {
@@ -104,13 +111,15 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
return codec->hw_read(codec, reg);
}
- return cache[reg];
+ ret = snd_soc_cache_read(codec, reg, &val);
+ if (ret < 0)
+ return -1;
+ return val;
}
static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- u16 *cache = codec->reg_cache;
u8 data[2];
int ret;
@@ -118,8 +127,11 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
data[1] = value & 0x00ff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size)
- cache[reg] = value;
+ reg < codec->driver->reg_cache_size) {
+ ret = snd_soc_cache_write(codec, reg, value);
+ if (ret < 0)
+ return -1;
+ }
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -170,16 +182,19 @@ static int snd_soc_7_9_spi_write(void *control_data, const char *data,
static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- u8 *cache = codec->reg_cache;
u8 data[2];
+ int ret;
reg &= 0xff;
data[0] = reg;
data[1] = value & 0xff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size)
- cache[reg] = value;
+ reg < codec->driver->reg_cache_size) {
+ ret = snd_soc_cache_write(codec, reg, value);
+ if (ret < 0)
+ return -1;
+ }
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -197,7 +212,8 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- u8 *cache = codec->reg_cache;
+ int ret;
+ unsigned int val;
reg &= 0xff;
if (reg >= codec->driver->reg_cache_size ||
@@ -208,7 +224,10 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
return codec->hw_read(codec, reg);
}
- return cache[reg];
+ ret = snd_soc_cache_read(codec, reg, &val);
+ if (ret < 0)
+ return -1;
+ return val;
}
#if defined(CONFIG_SPI_MASTER)
@@ -244,16 +263,19 @@ static int snd_soc_8_8_spi_write(void *control_data, const char *data,
static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- u16 *reg_cache = codec->reg_cache;
u8 data[3];
+ int ret;
data[0] = reg;
data[1] = (value >> 8) & 0xff;
data[2] = value & 0xff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size)
- reg_cache[reg] = value;
+ reg < codec->driver->reg_cache_size) {
+ ret = snd_soc_cache_write(codec, reg, value);
+ if (ret < 0)
+ return -1;
+ }
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -271,7 +293,8 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- u16 *cache = codec->reg_cache;
+ int ret;
+ unsigned int val;
if (reg >= codec->driver->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg)) {
@@ -279,9 +302,12 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
return -1;
return codec->hw_read(codec, reg);
- } else {
- return cache[reg];
}
+
+ ret = snd_soc_cache_read(codec, reg, &val);
+ if (ret < 0)
+ return -1;
+ return val;
}
#if defined(CONFIG_SPI_MASTER)
@@ -420,7 +446,8 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- u8 *cache = codec->reg_cache;
+ int ret;
+ unsigned int val;
reg &= 0xff;
if (reg >= codec->driver->reg_cache_size ||
@@ -431,13 +458,15 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
return codec->hw_read(codec, reg);
}
- return cache[reg];
+ ret = snd_soc_cache_read(codec, reg, &val);
+ if (ret < 0)
+ return -1;
+ return val;
}
static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- u8 *cache = codec->reg_cache;
u8 data[3];
int ret;
@@ -447,8 +476,11 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
reg &= 0xff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size)
- cache[reg] = value;
+ reg < codec->driver->reg_cache_size) {
+ ret = snd_soc_cache_write(codec, reg, value);
+ if (ret < 0)
+ return -1;
+ }
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -534,7 +566,8 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- u16 *cache = codec->reg_cache;
+ int ret;
+ unsigned int val;
if (reg >= codec->driver->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg)) {
@@ -544,13 +577,16 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
return codec->hw_read(codec, reg);
}
- return cache[reg];
+ ret = snd_soc_cache_read(codec, reg, &val);
+ if (ret < 0)
+ return -1;
+
+ return val;
}
static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- u16 *cache = codec->reg_cache;
u8 data[4];
int ret;
@@ -560,8 +596,11 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
data[3] = value & 0xff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size)
- cache[reg] = value;
+ reg < codec->driver->reg_cache_size) {
+ ret = snd_soc_cache_write(codec, reg, value);
+ if (ret < 0)
+ return -1;
+ }
if (codec->cache_only) {
codec->cache_sync = 1;
@@ -724,3 +763,169 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
+
+static int snd_soc_cache_default_sync(struct snd_soc_codec *codec)
+{
+ const u8 *cache;
+ struct snd_soc_codec_driver *codec_drv;
+ unsigned int val;
+ int n;
+
+ codec_drv = codec->driver;
+ for (n = 0; n < codec_drv->reg_cache_size; ++n) {
+ snd_soc_cache_read(codec, n, &val);
+ if (codec_drv->reg_cache_default) {
+ cache = codec_drv->reg_cache_default;
+ cache += (n * codec_drv->reg_word_size);
+ if (!memcmp(&val, cache, codec_drv->reg_word_size))
+ continue;
+ }
+ snd_soc_write(codec, n, val);
+ }
+ return 0;
+}
+
+static int snd_soc_cache_default_write(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ u8 *cache;
+
+ cache = codec->reg_cache;
+ memcpy(&cache[reg * codec->driver->reg_word_size],
+ &value, codec->driver->reg_word_size);
+ return 0;
+}
+
+static int snd_soc_cache_default_read(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int *value)
+{
+ u8 *cache;
+
+ *value = 0;
+ cache = codec->reg_cache;
+ memcpy(value, &cache[reg * codec->driver->reg_word_size],
+ codec->driver->reg_word_size);
+ return 0;
+}
+
+static int snd_soc_cache_default_deinit(struct snd_soc_codec *codec)
+{
+ kfree(codec->reg_cache);
+ return 0;
+};
+
+static int snd_soc_cache_default_init(struct snd_soc_codec *codec)
+{
+ struct snd_soc_codec_driver *codec_drv;
+ size_t reg_size;
+
+ codec_drv = codec->driver;
+ reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+
+ if (codec_drv->reg_cache_default)
+ codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
+ reg_size, GFP_KERNEL);
+ else
+ codec->reg_cache = kzalloc(reg_size, GFP_KERNEL);
+ if (!codec->reg_cache)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* an array of all supported compression types */
+static const struct snd_soc_cache_ops cache_types[] = {
+ {
+ .id = SND_SOC_NO_COMPRESSION,
+ .init = snd_soc_cache_default_init,
+ .deinit = snd_soc_cache_default_deinit,
+ .read = snd_soc_cache_default_read,
+ .write = snd_soc_cache_default_write,
+ .sync = snd_soc_cache_default_sync
+ }
+};
+
+int snd_soc_cache_init(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
+ if (cache_types[i].id == codec->driver->compress_type)
+ break;
+ if (i == ARRAY_SIZE(cache_types)) {
+ dev_err(codec->dev, "Could not match compress type: %d\n",
+ codec->driver->compress_type);
+ return -EINVAL;
+ }
+
+ codec->cache_ops = &cache_types[i];
+
+ if (codec->cache_ops->init)
+ return codec->cache_ops->init(codec);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_cache_init);
+
+int snd_soc_cache_deinit(struct snd_soc_codec *codec)
+{
+ if (codec->cache_ops && codec->cache_ops->deinit)
+ return codec->cache_ops->deinit(codec);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_cache_deinit);
+
+/**
+ * snd_soc_cache_read: Fetch the value of a given register from the cache.
+ *
+ * @codec: CODEC to configure.
+ * @reg: The register index.
+ * @value: The value to be returned.
+ */
+int snd_soc_cache_read(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int *value)
+{
+ if (value && codec->cache_ops && codec->cache_ops->read)
+ return codec->cache_ops->read(codec, reg, value);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_cache_read);
+
+/**
+ * snd_soc_cache_write: Set the value of a given register in the cache.
+ *
+ * @codec: CODEC to configure.
+ * @reg: The register index.
+ * @value: The new register value.
+ */
+int snd_soc_cache_write(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ if (codec->cache_ops && codec->cache_ops->write)
+ return codec->cache_ops->write(codec, reg, value);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_cache_write);
+
+/**
+ * snd_soc_cache_sync: Sync the register cache with the hardware.
+ *
+ * @codec: CODEC to configure.
+ *
+ * Any registers that should not be synced should be marked as
+ * volatile.
+ */
+int snd_soc_cache_sync(struct snd_soc_codec *codec)
+{
+ int ret;
+
+ if (!codec->cache_sync)
+ return 0;
+ if (codec->cache_ops && codec->cache_ops->sync) {
+ ret = codec->cache_ops->sync(codec);
+ if (!ret)
+ codec->cache_sync = 0;
+ return ret;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
--
1.7.3.1
next prev parent reply other threads:[~2010-10-22 14:28 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-22 14:28 [PATCH 0/4] ASoC: Implement new caching API Dimitris Papastamos
2010-10-22 14:28 ` [PATCH 1/4] ASoC: soc.h: Add new caching API prototypes and hooks Dimitris Papastamos
2010-10-22 15:44 ` Mark Brown
2010-10-22 14:28 ` Dimitris Papastamos [this message]
2010-10-22 16:03 ` [PATCH 2/4] ASoC: soc-cache: Add support for standard register caching Mark Brown
2010-10-23 18:24 ` Dimitris Papastamos
2010-10-24 13:18 ` Timur Tabi
2010-10-24 21:35 ` Mark Brown
2010-10-25 8:09 ` Dimitris Papastamos
2010-10-22 14:28 ` [PATCH 3/4] ASoC: soc-core: Adapt soc-core to fit the new caching API Dimitris Papastamos
2010-10-22 14:28 ` [PATCH 4/4] ASoC: soc-cache: Add support for LZO based register caching Dimitris Papastamos
2010-10-22 16:18 ` Mark Brown
2010-10-23 18:28 ` Dimitris Papastamos
2010-10-25 18:13 ` Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1287757702-9573-3-git-send-email-dp@opensource.wolfsonmicro.com \
--to=dp@opensource.wolfsonmicro.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@opensource.wolfsonmicro.com \
--cc=lrg@slimlogic.co.uk \
--cc=patches@opensource.wolfsonmicro.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.