|
5 | 5 | #include <linux/string.h> |
6 | 6 | #include <sound/pcm.h> |
7 | 7 | #include <sound/soc.h> |
| 8 | +#include <sound/soc-acpi.h> |
8 | 9 | #include <sound/soc-dai.h> |
9 | 10 | #include <sound/soc-dapm.h> |
10 | 11 | #include <uapi/sound/asound.h> |
@@ -133,6 +134,185 @@ void max_98373_set_codec_conf(struct snd_soc_card *card) |
133 | 134 | } |
134 | 135 | EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); |
135 | 136 |
|
| 137 | +/* |
| 138 | + * Maxim MAX98390 |
| 139 | + */ |
| 140 | +const struct snd_soc_dapm_route max_98390_dapm_routes[] = { |
| 141 | + /* speaker */ |
| 142 | + { "Left Spk", NULL, "Left BE_OUT" }, |
| 143 | + { "Right Spk", NULL, "Right BE_OUT" }, |
| 144 | +}; |
| 145 | + |
| 146 | +static const struct snd_kcontrol_new max_98390_tt_kcontrols[] = { |
| 147 | + SOC_DAPM_PIN_SWITCH("TL Spk"), |
| 148 | + SOC_DAPM_PIN_SWITCH("TR Spk"), |
| 149 | +}; |
| 150 | + |
| 151 | +static const struct snd_soc_dapm_widget max_98390_tt_dapm_widgets[] = { |
| 152 | + SND_SOC_DAPM_SPK("TL Spk", NULL), |
| 153 | + SND_SOC_DAPM_SPK("TR Spk", NULL), |
| 154 | +}; |
| 155 | + |
| 156 | +const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = { |
| 157 | + /* Tweeter speaker */ |
| 158 | + { "TL Spk", NULL, "Tweeter Left BE_OUT" }, |
| 159 | + { "TR Spk", NULL, "Tweeter Right BE_OUT" }, |
| 160 | +}; |
| 161 | + |
| 162 | +static struct snd_soc_codec_conf max_98390_codec_conf[] = { |
| 163 | + { |
| 164 | + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), |
| 165 | + .name_prefix = "Right", |
| 166 | + }, |
| 167 | + { |
| 168 | + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), |
| 169 | + .name_prefix = "Left", |
| 170 | + }, |
| 171 | +}; |
| 172 | + |
| 173 | +static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = { |
| 174 | + { |
| 175 | + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), |
| 176 | + .name_prefix = "Right", |
| 177 | + }, |
| 178 | + { |
| 179 | + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), |
| 180 | + .name_prefix = "Left", |
| 181 | + }, |
| 182 | + { |
| 183 | + .dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME), |
| 184 | + .name_prefix = "Tweeter Right", |
| 185 | + }, |
| 186 | + { |
| 187 | + .dlc = COMP_CODEC_CONF(MAX_98390_DEV3_NAME), |
| 188 | + .name_prefix = "Tweeter Left", |
| 189 | + }, |
| 190 | +}; |
| 191 | + |
| 192 | +struct snd_soc_dai_link_component max_98390_components[] = { |
| 193 | + { |
| 194 | + .name = MAX_98390_DEV0_NAME, |
| 195 | + .dai_name = MAX_98390_CODEC_DAI, |
| 196 | + }, |
| 197 | + { |
| 198 | + .name = MAX_98390_DEV1_NAME, |
| 199 | + .dai_name = MAX_98390_CODEC_DAI, |
| 200 | + }, |
| 201 | +}; |
| 202 | +EXPORT_SYMBOL_NS(max_98390_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); |
| 203 | + |
| 204 | +struct snd_soc_dai_link_component max_98390_4spk_components[] = { |
| 205 | + { |
| 206 | + .name = MAX_98390_DEV0_NAME, |
| 207 | + .dai_name = MAX_98390_CODEC_DAI, |
| 208 | + }, |
| 209 | + { |
| 210 | + .name = MAX_98390_DEV1_NAME, |
| 211 | + .dai_name = MAX_98390_CODEC_DAI, |
| 212 | + }, |
| 213 | + { |
| 214 | + .name = MAX_98390_DEV2_NAME, |
| 215 | + .dai_name = MAX_98390_CODEC_DAI, |
| 216 | + }, |
| 217 | + { |
| 218 | + .name = MAX_98390_DEV3_NAME, |
| 219 | + .dai_name = MAX_98390_CODEC_DAI, |
| 220 | + }, |
| 221 | +}; |
| 222 | +EXPORT_SYMBOL_NS(max_98390_4spk_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); |
| 223 | + |
| 224 | +static int max_98390_hw_params(struct snd_pcm_substream *substream, |
| 225 | + struct snd_pcm_hw_params *params) |
| 226 | +{ |
| 227 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
| 228 | + struct snd_soc_dai *codec_dai; |
| 229 | + int i; |
| 230 | + |
| 231 | + for_each_rtd_codec_dais(rtd, i, codec_dai) { |
| 232 | + if (i >= ARRAY_SIZE(max_98390_4spk_components)) { |
| 233 | + dev_err(codec_dai->dev, "invalid codec index %d\n", i); |
| 234 | + return -ENODEV; |
| 235 | + } |
| 236 | + |
| 237 | + if (!strcmp(codec_dai->component->name, MAX_98390_DEV0_NAME)) { |
| 238 | + /* DEV0 tdm slot configuration Right */ |
| 239 | + snd_soc_dai_set_tdm_slot(codec_dai, 0x01, 3, 4, 32); |
| 240 | + } |
| 241 | + if (!strcmp(codec_dai->component->name, MAX_98390_DEV1_NAME)) { |
| 242 | + /* DEV1 tdm slot configuration Left */ |
| 243 | + snd_soc_dai_set_tdm_slot(codec_dai, 0x02, 3, 4, 32); |
| 244 | + } |
| 245 | + |
| 246 | + if (!strcmp(codec_dai->component->name, MAX_98390_DEV2_NAME)) { |
| 247 | + /* DEVi2 tdm slot configuration Tweeter Right */ |
| 248 | + snd_soc_dai_set_tdm_slot(codec_dai, 0x04, 3, 4, 32); |
| 249 | + } |
| 250 | + if (!strcmp(codec_dai->component->name, MAX_98390_DEV3_NAME)) { |
| 251 | + /* DEV3 tdm slot configuration Tweeter Left */ |
| 252 | + snd_soc_dai_set_tdm_slot(codec_dai, 0x08, 3, 4, 32); |
| 253 | + } |
| 254 | + } |
| 255 | + return 0; |
| 256 | +} |
| 257 | + |
| 258 | +int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd) |
| 259 | +{ |
| 260 | + struct snd_soc_card *card = rtd->card; |
| 261 | + int ret; |
| 262 | + |
| 263 | + /* add regular speakers dapm route */ |
| 264 | + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, |
| 265 | + ARRAY_SIZE(max_98390_dapm_routes)); |
| 266 | + if (ret) { |
| 267 | + dev_err(rtd->dev, "unable to add Left/Right Speaker dapm, ret %d\n", ret); |
| 268 | + return ret; |
| 269 | + } |
| 270 | + |
| 271 | + /* add widgets/controls/dapm for tweeter speakers */ |
| 272 | + if (acpi_dev_present("MX98390", "3", -1)) { |
| 273 | + ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets, |
| 274 | + ARRAY_SIZE(max_98390_tt_dapm_widgets)); |
| 275 | + |
| 276 | + if (ret) { |
| 277 | + dev_err(rtd->dev, "unable to add tweeter dapm controls, ret %d\n", ret); |
| 278 | + /* Don't need to add routes if widget addition failed */ |
| 279 | + return ret; |
| 280 | + } |
| 281 | + |
| 282 | + ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols, |
| 283 | + ARRAY_SIZE(max_98390_tt_kcontrols)); |
| 284 | + if (ret) { |
| 285 | + dev_err(rtd->dev, "unable to add tweeter card controls, ret %d\n", ret); |
| 286 | + return ret; |
| 287 | + } |
| 288 | + |
| 289 | + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes, |
| 290 | + ARRAY_SIZE(max_98390_tt_dapm_routes)); |
| 291 | + if (ret) |
| 292 | + dev_err(rtd->dev, |
| 293 | + "unable to add Tweeter Left/Right Speaker dapm, ret %d\n", ret); |
| 294 | + } |
| 295 | + return ret; |
| 296 | +} |
| 297 | +EXPORT_SYMBOL_NS(max_98390_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON); |
| 298 | + |
| 299 | +const struct snd_soc_ops max_98390_ops = { |
| 300 | + .hw_params = max_98390_hw_params, |
| 301 | +}; |
| 302 | +EXPORT_SYMBOL_NS(max_98390_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON); |
| 303 | + |
| 304 | +void max_98390_set_codec_conf(struct snd_soc_card *card, int ch) |
| 305 | +{ |
| 306 | + if (ch == ARRAY_SIZE(max_98390_4spk_codec_conf)) { |
| 307 | + card->codec_conf = max_98390_4spk_codec_conf; |
| 308 | + card->num_configs = ARRAY_SIZE(max_98390_4spk_codec_conf); |
| 309 | + } else { |
| 310 | + card->codec_conf = max_98390_codec_conf; |
| 311 | + card->num_configs = ARRAY_SIZE(max_98390_codec_conf); |
| 312 | + } |
| 313 | +} |
| 314 | +EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); |
| 315 | + |
136 | 316 | /* |
137 | 317 | * Maxim MAX98357A/MAX98360A |
138 | 318 | */ |
|
0 commit comments