Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  bytcht_nocodec.c - ASoc Machine driver for MinnowBoard Max and Up
0004  *  to make I2S signals observable on the Low-Speed connector. Audio codec
0005  *  is not managed by ASoC/DAPM
0006  *
0007  *  Copyright (C) 2015-2017 Intel Corp
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     /* The DSP will convert the FE rate to 48k, stereo, 24bits */
0050     rate->min = rate->max = 48000;
0051     channels->min = channels->max = 2;
0052 
0053     /* set SSP2 to 24-bit */
0054     params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
0055 
0056     /*
0057      * Default mode for SSP configuration is TDM 4 slot, override config
0058      * with explicit setting to I2S 2ch 24-bit. The word length is set with
0059      * dai_set_tdm_slot() since there is no other API exposed
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     /* CODEC<->CODEC link */
0138     /* back ends */
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 /* SoC card */
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     /* register the soc card */
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");