mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
ASoC: tegra: merge 'tegra' and 'tegra-alt' directories
Tegra210 and later audio drivers have been using 'tegra-alt' directory from the beginning. As per the upstream roadmap, we plan to use the same 'tegra' directory and place all the drivers under it. This patch thus moves all the drivers to 'tegra' and renames the files accordingly. The '_alt' suffix is removed from header and source files. For some files still the '_alt' suffix is retained because 'tegra' already has the corresponding files. Manual merge of following files is needed and will be done in separate commits. * tegra_asoc_utils_alt.c and tegra_asoc_utils.c * tegra_asoc_utils_alt.h and tegra_asoc_utils.h * tegra_pcm_alt.c and tegra_pcm.c * tegra_pcm_alt.h and tegra_pcm.h * Corresponding Makefile and Kconfig files. * Source files related to ADSP audio, FPGA, bandwidth manager are not considered at the moment and will be tracked separately. Bug 2845498 Change-Id: I51dae3971c72b58d921dc19f0553a83422fd3f9e Signed-off-by: Sameer Pujar <spujar@nvidia.com>
This commit is contained in:
@@ -1,255 +0,0 @@
|
||||
/*
|
||||
* tegra210_spdif.h - Definitions for Tegra210 SPDIF driver
|
||||
*
|
||||
* Copyright (c) 2014-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TEGRA210_SPDIF_ALT_H__
|
||||
#define __TEGRA210_SPDIF_ALT_H__
|
||||
|
||||
/* Register offsets from TEGRA_SPDIF_BASE */
|
||||
|
||||
#define TEGRA210_SPDIF_CTRL 0x0
|
||||
#define TEGRA210_SPDIF_STROBE_CTRL 0x4
|
||||
#define TEGRA210_SPDIF_CIF_TXD_CTRL 0x08
|
||||
#define TEGRA210_SPDIF_CIF_RXD_CTRL 0x0C
|
||||
#define TEGRA210_SPDIF_CIF_TXU_CTRL 0x10
|
||||
#define TEGRA210_SPDIF_CIF_RXU_CTRL 0x14
|
||||
#define TEGRA210_SPDIF_CH_STA_RX_A 0x18
|
||||
#define TEGRA210_SPDIF_CH_STA_RX_B 0x1C
|
||||
#define TEGRA210_SPDIF_CH_STA_RX_C 0x20
|
||||
#define TEGRA210_SPDIF_CH_STA_RX_D 0x24
|
||||
#define TEGRA210_SPDIF_CH_STA_RX_E 0x28
|
||||
#define TEGRA210_SPDIF_CH_STA_RX_F 0x2C
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A 0x30
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B 0x34
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_C 0x38
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_D 0x3C
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_E 0x40
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_F 0x44
|
||||
#define TEGRA210_SPDIF_FLOWCTL_CTRL 0x70
|
||||
#define TEGRA210_SPDIF_TX_STEP 0x74
|
||||
#define TEGRA210_SPDIF_FLOW_STATUS 0x78
|
||||
#define TEGRA210_SPDIF_FLOW_TOTAL 0x7c
|
||||
#define TEGRA210_SPDIF_FLOW_OVER 0x80
|
||||
#define TEGRA210_SPDIF_FLOW_UNDER 0x84
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_0 0x88
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_1 0x8c
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_2 0x90
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_3 0x94
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_4 0x98
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_5 0x9c
|
||||
#define TEGRA210_SPDIF_LCOEF_2_4_0 0xa0
|
||||
#define TEGRA210_SPDIF_LCOEF_2_4_1 0xa4
|
||||
#define TEGRA210_SPDIF_LCOEF_2_4_2 0xa8
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_CTRL */
|
||||
#define TEGRA210_SPDIF_CTRL_FLOWCTL_EN_ENABLE (1<<31)
|
||||
#define TEGRA210_SPDIF_CTRL_CAP_LC_LEFT_CH (1<<30)
|
||||
#define TEGRA210_SPDIF_CTRL_RX_EN_ENABLE (1<<29)
|
||||
#define TEGRA210_SPDIF_CTRL_TX_EN_ENABLE (1<<28)
|
||||
#define TEGRA210_SPDIF_CTRL_TC_EN_ENABLE (1<<27)
|
||||
#define TEGRA210_SPDIF_CTRL_TU_EN_ENABLE (1<<26)
|
||||
#define TEGRA210_SPDIF_CTRL_IE_P_RSVD_ENABLE (1<<23)
|
||||
#define TEGRA210_SPDIF_CTRL_IE_B_RSVD_ENABLE (1<<22)
|
||||
#define TEGRA210_SPDIF_CTRL_IE_C_RSVD_ENABLE (1<<21)
|
||||
#define TEGRA210_SPDIF_CTRL_IE_U_RSVD_ENABLE (1<<20)
|
||||
#define TEGRA210_SPDIF_CTRL_LBK_EN_ENABLE_MASK (1<<15)
|
||||
#define TEGRA210_SPDIF_CTRL_LBK_EN_ENABLE_SHIFT 15
|
||||
#define TEGRA210_SPDIF_CTRL_PACK_ENABLE (1<<14)
|
||||
|
||||
#define TEGRA210_SPDIF_BIT_MODE16 0
|
||||
#define TEGRA210_SPDIF_BIT_MODE20 1
|
||||
#define TEGRA210_SPDIF_BIT_MODE24 2
|
||||
#define TEGRA210_SPDIF_BIT_MODERAW 3
|
||||
|
||||
#define TEGRA210_SPDIF_CTRL_BIT_MODE_SHIFT 12
|
||||
#define TEGRA210_SPDIF_CTRL_BIT_MODE_MASK (3 << TEGRA210_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
#define TEGRA210_SPDIF_CTRL_BIT_MODE_16BIT (TEGRA210_SPDIF_BIT_MODE16 << TEGRA210_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
#define TEGRA210_SPDIF_CTRL_BIT_MODE_20BIT (TEGRA210_SPDIF_BIT_MODE20 << TEGRA210_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
#define TEGRA210_SPDIF_CTRL_BIT_MODE_24BIT (TEGRA210_SPDIF_BIT_MODE24 << TEGRA210_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
#define TEGRA210_SPDIF_CTRL_BIT_MODE_RAW (TEGRA210_SPDIF_BIT_MODERAW << TEGRA210_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
|
||||
#define TEGRA210_SPDIF_CTRL_CG_EN_ENABLE (1<<11)
|
||||
|
||||
#define TEGRA210_SPDIF_CTRL_OBS_SEL_SHIFT 8
|
||||
#define TEGRA210_SPDIF_CTRL_OBS_SEL_NASK (0x7 << TEGRA210_SPDIF_CTRL_OBS_SEL_SHIFT)
|
||||
|
||||
#define TEGRA210_SPDIF_CTRL_SOFT_RESET_ENABLE (1<<7)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_STROBE_CTRL */
|
||||
#define TEGRA210_SPDIF_STROBE_CTRL_PERIOD_SHIFT 16
|
||||
#define TEGRA210_SPDIF_STROBE_CTRL_PERIOD_MASK (0xff << TEGRA210_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
|
||||
|
||||
#define TEGRA210_SPDIF_STROBE_CTRL_STROBE (1<<15)
|
||||
|
||||
#define TEGRA210_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT 8
|
||||
#define TEGRA210_SPDIF_STROBE_CTRL_DATA_STROBES_MASK (0x1f << TEGRA210_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
|
||||
|
||||
#define TEGRA210_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT 0
|
||||
#define TEGRA210_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK (0x3f << TEGRA210_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
|
||||
|
||||
/*
|
||||
* The 6-word receive channel data page buffer holds a block (192 frames) of
|
||||
* channel status information. The order of receive is from LSB to MSB
|
||||
* bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
|
||||
*/
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_CH_STA_TX_A */
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SF_22050 0x4
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SF_24000 0x6
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SF_32000 0x3
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SF_44100 0x0
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SF_48000 0x2
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SF_88200 0x8
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SF_96000 0xA
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SF_176400 0xC
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SF_192000 0xE
|
||||
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT 24
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_MASK \
|
||||
(0xF << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_22050 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_A_SF_22050 << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_24000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_A_SF_24000 << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_32000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_A_SF_32000 << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_44100 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_A_SF_44100 << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_48000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_A_SF_48000 << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_88200 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_A_SF_88200 << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_96000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_A_SF_96000 << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_176400 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_A_SF_176400 << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_192000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_A_SF_192000 << TEGRA210_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_CH_STA_TX_B */
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_8000 0x6
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_11025 0xA
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_12000 0x2
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_16000 0x8
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_22050 0xB
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_24000 0x9
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_32000 0xC
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_44100 0xF
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_48000 0xD
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_88200 0x7
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_96000 0x5
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_176400 0x3
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_SF_192000 0x1
|
||||
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT 4
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_MASK \
|
||||
(0xF << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_8000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_8000 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_11025 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_11025 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_12000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_12000 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_16000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_16000 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_22050 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_22025 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_24000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_24000 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_32000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_32000 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_44100 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_44100 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_48000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_48000 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_88200 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_88200 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_96000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_96000 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_176400 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_176400 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
#define TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_192000 \
|
||||
(TEGRA210_SPDIF_CH_STA_TX_B_SF_192000 << TEGRA210_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_CH_STA_TX_C */
|
||||
/* Fields in TEGRA210_SPDIF_CH_STA_TX_D */
|
||||
/* Fields in TEGRA210_SPDIF_CH_STA_TX_E */
|
||||
/* Fields in TEGRA210_SPDIF_CH_STA_TX_F */
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_FLOWCTL_CTRL */
|
||||
#define TEGRA210_SPDIF_FLOWCTL_CTRL_FILTER_QUAD (1<<31)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_TX_STEP */
|
||||
#define TEGRA210_SPDIF_TX_STEP_STEP_SIZE_SHIFT 0
|
||||
#define TEGRA210_SPDIF_TX_STEP_STEP_SIZE_MASK (0xffff << TEGRA210_SPDIF_TX_STEP_STEP_SIZE_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_FLOW_STATUS */
|
||||
#define TEGRA210_SPDIF_FLOW_STATUS_COUNTER_EN_ENABLE (1<<1)
|
||||
#define TEGRA210_SPDIF_FLOW_STATUS_MONITOR_CLR_CLEAR (1<<2)
|
||||
#define TEGRA210_SPDIF_FLOW_STATUS_COUNTER_CLR_CLEAR (1<<3)
|
||||
#define TEGRA210_SPDIF_FLOW_STATUS_MONITOR_INT_EN_ENABLE (1<<4)
|
||||
#define TEGRA210_SPDIF_FLOW_STATUS_FLOW_OVERFLOW_OVER (1<<30)
|
||||
#define TEGRA210_SPDIF_FLOW_STATUS_FLOW_UNDERFLOW_UNDER (1<<31)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_FLOW_TOTAL */
|
||||
/* Fields in TEGRA210_SPDIF_FLOW_OVER */
|
||||
/* Fields in TEGRA210_SPDIF_FLOW_UNDER */
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_LCOEF_1_4_0 */
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_0_COEF_SHIFT 0
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_0_COEF_MASK (0xffff << TEGRA30_TEGRA210_SPDIF_LCOEF_1_4_0_COEF_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_LCOEF_1_4_1 */
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_1_COEF_SHIFT 0
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_1_COEF_MASK (0xffff << TEGRA210_SPDIF_LCOEF_1_4_1_COEF_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_LCOEF_1_4_2 */
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_2_COEF_SHIFT 0
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_2_COEF_MASK (0xffff << TEGRA210_SPDIF_LCOEF_1_4_2_COEF_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_LCOEF_1_4_3 */
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_3_COEF_SHIFT 0
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_3_COEF_MASK (0xffff << TEGRA210_SPDIF_LCOEF_1_4_3_COEF_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_LCOEF_1_4_4 */
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_4_COEF_SHIFT 0
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_4_COEF_MASK (0xffff << TEGRA210_SPDIF_LCOEF_1_4_4_COEF_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_LCOEF_1_4_5 */
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_5_COEF_SHIFT 0
|
||||
#define TEGRA210_SPDIF_LCOEF_1_4_5_COEF_MASK (0xffff << TEGRA210_SPDIF_LCOEF_1_4_5_COEF_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_LCOEF_2_4_0 */
|
||||
#define TEGRA210_SPDIF_LCOEF_2_4_0_COEF_SHIFT 0
|
||||
#define TEGRA210_SPDIF_LCOEF_2_4_0_COEF_MASK (0xffff << TEGRA210_SPDIF_LCOEF_2_4_0_COEF_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_LCOEF_2_4_1 */
|
||||
#define TEGRA210_SPDIF_LCOEF_2_4_1_COEF_SHIFT 0
|
||||
#define TEGRA210_SPDIF_LCOEF_2_4_1_COEF_MASK (0xffff << TEGRA210_SPDIF_LCOEF_2_4_1_COEF_SHIFT)
|
||||
|
||||
/* Fields in TEGRA210_SPDIF_LCOEF_2_4_2 */
|
||||
#define TEGRA210_SPDIF_LCOEF_2_4_2_COEF_SHIFT 0
|
||||
#define TEGRA210_SPDIF_LCOEF_2_4_2_COEF_MASK (0xffff << TEGRA210_SPDIF_LCOEF_2_4_2_COEF_SHIFT)
|
||||
|
||||
struct tegra210_spdif {
|
||||
struct clk *clk_spdif_out;
|
||||
struct clk *clk_spdif_in;
|
||||
struct regmap *regmap;
|
||||
unsigned int loopback;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
* tegra210_xbar_alt.h - TEGRA210 XBAR registers
|
||||
*
|
||||
* Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TEGRA210_XBAR_ALT_H__
|
||||
#define __TEGRA210_XBAR_ALT_H__
|
||||
|
||||
#define TEGRA210_XBAR_PART0_RX 0x0
|
||||
#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
|
||||
|
||||
/* This register repeats twice for each XBAR TX CIF */
|
||||
/* The fields in this register are 1 bit per XBAR RX CIF */
|
||||
|
||||
/* Fields in *_CIF_RX/TX_CTRL; used by AHUB FIFOs, and all other audio modules */
|
||||
|
||||
#define TEGRA210_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT 24
|
||||
/* Channel count minus 1 */
|
||||
#define TEGRA210_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT 20
|
||||
/* Channel count minus 1 */
|
||||
#define TEGRA210_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT 16
|
||||
|
||||
#define TEGRA210_AUDIOCIF_BITS_8 1
|
||||
#define TEGRA210_AUDIOCIF_BITS_16 3
|
||||
#define TEGRA210_AUDIOCIF_BITS_24 5
|
||||
#define TEGRA210_AUDIOCIF_BITS_32 7
|
||||
|
||||
#define TEGRA210_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT 12
|
||||
#define TEGRA210_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT 8
|
||||
#define TEGRA210_AUDIOCIF_CTRL_EXPAND_SHIFT 6
|
||||
#define TEGRA210_AUDIOCIF_CTRL_STEREO_CONV_SHIFT 4
|
||||
#define TEGRA210_AUDIOCIF_CTRL_REPLICATE_SHIFT 3
|
||||
#define TEGRA210_AUDIOCIF_CTRL_TRUNCATE_SHIFT 1
|
||||
#define TEGRA210_AUDIOCIF_CTRL_MONO_CONV_SHIFT 0
|
||||
|
||||
/* Fields in *AHUBRAMCTL_CTRL; used by different AHUB modules */
|
||||
#define TEGRA210_AHUBRAMCTL_CTRL_RW_READ 0
|
||||
#define TEGRA210_AHUBRAMCTL_CTRL_RW_WRITE (1 << 14)
|
||||
#define TEGRA210_AHUBRAMCTL_CTRL_ADDR_INIT_EN (1 << 13)
|
||||
#define TEGRA210_AHUBRAMCTL_CTRL_SEQ_ACCESS_EN (1 << 12)
|
||||
#define TEGRA210_AHUBRAMCTL_CTRL_RAM_ADDR_MASK 0x1ff
|
||||
|
||||
#define TEGRA210_MAX_REGISTER_ADDR (TEGRA210_XBAR_PART2_RX + \
|
||||
(TEGRA210_XBAR_RX_STRIDE * (TEGRA210_XBAR_AUDIO_RX_COUNT - 1)))
|
||||
|
||||
#define TEGRA186_XBAR_PART3_RX 0x600
|
||||
#define TEGRA186_XBAR_AUDIO_RX_COUNT 115
|
||||
|
||||
#define TEGRA186_MAX_REGISTER_ADDR (TEGRA186_XBAR_PART3_RX +\
|
||||
(TEGRA210_XBAR_RX_STRIDE * (TEGRA186_XBAR_AUDIO_RX_COUNT - 1)))
|
||||
|
||||
#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
|
||||
|
||||
#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 MUX_ENUM_CTRL_DECL(ename, id) \
|
||||
SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0, \
|
||||
tegra210_xbar_mux_texts, \
|
||||
tegra210_xbar_mux_values); \
|
||||
static const struct snd_kcontrol_new ename##_control = \
|
||||
SOC_DAPM_ENUM_EXT("Route", ename##_enum, \
|
||||
tegra_xbar_get_value_enum, \
|
||||
tegra_xbar_put_value_enum)
|
||||
|
||||
#define MUX_ENUM_CTRL_DECL_186(ename, id) \
|
||||
SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0, \
|
||||
tegra186_xbar_mux_texts, \
|
||||
tegra186_xbar_mux_values); \
|
||||
static const struct snd_kcontrol_new ename##_control = \
|
||||
SOC_DAPM_ENUM_EXT("Route", ename##_enum, \
|
||||
tegra_xbar_get_value_enum, \
|
||||
tegra_xbar_put_value_enum)
|
||||
|
||||
#define DAI(sname) \
|
||||
{ \
|
||||
.name = #sname, \
|
||||
.playback = { \
|
||||
.stream_name = #sname " Receive", \
|
||||
.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 = #sname " Transmit", \
|
||||
.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, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define MUX_REG(id) (TEGRA210_XBAR_RX_STRIDE * (id))
|
||||
|
||||
#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 WIDGETS(sname, ename) \
|
||||
SND_SOC_DAPM_AIF_IN(sname " RX", NULL, 0, SND_SOC_NOPM, 0, 0), \
|
||||
SND_SOC_DAPM_AIF_OUT(sname " 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 " RX", NULL, 0, SND_SOC_NOPM, 0, 0), \
|
||||
SND_SOC_DAPM_AIF_OUT(sname " TX", NULL, 0, SND_SOC_NOPM, 0, 0)
|
||||
|
||||
#define MUX_VALUE(npart, nbit) (1 + nbit + npart * 32)
|
||||
|
||||
#define IN_OUT_ROUTES(name) \
|
||||
{ name " RX", NULL, name " Receive" }, \
|
||||
{ name " Transmit", NULL, name " TX" },
|
||||
|
||||
struct tegra210_xbar_cif_conf {
|
||||
unsigned int threshold;
|
||||
unsigned int audio_channels;
|
||||
unsigned int client_channels;
|
||||
unsigned int audio_bits;
|
||||
unsigned int client_bits;
|
||||
unsigned int expand;
|
||||
unsigned int stereo_conv;
|
||||
union {
|
||||
unsigned int fifo_size_downshift;
|
||||
unsigned int replicate;
|
||||
};
|
||||
unsigned int truncate;
|
||||
unsigned int mono_conv;
|
||||
};
|
||||
|
||||
struct tegra_xbar_soc_data {
|
||||
const struct regmap_config *regmap_config;
|
||||
unsigned int mask[4];
|
||||
unsigned int reg_count;
|
||||
unsigned int num_dais;
|
||||
struct snd_soc_codec_driver *codec_drv;
|
||||
struct snd_soc_dai_driver *dai_drv;
|
||||
};
|
||||
|
||||
struct tegra_xbar {
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
const struct tegra_xbar_soc_data *soc_data;
|
||||
};
|
||||
|
||||
/* Extension of soc_bytes structure defined in sound/soc.h */
|
||||
struct tegra_soc_bytes {
|
||||
struct soc_bytes soc;
|
||||
u32 shift; /* Used as offset for ahub ram related programing */
|
||||
};
|
||||
|
||||
void tegra210_xbar_set_cif(struct regmap *regmap, unsigned int reg,
|
||||
struct tegra210_xbar_cif_conf *conf);
|
||||
void tegra210_xbar_write_ahubram(struct regmap *regmap, unsigned int reg_ctrl,
|
||||
unsigned int reg_data, unsigned int ram_offset,
|
||||
unsigned int *data, size_t size);
|
||||
void tegra210_xbar_read_ahubram(struct regmap *regmap, unsigned int reg_ctrl,
|
||||
unsigned int reg_data, unsigned int ram_offset,
|
||||
unsigned int *data, size_t size);
|
||||
|
||||
/* Utility structures for using mixer control of type snd_soc_bytes */
|
||||
#define TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, \
|
||||
xhandler_get, xhandler_put, xinfo) \
|
||||
{.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = xinfo, .get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = ((unsigned long)&(struct tegra_soc_bytes) \
|
||||
{.soc.base = xbase, .soc.num_regs = xregs, .soc.mask = xmask, \
|
||||
.shift = xshift })}
|
||||
#endif
|
||||
@@ -1,578 +0,0 @@
|
||||
/*
|
||||
* tegra_machine_driver_mobile.c - Tegra ASoC Machine driver for mobile
|
||||
*
|
||||
* Copyright (c) 2017-2020 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <dt-bindings/sound/tas2552.h>
|
||||
#include "rt5659.h"
|
||||
#include "sgtl5000.h"
|
||||
#include "tegra_asoc_machine_alt.h"
|
||||
#include "tegra210_xbar_alt.h"
|
||||
|
||||
#define DRV_NAME "tegra-asoc:"
|
||||
|
||||
static const char * const tegra_machine_srate_text[] = {
|
||||
"None",
|
||||
"8kHz",
|
||||
"16kHz",
|
||||
"44kHz",
|
||||
"48kHz",
|
||||
"11kHz",
|
||||
"22kHz",
|
||||
"24kHz",
|
||||
"32kHz",
|
||||
"88kHz",
|
||||
"96kHz",
|
||||
"176kHz",
|
||||
"192kHz",
|
||||
};
|
||||
|
||||
static const char * const tegra_machine_format_text[] = {
|
||||
"None",
|
||||
"16",
|
||||
"32",
|
||||
};
|
||||
|
||||
static const struct soc_enum tegra_machine_codec_rate =
|
||||
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tegra_machine_srate_text),
|
||||
tegra_machine_srate_text);
|
||||
|
||||
static const struct soc_enum tegra_machine_codec_format =
|
||||
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tegra_machine_format_text),
|
||||
tegra_machine_format_text);
|
||||
|
||||
static const int tegra_machine_srate_values[] = {
|
||||
0,
|
||||
8000,
|
||||
16000,
|
||||
44100,
|
||||
48000,
|
||||
11025,
|
||||
22050,
|
||||
24000,
|
||||
32000,
|
||||
88200,
|
||||
96000,
|
||||
176400,
|
||||
192000,
|
||||
};
|
||||
|
||||
static int tegra_machine_codec_get_rate(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
ucontrol->value.integer.value[0] = machine->rate_via_kcontrol;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_machine_codec_put_rate(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
/* set the rate control flag */
|
||||
machine->rate_via_kcontrol = ucontrol->value.integer.value[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_machine_codec_get_format(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
ucontrol->value.integer.value[0] = machine->fmt_via_kcontrol;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_machine_codec_put_format(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
/* set the format control flag */
|
||||
machine->fmt_via_kcontrol = ucontrol->value.integer.value[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
unsigned int rate, unsigned int channels,
|
||||
u64 formats)
|
||||
{
|
||||
unsigned int mask = (1 << channels) - 1;
|
||||
struct snd_soc_card *card = runtime->card;
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
struct snd_soc_pcm_stream *dai_params;
|
||||
unsigned int aud_mclk, srate;
|
||||
u64 format_k, fmt;
|
||||
int err;
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
|
||||
srate = (machine->rate_via_kcontrol) ?
|
||||
tegra_machine_srate_values[machine->rate_via_kcontrol] :
|
||||
rate;
|
||||
format_k = (machine->fmt_via_kcontrol == 2) ?
|
||||
(1ULL << SNDRV_PCM_FORMAT_S32_LE) : formats;
|
||||
|
||||
err = tegra_alt_asoc_utils_set_rate(&machine->audio_clock, srate, 0, 0);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "Can't configure clocks\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
aud_mclk = machine->audio_clock.set_aud_mclk_rate;
|
||||
|
||||
pr_debug("pll_a_out0 = %u Hz, aud_mclk = %u Hz, sample rate = %u Hz\n",
|
||||
machine->audio_clock.set_pll_out_rate, aud_mclk, srate);
|
||||
|
||||
list_for_each_entry(rtd, &card->rtd_list, list) {
|
||||
if (!rtd->dai_link->params)
|
||||
continue;
|
||||
dai_params = (struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
dai_params->rate_min = srate;
|
||||
dai_params->channels_min = channels;
|
||||
dai_params->formats = format_k;
|
||||
|
||||
fmt = rtd->dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
/* set TDM slot mask */
|
||||
if (fmt == SND_SOC_DAIFMT_DSP_A ||
|
||||
fmt == SND_SOC_DAIFMT_DSP_B) {
|
||||
err = snd_soc_dai_set_tdm_slot(
|
||||
rtd->cpu_dai, mask,
|
||||
mask, 0, 0);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev,
|
||||
"%s cpu DAI slot mask not set\n",
|
||||
rtd->cpu_dai->name);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rtd = snd_soc_get_pcm_runtime(card, "rt565x-playback");
|
||||
if (rtd) {
|
||||
err = snd_soc_dai_set_sysclk(rtd->codec_dai, RT5659_SCLK_S_MCLK,
|
||||
aud_mclk, SND_SOC_CLOCK_IN);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "codec_dai clock not set\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
rtd = snd_soc_get_pcm_runtime(card, "rt565x-codec-sysclk-bclk1");
|
||||
if (rtd) {
|
||||
unsigned int bclk_rate;
|
||||
dai_params = (struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
|
||||
switch (dai_params->formats) {
|
||||
case SNDRV_PCM_FMTBIT_S8:
|
||||
bclk_rate = srate * channels * 8;
|
||||
break;
|
||||
case SNDRV_PCM_FMTBIT_S16_LE:
|
||||
bclk_rate = srate * channels * 16;
|
||||
break;
|
||||
case SNDRV_PCM_FMTBIT_S32_LE:
|
||||
bclk_rate = srate * channels * 32;
|
||||
break;
|
||||
default:
|
||||
dev_err(card->dev, "invalid format %llu\n",
|
||||
dai_params->formats);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = snd_soc_dai_set_pll(rtd->codec_dai, 0,
|
||||
RT5659_PLL1_S_BCLK1,
|
||||
bclk_rate, srate * 256);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "failed to set codec pll\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_soc_dai_set_sysclk(rtd->codec_dai, RT5659_SCLK_S_PLL1,
|
||||
srate * 256, SND_SOC_CLOCK_IN);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "codec_dai clock not set\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
rtd = snd_soc_get_pcm_runtime(card, "dspk-playback-r");
|
||||
if (rtd) {
|
||||
if (!strcmp(rtd->codec_dai->name, "tas2552-amplifier")) {
|
||||
err = snd_soc_dai_set_sysclk(rtd->codec_dai,
|
||||
TAS2552_PDM_CLK_IVCLKIN, aud_mclk,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "codec_dai clock not set\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rtd = snd_soc_get_pcm_runtime(card, "dspk-playback-l");
|
||||
if (rtd) {
|
||||
if (!strcmp(rtd->codec_dai->name, "tas2552-amplifier")) {
|
||||
err = snd_soc_dai_set_sysclk(rtd->codec_dai,
|
||||
TAS2552_PDM_CLK_IVCLKIN, aud_mclk,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "codec_dai clock not set\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_machine_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
int err;
|
||||
|
||||
err = tegra_machine_dai_init(rtd, params_rate(params),
|
||||
params_channels(params),
|
||||
1ULL << params_format(params));
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "Failed dai init\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_machine_pcm_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
tegra_alt_asoc_utils_clk_enable(&machine->audio_clock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_machine_pcm_shutdown(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
tegra_alt_asoc_utils_clk_disable(&machine->audio_clock);
|
||||
}
|
||||
|
||||
static int tegra_machine_suspend_pre(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
|
||||
/* DAPM dai link stream work for non pcm links */
|
||||
list_for_each_entry(rtd, &card->rtd_list, list) {
|
||||
if (rtd->dai_link->params)
|
||||
INIT_DELAYED_WORK(&rtd->delayed_work, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_machine_compr_startup(struct snd_compr_stream *cstream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
tegra_alt_asoc_utils_clk_enable(&machine->audio_clock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_machine_compr_shutdown(struct snd_compr_stream *cstream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
tegra_alt_asoc_utils_clk_disable(&machine->audio_clock);
|
||||
}
|
||||
|
||||
static int tegra_machine_compr_set_params(struct snd_compr_stream *cstream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_platform *platform = rtd->platform;
|
||||
struct snd_codec codec_params;
|
||||
int err;
|
||||
|
||||
if (platform->driver->compr_ops &&
|
||||
platform->driver->compr_ops->get_params) {
|
||||
err = platform->driver->compr_ops->get_params(cstream,
|
||||
&codec_params);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "Failed to get compr params\n");
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
dev_err(card->dev, "compr ops not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = tegra_machine_dai_init(rtd, codec_params.sample_rate,
|
||||
codec_params.ch_out,
|
||||
SNDRV_PCM_FMTBIT_S16_LE);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "Failed dai init\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_machine_fepi_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct device *dev = rtd->card->dev;
|
||||
int err;
|
||||
|
||||
err = snd_soc_dai_set_sysclk(rtd->codec_dai, SGTL5000_SYSCLK, 12288000,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to set sgtl5000 sysclk!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_machine_rt565x_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_jack *jack;
|
||||
int err;
|
||||
|
||||
jack = devm_kzalloc(card->dev, sizeof(struct snd_soc_jack), GFP_KERNEL);
|
||||
if (!jack)
|
||||
return -ENOMEM;
|
||||
|
||||
err = snd_soc_card_jack_new(card, "Headset Jack", SND_JACK_HEADSET,
|
||||
jack, NULL, 0);
|
||||
if (err) {
|
||||
dev_err(card->dev, "Headset Jack creation failed %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = tegra_machine_add_codec_jack_control(card, rtd, jack);
|
||||
if (err) {
|
||||
dev_err(card->dev, "Failed to add jack control: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rt5659_set_jack_detect(rtd->codec, jack);
|
||||
if (err) {
|
||||
dev_err(card->dev, "Failed to set jack for RT565x: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* single button supporting play/pause */
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
|
||||
|
||||
/* multiple buttons supporting play/pause and volume up/down */
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_MEDIA);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
|
||||
|
||||
snd_soc_dapm_sync(&card->dapm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codec_init(struct tegra_machine *machine)
|
||||
{
|
||||
struct snd_soc_dai_link *dai_links = machine->asoc->dai_links;
|
||||
unsigned int num_links = machine->asoc->num_links, i;
|
||||
|
||||
if (!dai_links || !num_links)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num_links; i++) {
|
||||
if (!dai_links[i].name)
|
||||
continue;
|
||||
|
||||
if (strstr(dai_links[i].name, "rt565x-playback") ||
|
||||
strstr(dai_links[i].name, "rt565x-codec-sysclk-bclk1"))
|
||||
dai_links[i].init = tegra_machine_rt565x_init;
|
||||
else if (strstr(dai_links[i].name, "fe-pi-audio-z-v2"))
|
||||
dai_links[i].init = tegra_machine_fepi_init;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops tegra_machine_pcm_ops = {
|
||||
.hw_params = tegra_machine_pcm_hw_params,
|
||||
.startup = tegra_machine_pcm_startup,
|
||||
.shutdown = tegra_machine_pcm_shutdown,
|
||||
};
|
||||
|
||||
static struct snd_soc_compr_ops tegra_machine_compr_ops = {
|
||||
.set_params = tegra_machine_compr_set_params,
|
||||
.startup = tegra_machine_compr_startup,
|
||||
.shutdown = tegra_machine_compr_shutdown,
|
||||
};
|
||||
|
||||
static int add_dai_links(struct snd_soc_card *card)
|
||||
{
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
int ret;
|
||||
|
||||
ret = parse_card_info(card, &tegra_machine_pcm_ops,
|
||||
&tegra_machine_compr_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = codec_init(machine);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new tegra_machine_controls[] = {
|
||||
SOC_ENUM_EXT("codec-x rate", tegra_machine_codec_rate,
|
||||
tegra_machine_codec_get_rate, tegra_machine_codec_put_rate),
|
||||
SOC_ENUM_EXT("codec-x format", tegra_machine_codec_format,
|
||||
tegra_machine_codec_get_format, tegra_machine_codec_put_format),
|
||||
};
|
||||
|
||||
static struct snd_soc_card snd_soc_tegra_card = {
|
||||
.owner = THIS_MODULE,
|
||||
.controls = tegra_machine_controls,
|
||||
.num_controls = ARRAY_SIZE(tegra_machine_controls),
|
||||
.suspend_pre = tegra_machine_suspend_pre,
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
/* structure to match device tree node */
|
||||
static const struct of_device_id tegra_machine_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra-audio-t186ref-mobile-rt565x" },
|
||||
{ .compatible = "nvidia,tegra-audio-t210ref-mobile-rt565x" },
|
||||
{},
|
||||
};
|
||||
|
||||
static int tegra_machine_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &snd_soc_tegra_card;
|
||||
struct tegra_machine *machine;
|
||||
int ret = 0;
|
||||
|
||||
machine = devm_kzalloc(&pdev->dev, sizeof(*machine), GFP_KERNEL);
|
||||
if (!machine)
|
||||
return -ENOMEM;
|
||||
|
||||
machine->asoc = devm_kzalloc(&pdev->dev, sizeof(*machine->asoc),
|
||||
GFP_KERNEL);
|
||||
if (!machine->asoc)
|
||||
return -ENOMEM;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, card);
|
||||
snd_soc_card_set_drvdata(card, machine);
|
||||
|
||||
card->dapm.idle_bias_off = true;
|
||||
|
||||
memset(&machine->audio_clock, 0, sizeof(machine->audio_clock));
|
||||
ret = tegra_alt_asoc_utils_init(&machine->audio_clock,
|
||||
&pdev->dev,
|
||||
card);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = add_dai_links(card);
|
||||
if (ret < 0)
|
||||
goto cleanup_asoc;
|
||||
|
||||
ret = snd_soc_register_card(card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
|
||||
ret);
|
||||
goto cleanup_asoc;
|
||||
}
|
||||
|
||||
tegra_machine_add_i2s_codec_controls(card);
|
||||
|
||||
return 0;
|
||||
cleanup_asoc:
|
||||
release_asoc_phandles(machine);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_machine_driver_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_PM
|
||||
static void tegra_asoc_machine_resume(struct device *dev)
|
||||
{
|
||||
WARN_ON(snd_soc_resume(dev));
|
||||
}
|
||||
#else
|
||||
#define tegra_asoc_machine_resume NULL
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops tegra_asoc_machine_pm_ops = {
|
||||
.prepare = snd_soc_suspend,
|
||||
.complete = tegra_asoc_machine_resume,
|
||||
.poweroff = snd_soc_poweroff,
|
||||
};
|
||||
|
||||
static struct platform_driver tegra_asoc_machine_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &tegra_asoc_machine_pm_ops,
|
||||
.of_match_table = tegra_machine_of_match,
|
||||
},
|
||||
.probe = tegra_machine_driver_probe,
|
||||
.remove = tegra_machine_driver_remove,
|
||||
};
|
||||
module_platform_driver(tegra_asoc_machine_driver);
|
||||
|
||||
MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>, Sameer Pujar <spujar@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Tegra ASoC machine driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
MODULE_DEVICE_TABLE(of, tegra_machine_of_match);
|
||||
@@ -1,485 +0,0 @@
|
||||
/*
|
||||
* tegra210_spdif_alt.c - Tegra210 SPDIF driver
|
||||
*
|
||||
* Copyright (c) 2014-2019 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <soc/tegra/chip-id.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/pinconf-tegra.h>
|
||||
|
||||
#include "tegra210_xbar_alt.h"
|
||||
#include "tegra210_spdif_alt.h"
|
||||
|
||||
#define DRV_NAME "tegra210-spdif"
|
||||
|
||||
static const struct reg_default tegra210_spdif_reg_defaults[] = {
|
||||
{ TEGRA210_SPDIF_CIF_TXD_CTRL, 0x00001100},
|
||||
{ TEGRA210_SPDIF_CIF_RXD_CTRL, 0x00001100},
|
||||
{ TEGRA210_SPDIF_CIF_TXU_CTRL, 0x00001100},
|
||||
{ TEGRA210_SPDIF_CIF_RXU_CTRL, 0x00001100},
|
||||
{ TEGRA210_SPDIF_FLOWCTL_CTRL, 0x80000000},
|
||||
{ TEGRA210_SPDIF_TX_STEP, 0x00008000},
|
||||
{ TEGRA210_SPDIF_LCOEF_1_4_0, 0x0000002e},
|
||||
{ TEGRA210_SPDIF_LCOEF_1_4_1, 0x0000f9e6},
|
||||
{ TEGRA210_SPDIF_LCOEF_1_4_2, 0x000020ca},
|
||||
{ TEGRA210_SPDIF_LCOEF_1_4_3, 0x00007147},
|
||||
{ TEGRA210_SPDIF_LCOEF_1_4_4, 0x0000f17e},
|
||||
{ TEGRA210_SPDIF_LCOEF_1_4_5, 0x000001e0},
|
||||
{ TEGRA210_SPDIF_LCOEF_2_4_0, 0x00000117},
|
||||
{ TEGRA210_SPDIF_LCOEF_2_4_1, 0x0000f26b},
|
||||
{ TEGRA210_SPDIF_LCOEF_2_4_2, 0x00004c07},
|
||||
};
|
||||
|
||||
static int tegra210_spdif_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra210_spdif *spdif = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
regcache_cache_only(spdif->regmap, true);
|
||||
regcache_mark_dirty(spdif->regmap);
|
||||
if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
|
||||
clk_disable_unprepare(spdif->clk_spdif_out);
|
||||
clk_disable_unprepare(spdif->clk_spdif_in);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_spdif_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct tegra210_spdif *spdif = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
|
||||
ret = clk_prepare_enable(spdif->clk_spdif_out);
|
||||
if (ret) {
|
||||
dev_err(dev, "spdif_out_clk_enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(spdif->clk_spdif_in);
|
||||
if (ret) {
|
||||
dev_err(dev, "spdif_in_clk_enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
regcache_cache_only(spdif->regmap, false);
|
||||
regcache_sync(spdif->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_spdif_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct device *dev = dai->dev;
|
||||
struct tegra210_spdif *spdif = snd_soc_dai_get_drvdata(dai);
|
||||
int spdif_out_clock_rate, spdif_in_clock_rate;
|
||||
int ret;
|
||||
|
||||
switch (freq) {
|
||||
case 32000:
|
||||
spdif_out_clock_rate = 4096000;
|
||||
spdif_in_clock_rate = 48000000;
|
||||
break;
|
||||
case 44100:
|
||||
spdif_out_clock_rate = 5644800;
|
||||
spdif_in_clock_rate = 48000000;
|
||||
break;
|
||||
case 48000:
|
||||
spdif_out_clock_rate = 6144000;
|
||||
spdif_in_clock_rate = 48000000;
|
||||
break;
|
||||
case 88200:
|
||||
spdif_out_clock_rate = 11289600;
|
||||
spdif_in_clock_rate = 72000000;
|
||||
break;
|
||||
case 96000:
|
||||
spdif_out_clock_rate = 12288000;
|
||||
spdif_in_clock_rate = 72000000;
|
||||
break;
|
||||
case 176400:
|
||||
spdif_out_clock_rate = 22579200;
|
||||
spdif_in_clock_rate = 108000000;
|
||||
break;
|
||||
case 192000:
|
||||
spdif_out_clock_rate = 24576000;
|
||||
spdif_in_clock_rate = 108000000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
|
||||
if (dir == SND_SOC_CLOCK_OUT) {
|
||||
ret = clk_set_rate(spdif->clk_spdif_out,
|
||||
spdif_out_clock_rate);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Can't set SPDIF Out clock rate: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = clk_set_rate(spdif->clk_spdif_in,
|
||||
spdif_in_clock_rate);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Can't set SPDIF In clock rate: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_spdif_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_spdif *spdif = snd_soc_dai_get_drvdata(dai);
|
||||
int channels, audio_bits, bit_mode;
|
||||
struct tegra210_xbar_cif_conf cif_conf;
|
||||
|
||||
memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
|
||||
|
||||
channels = params_channels(params);
|
||||
|
||||
if (channels < 2) {
|
||||
dev_err(dev, "Doesn't support %d channels\n", channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
audio_bits = TEGRA210_AUDIOCIF_BITS_16;
|
||||
bit_mode = TEGRA210_SPDIF_BIT_MODE16;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
audio_bits = TEGRA210_AUDIOCIF_BITS_32;
|
||||
bit_mode = TEGRA210_SPDIF_BIT_MODERAW;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cif_conf.audio_channels = channels;
|
||||
cif_conf.client_channels = channels;
|
||||
cif_conf.audio_bits = audio_bits;
|
||||
cif_conf.client_bits = audio_bits;
|
||||
|
||||
regmap_update_bits(spdif->regmap, TEGRA210_SPDIF_CTRL,
|
||||
TEGRA210_SPDIF_CTRL_BIT_MODE_MASK,
|
||||
bit_mode);
|
||||
|
||||
/* As a CODEC DAI, CAPTURE is transmit */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
tegra210_xbar_set_cif(spdif->regmap,
|
||||
TEGRA210_SPDIF_CIF_TXD_CTRL,
|
||||
&cif_conf);
|
||||
} else {
|
||||
tegra210_xbar_set_cif(spdif->regmap,
|
||||
TEGRA210_SPDIF_CIF_RXD_CTRL,
|
||||
&cif_conf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops tegra210_spdif_dai_ops = {
|
||||
.hw_params = tegra210_spdif_hw_params,
|
||||
.set_sysclk = tegra210_spdif_set_dai_sysclk,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver tegra210_spdif_dais[] = {
|
||||
{
|
||||
.name = "CIF",
|
||||
.playback = {
|
||||
.stream_name = "CIF Receive",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "CIF Transmit",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "DAP",
|
||||
.playback = {
|
||||
.stream_name = "DAP Receive",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "DAP Transmit",
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.ops = &tegra210_spdif_dai_ops,
|
||||
}
|
||||
};
|
||||
|
||||
static int tegra210_spdif_loopback_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct tegra210_spdif *spdif = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = spdif->loopback;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_spdif_loopback_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct tegra210_spdif *spdif = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
spdif->loopback = ucontrol->value.integer.value[0];
|
||||
|
||||
pm_runtime_get_sync(codec->dev);
|
||||
regmap_update_bits(spdif->regmap, TEGRA210_SPDIF_CTRL,
|
||||
TEGRA210_SPDIF_CTRL_LBK_EN_ENABLE_MASK,
|
||||
spdif->loopback << TEGRA210_SPDIF_CTRL_LBK_EN_ENABLE_SHIFT);
|
||||
pm_runtime_put(codec->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new tegra210_spdif_controls[] = {
|
||||
SOC_SINGLE_EXT("Loopback", SND_SOC_NOPM, 0, 1, 0,
|
||||
tegra210_spdif_loopback_get, tegra210_spdif_loopback_put),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget tegra210_spdif_widgets[] = {
|
||||
SND_SOC_DAPM_AIF_IN("CIF RX", NULL, 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("CIF TX", NULL, 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_IN("DAP RX", NULL, 0, TEGRA210_SPDIF_CTRL, 29, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("DAP TX", NULL, 0, TEGRA210_SPDIF_CTRL, 28, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route tegra210_spdif_routes[] = {
|
||||
{ "CIF RX", NULL, "CIF Receive"},
|
||||
{ "DAP TX", NULL, "CIF RX"},
|
||||
{ "DAP Transmit", NULL, "DAP TX"},
|
||||
|
||||
{ "DAP RX", NULL, "DAP Receive"},
|
||||
{ "CIF TX", NULL, "DAP RX"},
|
||||
{ "CIF Transmit", NULL, "CIF TX"},
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver tegra210_spdif_codec = {
|
||||
.idle_bias_off = 1,
|
||||
.component_driver = {
|
||||
.dapm_widgets = tegra210_spdif_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tegra210_spdif_widgets),
|
||||
.dapm_routes = tegra210_spdif_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(tegra210_spdif_routes),
|
||||
.controls = tegra210_spdif_controls,
|
||||
.num_controls = ARRAY_SIZE(tegra210_spdif_controls),
|
||||
},
|
||||
};
|
||||
|
||||
static bool tegra210_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case TEGRA210_SPDIF_CTRL:
|
||||
case TEGRA210_SPDIF_STROBE_CTRL:
|
||||
case TEGRA210_SPDIF_CIF_TXD_CTRL:
|
||||
case TEGRA210_SPDIF_CIF_RXD_CTRL:
|
||||
case TEGRA210_SPDIF_CIF_TXU_CTRL:
|
||||
case TEGRA210_SPDIF_CIF_RXU_CTRL:
|
||||
case TEGRA210_SPDIF_CH_STA_RX_A:
|
||||
case TEGRA210_SPDIF_CH_STA_RX_B:
|
||||
case TEGRA210_SPDIF_CH_STA_RX_C:
|
||||
case TEGRA210_SPDIF_CH_STA_RX_D:
|
||||
case TEGRA210_SPDIF_CH_STA_RX_E:
|
||||
case TEGRA210_SPDIF_CH_STA_RX_F:
|
||||
case TEGRA210_SPDIF_CH_STA_TX_A:
|
||||
case TEGRA210_SPDIF_CH_STA_TX_B:
|
||||
case TEGRA210_SPDIF_CH_STA_TX_C:
|
||||
case TEGRA210_SPDIF_CH_STA_TX_D:
|
||||
case TEGRA210_SPDIF_CH_STA_TX_E:
|
||||
case TEGRA210_SPDIF_CH_STA_TX_F:
|
||||
case TEGRA210_SPDIF_FLOWCTL_CTRL:
|
||||
case TEGRA210_SPDIF_TX_STEP:
|
||||
case TEGRA210_SPDIF_FLOW_STATUS:
|
||||
case TEGRA210_SPDIF_FLOW_TOTAL:
|
||||
case TEGRA210_SPDIF_FLOW_OVER:
|
||||
case TEGRA210_SPDIF_FLOW_UNDER:
|
||||
case TEGRA210_SPDIF_LCOEF_1_4_0:
|
||||
case TEGRA210_SPDIF_LCOEF_1_4_1:
|
||||
case TEGRA210_SPDIF_LCOEF_1_4_2:
|
||||
case TEGRA210_SPDIF_LCOEF_1_4_3:
|
||||
case TEGRA210_SPDIF_LCOEF_1_4_4:
|
||||
case TEGRA210_SPDIF_LCOEF_1_4_5:
|
||||
case TEGRA210_SPDIF_LCOEF_2_4_0:
|
||||
case TEGRA210_SPDIF_LCOEF_2_4_1:
|
||||
case TEGRA210_SPDIF_LCOEF_2_4_2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static const struct regmap_config tegra210_spdif_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = TEGRA210_SPDIF_LCOEF_2_4_2,
|
||||
.writeable_reg = tegra210_spdif_wr_rd_reg,
|
||||
.readable_reg = tegra210_spdif_wr_rd_reg,
|
||||
.reg_defaults = tegra210_spdif_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(tegra210_spdif_reg_defaults),
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra210_spdif_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra210-spdif" },
|
||||
{},
|
||||
};
|
||||
|
||||
static int tegra210_spdif_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra210_spdif *spdif;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *mem;
|
||||
void __iomem *regs;
|
||||
const struct of_device_id *match;
|
||||
const char *prod_name;
|
||||
int ret;
|
||||
|
||||
match = of_match_device(tegra210_spdif_of_match, &pdev->dev);
|
||||
if (!match) {
|
||||
dev_err(&pdev->dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
|
||||
if (!spdif)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, spdif);
|
||||
|
||||
if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
|
||||
spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "spdif_out");
|
||||
if (IS_ERR(spdif->clk_spdif_out)) {
|
||||
dev_err(&pdev->dev, "Can't retrieve spdif clock\n");
|
||||
return PTR_ERR(spdif->clk_spdif_out);
|
||||
}
|
||||
|
||||
spdif->clk_spdif_in = devm_clk_get(&pdev->dev, "spdif_in");
|
||||
if (IS_ERR(spdif->clk_spdif_in)) {
|
||||
dev_err(&pdev->dev, "Can't retrieve spdif clock\n");
|
||||
return PTR_ERR(spdif->clk_spdif_in);
|
||||
}
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
|
||||
&tegra210_spdif_regmap_config);
|
||||
if (IS_ERR(spdif->regmap)) {
|
||||
dev_err(&pdev->dev, "regmap init failed\n");
|
||||
return PTR_ERR(spdif->regmap);
|
||||
}
|
||||
regcache_cache_only(spdif->regmap, true);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
ret = snd_soc_register_codec(&pdev->dev, &tegra210_spdif_codec,
|
||||
tegra210_spdif_dais,
|
||||
ARRAY_SIZE(tegra210_spdif_dais));
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (of_property_read_string(np, "prod-name", &prod_name) == 0) {
|
||||
ret = tegra_pinctrl_config_prod(&pdev->dev, prod_name);
|
||||
if (ret < 0)
|
||||
dev_warn(&pdev->dev, "Failed to set %s setting\n",
|
||||
prod_name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra210_spdif_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
tegra210_spdif_runtime_suspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tegra210_spdif_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(tegra210_spdif_runtime_suspend,
|
||||
tegra210_spdif_runtime_resume, NULL)
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver tegra210_spdif_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = tegra210_spdif_of_match,
|
||||
.pm = &tegra210_spdif_pm_ops,
|
||||
},
|
||||
.probe = tegra210_spdif_platform_probe,
|
||||
.remove = tegra210_spdif_platform_remove,
|
||||
};
|
||||
module_platform_driver(tegra210_spdif_driver);
|
||||
|
||||
MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
|
||||
MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Tegra210 SPDIF ASoC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
MODULE_DEVICE_TABLE(of, tegra210_spdif_of_match);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,463 +0,0 @@
|
||||
/*
|
||||
* tegra_asoc_dt_parser.c - Tegra DAI links parser
|
||||
*
|
||||
* Copyright (c) 2019 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <sound/simple_card_utils.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/soc.h>
|
||||
#include "tegra_asoc_machine_alt.h"
|
||||
|
||||
#define PREFIX "nvidia-audio-card,"
|
||||
#define CELL "#sound-dai-cells"
|
||||
#define DAI "sound-dai"
|
||||
|
||||
/* DT also uses similar values to specify link type */
|
||||
enum dai_link_type {
|
||||
PCM_LINK,
|
||||
COMPR_LINK,
|
||||
C2C_LINK,
|
||||
};
|
||||
|
||||
struct snd_soc_pcm_stream link_params = {
|
||||
.formats = SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 192000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 16,
|
||||
};
|
||||
|
||||
/* find if DAI link or its cpu/codec DAI nodes are disabled */
|
||||
static bool of_dai_link_is_available(struct device_node *link_node)
|
||||
{
|
||||
struct device_node *child, *dai_node;
|
||||
|
||||
if (!of_device_is_available(link_node))
|
||||
return false;
|
||||
|
||||
for_each_child_of_node(link_node, child) {
|
||||
/* check for "cpu" and "codec" nodes only */
|
||||
if (of_node_cmp(child->name, "cpu") &&
|
||||
of_node_cmp(child->name, "codec"))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Skip a codec subnode if DAI property is missing. For a
|
||||
* link with multiple codecs, at least one codec needs to
|
||||
* have DAI property (which is ensured while counting the
|
||||
* number of links that DT exposes). Other codec subnodes
|
||||
* can be empty and populated in override file.
|
||||
*/
|
||||
if (!of_property_read_bool(child, DAI) &&
|
||||
!of_node_cmp(child->name, "codec"))
|
||||
continue;
|
||||
|
||||
dai_node = of_parse_phandle(child, DAI, 0);
|
||||
if (!dai_node) {
|
||||
of_node_put(child);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!of_device_is_available(dai_node)) {
|
||||
of_node_put(dai_node);
|
||||
of_node_put(child);
|
||||
return false;
|
||||
}
|
||||
|
||||
of_node_put(dai_node);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* find number of child nodes with given name and containing DAI property */
|
||||
static int of_get_child_count_with_name(struct device_node *node,
|
||||
const char *name)
|
||||
{
|
||||
struct device_node *child;
|
||||
int num = 0;
|
||||
|
||||
for_each_child_of_node(node, child)
|
||||
if (!of_node_cmp(child->name, name) &&
|
||||
of_property_read_bool(child, DAI))
|
||||
num++;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static int get_num_dai_links(struct platform_device *pdev,
|
||||
unsigned int *num_links)
|
||||
{
|
||||
struct device_node *top = pdev->dev.of_node;
|
||||
struct device_node *link_node, *codec;
|
||||
unsigned int link_count = 0, num_codecs;
|
||||
|
||||
link_node = of_get_child_by_name(top, PREFIX "dai-link");
|
||||
if (!link_node) {
|
||||
dev_err(&pdev->dev, "no dai links found\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!of_dai_link_is_available(link_node)) {
|
||||
link_node = of_get_next_child(top, link_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* depending on the number of codec subnodes, DAI link
|
||||
* count is incremented. DT can have one DAI link entry
|
||||
* with multiple codec nodes(for ex: DSPK), driver can
|
||||
* create multiple links out of it.
|
||||
*/
|
||||
num_codecs = of_get_child_count_with_name(link_node,
|
||||
"codec");
|
||||
if (!num_codecs) {
|
||||
of_node_put(link_node);
|
||||
dev_err(&pdev->dev,
|
||||
"no codec subnode or sound-dai property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for_each_child_of_node(link_node, codec) {
|
||||
if (of_node_cmp(codec->name, "codec"))
|
||||
continue;
|
||||
|
||||
if (of_property_read_bool(codec, DAI))
|
||||
link_count++;
|
||||
}
|
||||
|
||||
link_node = of_get_next_child(top, link_node);
|
||||
} while (link_node);
|
||||
|
||||
*num_links = link_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_num_codec_confs(struct platform_device *pdev, int *num_confs)
|
||||
{
|
||||
struct device_node *top = pdev->dev.of_node;
|
||||
struct device_node *link_node, *codec;
|
||||
unsigned int conf_count = 0, num_codecs;
|
||||
|
||||
link_node = of_get_child_by_name(top, PREFIX "dai-link");
|
||||
if (!link_node) {
|
||||
dev_err(&pdev->dev, "no dai links found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!of_dai_link_is_available(link_node)) {
|
||||
link_node = of_get_next_child(top, link_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
num_codecs = of_get_child_count_with_name(link_node,
|
||||
"codec");
|
||||
if (!num_codecs) {
|
||||
of_node_put(link_node);
|
||||
dev_err(&pdev->dev, "missing codec subnode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for_each_child_of_node(link_node, codec) {
|
||||
if (of_node_cmp(codec->name, "codec"))
|
||||
continue;
|
||||
|
||||
if (of_property_read_bool(codec, "prefix"))
|
||||
conf_count++;
|
||||
}
|
||||
|
||||
link_node = of_get_next_child(top, link_node);
|
||||
} while (link_node);
|
||||
|
||||
*num_confs = conf_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_mclk_fs(struct snd_soc_card *card)
|
||||
{
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
struct platform_device *pdev = to_platform_device(card->dev);
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node, PREFIX "mclk-fs",
|
||||
&machine->audio_clock.mclk_scale))
|
||||
dev_dbg(&pdev->dev, "'%smclk-fs' property is missing\n",
|
||||
PREFIX);
|
||||
}
|
||||
|
||||
static int parse_dt_codec_confs(struct snd_soc_card *card)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(card->dev);
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
struct device_node *top = pdev->dev.of_node;
|
||||
struct device_node *link_node;
|
||||
struct snd_soc_codec_conf *codec_confs;
|
||||
unsigned int num_confs, i = 0;
|
||||
int err;
|
||||
|
||||
err = get_num_codec_confs(pdev, &machine->asoc->num_confs);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
num_confs = machine->asoc->num_confs;
|
||||
if (!num_confs)
|
||||
return 0;
|
||||
|
||||
machine->asoc->codec_confs = devm_kcalloc(&pdev->dev,
|
||||
num_confs,
|
||||
sizeof(*codec_confs),
|
||||
GFP_KERNEL);
|
||||
if (!machine->asoc->codec_confs)
|
||||
return -ENOMEM;
|
||||
codec_confs = machine->asoc->codec_confs;
|
||||
|
||||
link_node = of_get_child_by_name(top, PREFIX "dai-link");
|
||||
if (!link_node) {
|
||||
dev_err(&pdev->dev, "DAI links not found in DT\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
do {
|
||||
struct of_phandle_args args;
|
||||
struct device_node *codec;
|
||||
|
||||
if (!of_dai_link_is_available(link_node)) {
|
||||
link_node = of_get_next_child(top, link_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
for_each_child_of_node(link_node, codec) {
|
||||
if (of_node_cmp(codec->name, "codec"))
|
||||
continue;
|
||||
|
||||
if (!of_property_read_bool(codec, "prefix"))
|
||||
continue;
|
||||
|
||||
err = of_parse_phandle_with_args(codec, DAI, CELL, 0,
|
||||
&args);
|
||||
if (err < 0) {
|
||||
of_node_put(codec);
|
||||
of_node_put(link_node);
|
||||
return err;
|
||||
}
|
||||
|
||||
codec_confs[i].of_node = args.np;
|
||||
codec_confs[i].dev_name = NULL;
|
||||
of_property_read_string(codec, "prefix",
|
||||
&codec_confs[i].name_prefix);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
link_node = of_get_next_child(top, link_node);
|
||||
} while (link_node);
|
||||
|
||||
card->num_configs = num_confs;
|
||||
card->codec_conf = codec_confs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_dt_dai_links(struct snd_soc_card *card,
|
||||
struct snd_soc_ops *pcm_ops,
|
||||
struct snd_soc_compr_ops *compr_ops)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(card->dev);
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
struct device_node *top = pdev->dev.of_node;
|
||||
struct device_node *link_node;
|
||||
struct snd_soc_dai_link *dai_links;
|
||||
unsigned int num_links, link_count = 0;
|
||||
int ret;
|
||||
|
||||
ret = get_num_dai_links(pdev, &machine->asoc->num_links);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
num_links = machine->asoc->num_links;
|
||||
if (!num_links)
|
||||
return -EINVAL;
|
||||
|
||||
dai_links = devm_kcalloc(&pdev->dev, num_links, sizeof(*dai_links),
|
||||
GFP_KERNEL);
|
||||
if (!dai_links)
|
||||
return -ENOMEM;
|
||||
machine->asoc->dai_links = dai_links;
|
||||
|
||||
link_node = of_get_child_by_name(top, PREFIX "dai-link");
|
||||
if (!link_node) {
|
||||
dev_err(&pdev->dev, "DAI links not found in DT\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
do {
|
||||
struct device_node *codec = NULL, *cpu = NULL;
|
||||
struct snd_soc_dai_link *dai_link;
|
||||
int link_type = 0, codec_count = 0;
|
||||
|
||||
if (!of_dai_link_is_available(link_node)) {
|
||||
link_node = of_get_next_child(top, link_node);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "parsing (%pOF)\n", link_node);
|
||||
|
||||
cpu = of_get_child_by_name(link_node, "cpu");
|
||||
if (!cpu) {
|
||||
dev_err(&pdev->dev, "cpu subnode is missing");
|
||||
ret = -ENOENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for_each_child_of_node(link_node, codec) {
|
||||
/* loop over codecs only */
|
||||
if (of_node_cmp(codec->name, "codec"))
|
||||
continue;
|
||||
|
||||
if (!of_property_read_bool(codec, DAI)) {
|
||||
dev_dbg(&pdev->dev,
|
||||
"sound-dai prop missing for (%pOF)\n",
|
||||
codec);
|
||||
codec_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
dai_link = &dai_links[link_count];
|
||||
|
||||
/* parse CPU DAI */
|
||||
ret = asoc_simple_card_parse_cpu(cpu, dai_link, DAI,
|
||||
CELL, NULL);
|
||||
if (ret < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* parse CODEC DAI */
|
||||
ret = asoc_simple_card_parse_codec(codec, dai_link,
|
||||
DAI, CELL);
|
||||
if (ret < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* set DAI link name */
|
||||
if (of_property_read_string_index(link_node,
|
||||
"link-name",
|
||||
codec_count,
|
||||
&dai_link->name)) {
|
||||
ret = asoc_simple_card_set_dailink_name(
|
||||
&pdev->dev, dai_link, "%s-%d",
|
||||
"tegra-dlink", link_count);
|
||||
if (ret < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
asoc_simple_card_parse_daifmt(&pdev->dev, link_node,
|
||||
codec, NULL,
|
||||
&dai_link->dai_fmt);
|
||||
|
||||
of_property_read_u32(link_node, "link-type",
|
||||
&link_type);
|
||||
switch (link_type) {
|
||||
case PCM_LINK:
|
||||
dai_link->ops = pcm_ops;
|
||||
asoc_simple_card_canonicalize_dailink(dai_link);
|
||||
dai_link->ignore_pmdown_time = 1;
|
||||
break;
|
||||
case COMPR_LINK:
|
||||
dai_link->compr_ops = compr_ops;
|
||||
asoc_simple_card_canonicalize_dailink(dai_link);
|
||||
dai_link->ignore_pmdown_time = 1;
|
||||
break;
|
||||
case C2C_LINK:
|
||||
dai_link->params = &link_params;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "DAI link type invalid\n");
|
||||
ret = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
link_count++;
|
||||
codec_count++;
|
||||
}
|
||||
cleanup:
|
||||
of_node_put(cpu);
|
||||
if (ret < 0) {
|
||||
of_node_put(codec);
|
||||
of_node_put(link_node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
link_node = of_get_next_child(top, link_node);
|
||||
} while (link_node);
|
||||
|
||||
card->num_links = num_links;
|
||||
card->dai_link = dai_links;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_card_info(struct snd_soc_card *card, struct snd_soc_ops *pcm_ops,
|
||||
struct snd_soc_compr_ops *compr_ops)
|
||||
{
|
||||
struct device_node *node = card->dev->of_node;
|
||||
int ret;
|
||||
|
||||
ret = asoc_simple_card_parse_card_name(card, PREFIX);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* parse machine DAPM widgets */
|
||||
if (of_property_read_bool(node, PREFIX "widgets")) {
|
||||
ret = snd_soc_of_parse_audio_simple_widgets(card,
|
||||
PREFIX "widgets");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Below property of routing map is required only when there
|
||||
* are DAPM input/output widgets available for external codec,
|
||||
* which require them to be connected to machine source/sink
|
||||
* DAPM widgets.
|
||||
*/
|
||||
if (of_property_read_bool(node, PREFIX "routing")) {
|
||||
ret = snd_soc_of_parse_audio_routing(card, PREFIX "routing");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
parse_mclk_fs(card);
|
||||
|
||||
ret = parse_dt_dai_links(card, pcm_ops, compr_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = parse_dt_codec_confs(card);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(parse_card_info);
|
||||
|
||||
MODULE_DESCRIPTION("Tegra ASoC Machine driver DT parser code");
|
||||
MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Reference in New Issue
Block a user