Loading include/sound/soc.h +3 −57 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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 * Loading Loading @@ -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; Loading @@ -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; }; Loading @@ -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); Loading @@ -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; Loading Loading @@ -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 *, Loading Loading @@ -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 { Loading Loading @@ -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 */ Loading include/trace/events/asoc.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading sound/soc/soc-cache.c +61 −202 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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; } /** Loading @@ -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); Loading @@ -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. Loading @@ -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); sound/soc/soc-core.c +26 −67 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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; /* Loading Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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); } Loading Loading @@ -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); Loading sound/soc/soc-io.c +0 −26 Original line number Diff line number Diff line Loading @@ -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. * Loading Loading @@ -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 Loading
include/sound/soc.h +3 −57 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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 * Loading Loading @@ -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; Loading @@ -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; }; Loading @@ -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); Loading @@ -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; Loading Loading @@ -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 *, Loading Loading @@ -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 { Loading Loading @@ -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 */ Loading
include/trace/events/asoc.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
sound/soc/soc-cache.c +61 −202 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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; } /** Loading @@ -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); Loading @@ -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. Loading @@ -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);
sound/soc/soc-core.c +26 −67 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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; /* Loading Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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); } Loading Loading @@ -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); Loading
sound/soc/soc-io.c +0 −26 Original line number Diff line number Diff line Loading @@ -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. * Loading Loading @@ -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