2 * tegra210_dmic_alt.c - Tegra210 DMIC driver
4 * Copyright (c) 2014-2017 NVIDIA CORPORATION. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <linux/clk.h>
19 #include <linux/device.h>
21 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 #include <linux/pm_runtime.h>
25 #include <linux/regmap.h>
26 #include <linux/slab.h>
27 #include <soc/tegra/chip-id.h>
28 #include <sound/core.h>
29 #include <sound/pcm.h>
30 #include <sound/pcm_params.h>
31 #include <sound/soc.h>
32 #include <linux/of_device.h>
33 #include <linux/debugfs.h>
34 #include <linux/pinctrl/consumer.h>
35 #include <linux/pinctrl/pinconf-tegra.h>
37 #include "tegra210_xbar_alt.h"
38 #include "tegra210_dmic_alt.h"
39 #include "ahub_unit_fpga_clock.h"
41 #define DRV_NAME "tegra210-dmic"
43 static const struct reg_default tegra210_dmic_reg_defaults[] = {
44 { TEGRA210_DMIC_TX_INT_MASK, 0x00000001},
45 { TEGRA210_DMIC_TX_CIF_CTRL, 0x00007700},
46 { TEGRA210_DMIC_CG, 0x1},
47 { TEGRA210_DMIC_CTRL, 0x00000301},
48 { TEGRA210_DMIC_DCR_FILTER_GAIN, 0x00800000},
49 { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_0, 0x00800000},
50 { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_1, 0xff800000},
51 { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_3, 0xff800347},
52 { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, 0xffc0ff97},
53 { TEGRA210_DMIC_LP_FILTER_GAIN, 0x004c255a},
54 { TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, 0x00800000},
55 { TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, 0x00ffa74b},
56 { TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, 0x00800000},
57 { TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, 0x009e382a},
58 { TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, 0x00380f38},
59 { TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, 0x00800000},
60 { TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, 0x00fe1178},
61 { TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, 0x00800000},
62 { TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, 0x00e05f02},
63 { TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x006fc80d},
64 { TEGRA210_DMIC_CORRECTION_FILTER_GAIN, 0x010628f6},
65 { TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_0, 0x00800000},
66 { TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_3, 0x0067ffff},
67 { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_0, 0x00800000},
68 { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_1, 0x0048f5c2},
69 { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_3, 0x00562394},
70 { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4, 0x00169446},
73 static int tegra210_dmic_runtime_suspend(struct device *dev)
75 struct tegra210_dmic *dmic = dev_get_drvdata(dev);
78 regcache_cache_only(dmic->regmap, true);
79 regcache_mark_dirty(dmic->regmap);
81 if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
82 if (!IS_ERR(dmic->pin_idle_state) && dmic->is_pinctrl) {
83 ret = pinctrl_select_state(
84 dmic->pinctrl, dmic->pin_idle_state);
87 "setting dap pinctrl idle state failed\n");
90 clk_disable_unprepare(dmic->clk_dmic);
96 static int tegra210_dmic_runtime_resume(struct device *dev)
98 struct tegra210_dmic *dmic = dev_get_drvdata(dev);
101 if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
102 if (!IS_ERR(dmic->pin_active_state) && dmic->is_pinctrl) {
103 ret = pinctrl_select_state(dmic->pinctrl,
104 dmic->pin_active_state);
107 "setting dap pinctrl active state failed\n");
110 ret = clk_prepare_enable(dmic->clk_dmic);
112 dev_err(dev, "clk_enable failed: %d\n", ret);
117 regcache_cache_only(dmic->regmap, false);
119 if (!dmic->is_shutdown)
120 regcache_sync(dmic->regmap);
125 #ifdef CONFIG_PM_SLEEP
126 static int tegra210_dmic_suspend(struct device *dev)
128 if (pm_runtime_status_suspended(dev))
131 return tegra210_dmic_runtime_suspend(dev);
134 static int tegra210_dmic_resume(struct device *dev)
136 if (pm_runtime_status_suspended(dev))
139 return tegra210_dmic_runtime_resume(dev);
143 static int tegra210_dmic_set_dai_bclk_ratio(struct snd_soc_dai *dai,
149 static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
150 struct snd_pcm_hw_params *params,
151 struct snd_soc_dai *dai)
153 struct device *dev = dai->dev;
154 struct tegra210_dmic *dmic = snd_soc_dai_get_drvdata(dai);
155 int channels, srate, dmic_clk, osr = TEGRA210_DMIC_OSR_64, ret;
156 struct tegra210_xbar_cif_conf cif_conf;
157 unsigned long long boost_gain;
160 memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
162 srate = params_rate(params);
163 dmic_clk = (1 << (6+osr)) * srate;
165 if (dmic->ch_select == DMIC_CH_SELECT_NONE) {
167 channel_select = DMIC_CH_SELECT_STEREO;
170 channel_select = dmic->ch_select;
173 cif_conf.client_channels = channels;
174 cif_conf.audio_channels = channels;
176 /* For capture path, the mono input from client channel
177 * can be converted to stereo with cif controls.
179 if (dmic->tx_mono_to_stereo > 0) {
180 cif_conf.mono_conv = dmic->tx_mono_to_stereo - 1;
181 cif_conf.audio_channels = 2;
184 if ((tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
186 program_dmic_clk(dmic_clk);
188 ret = clk_set_rate(dmic->clk_dmic, dmic_clk);
190 dev_err(dev, "Can't set dmic clock rate: %d\n", ret);
195 regmap_update_bits(dmic->regmap,
197 TEGRA210_DMIC_CTRL_OSR_MASK,
198 osr << TEGRA210_DMIC_CTRL_OSR_SHIFT);
200 regmap_update_bits(dmic->regmap,
201 TEGRA210_DMIC_DBG_CTRL,
202 TEGRA210_DMIC_DBG_CTRL_SC_ENABLE,
203 TEGRA210_DMIC_DBG_CTRL_SC_ENABLE);
205 regmap_update_bits(dmic->regmap,
206 TEGRA210_DMIC_DBG_CTRL,
207 TEGRA210_DMIC_DBG_CTRL_DCR_ENABLE,
208 TEGRA210_DMIC_DBG_CTRL_DCR_ENABLE);
210 regmap_update_bits(dmic->regmap,
212 TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK,
214 TEGRA210_DMIC_CTRL_CHANNEL_SELECT_SHIFT);
216 /* Configure LPF for passthrough and use */
217 /* its gain register for applying boost; */
218 /* Boost Gain control has 100x factor */
219 boost_gain = 0x00800000;
220 if (dmic->boost_gain > 0) {
221 boost_gain = ((boost_gain * dmic->boost_gain) / 100);
222 if (boost_gain > 0x7FFFFFFF) {
223 dev_warn(dev, "Boost Gain overflow\n");
224 boost_gain = 0x7FFFFFFF;
227 regmap_write(dmic->regmap,
228 TEGRA210_DMIC_LP_FILTER_GAIN,
229 (unsigned int)boost_gain);
231 regmap_update_bits(dmic->regmap,
232 TEGRA210_DMIC_DBG_CTRL,
233 TEGRA210_DMIC_DBG_CTRL_LP_ENABLE,
234 TEGRA210_DMIC_DBG_CTRL_LP_ENABLE);
236 /* Configure the two biquads for passthrough, */
237 /* i.e. b0=1, b1=0, b2=0, a1=0, a2=0 */
238 regmap_write(dmic->regmap,
239 TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, 0x00800000);
240 regmap_write(dmic->regmap,
241 TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, 0x00000000);
242 regmap_write(dmic->regmap,
243 TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, 0x00000000);
244 regmap_write(dmic->regmap,
245 TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, 0x00000000);
246 regmap_write(dmic->regmap,
247 TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, 0x00000000);
248 regmap_write(dmic->regmap,
249 TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, 0x00800000);
250 regmap_write(dmic->regmap,
251 TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, 0x00000000);
252 regmap_write(dmic->regmap,
253 TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, 0x00000000);
254 regmap_write(dmic->regmap,
255 TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, 0x00000000);
256 regmap_write(dmic->regmap,
257 TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x00000000);
259 switch (params_format(params)) {
260 case SNDRV_PCM_FORMAT_S16_LE:
261 cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16;
263 case SNDRV_PCM_FORMAT_S32_LE:
264 cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32;
267 dev_err(dev, "Wrong format!\n");
271 cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_24;
273 dmic->soc_data->set_audio_cif(dmic->regmap, TEGRA210_DMIC_TX_CIF_CTRL,
279 static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol,
280 struct snd_ctl_elem_value *ucontrol)
282 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
283 struct tegra210_dmic *dmic = snd_soc_codec_get_drvdata(codec);
285 if (strstr(kcontrol->id.name, "Boost"))
286 ucontrol->value.integer.value[0] = dmic->boost_gain;
287 else if (strstr(kcontrol->id.name, "Mono"))
288 ucontrol->value.integer.value[0] = dmic->ch_select;
289 else if (strstr(kcontrol->id.name, "TX mono to stereo"))
290 ucontrol->value.integer.value[0] =
291 dmic->tx_mono_to_stereo;
296 static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol,
297 struct snd_ctl_elem_value *ucontrol)
299 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
300 struct tegra210_dmic *dmic = snd_soc_codec_get_drvdata(codec);
301 int value = ucontrol->value.integer.value[0];
303 if (strstr(kcontrol->id.name, "Boost"))
304 dmic->boost_gain = value;
305 else if (strstr(kcontrol->id.name, "Mono"))
306 dmic->ch_select = ucontrol->value.integer.value[0];
307 else if (strstr(kcontrol->id.name, "TX mono to stereo"))
308 dmic->tx_mono_to_stereo = value;
313 static int tegra210_dmic_codec_probe(struct snd_soc_codec *codec)
315 struct tegra210_dmic *dmic = snd_soc_codec_get_drvdata(codec);
317 codec->control_data = dmic->regmap;
322 static struct snd_soc_dai_ops tegra210_dmic_dai_ops = {
323 .hw_params = tegra210_dmic_hw_params,
324 .set_bclk_ratio = tegra210_dmic_set_dai_bclk_ratio,
327 static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
331 .stream_name = "DMIC Transmit",
334 .rates = SNDRV_PCM_RATE_8000_48000,
335 .formats = SNDRV_PCM_FMTBIT_S16_LE,
337 .ops = &tegra210_dmic_dai_ops,
338 .symmetric_rates = 1,
343 .stream_name = "DMIC Receive",
346 .rates = SNDRV_PCM_RATE_8000_48000,
347 .formats = SNDRV_PCM_FMTBIT_S16_LE,
349 .ops = &tegra210_dmic_dai_ops,
350 .symmetric_rates = 1,
354 static const struct snd_soc_dapm_widget tegra210_dmic_widgets[] = {
355 SND_SOC_DAPM_AIF_OUT("DMIC TX", NULL, 0, SND_SOC_NOPM,
357 SND_SOC_DAPM_AIF_IN("DMIC RX", NULL, 0, TEGRA210_DMIC_ENABLE,
358 TEGRA210_DMIC_ENABLE_EN_SHIFT, 0),
361 static const struct snd_soc_dapm_route tegra210_dmic_routes[] = {
362 { "DMIC RX", NULL, "DMIC Receive" },
363 { "DMIC TX", NULL, "DMIC RX" },
364 { "DMIC Transmit", NULL, "DMIC TX" },
367 static const char * const tegra210_dmic_ch_select[] = {
371 static const struct soc_enum tegra210_dmic_ch_enum =
372 SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
373 ARRAY_SIZE(tegra210_dmic_ch_select),
374 tegra210_dmic_ch_select);
376 static const char * const tegra210_dmic_mono_conv_text[] = {
377 "None", "ZERO", "COPY",
380 static const struct soc_enum tegra210_dmic_mono_conv_enum =
381 SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
382 ARRAY_SIZE(tegra210_dmic_mono_conv_text),
383 tegra210_dmic_mono_conv_text);
385 static const struct snd_kcontrol_new tegra210_dmic_controls[] = {
386 SOC_SINGLE_EXT("Boost Gain", 0, 0, 25600, 0,
387 tegra210_dmic_get_control, tegra210_dmic_put_control),
388 SOC_ENUM_EXT("Mono Channel Select", tegra210_dmic_ch_enum,
389 tegra210_dmic_get_control, tegra210_dmic_put_control),
390 SOC_ENUM_EXT("TX mono to stereo conv", tegra210_dmic_mono_conv_enum,
391 tegra210_dmic_get_control, tegra210_dmic_put_control),
394 static struct snd_soc_codec_driver tegra210_dmic_codec = {
395 .probe = tegra210_dmic_codec_probe,
396 .dapm_widgets = tegra210_dmic_widgets,
397 .num_dapm_widgets = ARRAY_SIZE(tegra210_dmic_widgets),
398 .dapm_routes = tegra210_dmic_routes,
399 .num_dapm_routes = ARRAY_SIZE(tegra210_dmic_routes),
400 .controls = tegra210_dmic_controls,
401 .num_controls = ARRAY_SIZE(tegra210_dmic_controls),
405 /* Regmap callback functions */
406 static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg)
409 case TEGRA210_DMIC_TX_INT_MASK:
410 case TEGRA210_DMIC_TX_INT_SET:
411 case TEGRA210_DMIC_TX_INT_CLEAR:
412 case TEGRA210_DMIC_TX_CIF_CTRL:
414 case TEGRA210_DMIC_ENABLE:
415 case TEGRA210_DMIC_SOFT_RESET:
416 case TEGRA210_DMIC_CG:
417 case TEGRA210_DMIC_CTRL:
420 if (((reg % 4) == 0) && (reg >= TEGRA210_DMIC_DBG_CTRL) &&
421 (reg <= TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4))
428 static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg)
431 case TEGRA210_DMIC_TX_STATUS:
432 case TEGRA210_DMIC_TX_INT_STATUS:
433 case TEGRA210_DMIC_TX_INT_MASK:
434 case TEGRA210_DMIC_TX_INT_SET:
435 case TEGRA210_DMIC_TX_INT_CLEAR:
436 case TEGRA210_DMIC_TX_CIF_CTRL:
438 case TEGRA210_DMIC_ENABLE:
439 case TEGRA210_DMIC_SOFT_RESET:
440 case TEGRA210_DMIC_CG:
441 case TEGRA210_DMIC_STATUS:
442 case TEGRA210_DMIC_INT_STATUS:
443 case TEGRA210_DMIC_CTRL:
446 if (((reg % 4) == 0) && (reg >= TEGRA210_DMIC_DBG_CTRL) &&
447 (reg <= TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4))
454 static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg)
457 case TEGRA210_DMIC_TX_STATUS:
458 case TEGRA210_DMIC_TX_INT_STATUS:
459 case TEGRA210_DMIC_TX_INT_SET:
461 case TEGRA210_DMIC_SOFT_RESET:
462 case TEGRA210_DMIC_STATUS:
463 case TEGRA210_DMIC_INT_STATUS:
470 static const struct regmap_config tegra210_dmic_regmap_config = {
474 .max_register = TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4,
475 .writeable_reg = tegra210_dmic_wr_reg,
476 .readable_reg = tegra210_dmic_rd_reg,
477 .volatile_reg = tegra210_dmic_volatile_reg,
478 .precious_reg = NULL,
479 .reg_defaults = tegra210_dmic_reg_defaults,
480 .num_reg_defaults = ARRAY_SIZE(tegra210_dmic_reg_defaults),
481 .cache_type = REGCACHE_FLAT,
484 static const struct tegra210_dmic_soc_data soc_data_tegra210 = {
485 .set_audio_cif = tegra210_xbar_set_cif,
488 static const struct of_device_id tegra210_dmic_of_match[] = {
489 { .compatible = "nvidia,tegra210-dmic", .data = &soc_data_tegra210 },
493 static int tegra210_dmic_platform_probe(struct platform_device *pdev)
495 struct tegra210_dmic *dmic;
496 struct device_node *np = pdev->dev.of_node;
497 struct resource *mem, *memregion;
500 const struct of_device_id *match;
501 struct tegra210_dmic_soc_data *soc_data;
502 const char *prod_name;
504 match = of_match_device(tegra210_dmic_of_match, &pdev->dev);
506 dev_err(&pdev->dev, "Error: No device match found\n");
510 soc_data = (struct tegra210_dmic_soc_data *)match->data;
512 dmic = devm_kzalloc(&pdev->dev, sizeof(struct tegra210_dmic), GFP_KERNEL);
514 dev_err(&pdev->dev, "Can't allocate dmic\n");
519 dmic->soc_data = soc_data;
520 dmic->is_shutdown = false;
522 if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
523 dmic->clk_dmic = devm_clk_get(&pdev->dev, NULL);
524 if (IS_ERR(dmic->clk_dmic)) {
525 dev_err(&pdev->dev, "Can't retrieve dmic clock\n");
526 ret = PTR_ERR(dmic->clk_dmic);
529 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
530 dmic->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
532 dmic->clk_pll_a_out0 = devm_clk_get(&pdev->dev, "pll_a_out0");
534 if (IS_ERR_OR_NULL(dmic->clk_pll_a_out0)) {
535 dev_err(&pdev->dev, "Can't retrieve pll_a_out0 clock\n");
540 ret = clk_set_parent(dmic->clk_dmic, dmic->clk_pll_a_out0);
542 dev_err(&pdev->dev, "Can't set parent of dmic clock\n");
543 goto err_plla_clk_put;
547 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
549 dev_err(&pdev->dev, "No memory resource\n");
551 goto err_plla_clk_put;
554 memregion = devm_request_mem_region(&pdev->dev, mem->start,
555 resource_size(mem), pdev->name);
557 dev_err(&pdev->dev, "Memory region already claimed\n");
559 goto err_plla_clk_put;
562 regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
564 dev_err(&pdev->dev, "ioremap failed\n");
566 goto err_plla_clk_put;
569 dmic->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
570 &tegra210_dmic_regmap_config);
571 if (IS_ERR(dmic->regmap)) {
572 dev_err(&pdev->dev, "regmap init failed\n");
573 ret = PTR_ERR(dmic->regmap);
574 goto err_plla_clk_put;
576 regcache_cache_only(dmic->regmap, true);
578 /* Below patch is as per latest POR value */
579 regmap_write(dmic->regmap,
580 TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, 0x00000000);
582 if (of_property_read_u32(np, "nvidia,ahub-dmic-id",
583 &pdev->dev.id) < 0) {
585 "Missing property nvidia,ahub-dmic-id\n");
587 goto err_plla_clk_put;
590 pm_runtime_enable(&pdev->dev);
591 if (!pm_runtime_enabled(&pdev->dev)) {
592 ret = tegra210_dmic_runtime_resume(&pdev->dev);
597 ret = snd_soc_register_codec(&pdev->dev, &tegra210_dmic_codec,
599 ARRAY_SIZE(tegra210_dmic_dais));
601 dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
605 if (of_property_read_string(np, "prod-name", &prod_name) == 0) {
606 ret = tegra_pinctrl_config_prod(&pdev->dev, prod_name);
608 dev_warn(&pdev->dev, "Failed to set %s setting\n",
612 if (of_property_read_u32(np, "nvidia,is-pinctrl",
613 &dmic->is_pinctrl) < 0)
614 dmic->is_pinctrl = 0;
616 if (dmic->is_pinctrl) {
617 dmic->pinctrl = devm_pinctrl_get(&pdev->dev);
618 if (IS_ERR(dmic->pinctrl)) {
619 dev_warn(&pdev->dev, "Missing pinctrl device\n");
623 dmic->pin_active_state = pinctrl_lookup_state(dmic->pinctrl,
625 if (IS_ERR(dmic->pin_active_state)) {
626 dev_warn(&pdev->dev, "Missing dap-active state\n");
630 dmic->pin_idle_state = pinctrl_lookup_state(dmic->pinctrl,
632 if (IS_ERR(dmic->pin_idle_state)) {
633 dev_warn(&pdev->dev, "Missing dap-inactive state\n");
637 ret = pinctrl_select_state(dmic->pinctrl, dmic->pin_idle_state);
639 dev_err(&pdev->dev, "setting state failed\n");
645 dev_set_drvdata(&pdev->dev, dmic);
650 if (!pm_runtime_status_suspended(&pdev->dev))
651 tegra210_dmic_runtime_suspend(&pdev->dev);
653 pm_runtime_disable(&pdev->dev);
655 devm_clk_put(&pdev->dev, dmic->clk_pll_a_out0);
657 if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga()))
658 devm_clk_put(&pdev->dev, dmic->clk_dmic);
663 static void tegra210_dmic_platform_shutdown(struct platform_device *pdev)
665 struct tegra210_dmic *dmic = dev_get_drvdata(&pdev->dev);
667 dmic->is_shutdown = true;
670 static int tegra210_dmic_platform_remove(struct platform_device *pdev)
672 struct tegra210_dmic *dmic;
674 dmic = dev_get_drvdata(&pdev->dev);
675 snd_soc_unregister_codec(&pdev->dev);
677 pm_runtime_disable(&pdev->dev);
678 if (!pm_runtime_status_suspended(&pdev->dev))
679 tegra210_dmic_runtime_suspend(&pdev->dev);
681 devm_clk_put(&pdev->dev, dmic->clk_pll_a_out0);
682 devm_clk_put(&pdev->dev, dmic->clk_dmic);
686 static const struct dev_pm_ops tegra210_dmic_pm_ops = {
687 SET_RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend,
688 tegra210_dmic_runtime_resume, NULL)
689 SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_dmic_suspend,
690 tegra210_dmic_resume)
693 static struct platform_driver tegra210_dmic_driver = {
696 .owner = THIS_MODULE,
697 .of_match_table = tegra210_dmic_of_match,
698 .pm = &tegra210_dmic_pm_ops,
700 .probe = tegra210_dmic_platform_probe,
701 .remove = tegra210_dmic_platform_remove,
702 .shutdown = tegra210_dmic_platform_shutdown,
704 module_platform_driver(tegra210_dmic_driver)
706 MODULE_AUTHOR("Rahul Mittal <rmittal@nvidia.com>");
707 MODULE_DESCRIPTION("Tegra210 DMIC ASoC driver");
708 MODULE_LICENSE("GPL");
709 MODULE_ALIAS("platform:" DRV_NAME);
710 MODULE_DEVICE_TABLE(of, tegra210_dmic_of_match);