unsigned int freq_in, unsigned int freq_out);
/* codec IO */
++++ struct regmap *(*get_regmap)(struct device *);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
- -- int (*display_register)(struct snd_soc_codec *, char *,
- -- size_t, unsigned int);
- -- 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);
unsigned int reg_cache_size;
short reg_cache_step;
short reg_word_size;
return container_of(component, struct snd_soc_codec, component);
}
+ ++/**
+ ++ * snd_soc_component_to_platform() - Casts a component to the platform it is embedded in
+ ++ * @component: The component to cast to a platform
+ ++ *
+ ++ * This function must only be used on components that are known to be platforms.
+ ++ * Otherwise the behavior is undefined.
+ ++ */
+ ++static inline struct snd_soc_platform *snd_soc_component_to_platform(
+ ++ struct snd_soc_component *component)
+ ++{
+ ++ return container_of(component, struct snd_soc_platform, component);
+ ++}
+ ++
/* codec IO */
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);
++ ++int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
++ ++ unsigned int val);
/* device driver data */
return snd_soc_component_is_active(&codec->component);
}
- static inline struct snd_soc_codec *snd_soc_kcontrol_platform(
+ ++/**
+ ++ * snd_soc_kcontrol_codec() - Returns the CODEC that registered the control
+ ++ * @kcontrol: The control for which to get the CODEC
+ ++ *
+ ++ * Note: This function will only work correctly if the control has been
+ ++ * registered with snd_soc_add_codec_controls() or via table based setup of
+ ++ * snd_soc_codec_driver. Otherwise the behavior is undefined.
+ ++ */
+ ++static inline struct snd_soc_codec *snd_soc_kcontrol_codec(
+ ++ struct snd_kcontrol *kcontrol)
+ ++{
+ ++ return snd_kcontrol_chip(kcontrol);
+ ++}
+ ++
+ ++/**
+ ++ * snd_soc_kcontrol_platform() - Returns the platform that registerd the control
+ ++ * @kcontrol: The control for which to get the platform
+ ++ *
+ ++ * Note: This function will only work correctly if the control has been
+ ++ * registered with snd_soc_add_platform_controls() or via table based setup of
+ ++ * a snd_soc_platform_driver. Otherwise the behavior is undefined.
+ ++ */
++++static inline struct snd_soc_platform *snd_soc_kcontrol_platform(
+ ++ struct snd_kcontrol *kcontrol)
+ ++{
+ ++ return snd_kcontrol_chip(kcontrol);
+ ++}
+ ++
int snd_soc_util_init(void);
void snd_soc_util_exit(void);
soc_init_codec_debugfs(codec);
-- -- if (driver->dapm_widgets)
-- -- snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
-- -- driver->num_dapm_widgets);
++ ++ if (driver->dapm_widgets) {
++ ++ ret = snd_soc_dapm_new_controls(&codec->dapm,
++ ++ driver->dapm_widgets,
++ ++ driver->num_dapm_widgets);
+
-- - /* Create DAPM widgets for each DAI stream */
-- - list_for_each_entry(dai, &codec->component.dai_list, list)
-- - snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
++ ++ if (ret != 0) {
++ ++ dev_err(codec->dev,
++ ++ "Failed to create new controls %d\n", ret);
++ ++ goto err_probe;
++ ++ }
++ ++ }
-- - codec->dapm.idle_bias_off = driver->idle_bias_off;
++ + /* Create DAPM widgets for each DAI stream */
- list_for_each_entry(dai, &codec->component.dai_list, list)
- snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
++ ++ list_for_each_entry(dai, &codec->component.dai_list, list) {
++ ++ ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
+
-- - if (!codec->write && dev_get_regmap(codec->dev, NULL)) {
-- - /* Set the default I/O up try regmap */
-- - ret = snd_soc_codec_set_cache_io(codec, NULL);
-- - if (ret < 0) {
++ ++ if (ret != 0) {
+ dev_err(codec->dev,
-- - "Failed to set cache I/O: %d\n", ret);
++ ++ "Failed to create DAI widgets %d\n", ret);
+ goto err_probe;
+ }
+ }
- if (!codec->write && dev_get_regmap(codec->dev, NULL)) {
- /* Set the default I/O up try regmap */
- ret = snd_soc_codec_set_cache_io(codec, NULL);
- if (ret < 0) {
- dev_err(codec->dev,
- "Failed to set cache I/O: %d\n", ret);
- goto err_probe;
- }
- }
-
++ + codec->dapm.idle_bias_off = driver->idle_bias_off;
++ +
if (driver->probe) {
ret = driver->probe(codec);
if (ret < 0) {
codec->dev = dev;
codec->driver = codec_drv;
codec->num_dai = num_dai;
+ ++ codec->val_bytes = codec_drv->reg_word_size;
mutex_init(&codec->mutex);
++++ if (!codec->write) {
++++ if (codec_drv->get_regmap)
++++ regmap = codec_drv->get_regmap(dev);
++++ else
++++ regmap = dev_get_regmap(dev, NULL);
++++
++++ if (regmap) {
++++ ret = snd_soc_codec_set_cache_io(codec, regmap);
++++ if (ret && ret != -ENOTSUPP) {
++++ dev_err(codec->dev,
++++ "Failed to set cache I/O:%d\n",
++++ ret);
++++ return ret;
++++ }
++++ }
++++ }
++++
for (i = 0; i < num_dai; i++) {
fixup_codec_formats(&dai_drv[i].playback);
fixup_codec_formats(&dai_drv[i].capture);
#include <trace/events/asoc.h>
- unsigned int snd_soc_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int val)
+ ++unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
+ ++{
+ ++ unsigned int ret;
+ ++
+ ++ ret = codec->read(codec, reg);
+ ++ dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
+ ++ trace_snd_soc_reg_read(codec, reg, ret);
+ ++
+ ++ return ret;
+ ++}
+ ++EXPORT_SYMBOL_GPL(snd_soc_read);
+ ++
- int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
++ ++int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
++ ++ unsigned int val)
+ ++{
+ ++ dev_dbg(codec->dev, "write %x = %x\n", reg, val);
+ ++ trace_snd_soc_reg_write(codec, reg, val);
+ ++ return codec->write(codec, reg, val);
+ ++}
+ ++EXPORT_SYMBOL_GPL(snd_soc_write);
+ ++
+ ++/**
+ ++ * snd_soc_update_bits - update codec register bits
+ ++ * @codec: audio codec
+ ++ * @reg: codec register
+ ++ * @mask: register mask
+ ++ * @value: new value
+ ++ *
+ ++ * Writes new register value.
+ ++ *
+ ++ * Returns 1 for change, 0 for no change, or negative error code.
+ ++ */
- unsigned short reg, unsigned int mask,
++ ++int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,
+ ++ unsigned int mask, unsigned int value)
+ ++{
+ ++ bool change;
+ ++ unsigned int old, new;
+ ++ int ret;
+ ++
+ ++ if (codec->using_regmap) {
+ ++ ret = regmap_update_bits_check(codec->control_data, reg,
+ ++ mask, value, &change);
+ ++ } else {
+ ++ ret = snd_soc_read(codec, reg);
+ ++ if (ret < 0)
+ ++ return ret;
+ ++
+ ++ old = ret;
+ ++ new = (old & ~mask) | (value & mask);
+ ++ change = old != new;
+ ++ if (change)
+ ++ ret = snd_soc_write(codec, reg, new);
+ ++ }
+ ++
+ ++ if (ret < 0)
+ ++ return ret;
+ ++
+ ++ return change;
+ ++}
+ ++EXPORT_SYMBOL_GPL(snd_soc_update_bits);
+ ++
+ ++/**
+ ++ * snd_soc_update_bits_locked - update codec register bits
+ ++ * @codec: audio codec
+ ++ * @reg: codec register
+ ++ * @mask: register mask
+ ++ * @value: new value
+ ++ *
+ ++ * Writes new register value, and takes the codec mutex.
+ ++ *
+ ++ * Returns 1 for change else 0.
+ ++ */
+ ++int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
- int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
++ ++ unsigned int reg, unsigned int mask,
+ ++ unsigned int value)
+ ++{
+ ++ int change;
+ ++
+ ++ mutex_lock(&codec->mutex);
+ ++ change = snd_soc_update_bits(codec, reg, mask, value);
+ ++ mutex_unlock(&codec->mutex);
+ ++
+ ++ return change;
+ ++}
+ ++EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked);
+ ++
+ ++/**
+ ++ * snd_soc_test_bits - test register for change
+ ++ * @codec: audio codec
+ ++ * @reg: codec register
+ ++ * @mask: register mask
+ ++ * @value: new value
+ ++ *
+ ++ * Tests a register with a new value and checks if the new value is
+ ++ * different from the old value.
+ ++ *
+ ++ * Returns 1 for change else 0.
+ ++ */
++ ++int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
+ ++ unsigned int mask, unsigned int value)
+ ++{
+ ++ int change;
+ ++ unsigned int old, new;
+ ++
+ ++ old = snd_soc_read(codec, reg);
+ ++ new = (old & ~mask) | value;
+ ++ change = old != new;
+ ++
+ ++ return change;
+ ++}
+ ++EXPORT_SYMBOL_GPL(snd_soc_test_bits);
+ ++
+ ++int snd_soc_platform_read(struct snd_soc_platform *platform,
+ ++ unsigned int reg)
+ ++{
+ ++ unsigned int ret;
+ ++
+ ++ if (!platform->driver->read) {
+ ++ dev_err(platform->dev, "ASoC: platform has no read back\n");
+ ++ return -1;
+ ++ }
+ ++
+ ++ ret = platform->driver->read(platform, reg);
+ ++ dev_dbg(platform->dev, "read %x => %x\n", reg, ret);
+ ++ trace_snd_soc_preg_read(platform, reg, ret);
+ ++
+ ++ return ret;
+ ++}
+ ++EXPORT_SYMBOL_GPL(snd_soc_platform_read);
+ ++
+ ++int snd_soc_platform_write(struct snd_soc_platform *platform,
+ ++ unsigned int reg, unsigned int val)
+ ++{
+ ++ if (!platform->driver->write) {
+ ++ dev_err(platform->dev, "ASoC: platform has no write back\n");
+ ++ return -1;
+ ++ }
+ ++
+ ++ dev_dbg(platform->dev, "write %x = %x\n", reg, val);
+ ++ trace_snd_soc_preg_write(platform, reg, val);
+ ++ return platform->driver->write(platform, reg, val);
+ ++}
+ ++EXPORT_SYMBOL_GPL(snd_soc_platform_write);
+ ++
#ifdef CONFIG_REGMAP
static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)