diff options
Diffstat (limited to 'sound/soc/soc-cache.c')
| -rw-r--r-- | sound/soc/soc-cache.c | 213 | 
1 files changed, 210 insertions, 3 deletions
| diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index d2505e8b06c9..5869dc3be781 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -15,6 +15,74 @@  #include <linux/spi/spi.h>  #include <sound/soc.h> +static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, +				     unsigned int reg) +{ +	u16 *cache = codec->reg_cache; +	if (reg >= codec->reg_cache_size) +		return -1; +	return cache[reg]; +} + +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; + +	BUG_ON(codec->volatile_register); + +	data[0] = (reg << 4) | ((value >> 8) & 0x000f); +	data[1] = value & 0x00ff; + +	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, 2); +	if (ret == 2) +		return 0; +	if (ret < 0) +		return ret; +	else +		return -EIO; +} + +#if defined(CONFIG_SPI_MASTER) +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; +} +#else +#define snd_soc_4_12_spi_write NULL +#endif +  static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,  				     unsigned int reg)  { @@ -38,6 +106,12 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,  	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, 2);  	if (ret == 2)  		return 0; @@ -91,6 +165,11 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,  	if (reg < codec->reg_cache_size)  		cache[reg] = value; +	if (codec->cache_only) { +		codec->cache_sync = 1; +		return 0; +	} +  	if (codec->hw_write(codec->control_data, data, 2) == 2)  		return 0;  	else @@ -119,6 +198,11 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,  	if (!snd_soc_codec_volatile_register(codec, reg))  		reg_cache[reg] = value; +	if (codec->cache_only) { +		codec->cache_sync = 1; +		return 0; +	} +  	if (codec->hw_write(codec->control_data, data, 3) == 3)  		return 0;  	else @@ -131,10 +215,14 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,  	u16 *cache = codec->reg_cache;  	if (reg >= codec->reg_cache_size || -	    snd_soc_codec_volatile_register(codec, reg)) +	    snd_soc_codec_volatile_register(codec, reg)) { +		if (codec->cache_only) +			return -EINVAL; +  		return codec->hw_read(codec, reg); -	else +	} else {  		return cache[reg]; +	}  }  #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) @@ -171,6 +259,114 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,  #define snd_soc_8_16_read_i2c NULL  #endif +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +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); +		return 0; +	} + +	return data; +} +#else +#define snd_soc_16_8_read_i2c NULL +#endif + +static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, +				     unsigned int reg) +{ +	u16 *cache = codec->reg_cache; + +	reg &= 0xff; +	if (reg >= codec->reg_cache_size) +		return -1; +	return cache[reg]; +} + +static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, +			     unsigned int value) +{ +	u16 *cache = codec->reg_cache; +	u8 data[3]; +	int ret; + +	BUG_ON(codec->volatile_register); + +	data[0] = (reg >> 8) & 0xff; +	data[1] = reg & 0xff; +	data[2] = value; + +	reg &= 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, 3); +	if (ret == 3) +		return 0; +	if (ret < 0) +		return ret; +	else +		return -EIO; +} + +#if defined(CONFIG_SPI_MASTER) +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; +} +#else +#define snd_soc_16_8_spi_write NULL +#endif + +  static struct {  	int addr_bits;  	int data_bits; @@ -180,9 +376,14 @@ static struct {  	unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);  } io_types[] = {  	{ +		.addr_bits = 4, .data_bits = 12, +		.write = snd_soc_4_12_write, .read = snd_soc_4_12_read, +		.spi_write = snd_soc_4_12_spi_write, +	}, +	{  		.addr_bits = 7, .data_bits = 9,  		.write = snd_soc_7_9_write, .read = snd_soc_7_9_read, -		.spi_write = snd_soc_7_9_spi_write  +		.spi_write = snd_soc_7_9_spi_write,  	},  	{  		.addr_bits = 8, .data_bits = 8, @@ -193,6 +394,12 @@ static struct {  		.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,  		.i2c_read = snd_soc_8_16_read_i2c,  	}, +	{ +		.addr_bits = 16, .data_bits = 8, +		.write = snd_soc_16_8_write, .read = snd_soc_16_8_read, +		.i2c_read = snd_soc_16_8_read_i2c, +		.spi_write = snd_soc_16_8_spi_write, +	},  };  /** | 
