^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // ASoC audio graph sound card support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) // Copyright (C) 2016 Renesas Solutions Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) // based on ${LINUX}/sound/soc/generic/simple-card.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/gpio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/of_gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/of_graph.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <sound/simple_card_utils.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define DPCM_SELECTABLE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define PREFIX "audio-graph-card,"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static int graph_outdrv_event(struct snd_soc_dapm_widget *w,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct snd_soc_dapm_context *dapm = w->dapm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(dapm->card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) case SND_SOC_DAPM_POST_PMU:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) gpiod_set_value_cansleep(priv->pa_gpio, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) case SND_SOC_DAPM_PRE_PMD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) gpiod_set_value_cansleep(priv->pa_gpio, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static const struct snd_soc_dapm_widget graph_dapm_widgets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) 0, 0, NULL, 0, graph_outdrv_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static const struct snd_soc_ops graph_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) .startup = asoc_simple_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) .shutdown = asoc_simple_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .hw_params = asoc_simple_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static int graph_get_dai_id(struct device_node *ep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct device_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct device_node *endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct of_endpoint info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) int i, id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) const u32 *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* use driver specified DAI ID if exist */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ret = snd_soc_get_dai_id(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (ret != -ENOTSUPP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* use endpoint/port reg if exist */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ret = of_graph_parse_endpoint(ep, &info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * Because it will count port/endpoint if it doesn't have "reg".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * But, we can't judge whether it has "no reg", or "reg = <0>"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * only of_graph_parse_endpoint().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * We need to check "reg" property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (of_get_property(ep, "reg", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return info.id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) node = of_get_parent(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) reg = of_get_property(node, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) of_node_put(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return info.port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) node = of_graph_get_port_parent(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * Non HDMI sound case, counting port/endpoint on its DT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * is enough. Let's count it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) id = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) for_each_endpoint_of_node(node, endpoint) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (endpoint == ep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) id = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) of_node_put(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (id < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static int asoc_simple_parse_dai(struct device_node *ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct snd_soc_dai_link_component *dlc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int *is_single_link)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct device_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct of_phandle_args args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (!ep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) node = of_graph_get_port_parent(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /* Get dai->name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) args.np = node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) args.args[0] = graph_get_dai_id(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) args.args_count = (of_graph_get_endpoint_count(node) > 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * FIXME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * Here, dlc->dai_name is pointer to CPU/Codec DAI name.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * If user unbinded CPU or Codec driver, but not for Sound Card,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * dlc->dai_name is keeping unbinded CPU or Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * driver's pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * If user re-bind CPU or Codec driver again, ALSA SoC will try
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * to rebind Card via snd_soc_try_rebind_card(), but because of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * above reason, it might can't bind Sound Card.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * Because Sound Card is pointing to released dai_name pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * To avoid this rebind Card issue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * 1) It needs to alloc memory to keep dai_name eventhough
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * CPU or Codec driver was unbinded, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * 2) user need to rebind Sound Card everytime
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * if he unbinded CPU or Codec.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ret = snd_soc_get_dai_name(&args, &dlc->dai_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) dlc->of_node = node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (is_single_link)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) *is_single_link = of_graph_get_endpoint_count(node) == 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) static void graph_parse_convert(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) struct device_node *ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) struct asoc_simple_data *adata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct device_node *top = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) struct device_node *port = of_get_parent(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) struct device_node *ports = of_get_parent(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct device_node *node = of_graph_get_port_parent(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) asoc_simple_parse_convert(dev, top, NULL, adata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) asoc_simple_parse_convert(dev, node, PREFIX, adata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) asoc_simple_parse_convert(dev, ports, NULL, adata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) asoc_simple_parse_convert(dev, port, NULL, adata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) asoc_simple_parse_convert(dev, ep, NULL, adata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) of_node_put(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) of_node_put(ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) of_node_put(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static void graph_parse_mclk_fs(struct device_node *top,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct device_node *ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct simple_dai_props *props)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct device_node *port = of_get_parent(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) struct device_node *ports = of_get_parent(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct device_node *node = of_graph_get_port_parent(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) of_property_read_u32(top, "mclk-fs", &props->mclk_fs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) of_property_read_u32(port, "mclk-fs", &props->mclk_fs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) of_property_read_u32(ep, "mclk-fs", &props->mclk_fs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) of_node_put(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) of_node_put(ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) of_node_put(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct device_node *cpu_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct device_node *codec_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct link_info *li,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int dup_codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) struct device *dev = simple_priv_to_dev(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct device_node *top = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct device_node *ep = li->cpu ? cpu_ep : codec_ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) struct device_node *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) struct device_node *ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct device_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct asoc_simple_dai *dai;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct snd_soc_dai_link_component *cpus = dai_link->cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) struct snd_soc_dai_link_component *codecs = dai_link->codecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* Do it all CPU endpoint, and 1st Codec endpoint */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (!li->cpu && dup_codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) port = of_get_parent(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ports = of_get_parent(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) node = of_graph_get_port_parent(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) li->link++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) dev_dbg(dev, "link_of DPCM (%pOF)\n", ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (li->cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) int is_single_links = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* Codec is dummy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) codecs->of_node = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) codecs->dai_name = "snd-soc-dummy-dai";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) codecs->name = "snd-soc-dummy";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) /* FE settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) dai_link->dynamic = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) dai_link->dpcm_merged_format = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) dai =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) dai_props->cpu_dai = &priv->dais[li->dais++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ret = asoc_simple_parse_cpu(ep, dai_link, &is_single_links);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) goto out_put_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) ret = asoc_simple_parse_clk_cpu(dev, ep, dai_link, dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) goto out_put_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) ret = asoc_simple_set_dailink_name(dev, dai_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) "fe.%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) cpus->dai_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) goto out_put_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* card->num_links includes Codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) asoc_simple_canonicalize_cpu(dai_link, is_single_links);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct snd_soc_codec_conf *cconf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) /* CPU is dummy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) cpus->of_node = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) cpus->dai_name = "snd-soc-dummy-dai";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) cpus->name = "snd-soc-dummy";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /* BE settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) dai_link->no_pcm = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) dai =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dai_props->codec_dai = &priv->dais[li->dais++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) cconf =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) dai_props->codec_conf = &priv->codec_conf[li->conf++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) ret = asoc_simple_parse_codec(ep, dai_link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) goto out_put_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) ret = asoc_simple_parse_clk_codec(dev, ep, dai_link, dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) goto out_put_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) ret = asoc_simple_set_dailink_name(dev, dai_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) "be.%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) codecs->dai_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) goto out_put_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) /* check "prefix" from top node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) "prefix");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) PREFIX "prefix");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) "prefix");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) "prefix");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) graph_parse_convert(dev, ep, &dai_props->adata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) graph_parse_mclk_fs(top, ep, dai_props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) asoc_simple_canonicalize_platform(dai_link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) ret = asoc_simple_parse_tdm(ep, dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) goto out_put_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) NULL, &dai_link->dai_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) goto out_put_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) snd_soc_dai_link_set_capabilities(dai_link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) dai_link->ops = &graph_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) dai_link->init = asoc_simple_dai_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) out_put_node:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) of_node_put(ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) of_node_put(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) of_node_put(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) static int graph_dai_link_of(struct asoc_simple_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) struct device_node *cpu_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) struct device_node *codec_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) struct link_info *li)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) struct device *dev = simple_priv_to_dev(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) struct device_node *top = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) struct asoc_simple_dai *cpu_dai;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) struct asoc_simple_dai *codec_dai;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) int ret, single_cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /* Do it only CPU turn */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (!li->cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) dev_dbg(dev, "link_of (%pOF)\n", cpu_ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) li->link++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) cpu_dai =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) dai_props->cpu_dai = &priv->dais[li->dais++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) codec_dai =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) dai_props->codec_dai = &priv->dais[li->dais++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) /* Factor to mclk, used in hw_params() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) graph_parse_mclk_fs(top, cpu_ep, dai_props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) graph_parse_mclk_fs(top, codec_ep, dai_props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) NULL, &dai_link->dai_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) ret = asoc_simple_parse_cpu(cpu_ep, dai_link, &single_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) ret = asoc_simple_parse_codec(codec_ep, dai_link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) ret = asoc_simple_parse_tdm(cpu_ep, cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) ret = asoc_simple_parse_tdm(codec_ep, codec_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) ret = asoc_simple_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) ret = asoc_simple_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) ret = asoc_simple_set_dailink_name(dev, dai_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) "%s-%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) dai_link->cpus->dai_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) dai_link->codecs->dai_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) dai_link->ops = &graph_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) dai_link->init = asoc_simple_dai_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) asoc_simple_canonicalize_cpu(dai_link, single_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) asoc_simple_canonicalize_platform(dai_link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) static int graph_for_each_link(struct asoc_simple_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) struct link_info *li,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) int (*func_noml)(struct asoc_simple_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) struct device_node *cpu_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) struct device_node *codec_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) struct link_info *li),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) int (*func_dpcm)(struct asoc_simple_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) struct device_node *cpu_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) struct device_node *codec_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) struct link_info *li, int dup_codec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) struct of_phandle_iterator it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) struct device *dev = simple_priv_to_dev(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) struct device_node *node = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) struct device_node *cpu_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) struct device_node *cpu_ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) struct device_node *codec_ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) struct device_node *codec_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) struct device_node *codec_port_old = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) struct asoc_simple_data adata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) int rc, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) /* loop for all listed CPU port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) cpu_port = it.node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) cpu_ep = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* loop for all CPU endpoint */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) cpu_ep = of_get_next_child(cpu_port, cpu_ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (!cpu_ep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) /* get codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) codec_ep = of_graph_get_remote_endpoint(cpu_ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) codec_port = of_get_parent(codec_ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /* get convert-xxx property */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) memset(&adata, 0, sizeof(adata));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) graph_parse_convert(dev, codec_ep, &adata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) graph_parse_convert(dev, cpu_ep, &adata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * It is DPCM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * if Codec port has many endpoints,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * or has convert-xxx property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (dpcm_selectable &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) ((of_get_child_count(codec_port) > 1) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) adata.convert_rate || adata.convert_channels))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) ret = func_dpcm(priv, cpu_ep, codec_ep, li,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) (codec_port_old == codec_port));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) /* else normal sound */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) ret = func_noml(priv, cpu_ep, codec_ep, li);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) of_node_put(codec_ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) of_node_put(codec_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) codec_port_old = codec_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static int graph_parse_of(struct asoc_simple_priv *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) struct snd_soc_card *card = simple_priv_to_card(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) struct link_info li;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) ret = asoc_simple_parse_widgets(card, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) ret = asoc_simple_parse_routing(card, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) memset(&li, 0, sizeof(li));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) for (li.cpu = 1; li.cpu >= 0; li.cpu--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) * Detect all CPU first, and Detect all Codec 2nd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * In Normal sound case, all DAIs are detected
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * as "CPU-Codec".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * In DPCM sound case,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * all CPUs are detected as "CPU-dummy", and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) * all Codecs are detected as "dummy-Codec".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * To avoid random sub-device numbering,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) * detect "dummy-Codec" in last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) ret = graph_for_each_link(priv, &li,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) graph_dai_link_of,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) graph_dai_link_of_dpcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return asoc_simple_parse_card_name(card, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) static int graph_count_noml(struct asoc_simple_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) struct device_node *cpu_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) struct device_node *codec_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) struct link_info *li)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) struct device *dev = simple_priv_to_dev(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) li->link += 1; /* 1xCPU-Codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) li->dais += 2; /* 1xCPU + 1xCodec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) dev_dbg(dev, "Count As Normal\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) static int graph_count_dpcm(struct asoc_simple_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) struct device_node *cpu_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) struct device_node *codec_ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) struct link_info *li,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) int dup_codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) struct device *dev = simple_priv_to_dev(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) li->link++; /* 1xCPU-dummy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) li->dais++; /* 1xCPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) if (!dup_codec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) li->link++; /* 1xdummy-Codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) li->conf++; /* 1xdummy-Codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) li->dais++; /* 1xCodec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) dev_dbg(dev, "Count As DPCM\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) static void graph_get_dais_count(struct asoc_simple_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) struct link_info *li)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) struct device *dev = simple_priv_to_dev(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * link_num : number of links.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * CPU-Codec / CPU-dummy / dummy-Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) * dais_num : number of DAIs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * ccnf_num : number of codec_conf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * same number for "dummy-Codec"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * ex1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) * CPU0 --- Codec0 link : 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * CPU1 --- Codec1 dais : 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * CPU2 -/ ccnf : 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) * CPU3 --- Codec2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * => 7 DAIs = 4xCPU + 3xCodec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) * => 1 ccnf = 1xdummy-Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) * ex2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) * CPU0 --- Codec0 link : 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * CPU1 --- Codec1 dais : 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * CPU2 -/ ccnf : 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) * CPU3 -/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) * => 6 DAIs = 4xCPU + 2xCodec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) * => 1 ccnf = 1xdummy-Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) * ex3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) * CPU0 --- Codec0 link : 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) * CPU1 -/ dais : 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) * CPU2 --- Codec1 ccnf : 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) * CPU3 -/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) * => 6 DAIs = 4xCPU + 2xCodec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) * => 2 ccnf = 2xdummy-Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) * ex4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) * CPU0 --- Codec0 (convert-rate) link : 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) * CPU1 --- Codec1 dais : 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) * ccnf : 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) * => 4 DAIs = 2xCPU + 2xCodec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) * => 1 ccnf = 1xdummy-Codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) graph_for_each_link(priv, li,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) graph_count_noml,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) graph_count_dpcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) li->link, li->dais, li->conf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) static int graph_card_probe(struct snd_soc_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) static int graph_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) struct asoc_simple_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) struct snd_soc_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) struct link_info li;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) /* Allocate the private data and the DAI link array */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) card = simple_priv_to_card(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) card->owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) card->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) card->dapm_widgets = graph_dapm_widgets;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) card->probe = graph_card_probe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) memset(&li, 0, sizeof(li));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) graph_get_dais_count(priv, &li);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (!li.link || !li.dais)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) ret = asoc_simple_init_priv(priv, &li);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (IS_ERR(priv->pa_gpio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) ret = PTR_ERR(priv->pa_gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) ret = graph_parse_of(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) if (ret != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) dev_err(dev, "parse error %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) snd_soc_card_set_drvdata(card, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) asoc_simple_debug_info(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) ret = devm_snd_soc_register_card(dev, card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) asoc_simple_clean_reference(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) static int graph_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) struct snd_soc_card *card = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return asoc_simple_clean_reference(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) static const struct of_device_id graph_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) { .compatible = "audio-graph-card", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) { .compatible = "audio-graph-scu-card",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) .data = (void *)DPCM_SELECTABLE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) MODULE_DEVICE_TABLE(of, graph_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) static struct platform_driver graph_card = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) .name = "asoc-audio-graph-card",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) .pm = &snd_soc_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) .of_match_table = graph_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) .probe = graph_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) .remove = graph_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) module_platform_driver(graph_card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) MODULE_ALIAS("platform:asoc-audio-graph-card");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) MODULE_DESCRIPTION("ASoC Audio Graph Sound Card");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");