0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/module.h>
0015 #include <sound/pcm.h>
0016 #include <sound/pcm_params.h>
0017 #include <sound/soc.h>
0018 #include "../atom/sst-atom-controls.h"
0019
0020 static const struct snd_soc_dapm_widget widgets[] = {
0021 SND_SOC_DAPM_MIC("Mic", NULL),
0022 SND_SOC_DAPM_SPK("Speaker", NULL),
0023 };
0024
0025 static const struct snd_kcontrol_new controls[] = {
0026 SOC_DAPM_PIN_SWITCH("Mic"),
0027 SOC_DAPM_PIN_SWITCH("Speaker"),
0028 };
0029
0030 static const struct snd_soc_dapm_route audio_map[] = {
0031 {"ssp2 Tx", NULL, "codec_out0"},
0032 {"ssp2 Tx", NULL, "codec_out1"},
0033 {"codec_in0", NULL, "ssp2 Rx"},
0034 {"codec_in1", NULL, "ssp2 Rx"},
0035
0036 {"ssp2 Rx", NULL, "Mic"},
0037 {"Speaker", NULL, "ssp2 Tx"},
0038 };
0039
0040 static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
0041 struct snd_pcm_hw_params *params)
0042 {
0043 struct snd_interval *rate = hw_param_interval(params,
0044 SNDRV_PCM_HW_PARAM_RATE);
0045 struct snd_interval *channels = hw_param_interval(params,
0046 SNDRV_PCM_HW_PARAM_CHANNELS);
0047 int ret;
0048
0049
0050 rate->min = rate->max = 48000;
0051 channels->min = channels->max = 2;
0052
0053
0054 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
0055
0056
0057
0058
0059
0060
0061 ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
0062 SND_SOC_DAIFMT_I2S |
0063 SND_SOC_DAIFMT_NB_NF |
0064 SND_SOC_DAIFMT_BP_FP);
0065
0066 if (ret < 0) {
0067 dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
0068 return ret;
0069 }
0070
0071 ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
0072 if (ret < 0) {
0073 dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
0074 return ret;
0075 }
0076
0077 return 0;
0078 }
0079
0080 static const unsigned int rates_48000[] = {
0081 48000,
0082 };
0083
0084 static const struct snd_pcm_hw_constraint_list constraints_48000 = {
0085 .count = ARRAY_SIZE(rates_48000),
0086 .list = rates_48000,
0087 };
0088
0089 static int aif1_startup(struct snd_pcm_substream *substream)
0090 {
0091 return snd_pcm_hw_constraint_list(substream->runtime, 0,
0092 SNDRV_PCM_HW_PARAM_RATE,
0093 &constraints_48000);
0094 }
0095
0096 static const struct snd_soc_ops aif1_ops = {
0097 .startup = aif1_startup,
0098 };
0099
0100 SND_SOC_DAILINK_DEF(dummy,
0101 DAILINK_COMP_ARRAY(COMP_DUMMY()));
0102
0103 SND_SOC_DAILINK_DEF(media,
0104 DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
0105
0106 SND_SOC_DAILINK_DEF(deepbuffer,
0107 DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
0108
0109 SND_SOC_DAILINK_DEF(ssp2_port,
0110 DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
0111
0112 SND_SOC_DAILINK_DEF(platform,
0113 DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
0114
0115 static struct snd_soc_dai_link dais[] = {
0116 [MERR_DPCM_AUDIO] = {
0117 .name = "Audio Port",
0118 .stream_name = "Audio",
0119 .ignore_suspend = 1,
0120 .nonatomic = true,
0121 .dynamic = 1,
0122 .dpcm_playback = 1,
0123 .dpcm_capture = 1,
0124 .ops = &aif1_ops,
0125 SND_SOC_DAILINK_REG(media, dummy, platform),
0126 },
0127 [MERR_DPCM_DEEP_BUFFER] = {
0128 .name = "Deep-Buffer Audio Port",
0129 .stream_name = "Deep-Buffer Audio",
0130 .ignore_suspend = 1,
0131 .nonatomic = true,
0132 .dynamic = 1,
0133 .dpcm_playback = 1,
0134 .ops = &aif1_ops,
0135 SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
0136 },
0137
0138
0139 {
0140 .name = "SSP2-LowSpeed Connector",
0141 .id = 0,
0142 .no_pcm = 1,
0143 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
0144 | SND_SOC_DAIFMT_CBC_CFC,
0145 .be_hw_params_fixup = codec_fixup,
0146 .ignore_suspend = 1,
0147 .dpcm_playback = 1,
0148 .dpcm_capture = 1,
0149 SND_SOC_DAILINK_REG(ssp2_port, dummy, platform),
0150 },
0151 };
0152
0153
0154 static struct snd_soc_card bytcht_nocodec_card = {
0155 .name = "bytcht-nocodec",
0156 .owner = THIS_MODULE,
0157 .dai_link = dais,
0158 .num_links = ARRAY_SIZE(dais),
0159 .dapm_widgets = widgets,
0160 .num_dapm_widgets = ARRAY_SIZE(widgets),
0161 .dapm_routes = audio_map,
0162 .num_dapm_routes = ARRAY_SIZE(audio_map),
0163 .controls = controls,
0164 .num_controls = ARRAY_SIZE(controls),
0165 .fully_routed = true,
0166 };
0167
0168 static int snd_bytcht_nocodec_mc_probe(struct platform_device *pdev)
0169 {
0170 int ret_val = 0;
0171
0172
0173 bytcht_nocodec_card.dev = &pdev->dev;
0174
0175 ret_val = devm_snd_soc_register_card(&pdev->dev, &bytcht_nocodec_card);
0176
0177 if (ret_val) {
0178 dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
0179 ret_val);
0180 return ret_val;
0181 }
0182 platform_set_drvdata(pdev, &bytcht_nocodec_card);
0183 return ret_val;
0184 }
0185
0186 static struct platform_driver snd_bytcht_nocodec_mc_driver = {
0187 .driver = {
0188 .name = "bytcht_nocodec",
0189 },
0190 .probe = snd_bytcht_nocodec_mc_probe,
0191 };
0192 module_platform_driver(snd_bytcht_nocodec_mc_driver);
0193
0194 MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Nocodec Machine driver");
0195 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>");
0196 MODULE_LICENSE("GPL v2");
0197 MODULE_ALIAS("platform:bytcht_nocodec");