diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-03-05 16:27:15 +0000 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-03-05 16:42:06 +0000 |
commit | bc6552f4717e07e7737b5dc17883c2ff99f2a315 (patch) | |
tree | 73bb1869ab320aba08f63d27760dd6231c709f8e /sound | |
parent | 1ca7578043a79d74152774acee0ed6e393134d12 (diff) | |
download | linux-3.10-bc6552f4717e07e7737b5dc17883c2ff99f2a315.tar.gz linux-3.10-bc6552f4717e07e7737b5dc17883c2ff99f2a315.tar.bz2 linux-3.10-bc6552f4717e07e7737b5dc17883c2ff99f2a315.zip |
ASoC: Add 16/16 registers to soc-cache
I2C only at the minute.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/soc-cache.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 5869dc3be78..bf593a834f5 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -366,6 +366,84 @@ static int snd_soc_16_8_spi_write(void *control_data, const char *data, #define snd_soc_16_8_spi_write NULL #endif +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +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); + return 0; + } + + return be16_to_cpu(data); +} +#else +#define snd_soc_16_16_read_i2c NULL +#endif + +static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + + if (reg >= codec->reg_cache_size || + snd_soc_codec_volatile_register(codec, reg)) { + if (codec->cache_only) + return -EINVAL; + + return codec->hw_read(codec, reg); + } + + return cache[reg]; +} + +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; + + data[0] = (reg >> 8) & 0xff; + data[1] = reg & 0xff; + data[2] = (value >> 8) & 0xff; + data[3] = value & 0xff; + + if (reg < codec->reg_cache_size) + cache[reg] = value; + + 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; +} static struct { int addr_bits; @@ -400,6 +478,11 @@ static struct { .i2c_read = snd_soc_16_8_read_i2c, .spi_write = snd_soc_16_8_spi_write, }, + { + .addr_bits = 16, .data_bits = 16, + .write = snd_soc_16_16_write, .read = snd_soc_16_16_read, + .i2c_read = snd_soc_16_16_read_i2c, + }, }; /** |