0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/gpio/consumer.h>
0018 #include <linux/of.h>
0019 #include <linux/module.h>
0020 #include <linux/platform_device.h>
0021
0022 #include <sound/core.h>
0023 #include <sound/jack.h>
0024 #include <sound/soc.h>
0025
0026 #include "../codecs/wm8903.h"
0027
0028 #include "tegra_asoc_machine.h"
0029
0030 static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = {
0031 { .pin = "Mic Jack", .mask = SND_JACK_MICROPHONE },
0032 };
0033
0034 static unsigned int tegra_wm8903_mclk_rate(unsigned int srate)
0035 {
0036 unsigned int mclk;
0037
0038 switch (srate) {
0039 case 64000:
0040 case 88200:
0041 case 96000:
0042 mclk = 128 * srate;
0043 break;
0044 default:
0045 mclk = 256 * srate;
0046 break;
0047 }
0048
0049 while (mclk < 6000000)
0050 mclk *= 2;
0051
0052 return mclk;
0053 }
0054
0055 static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
0056 {
0057 struct tegra_machine *machine = snd_soc_card_get_drvdata(rtd->card);
0058 struct snd_soc_card *card = rtd->card;
0059 int err;
0060
0061
0062
0063
0064
0065
0066
0067 if (machine->asoc->hp_jack_gpio_active_low) {
0068 bool active_low = gpiod_is_active_low(machine->gpiod_hp_det);
0069
0070 machine->hp_jack_gpio->invert = !active_low;
0071 }
0072
0073 err = tegra_asoc_machine_init(rtd);
0074 if (err)
0075 return err;
0076
0077 if (!machine->gpiod_mic_det && machine->asoc->add_mic_jack) {
0078 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0079 struct snd_soc_component *component = codec_dai->component;
0080 int shrt = 0;
0081
0082 err = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack",
0083 SND_JACK_MICROPHONE,
0084 machine->mic_jack,
0085 tegra_wm8903_mic_jack_pins,
0086 ARRAY_SIZE(tegra_wm8903_mic_jack_pins));
0087 if (err) {
0088 dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err);
0089 return err;
0090 }
0091
0092 if (of_property_read_bool(card->dev->of_node, "nvidia,headset"))
0093 shrt = SND_JACK_MICROPHONE;
0094
0095 wm8903_mic_detect(component, machine->mic_jack,
0096 SND_JACK_MICROPHONE, shrt);
0097 }
0098
0099 snd_soc_dapm_force_enable_pin(&card->dapm, "MICBIAS");
0100
0101 return 0;
0102 }
0103
0104 static int tegra_wm8903_remove(struct snd_soc_card *card)
0105 {
0106 struct snd_soc_dai_link *link = &card->dai_link[0];
0107 struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card, link);
0108 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0109 struct snd_soc_component *component = codec_dai->component;
0110
0111 wm8903_mic_detect(component, NULL, 0, 0);
0112
0113 return 0;
0114 }
0115
0116 SND_SOC_DAILINK_DEFS(hifi,
0117 DAILINK_COMP_ARRAY(COMP_EMPTY()),
0118 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8903-hifi")),
0119 DAILINK_COMP_ARRAY(COMP_EMPTY()));
0120
0121 static struct snd_soc_dai_link tegra_wm8903_dai = {
0122 .name = "WM8903",
0123 .stream_name = "WM8903 PCM",
0124 .init = tegra_wm8903_init,
0125 .dai_fmt = SND_SOC_DAIFMT_I2S |
0126 SND_SOC_DAIFMT_NB_NF |
0127 SND_SOC_DAIFMT_CBS_CFS,
0128 SND_SOC_DAILINK_REG(hifi),
0129 };
0130
0131 static struct snd_soc_card snd_soc_tegra_wm8903 = {
0132 .components = "codec:wm8903",
0133 .owner = THIS_MODULE,
0134 .dai_link = &tegra_wm8903_dai,
0135 .num_links = 1,
0136 .remove = tegra_wm8903_remove,
0137 .fully_routed = true,
0138 };
0139
0140
0141 static const struct tegra_asoc_data tegra_wm8903_data_legacy = {
0142 .mclk_rate = tegra_wm8903_mclk_rate,
0143 .card = &snd_soc_tegra_wm8903,
0144 .hp_jack_gpio_active_low = true,
0145 .add_common_dapm_widgets = true,
0146 .add_common_controls = true,
0147 .add_common_snd_ops = true,
0148 .add_mic_jack = true,
0149 .add_hp_jack = true,
0150 };
0151
0152 static const struct tegra_asoc_data tegra_wm8903_data = {
0153 .mclk_rate = tegra_wm8903_mclk_rate,
0154 .card = &snd_soc_tegra_wm8903,
0155 .add_common_dapm_widgets = true,
0156 .add_common_controls = true,
0157 .add_common_snd_ops = true,
0158 .add_mic_jack = true,
0159 .add_hp_jack = true,
0160 };
0161
0162 static const struct of_device_id tegra_wm8903_of_match[] = {
0163 { .compatible = "ad,tegra-audio-plutux", .data = &tegra_wm8903_data_legacy },
0164 { .compatible = "ad,tegra-audio-wm8903-medcom-wide", .data = &tegra_wm8903_data_legacy },
0165 { .compatible = "ad,tegra-audio-wm8903-tec", .data = &tegra_wm8903_data_legacy },
0166 { .compatible = "nvidia,tegra-audio-wm8903-cardhu", .data = &tegra_wm8903_data_legacy },
0167 { .compatible = "nvidia,tegra-audio-wm8903-harmony", .data = &tegra_wm8903_data_legacy },
0168 { .compatible = "nvidia,tegra-audio-wm8903-picasso", .data = &tegra_wm8903_data_legacy },
0169 { .compatible = "nvidia,tegra-audio-wm8903-seaboard", .data = &tegra_wm8903_data_legacy },
0170 { .compatible = "nvidia,tegra-audio-wm8903-ventana", .data = &tegra_wm8903_data_legacy },
0171 { .compatible = "nvidia,tegra-audio-wm8903", .data = &tegra_wm8903_data },
0172 {},
0173 };
0174 MODULE_DEVICE_TABLE(of, tegra_wm8903_of_match);
0175
0176 static struct platform_driver tegra_wm8903_driver = {
0177 .driver = {
0178 .name = "tegra-wm8903",
0179 .of_match_table = tegra_wm8903_of_match,
0180 .pm = &snd_soc_pm_ops,
0181 },
0182 .probe = tegra_asoc_machine_probe,
0183 };
0184 module_platform_driver(tegra_wm8903_driver);
0185
0186 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
0187 MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver");
0188 MODULE_LICENSE("GPL");