FILE
bytcht_cx2072x.c
File preview with syntax highlighting.
linux-6.19.14/sound/soc/intel/boards/bytcht_cx2072x.c
1// SPDX-License-Identifier: GPL-2.0-only 2// 3// ASoC DPCM Machine driver for Baytrail / Cherrytrail platforms with 4// CX2072X codec 5// 6 7#include <linux/acpi.h> 8#include <linux/device.h> 9#include <linux/gpio/consumer.h> 10#include <linux/module.h> 11#include <linux/platform_device.h> 12#include <linux/slab.h> 13#include <sound/pcm.h> 14#include <sound/pcm_params.h> 15#include <sound/jack.h> 16#include <sound/soc.h> 17#include <sound/soc-acpi.h> 18#include "../../codecs/cx2072x.h" 19#include "../atom/sst-atom-controls.h" 20 21static const struct snd_soc_dapm_widget byt_cht_cx2072x_widgets[] = { 22 SND_SOC_DAPM_HP("Headphone", NULL), 23 SND_SOC_DAPM_MIC("Headset Mic", NULL), 24 SND_SOC_DAPM_MIC("Int Mic", NULL), 25 SND_SOC_DAPM_SPK("Ext Spk", NULL), 26}; 27 28static const struct snd_soc_dapm_route byt_cht_cx2072x_audio_map[] = { 29 /* External Speakers: HFL, HFR */ 30 {"Headphone", NULL, "PORTA"}, 31 {"Ext Spk", NULL, "PORTG"}, 32 {"PORTC", NULL, "Int Mic"}, 33 {"PORTD", NULL, "Headset Mic"}, 34 35 {"Playback", NULL, "ssp2 Tx"}, 36 {"ssp2 Tx", NULL, "codec_out0"}, 37 {"ssp2 Tx", NULL, "codec_out1"}, 38 {"codec_in0", NULL, "ssp2 Rx"}, 39 {"codec_in1", NULL, "ssp2 Rx"}, 40 {"ssp2 Rx", NULL, "Capture"}, 41}; 42 43static const struct snd_kcontrol_new byt_cht_cx2072x_controls[] = { 44 SOC_DAPM_PIN_SWITCH("Headphone"), 45 SOC_DAPM_PIN_SWITCH("Headset Mic"), 46 SOC_DAPM_PIN_SWITCH("Int Mic"), 47 SOC_DAPM_PIN_SWITCH("Ext Spk"), 48}; 49 50static struct snd_soc_jack byt_cht_cx2072x_headset; 51 52/* Headset jack detection DAPM pins */ 53static struct snd_soc_jack_pin byt_cht_cx2072x_headset_pins[] = { 54 { 55 .pin = "Headset Mic", 56 .mask = SND_JACK_MICROPHONE, 57 }, 58 { 59 .pin = "Headphone", 60 .mask = SND_JACK_HEADPHONE, 61 }, 62}; 63 64static const struct acpi_gpio_params byt_cht_cx2072x_headset_gpios; 65static const struct acpi_gpio_mapping byt_cht_cx2072x_acpi_gpios[] = { 66 { "headset-gpios", &byt_cht_cx2072x_headset_gpios, 1 }, 67 {}, 68}; 69 70static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd) 71{ 72 struct snd_soc_card *card = rtd->card; 73 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); 74 struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component; 75 int ret; 76 77 if (devm_acpi_dev_add_driver_gpios(codec->dev, 78 byt_cht_cx2072x_acpi_gpios)) 79 dev_warn(rtd->dev, "Unable to add GPIO mapping table\n"); 80 81 snd_soc_dapm_set_idle_bias(dapm, false); 82 83 /* set the default PLL rate, the clock is handled by the codec driver */ 84 ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), CX2072X_MCLK_EXTERNAL_PLL, 85 19200000, SND_SOC_CLOCK_IN); 86 if (ret) { 87 dev_err(rtd->dev, "Could not set sysclk\n"); 88 return ret; 89 } 90 91 ret = snd_soc_card_jack_new_pins(card, "Headset", 92 SND_JACK_HEADSET | SND_JACK_BTN_0, 93 &byt_cht_cx2072x_headset, 94 byt_cht_cx2072x_headset_pins, 95 ARRAY_SIZE(byt_cht_cx2072x_headset_pins)); 96 if (ret) 97 return ret; 98 99 snd_soc_component_set_jack(codec, &byt_cht_cx2072x_headset, NULL); 100 101 snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_codec(rtd, 0), 50); 102 103 return 0; 104} 105 106static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd, 107 struct snd_pcm_hw_params *params) 108{ 109 struct snd_interval *rate = 110 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 111 struct snd_interval *channels = 112 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 113 int ret; 114 115 /* The DSP will convert the FE rate to 48k, stereo, 24bits */ 116 rate->min = rate->max = 48000; 117 channels->min = channels->max = 2; 118 119 /* set SSP2 to 24-bit */ 120 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); 121 122 /* 123 * Default mode for SSP configuration is TDM 4 slot, override config 124 * with explicit setting to I2S 2ch 24-bit. The word length is set with 125 * dai_set_tdm_slot() since there is no other API exposed 126 */ 127 ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), 128 SND_SOC_DAIFMT_I2S | 129 SND_SOC_DAIFMT_NB_NF | 130 SND_SOC_DAIFMT_BP_FP); 131 if (ret < 0) { 132 dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); 133 return ret; 134 } 135 136 ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24); 137 if (ret < 0) { 138 dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); 139 return ret; 140 } 141 142 return 0; 143} 144 145static int byt_cht_cx2072x_aif1_startup(struct snd_pcm_substream *substream) 146{ 147 return snd_pcm_hw_constraint_single(substream->runtime, 148 SNDRV_PCM_HW_PARAM_RATE, 48000); 149} 150 151static const struct snd_soc_ops byt_cht_cx2072x_aif1_ops = { 152 .startup = byt_cht_cx2072x_aif1_startup, 153}; 154 155SND_SOC_DAILINK_DEF(dummy, 156 DAILINK_COMP_ARRAY(COMP_DUMMY())); 157 158SND_SOC_DAILINK_DEF(media, 159 DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai"))); 160 161SND_SOC_DAILINK_DEF(deepbuffer, 162 DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai"))); 163 164SND_SOC_DAILINK_DEF(ssp2, 165 DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port"))); 166 167SND_SOC_DAILINK_DEF(cx2072x, 168 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-14F10720:00", "cx2072x-hifi"))); 169 170SND_SOC_DAILINK_DEF(platform, 171 DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform"))); 172 173static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { 174 [MERR_DPCM_AUDIO] = { 175 .name = "Audio Port", 176 .stream_name = "Audio", 177 .nonatomic = true, 178 .dynamic = 1, 179 .ops = &byt_cht_cx2072x_aif1_ops, 180 SND_SOC_DAILINK_REG(media, dummy, platform), 181 }, 182 [MERR_DPCM_DEEP_BUFFER] = { 183 .name = "Deep-Buffer Audio Port", 184 .stream_name = "Deep-Buffer Audio", 185 .nonatomic = true, 186 .dynamic = 1, 187 .playback_only = 1, 188 .ops = &byt_cht_cx2072x_aif1_ops, 189 SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), 190 }, 191 /* back ends */ 192 { 193 .name = "SSP2-Codec", 194 .id = 0, 195 .no_pcm = 1, 196 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 197 | SND_SOC_DAIFMT_CBC_CFC, 198 .init = byt_cht_cx2072x_init, 199 .be_hw_params_fixup = byt_cht_cx2072x_fixup, 200 SND_SOC_DAILINK_REG(ssp2, cx2072x, platform), 201 }, 202}; 203 204/* use space before codec name to simplify card ID, and simplify driver name */ 205#define SOF_CARD_NAME "bytcht cx2072x" /* card name will be 'sof-bytcht cx2072x' */ 206#define SOF_DRIVER_NAME "SOF" 207 208#define CARD_NAME "bytcht-cx2072x" 209#define DRIVER_NAME NULL /* card name will be used for driver name */ 210 211/* SoC card */ 212static struct snd_soc_card byt_cht_cx2072x_card = { 213 .name = CARD_NAME, 214 .driver_name = DRIVER_NAME, 215 .owner = THIS_MODULE, 216 .dai_link = byt_cht_cx2072x_dais, 217 .num_links = ARRAY_SIZE(byt_cht_cx2072x_dais), 218 .dapm_widgets = byt_cht_cx2072x_widgets, 219 .num_dapm_widgets = ARRAY_SIZE(byt_cht_cx2072x_widgets), 220 .dapm_routes = byt_cht_cx2072x_audio_map, 221 .num_dapm_routes = ARRAY_SIZE(byt_cht_cx2072x_audio_map), 222 .controls = byt_cht_cx2072x_controls, 223 .num_controls = ARRAY_SIZE(byt_cht_cx2072x_controls), 224}; 225 226static char codec_name[SND_ACPI_I2C_ID_LEN]; 227 228static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) 229{ 230 struct snd_soc_acpi_mach *mach; 231 struct acpi_device *adev; 232 int dai_index = 0; 233 bool sof_parent; 234 int i, ret; 235 236 byt_cht_cx2072x_card.dev = &pdev->dev; 237 mach = dev_get_platdata(&pdev->dev); 238 239 /* fix index of codec dai */ 240 for (i = 0; i < ARRAY_SIZE(byt_cht_cx2072x_dais); i++) { 241 if (byt_cht_cx2072x_dais[i].num_codecs && 242 !strcmp(byt_cht_cx2072x_dais[i].codecs->name, 243 "i2c-14F10720:00")) { 244 dai_index = i; 245 break; 246 } 247 } 248 249 /* fixup codec name based on HID */ 250 adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); 251 if (adev) { 252 snprintf(codec_name, sizeof(codec_name), "i2c-%s", 253 acpi_dev_name(adev)); 254 byt_cht_cx2072x_dais[dai_index].codecs->name = codec_name; 255 } else { 256 dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); 257 return -ENOENT; 258 } 259 260 acpi_dev_put(adev); 261 262 /* override platform name, if required */ 263 ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_cx2072x_card, 264 mach->mach_params.platform); 265 if (ret) 266 return ret; 267 268 sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); 269 270 /* set card and driver name */ 271 if (sof_parent) { 272 byt_cht_cx2072x_card.name = SOF_CARD_NAME; 273 byt_cht_cx2072x_card.driver_name = SOF_DRIVER_NAME; 274 } else { 275 byt_cht_cx2072x_card.name = CARD_NAME; 276 byt_cht_cx2072x_card.driver_name = DRIVER_NAME; 277 } 278 279 /* set pm ops */ 280 if (sof_parent) 281 pdev->dev.driver->pm = &snd_soc_pm_ops; 282 283 return devm_snd_soc_register_card(&pdev->dev, &byt_cht_cx2072x_card); 284} 285 286static struct platform_driver snd_byt_cht_cx2072x_driver = { 287 .driver = { 288 .name = "bytcht_cx2072x", 289 }, 290 .probe = snd_byt_cht_cx2072x_probe, 291}; 292module_platform_driver(snd_byt_cht_cx2072x_driver); 293 294MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver"); 295MODULE_LICENSE("GPL v2"); 296MODULE_ALIAS("platform:bytcht_cx2072x");
~/
Read-only file preview.