Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright (c) 2020 Intel Corporation
0003 
0004 /*
0005  *  sof_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver
0006  */
0007 
0008 #include <linux/device.h>
0009 #include <linux/errno.h>
0010 #include <linux/input.h>
0011 #include <linux/soundwire/sdw.h>
0012 #include <linux/soundwire/sdw_type.h>
0013 #include <sound/control.h>
0014 #include <sound/soc.h>
0015 #include <sound/soc-acpi.h>
0016 #include <sound/soc-dapm.h>
0017 #include <sound/jack.h>
0018 #include "sof_sdw_common.h"
0019 
0020 /*
0021  * Note this MUST be called before snd_soc_register_card(), so that the props
0022  * are in place before the codec component driver's probe function parses them.
0023  */
0024 static int rt711_sdca_add_codec_device_props(struct device *sdw_dev)
0025 {
0026     struct property_entry props[MAX_NO_PROPS] = {};
0027     struct fwnode_handle *fwnode;
0028     int ret;
0029 
0030     if (!SOF_RT711_JDSRC(sof_sdw_quirk))
0031         return 0;
0032 
0033     props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_RT711_JDSRC(sof_sdw_quirk));
0034 
0035     fwnode = fwnode_create_software_node(props, NULL);
0036     if (IS_ERR(fwnode))
0037         return PTR_ERR(fwnode);
0038 
0039     ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
0040 
0041     fwnode_handle_put(fwnode);
0042 
0043     return ret;
0044 }
0045 
0046 static const struct snd_soc_dapm_widget rt711_sdca_widgets[] = {
0047     SND_SOC_DAPM_HP("Headphone", NULL),
0048     SND_SOC_DAPM_MIC("Headset Mic", NULL),
0049 };
0050 
0051 static const struct snd_soc_dapm_route rt711_sdca_map[] = {
0052     /* Headphones */
0053     { "Headphone", NULL, "rt711 HP" },
0054     { "rt711 MIC2", NULL, "Headset Mic" },
0055 };
0056 
0057 static const struct snd_kcontrol_new rt711_sdca_controls[] = {
0058     SOC_DAPM_PIN_SWITCH("Headphone"),
0059     SOC_DAPM_PIN_SWITCH("Headset Mic"),
0060 };
0061 
0062 static struct snd_soc_jack_pin rt711_sdca_jack_pins[] = {
0063     {
0064         .pin    = "Headphone",
0065         .mask   = SND_JACK_HEADPHONE,
0066     },
0067     {
0068         .pin    = "Headset Mic",
0069         .mask   = SND_JACK_MICROPHONE,
0070     },
0071 };
0072 
0073 static int rt711_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd)
0074 {
0075     struct snd_soc_card *card = rtd->card;
0076     struct mc_private *ctx = snd_soc_card_get_drvdata(card);
0077     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0078     struct snd_soc_component *component = codec_dai->component;
0079     struct snd_soc_jack *jack;
0080     int ret;
0081 
0082     card->components = devm_kasprintf(card->dev, GFP_KERNEL,
0083                       "%s hs:rt711-sdca",
0084                       card->components);
0085     if (!card->components)
0086         return -ENOMEM;
0087 
0088     ret = snd_soc_add_card_controls(card, rt711_sdca_controls,
0089                     ARRAY_SIZE(rt711_sdca_controls));
0090     if (ret) {
0091         dev_err(card->dev, "rt711-sdca controls addition failed: %d\n", ret);
0092         return ret;
0093     }
0094 
0095     ret = snd_soc_dapm_new_controls(&card->dapm, rt711_sdca_widgets,
0096                     ARRAY_SIZE(rt711_sdca_widgets));
0097     if (ret) {
0098         dev_err(card->dev, "rt711-sdca widgets addition failed: %d\n", ret);
0099         return ret;
0100     }
0101 
0102     ret = snd_soc_dapm_add_routes(&card->dapm, rt711_sdca_map,
0103                       ARRAY_SIZE(rt711_sdca_map));
0104 
0105     if (ret) {
0106         dev_err(card->dev, "rt711-sdca map addition failed: %d\n", ret);
0107         return ret;
0108     }
0109 
0110     ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
0111                      SND_JACK_HEADSET | SND_JACK_BTN_0 |
0112                      SND_JACK_BTN_1 | SND_JACK_BTN_2 |
0113                      SND_JACK_BTN_3,
0114                      &ctx->sdw_headset,
0115                      rt711_sdca_jack_pins,
0116                      ARRAY_SIZE(rt711_sdca_jack_pins));
0117     if (ret) {
0118         dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n",
0119             ret);
0120         return ret;
0121     }
0122 
0123     jack = &ctx->sdw_headset;
0124 
0125     snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
0126     snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
0127     snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
0128     snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
0129 
0130     ret = snd_soc_component_set_jack(component, jack, NULL);
0131 
0132     if (ret)
0133         dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n",
0134             ret);
0135 
0136     return ret;
0137 }
0138 
0139 int sof_sdw_rt711_sdca_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
0140 {
0141     struct mc_private *ctx = snd_soc_card_get_drvdata(card);
0142 
0143     if (!ctx->headset_codec_dev)
0144         return 0;
0145 
0146     device_remove_software_node(ctx->headset_codec_dev);
0147     put_device(ctx->headset_codec_dev);
0148 
0149     return 0;
0150 }
0151 
0152 int sof_sdw_rt711_sdca_init(struct snd_soc_card *card,
0153                 const struct snd_soc_acpi_link_adr *link,
0154                 struct snd_soc_dai_link *dai_links,
0155                 struct sof_sdw_codec_info *info,
0156                 bool playback)
0157 {
0158     struct mc_private *ctx = snd_soc_card_get_drvdata(card);
0159     struct device *sdw_dev;
0160     int ret;
0161 
0162     /*
0163      * headset should be initialized once.
0164      * Do it with dai link for playback.
0165      */
0166     if (!playback)
0167         return 0;
0168 
0169     sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
0170     if (!sdw_dev)
0171         return -EPROBE_DEFER;
0172 
0173     ret = rt711_sdca_add_codec_device_props(sdw_dev);
0174     if (ret < 0) {
0175         put_device(sdw_dev);
0176         return ret;
0177     }
0178     ctx->headset_codec_dev = sdw_dev;
0179 
0180     dai_links->init = rt711_sdca_rtd_init;
0181 
0182     return 0;
0183 }