xref: /linux/sound/soc/tegra/tegra_wm8962.c (revision a8e7ef3cec99ba2487110e01d77a8a278593b3e9)
1*536ffa10SJonas Schwöbel // SPDX-License-Identifier: GPL-2.0-only
2*536ffa10SJonas Schwöbel /*
3*536ffa10SJonas Schwöbel  * tegra_wm8962.c - Tegra machine ASoC driver for boards using WM8962 codec.
4*536ffa10SJonas Schwöbel  *
5*536ffa10SJonas Schwöbel  * Copyright (C) 2021-2024 Jonas Schwöbel <jonasschwoebel@yahoo.de>
6*536ffa10SJonas Schwöbel  *			   Svyatoslav Ryhel <clamor95@gmail.com>
7*536ffa10SJonas Schwöbel  *
8*536ffa10SJonas Schwöbel  * Based on tegra_wm8903 code copyright/by:
9*536ffa10SJonas Schwöbel  *
10*536ffa10SJonas Schwöbel  * Author: Stephen Warren <swarren@nvidia.com>
11*536ffa10SJonas Schwöbel  * Copyright (C) 2010-2012 - NVIDIA, Inc.
12*536ffa10SJonas Schwöbel  *
13*536ffa10SJonas Schwöbel  * Based on code copyright/by:
14*536ffa10SJonas Schwöbel  *
15*536ffa10SJonas Schwöbel  * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
16*536ffa10SJonas Schwöbel  *
17*536ffa10SJonas Schwöbel  * Copyright 2007 Wolfson Microelectronics PLC.
18*536ffa10SJonas Schwöbel  * Author: Graeme Gregory
19*536ffa10SJonas Schwöbel  *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
20*536ffa10SJonas Schwöbel  */
21*536ffa10SJonas Schwöbel 
22*536ffa10SJonas Schwöbel #include <linux/gpio/consumer.h>
23*536ffa10SJonas Schwöbel #include <linux/of.h>
24*536ffa10SJonas Schwöbel #include <linux/module.h>
25*536ffa10SJonas Schwöbel #include <linux/platform_device.h>
26*536ffa10SJonas Schwöbel 
27*536ffa10SJonas Schwöbel #include <sound/core.h>
28*536ffa10SJonas Schwöbel #include <sound/jack.h>
29*536ffa10SJonas Schwöbel #include <sound/soc.h>
30*536ffa10SJonas Schwöbel 
31*536ffa10SJonas Schwöbel #include "../codecs/wm8962.h"
32*536ffa10SJonas Schwöbel 
33*536ffa10SJonas Schwöbel #include "tegra_asoc_machine.h"
34*536ffa10SJonas Schwöbel 
35*536ffa10SJonas Schwöbel static struct snd_soc_jack_pin tegra_wm8962_mic_jack_pins[] = {
36*536ffa10SJonas Schwöbel 	{ .pin = "Mic Jack", .mask = SND_JACK_MICROPHONE },
37*536ffa10SJonas Schwöbel };
38*536ffa10SJonas Schwöbel 
39*536ffa10SJonas Schwöbel static unsigned int tegra_wm8962_mclk_rate(unsigned int srate)
40*536ffa10SJonas Schwöbel {
41*536ffa10SJonas Schwöbel 	unsigned int mclk;
42*536ffa10SJonas Schwöbel 
43*536ffa10SJonas Schwöbel 	switch (srate) {
44*536ffa10SJonas Schwöbel 	case 8000:
45*536ffa10SJonas Schwöbel 	case 16000:
46*536ffa10SJonas Schwöbel 	case 24000:
47*536ffa10SJonas Schwöbel 	case 32000:
48*536ffa10SJonas Schwöbel 	case 48000:
49*536ffa10SJonas Schwöbel 	case 64000:
50*536ffa10SJonas Schwöbel 	case 96000:
51*536ffa10SJonas Schwöbel 		mclk = 12288000;
52*536ffa10SJonas Schwöbel 		break;
53*536ffa10SJonas Schwöbel 	case 11025:
54*536ffa10SJonas Schwöbel 	case 22050:
55*536ffa10SJonas Schwöbel 	case 44100:
56*536ffa10SJonas Schwöbel 	case 88200:
57*536ffa10SJonas Schwöbel 		mclk = 11289600;
58*536ffa10SJonas Schwöbel 		break;
59*536ffa10SJonas Schwöbel 	default:
60*536ffa10SJonas Schwöbel 		mclk = 12000000;
61*536ffa10SJonas Schwöbel 		break;
62*536ffa10SJonas Schwöbel 	}
63*536ffa10SJonas Schwöbel 
64*536ffa10SJonas Schwöbel 	return mclk;
65*536ffa10SJonas Schwöbel }
66*536ffa10SJonas Schwöbel 
67*536ffa10SJonas Schwöbel static int tegra_wm8962_init(struct snd_soc_pcm_runtime *rtd)
68*536ffa10SJonas Schwöbel {
69*536ffa10SJonas Schwöbel 	struct tegra_machine *machine = snd_soc_card_get_drvdata(rtd->card);
70*536ffa10SJonas Schwöbel 	struct snd_soc_card *card = rtd->card;
71*536ffa10SJonas Schwöbel 	struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
72*536ffa10SJonas Schwöbel 	int err;
73*536ffa10SJonas Schwöbel 
74*536ffa10SJonas Schwöbel 	err = tegra_asoc_machine_init(rtd);
75*536ffa10SJonas Schwöbel 	if (err)
76*536ffa10SJonas Schwöbel 		return err;
77*536ffa10SJonas Schwöbel 
78*536ffa10SJonas Schwöbel 	if (!machine->gpiod_mic_det && machine->asoc->add_mic_jack) {
79*536ffa10SJonas Schwöbel 		struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
80*536ffa10SJonas Schwöbel 		struct snd_soc_component *component = codec_dai->component;
81*536ffa10SJonas Schwöbel 
82*536ffa10SJonas Schwöbel 		err = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack",
83*536ffa10SJonas Schwöbel 						 SND_JACK_MICROPHONE,
84*536ffa10SJonas Schwöbel 						 machine->mic_jack,
85*536ffa10SJonas Schwöbel 						 tegra_wm8962_mic_jack_pins,
86*536ffa10SJonas Schwöbel 						 ARRAY_SIZE(tegra_wm8962_mic_jack_pins));
87*536ffa10SJonas Schwöbel 		if (err) {
88*536ffa10SJonas Schwöbel 			dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err);
89*536ffa10SJonas Schwöbel 			return err;
90*536ffa10SJonas Schwöbel 		}
91*536ffa10SJonas Schwöbel 
92*536ffa10SJonas Schwöbel 		wm8962_mic_detect(component, machine->mic_jack);
93*536ffa10SJonas Schwöbel 	}
94*536ffa10SJonas Schwöbel 
95*536ffa10SJonas Schwöbel 	snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
96*536ffa10SJonas Schwöbel 
97*536ffa10SJonas Schwöbel 	return 0;
98*536ffa10SJonas Schwöbel }
99*536ffa10SJonas Schwöbel 
100*536ffa10SJonas Schwöbel static int tegra_wm8962_remove(struct snd_soc_card *card)
101*536ffa10SJonas Schwöbel {
102*536ffa10SJonas Schwöbel 	struct snd_soc_dai_link *link = &card->dai_link[0];
103*536ffa10SJonas Schwöbel 	struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card, link);
104*536ffa10SJonas Schwöbel 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
105*536ffa10SJonas Schwöbel 	struct snd_soc_component *component = codec_dai->component;
106*536ffa10SJonas Schwöbel 
107*536ffa10SJonas Schwöbel 	wm8962_mic_detect(component, NULL);
108*536ffa10SJonas Schwöbel 
109*536ffa10SJonas Schwöbel 	return 0;
110*536ffa10SJonas Schwöbel }
111*536ffa10SJonas Schwöbel 
112*536ffa10SJonas Schwöbel SND_SOC_DAILINK_DEFS(wm8962_hifi,
113*536ffa10SJonas Schwöbel 	DAILINK_COMP_ARRAY(COMP_EMPTY()),
114*536ffa10SJonas Schwöbel 	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8962")),
115*536ffa10SJonas Schwöbel 	DAILINK_COMP_ARRAY(COMP_EMPTY()));
116*536ffa10SJonas Schwöbel 
117*536ffa10SJonas Schwöbel static struct snd_soc_dai_link tegra_wm8962_dai = {
118*536ffa10SJonas Schwöbel 	.name = "WM8962",
119*536ffa10SJonas Schwöbel 	.stream_name = "WM8962 PCM",
120*536ffa10SJonas Schwöbel 	.init = tegra_wm8962_init,
121*536ffa10SJonas Schwöbel 	.dai_fmt = SND_SOC_DAIFMT_I2S |
122*536ffa10SJonas Schwöbel 		   SND_SOC_DAIFMT_NB_NF |
123*536ffa10SJonas Schwöbel 		   SND_SOC_DAIFMT_CBC_CFC,
124*536ffa10SJonas Schwöbel 	SND_SOC_DAILINK_REG(wm8962_hifi),
125*536ffa10SJonas Schwöbel };
126*536ffa10SJonas Schwöbel 
127*536ffa10SJonas Schwöbel static struct snd_soc_card snd_soc_tegra_wm8962 = {
128*536ffa10SJonas Schwöbel 	.components = "codec:wm8962",
129*536ffa10SJonas Schwöbel 	.owner = THIS_MODULE,
130*536ffa10SJonas Schwöbel 	.dai_link = &tegra_wm8962_dai,
131*536ffa10SJonas Schwöbel 	.num_links = 1,
132*536ffa10SJonas Schwöbel 	.remove = tegra_wm8962_remove,
133*536ffa10SJonas Schwöbel 	.fully_routed = true,
134*536ffa10SJonas Schwöbel };
135*536ffa10SJonas Schwöbel 
136*536ffa10SJonas Schwöbel static const struct tegra_asoc_data tegra_wm8962_data = {
137*536ffa10SJonas Schwöbel 	.mclk_rate = tegra_wm8962_mclk_rate,
138*536ffa10SJonas Schwöbel 	.card = &snd_soc_tegra_wm8962,
139*536ffa10SJonas Schwöbel 	.add_common_dapm_widgets = true,
140*536ffa10SJonas Schwöbel 	.add_common_controls = true,
141*536ffa10SJonas Schwöbel 	.add_common_snd_ops = true,
142*536ffa10SJonas Schwöbel 	.add_mic_jack = true,
143*536ffa10SJonas Schwöbel 	.add_hp_jack = true,
144*536ffa10SJonas Schwöbel };
145*536ffa10SJonas Schwöbel 
146*536ffa10SJonas Schwöbel static const struct of_device_id tegra_wm8962_of_match[] = {
147*536ffa10SJonas Schwöbel 	{ .compatible = "nvidia,tegra-audio-wm8962", .data = &tegra_wm8962_data },
148*536ffa10SJonas Schwöbel 	{},
149*536ffa10SJonas Schwöbel };
150*536ffa10SJonas Schwöbel MODULE_DEVICE_TABLE(of, tegra_wm8962_of_match);
151*536ffa10SJonas Schwöbel 
152*536ffa10SJonas Schwöbel static struct platform_driver tegra_wm8962_driver = {
153*536ffa10SJonas Schwöbel 	.driver = {
154*536ffa10SJonas Schwöbel 		.name = "tegra-wm8962",
155*536ffa10SJonas Schwöbel 		.of_match_table = tegra_wm8962_of_match,
156*536ffa10SJonas Schwöbel 		.pm = &snd_soc_pm_ops,
157*536ffa10SJonas Schwöbel 	},
158*536ffa10SJonas Schwöbel 	.probe = tegra_asoc_machine_probe,
159*536ffa10SJonas Schwöbel };
160*536ffa10SJonas Schwöbel module_platform_driver(tegra_wm8962_driver);
161*536ffa10SJonas Schwöbel 
162*536ffa10SJonas Schwöbel MODULE_AUTHOR("Jonas Schwöbel <jonasschwoebel@yahoo.de>");
163*536ffa10SJonas Schwöbel MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
164*536ffa10SJonas Schwöbel MODULE_DESCRIPTION("Tegra+WM8962 machine ASoC driver");
165*536ffa10SJonas Schwöbel MODULE_LICENSE("GPL");
166