All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/23] Add support for Tegra210 Audio
@ 2020-06-27  4:53 ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

Overview
========
Audio Processing Engine (APE) comprises of Audio DMA (ADMA) and Audio
Hub (AHUB) unit. AHUB is a collection of hardware accelerators for audio
pre-processing and post-processing. It also includes a programmable full
crossbar for routing audio data across these accelerators.

This series exposes some of these below mentioned HW devices as ASoC
components for Tegra platforms from Tegra210 onwards.
 * ADMAIF : The interface between ADMA and AHUB
 * XBAR   : Crossbar for routing audio samples across various modules
 * I2S    : Inter-IC Sound Controller
 * DMIC   : Digital Microphone
 * DSPK   : Digital Speaker

Following is the summary of current series.
 * Add YAML DT binding documentation for above mentioned modules.
 * Helper function for ACIF programming is exposed for Tegra210 and later.
 * Add ASoC driver components for each of the above modules.
 * Add DT entries for above components for Tegra210, Tegra186 and
   Tegra194.
 * Enable these components for Jetson Nano/TX1/TX2/Xavier
 * Enhance simple-card DPCM driver to suit Tegra Audio applications with
   few changes in core.
 * To begin with, enable sound card support for Tegra210 based platforms
   like Jetson Nano/TX1.

Sound card support for platforms based on Tegra186 and later will be
subsequently added which can re-use all of the above components.

Changelog
=========

v3 -> v4
--------
 * [1/23] "ASoC: dt-bindings: tegra: Add DT bindings for Tegra210"
   - Removed multiple examples and retained one example per doc
   - Fixed as per inputs on the previous series
   - Tested bindings with 'make dt_binding_check/dtbs_check'

 * [2/23] "ASoC: tegra: Add support for CIF programming"
   - No change

 * Common changes (for patch [3/10] to [7/10])
   - Mixer control overrides, for PCM parameters (rate, channel, bits),
     in each driver are dropped.
   - Updated routing as per DPCM usage
   - Minor changes related to formatting

 * New changes (patch [8/23] to [18/23] and patch [23/23])
   - Based on discussions in following threads DPCM is used for Tegra Audio.
     https://lkml.org/lkml/2020/2/20/91
     https://lkml.org/lkml/2020/4/30/519
   - The simple-card driver is used for Tegra Audio and accordingly
     some enhancements are made in simple-card and core drivers.
   - Patch [8/23] to [18/23] are related to simple-card and core changes.
   - Patch [23/23] adds sound card support to realize complete audio path.
     This is based on simple-card driver with proposed enhancements.
   - Re-ordered patches depending on above 

v2 -> v3
--------
 * [1/10]  "dt-bindings: sound: tegra: add DT binding for AHUB
   - Updated licence
   - Removed redundancy w.r.t items/const/enum
   - Added constraints wherever needed with "pattern" property

 * [2/10]  "ASoC: tegra: add support for CIF programming"
   - Removed tegra_cif.c
   - Instead added inline helper function in tegra_cif.h

 * common changes (for patch [3/10] to [7/10])
   - Replace LATE system calls with Normal sleep
   - Remove explicit RPM suspend in driver remove() call
   - Use devm_kzalloc() instead of devm_kcalloc() for single element
   - Replace 'ret' with 'err' for better reading
   - Consistent error printing style across drivers
   - Minor formating fixes

 * [8/10]  "arm64: tegra: add AHUB components for few Tegra chips"
   - no change

 * [9/10]  "arm64: tegra: enable AHUB modules for few Tegra chips"
   - no change

 * [10/10] "arm64: defconfig: enable AHUB components for Tegra210 and later"
   (New patch)
   - Enables ACONNECT and AHUB components. With this AHUB and components are
     registered with ASoC core.


v1 -> v2
--------
 * [1/9] "dt-bindings: sound: tegra: add DT binding for AHUB"
   - no changes

 * [2/9] "ASoC: tegra: add support for CIF programming"
   - removed CIF programming changes for legacy chips.
   - this patch now exposes helper function for CIF programming,
     which can be used on Tegra210 later.
   - later tegra_cif.c can be extended for legacy chips as well.
   - updated commit message accordingly

 * [3/9] "ASoC: tegra: add Tegra210 based DMIC driver"
   - removed unnecessary initialization of 'ret' in probe()

 * [4/9] "ASoC: tegra: add Tegra210 based I2S driver"
   - removed unnecessary initialization of 'ret' in probe()
   - fixed indentation
   - added consistent bracing for if-else clauses
   - updated 'rx_fifo_th' type to 'unsigned int'
   - used BIT() macro for defines like '1 << {x}' in tegra210_i2s.h

 * [5/9] "ASoC: tegra: add Tegra210 based AHUB driver"
   - used of_device_get_match_data() to get 'soc_data' and removed
    explicit of_match_device()
   - used devm_platform_ioremap_resource() and removed explicit
    platform_get_resource()
   - fixed indentation for devm_snd_soc_register_component()
   - updated commit message
   - updated commit message to reflect compatible binding for Tegra186 and
     Tegra194.
* [6/9] "ASoC: tegra: add Tegra186 based DSPK driver"
   - removed unnecessary initialization of 'ret' in probe()
   - updated 'max_th' to 'unsigned int'
   - shortened lengthy macro names to avoid wrapping in
     tegra186_dspk_wr_reg() and to be consistent

 * [7/9] "ASoC: tegra: add Tegra210 based ADMAIF driver"
   - used of_device_get_match_data() and removed explicit of_match_device()
   - used BIT() macro for defines like '1 << {x}' in tegra210_admaif.h
   - updated commit message to reflect compatible binding for Tegra186 and
     Tegra194.

 * [8/9] "arm64: tegra: add AHUB components for few Tegra chips"
   - no change

 * [9/9] "arm64: tegra: enable AHUB modules for few Tegra chips"
   - no change

 * common changes for patch [3/9] to [7/9]
   - sorted headers in alphabetical order
   - moved MODULE_DEVICE_TABLE() right below *_of_match table
   - removed macro DRV_NAME
   - removed explicit 'owner' field from platform_driver structure
   - added 'const' to snd_soc_dai_ops structure

==================
Sameer Pujar (23):
  ASoC: dt-bindings: tegra: Add DT bindings for Tegra210
  ASoC: tegra: Add support for CIF programming
  ASoC: tegra: Add Tegra210 based DMIC driver
  ASoC: tegra: Add Tegra210 based I2S driver
  ASoC: tegra: Add Tegra210 based AHUB driver
  ASoC: tegra: Add Tegra186 based DSPK driver
  ASoC: tegra: Add Tegra210 based ADMAIF driver
  ASoC: soc-core: Fix component name_prefix parsing
  ASoC: simple-card: Use of_node and DAI names for DAI link names
  ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
  ASoC: simple-card: Loop over all children for 'mclk-fs'
  ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  ASoC: simple-card: DPCM DAI link direction as per DAI capability
  ASoC: soc-core: Probe auxiliary component before others
  ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  ASoC: soc-pcm: Get all BEs along DAPM path
  ASoC: dt-bindings: simple-card: Add compatible for component chaining
  ASoC: simple-card: Add support for component chaining
  arm64: defconfig: Build AHUB component drivers
  arm64: defconfig: Enable CONFIG_TEGRA210_ADMA
  arm64: tegra: Add DT binding for AHUB components
  arm64: tegra: Enable AHUB components on few Tegra platforms
  arm64: tegra: Add support for APE sound card on Jetson Nano and TX1

 .../bindings/sound/nvidia,tegra186-dspk.yaml       |  88 +++
 .../bindings/sound/nvidia,tegra210-admaif.yaml     | 116 +++
 .../bindings/sound/nvidia,tegra210-ahub.yaml       | 144 ++++
 .../bindings/sound/nvidia,tegra210-dmic.yaml       |  88 +++
 .../bindings/sound/nvidia,tegra210-i2s.yaml        | 106 +++
 .../devicetree/bindings/sound/simple-card.yaml     |   1 +
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts |  48 ++
 arch/arm64/boot/dts/nvidia/tegra186.dtsi           | 231 +++++-
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts |  36 +
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           | 239 +++++-
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 136 +++-
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts |  85 +++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           | 219 +++++-
 arch/arm64/configs/defconfig                       |   8 +
 include/sound/simple_card.h                        |   5 +
 include/sound/soc.h                                |   3 +
 sound/soc/generic/simple-card.c                    |  96 ++-
 sound/soc/soc-core.c                               |  43 +-
 sound/soc/soc-dai.c                                |   1 +
 sound/soc/soc-pcm.c                                |   3 +-
 sound/soc/tegra/Kconfig                            |  56 ++
 sound/soc/tegra/Makefile                           |  10 +
 sound/soc/tegra/tegra186_dspk.c                    | 427 +++++++++++
 sound/soc/tegra/tegra186_dspk.h                    |  70 ++
 sound/soc/tegra/tegra210_admaif.c                  | 845 +++++++++++++++++++++
 sound/soc/tegra/tegra210_admaif.h                  | 162 ++++
 sound/soc/tegra/tegra210_ahub.c                    | 578 ++++++++++++++
 sound/soc/tegra/tegra210_ahub.h                    | 100 +++
 sound/soc/tegra/tegra210_dmic.c                    | 440 +++++++++++
 sound/soc/tegra/tegra210_dmic.h                    |  82 ++
 sound/soc/tegra/tegra210_i2s.c                     | 780 +++++++++++++++++++
 sound/soc/tegra/tegra210_i2s.h                     | 126 +++
 sound/soc/tegra/tegra_cif.h                        |  65 ++
 sound/soc/tegra/tegra_pcm.c                        | 235 +++++-
 sound/soc/tegra/tegra_pcm.h                        |  21 +-
 35 files changed, 5657 insertions(+), 36 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
 create mode 100644 sound/soc/tegra/tegra186_dspk.c
 create mode 100644 sound/soc/tegra/tegra186_dspk.h
 create mode 100644 sound/soc/tegra/tegra210_admaif.c
 create mode 100644 sound/soc/tegra/tegra210_admaif.h
 create mode 100644 sound/soc/tegra/tegra210_ahub.c
 create mode 100644 sound/soc/tegra/tegra210_ahub.h
 create mode 100644 sound/soc/tegra/tegra210_dmic.c
 create mode 100644 sound/soc/tegra/tegra210_dmic.h
 create mode 100644 sound/soc/tegra/tegra210_i2s.c
 create mode 100644 sound/soc/tegra/tegra210_i2s.h
 create mode 100644 sound/soc/tegra/tegra_cif.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 181+ messages in thread

* [PATCH v4 00/23] Add support for Tegra210 Audio
@ 2020-06-27  4:53 ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

Overview
========
Audio Processing Engine (APE) comprises of Audio DMA (ADMA) and Audio
Hub (AHUB) unit. AHUB is a collection of hardware accelerators for audio
pre-processing and post-processing. It also includes a programmable full
crossbar for routing audio data across these accelerators.

This series exposes some of these below mentioned HW devices as ASoC
components for Tegra platforms from Tegra210 onwards.
 * ADMAIF : The interface between ADMA and AHUB
 * XBAR   : Crossbar for routing audio samples across various modules
 * I2S    : Inter-IC Sound Controller
 * DMIC   : Digital Microphone
 * DSPK   : Digital Speaker

Following is the summary of current series.
 * Add YAML DT binding documentation for above mentioned modules.
 * Helper function for ACIF programming is exposed for Tegra210 and later.
 * Add ASoC driver components for each of the above modules.
 * Add DT entries for above components for Tegra210, Tegra186 and
   Tegra194.
 * Enable these components for Jetson Nano/TX1/TX2/Xavier
 * Enhance simple-card DPCM driver to suit Tegra Audio applications with
   few changes in core.
 * To begin with, enable sound card support for Tegra210 based platforms
   like Jetson Nano/TX1.

Sound card support for platforms based on Tegra186 and later will be
subsequently added which can re-use all of the above components.

Changelog
=========

v3 -> v4
--------
 * [1/23] "ASoC: dt-bindings: tegra: Add DT bindings for Tegra210"
   - Removed multiple examples and retained one example per doc
   - Fixed as per inputs on the previous series
   - Tested bindings with 'make dt_binding_check/dtbs_check'

 * [2/23] "ASoC: tegra: Add support for CIF programming"
   - No change

 * Common changes (for patch [3/10] to [7/10])
   - Mixer control overrides, for PCM parameters (rate, channel, bits),
     in each driver are dropped.
   - Updated routing as per DPCM usage
   - Minor changes related to formatting

 * New changes (patch [8/23] to [18/23] and patch [23/23])
   - Based on discussions in following threads DPCM is used for Tegra Audio.
     https://lkml.org/lkml/2020/2/20/91
     https://lkml.org/lkml/2020/4/30/519
   - The simple-card driver is used for Tegra Audio and accordingly
     some enhancements are made in simple-card and core drivers.
   - Patch [8/23] to [18/23] are related to simple-card and core changes.
   - Patch [23/23] adds sound card support to realize complete audio path.
     This is based on simple-card driver with proposed enhancements.
   - Re-ordered patches depending on above 

v2 -> v3
--------
 * [1/10]  "dt-bindings: sound: tegra: add DT binding for AHUB
   - Updated licence
   - Removed redundancy w.r.t items/const/enum
   - Added constraints wherever needed with "pattern" property

 * [2/10]  "ASoC: tegra: add support for CIF programming"
   - Removed tegra_cif.c
   - Instead added inline helper function in tegra_cif.h

 * common changes (for patch [3/10] to [7/10])
   - Replace LATE system calls with Normal sleep
   - Remove explicit RPM suspend in driver remove() call
   - Use devm_kzalloc() instead of devm_kcalloc() for single element
   - Replace 'ret' with 'err' for better reading
   - Consistent error printing style across drivers
   - Minor formating fixes

 * [8/10]  "arm64: tegra: add AHUB components for few Tegra chips"
   - no change

 * [9/10]  "arm64: tegra: enable AHUB modules for few Tegra chips"
   - no change

 * [10/10] "arm64: defconfig: enable AHUB components for Tegra210 and later"
   (New patch)
   - Enables ACONNECT and AHUB components. With this AHUB and components are
     registered with ASoC core.


v1 -> v2
--------
 * [1/9] "dt-bindings: sound: tegra: add DT binding for AHUB"
   - no changes

 * [2/9] "ASoC: tegra: add support for CIF programming"
   - removed CIF programming changes for legacy chips.
   - this patch now exposes helper function for CIF programming,
     which can be used on Tegra210 later.
   - later tegra_cif.c can be extended for legacy chips as well.
   - updated commit message accordingly

 * [3/9] "ASoC: tegra: add Tegra210 based DMIC driver"
   - removed unnecessary initialization of 'ret' in probe()

 * [4/9] "ASoC: tegra: add Tegra210 based I2S driver"
   - removed unnecessary initialization of 'ret' in probe()
   - fixed indentation
   - added consistent bracing for if-else clauses
   - updated 'rx_fifo_th' type to 'unsigned int'
   - used BIT() macro for defines like '1 << {x}' in tegra210_i2s.h

 * [5/9] "ASoC: tegra: add Tegra210 based AHUB driver"
   - used of_device_get_match_data() to get 'soc_data' and removed
    explicit of_match_device()
   - used devm_platform_ioremap_resource() and removed explicit
    platform_get_resource()
   - fixed indentation for devm_snd_soc_register_component()
   - updated commit message
   - updated commit message to reflect compatible binding for Tegra186 and
     Tegra194.
* [6/9] "ASoC: tegra: add Tegra186 based DSPK driver"
   - removed unnecessary initialization of 'ret' in probe()
   - updated 'max_th' to 'unsigned int'
   - shortened lengthy macro names to avoid wrapping in
     tegra186_dspk_wr_reg() and to be consistent

 * [7/9] "ASoC: tegra: add Tegra210 based ADMAIF driver"
   - used of_device_get_match_data() and removed explicit of_match_device()
   - used BIT() macro for defines like '1 << {x}' in tegra210_admaif.h
   - updated commit message to reflect compatible binding for Tegra186 and
     Tegra194.

 * [8/9] "arm64: tegra: add AHUB components for few Tegra chips"
   - no change

 * [9/9] "arm64: tegra: enable AHUB modules for few Tegra chips"
   - no change

 * common changes for patch [3/9] to [7/9]
   - sorted headers in alphabetical order
   - moved MODULE_DEVICE_TABLE() right below *_of_match table
   - removed macro DRV_NAME
   - removed explicit 'owner' field from platform_driver structure
   - added 'const' to snd_soc_dai_ops structure

==================
Sameer Pujar (23):
  ASoC: dt-bindings: tegra: Add DT bindings for Tegra210
  ASoC: tegra: Add support for CIF programming
  ASoC: tegra: Add Tegra210 based DMIC driver
  ASoC: tegra: Add Tegra210 based I2S driver
  ASoC: tegra: Add Tegra210 based AHUB driver
  ASoC: tegra: Add Tegra186 based DSPK driver
  ASoC: tegra: Add Tegra210 based ADMAIF driver
  ASoC: soc-core: Fix component name_prefix parsing
  ASoC: simple-card: Use of_node and DAI names for DAI link names
  ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
  ASoC: simple-card: Loop over all children for 'mclk-fs'
  ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  ASoC: simple-card: DPCM DAI link direction as per DAI capability
  ASoC: soc-core: Probe auxiliary component before others
  ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  ASoC: soc-pcm: Get all BEs along DAPM path
  ASoC: dt-bindings: simple-card: Add compatible for component chaining
  ASoC: simple-card: Add support for component chaining
  arm64: defconfig: Build AHUB component drivers
  arm64: defconfig: Enable CONFIG_TEGRA210_ADMA
  arm64: tegra: Add DT binding for AHUB components
  arm64: tegra: Enable AHUB components on few Tegra platforms
  arm64: tegra: Add support for APE sound card on Jetson Nano and TX1

 .../bindings/sound/nvidia,tegra186-dspk.yaml       |  88 +++
 .../bindings/sound/nvidia,tegra210-admaif.yaml     | 116 +++
 .../bindings/sound/nvidia,tegra210-ahub.yaml       | 144 ++++
 .../bindings/sound/nvidia,tegra210-dmic.yaml       |  88 +++
 .../bindings/sound/nvidia,tegra210-i2s.yaml        | 106 +++
 .../devicetree/bindings/sound/simple-card.yaml     |   1 +
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts |  48 ++
 arch/arm64/boot/dts/nvidia/tegra186.dtsi           | 231 +++++-
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts |  36 +
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           | 239 +++++-
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 136 +++-
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts |  85 +++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           | 219 +++++-
 arch/arm64/configs/defconfig                       |   8 +
 include/sound/simple_card.h                        |   5 +
 include/sound/soc.h                                |   3 +
 sound/soc/generic/simple-card.c                    |  96 ++-
 sound/soc/soc-core.c                               |  43 +-
 sound/soc/soc-dai.c                                |   1 +
 sound/soc/soc-pcm.c                                |   3 +-
 sound/soc/tegra/Kconfig                            |  56 ++
 sound/soc/tegra/Makefile                           |  10 +
 sound/soc/tegra/tegra186_dspk.c                    | 427 +++++++++++
 sound/soc/tegra/tegra186_dspk.h                    |  70 ++
 sound/soc/tegra/tegra210_admaif.c                  | 845 +++++++++++++++++++++
 sound/soc/tegra/tegra210_admaif.h                  | 162 ++++
 sound/soc/tegra/tegra210_ahub.c                    | 578 ++++++++++++++
 sound/soc/tegra/tegra210_ahub.h                    | 100 +++
 sound/soc/tegra/tegra210_dmic.c                    | 440 +++++++++++
 sound/soc/tegra/tegra210_dmic.h                    |  82 ++
 sound/soc/tegra/tegra210_i2s.c                     | 780 +++++++++++++++++++
 sound/soc/tegra/tegra210_i2s.h                     | 126 +++
 sound/soc/tegra/tegra_cif.h                        |  65 ++
 sound/soc/tegra/tegra_pcm.c                        | 235 +++++-
 sound/soc/tegra/tegra_pcm.h                        |  21 +-
 35 files changed, 5657 insertions(+), 36 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
 create mode 100644 sound/soc/tegra/tegra186_dspk.c
 create mode 100644 sound/soc/tegra/tegra186_dspk.h
 create mode 100644 sound/soc/tegra/tegra210_admaif.c
 create mode 100644 sound/soc/tegra/tegra210_admaif.h
 create mode 100644 sound/soc/tegra/tegra210_ahub.c
 create mode 100644 sound/soc/tegra/tegra210_ahub.h
 create mode 100644 sound/soc/tegra/tegra210_dmic.c
 create mode 100644 sound/soc/tegra/tegra210_dmic.h
 create mode 100644 sound/soc/tegra/tegra210_i2s.c
 create mode 100644 sound/soc/tegra/tegra210_i2s.h
 create mode 100644 sound/soc/tegra/tegra_cif.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 181+ messages in thread

* [PATCH v4 00/23] Add support for Tegra210 Audio
@ 2020-06-27  4:53 ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

Overview
========
Audio Processing Engine (APE) comprises of Audio DMA (ADMA) and Audio
Hub (AHUB) unit. AHUB is a collection of hardware accelerators for audio
pre-processing and post-processing. It also includes a programmable full
crossbar for routing audio data across these accelerators.

This series exposes some of these below mentioned HW devices as ASoC
components for Tegra platforms from Tegra210 onwards.
 * ADMAIF : The interface between ADMA and AHUB
 * XBAR   : Crossbar for routing audio samples across various modules
 * I2S    : Inter-IC Sound Controller
 * DMIC   : Digital Microphone
 * DSPK   : Digital Speaker

Following is the summary of current series.
 * Add YAML DT binding documentation for above mentioned modules.
 * Helper function for ACIF programming is exposed for Tegra210 and later.
 * Add ASoC driver components for each of the above modules.
 * Add DT entries for above components for Tegra210, Tegra186 and
   Tegra194.
 * Enable these components for Jetson Nano/TX1/TX2/Xavier
 * Enhance simple-card DPCM driver to suit Tegra Audio applications with
   few changes in core.
 * To begin with, enable sound card support for Tegra210 based platforms
   like Jetson Nano/TX1.

Sound card support for platforms based on Tegra186 and later will be
subsequently added which can re-use all of the above components.

Changelog
=========

v3 -> v4
--------
 * [1/23] "ASoC: dt-bindings: tegra: Add DT bindings for Tegra210"
   - Removed multiple examples and retained one example per doc
   - Fixed as per inputs on the previous series
   - Tested bindings with 'make dt_binding_check/dtbs_check'

 * [2/23] "ASoC: tegra: Add support for CIF programming"
   - No change

 * Common changes (for patch [3/10] to [7/10])
   - Mixer control overrides, for PCM parameters (rate, channel, bits),
     in each driver are dropped.
   - Updated routing as per DPCM usage
   - Minor changes related to formatting

 * New changes (patch [8/23] to [18/23] and patch [23/23])
   - Based on discussions in following threads DPCM is used for Tegra Audio.
     https://lkml.org/lkml/2020/2/20/91
     https://lkml.org/lkml/2020/4/30/519
   - The simple-card driver is used for Tegra Audio and accordingly
     some enhancements are made in simple-card and core drivers.
   - Patch [8/23] to [18/23] are related to simple-card and core changes.
   - Patch [23/23] adds sound card support to realize complete audio path.
     This is based on simple-card driver with proposed enhancements.
   - Re-ordered patches depending on above 

v2 -> v3
--------
 * [1/10]  "dt-bindings: sound: tegra: add DT binding for AHUB
   - Updated licence
   - Removed redundancy w.r.t items/const/enum
   - Added constraints wherever needed with "pattern" property

 * [2/10]  "ASoC: tegra: add support for CIF programming"
   - Removed tegra_cif.c
   - Instead added inline helper function in tegra_cif.h

 * common changes (for patch [3/10] to [7/10])
   - Replace LATE system calls with Normal sleep
   - Remove explicit RPM suspend in driver remove() call
   - Use devm_kzalloc() instead of devm_kcalloc() for single element
   - Replace 'ret' with 'err' for better reading
   - Consistent error printing style across drivers
   - Minor formating fixes

 * [8/10]  "arm64: tegra: add AHUB components for few Tegra chips"
   - no change

 * [9/10]  "arm64: tegra: enable AHUB modules for few Tegra chips"
   - no change

 * [10/10] "arm64: defconfig: enable AHUB components for Tegra210 and later"
   (New patch)
   - Enables ACONNECT and AHUB components. With this AHUB and components are
     registered with ASoC core.


v1 -> v2
--------
 * [1/9] "dt-bindings: sound: tegra: add DT binding for AHUB"
   - no changes

 * [2/9] "ASoC: tegra: add support for CIF programming"
   - removed CIF programming changes for legacy chips.
   - this patch now exposes helper function for CIF programming,
     which can be used on Tegra210 later.
   - later tegra_cif.c can be extended for legacy chips as well.
   - updated commit message accordingly

 * [3/9] "ASoC: tegra: add Tegra210 based DMIC driver"
   - removed unnecessary initialization of 'ret' in probe()

 * [4/9] "ASoC: tegra: add Tegra210 based I2S driver"
   - removed unnecessary initialization of 'ret' in probe()
   - fixed indentation
   - added consistent bracing for if-else clauses
   - updated 'rx_fifo_th' type to 'unsigned int'
   - used BIT() macro for defines like '1 << {x}' in tegra210_i2s.h

 * [5/9] "ASoC: tegra: add Tegra210 based AHUB driver"
   - used of_device_get_match_data() to get 'soc_data' and removed
    explicit of_match_device()
   - used devm_platform_ioremap_resource() and removed explicit
    platform_get_resource()
   - fixed indentation for devm_snd_soc_register_component()
   - updated commit message
   - updated commit message to reflect compatible binding for Tegra186 and
     Tegra194.
* [6/9] "ASoC: tegra: add Tegra186 based DSPK driver"
   - removed unnecessary initialization of 'ret' in probe()
   - updated 'max_th' to 'unsigned int'
   - shortened lengthy macro names to avoid wrapping in
     tegra186_dspk_wr_reg() and to be consistent

 * [7/9] "ASoC: tegra: add Tegra210 based ADMAIF driver"
   - used of_device_get_match_data() and removed explicit of_match_device()
   - used BIT() macro for defines like '1 << {x}' in tegra210_admaif.h
   - updated commit message to reflect compatible binding for Tegra186 and
     Tegra194.

 * [8/9] "arm64: tegra: add AHUB components for few Tegra chips"
   - no change

 * [9/9] "arm64: tegra: enable AHUB modules for few Tegra chips"
   - no change

 * common changes for patch [3/9] to [7/9]
   - sorted headers in alphabetical order
   - moved MODULE_DEVICE_TABLE() right below *_of_match table
   - removed macro DRV_NAME
   - removed explicit 'owner' field from platform_driver structure
   - added 'const' to snd_soc_dai_ops structure

==================
Sameer Pujar (23):
  ASoC: dt-bindings: tegra: Add DT bindings for Tegra210
  ASoC: tegra: Add support for CIF programming
  ASoC: tegra: Add Tegra210 based DMIC driver
  ASoC: tegra: Add Tegra210 based I2S driver
  ASoC: tegra: Add Tegra210 based AHUB driver
  ASoC: tegra: Add Tegra186 based DSPK driver
  ASoC: tegra: Add Tegra210 based ADMAIF driver
  ASoC: soc-core: Fix component name_prefix parsing
  ASoC: simple-card: Use of_node and DAI names for DAI link names
  ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
  ASoC: simple-card: Loop over all children for 'mclk-fs'
  ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  ASoC: simple-card: DPCM DAI link direction as per DAI capability
  ASoC: soc-core: Probe auxiliary component before others
  ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  ASoC: soc-pcm: Get all BEs along DAPM path
  ASoC: dt-bindings: simple-card: Add compatible for component chaining
  ASoC: simple-card: Add support for component chaining
  arm64: defconfig: Build AHUB component drivers
  arm64: defconfig: Enable CONFIG_TEGRA210_ADMA
  arm64: tegra: Add DT binding for AHUB components
  arm64: tegra: Enable AHUB components on few Tegra platforms
  arm64: tegra: Add support for APE sound card on Jetson Nano and TX1

 .../bindings/sound/nvidia,tegra186-dspk.yaml       |  88 +++
 .../bindings/sound/nvidia,tegra210-admaif.yaml     | 116 +++
 .../bindings/sound/nvidia,tegra210-ahub.yaml       | 144 ++++
 .../bindings/sound/nvidia,tegra210-dmic.yaml       |  88 +++
 .../bindings/sound/nvidia,tegra210-i2s.yaml        | 106 +++
 .../devicetree/bindings/sound/simple-card.yaml     |   1 +
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts |  48 ++
 arch/arm64/boot/dts/nvidia/tegra186.dtsi           | 231 +++++-
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts |  36 +
 arch/arm64/boot/dts/nvidia/tegra194.dtsi           | 239 +++++-
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 136 +++-
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts |  85 +++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           | 219 +++++-
 arch/arm64/configs/defconfig                       |   8 +
 include/sound/simple_card.h                        |   5 +
 include/sound/soc.h                                |   3 +
 sound/soc/generic/simple-card.c                    |  96 ++-
 sound/soc/soc-core.c                               |  43 +-
 sound/soc/soc-dai.c                                |   1 +
 sound/soc/soc-pcm.c                                |   3 +-
 sound/soc/tegra/Kconfig                            |  56 ++
 sound/soc/tegra/Makefile                           |  10 +
 sound/soc/tegra/tegra186_dspk.c                    | 427 +++++++++++
 sound/soc/tegra/tegra186_dspk.h                    |  70 ++
 sound/soc/tegra/tegra210_admaif.c                  | 845 +++++++++++++++++++++
 sound/soc/tegra/tegra210_admaif.h                  | 162 ++++
 sound/soc/tegra/tegra210_ahub.c                    | 578 ++++++++++++++
 sound/soc/tegra/tegra210_ahub.h                    | 100 +++
 sound/soc/tegra/tegra210_dmic.c                    | 440 +++++++++++
 sound/soc/tegra/tegra210_dmic.h                    |  82 ++
 sound/soc/tegra/tegra210_i2s.c                     | 780 +++++++++++++++++++
 sound/soc/tegra/tegra210_i2s.h                     | 126 +++
 sound/soc/tegra/tegra_cif.h                        |  65 ++
 sound/soc/tegra/tegra_pcm.c                        | 235 +++++-
 sound/soc/tegra/tegra_pcm.h                        |  21 +-
 35 files changed, 5657 insertions(+), 36 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
 create mode 100644 sound/soc/tegra/tegra186_dspk.c
 create mode 100644 sound/soc/tegra/tegra186_dspk.h
 create mode 100644 sound/soc/tegra/tegra210_admaif.c
 create mode 100644 sound/soc/tegra/tegra210_admaif.h
 create mode 100644 sound/soc/tegra/tegra210_ahub.c
 create mode 100644 sound/soc/tegra/tegra210_ahub.h
 create mode 100644 sound/soc/tegra/tegra210_dmic.c
 create mode 100644 sound/soc/tegra/tegra210_dmic.h
 create mode 100644 sound/soc/tegra/tegra210_i2s.c
 create mode 100644 sound/soc/tegra/tegra210_i2s.h
 create mode 100644 sound/soc/tegra/tegra_cif.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 181+ messages in thread

* [PATCH v4 01/23] ASoC: dt-bindings: tegra: Add DT bindings for Tegra210
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

This patch adds YAML schema for DT binding of AHUB and few of its
following components. These devices will be registered as ASoC
components and binding will be used on Tegra210 and later chips.
 * ADMAIF
 * I2S
 * DMIC
 * DSPK

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 .../bindings/sound/nvidia,tegra186-dspk.yaml       |  88 +++++++++++++
 .../bindings/sound/nvidia,tegra210-admaif.yaml     | 116 +++++++++++++++++
 .../bindings/sound/nvidia,tegra210-ahub.yaml       | 144 +++++++++++++++++++++
 .../bindings/sound/nvidia,tegra210-dmic.yaml       |  88 +++++++++++++
 .../bindings/sound/nvidia,tegra210-i2s.yaml        | 106 +++++++++++++++
 5 files changed, 542 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml

diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
new file mode 100644
index 0000000..13a9570
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra186-dspk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra186 DSPK Controller Device Tree Bindings
+
+description: |
+  The Digital Speaker Controller (DSPK) can be viewed as a Pulse
+  Density Modulation (PDM) transmitter that up-samples the input to
+  the desired sampling rate by interpolation and then converts the
+  over sampled Pulse Code Modulation (PCM) input to the desired 1-bit
+  output via Delta Sigma Modulation (DSM).
+
+maintainers:
+  - Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+  - Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+
+properties:
+  $nodename:
+    pattern: "^dspk@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra186-dspk
+      - items:
+          - const: nvidia,tegra194-dspk
+          - const: nvidia,tegra186-dspk
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: dspk
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clock-parents:
+    maxItems: 1
+
+  assigned-clock-rates:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  sound-name-prefix:
+    pattern: "^DSPK[1-9]$"
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+      The name can be "DSPK1" or "DSPKx", where x depends on the maximum
+      available instances on a Tegra SoC.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#sound-dai-cells"
+  - sound-name-prefix
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra186-clock.h>
+
+    dspk@2905000 {
+        compatible = "nvidia,tegra186-dspk";
+        reg = <0x2905000 0x100>;
+        clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+        clock-names = "dspk";
+        assigned-clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+        assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <12288000>;
+        #sound-dai-cells = <1>;
+        sound-name-prefix = "DSPK1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
new file mode 100644
index 0000000..aab60cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-admaif.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 ADMAIF Device Tree Bindings
+
+description: |
+  ADMAIF is the interface between ADMA and AHUB. Each ADMA channel
+  that sends/receives data to/from AHUB must interface through an
+  ADMAIF channel. ADMA channel sending data to AHUB pairs with ADMAIF
+  Tx channel and ADMA channel receiving data from AHUB pairs with
+  ADMAIF Rx channel.
+
+maintainers:
+  - Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+  - Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+
+properties:
+  $nodename:
+    pattern: "^admaif@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - enum:
+          - nvidia,tegra210-admaif
+          - nvidia,tegra186-admaif
+      - items:
+          - const: nvidia,tegra194-admaif
+          - const: nvidia,tegra186-admaif
+
+  reg:
+    maxItems: 1
+
+  dmas: true
+
+  dma-names: true
+
+  "#sound-dai-cells":
+    const: 1
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: nvidia,tegra210-admaif
+
+then:
+  properties:
+    dmas:
+      description:
+        DMA channel specifiers, equally divided for Tx and Rx.
+      minItems: 1
+      maxItems: 20
+    dma-names:
+      items:
+        pattern: "^[rt]x(10|[1-9])$"
+      description:
+        Should be "rx1", "rx2" ... "rx10" for DMA Rx channel
+        Should be "tx1", "tx2" ... "tx10" for DMA Tx channel
+      minItems: 1
+      maxItems: 20
+
+else:
+  properties:
+    dmas:
+      description:
+        DMA channel specifiers, equally divided for Tx and Rx.
+      minItems: 1
+      maxItems: 40
+    dma-names:
+      items:
+        pattern: "^[rt]x(1[0-9]|[1-9]|20)$"
+      description:
+        Should be "rx1", "rx2" ... "rx20" for DMA Rx channel
+        Should be "tx1", "tx2" ... "tx20" for DMA Tx channel
+      minItems: 1
+      maxItems: 40
+
+required:
+  - compatible
+  - reg
+  - dmas
+  - dma-names
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    admaif@702d0000 {
+        compatible = "nvidia,tegra210-admaif";
+        reg = <0x702d0000 0x800>;
+        dmas = <&adma 1>,  <&adma 1>,
+               <&adma 2>,  <&adma 2>,
+               <&adma 3>,  <&adma 3>,
+               <&adma 4>,  <&adma 4>,
+               <&adma 5>,  <&adma 5>,
+               <&adma 6>,  <&adma 6>,
+               <&adma 7>,  <&adma 7>,
+               <&adma 8>,  <&adma 8>,
+               <&adma 9>,  <&adma 9>,
+               <&adma 10>, <&adma 10>;
+        dma-names = "rx1",  "tx1",
+                    "rx2",  "tx2",
+                    "rx3",  "tx3",
+                    "rx4",  "tx4",
+                    "rx5",  "tx5",
+                    "rx6",  "tx6",
+                    "rx7",  "tx7",
+                    "rx8",  "tx8",
+                    "rx9",  "tx9",
+                    "rx10", "tx10";
+        #sound-dai-cells = <1>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
new file mode 100644
index 0000000..44ee497
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
@@ -0,0 +1,144 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ahub.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 AHUB Device Tree Bindings
+
+description: |
+  The Audio Hub (AHUB) comprises a collection of hardware accelerators
+  for audio pre-processing, post-processing and a programmable full
+  crossbar for routing audio data across these accelerators. It has
+  external interfaces such as I2S, DMIC, DSPK. It interfaces with ADMA
+  engine through ADMAIF.
+
+maintainers:
+  - Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+  - Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+
+properties:
+  $nodename:
+    pattern: "^ahub@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - enum:
+          - nvidia,tegra210-ahub
+          - nvidia,tegra186-ahub
+      - items:
+          - const: nvidia,tegra194-ahub
+          - const: nvidia,tegra186-ahub
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: ahub
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clock-parents:
+    maxItems: 1
+
+  assigned-clock-rates:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges: true
+
+  "#sound-dai-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    ahub@702d0800 {
+        compatible = "nvidia,tegra210-ahub";
+        reg = <0x702d0800 0x800>;
+        clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        clock-names = "ahub";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x702d0000 0x702d0000 0x0000e400>;
+        #sound-dai-cells = <1>;
+
+        // All AHUB child nodes below
+        admaif@702d0000 {
+            compatible = "nvidia,tegra210-admaif";
+            reg = <0x702d0000 0x800>;
+            dmas = <&adma 1>,  <&adma 1>,
+               <&adma 2>,  <&adma 2>,
+               <&adma 3>,  <&adma 3>,
+               <&adma 4>,  <&adma 4>,
+               <&adma 5>,  <&adma 5>,
+               <&adma 6>,  <&adma 6>,
+               <&adma 7>,  <&adma 7>,
+               <&adma 8>,  <&adma 8>,
+               <&adma 9>,  <&adma 9>,
+               <&adma 10>, <&adma 10>;
+            dma-names = "rx1",  "tx1",
+                    "rx2",  "tx2",
+                    "rx3",  "tx3",
+                    "rx4",  "tx4",
+                    "rx5",  "tx5",
+                    "rx6",  "tx6",
+                    "rx7",  "tx7",
+                    "rx8",  "tx8",
+                    "rx9",  "tx9",
+                    "rx10", "tx10";
+            #sound-dai-cells = <1>;
+        };
+
+        i2s@702d1000 {
+            compatible = "nvidia,tegra210-i2s";
+            reg = <0x702d1000 0x100>;
+            clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            clock-names = "i2s";
+            assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+            assigned-clock-rates = <1536000>;
+            #sound-dai-cells = <1>;
+            sound-name-prefix = "I2S1";
+        };
+
+        dmic@702d4000 {
+            compatible = "nvidia,tegra210-dmic";
+            reg = <0x702d4000 0x100>;
+            clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+            clock-names = "dmic";
+            assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+            assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+            assigned-clock-rates = <3072000>;
+            #sound-dai-cells = <1>;
+            sound-name-prefix = "DMIC1";
+        };
+
+        // More child nodes to follow
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
new file mode 100644
index 0000000..b49d0ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-dmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 DMIC Controller Device Tree Bindings
+
+description: |
+  The Digital MIC (DMIC) Controller is used to interface with Pulse
+  Density Modulation (PDM) input devices. It converts PDM signals to
+  Pulse Coded Modulation (PCM) signals. DMIC can be viewed as a PDM
+  receiver.
+
+maintainers:
+  - Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+  - Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+
+properties:
+  $nodename:
+    pattern: "^dmic@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-dmic
+      - items:
+          - enum:
+              - nvidia,tegra194-dmic
+              - nvidia,tegra186-dmic
+          - const: nvidia,tegra210-dmic
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: dmic
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clock-parents:
+    maxItems: 1
+
+  assigned-clock-rates:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  sound-name-prefix:
+    pattern: "^DMIC[1-9]$"
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+    description:
+      used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+      The name can be "DMIC1" or "DMIC2" ... "DMICx", where x depends
+      on the maximum available instances on a Tegra SoC.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    dmic@702d4000 {
+        compatible = "nvidia,tegra210-dmic";
+        reg = <0x702d4000 0x100>;
+        clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+        clock-names = "dmic";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <3072000>;
+        #sound-dai-cells = <1>;
+        sound-name-prefix = "DMIC1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
new file mode 100644
index 0000000..9465216
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 I2S Controller Device Tree Bindings
+
+description: |
+  The Inter-IC Sound (I2S) controller implements full-duplex,
+  bi-directional and single direction point-to-point serial
+  interfaces. It can interface with I2S compatible devices.
+  I2S controller can operate both in master and slave mode.
+
+maintainers:
+  - Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+  - Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+
+properties:
+  $nodename:
+    pattern: "^i2s@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-i2s
+      - items:
+          - enum:
+              - nvidia,tegra194-i2s
+              - nvidia,tegra186-i2s
+          - const: nvidia,tegra210-i2s
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    maxItems: 2
+    items:
+      - description: I2S bit clock
+      - description:
+          Sync input clock, which can act as clock source to other I/O
+          modules in AHUB. The Tegra I2S driver sets this clock rate as
+          per bit clock rate. I/O module which wants to use this clock
+          as source, can mention this clock as parent in the DT bindings.
+          This is an optional clock entry, since it is only required when
+          some other I/O wants to reference from a particular I2Sx
+          instance.
+
+  clock-names:
+    minItems: 1
+    maxItems: 2
+    items:
+      - const: i2s
+      - const: sync_input
+
+  assigned-clocks:
+    minItems: 1
+    maxItems: 2
+
+  assigned-clock-parents:
+    minItems: 1
+    maxItems: 2
+
+  assigned-clock-rates:
+    minItems: 1
+    maxItems: 2
+
+  "#sound-dai-cells":
+    const: 1
+
+  sound-name-prefix:
+    pattern: "^I2S[1-9]$"
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+      The name can be "I2S1" or "I2S2" ... "I2Sx", where x depends
+      on the maximum available instances on a Tegra SoC.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    i2s@702d1000 {
+        compatible = "nvidia,tegra210-i2s";
+        reg = <0x702d1000 0x100>;
+        clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+        clock-names = "i2s";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <1536000>;
+        #sound-dai-cells = <1>;
+        sound-name-prefix = "I2S1";
+    };
+
+...
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 01/23] ASoC: dt-bindings: tegra: Add DT bindings for Tegra210
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

This patch adds YAML schema for DT binding of AHUB and few of its
following components. These devices will be registered as ASoC
components and binding will be used on Tegra210 and later chips.
 * ADMAIF
 * I2S
 * DMIC
 * DSPK

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 .../bindings/sound/nvidia,tegra186-dspk.yaml       |  88 +++++++++++++
 .../bindings/sound/nvidia,tegra210-admaif.yaml     | 116 +++++++++++++++++
 .../bindings/sound/nvidia,tegra210-ahub.yaml       | 144 +++++++++++++++++++++
 .../bindings/sound/nvidia,tegra210-dmic.yaml       |  88 +++++++++++++
 .../bindings/sound/nvidia,tegra210-i2s.yaml        | 106 +++++++++++++++
 5 files changed, 542 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml

diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
new file mode 100644
index 0000000..13a9570
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra186-dspk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra186 DSPK Controller Device Tree Bindings
+
+description: |
+  The Digital Speaker Controller (DSPK) can be viewed as a Pulse
+  Density Modulation (PDM) transmitter that up-samples the input to
+  the desired sampling rate by interpolation and then converts the
+  over sampled Pulse Code Modulation (PCM) input to the desired 1-bit
+  output via Delta Sigma Modulation (DSM).
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^dspk@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra186-dspk
+      - items:
+          - const: nvidia,tegra194-dspk
+          - const: nvidia,tegra186-dspk
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: dspk
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clock-parents:
+    maxItems: 1
+
+  assigned-clock-rates:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  sound-name-prefix:
+    pattern: "^DSPK[1-9]$"
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+      The name can be "DSPK1" or "DSPKx", where x depends on the maximum
+      available instances on a Tegra SoC.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#sound-dai-cells"
+  - sound-name-prefix
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra186-clock.h>
+
+    dspk@2905000 {
+        compatible = "nvidia,tegra186-dspk";
+        reg = <0x2905000 0x100>;
+        clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+        clock-names = "dspk";
+        assigned-clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+        assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <12288000>;
+        #sound-dai-cells = <1>;
+        sound-name-prefix = "DSPK1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
new file mode 100644
index 0000000..aab60cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-admaif.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 ADMAIF Device Tree Bindings
+
+description: |
+  ADMAIF is the interface between ADMA and AHUB. Each ADMA channel
+  that sends/receives data to/from AHUB must interface through an
+  ADMAIF channel. ADMA channel sending data to AHUB pairs with ADMAIF
+  Tx channel and ADMA channel receiving data from AHUB pairs with
+  ADMAIF Rx channel.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^admaif@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - enum:
+          - nvidia,tegra210-admaif
+          - nvidia,tegra186-admaif
+      - items:
+          - const: nvidia,tegra194-admaif
+          - const: nvidia,tegra186-admaif
+
+  reg:
+    maxItems: 1
+
+  dmas: true
+
+  dma-names: true
+
+  "#sound-dai-cells":
+    const: 1
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: nvidia,tegra210-admaif
+
+then:
+  properties:
+    dmas:
+      description:
+        DMA channel specifiers, equally divided for Tx and Rx.
+      minItems: 1
+      maxItems: 20
+    dma-names:
+      items:
+        pattern: "^[rt]x(10|[1-9])$"
+      description:
+        Should be "rx1", "rx2" ... "rx10" for DMA Rx channel
+        Should be "tx1", "tx2" ... "tx10" for DMA Tx channel
+      minItems: 1
+      maxItems: 20
+
+else:
+  properties:
+    dmas:
+      description:
+        DMA channel specifiers, equally divided for Tx and Rx.
+      minItems: 1
+      maxItems: 40
+    dma-names:
+      items:
+        pattern: "^[rt]x(1[0-9]|[1-9]|20)$"
+      description:
+        Should be "rx1", "rx2" ... "rx20" for DMA Rx channel
+        Should be "tx1", "tx2" ... "tx20" for DMA Tx channel
+      minItems: 1
+      maxItems: 40
+
+required:
+  - compatible
+  - reg
+  - dmas
+  - dma-names
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    admaif@702d0000 {
+        compatible = "nvidia,tegra210-admaif";
+        reg = <0x702d0000 0x800>;
+        dmas = <&adma 1>,  <&adma 1>,
+               <&adma 2>,  <&adma 2>,
+               <&adma 3>,  <&adma 3>,
+               <&adma 4>,  <&adma 4>,
+               <&adma 5>,  <&adma 5>,
+               <&adma 6>,  <&adma 6>,
+               <&adma 7>,  <&adma 7>,
+               <&adma 8>,  <&adma 8>,
+               <&adma 9>,  <&adma 9>,
+               <&adma 10>, <&adma 10>;
+        dma-names = "rx1",  "tx1",
+                    "rx2",  "tx2",
+                    "rx3",  "tx3",
+                    "rx4",  "tx4",
+                    "rx5",  "tx5",
+                    "rx6",  "tx6",
+                    "rx7",  "tx7",
+                    "rx8",  "tx8",
+                    "rx9",  "tx9",
+                    "rx10", "tx10";
+        #sound-dai-cells = <1>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
new file mode 100644
index 0000000..44ee497
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
@@ -0,0 +1,144 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ahub.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 AHUB Device Tree Bindings
+
+description: |
+  The Audio Hub (AHUB) comprises a collection of hardware accelerators
+  for audio pre-processing, post-processing and a programmable full
+  crossbar for routing audio data across these accelerators. It has
+  external interfaces such as I2S, DMIC, DSPK. It interfaces with ADMA
+  engine through ADMAIF.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^ahub@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - enum:
+          - nvidia,tegra210-ahub
+          - nvidia,tegra186-ahub
+      - items:
+          - const: nvidia,tegra194-ahub
+          - const: nvidia,tegra186-ahub
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: ahub
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clock-parents:
+    maxItems: 1
+
+  assigned-clock-rates:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges: true
+
+  "#sound-dai-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    ahub@702d0800 {
+        compatible = "nvidia,tegra210-ahub";
+        reg = <0x702d0800 0x800>;
+        clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        clock-names = "ahub";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x702d0000 0x702d0000 0x0000e400>;
+        #sound-dai-cells = <1>;
+
+        // All AHUB child nodes below
+        admaif@702d0000 {
+            compatible = "nvidia,tegra210-admaif";
+            reg = <0x702d0000 0x800>;
+            dmas = <&adma 1>,  <&adma 1>,
+               <&adma 2>,  <&adma 2>,
+               <&adma 3>,  <&adma 3>,
+               <&adma 4>,  <&adma 4>,
+               <&adma 5>,  <&adma 5>,
+               <&adma 6>,  <&adma 6>,
+               <&adma 7>,  <&adma 7>,
+               <&adma 8>,  <&adma 8>,
+               <&adma 9>,  <&adma 9>,
+               <&adma 10>, <&adma 10>;
+            dma-names = "rx1",  "tx1",
+                    "rx2",  "tx2",
+                    "rx3",  "tx3",
+                    "rx4",  "tx4",
+                    "rx5",  "tx5",
+                    "rx6",  "tx6",
+                    "rx7",  "tx7",
+                    "rx8",  "tx8",
+                    "rx9",  "tx9",
+                    "rx10", "tx10";
+            #sound-dai-cells = <1>;
+        };
+
+        i2s@702d1000 {
+            compatible = "nvidia,tegra210-i2s";
+            reg = <0x702d1000 0x100>;
+            clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            clock-names = "i2s";
+            assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+            assigned-clock-rates = <1536000>;
+            #sound-dai-cells = <1>;
+            sound-name-prefix = "I2S1";
+        };
+
+        dmic@702d4000 {
+            compatible = "nvidia,tegra210-dmic";
+            reg = <0x702d4000 0x100>;
+            clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+            clock-names = "dmic";
+            assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+            assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+            assigned-clock-rates = <3072000>;
+            #sound-dai-cells = <1>;
+            sound-name-prefix = "DMIC1";
+        };
+
+        // More child nodes to follow
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
new file mode 100644
index 0000000..b49d0ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-dmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 DMIC Controller Device Tree Bindings
+
+description: |
+  The Digital MIC (DMIC) Controller is used to interface with Pulse
+  Density Modulation (PDM) input devices. It converts PDM signals to
+  Pulse Coded Modulation (PCM) signals. DMIC can be viewed as a PDM
+  receiver.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^dmic@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-dmic
+      - items:
+          - enum:
+              - nvidia,tegra194-dmic
+              - nvidia,tegra186-dmic
+          - const: nvidia,tegra210-dmic
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: dmic
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clock-parents:
+    maxItems: 1
+
+  assigned-clock-rates:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  sound-name-prefix:
+    pattern: "^DMIC[1-9]$"
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+    description:
+      used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+      The name can be "DMIC1" or "DMIC2" ... "DMICx", where x depends
+      on the maximum available instances on a Tegra SoC.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    dmic@702d4000 {
+        compatible = "nvidia,tegra210-dmic";
+        reg = <0x702d4000 0x100>;
+        clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+        clock-names = "dmic";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <3072000>;
+        #sound-dai-cells = <1>;
+        sound-name-prefix = "DMIC1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
new file mode 100644
index 0000000..9465216
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 I2S Controller Device Tree Bindings
+
+description: |
+  The Inter-IC Sound (I2S) controller implements full-duplex,
+  bi-directional and single direction point-to-point serial
+  interfaces. It can interface with I2S compatible devices.
+  I2S controller can operate both in master and slave mode.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^i2s@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-i2s
+      - items:
+          - enum:
+              - nvidia,tegra194-i2s
+              - nvidia,tegra186-i2s
+          - const: nvidia,tegra210-i2s
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    maxItems: 2
+    items:
+      - description: I2S bit clock
+      - description:
+          Sync input clock, which can act as clock source to other I/O
+          modules in AHUB. The Tegra I2S driver sets this clock rate as
+          per bit clock rate. I/O module which wants to use this clock
+          as source, can mention this clock as parent in the DT bindings.
+          This is an optional clock entry, since it is only required when
+          some other I/O wants to reference from a particular I2Sx
+          instance.
+
+  clock-names:
+    minItems: 1
+    maxItems: 2
+    items:
+      - const: i2s
+      - const: sync_input
+
+  assigned-clocks:
+    minItems: 1
+    maxItems: 2
+
+  assigned-clock-parents:
+    minItems: 1
+    maxItems: 2
+
+  assigned-clock-rates:
+    minItems: 1
+    maxItems: 2
+
+  "#sound-dai-cells":
+    const: 1
+
+  sound-name-prefix:
+    pattern: "^I2S[1-9]$"
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+      The name can be "I2S1" or "I2S2" ... "I2Sx", where x depends
+      on the maximum available instances on a Tegra SoC.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    i2s@702d1000 {
+        compatible = "nvidia,tegra210-i2s";
+        reg = <0x702d1000 0x100>;
+        clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+        clock-names = "i2s";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <1536000>;
+        #sound-dai-cells = <1>;
+        sound-name-prefix = "I2S1";
+    };
+
+...
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 01/23] ASoC: dt-bindings: tegra: Add DT bindings for Tegra210
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

This patch adds YAML schema for DT binding of AHUB and few of its
following components. These devices will be registered as ASoC
components and binding will be used on Tegra210 and later chips.
 * ADMAIF
 * I2S
 * DMIC
 * DSPK

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 .../bindings/sound/nvidia,tegra186-dspk.yaml       |  88 +++++++++++++
 .../bindings/sound/nvidia,tegra210-admaif.yaml     | 116 +++++++++++++++++
 .../bindings/sound/nvidia,tegra210-ahub.yaml       | 144 +++++++++++++++++++++
 .../bindings/sound/nvidia,tegra210-dmic.yaml       |  88 +++++++++++++
 .../bindings/sound/nvidia,tegra210-i2s.yaml        | 106 +++++++++++++++
 5 files changed, 542 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml

diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
new file mode 100644
index 0000000..13a9570
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra186-dspk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra186 DSPK Controller Device Tree Bindings
+
+description: |
+  The Digital Speaker Controller (DSPK) can be viewed as a Pulse
+  Density Modulation (PDM) transmitter that up-samples the input to
+  the desired sampling rate by interpolation and then converts the
+  over sampled Pulse Code Modulation (PCM) input to the desired 1-bit
+  output via Delta Sigma Modulation (DSM).
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^dspk@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra186-dspk
+      - items:
+          - const: nvidia,tegra194-dspk
+          - const: nvidia,tegra186-dspk
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: dspk
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clock-parents:
+    maxItems: 1
+
+  assigned-clock-rates:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  sound-name-prefix:
+    pattern: "^DSPK[1-9]$"
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+      The name can be "DSPK1" or "DSPKx", where x depends on the maximum
+      available instances on a Tegra SoC.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#sound-dai-cells"
+  - sound-name-prefix
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra186-clock.h>
+
+    dspk@2905000 {
+        compatible = "nvidia,tegra186-dspk";
+        reg = <0x2905000 0x100>;
+        clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+        clock-names = "dspk";
+        assigned-clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+        assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <12288000>;
+        #sound-dai-cells = <1>;
+        sound-name-prefix = "DSPK1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
new file mode 100644
index 0000000..aab60cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-admaif.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 ADMAIF Device Tree Bindings
+
+description: |
+  ADMAIF is the interface between ADMA and AHUB. Each ADMA channel
+  that sends/receives data to/from AHUB must interface through an
+  ADMAIF channel. ADMA channel sending data to AHUB pairs with ADMAIF
+  Tx channel and ADMA channel receiving data from AHUB pairs with
+  ADMAIF Rx channel.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^admaif@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - enum:
+          - nvidia,tegra210-admaif
+          - nvidia,tegra186-admaif
+      - items:
+          - const: nvidia,tegra194-admaif
+          - const: nvidia,tegra186-admaif
+
+  reg:
+    maxItems: 1
+
+  dmas: true
+
+  dma-names: true
+
+  "#sound-dai-cells":
+    const: 1
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: nvidia,tegra210-admaif
+
+then:
+  properties:
+    dmas:
+      description:
+        DMA channel specifiers, equally divided for Tx and Rx.
+      minItems: 1
+      maxItems: 20
+    dma-names:
+      items:
+        pattern: "^[rt]x(10|[1-9])$"
+      description:
+        Should be "rx1", "rx2" ... "rx10" for DMA Rx channel
+        Should be "tx1", "tx2" ... "tx10" for DMA Tx channel
+      minItems: 1
+      maxItems: 20
+
+else:
+  properties:
+    dmas:
+      description:
+        DMA channel specifiers, equally divided for Tx and Rx.
+      minItems: 1
+      maxItems: 40
+    dma-names:
+      items:
+        pattern: "^[rt]x(1[0-9]|[1-9]|20)$"
+      description:
+        Should be "rx1", "rx2" ... "rx20" for DMA Rx channel
+        Should be "tx1", "tx2" ... "tx20" for DMA Tx channel
+      minItems: 1
+      maxItems: 40
+
+required:
+  - compatible
+  - reg
+  - dmas
+  - dma-names
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    admaif@702d0000 {
+        compatible = "nvidia,tegra210-admaif";
+        reg = <0x702d0000 0x800>;
+        dmas = <&adma 1>,  <&adma 1>,
+               <&adma 2>,  <&adma 2>,
+               <&adma 3>,  <&adma 3>,
+               <&adma 4>,  <&adma 4>,
+               <&adma 5>,  <&adma 5>,
+               <&adma 6>,  <&adma 6>,
+               <&adma 7>,  <&adma 7>,
+               <&adma 8>,  <&adma 8>,
+               <&adma 9>,  <&adma 9>,
+               <&adma 10>, <&adma 10>;
+        dma-names = "rx1",  "tx1",
+                    "rx2",  "tx2",
+                    "rx3",  "tx3",
+                    "rx4",  "tx4",
+                    "rx5",  "tx5",
+                    "rx6",  "tx6",
+                    "rx7",  "tx7",
+                    "rx8",  "tx8",
+                    "rx9",  "tx9",
+                    "rx10", "tx10";
+        #sound-dai-cells = <1>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
new file mode 100644
index 0000000..44ee497
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
@@ -0,0 +1,144 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ahub.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 AHUB Device Tree Bindings
+
+description: |
+  The Audio Hub (AHUB) comprises a collection of hardware accelerators
+  for audio pre-processing, post-processing and a programmable full
+  crossbar for routing audio data across these accelerators. It has
+  external interfaces such as I2S, DMIC, DSPK. It interfaces with ADMA
+  engine through ADMAIF.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^ahub@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - enum:
+          - nvidia,tegra210-ahub
+          - nvidia,tegra186-ahub
+      - items:
+          - const: nvidia,tegra194-ahub
+          - const: nvidia,tegra186-ahub
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: ahub
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clock-parents:
+    maxItems: 1
+
+  assigned-clock-rates:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges: true
+
+  "#sound-dai-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#address-cells"
+  - "#size-cells"
+  - ranges
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    ahub@702d0800 {
+        compatible = "nvidia,tegra210-ahub";
+        reg = <0x702d0800 0x800>;
+        clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        clock-names = "ahub";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        ranges = <0x702d0000 0x702d0000 0x0000e400>;
+        #sound-dai-cells = <1>;
+
+        // All AHUB child nodes below
+        admaif@702d0000 {
+            compatible = "nvidia,tegra210-admaif";
+            reg = <0x702d0000 0x800>;
+            dmas = <&adma 1>,  <&adma 1>,
+               <&adma 2>,  <&adma 2>,
+               <&adma 3>,  <&adma 3>,
+               <&adma 4>,  <&adma 4>,
+               <&adma 5>,  <&adma 5>,
+               <&adma 6>,  <&adma 6>,
+               <&adma 7>,  <&adma 7>,
+               <&adma 8>,  <&adma 8>,
+               <&adma 9>,  <&adma 9>,
+               <&adma 10>, <&adma 10>;
+            dma-names = "rx1",  "tx1",
+                    "rx2",  "tx2",
+                    "rx3",  "tx3",
+                    "rx4",  "tx4",
+                    "rx5",  "tx5",
+                    "rx6",  "tx6",
+                    "rx7",  "tx7",
+                    "rx8",  "tx8",
+                    "rx9",  "tx9",
+                    "rx10", "tx10";
+            #sound-dai-cells = <1>;
+        };
+
+        i2s@702d1000 {
+            compatible = "nvidia,tegra210-i2s";
+            reg = <0x702d1000 0x100>;
+            clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            clock-names = "i2s";
+            assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+            assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+            assigned-clock-rates = <1536000>;
+            #sound-dai-cells = <1>;
+            sound-name-prefix = "I2S1";
+        };
+
+        dmic@702d4000 {
+            compatible = "nvidia,tegra210-dmic";
+            reg = <0x702d4000 0x100>;
+            clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+            clock-names = "dmic";
+            assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+            assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+            assigned-clock-rates = <3072000>;
+            #sound-dai-cells = <1>;
+            sound-name-prefix = "DMIC1";
+        };
+
+        // More child nodes to follow
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
new file mode 100644
index 0000000..b49d0ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-dmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 DMIC Controller Device Tree Bindings
+
+description: |
+  The Digital MIC (DMIC) Controller is used to interface with Pulse
+  Density Modulation (PDM) input devices. It converts PDM signals to
+  Pulse Coded Modulation (PCM) signals. DMIC can be viewed as a PDM
+  receiver.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^dmic@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-dmic
+      - items:
+          - enum:
+              - nvidia,tegra194-dmic
+              - nvidia,tegra186-dmic
+          - const: nvidia,tegra210-dmic
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: dmic
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clock-parents:
+    maxItems: 1
+
+  assigned-clock-rates:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  sound-name-prefix:
+    pattern: "^DMIC[1-9]$"
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+    description:
+      used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+      The name can be "DMIC1" or "DMIC2" ... "DMICx", where x depends
+      on the maximum available instances on a Tegra SoC.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    dmic@702d4000 {
+        compatible = "nvidia,tegra210-dmic";
+        reg = <0x702d4000 0x100>;
+        clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+        clock-names = "dmic";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <3072000>;
+        #sound-dai-cells = <1>;
+        sound-name-prefix = "DMIC1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
new file mode 100644
index 0000000..9465216
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 I2S Controller Device Tree Bindings
+
+description: |
+  The Inter-IC Sound (I2S) controller implements full-duplex,
+  bi-directional and single direction point-to-point serial
+  interfaces. It can interface with I2S compatible devices.
+  I2S controller can operate both in master and slave mode.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  $nodename:
+    pattern: "^i2s@[0-9a-f]*$"
+
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-i2s
+      - items:
+          - enum:
+              - nvidia,tegra194-i2s
+              - nvidia,tegra186-i2s
+          - const: nvidia,tegra210-i2s
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    maxItems: 2
+    items:
+      - description: I2S bit clock
+      - description:
+          Sync input clock, which can act as clock source to other I/O
+          modules in AHUB. The Tegra I2S driver sets this clock rate as
+          per bit clock rate. I/O module which wants to use this clock
+          as source, can mention this clock as parent in the DT bindings.
+          This is an optional clock entry, since it is only required when
+          some other I/O wants to reference from a particular I2Sx
+          instance.
+
+  clock-names:
+    minItems: 1
+    maxItems: 2
+    items:
+      - const: i2s
+      - const: sync_input
+
+  assigned-clocks:
+    minItems: 1
+    maxItems: 2
+
+  assigned-clock-parents:
+    minItems: 1
+    maxItems: 2
+
+  assigned-clock-rates:
+    minItems: 1
+    maxItems: 2
+
+  "#sound-dai-cells":
+    const: 1
+
+  sound-name-prefix:
+    pattern: "^I2S[1-9]$"
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Used as prefix for sink/source names of the component. Must be a
+      unique string among multiple instances of the same component.
+      The name can be "I2S1" or "I2S2" ... "I2Sx", where x depends
+      on the maximum available instances on a Tegra SoC.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - assigned-clocks
+  - assigned-clock-parents
+  - "#sound-dai-cells"
+
+examples:
+  - |
+    #include<dt-bindings/clock/tegra210-car.h>
+
+    i2s@702d1000 {
+        compatible = "nvidia,tegra210-i2s";
+        reg = <0x702d1000 0x100>;
+        clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+        clock-names = "i2s";
+        assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+        assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+        assigned-clock-rates = <1536000>;
+        #sound-dai-cells = <1>;
+        sound-name-prefix = "I2S1";
+    };
+
+...
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 02/23] ASoC: tegra: Add support for CIF programming
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

Audio Client Interface (CIF) is a proprietary interface employed to route
audio samples through Audio Hub (AHUB) components by inter connecting the
various modules.

This patch exports an inline function tegra_set_cif() which can be used,
for now, to program CIF on Tegra210 and later Tegra generations. Later it
can be extended to include helpers for legacy chips as well.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Jon Hunter <jonathanh-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Reviewed-by: Dmitry Osipenko <digetx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 sound/soc/tegra/tegra_cif.h | 65 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)
 create mode 100644 sound/soc/tegra/tegra_cif.h

diff --git a/sound/soc/tegra/tegra_cif.h b/sound/soc/tegra/tegra_cif.h
new file mode 100644
index 0000000..7cca806
--- /dev/null
+++ b/sound/soc/tegra/tegra_cif.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra_cif.h - TEGRA Audio CIF Programming
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA_CIF_H__
+#define __TEGRA_CIF_H__
+
+#include <linux/regmap.h>
+
+#define TEGRA_ACIF_CTRL_FIFO_TH_SHIFT		24
+#define TEGRA_ACIF_CTRL_AUDIO_CH_SHIFT		20
+#define TEGRA_ACIF_CTRL_CLIENT_CH_SHIFT		16
+#define TEGRA_ACIF_CTRL_AUDIO_BITS_SHIFT	12
+#define TEGRA_ACIF_CTRL_CLIENT_BITS_SHIFT	8
+#define TEGRA_ACIF_CTRL_EXPAND_SHIFT		6
+#define TEGRA_ACIF_CTRL_STEREO_CONV_SHIFT	4
+#define TEGRA_ACIF_CTRL_REPLICATE_SHIFT		3
+#define TEGRA_ACIF_CTRL_TRUNCATE_SHIFT		1
+#define TEGRA_ACIF_CTRL_MONO_CONV_SHIFT		0
+
+/* AUDIO/CLIENT_BITS values */
+#define TEGRA_ACIF_BITS_8			1
+#define TEGRA_ACIF_BITS_16			3
+#define TEGRA_ACIF_BITS_24			5
+#define TEGRA_ACIF_BITS_32			7
+
+#define TEGRA_ACIF_UPDATE_MASK			0x3ffffffb
+
+struct tegra_cif_conf {
+	unsigned int threshold;
+	unsigned int audio_ch;
+	unsigned int client_ch;
+	unsigned int audio_bits;
+	unsigned int client_bits;
+	unsigned int expand;
+	unsigned int stereo_conv;
+	unsigned int replicate;
+	unsigned int truncate;
+	unsigned int mono_conv;
+};
+
+static inline void tegra_set_cif(struct regmap *regmap, unsigned int reg,
+				 struct tegra_cif_conf *conf)
+{
+	unsigned int value;
+
+	value = (conf->threshold << TEGRA_ACIF_CTRL_FIFO_TH_SHIFT) |
+		((conf->audio_ch - 1) << TEGRA_ACIF_CTRL_AUDIO_CH_SHIFT) |
+		((conf->client_ch - 1) << TEGRA_ACIF_CTRL_CLIENT_CH_SHIFT) |
+		(conf->audio_bits << TEGRA_ACIF_CTRL_AUDIO_BITS_SHIFT) |
+		(conf->client_bits << TEGRA_ACIF_CTRL_CLIENT_BITS_SHIFT) |
+		(conf->expand << TEGRA_ACIF_CTRL_EXPAND_SHIFT) |
+		(conf->stereo_conv << TEGRA_ACIF_CTRL_STEREO_CONV_SHIFT) |
+		(conf->replicate << TEGRA_ACIF_CTRL_REPLICATE_SHIFT) |
+		(conf->truncate << TEGRA_ACIF_CTRL_TRUNCATE_SHIFT) |
+		(conf->mono_conv << TEGRA_ACIF_CTRL_MONO_CONV_SHIFT);
+
+	regmap_update_bits(regmap, reg, TEGRA_ACIF_UPDATE_MASK, value);
+}
+
+#endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 02/23] ASoC: tegra: Add support for CIF programming
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

Audio Client Interface (CIF) is a proprietary interface employed to route
audio samples through Audio Hub (AHUB) components by inter connecting the
various modules.

This patch exports an inline function tegra_set_cif() which can be used,
for now, to program CIF on Tegra210 and later Tegra generations. Later it
can be extended to include helpers for legacy chips as well.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra_cif.h | 65 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)
 create mode 100644 sound/soc/tegra/tegra_cif.h

diff --git a/sound/soc/tegra/tegra_cif.h b/sound/soc/tegra/tegra_cif.h
new file mode 100644
index 0000000..7cca806
--- /dev/null
+++ b/sound/soc/tegra/tegra_cif.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra_cif.h - TEGRA Audio CIF Programming
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA_CIF_H__
+#define __TEGRA_CIF_H__
+
+#include <linux/regmap.h>
+
+#define TEGRA_ACIF_CTRL_FIFO_TH_SHIFT		24
+#define TEGRA_ACIF_CTRL_AUDIO_CH_SHIFT		20
+#define TEGRA_ACIF_CTRL_CLIENT_CH_SHIFT		16
+#define TEGRA_ACIF_CTRL_AUDIO_BITS_SHIFT	12
+#define TEGRA_ACIF_CTRL_CLIENT_BITS_SHIFT	8
+#define TEGRA_ACIF_CTRL_EXPAND_SHIFT		6
+#define TEGRA_ACIF_CTRL_STEREO_CONV_SHIFT	4
+#define TEGRA_ACIF_CTRL_REPLICATE_SHIFT		3
+#define TEGRA_ACIF_CTRL_TRUNCATE_SHIFT		1
+#define TEGRA_ACIF_CTRL_MONO_CONV_SHIFT		0
+
+/* AUDIO/CLIENT_BITS values */
+#define TEGRA_ACIF_BITS_8			1
+#define TEGRA_ACIF_BITS_16			3
+#define TEGRA_ACIF_BITS_24			5
+#define TEGRA_ACIF_BITS_32			7
+
+#define TEGRA_ACIF_UPDATE_MASK			0x3ffffffb
+
+struct tegra_cif_conf {
+	unsigned int threshold;
+	unsigned int audio_ch;
+	unsigned int client_ch;
+	unsigned int audio_bits;
+	unsigned int client_bits;
+	unsigned int expand;
+	unsigned int stereo_conv;
+	unsigned int replicate;
+	unsigned int truncate;
+	unsigned int mono_conv;
+};
+
+static inline void tegra_set_cif(struct regmap *regmap, unsigned int reg,
+				 struct tegra_cif_conf *conf)
+{
+	unsigned int value;
+
+	value = (conf->threshold << TEGRA_ACIF_CTRL_FIFO_TH_SHIFT) |
+		((conf->audio_ch - 1) << TEGRA_ACIF_CTRL_AUDIO_CH_SHIFT) |
+		((conf->client_ch - 1) << TEGRA_ACIF_CTRL_CLIENT_CH_SHIFT) |
+		(conf->audio_bits << TEGRA_ACIF_CTRL_AUDIO_BITS_SHIFT) |
+		(conf->client_bits << TEGRA_ACIF_CTRL_CLIENT_BITS_SHIFT) |
+		(conf->expand << TEGRA_ACIF_CTRL_EXPAND_SHIFT) |
+		(conf->stereo_conv << TEGRA_ACIF_CTRL_STEREO_CONV_SHIFT) |
+		(conf->replicate << TEGRA_ACIF_CTRL_REPLICATE_SHIFT) |
+		(conf->truncate << TEGRA_ACIF_CTRL_TRUNCATE_SHIFT) |
+		(conf->mono_conv << TEGRA_ACIF_CTRL_MONO_CONV_SHIFT);
+
+	regmap_update_bits(regmap, reg, TEGRA_ACIF_UPDATE_MASK, value);
+}
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 02/23] ASoC: tegra: Add support for CIF programming
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

Audio Client Interface (CIF) is a proprietary interface employed to route
audio samples through Audio Hub (AHUB) components by inter connecting the
various modules.

This patch exports an inline function tegra_set_cif() which can be used,
for now, to program CIF on Tegra210 and later Tegra generations. Later it
can be extended to include helpers for legacy chips as well.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra_cif.h | 65 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)
 create mode 100644 sound/soc/tegra/tegra_cif.h

diff --git a/sound/soc/tegra/tegra_cif.h b/sound/soc/tegra/tegra_cif.h
new file mode 100644
index 0000000..7cca806
--- /dev/null
+++ b/sound/soc/tegra/tegra_cif.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra_cif.h - TEGRA Audio CIF Programming
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA_CIF_H__
+#define __TEGRA_CIF_H__
+
+#include <linux/regmap.h>
+
+#define TEGRA_ACIF_CTRL_FIFO_TH_SHIFT		24
+#define TEGRA_ACIF_CTRL_AUDIO_CH_SHIFT		20
+#define TEGRA_ACIF_CTRL_CLIENT_CH_SHIFT		16
+#define TEGRA_ACIF_CTRL_AUDIO_BITS_SHIFT	12
+#define TEGRA_ACIF_CTRL_CLIENT_BITS_SHIFT	8
+#define TEGRA_ACIF_CTRL_EXPAND_SHIFT		6
+#define TEGRA_ACIF_CTRL_STEREO_CONV_SHIFT	4
+#define TEGRA_ACIF_CTRL_REPLICATE_SHIFT		3
+#define TEGRA_ACIF_CTRL_TRUNCATE_SHIFT		1
+#define TEGRA_ACIF_CTRL_MONO_CONV_SHIFT		0
+
+/* AUDIO/CLIENT_BITS values */
+#define TEGRA_ACIF_BITS_8			1
+#define TEGRA_ACIF_BITS_16			3
+#define TEGRA_ACIF_BITS_24			5
+#define TEGRA_ACIF_BITS_32			7
+
+#define TEGRA_ACIF_UPDATE_MASK			0x3ffffffb
+
+struct tegra_cif_conf {
+	unsigned int threshold;
+	unsigned int audio_ch;
+	unsigned int client_ch;
+	unsigned int audio_bits;
+	unsigned int client_bits;
+	unsigned int expand;
+	unsigned int stereo_conv;
+	unsigned int replicate;
+	unsigned int truncate;
+	unsigned int mono_conv;
+};
+
+static inline void tegra_set_cif(struct regmap *regmap, unsigned int reg,
+				 struct tegra_cif_conf *conf)
+{
+	unsigned int value;
+
+	value = (conf->threshold << TEGRA_ACIF_CTRL_FIFO_TH_SHIFT) |
+		((conf->audio_ch - 1) << TEGRA_ACIF_CTRL_AUDIO_CH_SHIFT) |
+		((conf->client_ch - 1) << TEGRA_ACIF_CTRL_CLIENT_CH_SHIFT) |
+		(conf->audio_bits << TEGRA_ACIF_CTRL_AUDIO_BITS_SHIFT) |
+		(conf->client_bits << TEGRA_ACIF_CTRL_CLIENT_BITS_SHIFT) |
+		(conf->expand << TEGRA_ACIF_CTRL_EXPAND_SHIFT) |
+		(conf->stereo_conv << TEGRA_ACIF_CTRL_STEREO_CONV_SHIFT) |
+		(conf->replicate << TEGRA_ACIF_CTRL_REPLICATE_SHIFT) |
+		(conf->truncate << TEGRA_ACIF_CTRL_TRUNCATE_SHIFT) |
+		(conf->mono_conv << TEGRA_ACIF_CTRL_MONO_CONV_SHIFT);
+
+	regmap_update_bits(regmap, reg, TEGRA_ACIF_UPDATE_MASK, value);
+}
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 03/23] ASoC: tegra: Add Tegra210 based DMIC driver
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

The Digital MIC (DMIC) Controller is used to interface with Pulse Density
Modulation (PDM) input devices. The DMIC controller implements a converter
to convert PDM signals to Pulse Code Modulation (PCM) signals. From signal
flow perspective, the DMIC can be viewed as a PDM receiver.

This patch registers DMIC component with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes DMIC interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The DMIC devices can be enabled in the DT via
"nvidia,tegra210-dmic" compatible string. This driver can be used for
Tegra186 and Tegra194 chips as well.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/tegra/Kconfig         |  11 +
 sound/soc/tegra/Makefile        |   2 +
 sound/soc/tegra/tegra210_dmic.c | 440 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_dmic.h |  82 ++++++++
 4 files changed, 535 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_dmic.c
 create mode 100644 sound/soc/tegra/tegra210_dmic.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index addadc8..2bde1e6 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -62,6 +62,17 @@ config SND_SOC_TEGRA30_I2S
 	  Tegra30 I2S interface. You will also need to select the individual
 	  machine drivers to support below.
 
+config SND_SOC_TEGRA210_DMIC
+        tristate "Tegra210 DMIC module"
+        depends on SND_SOC_TEGRA
+        help
+          Config to enable the Digital MIC (DMIC) controller which is used
+          to interface with Pulse Density Modulation (PDM) input devices.
+          The DMIC controller implements a converter to convert PDM signals
+          to Pulse Code Modulation (PCM) signals. This can be viewed as a
+          PDM receiver.
+          Say Y or M if you want to add support for Tegra210 DMIC module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index c84f183..f0690cf 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -8,6 +8,7 @@ snd-soc-tegra20-i2s-objs := tegra20_i2s.o
 snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 snd-soc-tegra30-ahub-objs := tegra30_ahub.o
 snd-soc-tegra30-i2s-objs := tegra30_i2s.o
+snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
new file mode 100644
index 0000000..15761cb
--- /dev/null
+++ b/sound/soc/tegra/tegra210_dmic.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_dmic.c - Tegra210 DMIC driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra210_dmic.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_dmic_reg_defaults[] = {
+	{ TEGRA210_DMIC_TX_INT_MASK, 0x00000001 },
+	{ TEGRA210_DMIC_TX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_DMIC_CG, 0x1 },
+	{ TEGRA210_DMIC_CTRL, 0x00000301 },
+	/* Below enables all filters - DCR, LP and SC */
+	{ TEGRA210_DMIC_DBG_CTRL, 0xe },
+	/* Below as per latest POR value */
+	{ TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, 0x0 },
+	/* LP filter is configured for pass through and used to apply gain */
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, 0x00800000 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, 0x00800000 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x0 },
+};
+
+static int tegra210_dmic_runtime_suspend(struct device *dev)
+{
+	struct tegra210_dmic *dmic = dev_get_drvdata(dev);
+
+	regcache_cache_only(dmic->regmap, true);
+	regcache_mark_dirty(dmic->regmap);
+
+	clk_disable_unprepare(dmic->clk_dmic);
+
+	return 0;
+}
+
+static int tegra210_dmic_runtime_resume(struct device *dev)
+{
+	struct tegra210_dmic *dmic = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(dmic->clk_dmic);
+	if (err) {
+		dev_err(dev, "failed to enable DMIC clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(dmic->regmap, false);
+	regcache_sync(dmic->regmap);
+
+	return 0;
+}
+
+static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct tegra210_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+	unsigned int srate, clk_rate, channels;
+	struct tegra_cif_conf cif_conf;
+	unsigned long long gain_q23 = DEFAULT_GAIN_Q23;
+	int err;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+
+	cif_conf.audio_ch = channels;
+
+	switch (dmic->ch_select) {
+	case DMIC_CH_SELECT_LEFT:
+	case DMIC_CH_SELECT_RIGHT:
+		cif_conf.client_ch = 1;
+		break;
+	case DMIC_CH_SELECT_STEREO:
+		cif_conf.client_ch = 2;
+		break;
+	default:
+		dev_err(dai->dev, "invalid DMIC client channels\n");
+		return -EINVAL;
+	}
+
+	srate = params_rate(params);
+
+	/*
+	 * DMIC clock rate is a multiple of 'Over Sampling Ratio' and
+	 * 'Sample Rate'. The supported OSR values are 64, 128 and 256.
+	 */
+	clk_rate = (DMIC_OSR_FACTOR << dmic->osr_val) * srate;
+
+	err = clk_set_rate(dmic->clk_dmic, clk_rate);
+	if (err) {
+		dev_err(dai->dev, "can't set DMIC clock rate %u, err: %d\n",
+			clk_rate, err);
+		return err;
+	}
+
+	regmap_update_bits(dmic->regmap,
+			   /* Reg */
+			   TEGRA210_DMIC_CTRL,
+			   /* Mask */
+			   TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK |
+			   TEGRA210_DMIC_CTRL_OSR_MASK |
+			   TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK,
+			   /* Value */
+			   (dmic->lrsel << LRSEL_POL_SHIFT) |
+			   (dmic->osr_val << OSR_SHIFT) |
+			   ((dmic->ch_select + 1) << CH_SEL_SHIFT));
+
+	/*
+	 * Use LP filter gain register to apply boost.
+	 * Boost Gain Volume control has 100x factor.
+	 */
+	if (dmic->boost_gain)
+		gain_q23 = (gain_q23 * dmic->boost_gain) / 100;
+
+	regmap_write(dmic->regmap, TEGRA210_DMIC_LP_FILTER_GAIN,
+		     (unsigned int)gain_q23);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dai->dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	cif_conf.client_bits = TEGRA_ACIF_BITS_24;
+	cif_conf.mono_conv = dmic->mono_to_stereo;
+	cif_conf.stereo_conv = dmic->stereo_to_mono;
+
+	tegra_set_cif(dmic->regmap, TEGRA210_DMIC_TX_CIF_CTRL, &cif_conf);
+
+	return 0;
+}
+
+static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+
+	if (strstr(kcontrol->id.name, "Boost Gain Volume"))
+		ucontrol->value.integer.value[0] = dmic->boost_gain;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		ucontrol->value.integer.value[0] = dmic->ch_select;
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		ucontrol->value.integer.value[0] = dmic->mono_to_stereo;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		ucontrol->value.integer.value[0] = dmic->stereo_to_mono;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		ucontrol->value.integer.value[0] = dmic->osr_val;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		ucontrol->value.integer.value[0] = dmic->lrsel;
+
+	return 0;
+}
+
+static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+	int value = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Boost Gain Volume"))
+		dmic->boost_gain = value;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		dmic->ch_select = ucontrol->value.integer.value[0];
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		dmic->mono_to_stereo = value;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		dmic->stereo_to_mono = value;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		dmic->osr_val = value;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		dmic->lrsel = value;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra210_dmic_dai_ops = {
+	.hw_params	= tegra210_dmic_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
+	{
+		.name = "DMIC",
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &tegra210_dmic_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const struct snd_soc_dapm_widget tegra210_dmic_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_DMIC_ENABLE, 0, 0),
+};
+
+static const struct snd_soc_dapm_route tegra210_dmic_routes[] = {
+	{ "TX",		NULL,	"Capture" },
+	{ "XBAR-RX",	NULL,	"TX" },
+};
+
+static const char * const tegra210_dmic_ch_select[] = {
+	"Left", "Right", "Stereo",
+};
+
+static const struct soc_enum tegra210_dmic_ch_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_ch_select),
+			tegra210_dmic_ch_select);
+
+static const char * const tegra210_dmic_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+static const char * const tegra210_dmic_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const struct soc_enum tegra210_dmic_mono_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_mono_conv_text),
+			tegra210_dmic_mono_conv_text);
+
+static const struct soc_enum tegra210_dmic_stereo_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_stereo_conv_text),
+			tegra210_dmic_stereo_conv_text);
+
+static const char * const tegra210_dmic_osr_text[] = {
+	"OSR_64", "OSR_128", "OSR_256",
+};
+
+static const struct soc_enum tegra210_dmic_osr_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_osr_text),
+			tegra210_dmic_osr_text);
+
+static const char * const tegra210_dmic_lrsel_text[] = {
+	"Left", "Right",
+};
+
+static const struct soc_enum tegra210_dmic_lrsel_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_lrsel_text),
+			tegra210_dmic_lrsel_text);
+
+static const struct snd_kcontrol_new tegra210_dmic_controls[] = {
+	SOC_SINGLE_EXT("Boost Gain Volume", 0, 0, MAX_BOOST_GAIN, 0,
+		       tegra210_dmic_get_control, tegra210_dmic_put_control),
+	SOC_ENUM_EXT("Channel Select", tegra210_dmic_ch_enum,
+		     tegra210_dmic_get_control, tegra210_dmic_put_control),
+	SOC_ENUM_EXT("Mono To Stereo",
+		     tegra210_dmic_mono_conv_enum, tegra210_dmic_get_control,
+		     tegra210_dmic_put_control),
+	SOC_ENUM_EXT("Stereo To Mono",
+		     tegra210_dmic_stereo_conv_enum, tegra210_dmic_get_control,
+		     tegra210_dmic_put_control),
+	SOC_ENUM_EXT("OSR Value", tegra210_dmic_osr_enum,
+		     tegra210_dmic_get_control, tegra210_dmic_put_control),
+	SOC_ENUM_EXT("LR Polarity Select", tegra210_dmic_lrsel_enum,
+		     tegra210_dmic_get_control, tegra210_dmic_put_control),
+};
+
+static const struct snd_soc_component_driver tegra210_dmic_compnt = {
+	.dapm_widgets		= tegra210_dmic_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tegra210_dmic_widgets),
+	.dapm_routes		= tegra210_dmic_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tegra210_dmic_routes),
+	.controls		= tegra210_dmic_controls,
+	.num_controls		= ARRAY_SIZE(tegra210_dmic_controls),
+};
+
+static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_DMIC_TX_INT_MASK ... TEGRA210_DMIC_TX_CIF_CTRL:
+	case TEGRA210_DMIC_ENABLE ... TEGRA210_DMIC_CG:
+	case TEGRA210_DMIC_CTRL:
+	case TEGRA210_DMIC_DBG_CTRL:
+	case TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4 ... TEGRA210_DMIC_LP_BIQUAD_1_COEF_4:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_dmic_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_DMIC_TX_STATUS:
+	case TEGRA210_DMIC_TX_INT_STATUS:
+	case TEGRA210_DMIC_STATUS:
+	case TEGRA210_DMIC_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_DMIC_TX_STATUS:
+	case TEGRA210_DMIC_TX_INT_STATUS:
+	case TEGRA210_DMIC_TX_INT_SET:
+	case TEGRA210_DMIC_SOFT_RESET:
+	case TEGRA210_DMIC_STATUS:
+	case TEGRA210_DMIC_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra210_dmic_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = TEGRA210_DMIC_LP_BIQUAD_1_COEF_4,
+	.writeable_reg = tegra210_dmic_wr_reg,
+	.readable_reg = tegra210_dmic_rd_reg,
+	.volatile_reg = tegra210_dmic_volatile_reg,
+	.reg_defaults = tegra210_dmic_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tegra210_dmic_reg_defaults),
+	.cache_type = REGCACHE_FLAT,
+};
+
+static int tegra210_dmic_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_dmic *dmic;
+	void __iomem *regs;
+	int err;
+
+	dmic = devm_kzalloc(dev, sizeof(*dmic), GFP_KERNEL);
+	if (!dmic)
+		return -ENOMEM;
+
+	dmic->osr_val = DMIC_OSR_64;
+	dmic->ch_select = DMIC_CH_SELECT_STEREO;
+	dmic->lrsel = DMIC_LRSEL_LEFT;
+	dmic->boost_gain = 0;
+	dmic->stereo_to_mono = 0; /* "CH0" */
+
+	dev_set_drvdata(dev, dmic);
+
+	dmic->clk_dmic = devm_clk_get(dev, "dmic");
+	if (IS_ERR(dmic->clk_dmic)) {
+		dev_err(dev, "can't retrieve DMIC clock\n");
+		return PTR_ERR(dmic->clk_dmic);
+	}
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	dmic->regmap = devm_regmap_init_mmio(dev, regs,
+					     &tegra210_dmic_regmap_config);
+	if (IS_ERR(dmic->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(dmic->regmap);
+	}
+
+	regcache_cache_only(dmic->regmap, true);
+
+	err = devm_snd_soc_register_component(dev, &tegra210_dmic_compnt,
+					      tegra210_dmic_dais,
+					      ARRAY_SIZE(tegra210_dmic_dais));
+	if (err) {
+		dev_err(dev, "can't register DMIC component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra210_dmic_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra210_dmic_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend,
+			   tegra210_dmic_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_dmic_of_match[] = {
+	{ .compatible = "nvidia,tegra210-dmic" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra210_dmic_of_match);
+
+static struct platform_driver tegra210_dmic_driver = {
+	.driver = {
+		.name = "tegra210-dmic",
+		.of_match_table = tegra210_dmic_of_match,
+		.pm = &tegra210_dmic_pm_ops,
+	},
+	.probe = tegra210_dmic_probe,
+	.remove = tegra210_dmic_remove,
+};
+module_platform_driver(tegra210_dmic_driver)
+
+MODULE_AUTHOR("Rahul Mittal <rmittal-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
+MODULE_DESCRIPTION("Tegra210 ASoC DMIC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_dmic.h b/sound/soc/tegra/tegra210_dmic.h
new file mode 100644
index 0000000..6418c22
--- /dev/null
+++ b/sound/soc/tegra/tegra210_dmic.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_dmic.h - Definitions for Tegra210 DMIC driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_DMIC_H__
+#define __TEGRA210_DMIC_H__
+
+/* Register offsets from DMIC BASE */
+#define TEGRA210_DMIC_TX_STATUS				0x0c
+#define TEGRA210_DMIC_TX_INT_STATUS			0x10
+#define TEGRA210_DMIC_TX_INT_MASK			0x14
+#define TEGRA210_DMIC_TX_INT_SET			0x18
+#define TEGRA210_DMIC_TX_INT_CLEAR			0x1c
+#define TEGRA210_DMIC_TX_CIF_CTRL			0x20
+#define TEGRA210_DMIC_ENABLE				0x40
+#define TEGRA210_DMIC_SOFT_RESET			0x44
+#define TEGRA210_DMIC_CG				0x48
+#define TEGRA210_DMIC_STATUS				0x4c
+#define TEGRA210_DMIC_INT_STATUS			0x50
+#define TEGRA210_DMIC_CTRL				0x64
+#define TEGRA210_DMIC_DBG_CTRL				0x70
+#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4		0x88
+#define TEGRA210_DMIC_LP_FILTER_GAIN			0x8c
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_0		0x90
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_1		0x94
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_2		0x98
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_3		0x9c
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_4		0xa0
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_0		0xa4
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_1		0xa8
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_2		0xac
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_3		0xb0
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_4		0xb4
+
+/* Fields in TEGRA210_DMIC_CTRL */
+#define CH_SEL_SHIFT					8
+#define TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK		(0x3 << CH_SEL_SHIFT)
+#define LRSEL_POL_SHIFT					4
+#define TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK		(0x1 << LRSEL_POL_SHIFT)
+#define OSR_SHIFT					0
+#define TEGRA210_DMIC_CTRL_OSR_MASK			(0x3 << OSR_SHIFT)
+
+#define DMIC_OSR_FACTOR					64
+
+#define DEFAULT_GAIN_Q23				0x800000
+
+/* Max boost gain factor used for mixer control */
+#define MAX_BOOST_GAIN 25599
+
+enum tegra_dmic_ch_select {
+	DMIC_CH_SELECT_LEFT,
+	DMIC_CH_SELECT_RIGHT,
+	DMIC_CH_SELECT_STEREO,
+};
+
+enum tegra_dmic_osr {
+	DMIC_OSR_64,
+	DMIC_OSR_128,
+	DMIC_OSR_256,
+};
+
+enum tegra_dmic_lrsel {
+	DMIC_LRSEL_LEFT,
+	DMIC_LRSEL_RIGHT,
+};
+
+struct tegra210_dmic {
+	struct clk *clk_dmic;
+	struct regmap *regmap;
+	unsigned int mono_to_stereo;
+	unsigned int stereo_to_mono;
+	unsigned int boost_gain;
+	unsigned int ch_select;
+	unsigned int osr_val;
+	unsigned int lrsel;
+};
+
+#endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 03/23] ASoC: tegra: Add Tegra210 based DMIC driver
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

The Digital MIC (DMIC) Controller is used to interface with Pulse Density
Modulation (PDM) input devices. The DMIC controller implements a converter
to convert PDM signals to Pulse Code Modulation (PCM) signals. From signal
flow perspective, the DMIC can be viewed as a PDM receiver.

This patch registers DMIC component with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes DMIC interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The DMIC devices can be enabled in the DT via
"nvidia,tegra210-dmic" compatible string. This driver can be used for
Tegra186 and Tegra194 chips as well.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig         |  11 +
 sound/soc/tegra/Makefile        |   2 +
 sound/soc/tegra/tegra210_dmic.c | 440 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_dmic.h |  82 ++++++++
 4 files changed, 535 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_dmic.c
 create mode 100644 sound/soc/tegra/tegra210_dmic.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index addadc8..2bde1e6 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -62,6 +62,17 @@ config SND_SOC_TEGRA30_I2S
 	  Tegra30 I2S interface. You will also need to select the individual
 	  machine drivers to support below.
 
+config SND_SOC_TEGRA210_DMIC
+        tristate "Tegra210 DMIC module"
+        depends on SND_SOC_TEGRA
+        help
+          Config to enable the Digital MIC (DMIC) controller which is used
+          to interface with Pulse Density Modulation (PDM) input devices.
+          The DMIC controller implements a converter to convert PDM signals
+          to Pulse Code Modulation (PCM) signals. This can be viewed as a
+          PDM receiver.
+          Say Y or M if you want to add support for Tegra210 DMIC module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index c84f183..f0690cf 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -8,6 +8,7 @@ snd-soc-tegra20-i2s-objs := tegra20_i2s.o
 snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 snd-soc-tegra30-ahub-objs := tegra30_ahub.o
 snd-soc-tegra30-i2s-objs := tegra30_i2s.o
+snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
new file mode 100644
index 0000000..15761cb
--- /dev/null
+++ b/sound/soc/tegra/tegra210_dmic.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_dmic.c - Tegra210 DMIC driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra210_dmic.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_dmic_reg_defaults[] = {
+	{ TEGRA210_DMIC_TX_INT_MASK, 0x00000001 },
+	{ TEGRA210_DMIC_TX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_DMIC_CG, 0x1 },
+	{ TEGRA210_DMIC_CTRL, 0x00000301 },
+	/* Below enables all filters - DCR, LP and SC */
+	{ TEGRA210_DMIC_DBG_CTRL, 0xe },
+	/* Below as per latest POR value */
+	{ TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, 0x0 },
+	/* LP filter is configured for pass through and used to apply gain */
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, 0x00800000 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, 0x00800000 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x0 },
+};
+
+static int tegra210_dmic_runtime_suspend(struct device *dev)
+{
+	struct tegra210_dmic *dmic = dev_get_drvdata(dev);
+
+	regcache_cache_only(dmic->regmap, true);
+	regcache_mark_dirty(dmic->regmap);
+
+	clk_disable_unprepare(dmic->clk_dmic);
+
+	return 0;
+}
+
+static int tegra210_dmic_runtime_resume(struct device *dev)
+{
+	struct tegra210_dmic *dmic = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(dmic->clk_dmic);
+	if (err) {
+		dev_err(dev, "failed to enable DMIC clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(dmic->regmap, false);
+	regcache_sync(dmic->regmap);
+
+	return 0;
+}
+
+static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct tegra210_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+	unsigned int srate, clk_rate, channels;
+	struct tegra_cif_conf cif_conf;
+	unsigned long long gain_q23 = DEFAULT_GAIN_Q23;
+	int err;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+
+	cif_conf.audio_ch = channels;
+
+	switch (dmic->ch_select) {
+	case DMIC_CH_SELECT_LEFT:
+	case DMIC_CH_SELECT_RIGHT:
+		cif_conf.client_ch = 1;
+		break;
+	case DMIC_CH_SELECT_STEREO:
+		cif_conf.client_ch = 2;
+		break;
+	default:
+		dev_err(dai->dev, "invalid DMIC client channels\n");
+		return -EINVAL;
+	}
+
+	srate = params_rate(params);
+
+	/*
+	 * DMIC clock rate is a multiple of 'Over Sampling Ratio' and
+	 * 'Sample Rate'. The supported OSR values are 64, 128 and 256.
+	 */
+	clk_rate = (DMIC_OSR_FACTOR << dmic->osr_val) * srate;
+
+	err = clk_set_rate(dmic->clk_dmic, clk_rate);
+	if (err) {
+		dev_err(dai->dev, "can't set DMIC clock rate %u, err: %d\n",
+			clk_rate, err);
+		return err;
+	}
+
+	regmap_update_bits(dmic->regmap,
+			   /* Reg */
+			   TEGRA210_DMIC_CTRL,
+			   /* Mask */
+			   TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK |
+			   TEGRA210_DMIC_CTRL_OSR_MASK |
+			   TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK,
+			   /* Value */
+			   (dmic->lrsel << LRSEL_POL_SHIFT) |
+			   (dmic->osr_val << OSR_SHIFT) |
+			   ((dmic->ch_select + 1) << CH_SEL_SHIFT));
+
+	/*
+	 * Use LP filter gain register to apply boost.
+	 * Boost Gain Volume control has 100x factor.
+	 */
+	if (dmic->boost_gain)
+		gain_q23 = (gain_q23 * dmic->boost_gain) / 100;
+
+	regmap_write(dmic->regmap, TEGRA210_DMIC_LP_FILTER_GAIN,
+		     (unsigned int)gain_q23);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dai->dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	cif_conf.client_bits = TEGRA_ACIF_BITS_24;
+	cif_conf.mono_conv = dmic->mono_to_stereo;
+	cif_conf.stereo_conv = dmic->stereo_to_mono;
+
+	tegra_set_cif(dmic->regmap, TEGRA210_DMIC_TX_CIF_CTRL, &cif_conf);
+
+	return 0;
+}
+
+static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+
+	if (strstr(kcontrol->id.name, "Boost Gain Volume"))
+		ucontrol->value.integer.value[0] = dmic->boost_gain;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		ucontrol->value.integer.value[0] = dmic->ch_select;
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		ucontrol->value.integer.value[0] = dmic->mono_to_stereo;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		ucontrol->value.integer.value[0] = dmic->stereo_to_mono;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		ucontrol->value.integer.value[0] = dmic->osr_val;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		ucontrol->value.integer.value[0] = dmic->lrsel;
+
+	return 0;
+}
+
+static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+	int value = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Boost Gain Volume"))
+		dmic->boost_gain = value;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		dmic->ch_select = ucontrol->value.integer.value[0];
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		dmic->mono_to_stereo = value;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		dmic->stereo_to_mono = value;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		dmic->osr_val = value;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		dmic->lrsel = value;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra210_dmic_dai_ops = {
+	.hw_params	= tegra210_dmic_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
+	{
+		.name = "DMIC",
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &tegra210_dmic_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const struct snd_soc_dapm_widget tegra210_dmic_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_DMIC_ENABLE, 0, 0),
+};
+
+static const struct snd_soc_dapm_route tegra210_dmic_routes[] = {
+	{ "TX",		NULL,	"Capture" },
+	{ "XBAR-RX",	NULL,	"TX" },
+};
+
+static const char * const tegra210_dmic_ch_select[] = {
+	"Left", "Right", "Stereo",
+};
+
+static const struct soc_enum tegra210_dmic_ch_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_ch_select),
+			tegra210_dmic_ch_select);
+
+static const char * const tegra210_dmic_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+static const char * const tegra210_dmic_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const struct soc_enum tegra210_dmic_mono_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_mono_conv_text),
+			tegra210_dmic_mono_conv_text);
+
+static const struct soc_enum tegra210_dmic_stereo_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_stereo_conv_text),
+			tegra210_dmic_stereo_conv_text);
+
+static const char * const tegra210_dmic_osr_text[] = {
+	"OSR_64", "OSR_128", "OSR_256",
+};
+
+static const struct soc_enum tegra210_dmic_osr_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_osr_text),
+			tegra210_dmic_osr_text);
+
+static const char * const tegra210_dmic_lrsel_text[] = {
+	"Left", "Right",
+};
+
+static const struct soc_enum tegra210_dmic_lrsel_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_lrsel_text),
+			tegra210_dmic_lrsel_text);
+
+static const struct snd_kcontrol_new tegra210_dmic_controls[] = {
+	SOC_SINGLE_EXT("Boost Gain Volume", 0, 0, MAX_BOOST_GAIN, 0,
+		       tegra210_dmic_get_control, tegra210_dmic_put_control),
+	SOC_ENUM_EXT("Channel Select", tegra210_dmic_ch_enum,
+		     tegra210_dmic_get_control, tegra210_dmic_put_control),
+	SOC_ENUM_EXT("Mono To Stereo",
+		     tegra210_dmic_mono_conv_enum, tegra210_dmic_get_control,
+		     tegra210_dmic_put_control),
+	SOC_ENUM_EXT("Stereo To Mono",
+		     tegra210_dmic_stereo_conv_enum, tegra210_dmic_get_control,
+		     tegra210_dmic_put_control),
+	SOC_ENUM_EXT("OSR Value", tegra210_dmic_osr_enum,
+		     tegra210_dmic_get_control, tegra210_dmic_put_control),
+	SOC_ENUM_EXT("LR Polarity Select", tegra210_dmic_lrsel_enum,
+		     tegra210_dmic_get_control, tegra210_dmic_put_control),
+};
+
+static const struct snd_soc_component_driver tegra210_dmic_compnt = {
+	.dapm_widgets		= tegra210_dmic_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tegra210_dmic_widgets),
+	.dapm_routes		= tegra210_dmic_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tegra210_dmic_routes),
+	.controls		= tegra210_dmic_controls,
+	.num_controls		= ARRAY_SIZE(tegra210_dmic_controls),
+};
+
+static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_DMIC_TX_INT_MASK ... TEGRA210_DMIC_TX_CIF_CTRL:
+	case TEGRA210_DMIC_ENABLE ... TEGRA210_DMIC_CG:
+	case TEGRA210_DMIC_CTRL:
+	case TEGRA210_DMIC_DBG_CTRL:
+	case TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4 ... TEGRA210_DMIC_LP_BIQUAD_1_COEF_4:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_dmic_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_DMIC_TX_STATUS:
+	case TEGRA210_DMIC_TX_INT_STATUS:
+	case TEGRA210_DMIC_STATUS:
+	case TEGRA210_DMIC_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_DMIC_TX_STATUS:
+	case TEGRA210_DMIC_TX_INT_STATUS:
+	case TEGRA210_DMIC_TX_INT_SET:
+	case TEGRA210_DMIC_SOFT_RESET:
+	case TEGRA210_DMIC_STATUS:
+	case TEGRA210_DMIC_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra210_dmic_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = TEGRA210_DMIC_LP_BIQUAD_1_COEF_4,
+	.writeable_reg = tegra210_dmic_wr_reg,
+	.readable_reg = tegra210_dmic_rd_reg,
+	.volatile_reg = tegra210_dmic_volatile_reg,
+	.reg_defaults = tegra210_dmic_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tegra210_dmic_reg_defaults),
+	.cache_type = REGCACHE_FLAT,
+};
+
+static int tegra210_dmic_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_dmic *dmic;
+	void __iomem *regs;
+	int err;
+
+	dmic = devm_kzalloc(dev, sizeof(*dmic), GFP_KERNEL);
+	if (!dmic)
+		return -ENOMEM;
+
+	dmic->osr_val = DMIC_OSR_64;
+	dmic->ch_select = DMIC_CH_SELECT_STEREO;
+	dmic->lrsel = DMIC_LRSEL_LEFT;
+	dmic->boost_gain = 0;
+	dmic->stereo_to_mono = 0; /* "CH0" */
+
+	dev_set_drvdata(dev, dmic);
+
+	dmic->clk_dmic = devm_clk_get(dev, "dmic");
+	if (IS_ERR(dmic->clk_dmic)) {
+		dev_err(dev, "can't retrieve DMIC clock\n");
+		return PTR_ERR(dmic->clk_dmic);
+	}
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	dmic->regmap = devm_regmap_init_mmio(dev, regs,
+					     &tegra210_dmic_regmap_config);
+	if (IS_ERR(dmic->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(dmic->regmap);
+	}
+
+	regcache_cache_only(dmic->regmap, true);
+
+	err = devm_snd_soc_register_component(dev, &tegra210_dmic_compnt,
+					      tegra210_dmic_dais,
+					      ARRAY_SIZE(tegra210_dmic_dais));
+	if (err) {
+		dev_err(dev, "can't register DMIC component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra210_dmic_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra210_dmic_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend,
+			   tegra210_dmic_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_dmic_of_match[] = {
+	{ .compatible = "nvidia,tegra210-dmic" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra210_dmic_of_match);
+
+static struct platform_driver tegra210_dmic_driver = {
+	.driver = {
+		.name = "tegra210-dmic",
+		.of_match_table = tegra210_dmic_of_match,
+		.pm = &tegra210_dmic_pm_ops,
+	},
+	.probe = tegra210_dmic_probe,
+	.remove = tegra210_dmic_remove,
+};
+module_platform_driver(tegra210_dmic_driver)
+
+MODULE_AUTHOR("Rahul Mittal <rmittal@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 ASoC DMIC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_dmic.h b/sound/soc/tegra/tegra210_dmic.h
new file mode 100644
index 0000000..6418c22
--- /dev/null
+++ b/sound/soc/tegra/tegra210_dmic.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_dmic.h - Definitions for Tegra210 DMIC driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_DMIC_H__
+#define __TEGRA210_DMIC_H__
+
+/* Register offsets from DMIC BASE */
+#define TEGRA210_DMIC_TX_STATUS				0x0c
+#define TEGRA210_DMIC_TX_INT_STATUS			0x10
+#define TEGRA210_DMIC_TX_INT_MASK			0x14
+#define TEGRA210_DMIC_TX_INT_SET			0x18
+#define TEGRA210_DMIC_TX_INT_CLEAR			0x1c
+#define TEGRA210_DMIC_TX_CIF_CTRL			0x20
+#define TEGRA210_DMIC_ENABLE				0x40
+#define TEGRA210_DMIC_SOFT_RESET			0x44
+#define TEGRA210_DMIC_CG				0x48
+#define TEGRA210_DMIC_STATUS				0x4c
+#define TEGRA210_DMIC_INT_STATUS			0x50
+#define TEGRA210_DMIC_CTRL				0x64
+#define TEGRA210_DMIC_DBG_CTRL				0x70
+#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4		0x88
+#define TEGRA210_DMIC_LP_FILTER_GAIN			0x8c
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_0		0x90
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_1		0x94
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_2		0x98
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_3		0x9c
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_4		0xa0
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_0		0xa4
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_1		0xa8
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_2		0xac
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_3		0xb0
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_4		0xb4
+
+/* Fields in TEGRA210_DMIC_CTRL */
+#define CH_SEL_SHIFT					8
+#define TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK		(0x3 << CH_SEL_SHIFT)
+#define LRSEL_POL_SHIFT					4
+#define TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK		(0x1 << LRSEL_POL_SHIFT)
+#define OSR_SHIFT					0
+#define TEGRA210_DMIC_CTRL_OSR_MASK			(0x3 << OSR_SHIFT)
+
+#define DMIC_OSR_FACTOR					64
+
+#define DEFAULT_GAIN_Q23				0x800000
+
+/* Max boost gain factor used for mixer control */
+#define MAX_BOOST_GAIN 25599
+
+enum tegra_dmic_ch_select {
+	DMIC_CH_SELECT_LEFT,
+	DMIC_CH_SELECT_RIGHT,
+	DMIC_CH_SELECT_STEREO,
+};
+
+enum tegra_dmic_osr {
+	DMIC_OSR_64,
+	DMIC_OSR_128,
+	DMIC_OSR_256,
+};
+
+enum tegra_dmic_lrsel {
+	DMIC_LRSEL_LEFT,
+	DMIC_LRSEL_RIGHT,
+};
+
+struct tegra210_dmic {
+	struct clk *clk_dmic;
+	struct regmap *regmap;
+	unsigned int mono_to_stereo;
+	unsigned int stereo_to_mono;
+	unsigned int boost_gain;
+	unsigned int ch_select;
+	unsigned int osr_val;
+	unsigned int lrsel;
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 03/23] ASoC: tegra: Add Tegra210 based DMIC driver
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

The Digital MIC (DMIC) Controller is used to interface with Pulse Density
Modulation (PDM) input devices. The DMIC controller implements a converter
to convert PDM signals to Pulse Code Modulation (PCM) signals. From signal
flow perspective, the DMIC can be viewed as a PDM receiver.

This patch registers DMIC component with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes DMIC interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The DMIC devices can be enabled in the DT via
"nvidia,tegra210-dmic" compatible string. This driver can be used for
Tegra186 and Tegra194 chips as well.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig         |  11 +
 sound/soc/tegra/Makefile        |   2 +
 sound/soc/tegra/tegra210_dmic.c | 440 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_dmic.h |  82 ++++++++
 4 files changed, 535 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_dmic.c
 create mode 100644 sound/soc/tegra/tegra210_dmic.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index addadc8..2bde1e6 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -62,6 +62,17 @@ config SND_SOC_TEGRA30_I2S
 	  Tegra30 I2S interface. You will also need to select the individual
 	  machine drivers to support below.
 
+config SND_SOC_TEGRA210_DMIC
+        tristate "Tegra210 DMIC module"
+        depends on SND_SOC_TEGRA
+        help
+          Config to enable the Digital MIC (DMIC) controller which is used
+          to interface with Pulse Density Modulation (PDM) input devices.
+          The DMIC controller implements a converter to convert PDM signals
+          to Pulse Code Modulation (PCM) signals. This can be viewed as a
+          PDM receiver.
+          Say Y or M if you want to add support for Tegra210 DMIC module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index c84f183..f0690cf 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -8,6 +8,7 @@ snd-soc-tegra20-i2s-objs := tegra20_i2s.o
 snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 snd-soc-tegra30-ahub-objs := tegra30_ahub.o
 snd-soc-tegra30-i2s-objs := tegra30_i2s.o
+snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
new file mode 100644
index 0000000..15761cb
--- /dev/null
+++ b/sound/soc/tegra/tegra210_dmic.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_dmic.c - Tegra210 DMIC driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra210_dmic.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_dmic_reg_defaults[] = {
+	{ TEGRA210_DMIC_TX_INT_MASK, 0x00000001 },
+	{ TEGRA210_DMIC_TX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_DMIC_CG, 0x1 },
+	{ TEGRA210_DMIC_CTRL, 0x00000301 },
+	/* Below enables all filters - DCR, LP and SC */
+	{ TEGRA210_DMIC_DBG_CTRL, 0xe },
+	/* Below as per latest POR value */
+	{ TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, 0x0 },
+	/* LP filter is configured for pass through and used to apply gain */
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, 0x00800000 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, 0x00800000 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, 0x0 },
+	{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x0 },
+};
+
+static int tegra210_dmic_runtime_suspend(struct device *dev)
+{
+	struct tegra210_dmic *dmic = dev_get_drvdata(dev);
+
+	regcache_cache_only(dmic->regmap, true);
+	regcache_mark_dirty(dmic->regmap);
+
+	clk_disable_unprepare(dmic->clk_dmic);
+
+	return 0;
+}
+
+static int tegra210_dmic_runtime_resume(struct device *dev)
+{
+	struct tegra210_dmic *dmic = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(dmic->clk_dmic);
+	if (err) {
+		dev_err(dev, "failed to enable DMIC clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(dmic->regmap, false);
+	regcache_sync(dmic->regmap);
+
+	return 0;
+}
+
+static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct tegra210_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+	unsigned int srate, clk_rate, channels;
+	struct tegra_cif_conf cif_conf;
+	unsigned long long gain_q23 = DEFAULT_GAIN_Q23;
+	int err;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+
+	cif_conf.audio_ch = channels;
+
+	switch (dmic->ch_select) {
+	case DMIC_CH_SELECT_LEFT:
+	case DMIC_CH_SELECT_RIGHT:
+		cif_conf.client_ch = 1;
+		break;
+	case DMIC_CH_SELECT_STEREO:
+		cif_conf.client_ch = 2;
+		break;
+	default:
+		dev_err(dai->dev, "invalid DMIC client channels\n");
+		return -EINVAL;
+	}
+
+	srate = params_rate(params);
+
+	/*
+	 * DMIC clock rate is a multiple of 'Over Sampling Ratio' and
+	 * 'Sample Rate'. The supported OSR values are 64, 128 and 256.
+	 */
+	clk_rate = (DMIC_OSR_FACTOR << dmic->osr_val) * srate;
+
+	err = clk_set_rate(dmic->clk_dmic, clk_rate);
+	if (err) {
+		dev_err(dai->dev, "can't set DMIC clock rate %u, err: %d\n",
+			clk_rate, err);
+		return err;
+	}
+
+	regmap_update_bits(dmic->regmap,
+			   /* Reg */
+			   TEGRA210_DMIC_CTRL,
+			   /* Mask */
+			   TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK |
+			   TEGRA210_DMIC_CTRL_OSR_MASK |
+			   TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK,
+			   /* Value */
+			   (dmic->lrsel << LRSEL_POL_SHIFT) |
+			   (dmic->osr_val << OSR_SHIFT) |
+			   ((dmic->ch_select + 1) << CH_SEL_SHIFT));
+
+	/*
+	 * Use LP filter gain register to apply boost.
+	 * Boost Gain Volume control has 100x factor.
+	 */
+	if (dmic->boost_gain)
+		gain_q23 = (gain_q23 * dmic->boost_gain) / 100;
+
+	regmap_write(dmic->regmap, TEGRA210_DMIC_LP_FILTER_GAIN,
+		     (unsigned int)gain_q23);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dai->dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	cif_conf.client_bits = TEGRA_ACIF_BITS_24;
+	cif_conf.mono_conv = dmic->mono_to_stereo;
+	cif_conf.stereo_conv = dmic->stereo_to_mono;
+
+	tegra_set_cif(dmic->regmap, TEGRA210_DMIC_TX_CIF_CTRL, &cif_conf);
+
+	return 0;
+}
+
+static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+
+	if (strstr(kcontrol->id.name, "Boost Gain Volume"))
+		ucontrol->value.integer.value[0] = dmic->boost_gain;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		ucontrol->value.integer.value[0] = dmic->ch_select;
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		ucontrol->value.integer.value[0] = dmic->mono_to_stereo;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		ucontrol->value.integer.value[0] = dmic->stereo_to_mono;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		ucontrol->value.integer.value[0] = dmic->osr_val;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		ucontrol->value.integer.value[0] = dmic->lrsel;
+
+	return 0;
+}
+
+static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+	int value = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Boost Gain Volume"))
+		dmic->boost_gain = value;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		dmic->ch_select = ucontrol->value.integer.value[0];
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		dmic->mono_to_stereo = value;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		dmic->stereo_to_mono = value;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		dmic->osr_val = value;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		dmic->lrsel = value;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra210_dmic_dai_ops = {
+	.hw_params	= tegra210_dmic_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
+	{
+		.name = "DMIC",
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &tegra210_dmic_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const struct snd_soc_dapm_widget tegra210_dmic_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_DMIC_ENABLE, 0, 0),
+};
+
+static const struct snd_soc_dapm_route tegra210_dmic_routes[] = {
+	{ "TX",		NULL,	"Capture" },
+	{ "XBAR-RX",	NULL,	"TX" },
+};
+
+static const char * const tegra210_dmic_ch_select[] = {
+	"Left", "Right", "Stereo",
+};
+
+static const struct soc_enum tegra210_dmic_ch_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_ch_select),
+			tegra210_dmic_ch_select);
+
+static const char * const tegra210_dmic_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+static const char * const tegra210_dmic_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const struct soc_enum tegra210_dmic_mono_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_mono_conv_text),
+			tegra210_dmic_mono_conv_text);
+
+static const struct soc_enum tegra210_dmic_stereo_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_stereo_conv_text),
+			tegra210_dmic_stereo_conv_text);
+
+static const char * const tegra210_dmic_osr_text[] = {
+	"OSR_64", "OSR_128", "OSR_256",
+};
+
+static const struct soc_enum tegra210_dmic_osr_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_osr_text),
+			tegra210_dmic_osr_text);
+
+static const char * const tegra210_dmic_lrsel_text[] = {
+	"Left", "Right",
+};
+
+static const struct soc_enum tegra210_dmic_lrsel_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_lrsel_text),
+			tegra210_dmic_lrsel_text);
+
+static const struct snd_kcontrol_new tegra210_dmic_controls[] = {
+	SOC_SINGLE_EXT("Boost Gain Volume", 0, 0, MAX_BOOST_GAIN, 0,
+		       tegra210_dmic_get_control, tegra210_dmic_put_control),
+	SOC_ENUM_EXT("Channel Select", tegra210_dmic_ch_enum,
+		     tegra210_dmic_get_control, tegra210_dmic_put_control),
+	SOC_ENUM_EXT("Mono To Stereo",
+		     tegra210_dmic_mono_conv_enum, tegra210_dmic_get_control,
+		     tegra210_dmic_put_control),
+	SOC_ENUM_EXT("Stereo To Mono",
+		     tegra210_dmic_stereo_conv_enum, tegra210_dmic_get_control,
+		     tegra210_dmic_put_control),
+	SOC_ENUM_EXT("OSR Value", tegra210_dmic_osr_enum,
+		     tegra210_dmic_get_control, tegra210_dmic_put_control),
+	SOC_ENUM_EXT("LR Polarity Select", tegra210_dmic_lrsel_enum,
+		     tegra210_dmic_get_control, tegra210_dmic_put_control),
+};
+
+static const struct snd_soc_component_driver tegra210_dmic_compnt = {
+	.dapm_widgets		= tegra210_dmic_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tegra210_dmic_widgets),
+	.dapm_routes		= tegra210_dmic_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tegra210_dmic_routes),
+	.controls		= tegra210_dmic_controls,
+	.num_controls		= ARRAY_SIZE(tegra210_dmic_controls),
+};
+
+static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_DMIC_TX_INT_MASK ... TEGRA210_DMIC_TX_CIF_CTRL:
+	case TEGRA210_DMIC_ENABLE ... TEGRA210_DMIC_CG:
+	case TEGRA210_DMIC_CTRL:
+	case TEGRA210_DMIC_DBG_CTRL:
+	case TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4 ... TEGRA210_DMIC_LP_BIQUAD_1_COEF_4:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_dmic_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_DMIC_TX_STATUS:
+	case TEGRA210_DMIC_TX_INT_STATUS:
+	case TEGRA210_DMIC_STATUS:
+	case TEGRA210_DMIC_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_DMIC_TX_STATUS:
+	case TEGRA210_DMIC_TX_INT_STATUS:
+	case TEGRA210_DMIC_TX_INT_SET:
+	case TEGRA210_DMIC_SOFT_RESET:
+	case TEGRA210_DMIC_STATUS:
+	case TEGRA210_DMIC_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra210_dmic_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = TEGRA210_DMIC_LP_BIQUAD_1_COEF_4,
+	.writeable_reg = tegra210_dmic_wr_reg,
+	.readable_reg = tegra210_dmic_rd_reg,
+	.volatile_reg = tegra210_dmic_volatile_reg,
+	.reg_defaults = tegra210_dmic_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tegra210_dmic_reg_defaults),
+	.cache_type = REGCACHE_FLAT,
+};
+
+static int tegra210_dmic_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_dmic *dmic;
+	void __iomem *regs;
+	int err;
+
+	dmic = devm_kzalloc(dev, sizeof(*dmic), GFP_KERNEL);
+	if (!dmic)
+		return -ENOMEM;
+
+	dmic->osr_val = DMIC_OSR_64;
+	dmic->ch_select = DMIC_CH_SELECT_STEREO;
+	dmic->lrsel = DMIC_LRSEL_LEFT;
+	dmic->boost_gain = 0;
+	dmic->stereo_to_mono = 0; /* "CH0" */
+
+	dev_set_drvdata(dev, dmic);
+
+	dmic->clk_dmic = devm_clk_get(dev, "dmic");
+	if (IS_ERR(dmic->clk_dmic)) {
+		dev_err(dev, "can't retrieve DMIC clock\n");
+		return PTR_ERR(dmic->clk_dmic);
+	}
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	dmic->regmap = devm_regmap_init_mmio(dev, regs,
+					     &tegra210_dmic_regmap_config);
+	if (IS_ERR(dmic->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(dmic->regmap);
+	}
+
+	regcache_cache_only(dmic->regmap, true);
+
+	err = devm_snd_soc_register_component(dev, &tegra210_dmic_compnt,
+					      tegra210_dmic_dais,
+					      ARRAY_SIZE(tegra210_dmic_dais));
+	if (err) {
+		dev_err(dev, "can't register DMIC component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra210_dmic_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra210_dmic_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend,
+			   tegra210_dmic_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_dmic_of_match[] = {
+	{ .compatible = "nvidia,tegra210-dmic" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra210_dmic_of_match);
+
+static struct platform_driver tegra210_dmic_driver = {
+	.driver = {
+		.name = "tegra210-dmic",
+		.of_match_table = tegra210_dmic_of_match,
+		.pm = &tegra210_dmic_pm_ops,
+	},
+	.probe = tegra210_dmic_probe,
+	.remove = tegra210_dmic_remove,
+};
+module_platform_driver(tegra210_dmic_driver)
+
+MODULE_AUTHOR("Rahul Mittal <rmittal@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 ASoC DMIC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_dmic.h b/sound/soc/tegra/tegra210_dmic.h
new file mode 100644
index 0000000..6418c22
--- /dev/null
+++ b/sound/soc/tegra/tegra210_dmic.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_dmic.h - Definitions for Tegra210 DMIC driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_DMIC_H__
+#define __TEGRA210_DMIC_H__
+
+/* Register offsets from DMIC BASE */
+#define TEGRA210_DMIC_TX_STATUS				0x0c
+#define TEGRA210_DMIC_TX_INT_STATUS			0x10
+#define TEGRA210_DMIC_TX_INT_MASK			0x14
+#define TEGRA210_DMIC_TX_INT_SET			0x18
+#define TEGRA210_DMIC_TX_INT_CLEAR			0x1c
+#define TEGRA210_DMIC_TX_CIF_CTRL			0x20
+#define TEGRA210_DMIC_ENABLE				0x40
+#define TEGRA210_DMIC_SOFT_RESET			0x44
+#define TEGRA210_DMIC_CG				0x48
+#define TEGRA210_DMIC_STATUS				0x4c
+#define TEGRA210_DMIC_INT_STATUS			0x50
+#define TEGRA210_DMIC_CTRL				0x64
+#define TEGRA210_DMIC_DBG_CTRL				0x70
+#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4		0x88
+#define TEGRA210_DMIC_LP_FILTER_GAIN			0x8c
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_0		0x90
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_1		0x94
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_2		0x98
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_3		0x9c
+#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_4		0xa0
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_0		0xa4
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_1		0xa8
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_2		0xac
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_3		0xb0
+#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_4		0xb4
+
+/* Fields in TEGRA210_DMIC_CTRL */
+#define CH_SEL_SHIFT					8
+#define TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK		(0x3 << CH_SEL_SHIFT)
+#define LRSEL_POL_SHIFT					4
+#define TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK		(0x1 << LRSEL_POL_SHIFT)
+#define OSR_SHIFT					0
+#define TEGRA210_DMIC_CTRL_OSR_MASK			(0x3 << OSR_SHIFT)
+
+#define DMIC_OSR_FACTOR					64
+
+#define DEFAULT_GAIN_Q23				0x800000
+
+/* Max boost gain factor used for mixer control */
+#define MAX_BOOST_GAIN 25599
+
+enum tegra_dmic_ch_select {
+	DMIC_CH_SELECT_LEFT,
+	DMIC_CH_SELECT_RIGHT,
+	DMIC_CH_SELECT_STEREO,
+};
+
+enum tegra_dmic_osr {
+	DMIC_OSR_64,
+	DMIC_OSR_128,
+	DMIC_OSR_256,
+};
+
+enum tegra_dmic_lrsel {
+	DMIC_LRSEL_LEFT,
+	DMIC_LRSEL_RIGHT,
+};
+
+struct tegra210_dmic {
+	struct clk *clk_dmic;
+	struct regmap *regmap;
+	unsigned int mono_to_stereo;
+	unsigned int stereo_to_mono;
+	unsigned int boost_gain;
+	unsigned int ch_select;
+	unsigned int osr_val;
+	unsigned int lrsel;
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 04/23] ASoC: tegra: Add Tegra210 based I2S driver
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

The Inter-IC Sound (I2S) controller implements full-duplex, bi-directional
and single direction point to point serial interface. It can interface
with I2S compatible devices. Tegra I2S controller can operate as both
master and slave.

This patch registers I2S controller with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes I2S interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The I2S devices can be enabled in the DT via
"nvidia,tegra210-i2s" compatible binding.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/tegra/Kconfig        |  10 +
 sound/soc/tegra/Makefile       |   2 +
 sound/soc/tegra/tegra210_i2s.c | 780 +++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_i2s.h | 126 +++++++
 4 files changed, 918 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_i2s.c
 create mode 100644 sound/soc/tegra/tegra210_i2s.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 2bde1e6..157fa7a 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -73,6 +73,16 @@ config SND_SOC_TEGRA210_DMIC
           PDM receiver.
           Say Y or M if you want to add support for Tegra210 DMIC module.
 
+config SND_SOC_TEGRA210_I2S
+        tristate "Tegra210 I2S module"
+        depends on SND_SOC_TEGRA
+        help
+          Config to enable the Inter-IC Sound (I2S) Controller which
+          implements full-duplex and bidirectional and single direction
+          point-to-point serial interfaces. It can interface with I2S
+          compatible devices.
+          Say Y or M if you want to add support for Tegra210 I2S module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index f0690cf..e30f6a3 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -9,6 +9,7 @@ snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 snd-soc-tegra30-ahub-objs := tegra30_ahub.o
 snd-soc-tegra30-i2s-objs := tegra30_i2s.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
+snd-soc-tegra210-i2s-objs := tegra210_i2s.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
+obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
new file mode 100644
index 0000000..a48124c
--- /dev/null
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -0,0 +1,780 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_i2s.c - Tegra210 I2S driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra210_i2s.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_i2s_reg_defaults[] = {
+	{ TEGRA210_I2S_RX_INT_MASK, 0x00000003 },
+	{ TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_I2S_TX_INT_MASK, 0x00000003 },
+	{ TEGRA210_I2S_TX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_I2S_CG, 0x1 },
+	{ TEGRA210_I2S_TIMING, 0x0000001f },
+	{ TEGRA210_I2S_ENABLE, 0x1 },
+	/*
+	 * Below update does not have any effect on Tegra186 and Tegra194.
+	 * On Tegra210, I2S4 has "i2s4a" and "i2s4b" pins and below update
+	 * is required to select i2s4b for it to be functional for I2S
+	 * operation.
+	 */
+	{ TEGRA210_I2S_CYA, 0x1 },
+};
+
+static void tegra210_i2s_set_slot_ctrl(struct regmap *regmap,
+				       unsigned int total_slots,
+				       unsigned int tx_slot_mask,
+				       unsigned int rx_slot_mask)
+{
+	regmap_write(regmap, TEGRA210_I2S_SLOT_CTRL, total_slots - 1);
+	regmap_write(regmap, TEGRA210_I2S_TX_SLOT_CTRL, tx_slot_mask);
+	regmap_write(regmap, TEGRA210_I2S_RX_SLOT_CTRL, rx_slot_mask);
+}
+
+static int tegra210_i2s_set_clock_rate(struct device *dev,
+				       unsigned int clock_rate)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int val;
+	int err;
+
+	regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
+
+	/* No need to set rates if I2S is being operated in slave */
+	if (!(val & I2S_CTRL_MASTER_EN))
+		return 0;
+
+	err = clk_set_rate(i2s->clk_i2s, clock_rate);
+	if (err) {
+		dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
+			clock_rate, err);
+		return err;
+	}
+
+	if (!IS_ERR(i2s->clk_sync_input)) {
+		/*
+		 * Other I/O modules in AHUB can use i2s bclk as reference
+		 * clock. Below sets sync input clock rate as per bclk,
+		 * which can be used as input to other I/O modules.
+		 */
+		err = clk_set_rate(i2s->clk_sync_input, clock_rate);
+		if (err) {
+			dev_err(dev,
+				"can't set I2S sync input rate %u, err = %d\n",
+				clock_rate, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt,
+				 bool is_playback)
+{
+	struct device *dev = compnt->dev;
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int reset_mask = I2S_SOFT_RESET_MASK;
+	unsigned int reset_en = I2S_SOFT_RESET_EN;
+	unsigned int reset_reg, cif_reg, stream_reg;
+	unsigned int cif_ctrl, stream_ctrl, i2s_ctrl, val;
+	int err;
+
+	if (is_playback) {
+		reset_reg = TEGRA210_I2S_RX_SOFT_RESET;
+		cif_reg = TEGRA210_I2S_RX_CIF_CTRL;
+		stream_reg = TEGRA210_I2S_RX_CTRL;
+	} else {
+		reset_reg = TEGRA210_I2S_TX_SOFT_RESET;
+		cif_reg = TEGRA210_I2S_TX_CIF_CTRL;
+		stream_reg = TEGRA210_I2S_TX_CTRL;
+	}
+
+	/* Store CIF and I2S control values */
+	regmap_read(i2s->regmap, cif_reg, &cif_ctrl);
+	regmap_read(i2s->regmap, stream_reg, &stream_ctrl);
+	regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &i2s_ctrl);
+
+	/* Reset to make sure the previous transactions are clean */
+	regmap_update_bits(i2s->regmap, reset_reg, reset_mask, reset_en);
+
+	err = regmap_read_poll_timeout(i2s->regmap, reset_reg, val,
+				       !(val & reset_mask & reset_en),
+				       10, 10000);
+	if (err) {
+		dev_err(dev, "timeout: failed to reset I2S for %s\n",
+			is_playback ? "playback" : "capture");
+		return err;
+	}
+
+	/* Restore CIF and I2S control values */
+	regmap_write(i2s->regmap, cif_reg, cif_ctrl);
+	regmap_write(i2s->regmap, stream_reg, stream_ctrl);
+	regmap_write(i2s->regmap, TEGRA210_I2S_CTRL, i2s_ctrl);
+
+	return 0;
+}
+
+static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *compnt = snd_soc_dapm_to_component(w->dapm);
+	struct device *dev = compnt->dev;
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int val, status_reg;
+	bool is_playback;
+	int err;
+
+	switch (w->reg) {
+	case TEGRA210_I2S_RX_ENABLE:
+		is_playback = true;
+		status_reg = TEGRA210_I2S_RX_STATUS;
+		break;
+	case TEGRA210_I2S_TX_ENABLE:
+		is_playback = false;
+		status_reg = TEGRA210_I2S_TX_STATUS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Ensure I2S is in disabled state before new session */
+	err = regmap_read_poll_timeout(i2s->regmap, status_reg, val,
+				       !(val & I2S_EN_MASK & I2S_EN),
+				       10, 10000);
+	if (err) {
+		dev_err(dev, "timeout: previous I2S %s is still active\n",
+			is_playback ? "playback" : "capture");
+		return err;
+	}
+
+	return tegra210_i2s_sw_reset(compnt, is_playback);
+}
+
+static int tegra210_i2s_runtime_suspend(struct device *dev)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+
+	regcache_cache_only(i2s->regmap, true);
+	regcache_mark_dirty(i2s->regmap);
+
+	clk_disable_unprepare(i2s->clk_i2s);
+
+	return 0;
+}
+
+static int tegra210_i2s_runtime_resume(struct device *dev)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(i2s->clk_i2s);
+	if (err) {
+		dev_err(dev, "failed to enable I2S bit clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(i2s->regmap, false);
+	regcache_sync(i2s->regmap);
+
+	return 0;
+}
+
+static void tegra210_i2s_set_data_offset(struct tegra210_i2s *i2s,
+					 unsigned int data_offset)
+{
+	/* Capture path */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_TX_CTRL,
+			   I2S_CTRL_DATA_OFFSET_MASK,
+			   data_offset << I2S_DATA_SHIFT);
+
+	/* Playback path */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_RX_CTRL,
+			   I2S_CTRL_DATA_OFFSET_MASK,
+			   data_offset << I2S_DATA_SHIFT);
+}
+
+static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
+				unsigned int fmt)
+{
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int mask, val;
+
+	mask = I2S_CTRL_MASTER_EN_MASK;
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		val = 0;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		val = I2S_CTRL_MASTER_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask |= I2S_CTRL_FRAME_FMT_MASK | I2S_CTRL_LRCK_POL_MASK;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		tegra210_i2s_set_data_offset(i2s, 1);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		tegra210_i2s_set_data_offset(i2s, 0);
+		break;
+	/* I2S mode has data offset of 1 */
+	case SND_SOC_DAIFMT_I2S:
+		val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+		val |= I2S_CTRL_LRCK_POL_LOW;
+		tegra210_i2s_set_data_offset(i2s, 1);
+		break;
+	/*
+	 * For RJ mode data offset is dependent on the sample size
+	 * and the bclk ratio, and so is set when hw_params is called.
+	 */
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		tegra210_i2s_set_data_offset(i2s, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask |= I2S_CTRL_EDGE_CTRL_MASK;
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
+		val ^= I2S_CTRL_LRCK_POL_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
+		val ^= I2S_CTRL_LRCK_POL_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, mask, val);
+
+	i2s->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	return 0;
+}
+
+static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai,
+				     unsigned int tx_mask, unsigned int rx_mask,
+				     int slots, int slot_width)
+{
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	/* Copy the required tx and rx mask */
+	i2s->tx_mask = (tx_mask > DEFAULT_I2S_SLOT_MASK) ?
+		       DEFAULT_I2S_SLOT_MASK : tx_mask;
+	i2s->rx_mask = (rx_mask > DEFAULT_I2S_SLOT_MASK) ?
+		       DEFAULT_I2S_SLOT_MASK : rx_mask;
+
+	return 0;
+}
+
+static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+					   unsigned int ratio)
+{
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	i2s->bclk_ratio = ratio;
+
+	return 0;
+}
+
+static int tegra210_i2s_get_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+	long *uctl_val = &ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Loopback"))
+		*uctl_val = i2s->loopback;
+	else if (strstr(kcontrol->id.name, "FSYNC Width"))
+		*uctl_val = i2s->fsync_width;
+	else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+		*uctl_val = i2s->stereo_to_mono[I2S_TX_PATH];
+	else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+		*uctl_val = i2s->mono_to_stereo[I2S_TX_PATH];
+	else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+		*uctl_val = i2s->stereo_to_mono[I2S_RX_PATH];
+	else if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+		*uctl_val = i2s->mono_to_stereo[I2S_RX_PATH];
+	else if (strstr(kcontrol->id.name, "Playback FIFO Threshold"))
+		*uctl_val = i2s->rx_fifo_th;
+	else if (strstr(kcontrol->id.name, "BCLK Ratio"))
+		*uctl_val = i2s->bclk_ratio;
+
+	return 0;
+}
+
+static int tegra210_i2s_put_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+	int value = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Loopback")) {
+		i2s->loopback = value;
+
+		regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+				   I2S_CTRL_LPBK_MASK,
+				   i2s->loopback << I2S_CTRL_LPBK_SHIFT);
+
+	} else if (strstr(kcontrol->id.name, "FSYNC Width")) {
+		/*
+		 * Frame sync width is used only for FSYNC modes and not
+		 * applicable for LRCK modes. Reset value for this field is "0",
+		 * which means the width is one bit clock wide.
+		 * The width requirement may depend on the codec and in such
+		 * cases mixer control is used to update custom values. A value
+		 * of "N" here means, width is "N + 1" bit clock wide.
+		 */
+		i2s->fsync_width = value;
+
+		regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+				   I2S_CTRL_FSYNC_WIDTH_MASK,
+				   i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
+
+	} else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) {
+		i2s->stereo_to_mono[I2S_TX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) {
+		i2s->mono_to_stereo[I2S_TX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) {
+		i2s->stereo_to_mono[I2S_RX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) {
+		i2s->mono_to_stereo[I2S_RX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) {
+		i2s->rx_fifo_th = value;
+	} else if (strstr(kcontrol->id.name, "BCLK Ratio")) {
+		i2s->bclk_ratio = value;
+	}
+
+	return 0;
+}
+
+static int tegra210_i2s_set_timing_params(struct device *dev,
+					  unsigned int sample_size,
+					  unsigned int srate,
+					  unsigned int channels)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int val, bit_count, bclk_rate, num_bclk = sample_size;
+	int err;
+
+	if (i2s->bclk_ratio)
+		num_bclk *= i2s->bclk_ratio;
+
+	if (i2s->dai_fmt == SND_SOC_DAIFMT_RIGHT_J)
+		tegra210_i2s_set_data_offset(i2s, num_bclk - sample_size);
+
+	/* I2S bit clock rate */
+	bclk_rate = srate * channels * num_bclk;
+
+	err = tegra210_i2s_set_clock_rate(dev, bclk_rate);
+	if (err) {
+		dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
+			bclk_rate, err);
+		return err;
+	}
+
+	regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
+
+	/*
+	 * For LRCK mode, channel bit count depends on number of bit clocks
+	 * on the left channel, where as for FSYNC mode bit count depends on
+	 * the number of bit clocks in both left and right channels for DSP
+	 * mode or the number of bit clocks in one TDM frame.
+	 *
+	 */
+	switch (val & I2S_CTRL_FRAME_FMT_MASK) {
+	case I2S_CTRL_FRAME_FMT_LRCK_MODE:
+		bit_count = (bclk_rate / (srate * 2)) - 1;
+		break;
+	case I2S_CTRL_FRAME_FMT_FSYNC_MODE:
+		bit_count = (bclk_rate / srate) - 1;
+
+		tegra210_i2s_set_slot_ctrl(i2s->regmap, channels,
+					   i2s->tx_mask, i2s->rx_mask);
+		break;
+	default:
+		dev_err(dev, "invalid I2S frame format\n");
+		return -EINVAL;
+	}
+
+	if (bit_count > I2S_TIMING_CH_BIT_CNT_MASK) {
+		dev_err(dev, "invalid I2S channel bit count %u\n", bit_count);
+		return -EINVAL;
+	}
+
+	regmap_write(i2s->regmap, TEGRA210_I2S_TIMING,
+		     bit_count << I2S_TIMING_CH_BIT_CNT_SHIFT);
+
+	return 0;
+}
+
+static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int sample_size, channels, srate, val, reg, path;
+	struct tegra_cif_conf cif_conf;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+	if (channels < 1) {
+		dev_err(dev, "invalid I2S %d channel configuration\n",
+			channels);
+		return -EINVAL;
+	}
+
+	cif_conf.audio_ch = channels;
+	cif_conf.client_ch = channels;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		val = I2S_BITS_8;
+		sample_size = 8;
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		val = I2S_BITS_16;
+		sample_size = 16;
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		val = I2S_BITS_32;
+		sample_size = 32;
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	/* Program sample size */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+			   I2S_CTRL_BIT_SIZE_MASK, val);
+
+	srate = params_rate(params);
+
+	/* For playback I2S RX-CIF and for capture TX-CIF is used */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		path = I2S_RX_PATH;
+	else
+		path = I2S_TX_PATH;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		unsigned int max_th;
+
+		/* FIFO threshold in terms of frames */
+		max_th = (I2S_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
+
+		if (i2s->rx_fifo_th > max_th)
+			i2s->rx_fifo_th = max_th;
+
+		cif_conf.threshold = i2s->rx_fifo_th;
+
+		reg = TEGRA210_I2S_RX_CIF_CTRL;
+	} else {
+		reg = TEGRA210_I2S_TX_CIF_CTRL;
+	}
+
+	cif_conf.mono_conv = i2s->mono_to_stereo[path];
+	cif_conf.stereo_conv = i2s->stereo_to_mono[path];
+
+	tegra_set_cif(i2s->regmap, reg, &cif_conf);
+
+	return tegra210_i2s_set_timing_params(dev, sample_size, srate,
+					      cif_conf.client_ch);
+}
+
+static const struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
+	.set_fmt	= tegra210_i2s_set_fmt,
+	.hw_params	= tegra210_i2s_hw_params,
+	.set_bclk_ratio	= tegra210_i2s_set_dai_bclk_ratio,
+	.set_tdm_slot	= tegra210_i2s_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
+	{
+		.name = "I2S",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &tegra210_i2s_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const char * const tegra210_i2s_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const char * const tegra210_i2s_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+static const struct soc_enum tegra210_i2s_mono_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_mono_conv_text),
+			tegra210_i2s_mono_conv_text);
+
+static const struct soc_enum tegra210_i2s_stereo_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_stereo_conv_text),
+			tegra210_i2s_stereo_conv_text);
+
+static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
+	SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_control,
+		       tegra210_i2s_put_control),
+	SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control,
+		       tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Playback Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Playback Mono To Stereo", tegra210_i2s_mono_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_SINGLE_EXT("Playback FIFO Threshold", 0, 0, I2S_RX_FIFO_DEPTH - 1,
+		       0, tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, tegra210_i2s_get_control,
+		       tegra210_i2s_put_control),
+};
+
+static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
+	SND_SOC_DAPM_AIF_IN_E("RX", NULL, 0, TEGRA210_I2S_RX_ENABLE,
+			      0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_AIF_OUT_E("TX", NULL, 0, TEGRA210_I2S_TX_ENABLE,
+			       0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_route tegra210_i2s_routes[] = {
+	{ "RX",		NULL,	"XBAR-TX" },
+	{ "Playback",	NULL,	"RX" },
+	{ "XBAR-RX",	NULL,	"TX" },
+	{ "TX",		NULL,	"Capture" },
+};
+
+static const struct snd_soc_component_driver tegra210_i2s_cmpnt = {
+	.dapm_widgets = tegra210_i2s_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets),
+	.dapm_routes = tegra210_i2s_routes,
+	.num_dapm_routes = ARRAY_SIZE(tegra210_i2s_routes),
+	.controls = tegra210_i2s_controls,
+	.num_controls = ARRAY_SIZE(tegra210_i2s_controls),
+};
+
+static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_I2S_RX_ENABLE ... TEGRA210_I2S_RX_SOFT_RESET:
+	case TEGRA210_I2S_RX_INT_MASK ... TEGRA210_I2S_RX_CLK_TRIM:
+	case TEGRA210_I2S_TX_ENABLE ... TEGRA210_I2S_TX_SOFT_RESET:
+	case TEGRA210_I2S_TX_INT_MASK ... TEGRA210_I2S_TX_CLK_TRIM:
+	case TEGRA210_I2S_ENABLE ... TEGRA210_I2S_CG:
+	case TEGRA210_I2S_CTRL ... TEGRA210_I2S_CYA:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_i2s_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_I2S_RX_STATUS:
+	case TEGRA210_I2S_RX_INT_STATUS:
+	case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_TX_STATUS:
+	case TEGRA210_I2S_TX_INT_STATUS:
+	case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_STATUS:
+	case TEGRA210_I2S_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_I2S_RX_STATUS:
+	case TEGRA210_I2S_RX_INT_STATUS:
+	case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_TX_STATUS:
+	case TEGRA210_I2S_TX_INT_STATUS:
+	case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_STATUS:
+	case TEGRA210_I2S_INT_STATUS:
+	case TEGRA210_I2S_RX_SOFT_RESET:
+	case TEGRA210_I2S_TX_SOFT_RESET:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra210_i2s_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_I2S_CYA,
+	.writeable_reg		= tegra210_i2s_wr_reg,
+	.readable_reg		= tegra210_i2s_rd_reg,
+	.volatile_reg		= tegra210_i2s_volatile_reg,
+	.reg_defaults		= tegra210_i2s_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_i2s_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static int tegra210_i2s_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_i2s *i2s;
+	void __iomem *regs;
+	int err;
+
+	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
+	if (!i2s)
+		return -ENOMEM;
+
+	i2s->rx_fifo_th = DEFAULT_I2S_RX_FIFO_THRESHOLD;
+	i2s->tx_mask = DEFAULT_I2S_SLOT_MASK;
+	i2s->rx_mask = DEFAULT_I2S_SLOT_MASK;
+	i2s->loopback = false;
+
+	dev_set_drvdata(dev, i2s);
+
+	i2s->clk_i2s = devm_clk_get(dev, "i2s");
+	if (IS_ERR(i2s->clk_i2s)) {
+		dev_err(dev, "can't retrieve I2S bit clock\n");
+		return PTR_ERR(i2s->clk_i2s);
+	}
+
+	/*
+	 * Not an error, as this clock is needed only when some other I/O
+	 * requires input clock from current I2S instance, which is
+	 * configurable from DT.
+	 */
+	i2s->clk_sync_input = devm_clk_get(dev, "sync_input");
+	if (IS_ERR(i2s->clk_sync_input))
+		dev_dbg(dev, "can't retrieve I2S sync input clock\n");
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	i2s->regmap = devm_regmap_init_mmio(dev, regs,
+					    &tegra210_i2s_regmap_config);
+	if (IS_ERR(i2s->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(i2s->regmap);
+	}
+
+	regcache_cache_only(i2s->regmap, true);
+
+	err = devm_snd_soc_register_component(dev, &tegra210_i2s_cmpnt,
+					      tegra210_i2s_dais,
+					      ARRAY_SIZE(tegra210_i2s_dais));
+	if (err) {
+		dev_err(dev, "can't register I2S component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra210_i2s_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra210_i2s_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend,
+			   tegra210_i2s_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_i2s_of_match[] = {
+	{ .compatible = "nvidia,tegra210-i2s" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match);
+
+static struct platform_driver tegra210_i2s_driver = {
+	.driver = {
+		.name = "tegra210-i2s",
+		.of_match_table = tegra210_i2s_of_match,
+		.pm = &tegra210_i2s_pm_ops,
+	},
+	.probe = tegra210_i2s_probe,
+	.remove = tegra210_i2s_remove,
+};
+module_platform_driver(tegra210_i2s_driver)
+
+MODULE_AUTHOR("Songhee Baek <sbaek-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
+MODULE_DESCRIPTION("Tegra210 ASoC I2S driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_i2s.h b/sound/soc/tegra/tegra210_i2s.h
new file mode 100644
index 0000000..030d70c
--- /dev/null
+++ b/sound/soc/tegra/tegra210_i2s.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_i2s.h - Definitions for Tegra210 I2S driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_I2S_H__
+#define __TEGRA210_I2S_H__
+
+/* Register offsets from I2S*_BASE */
+#define TEGRA210_I2S_RX_ENABLE			0x0
+#define TEGRA210_I2S_RX_SOFT_RESET		0x4
+#define TEGRA210_I2S_RX_STATUS			0x0c
+#define TEGRA210_I2S_RX_INT_STATUS		0x10
+#define TEGRA210_I2S_RX_INT_MASK		0x14
+#define TEGRA210_I2S_RX_INT_SET			0x18
+#define TEGRA210_I2S_RX_INT_CLEAR		0x1c
+#define TEGRA210_I2S_RX_CIF_CTRL		0x20
+#define TEGRA210_I2S_RX_CTRL			0x24
+#define TEGRA210_I2S_RX_SLOT_CTRL		0x28
+#define TEGRA210_I2S_RX_CLK_TRIM		0x2c
+#define TEGRA210_I2S_RX_CYA			0x30
+#define TEGRA210_I2S_RX_CIF_FIFO_STATUS		0x34
+#define TEGRA210_I2S_TX_ENABLE			0x40
+#define TEGRA210_I2S_TX_SOFT_RESET		0x44
+#define TEGRA210_I2S_TX_STATUS			0x4c
+#define TEGRA210_I2S_TX_INT_STATUS		0x50
+#define TEGRA210_I2S_TX_INT_MASK		0x54
+#define TEGRA210_I2S_TX_INT_SET			0x58
+#define TEGRA210_I2S_TX_INT_CLEAR		0x5c
+#define TEGRA210_I2S_TX_CIF_CTRL		0x60
+#define TEGRA210_I2S_TX_CTRL			0x64
+#define TEGRA210_I2S_TX_SLOT_CTRL		0x68
+#define TEGRA210_I2S_TX_CLK_TRIM		0x6c
+#define TEGRA210_I2S_TX_CYA			0x70
+#define TEGRA210_I2S_TX_CIF_FIFO_STATUS		0x74
+#define TEGRA210_I2S_ENABLE			0x80
+#define TEGRA210_I2S_SOFT_RESET			0x84
+#define TEGRA210_I2S_CG				0x88
+#define TEGRA210_I2S_STATUS			0x8c
+#define TEGRA210_I2S_INT_STATUS			0x90
+#define TEGRA210_I2S_CTRL			0xa0
+#define TEGRA210_I2S_TIMING			0xa4
+#define TEGRA210_I2S_SLOT_CTRL			0xa8
+#define TEGRA210_I2S_CLK_TRIM			0xac
+#define TEGRA210_I2S_CYA			0xb0
+
+/* Bit fields, shifts and masks */
+#define I2S_DATA_SHIFT				8
+#define I2S_CTRL_DATA_OFFSET_MASK		(0x7ff << I2S_DATA_SHIFT)
+
+#define I2S_EN_SHIFT				0
+#define I2S_EN_MASK				BIT(I2S_EN_SHIFT)
+#define I2S_EN					BIT(I2S_EN_SHIFT)
+
+#define I2S_FSYNC_WIDTH_SHIFT			24
+#define I2S_CTRL_FSYNC_WIDTH_MASK		(0xff << I2S_FSYNC_WIDTH_SHIFT)
+
+#define I2S_POS_EDGE				0
+#define I2S_NEG_EDGE				1
+#define I2S_EDGE_SHIFT				20
+#define I2S_CTRL_EDGE_CTRL_MASK			BIT(I2S_EDGE_SHIFT)
+#define I2S_CTRL_EDGE_CTRL_POS_EDGE		(I2S_POS_EDGE << I2S_EDGE_SHIFT)
+#define I2S_CTRL_EDGE_CTRL_NEG_EDGE		(I2S_NEG_EDGE << I2S_EDGE_SHIFT)
+
+#define I2S_FMT_LRCK				0
+#define I2S_FMT_FSYNC				1
+#define I2S_FMT_SHIFT				12
+#define I2S_CTRL_FRAME_FMT_MASK			(7 << I2S_FMT_SHIFT)
+#define I2S_CTRL_FRAME_FMT_LRCK_MODE		(I2S_FMT_LRCK << I2S_FMT_SHIFT)
+#define I2S_CTRL_FRAME_FMT_FSYNC_MODE		(I2S_FMT_FSYNC << I2S_FMT_SHIFT)
+
+#define I2S_CTRL_MASTER_EN_SHIFT		10
+#define I2S_CTRL_MASTER_EN_MASK			BIT(I2S_CTRL_MASTER_EN_SHIFT)
+#define I2S_CTRL_MASTER_EN			BIT(I2S_CTRL_MASTER_EN_SHIFT)
+
+#define I2S_CTRL_LRCK_POL_SHIFT			9
+#define I2S_CTRL_LRCK_POL_MASK			BIT(I2S_CTRL_LRCK_POL_SHIFT)
+#define I2S_CTRL_LRCK_POL_LOW			(0 << I2S_CTRL_LRCK_POL_SHIFT)
+#define I2S_CTRL_LRCK_POL_HIGH			BIT(I2S_CTRL_LRCK_POL_SHIFT)
+
+#define I2S_CTRL_LPBK_SHIFT			8
+#define I2S_CTRL_LPBK_MASK			BIT(I2S_CTRL_LPBK_SHIFT)
+#define I2S_CTRL_LPBK_EN			BIT(I2S_CTRL_LPBK_SHIFT)
+
+#define I2S_BITS_8				1
+#define I2S_BITS_16				3
+#define I2S_BITS_32				7
+#define I2S_CTRL_BIT_SIZE_MASK			0x7
+
+#define I2S_TIMING_CH_BIT_CNT_MASK		0x7ff
+#define I2S_TIMING_CH_BIT_CNT_SHIFT		0
+
+#define I2S_SOFT_RESET_SHIFT			0
+#define I2S_SOFT_RESET_MASK			BIT(I2S_SOFT_RESET_SHIFT)
+#define I2S_SOFT_RESET_EN			BIT(I2S_SOFT_RESET_SHIFT)
+
+#define I2S_RX_FIFO_DEPTH			64
+#define DEFAULT_I2S_RX_FIFO_THRESHOLD		3
+
+#define DEFAULT_I2S_SLOT_MASK			0xffff
+
+enum tegra210_i2s_path {
+	I2S_RX_PATH,
+	I2S_TX_PATH,
+	I2S_PATHS,
+};
+
+struct tegra210_i2s {
+	struct clk *clk_i2s;
+	struct clk *clk_sync_input;
+	struct regmap *regmap;
+	unsigned int stereo_to_mono[I2S_PATHS];
+	unsigned int mono_to_stereo[I2S_PATHS];
+	unsigned int dai_fmt;
+	unsigned int fsync_width;
+	unsigned int bclk_ratio;
+	unsigned int tx_mask;
+	unsigned int rx_mask;
+	unsigned int rx_fifo_th;
+	bool loopback;
+};
+
+#endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 04/23] ASoC: tegra: Add Tegra210 based I2S driver
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

The Inter-IC Sound (I2S) controller implements full-duplex, bi-directional
and single direction point to point serial interface. It can interface
with I2S compatible devices. Tegra I2S controller can operate as both
master and slave.

This patch registers I2S controller with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes I2S interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The I2S devices can be enabled in the DT via
"nvidia,tegra210-i2s" compatible binding.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig        |  10 +
 sound/soc/tegra/Makefile       |   2 +
 sound/soc/tegra/tegra210_i2s.c | 780 +++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_i2s.h | 126 +++++++
 4 files changed, 918 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_i2s.c
 create mode 100644 sound/soc/tegra/tegra210_i2s.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 2bde1e6..157fa7a 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -73,6 +73,16 @@ config SND_SOC_TEGRA210_DMIC
           PDM receiver.
           Say Y or M if you want to add support for Tegra210 DMIC module.
 
+config SND_SOC_TEGRA210_I2S
+        tristate "Tegra210 I2S module"
+        depends on SND_SOC_TEGRA
+        help
+          Config to enable the Inter-IC Sound (I2S) Controller which
+          implements full-duplex and bidirectional and single direction
+          point-to-point serial interfaces. It can interface with I2S
+          compatible devices.
+          Say Y or M if you want to add support for Tegra210 I2S module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index f0690cf..e30f6a3 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -9,6 +9,7 @@ snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 snd-soc-tegra30-ahub-objs := tegra30_ahub.o
 snd-soc-tegra30-i2s-objs := tegra30_i2s.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
+snd-soc-tegra210-i2s-objs := tegra210_i2s.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
+obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
new file mode 100644
index 0000000..a48124c
--- /dev/null
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -0,0 +1,780 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_i2s.c - Tegra210 I2S driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra210_i2s.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_i2s_reg_defaults[] = {
+	{ TEGRA210_I2S_RX_INT_MASK, 0x00000003 },
+	{ TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_I2S_TX_INT_MASK, 0x00000003 },
+	{ TEGRA210_I2S_TX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_I2S_CG, 0x1 },
+	{ TEGRA210_I2S_TIMING, 0x0000001f },
+	{ TEGRA210_I2S_ENABLE, 0x1 },
+	/*
+	 * Below update does not have any effect on Tegra186 and Tegra194.
+	 * On Tegra210, I2S4 has "i2s4a" and "i2s4b" pins and below update
+	 * is required to select i2s4b for it to be functional for I2S
+	 * operation.
+	 */
+	{ TEGRA210_I2S_CYA, 0x1 },
+};
+
+static void tegra210_i2s_set_slot_ctrl(struct regmap *regmap,
+				       unsigned int total_slots,
+				       unsigned int tx_slot_mask,
+				       unsigned int rx_slot_mask)
+{
+	regmap_write(regmap, TEGRA210_I2S_SLOT_CTRL, total_slots - 1);
+	regmap_write(regmap, TEGRA210_I2S_TX_SLOT_CTRL, tx_slot_mask);
+	regmap_write(regmap, TEGRA210_I2S_RX_SLOT_CTRL, rx_slot_mask);
+}
+
+static int tegra210_i2s_set_clock_rate(struct device *dev,
+				       unsigned int clock_rate)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int val;
+	int err;
+
+	regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
+
+	/* No need to set rates if I2S is being operated in slave */
+	if (!(val & I2S_CTRL_MASTER_EN))
+		return 0;
+
+	err = clk_set_rate(i2s->clk_i2s, clock_rate);
+	if (err) {
+		dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
+			clock_rate, err);
+		return err;
+	}
+
+	if (!IS_ERR(i2s->clk_sync_input)) {
+		/*
+		 * Other I/O modules in AHUB can use i2s bclk as reference
+		 * clock. Below sets sync input clock rate as per bclk,
+		 * which can be used as input to other I/O modules.
+		 */
+		err = clk_set_rate(i2s->clk_sync_input, clock_rate);
+		if (err) {
+			dev_err(dev,
+				"can't set I2S sync input rate %u, err = %d\n",
+				clock_rate, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt,
+				 bool is_playback)
+{
+	struct device *dev = compnt->dev;
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int reset_mask = I2S_SOFT_RESET_MASK;
+	unsigned int reset_en = I2S_SOFT_RESET_EN;
+	unsigned int reset_reg, cif_reg, stream_reg;
+	unsigned int cif_ctrl, stream_ctrl, i2s_ctrl, val;
+	int err;
+
+	if (is_playback) {
+		reset_reg = TEGRA210_I2S_RX_SOFT_RESET;
+		cif_reg = TEGRA210_I2S_RX_CIF_CTRL;
+		stream_reg = TEGRA210_I2S_RX_CTRL;
+	} else {
+		reset_reg = TEGRA210_I2S_TX_SOFT_RESET;
+		cif_reg = TEGRA210_I2S_TX_CIF_CTRL;
+		stream_reg = TEGRA210_I2S_TX_CTRL;
+	}
+
+	/* Store CIF and I2S control values */
+	regmap_read(i2s->regmap, cif_reg, &cif_ctrl);
+	regmap_read(i2s->regmap, stream_reg, &stream_ctrl);
+	regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &i2s_ctrl);
+
+	/* Reset to make sure the previous transactions are clean */
+	regmap_update_bits(i2s->regmap, reset_reg, reset_mask, reset_en);
+
+	err = regmap_read_poll_timeout(i2s->regmap, reset_reg, val,
+				       !(val & reset_mask & reset_en),
+				       10, 10000);
+	if (err) {
+		dev_err(dev, "timeout: failed to reset I2S for %s\n",
+			is_playback ? "playback" : "capture");
+		return err;
+	}
+
+	/* Restore CIF and I2S control values */
+	regmap_write(i2s->regmap, cif_reg, cif_ctrl);
+	regmap_write(i2s->regmap, stream_reg, stream_ctrl);
+	regmap_write(i2s->regmap, TEGRA210_I2S_CTRL, i2s_ctrl);
+
+	return 0;
+}
+
+static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *compnt = snd_soc_dapm_to_component(w->dapm);
+	struct device *dev = compnt->dev;
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int val, status_reg;
+	bool is_playback;
+	int err;
+
+	switch (w->reg) {
+	case TEGRA210_I2S_RX_ENABLE:
+		is_playback = true;
+		status_reg = TEGRA210_I2S_RX_STATUS;
+		break;
+	case TEGRA210_I2S_TX_ENABLE:
+		is_playback = false;
+		status_reg = TEGRA210_I2S_TX_STATUS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Ensure I2S is in disabled state before new session */
+	err = regmap_read_poll_timeout(i2s->regmap, status_reg, val,
+				       !(val & I2S_EN_MASK & I2S_EN),
+				       10, 10000);
+	if (err) {
+		dev_err(dev, "timeout: previous I2S %s is still active\n",
+			is_playback ? "playback" : "capture");
+		return err;
+	}
+
+	return tegra210_i2s_sw_reset(compnt, is_playback);
+}
+
+static int tegra210_i2s_runtime_suspend(struct device *dev)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+
+	regcache_cache_only(i2s->regmap, true);
+	regcache_mark_dirty(i2s->regmap);
+
+	clk_disable_unprepare(i2s->clk_i2s);
+
+	return 0;
+}
+
+static int tegra210_i2s_runtime_resume(struct device *dev)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(i2s->clk_i2s);
+	if (err) {
+		dev_err(dev, "failed to enable I2S bit clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(i2s->regmap, false);
+	regcache_sync(i2s->regmap);
+
+	return 0;
+}
+
+static void tegra210_i2s_set_data_offset(struct tegra210_i2s *i2s,
+					 unsigned int data_offset)
+{
+	/* Capture path */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_TX_CTRL,
+			   I2S_CTRL_DATA_OFFSET_MASK,
+			   data_offset << I2S_DATA_SHIFT);
+
+	/* Playback path */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_RX_CTRL,
+			   I2S_CTRL_DATA_OFFSET_MASK,
+			   data_offset << I2S_DATA_SHIFT);
+}
+
+static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
+				unsigned int fmt)
+{
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int mask, val;
+
+	mask = I2S_CTRL_MASTER_EN_MASK;
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		val = 0;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		val = I2S_CTRL_MASTER_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask |= I2S_CTRL_FRAME_FMT_MASK | I2S_CTRL_LRCK_POL_MASK;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		tegra210_i2s_set_data_offset(i2s, 1);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		tegra210_i2s_set_data_offset(i2s, 0);
+		break;
+	/* I2S mode has data offset of 1 */
+	case SND_SOC_DAIFMT_I2S:
+		val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+		val |= I2S_CTRL_LRCK_POL_LOW;
+		tegra210_i2s_set_data_offset(i2s, 1);
+		break;
+	/*
+	 * For RJ mode data offset is dependent on the sample size
+	 * and the bclk ratio, and so is set when hw_params is called.
+	 */
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		tegra210_i2s_set_data_offset(i2s, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask |= I2S_CTRL_EDGE_CTRL_MASK;
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
+		val ^= I2S_CTRL_LRCK_POL_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
+		val ^= I2S_CTRL_LRCK_POL_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, mask, val);
+
+	i2s->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	return 0;
+}
+
+static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai,
+				     unsigned int tx_mask, unsigned int rx_mask,
+				     int slots, int slot_width)
+{
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	/* Copy the required tx and rx mask */
+	i2s->tx_mask = (tx_mask > DEFAULT_I2S_SLOT_MASK) ?
+		       DEFAULT_I2S_SLOT_MASK : tx_mask;
+	i2s->rx_mask = (rx_mask > DEFAULT_I2S_SLOT_MASK) ?
+		       DEFAULT_I2S_SLOT_MASK : rx_mask;
+
+	return 0;
+}
+
+static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+					   unsigned int ratio)
+{
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	i2s->bclk_ratio = ratio;
+
+	return 0;
+}
+
+static int tegra210_i2s_get_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+	long *uctl_val = &ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Loopback"))
+		*uctl_val = i2s->loopback;
+	else if (strstr(kcontrol->id.name, "FSYNC Width"))
+		*uctl_val = i2s->fsync_width;
+	else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+		*uctl_val = i2s->stereo_to_mono[I2S_TX_PATH];
+	else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+		*uctl_val = i2s->mono_to_stereo[I2S_TX_PATH];
+	else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+		*uctl_val = i2s->stereo_to_mono[I2S_RX_PATH];
+	else if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+		*uctl_val = i2s->mono_to_stereo[I2S_RX_PATH];
+	else if (strstr(kcontrol->id.name, "Playback FIFO Threshold"))
+		*uctl_val = i2s->rx_fifo_th;
+	else if (strstr(kcontrol->id.name, "BCLK Ratio"))
+		*uctl_val = i2s->bclk_ratio;
+
+	return 0;
+}
+
+static int tegra210_i2s_put_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+	int value = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Loopback")) {
+		i2s->loopback = value;
+
+		regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+				   I2S_CTRL_LPBK_MASK,
+				   i2s->loopback << I2S_CTRL_LPBK_SHIFT);
+
+	} else if (strstr(kcontrol->id.name, "FSYNC Width")) {
+		/*
+		 * Frame sync width is used only for FSYNC modes and not
+		 * applicable for LRCK modes. Reset value for this field is "0",
+		 * which means the width is one bit clock wide.
+		 * The width requirement may depend on the codec and in such
+		 * cases mixer control is used to update custom values. A value
+		 * of "N" here means, width is "N + 1" bit clock wide.
+		 */
+		i2s->fsync_width = value;
+
+		regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+				   I2S_CTRL_FSYNC_WIDTH_MASK,
+				   i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
+
+	} else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) {
+		i2s->stereo_to_mono[I2S_TX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) {
+		i2s->mono_to_stereo[I2S_TX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) {
+		i2s->stereo_to_mono[I2S_RX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) {
+		i2s->mono_to_stereo[I2S_RX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) {
+		i2s->rx_fifo_th = value;
+	} else if (strstr(kcontrol->id.name, "BCLK Ratio")) {
+		i2s->bclk_ratio = value;
+	}
+
+	return 0;
+}
+
+static int tegra210_i2s_set_timing_params(struct device *dev,
+					  unsigned int sample_size,
+					  unsigned int srate,
+					  unsigned int channels)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int val, bit_count, bclk_rate, num_bclk = sample_size;
+	int err;
+
+	if (i2s->bclk_ratio)
+		num_bclk *= i2s->bclk_ratio;
+
+	if (i2s->dai_fmt == SND_SOC_DAIFMT_RIGHT_J)
+		tegra210_i2s_set_data_offset(i2s, num_bclk - sample_size);
+
+	/* I2S bit clock rate */
+	bclk_rate = srate * channels * num_bclk;
+
+	err = tegra210_i2s_set_clock_rate(dev, bclk_rate);
+	if (err) {
+		dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
+			bclk_rate, err);
+		return err;
+	}
+
+	regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
+
+	/*
+	 * For LRCK mode, channel bit count depends on number of bit clocks
+	 * on the left channel, where as for FSYNC mode bit count depends on
+	 * the number of bit clocks in both left and right channels for DSP
+	 * mode or the number of bit clocks in one TDM frame.
+	 *
+	 */
+	switch (val & I2S_CTRL_FRAME_FMT_MASK) {
+	case I2S_CTRL_FRAME_FMT_LRCK_MODE:
+		bit_count = (bclk_rate / (srate * 2)) - 1;
+		break;
+	case I2S_CTRL_FRAME_FMT_FSYNC_MODE:
+		bit_count = (bclk_rate / srate) - 1;
+
+		tegra210_i2s_set_slot_ctrl(i2s->regmap, channels,
+					   i2s->tx_mask, i2s->rx_mask);
+		break;
+	default:
+		dev_err(dev, "invalid I2S frame format\n");
+		return -EINVAL;
+	}
+
+	if (bit_count > I2S_TIMING_CH_BIT_CNT_MASK) {
+		dev_err(dev, "invalid I2S channel bit count %u\n", bit_count);
+		return -EINVAL;
+	}
+
+	regmap_write(i2s->regmap, TEGRA210_I2S_TIMING,
+		     bit_count << I2S_TIMING_CH_BIT_CNT_SHIFT);
+
+	return 0;
+}
+
+static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int sample_size, channels, srate, val, reg, path;
+	struct tegra_cif_conf cif_conf;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+	if (channels < 1) {
+		dev_err(dev, "invalid I2S %d channel configuration\n",
+			channels);
+		return -EINVAL;
+	}
+
+	cif_conf.audio_ch = channels;
+	cif_conf.client_ch = channels;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		val = I2S_BITS_8;
+		sample_size = 8;
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		val = I2S_BITS_16;
+		sample_size = 16;
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		val = I2S_BITS_32;
+		sample_size = 32;
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	/* Program sample size */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+			   I2S_CTRL_BIT_SIZE_MASK, val);
+
+	srate = params_rate(params);
+
+	/* For playback I2S RX-CIF and for capture TX-CIF is used */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		path = I2S_RX_PATH;
+	else
+		path = I2S_TX_PATH;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		unsigned int max_th;
+
+		/* FIFO threshold in terms of frames */
+		max_th = (I2S_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
+
+		if (i2s->rx_fifo_th > max_th)
+			i2s->rx_fifo_th = max_th;
+
+		cif_conf.threshold = i2s->rx_fifo_th;
+
+		reg = TEGRA210_I2S_RX_CIF_CTRL;
+	} else {
+		reg = TEGRA210_I2S_TX_CIF_CTRL;
+	}
+
+	cif_conf.mono_conv = i2s->mono_to_stereo[path];
+	cif_conf.stereo_conv = i2s->stereo_to_mono[path];
+
+	tegra_set_cif(i2s->regmap, reg, &cif_conf);
+
+	return tegra210_i2s_set_timing_params(dev, sample_size, srate,
+					      cif_conf.client_ch);
+}
+
+static const struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
+	.set_fmt	= tegra210_i2s_set_fmt,
+	.hw_params	= tegra210_i2s_hw_params,
+	.set_bclk_ratio	= tegra210_i2s_set_dai_bclk_ratio,
+	.set_tdm_slot	= tegra210_i2s_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
+	{
+		.name = "I2S",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &tegra210_i2s_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const char * const tegra210_i2s_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const char * const tegra210_i2s_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+static const struct soc_enum tegra210_i2s_mono_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_mono_conv_text),
+			tegra210_i2s_mono_conv_text);
+
+static const struct soc_enum tegra210_i2s_stereo_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_stereo_conv_text),
+			tegra210_i2s_stereo_conv_text);
+
+static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
+	SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_control,
+		       tegra210_i2s_put_control),
+	SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control,
+		       tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Playback Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Playback Mono To Stereo", tegra210_i2s_mono_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_SINGLE_EXT("Playback FIFO Threshold", 0, 0, I2S_RX_FIFO_DEPTH - 1,
+		       0, tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, tegra210_i2s_get_control,
+		       tegra210_i2s_put_control),
+};
+
+static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
+	SND_SOC_DAPM_AIF_IN_E("RX", NULL, 0, TEGRA210_I2S_RX_ENABLE,
+			      0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_AIF_OUT_E("TX", NULL, 0, TEGRA210_I2S_TX_ENABLE,
+			       0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_route tegra210_i2s_routes[] = {
+	{ "RX",		NULL,	"XBAR-TX" },
+	{ "Playback",	NULL,	"RX" },
+	{ "XBAR-RX",	NULL,	"TX" },
+	{ "TX",		NULL,	"Capture" },
+};
+
+static const struct snd_soc_component_driver tegra210_i2s_cmpnt = {
+	.dapm_widgets = tegra210_i2s_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets),
+	.dapm_routes = tegra210_i2s_routes,
+	.num_dapm_routes = ARRAY_SIZE(tegra210_i2s_routes),
+	.controls = tegra210_i2s_controls,
+	.num_controls = ARRAY_SIZE(tegra210_i2s_controls),
+};
+
+static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_I2S_RX_ENABLE ... TEGRA210_I2S_RX_SOFT_RESET:
+	case TEGRA210_I2S_RX_INT_MASK ... TEGRA210_I2S_RX_CLK_TRIM:
+	case TEGRA210_I2S_TX_ENABLE ... TEGRA210_I2S_TX_SOFT_RESET:
+	case TEGRA210_I2S_TX_INT_MASK ... TEGRA210_I2S_TX_CLK_TRIM:
+	case TEGRA210_I2S_ENABLE ... TEGRA210_I2S_CG:
+	case TEGRA210_I2S_CTRL ... TEGRA210_I2S_CYA:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_i2s_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_I2S_RX_STATUS:
+	case TEGRA210_I2S_RX_INT_STATUS:
+	case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_TX_STATUS:
+	case TEGRA210_I2S_TX_INT_STATUS:
+	case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_STATUS:
+	case TEGRA210_I2S_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_I2S_RX_STATUS:
+	case TEGRA210_I2S_RX_INT_STATUS:
+	case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_TX_STATUS:
+	case TEGRA210_I2S_TX_INT_STATUS:
+	case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_STATUS:
+	case TEGRA210_I2S_INT_STATUS:
+	case TEGRA210_I2S_RX_SOFT_RESET:
+	case TEGRA210_I2S_TX_SOFT_RESET:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra210_i2s_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_I2S_CYA,
+	.writeable_reg		= tegra210_i2s_wr_reg,
+	.readable_reg		= tegra210_i2s_rd_reg,
+	.volatile_reg		= tegra210_i2s_volatile_reg,
+	.reg_defaults		= tegra210_i2s_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_i2s_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static int tegra210_i2s_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_i2s *i2s;
+	void __iomem *regs;
+	int err;
+
+	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
+	if (!i2s)
+		return -ENOMEM;
+
+	i2s->rx_fifo_th = DEFAULT_I2S_RX_FIFO_THRESHOLD;
+	i2s->tx_mask = DEFAULT_I2S_SLOT_MASK;
+	i2s->rx_mask = DEFAULT_I2S_SLOT_MASK;
+	i2s->loopback = false;
+
+	dev_set_drvdata(dev, i2s);
+
+	i2s->clk_i2s = devm_clk_get(dev, "i2s");
+	if (IS_ERR(i2s->clk_i2s)) {
+		dev_err(dev, "can't retrieve I2S bit clock\n");
+		return PTR_ERR(i2s->clk_i2s);
+	}
+
+	/*
+	 * Not an error, as this clock is needed only when some other I/O
+	 * requires input clock from current I2S instance, which is
+	 * configurable from DT.
+	 */
+	i2s->clk_sync_input = devm_clk_get(dev, "sync_input");
+	if (IS_ERR(i2s->clk_sync_input))
+		dev_dbg(dev, "can't retrieve I2S sync input clock\n");
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	i2s->regmap = devm_regmap_init_mmio(dev, regs,
+					    &tegra210_i2s_regmap_config);
+	if (IS_ERR(i2s->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(i2s->regmap);
+	}
+
+	regcache_cache_only(i2s->regmap, true);
+
+	err = devm_snd_soc_register_component(dev, &tegra210_i2s_cmpnt,
+					      tegra210_i2s_dais,
+					      ARRAY_SIZE(tegra210_i2s_dais));
+	if (err) {
+		dev_err(dev, "can't register I2S component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra210_i2s_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra210_i2s_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend,
+			   tegra210_i2s_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_i2s_of_match[] = {
+	{ .compatible = "nvidia,tegra210-i2s" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match);
+
+static struct platform_driver tegra210_i2s_driver = {
+	.driver = {
+		.name = "tegra210-i2s",
+		.of_match_table = tegra210_i2s_of_match,
+		.pm = &tegra210_i2s_pm_ops,
+	},
+	.probe = tegra210_i2s_probe,
+	.remove = tegra210_i2s_remove,
+};
+module_platform_driver(tegra210_i2s_driver)
+
+MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 ASoC I2S driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_i2s.h b/sound/soc/tegra/tegra210_i2s.h
new file mode 100644
index 0000000..030d70c
--- /dev/null
+++ b/sound/soc/tegra/tegra210_i2s.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_i2s.h - Definitions for Tegra210 I2S driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_I2S_H__
+#define __TEGRA210_I2S_H__
+
+/* Register offsets from I2S*_BASE */
+#define TEGRA210_I2S_RX_ENABLE			0x0
+#define TEGRA210_I2S_RX_SOFT_RESET		0x4
+#define TEGRA210_I2S_RX_STATUS			0x0c
+#define TEGRA210_I2S_RX_INT_STATUS		0x10
+#define TEGRA210_I2S_RX_INT_MASK		0x14
+#define TEGRA210_I2S_RX_INT_SET			0x18
+#define TEGRA210_I2S_RX_INT_CLEAR		0x1c
+#define TEGRA210_I2S_RX_CIF_CTRL		0x20
+#define TEGRA210_I2S_RX_CTRL			0x24
+#define TEGRA210_I2S_RX_SLOT_CTRL		0x28
+#define TEGRA210_I2S_RX_CLK_TRIM		0x2c
+#define TEGRA210_I2S_RX_CYA			0x30
+#define TEGRA210_I2S_RX_CIF_FIFO_STATUS		0x34
+#define TEGRA210_I2S_TX_ENABLE			0x40
+#define TEGRA210_I2S_TX_SOFT_RESET		0x44
+#define TEGRA210_I2S_TX_STATUS			0x4c
+#define TEGRA210_I2S_TX_INT_STATUS		0x50
+#define TEGRA210_I2S_TX_INT_MASK		0x54
+#define TEGRA210_I2S_TX_INT_SET			0x58
+#define TEGRA210_I2S_TX_INT_CLEAR		0x5c
+#define TEGRA210_I2S_TX_CIF_CTRL		0x60
+#define TEGRA210_I2S_TX_CTRL			0x64
+#define TEGRA210_I2S_TX_SLOT_CTRL		0x68
+#define TEGRA210_I2S_TX_CLK_TRIM		0x6c
+#define TEGRA210_I2S_TX_CYA			0x70
+#define TEGRA210_I2S_TX_CIF_FIFO_STATUS		0x74
+#define TEGRA210_I2S_ENABLE			0x80
+#define TEGRA210_I2S_SOFT_RESET			0x84
+#define TEGRA210_I2S_CG				0x88
+#define TEGRA210_I2S_STATUS			0x8c
+#define TEGRA210_I2S_INT_STATUS			0x90
+#define TEGRA210_I2S_CTRL			0xa0
+#define TEGRA210_I2S_TIMING			0xa4
+#define TEGRA210_I2S_SLOT_CTRL			0xa8
+#define TEGRA210_I2S_CLK_TRIM			0xac
+#define TEGRA210_I2S_CYA			0xb0
+
+/* Bit fields, shifts and masks */
+#define I2S_DATA_SHIFT				8
+#define I2S_CTRL_DATA_OFFSET_MASK		(0x7ff << I2S_DATA_SHIFT)
+
+#define I2S_EN_SHIFT				0
+#define I2S_EN_MASK				BIT(I2S_EN_SHIFT)
+#define I2S_EN					BIT(I2S_EN_SHIFT)
+
+#define I2S_FSYNC_WIDTH_SHIFT			24
+#define I2S_CTRL_FSYNC_WIDTH_MASK		(0xff << I2S_FSYNC_WIDTH_SHIFT)
+
+#define I2S_POS_EDGE				0
+#define I2S_NEG_EDGE				1
+#define I2S_EDGE_SHIFT				20
+#define I2S_CTRL_EDGE_CTRL_MASK			BIT(I2S_EDGE_SHIFT)
+#define I2S_CTRL_EDGE_CTRL_POS_EDGE		(I2S_POS_EDGE << I2S_EDGE_SHIFT)
+#define I2S_CTRL_EDGE_CTRL_NEG_EDGE		(I2S_NEG_EDGE << I2S_EDGE_SHIFT)
+
+#define I2S_FMT_LRCK				0
+#define I2S_FMT_FSYNC				1
+#define I2S_FMT_SHIFT				12
+#define I2S_CTRL_FRAME_FMT_MASK			(7 << I2S_FMT_SHIFT)
+#define I2S_CTRL_FRAME_FMT_LRCK_MODE		(I2S_FMT_LRCK << I2S_FMT_SHIFT)
+#define I2S_CTRL_FRAME_FMT_FSYNC_MODE		(I2S_FMT_FSYNC << I2S_FMT_SHIFT)
+
+#define I2S_CTRL_MASTER_EN_SHIFT		10
+#define I2S_CTRL_MASTER_EN_MASK			BIT(I2S_CTRL_MASTER_EN_SHIFT)
+#define I2S_CTRL_MASTER_EN			BIT(I2S_CTRL_MASTER_EN_SHIFT)
+
+#define I2S_CTRL_LRCK_POL_SHIFT			9
+#define I2S_CTRL_LRCK_POL_MASK			BIT(I2S_CTRL_LRCK_POL_SHIFT)
+#define I2S_CTRL_LRCK_POL_LOW			(0 << I2S_CTRL_LRCK_POL_SHIFT)
+#define I2S_CTRL_LRCK_POL_HIGH			BIT(I2S_CTRL_LRCK_POL_SHIFT)
+
+#define I2S_CTRL_LPBK_SHIFT			8
+#define I2S_CTRL_LPBK_MASK			BIT(I2S_CTRL_LPBK_SHIFT)
+#define I2S_CTRL_LPBK_EN			BIT(I2S_CTRL_LPBK_SHIFT)
+
+#define I2S_BITS_8				1
+#define I2S_BITS_16				3
+#define I2S_BITS_32				7
+#define I2S_CTRL_BIT_SIZE_MASK			0x7
+
+#define I2S_TIMING_CH_BIT_CNT_MASK		0x7ff
+#define I2S_TIMING_CH_BIT_CNT_SHIFT		0
+
+#define I2S_SOFT_RESET_SHIFT			0
+#define I2S_SOFT_RESET_MASK			BIT(I2S_SOFT_RESET_SHIFT)
+#define I2S_SOFT_RESET_EN			BIT(I2S_SOFT_RESET_SHIFT)
+
+#define I2S_RX_FIFO_DEPTH			64
+#define DEFAULT_I2S_RX_FIFO_THRESHOLD		3
+
+#define DEFAULT_I2S_SLOT_MASK			0xffff
+
+enum tegra210_i2s_path {
+	I2S_RX_PATH,
+	I2S_TX_PATH,
+	I2S_PATHS,
+};
+
+struct tegra210_i2s {
+	struct clk *clk_i2s;
+	struct clk *clk_sync_input;
+	struct regmap *regmap;
+	unsigned int stereo_to_mono[I2S_PATHS];
+	unsigned int mono_to_stereo[I2S_PATHS];
+	unsigned int dai_fmt;
+	unsigned int fsync_width;
+	unsigned int bclk_ratio;
+	unsigned int tx_mask;
+	unsigned int rx_mask;
+	unsigned int rx_fifo_th;
+	bool loopback;
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 04/23] ASoC: tegra: Add Tegra210 based I2S driver
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

The Inter-IC Sound (I2S) controller implements full-duplex, bi-directional
and single direction point to point serial interface. It can interface
with I2S compatible devices. Tegra I2S controller can operate as both
master and slave.

This patch registers I2S controller with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes I2S interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The I2S devices can be enabled in the DT via
"nvidia,tegra210-i2s" compatible binding.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig        |  10 +
 sound/soc/tegra/Makefile       |   2 +
 sound/soc/tegra/tegra210_i2s.c | 780 +++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_i2s.h | 126 +++++++
 4 files changed, 918 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_i2s.c
 create mode 100644 sound/soc/tegra/tegra210_i2s.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 2bde1e6..157fa7a 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -73,6 +73,16 @@ config SND_SOC_TEGRA210_DMIC
           PDM receiver.
           Say Y or M if you want to add support for Tegra210 DMIC module.
 
+config SND_SOC_TEGRA210_I2S
+        tristate "Tegra210 I2S module"
+        depends on SND_SOC_TEGRA
+        help
+          Config to enable the Inter-IC Sound (I2S) Controller which
+          implements full-duplex and bidirectional and single direction
+          point-to-point serial interfaces. It can interface with I2S
+          compatible devices.
+          Say Y or M if you want to add support for Tegra210 I2S module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index f0690cf..e30f6a3 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -9,6 +9,7 @@ snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 snd-soc-tegra30-ahub-objs := tegra30_ahub.o
 snd-soc-tegra30-i2s-objs := tegra30_i2s.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
+snd-soc-tegra210-i2s-objs := tegra210_i2s.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
+obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
new file mode 100644
index 0000000..a48124c
--- /dev/null
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -0,0 +1,780 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_i2s.c - Tegra210 I2S driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra210_i2s.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_i2s_reg_defaults[] = {
+	{ TEGRA210_I2S_RX_INT_MASK, 0x00000003 },
+	{ TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_I2S_TX_INT_MASK, 0x00000003 },
+	{ TEGRA210_I2S_TX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_I2S_CG, 0x1 },
+	{ TEGRA210_I2S_TIMING, 0x0000001f },
+	{ TEGRA210_I2S_ENABLE, 0x1 },
+	/*
+	 * Below update does not have any effect on Tegra186 and Tegra194.
+	 * On Tegra210, I2S4 has "i2s4a" and "i2s4b" pins and below update
+	 * is required to select i2s4b for it to be functional for I2S
+	 * operation.
+	 */
+	{ TEGRA210_I2S_CYA, 0x1 },
+};
+
+static void tegra210_i2s_set_slot_ctrl(struct regmap *regmap,
+				       unsigned int total_slots,
+				       unsigned int tx_slot_mask,
+				       unsigned int rx_slot_mask)
+{
+	regmap_write(regmap, TEGRA210_I2S_SLOT_CTRL, total_slots - 1);
+	regmap_write(regmap, TEGRA210_I2S_TX_SLOT_CTRL, tx_slot_mask);
+	regmap_write(regmap, TEGRA210_I2S_RX_SLOT_CTRL, rx_slot_mask);
+}
+
+static int tegra210_i2s_set_clock_rate(struct device *dev,
+				       unsigned int clock_rate)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int val;
+	int err;
+
+	regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
+
+	/* No need to set rates if I2S is being operated in slave */
+	if (!(val & I2S_CTRL_MASTER_EN))
+		return 0;
+
+	err = clk_set_rate(i2s->clk_i2s, clock_rate);
+	if (err) {
+		dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
+			clock_rate, err);
+		return err;
+	}
+
+	if (!IS_ERR(i2s->clk_sync_input)) {
+		/*
+		 * Other I/O modules in AHUB can use i2s bclk as reference
+		 * clock. Below sets sync input clock rate as per bclk,
+		 * which can be used as input to other I/O modules.
+		 */
+		err = clk_set_rate(i2s->clk_sync_input, clock_rate);
+		if (err) {
+			dev_err(dev,
+				"can't set I2S sync input rate %u, err = %d\n",
+				clock_rate, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt,
+				 bool is_playback)
+{
+	struct device *dev = compnt->dev;
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int reset_mask = I2S_SOFT_RESET_MASK;
+	unsigned int reset_en = I2S_SOFT_RESET_EN;
+	unsigned int reset_reg, cif_reg, stream_reg;
+	unsigned int cif_ctrl, stream_ctrl, i2s_ctrl, val;
+	int err;
+
+	if (is_playback) {
+		reset_reg = TEGRA210_I2S_RX_SOFT_RESET;
+		cif_reg = TEGRA210_I2S_RX_CIF_CTRL;
+		stream_reg = TEGRA210_I2S_RX_CTRL;
+	} else {
+		reset_reg = TEGRA210_I2S_TX_SOFT_RESET;
+		cif_reg = TEGRA210_I2S_TX_CIF_CTRL;
+		stream_reg = TEGRA210_I2S_TX_CTRL;
+	}
+
+	/* Store CIF and I2S control values */
+	regmap_read(i2s->regmap, cif_reg, &cif_ctrl);
+	regmap_read(i2s->regmap, stream_reg, &stream_ctrl);
+	regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &i2s_ctrl);
+
+	/* Reset to make sure the previous transactions are clean */
+	regmap_update_bits(i2s->regmap, reset_reg, reset_mask, reset_en);
+
+	err = regmap_read_poll_timeout(i2s->regmap, reset_reg, val,
+				       !(val & reset_mask & reset_en),
+				       10, 10000);
+	if (err) {
+		dev_err(dev, "timeout: failed to reset I2S for %s\n",
+			is_playback ? "playback" : "capture");
+		return err;
+	}
+
+	/* Restore CIF and I2S control values */
+	regmap_write(i2s->regmap, cif_reg, cif_ctrl);
+	regmap_write(i2s->regmap, stream_reg, stream_ctrl);
+	regmap_write(i2s->regmap, TEGRA210_I2S_CTRL, i2s_ctrl);
+
+	return 0;
+}
+
+static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *compnt = snd_soc_dapm_to_component(w->dapm);
+	struct device *dev = compnt->dev;
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int val, status_reg;
+	bool is_playback;
+	int err;
+
+	switch (w->reg) {
+	case TEGRA210_I2S_RX_ENABLE:
+		is_playback = true;
+		status_reg = TEGRA210_I2S_RX_STATUS;
+		break;
+	case TEGRA210_I2S_TX_ENABLE:
+		is_playback = false;
+		status_reg = TEGRA210_I2S_TX_STATUS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Ensure I2S is in disabled state before new session */
+	err = regmap_read_poll_timeout(i2s->regmap, status_reg, val,
+				       !(val & I2S_EN_MASK & I2S_EN),
+				       10, 10000);
+	if (err) {
+		dev_err(dev, "timeout: previous I2S %s is still active\n",
+			is_playback ? "playback" : "capture");
+		return err;
+	}
+
+	return tegra210_i2s_sw_reset(compnt, is_playback);
+}
+
+static int tegra210_i2s_runtime_suspend(struct device *dev)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+
+	regcache_cache_only(i2s->regmap, true);
+	regcache_mark_dirty(i2s->regmap);
+
+	clk_disable_unprepare(i2s->clk_i2s);
+
+	return 0;
+}
+
+static int tegra210_i2s_runtime_resume(struct device *dev)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(i2s->clk_i2s);
+	if (err) {
+		dev_err(dev, "failed to enable I2S bit clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(i2s->regmap, false);
+	regcache_sync(i2s->regmap);
+
+	return 0;
+}
+
+static void tegra210_i2s_set_data_offset(struct tegra210_i2s *i2s,
+					 unsigned int data_offset)
+{
+	/* Capture path */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_TX_CTRL,
+			   I2S_CTRL_DATA_OFFSET_MASK,
+			   data_offset << I2S_DATA_SHIFT);
+
+	/* Playback path */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_RX_CTRL,
+			   I2S_CTRL_DATA_OFFSET_MASK,
+			   data_offset << I2S_DATA_SHIFT);
+}
+
+static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
+				unsigned int fmt)
+{
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int mask, val;
+
+	mask = I2S_CTRL_MASTER_EN_MASK;
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		val = 0;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		val = I2S_CTRL_MASTER_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask |= I2S_CTRL_FRAME_FMT_MASK | I2S_CTRL_LRCK_POL_MASK;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		tegra210_i2s_set_data_offset(i2s, 1);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		tegra210_i2s_set_data_offset(i2s, 0);
+		break;
+	/* I2S mode has data offset of 1 */
+	case SND_SOC_DAIFMT_I2S:
+		val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+		val |= I2S_CTRL_LRCK_POL_LOW;
+		tegra210_i2s_set_data_offset(i2s, 1);
+		break;
+	/*
+	 * For RJ mode data offset is dependent on the sample size
+	 * and the bclk ratio, and so is set when hw_params is called.
+	 */
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+		val |= I2S_CTRL_LRCK_POL_HIGH;
+		tegra210_i2s_set_data_offset(i2s, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask |= I2S_CTRL_EDGE_CTRL_MASK;
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
+		val ^= I2S_CTRL_LRCK_POL_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
+		val ^= I2S_CTRL_LRCK_POL_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, mask, val);
+
+	i2s->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	return 0;
+}
+
+static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai,
+				     unsigned int tx_mask, unsigned int rx_mask,
+				     int slots, int slot_width)
+{
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	/* Copy the required tx and rx mask */
+	i2s->tx_mask = (tx_mask > DEFAULT_I2S_SLOT_MASK) ?
+		       DEFAULT_I2S_SLOT_MASK : tx_mask;
+	i2s->rx_mask = (rx_mask > DEFAULT_I2S_SLOT_MASK) ?
+		       DEFAULT_I2S_SLOT_MASK : rx_mask;
+
+	return 0;
+}
+
+static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+					   unsigned int ratio)
+{
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+	i2s->bclk_ratio = ratio;
+
+	return 0;
+}
+
+static int tegra210_i2s_get_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+	long *uctl_val = &ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Loopback"))
+		*uctl_val = i2s->loopback;
+	else if (strstr(kcontrol->id.name, "FSYNC Width"))
+		*uctl_val = i2s->fsync_width;
+	else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+		*uctl_val = i2s->stereo_to_mono[I2S_TX_PATH];
+	else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+		*uctl_val = i2s->mono_to_stereo[I2S_TX_PATH];
+	else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+		*uctl_val = i2s->stereo_to_mono[I2S_RX_PATH];
+	else if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+		*uctl_val = i2s->mono_to_stereo[I2S_RX_PATH];
+	else if (strstr(kcontrol->id.name, "Playback FIFO Threshold"))
+		*uctl_val = i2s->rx_fifo_th;
+	else if (strstr(kcontrol->id.name, "BCLK Ratio"))
+		*uctl_val = i2s->bclk_ratio;
+
+	return 0;
+}
+
+static int tegra210_i2s_put_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+	struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+	int value = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Loopback")) {
+		i2s->loopback = value;
+
+		regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+				   I2S_CTRL_LPBK_MASK,
+				   i2s->loopback << I2S_CTRL_LPBK_SHIFT);
+
+	} else if (strstr(kcontrol->id.name, "FSYNC Width")) {
+		/*
+		 * Frame sync width is used only for FSYNC modes and not
+		 * applicable for LRCK modes. Reset value for this field is "0",
+		 * which means the width is one bit clock wide.
+		 * The width requirement may depend on the codec and in such
+		 * cases mixer control is used to update custom values. A value
+		 * of "N" here means, width is "N + 1" bit clock wide.
+		 */
+		i2s->fsync_width = value;
+
+		regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+				   I2S_CTRL_FSYNC_WIDTH_MASK,
+				   i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
+
+	} else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) {
+		i2s->stereo_to_mono[I2S_TX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) {
+		i2s->mono_to_stereo[I2S_TX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) {
+		i2s->stereo_to_mono[I2S_RX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) {
+		i2s->mono_to_stereo[I2S_RX_PATH] = value;
+	} else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) {
+		i2s->rx_fifo_th = value;
+	} else if (strstr(kcontrol->id.name, "BCLK Ratio")) {
+		i2s->bclk_ratio = value;
+	}
+
+	return 0;
+}
+
+static int tegra210_i2s_set_timing_params(struct device *dev,
+					  unsigned int sample_size,
+					  unsigned int srate,
+					  unsigned int channels)
+{
+	struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+	unsigned int val, bit_count, bclk_rate, num_bclk = sample_size;
+	int err;
+
+	if (i2s->bclk_ratio)
+		num_bclk *= i2s->bclk_ratio;
+
+	if (i2s->dai_fmt == SND_SOC_DAIFMT_RIGHT_J)
+		tegra210_i2s_set_data_offset(i2s, num_bclk - sample_size);
+
+	/* I2S bit clock rate */
+	bclk_rate = srate * channels * num_bclk;
+
+	err = tegra210_i2s_set_clock_rate(dev, bclk_rate);
+	if (err) {
+		dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
+			bclk_rate, err);
+		return err;
+	}
+
+	regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
+
+	/*
+	 * For LRCK mode, channel bit count depends on number of bit clocks
+	 * on the left channel, where as for FSYNC mode bit count depends on
+	 * the number of bit clocks in both left and right channels for DSP
+	 * mode or the number of bit clocks in one TDM frame.
+	 *
+	 */
+	switch (val & I2S_CTRL_FRAME_FMT_MASK) {
+	case I2S_CTRL_FRAME_FMT_LRCK_MODE:
+		bit_count = (bclk_rate / (srate * 2)) - 1;
+		break;
+	case I2S_CTRL_FRAME_FMT_FSYNC_MODE:
+		bit_count = (bclk_rate / srate) - 1;
+
+		tegra210_i2s_set_slot_ctrl(i2s->regmap, channels,
+					   i2s->tx_mask, i2s->rx_mask);
+		break;
+	default:
+		dev_err(dev, "invalid I2S frame format\n");
+		return -EINVAL;
+	}
+
+	if (bit_count > I2S_TIMING_CH_BIT_CNT_MASK) {
+		dev_err(dev, "invalid I2S channel bit count %u\n", bit_count);
+		return -EINVAL;
+	}
+
+	regmap_write(i2s->regmap, TEGRA210_I2S_TIMING,
+		     bit_count << I2S_TIMING_CH_BIT_CNT_SHIFT);
+
+	return 0;
+}
+
+static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int sample_size, channels, srate, val, reg, path;
+	struct tegra_cif_conf cif_conf;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+	if (channels < 1) {
+		dev_err(dev, "invalid I2S %d channel configuration\n",
+			channels);
+		return -EINVAL;
+	}
+
+	cif_conf.audio_ch = channels;
+	cif_conf.client_ch = channels;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		val = I2S_BITS_8;
+		sample_size = 8;
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		val = I2S_BITS_16;
+		sample_size = 16;
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		val = I2S_BITS_32;
+		sample_size = 32;
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	/* Program sample size */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+			   I2S_CTRL_BIT_SIZE_MASK, val);
+
+	srate = params_rate(params);
+
+	/* For playback I2S RX-CIF and for capture TX-CIF is used */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		path = I2S_RX_PATH;
+	else
+		path = I2S_TX_PATH;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		unsigned int max_th;
+
+		/* FIFO threshold in terms of frames */
+		max_th = (I2S_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
+
+		if (i2s->rx_fifo_th > max_th)
+			i2s->rx_fifo_th = max_th;
+
+		cif_conf.threshold = i2s->rx_fifo_th;
+
+		reg = TEGRA210_I2S_RX_CIF_CTRL;
+	} else {
+		reg = TEGRA210_I2S_TX_CIF_CTRL;
+	}
+
+	cif_conf.mono_conv = i2s->mono_to_stereo[path];
+	cif_conf.stereo_conv = i2s->stereo_to_mono[path];
+
+	tegra_set_cif(i2s->regmap, reg, &cif_conf);
+
+	return tegra210_i2s_set_timing_params(dev, sample_size, srate,
+					      cif_conf.client_ch);
+}
+
+static const struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
+	.set_fmt	= tegra210_i2s_set_fmt,
+	.hw_params	= tegra210_i2s_hw_params,
+	.set_bclk_ratio	= tegra210_i2s_set_dai_bclk_ratio,
+	.set_tdm_slot	= tegra210_i2s_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
+	{
+		.name = "I2S",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S8 |
+				SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &tegra210_i2s_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const char * const tegra210_i2s_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const char * const tegra210_i2s_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+static const struct soc_enum tegra210_i2s_mono_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_mono_conv_text),
+			tegra210_i2s_mono_conv_text);
+
+static const struct soc_enum tegra210_i2s_stereo_conv_enum =
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_stereo_conv_text),
+			tegra210_i2s_stereo_conv_text);
+
+static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
+	SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_control,
+		       tegra210_i2s_put_control),
+	SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control,
+		       tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Playback Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_ENUM_EXT("Playback Mono To Stereo", tegra210_i2s_mono_conv_enum,
+		     tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_SINGLE_EXT("Playback FIFO Threshold", 0, 0, I2S_RX_FIFO_DEPTH - 1,
+		       0, tegra210_i2s_get_control, tegra210_i2s_put_control),
+	SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, tegra210_i2s_get_control,
+		       tegra210_i2s_put_control),
+};
+
+static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
+	SND_SOC_DAPM_AIF_IN_E("RX", NULL, 0, TEGRA210_I2S_RX_ENABLE,
+			      0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_AIF_OUT_E("TX", NULL, 0, TEGRA210_I2S_TX_ENABLE,
+			       0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_route tegra210_i2s_routes[] = {
+	{ "RX",		NULL,	"XBAR-TX" },
+	{ "Playback",	NULL,	"RX" },
+	{ "XBAR-RX",	NULL,	"TX" },
+	{ "TX",		NULL,	"Capture" },
+};
+
+static const struct snd_soc_component_driver tegra210_i2s_cmpnt = {
+	.dapm_widgets = tegra210_i2s_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets),
+	.dapm_routes = tegra210_i2s_routes,
+	.num_dapm_routes = ARRAY_SIZE(tegra210_i2s_routes),
+	.controls = tegra210_i2s_controls,
+	.num_controls = ARRAY_SIZE(tegra210_i2s_controls),
+};
+
+static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_I2S_RX_ENABLE ... TEGRA210_I2S_RX_SOFT_RESET:
+	case TEGRA210_I2S_RX_INT_MASK ... TEGRA210_I2S_RX_CLK_TRIM:
+	case TEGRA210_I2S_TX_ENABLE ... TEGRA210_I2S_TX_SOFT_RESET:
+	case TEGRA210_I2S_TX_INT_MASK ... TEGRA210_I2S_TX_CLK_TRIM:
+	case TEGRA210_I2S_ENABLE ... TEGRA210_I2S_CG:
+	case TEGRA210_I2S_CTRL ... TEGRA210_I2S_CYA:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra210_i2s_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA210_I2S_RX_STATUS:
+	case TEGRA210_I2S_RX_INT_STATUS:
+	case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_TX_STATUS:
+	case TEGRA210_I2S_TX_INT_STATUS:
+	case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_STATUS:
+	case TEGRA210_I2S_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA210_I2S_RX_STATUS:
+	case TEGRA210_I2S_RX_INT_STATUS:
+	case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_TX_STATUS:
+	case TEGRA210_I2S_TX_INT_STATUS:
+	case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
+	case TEGRA210_I2S_STATUS:
+	case TEGRA210_I2S_INT_STATUS:
+	case TEGRA210_I2S_RX_SOFT_RESET:
+	case TEGRA210_I2S_TX_SOFT_RESET:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra210_i2s_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_I2S_CYA,
+	.writeable_reg		= tegra210_i2s_wr_reg,
+	.readable_reg		= tegra210_i2s_rd_reg,
+	.volatile_reg		= tegra210_i2s_volatile_reg,
+	.reg_defaults		= tegra210_i2s_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra210_i2s_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static int tegra210_i2s_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra210_i2s *i2s;
+	void __iomem *regs;
+	int err;
+
+	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
+	if (!i2s)
+		return -ENOMEM;
+
+	i2s->rx_fifo_th = DEFAULT_I2S_RX_FIFO_THRESHOLD;
+	i2s->tx_mask = DEFAULT_I2S_SLOT_MASK;
+	i2s->rx_mask = DEFAULT_I2S_SLOT_MASK;
+	i2s->loopback = false;
+
+	dev_set_drvdata(dev, i2s);
+
+	i2s->clk_i2s = devm_clk_get(dev, "i2s");
+	if (IS_ERR(i2s->clk_i2s)) {
+		dev_err(dev, "can't retrieve I2S bit clock\n");
+		return PTR_ERR(i2s->clk_i2s);
+	}
+
+	/*
+	 * Not an error, as this clock is needed only when some other I/O
+	 * requires input clock from current I2S instance, which is
+	 * configurable from DT.
+	 */
+	i2s->clk_sync_input = devm_clk_get(dev, "sync_input");
+	if (IS_ERR(i2s->clk_sync_input))
+		dev_dbg(dev, "can't retrieve I2S sync input clock\n");
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	i2s->regmap = devm_regmap_init_mmio(dev, regs,
+					    &tegra210_i2s_regmap_config);
+	if (IS_ERR(i2s->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(i2s->regmap);
+	}
+
+	regcache_cache_only(i2s->regmap, true);
+
+	err = devm_snd_soc_register_component(dev, &tegra210_i2s_cmpnt,
+					      tegra210_i2s_dais,
+					      ARRAY_SIZE(tegra210_i2s_dais));
+	if (err) {
+		dev_err(dev, "can't register I2S component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra210_i2s_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra210_i2s_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend,
+			   tegra210_i2s_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_i2s_of_match[] = {
+	{ .compatible = "nvidia,tegra210-i2s" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match);
+
+static struct platform_driver tegra210_i2s_driver = {
+	.driver = {
+		.name = "tegra210-i2s",
+		.of_match_table = tegra210_i2s_of_match,
+		.pm = &tegra210_i2s_pm_ops,
+	},
+	.probe = tegra210_i2s_probe,
+	.remove = tegra210_i2s_remove,
+};
+module_platform_driver(tegra210_i2s_driver)
+
+MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 ASoC I2S driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_i2s.h b/sound/soc/tegra/tegra210_i2s.h
new file mode 100644
index 0000000..030d70c
--- /dev/null
+++ b/sound/soc/tegra/tegra210_i2s.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_i2s.h - Definitions for Tegra210 I2S driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_I2S_H__
+#define __TEGRA210_I2S_H__
+
+/* Register offsets from I2S*_BASE */
+#define TEGRA210_I2S_RX_ENABLE			0x0
+#define TEGRA210_I2S_RX_SOFT_RESET		0x4
+#define TEGRA210_I2S_RX_STATUS			0x0c
+#define TEGRA210_I2S_RX_INT_STATUS		0x10
+#define TEGRA210_I2S_RX_INT_MASK		0x14
+#define TEGRA210_I2S_RX_INT_SET			0x18
+#define TEGRA210_I2S_RX_INT_CLEAR		0x1c
+#define TEGRA210_I2S_RX_CIF_CTRL		0x20
+#define TEGRA210_I2S_RX_CTRL			0x24
+#define TEGRA210_I2S_RX_SLOT_CTRL		0x28
+#define TEGRA210_I2S_RX_CLK_TRIM		0x2c
+#define TEGRA210_I2S_RX_CYA			0x30
+#define TEGRA210_I2S_RX_CIF_FIFO_STATUS		0x34
+#define TEGRA210_I2S_TX_ENABLE			0x40
+#define TEGRA210_I2S_TX_SOFT_RESET		0x44
+#define TEGRA210_I2S_TX_STATUS			0x4c
+#define TEGRA210_I2S_TX_INT_STATUS		0x50
+#define TEGRA210_I2S_TX_INT_MASK		0x54
+#define TEGRA210_I2S_TX_INT_SET			0x58
+#define TEGRA210_I2S_TX_INT_CLEAR		0x5c
+#define TEGRA210_I2S_TX_CIF_CTRL		0x60
+#define TEGRA210_I2S_TX_CTRL			0x64
+#define TEGRA210_I2S_TX_SLOT_CTRL		0x68
+#define TEGRA210_I2S_TX_CLK_TRIM		0x6c
+#define TEGRA210_I2S_TX_CYA			0x70
+#define TEGRA210_I2S_TX_CIF_FIFO_STATUS		0x74
+#define TEGRA210_I2S_ENABLE			0x80
+#define TEGRA210_I2S_SOFT_RESET			0x84
+#define TEGRA210_I2S_CG				0x88
+#define TEGRA210_I2S_STATUS			0x8c
+#define TEGRA210_I2S_INT_STATUS			0x90
+#define TEGRA210_I2S_CTRL			0xa0
+#define TEGRA210_I2S_TIMING			0xa4
+#define TEGRA210_I2S_SLOT_CTRL			0xa8
+#define TEGRA210_I2S_CLK_TRIM			0xac
+#define TEGRA210_I2S_CYA			0xb0
+
+/* Bit fields, shifts and masks */
+#define I2S_DATA_SHIFT				8
+#define I2S_CTRL_DATA_OFFSET_MASK		(0x7ff << I2S_DATA_SHIFT)
+
+#define I2S_EN_SHIFT				0
+#define I2S_EN_MASK				BIT(I2S_EN_SHIFT)
+#define I2S_EN					BIT(I2S_EN_SHIFT)
+
+#define I2S_FSYNC_WIDTH_SHIFT			24
+#define I2S_CTRL_FSYNC_WIDTH_MASK		(0xff << I2S_FSYNC_WIDTH_SHIFT)
+
+#define I2S_POS_EDGE				0
+#define I2S_NEG_EDGE				1
+#define I2S_EDGE_SHIFT				20
+#define I2S_CTRL_EDGE_CTRL_MASK			BIT(I2S_EDGE_SHIFT)
+#define I2S_CTRL_EDGE_CTRL_POS_EDGE		(I2S_POS_EDGE << I2S_EDGE_SHIFT)
+#define I2S_CTRL_EDGE_CTRL_NEG_EDGE		(I2S_NEG_EDGE << I2S_EDGE_SHIFT)
+
+#define I2S_FMT_LRCK				0
+#define I2S_FMT_FSYNC				1
+#define I2S_FMT_SHIFT				12
+#define I2S_CTRL_FRAME_FMT_MASK			(7 << I2S_FMT_SHIFT)
+#define I2S_CTRL_FRAME_FMT_LRCK_MODE		(I2S_FMT_LRCK << I2S_FMT_SHIFT)
+#define I2S_CTRL_FRAME_FMT_FSYNC_MODE		(I2S_FMT_FSYNC << I2S_FMT_SHIFT)
+
+#define I2S_CTRL_MASTER_EN_SHIFT		10
+#define I2S_CTRL_MASTER_EN_MASK			BIT(I2S_CTRL_MASTER_EN_SHIFT)
+#define I2S_CTRL_MASTER_EN			BIT(I2S_CTRL_MASTER_EN_SHIFT)
+
+#define I2S_CTRL_LRCK_POL_SHIFT			9
+#define I2S_CTRL_LRCK_POL_MASK			BIT(I2S_CTRL_LRCK_POL_SHIFT)
+#define I2S_CTRL_LRCK_POL_LOW			(0 << I2S_CTRL_LRCK_POL_SHIFT)
+#define I2S_CTRL_LRCK_POL_HIGH			BIT(I2S_CTRL_LRCK_POL_SHIFT)
+
+#define I2S_CTRL_LPBK_SHIFT			8
+#define I2S_CTRL_LPBK_MASK			BIT(I2S_CTRL_LPBK_SHIFT)
+#define I2S_CTRL_LPBK_EN			BIT(I2S_CTRL_LPBK_SHIFT)
+
+#define I2S_BITS_8				1
+#define I2S_BITS_16				3
+#define I2S_BITS_32				7
+#define I2S_CTRL_BIT_SIZE_MASK			0x7
+
+#define I2S_TIMING_CH_BIT_CNT_MASK		0x7ff
+#define I2S_TIMING_CH_BIT_CNT_SHIFT		0
+
+#define I2S_SOFT_RESET_SHIFT			0
+#define I2S_SOFT_RESET_MASK			BIT(I2S_SOFT_RESET_SHIFT)
+#define I2S_SOFT_RESET_EN			BIT(I2S_SOFT_RESET_SHIFT)
+
+#define I2S_RX_FIFO_DEPTH			64
+#define DEFAULT_I2S_RX_FIFO_THRESHOLD		3
+
+#define DEFAULT_I2S_SLOT_MASK			0xffff
+
+enum tegra210_i2s_path {
+	I2S_RX_PATH,
+	I2S_TX_PATH,
+	I2S_PATHS,
+};
+
+struct tegra210_i2s {
+	struct clk *clk_i2s;
+	struct clk *clk_sync_input;
+	struct regmap *regmap;
+	unsigned int stereo_to_mono[I2S_PATHS];
+	unsigned int mono_to_stereo[I2S_PATHS];
+	unsigned int dai_fmt;
+	unsigned int fsync_width;
+	unsigned int bclk_ratio;
+	unsigned int tx_mask;
+	unsigned int rx_mask;
+	unsigned int rx_fifo_th;
+	bool loopback;
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 05/23] ASoC: tegra: Add Tegra210 based AHUB driver
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

The Audio Hub (AHUB) comprises a collection of hardware accelerators for
audio pre/post-processing and a programmable full crossbar (XBAR) for
routing audio data across these accelerators in time and in parallel.
AHUB supports multiple interfaces to I2S, DSPK, DMIC etc., XBAR is a
switch used to configure or modify audio routing between HW accelerators
present inside AHUB.

This patch registers AHUB component with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes AHUB interfaces, which can be used to connect different
components in the ASoC layer. Currently the driver takes care of XBAR
programming to allow audio data flow through various clients of the AHUB.
Makefile and Kconfig support is added to allow to build the driver. The
AHUB component can be enabled in the DT via below compatible bindings.
  - "nvidia,tegra210-ahub" for Tegra210
  - "nvidia,tegra186-ahub" for Tegra186 and Tegra194

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/tegra/Kconfig         |  10 +
 sound/soc/tegra/Makefile        |   2 +
 sound/soc/tegra/tegra210_ahub.c | 578 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_ahub.h | 100 +++++++
 4 files changed, 690 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_ahub.c
 create mode 100644 sound/soc/tegra/tegra210_ahub.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 157fa7a..3166d03 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -62,6 +62,16 @@ config SND_SOC_TEGRA30_I2S
 	  Tegra30 I2S interface. You will also need to select the individual
 	  machine drivers to support below.
 
+config SND_SOC_TEGRA210_AHUB
+	tristate "Tegra210 AHUB module"
+	depends on SND_SOC_TEGRA
+	help
+	  Config to enable Audio Hub (AHUB) module, which comprises of a
+	  switch called Audio Crossbar (AXBAR) used to configure or modify
+	  the audio routing path between various HW accelerators present in
+	  AHUB.
+	  Say Y or M if you want to add support for Tegra210 AHUB module.
+
 config SND_SOC_TEGRA210_DMIC
         tristate "Tegra210 DMIC module"
         depends on SND_SOC_TEGRA
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index e30f6a3..b01d88e 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -8,6 +8,7 @@ snd-soc-tegra20-i2s-objs := tegra20_i2s.o
 snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 snd-soc-tegra30-ahub-objs := tegra30_ahub.o
 snd-soc-tegra30-i2s-objs := tegra30_i2s.o
+snd-soc-tegra210-ahub-objs := tegra210_ahub.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 snd-soc-tegra210-i2s-objs := tegra210_i2s.o
 
@@ -20,6 +21,7 @@ obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
+obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
 
 # Tegra machine Support
diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
new file mode 100644
index 0000000..93bd23f
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_ahub.c - Tegra210 AHUB driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "tegra210_ahub.h"
+
+static int tegra_ahub_get_value_enum(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
+	struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
+	struct soc_enum *e = (struct soc_enum *)kctl->private_value;
+	unsigned int reg, i, bit_pos = 0;
+
+	/*
+	 * Find the bit position of current MUX input.
+	 * If nothing is set, position would be 0 and it corresponds to 'None'.
+	 */
+	for (i = 0; i < ahub->soc_data->reg_count; i++) {
+		unsigned int reg_val;
+
+		reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
+		reg_val = snd_soc_component_read(cmpnt, reg);
+		reg_val &= ahub->soc_data->mask[i];
+
+		if (reg_val) {
+			bit_pos = ffs(reg_val) +
+				  (8 * cmpnt->val_bytes * i);
+			break;
+		}
+	}
+
+	/* Find index related to the item in array *_ahub_mux_texts[] */
+	for (i = 0; i < e->items; i++) {
+		if (bit_pos == e->values[i]) {
+			uctl->value.enumerated.item[0] = i;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
+	struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctl);
+	struct soc_enum *e = (struct soc_enum *)kctl->private_value;
+	struct snd_soc_dapm_update update[TEGRA_XBAR_UPDATE_MAX_REG] = { };
+	unsigned int *item = uctl->value.enumerated.item;
+	unsigned int value = e->values[item[0]];
+	unsigned int i, bit_pos, reg_idx = 0, reg_val = 0;
+
+	if (item[0] >= e->items)
+		return -EINVAL;
+
+	if (value) {
+		/* Get the register index and value to set */
+		reg_idx = (value - 1) / (8 * cmpnt->val_bytes);
+		bit_pos = (value - 1) % (8 * cmpnt->val_bytes);
+		reg_val = BIT(bit_pos);
+	}
+
+	/*
+	 * Run through all parts of a MUX register to find the state changes.
+	 * There will be an additional update if new MUX input value is from
+	 * different part of the MUX register.
+	 */
+	for (i = 0; i < ahub->soc_data->reg_count; i++) {
+		update[i].reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
+		update[i].val = (i == reg_idx) ? reg_val : 0;
+		update[i].mask = ahub->soc_data->mask[i];
+		update[i].kcontrol = kctl;
+
+		/* Update widget power if state has changed */
+		if (snd_soc_component_test_bits(cmpnt, update[i].reg,
+						update[i].mask, update[i].val))
+			snd_soc_dapm_mux_update_power(dapm, kctl, item[0], e,
+						      &update[i]);
+	}
+
+	return 0;
+}
+
+static const char * const tegra210_ahub_mux_texts[] = {
+	"None",
+	"ADMAIF1",
+	"ADMAIF2",
+	"ADMAIF3",
+	"ADMAIF4",
+	"ADMAIF5",
+	"ADMAIF6",
+	"ADMAIF7",
+	"ADMAIF8",
+	"ADMAIF9",
+	"ADMAIF10",
+	"I2S1",
+	"I2S2",
+	"I2S3",
+	"I2S4",
+	"I2S5",
+	"DMIC1",
+	"DMIC2",
+	"DMIC3",
+};
+
+static const char * const tegra186_ahub_mux_texts[] = {
+	"None",
+	"ADMAIF1",
+	"ADMAIF2",
+	"ADMAIF3",
+	"ADMAIF4",
+	"ADMAIF5",
+	"ADMAIF6",
+	"ADMAIF7",
+	"ADMAIF8",
+	"ADMAIF9",
+	"ADMAIF10",
+	"ADMAIF11",
+	"ADMAIF12",
+	"ADMAIF13",
+	"ADMAIF14",
+	"ADMAIF15",
+	"ADMAIF16",
+	"I2S1",
+	"I2S2",
+	"I2S3",
+	"I2S4",
+	"I2S5",
+	"I2S6",
+	"ADMAIF17",
+	"ADMAIF18",
+	"ADMAIF19",
+	"ADMAIF20",
+	"DMIC1",
+	"DMIC2",
+	"DMIC3",
+	"DMIC4",
+};
+
+static const unsigned int tegra210_ahub_mux_values[] = {
+	0,
+	MUX_VALUE(0, 0),
+	MUX_VALUE(0, 1),
+	MUX_VALUE(0, 2),
+	MUX_VALUE(0, 3),
+	MUX_VALUE(0, 4),
+	MUX_VALUE(0, 5),
+	MUX_VALUE(0, 6),
+	MUX_VALUE(0, 7),
+	MUX_VALUE(0, 8),
+	MUX_VALUE(0, 9),
+	MUX_VALUE(0, 16),
+	MUX_VALUE(0, 17),
+	MUX_VALUE(0, 18),
+	MUX_VALUE(0, 19),
+	MUX_VALUE(0, 20),
+	MUX_VALUE(2, 18),
+	MUX_VALUE(2, 19),
+	MUX_VALUE(2, 20),
+};
+
+static const unsigned int tegra186_ahub_mux_values[] = {
+	0,
+	MUX_VALUE(0, 0),
+	MUX_VALUE(0, 1),
+	MUX_VALUE(0, 2),
+	MUX_VALUE(0, 3),
+	MUX_VALUE(0, 4),
+	MUX_VALUE(0, 5),
+	MUX_VALUE(0, 6),
+	MUX_VALUE(0, 7),
+	MUX_VALUE(0, 8),
+	MUX_VALUE(0, 9),
+	MUX_VALUE(0, 10),
+	MUX_VALUE(0, 11),
+	MUX_VALUE(0, 12),
+	MUX_VALUE(0, 13),
+	MUX_VALUE(0, 14),
+	MUX_VALUE(0, 15),
+	MUX_VALUE(0, 16),
+	MUX_VALUE(0, 17),
+	MUX_VALUE(0, 18),
+	MUX_VALUE(0, 19),
+	MUX_VALUE(0, 20),
+	MUX_VALUE(0, 21),
+	MUX_VALUE(3, 16),
+	MUX_VALUE(3, 17),
+	MUX_VALUE(3, 18),
+	MUX_VALUE(3, 19),
+	MUX_VALUE(2, 18),
+	MUX_VALUE(2, 19),
+	MUX_VALUE(2, 20),
+	MUX_VALUE(2, 21),
+};
+
+/* Controls for t210 */
+MUX_ENUM_CTRL_DECL(t210_admaif1_tx, 0x00);
+MUX_ENUM_CTRL_DECL(t210_admaif2_tx, 0x01);
+MUX_ENUM_CTRL_DECL(t210_admaif3_tx, 0x02);
+MUX_ENUM_CTRL_DECL(t210_admaif4_tx, 0x03);
+MUX_ENUM_CTRL_DECL(t210_admaif5_tx, 0x04);
+MUX_ENUM_CTRL_DECL(t210_admaif6_tx, 0x05);
+MUX_ENUM_CTRL_DECL(t210_admaif7_tx, 0x06);
+MUX_ENUM_CTRL_DECL(t210_admaif8_tx, 0x07);
+MUX_ENUM_CTRL_DECL(t210_admaif9_tx, 0x08);
+MUX_ENUM_CTRL_DECL(t210_admaif10_tx, 0x09);
+MUX_ENUM_CTRL_DECL(t210_i2s1_tx, 0x10);
+MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11);
+MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12);
+MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13);
+MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14);
+
+/* Controls for t186 */
+MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
+MUX_ENUM_CTRL_DECL_186(t186_admaif2_tx, 0x01);
+MUX_ENUM_CTRL_DECL_186(t186_admaif3_tx, 0x02);
+MUX_ENUM_CTRL_DECL_186(t186_admaif4_tx, 0x03);
+MUX_ENUM_CTRL_DECL_186(t186_admaif5_tx, 0x04);
+MUX_ENUM_CTRL_DECL_186(t186_admaif6_tx, 0x05);
+MUX_ENUM_CTRL_DECL_186(t186_admaif7_tx, 0x06);
+MUX_ENUM_CTRL_DECL_186(t186_admaif8_tx, 0x07);
+MUX_ENUM_CTRL_DECL_186(t186_admaif9_tx, 0x08);
+MUX_ENUM_CTRL_DECL_186(t186_admaif10_tx, 0x09);
+MUX_ENUM_CTRL_DECL_186(t186_i2s1_tx, 0x10);
+MUX_ENUM_CTRL_DECL_186(t186_i2s2_tx, 0x11);
+MUX_ENUM_CTRL_DECL_186(t186_i2s3_tx, 0x12);
+MUX_ENUM_CTRL_DECL_186(t186_i2s4_tx, 0x13);
+MUX_ENUM_CTRL_DECL_186(t186_i2s5_tx, 0x14);
+MUX_ENUM_CTRL_DECL_186(t186_admaif11_tx, 0x0a);
+MUX_ENUM_CTRL_DECL_186(t186_admaif12_tx, 0x0b);
+MUX_ENUM_CTRL_DECL_186(t186_admaif13_tx, 0x0c);
+MUX_ENUM_CTRL_DECL_186(t186_admaif14_tx, 0x0d);
+MUX_ENUM_CTRL_DECL_186(t186_admaif15_tx, 0x0e);
+MUX_ENUM_CTRL_DECL_186(t186_admaif16_tx, 0x0f);
+MUX_ENUM_CTRL_DECL_186(t186_i2s6_tx, 0x15);
+MUX_ENUM_CTRL_DECL_186(t186_dspk1_tx, 0x30);
+MUX_ENUM_CTRL_DECL_186(t186_dspk2_tx, 0x31);
+MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68);
+MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69);
+MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a);
+MUX_ENUM_CTRL_DECL_186(t186_admaif20_tx, 0x6b);
+
+/*
+ * The number of entries in, and order of, this array is closely tied to the
+ * calculation of tegra210_ahub_codec.num_dapm_widgets near the end of
+ * tegra210_ahub_probe()
+ */
+static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
+	WIDGETS("ADMAIF1", t210_admaif1_tx),
+	WIDGETS("ADMAIF2", t210_admaif2_tx),
+	WIDGETS("ADMAIF3", t210_admaif3_tx),
+	WIDGETS("ADMAIF4", t210_admaif4_tx),
+	WIDGETS("ADMAIF5", t210_admaif5_tx),
+	WIDGETS("ADMAIF6", t210_admaif6_tx),
+	WIDGETS("ADMAIF7", t210_admaif7_tx),
+	WIDGETS("ADMAIF8", t210_admaif8_tx),
+	WIDGETS("ADMAIF9", t210_admaif9_tx),
+	WIDGETS("ADMAIF10", t210_admaif10_tx),
+	WIDGETS("I2S1", t210_i2s1_tx),
+	WIDGETS("I2S2", t210_i2s2_tx),
+	WIDGETS("I2S3", t210_i2s3_tx),
+	WIDGETS("I2S4", t210_i2s4_tx),
+	WIDGETS("I2S5", t210_i2s5_tx),
+	TX_WIDGETS("DMIC1"),
+	TX_WIDGETS("DMIC2"),
+	TX_WIDGETS("DMIC3"),
+};
+
+static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
+	WIDGETS("ADMAIF1", t186_admaif1_tx),
+	WIDGETS("ADMAIF2", t186_admaif2_tx),
+	WIDGETS("ADMAIF3", t186_admaif3_tx),
+	WIDGETS("ADMAIF4", t186_admaif4_tx),
+	WIDGETS("ADMAIF5", t186_admaif5_tx),
+	WIDGETS("ADMAIF6", t186_admaif6_tx),
+	WIDGETS("ADMAIF7", t186_admaif7_tx),
+	WIDGETS("ADMAIF8", t186_admaif8_tx),
+	WIDGETS("ADMAIF9", t186_admaif9_tx),
+	WIDGETS("ADMAIF10", t186_admaif10_tx),
+	WIDGETS("ADMAIF11", t186_admaif11_tx),
+	WIDGETS("ADMAIF12", t186_admaif12_tx),
+	WIDGETS("ADMAIF13", t186_admaif13_tx),
+	WIDGETS("ADMAIF14", t186_admaif14_tx),
+	WIDGETS("ADMAIF15", t186_admaif15_tx),
+	WIDGETS("ADMAIF16", t186_admaif16_tx),
+	WIDGETS("ADMAIF17", t186_admaif17_tx),
+	WIDGETS("ADMAIF18", t186_admaif18_tx),
+	WIDGETS("ADMAIF19", t186_admaif19_tx),
+	WIDGETS("ADMAIF20", t186_admaif20_tx),
+	WIDGETS("I2S1", t186_i2s1_tx),
+	WIDGETS("I2S2", t186_i2s2_tx),
+	WIDGETS("I2S3", t186_i2s3_tx),
+	WIDGETS("I2S4", t186_i2s4_tx),
+	WIDGETS("I2S5", t186_i2s5_tx),
+	WIDGETS("I2S6", t186_i2s6_tx),
+	TX_WIDGETS("DMIC1"),
+	TX_WIDGETS("DMIC2"),
+	TX_WIDGETS("DMIC3"),
+	TX_WIDGETS("DMIC4"),
+	WIDGETS("DSPK1", t186_dspk1_tx),
+	WIDGETS("DSPK2", t186_dspk2_tx),
+};
+
+#define TEGRA_COMMON_ROUTES(name)					\
+	{ name " XBAR-TX",	NULL,		name " Mux" },		\
+	{ name " Mux",		"ADMAIF1",	"ADMAIF1 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF2",	"ADMAIF2 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF3",	"ADMAIF3 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF4",	"ADMAIF4 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF5",	"ADMAIF5 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF6",	"ADMAIF6 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF7",	"ADMAIF7 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF8",	"ADMAIF8 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF9",	"ADMAIF9 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF10",	"ADMAIF10 XBAR-RX" },	\
+	{ name " Mux",		"I2S1",		"I2S1 XBAR-RX" },	\
+	{ name " Mux",		"I2S2",		"I2S2 XBAR-RX" },	\
+	{ name " Mux",		"I2S3",		"I2S3 XBAR-RX" },	\
+	{ name " Mux",		"I2S4",		"I2S4 XBAR-RX" },	\
+	{ name " Mux",		"I2S5",		"I2S5 XBAR-RX" },	\
+	{ name " Mux",		"DMIC1",	"DMIC1 XBAR-RX" },	\
+	{ name " Mux",		"DMIC2",	"DMIC2 XBAR-RX" },	\
+	{ name " Mux",		"DMIC3",	"DMIC3 XBAR-RX" },
+
+#define TEGRA186_ONLY_ROUTES(name)					\
+	{ name " Mux",		"ADMAIF11",	"ADMAIF11 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF12",	"ADMAIF12 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF13",	"ADMAIF13 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF14",	"ADMAIF14 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF15",	"ADMAIF15 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF16",	"ADMAIF16 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF17",	"ADMAIF17 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF18",	"ADMAIF18 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF19",	"ADMAIF19 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF20",	"ADMAIF20 XBAR-RX" },	\
+	{ name " Mux",		"I2S6",		"I2S6 XBAR-RX" },	\
+	{ name " Mux",		"DMIC4",	"DMIC4 XBAR-RX" },
+
+#define TEGRA210_ROUTES(name)						\
+	TEGRA_COMMON_ROUTES(name)
+
+#define TEGRA186_ROUTES(name)						\
+	TEGRA_COMMON_ROUTES(name)					\
+	TEGRA186_ONLY_ROUTES(name)
+
+/*
+ * The number of entries in, and order of, this array is closely tied to the
+ * calculation of tegra210_ahub_codec.num_dapm_routes near the end of
+ * tegra210_ahub_probe()
+ */
+static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
+	TEGRA210_ROUTES("ADMAIF1")
+	TEGRA210_ROUTES("ADMAIF2")
+	TEGRA210_ROUTES("ADMAIF3")
+	TEGRA210_ROUTES("ADMAIF4")
+	TEGRA210_ROUTES("ADMAIF5")
+	TEGRA210_ROUTES("ADMAIF6")
+	TEGRA210_ROUTES("ADMAIF7")
+	TEGRA210_ROUTES("ADMAIF8")
+	TEGRA210_ROUTES("ADMAIF9")
+	TEGRA210_ROUTES("ADMAIF10")
+	TEGRA210_ROUTES("I2S1")
+	TEGRA210_ROUTES("I2S2")
+	TEGRA210_ROUTES("I2S3")
+	TEGRA210_ROUTES("I2S4")
+	TEGRA210_ROUTES("I2S5")
+};
+
+static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
+	TEGRA186_ROUTES("ADMAIF1")
+	TEGRA186_ROUTES("ADMAIF2")
+	TEGRA186_ROUTES("ADMAIF3")
+	TEGRA186_ROUTES("ADMAIF4")
+	TEGRA186_ROUTES("ADMAIF5")
+	TEGRA186_ROUTES("ADMAIF6")
+	TEGRA186_ROUTES("ADMAIF7")
+	TEGRA186_ROUTES("ADMAIF8")
+	TEGRA186_ROUTES("ADMAIF9")
+	TEGRA186_ROUTES("ADMAIF10")
+	TEGRA186_ROUTES("ADMAIF11")
+	TEGRA186_ROUTES("ADMAIF12")
+	TEGRA186_ROUTES("ADMAIF13")
+	TEGRA186_ROUTES("ADMAIF14")
+	TEGRA186_ROUTES("ADMAIF15")
+	TEGRA186_ROUTES("ADMAIF16")
+	TEGRA186_ROUTES("ADMAIF17")
+	TEGRA186_ROUTES("ADMAIF18")
+	TEGRA186_ROUTES("ADMAIF19")
+	TEGRA186_ROUTES("ADMAIF20")
+	TEGRA186_ROUTES("I2S1")
+	TEGRA186_ROUTES("I2S2")
+	TEGRA186_ROUTES("I2S3")
+	TEGRA186_ROUTES("I2S4")
+	TEGRA186_ROUTES("I2S5")
+	TEGRA186_ROUTES("I2S6")
+	TEGRA186_ROUTES("DSPK1")
+	TEGRA186_ROUTES("DSPK2")
+};
+
+static const struct snd_soc_component_driver tegra210_ahub_component = {
+	.dapm_widgets		= tegra210_ahub_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tegra210_ahub_widgets),
+	.dapm_routes		= tegra210_ahub_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tegra210_ahub_routes),
+};
+
+static const struct snd_soc_component_driver tegra186_ahub_component = {
+	.dapm_widgets = tegra186_ahub_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra186_ahub_widgets),
+	.dapm_routes = tegra186_ahub_routes,
+	.num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes),
+};
+
+static const struct regmap_config tegra210_ahub_regmap_config = {
+	.reg_bits		= 32,
+	.val_bits		= 32,
+	.reg_stride		= 4,
+	.max_register		= TEGRA210_MAX_REGISTER_ADDR,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct regmap_config tegra186_ahub_regmap_config = {
+	.reg_bits		= 32,
+	.val_bits		= 32,
+	.reg_stride		= 4,
+	.max_register		= TEGRA186_MAX_REGISTER_ADDR,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct tegra_ahub_soc_data soc_data_tegra210 = {
+	.cmpnt_drv	= &tegra210_ahub_component,
+	.regmap_config	= &tegra210_ahub_regmap_config,
+	.mask[0]	= TEGRA210_XBAR_REG_MASK_0,
+	.mask[1]	= TEGRA210_XBAR_REG_MASK_1,
+	.mask[2]	= TEGRA210_XBAR_REG_MASK_2,
+	.mask[3]	= TEGRA210_XBAR_REG_MASK_3,
+	.reg_count	= TEGRA210_XBAR_UPDATE_MAX_REG,
+};
+
+static const struct tegra_ahub_soc_data soc_data_tegra186 = {
+	.cmpnt_drv	= &tegra186_ahub_component,
+	.regmap_config	= &tegra186_ahub_regmap_config,
+	.mask[0]	= TEGRA186_XBAR_REG_MASK_0,
+	.mask[1]	= TEGRA186_XBAR_REG_MASK_1,
+	.mask[2]	= TEGRA186_XBAR_REG_MASK_2,
+	.mask[3]	= TEGRA186_XBAR_REG_MASK_3,
+	.reg_count	= TEGRA186_XBAR_UPDATE_MAX_REG,
+};
+
+static const struct of_device_id tegra_ahub_of_match[] = {
+	{ .compatible = "nvidia,tegra210-ahub", .data = &soc_data_tegra210 },
+	{ .compatible = "nvidia,tegra186-ahub", .data = &soc_data_tegra186 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra_ahub_of_match);
+
+static int tegra_ahub_runtime_suspend(struct device *dev)
+{
+	struct tegra_ahub *ahub = dev_get_drvdata(dev);
+
+	regcache_cache_only(ahub->regmap, true);
+	regcache_mark_dirty(ahub->regmap);
+
+	clk_disable_unprepare(ahub->clk);
+
+	return 0;
+}
+
+static int tegra_ahub_runtime_resume(struct device *dev)
+{
+	struct tegra_ahub *ahub = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(ahub->clk);
+	if (err) {
+		dev_err(dev, "failed to enable AHUB clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(ahub->regmap, false);
+	regcache_sync(ahub->regmap);
+
+	return 0;
+}
+
+static int tegra_ahub_probe(struct platform_device *pdev)
+{
+	struct tegra_ahub *ahub;
+	void __iomem *regs;
+	int err;
+
+	ahub = devm_kzalloc(&pdev->dev, sizeof(*ahub), GFP_KERNEL);
+	if (!ahub)
+		return -ENOMEM;
+
+	ahub->soc_data = of_device_get_match_data(&pdev->dev);
+
+	platform_set_drvdata(pdev, ahub);
+
+	ahub->clk = devm_clk_get(&pdev->dev, "ahub");
+	if (IS_ERR(ahub->clk)) {
+		dev_err(&pdev->dev, "can't retrieve AHUB clock\n");
+		return PTR_ERR(ahub->clk);
+	}
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ahub->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					     ahub->soc_data->regmap_config);
+	if (IS_ERR(ahub->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(ahub->regmap);
+	}
+
+	regcache_cache_only(ahub->regmap, true);
+
+	err = devm_snd_soc_register_component(&pdev->dev,
+					      ahub->soc_data->cmpnt_drv,
+					      NULL, 0);
+	if (err) {
+		dev_err(&pdev->dev, "can't register AHUB component, err: %d\n",
+			err);
+		return err;
+	}
+
+	err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (err)
+		return err;
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static int tegra_ahub_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra_ahub_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra_ahub_runtime_suspend,
+			   tegra_ahub_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra_ahub_driver = {
+	.probe = tegra_ahub_probe,
+	.remove = tegra_ahub_remove,
+	.driver = {
+		.name = "tegra210-ahub",
+		.of_match_table = tegra_ahub_of_match,
+		.pm = &tegra_ahub_pm_ops,
+	},
+};
+module_platform_driver(tegra_ahub_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
+MODULE_AUTHOR("Mohan Kumar <mkumard-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
+MODULE_DESCRIPTION("Tegra210 ASoC AHUB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_ahub.h b/sound/soc/tegra/tegra210_ahub.h
new file mode 100644
index 0000000..db3c8ce
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ahub.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_ahub.h - TEGRA210 AHUB
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_AHUB__H__
+#define __TEGRA210_AHUB__H__
+
+/* Tegra210 specific */
+#define TEGRA210_XBAR_PART1_RX				0x200
+#define TEGRA210_XBAR_PART2_RX				0x400
+#define TEGRA210_XBAR_RX_STRIDE				0x4
+#define TEGRA210_XBAR_AUDIO_RX_COUNT			90
+#define TEGRA210_XBAR_REG_MASK_0			0xf1f03ff
+#define TEGRA210_XBAR_REG_MASK_1			0x3f30031f
+#define TEGRA210_XBAR_REG_MASK_2			0xff1cf313
+#define TEGRA210_XBAR_REG_MASK_3			0x0
+#define TEGRA210_XBAR_UPDATE_MAX_REG			3
+/* Tegra186 specific */
+#define TEGRA186_XBAR_PART3_RX				0x600
+#define TEGRA186_XBAR_AUDIO_RX_COUNT			115
+#define TEGRA186_XBAR_REG_MASK_0			0xf3fffff
+#define TEGRA186_XBAR_REG_MASK_1			0x3f310f1f
+#define TEGRA186_XBAR_REG_MASK_2			0xff3cf311
+#define TEGRA186_XBAR_REG_MASK_3			0x3f0f00ff
+#define TEGRA186_XBAR_UPDATE_MAX_REG			4
+
+#define TEGRA_XBAR_UPDATE_MAX_REG (TEGRA186_XBAR_UPDATE_MAX_REG)
+
+#define TEGRA186_MAX_REGISTER_ADDR (TEGRA186_XBAR_PART3_RX +		\
+	(TEGRA210_XBAR_RX_STRIDE * (TEGRA186_XBAR_AUDIO_RX_COUNT - 1)))
+
+#define TEGRA210_MAX_REGISTER_ADDR (TEGRA210_XBAR_PART2_RX +		\
+	(TEGRA210_XBAR_RX_STRIDE * (TEGRA210_XBAR_AUDIO_RX_COUNT - 1)))
+
+#define MUX_REG(id) (TEGRA210_XBAR_RX_STRIDE * (id))
+
+#define MUX_VALUE(npart, nbit) (1 + (nbit) + (npart) * 32)
+
+#define SOC_VALUE_ENUM_WIDE(xreg, shift, xmax, xtexts, xvalues)		\
+	{								\
+		.reg = xreg,						\
+		.shift_l = shift,					\
+		.shift_r = shift,					\
+		.items = xmax,						\
+		.texts = xtexts,					\
+		.values = xvalues,					\
+		.mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0		\
+	}
+
+#define SOC_VALUE_ENUM_WIDE_DECL(name, xreg, shift, xtexts, xvalues)	\
+	static struct soc_enum name =					\
+		SOC_VALUE_ENUM_WIDE(xreg, shift, ARRAY_SIZE(xtexts),	\
+				    xtexts, xvalues)
+
+#define MUX_ENUM_CTRL_DECL(ename, id)					\
+	SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0,		\
+				 tegra210_ahub_mux_texts,		\
+				 tegra210_ahub_mux_values);		\
+	static const struct snd_kcontrol_new ename##_control =		\
+		SOC_DAPM_ENUM_EXT("Route", ename##_enum,		\
+				  tegra_ahub_get_value_enum,		\
+				  tegra_ahub_put_value_enum)
+
+#define MUX_ENUM_CTRL_DECL_186(ename, id)				\
+	SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0,		\
+				 tegra186_ahub_mux_texts,		\
+				 tegra186_ahub_mux_values);		\
+	static const struct snd_kcontrol_new ename##_control =		\
+		SOC_DAPM_ENUM_EXT("Route", ename##_enum,		\
+				  tegra_ahub_get_value_enum,		\
+				  tegra_ahub_put_value_enum)
+
+#define WIDGETS(sname, ename)						     \
+	SND_SOC_DAPM_AIF_IN(sname " XBAR-RX", NULL, 0, SND_SOC_NOPM, 0, 0),  \
+	SND_SOC_DAPM_AIF_OUT(sname " XBAR-TX", NULL, 0, SND_SOC_NOPM, 0, 0), \
+	SND_SOC_DAPM_MUX(sname " Mux", SND_SOC_NOPM, 0, 0,		     \
+			 &ename##_control)
+
+#define TX_WIDGETS(sname)						    \
+	SND_SOC_DAPM_AIF_IN(sname " XBAR-RX", NULL, 0, SND_SOC_NOPM, 0, 0), \
+	SND_SOC_DAPM_AIF_OUT(sname " XBAR-TX", NULL, 0, SND_SOC_NOPM, 0, 0)
+
+struct tegra_ahub_soc_data {
+	const struct regmap_config *regmap_config;
+	const struct snd_soc_component_driver *cmpnt_drv;
+	unsigned int mask[4];
+	unsigned int reg_count;
+};
+
+struct tegra_ahub {
+	const struct tegra_ahub_soc_data *soc_data;
+	struct regmap *regmap;
+	struct clk *clk;
+};
+
+#endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 05/23] ASoC: tegra: Add Tegra210 based AHUB driver
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

The Audio Hub (AHUB) comprises a collection of hardware accelerators for
audio pre/post-processing and a programmable full crossbar (XBAR) for
routing audio data across these accelerators in time and in parallel.
AHUB supports multiple interfaces to I2S, DSPK, DMIC etc., XBAR is a
switch used to configure or modify audio routing between HW accelerators
present inside AHUB.

This patch registers AHUB component with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes AHUB interfaces, which can be used to connect different
components in the ASoC layer. Currently the driver takes care of XBAR
programming to allow audio data flow through various clients of the AHUB.
Makefile and Kconfig support is added to allow to build the driver. The
AHUB component can be enabled in the DT via below compatible bindings.
  - "nvidia,tegra210-ahub" for Tegra210
  - "nvidia,tegra186-ahub" for Tegra186 and Tegra194

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig         |  10 +
 sound/soc/tegra/Makefile        |   2 +
 sound/soc/tegra/tegra210_ahub.c | 578 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_ahub.h | 100 +++++++
 4 files changed, 690 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_ahub.c
 create mode 100644 sound/soc/tegra/tegra210_ahub.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 157fa7a..3166d03 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -62,6 +62,16 @@ config SND_SOC_TEGRA30_I2S
 	  Tegra30 I2S interface. You will also need to select the individual
 	  machine drivers to support below.
 
+config SND_SOC_TEGRA210_AHUB
+	tristate "Tegra210 AHUB module"
+	depends on SND_SOC_TEGRA
+	help
+	  Config to enable Audio Hub (AHUB) module, which comprises of a
+	  switch called Audio Crossbar (AXBAR) used to configure or modify
+	  the audio routing path between various HW accelerators present in
+	  AHUB.
+	  Say Y or M if you want to add support for Tegra210 AHUB module.
+
 config SND_SOC_TEGRA210_DMIC
         tristate "Tegra210 DMIC module"
         depends on SND_SOC_TEGRA
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index e30f6a3..b01d88e 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -8,6 +8,7 @@ snd-soc-tegra20-i2s-objs := tegra20_i2s.o
 snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 snd-soc-tegra30-ahub-objs := tegra30_ahub.o
 snd-soc-tegra30-i2s-objs := tegra30_i2s.o
+snd-soc-tegra210-ahub-objs := tegra210_ahub.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 snd-soc-tegra210-i2s-objs := tegra210_i2s.o
 
@@ -20,6 +21,7 @@ obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
+obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
 
 # Tegra machine Support
diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
new file mode 100644
index 0000000..93bd23f
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_ahub.c - Tegra210 AHUB driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "tegra210_ahub.h"
+
+static int tegra_ahub_get_value_enum(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
+	struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
+	struct soc_enum *e = (struct soc_enum *)kctl->private_value;
+	unsigned int reg, i, bit_pos = 0;
+
+	/*
+	 * Find the bit position of current MUX input.
+	 * If nothing is set, position would be 0 and it corresponds to 'None'.
+	 */
+	for (i = 0; i < ahub->soc_data->reg_count; i++) {
+		unsigned int reg_val;
+
+		reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
+		reg_val = snd_soc_component_read(cmpnt, reg);
+		reg_val &= ahub->soc_data->mask[i];
+
+		if (reg_val) {
+			bit_pos = ffs(reg_val) +
+				  (8 * cmpnt->val_bytes * i);
+			break;
+		}
+	}
+
+	/* Find index related to the item in array *_ahub_mux_texts[] */
+	for (i = 0; i < e->items; i++) {
+		if (bit_pos == e->values[i]) {
+			uctl->value.enumerated.item[0] = i;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
+	struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctl);
+	struct soc_enum *e = (struct soc_enum *)kctl->private_value;
+	struct snd_soc_dapm_update update[TEGRA_XBAR_UPDATE_MAX_REG] = { };
+	unsigned int *item = uctl->value.enumerated.item;
+	unsigned int value = e->values[item[0]];
+	unsigned int i, bit_pos, reg_idx = 0, reg_val = 0;
+
+	if (item[0] >= e->items)
+		return -EINVAL;
+
+	if (value) {
+		/* Get the register index and value to set */
+		reg_idx = (value - 1) / (8 * cmpnt->val_bytes);
+		bit_pos = (value - 1) % (8 * cmpnt->val_bytes);
+		reg_val = BIT(bit_pos);
+	}
+
+	/*
+	 * Run through all parts of a MUX register to find the state changes.
+	 * There will be an additional update if new MUX input value is from
+	 * different part of the MUX register.
+	 */
+	for (i = 0; i < ahub->soc_data->reg_count; i++) {
+		update[i].reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
+		update[i].val = (i == reg_idx) ? reg_val : 0;
+		update[i].mask = ahub->soc_data->mask[i];
+		update[i].kcontrol = kctl;
+
+		/* Update widget power if state has changed */
+		if (snd_soc_component_test_bits(cmpnt, update[i].reg,
+						update[i].mask, update[i].val))
+			snd_soc_dapm_mux_update_power(dapm, kctl, item[0], e,
+						      &update[i]);
+	}
+
+	return 0;
+}
+
+static const char * const tegra210_ahub_mux_texts[] = {
+	"None",
+	"ADMAIF1",
+	"ADMAIF2",
+	"ADMAIF3",
+	"ADMAIF4",
+	"ADMAIF5",
+	"ADMAIF6",
+	"ADMAIF7",
+	"ADMAIF8",
+	"ADMAIF9",
+	"ADMAIF10",
+	"I2S1",
+	"I2S2",
+	"I2S3",
+	"I2S4",
+	"I2S5",
+	"DMIC1",
+	"DMIC2",
+	"DMIC3",
+};
+
+static const char * const tegra186_ahub_mux_texts[] = {
+	"None",
+	"ADMAIF1",
+	"ADMAIF2",
+	"ADMAIF3",
+	"ADMAIF4",
+	"ADMAIF5",
+	"ADMAIF6",
+	"ADMAIF7",
+	"ADMAIF8",
+	"ADMAIF9",
+	"ADMAIF10",
+	"ADMAIF11",
+	"ADMAIF12",
+	"ADMAIF13",
+	"ADMAIF14",
+	"ADMAIF15",
+	"ADMAIF16",
+	"I2S1",
+	"I2S2",
+	"I2S3",
+	"I2S4",
+	"I2S5",
+	"I2S6",
+	"ADMAIF17",
+	"ADMAIF18",
+	"ADMAIF19",
+	"ADMAIF20",
+	"DMIC1",
+	"DMIC2",
+	"DMIC3",
+	"DMIC4",
+};
+
+static const unsigned int tegra210_ahub_mux_values[] = {
+	0,
+	MUX_VALUE(0, 0),
+	MUX_VALUE(0, 1),
+	MUX_VALUE(0, 2),
+	MUX_VALUE(0, 3),
+	MUX_VALUE(0, 4),
+	MUX_VALUE(0, 5),
+	MUX_VALUE(0, 6),
+	MUX_VALUE(0, 7),
+	MUX_VALUE(0, 8),
+	MUX_VALUE(0, 9),
+	MUX_VALUE(0, 16),
+	MUX_VALUE(0, 17),
+	MUX_VALUE(0, 18),
+	MUX_VALUE(0, 19),
+	MUX_VALUE(0, 20),
+	MUX_VALUE(2, 18),
+	MUX_VALUE(2, 19),
+	MUX_VALUE(2, 20),
+};
+
+static const unsigned int tegra186_ahub_mux_values[] = {
+	0,
+	MUX_VALUE(0, 0),
+	MUX_VALUE(0, 1),
+	MUX_VALUE(0, 2),
+	MUX_VALUE(0, 3),
+	MUX_VALUE(0, 4),
+	MUX_VALUE(0, 5),
+	MUX_VALUE(0, 6),
+	MUX_VALUE(0, 7),
+	MUX_VALUE(0, 8),
+	MUX_VALUE(0, 9),
+	MUX_VALUE(0, 10),
+	MUX_VALUE(0, 11),
+	MUX_VALUE(0, 12),
+	MUX_VALUE(0, 13),
+	MUX_VALUE(0, 14),
+	MUX_VALUE(0, 15),
+	MUX_VALUE(0, 16),
+	MUX_VALUE(0, 17),
+	MUX_VALUE(0, 18),
+	MUX_VALUE(0, 19),
+	MUX_VALUE(0, 20),
+	MUX_VALUE(0, 21),
+	MUX_VALUE(3, 16),
+	MUX_VALUE(3, 17),
+	MUX_VALUE(3, 18),
+	MUX_VALUE(3, 19),
+	MUX_VALUE(2, 18),
+	MUX_VALUE(2, 19),
+	MUX_VALUE(2, 20),
+	MUX_VALUE(2, 21),
+};
+
+/* Controls for t210 */
+MUX_ENUM_CTRL_DECL(t210_admaif1_tx, 0x00);
+MUX_ENUM_CTRL_DECL(t210_admaif2_tx, 0x01);
+MUX_ENUM_CTRL_DECL(t210_admaif3_tx, 0x02);
+MUX_ENUM_CTRL_DECL(t210_admaif4_tx, 0x03);
+MUX_ENUM_CTRL_DECL(t210_admaif5_tx, 0x04);
+MUX_ENUM_CTRL_DECL(t210_admaif6_tx, 0x05);
+MUX_ENUM_CTRL_DECL(t210_admaif7_tx, 0x06);
+MUX_ENUM_CTRL_DECL(t210_admaif8_tx, 0x07);
+MUX_ENUM_CTRL_DECL(t210_admaif9_tx, 0x08);
+MUX_ENUM_CTRL_DECL(t210_admaif10_tx, 0x09);
+MUX_ENUM_CTRL_DECL(t210_i2s1_tx, 0x10);
+MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11);
+MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12);
+MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13);
+MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14);
+
+/* Controls for t186 */
+MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
+MUX_ENUM_CTRL_DECL_186(t186_admaif2_tx, 0x01);
+MUX_ENUM_CTRL_DECL_186(t186_admaif3_tx, 0x02);
+MUX_ENUM_CTRL_DECL_186(t186_admaif4_tx, 0x03);
+MUX_ENUM_CTRL_DECL_186(t186_admaif5_tx, 0x04);
+MUX_ENUM_CTRL_DECL_186(t186_admaif6_tx, 0x05);
+MUX_ENUM_CTRL_DECL_186(t186_admaif7_tx, 0x06);
+MUX_ENUM_CTRL_DECL_186(t186_admaif8_tx, 0x07);
+MUX_ENUM_CTRL_DECL_186(t186_admaif9_tx, 0x08);
+MUX_ENUM_CTRL_DECL_186(t186_admaif10_tx, 0x09);
+MUX_ENUM_CTRL_DECL_186(t186_i2s1_tx, 0x10);
+MUX_ENUM_CTRL_DECL_186(t186_i2s2_tx, 0x11);
+MUX_ENUM_CTRL_DECL_186(t186_i2s3_tx, 0x12);
+MUX_ENUM_CTRL_DECL_186(t186_i2s4_tx, 0x13);
+MUX_ENUM_CTRL_DECL_186(t186_i2s5_tx, 0x14);
+MUX_ENUM_CTRL_DECL_186(t186_admaif11_tx, 0x0a);
+MUX_ENUM_CTRL_DECL_186(t186_admaif12_tx, 0x0b);
+MUX_ENUM_CTRL_DECL_186(t186_admaif13_tx, 0x0c);
+MUX_ENUM_CTRL_DECL_186(t186_admaif14_tx, 0x0d);
+MUX_ENUM_CTRL_DECL_186(t186_admaif15_tx, 0x0e);
+MUX_ENUM_CTRL_DECL_186(t186_admaif16_tx, 0x0f);
+MUX_ENUM_CTRL_DECL_186(t186_i2s6_tx, 0x15);
+MUX_ENUM_CTRL_DECL_186(t186_dspk1_tx, 0x30);
+MUX_ENUM_CTRL_DECL_186(t186_dspk2_tx, 0x31);
+MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68);
+MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69);
+MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a);
+MUX_ENUM_CTRL_DECL_186(t186_admaif20_tx, 0x6b);
+
+/*
+ * The number of entries in, and order of, this array is closely tied to the
+ * calculation of tegra210_ahub_codec.num_dapm_widgets near the end of
+ * tegra210_ahub_probe()
+ */
+static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
+	WIDGETS("ADMAIF1", t210_admaif1_tx),
+	WIDGETS("ADMAIF2", t210_admaif2_tx),
+	WIDGETS("ADMAIF3", t210_admaif3_tx),
+	WIDGETS("ADMAIF4", t210_admaif4_tx),
+	WIDGETS("ADMAIF5", t210_admaif5_tx),
+	WIDGETS("ADMAIF6", t210_admaif6_tx),
+	WIDGETS("ADMAIF7", t210_admaif7_tx),
+	WIDGETS("ADMAIF8", t210_admaif8_tx),
+	WIDGETS("ADMAIF9", t210_admaif9_tx),
+	WIDGETS("ADMAIF10", t210_admaif10_tx),
+	WIDGETS("I2S1", t210_i2s1_tx),
+	WIDGETS("I2S2", t210_i2s2_tx),
+	WIDGETS("I2S3", t210_i2s3_tx),
+	WIDGETS("I2S4", t210_i2s4_tx),
+	WIDGETS("I2S5", t210_i2s5_tx),
+	TX_WIDGETS("DMIC1"),
+	TX_WIDGETS("DMIC2"),
+	TX_WIDGETS("DMIC3"),
+};
+
+static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
+	WIDGETS("ADMAIF1", t186_admaif1_tx),
+	WIDGETS("ADMAIF2", t186_admaif2_tx),
+	WIDGETS("ADMAIF3", t186_admaif3_tx),
+	WIDGETS("ADMAIF4", t186_admaif4_tx),
+	WIDGETS("ADMAIF5", t186_admaif5_tx),
+	WIDGETS("ADMAIF6", t186_admaif6_tx),
+	WIDGETS("ADMAIF7", t186_admaif7_tx),
+	WIDGETS("ADMAIF8", t186_admaif8_tx),
+	WIDGETS("ADMAIF9", t186_admaif9_tx),
+	WIDGETS("ADMAIF10", t186_admaif10_tx),
+	WIDGETS("ADMAIF11", t186_admaif11_tx),
+	WIDGETS("ADMAIF12", t186_admaif12_tx),
+	WIDGETS("ADMAIF13", t186_admaif13_tx),
+	WIDGETS("ADMAIF14", t186_admaif14_tx),
+	WIDGETS("ADMAIF15", t186_admaif15_tx),
+	WIDGETS("ADMAIF16", t186_admaif16_tx),
+	WIDGETS("ADMAIF17", t186_admaif17_tx),
+	WIDGETS("ADMAIF18", t186_admaif18_tx),
+	WIDGETS("ADMAIF19", t186_admaif19_tx),
+	WIDGETS("ADMAIF20", t186_admaif20_tx),
+	WIDGETS("I2S1", t186_i2s1_tx),
+	WIDGETS("I2S2", t186_i2s2_tx),
+	WIDGETS("I2S3", t186_i2s3_tx),
+	WIDGETS("I2S4", t186_i2s4_tx),
+	WIDGETS("I2S5", t186_i2s5_tx),
+	WIDGETS("I2S6", t186_i2s6_tx),
+	TX_WIDGETS("DMIC1"),
+	TX_WIDGETS("DMIC2"),
+	TX_WIDGETS("DMIC3"),
+	TX_WIDGETS("DMIC4"),
+	WIDGETS("DSPK1", t186_dspk1_tx),
+	WIDGETS("DSPK2", t186_dspk2_tx),
+};
+
+#define TEGRA_COMMON_ROUTES(name)					\
+	{ name " XBAR-TX",	NULL,		name " Mux" },		\
+	{ name " Mux",		"ADMAIF1",	"ADMAIF1 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF2",	"ADMAIF2 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF3",	"ADMAIF3 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF4",	"ADMAIF4 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF5",	"ADMAIF5 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF6",	"ADMAIF6 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF7",	"ADMAIF7 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF8",	"ADMAIF8 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF9",	"ADMAIF9 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF10",	"ADMAIF10 XBAR-RX" },	\
+	{ name " Mux",		"I2S1",		"I2S1 XBAR-RX" },	\
+	{ name " Mux",		"I2S2",		"I2S2 XBAR-RX" },	\
+	{ name " Mux",		"I2S3",		"I2S3 XBAR-RX" },	\
+	{ name " Mux",		"I2S4",		"I2S4 XBAR-RX" },	\
+	{ name " Mux",		"I2S5",		"I2S5 XBAR-RX" },	\
+	{ name " Mux",		"DMIC1",	"DMIC1 XBAR-RX" },	\
+	{ name " Mux",		"DMIC2",	"DMIC2 XBAR-RX" },	\
+	{ name " Mux",		"DMIC3",	"DMIC3 XBAR-RX" },
+
+#define TEGRA186_ONLY_ROUTES(name)					\
+	{ name " Mux",		"ADMAIF11",	"ADMAIF11 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF12",	"ADMAIF12 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF13",	"ADMAIF13 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF14",	"ADMAIF14 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF15",	"ADMAIF15 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF16",	"ADMAIF16 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF17",	"ADMAIF17 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF18",	"ADMAIF18 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF19",	"ADMAIF19 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF20",	"ADMAIF20 XBAR-RX" },	\
+	{ name " Mux",		"I2S6",		"I2S6 XBAR-RX" },	\
+	{ name " Mux",		"DMIC4",	"DMIC4 XBAR-RX" },
+
+#define TEGRA210_ROUTES(name)						\
+	TEGRA_COMMON_ROUTES(name)
+
+#define TEGRA186_ROUTES(name)						\
+	TEGRA_COMMON_ROUTES(name)					\
+	TEGRA186_ONLY_ROUTES(name)
+
+/*
+ * The number of entries in, and order of, this array is closely tied to the
+ * calculation of tegra210_ahub_codec.num_dapm_routes near the end of
+ * tegra210_ahub_probe()
+ */
+static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
+	TEGRA210_ROUTES("ADMAIF1")
+	TEGRA210_ROUTES("ADMAIF2")
+	TEGRA210_ROUTES("ADMAIF3")
+	TEGRA210_ROUTES("ADMAIF4")
+	TEGRA210_ROUTES("ADMAIF5")
+	TEGRA210_ROUTES("ADMAIF6")
+	TEGRA210_ROUTES("ADMAIF7")
+	TEGRA210_ROUTES("ADMAIF8")
+	TEGRA210_ROUTES("ADMAIF9")
+	TEGRA210_ROUTES("ADMAIF10")
+	TEGRA210_ROUTES("I2S1")
+	TEGRA210_ROUTES("I2S2")
+	TEGRA210_ROUTES("I2S3")
+	TEGRA210_ROUTES("I2S4")
+	TEGRA210_ROUTES("I2S5")
+};
+
+static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
+	TEGRA186_ROUTES("ADMAIF1")
+	TEGRA186_ROUTES("ADMAIF2")
+	TEGRA186_ROUTES("ADMAIF3")
+	TEGRA186_ROUTES("ADMAIF4")
+	TEGRA186_ROUTES("ADMAIF5")
+	TEGRA186_ROUTES("ADMAIF6")
+	TEGRA186_ROUTES("ADMAIF7")
+	TEGRA186_ROUTES("ADMAIF8")
+	TEGRA186_ROUTES("ADMAIF9")
+	TEGRA186_ROUTES("ADMAIF10")
+	TEGRA186_ROUTES("ADMAIF11")
+	TEGRA186_ROUTES("ADMAIF12")
+	TEGRA186_ROUTES("ADMAIF13")
+	TEGRA186_ROUTES("ADMAIF14")
+	TEGRA186_ROUTES("ADMAIF15")
+	TEGRA186_ROUTES("ADMAIF16")
+	TEGRA186_ROUTES("ADMAIF17")
+	TEGRA186_ROUTES("ADMAIF18")
+	TEGRA186_ROUTES("ADMAIF19")
+	TEGRA186_ROUTES("ADMAIF20")
+	TEGRA186_ROUTES("I2S1")
+	TEGRA186_ROUTES("I2S2")
+	TEGRA186_ROUTES("I2S3")
+	TEGRA186_ROUTES("I2S4")
+	TEGRA186_ROUTES("I2S5")
+	TEGRA186_ROUTES("I2S6")
+	TEGRA186_ROUTES("DSPK1")
+	TEGRA186_ROUTES("DSPK2")
+};
+
+static const struct snd_soc_component_driver tegra210_ahub_component = {
+	.dapm_widgets		= tegra210_ahub_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tegra210_ahub_widgets),
+	.dapm_routes		= tegra210_ahub_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tegra210_ahub_routes),
+};
+
+static const struct snd_soc_component_driver tegra186_ahub_component = {
+	.dapm_widgets = tegra186_ahub_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra186_ahub_widgets),
+	.dapm_routes = tegra186_ahub_routes,
+	.num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes),
+};
+
+static const struct regmap_config tegra210_ahub_regmap_config = {
+	.reg_bits		= 32,
+	.val_bits		= 32,
+	.reg_stride		= 4,
+	.max_register		= TEGRA210_MAX_REGISTER_ADDR,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct regmap_config tegra186_ahub_regmap_config = {
+	.reg_bits		= 32,
+	.val_bits		= 32,
+	.reg_stride		= 4,
+	.max_register		= TEGRA186_MAX_REGISTER_ADDR,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct tegra_ahub_soc_data soc_data_tegra210 = {
+	.cmpnt_drv	= &tegra210_ahub_component,
+	.regmap_config	= &tegra210_ahub_regmap_config,
+	.mask[0]	= TEGRA210_XBAR_REG_MASK_0,
+	.mask[1]	= TEGRA210_XBAR_REG_MASK_1,
+	.mask[2]	= TEGRA210_XBAR_REG_MASK_2,
+	.mask[3]	= TEGRA210_XBAR_REG_MASK_3,
+	.reg_count	= TEGRA210_XBAR_UPDATE_MAX_REG,
+};
+
+static const struct tegra_ahub_soc_data soc_data_tegra186 = {
+	.cmpnt_drv	= &tegra186_ahub_component,
+	.regmap_config	= &tegra186_ahub_regmap_config,
+	.mask[0]	= TEGRA186_XBAR_REG_MASK_0,
+	.mask[1]	= TEGRA186_XBAR_REG_MASK_1,
+	.mask[2]	= TEGRA186_XBAR_REG_MASK_2,
+	.mask[3]	= TEGRA186_XBAR_REG_MASK_3,
+	.reg_count	= TEGRA186_XBAR_UPDATE_MAX_REG,
+};
+
+static const struct of_device_id tegra_ahub_of_match[] = {
+	{ .compatible = "nvidia,tegra210-ahub", .data = &soc_data_tegra210 },
+	{ .compatible = "nvidia,tegra186-ahub", .data = &soc_data_tegra186 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra_ahub_of_match);
+
+static int tegra_ahub_runtime_suspend(struct device *dev)
+{
+	struct tegra_ahub *ahub = dev_get_drvdata(dev);
+
+	regcache_cache_only(ahub->regmap, true);
+	regcache_mark_dirty(ahub->regmap);
+
+	clk_disable_unprepare(ahub->clk);
+
+	return 0;
+}
+
+static int tegra_ahub_runtime_resume(struct device *dev)
+{
+	struct tegra_ahub *ahub = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(ahub->clk);
+	if (err) {
+		dev_err(dev, "failed to enable AHUB clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(ahub->regmap, false);
+	regcache_sync(ahub->regmap);
+
+	return 0;
+}
+
+static int tegra_ahub_probe(struct platform_device *pdev)
+{
+	struct tegra_ahub *ahub;
+	void __iomem *regs;
+	int err;
+
+	ahub = devm_kzalloc(&pdev->dev, sizeof(*ahub), GFP_KERNEL);
+	if (!ahub)
+		return -ENOMEM;
+
+	ahub->soc_data = of_device_get_match_data(&pdev->dev);
+
+	platform_set_drvdata(pdev, ahub);
+
+	ahub->clk = devm_clk_get(&pdev->dev, "ahub");
+	if (IS_ERR(ahub->clk)) {
+		dev_err(&pdev->dev, "can't retrieve AHUB clock\n");
+		return PTR_ERR(ahub->clk);
+	}
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ahub->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					     ahub->soc_data->regmap_config);
+	if (IS_ERR(ahub->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(ahub->regmap);
+	}
+
+	regcache_cache_only(ahub->regmap, true);
+
+	err = devm_snd_soc_register_component(&pdev->dev,
+					      ahub->soc_data->cmpnt_drv,
+					      NULL, 0);
+	if (err) {
+		dev_err(&pdev->dev, "can't register AHUB component, err: %d\n",
+			err);
+		return err;
+	}
+
+	err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (err)
+		return err;
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static int tegra_ahub_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra_ahub_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra_ahub_runtime_suspend,
+			   tegra_ahub_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra_ahub_driver = {
+	.probe = tegra_ahub_probe,
+	.remove = tegra_ahub_remove,
+	.driver = {
+		.name = "tegra210-ahub",
+		.of_match_table = tegra_ahub_of_match,
+		.pm = &tegra_ahub_pm_ops,
+	},
+};
+module_platform_driver(tegra_ahub_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 ASoC AHUB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_ahub.h b/sound/soc/tegra/tegra210_ahub.h
new file mode 100644
index 0000000..db3c8ce
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ahub.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_ahub.h - TEGRA210 AHUB
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_AHUB__H__
+#define __TEGRA210_AHUB__H__
+
+/* Tegra210 specific */
+#define TEGRA210_XBAR_PART1_RX				0x200
+#define TEGRA210_XBAR_PART2_RX				0x400
+#define TEGRA210_XBAR_RX_STRIDE				0x4
+#define TEGRA210_XBAR_AUDIO_RX_COUNT			90
+#define TEGRA210_XBAR_REG_MASK_0			0xf1f03ff
+#define TEGRA210_XBAR_REG_MASK_1			0x3f30031f
+#define TEGRA210_XBAR_REG_MASK_2			0xff1cf313
+#define TEGRA210_XBAR_REG_MASK_3			0x0
+#define TEGRA210_XBAR_UPDATE_MAX_REG			3
+/* Tegra186 specific */
+#define TEGRA186_XBAR_PART3_RX				0x600
+#define TEGRA186_XBAR_AUDIO_RX_COUNT			115
+#define TEGRA186_XBAR_REG_MASK_0			0xf3fffff
+#define TEGRA186_XBAR_REG_MASK_1			0x3f310f1f
+#define TEGRA186_XBAR_REG_MASK_2			0xff3cf311
+#define TEGRA186_XBAR_REG_MASK_3			0x3f0f00ff
+#define TEGRA186_XBAR_UPDATE_MAX_REG			4
+
+#define TEGRA_XBAR_UPDATE_MAX_REG (TEGRA186_XBAR_UPDATE_MAX_REG)
+
+#define TEGRA186_MAX_REGISTER_ADDR (TEGRA186_XBAR_PART3_RX +		\
+	(TEGRA210_XBAR_RX_STRIDE * (TEGRA186_XBAR_AUDIO_RX_COUNT - 1)))
+
+#define TEGRA210_MAX_REGISTER_ADDR (TEGRA210_XBAR_PART2_RX +		\
+	(TEGRA210_XBAR_RX_STRIDE * (TEGRA210_XBAR_AUDIO_RX_COUNT - 1)))
+
+#define MUX_REG(id) (TEGRA210_XBAR_RX_STRIDE * (id))
+
+#define MUX_VALUE(npart, nbit) (1 + (nbit) + (npart) * 32)
+
+#define SOC_VALUE_ENUM_WIDE(xreg, shift, xmax, xtexts, xvalues)		\
+	{								\
+		.reg = xreg,						\
+		.shift_l = shift,					\
+		.shift_r = shift,					\
+		.items = xmax,						\
+		.texts = xtexts,					\
+		.values = xvalues,					\
+		.mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0		\
+	}
+
+#define SOC_VALUE_ENUM_WIDE_DECL(name, xreg, shift, xtexts, xvalues)	\
+	static struct soc_enum name =					\
+		SOC_VALUE_ENUM_WIDE(xreg, shift, ARRAY_SIZE(xtexts),	\
+				    xtexts, xvalues)
+
+#define MUX_ENUM_CTRL_DECL(ename, id)					\
+	SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0,		\
+				 tegra210_ahub_mux_texts,		\
+				 tegra210_ahub_mux_values);		\
+	static const struct snd_kcontrol_new ename##_control =		\
+		SOC_DAPM_ENUM_EXT("Route", ename##_enum,		\
+				  tegra_ahub_get_value_enum,		\
+				  tegra_ahub_put_value_enum)
+
+#define MUX_ENUM_CTRL_DECL_186(ename, id)				\
+	SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0,		\
+				 tegra186_ahub_mux_texts,		\
+				 tegra186_ahub_mux_values);		\
+	static const struct snd_kcontrol_new ename##_control =		\
+		SOC_DAPM_ENUM_EXT("Route", ename##_enum,		\
+				  tegra_ahub_get_value_enum,		\
+				  tegra_ahub_put_value_enum)
+
+#define WIDGETS(sname, ename)						     \
+	SND_SOC_DAPM_AIF_IN(sname " XBAR-RX", NULL, 0, SND_SOC_NOPM, 0, 0),  \
+	SND_SOC_DAPM_AIF_OUT(sname " XBAR-TX", NULL, 0, SND_SOC_NOPM, 0, 0), \
+	SND_SOC_DAPM_MUX(sname " Mux", SND_SOC_NOPM, 0, 0,		     \
+			 &ename##_control)
+
+#define TX_WIDGETS(sname)						    \
+	SND_SOC_DAPM_AIF_IN(sname " XBAR-RX", NULL, 0, SND_SOC_NOPM, 0, 0), \
+	SND_SOC_DAPM_AIF_OUT(sname " XBAR-TX", NULL, 0, SND_SOC_NOPM, 0, 0)
+
+struct tegra_ahub_soc_data {
+	const struct regmap_config *regmap_config;
+	const struct snd_soc_component_driver *cmpnt_drv;
+	unsigned int mask[4];
+	unsigned int reg_count;
+};
+
+struct tegra_ahub {
+	const struct tegra_ahub_soc_data *soc_data;
+	struct regmap *regmap;
+	struct clk *clk;
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 05/23] ASoC: tegra: Add Tegra210 based AHUB driver
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

The Audio Hub (AHUB) comprises a collection of hardware accelerators for
audio pre/post-processing and a programmable full crossbar (XBAR) for
routing audio data across these accelerators in time and in parallel.
AHUB supports multiple interfaces to I2S, DSPK, DMIC etc., XBAR is a
switch used to configure or modify audio routing between HW accelerators
present inside AHUB.

This patch registers AHUB component with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes AHUB interfaces, which can be used to connect different
components in the ASoC layer. Currently the driver takes care of XBAR
programming to allow audio data flow through various clients of the AHUB.
Makefile and Kconfig support is added to allow to build the driver. The
AHUB component can be enabled in the DT via below compatible bindings.
  - "nvidia,tegra210-ahub" for Tegra210
  - "nvidia,tegra186-ahub" for Tegra186 and Tegra194

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig         |  10 +
 sound/soc/tegra/Makefile        |   2 +
 sound/soc/tegra/tegra210_ahub.c | 578 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_ahub.h | 100 +++++++
 4 files changed, 690 insertions(+)
 create mode 100644 sound/soc/tegra/tegra210_ahub.c
 create mode 100644 sound/soc/tegra/tegra210_ahub.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 157fa7a..3166d03 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -62,6 +62,16 @@ config SND_SOC_TEGRA30_I2S
 	  Tegra30 I2S interface. You will also need to select the individual
 	  machine drivers to support below.
 
+config SND_SOC_TEGRA210_AHUB
+	tristate "Tegra210 AHUB module"
+	depends on SND_SOC_TEGRA
+	help
+	  Config to enable Audio Hub (AHUB) module, which comprises of a
+	  switch called Audio Crossbar (AXBAR) used to configure or modify
+	  the audio routing path between various HW accelerators present in
+	  AHUB.
+	  Say Y or M if you want to add support for Tegra210 AHUB module.
+
 config SND_SOC_TEGRA210_DMIC
         tristate "Tegra210 DMIC module"
         depends on SND_SOC_TEGRA
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index e30f6a3..b01d88e 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -8,6 +8,7 @@ snd-soc-tegra20-i2s-objs := tegra20_i2s.o
 snd-soc-tegra20-spdif-objs := tegra20_spdif.o
 snd-soc-tegra30-ahub-objs := tegra30_ahub.o
 snd-soc-tegra30-i2s-objs := tegra30_i2s.o
+snd-soc-tegra210-ahub-objs := tegra210_ahub.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 snd-soc-tegra210-i2s-objs := tegra210_i2s.o
 
@@ -20,6 +21,7 @@ obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
 obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
+obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
 
 # Tegra machine Support
diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
new file mode 100644
index 0000000..93bd23f
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_ahub.c - Tegra210 AHUB driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "tegra210_ahub.h"
+
+static int tegra_ahub_get_value_enum(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
+	struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
+	struct soc_enum *e = (struct soc_enum *)kctl->private_value;
+	unsigned int reg, i, bit_pos = 0;
+
+	/*
+	 * Find the bit position of current MUX input.
+	 * If nothing is set, position would be 0 and it corresponds to 'None'.
+	 */
+	for (i = 0; i < ahub->soc_data->reg_count; i++) {
+		unsigned int reg_val;
+
+		reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
+		reg_val = snd_soc_component_read(cmpnt, reg);
+		reg_val &= ahub->soc_data->mask[i];
+
+		if (reg_val) {
+			bit_pos = ffs(reg_val) +
+				  (8 * cmpnt->val_bytes * i);
+			break;
+		}
+	}
+
+	/* Find index related to the item in array *_ahub_mux_texts[] */
+	for (i = 0; i < e->items; i++) {
+		if (bit_pos == e->values[i]) {
+			uctl->value.enumerated.item[0] = i;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
+	struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctl);
+	struct soc_enum *e = (struct soc_enum *)kctl->private_value;
+	struct snd_soc_dapm_update update[TEGRA_XBAR_UPDATE_MAX_REG] = { };
+	unsigned int *item = uctl->value.enumerated.item;
+	unsigned int value = e->values[item[0]];
+	unsigned int i, bit_pos, reg_idx = 0, reg_val = 0;
+
+	if (item[0] >= e->items)
+		return -EINVAL;
+
+	if (value) {
+		/* Get the register index and value to set */
+		reg_idx = (value - 1) / (8 * cmpnt->val_bytes);
+		bit_pos = (value - 1) % (8 * cmpnt->val_bytes);
+		reg_val = BIT(bit_pos);
+	}
+
+	/*
+	 * Run through all parts of a MUX register to find the state changes.
+	 * There will be an additional update if new MUX input value is from
+	 * different part of the MUX register.
+	 */
+	for (i = 0; i < ahub->soc_data->reg_count; i++) {
+		update[i].reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
+		update[i].val = (i == reg_idx) ? reg_val : 0;
+		update[i].mask = ahub->soc_data->mask[i];
+		update[i].kcontrol = kctl;
+
+		/* Update widget power if state has changed */
+		if (snd_soc_component_test_bits(cmpnt, update[i].reg,
+						update[i].mask, update[i].val))
+			snd_soc_dapm_mux_update_power(dapm, kctl, item[0], e,
+						      &update[i]);
+	}
+
+	return 0;
+}
+
+static const char * const tegra210_ahub_mux_texts[] = {
+	"None",
+	"ADMAIF1",
+	"ADMAIF2",
+	"ADMAIF3",
+	"ADMAIF4",
+	"ADMAIF5",
+	"ADMAIF6",
+	"ADMAIF7",
+	"ADMAIF8",
+	"ADMAIF9",
+	"ADMAIF10",
+	"I2S1",
+	"I2S2",
+	"I2S3",
+	"I2S4",
+	"I2S5",
+	"DMIC1",
+	"DMIC2",
+	"DMIC3",
+};
+
+static const char * const tegra186_ahub_mux_texts[] = {
+	"None",
+	"ADMAIF1",
+	"ADMAIF2",
+	"ADMAIF3",
+	"ADMAIF4",
+	"ADMAIF5",
+	"ADMAIF6",
+	"ADMAIF7",
+	"ADMAIF8",
+	"ADMAIF9",
+	"ADMAIF10",
+	"ADMAIF11",
+	"ADMAIF12",
+	"ADMAIF13",
+	"ADMAIF14",
+	"ADMAIF15",
+	"ADMAIF16",
+	"I2S1",
+	"I2S2",
+	"I2S3",
+	"I2S4",
+	"I2S5",
+	"I2S6",
+	"ADMAIF17",
+	"ADMAIF18",
+	"ADMAIF19",
+	"ADMAIF20",
+	"DMIC1",
+	"DMIC2",
+	"DMIC3",
+	"DMIC4",
+};
+
+static const unsigned int tegra210_ahub_mux_values[] = {
+	0,
+	MUX_VALUE(0, 0),
+	MUX_VALUE(0, 1),
+	MUX_VALUE(0, 2),
+	MUX_VALUE(0, 3),
+	MUX_VALUE(0, 4),
+	MUX_VALUE(0, 5),
+	MUX_VALUE(0, 6),
+	MUX_VALUE(0, 7),
+	MUX_VALUE(0, 8),
+	MUX_VALUE(0, 9),
+	MUX_VALUE(0, 16),
+	MUX_VALUE(0, 17),
+	MUX_VALUE(0, 18),
+	MUX_VALUE(0, 19),
+	MUX_VALUE(0, 20),
+	MUX_VALUE(2, 18),
+	MUX_VALUE(2, 19),
+	MUX_VALUE(2, 20),
+};
+
+static const unsigned int tegra186_ahub_mux_values[] = {
+	0,
+	MUX_VALUE(0, 0),
+	MUX_VALUE(0, 1),
+	MUX_VALUE(0, 2),
+	MUX_VALUE(0, 3),
+	MUX_VALUE(0, 4),
+	MUX_VALUE(0, 5),
+	MUX_VALUE(0, 6),
+	MUX_VALUE(0, 7),
+	MUX_VALUE(0, 8),
+	MUX_VALUE(0, 9),
+	MUX_VALUE(0, 10),
+	MUX_VALUE(0, 11),
+	MUX_VALUE(0, 12),
+	MUX_VALUE(0, 13),
+	MUX_VALUE(0, 14),
+	MUX_VALUE(0, 15),
+	MUX_VALUE(0, 16),
+	MUX_VALUE(0, 17),
+	MUX_VALUE(0, 18),
+	MUX_VALUE(0, 19),
+	MUX_VALUE(0, 20),
+	MUX_VALUE(0, 21),
+	MUX_VALUE(3, 16),
+	MUX_VALUE(3, 17),
+	MUX_VALUE(3, 18),
+	MUX_VALUE(3, 19),
+	MUX_VALUE(2, 18),
+	MUX_VALUE(2, 19),
+	MUX_VALUE(2, 20),
+	MUX_VALUE(2, 21),
+};
+
+/* Controls for t210 */
+MUX_ENUM_CTRL_DECL(t210_admaif1_tx, 0x00);
+MUX_ENUM_CTRL_DECL(t210_admaif2_tx, 0x01);
+MUX_ENUM_CTRL_DECL(t210_admaif3_tx, 0x02);
+MUX_ENUM_CTRL_DECL(t210_admaif4_tx, 0x03);
+MUX_ENUM_CTRL_DECL(t210_admaif5_tx, 0x04);
+MUX_ENUM_CTRL_DECL(t210_admaif6_tx, 0x05);
+MUX_ENUM_CTRL_DECL(t210_admaif7_tx, 0x06);
+MUX_ENUM_CTRL_DECL(t210_admaif8_tx, 0x07);
+MUX_ENUM_CTRL_DECL(t210_admaif9_tx, 0x08);
+MUX_ENUM_CTRL_DECL(t210_admaif10_tx, 0x09);
+MUX_ENUM_CTRL_DECL(t210_i2s1_tx, 0x10);
+MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11);
+MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12);
+MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13);
+MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14);
+
+/* Controls for t186 */
+MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
+MUX_ENUM_CTRL_DECL_186(t186_admaif2_tx, 0x01);
+MUX_ENUM_CTRL_DECL_186(t186_admaif3_tx, 0x02);
+MUX_ENUM_CTRL_DECL_186(t186_admaif4_tx, 0x03);
+MUX_ENUM_CTRL_DECL_186(t186_admaif5_tx, 0x04);
+MUX_ENUM_CTRL_DECL_186(t186_admaif6_tx, 0x05);
+MUX_ENUM_CTRL_DECL_186(t186_admaif7_tx, 0x06);
+MUX_ENUM_CTRL_DECL_186(t186_admaif8_tx, 0x07);
+MUX_ENUM_CTRL_DECL_186(t186_admaif9_tx, 0x08);
+MUX_ENUM_CTRL_DECL_186(t186_admaif10_tx, 0x09);
+MUX_ENUM_CTRL_DECL_186(t186_i2s1_tx, 0x10);
+MUX_ENUM_CTRL_DECL_186(t186_i2s2_tx, 0x11);
+MUX_ENUM_CTRL_DECL_186(t186_i2s3_tx, 0x12);
+MUX_ENUM_CTRL_DECL_186(t186_i2s4_tx, 0x13);
+MUX_ENUM_CTRL_DECL_186(t186_i2s5_tx, 0x14);
+MUX_ENUM_CTRL_DECL_186(t186_admaif11_tx, 0x0a);
+MUX_ENUM_CTRL_DECL_186(t186_admaif12_tx, 0x0b);
+MUX_ENUM_CTRL_DECL_186(t186_admaif13_tx, 0x0c);
+MUX_ENUM_CTRL_DECL_186(t186_admaif14_tx, 0x0d);
+MUX_ENUM_CTRL_DECL_186(t186_admaif15_tx, 0x0e);
+MUX_ENUM_CTRL_DECL_186(t186_admaif16_tx, 0x0f);
+MUX_ENUM_CTRL_DECL_186(t186_i2s6_tx, 0x15);
+MUX_ENUM_CTRL_DECL_186(t186_dspk1_tx, 0x30);
+MUX_ENUM_CTRL_DECL_186(t186_dspk2_tx, 0x31);
+MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68);
+MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69);
+MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a);
+MUX_ENUM_CTRL_DECL_186(t186_admaif20_tx, 0x6b);
+
+/*
+ * The number of entries in, and order of, this array is closely tied to the
+ * calculation of tegra210_ahub_codec.num_dapm_widgets near the end of
+ * tegra210_ahub_probe()
+ */
+static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
+	WIDGETS("ADMAIF1", t210_admaif1_tx),
+	WIDGETS("ADMAIF2", t210_admaif2_tx),
+	WIDGETS("ADMAIF3", t210_admaif3_tx),
+	WIDGETS("ADMAIF4", t210_admaif4_tx),
+	WIDGETS("ADMAIF5", t210_admaif5_tx),
+	WIDGETS("ADMAIF6", t210_admaif6_tx),
+	WIDGETS("ADMAIF7", t210_admaif7_tx),
+	WIDGETS("ADMAIF8", t210_admaif8_tx),
+	WIDGETS("ADMAIF9", t210_admaif9_tx),
+	WIDGETS("ADMAIF10", t210_admaif10_tx),
+	WIDGETS("I2S1", t210_i2s1_tx),
+	WIDGETS("I2S2", t210_i2s2_tx),
+	WIDGETS("I2S3", t210_i2s3_tx),
+	WIDGETS("I2S4", t210_i2s4_tx),
+	WIDGETS("I2S5", t210_i2s5_tx),
+	TX_WIDGETS("DMIC1"),
+	TX_WIDGETS("DMIC2"),
+	TX_WIDGETS("DMIC3"),
+};
+
+static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
+	WIDGETS("ADMAIF1", t186_admaif1_tx),
+	WIDGETS("ADMAIF2", t186_admaif2_tx),
+	WIDGETS("ADMAIF3", t186_admaif3_tx),
+	WIDGETS("ADMAIF4", t186_admaif4_tx),
+	WIDGETS("ADMAIF5", t186_admaif5_tx),
+	WIDGETS("ADMAIF6", t186_admaif6_tx),
+	WIDGETS("ADMAIF7", t186_admaif7_tx),
+	WIDGETS("ADMAIF8", t186_admaif8_tx),
+	WIDGETS("ADMAIF9", t186_admaif9_tx),
+	WIDGETS("ADMAIF10", t186_admaif10_tx),
+	WIDGETS("ADMAIF11", t186_admaif11_tx),
+	WIDGETS("ADMAIF12", t186_admaif12_tx),
+	WIDGETS("ADMAIF13", t186_admaif13_tx),
+	WIDGETS("ADMAIF14", t186_admaif14_tx),
+	WIDGETS("ADMAIF15", t186_admaif15_tx),
+	WIDGETS("ADMAIF16", t186_admaif16_tx),
+	WIDGETS("ADMAIF17", t186_admaif17_tx),
+	WIDGETS("ADMAIF18", t186_admaif18_tx),
+	WIDGETS("ADMAIF19", t186_admaif19_tx),
+	WIDGETS("ADMAIF20", t186_admaif20_tx),
+	WIDGETS("I2S1", t186_i2s1_tx),
+	WIDGETS("I2S2", t186_i2s2_tx),
+	WIDGETS("I2S3", t186_i2s3_tx),
+	WIDGETS("I2S4", t186_i2s4_tx),
+	WIDGETS("I2S5", t186_i2s5_tx),
+	WIDGETS("I2S6", t186_i2s6_tx),
+	TX_WIDGETS("DMIC1"),
+	TX_WIDGETS("DMIC2"),
+	TX_WIDGETS("DMIC3"),
+	TX_WIDGETS("DMIC4"),
+	WIDGETS("DSPK1", t186_dspk1_tx),
+	WIDGETS("DSPK2", t186_dspk2_tx),
+};
+
+#define TEGRA_COMMON_ROUTES(name)					\
+	{ name " XBAR-TX",	NULL,		name " Mux" },		\
+	{ name " Mux",		"ADMAIF1",	"ADMAIF1 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF2",	"ADMAIF2 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF3",	"ADMAIF3 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF4",	"ADMAIF4 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF5",	"ADMAIF5 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF6",	"ADMAIF6 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF7",	"ADMAIF7 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF8",	"ADMAIF8 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF9",	"ADMAIF9 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF10",	"ADMAIF10 XBAR-RX" },	\
+	{ name " Mux",		"I2S1",		"I2S1 XBAR-RX" },	\
+	{ name " Mux",		"I2S2",		"I2S2 XBAR-RX" },	\
+	{ name " Mux",		"I2S3",		"I2S3 XBAR-RX" },	\
+	{ name " Mux",		"I2S4",		"I2S4 XBAR-RX" },	\
+	{ name " Mux",		"I2S5",		"I2S5 XBAR-RX" },	\
+	{ name " Mux",		"DMIC1",	"DMIC1 XBAR-RX" },	\
+	{ name " Mux",		"DMIC2",	"DMIC2 XBAR-RX" },	\
+	{ name " Mux",		"DMIC3",	"DMIC3 XBAR-RX" },
+
+#define TEGRA186_ONLY_ROUTES(name)					\
+	{ name " Mux",		"ADMAIF11",	"ADMAIF11 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF12",	"ADMAIF12 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF13",	"ADMAIF13 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF14",	"ADMAIF14 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF15",	"ADMAIF15 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF16",	"ADMAIF16 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF17",	"ADMAIF17 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF18",	"ADMAIF18 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF19",	"ADMAIF19 XBAR-RX" },	\
+	{ name " Mux",		"ADMAIF20",	"ADMAIF20 XBAR-RX" },	\
+	{ name " Mux",		"I2S6",		"I2S6 XBAR-RX" },	\
+	{ name " Mux",		"DMIC4",	"DMIC4 XBAR-RX" },
+
+#define TEGRA210_ROUTES(name)						\
+	TEGRA_COMMON_ROUTES(name)
+
+#define TEGRA186_ROUTES(name)						\
+	TEGRA_COMMON_ROUTES(name)					\
+	TEGRA186_ONLY_ROUTES(name)
+
+/*
+ * The number of entries in, and order of, this array is closely tied to the
+ * calculation of tegra210_ahub_codec.num_dapm_routes near the end of
+ * tegra210_ahub_probe()
+ */
+static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
+	TEGRA210_ROUTES("ADMAIF1")
+	TEGRA210_ROUTES("ADMAIF2")
+	TEGRA210_ROUTES("ADMAIF3")
+	TEGRA210_ROUTES("ADMAIF4")
+	TEGRA210_ROUTES("ADMAIF5")
+	TEGRA210_ROUTES("ADMAIF6")
+	TEGRA210_ROUTES("ADMAIF7")
+	TEGRA210_ROUTES("ADMAIF8")
+	TEGRA210_ROUTES("ADMAIF9")
+	TEGRA210_ROUTES("ADMAIF10")
+	TEGRA210_ROUTES("I2S1")
+	TEGRA210_ROUTES("I2S2")
+	TEGRA210_ROUTES("I2S3")
+	TEGRA210_ROUTES("I2S4")
+	TEGRA210_ROUTES("I2S5")
+};
+
+static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
+	TEGRA186_ROUTES("ADMAIF1")
+	TEGRA186_ROUTES("ADMAIF2")
+	TEGRA186_ROUTES("ADMAIF3")
+	TEGRA186_ROUTES("ADMAIF4")
+	TEGRA186_ROUTES("ADMAIF5")
+	TEGRA186_ROUTES("ADMAIF6")
+	TEGRA186_ROUTES("ADMAIF7")
+	TEGRA186_ROUTES("ADMAIF8")
+	TEGRA186_ROUTES("ADMAIF9")
+	TEGRA186_ROUTES("ADMAIF10")
+	TEGRA186_ROUTES("ADMAIF11")
+	TEGRA186_ROUTES("ADMAIF12")
+	TEGRA186_ROUTES("ADMAIF13")
+	TEGRA186_ROUTES("ADMAIF14")
+	TEGRA186_ROUTES("ADMAIF15")
+	TEGRA186_ROUTES("ADMAIF16")
+	TEGRA186_ROUTES("ADMAIF17")
+	TEGRA186_ROUTES("ADMAIF18")
+	TEGRA186_ROUTES("ADMAIF19")
+	TEGRA186_ROUTES("ADMAIF20")
+	TEGRA186_ROUTES("I2S1")
+	TEGRA186_ROUTES("I2S2")
+	TEGRA186_ROUTES("I2S3")
+	TEGRA186_ROUTES("I2S4")
+	TEGRA186_ROUTES("I2S5")
+	TEGRA186_ROUTES("I2S6")
+	TEGRA186_ROUTES("DSPK1")
+	TEGRA186_ROUTES("DSPK2")
+};
+
+static const struct snd_soc_component_driver tegra210_ahub_component = {
+	.dapm_widgets		= tegra210_ahub_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tegra210_ahub_widgets),
+	.dapm_routes		= tegra210_ahub_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tegra210_ahub_routes),
+};
+
+static const struct snd_soc_component_driver tegra186_ahub_component = {
+	.dapm_widgets = tegra186_ahub_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra186_ahub_widgets),
+	.dapm_routes = tegra186_ahub_routes,
+	.num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes),
+};
+
+static const struct regmap_config tegra210_ahub_regmap_config = {
+	.reg_bits		= 32,
+	.val_bits		= 32,
+	.reg_stride		= 4,
+	.max_register		= TEGRA210_MAX_REGISTER_ADDR,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct regmap_config tegra186_ahub_regmap_config = {
+	.reg_bits		= 32,
+	.val_bits		= 32,
+	.reg_stride		= 4,
+	.max_register		= TEGRA186_MAX_REGISTER_ADDR,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct tegra_ahub_soc_data soc_data_tegra210 = {
+	.cmpnt_drv	= &tegra210_ahub_component,
+	.regmap_config	= &tegra210_ahub_regmap_config,
+	.mask[0]	= TEGRA210_XBAR_REG_MASK_0,
+	.mask[1]	= TEGRA210_XBAR_REG_MASK_1,
+	.mask[2]	= TEGRA210_XBAR_REG_MASK_2,
+	.mask[3]	= TEGRA210_XBAR_REG_MASK_3,
+	.reg_count	= TEGRA210_XBAR_UPDATE_MAX_REG,
+};
+
+static const struct tegra_ahub_soc_data soc_data_tegra186 = {
+	.cmpnt_drv	= &tegra186_ahub_component,
+	.regmap_config	= &tegra186_ahub_regmap_config,
+	.mask[0]	= TEGRA186_XBAR_REG_MASK_0,
+	.mask[1]	= TEGRA186_XBAR_REG_MASK_1,
+	.mask[2]	= TEGRA186_XBAR_REG_MASK_2,
+	.mask[3]	= TEGRA186_XBAR_REG_MASK_3,
+	.reg_count	= TEGRA186_XBAR_UPDATE_MAX_REG,
+};
+
+static const struct of_device_id tegra_ahub_of_match[] = {
+	{ .compatible = "nvidia,tegra210-ahub", .data = &soc_data_tegra210 },
+	{ .compatible = "nvidia,tegra186-ahub", .data = &soc_data_tegra186 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra_ahub_of_match);
+
+static int tegra_ahub_runtime_suspend(struct device *dev)
+{
+	struct tegra_ahub *ahub = dev_get_drvdata(dev);
+
+	regcache_cache_only(ahub->regmap, true);
+	regcache_mark_dirty(ahub->regmap);
+
+	clk_disable_unprepare(ahub->clk);
+
+	return 0;
+}
+
+static int tegra_ahub_runtime_resume(struct device *dev)
+{
+	struct tegra_ahub *ahub = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(ahub->clk);
+	if (err) {
+		dev_err(dev, "failed to enable AHUB clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(ahub->regmap, false);
+	regcache_sync(ahub->regmap);
+
+	return 0;
+}
+
+static int tegra_ahub_probe(struct platform_device *pdev)
+{
+	struct tegra_ahub *ahub;
+	void __iomem *regs;
+	int err;
+
+	ahub = devm_kzalloc(&pdev->dev, sizeof(*ahub), GFP_KERNEL);
+	if (!ahub)
+		return -ENOMEM;
+
+	ahub->soc_data = of_device_get_match_data(&pdev->dev);
+
+	platform_set_drvdata(pdev, ahub);
+
+	ahub->clk = devm_clk_get(&pdev->dev, "ahub");
+	if (IS_ERR(ahub->clk)) {
+		dev_err(&pdev->dev, "can't retrieve AHUB clock\n");
+		return PTR_ERR(ahub->clk);
+	}
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ahub->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					     ahub->soc_data->regmap_config);
+	if (IS_ERR(ahub->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(ahub->regmap);
+	}
+
+	regcache_cache_only(ahub->regmap, true);
+
+	err = devm_snd_soc_register_component(&pdev->dev,
+					      ahub->soc_data->cmpnt_drv,
+					      NULL, 0);
+	if (err) {
+		dev_err(&pdev->dev, "can't register AHUB component, err: %d\n",
+			err);
+		return err;
+	}
+
+	err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (err)
+		return err;
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static int tegra_ahub_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra_ahub_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra_ahub_runtime_suspend,
+			   tegra_ahub_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra_ahub_driver = {
+	.probe = tegra_ahub_probe,
+	.remove = tegra_ahub_remove,
+	.driver = {
+		.name = "tegra210-ahub",
+		.of_match_table = tegra_ahub_of_match,
+		.pm = &tegra_ahub_pm_ops,
+	},
+};
+module_platform_driver(tegra_ahub_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 ASoC AHUB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_ahub.h b/sound/soc/tegra/tegra210_ahub.h
new file mode 100644
index 0000000..db3c8ce
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ahub.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_ahub.h - TEGRA210 AHUB
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_AHUB__H__
+#define __TEGRA210_AHUB__H__
+
+/* Tegra210 specific */
+#define TEGRA210_XBAR_PART1_RX				0x200
+#define TEGRA210_XBAR_PART2_RX				0x400
+#define TEGRA210_XBAR_RX_STRIDE				0x4
+#define TEGRA210_XBAR_AUDIO_RX_COUNT			90
+#define TEGRA210_XBAR_REG_MASK_0			0xf1f03ff
+#define TEGRA210_XBAR_REG_MASK_1			0x3f30031f
+#define TEGRA210_XBAR_REG_MASK_2			0xff1cf313
+#define TEGRA210_XBAR_REG_MASK_3			0x0
+#define TEGRA210_XBAR_UPDATE_MAX_REG			3
+/* Tegra186 specific */
+#define TEGRA186_XBAR_PART3_RX				0x600
+#define TEGRA186_XBAR_AUDIO_RX_COUNT			115
+#define TEGRA186_XBAR_REG_MASK_0			0xf3fffff
+#define TEGRA186_XBAR_REG_MASK_1			0x3f310f1f
+#define TEGRA186_XBAR_REG_MASK_2			0xff3cf311
+#define TEGRA186_XBAR_REG_MASK_3			0x3f0f00ff
+#define TEGRA186_XBAR_UPDATE_MAX_REG			4
+
+#define TEGRA_XBAR_UPDATE_MAX_REG (TEGRA186_XBAR_UPDATE_MAX_REG)
+
+#define TEGRA186_MAX_REGISTER_ADDR (TEGRA186_XBAR_PART3_RX +		\
+	(TEGRA210_XBAR_RX_STRIDE * (TEGRA186_XBAR_AUDIO_RX_COUNT - 1)))
+
+#define TEGRA210_MAX_REGISTER_ADDR (TEGRA210_XBAR_PART2_RX +		\
+	(TEGRA210_XBAR_RX_STRIDE * (TEGRA210_XBAR_AUDIO_RX_COUNT - 1)))
+
+#define MUX_REG(id) (TEGRA210_XBAR_RX_STRIDE * (id))
+
+#define MUX_VALUE(npart, nbit) (1 + (nbit) + (npart) * 32)
+
+#define SOC_VALUE_ENUM_WIDE(xreg, shift, xmax, xtexts, xvalues)		\
+	{								\
+		.reg = xreg,						\
+		.shift_l = shift,					\
+		.shift_r = shift,					\
+		.items = xmax,						\
+		.texts = xtexts,					\
+		.values = xvalues,					\
+		.mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0		\
+	}
+
+#define SOC_VALUE_ENUM_WIDE_DECL(name, xreg, shift, xtexts, xvalues)	\
+	static struct soc_enum name =					\
+		SOC_VALUE_ENUM_WIDE(xreg, shift, ARRAY_SIZE(xtexts),	\
+				    xtexts, xvalues)
+
+#define MUX_ENUM_CTRL_DECL(ename, id)					\
+	SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0,		\
+				 tegra210_ahub_mux_texts,		\
+				 tegra210_ahub_mux_values);		\
+	static const struct snd_kcontrol_new ename##_control =		\
+		SOC_DAPM_ENUM_EXT("Route", ename##_enum,		\
+				  tegra_ahub_get_value_enum,		\
+				  tegra_ahub_put_value_enum)
+
+#define MUX_ENUM_CTRL_DECL_186(ename, id)				\
+	SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0,		\
+				 tegra186_ahub_mux_texts,		\
+				 tegra186_ahub_mux_values);		\
+	static const struct snd_kcontrol_new ename##_control =		\
+		SOC_DAPM_ENUM_EXT("Route", ename##_enum,		\
+				  tegra_ahub_get_value_enum,		\
+				  tegra_ahub_put_value_enum)
+
+#define WIDGETS(sname, ename)						     \
+	SND_SOC_DAPM_AIF_IN(sname " XBAR-RX", NULL, 0, SND_SOC_NOPM, 0, 0),  \
+	SND_SOC_DAPM_AIF_OUT(sname " XBAR-TX", NULL, 0, SND_SOC_NOPM, 0, 0), \
+	SND_SOC_DAPM_MUX(sname " Mux", SND_SOC_NOPM, 0, 0,		     \
+			 &ename##_control)
+
+#define TX_WIDGETS(sname)						    \
+	SND_SOC_DAPM_AIF_IN(sname " XBAR-RX", NULL, 0, SND_SOC_NOPM, 0, 0), \
+	SND_SOC_DAPM_AIF_OUT(sname " XBAR-TX", NULL, 0, SND_SOC_NOPM, 0, 0)
+
+struct tegra_ahub_soc_data {
+	const struct regmap_config *regmap_config;
+	const struct snd_soc_component_driver *cmpnt_drv;
+	unsigned int mask[4];
+	unsigned int reg_count;
+};
+
+struct tegra_ahub {
+	const struct tegra_ahub_soc_data *soc_data;
+	struct regmap *regmap;
+	struct clk *clk;
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 06/23] ASoC: tegra: Add Tegra186 based DSPK driver
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

The Digital Speaker Controller (DSPK) converts the multi-bit Pulse Code
Modulation (PCM) audio input to oversampled 1-bit Pulse Density Modulation
(PDM) output. From the signal flow perpsective, the DSPK can be viewed as
a PDM transmitter that up-samples the input to the desired sampling rate
by interpolation then converts the oversampled PCM input to the desired
1-bit output via Delta Sigma Modulation (DSM).

This patch registers DSPK component with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes DSPK interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The DSPK devices can be enabled in the DT via
"nvidia,tegra186-dspk" compatible binding. This driver can be used
on Tegra194 chip as well.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/tegra/Kconfig         |  13 ++
 sound/soc/tegra/Makefile        |   2 +
 sound/soc/tegra/tegra186_dspk.c | 427 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra186_dspk.h |  70 +++++++
 4 files changed, 512 insertions(+)
 create mode 100644 sound/soc/tegra/tegra186_dspk.c
 create mode 100644 sound/soc/tegra/tegra186_dspk.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 3166d03..63d5ae9 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -93,6 +93,19 @@ config SND_SOC_TEGRA210_I2S
           compatible devices.
           Say Y or M if you want to add support for Tegra210 I2S module.
 
+config SND_SOC_TEGRA186_DSPK
+	tristate "Tegra186 DSPK module"
+	depends on SND_SOC_TEGRA
+	help
+	  Config to enable the Digital Speaker Controller (DSPK) which
+	  converts the multi-bit Pulse Code Modulation (PCM) audio input to
+	  oversampled 1-bit Pulse Density Modulation (PDM) output. From the
+	  signal flow perspective DSPK can be viewed as a PDM transmitter
+	  that up-samples the input to the desired sampling rate by
+	  interpolation and then converts the oversampled PCM input to
+	  the desired 1-bit output via Delta Sigma Modulation (DSM).
+	  Say Y or M if you want to add support for Tegra186 DSPK module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index b01d88e..336c4c7 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -11,6 +11,7 @@ snd-soc-tegra30-i2s-objs := tegra30_i2s.o
 snd-soc-tegra210-ahub-objs := tegra210_ahub.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 snd-soc-tegra210-i2s-objs := tegra210_i2s.o
+snd-soc-tegra186-dspk-objs := tegra186_dspk.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -23,6 +24,7 @@ obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
new file mode 100644
index 0000000..d74aec8
--- /dev/null
+++ b/sound/soc/tegra/tegra186_dspk.c
@@ -0,0 +1,427 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra186_dspk.c - Tegra186 DSPK driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra186_dspk.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra186_dspk_reg_defaults[] = {
+	{ TEGRA186_DSPK_RX_INT_MASK, 0x00000007 },
+	{ TEGRA186_DSPK_RX_CIF_CTRL, 0x00007700 },
+	{ TEGRA186_DSPK_CG,	     0x00000001 },
+	{ TEGRA186_DSPK_CORE_CTRL,   0x00000310 },
+	{ TEGRA186_DSPK_CODEC_CTRL,  0x03000000 },
+};
+
+static int tegra186_dspk_get_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+
+	if (strstr(kcontrol->id.name, "FIFO Threshold"))
+		ucontrol->value.integer.value[0] = dspk->rx_fifo_th;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		ucontrol->value.integer.value[0] = dspk->osr_val;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		ucontrol->value.integer.value[0] = dspk->lrsel;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		ucontrol->value.integer.value[0] = dspk->ch_sel;
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		ucontrol->value.integer.value[0] = dspk->mono_to_stereo;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		ucontrol->value.integer.value[0] = dspk->stereo_to_mono;
+
+	return 0;
+}
+
+static int tegra186_dspk_put_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+	int val = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "FIFO Threshold"))
+		dspk->rx_fifo_th = val;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		dspk->osr_val = val;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		dspk->lrsel = val;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		dspk->ch_sel = val;
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		dspk->mono_to_stereo = val;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		dspk->stereo_to_mono = val;
+
+	return 0;
+}
+
+static int tegra186_dspk_runtime_suspend(struct device *dev)
+{
+	struct tegra186_dspk *dspk = dev_get_drvdata(dev);
+
+	regcache_cache_only(dspk->regmap, true);
+	regcache_mark_dirty(dspk->regmap);
+
+	clk_disable_unprepare(dspk->clk_dspk);
+
+	return 0;
+}
+
+static int tegra186_dspk_runtime_resume(struct device *dev)
+{
+	struct tegra186_dspk *dspk = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(dspk->clk_dspk);
+	if (err) {
+		dev_err(dev, "failed to enable DSPK clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(dspk->regmap, false);
+	regcache_sync(dspk->regmap);
+
+	return 0;
+}
+
+static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai);
+	unsigned int channels, srate, dspk_clk;
+	struct device *dev = dai->dev;
+	struct tegra_cif_conf cif_conf;
+	unsigned int max_th;
+	int err;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+	cif_conf.audio_ch = channels;
+
+	/* Client channel */
+	switch (dspk->ch_sel) {
+	case DSPK_CH_SELECT_LEFT:
+	case DSPK_CH_SELECT_RIGHT:
+		cif_conf.client_ch = 1;
+		break;
+	case DSPK_CH_SELECT_STEREO:
+		cif_conf.client_ch = 2;
+		break;
+	default:
+		dev_err(dev, "Invalid DSPK client channels\n");
+		return -EINVAL;
+	}
+
+	cif_conf.client_bits = TEGRA_ACIF_BITS_24;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	srate = params_rate(params);
+
+	/* RX FIFO threshold in terms of frames */
+	max_th = (TEGRA186_DSPK_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
+
+	if (dspk->rx_fifo_th > max_th)
+		dspk->rx_fifo_th = max_th;
+
+	cif_conf.threshold = dspk->rx_fifo_th;
+	cif_conf.mono_conv = dspk->mono_to_stereo;
+	cif_conf.stereo_conv = dspk->stereo_to_mono;
+
+	tegra_set_cif(dspk->regmap, TEGRA186_DSPK_RX_CIF_CTRL,
+		      &cif_conf);
+
+	/*
+	 * DSPK clock and PDM codec clock should be synchronous with 4:1 ratio,
+	 * this is because it takes 4 clock cycles to send out one sample to
+	 * codec by sigma delta modulator. Finally the clock rate is a multiple
+	 * of 'Over Sampling Ratio', 'Sample Rate' and 'Interface Clock Ratio'.
+	 */
+	dspk_clk = (DSPK_OSR_FACTOR << dspk->osr_val) * srate * DSPK_CLK_RATIO;
+
+	err = clk_set_rate(dspk->clk_dspk, dspk_clk);
+	if (err) {
+		dev_err(dev, "can't set DSPK clock rate %u, err: %d\n",
+			dspk_clk, err);
+
+		return err;
+	}
+
+	regmap_update_bits(dspk->regmap,
+			   /* Reg */
+			   TEGRA186_DSPK_CORE_CTRL,
+			   /* Mask */
+			   TEGRA186_DSPK_OSR_MASK |
+			   TEGRA186_DSPK_CHANNEL_SELECT_MASK |
+			   TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK,
+			   /* Value */
+			   (dspk->osr_val << DSPK_OSR_SHIFT) |
+			   ((dspk->ch_sel + 1) << CH_SEL_SHIFT) |
+			   (dspk->lrsel << LRSEL_POL_SHIFT));
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra186_dspk_dai_ops = {
+	.hw_params	= tegra186_dspk_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
+	{
+	    .name = "DSPK",
+	    .playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S32_LE,
+	    },
+	    .ops = &tegra186_dspk_dai_ops,
+	    .symmetric_rates = 1,
+	},
+};
+
+static const struct snd_soc_dapm_widget tegra186_dspk_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA186_DSPK_ENABLE, 0, 0),
+};
+
+static const struct snd_soc_dapm_route tegra186_dspk_routes[] = {
+	{ "RX",		NULL, "XBAR-TX" },
+	{ "Playback",	NULL, "RX" },
+};
+
+static const char * const tegra186_dspk_ch_sel_text[] = {
+	"Left", "Right", "Stereo",
+};
+
+static const struct soc_enum tegra186_dspk_ch_sel_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_ch_sel_text),
+			tegra186_dspk_ch_sel_text);
+
+static const char * const tegra186_dspk_osr_text[] = {
+	"OSR_32", "OSR_64", "OSR_128", "OSR_256",
+};
+
+static const struct soc_enum tegra186_dspk_osr_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_osr_text),
+			tegra186_dspk_osr_text);
+
+static const char * const tegra186_dspk_lrsel_text[] = {
+	"Left", "Right",
+};
+
+static const char * const tegra186_dspk_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+static const struct soc_enum tegra186_dspk_mono_conv_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+			ARRAY_SIZE(tegra186_dspk_mono_conv_text),
+			tegra186_dspk_mono_conv_text);
+
+static const char * const tegra186_dspk_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const struct soc_enum tegra186_dspk_stereo_conv_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+			ARRAY_SIZE(tegra186_dspk_stereo_conv_text),
+			tegra186_dspk_stereo_conv_text);
+
+static const struct soc_enum tegra186_dspk_lrsel_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_lrsel_text),
+			tegra186_dspk_lrsel_text);
+
+static const struct snd_kcontrol_new tegrat186_dspk_controls[] = {
+	SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM, 0,
+		       TEGRA186_DSPK_RX_FIFO_DEPTH - 1, 0,
+		       tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+};
+
+static const struct snd_soc_component_driver tegra186_dspk_cmpnt = {
+	.dapm_widgets = tegra186_dspk_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets),
+	.dapm_routes = tegra186_dspk_routes,
+	.num_dapm_routes = ARRAY_SIZE(tegra186_dspk_routes),
+	.controls = tegrat186_dspk_controls,
+	.num_controls = ARRAY_SIZE(tegrat186_dspk_controls),
+};
+
+static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA186_DSPK_RX_INT_MASK ... TEGRA186_DSPK_RX_CIF_CTRL:
+	case TEGRA186_DSPK_ENABLE ... TEGRA186_DSPK_CG:
+	case TEGRA186_DSPK_CORE_CTRL ... TEGRA186_DSPK_CODEC_CTRL:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra186_dspk_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA186_DSPK_RX_STATUS:
+	case TEGRA186_DSPK_RX_INT_STATUS:
+	case TEGRA186_DSPK_STATUS:
+	case TEGRA186_DSPK_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA186_DSPK_RX_STATUS:
+	case TEGRA186_DSPK_RX_INT_STATUS:
+	case TEGRA186_DSPK_STATUS:
+	case TEGRA186_DSPK_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra186_dspk_regmap = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA186_DSPK_CODEC_CTRL,
+	.writeable_reg		= tegra186_dspk_wr_reg,
+	.readable_reg		= tegra186_dspk_rd_reg,
+	.volatile_reg		= tegra186_dspk_volatile_reg,
+	.reg_defaults		= tegra186_dspk_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra186_dspk_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct of_device_id tegra186_dspk_of_match[] = {
+	{ .compatible = "nvidia,tegra186-dspk" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match);
+
+static int tegra186_dspk_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra186_dspk *dspk;
+	void __iomem *regs;
+	int err;
+
+	dspk = devm_kzalloc(dev, sizeof(*dspk), GFP_KERNEL);
+	if (!dspk)
+		return -ENOMEM;
+
+	dspk->osr_val = DSPK_OSR_64;
+	dspk->lrsel = DSPK_LRSEL_LEFT;
+	dspk->ch_sel = DSPK_CH_SELECT_STEREO;
+	dspk->mono_to_stereo = 0; /* "Zero" */
+
+	dev_set_drvdata(dev, dspk);
+
+	dspk->clk_dspk = devm_clk_get(dev, "dspk");
+	if (IS_ERR(dspk->clk_dspk)) {
+		dev_err(dev, "can't retrieve DSPK clock\n");
+		return PTR_ERR(dspk->clk_dspk);
+	}
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	dspk->regmap = devm_regmap_init_mmio(dev, regs, &tegra186_dspk_regmap);
+	if (IS_ERR(dspk->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(dspk->regmap);
+	}
+
+	regcache_cache_only(dspk->regmap, true);
+
+	err = devm_snd_soc_register_component(dev, &tegra186_dspk_cmpnt,
+					      tegra186_dspk_dais,
+					      ARRAY_SIZE(tegra186_dspk_dais));
+	if (err) {
+		dev_err(dev, "can't register DSPK component, err: %d\n",
+			err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra186_dspk_platform_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra186_dspk_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend,
+			   tegra186_dspk_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra186_dspk_driver = {
+	.driver = {
+		.name = "tegra186-dspk",
+		.of_match_table = tegra186_dspk_of_match,
+		.pm = &tegra186_dspk_pm_ops,
+	},
+	.probe = tegra186_dspk_platform_probe,
+	.remove = tegra186_dspk_platform_remove,
+};
+module_platform_driver(tegra186_dspk_driver);
+
+MODULE_AUTHOR("Mohan Kumar <mkumard-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
+MODULE_AUTHOR("Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>");
+MODULE_DESCRIPTION("Tegra186 ASoC DSPK driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra186_dspk.h b/sound/soc/tegra/tegra186_dspk.h
new file mode 100644
index 0000000..b2a87906
--- /dev/null
+++ b/sound/soc/tegra/tegra186_dspk.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra186_dspk.h - Definitions for Tegra186 DSPK driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA186_DSPK_H__
+#define __TEGRA186_DSPK_H__
+
+/* Register offsets from DSPK BASE */
+#define TEGRA186_DSPK_RX_STATUS			0x0c
+#define TEGRA186_DSPK_RX_INT_STATUS		0x10
+#define TEGRA186_DSPK_RX_INT_MASK		0x14
+#define TEGRA186_DSPK_RX_INT_SET		0x18
+#define TEGRA186_DSPK_RX_INT_CLEAR		0x1c
+#define TEGRA186_DSPK_RX_CIF_CTRL		0x20
+#define TEGRA186_DSPK_ENABLE			0x40
+#define TEGRA186_DSPK_SOFT_RESET		0x44
+#define TEGRA186_DSPK_CG			0x48
+#define TEGRA186_DSPK_STATUS			0x4c
+#define TEGRA186_DSPK_INT_STATUS		0x50
+#define TEGRA186_DSPK_CORE_CTRL			0x60
+#define TEGRA186_DSPK_CODEC_CTRL		0x64
+
+/* DSPK CORE CONTROL fields */
+#define CH_SEL_SHIFT				8
+#define TEGRA186_DSPK_CHANNEL_SELECT_MASK	(0x3 << CH_SEL_SHIFT)
+#define DSPK_OSR_SHIFT				4
+#define TEGRA186_DSPK_OSR_MASK			(0x3 << DSPK_OSR_SHIFT)
+#define LRSEL_POL_SHIFT				0
+#define TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK	(0x1 << LRSEL_POL_SHIFT)
+#define TEGRA186_DSPK_RX_FIFO_DEPTH		64
+
+#define DSPK_OSR_FACTOR				32
+
+/* DSPK interface clock ratio */
+#define DSPK_CLK_RATIO				4
+
+enum tegra_dspk_osr {
+	DSPK_OSR_32,
+	DSPK_OSR_64,
+	DSPK_OSR_128,
+	DSPK_OSR_256,
+};
+
+enum tegra_dspk_ch_sel {
+	DSPK_CH_SELECT_LEFT,
+	DSPK_CH_SELECT_RIGHT,
+	DSPK_CH_SELECT_STEREO,
+};
+
+enum tegra_dspk_lrsel {
+	DSPK_LRSEL_LEFT,
+	DSPK_LRSEL_RIGHT,
+};
+
+struct tegra186_dspk {
+	unsigned int rx_fifo_th;
+	unsigned int osr_val;
+	unsigned int lrsel;
+	unsigned int ch_sel;
+	unsigned int mono_to_stereo;
+	unsigned int stereo_to_mono;
+	struct clk *clk_dspk;
+	struct regmap *regmap;
+};
+
+#endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 06/23] ASoC: tegra: Add Tegra186 based DSPK driver
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

The Digital Speaker Controller (DSPK) converts the multi-bit Pulse Code
Modulation (PCM) audio input to oversampled 1-bit Pulse Density Modulation
(PDM) output. From the signal flow perpsective, the DSPK can be viewed as
a PDM transmitter that up-samples the input to the desired sampling rate
by interpolation then converts the oversampled PCM input to the desired
1-bit output via Delta Sigma Modulation (DSM).

This patch registers DSPK component with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes DSPK interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The DSPK devices can be enabled in the DT via
"nvidia,tegra186-dspk" compatible binding. This driver can be used
on Tegra194 chip as well.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig         |  13 ++
 sound/soc/tegra/Makefile        |   2 +
 sound/soc/tegra/tegra186_dspk.c | 427 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra186_dspk.h |  70 +++++++
 4 files changed, 512 insertions(+)
 create mode 100644 sound/soc/tegra/tegra186_dspk.c
 create mode 100644 sound/soc/tegra/tegra186_dspk.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 3166d03..63d5ae9 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -93,6 +93,19 @@ config SND_SOC_TEGRA210_I2S
           compatible devices.
           Say Y or M if you want to add support for Tegra210 I2S module.
 
+config SND_SOC_TEGRA186_DSPK
+	tristate "Tegra186 DSPK module"
+	depends on SND_SOC_TEGRA
+	help
+	  Config to enable the Digital Speaker Controller (DSPK) which
+	  converts the multi-bit Pulse Code Modulation (PCM) audio input to
+	  oversampled 1-bit Pulse Density Modulation (PDM) output. From the
+	  signal flow perspective DSPK can be viewed as a PDM transmitter
+	  that up-samples the input to the desired sampling rate by
+	  interpolation and then converts the oversampled PCM input to
+	  the desired 1-bit output via Delta Sigma Modulation (DSM).
+	  Say Y or M if you want to add support for Tegra186 DSPK module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index b01d88e..336c4c7 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -11,6 +11,7 @@ snd-soc-tegra30-i2s-objs := tegra30_i2s.o
 snd-soc-tegra210-ahub-objs := tegra210_ahub.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 snd-soc-tegra210-i2s-objs := tegra210_i2s.o
+snd-soc-tegra186-dspk-objs := tegra186_dspk.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -23,6 +24,7 @@ obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
new file mode 100644
index 0000000..d74aec8
--- /dev/null
+++ b/sound/soc/tegra/tegra186_dspk.c
@@ -0,0 +1,427 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra186_dspk.c - Tegra186 DSPK driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra186_dspk.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra186_dspk_reg_defaults[] = {
+	{ TEGRA186_DSPK_RX_INT_MASK, 0x00000007 },
+	{ TEGRA186_DSPK_RX_CIF_CTRL, 0x00007700 },
+	{ TEGRA186_DSPK_CG,	     0x00000001 },
+	{ TEGRA186_DSPK_CORE_CTRL,   0x00000310 },
+	{ TEGRA186_DSPK_CODEC_CTRL,  0x03000000 },
+};
+
+static int tegra186_dspk_get_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+
+	if (strstr(kcontrol->id.name, "FIFO Threshold"))
+		ucontrol->value.integer.value[0] = dspk->rx_fifo_th;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		ucontrol->value.integer.value[0] = dspk->osr_val;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		ucontrol->value.integer.value[0] = dspk->lrsel;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		ucontrol->value.integer.value[0] = dspk->ch_sel;
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		ucontrol->value.integer.value[0] = dspk->mono_to_stereo;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		ucontrol->value.integer.value[0] = dspk->stereo_to_mono;
+
+	return 0;
+}
+
+static int tegra186_dspk_put_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+	int val = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "FIFO Threshold"))
+		dspk->rx_fifo_th = val;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		dspk->osr_val = val;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		dspk->lrsel = val;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		dspk->ch_sel = val;
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		dspk->mono_to_stereo = val;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		dspk->stereo_to_mono = val;
+
+	return 0;
+}
+
+static int tegra186_dspk_runtime_suspend(struct device *dev)
+{
+	struct tegra186_dspk *dspk = dev_get_drvdata(dev);
+
+	regcache_cache_only(dspk->regmap, true);
+	regcache_mark_dirty(dspk->regmap);
+
+	clk_disable_unprepare(dspk->clk_dspk);
+
+	return 0;
+}
+
+static int tegra186_dspk_runtime_resume(struct device *dev)
+{
+	struct tegra186_dspk *dspk = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(dspk->clk_dspk);
+	if (err) {
+		dev_err(dev, "failed to enable DSPK clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(dspk->regmap, false);
+	regcache_sync(dspk->regmap);
+
+	return 0;
+}
+
+static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai);
+	unsigned int channels, srate, dspk_clk;
+	struct device *dev = dai->dev;
+	struct tegra_cif_conf cif_conf;
+	unsigned int max_th;
+	int err;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+	cif_conf.audio_ch = channels;
+
+	/* Client channel */
+	switch (dspk->ch_sel) {
+	case DSPK_CH_SELECT_LEFT:
+	case DSPK_CH_SELECT_RIGHT:
+		cif_conf.client_ch = 1;
+		break;
+	case DSPK_CH_SELECT_STEREO:
+		cif_conf.client_ch = 2;
+		break;
+	default:
+		dev_err(dev, "Invalid DSPK client channels\n");
+		return -EINVAL;
+	}
+
+	cif_conf.client_bits = TEGRA_ACIF_BITS_24;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	srate = params_rate(params);
+
+	/* RX FIFO threshold in terms of frames */
+	max_th = (TEGRA186_DSPK_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
+
+	if (dspk->rx_fifo_th > max_th)
+		dspk->rx_fifo_th = max_th;
+
+	cif_conf.threshold = dspk->rx_fifo_th;
+	cif_conf.mono_conv = dspk->mono_to_stereo;
+	cif_conf.stereo_conv = dspk->stereo_to_mono;
+
+	tegra_set_cif(dspk->regmap, TEGRA186_DSPK_RX_CIF_CTRL,
+		      &cif_conf);
+
+	/*
+	 * DSPK clock and PDM codec clock should be synchronous with 4:1 ratio,
+	 * this is because it takes 4 clock cycles to send out one sample to
+	 * codec by sigma delta modulator. Finally the clock rate is a multiple
+	 * of 'Over Sampling Ratio', 'Sample Rate' and 'Interface Clock Ratio'.
+	 */
+	dspk_clk = (DSPK_OSR_FACTOR << dspk->osr_val) * srate * DSPK_CLK_RATIO;
+
+	err = clk_set_rate(dspk->clk_dspk, dspk_clk);
+	if (err) {
+		dev_err(dev, "can't set DSPK clock rate %u, err: %d\n",
+			dspk_clk, err);
+
+		return err;
+	}
+
+	regmap_update_bits(dspk->regmap,
+			   /* Reg */
+			   TEGRA186_DSPK_CORE_CTRL,
+			   /* Mask */
+			   TEGRA186_DSPK_OSR_MASK |
+			   TEGRA186_DSPK_CHANNEL_SELECT_MASK |
+			   TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK,
+			   /* Value */
+			   (dspk->osr_val << DSPK_OSR_SHIFT) |
+			   ((dspk->ch_sel + 1) << CH_SEL_SHIFT) |
+			   (dspk->lrsel << LRSEL_POL_SHIFT));
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra186_dspk_dai_ops = {
+	.hw_params	= tegra186_dspk_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
+	{
+	    .name = "DSPK",
+	    .playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S32_LE,
+	    },
+	    .ops = &tegra186_dspk_dai_ops,
+	    .symmetric_rates = 1,
+	},
+};
+
+static const struct snd_soc_dapm_widget tegra186_dspk_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA186_DSPK_ENABLE, 0, 0),
+};
+
+static const struct snd_soc_dapm_route tegra186_dspk_routes[] = {
+	{ "RX",		NULL, "XBAR-TX" },
+	{ "Playback",	NULL, "RX" },
+};
+
+static const char * const tegra186_dspk_ch_sel_text[] = {
+	"Left", "Right", "Stereo",
+};
+
+static const struct soc_enum tegra186_dspk_ch_sel_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_ch_sel_text),
+			tegra186_dspk_ch_sel_text);
+
+static const char * const tegra186_dspk_osr_text[] = {
+	"OSR_32", "OSR_64", "OSR_128", "OSR_256",
+};
+
+static const struct soc_enum tegra186_dspk_osr_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_osr_text),
+			tegra186_dspk_osr_text);
+
+static const char * const tegra186_dspk_lrsel_text[] = {
+	"Left", "Right",
+};
+
+static const char * const tegra186_dspk_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+static const struct soc_enum tegra186_dspk_mono_conv_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+			ARRAY_SIZE(tegra186_dspk_mono_conv_text),
+			tegra186_dspk_mono_conv_text);
+
+static const char * const tegra186_dspk_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const struct soc_enum tegra186_dspk_stereo_conv_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+			ARRAY_SIZE(tegra186_dspk_stereo_conv_text),
+			tegra186_dspk_stereo_conv_text);
+
+static const struct soc_enum tegra186_dspk_lrsel_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_lrsel_text),
+			tegra186_dspk_lrsel_text);
+
+static const struct snd_kcontrol_new tegrat186_dspk_controls[] = {
+	SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM, 0,
+		       TEGRA186_DSPK_RX_FIFO_DEPTH - 1, 0,
+		       tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+};
+
+static const struct snd_soc_component_driver tegra186_dspk_cmpnt = {
+	.dapm_widgets = tegra186_dspk_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets),
+	.dapm_routes = tegra186_dspk_routes,
+	.num_dapm_routes = ARRAY_SIZE(tegra186_dspk_routes),
+	.controls = tegrat186_dspk_controls,
+	.num_controls = ARRAY_SIZE(tegrat186_dspk_controls),
+};
+
+static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA186_DSPK_RX_INT_MASK ... TEGRA186_DSPK_RX_CIF_CTRL:
+	case TEGRA186_DSPK_ENABLE ... TEGRA186_DSPK_CG:
+	case TEGRA186_DSPK_CORE_CTRL ... TEGRA186_DSPK_CODEC_CTRL:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra186_dspk_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA186_DSPK_RX_STATUS:
+	case TEGRA186_DSPK_RX_INT_STATUS:
+	case TEGRA186_DSPK_STATUS:
+	case TEGRA186_DSPK_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA186_DSPK_RX_STATUS:
+	case TEGRA186_DSPK_RX_INT_STATUS:
+	case TEGRA186_DSPK_STATUS:
+	case TEGRA186_DSPK_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra186_dspk_regmap = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA186_DSPK_CODEC_CTRL,
+	.writeable_reg		= tegra186_dspk_wr_reg,
+	.readable_reg		= tegra186_dspk_rd_reg,
+	.volatile_reg		= tegra186_dspk_volatile_reg,
+	.reg_defaults		= tegra186_dspk_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra186_dspk_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct of_device_id tegra186_dspk_of_match[] = {
+	{ .compatible = "nvidia,tegra186-dspk" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match);
+
+static int tegra186_dspk_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra186_dspk *dspk;
+	void __iomem *regs;
+	int err;
+
+	dspk = devm_kzalloc(dev, sizeof(*dspk), GFP_KERNEL);
+	if (!dspk)
+		return -ENOMEM;
+
+	dspk->osr_val = DSPK_OSR_64;
+	dspk->lrsel = DSPK_LRSEL_LEFT;
+	dspk->ch_sel = DSPK_CH_SELECT_STEREO;
+	dspk->mono_to_stereo = 0; /* "Zero" */
+
+	dev_set_drvdata(dev, dspk);
+
+	dspk->clk_dspk = devm_clk_get(dev, "dspk");
+	if (IS_ERR(dspk->clk_dspk)) {
+		dev_err(dev, "can't retrieve DSPK clock\n");
+		return PTR_ERR(dspk->clk_dspk);
+	}
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	dspk->regmap = devm_regmap_init_mmio(dev, regs, &tegra186_dspk_regmap);
+	if (IS_ERR(dspk->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(dspk->regmap);
+	}
+
+	regcache_cache_only(dspk->regmap, true);
+
+	err = devm_snd_soc_register_component(dev, &tegra186_dspk_cmpnt,
+					      tegra186_dspk_dais,
+					      ARRAY_SIZE(tegra186_dspk_dais));
+	if (err) {
+		dev_err(dev, "can't register DSPK component, err: %d\n",
+			err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra186_dspk_platform_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra186_dspk_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend,
+			   tegra186_dspk_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra186_dspk_driver = {
+	.driver = {
+		.name = "tegra186-dspk",
+		.of_match_table = tegra186_dspk_of_match,
+		.pm = &tegra186_dspk_pm_ops,
+	},
+	.probe = tegra186_dspk_platform_probe,
+	.remove = tegra186_dspk_platform_remove,
+};
+module_platform_driver(tegra186_dspk_driver);
+
+MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
+MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");
+MODULE_DESCRIPTION("Tegra186 ASoC DSPK driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra186_dspk.h b/sound/soc/tegra/tegra186_dspk.h
new file mode 100644
index 0000000..b2a87906
--- /dev/null
+++ b/sound/soc/tegra/tegra186_dspk.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra186_dspk.h - Definitions for Tegra186 DSPK driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA186_DSPK_H__
+#define __TEGRA186_DSPK_H__
+
+/* Register offsets from DSPK BASE */
+#define TEGRA186_DSPK_RX_STATUS			0x0c
+#define TEGRA186_DSPK_RX_INT_STATUS		0x10
+#define TEGRA186_DSPK_RX_INT_MASK		0x14
+#define TEGRA186_DSPK_RX_INT_SET		0x18
+#define TEGRA186_DSPK_RX_INT_CLEAR		0x1c
+#define TEGRA186_DSPK_RX_CIF_CTRL		0x20
+#define TEGRA186_DSPK_ENABLE			0x40
+#define TEGRA186_DSPK_SOFT_RESET		0x44
+#define TEGRA186_DSPK_CG			0x48
+#define TEGRA186_DSPK_STATUS			0x4c
+#define TEGRA186_DSPK_INT_STATUS		0x50
+#define TEGRA186_DSPK_CORE_CTRL			0x60
+#define TEGRA186_DSPK_CODEC_CTRL		0x64
+
+/* DSPK CORE CONTROL fields */
+#define CH_SEL_SHIFT				8
+#define TEGRA186_DSPK_CHANNEL_SELECT_MASK	(0x3 << CH_SEL_SHIFT)
+#define DSPK_OSR_SHIFT				4
+#define TEGRA186_DSPK_OSR_MASK			(0x3 << DSPK_OSR_SHIFT)
+#define LRSEL_POL_SHIFT				0
+#define TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK	(0x1 << LRSEL_POL_SHIFT)
+#define TEGRA186_DSPK_RX_FIFO_DEPTH		64
+
+#define DSPK_OSR_FACTOR				32
+
+/* DSPK interface clock ratio */
+#define DSPK_CLK_RATIO				4
+
+enum tegra_dspk_osr {
+	DSPK_OSR_32,
+	DSPK_OSR_64,
+	DSPK_OSR_128,
+	DSPK_OSR_256,
+};
+
+enum tegra_dspk_ch_sel {
+	DSPK_CH_SELECT_LEFT,
+	DSPK_CH_SELECT_RIGHT,
+	DSPK_CH_SELECT_STEREO,
+};
+
+enum tegra_dspk_lrsel {
+	DSPK_LRSEL_LEFT,
+	DSPK_LRSEL_RIGHT,
+};
+
+struct tegra186_dspk {
+	unsigned int rx_fifo_th;
+	unsigned int osr_val;
+	unsigned int lrsel;
+	unsigned int ch_sel;
+	unsigned int mono_to_stereo;
+	unsigned int stereo_to_mono;
+	struct clk *clk_dspk;
+	struct regmap *regmap;
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 06/23] ASoC: tegra: Add Tegra186 based DSPK driver
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

The Digital Speaker Controller (DSPK) converts the multi-bit Pulse Code
Modulation (PCM) audio input to oversampled 1-bit Pulse Density Modulation
(PDM) output. From the signal flow perpsective, the DSPK can be viewed as
a PDM transmitter that up-samples the input to the desired sampling rate
by interpolation then converts the oversampled PCM input to the desired
1-bit output via Delta Sigma Modulation (DSM).

This patch registers DSPK component with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes DSPK interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The DSPK devices can be enabled in the DT via
"nvidia,tegra186-dspk" compatible binding. This driver can be used
on Tegra194 chip as well.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig         |  13 ++
 sound/soc/tegra/Makefile        |   2 +
 sound/soc/tegra/tegra186_dspk.c | 427 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra186_dspk.h |  70 +++++++
 4 files changed, 512 insertions(+)
 create mode 100644 sound/soc/tegra/tegra186_dspk.c
 create mode 100644 sound/soc/tegra/tegra186_dspk.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 3166d03..63d5ae9 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -93,6 +93,19 @@ config SND_SOC_TEGRA210_I2S
           compatible devices.
           Say Y or M if you want to add support for Tegra210 I2S module.
 
+config SND_SOC_TEGRA186_DSPK
+	tristate "Tegra186 DSPK module"
+	depends on SND_SOC_TEGRA
+	help
+	  Config to enable the Digital Speaker Controller (DSPK) which
+	  converts the multi-bit Pulse Code Modulation (PCM) audio input to
+	  oversampled 1-bit Pulse Density Modulation (PDM) output. From the
+	  signal flow perspective DSPK can be viewed as a PDM transmitter
+	  that up-samples the input to the desired sampling rate by
+	  interpolation and then converts the oversampled PCM input to
+	  the desired 1-bit output via Delta Sigma Modulation (DSM).
+	  Say Y or M if you want to add support for Tegra186 DSPK module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index b01d88e..336c4c7 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -11,6 +11,7 @@ snd-soc-tegra30-i2s-objs := tegra30_i2s.o
 snd-soc-tegra210-ahub-objs := tegra210_ahub.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 snd-soc-tegra210-i2s-objs := tegra210_i2s.o
+snd-soc-tegra186-dspk-objs := tegra186_dspk.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -23,6 +24,7 @@ obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
new file mode 100644
index 0000000..d74aec8
--- /dev/null
+++ b/sound/soc/tegra/tegra186_dspk.c
@@ -0,0 +1,427 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra186_dspk.c - Tegra186 DSPK driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra186_dspk.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra186_dspk_reg_defaults[] = {
+	{ TEGRA186_DSPK_RX_INT_MASK, 0x00000007 },
+	{ TEGRA186_DSPK_RX_CIF_CTRL, 0x00007700 },
+	{ TEGRA186_DSPK_CG,	     0x00000001 },
+	{ TEGRA186_DSPK_CORE_CTRL,   0x00000310 },
+	{ TEGRA186_DSPK_CODEC_CTRL,  0x03000000 },
+};
+
+static int tegra186_dspk_get_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+
+	if (strstr(kcontrol->id.name, "FIFO Threshold"))
+		ucontrol->value.integer.value[0] = dspk->rx_fifo_th;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		ucontrol->value.integer.value[0] = dspk->osr_val;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		ucontrol->value.integer.value[0] = dspk->lrsel;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		ucontrol->value.integer.value[0] = dspk->ch_sel;
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		ucontrol->value.integer.value[0] = dspk->mono_to_stereo;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		ucontrol->value.integer.value[0] = dspk->stereo_to_mono;
+
+	return 0;
+}
+
+static int tegra186_dspk_put_control(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+	int val = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "FIFO Threshold"))
+		dspk->rx_fifo_th = val;
+	else if (strstr(kcontrol->id.name, "OSR Value"))
+		dspk->osr_val = val;
+	else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+		dspk->lrsel = val;
+	else if (strstr(kcontrol->id.name, "Channel Select"))
+		dspk->ch_sel = val;
+	else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+		dspk->mono_to_stereo = val;
+	else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+		dspk->stereo_to_mono = val;
+
+	return 0;
+}
+
+static int tegra186_dspk_runtime_suspend(struct device *dev)
+{
+	struct tegra186_dspk *dspk = dev_get_drvdata(dev);
+
+	regcache_cache_only(dspk->regmap, true);
+	regcache_mark_dirty(dspk->regmap);
+
+	clk_disable_unprepare(dspk->clk_dspk);
+
+	return 0;
+}
+
+static int tegra186_dspk_runtime_resume(struct device *dev)
+{
+	struct tegra186_dspk *dspk = dev_get_drvdata(dev);
+	int err;
+
+	err = clk_prepare_enable(dspk->clk_dspk);
+	if (err) {
+		dev_err(dev, "failed to enable DSPK clock, err: %d\n", err);
+		return err;
+	}
+
+	regcache_cache_only(dspk->regmap, false);
+	regcache_sync(dspk->regmap);
+
+	return 0;
+}
+
+static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai);
+	unsigned int channels, srate, dspk_clk;
+	struct device *dev = dai->dev;
+	struct tegra_cif_conf cif_conf;
+	unsigned int max_th;
+	int err;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	channels = params_channels(params);
+	cif_conf.audio_ch = channels;
+
+	/* Client channel */
+	switch (dspk->ch_sel) {
+	case DSPK_CH_SELECT_LEFT:
+	case DSPK_CH_SELECT_RIGHT:
+		cif_conf.client_ch = 1;
+		break;
+	case DSPK_CH_SELECT_STEREO:
+		cif_conf.client_ch = 2;
+		break;
+	default:
+		dev_err(dev, "Invalid DSPK client channels\n");
+		return -EINVAL;
+	}
+
+	cif_conf.client_bits = TEGRA_ACIF_BITS_24;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		break;
+	default:
+		dev_err(dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	srate = params_rate(params);
+
+	/* RX FIFO threshold in terms of frames */
+	max_th = (TEGRA186_DSPK_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
+
+	if (dspk->rx_fifo_th > max_th)
+		dspk->rx_fifo_th = max_th;
+
+	cif_conf.threshold = dspk->rx_fifo_th;
+	cif_conf.mono_conv = dspk->mono_to_stereo;
+	cif_conf.stereo_conv = dspk->stereo_to_mono;
+
+	tegra_set_cif(dspk->regmap, TEGRA186_DSPK_RX_CIF_CTRL,
+		      &cif_conf);
+
+	/*
+	 * DSPK clock and PDM codec clock should be synchronous with 4:1 ratio,
+	 * this is because it takes 4 clock cycles to send out one sample to
+	 * codec by sigma delta modulator. Finally the clock rate is a multiple
+	 * of 'Over Sampling Ratio', 'Sample Rate' and 'Interface Clock Ratio'.
+	 */
+	dspk_clk = (DSPK_OSR_FACTOR << dspk->osr_val) * srate * DSPK_CLK_RATIO;
+
+	err = clk_set_rate(dspk->clk_dspk, dspk_clk);
+	if (err) {
+		dev_err(dev, "can't set DSPK clock rate %u, err: %d\n",
+			dspk_clk, err);
+
+		return err;
+	}
+
+	regmap_update_bits(dspk->regmap,
+			   /* Reg */
+			   TEGRA186_DSPK_CORE_CTRL,
+			   /* Mask */
+			   TEGRA186_DSPK_OSR_MASK |
+			   TEGRA186_DSPK_CHANNEL_SELECT_MASK |
+			   TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK,
+			   /* Value */
+			   (dspk->osr_val << DSPK_OSR_SHIFT) |
+			   ((dspk->ch_sel + 1) << CH_SEL_SHIFT) |
+			   (dspk->lrsel << LRSEL_POL_SHIFT));
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tegra186_dspk_dai_ops = {
+	.hw_params	= tegra186_dspk_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
+	{
+	    .name = "DSPK",
+	    .playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S32_LE,
+	    },
+	    .ops = &tegra186_dspk_dai_ops,
+	    .symmetric_rates = 1,
+	},
+};
+
+static const struct snd_soc_dapm_widget tegra186_dspk_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA186_DSPK_ENABLE, 0, 0),
+};
+
+static const struct snd_soc_dapm_route tegra186_dspk_routes[] = {
+	{ "RX",		NULL, "XBAR-TX" },
+	{ "Playback",	NULL, "RX" },
+};
+
+static const char * const tegra186_dspk_ch_sel_text[] = {
+	"Left", "Right", "Stereo",
+};
+
+static const struct soc_enum tegra186_dspk_ch_sel_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_ch_sel_text),
+			tegra186_dspk_ch_sel_text);
+
+static const char * const tegra186_dspk_osr_text[] = {
+	"OSR_32", "OSR_64", "OSR_128", "OSR_256",
+};
+
+static const struct soc_enum tegra186_dspk_osr_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_osr_text),
+			tegra186_dspk_osr_text);
+
+static const char * const tegra186_dspk_lrsel_text[] = {
+	"Left", "Right",
+};
+
+static const char * const tegra186_dspk_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+static const struct soc_enum tegra186_dspk_mono_conv_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+			ARRAY_SIZE(tegra186_dspk_mono_conv_text),
+			tegra186_dspk_mono_conv_text);
+
+static const char * const tegra186_dspk_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const struct soc_enum tegra186_dspk_stereo_conv_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+			ARRAY_SIZE(tegra186_dspk_stereo_conv_text),
+			tegra186_dspk_stereo_conv_text);
+
+static const struct soc_enum tegra186_dspk_lrsel_enum =
+	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_lrsel_text),
+			tegra186_dspk_lrsel_text);
+
+static const struct snd_kcontrol_new tegrat186_dspk_controls[] = {
+	SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM, 0,
+		       TEGRA186_DSPK_RX_FIFO_DEPTH - 1, 0,
+		       tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+	SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum,
+		     tegra186_dspk_get_control, tegra186_dspk_put_control),
+};
+
+static const struct snd_soc_component_driver tegra186_dspk_cmpnt = {
+	.dapm_widgets = tegra186_dspk_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets),
+	.dapm_routes = tegra186_dspk_routes,
+	.num_dapm_routes = ARRAY_SIZE(tegra186_dspk_routes),
+	.controls = tegrat186_dspk_controls,
+	.num_controls = ARRAY_SIZE(tegrat186_dspk_controls),
+};
+
+static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA186_DSPK_RX_INT_MASK ... TEGRA186_DSPK_RX_CIF_CTRL:
+	case TEGRA186_DSPK_ENABLE ... TEGRA186_DSPK_CG:
+	case TEGRA186_DSPK_CORE_CTRL ... TEGRA186_DSPK_CODEC_CTRL:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg)
+{
+	if (tegra186_dspk_wr_reg(dev, reg))
+		return true;
+
+	switch (reg) {
+	case TEGRA186_DSPK_RX_STATUS:
+	case TEGRA186_DSPK_RX_INT_STATUS:
+	case TEGRA186_DSPK_STATUS:
+	case TEGRA186_DSPK_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TEGRA186_DSPK_RX_STATUS:
+	case TEGRA186_DSPK_RX_INT_STATUS:
+	case TEGRA186_DSPK_STATUS:
+	case TEGRA186_DSPK_INT_STATUS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tegra186_dspk_regmap = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA186_DSPK_CODEC_CTRL,
+	.writeable_reg		= tegra186_dspk_wr_reg,
+	.readable_reg		= tegra186_dspk_rd_reg,
+	.volatile_reg		= tegra186_dspk_volatile_reg,
+	.reg_defaults		= tegra186_dspk_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tegra186_dspk_reg_defaults),
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct of_device_id tegra186_dspk_of_match[] = {
+	{ .compatible = "nvidia,tegra186-dspk" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match);
+
+static int tegra186_dspk_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tegra186_dspk *dspk;
+	void __iomem *regs;
+	int err;
+
+	dspk = devm_kzalloc(dev, sizeof(*dspk), GFP_KERNEL);
+	if (!dspk)
+		return -ENOMEM;
+
+	dspk->osr_val = DSPK_OSR_64;
+	dspk->lrsel = DSPK_LRSEL_LEFT;
+	dspk->ch_sel = DSPK_CH_SELECT_STEREO;
+	dspk->mono_to_stereo = 0; /* "Zero" */
+
+	dev_set_drvdata(dev, dspk);
+
+	dspk->clk_dspk = devm_clk_get(dev, "dspk");
+	if (IS_ERR(dspk->clk_dspk)) {
+		dev_err(dev, "can't retrieve DSPK clock\n");
+		return PTR_ERR(dspk->clk_dspk);
+	}
+
+	regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	dspk->regmap = devm_regmap_init_mmio(dev, regs, &tegra186_dspk_regmap);
+	if (IS_ERR(dspk->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(dspk->regmap);
+	}
+
+	regcache_cache_only(dspk->regmap, true);
+
+	err = devm_snd_soc_register_component(dev, &tegra186_dspk_cmpnt,
+					      tegra186_dspk_dais,
+					      ARRAY_SIZE(tegra186_dspk_dais));
+	if (err) {
+		dev_err(dev, "can't register DSPK component, err: %d\n",
+			err);
+		return err;
+	}
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int tegra186_dspk_platform_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra186_dspk_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend,
+			   tegra186_dspk_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra186_dspk_driver = {
+	.driver = {
+		.name = "tegra186-dspk",
+		.of_match_table = tegra186_dspk_of_match,
+		.pm = &tegra186_dspk_pm_ops,
+	},
+	.probe = tegra186_dspk_platform_probe,
+	.remove = tegra186_dspk_platform_remove,
+};
+module_platform_driver(tegra186_dspk_driver);
+
+MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
+MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");
+MODULE_DESCRIPTION("Tegra186 ASoC DSPK driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra186_dspk.h b/sound/soc/tegra/tegra186_dspk.h
new file mode 100644
index 0000000..b2a87906
--- /dev/null
+++ b/sound/soc/tegra/tegra186_dspk.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra186_dspk.h - Definitions for Tegra186 DSPK driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA186_DSPK_H__
+#define __TEGRA186_DSPK_H__
+
+/* Register offsets from DSPK BASE */
+#define TEGRA186_DSPK_RX_STATUS			0x0c
+#define TEGRA186_DSPK_RX_INT_STATUS		0x10
+#define TEGRA186_DSPK_RX_INT_MASK		0x14
+#define TEGRA186_DSPK_RX_INT_SET		0x18
+#define TEGRA186_DSPK_RX_INT_CLEAR		0x1c
+#define TEGRA186_DSPK_RX_CIF_CTRL		0x20
+#define TEGRA186_DSPK_ENABLE			0x40
+#define TEGRA186_DSPK_SOFT_RESET		0x44
+#define TEGRA186_DSPK_CG			0x48
+#define TEGRA186_DSPK_STATUS			0x4c
+#define TEGRA186_DSPK_INT_STATUS		0x50
+#define TEGRA186_DSPK_CORE_CTRL			0x60
+#define TEGRA186_DSPK_CODEC_CTRL		0x64
+
+/* DSPK CORE CONTROL fields */
+#define CH_SEL_SHIFT				8
+#define TEGRA186_DSPK_CHANNEL_SELECT_MASK	(0x3 << CH_SEL_SHIFT)
+#define DSPK_OSR_SHIFT				4
+#define TEGRA186_DSPK_OSR_MASK			(0x3 << DSPK_OSR_SHIFT)
+#define LRSEL_POL_SHIFT				0
+#define TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK	(0x1 << LRSEL_POL_SHIFT)
+#define TEGRA186_DSPK_RX_FIFO_DEPTH		64
+
+#define DSPK_OSR_FACTOR				32
+
+/* DSPK interface clock ratio */
+#define DSPK_CLK_RATIO				4
+
+enum tegra_dspk_osr {
+	DSPK_OSR_32,
+	DSPK_OSR_64,
+	DSPK_OSR_128,
+	DSPK_OSR_256,
+};
+
+enum tegra_dspk_ch_sel {
+	DSPK_CH_SELECT_LEFT,
+	DSPK_CH_SELECT_RIGHT,
+	DSPK_CH_SELECT_STEREO,
+};
+
+enum tegra_dspk_lrsel {
+	DSPK_LRSEL_LEFT,
+	DSPK_LRSEL_RIGHT,
+};
+
+struct tegra186_dspk {
+	unsigned int rx_fifo_th;
+	unsigned int osr_val;
+	unsigned int lrsel;
+	unsigned int ch_sel;
+	unsigned int mono_to_stereo;
+	unsigned int stereo_to_mono;
+	struct clk *clk_dspk;
+	struct regmap *regmap;
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 07/23] ASoC: tegra: Add Tegra210 based ADMAIF driver
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53   ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

ADMAIF is the interface between ADMA and AHUB. Each ADMA channel that
sends/receives data to/from AHUB must intreface through an ADMAIF channel.
ADMA channel sending data to AHUB pairs with an ADMAIF Tx channel and
similarly ADMA channel receiving data from AHUB pairs with an ADMAIF Rx
channel. Buffer size is configurable for each ADMAIF channel, but currently
SW uses default values.

This patch registers ADMAIF driver with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes ADMAIF interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The ADMAIF device can be enabled in the DT via
"nvidia,tegra210-admaif" compatible binding.

Tegra PCM driver is updated to expose required PCM interfaces and
snd_pcm_ops callbacks.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig           |  12 +
 sound/soc/tegra/Makefile          |   2 +
 sound/soc/tegra/tegra210_admaif.c | 845 ++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_admaif.h | 162 ++++++++
 sound/soc/tegra/tegra_pcm.c       | 235 ++++++++++-
 sound/soc/tegra/tegra_pcm.h       |  21 +-
 6 files changed, 1275 insertions(+), 2 deletions(-)
 create mode 100644 sound/soc/tegra/tegra210_admaif.c
 create mode 100644 sound/soc/tegra/tegra210_admaif.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 63d5ae9..0a05992 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -106,6 +106,18 @@ config SND_SOC_TEGRA186_DSPK
 	  the desired 1-bit output via Delta Sigma Modulation (DSM).
 	  Say Y or M if you want to add support for Tegra186 DSPK module.
 
+config SND_SOC_TEGRA210_ADMAIF
+	tristate "Tegra210 ADMAIF module"
+	depends on SND_SOC_TEGRA
+	help
+	  Config to enable ADMAIF which is the interface between ADMA and
+	  Audio Hub (AHUB). Each ADMA channel that sends/receives data to/
+	  from AHUB must interface through an ADMAIF channel. ADMA channel
+	  sending data to AHUB pairs with an ADMAIF Tx channel, where as
+	  ADMA channel receiving data from AHUB pairs with an ADMAIF Rx
+	  channel. Buffer size is configurable for each ADMAIIF channel.
+	  Say Y or M if you want to add support for Tegra210 ADMAIF module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 336c4c7..60040a0 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -12,6 +12,7 @@ snd-soc-tegra210-ahub-objs := tegra210_ahub.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 snd-soc-tegra210-i2s-objs := tegra210_i2s.o
 snd-soc-tegra186-dspk-objs := tegra186_dspk.o
+snd-soc-tegra210-admaif-objs := tegra210_admaif.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o
+obj-$(CONFIG_SND_SOC_TEGRA210_ADMAIF) += snd-soc-tegra210-admaif.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c
new file mode 100644
index 0000000..a8cfacc
--- /dev/null
+++ b/sound/soc/tegra/tegra210_admaif.c
@@ -0,0 +1,845 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_admaif.c - Tegra ADMAIF driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra210_admaif.h"
+#include "tegra_cif.h"
+#include "tegra_pcm.h"
+
+#define CH_REG(offset, reg, id)						       \
+	((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id)))
+
+#define CH_TX_REG(reg, id) CH_REG(admaif->soc_data->tx_base, reg, id)
+
+#define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)
+
+#define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base)		       \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 },	       \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), 0x00007700 },     \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl },	       \
+	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 },	       \
+	{ CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), 0x00007700 },     \
+	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }
+
+#define ADMAIF_REG_DEFAULTS(id, chip)					       \
+	REG_DEFAULTS((id) - 1,						       \
+		chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
+		chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
+		chip ## _ADMAIF_TX_BASE,				       \
+		chip ## _ADMAIF_RX_BASE)
+
+static const struct reg_default tegra186_admaif_reg_defaults[] = {
+	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},
+	ADMAIF_REG_DEFAULTS(1, TEGRA186),
+	ADMAIF_REG_DEFAULTS(2, TEGRA186),
+	ADMAIF_REG_DEFAULTS(3, TEGRA186),
+	ADMAIF_REG_DEFAULTS(4, TEGRA186),
+	ADMAIF_REG_DEFAULTS(5, TEGRA186),
+	ADMAIF_REG_DEFAULTS(6, TEGRA186),
+	ADMAIF_REG_DEFAULTS(7, TEGRA186),
+	ADMAIF_REG_DEFAULTS(8, TEGRA186),
+	ADMAIF_REG_DEFAULTS(9, TEGRA186),
+	ADMAIF_REG_DEFAULTS(10, TEGRA186),
+	ADMAIF_REG_DEFAULTS(11, TEGRA186),
+	ADMAIF_REG_DEFAULTS(12, TEGRA186),
+	ADMAIF_REG_DEFAULTS(13, TEGRA186),
+	ADMAIF_REG_DEFAULTS(14, TEGRA186),
+	ADMAIF_REG_DEFAULTS(15, TEGRA186),
+	ADMAIF_REG_DEFAULTS(16, TEGRA186),
+	ADMAIF_REG_DEFAULTS(17, TEGRA186),
+	ADMAIF_REG_DEFAULTS(18, TEGRA186),
+	ADMAIF_REG_DEFAULTS(19, TEGRA186),
+	ADMAIF_REG_DEFAULTS(20, TEGRA186)
+};
+
+static const struct reg_default tegra210_admaif_reg_defaults[] = {
+	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},
+	ADMAIF_REG_DEFAULTS(1, TEGRA210),
+	ADMAIF_REG_DEFAULTS(2, TEGRA210),
+	ADMAIF_REG_DEFAULTS(3, TEGRA210),
+	ADMAIF_REG_DEFAULTS(4, TEGRA210),
+	ADMAIF_REG_DEFAULTS(5, TEGRA210),
+	ADMAIF_REG_DEFAULTS(6, TEGRA210),
+	ADMAIF_REG_DEFAULTS(7, TEGRA210),
+	ADMAIF_REG_DEFAULTS(8, TEGRA210),
+	ADMAIF_REG_DEFAULTS(9, TEGRA210),
+	ADMAIF_REG_DEFAULTS(10, TEGRA210)
+};
+
+static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
+	unsigned int num_ch = admaif->soc_data->num_ch;
+	unsigned int rx_base = admaif->soc_data->rx_base;
+	unsigned int tx_base = admaif->soc_data->tx_base;
+	unsigned int global_base = admaif->soc_data->global_base;
+	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
+	unsigned int rx_max = rx_base + (num_ch * ch_stride);
+	unsigned int tx_max = tx_base + (num_ch * ch_stride);
+
+	if ((reg >= rx_base) && (reg < rx_max)) {
+		reg = (reg - rx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
+			return true;
+	} else if ((reg >= tx_base) && (reg < tx_max)) {
+		reg = (reg - tx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
+			return true;
+	} else if ((reg >= global_base) && (reg < reg_max)) {
+		if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE))
+			return true;
+	}
+
+	return false;
+}
+
+static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
+	unsigned int num_ch = admaif->soc_data->num_ch;
+	unsigned int rx_base = admaif->soc_data->rx_base;
+	unsigned int tx_base = admaif->soc_data->tx_base;
+	unsigned int global_base = admaif->soc_data->global_base;
+	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
+	unsigned int rx_max = rx_base + (num_ch * ch_stride);
+	unsigned int tx_max = tx_base + (num_ch * ch_stride);
+
+	if ((reg >= rx_base) && (reg < rx_max)) {
+		reg = (reg - rx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
+			return true;
+	} else if ((reg >= tx_base) && (reg < tx_max)) {
+		reg = (reg - tx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
+			return true;
+	} else if ((reg >= global_base) && (reg < reg_max)) {
+		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) ||
+		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_CG_0)) ||
+		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
+			return true;
+	}
+
+	return false;
+}
+
+static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
+	unsigned int num_ch = admaif->soc_data->num_ch;
+	unsigned int rx_base = admaif->soc_data->rx_base;
+	unsigned int tx_base = admaif->soc_data->tx_base;
+	unsigned int global_base = admaif->soc_data->global_base;
+	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
+	unsigned int rx_max = rx_base + (num_ch * ch_stride);
+	unsigned int tx_max = tx_base + (num_ch * ch_stride);
+
+	if ((reg >= rx_base) && (reg < rx_max)) {
+		reg = (reg - rx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET))
+			return true;
+	} else if ((reg >= tx_base) && (reg < tx_max)) {
+		reg = (reg - tx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET))
+			return true;
+	} else if ((reg >= global_base) && (reg < reg_max)) {
+		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
+			return true;
+	}
+
+	return false;
+}
+
+static const struct regmap_config tegra210_admaif_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_ADMAIF_LAST_REG,
+	.writeable_reg		= tegra_admaif_wr_reg,
+	.readable_reg		= tegra_admaif_rd_reg,
+	.volatile_reg		= tegra_admaif_volatile_reg,
+	.reg_defaults		= tegra210_admaif_reg_defaults,
+	.num_reg_defaults	= TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct regmap_config tegra186_admaif_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA186_ADMAIF_LAST_REG,
+	.writeable_reg		= tegra_admaif_wr_reg,
+	.readable_reg		= tegra_admaif_rd_reg,
+	.volatile_reg		= tegra_admaif_volatile_reg,
+	.reg_defaults		= tegra186_admaif_reg_defaults,
+	.num_reg_defaults	= TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static int tegra_admaif_runtime_suspend(struct device *dev)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+
+	regcache_cache_only(admaif->regmap, true);
+	regcache_mark_dirty(admaif->regmap);
+
+	return 0;
+}
+
+static int tegra_admaif_runtime_resume(struct device *dev)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+
+	regcache_cache_only(admaif->regmap, false);
+	regcache_sync(admaif->regmap);
+
+	return 0;
+}
+
+static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,
+				      int valid_bit)
+{
+	switch (valid_bit) {
+	case DATA_8BIT:
+		regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN);
+		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
+		break;
+	case DATA_16BIT:
+		regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN);
+		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
+		break;
+	case DATA_32BIT:
+		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
+		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+	struct tegra_cif_conf cif_conf;
+	unsigned int reg, path;
+	int valid_bit, channels;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_8;
+		valid_bit = DATA_8BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_16;
+		valid_bit = DATA_16BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_32;
+		valid_bit  = DATA_32BIT;
+		break;
+	default:
+		dev_err(dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	channels = params_channels(params);
+	cif_conf.client_ch = channels;
+	cif_conf.audio_ch = channels;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		path = ADMAIF_TX_PATH;
+		reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id);
+	} else {
+		path = ADMAIF_RX_PATH;
+		reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id);
+	}
+
+	cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id];
+	cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id];
+
+	tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);
+
+	tegra_set_cif(admaif->regmap, reg, &cif_conf);
+
+	return 0;
+}
+
+static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)
+{
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+	unsigned int reg, mask, val;
+
+	switch (direction) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		mask = TX_ENABLE_MASK;
+		val = TX_ENABLE;
+		reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		mask = RX_ENABLE_MASK;
+		val = RX_ENABLE;
+		reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(admaif->regmap, reg, mask, val);
+
+	return 0;
+}
+
+static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
+{
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+	unsigned int enable_reg, status_reg, reset_reg, mask, val;
+	char *dir_name;
+	int err, enable;
+
+	switch (direction) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		mask = TX_ENABLE_MASK;
+		enable = TX_ENABLE;
+		dir_name = "TX";
+		enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
+		status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id);
+		reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		mask = RX_ENABLE_MASK;
+		enable = RX_ENABLE;
+		dir_name = "RX";
+		enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
+		status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id);
+		reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Disable TX/RX channel */
+	regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);
+
+	/* Wait until ADMAIF TX/RX status is disabled */
+	err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,
+					      !(val & enable), 10, 10000);
+	if (err < 0)
+		dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n",
+			 dai->id + 1, dir_name);
+
+	/* SW reset */
+	regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);
+
+	/* Wait till SW reset is complete */
+	err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,
+					      !(val & SW_RESET_MASK & SW_RESET),
+					      10, 10000);
+	if (err) {
+		dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n",
+			dai->id + 1, dir_name);
+		return err;
+	}
+
+	return 0;
+}
+
+static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	int err;
+
+	err = snd_dmaengine_pcm_trigger(substream, cmd);
+	if (err)
+		return err;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		return tegra_admaif_start(dai, substream->stream);
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		return tegra_admaif_stop(dai, substream->stream);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
+	.hw_params	= tegra_admaif_hw_params,
+	.trigger	= tegra_admaif_trigger,
+};
+
+static int tegra_admaif_get_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+	long *uctl_val = &ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+		*uctl_val = admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
+	else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+		*uctl_val = admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
+	else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+		*uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
+	else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+		*uctl_val = admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
+
+	return 0;
+}
+
+static int tegra_admaif_put_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+	int value = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+		admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
+	else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+		admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
+	else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+		admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
+	else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+		admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
+
+	return 0;
+}
+
+static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
+{
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+
+	dai->capture_dma_data = &admaif->capture_dma_data[dai->id];
+	dai->playback_dma_data = &admaif->playback_dma_data[dai->id];
+
+	return 0;
+}
+
+#define ADMAIF_DAI(id)						\
+	{							\
+		.name = "ADMAIF" #id,				\
+		.probe = tegra_admaif_dai_probe,		\
+		.playback = {					\
+			.stream_name = "Playback " #id,		\
+			.channels_min = 1,			\
+			.channels_max = 16,			\
+			.rates = SNDRV_PCM_RATE_8000_192000,	\
+			.formats = SNDRV_PCM_FMTBIT_S8 |	\
+				SNDRV_PCM_FMTBIT_S16_LE |	\
+				SNDRV_PCM_FMTBIT_S32_LE,	\
+		},						\
+		.capture = {					\
+			.stream_name = "Capture " #id,		\
+			.channels_min = 1,			\
+			.channels_max = 16,			\
+			.rates = SNDRV_PCM_RATE_8000_192000,	\
+			.formats = SNDRV_PCM_FMTBIT_S8 |	\
+				SNDRV_PCM_FMTBIT_S16_LE |	\
+				SNDRV_PCM_FMTBIT_S32_LE,	\
+		},						\
+		.ops = &tegra_admaif_dai_ops,			\
+	}
+
+static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {
+	ADMAIF_DAI(1),
+	ADMAIF_DAI(2),
+	ADMAIF_DAI(3),
+	ADMAIF_DAI(4),
+	ADMAIF_DAI(5),
+	ADMAIF_DAI(6),
+	ADMAIF_DAI(7),
+	ADMAIF_DAI(8),
+	ADMAIF_DAI(9),
+	ADMAIF_DAI(10),
+};
+
+static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {
+	ADMAIF_DAI(1),
+	ADMAIF_DAI(2),
+	ADMAIF_DAI(3),
+	ADMAIF_DAI(4),
+	ADMAIF_DAI(5),
+	ADMAIF_DAI(6),
+	ADMAIF_DAI(7),
+	ADMAIF_DAI(8),
+	ADMAIF_DAI(9),
+	ADMAIF_DAI(10),
+	ADMAIF_DAI(11),
+	ADMAIF_DAI(12),
+	ADMAIF_DAI(13),
+	ADMAIF_DAI(14),
+	ADMAIF_DAI(15),
+	ADMAIF_DAI(16),
+	ADMAIF_DAI(17),
+	ADMAIF_DAI(18),
+	ADMAIF_DAI(19),
+	ADMAIF_DAI(20),
+};
+
+static const char * const tegra_admaif_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const char * const tegra_admaif_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+/*
+ * Below macro is added to avoid looping over all ADMAIFx controls related
+ * to mono/stereo conversions in get()/put() callbacks.
+ */
+#define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text)   \
+{									       \
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				       \
+	.info = snd_soc_info_enum_double,				       \
+	.name = xname,							       \
+	.get = xhandler_get,						       \
+	.put = xhandler_put,						       \
+	.private_value = (unsigned long)&(struct soc_enum)		       \
+		SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text)   \
+}
+
+#define TEGRA_ADMAIF_CIF_CTRL(reg)					       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,\
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_mono_conv_text),			       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,\
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_stereo_conv_text),			       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_mono_conv_text),			       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_stereo_conv_text)
+
+static struct snd_kcontrol_new tegra210_admaif_controls[] = {
+	TEGRA_ADMAIF_CIF_CTRL(1),
+	TEGRA_ADMAIF_CIF_CTRL(2),
+	TEGRA_ADMAIF_CIF_CTRL(3),
+	TEGRA_ADMAIF_CIF_CTRL(4),
+	TEGRA_ADMAIF_CIF_CTRL(5),
+	TEGRA_ADMAIF_CIF_CTRL(6),
+	TEGRA_ADMAIF_CIF_CTRL(7),
+	TEGRA_ADMAIF_CIF_CTRL(8),
+	TEGRA_ADMAIF_CIF_CTRL(9),
+	TEGRA_ADMAIF_CIF_CTRL(10),
+};
+
+static struct snd_kcontrol_new tegra186_admaif_controls[] = {
+	TEGRA_ADMAIF_CIF_CTRL(1),
+	TEGRA_ADMAIF_CIF_CTRL(2),
+	TEGRA_ADMAIF_CIF_CTRL(3),
+	TEGRA_ADMAIF_CIF_CTRL(4),
+	TEGRA_ADMAIF_CIF_CTRL(5),
+	TEGRA_ADMAIF_CIF_CTRL(6),
+	TEGRA_ADMAIF_CIF_CTRL(7),
+	TEGRA_ADMAIF_CIF_CTRL(8),
+	TEGRA_ADMAIF_CIF_CTRL(9),
+	TEGRA_ADMAIF_CIF_CTRL(10),
+	TEGRA_ADMAIF_CIF_CTRL(11),
+	TEGRA_ADMAIF_CIF_CTRL(12),
+	TEGRA_ADMAIF_CIF_CTRL(13),
+	TEGRA_ADMAIF_CIF_CTRL(14),
+	TEGRA_ADMAIF_CIF_CTRL(15),
+	TEGRA_ADMAIF_CIF_CTRL(16),
+	TEGRA_ADMAIF_CIF_CTRL(17),
+	TEGRA_ADMAIF_CIF_CTRL(18),
+	TEGRA_ADMAIF_CIF_CTRL(19),
+	TEGRA_ADMAIF_CIF_CTRL(20),
+};
+
+/* Connect FEs with XBAR */
+#define TEGRA_FE(id) \
+	{ "ADMAIF"#id " XBAR-RX",	NULL,	"Playback "#id },	\
+	{ "Capture "#id,		NULL,	"ADMAIF"#id " XBAR-TX" },
+
+static const struct snd_soc_dapm_route tegra210_admaif_routes[] = {
+	TEGRA_FE(1)
+	TEGRA_FE(2)
+	TEGRA_FE(3)
+	TEGRA_FE(4)
+	TEGRA_FE(5)
+	TEGRA_FE(6)
+	TEGRA_FE(7)
+	TEGRA_FE(8)
+	TEGRA_FE(9)
+	TEGRA_FE(10)
+};
+
+static const struct snd_soc_dapm_route tegra186_admaif_routes[] = {
+	TEGRA_FE(1)
+	TEGRA_FE(2)
+	TEGRA_FE(3)
+	TEGRA_FE(4)
+	TEGRA_FE(5)
+	TEGRA_FE(6)
+	TEGRA_FE(7)
+	TEGRA_FE(8)
+	TEGRA_FE(9)
+	TEGRA_FE(10)
+	TEGRA_FE(11)
+	TEGRA_FE(12)
+	TEGRA_FE(13)
+	TEGRA_FE(14)
+	TEGRA_FE(15)
+	TEGRA_FE(16)
+	TEGRA_FE(17)
+	TEGRA_FE(18)
+	TEGRA_FE(19)
+	TEGRA_FE(20)
+};
+
+static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
+	.controls		= tegra210_admaif_controls,
+	.num_controls		= ARRAY_SIZE(tegra210_admaif_controls),
+	.dapm_routes            = tegra210_admaif_routes,
+	.num_dapm_routes        = ARRAY_SIZE(tegra210_admaif_routes),
+	.pcm_construct		= tegra_pcm_construct,
+	.pcm_destruct		= tegra_pcm_destruct,
+	.open			= tegra_pcm_open,
+	.close			= tegra_pcm_close,
+	.hw_params		= tegra_pcm_hw_params,
+	.hw_free		= tegra_pcm_hw_free,
+	.mmap			= tegra_pcm_mmap,
+	.pointer		= tegra_pcm_pointer,
+};
+
+static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
+	.controls		= tegra186_admaif_controls,
+	.num_controls		= ARRAY_SIZE(tegra186_admaif_controls),
+	.dapm_routes            = tegra186_admaif_routes,
+	.num_dapm_routes        = ARRAY_SIZE(tegra186_admaif_routes),
+	.pcm_construct		= tegra_pcm_construct,
+	.pcm_destruct		= tegra_pcm_destruct,
+	.open			= tegra_pcm_open,
+	.close			= tegra_pcm_close,
+	.hw_params		= tegra_pcm_hw_params,
+	.hw_free		= tegra_pcm_hw_free,
+	.mmap			= tegra_pcm_mmap,
+	.pointer		= tegra_pcm_pointer,
+};
+
+static const struct tegra_admaif_soc_data soc_data_tegra210 = {
+	.num_ch		= TEGRA210_ADMAIF_CHANNEL_COUNT,
+	.cmpnt		= &tegra210_admaif_cmpnt,
+	.dais		= tegra210_admaif_cmpnt_dais,
+	.regmap_conf	= &tegra210_admaif_regmap_config,
+	.global_base	= TEGRA210_ADMAIF_GLOBAL_BASE,
+	.tx_base	= TEGRA210_ADMAIF_TX_BASE,
+	.rx_base	= TEGRA210_ADMAIF_RX_BASE,
+};
+
+static const struct tegra_admaif_soc_data soc_data_tegra186 = {
+	.num_ch		= TEGRA186_ADMAIF_CHANNEL_COUNT,
+	.cmpnt		= &tegra186_admaif_cmpnt,
+	.dais		= tegra186_admaif_cmpnt_dais,
+	.regmap_conf	= &tegra186_admaif_regmap_config,
+	.global_base	= TEGRA186_ADMAIF_GLOBAL_BASE,
+	.tx_base	= TEGRA186_ADMAIF_TX_BASE,
+	.rx_base	= TEGRA186_ADMAIF_RX_BASE,
+};
+
+static const struct of_device_id tegra_admaif_of_match[] = {
+	{ .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },
+	{ .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);
+
+static int tegra_admaif_probe(struct platform_device *pdev)
+{
+	struct tegra_admaif *admaif;
+	void __iomem *regs;
+	struct resource *res;
+	int err, i;
+
+	admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL);
+	if (!admaif)
+		return -ENOMEM;
+
+	admaif->soc_data = of_device_get_match_data(&pdev->dev);
+
+	dev_set_drvdata(&pdev->dev, admaif);
+
+	admaif->capture_dma_data =
+		devm_kcalloc(&pdev->dev,
+			     admaif->soc_data->num_ch,
+			     sizeof(struct snd_dmaengine_dai_dma_data),
+			     GFP_KERNEL);
+	if (!admaif->capture_dma_data)
+		return -ENOMEM;
+
+	admaif->playback_dma_data =
+		devm_kcalloc(&pdev->dev,
+			     admaif->soc_data->num_ch,
+			     sizeof(struct snd_dmaengine_dai_dma_data),
+			     GFP_KERNEL);
+	if (!admaif->playback_dma_data)
+		return -ENOMEM;
+
+	for (i = 0; i < ADMAIF_PATHS; i++) {
+		admaif->mono_to_stereo[i] =
+			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
+				     sizeof(unsigned int), GFP_KERNEL);
+		if (!admaif->mono_to_stereo[i])
+			return -ENOMEM;
+
+		admaif->stereo_to_mono[i] =
+			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
+				     sizeof(unsigned int), GFP_KERNEL);
+		if (!admaif->stereo_to_mono[i])
+			return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					       admaif->soc_data->regmap_conf);
+	if (IS_ERR(admaif->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(admaif->regmap);
+	}
+
+	regcache_cache_only(admaif->regmap, true);
+
+	regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
+			   TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
+
+	for (i = 0; i < admaif->soc_data->num_ch; i++) {
+		admaif->playback_dma_data[i].addr = res->start +
+			CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);
+
+		admaif->capture_dma_data[i].addr = res->start +
+			CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);
+
+		admaif->playback_dma_data[i].addr_width = 32;
+
+		if (of_property_read_string_index(pdev->dev.of_node,
+				"dma-names", (i * 2) + 1,
+				&admaif->playback_dma_data[i].chan_name) < 0) {
+			dev_err(&pdev->dev,
+				"missing property nvidia,dma-names\n");
+
+			return -ENODEV;
+		}
+
+		admaif->capture_dma_data[i].addr_width = 32;
+
+		if (of_property_read_string_index(pdev->dev.of_node,
+				"dma-names",
+				(i * 2),
+				&admaif->capture_dma_data[i].chan_name) < 0) {
+			dev_err(&pdev->dev,
+				"missing property nvidia,dma-names\n");
+
+			return -ENODEV;
+		}
+	}
+
+	err = devm_snd_soc_register_component(&pdev->dev,
+					      admaif->soc_data->cmpnt,
+					      admaif->soc_data->dais,
+					      admaif->soc_data->num_ch);
+	if (err) {
+		dev_err(&pdev->dev,
+			"can't register ADMAIF component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static int tegra_admaif_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra_admaif_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
+			   tegra_admaif_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra_admaif_driver = {
+	.probe = tegra_admaif_probe,
+	.remove = tegra_admaif_remove,
+	.driver = {
+		.name = "tegra210-admaif",
+		.of_match_table = tegra_admaif_of_match,
+		.pm = &tegra_admaif_pm_ops,
+	},
+};
+module_platform_driver(tegra_admaif_driver);
+
+MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_admaif.h b/sound/soc/tegra/tegra210_admaif.h
new file mode 100644
index 0000000..96686dc
--- /dev/null
+++ b/sound/soc/tegra/tegra210_admaif.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_admaif.h - Tegra ADMAIF registers
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA_ADMAIF_H__
+#define __TEGRA_ADMAIF_H__
+
+#define TEGRA_ADMAIF_CHANNEL_REG_STRIDE			0x40
+/* Tegra210 specific */
+#define TEGRA210_ADMAIF_LAST_REG			0x75f
+#define TEGRA210_ADMAIF_CHANNEL_COUNT			10
+#define TEGRA210_ADMAIF_RX_BASE				0x0
+#define TEGRA210_ADMAIF_TX_BASE				0x300
+#define TEGRA210_ADMAIF_GLOBAL_BASE			0x700
+/* Tegra186 specific */
+#define TEGRA186_ADMAIF_LAST_REG			0xd5f
+#define TEGRA186_ADMAIF_CHANNEL_COUNT			20
+#define TEGRA186_ADMAIF_RX_BASE				0x0
+#define TEGRA186_ADMAIF_TX_BASE				0x500
+#define TEGRA186_ADMAIF_GLOBAL_BASE			0xd00
+/* Global registers */
+#define TEGRA_ADMAIF_GLOBAL_ENABLE			0x0
+#define TEGRA_ADMAIF_GLOBAL_CG_0			0x8
+#define TEGRA_ADMAIF_GLOBAL_STATUS			0x10
+#define TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS		0x20
+#define TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS		0x24
+/* RX channel registers */
+#define TEGRA_ADMAIF_RX_ENABLE				0x0
+#define TEGRA_ADMAIF_RX_SOFT_RESET			0x4
+#define TEGRA_ADMAIF_RX_STATUS				0xc
+#define TEGRA_ADMAIF_RX_INT_STATUS			0x10
+#define TEGRA_ADMAIF_RX_INT_MASK			0x14
+#define TEGRA_ADMAIF_RX_INT_SET				0x18
+#define TEGRA_ADMAIF_RX_INT_CLEAR			0x1c
+#define TEGRA_ADMAIF_CH_ACIF_RX_CTRL			0x20
+#define TEGRA_ADMAIF_RX_FIFO_CTRL			0x28
+#define TEGRA_ADMAIF_RX_FIFO_READ			0x2c
+/* TX channel registers */
+#define TEGRA_ADMAIF_TX_ENABLE				0x0
+#define TEGRA_ADMAIF_TX_SOFT_RESET			0x4
+#define TEGRA_ADMAIF_TX_STATUS				0xc
+#define TEGRA_ADMAIF_TX_INT_STATUS			0x10
+#define TEGRA_ADMAIF_TX_INT_MASK			0x14
+#define TEGRA_ADMAIF_TX_INT_SET				0x18
+#define TEGRA_ADMAIF_TX_INT_CLEAR			0x1c
+#define TEGRA_ADMAIF_CH_ACIF_TX_CTRL			0x20
+#define TEGRA_ADMAIF_TX_FIFO_CTRL			0x28
+#define TEGRA_ADMAIF_TX_FIFO_WRITE			0x2c
+/* Bit fields */
+#define PACK8_EN_SHIFT					31
+#define PACK8_EN_MASK					BIT(PACK8_EN_SHIFT)
+#define PACK8_EN					BIT(PACK8_EN_SHIFT)
+#define PACK16_EN_SHIFT					30
+#define PACK16_EN_MASK					BIT(PACK16_EN_SHIFT)
+#define PACK16_EN					BIT(PACK16_EN_SHIFT)
+#define TX_ENABLE_SHIFT					0
+#define TX_ENABLE_MASK					BIT(TX_ENABLE_SHIFT)
+#define TX_ENABLE					BIT(TX_ENABLE_SHIFT)
+#define RX_ENABLE_SHIFT					0
+#define RX_ENABLE_MASK					BIT(RX_ENABLE_SHIFT)
+#define RX_ENABLE					BIT(RX_ENABLE_SHIFT)
+#define SW_RESET_MASK					1
+#define SW_RESET					1
+/* Default values - Tegra210 */
+#define TEGRA210_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT	0x00000300
+#define TEGRA210_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT	0x00000304
+#define TEGRA210_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT	0x00000208
+#define TEGRA210_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT	0x0000020b
+#define TEGRA210_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT	0x0000020e
+#define TEGRA210_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT	0x00000211
+#define TEGRA210_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT	0x00000214
+#define TEGRA210_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT	0x00000217
+#define TEGRA210_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT	0x0000021a
+#define TEGRA210_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT	0x0000021d
+#define TEGRA210_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT	0x02000300
+#define TEGRA210_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT	0x02000304
+#define TEGRA210_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT	0x01800208
+#define TEGRA210_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT	0x0180020b
+#define TEGRA210_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT	0x0180020e
+#define TEGRA210_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT	0x01800211
+#define TEGRA210_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT	0x01800214
+#define TEGRA210_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT	0x01800217
+#define TEGRA210_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT	0x0180021a
+#define TEGRA210_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT	0x0180021d
+/* Default values - Tegra186 */
+#define TEGRA186_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT	0x00000300
+#define TEGRA186_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT	0x00000304
+#define TEGRA186_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT	0x00000308
+#define TEGRA186_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT	0x0000030c
+#define TEGRA186_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT	0x00000210
+#define TEGRA186_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT	0x00000213
+#define TEGRA186_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT	0x00000216
+#define TEGRA186_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT	0x00000219
+#define TEGRA186_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT	0x0000021c
+#define TEGRA186_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT	0x0000021f
+#define TEGRA186_ADMAIF_RX11_FIFO_CTRL_REG_DEFAULT	0x00000222
+#define TEGRA186_ADMAIF_RX12_FIFO_CTRL_REG_DEFAULT	0x00000225
+#define TEGRA186_ADMAIF_RX13_FIFO_CTRL_REG_DEFAULT	0x00000228
+#define TEGRA186_ADMAIF_RX14_FIFO_CTRL_REG_DEFAULT	0x0000022b
+#define TEGRA186_ADMAIF_RX15_FIFO_CTRL_REG_DEFAULT	0x0000022e
+#define TEGRA186_ADMAIF_RX16_FIFO_CTRL_REG_DEFAULT	0x00000231
+#define TEGRA186_ADMAIF_RX17_FIFO_CTRL_REG_DEFAULT	0x00000234
+#define TEGRA186_ADMAIF_RX18_FIFO_CTRL_REG_DEFAULT	0x00000237
+#define TEGRA186_ADMAIF_RX19_FIFO_CTRL_REG_DEFAULT	0x0000023a
+#define TEGRA186_ADMAIF_RX20_FIFO_CTRL_REG_DEFAULT	0x0000023d
+#define TEGRA186_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT	0x02000300
+#define TEGRA186_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT	0x02000304
+#define TEGRA186_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT	0x02000308
+#define TEGRA186_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT	0x0200030c
+#define TEGRA186_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT	0x01800210
+#define TEGRA186_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT	0x01800213
+#define TEGRA186_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT	0x01800216
+#define TEGRA186_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT	0x01800219
+#define TEGRA186_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT	0x0180021c
+#define TEGRA186_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT	0x0180021f
+#define TEGRA186_ADMAIF_TX11_FIFO_CTRL_REG_DEFAULT	0x01800222
+#define TEGRA186_ADMAIF_TX12_FIFO_CTRL_REG_DEFAULT	0x01800225
+#define TEGRA186_ADMAIF_TX13_FIFO_CTRL_REG_DEFAULT	0x01800228
+#define TEGRA186_ADMAIF_TX14_FIFO_CTRL_REG_DEFAULT	0x0180022b
+#define TEGRA186_ADMAIF_TX15_FIFO_CTRL_REG_DEFAULT	0x0180022e
+#define TEGRA186_ADMAIF_TX16_FIFO_CTRL_REG_DEFAULT	0x01800231
+#define TEGRA186_ADMAIF_TX17_FIFO_CTRL_REG_DEFAULT	0x01800234
+#define TEGRA186_ADMAIF_TX18_FIFO_CTRL_REG_DEFAULT	0x01800237
+#define TEGRA186_ADMAIF_TX19_FIFO_CTRL_REG_DEFAULT	0x0180023a
+#define TEGRA186_ADMAIF_TX20_FIFO_CTRL_REG_DEFAULT	0x0180023d
+
+enum {
+	DATA_8BIT,
+	DATA_16BIT,
+	DATA_32BIT
+};
+
+enum {
+	ADMAIF_RX_PATH,
+	ADMAIF_TX_PATH,
+	ADMAIF_PATHS,
+};
+
+struct tegra_admaif_soc_data {
+	const struct snd_soc_component_driver *cmpnt;
+	const struct regmap_config *regmap_conf;
+	struct snd_soc_dai_driver *dais;
+	unsigned int global_base;
+	unsigned int tx_base;
+	unsigned int rx_base;
+	unsigned int num_ch;
+};
+
+struct tegra_admaif {
+	struct snd_dmaengine_dai_dma_data *capture_dma_data;
+	struct snd_dmaengine_dai_dma_data *playback_dma_data;
+	const struct tegra_admaif_soc_data *soc_data;
+	unsigned int *mono_to_stereo[ADMAIF_PATHS];
+	unsigned int *stereo_to_mono[ADMAIF_PATHS];
+	struct regmap *regmap;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index f246df8..b3f3651 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -16,12 +16,12 @@
  */
 
 #include <linux/module.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
-
 #include "tegra_pcm.h"
 
 static const struct snd_pcm_hardware tegra_pcm_hardware = {
@@ -67,6 +67,239 @@ void tegra_pcm_platform_unregister(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
 
+int tegra_pcm_open(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_dmaengine_dai_dma_data *dmap;
+	struct dma_chan *chan;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	int ret;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	dmap = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	/* Set HW params now that initialization is complete */
+	snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
+
+	/* Ensure period size is multiple of 8 */
+	ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8);
+	if (ret) {
+		dev_err(rtd->dev, "failed to set constraint %d\n", ret);
+		return ret;
+	}
+
+	chan = dma_request_slave_channel(cpu_dai->dev, dmap->chan_name);
+	if (!chan) {
+		dev_err(cpu_dai->dev,
+			"dmaengine request slave channel failed! (%s)\n",
+			dmap->chan_name);
+		return -ENODEV;
+	}
+
+	ret = snd_dmaengine_pcm_open(substream, chan);
+	if (ret) {
+		dev_err(rtd->dev,
+			"dmaengine pcm open failed with err %d (%s)\n", ret,
+			dmap->chan_name);
+
+		dma_release_channel(chan);
+
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_open);
+
+int tegra_pcm_close(struct snd_soc_component *component,
+		    struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	snd_dmaengine_pcm_close_release_chan(substream);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_close);
+
+int tegra_pcm_hw_params(struct snd_soc_component *component,
+			struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_dmaengine_dai_dma_data *dmap;
+	struct dma_slave_config slave_config;
+	struct dma_chan *chan;
+	int ret;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	dmap = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+	if (!dmap)
+		return 0;
+
+	chan = snd_dmaengine_pcm_get_chan(substream);
+
+	ret = snd_hwparams_to_dma_slave_config(substream, params,
+					       &slave_config);
+	if (ret) {
+		dev_err(rtd->dev, "hw params config failed with err %d\n", ret);
+		return ret;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		slave_config.dst_addr = dmap->addr;
+		slave_config.dst_maxburst = 8;
+	} else {
+		slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		slave_config.src_addr = dmap->addr;
+		slave_config.src_maxburst = 8;
+	}
+
+	ret = dmaengine_slave_config(chan, &slave_config);
+	if (ret < 0) {
+		dev_err(rtd->dev, "dma slave config failed with err %d\n", ret);
+		return ret;
+	}
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_hw_params);
+
+int tegra_pcm_hw_free(struct snd_soc_component *component,
+		      struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	snd_pcm_set_runtime_buffer(substream, NULL);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_hw_free);
+
+int tegra_pcm_mmap(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream,
+		   struct vm_area_struct *vma)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area,
+			   runtime->dma_addr, runtime->dma_bytes);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_mmap);
+
+snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component,
+				    struct snd_pcm_substream *substream)
+{
+	return snd_dmaengine_pcm_pointer(substream);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_pointer);
+
+static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
+					    size_t size)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+	buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->private_data = NULL;
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->bytes = size;
+
+	return 0;
+}
+
+static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+
+	substream = pcm->streams[stream].substream;
+	if (!substream)
+		return;
+
+	buf = &substream->dma_buffer;
+	if (!buf->area)
+		return;
+
+	dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
+	buf->area = NULL;
+}
+
+static int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd,
+				  size_t size)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret;
+
+	ret = dma_set_mask(card->dev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		return ret;
+
+	ret = dma_set_coherent_mask(card->dev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		return ret;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ret = tegra_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK, size);
+		if (ret)
+			goto err;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ret = tegra_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE, size);
+		if (ret)
+			goto err_free_play;
+	}
+
+	return 0;
+
+err_free_play:
+	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+err:
+	return ret;
+}
+
+int tegra_pcm_construct(struct snd_soc_component *component,
+			struct snd_soc_pcm_runtime *rtd)
+{
+	return tegra_pcm_dma_allocate(rtd, tegra_pcm_hardware.buffer_bytes_max);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_construct);
+
+void tegra_pcm_destruct(struct snd_soc_component *component,
+			struct snd_pcm *pcm)
+{
+	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
+	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_destruct);
+
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra PCM ASoC driver");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index 0433372..4838cdc 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -17,8 +17,27 @@
 #ifndef __TEGRA_PCM_H__
 #define __TEGRA_PCM_H__
 
-struct snd_dmaengine_pcm_config;
+#include <sound/dmaengine_pcm.h>
+#include <sound/asound.h>
 
+int tegra_pcm_construct(struct snd_soc_component *component,
+			struct snd_soc_pcm_runtime *rtd);
+void tegra_pcm_destruct(struct snd_soc_component *component,
+			struct snd_pcm *pcm);
+int tegra_pcm_open(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream);
+int tegra_pcm_close(struct snd_soc_component *component,
+		    struct snd_pcm_substream *substream);
+int tegra_pcm_hw_params(struct snd_soc_component *component,
+			struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params);
+int tegra_pcm_hw_free(struct snd_soc_component *component,
+		      struct snd_pcm_substream *substream);
+int tegra_pcm_mmap(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream,
+		   struct vm_area_struct *vma);
+snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component,
+				    struct snd_pcm_substream *substream);
 int tegra_pcm_platform_register(struct device *dev);
 int tegra_pcm_platform_register_with_chan_names(struct device *dev,
 				struct snd_dmaengine_pcm_config *config,
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 07/23] ASoC: tegra: Add Tegra210 based ADMAIF driver
@ 2020-06-27  4:53   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

ADMAIF is the interface between ADMA and AHUB. Each ADMA channel that
sends/receives data to/from AHUB must intreface through an ADMAIF channel.
ADMA channel sending data to AHUB pairs with an ADMAIF Tx channel and
similarly ADMA channel receiving data from AHUB pairs with an ADMAIF Rx
channel. Buffer size is configurable for each ADMAIF channel, but currently
SW uses default values.

This patch registers ADMAIF driver with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes ADMAIF interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The ADMAIF device can be enabled in the DT via
"nvidia,tegra210-admaif" compatible binding.

Tegra PCM driver is updated to expose required PCM interfaces and
snd_pcm_ops callbacks.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig           |  12 +
 sound/soc/tegra/Makefile          |   2 +
 sound/soc/tegra/tegra210_admaif.c | 845 ++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_admaif.h | 162 ++++++++
 sound/soc/tegra/tegra_pcm.c       | 235 ++++++++++-
 sound/soc/tegra/tegra_pcm.h       |  21 +-
 6 files changed, 1275 insertions(+), 2 deletions(-)
 create mode 100644 sound/soc/tegra/tegra210_admaif.c
 create mode 100644 sound/soc/tegra/tegra210_admaif.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 63d5ae9..0a05992 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -106,6 +106,18 @@ config SND_SOC_TEGRA186_DSPK
 	  the desired 1-bit output via Delta Sigma Modulation (DSM).
 	  Say Y or M if you want to add support for Tegra186 DSPK module.
 
+config SND_SOC_TEGRA210_ADMAIF
+	tristate "Tegra210 ADMAIF module"
+	depends on SND_SOC_TEGRA
+	help
+	  Config to enable ADMAIF which is the interface between ADMA and
+	  Audio Hub (AHUB). Each ADMA channel that sends/receives data to/
+	  from AHUB must interface through an ADMAIF channel. ADMA channel
+	  sending data to AHUB pairs with an ADMAIF Tx channel, where as
+	  ADMA channel receiving data from AHUB pairs with an ADMAIF Rx
+	  channel. Buffer size is configurable for each ADMAIIF channel.
+	  Say Y or M if you want to add support for Tegra210 ADMAIF module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 336c4c7..60040a0 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -12,6 +12,7 @@ snd-soc-tegra210-ahub-objs := tegra210_ahub.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 snd-soc-tegra210-i2s-objs := tegra210_i2s.o
 snd-soc-tegra186-dspk-objs := tegra186_dspk.o
+snd-soc-tegra210-admaif-objs := tegra210_admaif.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o
+obj-$(CONFIG_SND_SOC_TEGRA210_ADMAIF) += snd-soc-tegra210-admaif.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c
new file mode 100644
index 0000000..a8cfacc
--- /dev/null
+++ b/sound/soc/tegra/tegra210_admaif.c
@@ -0,0 +1,845 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_admaif.c - Tegra ADMAIF driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra210_admaif.h"
+#include "tegra_cif.h"
+#include "tegra_pcm.h"
+
+#define CH_REG(offset, reg, id)						       \
+	((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id)))
+
+#define CH_TX_REG(reg, id) CH_REG(admaif->soc_data->tx_base, reg, id)
+
+#define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)
+
+#define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base)		       \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 },	       \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), 0x00007700 },     \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl },	       \
+	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 },	       \
+	{ CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), 0x00007700 },     \
+	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }
+
+#define ADMAIF_REG_DEFAULTS(id, chip)					       \
+	REG_DEFAULTS((id) - 1,						       \
+		chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
+		chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
+		chip ## _ADMAIF_TX_BASE,				       \
+		chip ## _ADMAIF_RX_BASE)
+
+static const struct reg_default tegra186_admaif_reg_defaults[] = {
+	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},
+	ADMAIF_REG_DEFAULTS(1, TEGRA186),
+	ADMAIF_REG_DEFAULTS(2, TEGRA186),
+	ADMAIF_REG_DEFAULTS(3, TEGRA186),
+	ADMAIF_REG_DEFAULTS(4, TEGRA186),
+	ADMAIF_REG_DEFAULTS(5, TEGRA186),
+	ADMAIF_REG_DEFAULTS(6, TEGRA186),
+	ADMAIF_REG_DEFAULTS(7, TEGRA186),
+	ADMAIF_REG_DEFAULTS(8, TEGRA186),
+	ADMAIF_REG_DEFAULTS(9, TEGRA186),
+	ADMAIF_REG_DEFAULTS(10, TEGRA186),
+	ADMAIF_REG_DEFAULTS(11, TEGRA186),
+	ADMAIF_REG_DEFAULTS(12, TEGRA186),
+	ADMAIF_REG_DEFAULTS(13, TEGRA186),
+	ADMAIF_REG_DEFAULTS(14, TEGRA186),
+	ADMAIF_REG_DEFAULTS(15, TEGRA186),
+	ADMAIF_REG_DEFAULTS(16, TEGRA186),
+	ADMAIF_REG_DEFAULTS(17, TEGRA186),
+	ADMAIF_REG_DEFAULTS(18, TEGRA186),
+	ADMAIF_REG_DEFAULTS(19, TEGRA186),
+	ADMAIF_REG_DEFAULTS(20, TEGRA186)
+};
+
+static const struct reg_default tegra210_admaif_reg_defaults[] = {
+	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},
+	ADMAIF_REG_DEFAULTS(1, TEGRA210),
+	ADMAIF_REG_DEFAULTS(2, TEGRA210),
+	ADMAIF_REG_DEFAULTS(3, TEGRA210),
+	ADMAIF_REG_DEFAULTS(4, TEGRA210),
+	ADMAIF_REG_DEFAULTS(5, TEGRA210),
+	ADMAIF_REG_DEFAULTS(6, TEGRA210),
+	ADMAIF_REG_DEFAULTS(7, TEGRA210),
+	ADMAIF_REG_DEFAULTS(8, TEGRA210),
+	ADMAIF_REG_DEFAULTS(9, TEGRA210),
+	ADMAIF_REG_DEFAULTS(10, TEGRA210)
+};
+
+static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
+	unsigned int num_ch = admaif->soc_data->num_ch;
+	unsigned int rx_base = admaif->soc_data->rx_base;
+	unsigned int tx_base = admaif->soc_data->tx_base;
+	unsigned int global_base = admaif->soc_data->global_base;
+	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
+	unsigned int rx_max = rx_base + (num_ch * ch_stride);
+	unsigned int tx_max = tx_base + (num_ch * ch_stride);
+
+	if ((reg >= rx_base) && (reg < rx_max)) {
+		reg = (reg - rx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
+			return true;
+	} else if ((reg >= tx_base) && (reg < tx_max)) {
+		reg = (reg - tx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
+			return true;
+	} else if ((reg >= global_base) && (reg < reg_max)) {
+		if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE))
+			return true;
+	}
+
+	return false;
+}
+
+static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
+	unsigned int num_ch = admaif->soc_data->num_ch;
+	unsigned int rx_base = admaif->soc_data->rx_base;
+	unsigned int tx_base = admaif->soc_data->tx_base;
+	unsigned int global_base = admaif->soc_data->global_base;
+	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
+	unsigned int rx_max = rx_base + (num_ch * ch_stride);
+	unsigned int tx_max = tx_base + (num_ch * ch_stride);
+
+	if ((reg >= rx_base) && (reg < rx_max)) {
+		reg = (reg - rx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
+			return true;
+	} else if ((reg >= tx_base) && (reg < tx_max)) {
+		reg = (reg - tx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
+			return true;
+	} else if ((reg >= global_base) && (reg < reg_max)) {
+		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) ||
+		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_CG_0)) ||
+		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
+			return true;
+	}
+
+	return false;
+}
+
+static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
+	unsigned int num_ch = admaif->soc_data->num_ch;
+	unsigned int rx_base = admaif->soc_data->rx_base;
+	unsigned int tx_base = admaif->soc_data->tx_base;
+	unsigned int global_base = admaif->soc_data->global_base;
+	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
+	unsigned int rx_max = rx_base + (num_ch * ch_stride);
+	unsigned int tx_max = tx_base + (num_ch * ch_stride);
+
+	if ((reg >= rx_base) && (reg < rx_max)) {
+		reg = (reg - rx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET))
+			return true;
+	} else if ((reg >= tx_base) && (reg < tx_max)) {
+		reg = (reg - tx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET))
+			return true;
+	} else if ((reg >= global_base) && (reg < reg_max)) {
+		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
+			return true;
+	}
+
+	return false;
+}
+
+static const struct regmap_config tegra210_admaif_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_ADMAIF_LAST_REG,
+	.writeable_reg		= tegra_admaif_wr_reg,
+	.readable_reg		= tegra_admaif_rd_reg,
+	.volatile_reg		= tegra_admaif_volatile_reg,
+	.reg_defaults		= tegra210_admaif_reg_defaults,
+	.num_reg_defaults	= TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct regmap_config tegra186_admaif_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA186_ADMAIF_LAST_REG,
+	.writeable_reg		= tegra_admaif_wr_reg,
+	.readable_reg		= tegra_admaif_rd_reg,
+	.volatile_reg		= tegra_admaif_volatile_reg,
+	.reg_defaults		= tegra186_admaif_reg_defaults,
+	.num_reg_defaults	= TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static int tegra_admaif_runtime_suspend(struct device *dev)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+
+	regcache_cache_only(admaif->regmap, true);
+	regcache_mark_dirty(admaif->regmap);
+
+	return 0;
+}
+
+static int tegra_admaif_runtime_resume(struct device *dev)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+
+	regcache_cache_only(admaif->regmap, false);
+	regcache_sync(admaif->regmap);
+
+	return 0;
+}
+
+static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,
+				      int valid_bit)
+{
+	switch (valid_bit) {
+	case DATA_8BIT:
+		regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN);
+		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
+		break;
+	case DATA_16BIT:
+		regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN);
+		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
+		break;
+	case DATA_32BIT:
+		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
+		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+	struct tegra_cif_conf cif_conf;
+	unsigned int reg, path;
+	int valid_bit, channels;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_8;
+		valid_bit = DATA_8BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_16;
+		valid_bit = DATA_16BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_32;
+		valid_bit  = DATA_32BIT;
+		break;
+	default:
+		dev_err(dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	channels = params_channels(params);
+	cif_conf.client_ch = channels;
+	cif_conf.audio_ch = channels;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		path = ADMAIF_TX_PATH;
+		reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id);
+	} else {
+		path = ADMAIF_RX_PATH;
+		reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id);
+	}
+
+	cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id];
+	cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id];
+
+	tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);
+
+	tegra_set_cif(admaif->regmap, reg, &cif_conf);
+
+	return 0;
+}
+
+static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)
+{
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+	unsigned int reg, mask, val;
+
+	switch (direction) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		mask = TX_ENABLE_MASK;
+		val = TX_ENABLE;
+		reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		mask = RX_ENABLE_MASK;
+		val = RX_ENABLE;
+		reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(admaif->regmap, reg, mask, val);
+
+	return 0;
+}
+
+static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
+{
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+	unsigned int enable_reg, status_reg, reset_reg, mask, val;
+	char *dir_name;
+	int err, enable;
+
+	switch (direction) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		mask = TX_ENABLE_MASK;
+		enable = TX_ENABLE;
+		dir_name = "TX";
+		enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
+		status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id);
+		reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		mask = RX_ENABLE_MASK;
+		enable = RX_ENABLE;
+		dir_name = "RX";
+		enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
+		status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id);
+		reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Disable TX/RX channel */
+	regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);
+
+	/* Wait until ADMAIF TX/RX status is disabled */
+	err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,
+					      !(val & enable), 10, 10000);
+	if (err < 0)
+		dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n",
+			 dai->id + 1, dir_name);
+
+	/* SW reset */
+	regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);
+
+	/* Wait till SW reset is complete */
+	err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,
+					      !(val & SW_RESET_MASK & SW_RESET),
+					      10, 10000);
+	if (err) {
+		dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n",
+			dai->id + 1, dir_name);
+		return err;
+	}
+
+	return 0;
+}
+
+static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	int err;
+
+	err = snd_dmaengine_pcm_trigger(substream, cmd);
+	if (err)
+		return err;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		return tegra_admaif_start(dai, substream->stream);
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		return tegra_admaif_stop(dai, substream->stream);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
+	.hw_params	= tegra_admaif_hw_params,
+	.trigger	= tegra_admaif_trigger,
+};
+
+static int tegra_admaif_get_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+	long *uctl_val = &ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+		*uctl_val = admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
+	else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+		*uctl_val = admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
+	else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+		*uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
+	else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+		*uctl_val = admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
+
+	return 0;
+}
+
+static int tegra_admaif_put_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+	int value = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+		admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
+	else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+		admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
+	else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+		admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
+	else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+		admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
+
+	return 0;
+}
+
+static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
+{
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+
+	dai->capture_dma_data = &admaif->capture_dma_data[dai->id];
+	dai->playback_dma_data = &admaif->playback_dma_data[dai->id];
+
+	return 0;
+}
+
+#define ADMAIF_DAI(id)						\
+	{							\
+		.name = "ADMAIF" #id,				\
+		.probe = tegra_admaif_dai_probe,		\
+		.playback = {					\
+			.stream_name = "Playback " #id,		\
+			.channels_min = 1,			\
+			.channels_max = 16,			\
+			.rates = SNDRV_PCM_RATE_8000_192000,	\
+			.formats = SNDRV_PCM_FMTBIT_S8 |	\
+				SNDRV_PCM_FMTBIT_S16_LE |	\
+				SNDRV_PCM_FMTBIT_S32_LE,	\
+		},						\
+		.capture = {					\
+			.stream_name = "Capture " #id,		\
+			.channels_min = 1,			\
+			.channels_max = 16,			\
+			.rates = SNDRV_PCM_RATE_8000_192000,	\
+			.formats = SNDRV_PCM_FMTBIT_S8 |	\
+				SNDRV_PCM_FMTBIT_S16_LE |	\
+				SNDRV_PCM_FMTBIT_S32_LE,	\
+		},						\
+		.ops = &tegra_admaif_dai_ops,			\
+	}
+
+static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {
+	ADMAIF_DAI(1),
+	ADMAIF_DAI(2),
+	ADMAIF_DAI(3),
+	ADMAIF_DAI(4),
+	ADMAIF_DAI(5),
+	ADMAIF_DAI(6),
+	ADMAIF_DAI(7),
+	ADMAIF_DAI(8),
+	ADMAIF_DAI(9),
+	ADMAIF_DAI(10),
+};
+
+static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {
+	ADMAIF_DAI(1),
+	ADMAIF_DAI(2),
+	ADMAIF_DAI(3),
+	ADMAIF_DAI(4),
+	ADMAIF_DAI(5),
+	ADMAIF_DAI(6),
+	ADMAIF_DAI(7),
+	ADMAIF_DAI(8),
+	ADMAIF_DAI(9),
+	ADMAIF_DAI(10),
+	ADMAIF_DAI(11),
+	ADMAIF_DAI(12),
+	ADMAIF_DAI(13),
+	ADMAIF_DAI(14),
+	ADMAIF_DAI(15),
+	ADMAIF_DAI(16),
+	ADMAIF_DAI(17),
+	ADMAIF_DAI(18),
+	ADMAIF_DAI(19),
+	ADMAIF_DAI(20),
+};
+
+static const char * const tegra_admaif_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const char * const tegra_admaif_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+/*
+ * Below macro is added to avoid looping over all ADMAIFx controls related
+ * to mono/stereo conversions in get()/put() callbacks.
+ */
+#define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text)   \
+{									       \
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				       \
+	.info = snd_soc_info_enum_double,				       \
+	.name = xname,							       \
+	.get = xhandler_get,						       \
+	.put = xhandler_put,						       \
+	.private_value = (unsigned long)&(struct soc_enum)		       \
+		SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text)   \
+}
+
+#define TEGRA_ADMAIF_CIF_CTRL(reg)					       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,\
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_mono_conv_text),			       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,\
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_stereo_conv_text),			       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_mono_conv_text),			       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_stereo_conv_text)
+
+static struct snd_kcontrol_new tegra210_admaif_controls[] = {
+	TEGRA_ADMAIF_CIF_CTRL(1),
+	TEGRA_ADMAIF_CIF_CTRL(2),
+	TEGRA_ADMAIF_CIF_CTRL(3),
+	TEGRA_ADMAIF_CIF_CTRL(4),
+	TEGRA_ADMAIF_CIF_CTRL(5),
+	TEGRA_ADMAIF_CIF_CTRL(6),
+	TEGRA_ADMAIF_CIF_CTRL(7),
+	TEGRA_ADMAIF_CIF_CTRL(8),
+	TEGRA_ADMAIF_CIF_CTRL(9),
+	TEGRA_ADMAIF_CIF_CTRL(10),
+};
+
+static struct snd_kcontrol_new tegra186_admaif_controls[] = {
+	TEGRA_ADMAIF_CIF_CTRL(1),
+	TEGRA_ADMAIF_CIF_CTRL(2),
+	TEGRA_ADMAIF_CIF_CTRL(3),
+	TEGRA_ADMAIF_CIF_CTRL(4),
+	TEGRA_ADMAIF_CIF_CTRL(5),
+	TEGRA_ADMAIF_CIF_CTRL(6),
+	TEGRA_ADMAIF_CIF_CTRL(7),
+	TEGRA_ADMAIF_CIF_CTRL(8),
+	TEGRA_ADMAIF_CIF_CTRL(9),
+	TEGRA_ADMAIF_CIF_CTRL(10),
+	TEGRA_ADMAIF_CIF_CTRL(11),
+	TEGRA_ADMAIF_CIF_CTRL(12),
+	TEGRA_ADMAIF_CIF_CTRL(13),
+	TEGRA_ADMAIF_CIF_CTRL(14),
+	TEGRA_ADMAIF_CIF_CTRL(15),
+	TEGRA_ADMAIF_CIF_CTRL(16),
+	TEGRA_ADMAIF_CIF_CTRL(17),
+	TEGRA_ADMAIF_CIF_CTRL(18),
+	TEGRA_ADMAIF_CIF_CTRL(19),
+	TEGRA_ADMAIF_CIF_CTRL(20),
+};
+
+/* Connect FEs with XBAR */
+#define TEGRA_FE(id) \
+	{ "ADMAIF"#id " XBAR-RX",	NULL,	"Playback "#id },	\
+	{ "Capture "#id,		NULL,	"ADMAIF"#id " XBAR-TX" },
+
+static const struct snd_soc_dapm_route tegra210_admaif_routes[] = {
+	TEGRA_FE(1)
+	TEGRA_FE(2)
+	TEGRA_FE(3)
+	TEGRA_FE(4)
+	TEGRA_FE(5)
+	TEGRA_FE(6)
+	TEGRA_FE(7)
+	TEGRA_FE(8)
+	TEGRA_FE(9)
+	TEGRA_FE(10)
+};
+
+static const struct snd_soc_dapm_route tegra186_admaif_routes[] = {
+	TEGRA_FE(1)
+	TEGRA_FE(2)
+	TEGRA_FE(3)
+	TEGRA_FE(4)
+	TEGRA_FE(5)
+	TEGRA_FE(6)
+	TEGRA_FE(7)
+	TEGRA_FE(8)
+	TEGRA_FE(9)
+	TEGRA_FE(10)
+	TEGRA_FE(11)
+	TEGRA_FE(12)
+	TEGRA_FE(13)
+	TEGRA_FE(14)
+	TEGRA_FE(15)
+	TEGRA_FE(16)
+	TEGRA_FE(17)
+	TEGRA_FE(18)
+	TEGRA_FE(19)
+	TEGRA_FE(20)
+};
+
+static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
+	.controls		= tegra210_admaif_controls,
+	.num_controls		= ARRAY_SIZE(tegra210_admaif_controls),
+	.dapm_routes            = tegra210_admaif_routes,
+	.num_dapm_routes        = ARRAY_SIZE(tegra210_admaif_routes),
+	.pcm_construct		= tegra_pcm_construct,
+	.pcm_destruct		= tegra_pcm_destruct,
+	.open			= tegra_pcm_open,
+	.close			= tegra_pcm_close,
+	.hw_params		= tegra_pcm_hw_params,
+	.hw_free		= tegra_pcm_hw_free,
+	.mmap			= tegra_pcm_mmap,
+	.pointer		= tegra_pcm_pointer,
+};
+
+static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
+	.controls		= tegra186_admaif_controls,
+	.num_controls		= ARRAY_SIZE(tegra186_admaif_controls),
+	.dapm_routes            = tegra186_admaif_routes,
+	.num_dapm_routes        = ARRAY_SIZE(tegra186_admaif_routes),
+	.pcm_construct		= tegra_pcm_construct,
+	.pcm_destruct		= tegra_pcm_destruct,
+	.open			= tegra_pcm_open,
+	.close			= tegra_pcm_close,
+	.hw_params		= tegra_pcm_hw_params,
+	.hw_free		= tegra_pcm_hw_free,
+	.mmap			= tegra_pcm_mmap,
+	.pointer		= tegra_pcm_pointer,
+};
+
+static const struct tegra_admaif_soc_data soc_data_tegra210 = {
+	.num_ch		= TEGRA210_ADMAIF_CHANNEL_COUNT,
+	.cmpnt		= &tegra210_admaif_cmpnt,
+	.dais		= tegra210_admaif_cmpnt_dais,
+	.regmap_conf	= &tegra210_admaif_regmap_config,
+	.global_base	= TEGRA210_ADMAIF_GLOBAL_BASE,
+	.tx_base	= TEGRA210_ADMAIF_TX_BASE,
+	.rx_base	= TEGRA210_ADMAIF_RX_BASE,
+};
+
+static const struct tegra_admaif_soc_data soc_data_tegra186 = {
+	.num_ch		= TEGRA186_ADMAIF_CHANNEL_COUNT,
+	.cmpnt		= &tegra186_admaif_cmpnt,
+	.dais		= tegra186_admaif_cmpnt_dais,
+	.regmap_conf	= &tegra186_admaif_regmap_config,
+	.global_base	= TEGRA186_ADMAIF_GLOBAL_BASE,
+	.tx_base	= TEGRA186_ADMAIF_TX_BASE,
+	.rx_base	= TEGRA186_ADMAIF_RX_BASE,
+};
+
+static const struct of_device_id tegra_admaif_of_match[] = {
+	{ .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },
+	{ .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);
+
+static int tegra_admaif_probe(struct platform_device *pdev)
+{
+	struct tegra_admaif *admaif;
+	void __iomem *regs;
+	struct resource *res;
+	int err, i;
+
+	admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL);
+	if (!admaif)
+		return -ENOMEM;
+
+	admaif->soc_data = of_device_get_match_data(&pdev->dev);
+
+	dev_set_drvdata(&pdev->dev, admaif);
+
+	admaif->capture_dma_data =
+		devm_kcalloc(&pdev->dev,
+			     admaif->soc_data->num_ch,
+			     sizeof(struct snd_dmaengine_dai_dma_data),
+			     GFP_KERNEL);
+	if (!admaif->capture_dma_data)
+		return -ENOMEM;
+
+	admaif->playback_dma_data =
+		devm_kcalloc(&pdev->dev,
+			     admaif->soc_data->num_ch,
+			     sizeof(struct snd_dmaengine_dai_dma_data),
+			     GFP_KERNEL);
+	if (!admaif->playback_dma_data)
+		return -ENOMEM;
+
+	for (i = 0; i < ADMAIF_PATHS; i++) {
+		admaif->mono_to_stereo[i] =
+			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
+				     sizeof(unsigned int), GFP_KERNEL);
+		if (!admaif->mono_to_stereo[i])
+			return -ENOMEM;
+
+		admaif->stereo_to_mono[i] =
+			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
+				     sizeof(unsigned int), GFP_KERNEL);
+		if (!admaif->stereo_to_mono[i])
+			return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					       admaif->soc_data->regmap_conf);
+	if (IS_ERR(admaif->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(admaif->regmap);
+	}
+
+	regcache_cache_only(admaif->regmap, true);
+
+	regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
+			   TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
+
+	for (i = 0; i < admaif->soc_data->num_ch; i++) {
+		admaif->playback_dma_data[i].addr = res->start +
+			CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);
+
+		admaif->capture_dma_data[i].addr = res->start +
+			CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);
+
+		admaif->playback_dma_data[i].addr_width = 32;
+
+		if (of_property_read_string_index(pdev->dev.of_node,
+				"dma-names", (i * 2) + 1,
+				&admaif->playback_dma_data[i].chan_name) < 0) {
+			dev_err(&pdev->dev,
+				"missing property nvidia,dma-names\n");
+
+			return -ENODEV;
+		}
+
+		admaif->capture_dma_data[i].addr_width = 32;
+
+		if (of_property_read_string_index(pdev->dev.of_node,
+				"dma-names",
+				(i * 2),
+				&admaif->capture_dma_data[i].chan_name) < 0) {
+			dev_err(&pdev->dev,
+				"missing property nvidia,dma-names\n");
+
+			return -ENODEV;
+		}
+	}
+
+	err = devm_snd_soc_register_component(&pdev->dev,
+					      admaif->soc_data->cmpnt,
+					      admaif->soc_data->dais,
+					      admaif->soc_data->num_ch);
+	if (err) {
+		dev_err(&pdev->dev,
+			"can't register ADMAIF component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static int tegra_admaif_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra_admaif_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
+			   tegra_admaif_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra_admaif_driver = {
+	.probe = tegra_admaif_probe,
+	.remove = tegra_admaif_remove,
+	.driver = {
+		.name = "tegra210-admaif",
+		.of_match_table = tegra_admaif_of_match,
+		.pm = &tegra_admaif_pm_ops,
+	},
+};
+module_platform_driver(tegra_admaif_driver);
+
+MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_admaif.h b/sound/soc/tegra/tegra210_admaif.h
new file mode 100644
index 0000000..96686dc
--- /dev/null
+++ b/sound/soc/tegra/tegra210_admaif.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_admaif.h - Tegra ADMAIF registers
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA_ADMAIF_H__
+#define __TEGRA_ADMAIF_H__
+
+#define TEGRA_ADMAIF_CHANNEL_REG_STRIDE			0x40
+/* Tegra210 specific */
+#define TEGRA210_ADMAIF_LAST_REG			0x75f
+#define TEGRA210_ADMAIF_CHANNEL_COUNT			10
+#define TEGRA210_ADMAIF_RX_BASE				0x0
+#define TEGRA210_ADMAIF_TX_BASE				0x300
+#define TEGRA210_ADMAIF_GLOBAL_BASE			0x700
+/* Tegra186 specific */
+#define TEGRA186_ADMAIF_LAST_REG			0xd5f
+#define TEGRA186_ADMAIF_CHANNEL_COUNT			20
+#define TEGRA186_ADMAIF_RX_BASE				0x0
+#define TEGRA186_ADMAIF_TX_BASE				0x500
+#define TEGRA186_ADMAIF_GLOBAL_BASE			0xd00
+/* Global registers */
+#define TEGRA_ADMAIF_GLOBAL_ENABLE			0x0
+#define TEGRA_ADMAIF_GLOBAL_CG_0			0x8
+#define TEGRA_ADMAIF_GLOBAL_STATUS			0x10
+#define TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS		0x20
+#define TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS		0x24
+/* RX channel registers */
+#define TEGRA_ADMAIF_RX_ENABLE				0x0
+#define TEGRA_ADMAIF_RX_SOFT_RESET			0x4
+#define TEGRA_ADMAIF_RX_STATUS				0xc
+#define TEGRA_ADMAIF_RX_INT_STATUS			0x10
+#define TEGRA_ADMAIF_RX_INT_MASK			0x14
+#define TEGRA_ADMAIF_RX_INT_SET				0x18
+#define TEGRA_ADMAIF_RX_INT_CLEAR			0x1c
+#define TEGRA_ADMAIF_CH_ACIF_RX_CTRL			0x20
+#define TEGRA_ADMAIF_RX_FIFO_CTRL			0x28
+#define TEGRA_ADMAIF_RX_FIFO_READ			0x2c
+/* TX channel registers */
+#define TEGRA_ADMAIF_TX_ENABLE				0x0
+#define TEGRA_ADMAIF_TX_SOFT_RESET			0x4
+#define TEGRA_ADMAIF_TX_STATUS				0xc
+#define TEGRA_ADMAIF_TX_INT_STATUS			0x10
+#define TEGRA_ADMAIF_TX_INT_MASK			0x14
+#define TEGRA_ADMAIF_TX_INT_SET				0x18
+#define TEGRA_ADMAIF_TX_INT_CLEAR			0x1c
+#define TEGRA_ADMAIF_CH_ACIF_TX_CTRL			0x20
+#define TEGRA_ADMAIF_TX_FIFO_CTRL			0x28
+#define TEGRA_ADMAIF_TX_FIFO_WRITE			0x2c
+/* Bit fields */
+#define PACK8_EN_SHIFT					31
+#define PACK8_EN_MASK					BIT(PACK8_EN_SHIFT)
+#define PACK8_EN					BIT(PACK8_EN_SHIFT)
+#define PACK16_EN_SHIFT					30
+#define PACK16_EN_MASK					BIT(PACK16_EN_SHIFT)
+#define PACK16_EN					BIT(PACK16_EN_SHIFT)
+#define TX_ENABLE_SHIFT					0
+#define TX_ENABLE_MASK					BIT(TX_ENABLE_SHIFT)
+#define TX_ENABLE					BIT(TX_ENABLE_SHIFT)
+#define RX_ENABLE_SHIFT					0
+#define RX_ENABLE_MASK					BIT(RX_ENABLE_SHIFT)
+#define RX_ENABLE					BIT(RX_ENABLE_SHIFT)
+#define SW_RESET_MASK					1
+#define SW_RESET					1
+/* Default values - Tegra210 */
+#define TEGRA210_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT	0x00000300
+#define TEGRA210_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT	0x00000304
+#define TEGRA210_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT	0x00000208
+#define TEGRA210_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT	0x0000020b
+#define TEGRA210_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT	0x0000020e
+#define TEGRA210_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT	0x00000211
+#define TEGRA210_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT	0x00000214
+#define TEGRA210_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT	0x00000217
+#define TEGRA210_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT	0x0000021a
+#define TEGRA210_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT	0x0000021d
+#define TEGRA210_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT	0x02000300
+#define TEGRA210_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT	0x02000304
+#define TEGRA210_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT	0x01800208
+#define TEGRA210_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT	0x0180020b
+#define TEGRA210_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT	0x0180020e
+#define TEGRA210_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT	0x01800211
+#define TEGRA210_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT	0x01800214
+#define TEGRA210_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT	0x01800217
+#define TEGRA210_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT	0x0180021a
+#define TEGRA210_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT	0x0180021d
+/* Default values - Tegra186 */
+#define TEGRA186_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT	0x00000300
+#define TEGRA186_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT	0x00000304
+#define TEGRA186_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT	0x00000308
+#define TEGRA186_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT	0x0000030c
+#define TEGRA186_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT	0x00000210
+#define TEGRA186_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT	0x00000213
+#define TEGRA186_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT	0x00000216
+#define TEGRA186_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT	0x00000219
+#define TEGRA186_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT	0x0000021c
+#define TEGRA186_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT	0x0000021f
+#define TEGRA186_ADMAIF_RX11_FIFO_CTRL_REG_DEFAULT	0x00000222
+#define TEGRA186_ADMAIF_RX12_FIFO_CTRL_REG_DEFAULT	0x00000225
+#define TEGRA186_ADMAIF_RX13_FIFO_CTRL_REG_DEFAULT	0x00000228
+#define TEGRA186_ADMAIF_RX14_FIFO_CTRL_REG_DEFAULT	0x0000022b
+#define TEGRA186_ADMAIF_RX15_FIFO_CTRL_REG_DEFAULT	0x0000022e
+#define TEGRA186_ADMAIF_RX16_FIFO_CTRL_REG_DEFAULT	0x00000231
+#define TEGRA186_ADMAIF_RX17_FIFO_CTRL_REG_DEFAULT	0x00000234
+#define TEGRA186_ADMAIF_RX18_FIFO_CTRL_REG_DEFAULT	0x00000237
+#define TEGRA186_ADMAIF_RX19_FIFO_CTRL_REG_DEFAULT	0x0000023a
+#define TEGRA186_ADMAIF_RX20_FIFO_CTRL_REG_DEFAULT	0x0000023d
+#define TEGRA186_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT	0x02000300
+#define TEGRA186_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT	0x02000304
+#define TEGRA186_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT	0x02000308
+#define TEGRA186_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT	0x0200030c
+#define TEGRA186_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT	0x01800210
+#define TEGRA186_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT	0x01800213
+#define TEGRA186_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT	0x01800216
+#define TEGRA186_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT	0x01800219
+#define TEGRA186_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT	0x0180021c
+#define TEGRA186_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT	0x0180021f
+#define TEGRA186_ADMAIF_TX11_FIFO_CTRL_REG_DEFAULT	0x01800222
+#define TEGRA186_ADMAIF_TX12_FIFO_CTRL_REG_DEFAULT	0x01800225
+#define TEGRA186_ADMAIF_TX13_FIFO_CTRL_REG_DEFAULT	0x01800228
+#define TEGRA186_ADMAIF_TX14_FIFO_CTRL_REG_DEFAULT	0x0180022b
+#define TEGRA186_ADMAIF_TX15_FIFO_CTRL_REG_DEFAULT	0x0180022e
+#define TEGRA186_ADMAIF_TX16_FIFO_CTRL_REG_DEFAULT	0x01800231
+#define TEGRA186_ADMAIF_TX17_FIFO_CTRL_REG_DEFAULT	0x01800234
+#define TEGRA186_ADMAIF_TX18_FIFO_CTRL_REG_DEFAULT	0x01800237
+#define TEGRA186_ADMAIF_TX19_FIFO_CTRL_REG_DEFAULT	0x0180023a
+#define TEGRA186_ADMAIF_TX20_FIFO_CTRL_REG_DEFAULT	0x0180023d
+
+enum {
+	DATA_8BIT,
+	DATA_16BIT,
+	DATA_32BIT
+};
+
+enum {
+	ADMAIF_RX_PATH,
+	ADMAIF_TX_PATH,
+	ADMAIF_PATHS,
+};
+
+struct tegra_admaif_soc_data {
+	const struct snd_soc_component_driver *cmpnt;
+	const struct regmap_config *regmap_conf;
+	struct snd_soc_dai_driver *dais;
+	unsigned int global_base;
+	unsigned int tx_base;
+	unsigned int rx_base;
+	unsigned int num_ch;
+};
+
+struct tegra_admaif {
+	struct snd_dmaengine_dai_dma_data *capture_dma_data;
+	struct snd_dmaengine_dai_dma_data *playback_dma_data;
+	const struct tegra_admaif_soc_data *soc_data;
+	unsigned int *mono_to_stereo[ADMAIF_PATHS];
+	unsigned int *stereo_to_mono[ADMAIF_PATHS];
+	struct regmap *regmap;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index f246df8..b3f3651 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -16,12 +16,12 @@
  */
 
 #include <linux/module.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
-
 #include "tegra_pcm.h"
 
 static const struct snd_pcm_hardware tegra_pcm_hardware = {
@@ -67,6 +67,239 @@ void tegra_pcm_platform_unregister(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
 
+int tegra_pcm_open(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_dmaengine_dai_dma_data *dmap;
+	struct dma_chan *chan;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	int ret;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	dmap = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	/* Set HW params now that initialization is complete */
+	snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
+
+	/* Ensure period size is multiple of 8 */
+	ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8);
+	if (ret) {
+		dev_err(rtd->dev, "failed to set constraint %d\n", ret);
+		return ret;
+	}
+
+	chan = dma_request_slave_channel(cpu_dai->dev, dmap->chan_name);
+	if (!chan) {
+		dev_err(cpu_dai->dev,
+			"dmaengine request slave channel failed! (%s)\n",
+			dmap->chan_name);
+		return -ENODEV;
+	}
+
+	ret = snd_dmaengine_pcm_open(substream, chan);
+	if (ret) {
+		dev_err(rtd->dev,
+			"dmaengine pcm open failed with err %d (%s)\n", ret,
+			dmap->chan_name);
+
+		dma_release_channel(chan);
+
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_open);
+
+int tegra_pcm_close(struct snd_soc_component *component,
+		    struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	snd_dmaengine_pcm_close_release_chan(substream);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_close);
+
+int tegra_pcm_hw_params(struct snd_soc_component *component,
+			struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_dmaengine_dai_dma_data *dmap;
+	struct dma_slave_config slave_config;
+	struct dma_chan *chan;
+	int ret;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	dmap = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+	if (!dmap)
+		return 0;
+
+	chan = snd_dmaengine_pcm_get_chan(substream);
+
+	ret = snd_hwparams_to_dma_slave_config(substream, params,
+					       &slave_config);
+	if (ret) {
+		dev_err(rtd->dev, "hw params config failed with err %d\n", ret);
+		return ret;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		slave_config.dst_addr = dmap->addr;
+		slave_config.dst_maxburst = 8;
+	} else {
+		slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		slave_config.src_addr = dmap->addr;
+		slave_config.src_maxburst = 8;
+	}
+
+	ret = dmaengine_slave_config(chan, &slave_config);
+	if (ret < 0) {
+		dev_err(rtd->dev, "dma slave config failed with err %d\n", ret);
+		return ret;
+	}
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_hw_params);
+
+int tegra_pcm_hw_free(struct snd_soc_component *component,
+		      struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	snd_pcm_set_runtime_buffer(substream, NULL);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_hw_free);
+
+int tegra_pcm_mmap(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream,
+		   struct vm_area_struct *vma)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area,
+			   runtime->dma_addr, runtime->dma_bytes);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_mmap);
+
+snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component,
+				    struct snd_pcm_substream *substream)
+{
+	return snd_dmaengine_pcm_pointer(substream);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_pointer);
+
+static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
+					    size_t size)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+	buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->private_data = NULL;
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->bytes = size;
+
+	return 0;
+}
+
+static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+
+	substream = pcm->streams[stream].substream;
+	if (!substream)
+		return;
+
+	buf = &substream->dma_buffer;
+	if (!buf->area)
+		return;
+
+	dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
+	buf->area = NULL;
+}
+
+static int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd,
+				  size_t size)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret;
+
+	ret = dma_set_mask(card->dev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		return ret;
+
+	ret = dma_set_coherent_mask(card->dev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		return ret;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ret = tegra_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK, size);
+		if (ret)
+			goto err;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ret = tegra_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE, size);
+		if (ret)
+			goto err_free_play;
+	}
+
+	return 0;
+
+err_free_play:
+	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+err:
+	return ret;
+}
+
+int tegra_pcm_construct(struct snd_soc_component *component,
+			struct snd_soc_pcm_runtime *rtd)
+{
+	return tegra_pcm_dma_allocate(rtd, tegra_pcm_hardware.buffer_bytes_max);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_construct);
+
+void tegra_pcm_destruct(struct snd_soc_component *component,
+			struct snd_pcm *pcm)
+{
+	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
+	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_destruct);
+
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra PCM ASoC driver");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index 0433372..4838cdc 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -17,8 +17,27 @@
 #ifndef __TEGRA_PCM_H__
 #define __TEGRA_PCM_H__
 
-struct snd_dmaengine_pcm_config;
+#include <sound/dmaengine_pcm.h>
+#include <sound/asound.h>
 
+int tegra_pcm_construct(struct snd_soc_component *component,
+			struct snd_soc_pcm_runtime *rtd);
+void tegra_pcm_destruct(struct snd_soc_component *component,
+			struct snd_pcm *pcm);
+int tegra_pcm_open(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream);
+int tegra_pcm_close(struct snd_soc_component *component,
+		    struct snd_pcm_substream *substream);
+int tegra_pcm_hw_params(struct snd_soc_component *component,
+			struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params);
+int tegra_pcm_hw_free(struct snd_soc_component *component,
+		      struct snd_pcm_substream *substream);
+int tegra_pcm_mmap(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream,
+		   struct vm_area_struct *vma);
+snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component,
+				    struct snd_pcm_substream *substream);
 int tegra_pcm_platform_register(struct device *dev);
 int tegra_pcm_platform_register_with_chan_names(struct device *dev,
 				struct snd_dmaengine_pcm_config *config,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 07/23] ASoC: tegra: Add Tegra210 based ADMAIF driver
@ 2020-06-27  4:53   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

ADMAIF is the interface between ADMA and AHUB. Each ADMA channel that
sends/receives data to/from AHUB must intreface through an ADMAIF channel.
ADMA channel sending data to AHUB pairs with an ADMAIF Tx channel and
similarly ADMA channel receiving data from AHUB pairs with an ADMAIF Rx
channel. Buffer size is configurable for each ADMAIF channel, but currently
SW uses default values.

This patch registers ADMAIF driver with ASoC framework. The component
driver exposes DAPM widgets, routes and kcontrols for the device. The DAI
driver exposes ADMAIF interfaces, which can be used to connect different
components in the ASoC layer. Makefile and Kconfig support is added to
allow to build the driver. The ADMAIF device can be enabled in the DT via
"nvidia,tegra210-admaif" compatible binding.

Tegra PCM driver is updated to expose required PCM interfaces and
snd_pcm_ops callbacks.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/tegra/Kconfig           |  12 +
 sound/soc/tegra/Makefile          |   2 +
 sound/soc/tegra/tegra210_admaif.c | 845 ++++++++++++++++++++++++++++++++++++++
 sound/soc/tegra/tegra210_admaif.h | 162 ++++++++
 sound/soc/tegra/tegra_pcm.c       | 235 ++++++++++-
 sound/soc/tegra/tegra_pcm.h       |  21 +-
 6 files changed, 1275 insertions(+), 2 deletions(-)
 create mode 100644 sound/soc/tegra/tegra210_admaif.c
 create mode 100644 sound/soc/tegra/tegra210_admaif.h

diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 63d5ae9..0a05992 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -106,6 +106,18 @@ config SND_SOC_TEGRA186_DSPK
 	  the desired 1-bit output via Delta Sigma Modulation (DSM).
 	  Say Y or M if you want to add support for Tegra186 DSPK module.
 
+config SND_SOC_TEGRA210_ADMAIF
+	tristate "Tegra210 ADMAIF module"
+	depends on SND_SOC_TEGRA
+	help
+	  Config to enable ADMAIF which is the interface between ADMA and
+	  Audio Hub (AHUB). Each ADMA channel that sends/receives data to/
+	  from AHUB must interface through an ADMAIF channel. ADMA channel
+	  sending data to AHUB pairs with an ADMAIF Tx channel, where as
+	  ADMA channel receiving data from AHUB pairs with an ADMAIF Rx
+	  channel. Buffer size is configurable for each ADMAIIF channel.
+	  Say Y or M if you want to add support for Tegra210 ADMAIF module.
+
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
 	depends on SND_SOC_TEGRA && I2C && GPIOLIB
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 336c4c7..60040a0 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -12,6 +12,7 @@ snd-soc-tegra210-ahub-objs := tegra210_ahub.o
 snd-soc-tegra210-dmic-objs := tegra210_dmic.o
 snd-soc-tegra210-i2s-objs := tegra210_i2s.o
 snd-soc-tegra186-dspk-objs := tegra186_dspk.o
+snd-soc-tegra210-admaif-objs := tegra210_admaif.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_DMIC) += snd-soc-tegra210-dmic.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o
 obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o
+obj-$(CONFIG_SND_SOC_TEGRA210_ADMAIF) += snd-soc-tegra210-admaif.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c
new file mode 100644
index 0000000..a8cfacc
--- /dev/null
+++ b/sound/soc/tegra/tegra210_admaif.c
@@ -0,0 +1,845 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_admaif.c - Tegra ADMAIF driver
+//
+// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra210_admaif.h"
+#include "tegra_cif.h"
+#include "tegra_pcm.h"
+
+#define CH_REG(offset, reg, id)						       \
+	((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id)))
+
+#define CH_TX_REG(reg, id) CH_REG(admaif->soc_data->tx_base, reg, id)
+
+#define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)
+
+#define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base)		       \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 },	       \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), 0x00007700 },     \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl },	       \
+	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 },	       \
+	{ CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), 0x00007700 },     \
+	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }
+
+#define ADMAIF_REG_DEFAULTS(id, chip)					       \
+	REG_DEFAULTS((id) - 1,						       \
+		chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
+		chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
+		chip ## _ADMAIF_TX_BASE,				       \
+		chip ## _ADMAIF_RX_BASE)
+
+static const struct reg_default tegra186_admaif_reg_defaults[] = {
+	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},
+	ADMAIF_REG_DEFAULTS(1, TEGRA186),
+	ADMAIF_REG_DEFAULTS(2, TEGRA186),
+	ADMAIF_REG_DEFAULTS(3, TEGRA186),
+	ADMAIF_REG_DEFAULTS(4, TEGRA186),
+	ADMAIF_REG_DEFAULTS(5, TEGRA186),
+	ADMAIF_REG_DEFAULTS(6, TEGRA186),
+	ADMAIF_REG_DEFAULTS(7, TEGRA186),
+	ADMAIF_REG_DEFAULTS(8, TEGRA186),
+	ADMAIF_REG_DEFAULTS(9, TEGRA186),
+	ADMAIF_REG_DEFAULTS(10, TEGRA186),
+	ADMAIF_REG_DEFAULTS(11, TEGRA186),
+	ADMAIF_REG_DEFAULTS(12, TEGRA186),
+	ADMAIF_REG_DEFAULTS(13, TEGRA186),
+	ADMAIF_REG_DEFAULTS(14, TEGRA186),
+	ADMAIF_REG_DEFAULTS(15, TEGRA186),
+	ADMAIF_REG_DEFAULTS(16, TEGRA186),
+	ADMAIF_REG_DEFAULTS(17, TEGRA186),
+	ADMAIF_REG_DEFAULTS(18, TEGRA186),
+	ADMAIF_REG_DEFAULTS(19, TEGRA186),
+	ADMAIF_REG_DEFAULTS(20, TEGRA186)
+};
+
+static const struct reg_default tegra210_admaif_reg_defaults[] = {
+	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},
+	ADMAIF_REG_DEFAULTS(1, TEGRA210),
+	ADMAIF_REG_DEFAULTS(2, TEGRA210),
+	ADMAIF_REG_DEFAULTS(3, TEGRA210),
+	ADMAIF_REG_DEFAULTS(4, TEGRA210),
+	ADMAIF_REG_DEFAULTS(5, TEGRA210),
+	ADMAIF_REG_DEFAULTS(6, TEGRA210),
+	ADMAIF_REG_DEFAULTS(7, TEGRA210),
+	ADMAIF_REG_DEFAULTS(8, TEGRA210),
+	ADMAIF_REG_DEFAULTS(9, TEGRA210),
+	ADMAIF_REG_DEFAULTS(10, TEGRA210)
+};
+
+static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
+	unsigned int num_ch = admaif->soc_data->num_ch;
+	unsigned int rx_base = admaif->soc_data->rx_base;
+	unsigned int tx_base = admaif->soc_data->tx_base;
+	unsigned int global_base = admaif->soc_data->global_base;
+	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
+	unsigned int rx_max = rx_base + (num_ch * ch_stride);
+	unsigned int tx_max = tx_base + (num_ch * ch_stride);
+
+	if ((reg >= rx_base) && (reg < rx_max)) {
+		reg = (reg - rx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
+			return true;
+	} else if ((reg >= tx_base) && (reg < tx_max)) {
+		reg = (reg - tx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
+			return true;
+	} else if ((reg >= global_base) && (reg < reg_max)) {
+		if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE))
+			return true;
+	}
+
+	return false;
+}
+
+static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
+	unsigned int num_ch = admaif->soc_data->num_ch;
+	unsigned int rx_base = admaif->soc_data->rx_base;
+	unsigned int tx_base = admaif->soc_data->tx_base;
+	unsigned int global_base = admaif->soc_data->global_base;
+	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
+	unsigned int rx_max = rx_base + (num_ch * ch_stride);
+	unsigned int tx_max = tx_base + (num_ch * ch_stride);
+
+	if ((reg >= rx_base) && (reg < rx_max)) {
+		reg = (reg - rx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
+			return true;
+	} else if ((reg >= tx_base) && (reg < tx_max)) {
+		reg = (reg - tx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
+		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
+		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
+			return true;
+	} else if ((reg >= global_base) && (reg < reg_max)) {
+		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) ||
+		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_CG_0)) ||
+		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
+			return true;
+	}
+
+	return false;
+}
+
+static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
+	unsigned int num_ch = admaif->soc_data->num_ch;
+	unsigned int rx_base = admaif->soc_data->rx_base;
+	unsigned int tx_base = admaif->soc_data->tx_base;
+	unsigned int global_base = admaif->soc_data->global_base;
+	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
+	unsigned int rx_max = rx_base + (num_ch * ch_stride);
+	unsigned int tx_max = tx_base + (num_ch * ch_stride);
+
+	if ((reg >= rx_base) && (reg < rx_max)) {
+		reg = (reg - rx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET))
+			return true;
+	} else if ((reg >= tx_base) && (reg < tx_max)) {
+		reg = (reg - tx_base) % ch_stride;
+		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
+		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET))
+			return true;
+	} else if ((reg >= global_base) && (reg < reg_max)) {
+		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
+		    (reg == (global_base +
+				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
+			return true;
+	}
+
+	return false;
+}
+
+static const struct regmap_config tegra210_admaif_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA210_ADMAIF_LAST_REG,
+	.writeable_reg		= tegra_admaif_wr_reg,
+	.readable_reg		= tegra_admaif_rd_reg,
+	.volatile_reg		= tegra_admaif_volatile_reg,
+	.reg_defaults		= tegra210_admaif_reg_defaults,
+	.num_reg_defaults	= TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static const struct regmap_config tegra186_admaif_regmap_config = {
+	.reg_bits		= 32,
+	.reg_stride		= 4,
+	.val_bits		= 32,
+	.max_register		= TEGRA186_ADMAIF_LAST_REG,
+	.writeable_reg		= tegra_admaif_wr_reg,
+	.readable_reg		= tegra_admaif_rd_reg,
+	.volatile_reg		= tegra_admaif_volatile_reg,
+	.reg_defaults		= tegra186_admaif_reg_defaults,
+	.num_reg_defaults	= TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,
+	.cache_type		= REGCACHE_FLAT,
+};
+
+static int tegra_admaif_runtime_suspend(struct device *dev)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+
+	regcache_cache_only(admaif->regmap, true);
+	regcache_mark_dirty(admaif->regmap);
+
+	return 0;
+}
+
+static int tegra_admaif_runtime_resume(struct device *dev)
+{
+	struct tegra_admaif *admaif = dev_get_drvdata(dev);
+
+	regcache_cache_only(admaif->regmap, false);
+	regcache_sync(admaif->regmap);
+
+	return 0;
+}
+
+static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,
+				      int valid_bit)
+{
+	switch (valid_bit) {
+	case DATA_8BIT:
+		regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN);
+		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
+		break;
+	case DATA_16BIT:
+		regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN);
+		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
+		break;
+	case DATA_32BIT:
+		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
+		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+	struct tegra_cif_conf cif_conf;
+	unsigned int reg, path;
+	int valid_bit, channels;
+
+	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_8;
+		valid_bit = DATA_8BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_16;
+		valid_bit = DATA_16BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+		cif_conf.client_bits = TEGRA_ACIF_BITS_32;
+		valid_bit  = DATA_32BIT;
+		break;
+	default:
+		dev_err(dev, "unsupported format!\n");
+		return -EOPNOTSUPP;
+	}
+
+	channels = params_channels(params);
+	cif_conf.client_ch = channels;
+	cif_conf.audio_ch = channels;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		path = ADMAIF_TX_PATH;
+		reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id);
+	} else {
+		path = ADMAIF_RX_PATH;
+		reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id);
+	}
+
+	cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id];
+	cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id];
+
+	tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);
+
+	tegra_set_cif(admaif->regmap, reg, &cif_conf);
+
+	return 0;
+}
+
+static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)
+{
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+	unsigned int reg, mask, val;
+
+	switch (direction) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		mask = TX_ENABLE_MASK;
+		val = TX_ENABLE;
+		reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		mask = RX_ENABLE_MASK;
+		val = RX_ENABLE;
+		reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(admaif->regmap, reg, mask, val);
+
+	return 0;
+}
+
+static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
+{
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+	unsigned int enable_reg, status_reg, reset_reg, mask, val;
+	char *dir_name;
+	int err, enable;
+
+	switch (direction) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		mask = TX_ENABLE_MASK;
+		enable = TX_ENABLE;
+		dir_name = "TX";
+		enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
+		status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id);
+		reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		mask = RX_ENABLE_MASK;
+		enable = RX_ENABLE;
+		dir_name = "RX";
+		enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
+		status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id);
+		reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Disable TX/RX channel */
+	regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);
+
+	/* Wait until ADMAIF TX/RX status is disabled */
+	err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,
+					      !(val & enable), 10, 10000);
+	if (err < 0)
+		dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n",
+			 dai->id + 1, dir_name);
+
+	/* SW reset */
+	regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);
+
+	/* Wait till SW reset is complete */
+	err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,
+					      !(val & SW_RESET_MASK & SW_RESET),
+					      10, 10000);
+	if (err) {
+		dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n",
+			dai->id + 1, dir_name);
+		return err;
+	}
+
+	return 0;
+}
+
+static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	int err;
+
+	err = snd_dmaengine_pcm_trigger(substream, cmd);
+	if (err)
+		return err;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		return tegra_admaif_start(dai, substream->stream);
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		return tegra_admaif_stop(dai, substream->stream);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
+	.hw_params	= tegra_admaif_hw_params,
+	.trigger	= tegra_admaif_trigger,
+};
+
+static int tegra_admaif_get_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+	long *uctl_val = &ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+		*uctl_val = admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
+	else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+		*uctl_val = admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
+	else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+		*uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
+	else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+		*uctl_val = admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
+
+	return 0;
+}
+
+static int tegra_admaif_put_control(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+	int value = ucontrol->value.integer.value[0];
+
+	if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
+		admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
+	else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
+		admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
+	else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+		admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
+	else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
+		admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
+
+	return 0;
+}
+
+static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
+{
+	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+
+	dai->capture_dma_data = &admaif->capture_dma_data[dai->id];
+	dai->playback_dma_data = &admaif->playback_dma_data[dai->id];
+
+	return 0;
+}
+
+#define ADMAIF_DAI(id)						\
+	{							\
+		.name = "ADMAIF" #id,				\
+		.probe = tegra_admaif_dai_probe,		\
+		.playback = {					\
+			.stream_name = "Playback " #id,		\
+			.channels_min = 1,			\
+			.channels_max = 16,			\
+			.rates = SNDRV_PCM_RATE_8000_192000,	\
+			.formats = SNDRV_PCM_FMTBIT_S8 |	\
+				SNDRV_PCM_FMTBIT_S16_LE |	\
+				SNDRV_PCM_FMTBIT_S32_LE,	\
+		},						\
+		.capture = {					\
+			.stream_name = "Capture " #id,		\
+			.channels_min = 1,			\
+			.channels_max = 16,			\
+			.rates = SNDRV_PCM_RATE_8000_192000,	\
+			.formats = SNDRV_PCM_FMTBIT_S8 |	\
+				SNDRV_PCM_FMTBIT_S16_LE |	\
+				SNDRV_PCM_FMTBIT_S32_LE,	\
+		},						\
+		.ops = &tegra_admaif_dai_ops,			\
+	}
+
+static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {
+	ADMAIF_DAI(1),
+	ADMAIF_DAI(2),
+	ADMAIF_DAI(3),
+	ADMAIF_DAI(4),
+	ADMAIF_DAI(5),
+	ADMAIF_DAI(6),
+	ADMAIF_DAI(7),
+	ADMAIF_DAI(8),
+	ADMAIF_DAI(9),
+	ADMAIF_DAI(10),
+};
+
+static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {
+	ADMAIF_DAI(1),
+	ADMAIF_DAI(2),
+	ADMAIF_DAI(3),
+	ADMAIF_DAI(4),
+	ADMAIF_DAI(5),
+	ADMAIF_DAI(6),
+	ADMAIF_DAI(7),
+	ADMAIF_DAI(8),
+	ADMAIF_DAI(9),
+	ADMAIF_DAI(10),
+	ADMAIF_DAI(11),
+	ADMAIF_DAI(12),
+	ADMAIF_DAI(13),
+	ADMAIF_DAI(14),
+	ADMAIF_DAI(15),
+	ADMAIF_DAI(16),
+	ADMAIF_DAI(17),
+	ADMAIF_DAI(18),
+	ADMAIF_DAI(19),
+	ADMAIF_DAI(20),
+};
+
+static const char * const tegra_admaif_stereo_conv_text[] = {
+	"CH0", "CH1", "AVG",
+};
+
+static const char * const tegra_admaif_mono_conv_text[] = {
+	"Zero", "Copy",
+};
+
+/*
+ * Below macro is added to avoid looping over all ADMAIFx controls related
+ * to mono/stereo conversions in get()/put() callbacks.
+ */
+#define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text)   \
+{									       \
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				       \
+	.info = snd_soc_info_enum_double,				       \
+	.name = xname,							       \
+	.get = xhandler_get,						       \
+	.put = xhandler_put,						       \
+	.private_value = (unsigned long)&(struct soc_enum)		       \
+		SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text)   \
+}
+
+#define TEGRA_ADMAIF_CIF_CTRL(reg)					       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,\
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_mono_conv_text),			       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,\
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_stereo_conv_text),			       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_mono_conv_text),			       \
+	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \
+			tegra_admaif_get_control, tegra_admaif_put_control,    \
+			tegra_admaif_stereo_conv_text)
+
+static struct snd_kcontrol_new tegra210_admaif_controls[] = {
+	TEGRA_ADMAIF_CIF_CTRL(1),
+	TEGRA_ADMAIF_CIF_CTRL(2),
+	TEGRA_ADMAIF_CIF_CTRL(3),
+	TEGRA_ADMAIF_CIF_CTRL(4),
+	TEGRA_ADMAIF_CIF_CTRL(5),
+	TEGRA_ADMAIF_CIF_CTRL(6),
+	TEGRA_ADMAIF_CIF_CTRL(7),
+	TEGRA_ADMAIF_CIF_CTRL(8),
+	TEGRA_ADMAIF_CIF_CTRL(9),
+	TEGRA_ADMAIF_CIF_CTRL(10),
+};
+
+static struct snd_kcontrol_new tegra186_admaif_controls[] = {
+	TEGRA_ADMAIF_CIF_CTRL(1),
+	TEGRA_ADMAIF_CIF_CTRL(2),
+	TEGRA_ADMAIF_CIF_CTRL(3),
+	TEGRA_ADMAIF_CIF_CTRL(4),
+	TEGRA_ADMAIF_CIF_CTRL(5),
+	TEGRA_ADMAIF_CIF_CTRL(6),
+	TEGRA_ADMAIF_CIF_CTRL(7),
+	TEGRA_ADMAIF_CIF_CTRL(8),
+	TEGRA_ADMAIF_CIF_CTRL(9),
+	TEGRA_ADMAIF_CIF_CTRL(10),
+	TEGRA_ADMAIF_CIF_CTRL(11),
+	TEGRA_ADMAIF_CIF_CTRL(12),
+	TEGRA_ADMAIF_CIF_CTRL(13),
+	TEGRA_ADMAIF_CIF_CTRL(14),
+	TEGRA_ADMAIF_CIF_CTRL(15),
+	TEGRA_ADMAIF_CIF_CTRL(16),
+	TEGRA_ADMAIF_CIF_CTRL(17),
+	TEGRA_ADMAIF_CIF_CTRL(18),
+	TEGRA_ADMAIF_CIF_CTRL(19),
+	TEGRA_ADMAIF_CIF_CTRL(20),
+};
+
+/* Connect FEs with XBAR */
+#define TEGRA_FE(id) \
+	{ "ADMAIF"#id " XBAR-RX",	NULL,	"Playback "#id },	\
+	{ "Capture "#id,		NULL,	"ADMAIF"#id " XBAR-TX" },
+
+static const struct snd_soc_dapm_route tegra210_admaif_routes[] = {
+	TEGRA_FE(1)
+	TEGRA_FE(2)
+	TEGRA_FE(3)
+	TEGRA_FE(4)
+	TEGRA_FE(5)
+	TEGRA_FE(6)
+	TEGRA_FE(7)
+	TEGRA_FE(8)
+	TEGRA_FE(9)
+	TEGRA_FE(10)
+};
+
+static const struct snd_soc_dapm_route tegra186_admaif_routes[] = {
+	TEGRA_FE(1)
+	TEGRA_FE(2)
+	TEGRA_FE(3)
+	TEGRA_FE(4)
+	TEGRA_FE(5)
+	TEGRA_FE(6)
+	TEGRA_FE(7)
+	TEGRA_FE(8)
+	TEGRA_FE(9)
+	TEGRA_FE(10)
+	TEGRA_FE(11)
+	TEGRA_FE(12)
+	TEGRA_FE(13)
+	TEGRA_FE(14)
+	TEGRA_FE(15)
+	TEGRA_FE(16)
+	TEGRA_FE(17)
+	TEGRA_FE(18)
+	TEGRA_FE(19)
+	TEGRA_FE(20)
+};
+
+static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
+	.controls		= tegra210_admaif_controls,
+	.num_controls		= ARRAY_SIZE(tegra210_admaif_controls),
+	.dapm_routes            = tegra210_admaif_routes,
+	.num_dapm_routes        = ARRAY_SIZE(tegra210_admaif_routes),
+	.pcm_construct		= tegra_pcm_construct,
+	.pcm_destruct		= tegra_pcm_destruct,
+	.open			= tegra_pcm_open,
+	.close			= tegra_pcm_close,
+	.hw_params		= tegra_pcm_hw_params,
+	.hw_free		= tegra_pcm_hw_free,
+	.mmap			= tegra_pcm_mmap,
+	.pointer		= tegra_pcm_pointer,
+};
+
+static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
+	.controls		= tegra186_admaif_controls,
+	.num_controls		= ARRAY_SIZE(tegra186_admaif_controls),
+	.dapm_routes            = tegra186_admaif_routes,
+	.num_dapm_routes        = ARRAY_SIZE(tegra186_admaif_routes),
+	.pcm_construct		= tegra_pcm_construct,
+	.pcm_destruct		= tegra_pcm_destruct,
+	.open			= tegra_pcm_open,
+	.close			= tegra_pcm_close,
+	.hw_params		= tegra_pcm_hw_params,
+	.hw_free		= tegra_pcm_hw_free,
+	.mmap			= tegra_pcm_mmap,
+	.pointer		= tegra_pcm_pointer,
+};
+
+static const struct tegra_admaif_soc_data soc_data_tegra210 = {
+	.num_ch		= TEGRA210_ADMAIF_CHANNEL_COUNT,
+	.cmpnt		= &tegra210_admaif_cmpnt,
+	.dais		= tegra210_admaif_cmpnt_dais,
+	.regmap_conf	= &tegra210_admaif_regmap_config,
+	.global_base	= TEGRA210_ADMAIF_GLOBAL_BASE,
+	.tx_base	= TEGRA210_ADMAIF_TX_BASE,
+	.rx_base	= TEGRA210_ADMAIF_RX_BASE,
+};
+
+static const struct tegra_admaif_soc_data soc_data_tegra186 = {
+	.num_ch		= TEGRA186_ADMAIF_CHANNEL_COUNT,
+	.cmpnt		= &tegra186_admaif_cmpnt,
+	.dais		= tegra186_admaif_cmpnt_dais,
+	.regmap_conf	= &tegra186_admaif_regmap_config,
+	.global_base	= TEGRA186_ADMAIF_GLOBAL_BASE,
+	.tx_base	= TEGRA186_ADMAIF_TX_BASE,
+	.rx_base	= TEGRA186_ADMAIF_RX_BASE,
+};
+
+static const struct of_device_id tegra_admaif_of_match[] = {
+	{ .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },
+	{ .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);
+
+static int tegra_admaif_probe(struct platform_device *pdev)
+{
+	struct tegra_admaif *admaif;
+	void __iomem *regs;
+	struct resource *res;
+	int err, i;
+
+	admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL);
+	if (!admaif)
+		return -ENOMEM;
+
+	admaif->soc_data = of_device_get_match_data(&pdev->dev);
+
+	dev_set_drvdata(&pdev->dev, admaif);
+
+	admaif->capture_dma_data =
+		devm_kcalloc(&pdev->dev,
+			     admaif->soc_data->num_ch,
+			     sizeof(struct snd_dmaengine_dai_dma_data),
+			     GFP_KERNEL);
+	if (!admaif->capture_dma_data)
+		return -ENOMEM;
+
+	admaif->playback_dma_data =
+		devm_kcalloc(&pdev->dev,
+			     admaif->soc_data->num_ch,
+			     sizeof(struct snd_dmaengine_dai_dma_data),
+			     GFP_KERNEL);
+	if (!admaif->playback_dma_data)
+		return -ENOMEM;
+
+	for (i = 0; i < ADMAIF_PATHS; i++) {
+		admaif->mono_to_stereo[i] =
+			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
+				     sizeof(unsigned int), GFP_KERNEL);
+		if (!admaif->mono_to_stereo[i])
+			return -ENOMEM;
+
+		admaif->stereo_to_mono[i] =
+			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
+				     sizeof(unsigned int), GFP_KERNEL);
+		if (!admaif->stereo_to_mono[i])
+			return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+					       admaif->soc_data->regmap_conf);
+	if (IS_ERR(admaif->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(admaif->regmap);
+	}
+
+	regcache_cache_only(admaif->regmap, true);
+
+	regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
+			   TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
+
+	for (i = 0; i < admaif->soc_data->num_ch; i++) {
+		admaif->playback_dma_data[i].addr = res->start +
+			CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);
+
+		admaif->capture_dma_data[i].addr = res->start +
+			CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);
+
+		admaif->playback_dma_data[i].addr_width = 32;
+
+		if (of_property_read_string_index(pdev->dev.of_node,
+				"dma-names", (i * 2) + 1,
+				&admaif->playback_dma_data[i].chan_name) < 0) {
+			dev_err(&pdev->dev,
+				"missing property nvidia,dma-names\n");
+
+			return -ENODEV;
+		}
+
+		admaif->capture_dma_data[i].addr_width = 32;
+
+		if (of_property_read_string_index(pdev->dev.of_node,
+				"dma-names",
+				(i * 2),
+				&admaif->capture_dma_data[i].chan_name) < 0) {
+			dev_err(&pdev->dev,
+				"missing property nvidia,dma-names\n");
+
+			return -ENODEV;
+		}
+	}
+
+	err = devm_snd_soc_register_component(&pdev->dev,
+					      admaif->soc_data->cmpnt,
+					      admaif->soc_data->dais,
+					      admaif->soc_data->num_ch);
+	if (err) {
+		dev_err(&pdev->dev,
+			"can't register ADMAIF component, err: %d\n", err);
+		return err;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static int tegra_admaif_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops tegra_admaif_pm_ops = {
+	SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
+			   tegra_admaif_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra_admaif_driver = {
+	.probe = tegra_admaif_probe,
+	.remove = tegra_admaif_remove,
+	.driver = {
+		.name = "tegra210-admaif",
+		.of_match_table = tegra_admaif_of_match,
+		.pm = &tegra_admaif_pm_ops,
+	},
+};
+module_platform_driver(tegra_admaif_driver);
+
+MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_admaif.h b/sound/soc/tegra/tegra210_admaif.h
new file mode 100644
index 0000000..96686dc
--- /dev/null
+++ b/sound/soc/tegra/tegra210_admaif.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_admaif.h - Tegra ADMAIF registers
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA_ADMAIF_H__
+#define __TEGRA_ADMAIF_H__
+
+#define TEGRA_ADMAIF_CHANNEL_REG_STRIDE			0x40
+/* Tegra210 specific */
+#define TEGRA210_ADMAIF_LAST_REG			0x75f
+#define TEGRA210_ADMAIF_CHANNEL_COUNT			10
+#define TEGRA210_ADMAIF_RX_BASE				0x0
+#define TEGRA210_ADMAIF_TX_BASE				0x300
+#define TEGRA210_ADMAIF_GLOBAL_BASE			0x700
+/* Tegra186 specific */
+#define TEGRA186_ADMAIF_LAST_REG			0xd5f
+#define TEGRA186_ADMAIF_CHANNEL_COUNT			20
+#define TEGRA186_ADMAIF_RX_BASE				0x0
+#define TEGRA186_ADMAIF_TX_BASE				0x500
+#define TEGRA186_ADMAIF_GLOBAL_BASE			0xd00
+/* Global registers */
+#define TEGRA_ADMAIF_GLOBAL_ENABLE			0x0
+#define TEGRA_ADMAIF_GLOBAL_CG_0			0x8
+#define TEGRA_ADMAIF_GLOBAL_STATUS			0x10
+#define TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS		0x20
+#define TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS		0x24
+/* RX channel registers */
+#define TEGRA_ADMAIF_RX_ENABLE				0x0
+#define TEGRA_ADMAIF_RX_SOFT_RESET			0x4
+#define TEGRA_ADMAIF_RX_STATUS				0xc
+#define TEGRA_ADMAIF_RX_INT_STATUS			0x10
+#define TEGRA_ADMAIF_RX_INT_MASK			0x14
+#define TEGRA_ADMAIF_RX_INT_SET				0x18
+#define TEGRA_ADMAIF_RX_INT_CLEAR			0x1c
+#define TEGRA_ADMAIF_CH_ACIF_RX_CTRL			0x20
+#define TEGRA_ADMAIF_RX_FIFO_CTRL			0x28
+#define TEGRA_ADMAIF_RX_FIFO_READ			0x2c
+/* TX channel registers */
+#define TEGRA_ADMAIF_TX_ENABLE				0x0
+#define TEGRA_ADMAIF_TX_SOFT_RESET			0x4
+#define TEGRA_ADMAIF_TX_STATUS				0xc
+#define TEGRA_ADMAIF_TX_INT_STATUS			0x10
+#define TEGRA_ADMAIF_TX_INT_MASK			0x14
+#define TEGRA_ADMAIF_TX_INT_SET				0x18
+#define TEGRA_ADMAIF_TX_INT_CLEAR			0x1c
+#define TEGRA_ADMAIF_CH_ACIF_TX_CTRL			0x20
+#define TEGRA_ADMAIF_TX_FIFO_CTRL			0x28
+#define TEGRA_ADMAIF_TX_FIFO_WRITE			0x2c
+/* Bit fields */
+#define PACK8_EN_SHIFT					31
+#define PACK8_EN_MASK					BIT(PACK8_EN_SHIFT)
+#define PACK8_EN					BIT(PACK8_EN_SHIFT)
+#define PACK16_EN_SHIFT					30
+#define PACK16_EN_MASK					BIT(PACK16_EN_SHIFT)
+#define PACK16_EN					BIT(PACK16_EN_SHIFT)
+#define TX_ENABLE_SHIFT					0
+#define TX_ENABLE_MASK					BIT(TX_ENABLE_SHIFT)
+#define TX_ENABLE					BIT(TX_ENABLE_SHIFT)
+#define RX_ENABLE_SHIFT					0
+#define RX_ENABLE_MASK					BIT(RX_ENABLE_SHIFT)
+#define RX_ENABLE					BIT(RX_ENABLE_SHIFT)
+#define SW_RESET_MASK					1
+#define SW_RESET					1
+/* Default values - Tegra210 */
+#define TEGRA210_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT	0x00000300
+#define TEGRA210_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT	0x00000304
+#define TEGRA210_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT	0x00000208
+#define TEGRA210_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT	0x0000020b
+#define TEGRA210_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT	0x0000020e
+#define TEGRA210_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT	0x00000211
+#define TEGRA210_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT	0x00000214
+#define TEGRA210_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT	0x00000217
+#define TEGRA210_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT	0x0000021a
+#define TEGRA210_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT	0x0000021d
+#define TEGRA210_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT	0x02000300
+#define TEGRA210_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT	0x02000304
+#define TEGRA210_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT	0x01800208
+#define TEGRA210_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT	0x0180020b
+#define TEGRA210_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT	0x0180020e
+#define TEGRA210_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT	0x01800211
+#define TEGRA210_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT	0x01800214
+#define TEGRA210_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT	0x01800217
+#define TEGRA210_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT	0x0180021a
+#define TEGRA210_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT	0x0180021d
+/* Default values - Tegra186 */
+#define TEGRA186_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT	0x00000300
+#define TEGRA186_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT	0x00000304
+#define TEGRA186_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT	0x00000308
+#define TEGRA186_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT	0x0000030c
+#define TEGRA186_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT	0x00000210
+#define TEGRA186_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT	0x00000213
+#define TEGRA186_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT	0x00000216
+#define TEGRA186_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT	0x00000219
+#define TEGRA186_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT	0x0000021c
+#define TEGRA186_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT	0x0000021f
+#define TEGRA186_ADMAIF_RX11_FIFO_CTRL_REG_DEFAULT	0x00000222
+#define TEGRA186_ADMAIF_RX12_FIFO_CTRL_REG_DEFAULT	0x00000225
+#define TEGRA186_ADMAIF_RX13_FIFO_CTRL_REG_DEFAULT	0x00000228
+#define TEGRA186_ADMAIF_RX14_FIFO_CTRL_REG_DEFAULT	0x0000022b
+#define TEGRA186_ADMAIF_RX15_FIFO_CTRL_REG_DEFAULT	0x0000022e
+#define TEGRA186_ADMAIF_RX16_FIFO_CTRL_REG_DEFAULT	0x00000231
+#define TEGRA186_ADMAIF_RX17_FIFO_CTRL_REG_DEFAULT	0x00000234
+#define TEGRA186_ADMAIF_RX18_FIFO_CTRL_REG_DEFAULT	0x00000237
+#define TEGRA186_ADMAIF_RX19_FIFO_CTRL_REG_DEFAULT	0x0000023a
+#define TEGRA186_ADMAIF_RX20_FIFO_CTRL_REG_DEFAULT	0x0000023d
+#define TEGRA186_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT	0x02000300
+#define TEGRA186_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT	0x02000304
+#define TEGRA186_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT	0x02000308
+#define TEGRA186_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT	0x0200030c
+#define TEGRA186_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT	0x01800210
+#define TEGRA186_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT	0x01800213
+#define TEGRA186_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT	0x01800216
+#define TEGRA186_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT	0x01800219
+#define TEGRA186_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT	0x0180021c
+#define TEGRA186_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT	0x0180021f
+#define TEGRA186_ADMAIF_TX11_FIFO_CTRL_REG_DEFAULT	0x01800222
+#define TEGRA186_ADMAIF_TX12_FIFO_CTRL_REG_DEFAULT	0x01800225
+#define TEGRA186_ADMAIF_TX13_FIFO_CTRL_REG_DEFAULT	0x01800228
+#define TEGRA186_ADMAIF_TX14_FIFO_CTRL_REG_DEFAULT	0x0180022b
+#define TEGRA186_ADMAIF_TX15_FIFO_CTRL_REG_DEFAULT	0x0180022e
+#define TEGRA186_ADMAIF_TX16_FIFO_CTRL_REG_DEFAULT	0x01800231
+#define TEGRA186_ADMAIF_TX17_FIFO_CTRL_REG_DEFAULT	0x01800234
+#define TEGRA186_ADMAIF_TX18_FIFO_CTRL_REG_DEFAULT	0x01800237
+#define TEGRA186_ADMAIF_TX19_FIFO_CTRL_REG_DEFAULT	0x0180023a
+#define TEGRA186_ADMAIF_TX20_FIFO_CTRL_REG_DEFAULT	0x0180023d
+
+enum {
+	DATA_8BIT,
+	DATA_16BIT,
+	DATA_32BIT
+};
+
+enum {
+	ADMAIF_RX_PATH,
+	ADMAIF_TX_PATH,
+	ADMAIF_PATHS,
+};
+
+struct tegra_admaif_soc_data {
+	const struct snd_soc_component_driver *cmpnt;
+	const struct regmap_config *regmap_conf;
+	struct snd_soc_dai_driver *dais;
+	unsigned int global_base;
+	unsigned int tx_base;
+	unsigned int rx_base;
+	unsigned int num_ch;
+};
+
+struct tegra_admaif {
+	struct snd_dmaengine_dai_dma_data *capture_dma_data;
+	struct snd_dmaengine_dai_dma_data *playback_dma_data;
+	const struct tegra_admaif_soc_data *soc_data;
+	unsigned int *mono_to_stereo[ADMAIF_PATHS];
+	unsigned int *stereo_to_mono[ADMAIF_PATHS];
+	struct regmap *regmap;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index f246df8..b3f3651 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -16,12 +16,12 @@
  */
 
 #include <linux/module.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
-
 #include "tegra_pcm.h"
 
 static const struct snd_pcm_hardware tegra_pcm_hardware = {
@@ -67,6 +67,239 @@ void tegra_pcm_platform_unregister(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
 
+int tegra_pcm_open(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_dmaengine_dai_dma_data *dmap;
+	struct dma_chan *chan;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	int ret;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	dmap = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	/* Set HW params now that initialization is complete */
+	snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
+
+	/* Ensure period size is multiple of 8 */
+	ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8);
+	if (ret) {
+		dev_err(rtd->dev, "failed to set constraint %d\n", ret);
+		return ret;
+	}
+
+	chan = dma_request_slave_channel(cpu_dai->dev, dmap->chan_name);
+	if (!chan) {
+		dev_err(cpu_dai->dev,
+			"dmaengine request slave channel failed! (%s)\n",
+			dmap->chan_name);
+		return -ENODEV;
+	}
+
+	ret = snd_dmaengine_pcm_open(substream, chan);
+	if (ret) {
+		dev_err(rtd->dev,
+			"dmaengine pcm open failed with err %d (%s)\n", ret,
+			dmap->chan_name);
+
+		dma_release_channel(chan);
+
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_open);
+
+int tegra_pcm_close(struct snd_soc_component *component,
+		    struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	snd_dmaengine_pcm_close_release_chan(substream);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_close);
+
+int tegra_pcm_hw_params(struct snd_soc_component *component,
+			struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_dmaengine_dai_dma_data *dmap;
+	struct dma_slave_config slave_config;
+	struct dma_chan *chan;
+	int ret;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	dmap = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+	if (!dmap)
+		return 0;
+
+	chan = snd_dmaengine_pcm_get_chan(substream);
+
+	ret = snd_hwparams_to_dma_slave_config(substream, params,
+					       &slave_config);
+	if (ret) {
+		dev_err(rtd->dev, "hw params config failed with err %d\n", ret);
+		return ret;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		slave_config.dst_addr = dmap->addr;
+		slave_config.dst_maxburst = 8;
+	} else {
+		slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		slave_config.src_addr = dmap->addr;
+		slave_config.src_maxburst = 8;
+	}
+
+	ret = dmaengine_slave_config(chan, &slave_config);
+	if (ret < 0) {
+		dev_err(rtd->dev, "dma slave config failed with err %d\n", ret);
+		return ret;
+	}
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_hw_params);
+
+int tegra_pcm_hw_free(struct snd_soc_component *component,
+		      struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	snd_pcm_set_runtime_buffer(substream, NULL);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_hw_free);
+
+int tegra_pcm_mmap(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream,
+		   struct vm_area_struct *vma)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (rtd->dai_link->no_pcm)
+		return 0;
+
+	return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area,
+			   runtime->dma_addr, runtime->dma_bytes);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_mmap);
+
+snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component,
+				    struct snd_pcm_substream *substream)
+{
+	return snd_dmaengine_pcm_pointer(substream);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_pointer);
+
+static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
+					    size_t size)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+	buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->private_data = NULL;
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->bytes = size;
+
+	return 0;
+}
+
+static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+
+	substream = pcm->streams[stream].substream;
+	if (!substream)
+		return;
+
+	buf = &substream->dma_buffer;
+	if (!buf->area)
+		return;
+
+	dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
+	buf->area = NULL;
+}
+
+static int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd,
+				  size_t size)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret;
+
+	ret = dma_set_mask(card->dev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		return ret;
+
+	ret = dma_set_coherent_mask(card->dev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		return ret;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ret = tegra_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK, size);
+		if (ret)
+			goto err;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ret = tegra_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE, size);
+		if (ret)
+			goto err_free_play;
+	}
+
+	return 0;
+
+err_free_play:
+	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+err:
+	return ret;
+}
+
+int tegra_pcm_construct(struct snd_soc_component *component,
+			struct snd_soc_pcm_runtime *rtd)
+{
+	return tegra_pcm_dma_allocate(rtd, tegra_pcm_hardware.buffer_bytes_max);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_construct);
+
+void tegra_pcm_destruct(struct snd_soc_component *component,
+			struct snd_pcm *pcm)
+{
+	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
+	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_destruct);
+
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra PCM ASoC driver");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index 0433372..4838cdc 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -17,8 +17,27 @@
 #ifndef __TEGRA_PCM_H__
 #define __TEGRA_PCM_H__
 
-struct snd_dmaengine_pcm_config;
+#include <sound/dmaengine_pcm.h>
+#include <sound/asound.h>
 
+int tegra_pcm_construct(struct snd_soc_component *component,
+			struct snd_soc_pcm_runtime *rtd);
+void tegra_pcm_destruct(struct snd_soc_component *component,
+			struct snd_pcm *pcm);
+int tegra_pcm_open(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream);
+int tegra_pcm_close(struct snd_soc_component *component,
+		    struct snd_pcm_substream *substream);
+int tegra_pcm_hw_params(struct snd_soc_component *component,
+			struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params);
+int tegra_pcm_hw_free(struct snd_soc_component *component,
+		      struct snd_pcm_substream *substream);
+int tegra_pcm_mmap(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream,
+		   struct vm_area_struct *vma);
+snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component,
+				    struct snd_pcm_substream *substream);
 int tegra_pcm_platform_register(struct device *dev);
 int tegra_pcm_platform_register_with_chan_names(struct device *dev,
 				struct snd_dmaengine_pcm_config *config,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

The "prefix" can be defined in DAI link node or it can be specified as
part of the component node itself. Currently "sound-name-prefix" defined
in a component is not taking effect. Actually the property is not getting
parsed. It can be fixed by parsing "sound-name-prefix" property whenever
"prefix" is missing in DAI link Codec node.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/soc-core.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index adedadc..8faca60 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1111,8 +1111,10 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
 		struct snd_soc_codec_conf *map = &card->codec_conf[i];
 
 		if (snd_soc_is_matching_component(&map->dlc, component)) {
-			component->name_prefix = map->name_prefix;
-			return;
+			if (map->name_prefix) {
+				component->name_prefix = map->name_prefix;
+				return;
+			}
 		}
 	}
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

The "prefix" can be defined in DAI link node or it can be specified as
part of the component node itself. Currently "sound-name-prefix" defined
in a component is not taking effect. Actually the property is not getting
parsed. It can be fixed by parsing "sound-name-prefix" property whenever
"prefix" is missing in DAI link Codec node.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/soc-core.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index adedadc..8faca60 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1111,8 +1111,10 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
 		struct snd_soc_codec_conf *map = &card->codec_conf[i];
 
 		if (snd_soc_is_matching_component(&map->dlc, component)) {
-			component->name_prefix = map->name_prefix;
-			return;
+			if (map->name_prefix) {
+				component->name_prefix = map->name_prefix;
+				return;
+			}
 		}
 	}
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

The "prefix" can be defined in DAI link node or it can be specified as
part of the component node itself. Currently "sound-name-prefix" defined
in a component is not taking effect. Actually the property is not getting
parsed. It can be fixed by parsing "sound-name-prefix" property whenever
"prefix" is missing in DAI link Codec node.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/soc-core.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index adedadc..8faca60 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1111,8 +1111,10 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
 		struct snd_soc_codec_conf *map = &card->codec_conf[i];
 
 		if (snd_soc_is_matching_component(&map->dlc, component)) {
-			component->name_prefix = map->name_prefix;
-			return;
+			if (map->name_prefix) {
+				component->name_prefix = map->name_prefix;
+				return;
+			}
 		}
 	}
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 09/23] ASoC: simple-card: Use of_node and DAI names for DAI link names
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

For multiple instances of components, using DAI name alone for DAI links
is causing conflicts. Components can define multiple DAIs and hence using
just a device name won't help either. Thus DT device node reference and
DAI names are used to uniquely represent DAI link names.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/generic/simple-card.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 55e9f88..0f443c0 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -170,7 +170,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		ret = asoc_simple_set_dailink_name(dev, dai_link,
-						   "fe.%s",
+						   "fe.%pOFP.%s",
+						   cpus->of_node,
 						   cpus->dai_name);
 		if (ret < 0)
 			goto out_put_node;
@@ -203,7 +204,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		ret = asoc_simple_set_dailink_name(dev, dai_link,
-						   "be.%s",
+						   "be.%pOFP.%s",
+						   codecs->of_node,
 						   codecs->dai_name);
 		if (ret < 0)
 			goto out_put_node;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 09/23] ASoC: simple-card: Use of_node and DAI names for DAI link names
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

For multiple instances of components, using DAI name alone for DAI links
is causing conflicts. Components can define multiple DAIs and hence using
just a device name won't help either. Thus DT device node reference and
DAI names are used to uniquely represent DAI link names.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 55e9f88..0f443c0 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -170,7 +170,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		ret = asoc_simple_set_dailink_name(dev, dai_link,
-						   "fe.%s",
+						   "fe.%pOFP.%s",
+						   cpus->of_node,
 						   cpus->dai_name);
 		if (ret < 0)
 			goto out_put_node;
@@ -203,7 +204,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		ret = asoc_simple_set_dailink_name(dev, dai_link,
-						   "be.%s",
+						   "be.%pOFP.%s",
+						   codecs->of_node,
 						   codecs->dai_name);
 		if (ret < 0)
 			goto out_put_node;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 09/23] ASoC: simple-card: Use of_node and DAI names for DAI link names
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

For multiple instances of components, using DAI name alone for DAI links
is causing conflicts. Components can define multiple DAIs and hence using
just a device name won't help either. Thus DT device node reference and
DAI names are used to uniquely represent DAI link names.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 55e9f88..0f443c0 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -170,7 +170,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		ret = asoc_simple_set_dailink_name(dev, dai_link,
-						   "fe.%s",
+						   "fe.%pOFP.%s",
+						   cpus->of_node,
 						   cpus->dai_name);
 		if (ret < 0)
 			goto out_put_node;
@@ -203,7 +204,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		ret = asoc_simple_set_dailink_name(dev, dai_link,
-						   "be.%s",
+						   "be.%pOFP.%s",
+						   codecs->of_node,
 						   codecs->dai_name);
 		if (ret < 0)
 			goto out_put_node;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

Consider following DPCM DAI link for example:

 simple-audio-card,dai-link@xxx {
     format = "i2s";
     bitclock-master=<&cpu1>;
     frame-master=<&cpu1>;

     cpu1: cpu@0 {
         ...
     };

     codec@0 {
         ...
     };

     ...
 };

In above case CPU is expected to be configured as a master and Codec as
a slave device. But both CPU/Codec are being configured as slave devices.
This happens because asoc_simple_parse_daifmt() uses Codec reference and
sets up the 'dai_link->dai_fmt' accordingly while parsing both CPU and
Codec. Though populating 'non_legacy_dai_naming' flag as true for CPU
component can address above issue in simple cases, but with multiple
CPU/Codecs with DPCM DAI link it becomes tricky because right now the
first Codec in the DAI link is used as reference.

This is fixed by passing current DAI link child node reference to
asoc_simple_parse_daifmt(). It parses a CPU/Codec node independently and
sets daifmt as per 'bitcloclk/frame-master' property.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/generic/simple-card.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 0f443c0..39cdc71 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -228,7 +228,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	if (ret)
 		goto out_put_node;
 
-	ret = asoc_simple_parse_daifmt(dev, node, codec,
+	ret = asoc_simple_parse_daifmt(dev, node, np,
 				       prefix, &dai_link->dai_fmt);
 	if (ret < 0)
 		goto out_put_node;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

Consider following DPCM DAI link for example:

 simple-audio-card,dai-link@xxx {
     format = "i2s";
     bitclock-master=<&cpu1>;
     frame-master=<&cpu1>;

     cpu1: cpu@0 {
         ...
     };

     codec@0 {
         ...
     };

     ...
 };

In above case CPU is expected to be configured as a master and Codec as
a slave device. But both CPU/Codec are being configured as slave devices.
This happens because asoc_simple_parse_daifmt() uses Codec reference and
sets up the 'dai_link->dai_fmt' accordingly while parsing both CPU and
Codec. Though populating 'non_legacy_dai_naming' flag as true for CPU
component can address above issue in simple cases, but with multiple
CPU/Codecs with DPCM DAI link it becomes tricky because right now the
first Codec in the DAI link is used as reference.

This is fixed by passing current DAI link child node reference to
asoc_simple_parse_daifmt(). It parses a CPU/Codec node independently and
sets daifmt as per 'bitcloclk/frame-master' property.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 0f443c0..39cdc71 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -228,7 +228,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	if (ret)
 		goto out_put_node;
 
-	ret = asoc_simple_parse_daifmt(dev, node, codec,
+	ret = asoc_simple_parse_daifmt(dev, node, np,
 				       prefix, &dai_link->dai_fmt);
 	if (ret < 0)
 		goto out_put_node;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

Consider following DPCM DAI link for example:

 simple-audio-card,dai-link@xxx {
     format = "i2s";
     bitclock-master=<&cpu1>;
     frame-master=<&cpu1>;

     cpu1: cpu@0 {
         ...
     };

     codec@0 {
         ...
     };

     ...
 };

In above case CPU is expected to be configured as a master and Codec as
a slave device. But both CPU/Codec are being configured as slave devices.
This happens because asoc_simple_parse_daifmt() uses Codec reference and
sets up the 'dai_link->dai_fmt' accordingly while parsing both CPU and
Codec. Though populating 'non_legacy_dai_naming' flag as true for CPU
component can address above issue in simple cases, but with multiple
CPU/Codecs with DPCM DAI link it becomes tricky because right now the
first Codec in the DAI link is used as reference.

This is fixed by passing current DAI link child node reference to
asoc_simple_parse_daifmt(). It parses a CPU/Codec node independently and
sets daifmt as per 'bitcloclk/frame-master' property.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 0f443c0..39cdc71 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -228,7 +228,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	if (ret)
 		goto out_put_node;
 
-	ret = asoc_simple_parse_daifmt(dev, node, codec,
+	ret = asoc_simple_parse_daifmt(dev, node, np,
 				       prefix, &dai_link->dai_fmt);
 	if (ret < 0)
 		goto out_put_node;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

CPU/Codec in DPCM DAI links are connected as CPU<->Dummy and Dummy<->Codec.
Though mostly CPU won't use/require 'mclk-fs' property, looping over
'np' (current child node in a DAI link) can help in cases where multiple
Codecs are defined. This further helps to get rid of 'codec' argument
from simple_dai_link_of_dpcm() function, which gets called for DPCM links.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/generic/simple-card.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 39cdc71..02d6295 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -107,7 +107,9 @@ static void simple_parse_mclk_fs(struct device_node *top,
 	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
 	of_property_read_u32(node,	prop, &props->mclk_fs);
 	of_property_read_u32(cpu,	prop, &props->mclk_fs);
-	of_property_read_u32(codec,	prop, &props->mclk_fs);
+
+	if (cpu != codec)
+		of_property_read_u32(codec, prop, &props->mclk_fs);
 
 	of_node_put(node);
 }
@@ -220,7 +222,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	}
 
 	simple_parse_convert(dev, np, &dai_props->adata);
-	simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
+	simple_parse_mclk_fs(top, np, np, dai_props, prefix);
 
 	asoc_simple_canonicalize_platform(dai_link);
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

CPU/Codec in DPCM DAI links are connected as CPU<->Dummy and Dummy<->Codec.
Though mostly CPU won't use/require 'mclk-fs' property, looping over
'np' (current child node in a DAI link) can help in cases where multiple
Codecs are defined. This further helps to get rid of 'codec' argument
from simple_dai_link_of_dpcm() function, which gets called for DPCM links.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 39cdc71..02d6295 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -107,7 +107,9 @@ static void simple_parse_mclk_fs(struct device_node *top,
 	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
 	of_property_read_u32(node,	prop, &props->mclk_fs);
 	of_property_read_u32(cpu,	prop, &props->mclk_fs);
-	of_property_read_u32(codec,	prop, &props->mclk_fs);
+
+	if (cpu != codec)
+		of_property_read_u32(codec, prop, &props->mclk_fs);
 
 	of_node_put(node);
 }
@@ -220,7 +222,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	}
 
 	simple_parse_convert(dev, np, &dai_props->adata);
-	simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
+	simple_parse_mclk_fs(top, np, np, dai_props, prefix);
 
 	asoc_simple_canonicalize_platform(dai_link);
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

CPU/Codec in DPCM DAI links are connected as CPU<->Dummy and Dummy<->Codec.
Though mostly CPU won't use/require 'mclk-fs' property, looping over
'np' (current child node in a DAI link) can help in cases where multiple
Codecs are defined. This further helps to get rid of 'codec' argument
from simple_dai_link_of_dpcm() function, which gets called for DPCM links.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 39cdc71..02d6295 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -107,7 +107,9 @@ static void simple_parse_mclk_fs(struct device_node *top,
 	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
 	of_property_read_u32(node,	prop, &props->mclk_fs);
 	of_property_read_u32(cpu,	prop, &props->mclk_fs);
-	of_property_read_u32(codec,	prop, &props->mclk_fs);
+
+	if (cpu != codec)
+		of_property_read_u32(codec, prop, &props->mclk_fs);
 
 	of_node_put(node);
 }
@@ -220,7 +222,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	}
 
 	simple_parse_convert(dev, np, &dai_props->adata);
-	simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
+	simple_parse_mclk_fs(top, np, np, dai_props, prefix);
 
 	asoc_simple_canonicalize_platform(dai_link);
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

The simple-card driver supports multiple CPU and single Codec entries
for DPCM DAI links. In some cases it is required to have multiple
CPU/Codecs. Currently parsing logic for DPCM link loops over all
children of DAI link but assumes that there is a single Codec entry.
When DAI link has multiple Codecs it considers only the first Codec
entry and remaining Codecs are wrongly treated as CPU. This happens
because first Codec is used as reference for parsing all other child
nodes.

This is fixed by using string comparisons of child node names instead
of node pointer reference in simple_dai_link_of_dpcm(). So All CPU
get parsed in first run and all Codecs in subsequent run. After this
simple_dai_link_of_dpcm() does not required 'codec' argument and hence
is removed.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/generic/simple-card.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 02d6295..15c4388 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -116,7 +116,6 @@ static void simple_parse_mclk_fs(struct device_node *top,
 
 static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 				   struct device_node *np,
-				   struct device_node *codec,
 				   struct link_info *li,
 				   bool is_top)
 {
@@ -137,8 +136,13 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	 * Codec |return|Pass
 	 * np
 	 */
-	if (li->cpu == (np == codec))
-		return 0;
+	if (li->cpu) {
+		if (!strcmp(np->name, "codec"))
+			return 0;
+	} else {
+		if (!strcmp(np->name, "cpu"))
+			return 0;
+	}
 
 	dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
 
@@ -354,7 +358,6 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 					 struct link_info *li, bool is_top),
 			int (*func_dpcm)(struct asoc_simple_priv *priv,
 					 struct device_node *np,
-					 struct device_node *codec,
 					 struct link_info *li, bool is_top))
 {
 	struct device *dev = simple_priv_to_dev(priv);
@@ -407,7 +410,7 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 			if (dpcm_selectable &&
 			    (num > 2 ||
 			     adata.convert_rate || adata.convert_channels))
-				ret = func_dpcm(priv, np, codec, li, is_top);
+				ret = func_dpcm(priv, np, li, is_top);
 			/* else normal sound */
 			else
 				ret = func_noml(priv, np, codec, li, is_top);
@@ -527,12 +530,11 @@ static int simple_count_noml(struct asoc_simple_priv *priv,
 
 static int simple_count_dpcm(struct asoc_simple_priv *priv,
 			     struct device_node *np,
-			     struct device_node *codec,
 			     struct link_info *li, bool is_top)
 {
 	li->dais++; /* CPU or Codec */
 	li->link++; /* CPU-dummy or dummy-Codec */
-	if (np == codec)
+	if (!strcmp(np->name, "codec"))
 		li->conf++;
 
 	return 0;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

The simple-card driver supports multiple CPU and single Codec entries
for DPCM DAI links. In some cases it is required to have multiple
CPU/Codecs. Currently parsing logic for DPCM link loops over all
children of DAI link but assumes that there is a single Codec entry.
When DAI link has multiple Codecs it considers only the first Codec
entry and remaining Codecs are wrongly treated as CPU. This happens
because first Codec is used as reference for parsing all other child
nodes.

This is fixed by using string comparisons of child node names instead
of node pointer reference in simple_dai_link_of_dpcm(). So All CPU
get parsed in first run and all Codecs in subsequent run. After this
simple_dai_link_of_dpcm() does not required 'codec' argument and hence
is removed.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 02d6295..15c4388 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -116,7 +116,6 @@ static void simple_parse_mclk_fs(struct device_node *top,
 
 static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 				   struct device_node *np,
-				   struct device_node *codec,
 				   struct link_info *li,
 				   bool is_top)
 {
@@ -137,8 +136,13 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	 * Codec |return|Pass
 	 * np
 	 */
-	if (li->cpu == (np == codec))
-		return 0;
+	if (li->cpu) {
+		if (!strcmp(np->name, "codec"))
+			return 0;
+	} else {
+		if (!strcmp(np->name, "cpu"))
+			return 0;
+	}
 
 	dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
 
@@ -354,7 +358,6 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 					 struct link_info *li, bool is_top),
 			int (*func_dpcm)(struct asoc_simple_priv *priv,
 					 struct device_node *np,
-					 struct device_node *codec,
 					 struct link_info *li, bool is_top))
 {
 	struct device *dev = simple_priv_to_dev(priv);
@@ -407,7 +410,7 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 			if (dpcm_selectable &&
 			    (num > 2 ||
 			     adata.convert_rate || adata.convert_channels))
-				ret = func_dpcm(priv, np, codec, li, is_top);
+				ret = func_dpcm(priv, np, li, is_top);
 			/* else normal sound */
 			else
 				ret = func_noml(priv, np, codec, li, is_top);
@@ -527,12 +530,11 @@ static int simple_count_noml(struct asoc_simple_priv *priv,
 
 static int simple_count_dpcm(struct asoc_simple_priv *priv,
 			     struct device_node *np,
-			     struct device_node *codec,
 			     struct link_info *li, bool is_top)
 {
 	li->dais++; /* CPU or Codec */
 	li->link++; /* CPU-dummy or dummy-Codec */
-	if (np == codec)
+	if (!strcmp(np->name, "codec"))
 		li->conf++;
 
 	return 0;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

The simple-card driver supports multiple CPU and single Codec entries
for DPCM DAI links. In some cases it is required to have multiple
CPU/Codecs. Currently parsing logic for DPCM link loops over all
children of DAI link but assumes that there is a single Codec entry.
When DAI link has multiple Codecs it considers only the first Codec
entry and remaining Codecs are wrongly treated as CPU. This happens
because first Codec is used as reference for parsing all other child
nodes.

This is fixed by using string comparisons of child node names instead
of node pointer reference in simple_dai_link_of_dpcm(). So All CPU
get parsed in first run and all Codecs in subsequent run. After this
simple_dai_link_of_dpcm() does not required 'codec' argument and hence
is removed.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 02d6295..15c4388 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -116,7 +116,6 @@ static void simple_parse_mclk_fs(struct device_node *top,
 
 static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 				   struct device_node *np,
-				   struct device_node *codec,
 				   struct link_info *li,
 				   bool is_top)
 {
@@ -137,8 +136,13 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	 * Codec |return|Pass
 	 * np
 	 */
-	if (li->cpu == (np == codec))
-		return 0;
+	if (li->cpu) {
+		if (!strcmp(np->name, "codec"))
+			return 0;
+	} else {
+		if (!strcmp(np->name, "cpu"))
+			return 0;
+	}
 
 	dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
 
@@ -354,7 +358,6 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 					 struct link_info *li, bool is_top),
 			int (*func_dpcm)(struct asoc_simple_priv *priv,
 					 struct device_node *np,
-					 struct device_node *codec,
 					 struct link_info *li, bool is_top))
 {
 	struct device *dev = simple_priv_to_dev(priv);
@@ -407,7 +410,7 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 			if (dpcm_selectable &&
 			    (num > 2 ||
 			     adata.convert_rate || adata.convert_channels))
-				ret = func_dpcm(priv, np, codec, li, is_top);
+				ret = func_dpcm(priv, np, li, is_top);
 			/* else normal sound */
 			else
 				ret = func_noml(priv, np, codec, li, is_top);
@@ -527,12 +530,11 @@ static int simple_count_noml(struct asoc_simple_priv *priv,
 
 static int simple_count_dpcm(struct asoc_simple_priv *priv,
 			     struct device_node *np,
-			     struct device_node *codec,
 			     struct link_info *li, bool is_top)
 {
 	li->dais++; /* CPU or Codec */
 	li->link++; /* CPU-dummy or dummy-Codec */
-	if (np == codec)
+	if (!strcmp(np->name, "codec"))
 		li->conf++;
 
 	return 0;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 13/23] ASoC: simple-card: DPCM DAI link direction as per DAI capability
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

The soc_new_pcm() fails for DAI link having DAI which supports a
single stream direction of either PLAYBACK or CAPTURE. For example
it fails for Microphone which can support CAPTURE stream only. This
happens because simple-card driver by default populates both stream
directions.

This can be fixed by populating directions based on DAI capability.
For 'CPU<->Dummy' DAI links CPU is used to setup the direction and
similarly Codec is used for 'Dummy<->Codec' DAI links.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/generic/simple-card.c | 27 +++++++++++++++++++++++++--
 sound/soc/soc-dai.c             |  1 +
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 15c4388..62f2978 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -114,6 +114,23 @@ static void simple_parse_mclk_fs(struct device_node *top,
 	of_node_put(node);
 }
 
+static int simple_parse_dpcm_dir(const struct snd_soc_dai_link_component *dlc,
+				 struct snd_soc_dai_link *dai_link)
+{
+	struct snd_soc_dai *dai = snd_soc_find_dai(dlc);
+
+	if (!dai)
+		return -EINVAL;
+
+	dai_link->dpcm_playback =
+		snd_soc_dai_stream_valid(dai, SNDRV_PCM_STREAM_PLAYBACK);
+
+	dai_link->dpcm_capture =
+		snd_soc_dai_stream_valid(dai, SNDRV_PCM_STREAM_CAPTURE);
+
+	return 0;
+}
+
 static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 				   struct device_node *np,
 				   struct link_info *li,
@@ -183,6 +200,10 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		asoc_simple_canonicalize_cpu(dai_link, is_single_links);
+
+		ret = simple_parse_dpcm_dir(cpus, dai_link);
+		if (ret < 0)
+			goto out_put_node;
 	} else {
 		struct snd_soc_codec_conf *cconf;
 
@@ -223,6 +244,10 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 					     "prefix");
 		snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
 					     "prefix");
+
+		ret = simple_parse_dpcm_dir(codecs, dai_link);
+		if (ret < 0)
+			goto out_put_node;
 	}
 
 	simple_parse_convert(dev, np, &dai_props->adata);
@@ -239,8 +264,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		goto out_put_node;
 
-	dai_link->dpcm_playback		= 1;
-	dai_link->dpcm_capture		= 1;
 	dai_link->ops			= &simple_ops;
 	dai_link->init			= asoc_simple_dai_init;
 
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index b05e18b..bd4465f 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -390,6 +390,7 @@ bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
 	/* If the codec specifies any channels at all, it supports the stream */
 	return stream->channels_min;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_valid);
 
 void snd_soc_dai_action(struct snd_soc_dai *dai,
 			int stream, int action)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 13/23] ASoC: simple-card: DPCM DAI link direction as per DAI capability
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

The soc_new_pcm() fails for DAI link having DAI which supports a
single stream direction of either PLAYBACK or CAPTURE. For example
it fails for Microphone which can support CAPTURE stream only. This
happens because simple-card driver by default populates both stream
directions.

This can be fixed by populating directions based on DAI capability.
For 'CPU<->Dummy' DAI links CPU is used to setup the direction and
similarly Codec is used for 'Dummy<->Codec' DAI links.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 27 +++++++++++++++++++++++++--
 sound/soc/soc-dai.c             |  1 +
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 15c4388..62f2978 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -114,6 +114,23 @@ static void simple_parse_mclk_fs(struct device_node *top,
 	of_node_put(node);
 }
 
+static int simple_parse_dpcm_dir(const struct snd_soc_dai_link_component *dlc,
+				 struct snd_soc_dai_link *dai_link)
+{
+	struct snd_soc_dai *dai = snd_soc_find_dai(dlc);
+
+	if (!dai)
+		return -EINVAL;
+
+	dai_link->dpcm_playback =
+		snd_soc_dai_stream_valid(dai, SNDRV_PCM_STREAM_PLAYBACK);
+
+	dai_link->dpcm_capture =
+		snd_soc_dai_stream_valid(dai, SNDRV_PCM_STREAM_CAPTURE);
+
+	return 0;
+}
+
 static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 				   struct device_node *np,
 				   struct link_info *li,
@@ -183,6 +200,10 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		asoc_simple_canonicalize_cpu(dai_link, is_single_links);
+
+		ret = simple_parse_dpcm_dir(cpus, dai_link);
+		if (ret < 0)
+			goto out_put_node;
 	} else {
 		struct snd_soc_codec_conf *cconf;
 
@@ -223,6 +244,10 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 					     "prefix");
 		snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
 					     "prefix");
+
+		ret = simple_parse_dpcm_dir(codecs, dai_link);
+		if (ret < 0)
+			goto out_put_node;
 	}
 
 	simple_parse_convert(dev, np, &dai_props->adata);
@@ -239,8 +264,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		goto out_put_node;
 
-	dai_link->dpcm_playback		= 1;
-	dai_link->dpcm_capture		= 1;
 	dai_link->ops			= &simple_ops;
 	dai_link->init			= asoc_simple_dai_init;
 
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index b05e18b..bd4465f 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -390,6 +390,7 @@ bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
 	/* If the codec specifies any channels at all, it supports the stream */
 	return stream->channels_min;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_valid);
 
 void snd_soc_dai_action(struct snd_soc_dai *dai,
 			int stream, int action)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 13/23] ASoC: simple-card: DPCM DAI link direction as per DAI capability
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

The soc_new_pcm() fails for DAI link having DAI which supports a
single stream direction of either PLAYBACK or CAPTURE. For example
it fails for Microphone which can support CAPTURE stream only. This
happens because simple-card driver by default populates both stream
directions.

This can be fixed by populating directions based on DAI capability.
For 'CPU<->Dummy' DAI links CPU is used to setup the direction and
similarly Codec is used for 'Dummy<->Codec' DAI links.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/generic/simple-card.c | 27 +++++++++++++++++++++++++--
 sound/soc/soc-dai.c             |  1 +
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 15c4388..62f2978 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -114,6 +114,23 @@ static void simple_parse_mclk_fs(struct device_node *top,
 	of_node_put(node);
 }
 
+static int simple_parse_dpcm_dir(const struct snd_soc_dai_link_component *dlc,
+				 struct snd_soc_dai_link *dai_link)
+{
+	struct snd_soc_dai *dai = snd_soc_find_dai(dlc);
+
+	if (!dai)
+		return -EINVAL;
+
+	dai_link->dpcm_playback =
+		snd_soc_dai_stream_valid(dai, SNDRV_PCM_STREAM_PLAYBACK);
+
+	dai_link->dpcm_capture =
+		snd_soc_dai_stream_valid(dai, SNDRV_PCM_STREAM_CAPTURE);
+
+	return 0;
+}
+
 static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 				   struct device_node *np,
 				   struct link_info *li,
@@ -183,6 +200,10 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 			goto out_put_node;
 
 		asoc_simple_canonicalize_cpu(dai_link, is_single_links);
+
+		ret = simple_parse_dpcm_dir(cpus, dai_link);
+		if (ret < 0)
+			goto out_put_node;
 	} else {
 		struct snd_soc_codec_conf *cconf;
 
@@ -223,6 +244,10 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 					     "prefix");
 		snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
 					     "prefix");
+
+		ret = simple_parse_dpcm_dir(codecs, dai_link);
+		if (ret < 0)
+			goto out_put_node;
 	}
 
 	simple_parse_convert(dev, np, &dai_props->adata);
@@ -239,8 +264,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		goto out_put_node;
 
-	dai_link->dpcm_playback		= 1;
-	dai_link->dpcm_capture		= 1;
 	dai_link->ops			= &simple_ops;
 	dai_link->init			= asoc_simple_dai_init;
 
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index b05e18b..bd4465f 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -390,6 +390,7 @@ bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
 	/* If the codec specifies any channels at all, it supports the stream */
 	return stream->channels_min;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dai_stream_valid);
 
 void snd_soc_dai_action(struct snd_soc_dai *dai,
 			int stream, int action)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 14/23] ASoC: soc-core: Probe auxiliary component before others
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

A router component can be added as an auxiliary device to the sound card
to help with audio routing across multiple components. DPCM dai links
use CPU<->Dummy or Dummy<->Codec style of links in simple-card driver and
hence do not have required DAI connections by default. Usually machine
driver can do the necessary mapping.

But if there is a crossbar switch HW which can connect multiple components,
it is expected to provide required user space configurability via MUX
controls. In such a case the crossbar can be represented as an independent
component and can be added as an auxiliary device. The exposed routing
interfaces can be used by other components in the system, thus probing it
first can avoid probe failures.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 sound/soc/soc-core.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 8faca60..9041a03 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1850,19 +1850,19 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
 	if (ret < 0)
 		goto probe_end;
 
-	/* probe all components used by DAI links on this card */
-	ret = soc_probe_link_components(card);
+	/* probe auxiliary components */
+	ret = soc_probe_aux_devices(card);
 	if (ret < 0) {
 		dev_err(card->dev,
-			"ASoC: failed to instantiate card %d\n", ret);
+			"ASoC: failed to probe aux component %d\n", ret);
 		goto probe_end;
 	}
 
-	/* probe auxiliary components */
-	ret = soc_probe_aux_devices(card);
+	/* probe all components used by DAI links on this card */
+	ret = soc_probe_link_components(card);
 	if (ret < 0) {
 		dev_err(card->dev,
-			"ASoC: failed to probe aux component %d\n", ret);
+			"ASoC: failed to instantiate card %d\n", ret);
 		goto probe_end;
 	}
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 14/23] ASoC: soc-core: Probe auxiliary component before others
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

A router component can be added as an auxiliary device to the sound card
to help with audio routing across multiple components. DPCM dai links
use CPU<->Dummy or Dummy<->Codec style of links in simple-card driver and
hence do not have required DAI connections by default. Usually machine
driver can do the necessary mapping.

But if there is a crossbar switch HW which can connect multiple components,
it is expected to provide required user space configurability via MUX
controls. In such a case the crossbar can be represented as an independent
component and can be added as an auxiliary device. The exposed routing
interfaces can be used by other components in the system, thus probing it
first can avoid probe failures.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/soc-core.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 8faca60..9041a03 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1850,19 +1850,19 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
 	if (ret < 0)
 		goto probe_end;
 
-	/* probe all components used by DAI links on this card */
-	ret = soc_probe_link_components(card);
+	/* probe auxiliary components */
+	ret = soc_probe_aux_devices(card);
 	if (ret < 0) {
 		dev_err(card->dev,
-			"ASoC: failed to instantiate card %d\n", ret);
+			"ASoC: failed to probe aux component %d\n", ret);
 		goto probe_end;
 	}
 
-	/* probe auxiliary components */
-	ret = soc_probe_aux_devices(card);
+	/* probe all components used by DAI links on this card */
+	ret = soc_probe_link_components(card);
 	if (ret < 0) {
 		dev_err(card->dev,
-			"ASoC: failed to probe aux component %d\n", ret);
+			"ASoC: failed to instantiate card %d\n", ret);
 		goto probe_end;
 	}
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 14/23] ASoC: soc-core: Probe auxiliary component before others
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

A router component can be added as an auxiliary device to the sound card
to help with audio routing across multiple components. DPCM dai links
use CPU<->Dummy or Dummy<->Codec style of links in simple-card driver and
hence do not have required DAI connections by default. Usually machine
driver can do the necessary mapping.

But if there is a crossbar switch HW which can connect multiple components,
it is expected to provide required user space configurability via MUX
controls. In such a case the crossbar can be represented as an independent
component and can be added as an auxiliary device. The exposed routing
interfaces can be used by other components in the system, thus probing it
first can avoid probe failures.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 sound/soc/soc-core.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 8faca60..9041a03 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1850,19 +1850,19 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
 	if (ret < 0)
 		goto probe_end;
 
-	/* probe all components used by DAI links on this card */
-	ret = soc_probe_link_components(card);
+	/* probe auxiliary components */
+	ret = soc_probe_aux_devices(card);
 	if (ret < 0) {
 		dev_err(card->dev,
-			"ASoC: failed to instantiate card %d\n", ret);
+			"ASoC: failed to probe aux component %d\n", ret);
 		goto probe_end;
 	}
 
-	/* probe auxiliary components */
-	ret = soc_probe_aux_devices(card);
+	/* probe all components used by DAI links on this card */
+	ret = soc_probe_link_components(card);
 	if (ret < 0) {
 		dev_err(card->dev,
-			"ASoC: failed to probe aux component %d\n", ret);
+			"ASoC: failed to instantiate card %d\n", ret);
 		goto probe_end;
 	}
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53   ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

PCM devices are created for dai links with 'no-pcm' flag as '0'.
Such DAI links have CPU component which implement pcm_construct()
and pcm_destruct() callbacks. Based on this, current patch exposes
a helper function to identify such components and populate 'no_pcm'
flag for DPCM DAI link.

This helps to have BE<->BE component links where PCM devices need
not be created for CPU components involved in the links.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 include/sound/soc.h             |  2 ++
 sound/soc/generic/simple-card.c |  3 +++
 sound/soc/soc-core.c            | 25 +++++++++++++++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 33acead..1e0376f 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -397,6 +397,7 @@ struct snd_soc_dai_driver;
 struct snd_soc_dai_link;
 struct snd_soc_component;
 struct snd_soc_component_driver;
+struct snd_soc_dai_link_component;
 struct soc_enum;
 struct snd_soc_jack;
 struct snd_soc_jack_zone;
@@ -437,6 +438,7 @@ int snd_soc_add_component(struct device *dev,
 		const struct snd_soc_component_driver *component_driver,
 		struct snd_soc_dai_driver *dai_drv,
 		int num_dai);
+bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc);
 int snd_soc_register_component(struct device *dev,
 			 const struct snd_soc_component_driver *component_driver,
 			 struct snd_soc_dai_driver *dai_drv, int num_dai);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 62f2978..f19030b 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -188,6 +188,9 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 		if (ret)
 			goto out_put_node;
 
+		if (!soc_component_is_pcm(cpus))
+			dai_link->no_pcm = 1;
+
 		ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai);
 		if (ret < 0)
 			goto out_put_node;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 9041a03..d2a47c3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -259,6 +259,31 @@ static inline void snd_soc_debugfs_exit(void)
 
 #endif
 
+bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
+{
+	struct snd_soc_component *component;
+	struct snd_soc_dai *dai;
+
+	for_each_component(component) {
+		if (!component->driver)
+			continue;
+
+		for_each_component_dais(component, dai) {
+			if (!dai->name || !dlc->dai_name)
+				continue;
+
+			if (strcmp(dai->name, dlc->dai_name))
+				continue;
+
+			if (component->driver->pcm_construct)
+				return true;
+		}
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(soc_component_is_pcm);
+
 static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
 				     struct snd_soc_component *component)
 {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-06-27  4:53   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

PCM devices are created for dai links with 'no-pcm' flag as '0'.
Such DAI links have CPU component which implement pcm_construct()
and pcm_destruct() callbacks. Based on this, current patch exposes
a helper function to identify such components and populate 'no_pcm'
flag for DPCM DAI link.

This helps to have BE<->BE component links where PCM devices need
not be created for CPU components involved in the links.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 include/sound/soc.h             |  2 ++
 sound/soc/generic/simple-card.c |  3 +++
 sound/soc/soc-core.c            | 25 +++++++++++++++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 33acead..1e0376f 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -397,6 +397,7 @@ struct snd_soc_dai_driver;
 struct snd_soc_dai_link;
 struct snd_soc_component;
 struct snd_soc_component_driver;
+struct snd_soc_dai_link_component;
 struct soc_enum;
 struct snd_soc_jack;
 struct snd_soc_jack_zone;
@@ -437,6 +438,7 @@ int snd_soc_add_component(struct device *dev,
 		const struct snd_soc_component_driver *component_driver,
 		struct snd_soc_dai_driver *dai_drv,
 		int num_dai);
+bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc);
 int snd_soc_register_component(struct device *dev,
 			 const struct snd_soc_component_driver *component_driver,
 			 struct snd_soc_dai_driver *dai_drv, int num_dai);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 62f2978..f19030b 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -188,6 +188,9 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 		if (ret)
 			goto out_put_node;
 
+		if (!soc_component_is_pcm(cpus))
+			dai_link->no_pcm = 1;
+
 		ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai);
 		if (ret < 0)
 			goto out_put_node;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 9041a03..d2a47c3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -259,6 +259,31 @@ static inline void snd_soc_debugfs_exit(void)
 
 #endif
 
+bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
+{
+	struct snd_soc_component *component;
+	struct snd_soc_dai *dai;
+
+	for_each_component(component) {
+		if (!component->driver)
+			continue;
+
+		for_each_component_dais(component, dai) {
+			if (!dai->name || !dlc->dai_name)
+				continue;
+
+			if (strcmp(dai->name, dlc->dai_name))
+				continue;
+
+			if (component->driver->pcm_construct)
+				return true;
+		}
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(soc_component_is_pcm);
+
 static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
 				     struct snd_soc_component *component)
 {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-06-27  4:53   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

PCM devices are created for dai links with 'no-pcm' flag as '0'.
Such DAI links have CPU component which implement pcm_construct()
and pcm_destruct() callbacks. Based on this, current patch exposes
a helper function to identify such components and populate 'no_pcm'
flag for DPCM DAI link.

This helps to have BE<->BE component links where PCM devices need
not be created for CPU components involved in the links.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 include/sound/soc.h             |  2 ++
 sound/soc/generic/simple-card.c |  3 +++
 sound/soc/soc-core.c            | 25 +++++++++++++++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 33acead..1e0376f 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -397,6 +397,7 @@ struct snd_soc_dai_driver;
 struct snd_soc_dai_link;
 struct snd_soc_component;
 struct snd_soc_component_driver;
+struct snd_soc_dai_link_component;
 struct soc_enum;
 struct snd_soc_jack;
 struct snd_soc_jack_zone;
@@ -437,6 +438,7 @@ int snd_soc_add_component(struct device *dev,
 		const struct snd_soc_component_driver *component_driver,
 		struct snd_soc_dai_driver *dai_drv,
 		int num_dai);
+bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc);
 int snd_soc_register_component(struct device *dev,
 			 const struct snd_soc_component_driver *component_driver,
 			 struct snd_soc_dai_driver *dai_drv, int num_dai);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 62f2978..f19030b 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -188,6 +188,9 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
 		if (ret)
 			goto out_put_node;
 
+		if (!soc_component_is_pcm(cpus))
+			dai_link->no_pcm = 1;
+
 		ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai);
 		if (ret < 0)
 			goto out_put_node;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 9041a03..d2a47c3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -259,6 +259,31 @@ static inline void snd_soc_debugfs_exit(void)
 
 #endif
 
+bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
+{
+	struct snd_soc_component *component;
+	struct snd_soc_dai *dai;
+
+	for_each_component(component) {
+		if (!component->driver)
+			continue;
+
+		for_each_component_dais(component, dai) {
+			if (!dai->name || !dlc->dai_name)
+				continue;
+
+			if (strcmp(dai->name, dlc->dai_name))
+				continue;
+
+			if (component->driver->pcm_construct)
+				return true;
+		}
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(soc_component_is_pcm);
+
 static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
 				     struct snd_soc_component *component)
 {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 16/23] ASoC: soc-pcm: Get all BEs along DAPM path
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

dpcm_end_walk_at_be() stops the graph walk when first BE is found for
the given FE component. In a component model we may want to connect
multiple DAIs from different components. A new flag is introduced in
'snd_soc_card', which when set allows DAI/component chaining. Later
PCM operations can be called for all these listed components for a
valid DAPM path.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 include/sound/soc.h | 1 +
 sound/soc/soc-pcm.c | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 1e0376f..95e02a7 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1069,6 +1069,7 @@ struct snd_soc_card {
 	int num_of_dapm_widgets;
 	const struct snd_soc_dapm_route *of_dapm_routes;
 	int num_of_dapm_routes;
+	bool component_chaining;
 
 	/* lists of probed devices belonging to this card */
 	struct list_head component_dev_list;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 6dc21b6..7f612e3 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1322,7 +1322,8 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
 
 	/* get number of valid DAI paths and their widgets */
 	paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
-			dpcm_end_walk_at_be);
+			fe->card->component_chaining ?
+				NULL : dpcm_end_walk_at_be);
 
 	dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
 			stream ? "capture" : "playback");
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 16/23] ASoC: soc-pcm: Get all BEs along DAPM path
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

dpcm_end_walk_at_be() stops the graph walk when first BE is found for
the given FE component. In a component model we may want to connect
multiple DAIs from different components. A new flag is introduced in
'snd_soc_card', which when set allows DAI/component chaining. Later
PCM operations can be called for all these listed components for a
valid DAPM path.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 include/sound/soc.h | 1 +
 sound/soc/soc-pcm.c | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 1e0376f..95e02a7 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1069,6 +1069,7 @@ struct snd_soc_card {
 	int num_of_dapm_widgets;
 	const struct snd_soc_dapm_route *of_dapm_routes;
 	int num_of_dapm_routes;
+	bool component_chaining;
 
 	/* lists of probed devices belonging to this card */
 	struct list_head component_dev_list;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 6dc21b6..7f612e3 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1322,7 +1322,8 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
 
 	/* get number of valid DAI paths and their widgets */
 	paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
-			dpcm_end_walk_at_be);
+			fe->card->component_chaining ?
+				NULL : dpcm_end_walk_at_be);
 
 	dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
 			stream ? "capture" : "playback");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 16/23] ASoC: soc-pcm: Get all BEs along DAPM path
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

dpcm_end_walk_at_be() stops the graph walk when first BE is found for
the given FE component. In a component model we may want to connect
multiple DAIs from different components. A new flag is introduced in
'snd_soc_card', which when set allows DAI/component chaining. Later
PCM operations can be called for all these listed components for a
valid DAPM path.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 include/sound/soc.h | 1 +
 sound/soc/soc-pcm.c | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 1e0376f..95e02a7 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1069,6 +1069,7 @@ struct snd_soc_card {
 	int num_of_dapm_widgets;
 	const struct snd_soc_dapm_route *of_dapm_routes;
 	int num_of_dapm_routes;
+	bool component_chaining;
 
 	/* lists of probed devices belonging to this card */
 	struct list_head component_dev_list;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 6dc21b6..7f612e3 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1322,7 +1322,8 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
 
 	/* get number of valid DAI paths and their widgets */
 	paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
-			dpcm_end_walk_at_be);
+			fe->card->component_chaining ?
+				NULL : dpcm_end_walk_at_be);
 
 	dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
 			stream ? "capture" : "playback");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 17/23] ASoC: dt-bindings: simple-card: Add compatible for component chaining
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

New compatible "simple-cc-audio-card" is exposed for simple-card driver
which allows usage of DAI link chaining and thus connects multiple
components together in a system.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 Documentation/devicetree/bindings/sound/simple-card.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
index 8132d0c..fcd0fd3 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
@@ -145,6 +145,7 @@ properties:
       enum:
         - simple-audio-card
         - simple-scu-audio-card
+        - simple-cc-audio-card
 
   "#address-cells":
     const: 1
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 17/23] ASoC: dt-bindings: simple-card: Add compatible for component chaining
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

New compatible "simple-cc-audio-card" is exposed for simple-card driver
which allows usage of DAI link chaining and thus connects multiple
components together in a system.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 Documentation/devicetree/bindings/sound/simple-card.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
index 8132d0c..fcd0fd3 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
@@ -145,6 +145,7 @@ properties:
       enum:
         - simple-audio-card
         - simple-scu-audio-card
+        - simple-cc-audio-card
 
   "#address-cells":
     const: 1
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 17/23] ASoC: dt-bindings: simple-card: Add compatible for component chaining
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

New compatible "simple-cc-audio-card" is exposed for simple-card driver
which allows usage of DAI link chaining and thus connects multiple
components together in a system.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 Documentation/devicetree/bindings/sound/simple-card.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
index 8132d0c..fcd0fd3 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
@@ -145,6 +145,7 @@ properties:
       enum:
         - simple-audio-card
         - simple-scu-audio-card
+        - simple-cc-audio-card
 
   "#address-cells":
     const: 1
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 18/23] ASoC: simple-card: Add support for component chaining
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53   ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

The simple-card driver supports both normal and DPCM DAI links. The
sound cards requiring DPCM DAI link support use DPCM_SELECTABLE flag
and DAI links are treated as DPCM links depending on the number of
child nodes in a given DAI link.

There is another requirement where multiple ASoC components need to
be connected together in a chained fashion in a component model. This
patch sets 'component_chaining' flag for such sound cards where FE<->BE
and multiple BE<->BE component connections is required. Hence support
for such sound cards is added under 'simple-cc-audio-card' compatible.
All DAI links under this are treated as DPCM links and links can have
empty Codec list since components are chainied via router controls.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 include/sound/simple_card.h     |  5 +++++
 sound/soc/generic/simple-card.c | 35 ++++++++++++++++++++++++++++-------
 2 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h
index d264e54..79019d0 100644
--- a/include/sound/simple_card.h
+++ b/include/sound/simple_card.h
@@ -23,4 +23,9 @@ struct asoc_simple_card_info {
 	struct asoc_simple_dai codec_dai;
 };
 
+struct asoc_simple_soc_data {
+	bool dpcm_selectable;
+	bool component_chaining;
+};
+
 #endif /* __SIMPLE_CARD_H */
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index f19030b..758c612 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -16,8 +16,6 @@
 #include <sound/soc-dai.h>
 #include <sound/soc.h>
 
-#define DPCM_SELECTABLE 1
-
 #define DAI	"sound-dai"
 #define CELL	"#sound-dai-cells"
 #define PREFIX	"simple-audio-card,"
@@ -386,10 +384,11 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 					 struct device_node *np,
 					 struct link_info *li, bool is_top))
 {
+	struct snd_soc_card *card = simple_priv_to_card(priv);
 	struct device *dev = simple_priv_to_dev(priv);
 	struct device_node *top = dev->of_node;
 	struct device_node *node;
-	uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
+	const struct asoc_simple_soc_data *data = of_device_get_match_data(dev);
 	bool is_top = 0;
 	int ret = 0;
 
@@ -411,10 +410,13 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 		/* get codec */
 		codec = of_get_child_by_name(node, is_top ?
 					     PREFIX "codec" : "codec");
-		if (!codec) {
+
+		/* Codec list can be empty for component<->component chain */
+		if (!codec && !card->component_chaining) {
 			ret = -ENODEV;
 			goto error;
 		}
+
 		/* get platform */
 		plat = of_get_child_by_name(node, is_top ?
 					    PREFIX "plat" : "plat");
@@ -432,9 +434,10 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 			 * It is DPCM
 			 * if it has many CPUs,
 			 * or has convert-xxx property
+			 * or if component_chaining is used
 			 */
-			if (dpcm_selectable &&
-			    (num > 2 ||
+			if (data && data->dpcm_selectable &&
+			    (num > 2 || data->component_chaining ||
 			     adata.convert_rate || adata.convert_channels))
 				ret = func_dpcm(priv, np, li, is_top);
 			/* else normal sound */
@@ -654,6 +657,7 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	struct asoc_simple_priv *priv;
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
+	const struct asoc_simple_soc_data *data;
 	struct snd_soc_card *card;
 	struct link_info li;
 	int ret;
@@ -668,6 +672,11 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	card->dev		= dev;
 	card->probe		= simple_soc_probe;
 
+	data = of_device_get_match_data(dev);
+
+	if (data)
+		card->component_chaining = data->component_chaining;
+
 	memset(&li, 0, sizeof(li));
 	simple_get_dais_count(priv, &li);
 	if (!li.link || !li.dais)
@@ -757,10 +766,22 @@ static int asoc_simple_remove(struct platform_device *pdev)
 	return asoc_simple_clean_reference(card);
 }
 
+static const struct asoc_simple_soc_data scu_card_data = {
+	.dpcm_selectable = true,
+};
+
+/* Component chaining with DPCM */
+static const struct asoc_simple_soc_data cc_card_data = {
+	.dpcm_selectable = true,
+	.component_chaining = true,
+};
+
 static const struct of_device_id simple_of_match[] = {
 	{ .compatible = "simple-audio-card", },
 	{ .compatible = "simple-scu-audio-card",
-	  .data = (void *)DPCM_SELECTABLE },
+	  .data = &scu_card_data },
+	{ .compatible = "simple-cc-audio-card",
+	  .data = &cc_card_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, simple_of_match);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 18/23] ASoC: simple-card: Add support for component chaining
@ 2020-06-27  4:53   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

The simple-card driver supports both normal and DPCM DAI links. The
sound cards requiring DPCM DAI link support use DPCM_SELECTABLE flag
and DAI links are treated as DPCM links depending on the number of
child nodes in a given DAI link.

There is another requirement where multiple ASoC components need to
be connected together in a chained fashion in a component model. This
patch sets 'component_chaining' flag for such sound cards where FE<->BE
and multiple BE<->BE component connections is required. Hence support
for such sound cards is added under 'simple-cc-audio-card' compatible.
All DAI links under this are treated as DPCM links and links can have
empty Codec list since components are chainied via router controls.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 include/sound/simple_card.h     |  5 +++++
 sound/soc/generic/simple-card.c | 35 ++++++++++++++++++++++++++++-------
 2 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h
index d264e54..79019d0 100644
--- a/include/sound/simple_card.h
+++ b/include/sound/simple_card.h
@@ -23,4 +23,9 @@ struct asoc_simple_card_info {
 	struct asoc_simple_dai codec_dai;
 };
 
+struct asoc_simple_soc_data {
+	bool dpcm_selectable;
+	bool component_chaining;
+};
+
 #endif /* __SIMPLE_CARD_H */
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index f19030b..758c612 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -16,8 +16,6 @@
 #include <sound/soc-dai.h>
 #include <sound/soc.h>
 
-#define DPCM_SELECTABLE 1
-
 #define DAI	"sound-dai"
 #define CELL	"#sound-dai-cells"
 #define PREFIX	"simple-audio-card,"
@@ -386,10 +384,11 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 					 struct device_node *np,
 					 struct link_info *li, bool is_top))
 {
+	struct snd_soc_card *card = simple_priv_to_card(priv);
 	struct device *dev = simple_priv_to_dev(priv);
 	struct device_node *top = dev->of_node;
 	struct device_node *node;
-	uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
+	const struct asoc_simple_soc_data *data = of_device_get_match_data(dev);
 	bool is_top = 0;
 	int ret = 0;
 
@@ -411,10 +410,13 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 		/* get codec */
 		codec = of_get_child_by_name(node, is_top ?
 					     PREFIX "codec" : "codec");
-		if (!codec) {
+
+		/* Codec list can be empty for component<->component chain */
+		if (!codec && !card->component_chaining) {
 			ret = -ENODEV;
 			goto error;
 		}
+
 		/* get platform */
 		plat = of_get_child_by_name(node, is_top ?
 					    PREFIX "plat" : "plat");
@@ -432,9 +434,10 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 			 * It is DPCM
 			 * if it has many CPUs,
 			 * or has convert-xxx property
+			 * or if component_chaining is used
 			 */
-			if (dpcm_selectable &&
-			    (num > 2 ||
+			if (data && data->dpcm_selectable &&
+			    (num > 2 || data->component_chaining ||
 			     adata.convert_rate || adata.convert_channels))
 				ret = func_dpcm(priv, np, li, is_top);
 			/* else normal sound */
@@ -654,6 +657,7 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	struct asoc_simple_priv *priv;
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
+	const struct asoc_simple_soc_data *data;
 	struct snd_soc_card *card;
 	struct link_info li;
 	int ret;
@@ -668,6 +672,11 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	card->dev		= dev;
 	card->probe		= simple_soc_probe;
 
+	data = of_device_get_match_data(dev);
+
+	if (data)
+		card->component_chaining = data->component_chaining;
+
 	memset(&li, 0, sizeof(li));
 	simple_get_dais_count(priv, &li);
 	if (!li.link || !li.dais)
@@ -757,10 +766,22 @@ static int asoc_simple_remove(struct platform_device *pdev)
 	return asoc_simple_clean_reference(card);
 }
 
+static const struct asoc_simple_soc_data scu_card_data = {
+	.dpcm_selectable = true,
+};
+
+/* Component chaining with DPCM */
+static const struct asoc_simple_soc_data cc_card_data = {
+	.dpcm_selectable = true,
+	.component_chaining = true,
+};
+
 static const struct of_device_id simple_of_match[] = {
 	{ .compatible = "simple-audio-card", },
 	{ .compatible = "simple-scu-audio-card",
-	  .data = (void *)DPCM_SELECTABLE },
+	  .data = &scu_card_data },
+	{ .compatible = "simple-cc-audio-card",
+	  .data = &cc_card_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, simple_of_match);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 18/23] ASoC: simple-card: Add support for component chaining
@ 2020-06-27  4:53   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

The simple-card driver supports both normal and DPCM DAI links. The
sound cards requiring DPCM DAI link support use DPCM_SELECTABLE flag
and DAI links are treated as DPCM links depending on the number of
child nodes in a given DAI link.

There is another requirement where multiple ASoC components need to
be connected together in a chained fashion in a component model. This
patch sets 'component_chaining' flag for such sound cards where FE<->BE
and multiple BE<->BE component connections is required. Hence support
for such sound cards is added under 'simple-cc-audio-card' compatible.
All DAI links under this are treated as DPCM links and links can have
empty Codec list since components are chainied via router controls.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 include/sound/simple_card.h     |  5 +++++
 sound/soc/generic/simple-card.c | 35 ++++++++++++++++++++++++++++-------
 2 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h
index d264e54..79019d0 100644
--- a/include/sound/simple_card.h
+++ b/include/sound/simple_card.h
@@ -23,4 +23,9 @@ struct asoc_simple_card_info {
 	struct asoc_simple_dai codec_dai;
 };
 
+struct asoc_simple_soc_data {
+	bool dpcm_selectable;
+	bool component_chaining;
+};
+
 #endif /* __SIMPLE_CARD_H */
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index f19030b..758c612 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -16,8 +16,6 @@
 #include <sound/soc-dai.h>
 #include <sound/soc.h>
 
-#define DPCM_SELECTABLE 1
-
 #define DAI	"sound-dai"
 #define CELL	"#sound-dai-cells"
 #define PREFIX	"simple-audio-card,"
@@ -386,10 +384,11 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 					 struct device_node *np,
 					 struct link_info *li, bool is_top))
 {
+	struct snd_soc_card *card = simple_priv_to_card(priv);
 	struct device *dev = simple_priv_to_dev(priv);
 	struct device_node *top = dev->of_node;
 	struct device_node *node;
-	uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
+	const struct asoc_simple_soc_data *data = of_device_get_match_data(dev);
 	bool is_top = 0;
 	int ret = 0;
 
@@ -411,10 +410,13 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 		/* get codec */
 		codec = of_get_child_by_name(node, is_top ?
 					     PREFIX "codec" : "codec");
-		if (!codec) {
+
+		/* Codec list can be empty for component<->component chain */
+		if (!codec && !card->component_chaining) {
 			ret = -ENODEV;
 			goto error;
 		}
+
 		/* get platform */
 		plat = of_get_child_by_name(node, is_top ?
 					    PREFIX "plat" : "plat");
@@ -432,9 +434,10 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 			 * It is DPCM
 			 * if it has many CPUs,
 			 * or has convert-xxx property
+			 * or if component_chaining is used
 			 */
-			if (dpcm_selectable &&
-			    (num > 2 ||
+			if (data && data->dpcm_selectable &&
+			    (num > 2 || data->component_chaining ||
 			     adata.convert_rate || adata.convert_channels))
 				ret = func_dpcm(priv, np, li, is_top);
 			/* else normal sound */
@@ -654,6 +657,7 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	struct asoc_simple_priv *priv;
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
+	const struct asoc_simple_soc_data *data;
 	struct snd_soc_card *card;
 	struct link_info li;
 	int ret;
@@ -668,6 +672,11 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	card->dev		= dev;
 	card->probe		= simple_soc_probe;
 
+	data = of_device_get_match_data(dev);
+
+	if (data)
+		card->component_chaining = data->component_chaining;
+
 	memset(&li, 0, sizeof(li));
 	simple_get_dais_count(priv, &li);
 	if (!li.link || !li.dais)
@@ -757,10 +766,22 @@ static int asoc_simple_remove(struct platform_device *pdev)
 	return asoc_simple_clean_reference(card);
 }
 
+static const struct asoc_simple_soc_data scu_card_data = {
+	.dpcm_selectable = true,
+};
+
+/* Component chaining with DPCM */
+static const struct asoc_simple_soc_data cc_card_data = {
+	.dpcm_selectable = true,
+	.component_chaining = true,
+};
+
 static const struct of_device_id simple_of_match[] = {
 	{ .compatible = "simple-audio-card", },
 	{ .compatible = "simple-scu-audio-card",
-	  .data = (void *)DPCM_SELECTABLE },
+	  .data = &scu_card_data },
+	{ .compatible = "simple-cc-audio-card",
+	  .data = &cc_card_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, simple_of_match);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 19/23] arm64: defconfig: Build AHUB component drivers
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

This patch enables following configs:
 +CONFIG_TEGRA_ACONNECT=m
 +CONFIG_SND_SOC_TEGRA=m
 +CONFIG_SND_SOC_TEGRA210_AHUB=m
 +CONFIG_SND_SOC_TEGRA210_DMIC=m
 +CONFIG_SND_SOC_TEGRA210_I2S=m
 +CONFIG_SND_SOC_TEGRA186_DSPK=m
 +CONFIG_SND_SOC_TEGRA210_ADMAIF=m

This patch helps to register AHUB and its clients (I2S, DMIC, DSPK, ADMAIF)
with ASoC core. Since AHUB is child of ACONNECT, config TEGRA_ACONNECT is
enabled as well.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm64/configs/defconfig | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index ae76fae..a8c0f77 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -218,6 +218,7 @@ CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
 CONFIG_HISILICON_LPC=y
 CONFIG_SIMPLE_PM_BUS=y
 CONFIG_FSL_MC_BUS=y
+CONFIG_TEGRA_ACONNECT=m
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
@@ -664,6 +665,12 @@ CONFIG_SND_SOC_RK3399_GRU_SOUND=m
 CONFIG_SND_SOC_SAMSUNG=y
 CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SUN4I_SPDIF=m
+CONFIG_SND_SOC_TEGRA=m
+CONFIG_SND_SOC_TEGRA210_AHUB=m
+CONFIG_SND_SOC_TEGRA210_DMIC=m
+CONFIG_SND_SOC_TEGRA210_I2S=m
+CONFIG_SND_SOC_TEGRA186_DSPK=m
+CONFIG_SND_SOC_TEGRA210_ADMAIF=m
 CONFIG_SND_SOC_AK4613=m
 CONFIG_SND_SOC_ES7134=m
 CONFIG_SND_SOC_ES7241=m
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 19/23] arm64: defconfig: Build AHUB component drivers
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

This patch enables following configs:
 +CONFIG_TEGRA_ACONNECT=m
 +CONFIG_SND_SOC_TEGRA=m
 +CONFIG_SND_SOC_TEGRA210_AHUB=m
 +CONFIG_SND_SOC_TEGRA210_DMIC=m
 +CONFIG_SND_SOC_TEGRA210_I2S=m
 +CONFIG_SND_SOC_TEGRA186_DSPK=m
 +CONFIG_SND_SOC_TEGRA210_ADMAIF=m

This patch helps to register AHUB and its clients (I2S, DMIC, DSPK, ADMAIF)
with ASoC core. Since AHUB is child of ACONNECT, config TEGRA_ACONNECT is
enabled as well.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/configs/defconfig | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index ae76fae..a8c0f77 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -218,6 +218,7 @@ CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
 CONFIG_HISILICON_LPC=y
 CONFIG_SIMPLE_PM_BUS=y
 CONFIG_FSL_MC_BUS=y
+CONFIG_TEGRA_ACONNECT=m
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
@@ -664,6 +665,12 @@ CONFIG_SND_SOC_RK3399_GRU_SOUND=m
 CONFIG_SND_SOC_SAMSUNG=y
 CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SUN4I_SPDIF=m
+CONFIG_SND_SOC_TEGRA=m
+CONFIG_SND_SOC_TEGRA210_AHUB=m
+CONFIG_SND_SOC_TEGRA210_DMIC=m
+CONFIG_SND_SOC_TEGRA210_I2S=m
+CONFIG_SND_SOC_TEGRA186_DSPK=m
+CONFIG_SND_SOC_TEGRA210_ADMAIF=m
 CONFIG_SND_SOC_AK4613=m
 CONFIG_SND_SOC_ES7134=m
 CONFIG_SND_SOC_ES7241=m
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 19/23] arm64: defconfig: Build AHUB component drivers
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

This patch enables following configs:
 +CONFIG_TEGRA_ACONNECT=m
 +CONFIG_SND_SOC_TEGRA=m
 +CONFIG_SND_SOC_TEGRA210_AHUB=m
 +CONFIG_SND_SOC_TEGRA210_DMIC=m
 +CONFIG_SND_SOC_TEGRA210_I2S=m
 +CONFIG_SND_SOC_TEGRA186_DSPK=m
 +CONFIG_SND_SOC_TEGRA210_ADMAIF=m

This patch helps to register AHUB and its clients (I2S, DMIC, DSPK, ADMAIF)
with ASoC core. Since AHUB is child of ACONNECT, config TEGRA_ACONNECT is
enabled as well.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/configs/defconfig | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index ae76fae..a8c0f77 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -218,6 +218,7 @@ CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
 CONFIG_HISILICON_LPC=y
 CONFIG_SIMPLE_PM_BUS=y
 CONFIG_FSL_MC_BUS=y
+CONFIG_TEGRA_ACONNECT=m
 CONFIG_MTD=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
@@ -664,6 +665,12 @@ CONFIG_SND_SOC_RK3399_GRU_SOUND=m
 CONFIG_SND_SOC_SAMSUNG=y
 CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SUN4I_SPDIF=m
+CONFIG_SND_SOC_TEGRA=m
+CONFIG_SND_SOC_TEGRA210_AHUB=m
+CONFIG_SND_SOC_TEGRA210_DMIC=m
+CONFIG_SND_SOC_TEGRA210_I2S=m
+CONFIG_SND_SOC_TEGRA186_DSPK=m
+CONFIG_SND_SOC_TEGRA210_ADMAIF=m
 CONFIG_SND_SOC_AK4613=m
 CONFIG_SND_SOC_ES7134=m
 CONFIG_SND_SOC_ES7241=m
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 20/23] arm64: defconfig: Enable CONFIG_TEGRA210_ADMA
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

This commit builds ADMA driver which can be used on Tegra210 and later
platforms to transfer audio data to/from AHUB (Audio Hub).

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index a8c0f77..599ed07 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -784,6 +784,7 @@ CONFIG_MV_XOR_V2=y
 CONFIG_OWL_DMA=y
 CONFIG_PL330_DMA=y
 CONFIG_TEGRA20_APB_DMA=y
+CONFIG_TEGRA210_ADMA=m
 CONFIG_QCOM_BAM_DMA=y
 CONFIG_QCOM_HIDMA_MGMT=y
 CONFIG_QCOM_HIDMA=y
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 20/23] arm64: defconfig: Enable CONFIG_TEGRA210_ADMA
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

This commit builds ADMA driver which can be used on Tegra210 and later
platforms to transfer audio data to/from AHUB (Audio Hub).

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index a8c0f77..599ed07 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -784,6 +784,7 @@ CONFIG_MV_XOR_V2=y
 CONFIG_OWL_DMA=y
 CONFIG_PL330_DMA=y
 CONFIG_TEGRA20_APB_DMA=y
+CONFIG_TEGRA210_ADMA=m
 CONFIG_QCOM_BAM_DMA=y
 CONFIG_QCOM_HIDMA_MGMT=y
 CONFIG_QCOM_HIDMA=y
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 20/23] arm64: defconfig: Enable CONFIG_TEGRA210_ADMA
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

This commit builds ADMA driver which can be used on Tegra210 and later
platforms to transfer audio data to/from AHUB (Audio Hub).

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index a8c0f77..599ed07 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -784,6 +784,7 @@ CONFIG_MV_XOR_V2=y
 CONFIG_OWL_DMA=y
 CONFIG_PL330_DMA=y
 CONFIG_TEGRA20_APB_DMA=y
+CONFIG_TEGRA210_ADMA=m
 CONFIG_QCOM_BAM_DMA=y
 CONFIG_QCOM_HIDMA_MGMT=y
 CONFIG_QCOM_HIDMA=y
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 21/23] arm64: tegra: Add DT binding for AHUB components
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

This patch adds few AHUB modules for Tegra210, Tegra186 and Tegra194.
Bindings for following modules are added.
 * AHUB added as a child node under ACONNECT
 * AHUB includes many HW accelerators and below components are added
   as its children.
   * ADMAIF
   * I2S
   * DMIC
   * DSPK (added for Tegra186 and Tegra194 only, since Tegra210 does
     not have this module)

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm64/boot/dts/nvidia/tegra186.dtsi | 231 ++++++++++++++++++++++++++++-
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 239 ++++++++++++++++++++++++++++++-
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 152 +++++++++++++++++++-
 3 files changed, 619 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 34d249d..01bae88 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -85,7 +85,7 @@
 		ranges = <0x02900000 0x0 0x02900000 0x200000>;
 		status = "disabled";
 
-		dma-controller@2930000 {
+		adma: dma-controller@2930000 {
 			compatible = "nvidia,tegra186-adma";
 			reg = <0x02930000 0x20000>;
 			interrupt-parent = <&agic>;
@@ -140,6 +140,235 @@
 			clock-names = "clk";
 			status = "disabled";
 		};
+
+		tegra_ahub: ahub@2900800 {
+			compatible = "nvidia,tegra186-ahub";
+			reg = <0x02900800 0x800>;
+			clocks = <&bpmp TEGRA186_CLK_AHUB>;
+			clock-names = "ahub";
+			assigned-clocks = <&bpmp TEGRA186_CLK_AHUB>;
+			assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x02900800 0x02900800 0x11800>;
+			#sound-dai-cells = <1>;
+			status = "disabled";
+
+			tegra_admaif: admaif@290f000 {
+				compatible = "nvidia,tegra186-admaif";
+				reg = <0x0290f000 0x1000>;
+				dmas = <&adma 1>, <&adma 1>,
+				       <&adma 2>, <&adma 2>,
+				       <&adma 3>, <&adma 3>,
+				       <&adma 4>, <&adma 4>,
+				       <&adma 5>, <&adma 5>,
+				       <&adma 6>, <&adma 6>,
+				       <&adma 7>, <&adma 7>,
+				       <&adma 8>, <&adma 8>,
+				       <&adma 9>, <&adma 9>,
+				       <&adma 10>, <&adma 10>,
+				       <&adma 11>, <&adma 11>,
+				       <&adma 12>, <&adma 12>,
+				       <&adma 13>, <&adma 13>,
+				       <&adma 14>, <&adma 14>,
+				       <&adma 15>, <&adma 15>,
+				       <&adma 16>, <&adma 16>,
+				       <&adma 17>, <&adma 17>,
+				       <&adma 18>, <&adma 18>,
+				       <&adma 19>, <&adma 19>,
+				       <&adma 20>, <&adma 20>;
+				dma-names = "rx1", "tx1",
+					    "rx2", "tx2",
+					    "rx3", "tx3",
+					    "rx4", "tx4",
+					    "rx5", "tx5",
+					    "rx6", "tx6",
+					    "rx7", "tx7",
+					    "rx8", "tx8",
+					    "rx9", "tx9",
+					    "rx10", "tx10",
+					    "rx11", "tx11",
+					    "rx12", "tx12",
+					    "rx13", "tx13",
+					    "rx14", "tx14",
+					    "rx15", "tx15",
+					    "rx16", "tx16",
+					    "rx17", "tx17",
+					    "rx18", "tx18",
+					    "rx19", "tx19",
+					    "rx20", "tx20";
+				#sound-dai-cells = <1>;
+				status = "disabled";
+			};
+
+			tegra_i2s1: i2s@2901000 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901000 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S1>,
+					 <&bpmp TEGRA186_CLK_I2S1_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S1>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S1";
+				status = "disabled";
+			};
+
+			tegra_i2s2: i2s@2901100 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901100 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S2>,
+					 <&bpmp TEGRA186_CLK_I2S2_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S2>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S2";
+				status = "disabled";
+			};
+
+			tegra_i2s3: i2s@2901200 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901200 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S3>,
+					 <&bpmp TEGRA186_CLK_I2S3_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S3>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S3";
+				status = "disabled";
+			};
+
+			tegra_i2s4: i2s@2901300 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901300 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S4>,
+					 <&bpmp TEGRA186_CLK_I2S4_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S4>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S4";
+				status = "disabled";
+			};
+
+			tegra_i2s5: i2s@2901400 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901400 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S5>,
+					 <&bpmp TEGRA186_CLK_I2S5_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S5>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S5";
+				status = "disabled";
+			};
+
+			tegra_i2s6: i2s@2901500 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901500 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S6>,
+					 <&bpmp TEGRA186_CLK_I2S6_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S6>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S6";
+				status = "disabled";
+			};
+
+			tegra_dmic1: dmic@2904000 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904000 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC1>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC1>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC1";
+				status = "disabled";
+			};
+
+			tegra_dmic2: dmic@2904100 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904100 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC2>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC2>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC2";
+				status = "disabled";
+			};
+
+			tegra_dmic3: dmic@2904200 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904200 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC3>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC3>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC3";
+				status = "disabled";
+			};
+
+			tegra_dmic4: dmic@2904300 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904300 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC4>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC4>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC4";
+				status = "disabled";
+			};
+
+			tegra_dspk1: dspk@2905000 {
+				compatible = "nvidia,tegra186-dspk";
+				reg = <0x2905000 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+				clock-names = "dspk";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <12288000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DSPK1";
+				status = "disabled";
+			};
+
+			tegra_dspk2: dspk@2905100 {
+				compatible = "nvidia,tegra186-dspk";
+				reg = <0x2905100 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DSPK2>;
+				clock-names = "dspk";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DSPK2>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <12288000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DSPK2";
+				status = "disabled";
+			};
+		};
 	};
 
 	mc: memory-controller@2c00000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index ea629da..7fa3873 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -83,7 +83,7 @@
 			ranges = <0x02900000 0x02900000 0x200000>;
 			status = "disabled";
 
-			dma-controller@2930000 {
+			adma: dma-controller@2930000 {
 				compatible = "nvidia,tegra194-adma",
 					     "nvidia,tegra186-adma";
 				reg = <0x02930000 0x20000>;
@@ -140,6 +140,243 @@
 				clock-names = "clk";
 				status = "disabled";
 			};
+
+			tegra_ahub: ahub@2900800 {
+				compatible = "nvidia,tegra194-ahub",
+					     "nvidia,tegra186-ahub";
+				reg = <0x02900800 0x800>;
+				clocks = <&bpmp TEGRA194_CLK_AHUB>;
+				clock-names = "ahub";
+				assigned-clocks = <&bpmp TEGRA194_CLK_AHUB>;
+				assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0x02900800 0x02900800 0x11800>;
+				#sound-dai-cells = <1>;
+				status = "disabled";
+
+				tegra_admaif: admaif@290f000 {
+					compatible = "nvidia,tegra194-admaif",
+						     "nvidia,tegra186-admaif";
+					reg = <0x0290f000 0x1000>;
+					dmas = <&adma 1>, <&adma 1>,
+					       <&adma 2>, <&adma 2>,
+					       <&adma 3>, <&adma 3>,
+					       <&adma 4>, <&adma 4>,
+					       <&adma 5>, <&adma 5>,
+					       <&adma 6>, <&adma 6>,
+					       <&adma 7>, <&adma 7>,
+					       <&adma 8>, <&adma 8>,
+					       <&adma 9>, <&adma 9>,
+					       <&adma 10>, <&adma 10>,
+					       <&adma 11>, <&adma 11>,
+					       <&adma 12>, <&adma 12>,
+					       <&adma 13>, <&adma 13>,
+					       <&adma 14>, <&adma 14>,
+					       <&adma 15>, <&adma 15>,
+					       <&adma 16>, <&adma 16>,
+					       <&adma 17>, <&adma 17>,
+					       <&adma 18>, <&adma 18>,
+					       <&adma 19>, <&adma 19>,
+					       <&adma 20>, <&adma 20>;
+					dma-names = "rx1", "tx1",
+						    "rx2", "tx2",
+						    "rx3", "tx3",
+						    "rx4", "tx4",
+						    "rx5", "tx5",
+						    "rx6", "tx6",
+						    "rx7", "tx7",
+						    "rx8", "tx8",
+						    "rx9", "tx9",
+						    "rx10", "tx10",
+						    "rx11", "tx11",
+						    "rx12", "tx12",
+						    "rx13", "tx13",
+						    "rx14", "tx14",
+						    "rx15", "tx15",
+						    "rx16", "tx16",
+						    "rx17", "tx17",
+						    "rx18", "tx18",
+						    "rx19", "tx19",
+						    "rx20", "tx20";
+					#sound-dai-cells = <1>;
+					status = "disabled";
+				};
+
+				tegra_i2s1: i2s@2901000 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901000 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S1>,
+						 <&bpmp TEGRA194_CLK_I2S1_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S1>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S1";
+					status = "disabled";
+				};
+
+				tegra_i2s2: i2s@2901100 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901100 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S2>,
+						 <&bpmp TEGRA194_CLK_I2S2_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S2>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S2";
+					status = "disabled";
+				};
+
+				tegra_i2s3: i2s@2901200 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901200 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S3>,
+						 <&bpmp TEGRA194_CLK_I2S3_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S3>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S3";
+					status = "disabled";
+				};
+
+				tegra_i2s4: i2s@2901300 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901300 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S4>,
+						 <&bpmp TEGRA194_CLK_I2S4_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S4>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S4";
+					status = "disabled";
+				};
+
+				tegra_i2s5: i2s@2901400 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901400 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S5>,
+						 <&bpmp TEGRA194_CLK_I2S5_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S5>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S5";
+					status = "disabled";
+				};
+
+				tegra_i2s6: i2s@2901500 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901500 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S6>,
+						 <&bpmp TEGRA194_CLK_I2S6_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S6>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S6";
+					status = "disabled";
+				};
+
+				tegra_dmic1: dmic@2904000 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904000 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC1>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC1>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC1";
+					status = "disabled";
+				};
+
+				tegra_dmic2: dmic@2904100 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904100 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC2>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC2>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC2";
+					status = "disabled";
+				};
+
+				tegra_dmic3: dmic@2904200 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904200 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC3>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC3>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC3";
+					status = "disabled";
+				};
+
+				tegra_dmic4: dmic@2904300 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904300 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC4>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC4>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC4";
+					status = "disabled";
+				};
+
+				tegra_dspk1: dspk@2905000 {
+					compatible = "nvidia,tegra194-dspk",
+						     "nvidia,tegra186-dspk";
+					reg = <0x2905000 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DSPK1>;
+					clock-names = "dspk";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DSPK1>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <12288000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DSPK1";
+					status = "disabled";
+				};
+
+				tegra_dspk2: dspk@2905100 {
+					compatible = "nvidia,tegra194-dspk",
+						     "nvidia,tegra186-dspk";
+					reg = <0x2905100 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DSPK2>;
+					clock-names = "dspk";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DSPK2>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <12288000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DSPK2";
+					status = "disabled";
+				};
+			};
 		};
 
 		pinmux: pinmux@2430000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index f4e0cc2..73ae58f 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1323,7 +1323,7 @@
 		ranges = <0x702c0000 0x0 0x702c0000 0x00040000>;
 		status = "disabled";
 
-		adma: dma@702e2000 {
+		adma: dma-controller@702e2000 {
 			compatible = "nvidia,tegra210-adma";
 			reg = <0x702e2000 0x2000>;
 			interrupt-parent = <&agic>;
@@ -1366,6 +1366,156 @@
 			clock-names = "clk";
 			status = "disabled";
 		};
+
+		tegra_ahub: ahub@702d0800 {
+			compatible = "nvidia,tegra210-ahub";
+			reg = <0x702d0800 0x800>;
+			clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+			clock-names = "ahub";
+			assigned-clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+			assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x702d0000 0x702d0000 0x0000e400>;
+			#sound-dai-cells = <1>;
+			status = "disabled";
+
+			tegra_admaif: admaif@702d0000 {
+				compatible = "nvidia,tegra210-admaif";
+				reg = <0x702d0000 0x800>;
+				dmas = <&adma 1>,  <&adma 1>,
+				       <&adma 2>,  <&adma 2>,
+				       <&adma 3>,  <&adma 3>,
+				       <&adma 4>,  <&adma 4>,
+				       <&adma 5>,  <&adma 5>,
+				       <&adma 6>,  <&adma 6>,
+				       <&adma 7>,  <&adma 7>,
+				       <&adma 8>,  <&adma 8>,
+				       <&adma 9>,  <&adma 9>,
+				       <&adma 10>, <&adma 10>;
+				dma-names = "rx1",  "tx1",
+					    "rx2",  "tx2",
+					    "rx3",  "tx3",
+					    "rx4",  "tx4",
+					    "rx5",  "tx5",
+					    "rx6",  "tx6",
+					    "rx7",  "tx7",
+					    "rx8",  "tx8",
+					    "rx9",  "tx9",
+					    "rx10", "tx10";
+				#sound-dai-cells = <1>;
+				status = "disabled";
+			};
+
+			tegra_i2s1: i2s@702d1000 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1000 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S0>,
+					 <&tegra_car TEGRA210_CLK_I2S0_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S1";
+				status = "disabled";
+			};
+
+			tegra_i2s2: i2s@702d1100 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1100 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S1>,
+					 <&tegra_car TEGRA210_CLK_I2S1_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S1>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S2";
+				status = "disabled";
+			};
+
+			tegra_i2s3: i2s@702d1200 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1200 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S2>,
+					 <&tegra_car TEGRA210_CLK_I2S2_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S2>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S3";
+				status = "disabled";
+			};
+
+			tegra_i2s4: i2s@702d1300 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1300 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S3>,
+					 <&tegra_car TEGRA210_CLK_I2S3_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S3>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S4";
+				status = "disabled";
+			};
+
+			tegra_i2s5: i2s@702d1400 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1400 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S4>,
+					 <&tegra_car TEGRA210_CLK_I2S4_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S4>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S5";
+				status = "disabled";
+			};
+
+			tegra_dmic1: dmic@702d4000 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x702d4000 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+				clock-names = "dmic";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC1";
+				status = "disabled";
+			};
+
+			tegra_dmic2: dmic@702d4100 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x702d4100 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_DMIC2>;
+				clock-names = "dmic";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC2>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC2";
+				status = "disabled";
+			};
+
+			tegra_dmic3: dmic@702d4200 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x702d4200 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_DMIC3>;
+				clock-names = "dmic";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC3>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC3";
+				status = "disabled";
+			};
+		};
 	};
 
 	spi@70410000 {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 21/23] arm64: tegra: Add DT binding for AHUB components
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

This patch adds few AHUB modules for Tegra210, Tegra186 and Tegra194.
Bindings for following modules are added.
 * AHUB added as a child node under ACONNECT
 * AHUB includes many HW accelerators and below components are added
   as its children.
   * ADMAIF
   * I2S
   * DMIC
   * DSPK (added for Tegra186 and Tegra194 only, since Tegra210 does
     not have this module)

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186.dtsi | 231 ++++++++++++++++++++++++++++-
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 239 ++++++++++++++++++++++++++++++-
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 152 +++++++++++++++++++-
 3 files changed, 619 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 34d249d..01bae88 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -85,7 +85,7 @@
 		ranges = <0x02900000 0x0 0x02900000 0x200000>;
 		status = "disabled";
 
-		dma-controller@2930000 {
+		adma: dma-controller@2930000 {
 			compatible = "nvidia,tegra186-adma";
 			reg = <0x02930000 0x20000>;
 			interrupt-parent = <&agic>;
@@ -140,6 +140,235 @@
 			clock-names = "clk";
 			status = "disabled";
 		};
+
+		tegra_ahub: ahub@2900800 {
+			compatible = "nvidia,tegra186-ahub";
+			reg = <0x02900800 0x800>;
+			clocks = <&bpmp TEGRA186_CLK_AHUB>;
+			clock-names = "ahub";
+			assigned-clocks = <&bpmp TEGRA186_CLK_AHUB>;
+			assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x02900800 0x02900800 0x11800>;
+			#sound-dai-cells = <1>;
+			status = "disabled";
+
+			tegra_admaif: admaif@290f000 {
+				compatible = "nvidia,tegra186-admaif";
+				reg = <0x0290f000 0x1000>;
+				dmas = <&adma 1>, <&adma 1>,
+				       <&adma 2>, <&adma 2>,
+				       <&adma 3>, <&adma 3>,
+				       <&adma 4>, <&adma 4>,
+				       <&adma 5>, <&adma 5>,
+				       <&adma 6>, <&adma 6>,
+				       <&adma 7>, <&adma 7>,
+				       <&adma 8>, <&adma 8>,
+				       <&adma 9>, <&adma 9>,
+				       <&adma 10>, <&adma 10>,
+				       <&adma 11>, <&adma 11>,
+				       <&adma 12>, <&adma 12>,
+				       <&adma 13>, <&adma 13>,
+				       <&adma 14>, <&adma 14>,
+				       <&adma 15>, <&adma 15>,
+				       <&adma 16>, <&adma 16>,
+				       <&adma 17>, <&adma 17>,
+				       <&adma 18>, <&adma 18>,
+				       <&adma 19>, <&adma 19>,
+				       <&adma 20>, <&adma 20>;
+				dma-names = "rx1", "tx1",
+					    "rx2", "tx2",
+					    "rx3", "tx3",
+					    "rx4", "tx4",
+					    "rx5", "tx5",
+					    "rx6", "tx6",
+					    "rx7", "tx7",
+					    "rx8", "tx8",
+					    "rx9", "tx9",
+					    "rx10", "tx10",
+					    "rx11", "tx11",
+					    "rx12", "tx12",
+					    "rx13", "tx13",
+					    "rx14", "tx14",
+					    "rx15", "tx15",
+					    "rx16", "tx16",
+					    "rx17", "tx17",
+					    "rx18", "tx18",
+					    "rx19", "tx19",
+					    "rx20", "tx20";
+				#sound-dai-cells = <1>;
+				status = "disabled";
+			};
+
+			tegra_i2s1: i2s@2901000 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901000 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S1>,
+					 <&bpmp TEGRA186_CLK_I2S1_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S1>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S1";
+				status = "disabled";
+			};
+
+			tegra_i2s2: i2s@2901100 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901100 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S2>,
+					 <&bpmp TEGRA186_CLK_I2S2_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S2>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S2";
+				status = "disabled";
+			};
+
+			tegra_i2s3: i2s@2901200 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901200 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S3>,
+					 <&bpmp TEGRA186_CLK_I2S3_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S3>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S3";
+				status = "disabled";
+			};
+
+			tegra_i2s4: i2s@2901300 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901300 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S4>,
+					 <&bpmp TEGRA186_CLK_I2S4_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S4>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S4";
+				status = "disabled";
+			};
+
+			tegra_i2s5: i2s@2901400 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901400 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S5>,
+					 <&bpmp TEGRA186_CLK_I2S5_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S5>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S5";
+				status = "disabled";
+			};
+
+			tegra_i2s6: i2s@2901500 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901500 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S6>,
+					 <&bpmp TEGRA186_CLK_I2S6_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S6>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S6";
+				status = "disabled";
+			};
+
+			tegra_dmic1: dmic@2904000 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904000 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC1>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC1>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC1";
+				status = "disabled";
+			};
+
+			tegra_dmic2: dmic@2904100 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904100 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC2>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC2>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC2";
+				status = "disabled";
+			};
+
+			tegra_dmic3: dmic@2904200 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904200 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC3>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC3>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC3";
+				status = "disabled";
+			};
+
+			tegra_dmic4: dmic@2904300 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904300 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC4>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC4>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC4";
+				status = "disabled";
+			};
+
+			tegra_dspk1: dspk@2905000 {
+				compatible = "nvidia,tegra186-dspk";
+				reg = <0x2905000 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+				clock-names = "dspk";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <12288000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DSPK1";
+				status = "disabled";
+			};
+
+			tegra_dspk2: dspk@2905100 {
+				compatible = "nvidia,tegra186-dspk";
+				reg = <0x2905100 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DSPK2>;
+				clock-names = "dspk";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DSPK2>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <12288000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DSPK2";
+				status = "disabled";
+			};
+		};
 	};
 
 	mc: memory-controller@2c00000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index ea629da..7fa3873 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -83,7 +83,7 @@
 			ranges = <0x02900000 0x02900000 0x200000>;
 			status = "disabled";
 
-			dma-controller@2930000 {
+			adma: dma-controller@2930000 {
 				compatible = "nvidia,tegra194-adma",
 					     "nvidia,tegra186-adma";
 				reg = <0x02930000 0x20000>;
@@ -140,6 +140,243 @@
 				clock-names = "clk";
 				status = "disabled";
 			};
+
+			tegra_ahub: ahub@2900800 {
+				compatible = "nvidia,tegra194-ahub",
+					     "nvidia,tegra186-ahub";
+				reg = <0x02900800 0x800>;
+				clocks = <&bpmp TEGRA194_CLK_AHUB>;
+				clock-names = "ahub";
+				assigned-clocks = <&bpmp TEGRA194_CLK_AHUB>;
+				assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0x02900800 0x02900800 0x11800>;
+				#sound-dai-cells = <1>;
+				status = "disabled";
+
+				tegra_admaif: admaif@290f000 {
+					compatible = "nvidia,tegra194-admaif",
+						     "nvidia,tegra186-admaif";
+					reg = <0x0290f000 0x1000>;
+					dmas = <&adma 1>, <&adma 1>,
+					       <&adma 2>, <&adma 2>,
+					       <&adma 3>, <&adma 3>,
+					       <&adma 4>, <&adma 4>,
+					       <&adma 5>, <&adma 5>,
+					       <&adma 6>, <&adma 6>,
+					       <&adma 7>, <&adma 7>,
+					       <&adma 8>, <&adma 8>,
+					       <&adma 9>, <&adma 9>,
+					       <&adma 10>, <&adma 10>,
+					       <&adma 11>, <&adma 11>,
+					       <&adma 12>, <&adma 12>,
+					       <&adma 13>, <&adma 13>,
+					       <&adma 14>, <&adma 14>,
+					       <&adma 15>, <&adma 15>,
+					       <&adma 16>, <&adma 16>,
+					       <&adma 17>, <&adma 17>,
+					       <&adma 18>, <&adma 18>,
+					       <&adma 19>, <&adma 19>,
+					       <&adma 20>, <&adma 20>;
+					dma-names = "rx1", "tx1",
+						    "rx2", "tx2",
+						    "rx3", "tx3",
+						    "rx4", "tx4",
+						    "rx5", "tx5",
+						    "rx6", "tx6",
+						    "rx7", "tx7",
+						    "rx8", "tx8",
+						    "rx9", "tx9",
+						    "rx10", "tx10",
+						    "rx11", "tx11",
+						    "rx12", "tx12",
+						    "rx13", "tx13",
+						    "rx14", "tx14",
+						    "rx15", "tx15",
+						    "rx16", "tx16",
+						    "rx17", "tx17",
+						    "rx18", "tx18",
+						    "rx19", "tx19",
+						    "rx20", "tx20";
+					#sound-dai-cells = <1>;
+					status = "disabled";
+				};
+
+				tegra_i2s1: i2s@2901000 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901000 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S1>,
+						 <&bpmp TEGRA194_CLK_I2S1_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S1>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S1";
+					status = "disabled";
+				};
+
+				tegra_i2s2: i2s@2901100 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901100 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S2>,
+						 <&bpmp TEGRA194_CLK_I2S2_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S2>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S2";
+					status = "disabled";
+				};
+
+				tegra_i2s3: i2s@2901200 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901200 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S3>,
+						 <&bpmp TEGRA194_CLK_I2S3_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S3>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S3";
+					status = "disabled";
+				};
+
+				tegra_i2s4: i2s@2901300 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901300 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S4>,
+						 <&bpmp TEGRA194_CLK_I2S4_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S4>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S4";
+					status = "disabled";
+				};
+
+				tegra_i2s5: i2s@2901400 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901400 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S5>,
+						 <&bpmp TEGRA194_CLK_I2S5_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S5>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S5";
+					status = "disabled";
+				};
+
+				tegra_i2s6: i2s@2901500 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901500 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S6>,
+						 <&bpmp TEGRA194_CLK_I2S6_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S6>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S6";
+					status = "disabled";
+				};
+
+				tegra_dmic1: dmic@2904000 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904000 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC1>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC1>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC1";
+					status = "disabled";
+				};
+
+				tegra_dmic2: dmic@2904100 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904100 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC2>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC2>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC2";
+					status = "disabled";
+				};
+
+				tegra_dmic3: dmic@2904200 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904200 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC3>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC3>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC3";
+					status = "disabled";
+				};
+
+				tegra_dmic4: dmic@2904300 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904300 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC4>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC4>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC4";
+					status = "disabled";
+				};
+
+				tegra_dspk1: dspk@2905000 {
+					compatible = "nvidia,tegra194-dspk",
+						     "nvidia,tegra186-dspk";
+					reg = <0x2905000 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DSPK1>;
+					clock-names = "dspk";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DSPK1>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <12288000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DSPK1";
+					status = "disabled";
+				};
+
+				tegra_dspk2: dspk@2905100 {
+					compatible = "nvidia,tegra194-dspk",
+						     "nvidia,tegra186-dspk";
+					reg = <0x2905100 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DSPK2>;
+					clock-names = "dspk";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DSPK2>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <12288000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DSPK2";
+					status = "disabled";
+				};
+			};
 		};
 
 		pinmux: pinmux@2430000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index f4e0cc2..73ae58f 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1323,7 +1323,7 @@
 		ranges = <0x702c0000 0x0 0x702c0000 0x00040000>;
 		status = "disabled";
 
-		adma: dma@702e2000 {
+		adma: dma-controller@702e2000 {
 			compatible = "nvidia,tegra210-adma";
 			reg = <0x702e2000 0x2000>;
 			interrupt-parent = <&agic>;
@@ -1366,6 +1366,156 @@
 			clock-names = "clk";
 			status = "disabled";
 		};
+
+		tegra_ahub: ahub@702d0800 {
+			compatible = "nvidia,tegra210-ahub";
+			reg = <0x702d0800 0x800>;
+			clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+			clock-names = "ahub";
+			assigned-clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+			assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x702d0000 0x702d0000 0x0000e400>;
+			#sound-dai-cells = <1>;
+			status = "disabled";
+
+			tegra_admaif: admaif@702d0000 {
+				compatible = "nvidia,tegra210-admaif";
+				reg = <0x702d0000 0x800>;
+				dmas = <&adma 1>,  <&adma 1>,
+				       <&adma 2>,  <&adma 2>,
+				       <&adma 3>,  <&adma 3>,
+				       <&adma 4>,  <&adma 4>,
+				       <&adma 5>,  <&adma 5>,
+				       <&adma 6>,  <&adma 6>,
+				       <&adma 7>,  <&adma 7>,
+				       <&adma 8>,  <&adma 8>,
+				       <&adma 9>,  <&adma 9>,
+				       <&adma 10>, <&adma 10>;
+				dma-names = "rx1",  "tx1",
+					    "rx2",  "tx2",
+					    "rx3",  "tx3",
+					    "rx4",  "tx4",
+					    "rx5",  "tx5",
+					    "rx6",  "tx6",
+					    "rx7",  "tx7",
+					    "rx8",  "tx8",
+					    "rx9",  "tx9",
+					    "rx10", "tx10";
+				#sound-dai-cells = <1>;
+				status = "disabled";
+			};
+
+			tegra_i2s1: i2s@702d1000 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1000 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S0>,
+					 <&tegra_car TEGRA210_CLK_I2S0_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S1";
+				status = "disabled";
+			};
+
+			tegra_i2s2: i2s@702d1100 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1100 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S1>,
+					 <&tegra_car TEGRA210_CLK_I2S1_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S1>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S2";
+				status = "disabled";
+			};
+
+			tegra_i2s3: i2s@702d1200 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1200 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S2>,
+					 <&tegra_car TEGRA210_CLK_I2S2_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S2>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S3";
+				status = "disabled";
+			};
+
+			tegra_i2s4: i2s@702d1300 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1300 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S3>,
+					 <&tegra_car TEGRA210_CLK_I2S3_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S3>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S4";
+				status = "disabled";
+			};
+
+			tegra_i2s5: i2s@702d1400 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1400 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S4>,
+					 <&tegra_car TEGRA210_CLK_I2S4_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S4>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S5";
+				status = "disabled";
+			};
+
+			tegra_dmic1: dmic@702d4000 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x702d4000 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+				clock-names = "dmic";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC1";
+				status = "disabled";
+			};
+
+			tegra_dmic2: dmic@702d4100 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x702d4100 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_DMIC2>;
+				clock-names = "dmic";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC2>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC2";
+				status = "disabled";
+			};
+
+			tegra_dmic3: dmic@702d4200 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x702d4200 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_DMIC3>;
+				clock-names = "dmic";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC3>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC3";
+				status = "disabled";
+			};
+		};
 	};
 
 	spi@70410000 {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 21/23] arm64: tegra: Add DT binding for AHUB components
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

This patch adds few AHUB modules for Tegra210, Tegra186 and Tegra194.
Bindings for following modules are added.
 * AHUB added as a child node under ACONNECT
 * AHUB includes many HW accelerators and below components are added
   as its children.
   * ADMAIF
   * I2S
   * DMIC
   * DSPK (added for Tegra186 and Tegra194 only, since Tegra210 does
     not have this module)

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186.dtsi | 231 ++++++++++++++++++++++++++++-
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 239 ++++++++++++++++++++++++++++++-
 arch/arm64/boot/dts/nvidia/tegra210.dtsi | 152 +++++++++++++++++++-
 3 files changed, 619 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 34d249d..01bae88 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -85,7 +85,7 @@
 		ranges = <0x02900000 0x0 0x02900000 0x200000>;
 		status = "disabled";
 
-		dma-controller@2930000 {
+		adma: dma-controller@2930000 {
 			compatible = "nvidia,tegra186-adma";
 			reg = <0x02930000 0x20000>;
 			interrupt-parent = <&agic>;
@@ -140,6 +140,235 @@
 			clock-names = "clk";
 			status = "disabled";
 		};
+
+		tegra_ahub: ahub@2900800 {
+			compatible = "nvidia,tegra186-ahub";
+			reg = <0x02900800 0x800>;
+			clocks = <&bpmp TEGRA186_CLK_AHUB>;
+			clock-names = "ahub";
+			assigned-clocks = <&bpmp TEGRA186_CLK_AHUB>;
+			assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x02900800 0x02900800 0x11800>;
+			#sound-dai-cells = <1>;
+			status = "disabled";
+
+			tegra_admaif: admaif@290f000 {
+				compatible = "nvidia,tegra186-admaif";
+				reg = <0x0290f000 0x1000>;
+				dmas = <&adma 1>, <&adma 1>,
+				       <&adma 2>, <&adma 2>,
+				       <&adma 3>, <&adma 3>,
+				       <&adma 4>, <&adma 4>,
+				       <&adma 5>, <&adma 5>,
+				       <&adma 6>, <&adma 6>,
+				       <&adma 7>, <&adma 7>,
+				       <&adma 8>, <&adma 8>,
+				       <&adma 9>, <&adma 9>,
+				       <&adma 10>, <&adma 10>,
+				       <&adma 11>, <&adma 11>,
+				       <&adma 12>, <&adma 12>,
+				       <&adma 13>, <&adma 13>,
+				       <&adma 14>, <&adma 14>,
+				       <&adma 15>, <&adma 15>,
+				       <&adma 16>, <&adma 16>,
+				       <&adma 17>, <&adma 17>,
+				       <&adma 18>, <&adma 18>,
+				       <&adma 19>, <&adma 19>,
+				       <&adma 20>, <&adma 20>;
+				dma-names = "rx1", "tx1",
+					    "rx2", "tx2",
+					    "rx3", "tx3",
+					    "rx4", "tx4",
+					    "rx5", "tx5",
+					    "rx6", "tx6",
+					    "rx7", "tx7",
+					    "rx8", "tx8",
+					    "rx9", "tx9",
+					    "rx10", "tx10",
+					    "rx11", "tx11",
+					    "rx12", "tx12",
+					    "rx13", "tx13",
+					    "rx14", "tx14",
+					    "rx15", "tx15",
+					    "rx16", "tx16",
+					    "rx17", "tx17",
+					    "rx18", "tx18",
+					    "rx19", "tx19",
+					    "rx20", "tx20";
+				#sound-dai-cells = <1>;
+				status = "disabled";
+			};
+
+			tegra_i2s1: i2s@2901000 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901000 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S1>,
+					 <&bpmp TEGRA186_CLK_I2S1_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S1>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S1";
+				status = "disabled";
+			};
+
+			tegra_i2s2: i2s@2901100 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901100 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S2>,
+					 <&bpmp TEGRA186_CLK_I2S2_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S2>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S2";
+				status = "disabled";
+			};
+
+			tegra_i2s3: i2s@2901200 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901200 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S3>,
+					 <&bpmp TEGRA186_CLK_I2S3_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S3>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S3";
+				status = "disabled";
+			};
+
+			tegra_i2s4: i2s@2901300 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901300 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S4>,
+					 <&bpmp TEGRA186_CLK_I2S4_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S4>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S4";
+				status = "disabled";
+			};
+
+			tegra_i2s5: i2s@2901400 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901400 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S5>,
+					 <&bpmp TEGRA186_CLK_I2S5_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S5>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S5";
+				status = "disabled";
+			};
+
+			tegra_i2s6: i2s@2901500 {
+				compatible = "nvidia,tegra186-i2s",
+					     "nvidia,tegra210-i2s";
+				reg = <0x2901500 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_I2S6>,
+					 <&bpmp TEGRA186_CLK_I2S6_SYNC_INPUT>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&bpmp TEGRA186_CLK_I2S6>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S6";
+				status = "disabled";
+			};
+
+			tegra_dmic1: dmic@2904000 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904000 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC1>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC1>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC1";
+				status = "disabled";
+			};
+
+			tegra_dmic2: dmic@2904100 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904100 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC2>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC2>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC2";
+				status = "disabled";
+			};
+
+			tegra_dmic3: dmic@2904200 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904200 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC3>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC3>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC3";
+				status = "disabled";
+			};
+
+			tegra_dmic4: dmic@2904300 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x2904300 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DMIC4>;
+				clock-names = "dmic";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DMIC4>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC4";
+				status = "disabled";
+			};
+
+			tegra_dspk1: dspk@2905000 {
+				compatible = "nvidia,tegra186-dspk";
+				reg = <0x2905000 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+				clock-names = "dspk";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DSPK1>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <12288000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DSPK1";
+				status = "disabled";
+			};
+
+			tegra_dspk2: dspk@2905100 {
+				compatible = "nvidia,tegra186-dspk";
+				reg = <0x2905100 0x100>;
+				clocks = <&bpmp TEGRA186_CLK_DSPK2>;
+				clock-names = "dspk";
+				assigned-clocks = <&bpmp TEGRA186_CLK_DSPK2>;
+				assigned-clock-parents = <&bpmp TEGRA186_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <12288000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DSPK2";
+				status = "disabled";
+			};
+		};
 	};
 
 	mc: memory-controller@2c00000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index ea629da..7fa3873 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -83,7 +83,7 @@
 			ranges = <0x02900000 0x02900000 0x200000>;
 			status = "disabled";
 
-			dma-controller@2930000 {
+			adma: dma-controller@2930000 {
 				compatible = "nvidia,tegra194-adma",
 					     "nvidia,tegra186-adma";
 				reg = <0x02930000 0x20000>;
@@ -140,6 +140,243 @@
 				clock-names = "clk";
 				status = "disabled";
 			};
+
+			tegra_ahub: ahub@2900800 {
+				compatible = "nvidia,tegra194-ahub",
+					     "nvidia,tegra186-ahub";
+				reg = <0x02900800 0x800>;
+				clocks = <&bpmp TEGRA194_CLK_AHUB>;
+				clock-names = "ahub";
+				assigned-clocks = <&bpmp TEGRA194_CLK_AHUB>;
+				assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0x02900800 0x02900800 0x11800>;
+				#sound-dai-cells = <1>;
+				status = "disabled";
+
+				tegra_admaif: admaif@290f000 {
+					compatible = "nvidia,tegra194-admaif",
+						     "nvidia,tegra186-admaif";
+					reg = <0x0290f000 0x1000>;
+					dmas = <&adma 1>, <&adma 1>,
+					       <&adma 2>, <&adma 2>,
+					       <&adma 3>, <&adma 3>,
+					       <&adma 4>, <&adma 4>,
+					       <&adma 5>, <&adma 5>,
+					       <&adma 6>, <&adma 6>,
+					       <&adma 7>, <&adma 7>,
+					       <&adma 8>, <&adma 8>,
+					       <&adma 9>, <&adma 9>,
+					       <&adma 10>, <&adma 10>,
+					       <&adma 11>, <&adma 11>,
+					       <&adma 12>, <&adma 12>,
+					       <&adma 13>, <&adma 13>,
+					       <&adma 14>, <&adma 14>,
+					       <&adma 15>, <&adma 15>,
+					       <&adma 16>, <&adma 16>,
+					       <&adma 17>, <&adma 17>,
+					       <&adma 18>, <&adma 18>,
+					       <&adma 19>, <&adma 19>,
+					       <&adma 20>, <&adma 20>;
+					dma-names = "rx1", "tx1",
+						    "rx2", "tx2",
+						    "rx3", "tx3",
+						    "rx4", "tx4",
+						    "rx5", "tx5",
+						    "rx6", "tx6",
+						    "rx7", "tx7",
+						    "rx8", "tx8",
+						    "rx9", "tx9",
+						    "rx10", "tx10",
+						    "rx11", "tx11",
+						    "rx12", "tx12",
+						    "rx13", "tx13",
+						    "rx14", "tx14",
+						    "rx15", "tx15",
+						    "rx16", "tx16",
+						    "rx17", "tx17",
+						    "rx18", "tx18",
+						    "rx19", "tx19",
+						    "rx20", "tx20";
+					#sound-dai-cells = <1>;
+					status = "disabled";
+				};
+
+				tegra_i2s1: i2s@2901000 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901000 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S1>,
+						 <&bpmp TEGRA194_CLK_I2S1_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S1>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S1";
+					status = "disabled";
+				};
+
+				tegra_i2s2: i2s@2901100 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901100 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S2>,
+						 <&bpmp TEGRA194_CLK_I2S2_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S2>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S2";
+					status = "disabled";
+				};
+
+				tegra_i2s3: i2s@2901200 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901200 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S3>,
+						 <&bpmp TEGRA194_CLK_I2S3_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S3>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S3";
+					status = "disabled";
+				};
+
+				tegra_i2s4: i2s@2901300 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901300 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S4>,
+						 <&bpmp TEGRA194_CLK_I2S4_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S4>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S4";
+					status = "disabled";
+				};
+
+				tegra_i2s5: i2s@2901400 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901400 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S5>,
+						 <&bpmp TEGRA194_CLK_I2S5_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S5>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S5";
+					status = "disabled";
+				};
+
+				tegra_i2s6: i2s@2901500 {
+					compatible = "nvidia,tegra194-i2s",
+						     "nvidia,tegra210-i2s";
+					reg = <0x2901500 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_I2S6>,
+						 <&bpmp TEGRA194_CLK_I2S6_SYNC_INPUT>;
+					clock-names = "i2s", "sync_input";
+					assigned-clocks = <&bpmp TEGRA194_CLK_I2S6>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <1536000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "I2S6";
+					status = "disabled";
+				};
+
+				tegra_dmic1: dmic@2904000 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904000 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC1>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC1>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC1";
+					status = "disabled";
+				};
+
+				tegra_dmic2: dmic@2904100 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904100 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC2>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC2>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC2";
+					status = "disabled";
+				};
+
+				tegra_dmic3: dmic@2904200 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904200 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC3>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC3>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC3";
+					status = "disabled";
+				};
+
+				tegra_dmic4: dmic@2904300 {
+					compatible = "nvidia,tegra194-dmic",
+						     "nvidia,tegra210-dmic";
+					reg = <0x2904300 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DMIC4>;
+					clock-names = "dmic";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DMIC4>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <3072000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DMIC4";
+					status = "disabled";
+				};
+
+				tegra_dspk1: dspk@2905000 {
+					compatible = "nvidia,tegra194-dspk",
+						     "nvidia,tegra186-dspk";
+					reg = <0x2905000 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DSPK1>;
+					clock-names = "dspk";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DSPK1>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <12288000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DSPK1";
+					status = "disabled";
+				};
+
+				tegra_dspk2: dspk@2905100 {
+					compatible = "nvidia,tegra194-dspk",
+						     "nvidia,tegra186-dspk";
+					reg = <0x2905100 0x100>;
+					clocks = <&bpmp TEGRA194_CLK_DSPK2>;
+					clock-names = "dspk";
+					assigned-clocks = <&bpmp TEGRA194_CLK_DSPK2>;
+					assigned-clock-parents = <&bpmp TEGRA194_CLK_PLLA_OUT0>;
+					assigned-clock-rates = <12288000>;
+					#sound-dai-cells = <1>;
+					sound-name-prefix = "DSPK2";
+					status = "disabled";
+				};
+			};
 		};
 
 		pinmux: pinmux@2430000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index f4e0cc2..73ae58f 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1323,7 +1323,7 @@
 		ranges = <0x702c0000 0x0 0x702c0000 0x00040000>;
 		status = "disabled";
 
-		adma: dma@702e2000 {
+		adma: dma-controller@702e2000 {
 			compatible = "nvidia,tegra210-adma";
 			reg = <0x702e2000 0x2000>;
 			interrupt-parent = <&agic>;
@@ -1366,6 +1366,156 @@
 			clock-names = "clk";
 			status = "disabled";
 		};
+
+		tegra_ahub: ahub@702d0800 {
+			compatible = "nvidia,tegra210-ahub";
+			reg = <0x702d0800 0x800>;
+			clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+			clock-names = "ahub";
+			assigned-clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>;
+			assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x702d0000 0x702d0000 0x0000e400>;
+			#sound-dai-cells = <1>;
+			status = "disabled";
+
+			tegra_admaif: admaif@702d0000 {
+				compatible = "nvidia,tegra210-admaif";
+				reg = <0x702d0000 0x800>;
+				dmas = <&adma 1>,  <&adma 1>,
+				       <&adma 2>,  <&adma 2>,
+				       <&adma 3>,  <&adma 3>,
+				       <&adma 4>,  <&adma 4>,
+				       <&adma 5>,  <&adma 5>,
+				       <&adma 6>,  <&adma 6>,
+				       <&adma 7>,  <&adma 7>,
+				       <&adma 8>,  <&adma 8>,
+				       <&adma 9>,  <&adma 9>,
+				       <&adma 10>, <&adma 10>;
+				dma-names = "rx1",  "tx1",
+					    "rx2",  "tx2",
+					    "rx3",  "tx3",
+					    "rx4",  "tx4",
+					    "rx5",  "tx5",
+					    "rx6",  "tx6",
+					    "rx7",  "tx7",
+					    "rx8",  "tx8",
+					    "rx9",  "tx9",
+					    "rx10", "tx10";
+				#sound-dai-cells = <1>;
+				status = "disabled";
+			};
+
+			tegra_i2s1: i2s@702d1000 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1000 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S0>,
+					 <&tegra_car TEGRA210_CLK_I2S0_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S0>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S1";
+				status = "disabled";
+			};
+
+			tegra_i2s2: i2s@702d1100 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1100 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S1>,
+					 <&tegra_car TEGRA210_CLK_I2S1_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S1>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S2";
+				status = "disabled";
+			};
+
+			tegra_i2s3: i2s@702d1200 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1200 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S2>,
+					 <&tegra_car TEGRA210_CLK_I2S2_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S2>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S3";
+				status = "disabled";
+			};
+
+			tegra_i2s4: i2s@702d1300 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1300 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S3>,
+					 <&tegra_car TEGRA210_CLK_I2S3_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S3>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S4";
+				status = "disabled";
+			};
+
+			tegra_i2s5: i2s@702d1400 {
+				compatible = "nvidia,tegra210-i2s";
+				reg = <0x702d1400 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_I2S4>,
+					 <&tegra_car TEGRA210_CLK_I2S4_SYNC>;
+				clock-names = "i2s", "sync_input";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_I2S4>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <1536000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "I2S5";
+				status = "disabled";
+			};
+
+			tegra_dmic1: dmic@702d4000 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x702d4000 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+				clock-names = "dmic";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC1>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC1";
+				status = "disabled";
+			};
+
+			tegra_dmic2: dmic@702d4100 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x702d4100 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_DMIC2>;
+				clock-names = "dmic";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC2>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC2";
+				status = "disabled";
+			};
+
+			tegra_dmic3: dmic@702d4200 {
+				compatible = "nvidia,tegra210-dmic";
+				reg = <0x702d4200 0x100>;
+				clocks = <&tegra_car TEGRA210_CLK_DMIC3>;
+				clock-names = "dmic";
+				assigned-clocks = <&tegra_car TEGRA210_CLK_DMIC3>;
+				assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+				assigned-clock-rates = <3072000>;
+				#sound-dai-cells = <1>;
+				sound-name-prefix = "DMIC3";
+				status = "disabled";
+			};
+		};
 	};
 
 	spi@70410000 {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 22/23] arm64: tegra: Enable AHUB components on few Tegra platforms
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

This patch enables AHUB, ADMAIF modules for following Tegra platforms.
Along with this specific instances of I/O modules are enabled as per
the board design.

 * Jetson TX1
   - I2S1, I2S2, I2S3, I2S4 and I2S5
   - DMIC1, DMIC2 and DMIC3

 * Jetson Nano
   - I2S3 and I2S4
   - DMIC1 and DMIC2

 * Jetson TX2
   - I2S1, I2S2, I2S3, I2S4, I2S5 and I2S6
   - DMIC1, DMIC2 and DMIC3
   - DSPK2

 * Jetson AGX Xavier
   - I2S1, I2S2, I2S4 and I2S6
   - DMIC2 and DMIC3
   - DSPK1

This helps to register above components with ASoC core.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts | 48 ++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts | 36 ++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 42 ++++++++++++++++++-
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 36 ++++++++++++++++
 4 files changed, 161 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
index a70fd4e..cb24b81 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
@@ -20,6 +20,54 @@
 		interrupt-controller@2a40000 {
 			status = "okay";
 		};
+
+		ahub@2900800 {
+			status = "okay";
+
+			admaif@290f000 {
+				status = "okay";
+			};
+
+			i2s@2901000 {
+				status = "okay";
+			};
+
+			i2s@2901100 {
+				status = "okay";
+			};
+
+			i2s@2901200 {
+				status = "okay";
+			};
+
+			i2s@2901300 {
+				status = "okay";
+			};
+
+			i2s@2901400 {
+				status = "okay";
+			};
+
+			i2s@2901500 {
+				status = "okay";
+			};
+
+			dmic@2904000 {
+				status = "okay";
+			};
+
+			dmic@2904100 {
+				status = "okay";
+			};
+
+			dmic@2904200 {
+				status = "okay";
+			};
+
+			dspk@2905100 {
+				status = "okay";
+			};
+		};
 	};
 
 	i2c@3160000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
index 90b6ea5..f71c3bd 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
@@ -21,6 +21,42 @@
 			interrupt-controller@2a40000 {
 				status = "okay";
 			};
+
+			ahub@2900800 {
+				status = "okay";
+
+				admaif@290f000 {
+					status = "okay";
+				};
+
+				i2s@2901000 {
+					status = "okay";
+				};
+
+				i2s@2901100 {
+					status = "okay";
+				};
+
+				i2s@2901300 {
+					status = "okay";
+				};
+
+				i2s@2901500 {
+					status = "okay";
+				};
+
+				dmic@2904100 {
+					status = "okay";
+				};
+
+				dmic@2904200 {
+					status = "okay";
+				};
+
+				dspk@2905000 {
+					status = "okay";
+				};
+			};
 		};
 
 		ddc: i2c@31c0000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
index 56adf28..3c21137 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
@@ -118,12 +118,52 @@
 	aconnect@702c0000 {
 		status = "okay";
 
-		dma@702e2000 {
+		dma-controller@702e2000 {
 			status = "okay";
 		};
 
 		interrupt-controller@702f9000 {
 			status = "okay";
 		};
+
+		ahub@702d0800 {
+			status = "okay";
+
+			admaif@702d0000 {
+				status = "okay";
+			};
+
+			i2s@702d1000 {
+				status = "okay";
+			};
+
+			i2s@702d1100 {
+				status = "okay";
+			};
+
+			i2s@702d1200 {
+				status = "okay";
+			};
+
+			i2s@702d1300 {
+				status = "okay";
+			};
+
+			i2s@702d1400 {
+				status = "okay";
+			};
+
+			dmic@702d4000 {
+				status = "okay";
+			};
+
+			dmic@702d4100 {
+				status = "okay";
+			};
+
+			dmic@702d4200 {
+				status = "okay";
+			};
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 9b63469..721f66c 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -806,4 +806,40 @@
 
 		vin-supply = <&avdd_1v05_pll>;
 	};
+
+	aconnect@702c0000 {
+		status = "okay";
+
+		dma-controller@702e2000 {
+			status = "okay";
+		};
+
+		interrupt-controller@702f9000 {
+			status = "okay";
+		};
+
+		ahub@702d0800 {
+			status = "okay";
+
+			admaif@702d0000 {
+				status = "okay";
+			};
+
+			i2s@702d1200 {
+				status = "okay";
+			};
+
+			i2s@702d1300 {
+				status = "okay";
+			};
+
+			dmic@702d4000 {
+				status = "okay";
+			};
+
+			dmic@702d4100 {
+				status = "okay";
+			};
+		};
+	};
 };
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 22/23] arm64: tegra: Enable AHUB components on few Tegra platforms
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

This patch enables AHUB, ADMAIF modules for following Tegra platforms.
Along with this specific instances of I/O modules are enabled as per
the board design.

 * Jetson TX1
   - I2S1, I2S2, I2S3, I2S4 and I2S5
   - DMIC1, DMIC2 and DMIC3

 * Jetson Nano
   - I2S3 and I2S4
   - DMIC1 and DMIC2

 * Jetson TX2
   - I2S1, I2S2, I2S3, I2S4, I2S5 and I2S6
   - DMIC1, DMIC2 and DMIC3
   - DSPK2

 * Jetson AGX Xavier
   - I2S1, I2S2, I2S4 and I2S6
   - DMIC2 and DMIC3
   - DSPK1

This helps to register above components with ASoC core.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts | 48 ++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts | 36 ++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 42 ++++++++++++++++++-
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 36 ++++++++++++++++
 4 files changed, 161 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
index a70fd4e..cb24b81 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
@@ -20,6 +20,54 @@
 		interrupt-controller@2a40000 {
 			status = "okay";
 		};
+
+		ahub@2900800 {
+			status = "okay";
+
+			admaif@290f000 {
+				status = "okay";
+			};
+
+			i2s@2901000 {
+				status = "okay";
+			};
+
+			i2s@2901100 {
+				status = "okay";
+			};
+
+			i2s@2901200 {
+				status = "okay";
+			};
+
+			i2s@2901300 {
+				status = "okay";
+			};
+
+			i2s@2901400 {
+				status = "okay";
+			};
+
+			i2s@2901500 {
+				status = "okay";
+			};
+
+			dmic@2904000 {
+				status = "okay";
+			};
+
+			dmic@2904100 {
+				status = "okay";
+			};
+
+			dmic@2904200 {
+				status = "okay";
+			};
+
+			dspk@2905100 {
+				status = "okay";
+			};
+		};
 	};
 
 	i2c@3160000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
index 90b6ea5..f71c3bd 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
@@ -21,6 +21,42 @@
 			interrupt-controller@2a40000 {
 				status = "okay";
 			};
+
+			ahub@2900800 {
+				status = "okay";
+
+				admaif@290f000 {
+					status = "okay";
+				};
+
+				i2s@2901000 {
+					status = "okay";
+				};
+
+				i2s@2901100 {
+					status = "okay";
+				};
+
+				i2s@2901300 {
+					status = "okay";
+				};
+
+				i2s@2901500 {
+					status = "okay";
+				};
+
+				dmic@2904100 {
+					status = "okay";
+				};
+
+				dmic@2904200 {
+					status = "okay";
+				};
+
+				dspk@2905000 {
+					status = "okay";
+				};
+			};
 		};
 
 		ddc: i2c@31c0000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
index 56adf28..3c21137 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
@@ -118,12 +118,52 @@
 	aconnect@702c0000 {
 		status = "okay";
 
-		dma@702e2000 {
+		dma-controller@702e2000 {
 			status = "okay";
 		};
 
 		interrupt-controller@702f9000 {
 			status = "okay";
 		};
+
+		ahub@702d0800 {
+			status = "okay";
+
+			admaif@702d0000 {
+				status = "okay";
+			};
+
+			i2s@702d1000 {
+				status = "okay";
+			};
+
+			i2s@702d1100 {
+				status = "okay";
+			};
+
+			i2s@702d1200 {
+				status = "okay";
+			};
+
+			i2s@702d1300 {
+				status = "okay";
+			};
+
+			i2s@702d1400 {
+				status = "okay";
+			};
+
+			dmic@702d4000 {
+				status = "okay";
+			};
+
+			dmic@702d4100 {
+				status = "okay";
+			};
+
+			dmic@702d4200 {
+				status = "okay";
+			};
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 9b63469..721f66c 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -806,4 +806,40 @@
 
 		vin-supply = <&avdd_1v05_pll>;
 	};
+
+	aconnect@702c0000 {
+		status = "okay";
+
+		dma-controller@702e2000 {
+			status = "okay";
+		};
+
+		interrupt-controller@702f9000 {
+			status = "okay";
+		};
+
+		ahub@702d0800 {
+			status = "okay";
+
+			admaif@702d0000 {
+				status = "okay";
+			};
+
+			i2s@702d1200 {
+				status = "okay";
+			};
+
+			i2s@702d1300 {
+				status = "okay";
+			};
+
+			dmic@702d4000 {
+				status = "okay";
+			};
+
+			dmic@702d4100 {
+				status = "okay";
+			};
+		};
+	};
 };
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 22/23] arm64: tegra: Enable AHUB components on few Tegra platforms
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

This patch enables AHUB, ADMAIF modules for following Tegra platforms.
Along with this specific instances of I/O modules are enabled as per
the board design.

 * Jetson TX1
   - I2S1, I2S2, I2S3, I2S4 and I2S5
   - DMIC1, DMIC2 and DMIC3

 * Jetson Nano
   - I2S3 and I2S4
   - DMIC1 and DMIC2

 * Jetson TX2
   - I2S1, I2S2, I2S3, I2S4, I2S5 and I2S6
   - DMIC1, DMIC2 and DMIC3
   - DSPK2

 * Jetson AGX Xavier
   - I2S1, I2S2, I2S4 and I2S6
   - DMIC2 and DMIC3
   - DSPK1

This helps to register above components with ASoC core.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts | 48 ++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts | 36 ++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 42 ++++++++++++++++++-
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 36 ++++++++++++++++
 4 files changed, 161 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
index a70fd4e..cb24b81 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts
@@ -20,6 +20,54 @@
 		interrupt-controller@2a40000 {
 			status = "okay";
 		};
+
+		ahub@2900800 {
+			status = "okay";
+
+			admaif@290f000 {
+				status = "okay";
+			};
+
+			i2s@2901000 {
+				status = "okay";
+			};
+
+			i2s@2901100 {
+				status = "okay";
+			};
+
+			i2s@2901200 {
+				status = "okay";
+			};
+
+			i2s@2901300 {
+				status = "okay";
+			};
+
+			i2s@2901400 {
+				status = "okay";
+			};
+
+			i2s@2901500 {
+				status = "okay";
+			};
+
+			dmic@2904000 {
+				status = "okay";
+			};
+
+			dmic@2904100 {
+				status = "okay";
+			};
+
+			dmic@2904200 {
+				status = "okay";
+			};
+
+			dspk@2905100 {
+				status = "okay";
+			};
+		};
 	};
 
 	i2c@3160000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
index 90b6ea5..f71c3bd 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts
@@ -21,6 +21,42 @@
 			interrupt-controller@2a40000 {
 				status = "okay";
 			};
+
+			ahub@2900800 {
+				status = "okay";
+
+				admaif@290f000 {
+					status = "okay";
+				};
+
+				i2s@2901000 {
+					status = "okay";
+				};
+
+				i2s@2901100 {
+					status = "okay";
+				};
+
+				i2s@2901300 {
+					status = "okay";
+				};
+
+				i2s@2901500 {
+					status = "okay";
+				};
+
+				dmic@2904100 {
+					status = "okay";
+				};
+
+				dmic@2904200 {
+					status = "okay";
+				};
+
+				dspk@2905000 {
+					status = "okay";
+				};
+			};
 		};
 
 		ddc: i2c@31c0000 {
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
index 56adf28..3c21137 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
@@ -118,12 +118,52 @@
 	aconnect@702c0000 {
 		status = "okay";
 
-		dma@702e2000 {
+		dma-controller@702e2000 {
 			status = "okay";
 		};
 
 		interrupt-controller@702f9000 {
 			status = "okay";
 		};
+
+		ahub@702d0800 {
+			status = "okay";
+
+			admaif@702d0000 {
+				status = "okay";
+			};
+
+			i2s@702d1000 {
+				status = "okay";
+			};
+
+			i2s@702d1100 {
+				status = "okay";
+			};
+
+			i2s@702d1200 {
+				status = "okay";
+			};
+
+			i2s@702d1300 {
+				status = "okay";
+			};
+
+			i2s@702d1400 {
+				status = "okay";
+			};
+
+			dmic@702d4000 {
+				status = "okay";
+			};
+
+			dmic@702d4100 {
+				status = "okay";
+			};
+
+			dmic@702d4200 {
+				status = "okay";
+			};
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 9b63469..721f66c 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -806,4 +806,40 @@
 
 		vin-supply = <&avdd_1v05_pll>;
 	};
+
+	aconnect@702c0000 {
+		status = "okay";
+
+		dma-controller@702e2000 {
+			status = "okay";
+		};
+
+		interrupt-controller@702f9000 {
+			status = "okay";
+		};
+
+		ahub@702d0800 {
+			status = "okay";
+
+			admaif@702d0000 {
+				status = "okay";
+			};
+
+			i2s@702d1200 {
+				status = "okay";
+			};
+
+			i2s@702d1300 {
+				status = "okay";
+			};
+
+			dmic@702d4000 {
+				status = "okay";
+			};
+
+			dmic@702d4100 {
+				status = "okay";
+			};
+		};
+	};
 };
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 23/23] arm64: tegra: Add support for APE sound card on Jetson Nano and TX1
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-27  4:53     ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w
  Cc: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w, Sameer Pujar

This adds APE sound card support on Jetson Nano and TX1 which is based
on simple-card driver. Earlier in the series simple-card driver is
enhanced to work with multiple ASoC components. Based on board design
required I/O interfaces are exposed for I2S and DMIC. More complicated
audio paths will be added going forward.

Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 94 ++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 49 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           | 67 +++++++++++++++
 3 files changed, 210 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
index 3c21137..7c4b521 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
@@ -166,4 +166,98 @@
 			};
 		};
 	};
+
+	tegra_sound {
+		status = "okay";
+
+		simple-audio-card,name = "jetson-tx1-ape";
+
+		simple-audio-card,widgets =
+			"Microphone",   "MIC",
+			"Speaker",	"SPK";
+
+		simple-audio-card,routing =
+			"SPK",		  "I2S1 Playback",
+			"SPK",		  "I2S2 Playback",
+			"SPK",		  "I2S3 Playback",
+			"SPK",		  "I2S4 Playback",
+			"SPK",		  "I2S5 Playback",
+			"I2S1 Capture",   "MIC",
+			"I2S2 Capture",   "MIC",
+			"I2S3 Capture",   "MIC",
+			"I2S4 Capture",   "MIC",
+			"I2S5 Capture",   "MIC",
+			"DMIC1 Capture",  "MIC",
+			"DMIC2 Capture",  "MIC",
+			"DMIC3 Capture",  "MIC";
+
+		/* BE links */
+		simple-audio-card,dai-link@1 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s1>;
+			frame-master = <&cpu_i2s1>;
+
+			cpu_i2s1: cpu@0 {
+				sound-dai = <&tegra_i2s1 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@2 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s2>;
+			frame-master = <&cpu_i2s2>;
+
+			cpu_i2s2: cpu@0 {
+				sound-dai = <&tegra_i2s2 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@3 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s3>;
+			frame-master = <&cpu_i2s3>;
+
+			cpu_i2s3: cpu@0 {
+				sound-dai = <&tegra_i2s3 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@4 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s4>;
+			frame-master = <&cpu_i2s4>;
+
+			cpu_i2s4: cpu@0 {
+				sound-dai = <&tegra_i2s4 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@5 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s5>;
+			frame-master = <&cpu_i2s5>;
+
+			cpu_i2s5: cpu@0 {
+				sound-dai = <&tegra_i2s5 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@6 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic1 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@7 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic2 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@8 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic3 0>;
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 721f66c..31994f6 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -842,4 +842,53 @@
 			};
 		};
 	};
+
+	tegra_sound {
+		status = "okay";
+
+		simple-audio-card,name = "jetson-nano-ape";
+		simple-audio-card,widgets =
+			"Microphone",   "MIC",
+			"Speaker",	"SPK";
+		simple-audio-card,routing =
+			"SPK",		  "I2S3 Playback",
+			"SPK",		  "I2S4 Playback",
+			"I2S3 Capture",   "MIC",
+			"I2S4 Capture",   "MIC",
+			"DMIC1 Capture",  "MIC",
+			"DMIC2 Capture",  "MIC";
+
+		/* BE links */
+		simple-audio-card,dai-link@1 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s1>;
+			frame-master = <&cpu_i2s1>;
+
+			cpu_i2s1: cpu@0 {
+				sound-dai = <&tegra_i2s3 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@2 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s2>;
+			frame-master = <&cpu_i2s2>;
+
+			cpu_i2s2: cpu@0 {
+				sound-dai = <&tegra_i2s4 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@3 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic1 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@4 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic2 0>;
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 73ae58f..f1925f1 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1841,4 +1841,71 @@
 			};
 		};
 	};
+
+	tegra_sound {
+		status = "disabled";
+
+		compatible = "simple-cc-audio-card";
+
+		clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+			 <&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
+			 <&tegra_car TEGRA210_CLK_EXTERN1>;
+		clock-names = "pll_a", "plla_out0", "aud_mclk";
+		assigned-clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+				  <&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
+				  <&tegra_car TEGRA210_CLK_EXTERN1>;
+		assigned-clock-parents = <0>, <0>, <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+		assigned-clock-rates = <368640000>, <49152000>, <12288000>;
+
+		simple-audio-card,aux-devs = <&tegra_ahub>;
+
+		/* FE links */
+		simple-audio-card,dai-link@0 {
+			cpu@0 {
+				sound-dai = <&tegra_admaif 0>;
+			};
+
+			cpu@1 {
+				sound-dai = <&tegra_admaif 1>;
+			};
+
+			cpu@2 {
+				sound-dai = <&tegra_admaif 2>;
+			};
+
+			cpu@3 {
+				sound-dai = <&tegra_admaif 3>;
+			};
+
+			cpu@4 {
+				sound-dai = <&tegra_admaif 4>;
+			};
+
+			cpu@5 {
+				sound-dai = <&tegra_admaif 5>;
+			};
+
+			cpu@6 {
+				sound-dai = <&tegra_admaif 6>;
+			};
+
+			cpu@7 {
+				sound-dai = <&tegra_admaif 7>;
+			};
+
+			cpu@8 {
+				sound-dai = <&tegra_admaif 8>;
+			};
+
+			cpu@9 {
+				sound-dai = <&tegra_admaif 9>;
+			};
+
+			/*
+			 * Empty codec list.
+			 * Router MUX controls take care of audio path by
+			 * connecting multiple components.
+			 */
+		};
+	};
 };
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 23/23] arm64: tegra: Add support for APE sound card on Jetson Nano and TX1
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka, Sameer Pujar

This adds APE sound card support on Jetson Nano and TX1 which is based
on simple-card driver. Earlier in the series simple-card driver is
enhanced to work with multiple ASoC components. Based on board design
required I/O interfaces are exposed for I2S and DMIC. More complicated
audio paths will be added going forward.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 94 ++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 49 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           | 67 +++++++++++++++
 3 files changed, 210 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
index 3c21137..7c4b521 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
@@ -166,4 +166,98 @@
 			};
 		};
 	};
+
+	tegra_sound {
+		status = "okay";
+
+		simple-audio-card,name = "jetson-tx1-ape";
+
+		simple-audio-card,widgets =
+			"Microphone",   "MIC",
+			"Speaker",	"SPK";
+
+		simple-audio-card,routing =
+			"SPK",		  "I2S1 Playback",
+			"SPK",		  "I2S2 Playback",
+			"SPK",		  "I2S3 Playback",
+			"SPK",		  "I2S4 Playback",
+			"SPK",		  "I2S5 Playback",
+			"I2S1 Capture",   "MIC",
+			"I2S2 Capture",   "MIC",
+			"I2S3 Capture",   "MIC",
+			"I2S4 Capture",   "MIC",
+			"I2S5 Capture",   "MIC",
+			"DMIC1 Capture",  "MIC",
+			"DMIC2 Capture",  "MIC",
+			"DMIC3 Capture",  "MIC";
+
+		/* BE links */
+		simple-audio-card,dai-link@1 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s1>;
+			frame-master = <&cpu_i2s1>;
+
+			cpu_i2s1: cpu@0 {
+				sound-dai = <&tegra_i2s1 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@2 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s2>;
+			frame-master = <&cpu_i2s2>;
+
+			cpu_i2s2: cpu@0 {
+				sound-dai = <&tegra_i2s2 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@3 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s3>;
+			frame-master = <&cpu_i2s3>;
+
+			cpu_i2s3: cpu@0 {
+				sound-dai = <&tegra_i2s3 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@4 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s4>;
+			frame-master = <&cpu_i2s4>;
+
+			cpu_i2s4: cpu@0 {
+				sound-dai = <&tegra_i2s4 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@5 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s5>;
+			frame-master = <&cpu_i2s5>;
+
+			cpu_i2s5: cpu@0 {
+				sound-dai = <&tegra_i2s5 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@6 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic1 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@7 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic2 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@8 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic3 0>;
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 721f66c..31994f6 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -842,4 +842,53 @@
 			};
 		};
 	};
+
+	tegra_sound {
+		status = "okay";
+
+		simple-audio-card,name = "jetson-nano-ape";
+		simple-audio-card,widgets =
+			"Microphone",   "MIC",
+			"Speaker",	"SPK";
+		simple-audio-card,routing =
+			"SPK",		  "I2S3 Playback",
+			"SPK",		  "I2S4 Playback",
+			"I2S3 Capture",   "MIC",
+			"I2S4 Capture",   "MIC",
+			"DMIC1 Capture",  "MIC",
+			"DMIC2 Capture",  "MIC";
+
+		/* BE links */
+		simple-audio-card,dai-link@1 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s1>;
+			frame-master = <&cpu_i2s1>;
+
+			cpu_i2s1: cpu@0 {
+				sound-dai = <&tegra_i2s3 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@2 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s2>;
+			frame-master = <&cpu_i2s2>;
+
+			cpu_i2s2: cpu@0 {
+				sound-dai = <&tegra_i2s4 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@3 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic1 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@4 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic2 0>;
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 73ae58f..f1925f1 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1841,4 +1841,71 @@
 			};
 		};
 	};
+
+	tegra_sound {
+		status = "disabled";
+
+		compatible = "simple-cc-audio-card";
+
+		clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+			 <&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
+			 <&tegra_car TEGRA210_CLK_EXTERN1>;
+		clock-names = "pll_a", "plla_out0", "aud_mclk";
+		assigned-clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+				  <&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
+				  <&tegra_car TEGRA210_CLK_EXTERN1>;
+		assigned-clock-parents = <0>, <0>, <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+		assigned-clock-rates = <368640000>, <49152000>, <12288000>;
+
+		simple-audio-card,aux-devs = <&tegra_ahub>;
+
+		/* FE links */
+		simple-audio-card,dai-link@0 {
+			cpu@0 {
+				sound-dai = <&tegra_admaif 0>;
+			};
+
+			cpu@1 {
+				sound-dai = <&tegra_admaif 1>;
+			};
+
+			cpu@2 {
+				sound-dai = <&tegra_admaif 2>;
+			};
+
+			cpu@3 {
+				sound-dai = <&tegra_admaif 3>;
+			};
+
+			cpu@4 {
+				sound-dai = <&tegra_admaif 4>;
+			};
+
+			cpu@5 {
+				sound-dai = <&tegra_admaif 5>;
+			};
+
+			cpu@6 {
+				sound-dai = <&tegra_admaif 6>;
+			};
+
+			cpu@7 {
+				sound-dai = <&tegra_admaif 7>;
+			};
+
+			cpu@8 {
+				sound-dai = <&tegra_admaif 8>;
+			};
+
+			cpu@9 {
+				sound-dai = <&tegra_admaif 9>;
+			};
+
+			/*
+			 * Empty codec list.
+			 * Router MUX controls take care of audio path by
+			 * connecting multiple components.
+			 */
+		};
+	};
 };
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* [PATCH v4 23/23] arm64: tegra: Add support for APE sound card on Jetson Nano and TX1
@ 2020-06-27  4:53     ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-27  4:53 UTC (permalink / raw)
  To: broonie, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood
  Cc: nicoleotsuka, alsa-devel, swarren, Sameer Pujar, nwartikar,
	linux-kernel, jonathanh, viswanathl, sharadg, thierry.reding,
	atalambedu, linux-tegra, digetx, rlokhande, mkumard, dramesh

This adds APE sound card support on Jetson Nano and TX1 which is based
on simple-card driver. Earlier in the series simple-card driver is
enhanced to work with multiple ASoC components. Based on board design
required I/O interfaces are exposed for I2S and DMIC. More complicated
audio paths will be added going forward.

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 94 ++++++++++++++++++++++
 arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 49 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra210.dtsi           | 67 +++++++++++++++
 3 files changed, 210 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
index 3c21137..7c4b521 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts
@@ -166,4 +166,98 @@
 			};
 		};
 	};
+
+	tegra_sound {
+		status = "okay";
+
+		simple-audio-card,name = "jetson-tx1-ape";
+
+		simple-audio-card,widgets =
+			"Microphone",   "MIC",
+			"Speaker",	"SPK";
+
+		simple-audio-card,routing =
+			"SPK",		  "I2S1 Playback",
+			"SPK",		  "I2S2 Playback",
+			"SPK",		  "I2S3 Playback",
+			"SPK",		  "I2S4 Playback",
+			"SPK",		  "I2S5 Playback",
+			"I2S1 Capture",   "MIC",
+			"I2S2 Capture",   "MIC",
+			"I2S3 Capture",   "MIC",
+			"I2S4 Capture",   "MIC",
+			"I2S5 Capture",   "MIC",
+			"DMIC1 Capture",  "MIC",
+			"DMIC2 Capture",  "MIC",
+			"DMIC3 Capture",  "MIC";
+
+		/* BE links */
+		simple-audio-card,dai-link@1 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s1>;
+			frame-master = <&cpu_i2s1>;
+
+			cpu_i2s1: cpu@0 {
+				sound-dai = <&tegra_i2s1 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@2 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s2>;
+			frame-master = <&cpu_i2s2>;
+
+			cpu_i2s2: cpu@0 {
+				sound-dai = <&tegra_i2s2 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@3 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s3>;
+			frame-master = <&cpu_i2s3>;
+
+			cpu_i2s3: cpu@0 {
+				sound-dai = <&tegra_i2s3 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@4 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s4>;
+			frame-master = <&cpu_i2s4>;
+
+			cpu_i2s4: cpu@0 {
+				sound-dai = <&tegra_i2s4 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@5 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s5>;
+			frame-master = <&cpu_i2s5>;
+
+			cpu_i2s5: cpu@0 {
+				sound-dai = <&tegra_i2s5 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@6 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic1 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@7 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic2 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@8 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic3 0>;
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
index 721f66c..31994f6 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts
@@ -842,4 +842,53 @@
 			};
 		};
 	};
+
+	tegra_sound {
+		status = "okay";
+
+		simple-audio-card,name = "jetson-nano-ape";
+		simple-audio-card,widgets =
+			"Microphone",   "MIC",
+			"Speaker",	"SPK";
+		simple-audio-card,routing =
+			"SPK",		  "I2S3 Playback",
+			"SPK",		  "I2S4 Playback",
+			"I2S3 Capture",   "MIC",
+			"I2S4 Capture",   "MIC",
+			"DMIC1 Capture",  "MIC",
+			"DMIC2 Capture",  "MIC";
+
+		/* BE links */
+		simple-audio-card,dai-link@1 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s1>;
+			frame-master = <&cpu_i2s1>;
+
+			cpu_i2s1: cpu@0 {
+				sound-dai = <&tegra_i2s3 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@2 {
+			format = "i2s";
+			bitclock-master = <&cpu_i2s2>;
+			frame-master = <&cpu_i2s2>;
+
+			cpu_i2s2: cpu@0 {
+				sound-dai = <&tegra_i2s4 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@3 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic1 0>;
+			};
+		};
+
+		simple-audio-card,dai-link@4 {
+			cpu@0 {
+				sound-dai = <&tegra_dmic2 0>;
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 73ae58f..f1925f1 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1841,4 +1841,71 @@
 			};
 		};
 	};
+
+	tegra_sound {
+		status = "disabled";
+
+		compatible = "simple-cc-audio-card";
+
+		clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+			 <&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
+			 <&tegra_car TEGRA210_CLK_EXTERN1>;
+		clock-names = "pll_a", "plla_out0", "aud_mclk";
+		assigned-clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
+				  <&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
+				  <&tegra_car TEGRA210_CLK_EXTERN1>;
+		assigned-clock-parents = <0>, <0>, <&tegra_car TEGRA210_CLK_PLL_A_OUT0>;
+		assigned-clock-rates = <368640000>, <49152000>, <12288000>;
+
+		simple-audio-card,aux-devs = <&tegra_ahub>;
+
+		/* FE links */
+		simple-audio-card,dai-link@0 {
+			cpu@0 {
+				sound-dai = <&tegra_admaif 0>;
+			};
+
+			cpu@1 {
+				sound-dai = <&tegra_admaif 1>;
+			};
+
+			cpu@2 {
+				sound-dai = <&tegra_admaif 2>;
+			};
+
+			cpu@3 {
+				sound-dai = <&tegra_admaif 3>;
+			};
+
+			cpu@4 {
+				sound-dai = <&tegra_admaif 4>;
+			};
+
+			cpu@5 {
+				sound-dai = <&tegra_admaif 5>;
+			};
+
+			cpu@6 {
+				sound-dai = <&tegra_admaif 6>;
+			};
+
+			cpu@7 {
+				sound-dai = <&tegra_admaif 7>;
+			};
+
+			cpu@8 {
+				sound-dai = <&tegra_admaif 8>;
+			};
+
+			cpu@9 {
+				sound-dai = <&tegra_admaif 9>;
+			};
+
+			/*
+			 * Empty codec list.
+			 * Router MUX controls take care of audio path by
+			 * connecting multiple components.
+			 */
+		};
+	};
 };
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
  2020-06-27  4:53     ` Sameer Pujar
  (?)
@ 2020-06-29  0:38         ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  0:38 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

Thank you for your patch

# I guess there was ML registering magic until v3 ?
# This is 1st time for me to get this patch series...

> The "prefix" can be defined in DAI link node or it can be specified as
> part of the component node itself. Currently "sound-name-prefix" defined
> in a component is not taking effect. Actually the property is not getting
> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
> "prefix" is missing in DAI link Codec node.
> 
> Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
(snip)
> @@ -1111,8 +1111,10 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
>  		struct snd_soc_codec_conf *map = &card->codec_conf[i];
>  
>  		if (snd_soc_is_matching_component(&map->dlc, component)) {
> -			component->name_prefix = map->name_prefix;
> -			return;
> +			if (map->name_prefix) {
> +				component->name_prefix = map->name_prefix;
> +				return;
> +			}
>  		}
>  	}

This is nit-pick but it can be like this ?

		if (snd_soc_is_matching_component(&map->dlc, component) &&
		    map->name_prefix) {
			...
		}

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
@ 2020-06-29  0:38         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  0:38 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

Thank you for your patch

# I guess there was ML registering magic until v3 ?
# This is 1st time for me to get this patch series...

> The "prefix" can be defined in DAI link node or it can be specified as
> part of the component node itself. Currently "sound-name-prefix" defined
> in a component is not taking effect. Actually the property is not getting
> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
> "prefix" is missing in DAI link Codec node.
> 
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
(snip)
> @@ -1111,8 +1111,10 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
>  		struct snd_soc_codec_conf *map = &card->codec_conf[i];
>  
>  		if (snd_soc_is_matching_component(&map->dlc, component)) {
> -			component->name_prefix = map->name_prefix;
> -			return;
> +			if (map->name_prefix) {
> +				component->name_prefix = map->name_prefix;
> +				return;
> +			}
>  		}
>  	}

This is nit-pick but it can be like this ?

		if (snd_soc_is_matching_component(&map->dlc, component) &&
		    map->name_prefix) {
			...
		}

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
@ 2020-06-29  0:38         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  0:38 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

Thank you for your patch

# I guess there was ML registering magic until v3 ?
# This is 1st time for me to get this patch series...

> The "prefix" can be defined in DAI link node or it can be specified as
> part of the component node itself. Currently "sound-name-prefix" defined
> in a component is not taking effect. Actually the property is not getting
> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
> "prefix" is missing in DAI link Codec node.
> 
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
(snip)
> @@ -1111,8 +1111,10 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
>  		struct snd_soc_codec_conf *map = &card->codec_conf[i];
>  
>  		if (snd_soc_is_matching_component(&map->dlc, component)) {
> -			component->name_prefix = map->name_prefix;
> -			return;
> +			if (map->name_prefix) {
> +				component->name_prefix = map->name_prefix;
> +				return;
> +			}
>  		}
>  	}

This is nit-pick but it can be like this ?

		if (snd_soc_is_matching_component(&map->dlc, component) &&
		    map->name_prefix) {
			...
		}

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
  2020-06-27  4:53     ` Sameer Pujar
  (?)
@ 2020-06-29  0:56         ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  0:56 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

>  simple-audio-card,dai-link@xxx {
>      format = "i2s";
>      bitclock-master=<&cpu1>;
>      frame-master=<&cpu1>;
> 
>      cpu1: cpu@0 {
>          ...
>      };
> 
>      codec@0 {
>          ...
>      };
> 
>      ...
>  };
> 
> In above case CPU is expected to be configured as a master and Codec as
> a slave device. But both CPU/Codec are being configured as slave devices.
> This happens because asoc_simple_parse_daifmt() uses Codec reference and
> sets up the 'dai_link->dai_fmt' accordingly while parsing both CPU and
> Codec.

I'm sorry but I don't 100% understand about this case...
asoc_simple_parse_daifmt() should work in this case

The reason why it needs codec node is that
SND_SOC_DAIFMT_CBx_CFx are "Codec" base Master/Slave.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-29  0:56         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  0:56 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

>  simple-audio-card,dai-link@xxx {
>      format = "i2s";
>      bitclock-master=<&cpu1>;
>      frame-master=<&cpu1>;
> 
>      cpu1: cpu@0 {
>          ...
>      };
> 
>      codec@0 {
>          ...
>      };
> 
>      ...
>  };
> 
> In above case CPU is expected to be configured as a master and Codec as
> a slave device. But both CPU/Codec are being configured as slave devices.
> This happens because asoc_simple_parse_daifmt() uses Codec reference and
> sets up the 'dai_link->dai_fmt' accordingly while parsing both CPU and
> Codec.

I'm sorry but I don't 100% understand about this case...
asoc_simple_parse_daifmt() should work in this case

The reason why it needs codec node is that
SND_SOC_DAIFMT_CBx_CFx are "Codec" base Master/Slave.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-29  0:56         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  0:56 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

>  simple-audio-card,dai-link@xxx {
>      format = "i2s";
>      bitclock-master=<&cpu1>;
>      frame-master=<&cpu1>;
> 
>      cpu1: cpu@0 {
>          ...
>      };
> 
>      codec@0 {
>          ...
>      };
> 
>      ...
>  };
> 
> In above case CPU is expected to be configured as a master and Codec as
> a slave device. But both CPU/Codec are being configured as slave devices.
> This happens because asoc_simple_parse_daifmt() uses Codec reference and
> sets up the 'dai_link->dai_fmt' accordingly while parsing both CPU and
> Codec.

I'm sorry but I don't 100% understand about this case...
asoc_simple_parse_daifmt() should work in this case

The reason why it needs codec node is that
SND_SOC_DAIFMT_CBx_CFx are "Codec" base Master/Slave.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
  2020-06-27  4:53     ` Sameer Pujar
  (?)
@ 2020-06-29  1:05         ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:05 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> CPU/Codec in DPCM DAI links are connected as CPU<->Dummy and Dummy<->Codec.
> Though mostly CPU won't use/require 'mclk-fs' property, looping over
> 'np' (current child node in a DAI link) can help in cases where multiple
> Codecs are defined. This further helps to get rid of 'codec' argument
> from simple_dai_link_of_dpcm() function, which gets called for DPCM links.
> 
> Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
(snip)
> diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
> index 39cdc71..02d6295 100644
> --- a/sound/soc/generic/simple-card.c
> +++ b/sound/soc/generic/simple-card.c
> @@ -107,7 +107,9 @@ static void simple_parse_mclk_fs(struct device_node *top,
>  	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
>  	of_property_read_u32(node,	prop, &props->mclk_fs);
>  	of_property_read_u32(cpu,	prop, &props->mclk_fs);
> -	of_property_read_u32(codec,	prop, &props->mclk_fs);
> +
> +	if (cpu != codec)
> +		of_property_read_u32(codec, prop, &props->mclk_fs);

Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
without using magical code in simple_parse_mclk_fs() side ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-29  1:05         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:05 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> CPU/Codec in DPCM DAI links are connected as CPU<->Dummy and Dummy<->Codec.
> Though mostly CPU won't use/require 'mclk-fs' property, looping over
> 'np' (current child node in a DAI link) can help in cases where multiple
> Codecs are defined. This further helps to get rid of 'codec' argument
> from simple_dai_link_of_dpcm() function, which gets called for DPCM links.
> 
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> ---
(snip)
> diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
> index 39cdc71..02d6295 100644
> --- a/sound/soc/generic/simple-card.c
> +++ b/sound/soc/generic/simple-card.c
> @@ -107,7 +107,9 @@ static void simple_parse_mclk_fs(struct device_node *top,
>  	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
>  	of_property_read_u32(node,	prop, &props->mclk_fs);
>  	of_property_read_u32(cpu,	prop, &props->mclk_fs);
> -	of_property_read_u32(codec,	prop, &props->mclk_fs);
> +
> +	if (cpu != codec)
> +		of_property_read_u32(codec, prop, &props->mclk_fs);

Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
without using magical code in simple_parse_mclk_fs() side ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-29  1:05         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:05 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> CPU/Codec in DPCM DAI links are connected as CPU<->Dummy and Dummy<->Codec.
> Though mostly CPU won't use/require 'mclk-fs' property, looping over
> 'np' (current child node in a DAI link) can help in cases where multiple
> Codecs are defined. This further helps to get rid of 'codec' argument
> from simple_dai_link_of_dpcm() function, which gets called for DPCM links.
> 
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> ---
(snip)
> diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
> index 39cdc71..02d6295 100644
> --- a/sound/soc/generic/simple-card.c
> +++ b/sound/soc/generic/simple-card.c
> @@ -107,7 +107,9 @@ static void simple_parse_mclk_fs(struct device_node *top,
>  	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
>  	of_property_read_u32(node,	prop, &props->mclk_fs);
>  	of_property_read_u32(cpu,	prop, &props->mclk_fs);
> -	of_property_read_u32(codec,	prop, &props->mclk_fs);
> +
> +	if (cpu != codec)
> +		of_property_read_u32(codec, prop, &props->mclk_fs);

Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
without using magical code in simple_parse_mclk_fs() side ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-27  4:53     ` Sameer Pujar
  (?)
@ 2020-06-29  1:24         ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:24 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> The simple-card driver supports multiple CPU and single Codec entries
> for DPCM DAI links. In some cases it is required to have multiple
> CPU/Codecs. Currently parsing logic for DPCM link loops over all
> children of DAI link but assumes that there is a single Codec entry.
> When DAI link has multiple Codecs it considers only the first Codec
> entry and remaining Codecs are wrongly treated as CPU. This happens
> because first Codec is used as reference for parsing all other child
> nodes.
(snip)
> @@ -137,8 +136,13 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
>  	 * Codec |return|Pass
>  	 * np
>  	 */
> -	if (li->cpu == (np == codec))
> -		return 0;
> +	if (li->cpu) {
> +		if (!strcmp(np->name, "codec"))
> +			return 0;
> +	} else {
> +		if (!strcmp(np->name, "cpu"))
> +			return 0;
> +	}

Checking node name is maybe nice idea,
but please consider "prefix" here.

Maybe base issue for multiple codec support
is that simple_for_each_link() is caring first codec only ?

	simple_for_each_link(...)
	{
		...
		do {
=>			/* get codec */
=>			codec = of_get_child_by_name(...);
			...
		}
	}

Remove above and having simple_node_is_codec(np, xxx) function
or something can help it ?


Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-29  1:24         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:24 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> The simple-card driver supports multiple CPU and single Codec entries
> for DPCM DAI links. In some cases it is required to have multiple
> CPU/Codecs. Currently parsing logic for DPCM link loops over all
> children of DAI link but assumes that there is a single Codec entry.
> When DAI link has multiple Codecs it considers only the first Codec
> entry and remaining Codecs are wrongly treated as CPU. This happens
> because first Codec is used as reference for parsing all other child
> nodes.
(snip)
> @@ -137,8 +136,13 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
>  	 * Codec |return|Pass
>  	 * np
>  	 */
> -	if (li->cpu == (np == codec))
> -		return 0;
> +	if (li->cpu) {
> +		if (!strcmp(np->name, "codec"))
> +			return 0;
> +	} else {
> +		if (!strcmp(np->name, "cpu"))
> +			return 0;
> +	}

Checking node name is maybe nice idea,
but please consider "prefix" here.

Maybe base issue for multiple codec support
is that simple_for_each_link() is caring first codec only ?

	simple_for_each_link(...)
	{
		...
		do {
=>			/* get codec */
=>			codec = of_get_child_by_name(...);
			...
		}
	}

Remove above and having simple_node_is_codec(np, xxx) function
or something can help it ?


Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-29  1:24         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:24 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> The simple-card driver supports multiple CPU and single Codec entries
> for DPCM DAI links. In some cases it is required to have multiple
> CPU/Codecs. Currently parsing logic for DPCM link loops over all
> children of DAI link but assumes that there is a single Codec entry.
> When DAI link has multiple Codecs it considers only the first Codec
> entry and remaining Codecs are wrongly treated as CPU. This happens
> because first Codec is used as reference for parsing all other child
> nodes.
(snip)
> @@ -137,8 +136,13 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
>  	 * Codec |return|Pass
>  	 * np
>  	 */
> -	if (li->cpu == (np == codec))
> -		return 0;
> +	if (li->cpu) {
> +		if (!strcmp(np->name, "codec"))
> +			return 0;
> +	} else {
> +		if (!strcmp(np->name, "cpu"))
> +			return 0;
> +	}

Checking node name is maybe nice idea,
but please consider "prefix" here.

Maybe base issue for multiple codec support
is that simple_for_each_link() is caring first codec only ?

	simple_for_each_link(...)
	{
		...
		do {
=>			/* get codec */
=>			codec = of_get_child_by_name(...);
			...
		}
	}

Remove above and having simple_node_is_codec(np, xxx) function
or something can help it ?


Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  2020-06-27  4:53   ` Sameer Pujar
  (?)
@ 2020-06-29  1:38       ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:38 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> PCM devices are created for dai links with 'no-pcm' flag as '0'.
> Such DAI links have CPU component which implement pcm_construct()
> and pcm_destruct() callbacks. Based on this, current patch exposes
> a helper function to identify such components and populate 'no_pcm'
> flag for DPCM DAI link.
(snip)
> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
> +{
> +	struct snd_soc_component *component;
> +	struct snd_soc_dai *dai;
> +
> +	for_each_component(component) {
> +		if (!component->driver)
> +			continue;
> +
> +		for_each_component_dais(component, dai) {
> +			if (!dai->name || !dlc->dai_name)
> +				continue;
> +
> +			if (strcmp(dai->name, dlc->dai_name))
> +				continue;


We can/should NULL poinster check for "dlc->dai_name" on top of
this function instead of inside loop ?
And then, we can remove "dai->name" check because next strcmp()
automatically fail if dai->name was NULL.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-06-29  1:38       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:38 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> PCM devices are created for dai links with 'no-pcm' flag as '0'.
> Such DAI links have CPU component which implement pcm_construct()
> and pcm_destruct() callbacks. Based on this, current patch exposes
> a helper function to identify such components and populate 'no_pcm'
> flag for DPCM DAI link.
(snip)
> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
> +{
> +	struct snd_soc_component *component;
> +	struct snd_soc_dai *dai;
> +
> +	for_each_component(component) {
> +		if (!component->driver)
> +			continue;
> +
> +		for_each_component_dais(component, dai) {
> +			if (!dai->name || !dlc->dai_name)
> +				continue;
> +
> +			if (strcmp(dai->name, dlc->dai_name))
> +				continue;


We can/should NULL poinster check for "dlc->dai_name" on top of
this function instead of inside loop ?
And then, we can remove "dai->name" check because next strcmp()
automatically fail if dai->name was NULL.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-06-29  1:38       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:38 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> PCM devices are created for dai links with 'no-pcm' flag as '0'.
> Such DAI links have CPU component which implement pcm_construct()
> and pcm_destruct() callbacks. Based on this, current patch exposes
> a helper function to identify such components and populate 'no_pcm'
> flag for DPCM DAI link.
(snip)
> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
> +{
> +	struct snd_soc_component *component;
> +	struct snd_soc_dai *dai;
> +
> +	for_each_component(component) {
> +		if (!component->driver)
> +			continue;
> +
> +		for_each_component_dais(component, dai) {
> +			if (!dai->name || !dlc->dai_name)
> +				continue;
> +
> +			if (strcmp(dai->name, dlc->dai_name))
> +				continue;


We can/should NULL poinster check for "dlc->dai_name" on top of
this function instead of inside loop ?
And then, we can remove "dai->name" check because next strcmp()
automatically fail if dai->name was NULL.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 16/23] ASoC: soc-pcm: Get all BEs along DAPM path
  2020-06-27  4:53     ` Sameer Pujar
  (?)
@ 2020-06-29  1:41         ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:41 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> dpcm_end_walk_at_be() stops the graph walk when first BE is found for
> the given FE component. In a component model we may want to connect
> multiple DAIs from different components. A new flag is introduced in
> 'snd_soc_card', which when set allows DAI/component chaining. Later
> PCM operations can be called for all these listed components for a
> valid DAPM path.
(snip)
> @@ -1069,6 +1069,7 @@ struct snd_soc_card {
>  	int num_of_dapm_widgets;
>  	const struct snd_soc_dapm_route *of_dapm_routes;
>  	int num_of_dapm_routes;
> +	bool component_chaining;

snd_soc_card has many /* bit field */ variables.
Please use it instead of bool.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 16/23] ASoC: soc-pcm: Get all BEs along DAPM path
@ 2020-06-29  1:41         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:41 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> dpcm_end_walk_at_be() stops the graph walk when first BE is found for
> the given FE component. In a component model we may want to connect
> multiple DAIs from different components. A new flag is introduced in
> 'snd_soc_card', which when set allows DAI/component chaining. Later
> PCM operations can be called for all these listed components for a
> valid DAPM path.
(snip)
> @@ -1069,6 +1069,7 @@ struct snd_soc_card {
>  	int num_of_dapm_widgets;
>  	const struct snd_soc_dapm_route *of_dapm_routes;
>  	int num_of_dapm_routes;
> +	bool component_chaining;

snd_soc_card has many /* bit field */ variables.
Please use it instead of bool.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 16/23] ASoC: soc-pcm: Get all BEs along DAPM path
@ 2020-06-29  1:41         ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-29  1:41 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> dpcm_end_walk_at_be() stops the graph walk when first BE is found for
> the given FE component. In a component model we may want to connect
> multiple DAIs from different components. A new flag is introduced in
> 'snd_soc_card', which when set allows DAI/component chaining. Later
> PCM operations can be called for all these listed components for a
> valid DAPM path.
(snip)
> @@ -1069,6 +1069,7 @@ struct snd_soc_card {
>  	int num_of_dapm_widgets;
>  	const struct snd_soc_dapm_route *of_dapm_routes;
>  	int num_of_dapm_routes;
> +	bool component_chaining;

snd_soc_card has many /* bit field */ variables.
Please use it instead of bool.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
  2020-06-29  0:38         ` Kuninori Morimoto
@ 2020-06-29 15:46           ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 15:46 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/29/2020 6:08 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
> Thank you for your patch
>
> # I guess there was ML registering magic until v3 ?
> # This is 1st time for me to get this patch series...

Until v3 the series was mostly about registering ASoC components. Based 
on the discussions in the previous series and threads, I have updated 
drivers to work with DPCM and added patches for simple-card driver to 
test complete audio path. Yes, simple-card driver patches are new and 
were not part of earlier series. Sorry if I was not clear in the cover 
letter.

Thank you for the review.
>
>> The "prefix" can be defined in DAI link node or it can be specified as
>> part of the component node itself. Currently "sound-name-prefix" defined
>> in a component is not taking effect. Actually the property is not getting
>> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
>> "prefix" is missing in DAI link Codec node.
>>
>> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> (snip)
>> @@ -1111,8 +1111,10 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
>>                struct snd_soc_codec_conf *map = &card->codec_conf[i];
>>
>>                if (snd_soc_is_matching_component(&map->dlc, component)) {
>> -                     component->name_prefix = map->name_prefix;
>> -                     return;
>> +                     if (map->name_prefix) {
>> +                             component->name_prefix = map->name_prefix;
>> +                             return;
>> +                     }
>>                }
>>        }
> This is nit-pick but it can be like this ?
>
>                  if (snd_soc_is_matching_component(&map->dlc, component) &&
>                      map->name_prefix) {
>                          ...
>                  }

Sounds fine. Will update.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
@ 2020-06-29 15:46           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 15:46 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/29/2020 6:08 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
> Thank you for your patch
>
> # I guess there was ML registering magic until v3 ?
> # This is 1st time for me to get this patch series...

Until v3 the series was mostly about registering ASoC components. Based 
on the discussions in the previous series and threads, I have updated 
drivers to work with DPCM and added patches for simple-card driver to 
test complete audio path. Yes, simple-card driver patches are new and 
were not part of earlier series. Sorry if I was not clear in the cover 
letter.

Thank you for the review.
>
>> The "prefix" can be defined in DAI link node or it can be specified as
>> part of the component node itself. Currently "sound-name-prefix" defined
>> in a component is not taking effect. Actually the property is not getting
>> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
>> "prefix" is missing in DAI link Codec node.
>>
>> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> (snip)
>> @@ -1111,8 +1111,10 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
>>                struct snd_soc_codec_conf *map = &card->codec_conf[i];
>>
>>                if (snd_soc_is_matching_component(&map->dlc, component)) {
>> -                     component->name_prefix = map->name_prefix;
>> -                     return;
>> +                     if (map->name_prefix) {
>> +                             component->name_prefix = map->name_prefix;
>> +                             return;
>> +                     }
>>                }
>>        }
> This is nit-pick but it can be like this ?
>
>                  if (snd_soc_is_matching_component(&map->dlc, component) &&
>                      map->name_prefix) {
>                          ...
>                  }

Sounds fine. Will update.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
  2020-06-29  0:56         ` Kuninori Morimoto
  (?)
  (?)
@ 2020-06-29 16:06         ` Sameer Pujar
       [not found]           ` <6e27daa5-331e-968b-4027-2e30aeb7d382-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  -1 siblings, 1 reply; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 16:06 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/29/2020 6:26 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>   simple-audio-card,dai-link@xxx {
>>       format = "i2s";
>>       bitclock-master=<&cpu1>;
>>       frame-master=<&cpu1>;
>>
>>       cpu1: cpu@0 {
>>           ...
>>       };
>>
>>       codec@0 {
>>           ...
>>       };
>>
>>       ...
>>   };
>>
>> In above case CPU is expected to be configured as a master and Codec as
>> a slave device. But both CPU/Codec are being configured as slave devices.
>> This happens because asoc_simple_parse_daifmt() uses Codec reference and
>> sets up the 'dai_link->dai_fmt' accordingly while parsing both CPU and
>> Codec.
> I'm sorry but I don't 100% understand about this case...
> asoc_simple_parse_daifmt() should work in this case
>
> The reason why it needs codec node is that
> SND_SOC_DAIFMT_CBx_CFx are "Codec" base Master/Slave.

Currently soc-core has following code snippet,

/snd_soc_runtime_set_dai_fmt() {//
//     ...//
//
//     if (cpu_dai->component->driver->non_legacy_dai_naming)//
//         fmt = inv_dai_fmt;//
//
//     ...//
// }/

Above flips polarity for 'cpu_dai' if 'non_legacy_dai_naming' flag is set.

1. Hence example mentioned in the commit message does not work if my 
'cpu_dai' driver does not have this flag set.

2. While it is true that we consider reference of 'Codec' mode for 
simple CPU<->Codec DAI links, for DPCM this does not seem flexible. For 
DPCM links CPU and Codec are not directly connected (CPU<->Dummy or 
Dummy<->Codec). Please consider, for example, if the DAI link has 
multiple CPU/Codecs. Which 'Codec' reference needs to be considered? 
Isn't it better if we explicitly mention which DAI we want to operate as 
'Master'?

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
  2020-06-29  1:05         ` Kuninori Morimoto
@ 2020-06-29 16:32           ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 16:32 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/29/2020 6:35 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> CPU/Codec in DPCM DAI links are connected as CPU<->Dummy and Dummy<->Codec.
>> Though mostly CPU won't use/require 'mclk-fs' property, looping over
>> 'np' (current child node in a DAI link) can help in cases where multiple
>> Codecs are defined. This further helps to get rid of 'codec' argument
>> from simple_dai_link_of_dpcm() function, which gets called for DPCM links.
>>
>> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
>> ---
> (snip)
>> diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
>> index 39cdc71..02d6295 100644
>> --- a/sound/soc/generic/simple-card.c
>> +++ b/sound/soc/generic/simple-card.c
>> @@ -107,7 +107,9 @@ static void simple_parse_mclk_fs(struct device_node *top,
>>        snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
>>        of_property_read_u32(node,      prop, &props->mclk_fs);
>>        of_property_read_u32(cpu,       prop, &props->mclk_fs);
>> -     of_property_read_u32(codec,     prop, &props->mclk_fs);
>> +
>> +     if (cpu != codec)
>> +             of_property_read_u32(codec, prop, &props->mclk_fs);
> Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
> without using magical code in simple_parse_mclk_fs() side ?

Are you suggesting if we should simplify simple_parse_mclk_fs() by 
either passing 'cpu' or 'codec'?
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-29 16:32           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 16:32 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/29/2020 6:35 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> CPU/Codec in DPCM DAI links are connected as CPU<->Dummy and Dummy<->Codec.
>> Though mostly CPU won't use/require 'mclk-fs' property, looping over
>> 'np' (current child node in a DAI link) can help in cases where multiple
>> Codecs are defined. This further helps to get rid of 'codec' argument
>> from simple_dai_link_of_dpcm() function, which gets called for DPCM links.
>>
>> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
>> ---
> (snip)
>> diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
>> index 39cdc71..02d6295 100644
>> --- a/sound/soc/generic/simple-card.c
>> +++ b/sound/soc/generic/simple-card.c
>> @@ -107,7 +107,9 @@ static void simple_parse_mclk_fs(struct device_node *top,
>>        snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
>>        of_property_read_u32(node,      prop, &props->mclk_fs);
>>        of_property_read_u32(cpu,       prop, &props->mclk_fs);
>> -     of_property_read_u32(codec,     prop, &props->mclk_fs);
>> +
>> +     if (cpu != codec)
>> +             of_property_read_u32(codec, prop, &props->mclk_fs);
> Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
> without using magical code in simple_parse_mclk_fs() side ?

Are you suggesting if we should simplify simple_parse_mclk_fs() by 
either passing 'cpu' or 'codec'?
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-29  1:24         ` Kuninori Morimoto
@ 2020-06-29 17:16           ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 17:16 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/29/2020 6:54 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> The simple-card driver supports multiple CPU and single Codec entries
>> for DPCM DAI links. In some cases it is required to have multiple
>> CPU/Codecs. Currently parsing logic for DPCM link loops over all
>> children of DAI link but assumes that there is a single Codec entry.
>> When DAI link has multiple Codecs it considers only the first Codec
>> entry and remaining Codecs are wrongly treated as CPU. This happens
>> because first Codec is used as reference for parsing all other child
>> nodes.
> (snip)
>> @@ -137,8 +136,13 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
>>         * Codec |return|Pass
>>         * np
>>         */
>> -     if (li->cpu == (np == codec))
>> -             return 0;
>> +     if (li->cpu) {
>> +             if (!strcmp(np->name, "codec"))
>> +                     return 0;
>> +     } else {
>> +             if (!strcmp(np->name, "cpu"))
>> +                     return 0;
>> +     }
> Checking node name is maybe nice idea,
> but please consider "prefix" here.

Sorry I missed that example where DAI is defined at sound level. I will 
update.
>
> Maybe base issue for multiple codec support
> is that simple_for_each_link() is caring first codec only ?

Yes that is true.
>
>          simple_for_each_link(...)
>          {
>                  ...
>                  do {
> =>                      /* get codec */
> =>                      codec = of_get_child_by_name(...);
>                          ...
>                  }
>          }
>
> Remove above and having simple_node_is_codec(np, xxx) function
> or something can help it ?

Ideally I wanted to remove above two lines and allow empty codec list. 
But some users may expect the parsing to fail if no 'Codec' is found in 
the DAI link, hence did not remove above. If it is fine to remove above 
two lines it would be simpler. The loop inside simple_for_each_link() 
would anyway loop for each child node of DAI link and 
simple_dai_link_of_dpcm() can parse each 'np'.
>
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-29 17:16           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 17:16 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/29/2020 6:54 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> The simple-card driver supports multiple CPU and single Codec entries
>> for DPCM DAI links. In some cases it is required to have multiple
>> CPU/Codecs. Currently parsing logic for DPCM link loops over all
>> children of DAI link but assumes that there is a single Codec entry.
>> When DAI link has multiple Codecs it considers only the first Codec
>> entry and remaining Codecs are wrongly treated as CPU. This happens
>> because first Codec is used as reference for parsing all other child
>> nodes.
> (snip)
>> @@ -137,8 +136,13 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
>>         * Codec |return|Pass
>>         * np
>>         */
>> -     if (li->cpu == (np == codec))
>> -             return 0;
>> +     if (li->cpu) {
>> +             if (!strcmp(np->name, "codec"))
>> +                     return 0;
>> +     } else {
>> +             if (!strcmp(np->name, "cpu"))
>> +                     return 0;
>> +     }
> Checking node name is maybe nice idea,
> but please consider "prefix" here.

Sorry I missed that example where DAI is defined at sound level. I will 
update.
>
> Maybe base issue for multiple codec support
> is that simple_for_each_link() is caring first codec only ?

Yes that is true.
>
>          simple_for_each_link(...)
>          {
>                  ...
>                  do {
> =>                      /* get codec */
> =>                      codec = of_get_child_by_name(...);
>                          ...
>                  }
>          }
>
> Remove above and having simple_node_is_codec(np, xxx) function
> or something can help it ?

Ideally I wanted to remove above two lines and allow empty codec list. 
But some users may expect the parsing to fail if no 'Codec' is found in 
the DAI link, hence did not remove above. If it is fine to remove above 
two lines it would be simpler. The loop inside simple_for_each_link() 
would anyway loop for each child node of DAI link and 
simple_dai_link_of_dpcm() can parse each 'np'.
>
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  2020-06-29  1:38       ` Kuninori Morimoto
@ 2020-06-29 17:19         ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 17:19 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/29/2020 7:08 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> PCM devices are created for dai links with 'no-pcm' flag as '0'.
>> Such DAI links have CPU component which implement pcm_construct()
>> and pcm_destruct() callbacks. Based on this, current patch exposes
>> a helper function to identify such components and populate 'no_pcm'
>> flag for DPCM DAI link.
> (snip)
>> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
>> +{
>> +     struct snd_soc_component *component;
>> +     struct snd_soc_dai *dai;
>> +
>> +     for_each_component(component) {
>> +             if (!component->driver)
>> +                     continue;
>> +
>> +             for_each_component_dais(component, dai) {
>> +                     if (!dai->name || !dlc->dai_name)
>> +                             continue;
>> +
>> +                     if (strcmp(dai->name, dlc->dai_name))
>> +                             continue;
>
> We can/should NULL poinster check for "dlc->dai_name" on top of
> this function instead of inside loop ?
> And then, we can remove "dai->name" check because next strcmp()
> automatically fail if dai->name was NULL.

Sounds good, will update.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-06-29 17:19         ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 17:19 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/29/2020 7:08 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> PCM devices are created for dai links with 'no-pcm' flag as '0'.
>> Such DAI links have CPU component which implement pcm_construct()
>> and pcm_destruct() callbacks. Based on this, current patch exposes
>> a helper function to identify such components and populate 'no_pcm'
>> flag for DPCM DAI link.
> (snip)
>> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
>> +{
>> +     struct snd_soc_component *component;
>> +     struct snd_soc_dai *dai;
>> +
>> +     for_each_component(component) {
>> +             if (!component->driver)
>> +                     continue;
>> +
>> +             for_each_component_dais(component, dai) {
>> +                     if (!dai->name || !dlc->dai_name)
>> +                             continue;
>> +
>> +                     if (strcmp(dai->name, dlc->dai_name))
>> +                             continue;
>
> We can/should NULL poinster check for "dlc->dai_name" on top of
> this function instead of inside loop ?
> And then, we can remove "dai->name" check because next strcmp()
> automatically fail if dai->name was NULL.

Sounds good, will update.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 16/23] ASoC: soc-pcm: Get all BEs along DAPM path
  2020-06-29  1:41         ` Kuninori Morimoto
@ 2020-06-29 17:29           ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 17:29 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/29/2020 7:11 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> dpcm_end_walk_at_be() stops the graph walk when first BE is found for
>> the given FE component. In a component model we may want to connect
>> multiple DAIs from different components. A new flag is introduced in
>> 'snd_soc_card', which when set allows DAI/component chaining. Later
>> PCM operations can be called for all these listed components for a
>> valid DAPM path.
> (snip)
>> @@ -1069,6 +1069,7 @@ struct snd_soc_card {
>>        int num_of_dapm_widgets;
>>        const struct snd_soc_dapm_route *of_dapm_routes;
>>        int num_of_dapm_routes;
>> +     bool component_chaining;
> snd_soc_card has many /* bit field */ variables.
> Please use it instead of bool.

OK, will use.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 16/23] ASoC: soc-pcm: Get all BEs along DAPM path
@ 2020-06-29 17:29           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-29 17:29 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/29/2020 7:11 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> dpcm_end_walk_at_be() stops the graph walk when first BE is found for
>> the given FE component. In a component model we may want to connect
>> multiple DAIs from different components. A new flag is introduced in
>> 'snd_soc_card', which when set allows DAI/component chaining. Later
>> PCM operations can be called for all these listed components for a
>> valid DAPM path.
> (snip)
>> @@ -1069,6 +1069,7 @@ struct snd_soc_card {
>>        int num_of_dapm_widgets;
>>        const struct snd_soc_dapm_route *of_dapm_routes;
>>        int num_of_dapm_routes;
>> +     bool component_chaining;
> snd_soc_card has many /* bit field */ variables.
> Please use it instead of bool.

OK, will use.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
  2020-06-29 16:06         ` Sameer Pujar
       [not found]           ` <6e27daa5-331e-968b-4027-2e30aeb7d382-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2020-06-30  0:56               ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  0:56 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

>  snd_soc_runtime_set_dai_fmt() {
>      ...
> 
>      if (cpu_dai->component->driver->non_legacy_dai_naming)
>          fmt = inv_dai_fmt;
> 
>      ...
>  }
> 
> Above flips polarity for 'cpu_dai' if 'non_legacy_dai_naming' flag is set.
> 
> 1. Hence example mentioned in the commit message does not work if my 'cpu_dai'
> driver does not have this flag set.

?
Do you want fo flip it ? or don't flip?
It is for Codec <-> Codec connection.

> 2. While it is true that we consider reference of 'Codec' mode for simple CPU<->
> Codec DAI links, for DPCM this does not seem flexible. For DPCM links CPU and
> Codec are not directly connected (CPU<->Dummy or Dummy<->Codec). Please
> consider, for example, if the DAI link has multiple CPU/Codecs. Which 'Codec'
> reference needs to be considered? Isn't it better if we explicitly mention which
> DAI we want to operate as 'Master'?

I think Lars-Peter has (had ?) plan for this SND_SOC_DAIFMT_CBx_CFx
flag flexibility ? Yes maybe it is needed for multi CPU/Codec system.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-30  0:56               ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  0:56 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

>  snd_soc_runtime_set_dai_fmt() {
>      ...
> 
>      if (cpu_dai->component->driver->non_legacy_dai_naming)
>          fmt = inv_dai_fmt;
> 
>      ...
>  }
> 
> Above flips polarity for 'cpu_dai' if 'non_legacy_dai_naming' flag is set.
> 
> 1. Hence example mentioned in the commit message does not work if my 'cpu_dai'
> driver does not have this flag set.

?
Do you want fo flip it ? or don't flip?
It is for Codec <-> Codec connection.

> 2. While it is true that we consider reference of 'Codec' mode for simple CPU<->
> Codec DAI links, for DPCM this does not seem flexible. For DPCM links CPU and
> Codec are not directly connected (CPU<->Dummy or Dummy<->Codec). Please
> consider, for example, if the DAI link has multiple CPU/Codecs. Which 'Codec'
> reference needs to be considered? Isn't it better if we explicitly mention which
> DAI we want to operate as 'Master'?

I think Lars-Peter has (had ?) plan for this SND_SOC_DAIFMT_CBx_CFx
flag flexibility ? Yes maybe it is needed for multi CPU/Codec system.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-30  0:56               ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  0:56 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

>  snd_soc_runtime_set_dai_fmt() {
>      ...
> 
>      if (cpu_dai->component->driver->non_legacy_dai_naming)
>          fmt = inv_dai_fmt;
> 
>      ...
>  }
> 
> Above flips polarity for 'cpu_dai' if 'non_legacy_dai_naming' flag is set.
> 
> 1. Hence example mentioned in the commit message does not work if my 'cpu_dai'
> driver does not have this flag set.

?
Do you want fo flip it ? or don't flip?
It is for Codec <-> Codec connection.

> 2. While it is true that we consider reference of 'Codec' mode for simple CPU<->
> Codec DAI links, for DPCM this does not seem flexible. For DPCM links CPU and
> Codec are not directly connected (CPU<->Dummy or Dummy<->Codec). Please
> consider, for example, if the DAI link has multiple CPU/Codecs. Which 'Codec'
> reference needs to be considered? Isn't it better if we explicitly mention which
> DAI we want to operate as 'Master'?

I think Lars-Peter has (had ?) plan for this SND_SOC_DAIFMT_CBx_CFx
flag flexibility ? Yes maybe it is needed for multi CPU/Codec system.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-29 17:16           ` Sameer Pujar
  (?)
@ 2020-06-30  1:24               ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  1:24 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> > Maybe base issue for multiple codec support
> > is that simple_for_each_link() is caring first codec only ?
(snip)
> Ideally I wanted to remove above two lines and allow empty codec
> list. But some users may expect the parsing to fail if no 'Codec' is
> found in the DAI link, hence did not remove above. If it is fine to
> remove above two lines it would be simpler. The loop inside
> simple_for_each_link() would anyway loop for each child node of DAI
> link and simple_dai_link_of_dpcm() can parse each 'np'.

Current simple-card is not assuming multi Codec,
thus, we need to update it correctly, not quick-hack.

I'm not sure how to do it, but it seems we need to update
many functions to support it, not only simple-card driver.
For example, simple-card-utils, soc-core, etc, etc...

I'm not sure, this is just my guess.
I'm happy if we can support it more easily :)

But, if it was difficult to keep compatibility on simple-card,
we/you need to have new one.
Actually, I had a plan to create more flexible sound card
driver, but it is not hi priority for me in these days.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30  1:24               ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  1:24 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> > Maybe base issue for multiple codec support
> > is that simple_for_each_link() is caring first codec only ?
(snip)
> Ideally I wanted to remove above two lines and allow empty codec
> list. But some users may expect the parsing to fail if no 'Codec' is
> found in the DAI link, hence did not remove above. If it is fine to
> remove above two lines it would be simpler. The loop inside
> simple_for_each_link() would anyway loop for each child node of DAI
> link and simple_dai_link_of_dpcm() can parse each 'np'.

Current simple-card is not assuming multi Codec,
thus, we need to update it correctly, not quick-hack.

I'm not sure how to do it, but it seems we need to update
many functions to support it, not only simple-card driver.
For example, simple-card-utils, soc-core, etc, etc...

I'm not sure, this is just my guess.
I'm happy if we can support it more easily :)

But, if it was difficult to keep compatibility on simple-card,
we/you need to have new one.
Actually, I had a plan to create more flexible sound card
driver, but it is not hi priority for me in these days.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30  1:24               ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  1:24 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> > Maybe base issue for multiple codec support
> > is that simple_for_each_link() is caring first codec only ?
(snip)
> Ideally I wanted to remove above two lines and allow empty codec
> list. But some users may expect the parsing to fail if no 'Codec' is
> found in the DAI link, hence did not remove above. If it is fine to
> remove above two lines it would be simpler. The loop inside
> simple_for_each_link() would anyway loop for each child node of DAI
> link and simple_dai_link_of_dpcm() can parse each 'np'.

Current simple-card is not assuming multi Codec,
thus, we need to update it correctly, not quick-hack.

I'm not sure how to do it, but it seems we need to update
many functions to support it, not only simple-card driver.
For example, simple-card-utils, soc-core, etc, etc...

I'm not sure, this is just my guess.
I'm happy if we can support it more easily :)

But, if it was difficult to keep compatibility on simple-card,
we/you need to have new one.
Actually, I had a plan to create more flexible sound card
driver, but it is not hi priority for me in these days.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
  2020-06-29 16:32           ` Sameer Pujar
  (?)
@ 2020-06-30  2:08               ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  2:08 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> >>        snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
> >>        of_property_read_u32(node,      prop, &props->mclk_fs);
> >>        of_property_read_u32(cpu,       prop, &props->mclk_fs);
> >> -     of_property_read_u32(codec,     prop, &props->mclk_fs);
> >> +
> >> +     if (cpu != codec)
> >> +             of_property_read_u32(codec, prop, &props->mclk_fs);
> > Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
> > without using magical code in simple_parse_mclk_fs() side ?
> 
> Are you suggesting if we should simplify simple_parse_mclk_fs() by
> either passing 'cpu' or 'codec'?

Oops, sorry I was misunderstand.

But I still not 100% understand what do you want to do here.
Maybe 50% is my English skill, but in your code
 
(C)	 	of_property_read_u32(cpu,	prop, &props->mclk_fs);
	-	of_property_read_u32(codec,	prop, &props->mclk_fs);
	+
	+	if (cpu != codec)
(B)	+		of_property_read_u32(codec, prop, &props->mclk_fs);

and

	-	simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
(A)	+	simple_parse_mclk_fs(top, np, np, dai_props, prefix);

Because of (A), cpu = codec = np in simple_parse_mclk_fs().
Do we have chance to call (B) ?
And it still have read_u32(cpu, ...) at (C),
this means all np will read mclk_fs anyway ?
For me, if you don't want/need mclk_fs, don't set it on DT
is the best answer, but am I misunderstanding ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-30  2:08               ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  2:08 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> >>        snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
> >>        of_property_read_u32(node,      prop, &props->mclk_fs);
> >>        of_property_read_u32(cpu,       prop, &props->mclk_fs);
> >> -     of_property_read_u32(codec,     prop, &props->mclk_fs);
> >> +
> >> +     if (cpu != codec)
> >> +             of_property_read_u32(codec, prop, &props->mclk_fs);
> > Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
> > without using magical code in simple_parse_mclk_fs() side ?
> 
> Are you suggesting if we should simplify simple_parse_mclk_fs() by
> either passing 'cpu' or 'codec'?

Oops, sorry I was misunderstand.

But I still not 100% understand what do you want to do here.
Maybe 50% is my English skill, but in your code
 
(C)	 	of_property_read_u32(cpu,	prop, &props->mclk_fs);
	-	of_property_read_u32(codec,	prop, &props->mclk_fs);
	+
	+	if (cpu != codec)
(B)	+		of_property_read_u32(codec, prop, &props->mclk_fs);

and

	-	simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
(A)	+	simple_parse_mclk_fs(top, np, np, dai_props, prefix);

Because of (A), cpu = codec = np in simple_parse_mclk_fs().
Do we have chance to call (B) ?
And it still have read_u32(cpu, ...) at (C),
this means all np will read mclk_fs anyway ?
For me, if you don't want/need mclk_fs, don't set it on DT
is the best answer, but am I misunderstanding ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-30  2:08               ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  2:08 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> >>        snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
> >>        of_property_read_u32(node,      prop, &props->mclk_fs);
> >>        of_property_read_u32(cpu,       prop, &props->mclk_fs);
> >> -     of_property_read_u32(codec,     prop, &props->mclk_fs);
> >> +
> >> +     if (cpu != codec)
> >> +             of_property_read_u32(codec, prop, &props->mclk_fs);
> > Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
> > without using magical code in simple_parse_mclk_fs() side ?
> 
> Are you suggesting if we should simplify simple_parse_mclk_fs() by
> either passing 'cpu' or 'codec'?

Oops, sorry I was misunderstand.

But I still not 100% understand what do you want to do here.
Maybe 50% is my English skill, but in your code
 
(C)	 	of_property_read_u32(cpu,	prop, &props->mclk_fs);
	-	of_property_read_u32(codec,	prop, &props->mclk_fs);
	+
	+	if (cpu != codec)
(B)	+		of_property_read_u32(codec, prop, &props->mclk_fs);

and

	-	simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
(A)	+	simple_parse_mclk_fs(top, np, np, dai_props, prefix);

Because of (A), cpu = codec = np in simple_parse_mclk_fs().
Do we have chance to call (B) ?
And it still have read_u32(cpu, ...) at (C),
this means all np will read mclk_fs anyway ?
For me, if you don't want/need mclk_fs, don't set it on DT
is the best answer, but am I misunderstanding ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
  2020-06-30  0:56               ` Kuninori Morimoto
  (?)
@ 2020-06-30  3:47                   ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  3:47 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 6/30/2020 6:26 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>   snd_soc_runtime_set_dai_fmt() {
>>       ...
>>
>>       if (cpu_dai->component->driver->non_legacy_dai_naming)
>>           fmt = inv_dai_fmt;
>>
>>       ...
>>   }
>>
>> Above flips polarity for 'cpu_dai' if 'non_legacy_dai_naming' flag is set.
>>
>> 1. Hence example mentioned in the commit message does not work if my 'cpu_dai'
>> driver does not have this flag set.
> ?
> Do you want fo flip it ? or don't flip?
> It is for Codec <-> Codec connection.

For DPCM links I don't want to flip based on one Codec reference. My 
goal was to make the binding work for multiple CPU/Codec link. Hence I 
thought it would be better to explicitly describe the 'Master' DAI. We 
can eventually get rid of 'codec' argument from simple_dai_link_of_dpcm().
>> 2. While it is true that we consider reference of 'Codec' mode for simple CPU<->
>> Codec DAI links, for DPCM this does not seem flexible. For DPCM links CPU and
>> Codec are not directly connected (CPU<->Dummy or Dummy<->Codec). Please
>> consider, for example, if the DAI link has multiple CPU/Codecs. Which 'Codec'
>> reference needs to be considered? Isn't it better if we explicitly mention which
>> DAI we want to operate as 'Master'?
> I think Lars-Peter has (had ?) plan for this SND_SOC_DAIFMT_CBx_CFx
> flag flexibility ? Yes maybe it is needed for multi CPU/Codec system.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-30  3:47                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  3:47 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 6:26 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>   snd_soc_runtime_set_dai_fmt() {
>>       ...
>>
>>       if (cpu_dai->component->driver->non_legacy_dai_naming)
>>           fmt = inv_dai_fmt;
>>
>>       ...
>>   }
>>
>> Above flips polarity for 'cpu_dai' if 'non_legacy_dai_naming' flag is set.
>>
>> 1. Hence example mentioned in the commit message does not work if my 'cpu_dai'
>> driver does not have this flag set.
> ?
> Do you want fo flip it ? or don't flip?
> It is for Codec <-> Codec connection.

For DPCM links I don't want to flip based on one Codec reference. My 
goal was to make the binding work for multiple CPU/Codec link. Hence I 
thought it would be better to explicitly describe the 'Master' DAI. We 
can eventually get rid of 'codec' argument from simple_dai_link_of_dpcm().
>> 2. While it is true that we consider reference of 'Codec' mode for simple CPU<->
>> Codec DAI links, for DPCM this does not seem flexible. For DPCM links CPU and
>> Codec are not directly connected (CPU<->Dummy or Dummy<->Codec). Please
>> consider, for example, if the DAI link has multiple CPU/Codecs. Which 'Codec'
>> reference needs to be considered? Isn't it better if we explicitly mention which
>> DAI we want to operate as 'Master'?
> I think Lars-Peter has (had ?) plan for this SND_SOC_DAIFMT_CBx_CFx
> flag flexibility ? Yes maybe it is needed for multi CPU/Codec system.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-30  3:47                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  3:47 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 6:26 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>   snd_soc_runtime_set_dai_fmt() {
>>       ...
>>
>>       if (cpu_dai->component->driver->non_legacy_dai_naming)
>>           fmt = inv_dai_fmt;
>>
>>       ...
>>   }
>>
>> Above flips polarity for 'cpu_dai' if 'non_legacy_dai_naming' flag is set.
>>
>> 1. Hence example mentioned in the commit message does not work if my 'cpu_dai'
>> driver does not have this flag set.
> ?
> Do you want fo flip it ? or don't flip?
> It is for Codec <-> Codec connection.

For DPCM links I don't want to flip based on one Codec reference. My 
goal was to make the binding work for multiple CPU/Codec link. Hence I 
thought it would be better to explicitly describe the 'Master' DAI. We 
can eventually get rid of 'codec' argument from simple_dai_link_of_dpcm().
>> 2. While it is true that we consider reference of 'Codec' mode for simple CPU<->
>> Codec DAI links, for DPCM this does not seem flexible. For DPCM links CPU and
>> Codec are not directly connected (CPU<->Dummy or Dummy<->Codec). Please
>> consider, for example, if the DAI link has multiple CPU/Codecs. Which 'Codec'
>> reference needs to be considered? Isn't it better if we explicitly mention which
>> DAI we want to operate as 'Master'?
> I think Lars-Peter has (had ?) plan for this SND_SOC_DAIFMT_CBx_CFx
> flag flexibility ? Yes maybe it is needed for multi CPU/Codec system.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-30  1:24               ` Kuninori Morimoto
  (?)
@ 2020-06-30  4:08                   ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  4:08 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 6/30/2020 6:54 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>> Maybe base issue for multiple codec support
>>> is that simple_for_each_link() is caring first codec only ?
> (snip)
>> Ideally I wanted to remove above two lines and allow empty codec
>> list. But some users may expect the parsing to fail if no 'Codec' is
>> found in the DAI link, hence did not remove above. If it is fine to
>> remove above two lines it would be simpler. The loop inside
>> simple_for_each_link() would anyway loop for each child node of DAI
>> link and simple_dai_link_of_dpcm() can parse each 'np'.

> Current simple-card is not assuming multi Codec,
> thus, we need to update it correctly, not quick-hack.
>
> I'm not sure how to do it, but it seems we need to update
> many functions to support it, not only simple-card driver.
> For example, simple-card-utils, soc-core, etc, etc...
>
> I'm not sure, this is just my guess.
> I'm happy if we can support it more easily :)
Right now I am trying re-use simple-card driver as much as possible and 
still make it work for flexible sound cards. I will be happy to discuss 
and improve the patch wherever necessary. Please help me understand 
which part you think looks to be hacky.

> But, if it was difficult to keep compatibility on simple-card,
> we/you need to have new one.
Patch 17/23 and 18/23 introduce new compatible 'simple-cc-audio-card'. 
Idea was to use component chaining which allows connection of FE<->BE 
and multiple BE<->BE components along the DAPM path (patch 16/23). Do 
you think it would be fine?

> Actually, I had a plan to create more flexible sound card
> driver, but it is not hi priority for me in these days.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30  4:08                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  4:08 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 6:54 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>> Maybe base issue for multiple codec support
>>> is that simple_for_each_link() is caring first codec only ?
> (snip)
>> Ideally I wanted to remove above two lines and allow empty codec
>> list. But some users may expect the parsing to fail if no 'Codec' is
>> found in the DAI link, hence did not remove above. If it is fine to
>> remove above two lines it would be simpler. The loop inside
>> simple_for_each_link() would anyway loop for each child node of DAI
>> link and simple_dai_link_of_dpcm() can parse each 'np'.

> Current simple-card is not assuming multi Codec,
> thus, we need to update it correctly, not quick-hack.
>
> I'm not sure how to do it, but it seems we need to update
> many functions to support it, not only simple-card driver.
> For example, simple-card-utils, soc-core, etc, etc...
>
> I'm not sure, this is just my guess.
> I'm happy if we can support it more easily :)
Right now I am trying re-use simple-card driver as much as possible and 
still make it work for flexible sound cards. I will be happy to discuss 
and improve the patch wherever necessary. Please help me understand 
which part you think looks to be hacky.

> But, if it was difficult to keep compatibility on simple-card,
> we/you need to have new one.
Patch 17/23 and 18/23 introduce new compatible 'simple-cc-audio-card'. 
Idea was to use component chaining which allows connection of FE<->BE 
and multiple BE<->BE components along the DAPM path (patch 16/23). Do 
you think it would be fine?

> Actually, I had a plan to create more flexible sound card
> driver, but it is not hi priority for me in these days.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30  4:08                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  4:08 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 6:54 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>> Maybe base issue for multiple codec support
>>> is that simple_for_each_link() is caring first codec only ?
> (snip)
>> Ideally I wanted to remove above two lines and allow empty codec
>> list. But some users may expect the parsing to fail if no 'Codec' is
>> found in the DAI link, hence did not remove above. If it is fine to
>> remove above two lines it would be simpler. The loop inside
>> simple_for_each_link() would anyway loop for each child node of DAI
>> link and simple_dai_link_of_dpcm() can parse each 'np'.

> Current simple-card is not assuming multi Codec,
> thus, we need to update it correctly, not quick-hack.
>
> I'm not sure how to do it, but it seems we need to update
> many functions to support it, not only simple-card driver.
> For example, simple-card-utils, soc-core, etc, etc...
>
> I'm not sure, this is just my guess.
> I'm happy if we can support it more easily :)
Right now I am trying re-use simple-card driver as much as possible and 
still make it work for flexible sound cards. I will be happy to discuss 
and improve the patch wherever necessary. Please help me understand 
which part you think looks to be hacky.

> But, if it was difficult to keep compatibility on simple-card,
> we/you need to have new one.
Patch 17/23 and 18/23 introduce new compatible 'simple-cc-audio-card'. 
Idea was to use component chaining which allows connection of FE<->BE 
and multiple BE<->BE components along the DAPM path (patch 16/23). Do 
you think it would be fine?

> Actually, I had a plan to create more flexible sound card
> driver, but it is not hi priority for me in these days.
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
  2020-06-30  2:08               ` Kuninori Morimoto
  (?)
@ 2020-06-30  4:23                   ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  4:23 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 6/30/2020 7:38 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>>>         snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
>>>>         of_property_read_u32(node,      prop, &props->mclk_fs);
>>>>         of_property_read_u32(cpu,       prop, &props->mclk_fs);
>>>> -     of_property_read_u32(codec,     prop, &props->mclk_fs);
>>>> +
>>>> +     if (cpu != codec)
>>>> +             of_property_read_u32(codec, prop, &props->mclk_fs);
>>> Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
>>> without using magical code in simple_parse_mclk_fs() side ?
>> Are you suggesting if we should simplify simple_parse_mclk_fs() by
>> either passing 'cpu' or 'codec'?
> Oops, sorry I was misunderstand.
>
> But I still not 100% understand what do you want to do here.
> Maybe 50% is my English skill, but in your code
>
> (C)             of_property_read_u32(cpu,       prop, &props->mclk_fs);
>          -       of_property_read_u32(codec,     prop, &props->mclk_fs);
>          +
>          +       if (cpu != codec)
> (B)     +               of_property_read_u32(codec, prop, &props->mclk_fs);
>
> and
>
>          -       simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
> (A)     +       simple_parse_mclk_fs(top, np, np, dai_props, prefix);
>
> Because of (A), cpu = codec = np in simple_parse_mclk_fs().
> Do we have chance to call (B) ?
> And it still have read_u32(cpu, ...) at (C),
> this means all np will read mclk_fs anyway ?
> For me, if you don't want/need mclk_fs, don't set it on DT
> is the best answer, but am I misunderstanding ?
Sorry if I was not clear before.

My goal was to get rid of 'codec' argument from DPCM function 
simple_dai_link_of_dpcm(). Patches 10/23, 11/23 are preparations for 
12/23 to have multiple Codec support.

simple_parse_mclk_fs() is used by both simple_dai_link_of_dpcm() and 
simple_dai_link_of(). To make the same API work for both the cases, I 
had to use (A) in DPCM function. Now (B) does not get used for 
simple_dai_link_of_dpcm(), but will get used by simple_dai_link_of().

If it is simpler I will just avoid 'cpu != codec' check and keep the 
function simple_parse_mclk_fs() as it is.

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-30  4:23                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  4:23 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 7:38 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>>>         snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
>>>>         of_property_read_u32(node,      prop, &props->mclk_fs);
>>>>         of_property_read_u32(cpu,       prop, &props->mclk_fs);
>>>> -     of_property_read_u32(codec,     prop, &props->mclk_fs);
>>>> +
>>>> +     if (cpu != codec)
>>>> +             of_property_read_u32(codec, prop, &props->mclk_fs);
>>> Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
>>> without using magical code in simple_parse_mclk_fs() side ?
>> Are you suggesting if we should simplify simple_parse_mclk_fs() by
>> either passing 'cpu' or 'codec'?
> Oops, sorry I was misunderstand.
>
> But I still not 100% understand what do you want to do here.
> Maybe 50% is my English skill, but in your code
>
> (C)             of_property_read_u32(cpu,       prop, &props->mclk_fs);
>          -       of_property_read_u32(codec,     prop, &props->mclk_fs);
>          +
>          +       if (cpu != codec)
> (B)     +               of_property_read_u32(codec, prop, &props->mclk_fs);
>
> and
>
>          -       simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
> (A)     +       simple_parse_mclk_fs(top, np, np, dai_props, prefix);
>
> Because of (A), cpu = codec = np in simple_parse_mclk_fs().
> Do we have chance to call (B) ?
> And it still have read_u32(cpu, ...) at (C),
> this means all np will read mclk_fs anyway ?
> For me, if you don't want/need mclk_fs, don't set it on DT
> is the best answer, but am I misunderstanding ?
Sorry if I was not clear before.

My goal was to get rid of 'codec' argument from DPCM function 
simple_dai_link_of_dpcm(). Patches 10/23, 11/23 are preparations for 
12/23 to have multiple Codec support.

simple_parse_mclk_fs() is used by both simple_dai_link_of_dpcm() and 
simple_dai_link_of(). To make the same API work for both the cases, I 
had to use (A) in DPCM function. Now (B) does not get used for 
simple_dai_link_of_dpcm(), but will get used by simple_dai_link_of().

If it is simpler I will just avoid 'cpu != codec' check and keep the 
function simple_parse_mclk_fs() as it is.

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-30  4:23                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  4:23 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 7:38 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>>>         snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
>>>>         of_property_read_u32(node,      prop, &props->mclk_fs);
>>>>         of_property_read_u32(cpu,       prop, &props->mclk_fs);
>>>> -     of_property_read_u32(codec,     prop, &props->mclk_fs);
>>>> +
>>>> +     if (cpu != codec)
>>>> +             of_property_read_u32(codec, prop, &props->mclk_fs);
>>> Maybe we want to have "cpu" in simple_dai_link_of_dpcm() side
>>> without using magical code in simple_parse_mclk_fs() side ?
>> Are you suggesting if we should simplify simple_parse_mclk_fs() by
>> either passing 'cpu' or 'codec'?
> Oops, sorry I was misunderstand.
>
> But I still not 100% understand what do you want to do here.
> Maybe 50% is my English skill, but in your code
>
> (C)             of_property_read_u32(cpu,       prop, &props->mclk_fs);
>          -       of_property_read_u32(codec,     prop, &props->mclk_fs);
>          +
>          +       if (cpu != codec)
> (B)     +               of_property_read_u32(codec, prop, &props->mclk_fs);
>
> and
>
>          -       simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
> (A)     +       simple_parse_mclk_fs(top, np, np, dai_props, prefix);
>
> Because of (A), cpu = codec = np in simple_parse_mclk_fs().
> Do we have chance to call (B) ?
> And it still have read_u32(cpu, ...) at (C),
> this means all np will read mclk_fs anyway ?
> For me, if you don't want/need mclk_fs, don't set it on DT
> is the best answer, but am I misunderstanding ?
Sorry if I was not clear before.

My goal was to get rid of 'codec' argument from DPCM function 
simple_dai_link_of_dpcm(). Patches 10/23, 11/23 are preparations for 
12/23 to have multiple Codec support.

simple_parse_mclk_fs() is used by both simple_dai_link_of_dpcm() and 
simple_dai_link_of(). To make the same API work for both the cases, I 
had to use (A) in DPCM function. Now (B) does not get used for 
simple_dai_link_of_dpcm(), but will get used by simple_dai_link_of().

If it is simpler I will just avoid 'cpu != codec' check and keep the 
function simple_parse_mclk_fs() as it is.

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
  2020-06-30  3:47                   ` Sameer Pujar
  (?)
@ 2020-06-30  5:07                       ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  5:07 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> For DPCM links I don't want to flip based on one Codec reference. My
> goal was to make the binding work for multiple CPU/Codec link. Hence I
> thought it would be better to explicitly describe the 'Master' DAI. We
> can eventually get rid of 'codec' argument from
> simple_dai_link_of_dpcm().

Yes. 'codec' argument on current simple_dai_link_of_dpcm()
is not good match for multi Codec support.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-30  5:07                       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  5:07 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> For DPCM links I don't want to flip based on one Codec reference. My
> goal was to make the binding work for multiple CPU/Codec link. Hence I
> thought it would be better to explicitly describe the 'Master' DAI. We
> can eventually get rid of 'codec' argument from
> simple_dai_link_of_dpcm().

Yes. 'codec' argument on current simple_dai_link_of_dpcm()
is not good match for multi Codec support.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link
@ 2020-06-30  5:07                       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  5:07 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> For DPCM links I don't want to flip based on one Codec reference. My
> goal was to make the binding work for multiple CPU/Codec link. Hence I
> thought it would be better to explicitly describe the 'Master' DAI. We
> can eventually get rid of 'codec' argument from
> simple_dai_link_of_dpcm().

Yes. 'codec' argument on current simple_dai_link_of_dpcm()
is not good match for multi Codec support.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  2020-06-27  4:53   ` Sameer Pujar
  (?)
@ 2020-06-30  6:07       ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  6:07 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> PCM devices are created for dai links with 'no-pcm' flag as '0'.
> Such DAI links have CPU component which implement pcm_construct()
> and pcm_destruct() callbacks. Based on this, current patch exposes
> a helper function to identify such components and populate 'no_pcm'
> flag for DPCM DAI link.
> 
> This helps to have BE<->BE component links where PCM devices need
> not be created for CPU components involved in the links.
> 
> Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
> ---
(snip)
> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
> +{
> +	struct snd_soc_component *component;
> +	struct snd_soc_dai *dai;
> +
> +	for_each_component(component) {
> +		if (!component->driver)
> +			continue;
> +
> +		for_each_component_dais(component, dai) {
> +			if (!dai->name || !dlc->dai_name)
> +				continue;
> +
> +			if (strcmp(dai->name, dlc->dai_name))
> +				continue;
> +
> +			if (component->driver->pcm_construct)
> +				return true;
> +		}
> +	}
> +
> +	return false;
> +}

At least my CPU driver doesn't use component:pcm_construct
but is using DAI:pcm_new for some reasons.
I'm not sure checking DAI:pcm here is enough, or not...

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-06-30  6:07       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  6:07 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> PCM devices are created for dai links with 'no-pcm' flag as '0'.
> Such DAI links have CPU component which implement pcm_construct()
> and pcm_destruct() callbacks. Based on this, current patch exposes
> a helper function to identify such components and populate 'no_pcm'
> flag for DPCM DAI link.
> 
> This helps to have BE<->BE component links where PCM devices need
> not be created for CPU components involved in the links.
> 
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> ---
(snip)
> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
> +{
> +	struct snd_soc_component *component;
> +	struct snd_soc_dai *dai;
> +
> +	for_each_component(component) {
> +		if (!component->driver)
> +			continue;
> +
> +		for_each_component_dais(component, dai) {
> +			if (!dai->name || !dlc->dai_name)
> +				continue;
> +
> +			if (strcmp(dai->name, dlc->dai_name))
> +				continue;
> +
> +			if (component->driver->pcm_construct)
> +				return true;
> +		}
> +	}
> +
> +	return false;
> +}

At least my CPU driver doesn't use component:pcm_construct
but is using DAI:pcm_new for some reasons.
I'm not sure checking DAI:pcm here is enough, or not...

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-06-30  6:07       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  6:07 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> PCM devices are created for dai links with 'no-pcm' flag as '0'.
> Such DAI links have CPU component which implement pcm_construct()
> and pcm_destruct() callbacks. Based on this, current patch exposes
> a helper function to identify such components and populate 'no_pcm'
> flag for DPCM DAI link.
> 
> This helps to have BE<->BE component links where PCM devices need
> not be created for CPU components involved in the links.
> 
> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
> ---
(snip)
> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
> +{
> +	struct snd_soc_component *component;
> +	struct snd_soc_dai *dai;
> +
> +	for_each_component(component) {
> +		if (!component->driver)
> +			continue;
> +
> +		for_each_component_dais(component, dai) {
> +			if (!dai->name || !dlc->dai_name)
> +				continue;
> +
> +			if (strcmp(dai->name, dlc->dai_name))
> +				continue;
> +
> +			if (component->driver->pcm_construct)
> +				return true;
> +		}
> +	}
> +
> +	return false;
> +}

At least my CPU driver doesn't use component:pcm_construct
but is using DAI:pcm_new for some reasons.
I'm not sure checking DAI:pcm here is enough, or not...

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-30  4:08                   ` Sameer Pujar
  (?)
@ 2020-06-30  6:55                       ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  6:55 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

Thank you for explaining detail at off-list mail.

Your issue happen on (C) case, and you are tring to solve it.
It is easy to understand if it was indicated at log area.
I have imagined other system from "multiple CPU/Codec support".

	(A)    (B)
	FE <-> BE

	(C)    (D)
	BE <-> BE

> > I'm not sure, this is just my guess.
> > I'm happy if we can support it more easily :)
> Right now I am trying re-use simple-card driver as much as possible
> and still make it work for flexible sound cards. I will be happy to
> discuss and improve the patch wherever necessary. Please help me
> understand which part you think looks to be hacky.

> > But, if it was difficult to keep compatibility on simple-card,
> > we/you need to have new one.
> Patch 17/23 and 18/23 introduce new compatible
> 'simple-cc-audio-card'. Idea was to use component chaining which
> allows connection of FE<->BE and multiple BE<->BE components along the
> DAPM path (patch 16/23). Do you think it would be fine?

This seems very complex system for current simple-card.
"concept" of simple-card is simple (but "code" is not so simple...)
Because of it, it doesn't assume flexible connection.

Maybe your patch works for you, but might breaks other systems.
Or, makes code or DT settings more complex/ununderstandable.
Not sure, but my guess.

Using cpu@0 node for BE is the 1st confusable point for me.
Using fe/be instead of cpu/codec is easy to understand.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30  6:55                       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  6:55 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

Thank you for explaining detail at off-list mail.

Your issue happen on (C) case, and you are tring to solve it.
It is easy to understand if it was indicated at log area.
I have imagined other system from "multiple CPU/Codec support".

	(A)    (B)
	FE <-> BE

	(C)    (D)
	BE <-> BE

> > I'm not sure, this is just my guess.
> > I'm happy if we can support it more easily :)
> Right now I am trying re-use simple-card driver as much as possible
> and still make it work for flexible sound cards. I will be happy to
> discuss and improve the patch wherever necessary. Please help me
> understand which part you think looks to be hacky.

> > But, if it was difficult to keep compatibility on simple-card,
> > we/you need to have new one.
> Patch 17/23 and 18/23 introduce new compatible
> 'simple-cc-audio-card'. Idea was to use component chaining which
> allows connection of FE<->BE and multiple BE<->BE components along the
> DAPM path (patch 16/23). Do you think it would be fine?

This seems very complex system for current simple-card.
"concept" of simple-card is simple (but "code" is not so simple...)
Because of it, it doesn't assume flexible connection.

Maybe your patch works for you, but might breaks other systems.
Or, makes code or DT settings more complex/ununderstandable.
Not sure, but my guess.

Using cpu@0 node for BE is the 1st confusable point for me.
Using fe/be instead of cpu/codec is easy to understand.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30  6:55                       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-06-30  6:55 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

Thank you for explaining detail at off-list mail.

Your issue happen on (C) case, and you are tring to solve it.
It is easy to understand if it was indicated at log area.
I have imagined other system from "multiple CPU/Codec support".

	(A)    (B)
	FE <-> BE

	(C)    (D)
	BE <-> BE

> > I'm not sure, this is just my guess.
> > I'm happy if we can support it more easily :)
> Right now I am trying re-use simple-card driver as much as possible
> and still make it work for flexible sound cards. I will be happy to
> discuss and improve the patch wherever necessary. Please help me
> understand which part you think looks to be hacky.

> > But, if it was difficult to keep compatibility on simple-card,
> > we/you need to have new one.
> Patch 17/23 and 18/23 introduce new compatible
> 'simple-cc-audio-card'. Idea was to use component chaining which
> allows connection of FE<->BE and multiple BE<->BE components along the
> DAPM path (patch 16/23). Do you think it would be fine?

This seems very complex system for current simple-card.
"concept" of simple-card is simple (but "code" is not so simple...)
Because of it, it doesn't assume flexible connection.

Maybe your patch works for you, but might breaks other systems.
Or, makes code or DT settings more complex/ununderstandable.
Not sure, but my guess.

Using cpu@0 node for BE is the 1st confusable point for me.
Using fe/be instead of cpu/codec is easy to understand.

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-30  6:55                       ` Kuninori Morimoto
  (?)
@ 2020-06-30  7:52                           ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  7:52 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 6/30/2020 12:25 PM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
> Thank you for explaining detail at off-list mail.
>
> Your issue happen on (C) case, and you are tring to solve it.
> It is easy to understand if it was indicated at log area.
> I have imagined other system from "multiple CPU/Codec support".
>
>          (A)    (B)
>          FE <-> BE
>
>          (C)    (D)
>          BE <-> BE
>
>>> I'm not sure, this is just my guess.
>>> I'm happy if we can support it more easily :)
>> Right now I am trying re-use simple-card driver as much as possible
>> and still make it work for flexible sound cards. I will be happy to
>> discuss and improve the patch wherever necessary. Please help me
>> understand which part you think looks to be hacky.
>>> But, if it was difficult to keep compatibility on simple-card,
>>> we/you need to have new one.
>> Patch 17/23 and 18/23 introduce new compatible
>> 'simple-cc-audio-card'. Idea was to use component chaining which
>> allows connection of FE<->BE and multiple BE<->BE components along the
>> DAPM path (patch 16/23). Do you think it would be fine?
> This seems very complex system for current simple-card.
> "concept" of simple-card is simple (but "code" is not so simple...)
> Because of it, it doesn't assume flexible connection.
>
> Maybe your patch works for you, but might breaks other systems.
> Or, makes code or DT settings more complex/ununderstandable.
> Not sure, but my guess.
Yes there are complex use cases, but if we look at the amount of changes 
required in simple-card driver that is not too much. Existing binding 
for simple-card driver would still work fine for our cases. Yes there 
are some deviations and we don't want to break existing users, that is 
why a *new* compatible was introduced and specific items can be pushed 
under it. Majority of the simple-card driver is getting re-used here. We 
just need to make sure it does not affect anyone else.

>
> Using cpu@0 node for BE is the 1st confusable point for me.
Don't we use the same methodology for CODEC<->CODEC link and still 
describe the DAI link with 'cpu@0' and 'codec@0'?

> Using fe/be instead of cpu/codec is easy to understand.
I guess you are referring to DT binding part. The parsing code 
specifically looks for "codec" sub node and thus present conventions had 
to be used.

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30  7:52                           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  7:52 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 12:25 PM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
> Thank you for explaining detail at off-list mail.
>
> Your issue happen on (C) case, and you are tring to solve it.
> It is easy to understand if it was indicated at log area.
> I have imagined other system from "multiple CPU/Codec support".
>
>          (A)    (B)
>          FE <-> BE
>
>          (C)    (D)
>          BE <-> BE
>
>>> I'm not sure, this is just my guess.
>>> I'm happy if we can support it more easily :)
>> Right now I am trying re-use simple-card driver as much as possible
>> and still make it work for flexible sound cards. I will be happy to
>> discuss and improve the patch wherever necessary. Please help me
>> understand which part you think looks to be hacky.
>>> But, if it was difficult to keep compatibility on simple-card,
>>> we/you need to have new one.
>> Patch 17/23 and 18/23 introduce new compatible
>> 'simple-cc-audio-card'. Idea was to use component chaining which
>> allows connection of FE<->BE and multiple BE<->BE components along the
>> DAPM path (patch 16/23). Do you think it would be fine?
> This seems very complex system for current simple-card.
> "concept" of simple-card is simple (but "code" is not so simple...)
> Because of it, it doesn't assume flexible connection.
>
> Maybe your patch works for you, but might breaks other systems.
> Or, makes code or DT settings more complex/ununderstandable.
> Not sure, but my guess.
Yes there are complex use cases, but if we look at the amount of changes 
required in simple-card driver that is not too much. Existing binding 
for simple-card driver would still work fine for our cases. Yes there 
are some deviations and we don't want to break existing users, that is 
why a *new* compatible was introduced and specific items can be pushed 
under it. Majority of the simple-card driver is getting re-used here. We 
just need to make sure it does not affect anyone else.

>
> Using cpu@0 node for BE is the 1st confusable point for me.
Don't we use the same methodology for CODEC<->CODEC link and still 
describe the DAI link with 'cpu@0' and 'codec@0'?

> Using fe/be instead of cpu/codec is easy to understand.
I guess you are referring to DT binding part. The parsing code 
specifically looks for "codec" sub node and thus present conventions had 
to be used.

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30  7:52                           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  7:52 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 12:25 PM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
> Thank you for explaining detail at off-list mail.
>
> Your issue happen on (C) case, and you are tring to solve it.
> It is easy to understand if it was indicated at log area.
> I have imagined other system from "multiple CPU/Codec support".
>
>          (A)    (B)
>          FE <-> BE
>
>          (C)    (D)
>          BE <-> BE
>
>>> I'm not sure, this is just my guess.
>>> I'm happy if we can support it more easily :)
>> Right now I am trying re-use simple-card driver as much as possible
>> and still make it work for flexible sound cards. I will be happy to
>> discuss and improve the patch wherever necessary. Please help me
>> understand which part you think looks to be hacky.
>>> But, if it was difficult to keep compatibility on simple-card,
>>> we/you need to have new one.
>> Patch 17/23 and 18/23 introduce new compatible
>> 'simple-cc-audio-card'. Idea was to use component chaining which
>> allows connection of FE<->BE and multiple BE<->BE components along the
>> DAPM path (patch 16/23). Do you think it would be fine?
> This seems very complex system for current simple-card.
> "concept" of simple-card is simple (but "code" is not so simple...)
> Because of it, it doesn't assume flexible connection.
>
> Maybe your patch works for you, but might breaks other systems.
> Or, makes code or DT settings more complex/ununderstandable.
> Not sure, but my guess.
Yes there are complex use cases, but if we look at the amount of changes 
required in simple-card driver that is not too much. Existing binding 
for simple-card driver would still work fine for our cases. Yes there 
are some deviations and we don't want to break existing users, that is 
why a *new* compatible was introduced and specific items can be pushed 
under it. Majority of the simple-card driver is getting re-used here. We 
just need to make sure it does not affect anyone else.

>
> Using cpu@0 node for BE is the 1st confusable point for me.
Don't we use the same methodology for CODEC<->CODEC link and still 
describe the DAI link with 'cpu@0' and 'codec@0'?

> Using fe/be instead of cpu/codec is easy to understand.
I guess you are referring to DT binding part. The parsing code 
specifically looks for "codec" sub node and thus present conventions had 
to be used.

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  2020-06-30  6:07       ` Kuninori Morimoto
  (?)
@ 2020-06-30  8:03           ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  8:03 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 6/30/2020 11:37 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> PCM devices are created for dai links with 'no-pcm' flag as '0'.
>> Such DAI links have CPU component which implement pcm_construct()
>> and pcm_destruct() callbacks. Based on this, current patch exposes
>> a helper function to identify such components and populate 'no_pcm'
>> flag for DPCM DAI link.
>>
>> This helps to have BE<->BE component links where PCM devices need
>> not be created for CPU components involved in the links.
>>
>> Signed-off-by: Sameer Pujar <spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>> ---
> (snip)
>> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
>> +{
>> +     struct snd_soc_component *component;
>> +     struct snd_soc_dai *dai;
>> +
>> +     for_each_component(component) {
>> +             if (!component->driver)
>> +                     continue;
>> +
>> +             for_each_component_dais(component, dai) {
>> +                     if (!dai->name || !dlc->dai_name)
>> +                             continue;
>> +
>> +                     if (strcmp(dai->name, dlc->dai_name))
>> +                             continue;
>> +
>> +                     if (component->driver->pcm_construct)
>> +                             return true;
>> +             }
>> +     }
>> +
>> +     return false;
>> +}
> At least my CPU driver doesn't use component:pcm_construct
> but is using DAI:pcm_new for some reasons.
> I'm not sure checking DAI:pcm here is enough, or not...

OK. If adding DAI:pcm_new above here is not sufficient, then a flag can 
be used to describe FE component? or is there a better alternative?
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-06-30  8:03           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  8:03 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 11:37 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> PCM devices are created for dai links with 'no-pcm' flag as '0'.
>> Such DAI links have CPU component which implement pcm_construct()
>> and pcm_destruct() callbacks. Based on this, current patch exposes
>> a helper function to identify such components and populate 'no_pcm'
>> flag for DPCM DAI link.
>>
>> This helps to have BE<->BE component links where PCM devices need
>> not be created for CPU components involved in the links.
>>
>> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
>> ---
> (snip)
>> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
>> +{
>> +     struct snd_soc_component *component;
>> +     struct snd_soc_dai *dai;
>> +
>> +     for_each_component(component) {
>> +             if (!component->driver)
>> +                     continue;
>> +
>> +             for_each_component_dais(component, dai) {
>> +                     if (!dai->name || !dlc->dai_name)
>> +                             continue;
>> +
>> +                     if (strcmp(dai->name, dlc->dai_name))
>> +                             continue;
>> +
>> +                     if (component->driver->pcm_construct)
>> +                             return true;
>> +             }
>> +     }
>> +
>> +     return false;
>> +}
> At least my CPU driver doesn't use component:pcm_construct
> but is using DAI:pcm_new for some reasons.
> I'm not sure checking DAI:pcm here is enough, or not...

OK. If adding DAI:pcm_new above here is not sufficient, then a flag can 
be used to describe FE component? or is there a better alternative?
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-06-30  8:03           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30  8:03 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 11:37 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>> PCM devices are created for dai links with 'no-pcm' flag as '0'.
>> Such DAI links have CPU component which implement pcm_construct()
>> and pcm_destruct() callbacks. Based on this, current patch exposes
>> a helper function to identify such components and populate 'no_pcm'
>> flag for DPCM DAI link.
>>
>> This helps to have BE<->BE component links where PCM devices need
>> not be created for CPU components involved in the links.
>>
>> Signed-off-by: Sameer Pujar <spujar@nvidia.com>
>> ---
> (snip)
>> +bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
>> +{
>> +     struct snd_soc_component *component;
>> +     struct snd_soc_dai *dai;
>> +
>> +     for_each_component(component) {
>> +             if (!component->driver)
>> +                     continue;
>> +
>> +             for_each_component_dais(component, dai) {
>> +                     if (!dai->name || !dlc->dai_name)
>> +                             continue;
>> +
>> +                     if (strcmp(dai->name, dlc->dai_name))
>> +                             continue;
>> +
>> +                     if (component->driver->pcm_construct)
>> +                             return true;
>> +             }
>> +     }
>> +
>> +     return false;
>> +}
> At least my CPU driver doesn't use component:pcm_construct
> but is using DAI:pcm_new for some reasons.
> I'm not sure checking DAI:pcm here is enough, or not...

OK. If adding DAI:pcm_new above here is not sufficient, then a flag can 
be used to describe FE component? or is there a better alternative?
>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
  2020-06-27  4:53     ` Sameer Pujar
  (?)
@ 2020-06-30 10:45         ` Mark Brown
  -1 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 10:45 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w

[-- Attachment #1: Type: text/plain, Size: 535 bytes --]

On Sat, Jun 27, 2020 at 10:23:30AM +0530, Sameer Pujar wrote:
> The "prefix" can be defined in DAI link node or it can be specified as
> part of the component node itself. Currently "sound-name-prefix" defined
> in a component is not taking effect. Actually the property is not getting
> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
> "prefix" is missing in DAI link Codec node.

Any fixes should go at the start of a series so they can be applied as
such without needing to pull in the rest of the series.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
@ 2020-06-30 10:45         ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 10:45 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka

[-- Attachment #1: Type: text/plain, Size: 535 bytes --]

On Sat, Jun 27, 2020 at 10:23:30AM +0530, Sameer Pujar wrote:
> The "prefix" can be defined in DAI link node or it can be specified as
> part of the component node itself. Currently "sound-name-prefix" defined
> in a component is not taking effect. Actually the property is not getting
> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
> "prefix" is missing in DAI link Codec node.

Any fixes should go at the start of a series so they can be applied as
such without needing to pull in the rest of the series.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
@ 2020-06-30 10:45         ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 10:45 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	kuninori.morimoto.gx, linux-kernel, nwartikar, lgirdwood, tiwai,
	viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh

[-- Attachment #1: Type: text/plain, Size: 535 bytes --]

On Sat, Jun 27, 2020 at 10:23:30AM +0530, Sameer Pujar wrote:
> The "prefix" can be defined in DAI link node or it can be specified as
> part of the component node itself. Currently "sound-name-prefix" defined
> in a component is not taking effect. Actually the property is not getting
> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
> "prefix" is missing in DAI link Codec node.

Any fixes should go at the start of a series so they can be applied as
such without needing to pull in the rest of the series.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 00/23] Add support for Tegra210 Audio
  2020-06-27  4:53 ` Sameer Pujar
  (?)
@ 2020-06-30 10:51     ` Mark Brown
  -1 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 10:51 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w

[-- Attachment #1: Type: text/plain, Size: 1067 bytes --]

On Sat, Jun 27, 2020 at 10:23:22AM +0530, Sameer Pujar wrote:

> Following is the summary of current series.
>  * Add YAML DT binding documentation for above mentioned modules.
>  * Helper function for ACIF programming is exposed for Tegra210 and later.
>  * Add ASoC driver components for each of the above modules.
>  * Add DT entries for above components for Tegra210, Tegra186 and
>    Tegra194.
>  * Enable these components for Jetson Nano/TX1/TX2/Xavier
>  * Enhance simple-card DPCM driver to suit Tegra Audio applications with
>    few changes in core.
>  * To begin with, enable sound card support for Tegra210 based platforms
>    like Jetson Nano/TX1.

This series is too big and covers a few different topics which makes it
difficult to manage, please split it up.  The most obvious thing here is
that it contains both the drivers you're adding and a bunch of changes
to the generic audio cards (which are a single throwaway line in your
cover letter) - splitting out the generic card changes into a separate
series would result in more manageable sizes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 00/23] Add support for Tegra210 Audio
@ 2020-06-30 10:51     ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 10:51 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka

[-- Attachment #1: Type: text/plain, Size: 1067 bytes --]

On Sat, Jun 27, 2020 at 10:23:22AM +0530, Sameer Pujar wrote:

> Following is the summary of current series.
>  * Add YAML DT binding documentation for above mentioned modules.
>  * Helper function for ACIF programming is exposed for Tegra210 and later.
>  * Add ASoC driver components for each of the above modules.
>  * Add DT entries for above components for Tegra210, Tegra186 and
>    Tegra194.
>  * Enable these components for Jetson Nano/TX1/TX2/Xavier
>  * Enhance simple-card DPCM driver to suit Tegra Audio applications with
>    few changes in core.
>  * To begin with, enable sound card support for Tegra210 based platforms
>    like Jetson Nano/TX1.

This series is too big and covers a few different topics which makes it
difficult to manage, please split it up.  The most obvious thing here is
that it contains both the drivers you're adding and a bunch of changes
to the generic audio cards (which are a single throwaway line in your
cover letter) - splitting out the generic card changes into a separate
series would result in more manageable sizes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 00/23] Add support for Tegra210 Audio
@ 2020-06-30 10:51     ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 10:51 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	kuninori.morimoto.gx, linux-kernel, nwartikar, lgirdwood, tiwai,
	viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh

[-- Attachment #1: Type: text/plain, Size: 1067 bytes --]

On Sat, Jun 27, 2020 at 10:23:22AM +0530, Sameer Pujar wrote:

> Following is the summary of current series.
>  * Add YAML DT binding documentation for above mentioned modules.
>  * Helper function for ACIF programming is exposed for Tegra210 and later.
>  * Add ASoC driver components for each of the above modules.
>  * Add DT entries for above components for Tegra210, Tegra186 and
>    Tegra194.
>  * Enable these components for Jetson Nano/TX1/TX2/Xavier
>  * Enhance simple-card DPCM driver to suit Tegra Audio applications with
>    few changes in core.
>  * To begin with, enable sound card support for Tegra210 based platforms
>    like Jetson Nano/TX1.

This series is too big and covers a few different topics which makes it
difficult to manage, please split it up.  The most obvious thing here is
that it contains both the drivers you're adding and a bunch of changes
to the generic audio cards (which are a single throwaway line in your
cover letter) - splitting out the generic card changes into a separate
series would result in more manageable sizes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
  2020-06-30  4:23                   ` Sameer Pujar
  (?)
@ 2020-06-30 10:55                       ` Mark Brown
  -1 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 10:55 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: Kuninori Morimoto, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w

[-- Attachment #1: Type: text/plain, Size: 1009 bytes --]

On Tue, Jun 30, 2020 at 09:53:13AM +0530, Sameer Pujar wrote:
> On 6/30/2020 7:38 AM, Kuninori Morimoto wrote:
> > External email: Use caution opening links or attachments

> > > > > +     if (cpu != codec)
> > > > > +             of_property_read_u32(codec, prop, &props->mclk_fs);

> Sorry if I was not clear before.

I agree with Moromito-san that the new code (especially the above bit)
is very confusing, I'm not sure how the reader is supposed to figure out
what the purpose of the check is or how the CPU could ever be the CODEC.

> simple_parse_mclk_fs() is used by both simple_dai_link_of_dpcm() and
> simple_dai_link_of(). To make the same API work for both the cases, I had to
> use (A) in DPCM function. Now (B) does not get used for
> simple_dai_link_of_dpcm(), but will get used by simple_dai_link_of().

> If it is simpler I will just avoid 'cpu != codec' check and keep the
> function simple_parse_mclk_fs() as it is.

That'd definitely be simpler, or supporting this with a CPU node as
well.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-30 10:55                       ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 10:55 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: Kuninori Morimoto, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka

[-- Attachment #1: Type: text/plain, Size: 1009 bytes --]

On Tue, Jun 30, 2020 at 09:53:13AM +0530, Sameer Pujar wrote:
> On 6/30/2020 7:38 AM, Kuninori Morimoto wrote:
> > External email: Use caution opening links or attachments

> > > > > +     if (cpu != codec)
> > > > > +             of_property_read_u32(codec, prop, &props->mclk_fs);

> Sorry if I was not clear before.

I agree with Moromito-san that the new code (especially the above bit)
is very confusing, I'm not sure how the reader is supposed to figure out
what the purpose of the check is or how the CPU could ever be the CODEC.

> simple_parse_mclk_fs() is used by both simple_dai_link_of_dpcm() and
> simple_dai_link_of(). To make the same API work for both the cases, I had to
> use (A) in DPCM function. Now (B) does not get used for
> simple_dai_link_of_dpcm(), but will get used by simple_dai_link_of().

> If it is simpler I will just avoid 'cpu != codec' check and keep the
> function simple_parse_mclk_fs() as it is.

That'd definitely be simpler, or supporting this with a CPU node as
well.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-30 10:55                       ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 10:55 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	Kuninori Morimoto, linux-kernel, nwartikar, lgirdwood, tiwai,
	viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh

[-- Attachment #1: Type: text/plain, Size: 1009 bytes --]

On Tue, Jun 30, 2020 at 09:53:13AM +0530, Sameer Pujar wrote:
> On 6/30/2020 7:38 AM, Kuninori Morimoto wrote:
> > External email: Use caution opening links or attachments

> > > > > +     if (cpu != codec)
> > > > > +             of_property_read_u32(codec, prop, &props->mclk_fs);

> Sorry if I was not clear before.

I agree with Moromito-san that the new code (especially the above bit)
is very confusing, I'm not sure how the reader is supposed to figure out
what the purpose of the check is or how the CPU could ever be the CODEC.

> simple_parse_mclk_fs() is used by both simple_dai_link_of_dpcm() and
> simple_dai_link_of(). To make the same API work for both the cases, I had to
> use (A) in DPCM function. Now (B) does not get used for
> simple_dai_link_of_dpcm(), but will get used by simple_dai_link_of().

> If it is simpler I will just avoid 'cpu != codec' check and keep the
> function simple_parse_mclk_fs() as it is.

That'd definitely be simpler, or supporting this with a CPU node as
well.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-30  7:52                           ` Sameer Pujar
  (?)
@ 2020-06-30 11:01                               ` Mark Brown
  -1 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 11:01 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: Kuninori Morimoto, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w

[-- Attachment #1: Type: text/plain, Size: 908 bytes --]

On Tue, Jun 30, 2020 at 01:22:29PM +0530, Sameer Pujar wrote:

> Yes there are complex use cases, but if we look at the amount of changes
> required in simple-card driver that is not too much. Existing binding for
> simple-card driver would still work fine for our cases. Yes there are some
> deviations and we don't want to break existing users, that is why a *new*
> compatible was introduced and specific items can be pushed under it.
> Majority of the simple-card driver is getting re-used here. We just need to
> make sure it does not affect anyone else.

Why simple-card and not audio-graph-card?

> > Using fe/be instead of cpu/codec is easy to understand.

> I guess you are referring to DT binding part. The parsing code specifically
> looks for "codec" sub node and thus present conventions had to be used.

Remember that this stuff gets fixed into the ABI so we'd have to live
with this for ever.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30 11:01                               ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 11:01 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: Kuninori Morimoto, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka

[-- Attachment #1: Type: text/plain, Size: 908 bytes --]

On Tue, Jun 30, 2020 at 01:22:29PM +0530, Sameer Pujar wrote:

> Yes there are complex use cases, but if we look at the amount of changes
> required in simple-card driver that is not too much. Existing binding for
> simple-card driver would still work fine for our cases. Yes there are some
> deviations and we don't want to break existing users, that is why a *new*
> compatible was introduced and specific items can be pushed under it.
> Majority of the simple-card driver is getting re-used here. We just need to
> make sure it does not affect anyone else.

Why simple-card and not audio-graph-card?

> > Using fe/be instead of cpu/codec is easy to understand.

> I guess you are referring to DT binding part. The parsing code specifically
> looks for "codec" sub node and thus present conventions had to be used.

Remember that this stuff gets fixed into the ABI so we'd have to live
with this for ever.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30 11:01                               ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 11:01 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	Kuninori Morimoto, linux-kernel, nwartikar, lgirdwood, tiwai,
	viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh

[-- Attachment #1: Type: text/plain, Size: 908 bytes --]

On Tue, Jun 30, 2020 at 01:22:29PM +0530, Sameer Pujar wrote:

> Yes there are complex use cases, but if we look at the amount of changes
> required in simple-card driver that is not too much. Existing binding for
> simple-card driver would still work fine for our cases. Yes there are some
> deviations and we don't want to break existing users, that is why a *new*
> compatible was introduced and specific items can be pushed under it.
> Majority of the simple-card driver is getting re-used here. We just need to
> make sure it does not affect anyone else.

Why simple-card and not audio-graph-card?

> > Using fe/be instead of cpu/codec is easy to understand.

> I guess you are referring to DT binding part. The parsing code specifically
> looks for "codec" sub node and thus present conventions had to be used.

Remember that this stuff gets fixed into the ABI so we'd have to live
with this for ever.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 00/23] Add support for Tegra210 Audio
  2020-06-30 10:51     ` Mark Brown
  (?)
@ 2020-06-30 11:54       ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 11:54 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 4:21 PM, Mark Brown wrote:
> On Sat, Jun 27, 2020 at 10:23:22AM +0530, Sameer Pujar wrote:
>
>> Following is the summary of current series.
>>   * Add YAML DT binding documentation for above mentioned modules.
>>   * Helper function for ACIF programming is exposed for Tegra210 and later.
>>   * Add ASoC driver components for each of the above modules.
>>   * Add DT entries for above components for Tegra210, Tegra186 and
>>     Tegra194.
>>   * Enable these components for Jetson Nano/TX1/TX2/Xavier
>>   * Enhance simple-card DPCM driver to suit Tegra Audio applications with
>>     few changes in core.
>>   * To begin with, enable sound card support for Tegra210 based platforms
>>     like Jetson Nano/TX1.
> This series is too big and covers a few different topics which makes it
> difficult to manage, please split it up.  The most obvious thing here is
> that it contains both the drivers you're adding and a bunch of changes
> to the generic audio cards (which are a single throwaway line in your
> cover letter) - splitting out the generic card changes into a separate
> series would result in more manageable sizes.

My initial thought was, it would be better to present a entire picture 
where complete audio path can be tested or reviewed and hence added 
simple-card patches in the series. I will split this up in next revision.

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 00/23] Add support for Tegra210 Audio
@ 2020-06-30 11:54       ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 11:54 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 4:21 PM, Mark Brown wrote:
> On Sat, Jun 27, 2020 at 10:23:22AM +0530, Sameer Pujar wrote:
>
>> Following is the summary of current series.
>>   * Add YAML DT binding documentation for above mentioned modules.
>>   * Helper function for ACIF programming is exposed for Tegra210 and later.
>>   * Add ASoC driver components for each of the above modules.
>>   * Add DT entries for above components for Tegra210, Tegra186 and
>>     Tegra194.
>>   * Enable these components for Jetson Nano/TX1/TX2/Xavier
>>   * Enhance simple-card DPCM driver to suit Tegra Audio applications with
>>     few changes in core.
>>   * To begin with, enable sound card support for Tegra210 based platforms
>>     like Jetson Nano/TX1.
> This series is too big and covers a few different topics which makes it
> difficult to manage, please split it up.  The most obvious thing here is
> that it contains both the drivers you're adding and a bunch of changes
> to the generic audio cards (which are a single throwaway line in your
> cover letter) - splitting out the generic card changes into a separate
> series would result in more manageable sizes.

My initial thought was, it would be better to present a entire picture 
where complete audio path can be tested or reviewed and hence added 
simple-card patches in the series. I will split this up in next revision.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 00/23] Add support for Tegra210 Audio
@ 2020-06-30 11:54       ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 11:54 UTC (permalink / raw)
  To: Mark Brown
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	kuninori.morimoto.gx, linux-kernel, spujar, nwartikar, lgirdwood,
	tiwai, viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 4:21 PM, Mark Brown wrote:
> On Sat, Jun 27, 2020 at 10:23:22AM +0530, Sameer Pujar wrote:
>
>> Following is the summary of current series.
>>   * Add YAML DT binding documentation for above mentioned modules.
>>   * Helper function for ACIF programming is exposed for Tegra210 and later.
>>   * Add ASoC driver components for each of the above modules.
>>   * Add DT entries for above components for Tegra210, Tegra186 and
>>     Tegra194.
>>   * Enable these components for Jetson Nano/TX1/TX2/Xavier
>>   * Enhance simple-card DPCM driver to suit Tegra Audio applications with
>>     few changes in core.
>>   * To begin with, enable sound card support for Tegra210 based platforms
>>     like Jetson Nano/TX1.
> This series is too big and covers a few different topics which makes it
> difficult to manage, please split it up.  The most obvious thing here is
> that it contains both the drivers you're adding and a bunch of changes
> to the generic audio cards (which are a single throwaway line in your
> cover letter) - splitting out the generic card changes into a separate
> series would result in more manageable sizes.

My initial thought was, it would be better to present a entire picture 
where complete audio path can be tested or reviewed and hence added 
simple-card patches in the series. I will split this up in next revision.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
  2020-06-30 10:55                       ` Mark Brown
  (?)
@ 2020-06-30 11:56                         ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 11:56 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar, Kuninori Morimoto, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 4:25 PM, Mark Brown wrote:
> On Tue, Jun 30, 2020 at 09:53:13AM +0530, Sameer Pujar wrote:
>> On 6/30/2020 7:38 AM, Kuninori Morimoto wrote:
>>> External email: Use caution opening links or attachments
>>>>>> +     if (cpu != codec)
>>>>>> +             of_property_read_u32(codec, prop, &props->mclk_fs);
>> Sorry if I was not clear before.
> I agree with Moromito-san that the new code (especially the above bit)
> is very confusing, I'm not sure how the reader is supposed to figure out
> what the purpose of the check is or how the CPU could ever be the CODEC.
>
>> simple_parse_mclk_fs() is used by both simple_dai_link_of_dpcm() and
>> simple_dai_link_of(). To make the same API work for both the cases, I had to
>> use (A) in DPCM function. Now (B) does not get used for
>> simple_dai_link_of_dpcm(), but will get used by simple_dai_link_of().
>> If it is simpler I will just avoid 'cpu != codec' check and keep the
>> function simple_parse_mclk_fs() as it is.
> That'd definitely be simpler, or supporting this with a CPU node as
> well.

OK. I will keep it simple.

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-30 11:56                         ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 11:56 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar, Kuninori Morimoto, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 4:25 PM, Mark Brown wrote:
> On Tue, Jun 30, 2020 at 09:53:13AM +0530, Sameer Pujar wrote:
>> On 6/30/2020 7:38 AM, Kuninori Morimoto wrote:
>>> External email: Use caution opening links or attachments
>>>>>> +     if (cpu != codec)
>>>>>> +             of_property_read_u32(codec, prop, &props->mclk_fs);
>> Sorry if I was not clear before.
> I agree with Moromito-san that the new code (especially the above bit)
> is very confusing, I'm not sure how the reader is supposed to figure out
> what the purpose of the check is or how the CPU could ever be the CODEC.
>
>> simple_parse_mclk_fs() is used by both simple_dai_link_of_dpcm() and
>> simple_dai_link_of(). To make the same API work for both the cases, I had to
>> use (A) in DPCM function. Now (B) does not get used for
>> simple_dai_link_of_dpcm(), but will get used by simple_dai_link_of().
>> If it is simpler I will just avoid 'cpu != codec' check and keep the
>> function simple_parse_mclk_fs() as it is.
> That'd definitely be simpler, or supporting this with a CPU node as
> well.

OK. I will keep it simple.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs'
@ 2020-06-30 11:56                         ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 11:56 UTC (permalink / raw)
  To: Mark Brown
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	Kuninori Morimoto, linux-kernel, spujar, nwartikar, lgirdwood,
	tiwai, viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 4:25 PM, Mark Brown wrote:
> On Tue, Jun 30, 2020 at 09:53:13AM +0530, Sameer Pujar wrote:
>> On 6/30/2020 7:38 AM, Kuninori Morimoto wrote:
>>> External email: Use caution opening links or attachments
>>>>>> +     if (cpu != codec)
>>>>>> +             of_property_read_u32(codec, prop, &props->mclk_fs);
>> Sorry if I was not clear before.
> I agree with Moromito-san that the new code (especially the above bit)
> is very confusing, I'm not sure how the reader is supposed to figure out
> what the purpose of the check is or how the CPU could ever be the CODEC.
>
>> simple_parse_mclk_fs() is used by both simple_dai_link_of_dpcm() and
>> simple_dai_link_of(). To make the same API work for both the cases, I had to
>> use (A) in DPCM function. Now (B) does not get used for
>> simple_dai_link_of_dpcm(), but will get used by simple_dai_link_of().
>> If it is simpler I will just avoid 'cpu != codec' check and keep the
>> function simple_parse_mclk_fs() as it is.
> That'd definitely be simpler, or supporting this with a CPU node as
> well.

OK. I will keep it simple.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-30 11:01                               ` Mark Brown
  (?)
@ 2020-06-30 12:53                                   ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 12:53 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, Kuninori Morimoto,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 6/30/2020 4:31 PM, Mark Brown wrote:
> On Tue, Jun 30, 2020 at 01:22:29PM +0530, Sameer Pujar wrote:
>
>> Yes there are complex use cases, but if we look at the amount of changes
>> required in simple-card driver that is not too much. Existing binding for
>> simple-card driver would still work fine for our cases. Yes there are some
>> deviations and we don't want to break existing users, that is why a *new*
>> compatible was introduced and specific items can be pushed under it.
>> Majority of the simple-card driver is getting re-used here. We just need to
>> make sure it does not affect anyone else.
> Why simple-card and not audio-graph-card?

Frankly speaking I have not used audio-graph-card before. I had a brief 
look at the related binding. It seems it can use similar DT properties 
that simple-card uses, although the binding style appears to be 
different. However I am not sure if it offers better solutions to the 
problems I am facing. For example, the ability to connect or form a 
chain of components to realize more complicated use cases with DPCM, 
some of which were discussed in [0]. Can you please help me understand 
why it could be preferred?

[0] https://lkml.org/lkml/2020/4/30/519

>>> Using fe/be instead of cpu/codec is easy to understand.
>> I guess you are referring to DT binding part. The parsing code specifically
>> looks for "codec" sub node and thus present conventions had to be used.
> Remember that this stuff gets fixed into the ABI so we'd have to live
> with this for ever.

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30 12:53                                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 12:53 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar, Kuninori Morimoto, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 4:31 PM, Mark Brown wrote:
> On Tue, Jun 30, 2020 at 01:22:29PM +0530, Sameer Pujar wrote:
>
>> Yes there are complex use cases, but if we look at the amount of changes
>> required in simple-card driver that is not too much. Existing binding for
>> simple-card driver would still work fine for our cases. Yes there are some
>> deviations and we don't want to break existing users, that is why a *new*
>> compatible was introduced and specific items can be pushed under it.
>> Majority of the simple-card driver is getting re-used here. We just need to
>> make sure it does not affect anyone else.
> Why simple-card and not audio-graph-card?

Frankly speaking I have not used audio-graph-card before. I had a brief 
look at the related binding. It seems it can use similar DT properties 
that simple-card uses, although the binding style appears to be 
different. However I am not sure if it offers better solutions to the 
problems I am facing. For example, the ability to connect or form a 
chain of components to realize more complicated use cases with DPCM, 
some of which were discussed in [0]. Can you please help me understand 
why it could be preferred?

[0] https://lkml.org/lkml/2020/4/30/519

>>> Using fe/be instead of cpu/codec is easy to understand.
>> I guess you are referring to DT binding part. The parsing code specifically
>> looks for "codec" sub node and thus present conventions had to be used.
> Remember that this stuff gets fixed into the ABI so we'd have to live
> with this for ever.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30 12:53                                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 12:53 UTC (permalink / raw)
  To: Mark Brown
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	Kuninori Morimoto, linux-kernel, spujar, nwartikar, lgirdwood,
	tiwai, viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 4:31 PM, Mark Brown wrote:
> On Tue, Jun 30, 2020 at 01:22:29PM +0530, Sameer Pujar wrote:
>
>> Yes there are complex use cases, but if we look at the amount of changes
>> required in simple-card driver that is not too much. Existing binding for
>> simple-card driver would still work fine for our cases. Yes there are some
>> deviations and we don't want to break existing users, that is why a *new*
>> compatible was introduced and specific items can be pushed under it.
>> Majority of the simple-card driver is getting re-used here. We just need to
>> make sure it does not affect anyone else.
> Why simple-card and not audio-graph-card?

Frankly speaking I have not used audio-graph-card before. I had a brief 
look at the related binding. It seems it can use similar DT properties 
that simple-card uses, although the binding style appears to be 
different. However I am not sure if it offers better solutions to the 
problems I am facing. For example, the ability to connect or form a 
chain of components to realize more complicated use cases with DPCM, 
some of which were discussed in [0]. Can you please help me understand 
why it could be preferred?

[0] https://lkml.org/lkml/2020/4/30/519

>>> Using fe/be instead of cpu/codec is easy to understand.
>> I guess you are referring to DT binding part. The parsing code specifically
>> looks for "codec" sub node and thus present conventions had to be used.
> Remember that this stuff gets fixed into the ABI so we'd have to live
> with this for ever.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
  2020-06-30 10:45         ` Mark Brown
  (?)
@ 2020-06-30 12:56             ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 12:56 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 6/30/2020 4:15 PM, Mark Brown wrote:
> On Sat, Jun 27, 2020 at 10:23:30AM +0530, Sameer Pujar wrote:
>> The "prefix" can be defined in DAI link node or it can be specified as
>> part of the component node itself. Currently "sound-name-prefix" defined
>> in a component is not taking effect. Actually the property is not getting
>> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
>> "prefix" is missing in DAI link Codec node.
> Any fixes should go at the start of a series so they can be applied as
> such without needing to pull in the rest of the series.

OK. I will re-order the patches accordingly in the next revision.

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
@ 2020-06-30 12:56             ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 12:56 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar, perex, tiwai, kuninori.morimoto.gx, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 4:15 PM, Mark Brown wrote:
> On Sat, Jun 27, 2020 at 10:23:30AM +0530, Sameer Pujar wrote:
>> The "prefix" can be defined in DAI link node or it can be specified as
>> part of the component node itself. Currently "sound-name-prefix" defined
>> in a component is not taking effect. Actually the property is not getting
>> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
>> "prefix" is missing in DAI link Codec node.
> Any fixes should go at the start of a series so they can be applied as
> such without needing to pull in the rest of the series.

OK. I will re-order the patches accordingly in the next revision.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing
@ 2020-06-30 12:56             ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-06-30 12:56 UTC (permalink / raw)
  To: Mark Brown
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	kuninori.morimoto.gx, linux-kernel, spujar, nwartikar, lgirdwood,
	tiwai, viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 4:15 PM, Mark Brown wrote:
> On Sat, Jun 27, 2020 at 10:23:30AM +0530, Sameer Pujar wrote:
>> The "prefix" can be defined in DAI link node or it can be specified as
>> part of the component node itself. Currently "sound-name-prefix" defined
>> in a component is not taking effect. Actually the property is not getting
>> parsed. It can be fixed by parsing "sound-name-prefix" property whenever
>> "prefix" is missing in DAI link Codec node.
> Any fixes should go at the start of a series so they can be applied as
> such without needing to pull in the rest of the series.

OK. I will re-order the patches accordingly in the next revision.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-30 12:53                                   ` Sameer Pujar
@ 2020-06-30 15:32                                     ` Mark Brown
  -1 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 15:32 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: Kuninori Morimoto, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka

[-- Attachment #1: Type: text/plain, Size: 868 bytes --]

On Tue, Jun 30, 2020 at 06:23:49PM +0530, Sameer Pujar wrote:
> On 6/30/2020 4:31 PM, Mark Brown wrote:

> > Why simple-card and not audio-graph-card?

> Frankly speaking I have not used audio-graph-card before. I had a brief look
> at the related binding. It seems it can use similar DT properties that
> simple-card uses, although the binding style appears to be different.
> However I am not sure if it offers better solutions to the problems I am
> facing. For example, the ability to connect or form a chain of components to
> realize more complicated use cases with DPCM, some of which were discussed
> in [0]. Can you please help me understand why it could be preferred?

> [0] https://lkml.org/lkml/2020/4/30/519

It's the more modern thing which covers everything simple-card does and
more, I'd expect new development to go into that rather than
simple-card.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-06-30 15:32                                     ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-06-30 15:32 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	Kuninori Morimoto, linux-kernel, nwartikar, lgirdwood, tiwai,
	viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh

[-- Attachment #1: Type: text/plain, Size: 868 bytes --]

On Tue, Jun 30, 2020 at 06:23:49PM +0530, Sameer Pujar wrote:
> On 6/30/2020 4:31 PM, Mark Brown wrote:

> > Why simple-card and not audio-graph-card?

> Frankly speaking I have not used audio-graph-card before. I had a brief look
> at the related binding. It seems it can use similar DT properties that
> simple-card uses, although the binding style appears to be different.
> However I am not sure if it offers better solutions to the problems I am
> facing. For example, the ability to connect or form a chain of components to
> realize more complicated use cases with DPCM, some of which were discussed
> in [0]. Can you please help me understand why it could be preferred?

> [0] https://lkml.org/lkml/2020/4/30/519

It's the more modern thing which covers everything simple-card does and
more, I'd expect new development to go into that rather than
simple-card.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  2020-06-30  8:03           ` Sameer Pujar
  (?)
@ 2020-07-02  0:52               ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-07-02  0:52 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> > At least my CPU driver doesn't use component:pcm_construct
> > but is using DAI:pcm_new for some reasons.
> > I'm not sure checking DAI:pcm here is enough, or not...
> 
> OK. If adding DAI:pcm_new above here is not sufficient, then a flag
> can be used to describe FE component? or is there a better
> alternative?

soc_component_is_pcm() is called from simple_dai_link_of_dpcm :: "FE" side.
I wonder component->driver->non_legacy_dai_naming can't work for you ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-07-02  0:52               ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-07-02  0:52 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> > At least my CPU driver doesn't use component:pcm_construct
> > but is using DAI:pcm_new for some reasons.
> > I'm not sure checking DAI:pcm here is enough, or not...
> 
> OK. If adding DAI:pcm_new above here is not sufficient, then a flag
> can be used to describe FE component? or is there a better
> alternative?

soc_component_is_pcm() is called from simple_dai_link_of_dpcm :: "FE" side.
I wonder component->driver->non_legacy_dai_naming can't work for you ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-07-02  0:52               ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-07-02  0:52 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> > At least my CPU driver doesn't use component:pcm_construct
> > but is using DAI:pcm_new for some reasons.
> > I'm not sure checking DAI:pcm here is enough, or not...
> 
> OK. If adding DAI:pcm_new above here is not sufficient, then a flag
> can be used to describe FE component? or is there a better
> alternative?

soc_component_is_pcm() is called from simple_dai_link_of_dpcm :: "FE" side.
I wonder component->driver->non_legacy_dai_naming can't work for you ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  2020-07-02  0:52               ` Kuninori Morimoto
  (?)
@ 2020-07-02  3:48                   ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-02  3:48 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 7/2/2020 6:22 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>> At least my CPU driver doesn't use component:pcm_construct
>>> but is using DAI:pcm_new for some reasons.
>>> I'm not sure checking DAI:pcm here is enough, or not...
>> OK. If adding DAI:pcm_new above here is not sufficient, then a flag
>> can be used to describe FE component? or is there a better
>> alternative?

> soc_component_is_pcm() is called from simple_dai_link_of_dpcm :: "FE" side.

Yes I had to use this on "FE" side only because I wanted to find a real 
"FE" in FE<->BE and BE<->BE links. Please have a look at patch [23/23] 
for the sound DT binding I am using. Basically I want to connect 
multiple components in a chained fashion (FE <-> BE1 <-> BE2 ... <BEx>). 
Some of these BEs can be SoC components like resampler/mixer/mux/de-mux 
etc., the HW I am using has a cross bar which allows me to 
select/connect BEs in any order and I am trying to have the same 
flexibility here. Hence I only want to create PCM devices for real "FE" 
and trying to use simple-card as much as possible. More details about 
the HW and problems were discussed in [0].

[0] https://lkml.org/lkml/2020/4/30/519

> I wonder component->driver->non_legacy_dai_naming can't work for you ?

I see currently in simple-card driver that, BE<->BE link would be 
treated as CODEC<->CODEC link if 'non_legacy_dai_naming' flag is set at 
both ends of BE. Do we need to set this flag for all BE?
However I am not sure how this will work out for a BE<->BE DPCM DAI link 
considering the fact that I want to use chain of components and I guess 
routing map would get complicated. Also going by the flag name it was 
not meant to differentiate between a FE and BE?
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-07-02  3:48                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-02  3:48 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 7/2/2020 6:22 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>> At least my CPU driver doesn't use component:pcm_construct
>>> but is using DAI:pcm_new for some reasons.
>>> I'm not sure checking DAI:pcm here is enough, or not...
>> OK. If adding DAI:pcm_new above here is not sufficient, then a flag
>> can be used to describe FE component? or is there a better
>> alternative?

> soc_component_is_pcm() is called from simple_dai_link_of_dpcm :: "FE" side.

Yes I had to use this on "FE" side only because I wanted to find a real 
"FE" in FE<->BE and BE<->BE links. Please have a look at patch [23/23] 
for the sound DT binding I am using. Basically I want to connect 
multiple components in a chained fashion (FE <-> BE1 <-> BE2 ... <BEx>). 
Some of these BEs can be SoC components like resampler/mixer/mux/de-mux 
etc., the HW I am using has a cross bar which allows me to 
select/connect BEs in any order and I am trying to have the same 
flexibility here. Hence I only want to create PCM devices for real "FE" 
and trying to use simple-card as much as possible. More details about 
the HW and problems were discussed in [0].

[0] https://lkml.org/lkml/2020/4/30/519

> I wonder component->driver->non_legacy_dai_naming can't work for you ?

I see currently in simple-card driver that, BE<->BE link would be 
treated as CODEC<->CODEC link if 'non_legacy_dai_naming' flag is set at 
both ends of BE. Do we need to set this flag for all BE?
However I am not sure how this will work out for a BE<->BE DPCM DAI link 
considering the fact that I want to use chain of components and I guess 
routing map would get complicated. Also going by the flag name it was 
not meant to differentiate between a FE and BE?
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-07-02  3:48                   ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-02  3:48 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 7/2/2020 6:22 AM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>> At least my CPU driver doesn't use component:pcm_construct
>>> but is using DAI:pcm_new for some reasons.
>>> I'm not sure checking DAI:pcm here is enough, or not...
>> OK. If adding DAI:pcm_new above here is not sufficient, then a flag
>> can be used to describe FE component? or is there a better
>> alternative?

> soc_component_is_pcm() is called from simple_dai_link_of_dpcm :: "FE" side.

Yes I had to use this on "FE" side only because I wanted to find a real 
"FE" in FE<->BE and BE<->BE links. Please have a look at patch [23/23] 
for the sound DT binding I am using. Basically I want to connect 
multiple components in a chained fashion (FE <-> BE1 <-> BE2 ... <BEx>). 
Some of these BEs can be SoC components like resampler/mixer/mux/de-mux 
etc., the HW I am using has a cross bar which allows me to 
select/connect BEs in any order and I am trying to have the same 
flexibility here. Hence I only want to create PCM devices for real "FE" 
and trying to use simple-card as much as possible. More details about 
the HW and problems were discussed in [0].

[0] https://lkml.org/lkml/2020/4/30/519

> I wonder component->driver->non_legacy_dai_naming can't work for you ?

I see currently in simple-card driver that, BE<->BE link would be 
treated as CODEC<->CODEC link if 'non_legacy_dai_naming' flag is set at 
both ends of BE. Do we need to set this flag for all BE?
However I am not sure how this will work out for a BE<->BE DPCM DAI link 
considering the fact that I want to use chain of components and I guess 
routing map would get complicated. Also going by the flag name it was 
not meant to differentiate between a FE and BE?
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  2020-07-02  3:48                   ` Sameer Pujar
  (?)
@ 2020-07-02  8:50                       ` Kuninori Morimoto
  -1 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-07-02  8:50 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w


Hi Sameer

> > I wonder component->driver->non_legacy_dai_naming can't work for you ?
> 
> I see currently in simple-card driver that, BE<->BE link would be
> treated as CODEC<->CODEC link if 'non_legacy_dai_naming' flag is set
> at both ends of BE. Do we need to set this flag for all BE?
> However I am not sure how this will work out for a BE<->BE DPCM DAI
> link considering the fact that I want to use chain of components and I
> guess routing map would get complicated. Also going by the flag name
> it was not meant to differentiate between a FE and BE?

OK, non_legacy_dai_naming was just my quick idea.

Maybe your soc_component_is_pcm() idea can work,
but it seems a littl bit hackish for me.
So, can you please

1) Add soc_component_is_pcm() on simple-card, not soc-core ?
   Maybe we can move it to soc-core later,
   but want to keep it under simple-card, so far.

2) Use it with data->component_chaining, and some comment ?
   non component_chaining user doesn't get damage in worst case,
   and easy to understand.

	/*
	 * This is for BE<->BE connection.
	 * It needs to ...
	 * It is assumng ...
	 * Note is ...
	 */
	if (data->component_chaining &&
	    !soc_component_is_pcm(cpus))
		dai_link->no_pcm = 1;

3) maybe you can reuse snd_soc_find_dai() for soc_component_is_pcm() ?

	dai = snd_soc_find_dai(dlc);
	if (dai &&
	    (dai->pcm_new || dai->component->driver->pcm_construct))
		return xxx

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-07-02  8:50                       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-07-02  8:50 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: broonie, perex, tiwai, robh+dt, lgirdwood, thierry.reding,
	jonathanh, digetx, alsa-devel, linux-tegra, linux-kernel,
	sharadg, mkumard, viswanathl, rlokhande, dramesh, atalambedu,
	nwartikar, swarren, nicoleotsuka


Hi Sameer

> > I wonder component->driver->non_legacy_dai_naming can't work for you ?
> 
> I see currently in simple-card driver that, BE<->BE link would be
> treated as CODEC<->CODEC link if 'non_legacy_dai_naming' flag is set
> at both ends of BE. Do we need to set this flag for all BE?
> However I am not sure how this will work out for a BE<->BE DPCM DAI
> link considering the fact that I want to use chain of components and I
> guess routing map would get complicated. Also going by the flag name
> it was not meant to differentiate between a FE and BE?

OK, non_legacy_dai_naming was just my quick idea.

Maybe your soc_component_is_pcm() idea can work,
but it seems a littl bit hackish for me.
So, can you please

1) Add soc_component_is_pcm() on simple-card, not soc-core ?
   Maybe we can move it to soc-core later,
   but want to keep it under simple-card, so far.

2) Use it with data->component_chaining, and some comment ?
   non component_chaining user doesn't get damage in worst case,
   and easy to understand.

	/*
	 * This is for BE<->BE connection.
	 * It needs to ...
	 * It is assumng ...
	 * Note is ...
	 */
	if (data->component_chaining &&
	    !soc_component_is_pcm(cpus))
		dai_link->no_pcm = 1;

3) maybe you can reuse snd_soc_find_dai() for soc_component_is_pcm() ?

	dai = snd_soc_find_dai(dlc);
	if (dai &&
	    (dai->pcm_new || dai->component->driver->pcm_construct))
		return xxx

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-07-02  8:50                       ` Kuninori Morimoto
  0 siblings, 0 replies; 181+ messages in thread
From: Kuninori Morimoto @ 2020-07-02  8:50 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, nwartikar, lgirdwood, robh+dt, tiwai, viswanathl,
	sharadg, broonie, thierry.reding, linux-tegra, digetx, rlokhande,
	mkumard, dramesh


Hi Sameer

> > I wonder component->driver->non_legacy_dai_naming can't work for you ?
> 
> I see currently in simple-card driver that, BE<->BE link would be
> treated as CODEC<->CODEC link if 'non_legacy_dai_naming' flag is set
> at both ends of BE. Do we need to set this flag for all BE?
> However I am not sure how this will work out for a BE<->BE DPCM DAI
> link considering the fact that I want to use chain of components and I
> guess routing map would get complicated. Also going by the flag name
> it was not meant to differentiate between a FE and BE?

OK, non_legacy_dai_naming was just my quick idea.

Maybe your soc_component_is_pcm() idea can work,
but it seems a littl bit hackish for me.
So, can you please

1) Add soc_component_is_pcm() on simple-card, not soc-core ?
   Maybe we can move it to soc-core later,
   but want to keep it under simple-card, so far.

2) Use it with data->component_chaining, and some comment ?
   non component_chaining user doesn't get damage in worst case,
   and easy to understand.

	/*
	 * This is for BE<->BE connection.
	 * It needs to ...
	 * It is assumng ...
	 * Note is ...
	 */
	if (data->component_chaining &&
	    !soc_component_is_pcm(cpus))
		dai_link->no_pcm = 1;

3) maybe you can reuse snd_soc_find_dai() for soc_component_is_pcm() ?

	dai = snd_soc_find_dai(dlc);
	if (dai &&
	    (dai->pcm_new || dai->component->driver->pcm_construct))
		return xxx

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
  2020-07-02  8:50                       ` Kuninori Morimoto
  (?)
@ 2020-07-02  9:56                           ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-02  9:56 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 7/2/2020 2:20 PM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>> I wonder component->driver->non_legacy_dai_naming can't work for you ?
>> I see currently in simple-card driver that, BE<->BE link would be
>> treated as CODEC<->CODEC link if 'non_legacy_dai_naming' flag is set
>> at both ends of BE. Do we need to set this flag for all BE?
>> However I am not sure how this will work out for a BE<->BE DPCM DAI
>> link considering the fact that I want to use chain of components and I
>> guess routing map would get complicated. Also going by the flag name
>> it was not meant to differentiate between a FE and BE?
> OK, non_legacy_dai_naming was just my quick idea.

>
> Maybe your soc_component_is_pcm() idea can work,
> but it seems a littl bit hackish for me.
> So, can you please
>
> 1) Add soc_component_is_pcm() on simple-card, not soc-core ?
>     Maybe we can move it to soc-core later,
>     but want to keep it under simple-card, so far.
>
> 2) Use it with data->component_chaining, and some comment ?
>     non component_chaining user doesn't get damage in worst case,
>     and easy to understand.
>
>          /*
>           * This is for BE<->BE connection.
>           * It needs to ...
>           * It is assumng ...
>           * Note is ...
>           */
>          if (data->component_chaining &&
>              !soc_component_is_pcm(cpus))
>                  dai_link->no_pcm = 1;
>
> 3) maybe you can reuse snd_soc_find_dai() for soc_component_is_pcm() ?
>
>          dai = snd_soc_find_dai(dlc);
>          if (dai &&
>              (dai->pcm_new || dai->component->driver->pcm_construct))
>                  return xxx

Sounds fine, I can make changes as per above points. Thanks.

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-07-02  9:56                           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-02  9:56 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: spujar, broonie, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 7/2/2020 2:20 PM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>> I wonder component->driver->non_legacy_dai_naming can't work for you ?
>> I see currently in simple-card driver that, BE<->BE link would be
>> treated as CODEC<->CODEC link if 'non_legacy_dai_naming' flag is set
>> at both ends of BE. Do we need to set this flag for all BE?
>> However I am not sure how this will work out for a BE<->BE DPCM DAI
>> link considering the fact that I want to use chain of components and I
>> guess routing map would get complicated. Also going by the flag name
>> it was not meant to differentiate between a FE and BE?
> OK, non_legacy_dai_naming was just my quick idea.

>
> Maybe your soc_component_is_pcm() idea can work,
> but it seems a littl bit hackish for me.
> So, can you please
>
> 1) Add soc_component_is_pcm() on simple-card, not soc-core ?
>     Maybe we can move it to soc-core later,
>     but want to keep it under simple-card, so far.
>
> 2) Use it with data->component_chaining, and some comment ?
>     non component_chaining user doesn't get damage in worst case,
>     and easy to understand.
>
>          /*
>           * This is for BE<->BE connection.
>           * It needs to ...
>           * It is assumng ...
>           * Note is ...
>           */
>          if (data->component_chaining &&
>              !soc_component_is_pcm(cpus))
>                  dai_link->no_pcm = 1;
>
> 3) maybe you can reuse snd_soc_find_dai() for soc_component_is_pcm() ?
>
>          dai = snd_soc_find_dai(dlc);
>          if (dai &&
>              (dai->pcm_new || dai->component->driver->pcm_construct))
>                  return xxx

Sounds fine, I can make changes as per above points. Thanks.

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM
@ 2020-07-02  9:56                           ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-02  9:56 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	linux-kernel, spujar, nwartikar, lgirdwood, robh+dt, tiwai,
	viswanathl, sharadg, broonie, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 7/2/2020 2:20 PM, Kuninori Morimoto wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sameer
>
>>> I wonder component->driver->non_legacy_dai_naming can't work for you ?
>> I see currently in simple-card driver that, BE<->BE link would be
>> treated as CODEC<->CODEC link if 'non_legacy_dai_naming' flag is set
>> at both ends of BE. Do we need to set this flag for all BE?
>> However I am not sure how this will work out for a BE<->BE DPCM DAI
>> link considering the fact that I want to use chain of components and I
>> guess routing map would get complicated. Also going by the flag name
>> it was not meant to differentiate between a FE and BE?
> OK, non_legacy_dai_naming was just my quick idea.

>
> Maybe your soc_component_is_pcm() idea can work,
> but it seems a littl bit hackish for me.
> So, can you please
>
> 1) Add soc_component_is_pcm() on simple-card, not soc-core ?
>     Maybe we can move it to soc-core later,
>     but want to keep it under simple-card, so far.
>
> 2) Use it with data->component_chaining, and some comment ?
>     non component_chaining user doesn't get damage in worst case,
>     and easy to understand.
>
>          /*
>           * This is for BE<->BE connection.
>           * It needs to ...
>           * It is assumng ...
>           * Note is ...
>           */
>          if (data->component_chaining &&
>              !soc_component_is_pcm(cpus))
>                  dai_link->no_pcm = 1;
>
> 3) maybe you can reuse snd_soc_find_dai() for soc_component_is_pcm() ?
>
>          dai = snd_soc_find_dai(dlc);
>          if (dai &&
>              (dai->pcm_new || dai->component->driver->pcm_construct))
>                  return xxx

Sounds fine, I can make changes as per above points. Thanks.

>
> Thank you for your help !!
>
> Best regards
> ---
> Kuninori Morimoto


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-06-30 15:32                                     ` Mark Brown
  (?)
@ 2020-07-02 10:36                                         ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-02 10:36 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, Kuninori Morimoto,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w



On 6/30/2020 9:02 PM, Mark Brown wrote:
> On Tue, Jun 30, 2020 at 06:23:49PM +0530, Sameer Pujar wrote:
>> On 6/30/2020 4:31 PM, Mark Brown wrote:
>>> Why simple-card and not audio-graph-card?
>> Frankly speaking I have not used audio-graph-card before. I had a brief look
>> at the related binding. It seems it can use similar DT properties that
>> simple-card uses, although the binding style appears to be different.
>> However I am not sure if it offers better solutions to the problems I am
>> facing. For example, the ability to connect or form a chain of components to
>> realize more complicated use cases with DPCM, some of which were discussed
>> in [0]. Can you please help me understand why it could be preferred?
>> [0] https://lkml.org/lkml/2020/4/30/519
> It's the more modern thing which covers everything simple-card does and
> more, I'd expect new development to go into that rather than
> simple-card.

Hi Mark & Kuninori,

For the HW I am using, there are no fixed endpoints and I am not sure if 
it is allowed to have empty endpoints in audio-graph-card. 
Crossbar/router provides the flexibility to connect the components in 
any required order. Patch [05/23] exposes required graph and MUX 
controls for the flexible configurations. Mostly, in DT, I am trying to 
model the component itself and finally router can help me specify the 
audio path to interconnect various components. Hence I was trying to 
understand if it is really necessary to represent the links using 
audio-graph-card. Kindly help me understand what more it offers. If 
simple-card works fine, are we allowed to use it?

Thank you,
Sameer.

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-07-02 10:36                                         ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-02 10:36 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar, Kuninori Morimoto, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka



On 6/30/2020 9:02 PM, Mark Brown wrote:
> On Tue, Jun 30, 2020 at 06:23:49PM +0530, Sameer Pujar wrote:
>> On 6/30/2020 4:31 PM, Mark Brown wrote:
>>> Why simple-card and not audio-graph-card?
>> Frankly speaking I have not used audio-graph-card before. I had a brief look
>> at the related binding. It seems it can use similar DT properties that
>> simple-card uses, although the binding style appears to be different.
>> However I am not sure if it offers better solutions to the problems I am
>> facing. For example, the ability to connect or form a chain of components to
>> realize more complicated use cases with DPCM, some of which were discussed
>> in [0]. Can you please help me understand why it could be preferred?
>> [0] https://lkml.org/lkml/2020/4/30/519
> It's the more modern thing which covers everything simple-card does and
> more, I'd expect new development to go into that rather than
> simple-card.

Hi Mark & Kuninori,

For the HW I am using, there are no fixed endpoints and I am not sure if 
it is allowed to have empty endpoints in audio-graph-card. 
Crossbar/router provides the flexibility to connect the components in 
any required order. Patch [05/23] exposes required graph and MUX 
controls for the flexible configurations. Mostly, in DT, I am trying to 
model the component itself and finally router can help me specify the 
audio path to interconnect various components. Hence I was trying to 
understand if it is really necessary to represent the links using 
audio-graph-card. Kindly help me understand what more it offers. If 
simple-card works fine, are we allowed to use it?

Thank you,
Sameer.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-07-02 10:36                                         ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-02 10:36 UTC (permalink / raw)
  To: Mark Brown
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	Kuninori Morimoto, linux-kernel, spujar, nwartikar, lgirdwood,
	tiwai, viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh



On 6/30/2020 9:02 PM, Mark Brown wrote:
> On Tue, Jun 30, 2020 at 06:23:49PM +0530, Sameer Pujar wrote:
>> On 6/30/2020 4:31 PM, Mark Brown wrote:
>>> Why simple-card and not audio-graph-card?
>> Frankly speaking I have not used audio-graph-card before. I had a brief look
>> at the related binding. It seems it can use similar DT properties that
>> simple-card uses, although the binding style appears to be different.
>> However I am not sure if it offers better solutions to the problems I am
>> facing. For example, the ability to connect or form a chain of components to
>> realize more complicated use cases with DPCM, some of which were discussed
>> in [0]. Can you please help me understand why it could be preferred?
>> [0] https://lkml.org/lkml/2020/4/30/519
> It's the more modern thing which covers everything simple-card does and
> more, I'd expect new development to go into that rather than
> simple-card.

Hi Mark & Kuninori,

For the HW I am using, there are no fixed endpoints and I am not sure if 
it is allowed to have empty endpoints in audio-graph-card. 
Crossbar/router provides the flexibility to connect the components in 
any required order. Patch [05/23] exposes required graph and MUX 
controls for the flexible configurations. Mostly, in DT, I am trying to 
model the component itself and finally router can help me specify the 
audio path to interconnect various components. Hence I was trying to 
understand if it is really necessary to represent the links using 
audio-graph-card. Kindly help me understand what more it offers. If 
simple-card works fine, are we allowed to use it?

Thank you,
Sameer.


^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-07-02 10:36                                         ` Sameer Pujar
  (?)
@ 2020-07-02 12:26                                             ` Mark Brown
  -1 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-07-02 12:26 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: Kuninori Morimoto, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w

[-- Attachment #1: Type: text/plain, Size: 865 bytes --]

On Thu, Jul 02, 2020 at 04:06:14PM +0530, Sameer Pujar wrote:

> For the HW I am using, there are no fixed endpoints and I am not sure if it
> is allowed to have empty endpoints in audio-graph-card. Crossbar/router
> provides the flexibility to connect the components in any required order.
> Patch [05/23] exposes required graph and MUX controls for the flexible
> configurations. Mostly, in DT, I am trying to model the component itself and
> finally router can help me specify the audio path to interconnect various
> components. Hence I was trying to understand if it is really necessary to
> represent the links using audio-graph-card. Kindly help me understand what
> more it offers. If simple-card works fine, are we allowed to use it?

The links in the graph card should be the physical links at the edge of
the devices, those must be fixed no matter what.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-07-02 12:26                                             ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-07-02 12:26 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: Kuninori Morimoto, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka

[-- Attachment #1: Type: text/plain, Size: 865 bytes --]

On Thu, Jul 02, 2020 at 04:06:14PM +0530, Sameer Pujar wrote:

> For the HW I am using, there are no fixed endpoints and I am not sure if it
> is allowed to have empty endpoints in audio-graph-card. Crossbar/router
> provides the flexibility to connect the components in any required order.
> Patch [05/23] exposes required graph and MUX controls for the flexible
> configurations. Mostly, in DT, I am trying to model the component itself and
> finally router can help me specify the audio path to interconnect various
> components. Hence I was trying to understand if it is really necessary to
> represent the links using audio-graph-card. Kindly help me understand what
> more it offers. If simple-card works fine, are we allowed to use it?

The links in the graph card should be the physical links at the edge of
the devices, those must be fixed no matter what.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-07-02 12:26                                             ` Mark Brown
  0 siblings, 0 replies; 181+ messages in thread
From: Mark Brown @ 2020-07-02 12:26 UTC (permalink / raw)
  To: Sameer Pujar
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	Kuninori Morimoto, linux-kernel, nwartikar, lgirdwood, tiwai,
	viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh

[-- Attachment #1: Type: text/plain, Size: 865 bytes --]

On Thu, Jul 02, 2020 at 04:06:14PM +0530, Sameer Pujar wrote:

> For the HW I am using, there are no fixed endpoints and I am not sure if it
> is allowed to have empty endpoints in audio-graph-card. Crossbar/router
> provides the flexibility to connect the components in any required order.
> Patch [05/23] exposes required graph and MUX controls for the flexible
> configurations. Mostly, in DT, I am trying to model the component itself and
> finally router can help me specify the audio path to interconnect various
> components. Hence I was trying to understand if it is really necessary to
> represent the links using audio-graph-card. Kindly help me understand what
> more it offers. If simple-card works fine, are we allowed to use it?

The links in the graph card should be the physical links at the edge of
the devices, those must be fixed no matter what.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
  2020-07-02 12:26                                             ` Mark Brown
  (?)
@ 2020-07-17 12:55                                                 ` Sameer Pujar
  -1 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-17 12:55 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar-DDmLM1+adcrQT0dZR+AlfA, Kuninori Morimoto,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	jonathanh-DDmLM1+adcrQT0dZR+AlfA, digetx-Re5JQEeQqe8AvxtiuMwx3w,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	sharadg-DDmLM1+adcrQT0dZR+AlfA, mkumard-DDmLM1+adcrQT0dZR+AlfA,
	viswanathl-DDmLM1+adcrQT0dZR+AlfA,
	rlokhande-DDmLM1+adcrQT0dZR+AlfA, dramesh-DDmLM1+adcrQT0dZR+AlfA,
	atalambedu-DDmLM1+adcrQT0dZR+AlfA,
	nwartikar-DDmLM1+adcrQT0dZR+AlfA, swarren-DDmLM1+adcrQT0dZR+AlfA,
	nicoleotsuka-Re5JQEeQqe8AvxtiuMwx3w

Hi Mark,


On 7/2/2020 5:56 PM, Mark Brown wrote:
> On Thu, Jul 02, 2020 at 04:06:14PM +0530, Sameer Pujar wrote:
>
>> For the HW I am using, there are no fixed endpoints and I am not sure if it
>> is allowed to have empty endpoints in audio-graph-card. Crossbar/router
>> provides the flexibility to connect the components in any required order.
>> Patch [05/23] exposes required graph and MUX controls for the flexible
>> configurations. Mostly, in DT, I am trying to model the component itself and
>> finally router can help me specify the audio path to interconnect various
>> components. Hence I was trying to understand if it is really necessary to
>> represent the links using audio-graph-card. Kindly help me understand what
>> more it offers. If simple-card works fine, are we allowed to use it?
> The links in the graph card should be the physical links at the edge of
> the devices, those must be fixed no matter what.

I used graph-card and could get few things working with it. Based on the 
feedback so far, I am planning to split the series as suggested and send 
two series as below.
[1] Tegra AHUB series and related DT bindings as V5.
[2] Audio graph card enhancements and related DT bindings for Tegra 
platforms as V1.

Thanks,
Sameer.

^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-07-17 12:55                                                 ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-17 12:55 UTC (permalink / raw)
  To: Mark Brown
  Cc: spujar, Kuninori Morimoto, perex, tiwai, robh+dt, lgirdwood,
	thierry.reding, jonathanh, digetx, alsa-devel, linux-tegra,
	linux-kernel, sharadg, mkumard, viswanathl, rlokhande, dramesh,
	atalambedu, nwartikar, swarren, nicoleotsuka

Hi Mark,


On 7/2/2020 5:56 PM, Mark Brown wrote:
> On Thu, Jul 02, 2020 at 04:06:14PM +0530, Sameer Pujar wrote:
>
>> For the HW I am using, there are no fixed endpoints and I am not sure if it
>> is allowed to have empty endpoints in audio-graph-card. Crossbar/router
>> provides the flexibility to connect the components in any required order.
>> Patch [05/23] exposes required graph and MUX controls for the flexible
>> configurations. Mostly, in DT, I am trying to model the component itself and
>> finally router can help me specify the audio path to interconnect various
>> components. Hence I was trying to understand if it is really necessary to
>> represent the links using audio-graph-card. Kindly help me understand what
>> more it offers. If simple-card works fine, are we allowed to use it?
> The links in the graph card should be the physical links at the edge of
> the devices, those must be fixed no matter what.

I used graph-card and could get few things working with it. Based on the 
feedback so far, I am planning to split the series as suggested and send 
two series as below.
[1] Tegra AHUB series and related DT bindings as V5.
[2] Audio graph card enhancements and related DT bindings for Tegra 
platforms as V1.

Thanks,
Sameer.



^ permalink raw reply	[flat|nested] 181+ messages in thread

* Re: Re: Re: Re: [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs
@ 2020-07-17 12:55                                                 ` Sameer Pujar
  0 siblings, 0 replies; 181+ messages in thread
From: Sameer Pujar @ 2020-07-17 12:55 UTC (permalink / raw)
  To: Mark Brown
  Cc: jonathanh, nicoleotsuka, alsa-devel, atalambedu, swarren,
	Kuninori Morimoto, linux-kernel, spujar, nwartikar, lgirdwood,
	tiwai, viswanathl, sharadg, robh+dt, thierry.reding, linux-tegra,
	digetx, rlokhande, mkumard, dramesh

Hi Mark,


On 7/2/2020 5:56 PM, Mark Brown wrote:
> On Thu, Jul 02, 2020 at 04:06:14PM +0530, Sameer Pujar wrote:
>
>> For the HW I am using, there are no fixed endpoints and I am not sure if it
>> is allowed to have empty endpoints in audio-graph-card. Crossbar/router
>> provides the flexibility to connect the components in any required order.
>> Patch [05/23] exposes required graph and MUX controls for the flexible
>> configurations. Mostly, in DT, I am trying to model the component itself and
>> finally router can help me specify the audio path to interconnect various
>> components. Hence I was trying to understand if it is really necessary to
>> represent the links using audio-graph-card. Kindly help me understand what
>> more it offers. If simple-card works fine, are we allowed to use it?
> The links in the graph card should be the physical links at the edge of
> the devices, those must be fixed no matter what.

I used graph-card and could get few things working with it. Based on the 
feedback so far, I am planning to split the series as suggested and send 
two series as below.
[1] Tegra AHUB series and related DT bindings as V5.
[2] Audio graph card enhancements and related DT bindings for Tegra 
platforms as V1.

Thanks,
Sameer.



^ permalink raw reply	[flat|nested] 181+ messages in thread

end of thread, other threads:[~2020-07-17 12:56 UTC | newest]

Thread overview: 181+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-27  4:53 [PATCH v4 00/23] Add support for Tegra210 Audio Sameer Pujar
2020-06-27  4:53 ` Sameer Pujar
2020-06-27  4:53 ` Sameer Pujar
2020-06-27  4:53 ` [PATCH v4 07/23] ASoC: tegra: Add Tegra210 based ADMAIF driver Sameer Pujar
2020-06-27  4:53   ` Sameer Pujar
2020-06-27  4:53   ` Sameer Pujar
2020-06-27  4:53 ` [PATCH v4 15/23] ASoC: soc-core: Identify 'no_pcm' DAI links for DPCM Sameer Pujar
2020-06-27  4:53   ` Sameer Pujar
2020-06-27  4:53   ` Sameer Pujar
     [not found]   ` <1593233625-14961-16-git-send-email-spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-29  1:38     ` Kuninori Morimoto
2020-06-29  1:38       ` Kuninori Morimoto
2020-06-29  1:38       ` Kuninori Morimoto
2020-06-29 17:19       ` Sameer Pujar
2020-06-29 17:19         ` Sameer Pujar
2020-06-30  6:07     ` Kuninori Morimoto
2020-06-30  6:07       ` Kuninori Morimoto
2020-06-30  6:07       ` Kuninori Morimoto
     [not found]       ` <87h7utytlx.wl-kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2020-06-30  8:03         ` Sameer Pujar
2020-06-30  8:03           ` Sameer Pujar
2020-06-30  8:03           ` Sameer Pujar
     [not found]           ` <9c7871ae-6649-7b0d-4780-c8389c299b04-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-07-02  0:52             ` Kuninori Morimoto
2020-07-02  0:52               ` Kuninori Morimoto
2020-07-02  0:52               ` Kuninori Morimoto
     [not found]               ` <87d05ezqlc.wl-kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2020-07-02  3:48                 ` Sameer Pujar
2020-07-02  3:48                   ` Sameer Pujar
2020-07-02  3:48                   ` Sameer Pujar
     [not found]                   ` <49bac9c1-093c-d353-cef3-c9c3391cc00d-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-07-02  8:50                     ` Kuninori Morimoto
2020-07-02  8:50                       ` Kuninori Morimoto
2020-07-02  8:50                       ` Kuninori Morimoto
     [not found]                       ` <875zb6z4fq.wl-kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2020-07-02  9:56                         ` Sameer Pujar
2020-07-02  9:56                           ` Sameer Pujar
2020-07-02  9:56                           ` Sameer Pujar
     [not found] ` <1593233625-14961-1-git-send-email-spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-27  4:53   ` [PATCH v4 01/23] ASoC: dt-bindings: tegra: Add DT bindings for Tegra210 Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 02/23] ASoC: tegra: Add support for CIF programming Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 03/23] ASoC: tegra: Add Tegra210 based DMIC driver Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 04/23] ASoC: tegra: Add Tegra210 based I2S driver Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 05/23] ASoC: tegra: Add Tegra210 based AHUB driver Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 06/23] ASoC: tegra: Add Tegra186 based DSPK driver Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 08/23] ASoC: soc-core: Fix component name_prefix parsing Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
     [not found]     ` <1593233625-14961-9-git-send-email-spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-29  0:38       ` Kuninori Morimoto
2020-06-29  0:38         ` Kuninori Morimoto
2020-06-29  0:38         ` Kuninori Morimoto
2020-06-29 15:46         ` Sameer Pujar
2020-06-29 15:46           ` Sameer Pujar
2020-06-30 10:45       ` Mark Brown
2020-06-30 10:45         ` Mark Brown
2020-06-30 10:45         ` Mark Brown
     [not found]         ` <20200630104514.GE5272-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2020-06-30 12:56           ` Sameer Pujar
2020-06-30 12:56             ` Sameer Pujar
2020-06-30 12:56             ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 09/23] ASoC: simple-card: Use of_node and DAI names for DAI link names Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 10/23] ASoC: simple-card: Wrong daifmt for CPU end of DPCM DAI link Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
     [not found]     ` <1593233625-14961-11-git-send-email-spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-29  0:56       ` Kuninori Morimoto
2020-06-29  0:56         ` Kuninori Morimoto
2020-06-29  0:56         ` Kuninori Morimoto
2020-06-29 16:06         ` Sameer Pujar
     [not found]           ` <6e27daa5-331e-968b-4027-2e30aeb7d382-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-30  0:56             ` Kuninori Morimoto
2020-06-30  0:56               ` Kuninori Morimoto
2020-06-30  0:56               ` Kuninori Morimoto
     [not found]               ` <87o8p1z81b.wl-kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2020-06-30  3:47                 ` Sameer Pujar
2020-06-30  3:47                   ` Sameer Pujar
2020-06-30  3:47                   ` Sameer Pujar
     [not found]                   ` <841ac69f-1c3f-2b13-17f9-6f196811ce52-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-30  5:07                     ` Kuninori Morimoto
2020-06-30  5:07                       ` Kuninori Morimoto
2020-06-30  5:07                       ` Kuninori Morimoto
2020-06-27  4:53   ` [PATCH v4 11/23] ASoC: simple-card: Loop over all children for 'mclk-fs' Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
     [not found]     ` <1593233625-14961-12-git-send-email-spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-29  1:05       ` Kuninori Morimoto
2020-06-29  1:05         ` Kuninori Morimoto
2020-06-29  1:05         ` Kuninori Morimoto
2020-06-29 16:32         ` Sameer Pujar
2020-06-29 16:32           ` Sameer Pujar
     [not found]           ` <58000bd3-861c-bbc2-75e1-128cf0199a76-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-30  2:08             ` Kuninori Morimoto
2020-06-30  2:08               ` Kuninori Morimoto
2020-06-30  2:08               ` Kuninori Morimoto
     [not found]               ` <87lfk5z4ov.wl-kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2020-06-30  4:23                 ` Sameer Pujar
2020-06-30  4:23                   ` Sameer Pujar
2020-06-30  4:23                   ` Sameer Pujar
     [not found]                   ` <b33d5a1b-ecd5-3618-4894-c3ab0f4b077d-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-30 10:55                     ` Mark Brown
2020-06-30 10:55                       ` Mark Brown
2020-06-30 10:55                       ` Mark Brown
2020-06-30 11:56                       ` Sameer Pujar
2020-06-30 11:56                         ` Sameer Pujar
2020-06-30 11:56                         ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 12/23] ASoC: simple-card: Support DPCM DAI link with multiple Codecs Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
     [not found]     ` <1593233625-14961-13-git-send-email-spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-29  1:24       ` Kuninori Morimoto
2020-06-29  1:24         ` Kuninori Morimoto
2020-06-29  1:24         ` Kuninori Morimoto
2020-06-29 17:16         ` Sameer Pujar
2020-06-29 17:16           ` Sameer Pujar
     [not found]           ` <1e0cf6d1-bf4e-8808-5390-c8a3b7c7fe7e-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-30  1:24             ` Kuninori Morimoto
2020-06-30  1:24               ` Kuninori Morimoto
2020-06-30  1:24               ` Kuninori Morimoto
     [not found]               ` <87mu4lz6pt.wl-kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2020-06-30  4:08                 ` Sameer Pujar
2020-06-30  4:08                   ` Sameer Pujar
2020-06-30  4:08                   ` Sameer Pujar
     [not found]                   ` <1d7888c7-a8cc-e891-01aa-016e31cc9113-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-30  6:55                     ` Kuninori Morimoto
2020-06-30  6:55                       ` Kuninori Morimoto
2020-06-30  6:55                       ` Kuninori Morimoto
     [not found]                       ` <87ftadyrec.wl-kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2020-06-30  7:52                         ` Sameer Pujar
2020-06-30  7:52                           ` Sameer Pujar
2020-06-30  7:52                           ` Sameer Pujar
     [not found]                           ` <492079e9-4518-78ba-a227-859d31594369-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-30 11:01                             ` Mark Brown
2020-06-30 11:01                               ` Mark Brown
2020-06-30 11:01                               ` Mark Brown
     [not found]                               ` <20200630110100.GH5272-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2020-06-30 12:53                                 ` Sameer Pujar
2020-06-30 12:53                                   ` Sameer Pujar
2020-06-30 12:53                                   ` Sameer Pujar
2020-06-30 15:32                                   ` Mark Brown
2020-06-30 15:32                                     ` Mark Brown
     [not found]                                     ` <20200630153220.GL5272-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2020-07-02 10:36                                       ` Sameer Pujar
2020-07-02 10:36                                         ` Sameer Pujar
2020-07-02 10:36                                         ` Sameer Pujar
     [not found]                                         ` <fb286ab7-21f2-43ad-2751-c76b7b6e4cf2-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-07-02 12:26                                           ` Mark Brown
2020-07-02 12:26                                             ` Mark Brown
2020-07-02 12:26                                             ` Mark Brown
     [not found]                                             ` <20200702122605.GE4483-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2020-07-17 12:55                                               ` Sameer Pujar
2020-07-17 12:55                                                 ` Sameer Pujar
2020-07-17 12:55                                                 ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 13/23] ASoC: simple-card: DPCM DAI link direction as per DAI capability Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 14/23] ASoC: soc-core: Probe auxiliary component before others Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 16/23] ASoC: soc-pcm: Get all BEs along DAPM path Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
     [not found]     ` <1593233625-14961-17-git-send-email-spujar-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2020-06-29  1:41       ` Kuninori Morimoto
2020-06-29  1:41         ` Kuninori Morimoto
2020-06-29  1:41         ` Kuninori Morimoto
2020-06-29 17:29         ` Sameer Pujar
2020-06-29 17:29           ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 17/23] ASoC: dt-bindings: simple-card: Add compatible for component chaining Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 19/23] arm64: defconfig: Build AHUB component drivers Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 20/23] arm64: defconfig: Enable CONFIG_TEGRA210_ADMA Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 21/23] arm64: tegra: Add DT binding for AHUB components Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 22/23] arm64: tegra: Enable AHUB components on few Tegra platforms Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53   ` [PATCH v4 23/23] arm64: tegra: Add support for APE sound card on Jetson Nano and TX1 Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-27  4:53     ` Sameer Pujar
2020-06-30 10:51   ` [PATCH v4 00/23] Add support for Tegra210 Audio Mark Brown
2020-06-30 10:51     ` Mark Brown
2020-06-30 10:51     ` Mark Brown
2020-06-30 11:54     ` Sameer Pujar
2020-06-30 11:54       ` Sameer Pujar
2020-06-30 11:54       ` Sameer Pujar
2020-06-27  4:53 ` [PATCH v4 18/23] ASoC: simple-card: Add support for component chaining Sameer Pujar
2020-06-27  4:53   ` Sameer Pujar
2020-06-27  4:53   ` Sameer Pujar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.