Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d6ee232c authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'asoc/topic/core' into asoc-next

parents 61805616 6833c452
Loading
Loading
Loading
Loading
+3 −57
Original line number Diff line number Diff line
@@ -331,7 +331,6 @@ struct soc_enum;
struct snd_soc_jack;
struct snd_soc_jack_zone;
struct snd_soc_jack_pin;
struct snd_soc_cache_ops;
#include <sound/soc-dapm.h>
#include <sound/soc-dpcm.h>

@@ -349,10 +348,6 @@ enum snd_soc_control_type {
	SND_SOC_REGMAP,
};

enum snd_soc_compress_type {
	SND_SOC_FLAT_COMPRESSION = 1,
};

enum snd_soc_pcm_subclass {
	SND_SOC_PCM_CLASS_PCM	= 0,
	SND_SOC_PCM_CLASS_BE	= 1,
@@ -404,12 +399,6 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
			unsigned int reg, unsigned int value);
int snd_soc_cache_read(struct snd_soc_codec *codec,
		       unsigned int reg, unsigned int *value);
int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
				      unsigned int reg);
int snd_soc_default_readable_register(struct snd_soc_codec *codec,
				      unsigned int reg);
int snd_soc_default_writable_register(struct snd_soc_codec *codec,
				      unsigned int reg);
int snd_soc_platform_read(struct snd_soc_platform *platform,
					unsigned int reg);
int snd_soc_platform_write(struct snd_soc_platform *platform,
@@ -542,22 +531,6 @@ int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol);

/**
 * struct snd_soc_reg_access - Describes whether a given register is
 * readable, writable or volatile.
 *
 * @reg: the register number
 * @read: whether this register is readable
 * @write: whether this register is writable
 * @vol: whether this register is volatile
 */
struct snd_soc_reg_access {
	u16 reg;
	u16 read;
	u16 write;
	u16 vol;
};

/**
 * struct snd_soc_jack_pin - Describes a pin to update based on jack detection
 *
@@ -658,19 +631,6 @@ struct snd_soc_compr_ops {
	int (*trigger)(struct snd_compr_stream *);
};

/* SoC cache ops */
struct snd_soc_cache_ops {
	const char *name;
	enum snd_soc_compress_type id;
	int (*init)(struct snd_soc_codec *codec);
	int (*exit)(struct snd_soc_codec *codec);
	int (*read)(struct snd_soc_codec *codec, unsigned int reg,
		unsigned int *value);
	int (*write)(struct snd_soc_codec *codec, unsigned int reg,
		unsigned int value);
	int (*sync)(struct snd_soc_codec *codec);
};

/* component interface */
struct snd_soc_component_driver {
	const char *name;
@@ -684,10 +644,12 @@ struct snd_soc_component_driver {
struct snd_soc_component {
	const char *name;
	int id;
	int num_dai;
	struct device *dev;
	struct list_head list;

	struct snd_soc_dai_driver *dai_drv;
	int num_dai;

	const struct snd_soc_component_driver *driver;
};

@@ -704,8 +666,6 @@ struct snd_soc_codec {
	struct list_head list;
	struct list_head card_list;
	int num_dai;
	enum snd_soc_compress_type compress_type;
	size_t reg_size;	/* reg_cache_size * reg_word_size */
	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
	int (*readable_register)(struct snd_soc_codec *, unsigned int);
	int (*writable_register)(struct snd_soc_codec *, unsigned int);
@@ -729,10 +689,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;
	struct mutex cache_rw_mutex;
	int val_bytes;

@@ -785,9 +742,6 @@ struct snd_soc_codec_driver {
	short reg_cache_step;
	short reg_word_size;
	const void *reg_cache_default;
	short reg_access_size;
	const struct snd_soc_reg_access *reg_access_default;
	enum snd_soc_compress_type compress_type;

	/* codec bias level */
	int (*set_bias_level)(struct snd_soc_codec *,
@@ -955,12 +909,6 @@ struct snd_soc_codec_conf {
	 * associated per device
	 */
	const char *name_prefix;

	/*
	 * set this to the desired compression type if you want to
	 * override the one supplied in codec->driver->compress_type
	 */
	enum snd_soc_compress_type compress_type;
};

struct snd_soc_aux_dev {
@@ -1132,8 +1080,6 @@ 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 */

+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ struct snd_soc_codec;
struct snd_soc_platform;
struct snd_soc_card;
struct snd_soc_dapm_widget;
struct snd_soc_dapm_path;

/*
 * Log register events
+61 −202
Original line number Diff line number Diff line
@@ -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>

@@ -66,126 +63,42 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
	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;

		WARN_ON(!snd_soc_codec_writable_register(codec, i));

		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;
}
	const struct snd_soc_codec_driver *codec_drv = codec->driver;
	size_t reg_size;

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;
}
	reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;

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);
	if (!codec->reg_cache)
		return 0;
	kfree(codec->reg_cache);
	codec->reg_cache = NULL;
	return 0;
}

/**
@@ -198,18 +111,15 @@ 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);
	*value = snd_soc_get_cache_val(codec->reg_cache, reg,
				       codec->driver->reg_word_size);
	mutex_unlock(&codec->cache_rw_mutex);
		return ret;
	}

	mutex_unlock(&codec->cache_rw_mutex);
	return -ENOSYS;
	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_cache_read);

@@ -223,20 +133,42 @@ 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);
	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);
		WARN_ON(!snd_soc_codec_writable_register(codec, i));

		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 +181,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);
+26 −67
Original line number Diff line number Diff line
@@ -1589,17 +1589,13 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
		soc_remove_codec(codec);
}

static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
				    enum snd_soc_compress_type compress_type)
static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
{
	int ret;

	if (codec->cache_init)
		return 0;

	/* override the compress_type if necessary */
	if (compress_type && codec->compress_type != compress_type)
		codec->compress_type = compress_type;
	ret = snd_soc_cache_init(codec);
	if (ret < 0) {
		dev_err(codec->dev,
@@ -1614,8 +1610,6 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
	struct snd_soc_codec *codec;
	struct snd_soc_codec_conf *codec_conf;
	enum snd_soc_compress_type compress_type;
	struct snd_soc_dai_link *dai_link;
	int ret, i, order, dai_fmt;

@@ -1639,19 +1633,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
	list_for_each_entry(codec, &codec_list, list) {
		if (codec->cache_init)
			continue;
		/* by default we don't override the compress_type */
		compress_type = 0;
		/* check to see if we need to override the compress_type */
		for (i = 0; i < card->num_configs; ++i) {
			codec_conf = &card->codec_conf[i];
			if (!strcmp(codec->name, codec_conf->dev_name)) {
				compress_type = codec_conf->compress_type;
				if (compress_type && compress_type
				    != codec->compress_type)
					break;
			}
		}
		ret = snd_soc_init_codec_cache(codec, compress_type);
		ret = snd_soc_init_codec_cache(codec);
		if (ret < 0)
			goto base_error;
	}
@@ -2297,13 +2279,6 @@ 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
@@ -4063,6 +4038,7 @@ __snd_soc_register_component(struct device *dev,

	cmpnt->dev	= dev;
	cmpnt->driver	= cmpnt_drv;
	cmpnt->dai_drv	= dai_drv;
	cmpnt->num_dai	= num_dai;

	/*
@@ -4287,7 +4263,6 @@ int snd_soc_register_codec(struct device *dev,
			   struct snd_soc_dai_driver *dai_drv,
			   int num_dai)
{
	size_t reg_size;
	struct snd_soc_codec *codec;
	int ret, i;

@@ -4304,11 +4279,6 @@ int snd_soc_register_codec(struct device *dev,
		goto fail_codec;
	}

	if (codec_drv->compress_type)
		codec->compress_type = codec_drv->compress_type;
	else
		codec->compress_type = SND_SOC_FLAT_COMPRESSION;

	codec->write = codec_drv->write;
	codec->read = codec_drv->read;
	codec->volatile_register = codec_drv->volatile_register;
@@ -4325,35 +4295,6 @@ int snd_soc_register_codec(struct device *dev,
	codec->num_dai = num_dai;
	mutex_init(&codec->mutex);

	/* allocate CODEC register cache */
	if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
		reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
		codec->reg_size = reg_size;
		/* it is necessary to make a copy of the default register cache
		 * because in the case of using a compression type that requires
		 * the default register cache to be marked as the
		 * kernel might have freed the array by the time we initialize
		 * the cache.
		 */
		if (codec_drv->reg_cache_default) {
			codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
						      reg_size, GFP_KERNEL);
			if (!codec->reg_def_copy) {
				ret = -ENOMEM;
				goto fail_codec_name;
			}
		}
	}

	if (codec_drv->reg_access_size && codec_drv->reg_access_default) {
		if (!codec->volatile_register)
			codec->volatile_register = snd_soc_default_volatile_register;
		if (!codec->readable_register)
			codec->readable_register = snd_soc_default_readable_register;
		if (!codec->writable_register)
			codec->writable_register = snd_soc_default_writable_register;
	}

	for (i = 0; i < num_dai; i++) {
		fixup_codec_formats(&dai_drv[i].playback);
		fixup_codec_formats(&dai_drv[i].capture);
@@ -4412,7 +4353,6 @@ found:
	dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->name);

	snd_soc_cache_exit(codec);
	kfree(codec->reg_def_copy);
	kfree(codec->name);
	kfree(codec);
}
@@ -4624,12 +4564,31 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
		if (pos->dev->of_node != args.np)
			continue;

		if (!pos->driver->of_xlate_dai_name) {
			ret = -ENOSYS;
		if (pos->driver->of_xlate_dai_name) {
			ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name);
		} else {
			int id = -1;

			switch (args.args_count) {
			case 0:
				id = 0; /* same as dai_drv[0] */
				break;
			case 1:
				id = args.args[0];
				break;
			default:
				/* not supported */
				break;
			}

		ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name);
			if (id < 0 || id >= pos->num_dai) {
				ret = -EINVAL;
			} else {
				*dai_name = pos->dai_drv[id].name;
				ret = 0;
			}
		}

		break;
	}
	mutex_unlock(&client_mutex);
+0 −26
Original line number Diff line number Diff line
@@ -65,31 +65,6 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
	return val;
}

/* Primitive bulk write support for soc-cache.  The data pointed to by
 * `data' needs to already be in the form the hardware expects.  Any
 * data written through this function will not go through the cache as
 * it only handles writing to volatile or out of bounds registers.
 *
 * This is currently only supported for devices using the regmap API
 * wrappers.
 */
static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec,
				     unsigned int reg,
				     const void *data, size_t len)
{
	/* 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;

	return regmap_raw_write(codec->control_data, reg, data, len);
}

/**
 * snd_soc_codec_set_cache_io: Set up standard I/O functions.
 *
@@ -119,7 +94,6 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
	memset(&config, 0, sizeof(config));
	codec->write = hw_write;
	codec->read = hw_read;
	codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;

	config.reg_bits = addr_bits;
	config.val_bits = data_bits;
Loading