^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * omap-abe-twl6040.c -- SoC audio for TI OMAP based boards with ABE and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * twl6040 codec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Misael Lopez Cruz <misael.lopez@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/mfd/twl6040.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <sound/jack.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "omap-dmic.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "omap-mcpdm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "../codecs/twl6040.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) SND_SOC_DAILINK_DEFS(link0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) DAILINK_COMP_ARRAY(COMP_EMPTY()),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) DAILINK_COMP_ARRAY(COMP_CODEC("twl6040-codec",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) "twl6040-legacy")),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) DAILINK_COMP_ARRAY(COMP_EMPTY()));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) SND_SOC_DAILINK_DEFS(link1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) DAILINK_COMP_ARRAY(COMP_EMPTY()),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) "dmic-hifi")),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) DAILINK_COMP_ARRAY(COMP_EMPTY()));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct abe_twl6040 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct snd_soc_card card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct snd_soc_dai_link dai_links[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int jack_detection; /* board can detect jack events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int mclk_freq; /* MCLK frequency speed for twl6040 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static struct platform_device *dmic_codec_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static int omap_abe_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct snd_soc_card *card = rtd->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int clk_id, freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) clk_id = twl6040_get_clk_id(codec_dai->component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) freq = priv->mclk_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) freq = 32768;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* set the codec mclk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) SND_SOC_CLOCK_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) printk(KERN_ERR "can't set codec system clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static const struct snd_soc_ops omap_abe_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) .hw_params = omap_abe_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static int omap_abe_dmic_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) 19200000, SND_SOC_CLOCK_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) printk(KERN_ERR "can't set DMIC cpu system clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) SND_SOC_CLOCK_OUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) printk(KERN_ERR "can't set DMIC output clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static struct snd_soc_ops omap_abe_dmic_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .hw_params = omap_abe_dmic_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* Headset jack */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static struct snd_soc_jack hs_jack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /*Headset jack detection DAPM pins */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static struct snd_soc_jack_pin hs_jack_pins[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .pin = "Headset Mic",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .mask = SND_JACK_MICROPHONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .pin = "Headset Stereophone",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) .mask = SND_JACK_HEADPHONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /* SDP4430 machine DAPM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* Outputs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) SND_SOC_DAPM_HP("Headset Stereophone", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) SND_SOC_DAPM_SPK("Earphone Spk", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) SND_SOC_DAPM_SPK("Ext Spk", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) SND_SOC_DAPM_LINE("Line Out", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) SND_SOC_DAPM_SPK("Vibrator", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /* Inputs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) SND_SOC_DAPM_MIC("Headset Mic", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) SND_SOC_DAPM_MIC("Main Handset Mic", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) SND_SOC_DAPM_MIC("Sub Handset Mic", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) SND_SOC_DAPM_LINE("Line In", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /* Digital microphones */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) SND_SOC_DAPM_MIC("Digital Mic", NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static const struct snd_soc_dapm_route audio_map[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* Routings for outputs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {"Headset Stereophone", NULL, "HSOL"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {"Headset Stereophone", NULL, "HSOR"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {"Earphone Spk", NULL, "EP"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {"Ext Spk", NULL, "HFL"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {"Ext Spk", NULL, "HFR"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {"Line Out", NULL, "AUXL"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {"Line Out", NULL, "AUXR"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {"Vibrator", NULL, "VIBRAL"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {"Vibrator", NULL, "VIBRAR"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* Routings for inputs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {"HSMIC", NULL, "Headset Mic"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {"Headset Mic", NULL, "Headset Mic Bias"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) {"MAINMIC", NULL, "Main Handset Mic"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {"Main Handset Mic", NULL, "Main Mic Bias"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {"SUBMIC", NULL, "Sub Handset Mic"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {"Sub Handset Mic", NULL, "Main Mic Bias"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {"AFML", NULL, "Line In"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {"AFMR", NULL, "Line In"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct snd_soc_card *card = rtd->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) int hs_trim;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * Configure McPDM offset cancellation based on the HSOTRIM value from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * twl6040.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) hs_trim = twl6040_get_trim_value(component, TWL6040_TRIM_HSOTRIM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) TWL6040_HSF_TRIM_RIGHT(hs_trim));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /* Headset jack detection only if it is supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (priv->jack_detection) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) SND_JACK_HEADSET, &hs_jack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) hs_jack_pins,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) ARRAY_SIZE(hs_jack_pins));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) twl6040_hs_jack_detect(component, &hs_jack, SND_JACK_HEADSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static const struct snd_soc_dapm_route dmic_audio_map[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {"DMic", NULL, "Digital Mic"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {"Digital Mic", NULL, "Digital Mic1 Bias"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) ARRAY_SIZE(dmic_audio_map));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static int omap_abe_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) struct device_node *node = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct snd_soc_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct device_node *dai_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct abe_twl6040 *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) int num_links = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (!node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) dev_err(&pdev->dev, "of node is missing.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (priv == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) card = &priv->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) card->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) card->owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) card->dapm_widgets = twl6040_dapm_widgets;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) card->num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) card->dapm_routes = audio_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) card->num_dapm_routes = ARRAY_SIZE(audio_map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (snd_soc_of_parse_card_name(card, "ti,model")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) dev_err(&pdev->dev, "Card name is not provided\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) dev_err(&pdev->dev, "Error while parsing DAPM routing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (!dai_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) dev_err(&pdev->dev, "McPDM node is not provided\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) priv->dai_links[0].name = "DMIC";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) priv->dai_links[0].stream_name = "TWL6040";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) priv->dai_links[0].cpus = link0_cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) priv->dai_links[0].num_cpus = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) priv->dai_links[0].cpus->of_node = dai_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) priv->dai_links[0].platforms = link0_platforms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) priv->dai_links[0].num_platforms = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) priv->dai_links[0].platforms->of_node = dai_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) priv->dai_links[0].codecs = link0_codecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) priv->dai_links[0].num_codecs = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) priv->dai_links[0].init = omap_abe_twl6040_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) priv->dai_links[0].ops = &omap_abe_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) dai_node = of_parse_phandle(node, "ti,dmic", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (dai_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) num_links = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) priv->dai_links[1].name = "TWL6040";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) priv->dai_links[1].stream_name = "DMIC Capture";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) priv->dai_links[1].cpus = link1_cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) priv->dai_links[1].num_cpus = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) priv->dai_links[1].cpus->of_node = dai_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) priv->dai_links[1].platforms = link1_platforms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) priv->dai_links[1].num_platforms = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) priv->dai_links[1].platforms->of_node = dai_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) priv->dai_links[1].codecs = link1_codecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) priv->dai_links[1].num_codecs = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) priv->dai_links[1].init = omap_abe_dmic_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) priv->dai_links[1].ops = &omap_abe_dmic_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) num_links = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) priv->jack_detection = of_property_read_bool(node, "ti,jack-detection");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (!priv->mclk_freq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) dev_err(&pdev->dev, "MCLK frequency not provided\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) card->fully_routed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (!priv->mclk_freq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) dev_err(&pdev->dev, "MCLK frequency missing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) card->dai_link = priv->dai_links;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) card->num_links = num_links;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) snd_soc_card_set_drvdata(card, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) ret = devm_snd_soc_register_card(&pdev->dev, card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static const struct of_device_id omap_abe_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) {.compatible = "ti,abe-twl6040", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) MODULE_DEVICE_TABLE(of, omap_abe_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) static struct platform_driver omap_abe_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .name = "omap-abe-twl6040",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .pm = &snd_soc_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .of_match_table = omap_abe_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .probe = omap_abe_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static int __init omap_abe_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (IS_ERR(dmic_codec_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) pr_err("%s: dmic-codec device registration failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return PTR_ERR(dmic_codec_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) ret = platform_driver_register(&omap_abe_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) pr_err("%s: platform driver registration failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) platform_device_unregister(dmic_codec_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) module_init(omap_abe_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) static void __exit omap_abe_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) platform_driver_unregister(&omap_abe_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) platform_device_unregister(dmic_codec_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) module_exit(omap_abe_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) MODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) MODULE_ALIAS("platform:omap-abe-twl6040");