Difference between revisions of "SAI device tree configuration"

[quality revision] [quality revision]
m (DT configuration (board level))
 
m
 
Template:ArticleMainWriter Template:ArticleApprovedVersion

1 Article purpose[edit]

This article explains how to configure the SAI internal peripheral when it is assigned to the Linux® Linux® OS. In that case, it is controlled by the ALSA framework.

The configuration is performed using the device tree mechanism that provides a hardware description of the SAI peripheral, used by the SAI linux driver.

If the peripheral is assigned to another execution context, refer to How to assign an internal peripheral to a runtime context article for guidelines on peripheral assignment and configuration.

2 DT bindings documentation[edit]

STM32 SAI device tree bindings [1] document describes all the required and optional configuration properties.

3 DT configuration[edit]

This hardware description is a combination of the STM32 microprocessor device tree files (.dtsi extension) and board device tree files (.dts extension). See the Device tree for an explanation of the device tree file split.
The SAI is used as a component of a sound card through Linux® kernel ALSA framework. The device tree nodes related to the sound card are described in board device tree.

The STM32 SAI peripheral includes two independent audio subblocks that share common resources. The SAI device tree nodes reflects this architecture, as shown in the SAI DT sample below.

Clock overview Pinctrl overview
SAI device tree configuration Template:WarningImageMapOverlay
&saix {
	/* SAIx parent node. Configure common ressources  */
	clock-names = "pclk", "x8k", "x11k"; /* Peripheral and parent clock configuration.  */
	... 

	saixa {
		/* child node. Configure ressources dedicated to SAIxA subblock */
		clock-names = "sai_ck"; /* SAIxA kernel clock confguration.  */
		pinctrl-names = "default"; /* GPIOsA configuration.  */
		... 
	};

	saixb {
		/* child node. Configure ressources dedicated to SAIxB subblock */
		clock-names = "sai_ck"; /* SAIxB kernel clock confguration.  */
		pinctrl-names = "default"; /* GPIOsB configuration.  */
		...
	};
};

The STM32CubeMX can be used to generate the board device tree. Refer to How to configure the DT using STM32CubeMX for more details.

3.1 DT configuration (STM32 level)[edit]

The SAI nodes are declared in STM32 microprocessor device tree. They describe hardware parameters such as registers address, interrupt and DMA. This set of properties may not vary for a given STM32MPU. For STM32MP1, the corresponding DT file is stm32mp157cstm32mp151.dtsi[2].

Warning.png This device tree part is related to STM32 microprocessors. It should be kept as is, without being modified by the end-user.

3.2 DT configuration (board level)[edit]

The SAI configuration is board dependent, whether is it connected or not to an external component such as an audio codec. The links between the SAI and the other components define a soundcard. This soundcard has to be configured in the board device tree. Refer to soundcard configuration for examples of SAI configuration on various STM32MPU boards.

3.3 DT configuration examples[edit]

This chapter describes in detail details advanced SAI configurations. These examples are based on STM32MP1 boards SAI use cases. The corresponding device trees can be found in soundcard article.

Info.png In this chapter, "SAI" stands for a an SAI subblock, SAIxA or SAIxB.

3.3.1 Setting SAI as a master clock provider[edit]

The SAI peripheral can provide a clock to an external component (such as a codec) through the mclk output pin. In this case, it acts as master clock (mclk) provider. The below DT sample gives an example of SAI configuration as mclk provider.

In this example the codec driver supports mclk input based on ASoC DAPM mechanism. If this is not the case, the codec driver has to be adapted. This can be achieved by adding a DAPM clock supply widget to the codec driver. An example of the required DAPM clock supply DAPM widget can be found in Cirrus CS42L51 codec source code[3]. In the below device tree example, the codec DAPM clock widget is named "MCLKX".

To allow mclk activation/deactivation, a DAPM route must be defined in the DT. This route is defined in the sound node, as shown below.

soundcard {
	routing =
		"Playback" , "MCLKX", /* Set a route between "MCLKX" and "playback" widgets */
		"Capture" , "MCLKX";
	...
};

codec: {
	clocks = <&sai2a>;     /* The codec is a consumer of SAI2A master clock */
	clock-names = "MCLKX"; /* Feed MCLKX codec clock with SAI2A master clock provider */
	...
};

&sai2 {
	...
		
	sai2a: audio-controller@4400b004 {
		#clock-cells = <0>; /* Set SAI2A as master clock provider */
		...
		sai2a_endpoint: endpoint {
			mclk-fs = <256>; /* Set mclk/fs ratio. (256 or 512) */
		};
	};
};

3.3.2 Sharing master clock between two SAIs[edit]

When a an SAI is set as a master clock provider, another SAI can share this master clock. This can be achieved by setting a the SAI as a mclk consumer through DT configuration. This means that the mclk consumer SAI can request to change the mclk rate, according to its own audio stream sampling rate. This implies that audio sampling rates must be identical when both SAI subblocks are used.

&sai2 {
	...
		
	sai2a: audio-controller@4400b004 {
		#clock-cells = <0>; /* Set SAI2A as master clock provider */
		...
	};

	sai2b: audio-controller@4400b024 {
		clocks = <&rcc SAI2_K>, <&sai2a>; /* SAI2B is a consumer of SAI2A master clock */
		clock-names = "sai_ck", "MCLK";   /* Feed SAI2B MCLK clock with SAI2A master clock provider */
		...
		sai2b_endpoint: endpoint {
			mclk-fs = <256>; /* Set mclk/fs ratio. (256 or 512) */
		};
	};
};

3.3.3 Sharing bus clocks the codec interface between two SAIs[edit]

Two SAIs can share be connected to the same codec interface. This is done , by sharing the I2S bus clocks (i.e. FS and SCK clocks). To achieve this, the codec

SAIs sharing the same codec interface

In such case:

  • The codec has to be
defined as
  • master on the I2S bus
master
  • .
  • Only one SAI is connected to the bus clocks. The other SAI has to be configured as a slave of the SAI connected to the bus.
In this case, the GPIOs of both subblocks
  • The I2S bus I/O pins must be managed at parent level, so that the corresponding pins are activated whatever the running SAI.

From ASoC point of view:
Two CPU DAIs have to be connected to the same codec DAI. Such topology is not supported natively by the ASoC audio graph card. Indeed, when the audio graph card parses the codec nodes, it expects to find DAI interface indexes, matching the endpoints indexes. A workaround consists in implementing the of_xlate_dai_id callback in the codec driver, to allow using the same DAI interface for both endpoints. An example of code can be found below or in the Cirrus CS42L51 codec source code[3].

  • Code example
static int codec_of_xlate_dai_id(struct snd_soc_component *component,
				   struct device_node *endpoint)
{
	/* return dai id 0, whatever the endpoint index */
	return 0;
}

  • DT example
codec {
	...
	codec_port {
		codec_tx_endpoint {
			remote-endpoint = <&sai2a_endpoint>;
			frame-master;    /* Set codec as master of SAI2A for FS clock. */
			bitclock-master; /* Set codec as master of SAI2A for SCK clock. */
		};

		codec_rx_endpoint { /* Second endpoint mapped on codec DAI 0 via of_xlate */
			remote-endpoint = <&sai2b_endpoint>;
			frame-master;    /* Set codec as master of SAI2B for FS clock. */
			bitclock-master; /* Set codec as master of SAI2B for SCK clock. */
		};
	};
};

&sai2 {
	pinctrl-names = "default", "sleep"; /* Defines SAI2A/B GPIOs at parent level. */
	pinctrl-0 = <&sai2a_pins_a>, <&sai2b_pins_b>;
	pinctrl-1 = <&sai2a_sleep_pins_a>, <&sai2b_sleep_pins_b>;
	...

	sai2a: audio-controller@4400b004 {
		remote-endpoint = <&codec_tx_endpoint>;
		...
	};

	sai2b: audio-controller@4400b024 {
		remote-endpoint = <&codec_rx_endpoint>;
		st,sync = <&sai2a 2>; /* Set SAI2B as slave of SAI2BSAI2A. */
	};
};

4 How to configure the DT using STM32CubeMX[edit]

The STM32CubeMX tool can be used to configure the STM32MPU device and get the corresponding platform configuration device tree files.
The STM32CubeMX may not support all the properties described in the above DT bindings documentation paragraph. If so, the tool inserts user sections in the generated device tree. These sections can then be edited to add some properties and they are preserved from one generation to another. Refer to STM32CubeMX user manual for further information.

Warning.png The STM32CubeMX does not allow the generation of all the nodes required to configure a soundcard. The soundcard node and the codec nodes have to be filled manually through user sections.

5 References[edit]



<noinclude>

{{ArticleBasedOnModel | [[Peripheral or framework device tree configuration model]]}}
{{ArticleMainWriter | OlivierM}}
{{ArticleApprovedVersion | OlivierM | ArnaudP(Passed 22Nov'18) | No previous approved version | AnneJ - 26Nov'18 - 9809 | 14Jan'19}}

[[Category:Device tree configuration]]
[[Category:ALSA]]</noinclude>

== Article purpose ==
This article explains how to configure the [[SAI internal peripheral]] when it is assigned to the '''Linux®Linux<sup>&reg;</sup> OS'''. In that case, it is controlled by the [[ALSA_overview|ALSA framework]].

The configuration is performed using the [[Device_tree|device tree]] mechanism that provides a hardware description of the SAI peripheral, used by the [[SAI_Linux_driver|SAI linux driver]].
If the peripheral is assigned to another execution context, refer to [[How to assign an internal peripheral to a runtime context]] article for guidelines on peripheral assignment and configuration.
== DT bindings documentation ==
STM32 SAI device tree bindings <ref name="sai bindings">[https://www.kernel.org/doc/Documentation/devicetree/bindings/sound/st%2Cstm32-sai.txt STM32 SAI bindings]</ref> document describes all the required and optional configuration properties. 

== DT configuration ==
This hardware description is a combination of the '''STM32 microprocessor''' device tree files (''.dtsi'' extension) and '''board''' device tree files (''.dts'' extension). See the [[Device tree]] for an explanation of the device tree file split.<br>

The SAI is used as a component of a sound card through Linux<sup>&reg;</sup> kernel ALSA framework. The device tree nodes related to the sound card are described in [[#DT_configuration_.28board_level.29|board device tree]].

The STM32 SAI peripheral includes two independent audio subblocks that share common resources.
The SAI device tree nodes reflects this architecture, as shown in the SAI DT sample below.
{{
ImageMap|
Image:Sai_configuration.png {{!}} frame {{!}} center{{!}} SAI device tree configuration<br/> {{WarningImageMapOverlay}}
rect 4 135 158 404 [[Clock_overview]]
rect 625 222 764 403 [[Pinctrl_overview]]
}}

 &saix {
 	{{highlight|/* SAIx parent node. Configure common ressources  */}}
 	clock-names = "pclk", "x8k", "x11k"; {{highlight|/* Peripheral and parent clock configuration.  */}}
 	... 

 	saixa {
 		{{highlight|/* child node. Configure ressources dedicated to SAIxA subblock */}}
 		clock-names = "sai_ck"; {{highlight|/* SAIxA kernel clock confguration.  */}}
 		pinctrl-names = "default"; {{highlight|/* GPIOsA configuration.  */}}
 		... 
 	};

 	saixb {
 		{{highlight|/* child node. Configure ressources dedicated to SAIxB subblock */}}
 		clock-names = "sai_ck"; {{highlight|/* SAIxB kernel clock confguration.  */}}
 		pinctrl-names = "default"; {{highlight|/* GPIOsB configuration.  */}}
 		...
 	};
 };

The '''STM32CubeMX''' can be used to generate the board device tree. Refer to [[#How_to_configure_the_DT_using_STM32CubeMX|How to configure the DT using STM32CubeMX]] for more details.

=== DT configuration (STM32 level) ===
The SAI nodes are declared in STM32 microprocessor device tree. They describe hardware parameters such as registers address, interrupt and DMA. This set of properties may not vary for a given STM32MPU. For STM32MP1, the corresponding DT file is stm32mp157cstm32mp151.dtsi<ref name="stm32mp157cstm32mp151.dtsi">{{CodeSource | Linux kernel | arch/arm/boot/dts/stm32mp157cstm32mp151.dtsi}}</ref>.
{{Warning|This device tree part is related to STM32 microprocessors. It should be kept as is, without being modified by the end-user.}}

=== DT configuration (board level) ===

The SAI configuration is board dependent, whether is it connected or not to an external component such as an audio codec. The links between the SAI and the other components define a soundcard. This soundcard has to be configured in the board device tree. Refer to [[Soundcard configuration|soundcard configuration]] for examples of SAI configuration on various STM32MPU boards.

=== DT configuration examples ===

This chapter describes in detaildetails advanced SAI configurations. These examples are based on [[:Category:Getting_started_with_STM32MP1_boards|STM32MP1 boards]] SAI use cases. The corresponding device trees can be found in [[Soundcard configuration|soundcard]] article.
{{Info|In this chapter, "SAI" stands for aan SAI subblock, SAIxA or SAIxB.}}

==== '''Setting SAI as a master clock provider''' ====
The SAI peripheral can provide a clock to an external component (such as a codec) through the mclk output pin. In this case, it acts as master clock (mclk) provider. The below DT sample gives an example of SAI configuration as mclk provider.

In this example the codec driver supports mclk input based on ASoC DAPM mechanism.
If this is not the case, the codec driver has to be adapted. This can be achieved by adding a DAPM clock supply widget to the codec driver. An example of the required DAPM clock supply DAPM widget can be found in Cirrus CS42L51 codec source code<ref name="CS42L51 code">{{CodeSource | Linux kernel | sound/soc/codecs/cs42l51.c}}</ref>.
In the below device tree example, the codec DAPM clock widget is named "MCLKX". 

To allow mclk activation/deactivation, a DAPM route must be defined in the DT. This route is defined in the sound node, as shown below.

 soundcard {
 	routing =
 		"Playback" , "MCLKX", {{highlight|/* Set a route between "MCLKX" and "playback" widgets */}}
 		"Capture" , "MCLKX";
 	...
 };

 codec: {
 	clocks = <&sai2a>;     {{highlight|/* The codec is a consumer of SAI2A master clock */}}
 	clock-names = "MCLKX"; {{highlight|/* Feed MCLKX codec clock with SAI2A master clock provider */}}
 	...
 };

 &sai2 {
 	...

 	sai2a: audio-controller@4400b004 {
 		#clock-cells = <0>; {{highlight|/* Set SAI2A as master clock provider */}}
 		...
 		sai2a_endpoint: endpoint {
 			mclk-fs = <256>; {{highlight|/* Set mclk/fs ratio. (256 or 512) */}}
 		};
 	};
 };

==== '''Sharing master clock between two SAIs''' ====

When aan SAI is set as a master clock provider, another SAI can share this master clock.
This can be achieved by setting athe SAI as a mclk consumer through DT configuration.
This means that the mclk consumer SAI can request to change the mclk rate, according to its own audio stream sampling rate.
This implies that audio sampling rates must be identical when both SAI subblocks are used.

 &sai2 {
 	...

 	sai2a: audio-controller@4400b004 {
 		#clock-cells = <0>; {{highlight|/* Set SAI2A as master clock provider */}}
 		...
 	};

 	sai2b: audio-controller@4400b024 {
 		clocks = <&rcc SAI2_K>, <&sai2a>; {{highlight|/* SAI2B is a consumer of SAI2A master clock */}}
 		clock-names = "sai_ck", "MCLK";   {{highlight|/* Feed SAI2B MCLK clock with SAI2A master clock provider */}}
 		...
 		sai2b_endpoint: endpoint {
 			mclk-fs = <256>; {{highlight|/* Set mclk/fs ratio. (256 or 512) */}}
 		};
 	};
 };

==== '''Sharing bus clocks the codec interface between two SAIs''' ====

Two SAIs can share be connected to the same codec interface. This is done , by sharing the I2S bus clocks (i.e. FS and SCK clocks). To achieve this, the codec has to be defined as the I2S bus master.


[[Image:sai_shared_codec.png {{!}} frame {{!}} center{{!}} SAIs sharing the same codec interface|link=]]

In such case:
*The codec has to be master on the I2S bus. 
*Only one SAI is connected to the bus clocks. The other SAI has to be configured as a slave of the SAI connected to the bus.In this case, the GPIOs of both subblocks *The I2S bus I/O pins must be managed at parent level, so that the corresponding pins are activated whatever the running SAI.
 codec {
 	...
 	codec_port {
 		codec_From ASoC point of view:<BR>

Two CPU DAIs have to be connected to the same codec DAI. Such topology is not supported natively by the ASoC audio graph card. Indeed, when the audio graph card parses the codec nodes, it expects to find DAI interface indexes, matching the endpoints indexes. A workaround consists in implementing the of_xlate_dai_id callback in the codec driver, to allow using the same DAI interface for both endpoints. An example of code can be found below or in the Cirrus CS42L51 codec source code<ref name="CS42L51 code">{{CodeSource | Linux kernel | sound/soc/codecs/cs42l51.c}}</ref>.

* Code example
<syntaxhighlight lang="c">

static int codec_of_xlate_dai_id(struct snd_soc_component *component,
				   struct device_node *endpoint)
{
	/* return dai id 0, whatever the endpoint index */
	return 0;
}</syntaxhighlight>


* DT example

 codec {
 	...
 	codec_port {
 		codec_tx_endpoint {
 			remote-endpoint = <&sai2a_endpoint>;
 			frame-master;    {{highlight|/* Set codec as master of SAI2A for FS clock. */}}
 			bitclock-master; {{highlight|/* Set codec as master of SAI2A for SCK clock. */}}
 		};	};
 };


 		codec_rx_endpoint { {{highlight|/* Second endpoint mapped on codec DAI 0 via of_xlate */}}
 			remote-endpoint = <&sai2b_endpoint>;
 			frame-master;    {{highlight|/* Set codec as master of SAI2B for FS clock. */}}
 			bitclock-master; {{highlight|/* Set codec as master of SAI2B for SCK clock. */}}
 		};
 	};
 };
&sai2 {
 	pinctrl-names = "default", "sleep"; {{highlight|/* Defines SAI2A/B GPIOs at parent level. */}}
 	pinctrl-0 = <&sai2a_pins_a>, <&sai2b_pins_b>;
 	pinctrl-1 = <&sai2a_sleep_pins_a>, <&sai2b_sleep_pins_b>;
 	...

 	sai2a: audio-controller@4400b004 {...
 	};

 	sai2b: audio-controller@4400b024 {remote-endpoint = <&codec_tx_endpoint>;
 		...
 	};

 	sai2b: audio-controller@4400b024 {
 		remote-endpoint = <&codec_rx_endpoint>;st,sync = <&sai2a 2>; {{highlight|/* Set SAI2B as slave of SAI2BSAI2A. */}}
 	};
 };

==How to configure the DT using STM32CubeMX==
The [[STM32CubeMX]] tool can be used to configure the STM32MPU device and get the corresponding [[Device_tree#STM32|platform configuration device tree]] files.<br />

The STM32CubeMX may not support all the properties described in the above [[#DT bindings documentation|DT bindings documentation]] paragraph. If so, the tool inserts '''user sections''' in the generated device tree. These sections can then be edited to add some properties and they are preserved from one generation to another. Refer to [[STM32CubeMX]] user manual for further information.
{{Warning|The STM32CubeMX does not allow the generation of all the nodes required to configure a soundcard. The soundcard node and the codec nodes have to be filled manually through user sections.}}

==References==
<references /><references />

<noinclude>

{{ArticleBasedOnModel | Peripheral or framework device tree configuration model}}
{{PublicationRequestId | 14728 | 2020-01-28 | AnneJ (9809)}}

[[Category:Device tree configuration]]
[[Category:ALSA]]</noinclude>
(24 intermediate revisions by 5 users not shown)
Line 1: Line 1:
<noinclude>
 
{{ArticleBasedOnModel | [[Peripheral or framework device tree configuration model]]}}
 
{{ArticleMainWriter | OlivierM}}
 
{{ArticleApprovedVersion | OlivierM | ArnaudP(Passed 22Nov'18) | No previous approved version | AnneJ - 26Nov'18 - 9809 | 14Jan'19}}
 
 
[[Category:Device tree configuration]]
 
[[Category:ALSA]]
 
</noinclude>
 
 
 
== Article purpose ==
 
== Article purpose ==
This article explains how to configure the [[SAI internal peripheral]] when it is assigned to the '''Linux® OS'''. In that case, it is controlled by the [[ALSA_overview|ALSA framework]].
+
This article explains how to configure the [[SAI internal peripheral]] when it is assigned to the '''Linux<sup>&reg;</sup> OS'''. In that case, it is controlled by the [[ALSA_overview|ALSA framework]].
   
 
The configuration is performed using the [[Device_tree|device tree]] mechanism that provides a hardware description of the SAI peripheral, used by the [[SAI_Linux_driver|SAI linux driver]].
 
The configuration is performed using the [[Device_tree|device tree]] mechanism that provides a hardware description of the SAI peripheral, used by the [[SAI_Linux_driver|SAI linux driver]].
  +
  +
If the peripheral is assigned to another execution context, refer to [[How to assign an internal peripheral to a runtime context]] article for guidelines on peripheral assignment and configuration.
   
 
== DT bindings documentation ==
 
== DT bindings documentation ==
Line 24: Line 17:
 
{{
 
{{
 
ImageMap|
 
ImageMap|
Image:Sai_configuration.png {{!}} frame {{!}} center{{!}} SAI device tree configuration<br/> {{WarningImageMapOverlay}}
+
Image:Sai_configuration.png {{!}} frame {{!}} center{{!}} SAI device tree configuration
 
rect 4 135 158 404 [[Clock_overview]]
 
rect 4 135 158 404 [[Clock_overview]]
 
rect 625 222 764 403 [[Pinctrl_overview]]
 
rect 625 222 764 403 [[Pinctrl_overview]]
Line 52: Line 45:
   
 
=== DT configuration (STM32 level) ===
 
=== DT configuration (STM32 level) ===
The SAI nodes are declared in STM32 microprocessor device tree. They describe hardware parameters such as registers address, interrupt and DMA. This set of properties may not vary for a given STM32MPU. For STM32MP1, the corresponding DT file is stm32mp157c.dtsi<ref name="stm32mp157c.dtsi">{{CodeSource | Linux kernel | arch/arm/boot/dts/stm32mp157c.dtsi}}</ref>.
+
The SAI nodes are declared in STM32 microprocessor device tree. They describe hardware parameters such as registers address, interrupt and DMA. This set of properties may not vary for a given STM32MPU. For STM32MP1, the corresponding DT file is stm32mp151.dtsi<ref name="stm32mp151.dtsi">{{CodeSource | Linux kernel | arch/arm/boot/dts/stm32mp151.dtsi}}</ref>.
 
{{Warning|This device tree part is related to STM32 microprocessors. It should be kept as is, without being modified by the end-user.}}
 
{{Warning|This device tree part is related to STM32 microprocessors. It should be kept as is, without being modified by the end-user.}}
   
Line 61: Line 54:
 
=== DT configuration examples ===
 
=== DT configuration examples ===
   
This chapter describes in detail advanced SAI configurations. These examples are based on [[:Category:Getting_started_with_STM32MP1_boards|STM32MP1 boards]] SAI use cases. The corresponding device trees can be found in [[Soundcard configuration|soundcard]] article.
+
This chapter describes in details advanced SAI configurations. These examples are based on [[:Category:Getting_started_with_STM32MP1_boards|STM32MP1 boards]] SAI use cases. The corresponding device trees can be found in [[Soundcard configuration|soundcard]] article.
{{Info|In this chapter, "SAI" stands for a SAI subblock, SAIxA or SAIxB.}}
+
{{Info|In this chapter, "SAI" stands for an SAI subblock, SAIxA or SAIxB.}}
   
==== '''Setting SAI as a master clock provider'''====
+
==== Setting SAI as a master clock provider ====
 
The SAI peripheral can provide a clock to an external component (such as a codec) through the mclk output pin. In this case, it acts as master clock (mclk) provider. The below DT sample gives an example of SAI configuration as mclk provider.
 
The SAI peripheral can provide a clock to an external component (such as a codec) through the mclk output pin. In this case, it acts as master clock (mclk) provider. The below DT sample gives an example of SAI configuration as mclk provider.
   
 
In this example the codec driver supports mclk input based on ASoC DAPM mechanism.
 
In this example the codec driver supports mclk input based on ASoC DAPM mechanism.
If this is not the case, the codec driver has to be adapted. This can be achieved by adding a DAPM clock supply widget to the codec driver. An example of the required clock supply DAPM widget can be found in Cirrus CS42L51 codec source code<ref name="CS42L51 code">{{CodeSource | Linux kernel | sound/soc/codecs/cs42l51.c}}</ref>.
+
If this is not the case, the codec driver has to be adapted. This can be achieved by adding a DAPM clock supply widget to the codec driver. An example of the required DAPM clock supply widget can be found in Cirrus CS42L51 codec source code<ref name="CS42L51 code">{{CodeSource | Linux kernel | sound/soc/codecs/cs42l51.c}}</ref>.
 
In the below device tree example, the codec DAPM clock widget is named "MCLKX".  
 
In the below device tree example, the codec DAPM clock widget is named "MCLKX".  
   
Line 98: Line 91:
 
  };
 
  };
   
==== '''Sharing master clock between two SAIs'''====
+
==== Sharing master clock between two SAIs ====
   
When a SAI is set as a master clock provider, another SAI can share this master clock.
+
When an SAI is set as a master clock provider, another SAI can share this master clock.
This can be achieved by setting a SAI as a mclk consumer through DT configuration.
+
This can be achieved by setting the SAI as a mclk consumer through DT configuration.
 
This means that the mclk consumer SAI can request to change the mclk rate, according to its own audio stream sampling rate.
 
This means that the mclk consumer SAI can request to change the mclk rate, according to its own audio stream sampling rate.
 
This implies that audio sampling rates must be identical when both SAI subblocks are used.
 
This implies that audio sampling rates must be identical when both SAI subblocks are used.
Line 123: Line 116:
 
  };
 
  };
   
==== '''Sharing bus clocks between two SAIs'''====
+
==== Sharing the codec interface between two SAIs ====
  +
 
  +
Two SAIs can be connected to the same codec interface, by sharing the I2S bus (i.e. FS and SCK clocks).
  +
 
  +
[[Image:sai_shared_codec.png {{!}} frame {{!}} center{{!}} SAIs sharing the same codec interface|link=]]
  +
 
  +
In such case:
  +
*The codec has to be master on the I2S bus.
  +
*Only one SAI is connected to the bus clocks. The other SAI has to be configured as a slave of the SAI connected to the bus.
  +
*The I2S bus I/O pins must be managed at parent level, so that the corresponding pins are activated whatever the running SAI.
  +
 
  +
From ASoC point of view:<BR>
  +
Two CPU DAIs have to be connected to the same codec DAI. Such topology is not supported natively by the ASoC audio graph card. Indeed, when the audio graph card parses the codec nodes, it expects to find DAI interface indexes, matching the endpoints indexes. A workaround consists in implementing the of_xlate_dai_id callback in the codec driver, to allow using the same DAI interface for both endpoints. An example of code can be found below or in the Cirrus CS42L51 codec source code<ref name="CS42L51 code">{{CodeSource | Linux kernel | sound/soc/codecs/cs42l51.c}}</ref>.
  +
 
  +
* Code example
   
Two SAIs can share the same codec interface. This is done by sharing the I2S bus clocks (i.e. FS and SCK clocks).
+
<syntaxhighlight lang="c">
To achieve this, the codec has to be defined as the I2S bus master.
+
static int codec_of_xlate_dai_id(struct snd_soc_component *component,
Only one SAI is connected to the bus clocks. The other SAI has to be configured as a slave of the SAI connected to the bus. In this case, the GPIOs of both subblocks must be managed at parent level, so that the corresponding pins are activated whatever the running SAI.
+
  struct device_node *endpoint)
  +
{
  +
/* return dai id 0, whatever the endpoint index */
  +
return 0;
  +
}
  +
</syntaxhighlight>
  +
 
  +
* DT example
   
 
  codec {
 
  codec {
 
  ...
 
  ...
 
  codec_port {
 
  codec_port {
  codec_endpoint {
+
  codec_tx_endpoint {
 
  remote-endpoint = <&sai2a_endpoint>;
 
  remote-endpoint = <&sai2a_endpoint>;
 
  frame-master;    {{highlight|/* Set codec as master of SAI2A for FS clock. */}}
 
  frame-master;    {{highlight|/* Set codec as master of SAI2A for FS clock. */}}
 
  bitclock-master; {{highlight|/* Set codec as master of SAI2A for SCK clock. */}}
 
  bitclock-master; {{highlight|/* Set codec as master of SAI2A for SCK clock. */}}
  +
};
  +
  +
codec_rx_endpoint { {{highlight|/* Second endpoint mapped on codec DAI 0 via of_xlate */}}
  +
remote-endpoint = <&sai2b_endpoint>;
  +
frame-master;    {{highlight|/* Set codec as master of SAI2B for FS clock. */}}
  +
bitclock-master; {{highlight|/* Set codec as master of SAI2B for SCK clock. */}}
 
  };
 
  };
 
  };
 
  };
Line 147: Line 167:
 
   
 
   
 
  sai2a: audio-controller@4400b004 {
 
  sai2a: audio-controller@4400b004 {
  +
remote-endpoint = <&codec_tx_endpoint>;
 
  ...
 
  ...
 
  };
 
  };
 
   
 
   
 
  sai2b: audio-controller@4400b024 {
 
  sai2b: audio-controller@4400b024 {
  st,sync = <&sai2a 2>; {{highlight|/* Set SAI2B as slave of SAI2B. */}}
+
remote-endpoint = <&codec_rx_endpoint>;
  +
  st,sync = <&sai2a 2>; {{highlight|/* Set SAI2B as slave of SAI2A. */}}
 
  };
 
  };
 
  };
 
  };
Line 161: Line 183:
   
 
==References==
 
==References==
  +
<references />
   
<references />
+
<noinclude>
  +
{{ArticleBasedOnModel | Peripheral or framework device tree configuration model}}
  +
{{PublicationRequestId | 14728 | 2020-01-28 | AnneJ (9809)}}
  +
 
  +
[[Category:Device tree configuration]]
  +
[[Category:ALSA]]
  +
</noinclude>