diff options
Diffstat (limited to 'sound/soc/soc-cache.c')
| -rw-r--r-- | sound/soc/soc-cache.c | 612 | 
1 files changed, 148 insertions, 464 deletions
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 5d76da43b14..06b7b81a160 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -20,40 +20,28 @@  #include <trace/events/asoc.h> -static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, -				     unsigned int reg) +#ifdef CONFIG_SPI_MASTER +static int do_spi_write(void *control, const char *data, int len)  { +	struct spi_device *spi = control;  	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); +	ret = spi_write(spi, data, len);  	if (ret < 0) -		return -1; -	return val; +		return ret; + +	return len;  } +#endif -static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, -			     unsigned int value) +static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, +		       unsigned int value, const void *data, int len)  { -	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) { +	    reg < codec->driver->reg_cache_size && +	    !codec->cache_bypass) {  		ret = snd_soc_cache_write(codec, reg, value);  		if (ret < 0)  			return -1; @@ -64,8 +52,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,  		return 0;  	} -	ret = codec->hw_write(codec->control_data, data, 2); -	if (ret == 2) +	ret = codec->hw_write(codec->control_data, data, len); +	if (ret == len)  		return 0;  	if (ret < 0)  		return ret; @@ -73,50 +61,19 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,  		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) +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); @@ -125,259 +82,117 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,  	return val;  } -static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, -			     unsigned int value) +static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, +				      unsigned int reg)  { -	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_read(codec, reg);  } -#if defined(CONFIG_SPI_MASTER) -static int snd_soc_7_9_spi_write(void *control_data, const char *data, -				 int len) +static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, +			      unsigned int value)  { -	struct spi_device *spi = control_data; -	struct spi_transfer t; -	struct spi_message m; -	u8 msg[2]; +	u16 data; -	if (len <= 0) -		return 0; +	data = cpu_to_be16((reg << 12) | (value & 0xffffff)); -	msg[0] = data[0]; -	msg[1] = data[1]; +	return do_hw_write(codec, reg, value, &data, 2); +} -	spi_message_init(&m); -	memset(&t, 0, sizeof t); +static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, +				     unsigned int reg) +{ +	return do_hw_read(codec, reg); +} -	t.tx_buf = &msg[0]; -	t.len = len; +static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, +			     unsigned int value) +{ +	u8 data[2]; -	spi_message_add_tail(&t, &m); -	spi_sync(spi, &m); +	data[0] = (reg << 1) | ((value >> 8) & 0x0001); +	data[1] = value & 0x00ff; -	return len; +	return do_hw_write(codec, reg, value, data, 2);  } -#else -#define snd_soc_7_9_spi_write NULL -#endif  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,  				     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; -} - -#if defined(CONFIG_SPI_MASTER) -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_hw_read(codec, reg);  } -#else -#define snd_soc_8_8_spi_write NULL -#endif  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,  				      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; -} - -#if defined(CONFIG_SPI_MASTER) -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_hw_read(codec, reg);  } -#else -#define snd_soc_8_16_spi_write NULL -#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); +	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 @@ -388,30 +203,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 @@ -422,30 +220,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 @@ -453,120 +234,34 @@ 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)  { -	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, -			     unsigned int value) +			      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; -} - -#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; +	return do_hw_write(codec, reg, value, data, 3);  } -#else -#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); +	ret = do_i2c_read(codec, ®, 2, &data, 2); +	if (ret < 0)  		return 0; -	} -  	return be16_to_cpu(data);  }  #else @@ -576,52 +271,59 @@ 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,  			       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; -	} +	return do_hw_write(codec, reg, value, data, 4); +} -	if (codec->cache_only) { -		codec->cache_sync = 1; -		return 0; +/* 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; + +	/* To ensure that we don't get out of sync with the cache, check +	 * whether the base register is volatile or if we've directly asked +	 * to bypass the cache.  Out of bounds registers are considered +	 * volatile. +	 */ +	if (!codec->cache_bypass +	    && !snd_soc_codec_volatile_register(codec, reg) +	    && reg < codec->driver->reg_cache_size) +		return -EINVAL; + +	switch (codec->control_type) { +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +	case SND_SOC_I2C: +		ret = i2c_master_send(codec->control_data, data, len); +		break; +#endif +#if defined(CONFIG_SPI_MASTER) +	case SND_SOC_SPI: +		ret = spi_write(codec->control_data, data, len); +		break; +#endif +	default: +		BUG();  	} -	ret = codec->hw_write(codec->control_data, data, 4); -	if (ret == 4) +	if (ret == len)  		return 0;  	if (ret < 0)  		return ret; @@ -629,79 +331,40 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,  		return -EIO;  } -#if defined(CONFIG_SPI_MASTER) -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; -} -#else -#define snd_soc_16_16_spi_write NULL -#endif -  static struct {  	int addr_bits;  	int data_bits;  	int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); -	int (*spi_write)(void *, const char *, int);  	unsigned int (*read)(struct snd_soc_codec *, unsigned int);  	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,  	},  	{  		.addr_bits = 8, .data_bits = 8,  		.write = snd_soc_8_8_write, .read = snd_soc_8_8_read,  		.i2c_read = snd_soc_8_8_read_i2c, -		.spi_write = snd_soc_8_8_spi_write,  	},  	{  		.addr_bits = 8, .data_bits = 16,  		.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,  		.i2c_read = snd_soc_8_16_read_i2c, -		.spi_write = snd_soc_8_16_spi_write,  	},  	{  		.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,  	},  	{  		.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, -		.spi_write = snd_soc_16_16_spi_write,  	},  }; @@ -709,7 +372,6 @@ static struct {   * snd_soc_codec_set_cache_io: Set up standard I/O functions.   *   * @codec: CODEC to configure. - * @type: Type of cache.   * @addr_bits: Number of bits of register address data.   * @data_bits: Number of bits of data per register.   * @control: Control bus used. @@ -744,6 +406,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: @@ -762,8 +425,9 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,  		break;  	case SND_SOC_SPI: -		if (io_types[i].spi_write) -			codec->hw_write = io_types[i].spi_write; +#ifdef CONFIG_SPI_MASTER +		codec->hw_write = do_spi_write; +#endif  		codec->control_data = container_of(codec->dev,  						   struct spi_device, @@ -889,6 +553,8 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)  		rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);  		if (rbnode->value == rbnode->defval)  			continue; +		WARN_ON(codec->writable_register && +			codec->writable_register(codec, rbnode->reg));  		ret = snd_soc_cache_read(codec, rbnode->reg, &val);  		if (ret)  			return ret; @@ -1149,6 +815,8 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)  	lzo_blocks = codec->reg_cache;  	for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) { +		WARN_ON(codec->writable_register && +			codec->writable_register(codec, i));  		ret = snd_soc_cache_read(codec, i, &val);  		if (ret)  			return ret; @@ -1407,6 +1075,8 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)  	codec_drv = codec->driver;  	for (i = 0; i < codec_drv->reg_cache_size; ++i) { +		WARN_ON(codec->writable_register && +			codec->writable_register(codec, i));  		ret = snd_soc_cache_read(codec, i, &val);  		if (ret)  			return ret; @@ -1523,7 +1193,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec)  				codec->cache_ops->name, codec->name);  		return codec->cache_ops->init(codec);  	} -	return -EINVAL; +	return -ENOSYS;  }  /* @@ -1538,7 +1208,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)  				codec->cache_ops->name, codec->name);  		return codec->cache_ops->exit(codec);  	} -	return -EINVAL; +	return -ENOSYS;  }  /** @@ -1562,7 +1232,7 @@ int snd_soc_cache_read(struct snd_soc_codec *codec,  	}  	mutex_unlock(&codec->cache_rw_mutex); -	return -EINVAL; +	return -ENOSYS;  }  EXPORT_SYMBOL_GPL(snd_soc_cache_read); @@ -1587,7 +1257,7 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,  	}  	mutex_unlock(&codec->cache_rw_mutex); -	return -EINVAL; +	return -ENOSYS;  }  EXPORT_SYMBOL_GPL(snd_soc_cache_write); @@ -1610,7 +1280,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec)  	}  	if (!codec->cache_ops || !codec->cache_ops->sync) -		return -EINVAL; +		return -ENOSYS;  	if (codec->cache_ops->name)  		name = codec->cache_ops->name; @@ -1677,3 +1347,17 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec,  	return codec->driver->reg_access_default[index].read;  }  EXPORT_SYMBOL_GPL(snd_soc_default_readable_register); + +int snd_soc_default_writable_register(struct snd_soc_codec *codec, +				      unsigned int reg) +{ +	int index; + +	if (reg >= codec->driver->reg_cache_size) +		return 1; +	index = snd_soc_get_reg_access_index(codec, reg); +	if (index < 0) +		return 0; +	return codec->driver->reg_access_default[index].write; +} +EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);  |