0001
0002
0003
0004
0005
0006
0007 #include <linux/acpi.h>
0008 #include <linux/device.h>
0009 #include <linux/gpio/consumer.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/slab.h>
0013 #include <sound/pcm.h>
0014 #include <sound/pcm_params.h>
0015 #include <sound/jack.h>
0016 #include <sound/soc.h>
0017 #include <sound/soc-acpi.h>
0018 #include "../../codecs/cx2072x.h"
0019 #include "../atom/sst-atom-controls.h"
0020
0021 static const struct snd_soc_dapm_widget byt_cht_cx2072x_widgets[] = {
0022 SND_SOC_DAPM_HP("Headphone", NULL),
0023 SND_SOC_DAPM_MIC("Headset Mic", NULL),
0024 SND_SOC_DAPM_MIC("Int Mic", NULL),
0025 SND_SOC_DAPM_SPK("Ext Spk", NULL),
0026 };
0027
0028 static const struct snd_soc_dapm_route byt_cht_cx2072x_audio_map[] = {
0029
0030 {"Headphone", NULL, "PORTA"},
0031 {"Ext Spk", NULL, "PORTG"},
0032 {"PORTC", NULL, "Int Mic"},
0033 {"PORTD", NULL, "Headset Mic"},
0034
0035 {"Playback", NULL, "ssp2 Tx"},
0036 {"ssp2 Tx", NULL, "codec_out0"},
0037 {"ssp2 Tx", NULL, "codec_out1"},
0038 {"codec_in0", NULL, "ssp2 Rx"},
0039 {"codec_in1", NULL, "ssp2 Rx"},
0040 {"ssp2 Rx", NULL, "Capture"},
0041 };
0042
0043 static const struct snd_kcontrol_new byt_cht_cx2072x_controls[] = {
0044 SOC_DAPM_PIN_SWITCH("Headphone"),
0045 SOC_DAPM_PIN_SWITCH("Headset Mic"),
0046 SOC_DAPM_PIN_SWITCH("Int Mic"),
0047 SOC_DAPM_PIN_SWITCH("Ext Spk"),
0048 };
0049
0050 static struct snd_soc_jack byt_cht_cx2072x_headset;
0051
0052
0053 static struct snd_soc_jack_pin byt_cht_cx2072x_headset_pins[] = {
0054 {
0055 .pin = "Headset Mic",
0056 .mask = SND_JACK_MICROPHONE,
0057 },
0058 {
0059 .pin = "Headphone",
0060 .mask = SND_JACK_HEADPHONE,
0061 },
0062 };
0063
0064 static const struct acpi_gpio_params byt_cht_cx2072x_headset_gpios;
0065 static const struct acpi_gpio_mapping byt_cht_cx2072x_acpi_gpios[] = {
0066 { "headset-gpios", &byt_cht_cx2072x_headset_gpios, 1 },
0067 {},
0068 };
0069
0070 static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd)
0071 {
0072 struct snd_soc_card *card = rtd->card;
0073 struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
0074 int ret;
0075
0076 if (devm_acpi_dev_add_driver_gpios(codec->dev,
0077 byt_cht_cx2072x_acpi_gpios))
0078 dev_warn(rtd->dev, "Unable to add GPIO mapping table\n");
0079
0080 card->dapm.idle_bias_off = true;
0081
0082
0083 ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0), CX2072X_MCLK_EXTERNAL_PLL,
0084 19200000, SND_SOC_CLOCK_IN);
0085 if (ret) {
0086 dev_err(rtd->dev, "Could not set sysclk\n");
0087 return ret;
0088 }
0089
0090 ret = snd_soc_card_jack_new_pins(card, "Headset",
0091 SND_JACK_HEADSET | SND_JACK_BTN_0,
0092 &byt_cht_cx2072x_headset,
0093 byt_cht_cx2072x_headset_pins,
0094 ARRAY_SIZE(byt_cht_cx2072x_headset_pins));
0095 if (ret)
0096 return ret;
0097
0098 snd_soc_component_set_jack(codec, &byt_cht_cx2072x_headset, NULL);
0099
0100 snd_soc_dai_set_bclk_ratio(asoc_rtd_to_codec(rtd, 0), 50);
0101
0102 return 0;
0103 }
0104
0105 static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd,
0106 struct snd_pcm_hw_params *params)
0107 {
0108 struct snd_interval *rate =
0109 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
0110 struct snd_interval *channels =
0111 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
0112 int ret;
0113
0114
0115 rate->min = rate->max = 48000;
0116 channels->min = channels->max = 2;
0117
0118
0119 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
0120
0121
0122
0123
0124
0125
0126 ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
0127 SND_SOC_DAIFMT_I2S |
0128 SND_SOC_DAIFMT_NB_NF |
0129 SND_SOC_DAIFMT_BP_FP);
0130 if (ret < 0) {
0131 dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
0132 return ret;
0133 }
0134
0135 ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
0136 if (ret < 0) {
0137 dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
0138 return ret;
0139 }
0140
0141 return 0;
0142 }
0143
0144 static int byt_cht_cx2072x_aif1_startup(struct snd_pcm_substream *substream)
0145 {
0146 return snd_pcm_hw_constraint_single(substream->runtime,
0147 SNDRV_PCM_HW_PARAM_RATE, 48000);
0148 }
0149
0150 static const struct snd_soc_ops byt_cht_cx2072x_aif1_ops = {
0151 .startup = byt_cht_cx2072x_aif1_startup,
0152 };
0153
0154 SND_SOC_DAILINK_DEF(dummy,
0155 DAILINK_COMP_ARRAY(COMP_DUMMY()));
0156
0157 SND_SOC_DAILINK_DEF(media,
0158 DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
0159
0160 SND_SOC_DAILINK_DEF(deepbuffer,
0161 DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
0162
0163 SND_SOC_DAILINK_DEF(ssp2,
0164 DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
0165
0166 SND_SOC_DAILINK_DEF(cx2072x,
0167 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-14F10720:00", "cx2072x-hifi")));
0168
0169 SND_SOC_DAILINK_DEF(platform,
0170 DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
0171
0172 static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = {
0173 [MERR_DPCM_AUDIO] = {
0174 .name = "Audio Port",
0175 .stream_name = "Audio",
0176 .nonatomic = true,
0177 .dynamic = 1,
0178 .dpcm_playback = 1,
0179 .dpcm_capture = 1,
0180 .ops = &byt_cht_cx2072x_aif1_ops,
0181 SND_SOC_DAILINK_REG(media, dummy, platform),
0182 },
0183 [MERR_DPCM_DEEP_BUFFER] = {
0184 .name = "Deep-Buffer Audio Port",
0185 .stream_name = "Deep-Buffer Audio",
0186 .nonatomic = true,
0187 .dynamic = 1,
0188 .dpcm_playback = 1,
0189 .ops = &byt_cht_cx2072x_aif1_ops,
0190 SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
0191 },
0192
0193 {
0194 .name = "SSP2-Codec",
0195 .id = 0,
0196 .no_pcm = 1,
0197 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
0198 | SND_SOC_DAIFMT_CBC_CFC,
0199 .init = byt_cht_cx2072x_init,
0200 .be_hw_params_fixup = byt_cht_cx2072x_fixup,
0201 .dpcm_playback = 1,
0202 .dpcm_capture = 1,
0203 SND_SOC_DAILINK_REG(ssp2, cx2072x, platform),
0204 },
0205 };
0206
0207
0208 #define SOF_CARD_NAME "bytcht cx2072x"
0209 #define SOF_DRIVER_NAME "SOF"
0210
0211 #define CARD_NAME "bytcht-cx2072x"
0212 #define DRIVER_NAME NULL
0213
0214
0215 static struct snd_soc_card byt_cht_cx2072x_card = {
0216 .name = CARD_NAME,
0217 .driver_name = DRIVER_NAME,
0218 .owner = THIS_MODULE,
0219 .dai_link = byt_cht_cx2072x_dais,
0220 .num_links = ARRAY_SIZE(byt_cht_cx2072x_dais),
0221 .dapm_widgets = byt_cht_cx2072x_widgets,
0222 .num_dapm_widgets = ARRAY_SIZE(byt_cht_cx2072x_widgets),
0223 .dapm_routes = byt_cht_cx2072x_audio_map,
0224 .num_dapm_routes = ARRAY_SIZE(byt_cht_cx2072x_audio_map),
0225 .controls = byt_cht_cx2072x_controls,
0226 .num_controls = ARRAY_SIZE(byt_cht_cx2072x_controls),
0227 };
0228
0229 static char codec_name[SND_ACPI_I2C_ID_LEN];
0230
0231 static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
0232 {
0233 struct snd_soc_acpi_mach *mach;
0234 struct acpi_device *adev;
0235 int dai_index = 0;
0236 bool sof_parent;
0237 int i, ret;
0238
0239 byt_cht_cx2072x_card.dev = &pdev->dev;
0240 mach = dev_get_platdata(&pdev->dev);
0241
0242
0243 for (i = 0; i < ARRAY_SIZE(byt_cht_cx2072x_dais); i++) {
0244 if (!strcmp(byt_cht_cx2072x_dais[i].codecs->name,
0245 "i2c-14F10720:00")) {
0246 dai_index = i;
0247 break;
0248 }
0249 }
0250
0251
0252 adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1);
0253 if (adev) {
0254 snprintf(codec_name, sizeof(codec_name), "i2c-%s",
0255 acpi_dev_name(adev));
0256 put_device(&adev->dev);
0257 byt_cht_cx2072x_dais[dai_index].codecs->name = codec_name;
0258 }
0259
0260
0261 ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_cx2072x_card,
0262 mach->mach_params.platform);
0263 if (ret)
0264 return ret;
0265
0266 sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
0267
0268
0269 if (sof_parent) {
0270 byt_cht_cx2072x_card.name = SOF_CARD_NAME;
0271 byt_cht_cx2072x_card.driver_name = SOF_DRIVER_NAME;
0272 } else {
0273 byt_cht_cx2072x_card.name = CARD_NAME;
0274 byt_cht_cx2072x_card.driver_name = DRIVER_NAME;
0275 }
0276
0277
0278 if (sof_parent)
0279 pdev->dev.driver->pm = &snd_soc_pm_ops;
0280
0281 return devm_snd_soc_register_card(&pdev->dev, &byt_cht_cx2072x_card);
0282 }
0283
0284 static struct platform_driver snd_byt_cht_cx2072x_driver = {
0285 .driver = {
0286 .name = "bytcht_cx2072x",
0287 },
0288 .probe = snd_byt_cht_cx2072x_probe,
0289 };
0290 module_platform_driver(snd_byt_cht_cx2072x_driver);
0291
0292 MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver");
0293 MODULE_LICENSE("GPL v2");
0294 MODULE_ALIAS("platform:bytcht_cx2072x");