1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2022 Intel Corporation 4 5 /* 6 * sof_ssp_amp.c - ASoc Machine driver for Intel platforms 7 * with RT1308/CS35L41 codec. 8 */ 9 10 #include <linux/acpi.h> 11 #include <linux/delay.h> 12 #include <linux/dmi.h> 13 #include <linux/module.h> 14 #include <linux/platform_device.h> 15 #include <sound/core.h> 16 #include <sound/jack.h> 17 #include <sound/pcm.h> 18 #include <sound/pcm_params.h> 19 #include <sound/sof.h> 20 #include "sof_board_helpers.h" 21 #include "sof_realtek_common.h" 22 #include "sof_cirrus_common.h" 23 24 /* Driver-specific board quirks: from bit 0 to 7 */ 25 #define SOF_HDMI_PLAYBACK_PRESENT BIT(0) 26 27 /* Default: SSP2 */ 28 static unsigned long sof_ssp_amp_quirk = SOF_SSP_PORT_AMP(2); 29 30 static const struct dmi_system_id chromebook_platforms[] = { 31 { 32 .ident = "Google Chromebooks", 33 .matches = { 34 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 35 } 36 }, 37 {}, 38 }; 39 40 static int sof_card_late_probe(struct snd_soc_card *card) 41 { 42 return sof_intel_board_card_late_probe(card); 43 } 44 45 static struct snd_soc_card sof_ssp_amp_card = { 46 .name = "ssp_amp", 47 .owner = THIS_MODULE, 48 .fully_routed = true, 49 .late_probe = sof_card_late_probe, 50 }; 51 52 /* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */ 53 #define HDMI_IN_BE_ID 0 54 #define SPK_BE_ID 2 55 #define DMIC01_BE_ID 3 56 #define INTEL_HDMI_BE_ID 5 57 /* extra BE links to support no-hdmi-in boards */ 58 #define DMIC16K_BE_ID 4 59 #define BT_OFFLOAD_BE_ID 8 60 61 #define SSP_AMP_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_HDMI_IN, \ 62 SOF_LINK_AMP, \ 63 SOF_LINK_DMIC01, \ 64 SOF_LINK_DMIC16K, \ 65 SOF_LINK_IDISP_HDMI, \ 66 SOF_LINK_BT_OFFLOAD, \ 67 SOF_LINK_NONE) 68 69 #define SSP_AMP_LINK_IDS SOF_LINK_ORDER(HDMI_IN_BE_ID, \ 70 SPK_BE_ID, \ 71 DMIC01_BE_ID, \ 72 DMIC16K_BE_ID, \ 73 INTEL_HDMI_BE_ID, \ 74 BT_OFFLOAD_BE_ID, \ 75 0) 76 77 static int 78 sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, 79 struct sof_card_private *ctx) 80 { 81 int ret; 82 83 ret = sof_intel_board_set_dai_link(dev, card, ctx); 84 if (ret) 85 return ret; 86 87 if (ctx->amp_type == CODEC_NONE) 88 return 0; 89 90 if (!ctx->amp_link) { 91 dev_err(dev, "amp link not available"); 92 return -EINVAL; 93 } 94 95 /* codec-specific fields for speaker amplifier */ 96 switch (ctx->amp_type) { 97 case CODEC_CS35L41: 98 cs35l41_set_dai_link(ctx->amp_link); 99 break; 100 case CODEC_RT1308: 101 sof_rt1308_dai_link(ctx->amp_link); 102 break; 103 default: 104 dev_err(dev, "invalid amp type %d\n", ctx->amp_type); 105 return -EINVAL; 106 } 107 108 return 0; 109 } 110 111 static int sof_ssp_amp_probe(struct platform_device *pdev) 112 { 113 struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; 114 struct sof_card_private *ctx; 115 int ret; 116 117 if (pdev->id_entry && pdev->id_entry->driver_data) 118 sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data; 119 120 dev_dbg(&pdev->dev, "sof_ssp_amp_quirk = %lx\n", sof_ssp_amp_quirk); 121 122 /* initialize ctx with board quirk */ 123 ctx = sof_intel_board_get_ctx(&pdev->dev, sof_ssp_amp_quirk); 124 if (!ctx) 125 return -ENOMEM; 126 127 if (!dmi_check_system(chromebook_platforms) && 128 (mach->mach_params.dmic_num == 0)) 129 ctx->dmic_be_num = 0; 130 131 if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { 132 if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) 133 ctx->hdmi.idisp_codec = true; 134 } else { 135 ctx->hdmi_num = 0; 136 } 137 138 ctx->link_order_overwrite = SSP_AMP_LINK_ORDER; 139 140 if (ctx->ssp_mask_hdmi_in) { 141 /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ 142 ctx->link_id_overwrite = SSP_AMP_LINK_IDS; 143 } 144 145 /* update dai_link */ 146 ret = sof_card_dai_links_create(&pdev->dev, &sof_ssp_amp_card, ctx); 147 if (ret) 148 return ret; 149 150 /* update codec_conf */ 151 switch (ctx->amp_type) { 152 case CODEC_CS35L41: 153 cs35l41_set_codec_conf(&sof_ssp_amp_card); 154 break; 155 case CODEC_RT1308: 156 case CODEC_NONE: 157 /* no codec conf required */ 158 break; 159 default: 160 dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); 161 return -EINVAL; 162 } 163 164 sof_ssp_amp_card.dev = &pdev->dev; 165 166 /* set platform name for each dailink */ 167 ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card, 168 mach->mach_params.platform); 169 if (ret) 170 return ret; 171 172 snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx); 173 174 return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card); 175 } 176 177 static const struct platform_device_id board_ids[] = { 178 { 179 .name = "sof_ssp_amp", 180 }, 181 { 182 .name = "tgl_rt1308_hdmi_ssp", 183 .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(2) | 184 SOF_SSP_MASK_HDMI_CAPTURE(0x22)), 185 /* SSP 1 and SSP 5 are used for HDMI IN */ 186 }, 187 { 188 .name = "adl_cs35l41", 189 .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(1) | 190 SOF_NUM_IDISP_HDMI(4) | 191 SOF_HDMI_PLAYBACK_PRESENT | 192 SOF_SSP_PORT_BT_OFFLOAD(2) | 193 SOF_BT_OFFLOAD_PRESENT), 194 }, 195 { 196 .name = "adl_lt6911_hdmi_ssp", 197 .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | 198 /* SSP 0 and SSP 2 are used for HDMI IN */ 199 SOF_HDMI_PLAYBACK_PRESENT), 200 }, 201 { 202 .name = "rpl_lt6911_hdmi_ssp", 203 .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | 204 /* SSP 0 and SSP 2 are used for HDMI IN */ 205 SOF_HDMI_PLAYBACK_PRESENT), 206 }, 207 { 208 .name = "mtl_lt6911_hdmi_ssp", 209 .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | 210 /* SSP 0 and SSP 2 are used for HDMI IN */ 211 SOF_HDMI_PLAYBACK_PRESENT), 212 }, 213 { } 214 }; 215 MODULE_DEVICE_TABLE(platform, board_ids); 216 217 static struct platform_driver sof_ssp_amp_driver = { 218 .probe = sof_ssp_amp_probe, 219 .driver = { 220 .name = "sof_ssp_amp", 221 .pm = &snd_soc_pm_ops, 222 }, 223 .id_table = board_ids, 224 }; 225 module_platform_driver(sof_ssp_amp_driver); 226 227 MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver"); 228 MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>"); 229 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 230 MODULE_LICENSE("GPL"); 231 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); 232 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); 233 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON); 234