|
@@ -593,6 +593,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
|
|
|
}
|
|
|
|
|
|
list_for_each_entry(path, &widget->sinks, list_source) {
|
|
|
+ if (path->weak)
|
|
|
+ continue;
|
|
|
+
|
|
|
if (path->walked)
|
|
|
continue;
|
|
|
|
|
@@ -643,6 +646,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
|
|
|
}
|
|
|
|
|
|
list_for_each_entry(path, &widget->sources, list_sink) {
|
|
|
+ if (path->weak)
|
|
|
+ continue;
|
|
|
+
|
|
|
if (path->walked)
|
|
|
continue;
|
|
|
|
|
@@ -724,6 +730,9 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
|
|
|
|
|
|
/* Check if one of our outputs is connected */
|
|
|
list_for_each_entry(path, &w->sinks, list_source) {
|
|
|
+ if (path->weak)
|
|
|
+ continue;
|
|
|
+
|
|
|
if (path->connected &&
|
|
|
!path->connected(path->source, path->sink))
|
|
|
continue;
|
|
@@ -1806,6 +1815,84 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
|
|
|
|
|
|
+static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
|
|
|
+ const struct snd_soc_dapm_route *route)
|
|
|
+{
|
|
|
+ struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
|
|
|
+ route->source,
|
|
|
+ true);
|
|
|
+ struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
|
|
|
+ route->sink,
|
|
|
+ true);
|
|
|
+ struct snd_soc_dapm_path *path;
|
|
|
+ int count = 0;
|
|
|
+
|
|
|
+ if (!source) {
|
|
|
+ dev_err(dapm->dev, "Unable to find source %s for weak route\n",
|
|
|
+ route->source);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!sink) {
|
|
|
+ dev_err(dapm->dev, "Unable to find sink %s for weak route\n",
|
|
|
+ route->sink);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (route->control || route->connected)
|
|
|
+ dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n",
|
|
|
+ route->source, route->sink);
|
|
|
+
|
|
|
+ list_for_each_entry(path, &source->sinks, list_source) {
|
|
|
+ if (path->sink == sink) {
|
|
|
+ path->weak = 1;
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (count == 0)
|
|
|
+ dev_err(dapm->dev, "No path found for weak route %s->%s\n",
|
|
|
+ route->source, route->sink);
|
|
|
+ if (count > 1)
|
|
|
+ dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n",
|
|
|
+ count, route->source, route->sink);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
|
|
|
+ * @dapm: DAPM context
|
|
|
+ * @route: audio routes
|
|
|
+ * @num: number of routes
|
|
|
+ *
|
|
|
+ * Mark existing routes matching those specified in the passed array
|
|
|
+ * as being weak, meaning that they are ignored for the purpose of
|
|
|
+ * power decisions. The main intended use case is for sidetone paths
|
|
|
+ * which couple audio between other independent paths if they are both
|
|
|
+ * active in order to make the combination work better at the user
|
|
|
+ * level but which aren't intended to be "used".
|
|
|
+ *
|
|
|
+ * Note that CODEC drivers should not use this as sidetone type paths
|
|
|
+ * can frequently also be used as bypass paths.
|
|
|
+ */
|
|
|
+int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
|
|
|
+ const struct snd_soc_dapm_route *route, int num)
|
|
|
+{
|
|
|
+ int i, err;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < num; i++) {
|
|
|
+ err = snd_soc_dapm_weak_route(dapm, route);
|
|
|
+ if (err)
|
|
|
+ ret = err;
|
|
|
+ route++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
|
|
|
+
|
|
|
/**
|
|
|
* snd_soc_dapm_new_widgets - add new dapm widgets
|
|
|
* @dapm: DAPM context
|