|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | +// Copyright (c) 2020 Intel Corporation |
| 3 | + |
| 4 | +/* |
| 5 | + * sof_sdw_rt5682 - Helpers to handle RT5682 from generic machine driver |
| 6 | + */ |
| 7 | + |
| 8 | +#include <linux/device.h> |
| 9 | +#include <linux/errno.h> |
| 10 | +#include <linux/input.h> |
| 11 | +#include <linux/soundwire/sdw.h> |
| 12 | +#include <linux/soundwire/sdw_type.h> |
| 13 | +#include <sound/soc.h> |
| 14 | +#include <sound/soc-acpi.h> |
| 15 | +#include <sound/jack.h> |
| 16 | +#include "sof_sdw_common.h" |
| 17 | + |
| 18 | +static const struct snd_soc_dapm_widget rt5682_widgets[] = { |
| 19 | + SND_SOC_DAPM_HP("Headphone", NULL), |
| 20 | + SND_SOC_DAPM_MIC("Headset Mic", NULL), |
| 21 | +}; |
| 22 | + |
| 23 | +static const struct snd_soc_dapm_route rt5682_map[] = { |
| 24 | + /*Headphones*/ |
| 25 | + { "Headphone", NULL, "rt5682 HPOL" }, |
| 26 | + { "Headphone", NULL, "rt5682 HPOR" }, |
| 27 | + { "rt5682 IN1P", NULL, "Headset Mic" }, |
| 28 | +}; |
| 29 | + |
| 30 | +static const struct snd_kcontrol_new rt5682_controls[] = { |
| 31 | + SOC_DAPM_PIN_SWITCH("Headphone"), |
| 32 | + SOC_DAPM_PIN_SWITCH("Headset Mic"), |
| 33 | +}; |
| 34 | + |
| 35 | +static struct snd_soc_jack_pin rt5682_jack_pins[] = { |
| 36 | + { |
| 37 | + .pin = "Headphone", |
| 38 | + .mask = SND_JACK_HEADPHONE, |
| 39 | + }, |
| 40 | + { |
| 41 | + .pin = "Headset Mic", |
| 42 | + .mask = SND_JACK_MICROPHONE, |
| 43 | + }, |
| 44 | +}; |
| 45 | + |
| 46 | +static int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd) |
| 47 | +{ |
| 48 | + struct snd_soc_card *card = rtd->card; |
| 49 | + struct mc_private *ctx = snd_soc_card_get_drvdata(card); |
| 50 | + struct snd_soc_component *component = rtd->codec_dai->component; |
| 51 | + struct snd_soc_jack *jack; |
| 52 | + int ret; |
| 53 | + |
| 54 | + card->components = devm_kasprintf(card->dev, GFP_KERNEL, |
| 55 | + "%s hs:rt5682", |
| 56 | + card->components); |
| 57 | + if (!card->components) |
| 58 | + return -ENOMEM; |
| 59 | + |
| 60 | + ret = snd_soc_add_card_controls(card, rt5682_controls, |
| 61 | + ARRAY_SIZE(rt5682_controls)); |
| 62 | + if (ret) { |
| 63 | + dev_err(card->dev, "rt5682 control addition failed: %d\n", ret); |
| 64 | + return ret; |
| 65 | + } |
| 66 | + |
| 67 | + ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets, |
| 68 | + ARRAY_SIZE(rt5682_widgets)); |
| 69 | + if (ret) { |
| 70 | + dev_err(card->dev, "rt5682 widgets addition failed: %d\n", ret); |
| 71 | + return ret; |
| 72 | + } |
| 73 | + |
| 74 | + ret = snd_soc_dapm_add_routes(&card->dapm, rt5682_map, |
| 75 | + ARRAY_SIZE(rt5682_map)); |
| 76 | + |
| 77 | + if (ret) { |
| 78 | + dev_err(card->dev, "rt5682 map addition failed: %d\n", ret); |
| 79 | + return ret; |
| 80 | + } |
| 81 | + |
| 82 | + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", |
| 83 | + SND_JACK_HEADSET | SND_JACK_BTN_0 | |
| 84 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | |
| 85 | + SND_JACK_BTN_3, |
| 86 | + &ctx->sdw_headset, |
| 87 | + rt5682_jack_pins, |
| 88 | + ARRAY_SIZE(rt5682_jack_pins)); |
| 89 | + if (ret) { |
| 90 | + dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", |
| 91 | + ret); |
| 92 | + return ret; |
| 93 | + } |
| 94 | + |
| 95 | + jack = &ctx->sdw_headset; |
| 96 | + |
| 97 | + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); |
| 98 | + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); |
| 99 | + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); |
| 100 | + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); |
| 101 | + |
| 102 | + ret = snd_soc_component_set_jack(component, jack, NULL); |
| 103 | + |
| 104 | + if (ret) |
| 105 | + dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", |
| 106 | + ret); |
| 107 | + |
| 108 | + return ret; |
| 109 | +} |
| 110 | + |
| 111 | +int sof_sdw_rt5682_init(const struct snd_soc_acpi_link_adr *link, |
| 112 | + struct snd_soc_dai_link *dai_links, |
| 113 | + struct sof_sdw_codec_info *info, |
| 114 | + bool playback) |
| 115 | +{ |
| 116 | + /* |
| 117 | + * headset should be initialized once. |
| 118 | + * Do it with dai link for playback. |
| 119 | + */ |
| 120 | + if (!playback) |
| 121 | + return 0; |
| 122 | + |
| 123 | + dai_links->init = rt5682_rtd_init; |
| 124 | + |
| 125 | + return 0; |
| 126 | +} |
0 commit comments