2018-05-18 15:56:10 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018, Linaro Limited
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/of_device.h>
# include <sound/soc.h>
# include <sound/soc-dapm.h>
# include <sound/pcm.h>
2018-08-01 12:01:08 +03:00
# include "common.h"
2018-05-18 15:56:10 +03:00
2019-01-28 17:27:53 +03:00
# define SLIM_MAX_TX_PORTS 16
# define SLIM_MAX_RX_PORTS 16
# define WCD9335_DEFAULT_MCLK_RATE 9600000
2018-05-18 15:56:10 +03:00
static int apq8096_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 ) ;
rate - > min = rate - > max = 48000 ;
channels - > min = channels - > max = 2 ;
return 0 ;
}
2019-01-28 17:27:53 +03:00
static int msm_snd_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
2020-07-20 04:19:00 +03:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-23 08:20:01 +03: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 ) ;
2019-01-28 17:27:53 +03:00
u32 rx_ch [ SLIM_MAX_RX_PORTS ] , tx_ch [ SLIM_MAX_TX_PORTS ] ;
u32 rx_ch_cnt = 0 , tx_ch_cnt = 0 ;
int ret = 0 ;
ret = snd_soc_dai_get_channel_map ( codec_dai ,
& 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 ) ;
goto end ;
} else if ( ret = = - ENOTSUPP ) {
return 0 ;
}
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 ) ;
if ( ret ! = 0 & & ret ! = - ENOTSUPP )
pr_err ( " Failed to set cpu chan map, err:%d \n " , ret ) ;
else if ( ret = = - ENOTSUPP )
ret = 0 ;
end :
return ret ;
}
2021-10-01 14:50:30 +03:00
static const struct snd_soc_ops apq8096_ops = {
2019-01-28 17:27:53 +03:00
. hw_params = msm_snd_hw_params ,
} ;
static int apq8096_init ( struct snd_soc_pcm_runtime * rtd )
{
2020-03-23 08:20:01 +03:00
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
2019-01-28 17:27:53 +03: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 } ;
snd_soc_dai_set_channel_map ( codec_dai , ARRAY_SIZE ( tx_ch ) ,
tx_ch , ARRAY_SIZE ( rx_ch ) , rx_ch ) ;
snd_soc_dai_set_sysclk ( codec_dai , 0 , WCD9335_DEFAULT_MCLK_RATE ,
SNDRV_PCM_STREAM_PLAYBACK ) ;
return 0 ;
}
2018-08-01 12:01:08 +03:00
static void apq8096_add_be_ops ( struct snd_soc_card * card )
2018-05-18 15:56:10 +03:00
{
2018-09-18 04:28:49 +03:00
struct snd_soc_dai_link * link ;
int i ;
2018-05-18 15:56:10 +03:00
2018-09-18 04:28:49 +03:00
for_each_card_prelinks ( card , i , link ) {
2019-01-28 17:27:53 +03:00
if ( link - > no_pcm = = 1 ) {
2018-05-18 15:56:10 +03:00
link - > be_hw_params_fixup = apq8096_be_hw_params_fixup ;
2019-01-28 17:27:53 +03:00
link - > init = apq8096_init ;
link - > ops = & apq8096_ops ;
}
2018-05-18 15:56:10 +03:00
}
}
2018-07-13 18:36:32 +03:00
static int apq8096_platform_probe ( struct platform_device * pdev )
2018-05-18 15:56:10 +03:00
{
struct snd_soc_card * card ;
2018-07-13 18:36:32 +03:00
struct device * dev = & pdev - > dev ;
2018-05-18 15:56:10 +03:00
int ret ;
2020-07-23 21:38:58 +03:00
card = devm_kzalloc ( dev , sizeof ( * card ) , GFP_KERNEL ) ;
2018-05-18 15:56:10 +03:00
if ( ! card )
return - ENOMEM ;
card - > dev = dev ;
2020-08-20 18:45:11 +03:00
card - > owner = THIS_MODULE ;
2018-06-06 11:55:24 +03:00
dev_set_drvdata ( dev , card ) ;
2018-08-01 12:01:08 +03:00
ret = qcom_snd_parse_of ( card ) ;
2020-04-06 03:32:29 +03:00
if ( ret )
2020-07-23 21:38:58 +03:00
return ret ;
2018-05-18 15:56:10 +03:00
2018-08-01 12:01:08 +03:00
apq8096_add_be_ops ( card ) ;
2020-07-23 21:38:58 +03:00
return devm_snd_soc_register_card ( dev , card ) ;
2018-05-18 15:56:10 +03:00
}
static const struct of_device_id msm_snd_apq8096_dt_match [ ] = {
{ . compatible = " qcom,apq8096-sndcard " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , msm_snd_apq8096_dt_match ) ;
static struct platform_driver msm_snd_apq8096_driver = {
. probe = apq8096_platform_probe ,
. driver = {
. name = " msm-snd-apq8096 " ,
. of_match_table = msm_snd_apq8096_dt_match ,
} ,
} ;
module_platform_driver ( msm_snd_apq8096_driver ) ;
MODULE_AUTHOR ( " Srinivas Kandagatla <srinivas.kandagatla@linaro.org " ) ;
MODULE_DESCRIPTION ( " APQ8096 ASoC Machine Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;