[alsa-devel] [PATCH 1/7] ASoC: Add control_type in snd_soc_codec
This is mainly used by the soc-cache code to easily determine the currently used underlying serial bus. Set SND_SOC_CUSTOM to 1 so we can distinguish it if it is not initialized or set.
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com --- include/sound/soc.h | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index bfa4836..abb56ef 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -248,7 +248,7 @@ typedef int (*hw_write_t)(void *,const char* ,int); extern struct snd_ac97_bus_ops soc_ac97_ops;
enum snd_soc_control_type { - SND_SOC_CUSTOM, + SND_SOC_CUSTOM = 1, SND_SOC_I2C, SND_SOC_SPI, }; @@ -539,6 +539,7 @@ struct snd_soc_codec {
/* codec IO */ void *control_data; /* codec control (i2c/3wire) data */ + enum snd_soc_control_type control_type; hw_write_t hw_write; unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); unsigned int (*read)(struct snd_soc_codec *, unsigned int);
The handling of all snd_soc_x_y_write() functions is similar. Factor it out into a separate function and update all functions to use it.
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com --- sound/soc/soc-cache.c | 153 +++++++++++-------------------------------------- 1 files changed, 33 insertions(+), 120 deletions(-)
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 5d76da4..e1ea456 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -20,6 +20,33 @@
#include <trace/events/asoc.h>
+static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value, const void *data, int len) +{ + int ret; + + if (!snd_soc_codec_volatile_register(codec, reg) && + reg < codec->driver->reg_cache_size && + !codec->cache_bypass) { + ret = snd_soc_cache_write(codec, reg, value); + if (ret < 0) + return -1; + } + + if (codec->cache_only) { + codec->cache_sync = 1; + return 0; + } + + ret = codec->hw_write(codec->control_data, data, len); + if (ret == len) + return 0; + if (ret < 0) + return ret; + else + return -EIO; +} + static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, unsigned int reg) { @@ -46,31 +73,11 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[2]; - int ret;
data[0] = (reg << 4) | ((value >> 8) & 0x000f); data[1] = value & 0x00ff;
- if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - ret = codec->hw_write(codec->control_data, data, 2); - if (ret == 2) - return 0; - if (ret < 0) - return ret; - else - return -EIO; + return do_hw_write(codec, reg, value, data, 2); }
#if defined(CONFIG_SPI_MASTER) @@ -129,31 +136,11 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[2]; - int ret;
data[0] = (reg << 1) | ((value >> 8) & 0x0001); data[1] = value & 0x00ff;
- if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - ret = codec->hw_write(codec->control_data, data, 2); - if (ret == 2) - return 0; - if (ret < 0) - return ret; - else - return -EIO; + return do_hw_write(codec, reg, value, data, 2); }
#if defined(CONFIG_SPI_MASTER) @@ -190,29 +177,12 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { 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 && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; + return do_hw_write(codec, reg, value, data, 2); }
static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, @@ -272,29 +242,12 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { 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 && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - if (codec->hw_write(codec->control_data, data, 3) == 3) - return 0; - else - return -EIO; + return do_hw_write(codec, reg, value, data, 3); }
static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, @@ -479,33 +432,13 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[3]; - int ret;
data[0] = (reg >> 8) & 0xff; data[1] = reg & 0xff; data[2] = value; - reg &= 0xff; - if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - }
- ret = codec->hw_write(codec->control_data, data, 3); - if (ret == 3) - return 0; - if (ret < 0) - return ret; - else - return -EIO; + return do_hw_write(codec, reg, value, data, 3); }
#if defined(CONFIG_SPI_MASTER) @@ -600,33 +533,13 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[4]; - int ret;
data[0] = (reg >> 8) & 0xff; data[1] = reg & 0xff; data[2] = (value >> 8) & 0xff; data[3] = value & 0xff;
- if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - ret = codec->hw_write(codec->control_data, data, 4); - if (ret == 4) - return 0; - if (ret < 0) - return ret; - else - return -EIO; + return do_hw_write(codec, reg, value, data, 4); }
#if defined(CONFIG_SPI_MASTER)
The handling of all snd_soc_x_y_read() functions is similar. Factor it out into a separate function and update all callers.
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com --- sound/soc/soc-cache.c | 114 ++++++++----------------------------------------- 1 files changed, 18 insertions(+), 96 deletions(-)
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index e1ea456..874e435 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -47,20 +47,19 @@ static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, return -EIO; }
-static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, - unsigned int reg) +static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg) { int ret; unsigned int val;
if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; + snd_soc_codec_volatile_register(codec, reg) || + codec->cache_bypass) { + if (codec->cache_only) + return -1;
- BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); + BUG_ON(!codec->hw_read); + return codec->hw_read(codec, reg); }
ret = snd_soc_cache_read(codec, reg, &val); @@ -69,6 +68,12 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, return val; }
+static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + return do_hw_read(codec, reg); +} + static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -113,23 +118,7 @@ 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) { - int ret; - unsigned int val; - - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - return val; + return do_hw_read(codec, reg); }
static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, @@ -188,24 +177,7 @@ 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) { - int ret; - unsigned int val; - - reg &= 0xff; - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - return val; + return do_hw_read(codec, reg); }
#if defined(CONFIG_SPI_MASTER) @@ -253,23 +225,7 @@ 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) { - int ret; - unsigned int val; - - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - return val; + return do_hw_read(codec, reg); }
#if defined(CONFIG_SPI_MASTER) @@ -408,24 +364,7 @@ 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) { - int ret; - unsigned int val; - - reg &= 0xff; - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - return val; + return do_hw_read(codec, reg); }
static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, @@ -509,24 +448,7 @@ 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) { - int ret; - unsigned int val; - - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - - return val; + return do_hw_read(codec, reg); }
static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
The handling of all snd_soc_x_y_spi_write() functions is similar. Create a separate function and update all callers to use it.
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com --- sound/soc/soc-cache.c | 126 ++++++++++++------------------------------------- 1 files changed, 30 insertions(+), 96 deletions(-)
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 874e435..e242ff7 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -20,6 +20,30 @@
#include <trace/events/asoc.h>
+#if defined(CONFIG_SPI_MASTER) +static int do_spi_write(void *control_data, const void *msg, + int len) +{ + struct spi_device *spi = control_data; + struct spi_transfer t; + struct spi_message m; + + if (len <= 0) + return 0; + + spi_message_init(&m); + memset(&t, 0, sizeof t); + + t.tx_buf = msg; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} +#endif + static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value, const void *data, int len) { @@ -89,27 +113,12 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, static int snd_soc_4_12_spi_write(void *control_data, const char *data, int len) { - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; u8 msg[2];
- if (len <= 0) - return 0; - msg[0] = data[1]; msg[1] = data[0];
- spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return do_spi_write(control_data, msg, len); } #else #define snd_soc_4_12_spi_write NULL @@ -136,27 +145,12 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, static int snd_soc_7_9_spi_write(void *control_data, const char *data, int len) { - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; u8 msg[2];
- if (len <= 0) - return 0; - msg[0] = data[0]; msg[1] = data[1];
- spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return do_spi_write(control_data, msg, len); } #else #define snd_soc_7_9_spi_write NULL @@ -184,27 +178,12 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, static int snd_soc_8_8_spi_write(void *control_data, const char *data, int len) { - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; u8 msg[2];
- if (len <= 0) - return 0; - msg[0] = data[0]; msg[1] = data[1];
- spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return do_spi_write(control_data, msg, len); } #else #define snd_soc_8_8_spi_write NULL @@ -232,28 +211,13 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, static int snd_soc_8_16_spi_write(void *control_data, const char *data, int len) { - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; u8 msg[3];
- if (len <= 0) - return 0; - msg[0] = data[0]; msg[1] = data[1]; msg[2] = data[2];
- spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return do_spi_write(control_data, msg, len); } #else #define snd_soc_8_16_spi_write NULL @@ -384,28 +348,13 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, static int snd_soc_16_8_spi_write(void *control_data, const char *data, int len) { - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; u8 msg[3];
- if (len <= 0) - return 0; - msg[0] = data[0]; msg[1] = data[1]; msg[2] = data[2];
- spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return do_spi_write(control_data, msg, len); } #else #define snd_soc_16_8_spi_write NULL @@ -468,29 +417,14 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, static int snd_soc_16_16_spi_write(void *control_data, const char *data, int len) { - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; u8 msg[4];
- if (len <= 0) - return 0; - msg[0] = data[0]; msg[1] = data[1]; msg[2] = data[2]; msg[3] = data[3];
- spi_message_init(&m); - memset(&t, 0, sizeof t); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return do_spi_write(control_data, msg, len); } #else #define snd_soc_16_16_spi_write NULL
The handling of all snd_soc_x_y_read_i2c() functions is similar. Make a generic I2C read function and update all callers to use it.
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com --- sound/soc/soc-cache.c | 100 ++++++++++++++++--------------------------------- 1 files changed, 32 insertions(+), 68 deletions(-)
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index e242ff7..4043a98 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -224,33 +224,48 @@ static int snd_soc_8_16_spi_write(void *control_data, const char *data, #endif
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, - unsigned int r) +static unsigned int do_i2c_read(struct snd_soc_codec *codec, + void *reg, int reglen, + void *data, int datalen) { struct i2c_msg xfer[2]; - u8 reg = r; - u8 data; int ret; struct i2c_client *client = codec->control_data;
/* Write register */ xfer[0].addr = client->addr; xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® + xfer[0].len = reglen; + xfer[0].buf = reg;
/* Read data */ xfer[1].addr = client->addr; xfer[1].flags = I2C_M_RD; - xfer[1].len = 1; - xfer[1].buf = &data; + xfer[1].len = datalen; + xfer[1].buf = data;
ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + if (ret == 2) return 0; - } + else if (ret < 0) + return ret; + else + return -EIO; +} +#endif
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, + unsigned int r) +{ + u8 reg = r; + u8 data; + int ret; + + ret = do_i2c_read(codec, ®, 1, &data, 1); + if (ret < 0) + return 0; return data; } #else @@ -261,30 +276,13 @@ static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, unsigned int r) { - struct i2c_msg xfer[2]; u8 reg = r; u16 data; int ret; - struct i2c_client *client = codec->control_data;
- /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + ret = do_i2c_read(codec, ®, 1, &data, 2); + if (ret < 0) return 0; - } - return (data >> 8) | ((data & 0xff) << 8); } #else @@ -295,30 +293,13 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, unsigned int r) { - struct i2c_msg xfer[2]; u16 reg = r; u8 data; int ret; - struct i2c_client *client = codec->control_data; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 2; - xfer[0].buf = (u8 *)® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 1; - xfer[1].buf = &data;
- ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + ret = do_i2c_read(codec, ®, 2, &data, 1); + if (ret < 0) return 0; - } - return data; } #else @@ -364,30 +345,13 @@ static int snd_soc_16_8_spi_write(void *control_data, const char *data, static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, unsigned int r) { - struct i2c_msg xfer[2]; u16 reg = cpu_to_be16(r); u16 data; int ret; - struct i2c_client *client = codec->control_data; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 2; - xfer[0].buf = (u8 *)®
- /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + ret = do_i2c_read(codec, ®, 2, &data, 2); + if (ret < 0) return 0; - } - return be16_to_cpu(data); } #else
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com --- sound/soc/soc-cache.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 4043a98..9ae0593 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -93,13 +93,13 @@ static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg) }
static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, - unsigned int reg) + unsigned int reg) { return do_hw_read(codec, reg); }
static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) + unsigned int value) { u8 data[2];
@@ -111,7 +111,7 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
#if defined(CONFIG_SPI_MASTER) static int snd_soc_4_12_spi_write(void *control_data, const char *data, - int len) + int len) { u8 msg[2];
@@ -209,7 +209,7 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
#if defined(CONFIG_SPI_MASTER) static int snd_soc_8_16_spi_write(void *control_data, const char *data, - int len) + int len) { u8 msg[3];
@@ -257,7 +257,7 @@ static unsigned int do_i2c_read(struct snd_soc_codec *codec,
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, - unsigned int r) + unsigned int r) { u8 reg = r; u8 data; @@ -307,13 +307,13 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, #endif
static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, - unsigned int reg) + unsigned int reg) { return do_hw_read(codec, reg); }
static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) + unsigned int value) { u8 data[3];
@@ -327,7 +327,7 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
#if defined(CONFIG_SPI_MASTER) static int snd_soc_16_8_spi_write(void *control_data, const char *data, - int len) + int len) { u8 msg[3];
@@ -379,7 +379,7 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
#if defined(CONFIG_SPI_MASTER) static int snd_soc_16_16_spi_write(void *control_data, const char *data, - int len) + int len) { u8 msg[4];
On Tue, Mar 22, 2011 at 10:37:02AM +0000, Dimitris Papastamos wrote:
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com
This doesn't apply, probably due to context changes. Applied all the rest.
As it has become more common to have to write firmware or similar large chunks of data to the hardware, add a function to perform raw bulk writes that bypass the cache. This only handles volatile registers as we should avoid getting out of sync with the actual cache.
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com --- include/sound/soc.h | 3 +++ sound/soc/soc-cache.c | 39 +++++++++++++++++++++++++++++++++++++++ sound/soc/soc-core.c | 7 +++++++ 3 files changed, 49 insertions(+), 0 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index abb56ef..4a11795 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -544,6 +544,7 @@ struct snd_soc_codec { unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); unsigned int (*read)(struct snd_soc_codec *, unsigned int); int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); + int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t); void *reg_cache; const void *reg_def_copy; const struct snd_soc_cache_ops *cache_ops; @@ -815,6 +816,8 @@ struct soc_enum { unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg); unsigned int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val); +unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, + unsigned int reg, const void *data, size_t len);
/* device driver data */
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 9ae0593..86beaad 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -394,6 +394,44 @@ static int snd_soc_16_16_spi_write(void *control_data, const char *data, #define snd_soc_16_16_spi_write NULL #endif
+/* Primitive bulk write support for soc-cache. The data pointed to by `data' needs + * to already be in the form the hardware expects including any leading register specific + * data. Any data written through this function will not go through the cache as it + * only handles writing to volatile or out of bounds registers. + */ +static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg, + const void *data, size_t len) +{ + int ret; + + /* Ensure that the base register is volatile. Subsequently + * any other register that is touched by this routine should be + * volatile as well to ensure that we don't get out of sync with + * the cache. + */ + if (!snd_soc_codec_volatile_register(codec, reg) + && reg < codec->driver->reg_cache_size) + return -EINVAL; + + switch (codec->control_type) { + case SND_SOC_I2C: + ret = i2c_master_send(codec->control_data, data, len); + break; + case SND_SOC_SPI: + ret = do_spi_write(codec->control_data, data, len); + break; + default: + BUG(); + } + + if (ret == len) + return 0; + if (ret < 0) + return ret; + else + return -EIO; +} + static struct { int addr_bits; int data_bits; @@ -477,6 +515,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
codec->write = io_types[i].write; codec->read = io_types[i].read; + codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
switch (control) { case SND_SOC_CUSTOM: diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4dda589..636328e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2228,6 +2228,13 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(snd_soc_write);
+unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec, + unsigned int reg, const void *data, size_t len) +{ + return codec->bulk_write_raw(codec, reg, data, len); +} +EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw); + /** * snd_soc_update_bits - update codec register bits * @codec: audio codec
On Tue, Mar 22, 2011 at 10:37:03AM +0000, Dimitris Papastamos wrote:
- switch (codec->control_type) {
- case SND_SOC_I2C:
ret = i2c_master_send(codec->control_data, data, len);
break;
- case SND_SOC_SPI:
ret = do_spi_write(codec->control_data, data, len);
break;
Hrm, I now realise that this doesn't actually do what I'd expect - it only writes out the provided data, there's no inclusion of the register address. I'd been mislead by the fact that it is taking in the register address as an argument and an overly hasty review it seems. That's a little too raw for me, we should be prefixing the data with the base register address.
On Tue, May 10, 2011 at 10:13:18PM +0100, Mark Brown wrote:
On Tue, Mar 22, 2011 at 10:37:03AM +0000, Dimitris Papastamos wrote:
- switch (codec->control_type) {
- case SND_SOC_I2C:
ret = i2c_master_send(codec->control_data, data, len);
break;
- case SND_SOC_SPI:
ret = do_spi_write(codec->control_data, data, len);
break;
Hrm, I now realise that this doesn't actually do what I'd expect - it only writes out the provided data, there's no inclusion of the register address. I'd been mislead by the fact that it is taking in the register address as an argument and an overly hasty review it seems. That's a little too raw for me, we should be prefixing the data with the base register address.
Yes, I was going to send a patch for this because I need it for syncing the block based rbtree cache.
On 22/03/11 10:36, Dimitris Papastamos wrote:
This is mainly used by the soc-cache code to easily determine the currently used underlying serial bus. Set SND_SOC_CUSTOM to 1 so we can distinguish it if it is not initialized or set.
Signed-off-by: Dimitris Papastamos dp@opensource.wolfsonmicro.com
All
Acked-by: Liam Girdwood lrg@ti.com
participants (3)
-
Dimitris Papastamos
-
Liam Girdwood
-
Mark Brown