diff options
Diffstat (limited to 'sound/soc/soc-cache.c')
| -rw-r--r-- | sound/soc/soc-cache.c | 269 | 
1 files changed, 66 insertions, 203 deletions
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index e72f55428f0..00e70b6c7da 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -11,12 +11,9 @@   *  option) any later version.   */ -#include <linux/i2c.h> -#include <linux/spi/spi.h>  #include <sound/soc.h> -#include <linux/bitmap.h> -#include <linux/rbtree.h>  #include <linux/export.h> +#include <linux/slab.h>  #include <trace/events/asoc.h> @@ -39,7 +36,8 @@ static bool snd_soc_set_cache_val(void *base, unsigned int idx,  		break;  	}  	default: -		BUG(); +		WARN(1, "Invalid word_size %d\n", word_size); +		break;  	}  	return false;  } @@ -60,132 +58,51 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,  		return cache[idx];  	}  	default: -		BUG(); +		WARN(1, "Invalid word_size %d\n", word_size); +		break;  	}  	/* unreachable */  	return -1;  } -static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) +int snd_soc_cache_init(struct snd_soc_codec *codec)  { -	int i; -	int ret; -	const struct snd_soc_codec_driver *codec_drv; -	unsigned int val; - -	codec_drv = codec->driver; -	for (i = 0; i < codec_drv->reg_cache_size; ++i) { -		ret = snd_soc_cache_read(codec, i, &val); -		if (ret) -			return ret; -		if (codec->reg_def_copy) -			if (snd_soc_get_cache_val(codec->reg_def_copy, -						  i, codec_drv->reg_word_size) == val) -				continue; +	const struct snd_soc_codec_driver *codec_drv = codec->driver; +	size_t reg_size; -		WARN_ON(!snd_soc_codec_writable_register(codec, i)); +	reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; -		ret = snd_soc_write(codec, i, val); -		if (ret) -			return ret; -		dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", -			i, val); -	} -	return 0; -} - -static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, -				    unsigned int reg, unsigned int value) -{ -	snd_soc_set_cache_val(codec->reg_cache, reg, value, -			      codec->driver->reg_word_size); -	return 0; -} +	if (!reg_size) +		return 0; -static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, -				   unsigned int reg, unsigned int *value) -{ -	*value = snd_soc_get_cache_val(codec->reg_cache, reg, -				       codec->driver->reg_word_size); -	return 0; -} +	mutex_init(&codec->cache_rw_mutex); -static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec) -{ -	if (!codec->reg_cache) -		return 0; -	kfree(codec->reg_cache); -	codec->reg_cache = NULL; -	return 0; -} +	dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", +				codec->name); -static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) -{ -	if (codec->reg_def_copy) -		codec->reg_cache = kmemdup(codec->reg_def_copy, -					   codec->reg_size, GFP_KERNEL); +	if (codec_drv->reg_cache_default) +		codec->reg_cache = kmemdup(codec_drv->reg_cache_default, +					   reg_size, GFP_KERNEL);  	else -		codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL); +		codec->reg_cache = kzalloc(reg_size, GFP_KERNEL);  	if (!codec->reg_cache)  		return -ENOMEM;  	return 0;  } -/* an array of all supported compression types */ -static const struct snd_soc_cache_ops cache_types[] = { -	/* Flat *must* be the first entry for fallback */ -	{ -		.id = SND_SOC_FLAT_COMPRESSION, -		.name = "flat", -		.init = snd_soc_flat_cache_init, -		.exit = snd_soc_flat_cache_exit, -		.read = snd_soc_flat_cache_read, -		.write = snd_soc_flat_cache_write, -		.sync = snd_soc_flat_cache_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->compress_type) -			break; - -	/* Fall back to flat compression */ -	if (i == ARRAY_SIZE(cache_types)) { -		dev_warn(codec->dev, "ASoC: Could not match compress type: %d\n", -			 codec->compress_type); -		i = 0; -	} - -	mutex_init(&codec->cache_rw_mutex); -	codec->cache_ops = &cache_types[i]; - -	if (codec->cache_ops->init) { -		if (codec->cache_ops->name) -			dev_dbg(codec->dev, "ASoC: Initializing %s cache for %s codec\n", -				codec->cache_ops->name, codec->name); -		return codec->cache_ops->init(codec); -	} -	return -ENOSYS; -} -  /*   * NOTE: keep in mind that this function might be called   * multiple times.   */  int snd_soc_cache_exit(struct snd_soc_codec *codec)  { -	if (codec->cache_ops && codec->cache_ops->exit) { -		if (codec->cache_ops->name) -			dev_dbg(codec->dev, "ASoC: Destroying %s cache for %s codec\n", -				codec->cache_ops->name, codec->name); -		return codec->cache_ops->exit(codec); -	} -	return -ENOSYS; +	dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", +			codec->name); + +	kfree(codec->reg_cache); +	codec->reg_cache = NULL; +	return 0;  }  /** @@ -198,18 +115,16 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)  int snd_soc_cache_read(struct snd_soc_codec *codec,  		       unsigned int reg, unsigned int *value)  { -	int ret; +	if (!value) +		return -EINVAL;  	mutex_lock(&codec->cache_rw_mutex); - -	if (value && codec->cache_ops && codec->cache_ops->read) { -		ret = codec->cache_ops->read(codec, reg, value); -		mutex_unlock(&codec->cache_rw_mutex); -		return ret; -	} - +	if (!ZERO_OR_NULL_PTR(codec->reg_cache)) +		*value = snd_soc_get_cache_val(codec->reg_cache, reg, +					       codec->driver->reg_word_size);  	mutex_unlock(&codec->cache_rw_mutex); -	return -ENOSYS; + +	return 0;  }  EXPORT_SYMBOL_GPL(snd_soc_cache_read); @@ -223,20 +138,41 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_read);  int snd_soc_cache_write(struct snd_soc_codec *codec,  			unsigned int reg, unsigned int value)  { +	mutex_lock(&codec->cache_rw_mutex); +	if (!ZERO_OR_NULL_PTR(codec->reg_cache)) +		snd_soc_set_cache_val(codec->reg_cache, reg, value, +				      codec->driver->reg_word_size); +	mutex_unlock(&codec->cache_rw_mutex); + +	return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_cache_write); + +static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) +{ +	int i;  	int ret; +	const struct snd_soc_codec_driver *codec_drv; +	unsigned int val; -	mutex_lock(&codec->cache_rw_mutex); +	codec_drv = codec->driver; +	for (i = 0; i < codec_drv->reg_cache_size; ++i) { +		ret = snd_soc_cache_read(codec, i, &val); +		if (ret) +			return ret; +		if (codec_drv->reg_cache_default) +			if (snd_soc_get_cache_val(codec_drv->reg_cache_default, +						  i, codec_drv->reg_word_size) == val) +				continue; -	if (codec->cache_ops && codec->cache_ops->write) { -		ret = codec->cache_ops->write(codec, reg, value); -		mutex_unlock(&codec->cache_rw_mutex); -		return ret; +		ret = snd_soc_write(codec, i, val); +		if (ret) +			return ret; +		dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", +			i, val);  	} - -	mutex_unlock(&codec->cache_rw_mutex); -	return -ENOSYS; +	return 0;  } -EXPORT_SYMBOL_GPL(snd_soc_cache_write);  /**   * snd_soc_cache_sync: Sync the register cache with the hardware. @@ -249,92 +185,19 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_write);   */  int snd_soc_cache_sync(struct snd_soc_codec *codec)  { +	const char *name = "flat";  	int ret; -	const char *name; -	if (!codec->cache_sync) { +	if (!codec->cache_sync)  		return 0; -	} - -	if (!codec->cache_ops || !codec->cache_ops->sync) -		return -ENOSYS; - -	if (codec->cache_ops->name) -		name = codec->cache_ops->name; -	else -		name = "unknown"; -	if (codec->cache_ops->name) -		dev_dbg(codec->dev, "ASoC: Syncing %s cache for %s codec\n", -			codec->cache_ops->name, codec->name); +	dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n", +		codec->name);  	trace_snd_soc_cache_sync(codec, name, "start"); -	ret = codec->cache_ops->sync(codec); +	ret = snd_soc_flat_cache_sync(codec);  	if (!ret)  		codec->cache_sync = 0;  	trace_snd_soc_cache_sync(codec, name, "end");  	return ret;  }  EXPORT_SYMBOL_GPL(snd_soc_cache_sync); - -static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec, -					unsigned int reg) -{ -	const struct snd_soc_codec_driver *codec_drv; -	unsigned int min, max, index; - -	codec_drv = codec->driver; -	min = 0; -	max = codec_drv->reg_access_size - 1; -	do { -		index = (min + max) / 2; -		if (codec_drv->reg_access_default[index].reg == reg) -			return index; -		if (codec_drv->reg_access_default[index].reg < reg) -			min = index + 1; -		else -			max = index; -	} while (min <= max); -	return -1; -} - -int snd_soc_default_volatile_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].vol; -} -EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register); - -int snd_soc_default_readable_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].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);  | 
