ASoC: simple-card: Move dai-link level properties away from dai subnodes
The properties like format, bitclock-master, frame-master, bitclock-inversion, and frame-inversion should be common to the dais connected with a dai-link. For bitclock-master and frame-master properties to be unambiguous they need to indicate the mastering dai node with a phandle. Signed-off-by: Jyri Sarha <jsarha@ti.com> Acked-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mark Brown <broonie@linaro.org>
This commit is contained in:
		
							parent
							
								
									389cb8348c
								
							
						
					
					
						commit
						b3ca11ff59
					
				| @ -1,6 +1,6 @@ | ||||
| Simple-Card: | ||||
| 
 | ||||
| Simple-Card specifies audio DAI connection of SoC <-> codec. | ||||
| Simple-Card specifies audio DAI connections of SoC <-> codec. | ||||
| 
 | ||||
| Required properties: | ||||
| 
 | ||||
| @ -10,26 +10,51 @@ Optional properties: | ||||
| 
 | ||||
| - simple-audio-card,name		: User specified audio sound card name, one string | ||||
| 					  property. | ||||
| - simple-audio-card,format		: CPU/CODEC common audio format. | ||||
| 					  "i2s", "right_j", "left_j" , "dsp_a" | ||||
| 					  "dsp_b", "ac97", "pdm", "msb", "lsb" | ||||
| - simple-audio-card,widgets		: Please refer to widgets.txt. | ||||
| - simple-audio-card,routing		: A list of the connections between audio components. | ||||
| 					  Each entry is a pair of strings, the first being the | ||||
| 					  connection's sink, the second being the connection's | ||||
| 					  source. | ||||
| - dai-tdm-slot-num			: Please refer to tdm-slot.txt. | ||||
| - dai-tdm-slot-width			: Please refer to tdm-slot.txt. | ||||
| Optional subnodes: | ||||
| 
 | ||||
| Required subnodes: | ||||
| - simple-audio-card,dai-link		: Container for dai-link level | ||||
| 					  properties and the CPU and CODEC | ||||
| 					  sub-nodes. This container may be | ||||
| 					  omitted when the card has only one | ||||
| 					  DAI link. See the examples and the | ||||
| 					  section bellow. | ||||
| 
 | ||||
| - simple-audio-card,dai-link		: container for the CPU and CODEC sub-nodes | ||||
| 					  This container may be omitted when the | ||||
| 					  card has only one DAI link. | ||||
| 					  See the examples. | ||||
| Dai-link subnode properties and subnodes: | ||||
| 
 | ||||
| - simple-audio-card,cpu			: CPU   sub-node | ||||
| - simple-audio-card,codec		: CODEC sub-node | ||||
| If dai-link subnode is omitted and the subnode properties are directly | ||||
| under "sound"-node the subnode property and subnode names have to be | ||||
| prefixed with "simple-audio-card,"-prefix. | ||||
| 
 | ||||
| Required dai-link subnodes: | ||||
| 
 | ||||
| - cpu					: CPU   sub-node | ||||
| - codec					: CODEC sub-node | ||||
| 
 | ||||
| Optional dai-link subnode properties: | ||||
| 
 | ||||
| - format				: CPU/CODEC common audio format. | ||||
| 					  "i2s", "right_j", "left_j" , "dsp_a" | ||||
| 					  "dsp_b", "ac97", "pdm", "msb", "lsb" | ||||
| - frame-master				: Indicates dai-link frame master. | ||||
| 					  phandle to a cpu or codec subnode. | ||||
| - bitclock-master			: Indicates dai-link bit clock master. | ||||
| 					  phandle to a cpu or codec subnode. | ||||
| - bitclock-inversion			: bool property. Add this if the | ||||
| 					  dai-link uses bit clock inversion. | ||||
| - frame-inversion			: bool property. Add this if the | ||||
| 					  dai-link uses frame clock inversion. | ||||
| 
 | ||||
| For backward compatibility the frame-master and bitclock-master | ||||
| properties can be used as booleans in codec subnode to indicate if the | ||||
| codec is the dai-link frame or bit clock master. In this case there | ||||
| should be no dai-link node, the same properties should not be present | ||||
| at sound-node level, and the bitclock-inversion and frame-inversion | ||||
| properties should also be placed in the codec node if needed. | ||||
| 
 | ||||
| Required CPU/CODEC subnodes properties: | ||||
| 
 | ||||
| @ -37,29 +62,21 @@ Required CPU/CODEC subnodes properties: | ||||
| 
 | ||||
| Optional CPU/CODEC subnodes properties: | ||||
| 
 | ||||
| - format				: CPU/CODEC specific audio format if needed. | ||||
| 					  see simple-audio-card,format | ||||
| - frame-master				: bool property. add this if subnode is frame master | ||||
| - bitclock-master			: bool property. add this if subnode is bitclock master | ||||
| - bitclock-inversion			: bool property. add this if subnode has clock inversion | ||||
| - frame-inversion			: bool property. add this if subnode has frame inversion | ||||
| - dai-tdm-slot-num			: Please refer to tdm-slot.txt. | ||||
| - dai-tdm-slot-width			: Please refer to tdm-slot.txt. | ||||
| - clocks / system-clock-frequency	: specify subnode's clock if needed. | ||||
| 					  it can be specified via "clocks" if system has | ||||
| 					  clock node (= common clock), or "system-clock-frequency" | ||||
| 					  (if system doens't support common clock) | ||||
| 
 | ||||
| Note: | ||||
|  * For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and | ||||
|    'frame-inversion', the simple card will use the settings of CODEC for both | ||||
|    CPU and CODEC sides as we need to keep the settings identical for both ends | ||||
|    of the link. | ||||
| 
 | ||||
| Example 1 - single DAI link: | ||||
| 
 | ||||
| sound { | ||||
| 	compatible = "simple-audio-card"; | ||||
| 	simple-audio-card,name = "VF610-Tower-Sound-Card"; | ||||
| 	simple-audio-card,format = "left_j"; | ||||
| 	simple-audio-card,bitclock-master = <&dailink0_master>; | ||||
| 	simple-audio-card,frame-master = <&dailink0_master>; | ||||
| 	simple-audio-card,widgets = | ||||
| 		"Microphone", "Microphone Jack", | ||||
| 		"Headphone", "Headphone Jack", | ||||
| @ -69,17 +86,12 @@ sound { | ||||
| 		"Headphone Jack", "HP_OUT", | ||||
| 		"External Speaker", "LINE_OUT"; | ||||
| 
 | ||||
| 	dai-tdm-slot-num = <2>; | ||||
| 	dai-tdm-slot-width = <8>; | ||||
| 
 | ||||
| 	simple-audio-card,cpu { | ||||
| 		sound-dai = <&sh_fsi2 0>; | ||||
| 	}; | ||||
| 
 | ||||
| 	simple-audio-card,codec { | ||||
| 	dailink0_master: simple-audio-card,codec { | ||||
| 		sound-dai = <&ak4648>; | ||||
| 		bitclock-master; | ||||
| 		frame-master; | ||||
| 		clocks = <&osc>; | ||||
| 	}; | ||||
| }; | ||||
| @ -105,31 +117,31 @@ Example 2 - many DAI links: | ||||
| sound { | ||||
| 	compatible = "simple-audio-card"; | ||||
| 	simple-audio-card,name = "Cubox Audio"; | ||||
| 	simple-audio-card,format = "i2s"; | ||||
| 
 | ||||
| 	simple-audio-card,dai-link@0 {		/* I2S - HDMI */ | ||||
| 		simple-audio-card,cpu { | ||||
| 		format = "i2s"; | ||||
| 		cpu { | ||||
| 			sound-dai = <&audio1 0>; | ||||
| 		}; | ||||
| 		simple-audio-card,codec { | ||||
| 		codec { | ||||
| 			sound-dai = <&tda998x 0>; | ||||
| 		}; | ||||
| 	}; | ||||
| 
 | ||||
| 	simple-audio-card,dai-link@1 {		/* S/PDIF - HDMI */ | ||||
| 		simple-audio-card,cpu { | ||||
| 		cpu { | ||||
| 			sound-dai = <&audio1 1>; | ||||
| 		}; | ||||
| 		simple-audio-card,codec { | ||||
| 		codec { | ||||
| 			sound-dai = <&tda998x 1>; | ||||
| 		}; | ||||
| 	}; | ||||
| 
 | ||||
| 	simple-audio-card,dai-link@2 {		/* S/PDIF - S/PDIF */ | ||||
| 		simple-audio-card,cpu { | ||||
| 		cpu { | ||||
| 			sound-dai = <&audio1 1>; | ||||
| 		}; | ||||
| 		simple-audio-card,codec { | ||||
| 		codec { | ||||
| 			sound-dai = <&spdif_codec>; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| @ -88,7 +88,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | ||||
| 
 | ||||
| static int | ||||
| asoc_simple_card_sub_parse_of(struct device_node *np, | ||||
| 			      unsigned int daifmt, | ||||
| 			      struct asoc_simple_dai *dai, | ||||
| 			      const struct device_node **p_node, | ||||
| 			      const char **name) | ||||
| @ -116,14 +115,6 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * bitclock-inversion, frame-inversion | ||||
| 	 * bitclock-master,    frame-master | ||||
| 	 * and specific "format" if it has | ||||
| 	 */ | ||||
| 	dai->fmt = snd_soc_of_parse_daifmt(np, NULL, NULL, NULL); | ||||
| 	dai->fmt |= daifmt; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * dai->sysclk come from | ||||
| 	 *  "clocks = <&xxx>" (if system has common clock) | ||||
| @ -151,37 +142,135 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int simple_card_cpu_codec_of(struct device_node *node, | ||||
| 				int daifmt, | ||||
| 				struct snd_soc_dai_link *dai_link, | ||||
| 				struct simple_dai_props *dai_props) | ||||
| static int simple_card_dai_link_of(struct device_node *node, | ||||
| 				   struct device *dev, | ||||
| 				   struct snd_soc_dai_link *dai_link, | ||||
| 				   struct simple_dai_props *dai_props) | ||||
| { | ||||
| 	struct device_node *np; | ||||
| 	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 sub-node */ | ||||
| 	ret = -EINVAL; | ||||
| 	np = of_get_child_by_name(node, "simple-audio-card,cpu"); | ||||
| 	if (np) { | ||||
| 		ret = asoc_simple_card_sub_parse_of(np, daifmt, | ||||
| 						&dai_props->cpu_dai, | ||||
| 						&dai_link->cpu_of_node, | ||||
| 						&dai_link->cpu_dai_name); | ||||
| 		of_node_put(np); | ||||
| 	} | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 	if (!strcmp("sound", node->name)) | ||||
| 		prefix = "simple-audio-card,"; | ||||
| 
 | ||||
| 	/* CODEC sub-node */ | ||||
| 	ret = -EINVAL; | ||||
| 	np = of_get_child_by_name(node, "simple-audio-card,codec"); | ||||
| 	if (np) { | ||||
| 		ret = asoc_simple_card_sub_parse_of(np, daifmt, | ||||
| 						&dai_props->codec_dai, | ||||
| 						&dai_link->codec_of_node, | ||||
| 						&dai_link->codec_dai_name); | ||||
| 		of_node_put(np); | ||||
| 	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 simple-audio-card,cpu DT node\n", | ||||
| 			__func__); | ||||
| 		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); | ||||
| 	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 simple-audio-card,codec DT node\n", | ||||
| 			__func__); | ||||
| 		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); | ||||
| 	if (ret < 0) | ||||
| 		goto dai_link_of_err; | ||||
| 
 | ||||
| 	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, "%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; | ||||
| 
 | ||||
| 	/* 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; | ||||
| 
 | ||||
| 	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); | ||||
| 
 | ||||
| dai_link_of_err: | ||||
| 	if (np) | ||||
| 		of_node_put(np); | ||||
| 	if (bitclkmaster) | ||||
| 		of_node_put(bitclkmaster); | ||||
| 	if (framemaster) | ||||
| 		of_node_put(framemaster); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -192,19 +281,11 @@ static int asoc_simple_card_parse_of(struct device_node *node, | ||||
| { | ||||
| 	struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; | ||||
| 	struct simple_dai_props *dai_props = priv->dai_props; | ||||
| 	struct device_node *np; | ||||
| 	char *name; | ||||
| 	unsigned int daifmt; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* parsing the card name from DT */ | ||||
| 	snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); | ||||
| 
 | ||||
| 	/* get CPU/CODEC common format via simple-audio-card,format */ | ||||
| 	daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,", NULL, | ||||
| 					 NULL) & | ||||
| 		(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); | ||||
| 
 | ||||
| 	/* off-codec widgets */ | ||||
| 	if (of_property_read_bool(node, "simple-audio-card,widgets")) { | ||||
| 		ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, | ||||
| @ -221,71 +302,31 @@ static int asoc_simple_card_parse_of(struct device_node *node, | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* loop on the DAI links */ | ||||
| 	np = NULL; | ||||
| 	for (;;) { | ||||
| 		if (multi) { | ||||
| 			np = of_get_next_child(node, np); | ||||
| 			if (!np) | ||||
| 				break; | ||||
| 		} | ||||
| 	dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? | ||||
| 		priv->snd_card.name : ""); | ||||
| 
 | ||||
| 		ret = simple_card_cpu_codec_of(multi ? np : node, | ||||
| 					daifmt, dai_link, dai_props); | ||||
| 	if (multi) { | ||||
| 		struct device_node *np = NULL; | ||||
| 		int i; | ||||
| 		for (i = 0; (np = of_get_next_child(node, np)); i++) { | ||||
| 			dev_dbg(dev, "\tlink %d:\n", i); | ||||
| 			ret = simple_card_dai_link_of(np, dev, dai_link + i, | ||||
| 						      dai_props + i); | ||||
| 			if (ret < 0) { | ||||
| 				of_node_put(np); | ||||
| 				return ret; | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		ret = simple_card_dai_link_of(node, dev, dai_link, dai_props); | ||||
| 		if (ret < 0) | ||||
| 			goto err; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC | ||||
| 		 * while the other bits should be identical unless buggy SW/HW design. | ||||
| 		 */ | ||||
| 		dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt; | ||||
| 
 | ||||
| 		if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { | ||||
| 			ret = -EINVAL; | ||||
| 			goto err; | ||||
| 		} | ||||
| 
 | ||||
| 		/* simple-card assumes platform == cpu */ | ||||
| 		dai_link->platform_of_node = dai_link->cpu_of_node; | ||||
| 
 | ||||
| 		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; | ||||
| 
 | ||||
| 		if (!multi) | ||||
| 			break; | ||||
| 
 | ||||
| 		dai_link++; | ||||
| 		dai_props++; | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* card name is created from CPU/CODEC dai name */ | ||||
| 	dai_link = priv->snd_card.dai_link; | ||||
| 	if (!priv->snd_card.name) | ||||
| 		priv->snd_card.name = dai_link->name; | ||||
| 
 | ||||
| 	dev_dbg(dev, "card-name : %s\n", priv->snd_card.name); | ||||
| 	dev_dbg(dev, "platform : %04x\n", daifmt); | ||||
| 	dai_props = priv->dai_props; | ||||
| 	dev_dbg(dev, "cpu : %s / %04x / %d\n", | ||||
| 		dai_link->cpu_dai_name, | ||||
| 		dai_props->cpu_dai.fmt, | ||||
| 		dai_props->cpu_dai.sysclk); | ||||
| 	dev_dbg(dev, "codec : %s / %04x / %d\n", | ||||
| 		dai_link->codec_dai_name, | ||||
| 		dai_props->codec_dai.fmt, | ||||
| 		dai_props->codec_dai.sysclk); | ||||
| 		priv->snd_card.name = priv->snd_card.dai_link->name; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	of_node_put(np); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /* update the reference count of the devices nodes at end of probe */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user