1 /* 2 * bytcr_rt5651.c - ASoc Machine driver for Intel Byt CR platform 3 * (derived from bytcr_rt5640.c) 4 * 5 * Copyright (C) 2015 Intel Corp 6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2 of the License. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 */ 19 20 #include <linux/init.h> 21 #include <linux/module.h> 22 #include <linux/platform_device.h> 23 #include <linux/acpi.h> 24 #include <linux/device.h> 25 #include <linux/dmi.h> 26 #include <linux/slab.h> 27 #include <sound/pcm.h> 28 #include <sound/pcm_params.h> 29 #include <sound/soc.h> 30 #include <sound/jack.h> 31 #include "../../codecs/rt5651.h" 32 #include "../atom/sst-atom-controls.h" 33 34 static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = { 35 SND_SOC_DAPM_HP("Headphone", NULL), 36 SND_SOC_DAPM_MIC("Headset Mic", NULL), 37 SND_SOC_DAPM_MIC("Internal Mic", NULL), 38 SND_SOC_DAPM_SPK("Speaker", NULL), 39 }; 40 41 static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { 42 {"AIF1 Playback", NULL, "ssp2 Tx"}, 43 {"ssp2 Tx", NULL, "codec_out0"}, 44 {"ssp2 Tx", NULL, "codec_out1"}, 45 {"codec_in0", NULL, "ssp2 Rx"}, 46 {"codec_in1", NULL, "ssp2 Rx"}, 47 {"ssp2 Rx", NULL, "AIF1 Capture"}, 48 49 {"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */ 50 {"IN2P", NULL, "Headset Mic"}, 51 {"Headphone", NULL, "HPOL"}, 52 {"Headphone", NULL, "HPOR"}, 53 {"Speaker", NULL, "LOUTL"}, 54 {"Speaker", NULL, "LOUTR"}, 55 }; 56 57 static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic1_map[] = { 58 {"DMIC1", NULL, "Internal Mic"}, 59 }; 60 61 static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic2_map[] = { 62 {"DMIC2", NULL, "Internal Mic"}, 63 }; 64 65 static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = { 66 {"Internal Mic", NULL, "micbias1"}, 67 {"IN1P", NULL, "Internal Mic"}, 68 }; 69 70 enum { 71 BYT_RT5651_DMIC1_MAP, 72 BYT_RT5651_DMIC2_MAP, 73 BYT_RT5651_IN1_MAP, 74 }; 75 76 #define BYT_RT5651_MAP(quirk) ((quirk) & 0xff) 77 #define BYT_RT5651_DMIC_EN BIT(16) 78 79 static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC1_MAP | 80 BYT_RT5651_DMIC_EN; 81 82 static const struct snd_kcontrol_new byt_rt5651_controls[] = { 83 SOC_DAPM_PIN_SWITCH("Headphone"), 84 SOC_DAPM_PIN_SWITCH("Headset Mic"), 85 SOC_DAPM_PIN_SWITCH("Internal Mic"), 86 SOC_DAPM_PIN_SWITCH("Speaker"), 87 }; 88 89 static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, 90 struct snd_pcm_hw_params *params) 91 { 92 struct snd_soc_pcm_runtime *rtd = substream->private_data; 93 struct snd_soc_dai *codec_dai = rtd->codec_dai; 94 int ret; 95 96 snd_soc_dai_set_bclk_ratio(codec_dai, 50); 97 98 ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_PLL1, 99 params_rate(params) * 512, 100 SND_SOC_CLOCK_IN); 101 if (ret < 0) { 102 dev_err(rtd->dev, "can't set codec clock %d\n", ret); 103 return ret; 104 } 105 106 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5651_PLL1_S_BCLK1, 107 params_rate(params) * 50, 108 params_rate(params) * 512); 109 if (ret < 0) { 110 dev_err(rtd->dev, "can't set codec pll: %d\n", ret); 111 return ret; 112 } 113 114 return 0; 115 } 116 117 static const struct dmi_system_id byt_rt5651_quirk_table[] = { 118 {} 119 }; 120 121 static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) 122 { 123 int ret; 124 struct snd_soc_card *card = runtime->card; 125 const struct snd_soc_dapm_route *custom_map; 126 int num_routes; 127 128 card->dapm.idle_bias_off = true; 129 130 dmi_check_system(byt_rt5651_quirk_table); 131 switch (BYT_RT5651_MAP(byt_rt5651_quirk)) { 132 case BYT_RT5651_IN1_MAP: 133 custom_map = byt_rt5651_intmic_in1_map; 134 num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_map); 135 break; 136 case BYT_RT5651_DMIC2_MAP: 137 custom_map = byt_rt5651_intmic_dmic2_map; 138 num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic2_map); 139 break; 140 default: 141 custom_map = byt_rt5651_intmic_dmic1_map; 142 num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic1_map); 143 } 144 145 ret = snd_soc_add_card_controls(card, byt_rt5651_controls, 146 ARRAY_SIZE(byt_rt5651_controls)); 147 if (ret) { 148 dev_err(card->dev, "unable to add card controls\n"); 149 return ret; 150 } 151 snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); 152 snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); 153 154 return ret; 155 } 156 157 static const struct snd_soc_pcm_stream byt_rt5651_dai_params = { 158 .formats = SNDRV_PCM_FMTBIT_S24_LE, 159 .rate_min = 48000, 160 .rate_max = 48000, 161 .channels_min = 2, 162 .channels_max = 2, 163 }; 164 165 static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, 166 struct snd_pcm_hw_params *params) 167 { 168 struct snd_interval *rate = hw_param_interval(params, 169 SNDRV_PCM_HW_PARAM_RATE); 170 struct snd_interval *channels = hw_param_interval(params, 171 SNDRV_PCM_HW_PARAM_CHANNELS); 172 int ret; 173 174 /* The DSP will covert the FE rate to 48k, stereo, 24bits */ 175 rate->min = rate->max = 48000; 176 channels->min = channels->max = 2; 177 178 /* set SSP2 to 24-bit */ 179 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); 180 181 /* 182 * Default mode for SSP configuration is TDM 4 slot, override config 183 * with explicit setting to I2S 2ch 24-bit. The word length is set with 184 * dai_set_tdm_slot() since there is no other API exposed 185 */ 186 ret = snd_soc_dai_set_fmt(rtd->cpu_dai, 187 SND_SOC_DAIFMT_I2S | 188 SND_SOC_DAIFMT_NB_NF | 189 SND_SOC_DAIFMT_CBS_CFS 190 ); 191 192 if (ret < 0) { 193 dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); 194 return ret; 195 } 196 197 ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); 198 if (ret < 0) { 199 dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); 200 return ret; 201 } 202 203 return 0; 204 } 205 206 static unsigned int rates_48000[] = { 207 48000, 208 }; 209 210 static struct snd_pcm_hw_constraint_list constraints_48000 = { 211 .count = ARRAY_SIZE(rates_48000), 212 .list = rates_48000, 213 }; 214 215 static int byt_rt5651_aif1_startup(struct snd_pcm_substream *substream) 216 { 217 return snd_pcm_hw_constraint_list(substream->runtime, 0, 218 SNDRV_PCM_HW_PARAM_RATE, 219 &constraints_48000); 220 } 221 222 static const struct snd_soc_ops byt_rt5651_aif1_ops = { 223 .startup = byt_rt5651_aif1_startup, 224 }; 225 226 static const struct snd_soc_ops byt_rt5651_be_ssp2_ops = { 227 .hw_params = byt_rt5651_aif1_hw_params, 228 }; 229 230 static struct snd_soc_dai_link byt_rt5651_dais[] = { 231 [MERR_DPCM_AUDIO] = { 232 .name = "Audio Port", 233 .stream_name = "Audio", 234 .cpu_dai_name = "media-cpu-dai", 235 .codec_dai_name = "snd-soc-dummy-dai", 236 .codec_name = "snd-soc-dummy", 237 .platform_name = "sst-mfld-platform", 238 .nonatomic = true, 239 .dynamic = 1, 240 .dpcm_playback = 1, 241 .dpcm_capture = 1, 242 .ops = &byt_rt5651_aif1_ops, 243 }, 244 [MERR_DPCM_DEEP_BUFFER] = { 245 .name = "Deep-Buffer Audio Port", 246 .stream_name = "Deep-Buffer Audio", 247 .cpu_dai_name = "deepbuffer-cpu-dai", 248 .codec_dai_name = "snd-soc-dummy-dai", 249 .codec_name = "snd-soc-dummy", 250 .platform_name = "sst-mfld-platform", 251 .nonatomic = true, 252 .dynamic = 1, 253 .dpcm_playback = 1, 254 .ops = &byt_rt5651_aif1_ops, 255 }, 256 [MERR_DPCM_COMPR] = { 257 .name = "Compressed Port", 258 .stream_name = "Compress", 259 .cpu_dai_name = "compress-cpu-dai", 260 .codec_dai_name = "snd-soc-dummy-dai", 261 .codec_name = "snd-soc-dummy", 262 .platform_name = "sst-mfld-platform", 263 }, 264 /* CODEC<->CODEC link */ 265 /* back ends */ 266 { 267 .name = "SSP2-Codec", 268 .id = 1, 269 .cpu_dai_name = "ssp2-port", 270 .platform_name = "sst-mfld-platform", 271 .no_pcm = 1, 272 .codec_dai_name = "rt5651-aif1", 273 .codec_name = "i2c-10EC5651:00", 274 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 275 | SND_SOC_DAIFMT_CBS_CFS, 276 .be_hw_params_fixup = byt_rt5651_codec_fixup, 277 .ignore_suspend = 1, 278 .nonatomic = true, 279 .dpcm_playback = 1, 280 .dpcm_capture = 1, 281 .init = byt_rt5651_init, 282 .ops = &byt_rt5651_be_ssp2_ops, 283 }, 284 }; 285 286 /* SoC card */ 287 static struct snd_soc_card byt_rt5651_card = { 288 .name = "bytcr-rt5651", 289 .owner = THIS_MODULE, 290 .dai_link = byt_rt5651_dais, 291 .num_links = ARRAY_SIZE(byt_rt5651_dais), 292 .dapm_widgets = byt_rt5651_widgets, 293 .num_dapm_widgets = ARRAY_SIZE(byt_rt5651_widgets), 294 .dapm_routes = byt_rt5651_audio_map, 295 .num_dapm_routes = ARRAY_SIZE(byt_rt5651_audio_map), 296 .fully_routed = true, 297 }; 298 299 static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) 300 { 301 int ret_val = 0; 302 303 /* register the soc card */ 304 byt_rt5651_card.dev = &pdev->dev; 305 306 ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); 307 308 if (ret_val) { 309 dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", 310 ret_val); 311 return ret_val; 312 } 313 platform_set_drvdata(pdev, &byt_rt5651_card); 314 return ret_val; 315 } 316 317 static struct platform_driver snd_byt_rt5651_mc_driver = { 318 .driver = { 319 .name = "bytcr_rt5651", 320 }, 321 .probe = snd_byt_rt5651_mc_probe, 322 }; 323 324 module_platform_driver(snd_byt_rt5651_mc_driver); 325 326 MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver for RT5651"); 327 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); 328 MODULE_LICENSE("GPL v2"); 329 MODULE_ALIAS("platform:bytcr_rt5651"); 330