^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Copyright (C) 2014-2015 Broadcom Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * This program is free software; you can redistribute it and/or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * modify it under the terms of the GNU General Public License as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * published by the Free Software Foundation version 2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This program is distributed "as is" WITHOUT ANY WARRANTY of any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * kind, whether express or implied; without even the implied warranty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * GNU General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <sound/soc-dai.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "cygnus-ssp.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define DEFAULT_VCO 1354750204
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define CAPTURE_FCI_ID_BASE 0x180
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define CYGNUS_PLLCLKSEL_MASK 0xf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* Used with stream_on field to indicate which streams are active */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define PLAYBACK_STREAM_MASK BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define CAPTURE_STREAM_MASK BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define I2S_STREAM_CFG_MASK 0xff003ff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define I2S_CAP_STREAM_CFG_MASK 0xf0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define SPDIF_STREAM_CFG_MASK 0x3ff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define CH_GRP_STEREO 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* Begin register offset defines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define AUD_MISC_SEROUT_OE_REG_BASE 0x01c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define AUD_MISC_SEROUT_SPDIF_OE 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define AUD_MISC_SEROUT_MCLK_OE 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define AUD_MISC_SEROUT_LRCK_OE 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define AUD_MISC_SEROUT_SCLK_OE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define AUD_MISC_SEROUT_SDAT_OE 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /* AUD_FMM_BF_CTRL_xxx regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define BF_DST_CFG0_OFFSET 0x100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define BF_DST_CFG1_OFFSET 0x104
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define BF_DST_CFG2_OFFSET 0x108
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define BF_DST_CTRL0_OFFSET 0x130
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define BF_DST_CTRL1_OFFSET 0x134
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define BF_DST_CTRL2_OFFSET 0x138
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define BF_SRC_CFG0_OFFSET 0x148
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define BF_SRC_CFG1_OFFSET 0x14c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define BF_SRC_CFG2_OFFSET 0x150
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define BF_SRC_CFG3_OFFSET 0x154
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define BF_SRC_CTRL0_OFFSET 0x1c0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define BF_SRC_CTRL1_OFFSET 0x1c4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define BF_SRC_CTRL2_OFFSET 0x1c8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define BF_SRC_CTRL3_OFFSET 0x1cc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define BF_SRC_GRP0_OFFSET 0x1fc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define BF_SRC_GRP1_OFFSET 0x200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define BF_SRC_GRP2_OFFSET 0x204
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define BF_SRC_GRP3_OFFSET 0x208
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define BF_SRC_GRP_EN_OFFSET 0x320
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define BF_SRC_GRP_FLOWON_OFFSET 0x324
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define BF_SRC_GRP_SYNC_DIS_OFFSET 0x328
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* AUD_FMM_IOP_OUT_I2S_xxx regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define OUT_I2S_0_STREAM_CFG_OFFSET 0xa00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define OUT_I2S_0_CFG_OFFSET 0xa04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define OUT_I2S_0_MCLK_CFG_OFFSET 0xa0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define OUT_I2S_1_STREAM_CFG_OFFSET 0xa40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define OUT_I2S_1_CFG_OFFSET 0xa44
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define OUT_I2S_1_MCLK_CFG_OFFSET 0xa4c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define OUT_I2S_2_STREAM_CFG_OFFSET 0xa80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define OUT_I2S_2_CFG_OFFSET 0xa84
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define OUT_I2S_2_MCLK_CFG_OFFSET 0xa8c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* AUD_FMM_IOP_OUT_SPDIF_xxx regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define SPDIF_STREAM_CFG_OFFSET 0xac0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define SPDIF_CTRL_OFFSET 0xac4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define SPDIF_FORMAT_CFG_OFFSET 0xad8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define SPDIF_MCLK_CFG_OFFSET 0xadc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /* AUD_FMM_IOP_PLL_0_xxx regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define IOP_PLL_0_MACRO_OFFSET 0xb00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #define IOP_PLL_0_MDIV_Ch0_OFFSET 0xb14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define IOP_PLL_0_MDIV_Ch1_OFFSET 0xb18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define IOP_PLL_0_MDIV_Ch2_OFFSET 0xb1c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define IOP_PLL_0_ACTIVE_MDIV_Ch0_OFFSET 0xb30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define IOP_PLL_0_ACTIVE_MDIV_Ch1_OFFSET 0xb34
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define IOP_PLL_0_ACTIVE_MDIV_Ch2_OFFSET 0xb38
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* AUD_FMM_IOP_xxx regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define IOP_PLL_0_CONTROL_OFFSET 0xb04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define IOP_PLL_0_USER_NDIV_OFFSET 0xb08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) #define IOP_PLL_0_ACTIVE_NDIV_OFFSET 0xb20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define IOP_PLL_0_RESET_OFFSET 0xb5c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* AUD_FMM_IOP_IN_I2S_xxx regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define IN_I2S_0_STREAM_CFG_OFFSET 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define IN_I2S_0_CFG_OFFSET 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define IN_I2S_1_STREAM_CFG_OFFSET 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define IN_I2S_1_CFG_OFFSET 0x44
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define IN_I2S_2_STREAM_CFG_OFFSET 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define IN_I2S_2_CFG_OFFSET 0x84
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /* AUD_FMM_IOP_MISC_xxx regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define IOP_SW_INIT_LOGIC 0x1c0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* End register offset defines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* AUD_FMM_IOP_OUT_I2S_x_MCLK_CFG_0_REG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #define I2S_OUT_MCLKRATE_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* AUD_FMM_IOP_OUT_I2S_x_MCLK_CFG_REG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #define I2S_OUT_PLLCLKSEL_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define I2S_OUT_STREAM_ENA 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #define I2S_OUT_STREAM_CFG_GROUP_ID 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define I2S_OUT_STREAM_CFG_CHANNEL_GROUPING 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* AUD_FMM_IOP_IN_I2S_x_CAP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #define I2S_IN_STREAM_CFG_CAP_ENA 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define I2S_IN_STREAM_CFG_0_GROUP_ID 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* AUD_FMM_IOP_OUT_I2S_x_I2S_CFG_REG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #define I2S_OUT_CFGX_CLK_ENA 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #define I2S_OUT_CFGX_DATA_ENABLE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #define I2S_OUT_CFGX_DATA_ALIGNMENT 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define I2S_OUT_CFGX_BITS_PER_SLOT 13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define I2S_OUT_CFGX_VALID_SLOT 14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #define I2S_OUT_CFGX_FSYNC_WIDTH 18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #define I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32 26
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define I2S_OUT_CFGX_SLAVE_MODE 30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) #define I2S_OUT_CFGX_TDM_MODE 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* AUD_FMM_BF_CTRL_SOURCECH_CFGx_REG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) #define BF_SRC_CFGX_SFIFO_ENA 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) #define BF_SRC_CFGX_BUFFER_PAIR_ENABLE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) #define BF_SRC_CFGX_SAMPLE_CH_MODE 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #define BF_SRC_CFGX_SFIFO_SZ_DOUBLE 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #define BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #define BF_SRC_CFGX_BIT_RES 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) #define BF_SRC_CFGX_PROCESS_SEQ_ID_VALID 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* AUD_FMM_BF_CTRL_DESTCH_CFGx_REG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #define BF_DST_CFGX_CAP_ENA 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #define BF_DST_CFGX_BUFFER_PAIR_ENABLE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #define BF_DST_CFGX_DFIFO_SZ_DOUBLE 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) #define BF_DST_CFGX_NOT_PAUSE_WHEN_FULL 11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #define BF_DST_CFGX_FCI_ID 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #define BF_DST_CFGX_CAP_MODE 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) #define BF_DST_CFGX_PROC_SEQ_ID_VALID 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /* AUD_FMM_IOP_OUT_SPDIF_xxx */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) #define SPDIF_0_OUT_DITHER_ENA 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) #define SPDIF_0_OUT_STREAM_ENA 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* AUD_FMM_IOP_PLL_0_USER */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) #define IOP_PLL_0_USER_NDIV_FRAC 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* AUD_FMM_IOP_PLL_0_ACTIVE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) #define IOP_PLL_0_ACTIVE_NDIV_FRAC 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) #define INIT_SSP_REGS(num) (struct cygnus_ssp_regs){ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .i2s_stream_cfg = OUT_I2S_ ##num## _STREAM_CFG_OFFSET, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) .i2s_cap_stream_cfg = IN_I2S_ ##num## _STREAM_CFG_OFFSET, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) .i2s_cfg = OUT_I2S_ ##num## _CFG_OFFSET, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) .i2s_cap_cfg = IN_I2S_ ##num## _CFG_OFFSET, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .i2s_mclk_cfg = OUT_I2S_ ##num## _MCLK_CFG_OFFSET, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .bf_destch_ctrl = BF_DST_CTRL ##num## _OFFSET, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .bf_destch_cfg = BF_DST_CFG ##num## _OFFSET, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .bf_sourcech_ctrl = BF_SRC_CTRL ##num## _OFFSET, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .bf_sourcech_cfg = BF_SRC_CFG ##num## _OFFSET, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .bf_sourcech_grp = BF_SRC_GRP ##num## _OFFSET \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct pll_macro_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) u32 mclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) u32 pll_ch_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * PLL has 3 output channels (1x, 2x, and 4x). Below are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * the common MCLK frequencies used by audio driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static const struct pll_macro_entry pll_predef_mclk[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) { 4096000, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) { 8192000, 1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {16384000, 2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) { 5644800, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) {11289600, 1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {22579200, 2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) { 6144000, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) {12288000, 1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) {24576000, 2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {12288000, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) {24576000, 1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {49152000, 2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {22579200, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {45158400, 1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {90316800, 2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) {24576000, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {49152000, 1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {98304000, 2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) #define CYGNUS_RATE_MIN 8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) #define CYGNUS_RATE_MAX 384000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* List of valid frame sizes for tdm mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static const unsigned int cygnus_rates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 8000, 11025, 16000, 22050, 32000, 44100, 48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 88200, 96000, 176400, 192000, 352800, 384000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static const struct snd_pcm_hw_constraint_list cygnus_rate_constraint = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .count = ARRAY_SIZE(cygnus_rates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .list = cygnus_rates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return &cygaud->portinfo[dai->id];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) u32 value, fci_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) int status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) switch (aio->port_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) case PORT_TDM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) value &= ~I2S_STREAM_CFG_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /* Set Group ID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) writel(aio->portnum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) aio->cygaud->audio + aio->regs.bf_sourcech_grp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /* Configure the AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) value |= aio->portnum << I2S_OUT_STREAM_CFG_GROUP_ID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) value |= aio->portnum; /* FCI ID is the port num */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) value |= CH_GRP_STEREO << I2S_OUT_STREAM_CFG_CHANNEL_GROUPING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /* Configure the AUD_FMM_BF_CTRL_SOURCECH_CFGX reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* Configure the AUD_FMM_IOP_IN_I2S_x_CAP_STREAM_CFG_0 reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) value = readl(aio->cygaud->i2s_in +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) aio->regs.i2s_cap_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) value &= ~I2S_CAP_STREAM_CFG_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) value |= aio->portnum << I2S_IN_STREAM_CFG_0_GROUP_ID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) writel(value, aio->cygaud->i2s_in +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) aio->regs.i2s_cap_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* Configure the AUD_FMM_BF_CTRL_DESTCH_CFGX_REG_BASE reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) fci_id = CAPTURE_FCI_ID_BASE + aio->portnum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) value |= BIT(BF_DST_CFGX_DFIFO_SZ_DOUBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) value &= ~BIT(BF_DST_CFGX_NOT_PAUSE_WHEN_FULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) value |= (fci_id << BF_DST_CFGX_FCI_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) value |= BIT(BF_DST_CFGX_PROC_SEQ_ID_VALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) /* Enable the transmit pin for this port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) value &= ~BIT((aio->portnum * 4) + AUD_MISC_SEROUT_SDAT_OE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) case PORT_SPDIF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) writel(aio->portnum, aio->cygaud->audio + BF_SRC_GRP3_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) value = readl(aio->cygaud->audio + SPDIF_CTRL_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) value |= BIT(SPDIF_0_OUT_DITHER_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) writel(value, aio->cygaud->audio + SPDIF_CTRL_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* Enable and set the FCI ID for the SPDIF channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) value = readl(aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) value &= ~SPDIF_STREAM_CFG_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) value |= aio->portnum; /* FCI ID is the port num */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) value |= BIT(SPDIF_0_OUT_STREAM_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) writel(value, aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* Enable the spdif output pin */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) value &= ~BIT(AUD_MISC_SEROUT_SPDIF_OE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) dev_err(aio->cygaud->dev, "Port not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) status = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) value |= BIT(BF_DST_CFGX_CAP_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) writel(0x1, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) value |= BIT(I2S_OUT_CFGX_CLK_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) value |= BIT(I2S_IN_STREAM_CFG_CAP_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) aio->streams_on |= CAPTURE_STREAM_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) value &= ~BIT(I2S_IN_STREAM_CFG_CAP_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) aio->streams_on &= ~CAPTURE_STREAM_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) /* If both playback and capture are off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (!aio->streams_on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) value &= ~BIT(BF_DST_CFGX_CAP_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) int status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) switch (aio->port_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) case PORT_TDM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) value |= BIT(I2S_OUT_STREAM_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) value |= BIT(I2S_OUT_CFGX_CLK_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) aio->streams_on |= PLAYBACK_STREAM_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) case PORT_SPDIF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) value |= 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) dev_err(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) "Port not supported %d\n", aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) status = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) int status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) switch (aio->port_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) case PORT_TDM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) aio->streams_on &= ~PLAYBACK_STREAM_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) /* If both playback and capture are off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (!aio->streams_on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /* set group_sync_dis = 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) value |= BIT(aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) /* set group_sync_dis = 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) value &= ~BIT(aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) value &= ~BIT(I2S_OUT_STREAM_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /* IOP SW INIT on OUT_I2S_x */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) value |= BIT(aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) value &= ~BIT(aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) case PORT_SPDIF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) value &= ~0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) dev_err(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) "Port not supported %d\n", aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) status = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) struct cygnus_aio_port *aio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) int i = 0, error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) const struct pll_macro_entry *p_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) struct clk *ch_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) for (i = 0; i < ARRAY_SIZE(pll_predef_mclk); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) p_entry = &pll_predef_mclk[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (p_entry->mclk == mclk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) if (!found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) dev_err(cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) "%s No valid mclk freq (%u) found!\n", __func__, mclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) ch_clk = cygaud->audio_clk[p_entry->pll_ch_num];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if ((aio->clk_trace.cap_en) && (!aio->clk_trace.cap_clk_en)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) error = clk_prepare_enable(ch_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) aio->clk_trace.cap_clk_en = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) if ((aio->clk_trace.play_en) && (!aio->clk_trace.play_clk_en)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) error = clk_prepare_enable(ch_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) aio->clk_trace.play_clk_en = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) error = clk_set_rate(ch_clk, mclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) dev_err(cygaud->dev, "%s Set MCLK rate failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) return p_entry->pll_ch_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) u32 mask = 0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) u32 sclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) u32 mclk_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) unsigned int bit_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) unsigned int ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) bit_rate = aio->bit_per_frame * aio->lrclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * Check if the bit clock can be generated from the given MCLK.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * MCLK must be a perfect multiple of bit clock and must be one of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * following values... (2,4,6,8,10,12,14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if ((aio->mclk % bit_rate) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) ratio = aio->mclk / bit_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) switch (ratio) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) case 10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) case 12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) case 14:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) mclk_rate = ratio / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) dev_err(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) "Invalid combination of MCLK and BCLK\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) aio->lrclk, aio->bit_per_frame, aio->mclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) /* Set sclk rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) switch (aio->port_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) case PORT_TDM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) sclk = aio->bit_per_frame;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (sclk == 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) sclk = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) /* sclks_per_1fs_div = sclk cycles/32 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) sclk /= 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) /* Set number of bitclks per frame */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) value |= sclk << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) dev_dbg(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) "SCLKS_PER_1FS_DIV32 = 0x%x\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) case PORT_SPDIF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) dev_err(aio->cygaud->dev, "Unknown port type\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) /* Set MCLK_RATE ssp port (spdif and ssp are the same) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) dev_dbg(aio->cygaud->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) aio->bit_per_frame, aio->mclk, aio->lrclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) struct snd_pcm_hw_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) int rate, bitres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) u32 mask = 0x1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) dev_dbg(aio->cygaud->dev, "%s port = %d\n", __func__, aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) dev_dbg(aio->cygaud->dev, "params_channels %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) params_channels(params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) dev_dbg(aio->cygaud->dev, "rate %d\n", params_rate(params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) dev_dbg(aio->cygaud->dev, "format %d\n", params_format(params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) rate = params_rate(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) switch (aio->mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) case CYGNUS_SSPMODE_TDM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) if ((rate == 192000) && (params_channels(params) > 4)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) dev_err(aio->cygaud->dev, "Cannot run %d channels at %dHz\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) params_channels(params), rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) case CYGNUS_SSPMODE_I2S:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) aio->bit_per_frame = 64; /* I2S must be 64 bit per frame */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) dev_err(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) "%s port running in unknown mode\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) switch (params_format(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) case SNDRV_PCM_FORMAT_S16_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) bitres = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) case SNDRV_PCM_FORMAT_S32_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) /* 32 bit mode is coded as 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) bitres = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) value &= ~(mask << BF_SRC_CFGX_BIT_RES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) value |= (bitres << BF_SRC_CFGX_BIT_RES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) switch (params_format(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) case SNDRV_PCM_FORMAT_S16_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) value = readl(aio->cygaud->audio +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) value |= BIT(BF_DST_CFGX_CAP_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) writel(value, aio->cygaud->audio +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) case SNDRV_PCM_FORMAT_S32_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) value = readl(aio->cygaud->audio +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) value &= ~BIT(BF_DST_CFGX_CAP_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) writel(value, aio->cygaud->audio +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) aio->regs.bf_destch_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) aio->lrclk = rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) if (!aio->is_slave)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) ret = cygnus_ssp_set_clocks(aio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) * This function sets the mclk frequency for pll clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) int clk_id, unsigned int freq, int dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) int sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) dev_dbg(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) "%s Enter port = %d\n", __func__, aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) sel = pll_configure_mclk(cygaud, freq, aio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) if (sel < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) dev_err(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) "%s Setting mclk failed.\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) aio->mclk = freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) value &= ~(0xf << I2S_OUT_PLLCLKSEL_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) value |= (sel << I2S_OUT_PLLCLKSEL_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) snd_soc_dai_set_dma_data(dai, substream, aio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) aio->clk_trace.play_en = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) aio->clk_trace.cap_en = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) snd_pcm_hw_constraint_list(substream->runtime, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) aio->clk_trace.play_en = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) aio->clk_trace.cap_en = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (!aio->is_slave) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) val &= CYGNUS_PLLCLKSEL_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (aio->clk_trace.play_clk_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) clk_disable_unprepare(aio->cygaud->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) audio_clk[val]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) aio->clk_trace.play_clk_en = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) if (aio->clk_trace.cap_clk_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) clk_disable_unprepare(aio->cygaud->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) audio_clk[val]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) aio->clk_trace.cap_clk_en = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) * Bit Update Notes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) * 31 Yes TDM Mode (1 = TDM, 0 = i2s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) * 30 Yes Slave Mode (1 = Slave, 0 = Master)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) * 29:26 No Sclks per frame
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) * 25:18 Yes FS Width
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) * 17:14 No Valid Slots
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) * 13 No Bits (1 = 16 bits, 0 = 32 bits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) * 12:08 No Bits per samp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) * 07 Yes Justifcation (1 = LSB, 0 = MSB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) * 06 Yes Alignment (1 = Delay 1 clk, 0 = no delay
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) * 05 Yes SCLK polarity (1 = Rising, 0 = Falling)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) * 04 Yes LRCLK Polarity (1 = High for left, 0 = Low for left)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) * 03:02 Yes Reserved - write as zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) * 01 No Data Enable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) * 00 No CLK Enable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) #define I2S_OUT_CFG_REG_UPDATE_MASK 0x3C03FF03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) /* Input cfg is same as output, but the FS width is not a valid field */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) #define I2S_IN_CFG_REG_UPDATE_MASK (I2S_OUT_CFG_REG_UPDATE_MASK | 0x03FC0000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) if ((len > 0) && (len < 256)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) aio->fsync_width = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) EXPORT_SYMBOL_GPL(cygnus_ssp_set_custom_fsync_width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) u32 ssp_curcfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) u32 ssp_newcfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) u32 ssp_outcfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) u32 ssp_incfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) u32 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) dev_dbg(aio->cygaud->dev, "%s Enter fmt: %x\n", __func__, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) if (aio->port_type == PORT_SPDIF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) ssp_newcfg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) case SND_SOC_DAIFMT_CBM_CFM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) aio->is_slave = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) case SND_SOC_DAIFMT_CBS_CFS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) aio->is_slave = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) case SND_SOC_DAIFMT_I2S:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) aio->mode = CYGNUS_SSPMODE_I2S;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) case SND_SOC_DAIFMT_DSP_A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) case SND_SOC_DAIFMT_DSP_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) ssp_newcfg |= BIT(I2S_OUT_CFGX_TDM_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) /* DSP_A = data after FS, DSP_B = data during FS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) if ((aio->fsync_width > 0) && (aio->fsync_width < 256))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) ssp_newcfg |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) (aio->fsync_width << I2S_OUT_CFGX_FSYNC_WIDTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) aio->mode = CYGNUS_SSPMODE_TDM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) * SSP out cfg.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) * Retain bits we do not want to update, then OR in new bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) * SSP in cfg.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) * Retain bits we do not want to update, then OR in new bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) val = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) * Configure the word clk and bit clk as output or tristate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) * Each port has 4 bits for controlling its pins.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) * Shift the mask based upon port number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) mask = BIT(AUD_MISC_SEROUT_LRCK_OE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) | BIT(AUD_MISC_SEROUT_SCLK_OE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) | BIT(AUD_MISC_SEROUT_MCLK_OE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) mask = mask << (aio->portnum * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) if (aio->is_slave)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) /* Set bit for tri-state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) val |= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) /* Clear bit for drive */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) val &= ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) dev_dbg(aio->cygaud->dev, "%s Set OE bits 0x%x\n", __func__, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) writel(val, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) dev_dbg(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) "%s cmd %d at port = %d\n", __func__, cmd, aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) case SNDRV_PCM_TRIGGER_RESUME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) audio_ssp_out_enable(aio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) audio_ssp_in_enable(aio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) cygaud->active_ports++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) audio_ssp_out_disable(aio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) audio_ssp_in_disable(aio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) cygaud->active_ports--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) int bits_per_slot = 0; /* default to 32-bits per slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) int frame_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) unsigned int active_slots;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) if (tx_mask != rx_mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) dev_err(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) "%s tx_mask must equal rx_mask\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) active_slots = hweight32(tx_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) if (active_slots > 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) /* Slot value must be even */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) if (active_slots % 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) /* We encode 16 slots as 0 in the reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) if (active_slots == 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) active_slots = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) /* Slot Width is either 16 or 32 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) switch (slot_width) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) bits_per_slot = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) bits_per_slot = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) bits_per_slot = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) dev_warn(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) "%s Defaulting Slot Width to 32\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) frame_bits = slots * slot_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) for (i = 0; i < ARRAY_SIZE(ssp_valid_tdm_framesize); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) if (ssp_valid_tdm_framesize[i] == frame_bits) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) if (!found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) dev_err(aio->cygaud->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) "%s In TDM mode, frame bits INVALID (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) __func__, frame_bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) aio->bit_per_frame = frame_bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) dev_dbg(aio->cygaud->dev, "%s active_slots %u, bits per frame %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) __func__, active_slots, frame_bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) /* Set capture side of ssp port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) /* Set playback side of ssp port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) static int __cygnus_ssp_suspend(struct snd_soc_dai *cpu_dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) if (!snd_soc_dai_active(cpu_dai))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) if (!aio->is_slave) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) val &= CYGNUS_PLLCLKSEL_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) if (aio->clk_trace.cap_clk_en)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) clk_disable_unprepare(aio->cygaud->audio_clk[val]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) if (aio->clk_trace.play_clk_en)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) clk_disable_unprepare(aio->cygaud->audio_clk[val]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) aio->pll_clk_num = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) static int cygnus_ssp_suspend(struct snd_soc_component *component)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) struct snd_soc_dai *dai;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) for_each_component_dais(component, dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) ret |= __cygnus_ssp_suspend(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) static int __cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) if (!snd_soc_dai_active(cpu_dai))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) if (!aio->is_slave) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) if (aio->clk_trace.cap_clk_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) error = clk_prepare_enable(aio->cygaud->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) audio_clk[aio->pll_clk_num]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) if (aio->clk_trace.play_clk_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) error = clk_prepare_enable(aio->cygaud->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) audio_clk[aio->pll_clk_num]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) if (aio->clk_trace.cap_clk_en)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) clk_disable_unprepare(aio->cygaud->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) audio_clk[aio->pll_clk_num]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) static int cygnus_ssp_resume(struct snd_soc_component *component)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) struct snd_soc_dai *dai;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) for_each_component_dais(component, dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) ret |= __cygnus_ssp_resume(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) #define cygnus_ssp_suspend NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) #define cygnus_ssp_resume NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) .startup = cygnus_ssp_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) .shutdown = cygnus_ssp_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) .trigger = cygnus_ssp_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) .hw_params = cygnus_ssp_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) .set_fmt = cygnus_ssp_set_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) .set_sysclk = cygnus_ssp_set_sysclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) .set_tdm_slot = cygnus_set_dai_tdm_slot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) .startup = cygnus_ssp_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) .shutdown = cygnus_ssp_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) .trigger = cygnus_ssp_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) .hw_params = cygnus_ssp_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) .set_sysclk = cygnus_ssp_set_sysclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) #define INIT_CPU_DAI(num) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) .name = "cygnus-ssp" #num, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) .playback = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) .channels_min = 2, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) .channels_max = 16, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) .rates = SNDRV_PCM_RATE_KNOT, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) .formats = SNDRV_PCM_FMTBIT_S16_LE | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) SNDRV_PCM_FMTBIT_S32_LE, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) }, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) .capture = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) .channels_min = 2, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) .channels_max = 16, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) .rates = SNDRV_PCM_RATE_KNOT, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) .formats = SNDRV_PCM_FMTBIT_S16_LE | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) SNDRV_PCM_FMTBIT_S32_LE, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) }, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) .ops = &cygnus_ssp_dai_ops, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) static const struct snd_soc_dai_driver cygnus_ssp_dai_info[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) INIT_CPU_DAI(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) INIT_CPU_DAI(1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) INIT_CPU_DAI(2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) static const struct snd_soc_dai_driver cygnus_spdif_dai_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) .name = "cygnus-spdif",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) .playback = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) .rates = SNDRV_PCM_RATE_KNOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) .formats = SNDRV_PCM_FMTBIT_S16_LE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) SNDRV_PCM_FMTBIT_S32_LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) .ops = &cygnus_spdif_dai_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) static const struct snd_soc_component_driver cygnus_ssp_component = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) .name = "cygnus-audio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) .suspend = cygnus_ssp_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) .resume = cygnus_ssp_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) * Return < 0 if error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) * Return 0 if disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) * Return 1 if enabled and node is parsed successfully
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) static int parse_ssp_child_node(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) struct device_node *dn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) struct cygnus_audio *cygaud,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) struct snd_soc_dai_driver *p_dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) struct cygnus_aio_port *aio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) struct cygnus_ssp_regs ssp_regs[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) u32 rawval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) int portnum = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) enum cygnus_audio_port_type port_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) if (of_property_read_u32(dn, "reg", &rawval)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) dev_err(&pdev->dev, "Missing reg property\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) portnum = rawval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) switch (rawval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) ssp_regs[0] = INIT_SSP_REGS(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) port_type = PORT_TDM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) ssp_regs[1] = INIT_SSP_REGS(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) port_type = PORT_TDM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) ssp_regs[2] = INIT_SSP_REGS(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) port_type = PORT_TDM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) port_type = PORT_SPDIF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) dev_err(&pdev->dev, "Bad value for reg %u\n", rawval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) aio = &cygaud->portinfo[portnum];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) aio->cygaud = cygaud;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) aio->portnum = portnum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) aio->port_type = port_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) aio->fsync_width = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) switch (port_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) case PORT_TDM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) aio->regs = ssp_regs[portnum];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) *p_dai = cygnus_ssp_dai_info[portnum];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) aio->mode = CYGNUS_SSPMODE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) case PORT_SPDIF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) aio->regs.bf_sourcech_cfg = BF_SRC_CFG3_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) aio->regs.bf_sourcech_ctrl = BF_SRC_CTRL3_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) aio->regs.i2s_mclk_cfg = SPDIF_MCLK_CFG_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) aio->regs.i2s_stream_cfg = SPDIF_STREAM_CFG_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) *p_dai = cygnus_spdif_dai_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) /* For the purposes of this code SPDIF can be I2S mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) aio->mode = CYGNUS_SSPMODE_I2S;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) dev_err(&pdev->dev, "Bad value for port_type %d\n", port_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) aio->streams_on = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) aio->cygaud->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) aio->clk_trace.play_en = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) aio->clk_trace.cap_en = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) audio_ssp_init_portregs(aio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) static int audio_clk_init(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) struct cygnus_audio *cygaud)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) char clk_name[PROP_LEN_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) for (i = 0; i < ARRAY_SIZE(cygaud->audio_clk); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) snprintf(clk_name, PROP_LEN_MAX, "ch%d_audio", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) cygaud->audio_clk[i] = devm_clk_get(&pdev->dev, clk_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) if (IS_ERR(cygaud->audio_clk[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) return PTR_ERR(cygaud->audio_clk[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) static int cygnus_ssp_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) struct device_node *child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) struct cygnus_audio *cygaud;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) int err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) int node_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) int active_port_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) cygaud = devm_kzalloc(dev, sizeof(struct cygnus_audio), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) if (!cygaud)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) dev_set_drvdata(dev, cygaud);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aud");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) cygaud->audio = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) if (IS_ERR(cygaud->audio))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) return PTR_ERR(cygaud->audio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "i2s_in");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) cygaud->i2s_in = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) if (IS_ERR(cygaud->i2s_in))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) return PTR_ERR(cygaud->i2s_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) /* Tri-state all controlable pins until we know that we need them */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) writel(CYGNUS_SSP_TRISTATE_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) node_count = of_get_child_count(pdev->dev.of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) if ((node_count < 1) || (node_count > CYGNUS_MAX_PORTS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) dev_err(dev, "child nodes is %d. Must be between 1 and %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) node_count, CYGNUS_MAX_PORTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) active_port_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) for_each_available_child_of_node(pdev->dev.of_node, child_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) err = parse_ssp_child_node(pdev, child_node, cygaud,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) &cygnus_ssp_dai[active_port_count]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) /* negative is err, 0 is active and good, 1 is disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) else if (!err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) dev_dbg(dev, "Activating DAI: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) cygnus_ssp_dai[active_port_count].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) active_port_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) cygaud->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) cygaud->active_ports = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) dev_dbg(dev, "Registering %d DAIs\n", active_port_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) err = devm_snd_soc_register_component(dev, &cygnus_ssp_component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) cygnus_ssp_dai, active_port_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) dev_err(dev, "snd_soc_register_dai failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) cygaud->irq_num = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) if (cygaud->irq_num <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) return cygaud->irq_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) err = audio_clk_init(pdev, cygaud);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) dev_err(dev, "audio clock initialization failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) err = cygnus_soc_platform_register(dev, cygaud);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) dev_err(dev, "platform reg error %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) static int cygnus_ssp_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) cygnus_soc_platform_unregister(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) static const struct of_device_id cygnus_ssp_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) { .compatible = "brcm,cygnus-audio" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) MODULE_DEVICE_TABLE(of, cygnus_ssp_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) static struct platform_driver cygnus_ssp_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) .probe = cygnus_ssp_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) .remove = cygnus_ssp_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) .name = "cygnus-ssp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) .of_match_table = cygnus_ssp_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) module_platform_driver(cygnus_ssp_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) MODULE_ALIAS("platform:cygnus-ssp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) MODULE_AUTHOR("Broadcom");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) MODULE_DESCRIPTION("Cygnus ASoC SSP Interface");