0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/slab.h>
0017 #include <sound/pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <sound/soc.h>
0020 #include <sound/soc-acpi.h>
0021 #include <sound/jack.h>
0022 #include <linux/input.h>
0023 #include "../atom/sst-atom-controls.h"
0024 #include "../../codecs/nau8824.h"
0025
0026 struct cht_mc_private {
0027 struct snd_soc_jack jack;
0028 };
0029
0030 static struct snd_soc_jack_pin cht_bsw_jack_pins[] = {
0031 {
0032 .pin = "Headphone",
0033 .mask = SND_JACK_HEADPHONE,
0034 },
0035 {
0036 .pin = "Headset Mic",
0037 .mask = SND_JACK_MICROPHONE,
0038 },
0039 };
0040
0041 static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
0042 SND_SOC_DAPM_HP("Headphone", NULL),
0043 SND_SOC_DAPM_MIC("Headset Mic", NULL),
0044 SND_SOC_DAPM_MIC("Int Mic", NULL),
0045 SND_SOC_DAPM_SPK("Ext Spk", NULL),
0046 };
0047
0048 static const struct snd_soc_dapm_route cht_audio_map[] = {
0049 {"Ext Spk", NULL, "SPKOUTL"},
0050 {"Ext Spk", NULL, "SPKOUTR"},
0051 {"Headphone", NULL, "HPOL"},
0052 {"Headphone", NULL, "HPOR"},
0053 {"MIC1", NULL, "Int Mic"},
0054 {"MIC2", NULL, "Int Mic"},
0055 {"HSMIC1", NULL, "Headset Mic"},
0056 {"HSMIC2", NULL, "Headset Mic"},
0057 {"Playback", NULL, "ssp2 Tx"},
0058 {"ssp2 Tx", NULL, "codec_out0"},
0059 {"ssp2 Tx", NULL, "codec_out1"},
0060 {"codec_in0", NULL, "ssp2 Rx" },
0061 {"codec_in1", NULL, "ssp2 Rx" },
0062 {"ssp2 Rx", NULL, "Capture"},
0063 };
0064
0065 static const struct snd_kcontrol_new cht_mc_controls[] = {
0066 SOC_DAPM_PIN_SWITCH("Headphone"),
0067 SOC_DAPM_PIN_SWITCH("Headset Mic"),
0068 SOC_DAPM_PIN_SWITCH("Int Mic"),
0069 SOC_DAPM_PIN_SWITCH("Ext Spk"),
0070 };
0071
0072 static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
0073 struct snd_pcm_hw_params *params)
0074 {
0075 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0076 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0077 int ret;
0078
0079 ret = snd_soc_dai_set_sysclk(codec_dai, NAU8824_CLK_FLL_FS, 0,
0080 SND_SOC_CLOCK_IN);
0081 if (ret < 0) {
0082 dev_err(codec_dai->dev, "can't set FS clock %d\n", ret);
0083 return ret;
0084 }
0085 ret = snd_soc_dai_set_pll(codec_dai, 0, 0, params_rate(params),
0086 params_rate(params) * 256);
0087 if (ret < 0) {
0088 dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
0089 return ret;
0090 }
0091
0092 return 0;
0093 }
0094
0095 static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
0096 {
0097 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
0098 struct snd_soc_jack *jack = &ctx->jack;
0099 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
0100 struct snd_soc_component *component = codec_dai->component;
0101 int ret, jack_type;
0102
0103
0104
0105
0106
0107
0108
0109 jack_type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
0110 SND_JACK_BTN_2 | SND_JACK_BTN_3;
0111 ret = snd_soc_card_jack_new_pins(runtime->card, "Headset", jack_type,
0112 jack, cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins));
0113 if (ret) {
0114 dev_err(runtime->dev,
0115 "Headset Jack creation failed %d\n", ret);
0116 return ret;
0117 }
0118 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
0119 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
0120 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
0121 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
0122
0123 nau8824_enable_jack_detect(component, jack);
0124
0125 return ret;
0126 }
0127
0128 static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
0129 struct snd_pcm_hw_params *params)
0130 {
0131 struct snd_interval *rate = hw_param_interval(params,
0132 SNDRV_PCM_HW_PARAM_RATE);
0133 struct snd_interval *channels = hw_param_interval(params,
0134 SNDRV_PCM_HW_PARAM_CHANNELS);
0135 struct snd_mask *fmt =
0136 hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
0137 int ret;
0138
0139
0140 rate->min = rate->max = 48000;
0141 channels->min = channels->max = 2;
0142
0143
0144 snd_mask_none(fmt);
0145 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
0146
0147
0148 ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 0xf, 0x1, 4, 24);
0149 if (ret < 0) {
0150 dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
0151 return ret;
0152 }
0153
0154 return 0;
0155 }
0156
0157 static int cht_aif1_startup(struct snd_pcm_substream *substream)
0158 {
0159 return snd_pcm_hw_constraint_single(substream->runtime,
0160 SNDRV_PCM_HW_PARAM_RATE, 48000);
0161 }
0162
0163 static const struct snd_soc_ops cht_aif1_ops = {
0164 .startup = cht_aif1_startup,
0165 };
0166
0167 static const struct snd_soc_ops cht_be_ssp2_ops = {
0168 .hw_params = cht_aif1_hw_params,
0169 };
0170
0171 SND_SOC_DAILINK_DEF(dummy,
0172 DAILINK_COMP_ARRAY(COMP_DUMMY()));
0173
0174 SND_SOC_DAILINK_DEF(media,
0175 DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
0176
0177 SND_SOC_DAILINK_DEF(deepbuffer,
0178 DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
0179
0180 SND_SOC_DAILINK_DEF(ssp2_port,
0181 DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
0182 SND_SOC_DAILINK_DEF(ssp2_codec,
0183 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508824:00",
0184 NAU8824_CODEC_DAI)));
0185
0186 SND_SOC_DAILINK_DEF(platform,
0187 DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
0188
0189 static struct snd_soc_dai_link cht_dailink[] = {
0190
0191 [MERR_DPCM_AUDIO] = {
0192 .name = "Audio Port",
0193 .stream_name = "Audio",
0194 .nonatomic = true,
0195 .dynamic = 1,
0196 .dpcm_playback = 1,
0197 .dpcm_capture = 1,
0198 .ops = &cht_aif1_ops,
0199 SND_SOC_DAILINK_REG(media, dummy, platform),
0200 },
0201 [MERR_DPCM_DEEP_BUFFER] = {
0202 .name = "Deep-Buffer Audio Port",
0203 .stream_name = "Deep-Buffer Audio",
0204 .nonatomic = true,
0205 .dynamic = 1,
0206 .dpcm_playback = 1,
0207 .ops = &cht_aif1_ops,
0208 SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
0209 },
0210
0211 {
0212
0213 .name = "SSP2-Codec",
0214 .id = 0,
0215 .no_pcm = 1,
0216 .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
0217 | SND_SOC_DAIFMT_CBC_CFC,
0218 .init = cht_codec_init,
0219 .be_hw_params_fixup = cht_codec_fixup,
0220 .dpcm_playback = 1,
0221 .dpcm_capture = 1,
0222 .ops = &cht_be_ssp2_ops,
0223 SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
0224 },
0225 };
0226
0227
0228 #define SOF_CARD_NAME "bytcht nau8824"
0229 #define SOF_DRIVER_NAME "SOF"
0230
0231 #define CARD_NAME "chtnau8824"
0232 #define DRIVER_NAME NULL
0233
0234
0235 static struct snd_soc_card snd_soc_card_cht = {
0236 .owner = THIS_MODULE,
0237 .dai_link = cht_dailink,
0238 .num_links = ARRAY_SIZE(cht_dailink),
0239 .dapm_widgets = cht_dapm_widgets,
0240 .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
0241 .dapm_routes = cht_audio_map,
0242 .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
0243 .controls = cht_mc_controls,
0244 .num_controls = ARRAY_SIZE(cht_mc_controls),
0245 };
0246
0247 static int snd_cht_mc_probe(struct platform_device *pdev)
0248 {
0249 struct cht_mc_private *drv;
0250 struct snd_soc_acpi_mach *mach;
0251 const char *platform_name;
0252 bool sof_parent;
0253 int ret_val;
0254
0255 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
0256 if (!drv)
0257 return -ENOMEM;
0258 snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
0259
0260
0261 snd_soc_card_cht.dev = &pdev->dev;
0262 mach = pdev->dev.platform_data;
0263 platform_name = mach->mach_params.platform;
0264
0265 ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht,
0266 platform_name);
0267 if (ret_val)
0268 return ret_val;
0269
0270 sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
0271
0272
0273 if (sof_parent) {
0274 snd_soc_card_cht.name = SOF_CARD_NAME;
0275 snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
0276 } else {
0277 snd_soc_card_cht.name = CARD_NAME;
0278 snd_soc_card_cht.driver_name = DRIVER_NAME;
0279 }
0280
0281 snd_soc_card_cht.components = nau8824_components();
0282
0283
0284 if (sof_parent)
0285 pdev->dev.driver->pm = &snd_soc_pm_ops;
0286
0287
0288 ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
0289 if (ret_val) {
0290 dev_err(&pdev->dev,
0291 "snd_soc_register_card failed %d\n", ret_val);
0292 return ret_val;
0293 }
0294 platform_set_drvdata(pdev, &snd_soc_card_cht);
0295
0296 return ret_val;
0297 }
0298
0299 static struct platform_driver snd_cht_mc_driver = {
0300 .driver = {
0301 .name = "cht-bsw-nau8824",
0302 },
0303 .probe = snd_cht_mc_probe,
0304 };
0305
0306 module_platform_driver(snd_cht_mc_driver);
0307
0308 MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
0309 MODULE_AUTHOR("Wang, Joseph C <joequant@gmail.com>");
0310 MODULE_AUTHOR("John Hsu <KCHSU0@nuvoton.com>");
0311 MODULE_LICENSE("GPL v2");
0312 MODULE_ALIAS("platform:cht-bsw-nau8824");