linux/sound/soc/sdw_utils/soc_sdw_cs42l43.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2// Based on sof_sdw_rt5682.c
   3// This file incorporates work covered by the following copyright notice:
   4// Copyright (c) 2023 Intel Corporation
   5// Copyright (c) 2024 Advanced Micro Devices, Inc.
   6
   7/*
   8 *  soc_sdw_cs42l43 - Helpers to handle CS42L43 from generic machine driver
   9 */
  10#include <linux/device.h>
  11#include <linux/errno.h>
  12#include <linux/input.h>
  13#include <sound/jack.h>
  14#include <linux/soundwire/sdw.h>
  15#include <linux/soundwire/sdw_type.h>
  16#include <sound/cs42l43.h>
  17#include <sound/control.h>
  18#include <sound/soc.h>
  19#include <sound/soc-acpi.h>
  20#include <sound/soc-dapm.h>
  21#include <sound/soc_sdw_utils.h>
  22
  23#define CS42L43_SPK_VOLUME_0DB  128 /* 0dB Max */
  24
  25static const struct snd_soc_dapm_route cs42l43_hs_map[] = {
  26        { "Headphone", NULL, "cs42l43 AMP3_OUT" },
  27        { "Headphone", NULL, "cs42l43 AMP4_OUT" },
  28        { "cs42l43 ADC1_IN1_P", NULL, "Headset Mic" },
  29        { "cs42l43 ADC1_IN1_N", NULL, "Headset Mic" },
  30};
  31
  32static const struct snd_soc_dapm_route cs42l43_spk_map[] = {
  33        { "Speaker", NULL, "cs42l43 AMP1_OUT_P", },
  34        { "Speaker", NULL, "cs42l43 AMP1_OUT_N", },
  35        { "Speaker", NULL, "cs42l43 AMP2_OUT_P", },
  36        { "Speaker", NULL, "cs42l43 AMP2_OUT_N", },
  37};
  38
  39static const struct snd_soc_dapm_route cs42l43_dmic_map[] = {
  40        { "cs42l43 PDM1_DIN", NULL, "DMIC" },
  41        { "cs42l43 PDM2_DIN", NULL, "DMIC" },
  42};
  43
  44static struct snd_soc_jack_pin soc_jack_pins[] = {
  45        {
  46                .pin    = "Headphone",
  47                .mask   = SND_JACK_HEADPHONE,
  48        },
  49        {
  50                .pin    = "Headset Mic",
  51                .mask   = SND_JACK_MICROPHONE,
  52        },
  53};
  54
  55int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
  56{
  57        struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
  58        struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card);
  59        struct snd_soc_jack *jack = &ctx->sdw_headset;
  60        struct snd_soc_card *card = rtd->card;
  61        int ret;
  62
  63        card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:cs42l43",
  64                                          card->components);
  65        if (!card->components)
  66                return -ENOMEM;
  67
  68        ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_hs_map,
  69                                      ARRAY_SIZE(cs42l43_hs_map));
  70        if (ret) {
  71                dev_err(card->dev, "cs42l43 hs map addition failed: %d\n", ret);
  72                return ret;
  73        }
  74
  75        ret = snd_soc_card_jack_new_pins(card, "Jack",
  76                                         SND_JACK_MECHANICAL | SND_JACK_AVOUT |
  77                                         SND_JACK_HEADSET | SND_JACK_LINEOUT |
  78                                         SND_JACK_BTN_0 | SND_JACK_BTN_1 |
  79                                         SND_JACK_BTN_2 | SND_JACK_BTN_3,
  80                                         jack, soc_jack_pins,
  81                                         ARRAY_SIZE(soc_jack_pins));
  82        if (ret) {
  83                dev_err(card->dev, "Failed to create jack: %d\n", ret);
  84                return ret;
  85        }
  86
  87        snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
  88        snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
  89        snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
  90        snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
  91
  92        ret = snd_soc_component_set_jack(component, jack, NULL);
  93        if (ret) {
  94                dev_err(card->dev, "Failed to register jack: %d\n", ret);
  95                return ret;
  96        }
  97
  98        ret = snd_soc_component_set_sysclk(component, CS42L43_SYSCLK, CS42L43_SYSCLK_SDW,
  99                                           0, SND_SOC_CLOCK_IN);
 100        if (ret)
 101                dev_err(card->dev, "Failed to set sysclk: %d\n", ret);
 102
 103        return ret;
 104}
 105EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_hs_rtd_init, "SND_SOC_SDW_UTILS");
 106
 107int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
 108{
 109        struct snd_soc_card *card = rtd->card;
 110        struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
 111        int ret;
 112
 113        if (!(ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS)) {
 114                /* Will be set by the bridge code in this case */
 115                card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 116                                                  "%s spk:cs42l43-spk",
 117                                                  card->components);
 118                if (!card->components)
 119                        return -ENOMEM;
 120        }
 121
 122        ret = snd_soc_limit_volume(card, "cs42l43 Speaker Digital Volume",
 123                                   CS42L43_SPK_VOLUME_0DB);
 124        if (ret)
 125                dev_err(card->dev, "cs42l43 speaker volume limit failed: %d\n", ret);
 126        else
 127                dev_info(card->dev, "Setting CS42L43 Speaker volume limit to %d\n",
 128                         CS42L43_SPK_VOLUME_0DB);
 129
 130        ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_spk_map,
 131                                      ARRAY_SIZE(cs42l43_spk_map));
 132        if (ret)
 133                dev_err(card->dev, "cs42l43 speaker map addition failed: %d\n", ret);
 134
 135        return ret;
 136}
 137EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_rtd_init, "SND_SOC_SDW_UTILS");
 138
 139int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card,
 140                              struct snd_soc_dai_link *dai_links,
 141                              struct asoc_sdw_codec_info *info,
 142                              bool playback)
 143{
 144        /* Do init on playback link only. */
 145        if (!playback)
 146                return 0;
 147
 148        info->amp_num++;
 149
 150        return asoc_sdw_bridge_cs35l56_spk_init(card, dai_links, info, playback);
 151}
 152EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_init, "SND_SOC_SDW_UTILS");
 153
 154int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
 155{
 156        struct snd_soc_card *card = rtd->card;
 157        int ret;
 158
 159        card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s mic:cs42l43-dmic",
 160                                          card->components);
 161        if (!card->components)
 162                return -ENOMEM;
 163
 164        ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_dmic_map,
 165                                      ARRAY_SIZE(cs42l43_dmic_map));
 166        if (ret)
 167                dev_err(card->dev, "cs42l43 dmic map addition failed: %d\n", ret);
 168
 169        return ret;
 170}
 171EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_dmic_rtd_init, "SND_SOC_SDW_UTILS");
 172