int asoc_simple_card_parse_daifmt(struct device *dev, struct device_node *node, struct device_node *codec, char *prefix, unsigned int *retfmt) { struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; unsigned int daifmt; daifmt = snd_soc_of_parse_daifmt(node, prefix, &bitclkmaster, &framemaster); daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; if (!bitclkmaster && !framemaster) { /* * No dai-link level and master setting was not found from * sound node level, revert back to legacy DT parsing and * take the settings from codec node. */ dev_dbg(dev, "Revert to legacy daifmt parsing\n"); daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); } else { if (codec == bitclkmaster) daifmt |= (codec == framemaster) ? SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; else daifmt |= (codec == framemaster) ? SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; } of_node_put(bitclkmaster); of_node_put(framemaster); *retfmt = daifmt; dev_dbg(dev, "format : %04x\n", daifmt); return 0; }
static int asoc_simple_card_parse_daifmt(struct device_node *node, struct simple_card_data *priv, struct device_node *codec, char *prefix, int idx) { struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); struct device *dev = simple_priv_to_dev(priv); struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; unsigned int daifmt; daifmt = snd_soc_of_parse_daifmt(node, prefix, &bitclkmaster, &framemaster); daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; if (strlen(prefix) && !bitclkmaster && !framemaster) { /* * No dai-link level and master setting was not found from * sound node level, revert back to legacy DT parsing and * take the settings from codec node. */ dev_dbg(dev, "Revert to legacy daifmt parsing\n"); daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); } else { if (codec == bitclkmaster) daifmt |= (codec == framemaster) ? SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; else daifmt |= (codec == framemaster) ? SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; } dai_link->dai_fmt = daifmt; of_node_put(bitclkmaster); of_node_put(framemaster); return 0; }
/* Get sound card infos: audio-codec i2s-controller format continuous-clock bitclock-inversion frame-inversion bitclock-master frame-master Get audio-codec and i2s-controller in this fun, and get oher infos in fun snd_soc_of_parse_daifmt(). Set in dts: dais { dai0 { audio-codec = <&codec_of_node>; i2s-controller = <&cpu_of_node>; format = "i2s"; //continuous-clock; //bitclock-inversion; //frame-inversion; //bitclock-master; //frame-master; }; dai1 { audio-codec = <&codec_of_node>; i2s-controller = <&cpu_of_node>; format = "dsp_a"; //continuous-clock; bitclock-inversion; //frame-inversion; //bitclock-master; //frame-master; }; }; */ int rockchip_of_get_sound_card_info_(struct snd_soc_card *card, bool is_need_fmt) { struct device_node *dai_node, *child_dai_node; int dai_num; dai_node = of_get_child_by_name(card->dev->of_node, "dais"); if (!dai_node) { dev_err(card->dev, "%s() Can not get child: dais\n", __func__); return -EINVAL; } dai_num = 0; for_each_child_of_node(dai_node, child_dai_node) { if (is_need_fmt) { card->dai_link[dai_num].dai_fmt = snd_soc_of_parse_daifmt(child_dai_node, NULL); if ((card->dai_link[dai_num].dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == 0) { dev_err(card->dev, "Property 'format' missing or invalid\n"); return -EINVAL; } } card->dai_link[dai_num].codec_name = NULL; card->dai_link[dai_num].cpu_dai_name = NULL; card->dai_link[dai_num].platform_name = NULL; card->dai_link[dai_num].codec_of_node = of_parse_phandle( child_dai_node, "audio-codec", 0); if (!card->dai_link[dai_num].codec_of_node) { dev_err(card->dev, "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } card->dai_link[dai_num].cpu_of_node = of_parse_phandle( child_dai_node, "i2s-controller", 0); if (!card->dai_link[dai_num].cpu_of_node) { dev_err(card->dev, "Property 'i2s-controller' missing or invalid\n"); return -EINVAL; } card->dai_link[dai_num].platform_of_node = card->dai_link[dai_num].cpu_of_node; if (++dai_num >= card->num_links) break; } if (dai_num < card->num_links) { dev_err(card->dev, "%s() Can not get enough property for dais, dai: %d, max dai num: %d\n", __func__, dai_num, card->num_links); return -EINVAL; } return 0; }
} else { clk = of_clk_get(args.np, 0); if (!IS_ERR(clk)) dai->sysclk = clk_get_rate(clk); } return 0; } static int asoc_s; struct device *dev = simple_priv_to_dev(priv); struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; unsigned int daifmt; daifmt = snd_soc_of_parse_daifmt(node, prefix, &bitclkmaster, &framemaster); daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; if (strlen(prefix) && !bitclkmaster && !framemaster) { /* * No dai-link level and master setting was not found from * sound node level, revert back to legacy DT parsing and * take the settings from codec node. */ dev_dbg(dev, "Revert to legacy daifmt parsing\n"); daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); } else { if (codec == bitclkmaster) daifmt |= (codec == framemaster) ?
static int asoc_simple_card_dai_link_of(struct device_node *node, struct simple_card_data *priv, int idx, bool is_top_level_node) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); struct device_node *np = NULL; struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; unsigned int daifmt; char *name; char prop[128]; char *prefix = ""; int ret, cpu_args; /* For single DAI link & old style of DT node */ if (is_top_level_node) prefix = "simple-audio-card,"; daifmt = snd_soc_of_parse_daifmt(node, prefix, &bitclkmaster, &framemaster); daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; snprintf(prop, sizeof(prop), "%scpu", prefix); np = of_get_child_by_name(node, prop); if (!np) { ret = -EINVAL; dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); goto dai_link_of_err; } ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai, &dai_link->cpu_of_node, &dai_link->cpu_dai_name, &cpu_args); if (ret < 0) goto dai_link_of_err; dai_props->cpu_dai.fmt = daifmt; switch (((np == bitclkmaster) << 4) | (np == framemaster)) { case 0x11: dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS; break; case 0x10: dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM; break; case 0x01: dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS; break; default: dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM; break; } of_node_put(np); snprintf(prop, sizeof(prop), "%scodec", prefix); np = of_get_child_by_name(node, prop); if (!np) { ret = -EINVAL; dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); goto dai_link_of_err; } ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai, &dai_link->codec_of_node, &dai_link->codec_dai_name, NULL); if (ret < 0) goto dai_link_of_err; if (strlen(prefix) && !bitclkmaster && !framemaster) { /* * No DAI link level and master setting was found * from sound node level, revert back to legacy DT * parsing and take the settings from codec node. */ dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n", __func__); dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt = snd_soc_of_parse_daifmt(np, NULL, NULL, NULL) | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); } else { dai_props->codec_dai.fmt = daifmt; switch (((np == bitclkmaster) << 4) | (np == framemaster)) { case 0x11: dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM; break; case 0x10: dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS; break; case 0x01: dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM; break; default: dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS; break; } } if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { ret = -EINVAL; goto dai_link_of_err; } /* Simple Card assumes platform == cpu */ dai_link->platform_of_node = dai_link->cpu_of_node; /* DAI link name is created from CPU/CODEC dai name */ name = devm_kzalloc(dev, strlen(dai_link->cpu_dai_name) + strlen(dai_link->codec_dai_name) + 2, GFP_KERNEL); sprintf(name, "%s-%s", dai_link->cpu_dai_name, dai_link->codec_dai_name); dai_link->name = dai_link->stream_name = name; dai_link->ops = &asoc_simple_card_ops; dai_link->init = asoc_simple_card_dai_init; dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); dev_dbg(dev, "\tcpu : %s / %04x / %d\n", dai_link->cpu_dai_name, dai_props->cpu_dai.fmt, dai_props->cpu_dai.sysclk); dev_dbg(dev, "\tcodec : %s / %04x / %d\n", dai_link->codec_dai_name, dai_props->codec_dai.fmt, dai_props->codec_dai.sysclk); /* * In soc_bind_dai_link() will check cpu name after * of_node matching if dai_link has cpu_dai_name. * but, it will never match if name was created by * fmt_single_name() remove cpu_dai_name if cpu_args * was 0. See: * fmt_single_name() * fmt_multiple_name() */ if (!cpu_args) dai_link->cpu_dai_name = NULL; dai_link_of_err: if (np) of_node_put(np); if (bitclkmaster) of_node_put(bitclkmaster); if (framemaster) of_node_put(framemaster); return ret; }