aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/soc/soc-component.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-component.c')
-rw-r--r--sound/soc/soc-component.c682
1 files changed, 588 insertions, 94 deletions
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index 5504b92946e3..25f5e543ae8d 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -9,30 +9,46 @@
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
//
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <sound/soc.h>
+#include <linux/bitops.h>
#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret)
-static inline int _soc_component_ret(struct snd_soc_component *component,
- const char *func, int ret)
+static inline int _soc_component_ret(struct snd_soc_component *component, const char *func, int ret)
{
- /* Positive/Zero values are not errors */
- if (ret >= 0)
- return ret;
+ return snd_soc_ret(component->dev, ret,
+ "at %s() on %s\n", func, component->name);
+}
- /* Negative values might be errors */
- switch (ret) {
- case -EPROBE_DEFER:
- case -ENOTSUPP:
- break;
- default:
- dev_err(component->dev,
- "ASoC: error at %s on %s: %d\n",
- func, component->name, ret);
+#define soc_component_ret_reg_rw(dai, ret, reg) _soc_component_ret_reg_rw(dai, __func__, ret, reg)
+static inline int _soc_component_ret_reg_rw(struct snd_soc_component *component,
+ const char *func, int ret, int reg)
+{
+ return snd_soc_ret(component->dev, ret,
+ "at %s() on %s for register: [0x%08x]\n",
+ func, component->name, reg);
+}
+
+static inline int soc_component_field_shift(struct snd_soc_component *component,
+ unsigned int mask)
+{
+ if (!mask) {
+ dev_err(component->dev, "ASoC: error field mask is zero for %s\n",
+ component->name);
+ return 0;
}
- return ret;
+ return (ffs(mask) - 1);
}
+/*
+ * We might want to check substream by using list.
+ * In such case, we can update these macros.
+ */
+#define soc_component_mark_push(component, substream, tgt) ((component)->mark_##tgt = substream)
+#define soc_component_mark_pop(component, tgt) ((component)->mark_##tgt = NULL)
+#define soc_component_mark_match(component, substream, tgt) ((component)->mark_##tgt == substream)
+
void snd_soc_component_set_aux(struct snd_soc_component *component,
struct snd_soc_aux_dev *aux)
{
@@ -126,86 +142,75 @@ int snd_soc_component_set_bias_level(struct snd_soc_component *component,
return soc_component_ret(component, ret);
}
-static int soc_component_pin(struct snd_soc_component *component,
- const char *pin,
- int (*pin_func)(struct snd_soc_dapm_context *dapm,
- const char *pin))
-{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
- char *full_name;
- int ret;
-
- if (!component->name_prefix) {
- ret = pin_func(dapm, pin);
- goto end;
- }
-
- full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
- if (!full_name) {
- ret = -ENOMEM;
- goto end;
- }
-
- ret = pin_func(dapm, full_name);
- kfree(full_name);
-end:
- return soc_component_ret(component, ret);
-}
-
int snd_soc_component_enable_pin(struct snd_soc_component *component,
const char *pin)
{
- return soc_component_pin(component, pin, snd_soc_dapm_enable_pin);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ return snd_soc_dapm_enable_pin(dapm, pin);
}
EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin);
int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component,
const char *pin)
{
- return soc_component_pin(component, pin, snd_soc_dapm_enable_pin_unlocked);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ return snd_soc_dapm_enable_pin_unlocked(dapm, pin);
}
EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked);
int snd_soc_component_disable_pin(struct snd_soc_component *component,
const char *pin)
{
- return soc_component_pin(component, pin, snd_soc_dapm_disable_pin);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ return snd_soc_dapm_disable_pin(dapm, pin);
}
EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin);
int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component,
const char *pin)
{
- return soc_component_pin(component, pin, snd_soc_dapm_disable_pin_unlocked);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ return snd_soc_dapm_disable_pin_unlocked(dapm, pin);
}
EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked);
int snd_soc_component_nc_pin(struct snd_soc_component *component,
const char *pin)
{
- return soc_component_pin(component, pin, snd_soc_dapm_nc_pin);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ return snd_soc_dapm_nc_pin(dapm, pin);
}
EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin);
int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component,
const char *pin)
{
- return soc_component_pin(component, pin, snd_soc_dapm_nc_pin_unlocked);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ return snd_soc_dapm_nc_pin_unlocked(dapm, pin);
}
EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked);
int snd_soc_component_get_pin_status(struct snd_soc_component *component,
const char *pin)
{
- return soc_component_pin(component, pin, snd_soc_dapm_get_pin_status);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ return snd_soc_dapm_get_pin_status(dapm, pin);
}
EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status);
int snd_soc_component_force_enable_pin(struct snd_soc_component *component,
const char *pin)
{
- return soc_component_pin(component, pin, snd_soc_dapm_force_enable_pin);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ return snd_soc_dapm_force_enable_pin(dapm, pin);
}
EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin);
@@ -213,10 +218,49 @@ int snd_soc_component_force_enable_pin_unlocked(
struct snd_soc_component *component,
const char *pin)
{
- return soc_component_pin(component, pin, snd_soc_dapm_force_enable_pin_unlocked);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
}
EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked);
+static void soc_get_kcontrol_name(struct snd_soc_component *component,
+ char *buf, int size, const char * const ctl)
+{
+ /* When updating, change also snd_soc_dapm_widget_name_cmp() */
+ if (component->name_prefix)
+ snprintf(buf, size, "%s %s", component->name_prefix, ctl);
+ else
+ snprintf(buf, size, "%s", ctl);
+}
+
+struct snd_kcontrol *snd_soc_component_get_kcontrol(struct snd_soc_component *component,
+ const char * const ctl)
+{
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+ soc_get_kcontrol_name(component, name, ARRAY_SIZE(name), ctl);
+
+ return snd_soc_card_get_kcontrol(component->card, name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_get_kcontrol);
+
+int snd_soc_component_notify_control(struct snd_soc_component *component,
+ const char * const ctl)
+{
+ struct snd_kcontrol *kctl;
+
+ kctl = snd_soc_component_get_kcontrol(component, ctl);
+ if (!kctl)
+ return soc_component_ret(component, -EINVAL);
+
+ snd_ctl_notify(component->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_notify_control);
+
/**
* snd_soc_component_set_jack - configure component jack.
* @component: COMPONENTs
@@ -237,8 +281,28 @@ int snd_soc_component_set_jack(struct snd_soc_component *component,
}
EXPORT_SYMBOL_GPL(snd_soc_component_set_jack);
+/**
+ * snd_soc_component_get_jack_type
+ * @component: COMPONENTs
+ *
+ * Returns the jack type of the component
+ * This can either be the supported type or one read from
+ * devicetree with the property: jack-type.
+ */
+int snd_soc_component_get_jack_type(
+ struct snd_soc_component *component)
+{
+ int ret = -ENOTSUPP;
+
+ if (component->driver->get_jack_type)
+ ret = component->driver->get_jack_type(component);
+
+ return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_get_jack_type);
+
int snd_soc_component_module_get(struct snd_soc_component *component,
- int upon_open)
+ void *mark, int upon_open)
{
int ret = 0;
@@ -246,14 +310,24 @@ int snd_soc_component_module_get(struct snd_soc_component *component,
!try_module_get(component->dev->driver->owner))
ret = -ENODEV;
+ /* mark module if succeeded */
+ if (ret == 0)
+ soc_component_mark_push(component, mark, module);
+
return soc_component_ret(component, ret);
}
void snd_soc_component_module_put(struct snd_soc_component *component,
- int upon_open)
+ void *mark, int upon_open, int rollback)
{
+ if (rollback && !soc_component_mark_match(component, mark, module))
+ return;
+
if (component->driver->module_get_upon_open == !!upon_open)
module_put(component->dev->driver->owner);
+
+ /* remove the mark from module */
+ soc_component_mark_pop(component, module);
}
int snd_soc_component_open(struct snd_soc_component *component,
@@ -264,17 +338,28 @@ int snd_soc_component_open(struct snd_soc_component *component,
if (component->driver->open)
ret = component->driver->open(component, substream);
+ /* mark substream if succeeded */
+ if (ret == 0)
+ soc_component_mark_push(component, substream, open);
+
return soc_component_ret(component, ret);
}
int snd_soc_component_close(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
+ struct snd_pcm_substream *substream,
+ int rollback)
{
int ret = 0;
+ if (rollback && !soc_component_mark_match(component, substream, open))
+ return 0;
+
if (component->driver->close)
ret = component->driver->close(component, substream);
+ /* remove marked substream */
+ soc_component_mark_pop(component, open);
+
return soc_component_ret(component, ret);
}
@@ -325,7 +410,7 @@ int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component,
}
int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component,
- struct of_phandle_args *args,
+ const struct of_phandle_args *args,
const char **dai_name)
{
if (component->driver->of_xlate_dai_name)
@@ -389,6 +474,253 @@ EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
#endif
+int snd_soc_component_compr_open(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream)
+{
+ int ret = 0;
+
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->open)
+ ret = component->driver->compress_ops->open(component, cstream);
+
+ /* mark substream if succeeded */
+ if (ret == 0)
+ soc_component_mark_push(component, cstream, compr_open);
+
+ return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_open);
+
+void snd_soc_component_compr_free(struct snd_soc_component *component,
+ struct snd_compr_stream *cstream,
+ int rollback)
+{
+ if (rollback && !soc_component_mark_match(component, cstream, compr_open))
+ return;
+
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->free)
+ component->driver->compress_ops->free(component, cstream);
+
+ /* remove marked substream */
+ soc_component_mark_pop(component, compr_open);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_free);
+
+int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret;
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->trigger) {
+ ret = component->driver->compress_ops->trigger(
+ component, cstream, cmd);
+ if (ret < 0)
+ return soc_component_ret(component, ret);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_trigger);
+
+int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream,
+ struct snd_compr_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret;
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->set_params) {
+ ret = component->driver->compress_ops->set_params(
+ component, cstream, params);
+ if (ret < 0)
+ return soc_component_ret(component, ret);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_params);
+
+int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream,
+ struct snd_codec *params)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret;
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->get_params) {
+ ret = component->driver->compress_ops->get_params(
+ component, cstream, params);
+ return soc_component_ret(component, ret);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_params);
+
+int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream,
+ struct snd_compr_caps *caps)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret = 0;
+
+ snd_soc_dpcm_mutex_lock(rtd);
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->get_caps) {
+ ret = component->driver->compress_ops->get_caps(
+ component, cstream, caps);
+ break;
+ }
+ }
+
+ snd_soc_dpcm_mutex_unlock(rtd);
+
+ return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_caps);
+
+int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream,
+ struct snd_compr_codec_caps *codec)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret = 0;
+
+ snd_soc_dpcm_mutex_lock(rtd);
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->get_codec_caps) {
+ ret = component->driver->compress_ops->get_codec_caps(
+ component, cstream, codec);
+ break;
+ }
+ }
+
+ snd_soc_dpcm_mutex_unlock(rtd);
+
+ return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_codec_caps);
+
+int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret;
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->ack) {
+ ret = component->driver->compress_ops->ack(
+ component, cstream, bytes);
+ if (ret < 0)
+ return soc_component_ret(component, ret);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_ack);
+
+int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream,
+ struct snd_compr_tstamp *tstamp)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret;
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->pointer) {
+ ret = component->driver->compress_ops->pointer(
+ component, cstream, tstamp);
+ return soc_component_ret(component, ret);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_pointer);
+
+int snd_soc_component_compr_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret = 0;
+
+ snd_soc_dpcm_mutex_lock(rtd);
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->copy) {
+ ret = component->driver->compress_ops->copy(
+ component, cstream, buf, count);
+ break;
+ }
+ }
+
+ snd_soc_dpcm_mutex_unlock(rtd);
+
+ return soc_component_ret(component, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_copy);
+
+int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream,
+ struct snd_compr_metadata *metadata)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret;
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->set_metadata) {
+ ret = component->driver->compress_ops->set_metadata(
+ component, cstream, metadata);
+ if (ret < 0)
+ return soc_component_ret(component, ret);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_metadata);
+
+int snd_soc_component_compr_get_metadata(struct snd_compr_stream *cstream,
+ struct snd_compr_metadata *metadata)
+{
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct snd_soc_component *component;
+ int i, ret;
+
+ for_each_rtd_components(rtd, i, component) {
+ if (component->driver->compress_ops &&
+ component->driver->compress_ops->get_metadata) {
+ ret = component->driver->compress_ops->get_metadata(
+ component, cstream, metadata);
+ return soc_component_ret(component, ret);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_metadata);
+
static unsigned int soc_component_read_no_lock(
struct snd_soc_component *component,
unsigned int reg)
@@ -406,7 +738,7 @@ static unsigned int soc_component_read_no_lock(
ret = -EIO;
if (ret < 0)
- return soc_component_ret(component, ret);
+ return soc_component_ret_reg_rw(component, ret, reg);
return val;
}
@@ -442,7 +774,7 @@ static int soc_component_write_no_lock(
else if (component->driver->write)
ret = component->driver->write(component, reg, val);
- return soc_component_ret(component, ret);
+ return soc_component_ret_reg_rw(component, ret, reg);
}
/**
@@ -484,7 +816,7 @@ static int snd_soc_component_update_bits_legacy(
mutex_unlock(&component->io_mutex);
- return soc_component_ret(component, ret);
+ return soc_component_ret_reg_rw(component, ret, reg);
}
/**
@@ -512,7 +844,7 @@ int snd_soc_component_update_bits(struct snd_soc_component *component,
mask, val, &change);
if (ret < 0)
- return soc_component_ret(component, ret);
+ return soc_component_ret_reg_rw(component, ret, reg);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_component_update_bits);
@@ -548,12 +880,53 @@ int snd_soc_component_update_bits_async(struct snd_soc_component *component,
mask, val, &change);
if (ret < 0)
- return soc_component_ret(component, ret);
+ return soc_component_ret_reg_rw(component, ret, reg);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async);
/**
+ * snd_soc_component_read_field() - Read register field value
+ * @component: Component to read from
+ * @reg: Register to read
+ * @mask: mask of the register field
+ *
+ * Return: read value of register field.
+ */
+unsigned int snd_soc_component_read_field(struct snd_soc_component *component,
+ unsigned int reg, unsigned int mask)
+{
+ unsigned int val;
+
+ val = snd_soc_component_read(component, reg);
+
+ val = (val & mask) >> soc_component_field_shift(component, mask);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_read_field);
+
+/**
+ * snd_soc_component_write_field() - write to register field
+ * @component: Component to write to
+ * @reg: Register to write
+ * @mask: mask of the register field to update
+ * @val: value of the field to write
+ *
+ * Return: 1 for change, otherwise 0.
+ */
+int snd_soc_component_write_field(struct snd_soc_component *component,
+ unsigned int reg, unsigned int mask,
+ unsigned int val)
+{
+
+ val = (val << soc_component_field_shift(component, mask)) & mask;
+
+ return snd_soc_component_update_bits(component, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_write_field);
+
+/**
* snd_soc_component_async_complete() - Ensure asynchronous I/O has completed
* @component: Component for which to wait
*
@@ -592,7 +965,7 @@ EXPORT_SYMBOL_GPL(snd_soc_component_test_bits);
int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i;
@@ -604,10 +977,52 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream)
return 0;
}
+static bool snd_soc_component_is_codec_on_rtd(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_component *component)
+{
+ struct snd_soc_dai *dai;
+ int i;
+
+ for_each_rtd_codec_dais(rtd, i, dai) {
+ if (dai->component == component)
+ return true;
+ }
+
+ return false;
+}
+
+void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream,
+ snd_pcm_sframes_t *cpu_delay,
+ snd_pcm_sframes_t *codec_delay)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *component;
+ snd_pcm_sframes_t delay;
+ int i;
+
+ /*
+ * We're looking for the delay through the full audio path so it needs to
+ * be the maximum of the Components doing transmit and the maximum of the
+ * Components doing receive (ie, all CPUs and all CODECs) rather than
+ * just the maximum of all Components.
+ */
+ for_each_rtd_components(rtd, i, component) {
+ if (!component->driver->delay)
+ continue;
+
+ delay = component->driver->delay(component, substream);
+
+ if (snd_soc_component_is_codec_on_rtd(rtd, component))
+ *codec_delay = max(*codec_delay, delay);
+ else
+ *cpu_delay = max(*cpu_delay, delay);
+ }
+}
+
int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i;
@@ -624,7 +1039,7 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream,
int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret;
@@ -640,22 +1055,20 @@ int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream)
return 0;
}
-int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void __user *buf, unsigned long bytes)
+int snd_soc_pcm_component_copy(struct snd_pcm_substream *substream,
+ int channel, unsigned long pos,
+ struct iov_iter *iter, unsigned long bytes)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i;
/* FIXME. it returns 1st copy now */
for_each_rtd_components(rtd, i, component)
- if (component->driver->copy_user)
- return soc_component_ret(
- component,
- component->driver->copy_user(
- component, substream, channel,
- pos, buf, bytes));
+ if (component->driver->copy)
+ return soc_component_ret(component,
+ component->driver->copy(component, substream,
+ channel, pos, iter, bytes));
return -EINVAL;
}
@@ -663,7 +1076,7 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream,
struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream,
unsigned long offset)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
struct page *page;
int i;
@@ -684,7 +1097,7 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream,
int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i;
@@ -731,7 +1144,7 @@ void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd)
int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret;
@@ -747,10 +1160,9 @@ int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
}
int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_component **last)
+ struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret;
@@ -758,50 +1170,132 @@ int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
if (component->driver->hw_params) {
ret = component->driver->hw_params(component,
substream, params);
- if (ret < 0) {
- *last = component;
+ if (ret < 0)
return soc_component_ret(component, ret);
- }
}
+ /* mark substream if succeeded */
+ soc_component_mark_push(component, substream, hw_params);
}
- *last = NULL;
return 0;
}
void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_component *last)
+ int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret;
for_each_rtd_components(rtd, i, component) {
- if (component == last)
- break;
+ if (rollback && !soc_component_mark_match(component, substream, hw_params))
+ continue;
if (component->driver->hw_free) {
ret = component->driver->hw_free(component, substream);
if (ret < 0)
soc_component_ret(component, ret);
}
+
+ /* remove marked substream */
+ soc_component_mark_pop(component, hw_params);
}
}
+static int soc_component_trigger(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ int cmd)
+{
+ int ret = 0;
+
+ if (component->driver->trigger)
+ ret = component->driver->trigger(component, substream, cmd);
+
+ return soc_component_ret(component, ret);
+}
+
int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream,
- int cmd)
+ int cmd, int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
- int i, ret;
+ int i, r, ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ for_each_rtd_components(rtd, i, component) {
+ ret = soc_component_trigger(component, substream, cmd);
+ if (ret < 0)
+ break;
+ soc_component_mark_push(component, substream, trigger);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ for_each_rtd_components(rtd, i, component) {
+ if (rollback && !soc_component_mark_match(component, substream, trigger))
+ continue;
+
+ r = soc_component_trigger(component, substream, cmd);
+ if (r < 0)
+ ret = r; /* use last ret */
+ soc_component_mark_pop(component, trigger);
+ }
+ }
+
+ return ret;
+}
+
+int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
+ void *stream)
+{
+ struct snd_soc_component *component;
+ int i;
for_each_rtd_components(rtd, i, component) {
- if (component->driver->trigger) {
- ret = component->driver->trigger(component, substream, cmd);
- if (ret < 0)
- return soc_component_ret(component, ret);
+ int ret = pm_runtime_get_sync(component->dev);
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_noidle(component->dev);
+ return soc_component_ret(component, ret);
}
+ /* mark stream if succeeded */
+ soc_component_mark_push(component, stream, pm);
}
return 0;
}
+
+void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd,
+ void *stream, int rollback)
+{
+ struct snd_soc_component *component;
+ int i;
+
+ for_each_rtd_components(rtd, i, component) {
+ if (rollback && !soc_component_mark_match(component, stream, pm))
+ continue;
+
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
+
+ /* remove marked stream */
+ soc_component_mark_pop(component, pm);
+ }
+}
+
+int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *component;
+ int i;
+
+ /* FIXME: use 1st pointer */
+ for_each_rtd_components(rtd, i, component)
+ if (component->driver->ack)
+ return component->driver->ack(component, substream);
+
+ return 0;
+}