1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright(c) 2021 Intel Corporation. 3 4 /* 5 * Intel SOF Machine Driver with Cirrus Logic CS42L42 Codec 6 * and speaker codec MAX98357A 7 */ 8 #include <linux/i2c.h> 9 #include <linux/input.h> 10 #include <linux/module.h> 11 #include <linux/platform_device.h> 12 #include <linux/regulator/consumer.h> 13 #include <linux/dmi.h> 14 #include <sound/core.h> 15 #include <sound/jack.h> 16 #include <sound/pcm.h> 17 #include <sound/pcm_params.h> 18 #include <sound/soc.h> 19 #include <sound/sof.h> 20 #include <sound/soc-acpi.h> 21 #include <dt-bindings/sound/cs42l42.h> 22 #include "../common/soc-intel-quirks.h" 23 #include "sof_board_helpers.h" 24 #include "sof_maxim_common.h" 25 #include "sof_ssp_common.h" 26 27 #define SOF_CS42L42_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) 28 #define SOF_CS42L42_SSP_CODEC_MASK (GENMASK(2, 0)) 29 #define SOF_CS42L42_SSP_AMP_SHIFT 4 30 #define SOF_CS42L42_SSP_AMP_MASK (GENMASK(6, 4)) 31 #define SOF_CS42L42_SSP_AMP(quirk) \ 32 (((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK) 33 #define SOF_CS42L42_NUM_HDMIDEV_SHIFT 7 34 #define SOF_CS42L42_NUM_HDMIDEV_MASK (GENMASK(9, 7)) 35 #define SOF_CS42L42_NUM_HDMIDEV(quirk) \ 36 (((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK) 37 #define SOF_BT_OFFLOAD_PRESENT BIT(25) 38 #define SOF_CS42L42_SSP_BT_SHIFT 26 39 #define SOF_CS42L42_SSP_BT_MASK (GENMASK(28, 26)) 40 #define SOF_CS42L42_SSP_BT(quirk) \ 41 (((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK) 42 43 static struct snd_soc_jack_pin jack_pins[] = { 44 { 45 .pin = "Headphone Jack", 46 .mask = SND_JACK_HEADPHONE, 47 }, 48 { 49 .pin = "Headset Mic", 50 .mask = SND_JACK_MICROPHONE, 51 }, 52 }; 53 54 /* Default: SSP2 */ 55 static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2); 56 57 static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd) 58 { 59 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 60 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; 61 struct snd_soc_jack *jack = &ctx->headset_jack; 62 int ret; 63 64 /* 65 * Headset buttons map to the google Reference headset. 66 * These can be configured by userspace. 67 */ 68 ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", 69 SND_JACK_HEADSET | SND_JACK_BTN_0 | 70 SND_JACK_BTN_1 | SND_JACK_BTN_2 | 71 SND_JACK_BTN_3, 72 jack, 73 jack_pins, 74 ARRAY_SIZE(jack_pins)); 75 if (ret) { 76 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); 77 return ret; 78 } 79 80 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 81 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); 82 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); 83 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); 84 85 ret = snd_soc_component_set_jack(component, jack, NULL); 86 if (ret) { 87 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); 88 return ret; 89 } 90 91 return ret; 92 }; 93 94 static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd) 95 { 96 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; 97 98 snd_soc_component_set_jack(component, NULL, NULL); 99 } 100 101 static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream, 102 struct snd_pcm_hw_params *params) 103 { 104 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 105 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 106 int clk_freq, ret; 107 108 clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */ 109 110 if (clk_freq <= 0) { 111 dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq); 112 return -EINVAL; 113 } 114 115 /* Configure sysclk for codec */ 116 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 117 clk_freq, SND_SOC_CLOCK_IN); 118 if (ret < 0) 119 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); 120 121 return ret; 122 } 123 124 static const struct snd_soc_ops sof_cs42l42_ops = { 125 .hw_params = sof_cs42l42_hw_params, 126 }; 127 128 static int sof_card_late_probe(struct snd_soc_card *card) 129 { 130 return sof_intel_board_card_late_probe(card); 131 } 132 133 static const struct snd_kcontrol_new sof_controls[] = { 134 SOC_DAPM_PIN_SWITCH("Headphone Jack"), 135 SOC_DAPM_PIN_SWITCH("Headset Mic"), 136 }; 137 138 static const struct snd_soc_dapm_widget sof_widgets[] = { 139 SND_SOC_DAPM_HP("Headphone Jack", NULL), 140 SND_SOC_DAPM_MIC("Headset Mic", NULL), 141 }; 142 143 static const struct snd_soc_dapm_route sof_map[] = { 144 /* HP jack connectors - unknown if we have jack detection */ 145 {"Headphone Jack", NULL, "HP"}, 146 147 /* other jacks */ 148 {"HS", NULL, "Headset Mic"}, 149 }; 150 151 /* sof audio machine driver for cs42l42 codec */ 152 static struct snd_soc_card sof_audio_card_cs42l42 = { 153 .name = "cs42l42", /* the sof- prefix is added by the core */ 154 .owner = THIS_MODULE, 155 .controls = sof_controls, 156 .num_controls = ARRAY_SIZE(sof_controls), 157 .dapm_widgets = sof_widgets, 158 .num_dapm_widgets = ARRAY_SIZE(sof_widgets), 159 .dapm_routes = sof_map, 160 .num_dapm_routes = ARRAY_SIZE(sof_map), 161 .fully_routed = true, 162 .late_probe = sof_card_late_probe, 163 }; 164 165 static struct snd_soc_dai_link_component cs42l42_component[] = { 166 { 167 .name = "i2c-10134242:00", 168 .dai_name = "cs42l42", 169 } 170 }; 171 172 static int 173 sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, 174 struct sof_card_private *ctx) 175 { 176 int ret; 177 178 ret = sof_intel_board_set_dai_link(dev, card, ctx); 179 if (ret) 180 return ret; 181 182 if (!ctx->codec_link) { 183 dev_err(dev, "codec link not available"); 184 return -EINVAL; 185 } 186 187 /* codec-specific fields for headphone codec */ 188 ctx->codec_link->codecs = cs42l42_component; 189 ctx->codec_link->num_codecs = ARRAY_SIZE(cs42l42_component); 190 ctx->codec_link->init = sof_cs42l42_init; 191 ctx->codec_link->exit = sof_cs42l42_exit; 192 ctx->codec_link->ops = &sof_cs42l42_ops; 193 194 if (ctx->amp_type == CODEC_NONE) 195 return 0; 196 197 if (!ctx->amp_link) { 198 dev_err(dev, "amp link not available"); 199 return -EINVAL; 200 } 201 202 /* codec-specific fields for speaker amplifier */ 203 switch (ctx->amp_type) { 204 case CODEC_MAX98357A: 205 max_98357a_dai_link(ctx->amp_link); 206 break; 207 case CODEC_MAX98360A: 208 max_98360a_dai_link(ctx->amp_link); 209 break; 210 default: 211 dev_err(dev, "invalid amp type %d\n", ctx->amp_type); 212 return -EINVAL; 213 } 214 215 return 0; 216 } 217 218 #define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ 219 SOF_LINK_CODEC, \ 220 SOF_LINK_DMIC01, \ 221 SOF_LINK_IDISP_HDMI, \ 222 SOF_LINK_NONE, \ 223 SOF_LINK_NONE, \ 224 SOF_LINK_NONE) 225 226 static int sof_audio_probe(struct platform_device *pdev) 227 { 228 struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; 229 struct sof_card_private *ctx; 230 int ret; 231 232 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 233 if (!ctx) 234 return -ENOMEM; 235 236 if (pdev->id_entry && pdev->id_entry->driver_data) 237 sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data; 238 239 ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); 240 ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); 241 242 if (soc_intel_is_glk()) { 243 ctx->dmic_be_num = 1; 244 ctx->hdmi_num = 3; 245 246 /* overwrite the DAI link order for GLK boards */ 247 ctx->link_order_overwrite = GLK_LINK_ORDER; 248 } else { 249 ctx->dmic_be_num = 2; 250 ctx->hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >> 251 SOF_CS42L42_NUM_HDMIDEV_SHIFT; 252 /* default number of HDMI DAI's */ 253 if (!ctx->hdmi_num) 254 ctx->hdmi_num = 3; 255 } 256 257 if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) 258 ctx->hdmi.idisp_codec = true; 259 260 dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); 261 262 /* port number of peripherals attached to ssp interface */ 263 ctx->ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >> 264 SOF_CS42L42_SSP_BT_SHIFT; 265 266 ctx->ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> 267 SOF_CS42L42_SSP_AMP_SHIFT; 268 269 ctx->ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK; 270 271 if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) 272 ctx->bt_offload_present = true; 273 274 /* update dai_link */ 275 ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_cs42l42, ctx); 276 if (ret) 277 return ret; 278 279 sof_audio_card_cs42l42.dev = &pdev->dev; 280 281 /* set platform name for each dailink */ 282 ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_cs42l42, 283 mach->mach_params.platform); 284 if (ret) 285 return ret; 286 287 snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx); 288 289 return devm_snd_soc_register_card(&pdev->dev, 290 &sof_audio_card_cs42l42); 291 } 292 293 static const struct platform_device_id board_ids[] = { 294 { 295 .name = "glk_cs4242_mx98357a", 296 .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) | 297 SOF_CS42L42_SSP_AMP(1)), 298 }, 299 { 300 .name = "jsl_cs4242_mx98360a", 301 .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) | 302 SOF_CS42L42_SSP_AMP(1)), 303 }, 304 { 305 .name = "adl_mx98360a_cs4242", 306 .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) | 307 SOF_CS42L42_SSP_AMP(1) | 308 SOF_CS42L42_NUM_HDMIDEV(4) | 309 SOF_BT_OFFLOAD_PRESENT | 310 SOF_CS42L42_SSP_BT(2)), 311 }, 312 { } 313 }; 314 MODULE_DEVICE_TABLE(platform, board_ids); 315 316 static struct platform_driver sof_audio = { 317 .probe = sof_audio_probe, 318 .driver = { 319 .name = "sof_cs42l42", 320 .pm = &snd_soc_pm_ops, 321 }, 322 .id_table = board_ids, 323 }; 324 module_platform_driver(sof_audio) 325 326 /* Module information */ 327 MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42"); 328 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 329 MODULE_LICENSE("GPL"); 330 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); 331 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); 332 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); 333