1 // SPDX-License-Identifier: GPL-2.0-only
3 * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec.
5 * Author: Stephen Warren <swarren@nvidia.com>
6 * Copyright (C) 2010-2012 - NVIDIA, Inc.
8 * Based on code copyright/by:
10 * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
12 * Copyright 2007 Wolfson Microelectronics PLC.
13 * Author: Graeme Gregory
14 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
17 #include <linux/gpio/consumer.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
22 #include <sound/core.h>
23 #include <sound/jack.h>
24 #include <sound/soc.h>
26 #include "../codecs/wm8903.h"
28 #include "tegra_asoc_machine.h"
30 static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins
[] = {
31 { .pin
= "Mic Jack", .mask
= SND_JACK_MICROPHONE
},
34 static unsigned int tegra_wm8903_mclk_rate(unsigned int srate
)
48 /* FIXME: Codec only requires >= 3MHz if OSR==0 */
49 while (mclk
< 6000000)
55 static int tegra_wm8903_init(struct snd_soc_pcm_runtime
*rtd
)
57 struct tegra_machine
*machine
= snd_soc_card_get_drvdata(rtd
->card
);
58 struct snd_soc_card
*card
= rtd
->card
;
62 * Older version of machine driver was ignoring GPIO polarity,
63 * forcing it to active-low. This means that all older device-trees
64 * which set the polarity to active-high are wrong and we need to fix
67 if (machine
->asoc
->hp_jack_gpio_active_low
) {
68 bool active_low
= gpiod_is_active_low(machine
->gpiod_hp_det
);
70 machine
->hp_jack_gpio
->invert
= !active_low
;
73 err
= tegra_asoc_machine_init(rtd
);
77 if (!machine
->gpiod_mic_det
&& machine
->asoc
->add_mic_jack
) {
78 struct snd_soc_dai
*codec_dai
= snd_soc_rtd_to_codec(rtd
, 0);
79 struct snd_soc_component
*component
= codec_dai
->component
;
82 err
= snd_soc_card_jack_new_pins(rtd
->card
, "Mic Jack",
85 tegra_wm8903_mic_jack_pins
,
86 ARRAY_SIZE(tegra_wm8903_mic_jack_pins
));
88 dev_err(rtd
->dev
, "Mic Jack creation failed: %d\n", err
);
92 if (of_property_read_bool(card
->dev
->of_node
, "nvidia,headset"))
93 shrt
= SND_JACK_MICROPHONE
;
95 wm8903_mic_detect(component
, machine
->mic_jack
,
96 SND_JACK_MICROPHONE
, shrt
);
99 snd_soc_dapm_force_enable_pin(&card
->dapm
, "MICBIAS");
104 static int tegra_wm8903_remove(struct snd_soc_card
*card
)
106 struct snd_soc_dai_link
*link
= &card
->dai_link
[0];
107 struct snd_soc_pcm_runtime
*rtd
= snd_soc_get_pcm_runtime(card
, link
);
108 struct snd_soc_dai
*codec_dai
= snd_soc_rtd_to_codec(rtd
, 0);
109 struct snd_soc_component
*component
= codec_dai
->component
;
111 wm8903_mic_detect(component
, NULL
, 0, 0);
116 SND_SOC_DAILINK_DEFS(hifi
,
117 DAILINK_COMP_ARRAY(COMP_EMPTY()),
118 DAILINK_COMP_ARRAY(COMP_CODEC(NULL
, "wm8903-hifi")),
119 DAILINK_COMP_ARRAY(COMP_EMPTY()));
121 static struct snd_soc_dai_link tegra_wm8903_dai
= {
123 .stream_name
= "WM8903 PCM",
124 .init
= tegra_wm8903_init
,
125 .dai_fmt
= SND_SOC_DAIFMT_I2S
|
126 SND_SOC_DAIFMT_NB_NF
|
127 SND_SOC_DAIFMT_CBS_CFS
,
128 SND_SOC_DAILINK_REG(hifi
),
131 static struct snd_soc_card snd_soc_tegra_wm8903
= {
132 .components
= "codec:wm8903",
133 .owner
= THIS_MODULE
,
134 .dai_link
= &tegra_wm8903_dai
,
136 .remove
= tegra_wm8903_remove
,
137 .fully_routed
= true,
140 /* older device-trees used wrong polarity for the headphones-detection GPIO */
141 static const struct tegra_asoc_data tegra_wm8903_data_legacy
= {
142 .mclk_rate
= tegra_wm8903_mclk_rate
,
143 .card
= &snd_soc_tegra_wm8903
,
144 .hp_jack_gpio_active_low
= true,
145 .add_common_dapm_widgets
= true,
146 .add_common_controls
= true,
147 .add_common_snd_ops
= true,
148 .add_mic_jack
= true,
152 static const struct tegra_asoc_data tegra_wm8903_data
= {
153 .mclk_rate
= tegra_wm8903_mclk_rate
,
154 .card
= &snd_soc_tegra_wm8903
,
155 .add_common_dapm_widgets
= true,
156 .add_common_controls
= true,
157 .add_common_snd_ops
= true,
158 .add_mic_jack
= true,
162 static const struct of_device_id tegra_wm8903_of_match
[] = {
163 { .compatible
= "ad,tegra-audio-plutux", .data
= &tegra_wm8903_data_legacy
},
164 { .compatible
= "ad,tegra-audio-wm8903-medcom-wide", .data
= &tegra_wm8903_data_legacy
},
165 { .compatible
= "ad,tegra-audio-wm8903-tec", .data
= &tegra_wm8903_data_legacy
},
166 { .compatible
= "nvidia,tegra-audio-wm8903-cardhu", .data
= &tegra_wm8903_data_legacy
},
167 { .compatible
= "nvidia,tegra-audio-wm8903-harmony", .data
= &tegra_wm8903_data_legacy
},
168 { .compatible
= "nvidia,tegra-audio-wm8903-picasso", .data
= &tegra_wm8903_data_legacy
},
169 { .compatible
= "nvidia,tegra-audio-wm8903-seaboard", .data
= &tegra_wm8903_data_legacy
},
170 { .compatible
= "nvidia,tegra-audio-wm8903-ventana", .data
= &tegra_wm8903_data_legacy
},
171 { .compatible
= "nvidia,tegra-audio-wm8903", .data
= &tegra_wm8903_data
},
174 MODULE_DEVICE_TABLE(of
, tegra_wm8903_of_match
);
176 static struct platform_driver tegra_wm8903_driver
= {
178 .name
= "tegra-wm8903",
179 .of_match_table
= tegra_wm8903_of_match
,
180 .pm
= &snd_soc_pm_ops
,
182 .probe
= tegra_asoc_machine_probe
,
184 module_platform_driver(tegra_wm8903_driver
);
186 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
187 MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver");
188 MODULE_LICENSE("GPL");