FILE
tegra_wm8903.c
File preview with syntax highlighting.
linux-6.19.14/sound/soc/tegra/tegra_wm8903.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec. 4 * 5 * Author: Stephen Warren <swarren@nvidia.com> 6 * Copyright (C) 2010-2012 - NVIDIA, Inc. 7 * 8 * Based on code copyright/by: 9 * 10 * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. 11 * 12 * Copyright 2007 Wolfson Microelectronics PLC. 13 * Author: Graeme Gregory 14 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com 15 */ 16 17#include <linux/gpio/consumer.h> 18#include <linux/of.h> 19#include <linux/module.h> 20#include <linux/platform_device.h> 21 22#include <sound/core.h> 23#include <sound/jack.h> 24#include <sound/soc.h> 25 26#include "../codecs/wm8903.h" 27 28#include "tegra_asoc_machine.h" 29 30static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { 31 { .pin = "Mic Jack", .mask = SND_JACK_MICROPHONE }, 32}; 33 34static unsigned int tegra_wm8903_mclk_rate(unsigned int srate) 35{ 36 unsigned int mclk; 37 38 switch (srate) { 39 case 64000: 40 case 88200: 41 case 96000: 42 mclk = 128 * srate; 43 break; 44 default: 45 mclk = 256 * srate; 46 break; 47 } 48 /* FIXME: Codec only requires >= 3MHz if OSR==0 */ 49 while (mclk < 6000000) 50 mclk *= 2; 51 52 return mclk; 53} 54 55static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) 56{ 57 struct tegra_machine *machine = snd_soc_card_get_drvdata(rtd->card); 58 struct snd_soc_card *card = rtd->card; 59 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); 60 int err; 61 62 /* 63 * Older version of machine driver was ignoring GPIO polarity, 64 * forcing it to active-low. This means that all older device-trees 65 * which set the polarity to active-high are wrong and we need to fix 66 * them up. 67 */ 68 if (machine->asoc->hp_jack_gpio_active_low) { 69 bool active_low = gpiod_is_active_low(machine->gpiod_hp_det); 70 71 machine->hp_jack_gpio->invert = !active_low; 72 } 73 74 err = tegra_asoc_machine_init(rtd); 75 if (err) 76 return err; 77 78 if (!machine->gpiod_mic_det && machine->asoc->add_mic_jack) { 79 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 80 struct snd_soc_component *component = codec_dai->component; 81 int shrt = 0; 82 83 err = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", 84 SND_JACK_MICROPHONE, 85 machine->mic_jack, 86 tegra_wm8903_mic_jack_pins, 87 ARRAY_SIZE(tegra_wm8903_mic_jack_pins)); 88 if (err) { 89 dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err); 90 return err; 91 } 92 93 if (of_property_read_bool(card->dev->of_node, "nvidia,headset")) 94 shrt = SND_JACK_MICROPHONE; 95 96 wm8903_mic_detect(component, machine->mic_jack, 97 SND_JACK_MICROPHONE, shrt); 98 } 99 100 snd_soc_dapm_force_enable_pin(dapm, "MICBIAS"); 101 102 return 0; 103} 104 105static int tegra_wm8903_remove(struct snd_soc_card *card) 106{ 107 struct snd_soc_dai_link *link = &card->dai_link[0]; 108 struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card, link); 109 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 110 struct snd_soc_component *component = codec_dai->component; 111 112 wm8903_mic_detect(component, NULL, 0, 0); 113 114 return 0; 115} 116 117SND_SOC_DAILINK_DEFS(hifi, 118 DAILINK_COMP_ARRAY(COMP_EMPTY()), 119 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8903-hifi")), 120 DAILINK_COMP_ARRAY(COMP_EMPTY())); 121 122static struct snd_soc_dai_link tegra_wm8903_dai = { 123 .name = "WM8903", 124 .stream_name = "WM8903 PCM", 125 .init = tegra_wm8903_init, 126 .dai_fmt = SND_SOC_DAIFMT_I2S | 127 SND_SOC_DAIFMT_NB_NF | 128 SND_SOC_DAIFMT_CBC_CFC, 129 SND_SOC_DAILINK_REG(hifi), 130}; 131 132static struct snd_soc_card snd_soc_tegra_wm8903 = { 133 .components = "codec:wm8903", 134 .owner = THIS_MODULE, 135 .dai_link = &tegra_wm8903_dai, 136 .num_links = 1, 137 .remove = tegra_wm8903_remove, 138 .fully_routed = true, 139}; 140 141/* older device-trees used wrong polarity for the headphones-detection GPIO */ 142static const struct tegra_asoc_data tegra_wm8903_data_legacy = { 143 .mclk_rate = tegra_wm8903_mclk_rate, 144 .card = &snd_soc_tegra_wm8903, 145 .hp_jack_gpio_active_low = true, 146 .add_common_dapm_widgets = true, 147 .add_common_controls = true, 148 .add_common_snd_ops = true, 149 .add_mic_jack = true, 150 .add_hp_jack = true, 151}; 152 153static const struct tegra_asoc_data tegra_wm8903_data = { 154 .mclk_rate = tegra_wm8903_mclk_rate, 155 .card = &snd_soc_tegra_wm8903, 156 .add_common_dapm_widgets = true, 157 .add_common_controls = true, 158 .add_common_snd_ops = true, 159 .add_mic_jack = true, 160 .add_hp_jack = true, 161}; 162 163static const struct of_device_id tegra_wm8903_of_match[] = { 164 { .compatible = "ad,tegra-audio-plutux", .data = &tegra_wm8903_data_legacy }, 165 { .compatible = "ad,tegra-audio-wm8903-medcom-wide", .data = &tegra_wm8903_data_legacy }, 166 { .compatible = "ad,tegra-audio-wm8903-tec", .data = &tegra_wm8903_data_legacy }, 167 { .compatible = "nvidia,tegra-audio-wm8903-cardhu", .data = &tegra_wm8903_data_legacy }, 168 { .compatible = "nvidia,tegra-audio-wm8903-harmony", .data = &tegra_wm8903_data_legacy }, 169 { .compatible = "nvidia,tegra-audio-wm8903-picasso", .data = &tegra_wm8903_data_legacy }, 170 { .compatible = "nvidia,tegra-audio-wm8903-seaboard", .data = &tegra_wm8903_data_legacy }, 171 { .compatible = "nvidia,tegra-audio-wm8903-ventana", .data = &tegra_wm8903_data_legacy }, 172 { .compatible = "nvidia,tegra-audio-wm8903", .data = &tegra_wm8903_data }, 173 {}, 174}; 175MODULE_DEVICE_TABLE(of, tegra_wm8903_of_match); 176 177static struct platform_driver tegra_wm8903_driver = { 178 .driver = { 179 .name = "tegra-wm8903", 180 .of_match_table = tegra_wm8903_of_match, 181 .pm = &snd_soc_pm_ops, 182 }, 183 .probe = tegra_asoc_machine_probe, 184}; 185module_platform_driver(tegra_wm8903_driver); 186 187MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 188MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); 189MODULE_LICENSE("GPL");
~/
Read-only file preview.