Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1// SPDX-License-Identifier: GPL-2.0-only
  2// Copyright (c) 2023 Intel Corporation
  3
  4/*
  5 *  sof_sdw_cs42l42 - Helpers to handle CS42L42 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/control.h>
 14#include <sound/soc.h>
 15#include <sound/soc-acpi.h>
 16#include <sound/soc-dapm.h>
 17#include <sound/jack.h>
 18#include "sof_sdw_common.h"
 19
 20static const struct snd_soc_dapm_widget cs42l42_widgets[] = {
 21	SND_SOC_DAPM_HP("Headphone", NULL),
 22	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 23};
 24
 25static const struct snd_soc_dapm_route cs42l42_map[] = {
 26	/* HP jack connectors - unknown if we have jack detection */
 27	{"Headphone", NULL, "cs42l42 HP"},
 28
 29	/* other jacks */
 30	{"cs42l42 HS", NULL, "Headset Mic"},
 31};
 32
 33static const struct snd_kcontrol_new cs42l42_controls[] = {
 34	SOC_DAPM_PIN_SWITCH("Headphone"),
 35	SOC_DAPM_PIN_SWITCH("Headset Mic"),
 36};
 37
 38static struct snd_soc_jack_pin cs42l42_jack_pins[] = {
 39	{
 40		.pin    = "Headphone",
 41		.mask   = SND_JACK_HEADPHONE,
 42	},
 43	{
 44		.pin    = "Headset Mic",
 45		.mask   = SND_JACK_MICROPHONE,
 46	},
 47};
 48
 49static int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd)
 50{
 51	struct snd_soc_card *card = rtd->card;
 52	struct mc_private *ctx = snd_soc_card_get_drvdata(card);
 53	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
 54	struct snd_soc_component *component = codec_dai->component;
 55	struct snd_soc_jack *jack;
 56	int ret;
 57
 58	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
 59					  "%s hs:cs42l42",
 60					  card->components);
 61	if (!card->components)
 62		return -ENOMEM;
 63
 64	ret = snd_soc_add_card_controls(card, cs42l42_controls,
 65					ARRAY_SIZE(cs42l42_controls));
 66	if (ret) {
 67		dev_err(card->dev, "cs42l42 control addition failed: %d\n", ret);
 68		return ret;
 69	}
 70
 71	ret = snd_soc_dapm_new_controls(&card->dapm, cs42l42_widgets,
 72					ARRAY_SIZE(cs42l42_widgets));
 73	if (ret) {
 74		dev_err(card->dev, "cs42l42 widgets addition failed: %d\n", ret);
 75		return ret;
 76	}
 77
 78	ret = snd_soc_dapm_add_routes(&card->dapm, cs42l42_map,
 79				      ARRAY_SIZE(cs42l42_map));
 80
 81	if (ret) {
 82		dev_err(card->dev, "cs42l42 map addition failed: %d\n", ret);
 83		return ret;
 84	}
 85
 86	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
 87					 SND_JACK_HEADSET | SND_JACK_BTN_0 |
 88					 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
 89					 SND_JACK_BTN_3,
 90					 &ctx->sdw_headset,
 91					 cs42l42_jack_pins,
 92					 ARRAY_SIZE(cs42l42_jack_pins));
 93	if (ret) {
 94		dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n",
 95			ret);
 96		return ret;
 97	}
 98
 99	jack = &ctx->sdw_headset;
100
101	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
102	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
103	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
104	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
105
106	ret = snd_soc_component_set_jack(component, jack, NULL);
107
108	if (ret)
109		dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n",
110			ret);
111
112	return ret;
113}
114
115int sof_sdw_cs42l42_init(struct snd_soc_card *card,
116			 const struct snd_soc_acpi_link_adr *link,
117			 struct snd_soc_dai_link *dai_links,
118			 struct sof_sdw_codec_info *info,
119			 bool playback)
120{
121	/*
122	 * headset should be initialized once.
123	 * Do it with dai link for playback.
124	 */
125	if (!playback)
126		return 0;
127
128	dai_links->init = cs42l42_rtd_init;
129
130	return 0;
131}