2018-08-01 14:31:09 +05:30
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2018 , The Linux Foundation . All rights reserved .
*/
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/of_device.h>
2018-11-28 17:00:35 +08:00
# include <sound/core.h>
2018-08-01 14:31:09 +05:30
# include <sound/pcm.h>
# include <sound/pcm_params.h>
2018-11-24 19:09:46 +08:00
# include <sound/jack.h>
2018-11-28 17:00:35 +08:00
# include <sound/soc.h>
2020-03-17 15:12:32 +00:00
# include <linux/soundwire/sdw.h>
2018-11-24 19:09:46 +08:00
# include <uapi/linux/input-event-codes.h>
2018-08-01 14:31:09 +05:30
# include "common.h"
# include "qdsp6/q6afe.h"
2018-11-28 17:00:36 +08:00
# include "../codecs/rt5663.h"
2018-08-01 14:31:09 +05:30
2020-10-23 10:58:49 +01:00
# define DRIVER_NAME "sdm845"
2018-08-01 14:31:09 +05:30
# define DEFAULT_SAMPLE_RATE_48K 48000
# define DEFAULT_MCLK_RATE 24576000
2018-11-16 13:11:57 +05:30
# define TDM_BCLK_RATE 6144000
# define MI2S_BCLK_RATE 1536000
2018-11-28 17:00:35 +08:00
# define LEFT_SPK_TDM_TX_MASK 0x30
# define RIGHT_SPK_TDM_TX_MASK 0xC0
# define SPK_TDM_RX_MASK 0x03
# define NUM_TDM_SLOTS 8
2019-12-19 10:31:53 +00:00
# define SLIM_MAX_TX_PORTS 16
2021-03-09 14:21:28 +00:00
# define SLIM_MAX_RX_PORTS 13
2019-12-19 10:31:53 +00:00
# define WCD934X_DEFAULT_MCLK_RATE 9600000
2018-08-01 14:31:09 +05:30
struct sdm845_snd_data {
2018-11-24 19:09:46 +08:00
struct snd_soc_jack jack ;
bool jack_setup ;
2021-11-16 11:50:21 +00:00
bool slim_port_setup ;
2021-03-09 14:21:27 +00:00
bool stream_prepared [ AFE_PORT_MAX ] ;
2018-08-01 14:31:09 +05:30
struct snd_soc_card * card ;
uint32_t pri_mi2s_clk_count ;
2018-11-16 13:11:58 +05:30
uint32_t sec_mi2s_clk_count ;
2018-08-01 14:31:09 +05:30
uint32_t quat_tdm_clk_count ;
2021-03-09 14:21:27 +00:00
struct sdw_stream_runtime * sruntime [ AFE_PORT_MAX ] ;
2018-08-01 14:31:09 +05:30
} ;
static unsigned int tdm_slot_offset [ 8 ] = { 0 , 4 , 8 , 12 , 16 , 20 , 24 , 28 } ;
2019-12-19 10:31:53 +00:00
static int sdm845_slim_snd_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
2020-07-20 10:19:00 +09:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-23 14:20:01 +09:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
2020-02-19 15:56:01 +09:00
struct snd_soc_dai * codec_dai ;
2020-03-17 15:12:32 +00:00
struct sdm845_snd_data * pdata = snd_soc_card_get_drvdata ( rtd - > card ) ;
2019-12-19 10:31:53 +00:00
u32 rx_ch [ SLIM_MAX_RX_PORTS ] , tx_ch [ SLIM_MAX_TX_PORTS ] ;
2020-03-17 15:12:32 +00:00
struct sdw_stream_runtime * sruntime ;
2019-12-19 10:31:53 +00:00
u32 rx_ch_cnt = 0 , tx_ch_cnt = 0 ;
int ret = 0 , i ;
2020-03-09 13:07:57 +09:00
for_each_rtd_codec_dais ( rtd , i , codec_dai ) {
2021-12-24 10:10:31 +08:00
sruntime = snd_soc_dai_get_stream ( codec_dai ,
substream - > stream ) ;
2020-03-17 15:12:32 +00:00
if ( sruntime ! = ERR_PTR ( - ENOTSUPP ) )
pdata - > sruntime [ cpu_dai - > id ] = sruntime ;
2020-02-19 15:56:01 +09:00
ret = snd_soc_dai_get_channel_map ( codec_dai ,
2019-12-19 10:31:53 +00:00
& tx_ch_cnt , tx_ch , & rx_ch_cnt , rx_ch ) ;
if ( ret ! = 0 & & ret ! = - ENOTSUPP ) {
pr_err ( " failed to get codec chan map, err:%d \n " , ret ) ;
return ret ;
} else if ( ret = = - ENOTSUPP ) {
/* Ignore unsupported */
continue ;
}
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
ret = snd_soc_dai_set_channel_map ( cpu_dai , 0 , NULL ,
rx_ch_cnt , rx_ch ) ;
else
ret = snd_soc_dai_set_channel_map ( cpu_dai , tx_ch_cnt ,
tx_ch , 0 , NULL ) ;
}
return 0 ;
}
2018-08-01 14:31:09 +05:30
static int sdm845_tdm_snd_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
2020-07-20 10:19:00 +09:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-23 14:20:01 +09:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
2020-02-19 15:56:01 +09:00
struct snd_soc_dai * codec_dai ;
2018-11-28 17:00:35 +08:00
int ret = 0 , j ;
2018-08-01 14:31:09 +05:30
int channels , slot_width ;
switch ( params_format ( params ) ) {
case SNDRV_PCM_FORMAT_S16_LE :
2018-11-16 13:11:57 +05:30
slot_width = 16 ;
2018-08-01 14:31:09 +05:30
break ;
default :
dev_err ( rtd - > dev , " %s: invalid param format 0x%x \n " ,
__func__ , params_format ( params ) ) ;
return - EINVAL ;
}
channels = params_channels ( params ) ;
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
ret = snd_soc_dai_set_tdm_slot ( cpu_dai , 0 , 0x3 ,
8 , slot_width ) ;
if ( ret < 0 ) {
dev_err ( rtd - > dev , " %s: failed to set tdm slot, err:%d \n " ,
__func__ , ret ) ;
goto end ;
}
ret = snd_soc_dai_set_channel_map ( cpu_dai , 0 , NULL ,
channels , tdm_slot_offset ) ;
if ( ret < 0 ) {
dev_err ( rtd - > dev , " %s: failed to set channel map, err:%d \n " ,
__func__ , ret ) ;
goto end ;
}
} else {
ret = snd_soc_dai_set_tdm_slot ( cpu_dai , 0xf , 0 ,
8 , slot_width ) ;
if ( ret < 0 ) {
dev_err ( rtd - > dev , " %s: failed to set tdm slot, err:%d \n " ,
__func__ , ret ) ;
goto end ;
}
ret = snd_soc_dai_set_channel_map ( cpu_dai , channels ,
tdm_slot_offset , 0 , NULL ) ;
if ( ret < 0 ) {
dev_err ( rtd - > dev , " %s: failed to set channel map, err:%d \n " ,
__func__ , ret ) ;
goto end ;
}
}
2018-11-28 17:00:35 +08:00
2020-03-09 13:07:57 +09:00
for_each_rtd_codec_dais ( rtd , j , codec_dai ) {
2018-11-28 17:00:35 +08:00
if ( ! strcmp ( codec_dai - > component - > name_prefix , " Left " ) ) {
ret = snd_soc_dai_set_tdm_slot (
codec_dai , LEFT_SPK_TDM_TX_MASK ,
SPK_TDM_RX_MASK , NUM_TDM_SLOTS ,
slot_width ) ;
if ( ret < 0 ) {
dev_err ( rtd - > dev ,
" DEV0 TDM slot err:%d \n " , ret ) ;
return ret ;
}
}
if ( ! strcmp ( codec_dai - > component - > name_prefix , " Right " ) ) {
ret = snd_soc_dai_set_tdm_slot (
codec_dai , RIGHT_SPK_TDM_TX_MASK ,
SPK_TDM_RX_MASK , NUM_TDM_SLOTS ,
slot_width ) ;
if ( ret < 0 ) {
dev_err ( rtd - > dev ,
" DEV1 TDM slot err:%d \n " , ret ) ;
return ret ;
}
}
}
2018-08-01 14:31:09 +05:30
end :
return ret ;
}
static int sdm845_snd_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
2020-07-20 10:19:00 +09:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-23 14:20:01 +09:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
2018-08-01 14:31:09 +05:30
int ret = 0 ;
switch ( cpu_dai - > id ) {
2018-11-28 17:00:36 +08:00
case PRIMARY_MI2S_RX :
case PRIMARY_MI2S_TX :
/*
* Use ASRC for internal clocks , as PLL rate isn ' t multiple
* of BCLK .
*/
rt5663_sel_asrc_clk_src (
codec_dai - > component ,
RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER ,
RT5663_CLK_SEL_I2S1_ASRC ) ;
ret = snd_soc_dai_set_sysclk (
codec_dai , RT5663_SCLK_S_MCLK , DEFAULT_MCLK_RATE ,
SND_SOC_CLOCK_IN ) ;
if ( ret < 0 )
dev_err ( rtd - > dev ,
" snd_soc_dai_set_sysclk err = %d \n " , ret ) ;
break ;
2018-08-01 14:31:09 +05:30
case QUATERNARY_TDM_RX_0 :
case QUATERNARY_TDM_TX_0 :
ret = sdm845_tdm_snd_hw_params ( substream , params ) ;
break ;
2019-12-19 10:31:53 +00:00
case SLIMBUS_0_RX . . . SLIMBUS_6_TX :
ret = sdm845_slim_snd_hw_params ( substream , params ) ;
break ;
case QUATERNARY_MI2S_RX :
break ;
2018-08-01 14:31:09 +05:30
default :
pr_err ( " %s: invalid dai id 0x%x \n " , __func__ , cpu_dai - > id ) ;
break ;
}
return ret ;
}
2018-12-14 15:31:43 +05:30
static void sdm845_jack_free ( struct snd_jack * jack )
{
struct snd_soc_component * component = jack - > private_data ;
snd_soc_component_set_jack ( component , NULL , NULL ) ;
}
2018-11-24 19:09:46 +08:00
static int sdm845_dai_init ( struct snd_soc_pcm_runtime * rtd )
{
struct snd_soc_component * component ;
struct snd_soc_card * card = rtd - > card ;
2020-03-23 14:20:01 +09:00
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
2018-11-24 19:09:46 +08:00
struct sdm845_snd_data * pdata = snd_soc_card_get_drvdata ( card ) ;
2021-11-16 11:50:21 +00:00
struct snd_soc_dai_link * link = rtd - > dai_link ;
2018-12-14 15:31:43 +05:30
struct snd_jack * jack ;
2019-12-19 10:31:53 +00:00
/*
* Codec SLIMBUS configuration
* RX1 , RX2 , RX3 , RX4 , RX5 , RX6 , RX7 , RX8 , RX9 , RX10 , RX11 , RX12 , RX13
* TX1 , TX2 , TX3 , TX4 , TX5 , TX6 , TX7 , TX8 , TX9 , TX10 , TX11 , TX12 , TX13
* TX14 , TX15 , TX16
*/
unsigned int rx_ch [ SLIM_MAX_RX_PORTS ] = { 144 , 145 , 146 , 147 , 148 , 149 ,
150 , 151 , 152 , 153 , 154 , 155 , 156 } ;
unsigned int tx_ch [ SLIM_MAX_TX_PORTS ] = { 128 , 129 , 130 , 131 , 132 , 133 ,
134 , 135 , 136 , 137 , 138 , 139 ,
140 , 141 , 142 , 143 } ;
int rval , i ;
2018-11-24 19:09:46 +08:00
if ( ! pdata - > jack_setup ) {
rval = snd_soc_card_jack_new ( card , " Headset Jack " ,
SND_JACK_HEADSET |
SND_JACK_HEADPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3 ,
2022-04-08 13:11:14 +09:00
& pdata - > jack ) ;
2018-11-24 19:09:46 +08:00
if ( rval < 0 ) {
dev_err ( card - > dev , " Unable to add Headphone Jack \n " ) ;
return rval ;
}
jack = pdata - > jack . jack ;
snd_jack_set_key ( jack , SND_JACK_BTN_0 , KEY_PLAYPAUSE ) ;
snd_jack_set_key ( jack , SND_JACK_BTN_1 , KEY_VOICECOMMAND ) ;
snd_jack_set_key ( jack , SND_JACK_BTN_2 , KEY_VOLUMEUP ) ;
snd_jack_set_key ( jack , SND_JACK_BTN_3 , KEY_VOLUMEDOWN ) ;
pdata - > jack_setup = true ;
}
2018-12-14 15:31:43 +05:30
switch ( cpu_dai - > id ) {
case PRIMARY_MI2S_RX :
jack = pdata - > jack . jack ;
component = codec_dai - > component ;
2018-11-24 19:09:46 +08:00
2018-12-14 15:31:43 +05:30
jack - > private_data = component ;
jack - > private_free = sdm845_jack_free ;
rval = snd_soc_component_set_jack ( component ,
& pdata - > jack , NULL ) ;
2018-11-24 19:09:46 +08:00
if ( rval ! = 0 & & rval ! = - ENOTSUPP ) {
dev_warn ( card - > dev , " Failed to set jack: %d \n " , rval ) ;
return rval ;
}
2018-12-14 15:31:43 +05:30
break ;
2019-12-19 10:31:53 +00:00
case SLIMBUS_0_RX . . . SLIMBUS_6_TX :
2021-11-16 11:50:21 +00:00
/* setting up wcd multiple times for slim port is redundant */
if ( pdata - > slim_port_setup | | ! link - > no_pcm )
return 0 ;
2020-03-09 13:07:57 +09:00
for_each_rtd_codec_dais ( rtd , i , codec_dai ) {
2020-02-19 15:56:01 +09:00
rval = snd_soc_dai_set_channel_map ( codec_dai ,
2019-12-19 10:31:53 +00:00
ARRAY_SIZE ( tx_ch ) ,
tx_ch ,
ARRAY_SIZE ( rx_ch ) ,
rx_ch ) ;
if ( rval ! = 0 & & rval ! = - ENOTSUPP )
return rval ;
2020-02-19 15:56:01 +09:00
snd_soc_dai_set_sysclk ( codec_dai , 0 ,
2019-12-19 10:31:53 +00:00
WCD934X_DEFAULT_MCLK_RATE ,
SNDRV_PCM_STREAM_PLAYBACK ) ;
2021-06-04 12:52:30 +01:00
rval = snd_soc_component_set_jack ( codec_dai - > component ,
& pdata - > jack , NULL ) ;
if ( rval ! = 0 & & rval ! = - ENOTSUPP ) {
dev_warn ( card - > dev , " Failed to set jack: %d \n " , rval ) ;
return rval ;
}
2019-12-19 10:31:53 +00:00
}
2021-11-16 11:50:21 +00:00
pdata - > slim_port_setup = true ;
2019-12-19 10:31:53 +00:00
break ;
2018-12-14 15:31:43 +05:30
default :
break ;
2018-11-24 19:09:46 +08:00
}
return 0 ;
}
2018-08-01 14:31:09 +05:30
static int sdm845_snd_startup ( struct snd_pcm_substream * substream )
{
2022-05-19 16:42:39 +01:00
unsigned int fmt = SND_SOC_DAIFMT_BP_FP ;
unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC ;
2020-07-20 10:19:00 +09:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2018-08-01 14:31:09 +05:30
struct snd_soc_card * card = rtd - > card ;
struct sdm845_snd_data * data = snd_soc_card_get_drvdata ( card ) ;
2020-03-23 14:20:01 +09:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
2018-11-28 17:00:35 +08:00
int j ;
int ret ;
2018-08-01 14:31:09 +05:30
switch ( cpu_dai - > id ) {
case PRIMARY_MI2S_RX :
case PRIMARY_MI2S_TX :
2018-11-28 17:00:36 +08:00
codec_dai_fmt | = SND_SOC_DAIFMT_NB_NF ;
2018-08-01 14:31:09 +05:30
if ( + + ( data - > pri_mi2s_clk_count ) = = 1 ) {
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_MCLK_1 ,
DEFAULT_MCLK_RATE , SNDRV_PCM_STREAM_PLAYBACK ) ;
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ,
2018-11-16 13:11:57 +05:30
MI2S_BCLK_RATE , SNDRV_PCM_STREAM_PLAYBACK ) ;
2018-08-01 14:31:09 +05:30
}
snd_soc_dai_set_fmt ( cpu_dai , fmt ) ;
2018-11-28 17:00:36 +08:00
snd_soc_dai_set_fmt ( codec_dai , codec_dai_fmt ) ;
2018-08-01 14:31:09 +05:30
break ;
2018-11-16 13:11:58 +05:30
case SECONDARY_MI2S_TX :
2019-01-15 16:41:59 +08:00
codec_dai_fmt | = SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S ;
2018-11-16 13:11:58 +05:30
if ( + + ( data - > sec_mi2s_clk_count ) = = 1 ) {
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT ,
MI2S_BCLK_RATE , SNDRV_PCM_STREAM_CAPTURE ) ;
}
snd_soc_dai_set_fmt ( cpu_dai , fmt ) ;
2019-01-15 16:41:59 +08:00
snd_soc_dai_set_fmt ( codec_dai , codec_dai_fmt ) ;
2019-12-19 10:31:53 +00:00
break ;
case QUATERNARY_MI2S_RX :
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT ,
MI2S_BCLK_RATE , SNDRV_PCM_STREAM_PLAYBACK ) ;
2022-05-19 16:42:39 +01:00
snd_soc_dai_set_fmt ( cpu_dai , fmt ) ;
2019-12-19 10:31:53 +00:00
2018-11-16 13:11:58 +05:30
break ;
2018-08-01 14:31:09 +05:30
case QUATERNARY_TDM_RX_0 :
case QUATERNARY_TDM_TX_0 :
if ( + + ( data - > quat_tdm_clk_count ) = = 1 ) {
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT ,
2018-11-16 13:11:57 +05:30
TDM_BCLK_RATE , SNDRV_PCM_STREAM_PLAYBACK ) ;
2018-08-01 14:31:09 +05:30
}
2018-11-28 17:00:35 +08:00
codec_dai_fmt | = SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B ;
2020-03-09 13:07:57 +09:00
for_each_rtd_codec_dais ( rtd , j , codec_dai ) {
2018-11-28 17:00:35 +08:00
if ( ! strcmp ( codec_dai - > component - > name_prefix ,
" Left " ) ) {
ret = snd_soc_dai_set_fmt (
codec_dai , codec_dai_fmt ) ;
if ( ret < 0 ) {
dev_err ( rtd - > dev ,
" Left TDM fmt err:%d \n " , ret ) ;
return ret ;
}
}
if ( ! strcmp ( codec_dai - > component - > name_prefix ,
" Right " ) ) {
ret = snd_soc_dai_set_fmt (
codec_dai , codec_dai_fmt ) ;
if ( ret < 0 ) {
dev_err ( rtd - > dev ,
" Right TDM slot err:%d \n " , ret ) ;
return ret ;
}
}
}
2018-08-01 14:31:09 +05:30
break ;
2019-12-19 10:31:53 +00:00
case SLIMBUS_0_RX . . . SLIMBUS_6_TX :
break ;
2018-08-01 14:31:09 +05:30
default :
pr_err ( " %s: invalid dai id 0x%x \n " , __func__ , cpu_dai - > id ) ;
break ;
}
return 0 ;
}
static void sdm845_snd_shutdown ( struct snd_pcm_substream * substream )
{
2020-07-20 10:19:00 +09:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2018-08-01 14:31:09 +05:30
struct snd_soc_card * card = rtd - > card ;
struct sdm845_snd_data * data = snd_soc_card_get_drvdata ( card ) ;
2020-03-23 14:20:01 +09:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
2018-08-01 14:31:09 +05:30
switch ( cpu_dai - > id ) {
case PRIMARY_MI2S_RX :
case PRIMARY_MI2S_TX :
if ( - - ( data - > pri_mi2s_clk_count ) = = 0 ) {
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_MCLK_1 ,
0 , SNDRV_PCM_STREAM_PLAYBACK ) ;
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ,
0 , SNDRV_PCM_STREAM_PLAYBACK ) ;
2019-09-14 08:41:33 +05:30
}
2018-08-01 14:31:09 +05:30
break ;
2018-11-16 13:11:58 +05:30
case SECONDARY_MI2S_TX :
if ( - - ( data - > sec_mi2s_clk_count ) = = 0 ) {
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT ,
0 , SNDRV_PCM_STREAM_CAPTURE ) ;
}
break ;
2018-08-01 14:31:09 +05:30
case QUATERNARY_TDM_RX_0 :
case QUATERNARY_TDM_TX_0 :
if ( - - ( data - > quat_tdm_clk_count ) = = 0 ) {
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT ,
0 , SNDRV_PCM_STREAM_PLAYBACK ) ;
}
break ;
2019-12-19 10:31:53 +00:00
case SLIMBUS_0_RX . . . SLIMBUS_6_TX :
case QUATERNARY_MI2S_RX :
break ;
2018-08-01 14:31:09 +05:30
default :
pr_err ( " %s: invalid dai id 0x%x \n " , __func__ , cpu_dai - > id ) ;
break ;
}
}
2020-03-17 15:12:32 +00:00
static int sdm845_snd_prepare ( struct snd_pcm_substream * substream )
{
2020-07-20 10:19:00 +09:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-17 15:12:32 +00:00
struct sdm845_snd_data * data = snd_soc_card_get_drvdata ( rtd - > card ) ;
2020-03-23 14:20:01 +09:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
2020-03-17 15:12:32 +00:00
struct sdw_stream_runtime * sruntime = data - > sruntime [ cpu_dai - > id ] ;
int ret ;
if ( ! sruntime )
return 0 ;
if ( data - > stream_prepared [ cpu_dai - > id ] ) {
sdw_disable_stream ( sruntime ) ;
sdw_deprepare_stream ( sruntime ) ;
data - > stream_prepared [ cpu_dai - > id ] = false ;
}
ret = sdw_prepare_stream ( sruntime ) ;
if ( ret )
return ret ;
/**
* NOTE : there is a strict hw requirement about the ordering of port
* enables and actual WSA881x PA enable . PA enable should only happen
* after soundwire ports are enabled if not DC on the line is
* accumulated resulting in Click / Pop Noise
* PA enable / mute are handled as part of codec DAPM and digital mute .
*/
ret = sdw_enable_stream ( sruntime ) ;
if ( ret ) {
sdw_deprepare_stream ( sruntime ) ;
return ret ;
}
data - > stream_prepared [ cpu_dai - > id ] = true ;
return ret ;
}
static int sdm845_snd_hw_free ( struct snd_pcm_substream * substream )
{
2020-07-20 10:19:00 +09:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-17 15:12:32 +00:00
struct sdm845_snd_data * data = snd_soc_card_get_drvdata ( rtd - > card ) ;
2020-03-23 14:20:01 +09:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
2020-03-17 15:12:32 +00:00
struct sdw_stream_runtime * sruntime = data - > sruntime [ cpu_dai - > id ] ;
if ( sruntime & & data - > stream_prepared [ cpu_dai - > id ] ) {
sdw_disable_stream ( sruntime ) ;
sdw_deprepare_stream ( sruntime ) ;
data - > stream_prepared [ cpu_dai - > id ] = false ;
}
return 0 ;
}
2018-11-02 16:00:18 +01:00
static const struct snd_soc_ops sdm845_be_ops = {
2018-08-01 14:31:09 +05:30
. hw_params = sdm845_snd_hw_params ,
2020-03-17 15:12:32 +00:00
. hw_free = sdm845_snd_hw_free ,
. prepare = sdm845_snd_prepare ,
2018-08-01 14:31:09 +05:30
. startup = sdm845_snd_startup ,
. shutdown = sdm845_snd_shutdown ,
} ;
static int sdm845_be_hw_params_fixup ( struct snd_soc_pcm_runtime * rtd ,
struct snd_pcm_hw_params * params )
{
struct snd_interval * rate = hw_param_interval ( params ,
SNDRV_PCM_HW_PARAM_RATE ) ;
struct snd_interval * channels = hw_param_interval ( params ,
SNDRV_PCM_HW_PARAM_CHANNELS ) ;
struct snd_mask * fmt = hw_param_mask ( params , SNDRV_PCM_HW_PARAM_FORMAT ) ;
rate - > min = rate - > max = DEFAULT_SAMPLE_RATE_48K ;
channels - > min = channels - > max = 2 ;
snd_mask_set_format ( fmt , SNDRV_PCM_FORMAT_S16_LE ) ;
return 0 ;
}
2018-11-24 19:09:45 +08:00
static const struct snd_soc_dapm_widget sdm845_snd_widgets [ ] = {
SND_SOC_DAPM_HP ( " Headphone Jack " , NULL ) ,
SND_SOC_DAPM_MIC ( " Headset Mic " , NULL ) ,
SND_SOC_DAPM_SPK ( " Left Spk " , NULL ) ,
SND_SOC_DAPM_SPK ( " Right Spk " , NULL ) ,
SND_SOC_DAPM_MIC ( " Int Mic " , NULL ) ,
} ;
2018-11-24 19:09:46 +08:00
static void sdm845_add_ops ( struct snd_soc_card * card )
2018-08-01 14:31:09 +05:30
{
2018-09-18 01:28:49 +00:00
struct snd_soc_dai_link * link ;
int i ;
2018-08-01 14:31:09 +05:30
2018-09-18 01:28:49 +00:00
for_each_card_prelinks ( card , i , link ) {
2018-08-01 14:31:09 +05:30
if ( link - > no_pcm = = 1 ) {
link - > ops = & sdm845_be_ops ;
link - > be_hw_params_fixup = sdm845_be_hw_params_fixup ;
}
2018-11-24 19:09:46 +08:00
link - > init = sdm845_dai_init ;
2018-08-01 14:31:09 +05:30
}
}
static int sdm845_snd_platform_probe ( struct platform_device * pdev )
{
struct snd_soc_card * card ;
struct sdm845_snd_data * data ;
struct device * dev = & pdev - > dev ;
int ret ;
2020-07-23 20:38:58 +02:00
card = devm_kzalloc ( dev , sizeof ( * card ) , GFP_KERNEL ) ;
2018-08-01 14:31:09 +05:30
if ( ! card )
return - ENOMEM ;
/* Allocate the private data */
2020-07-23 20:38:58 +02:00
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2018-08-01 14:31:09 +05:30
2020-10-23 10:58:49 +01:00
card - > driver_name = DRIVER_NAME ;
2018-11-24 19:09:45 +08:00
card - > dapm_widgets = sdm845_snd_widgets ;
card - > num_dapm_widgets = ARRAY_SIZE ( sdm845_snd_widgets ) ;
2018-08-01 14:31:09 +05:30
card - > dev = dev ;
2020-08-20 17:45:11 +02:00
card - > owner = THIS_MODULE ;
2018-08-01 14:31:09 +05:30
dev_set_drvdata ( dev , card ) ;
ret = qcom_snd_parse_of ( card ) ;
2020-04-05 17:32:29 -07:00
if ( ret )
2020-07-23 20:38:58 +02:00
return ret ;
2018-08-01 14:31:09 +05:30
data - > card = card ;
snd_soc_card_set_drvdata ( card , data ) ;
2018-11-24 19:09:46 +08:00
sdm845_add_ops ( card ) ;
2020-07-23 20:38:58 +02:00
return devm_snd_soc_register_card ( dev , card ) ;
2018-08-01 14:31:09 +05:30
}
static const struct of_device_id sdm845_snd_device_id [ ] = {
{ . compatible = " qcom,sdm845-sndcard " } ,
2023-01-18 11:15:42 +01:00
/* Do not grow the list for compatible devices */
2019-12-19 10:31:53 +00:00
{ . compatible = " qcom,db845c-sndcard " } ,
{ . compatible = " lenovo,yoga-c630-sndcard " } ,
2018-08-01 14:31:09 +05:30
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , sdm845_snd_device_id ) ;
static struct platform_driver sdm845_snd_driver = {
. probe = sdm845_snd_platform_probe ,
. driver = {
. name = " msm-snd-sdm845 " ,
. of_match_table = sdm845_snd_device_id ,
} ,
} ;
module_platform_driver ( sdm845_snd_driver ) ;
MODULE_DESCRIPTION ( " sdm845 ASoC Machine Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;