^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) * tegra20_i2s.c - Tegra20 I2S driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Stephen Warren <swarren@nvidia.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2010,2012 - NVIDIA, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Based on code copyright/by:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (c) 2009-2010, NVIDIA Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Scott Peterson <speterson@nvidia.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Copyright (C) 2010 Google, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Iliyan Malchev <malchev@google.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <sound/dmaengine_pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include "tegra20_i2s.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define DRV_NAME "tegra20-i2s"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static int tegra20_i2s_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct tegra20_i2s *i2s = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) clk_disable_unprepare(i2s->clk_i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static int tegra20_i2s_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct tegra20_i2s *i2s = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) ret = clk_prepare_enable(i2s->clk_i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) dev_err(dev, "clk_enable failed: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned int fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned int mask = 0, val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) case SND_SOC_DAIFMT_NB_NF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) mask |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) case SND_SOC_DAIFMT_CBS_CFS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) val |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) case SND_SOC_DAIFMT_CBM_CFM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) mask |= TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) TEGRA20_I2S_CTRL_LRCK_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) case SND_SOC_DAIFMT_DSP_A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) case SND_SOC_DAIFMT_DSP_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) val |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) case SND_SOC_DAIFMT_I2S:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) val |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) case SND_SOC_DAIFMT_RIGHT_J:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) val |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) case SND_SOC_DAIFMT_LEFT_J:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) val |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct snd_pcm_hw_params *params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct device *dev = dai->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) unsigned int mask, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) int ret, sample_size, srate, i2sclock, bitcnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) mask = TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) switch (params_format(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) case SNDRV_PCM_FORMAT_S16_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) val = TEGRA20_I2S_CTRL_BIT_SIZE_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) sample_size = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) case SNDRV_PCM_FORMAT_S24_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) val = TEGRA20_I2S_CTRL_BIT_SIZE_24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) sample_size = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) case SNDRV_PCM_FORMAT_S32_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) val = TEGRA20_I2S_CTRL_BIT_SIZE_32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) sample_size = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) mask |= TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) val |= TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) srate = params_rate(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /* Final "* 2" required by Tegra hardware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) i2sclock = srate * params_channels(params) * sample_size * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) ret = clk_set_rate(i2s->clk_i2s, i2sclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) bitcnt = (i2sclock / (2 * srate)) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) val = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (i2sclock % (2 * srate))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) val |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) regmap_write(i2s->regmap, TEGRA20_I2S_TIMING, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) regmap_write(i2s->regmap, TEGRA20_I2S_FIFO_SCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) TEGRA20_I2S_CTRL_FIFO1_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) TEGRA20_I2S_CTRL_FIFO1_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) TEGRA20_I2S_CTRL_FIFO1_ENABLE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) TEGRA20_I2S_CTRL_FIFO2_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) TEGRA20_I2S_CTRL_FIFO2_ENABLE);
^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) static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) TEGRA20_I2S_CTRL_FIFO2_ENABLE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) case SNDRV_PCM_TRIGGER_RESUME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) tegra20_i2s_start_playback(i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) tegra20_i2s_start_capture(i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) tegra20_i2s_stop_playback(i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) tegra20_i2s_stop_capture(i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static int tegra20_i2s_probe(struct snd_soc_dai *dai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) dai->capture_dma_data = &i2s->capture_dma_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) dai->playback_dma_data = &i2s->playback_dma_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .set_fmt = tegra20_i2s_set_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .hw_params = tegra20_i2s_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .trigger = tegra20_i2s_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .probe = tegra20_i2s_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .playback = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .stream_name = "Playback",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) .rates = SNDRV_PCM_RATE_8000_96000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) .formats = SNDRV_PCM_FMTBIT_S16_LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .capture = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) .stream_name = "Capture",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) .rates = SNDRV_PCM_RATE_8000_96000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) .formats = SNDRV_PCM_FMTBIT_S16_LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) .ops = &tegra20_i2s_dai_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) .symmetric_rates = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static const struct snd_soc_component_driver tegra20_i2s_component = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) case TEGRA20_I2S_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) case TEGRA20_I2S_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) case TEGRA20_I2S_TIMING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) case TEGRA20_I2S_FIFO_SCR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) case TEGRA20_I2S_PCM_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) case TEGRA20_I2S_NW_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) case TEGRA20_I2S_TDM_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) case TEGRA20_I2S_TDM_TX_RX_CTRL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) case TEGRA20_I2S_FIFO1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) case TEGRA20_I2S_FIFO2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) case TEGRA20_I2S_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) case TEGRA20_I2S_FIFO_SCR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) case TEGRA20_I2S_FIFO1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) case TEGRA20_I2S_FIFO2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) case TEGRA20_I2S_FIFO1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) case TEGRA20_I2S_FIFO2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^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 regmap_config tegra20_i2s_regmap_config = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .reg_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) .reg_stride = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .val_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .max_register = TEGRA20_I2S_FIFO2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .writeable_reg = tegra20_i2s_wr_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .readable_reg = tegra20_i2s_wr_rd_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .volatile_reg = tegra20_i2s_volatile_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .precious_reg = tegra20_i2s_precious_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .cache_type = REGCACHE_FLAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static int tegra20_i2s_platform_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) struct tegra20_i2s *i2s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) struct resource *mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) void __iomem *regs;
^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) i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_i2s), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (!i2s) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) dev_set_drvdata(&pdev->dev, i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) i2s->dai = tegra20_i2s_dai_template;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) i2s->dai.name = dev_name(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) i2s->clk_i2s = clk_get(&pdev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (IS_ERR(i2s->clk_i2s)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) ret = PTR_ERR(i2s->clk_i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) regs = devm_ioremap_resource(&pdev->dev, mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (IS_ERR(regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) ret = PTR_ERR(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) goto err_clk_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) &tegra20_i2s_regmap_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (IS_ERR(i2s->regmap)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) dev_err(&pdev->dev, "regmap init failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ret = PTR_ERR(i2s->regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) goto err_clk_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) i2s->capture_dma_data.maxburst = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) i2s->playback_dma_data.maxburst = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) pm_runtime_enable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (!pm_runtime_enabled(&pdev->dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) ret = tegra20_i2s_runtime_resume(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) goto err_pm_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) &i2s->dai, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) goto err_suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) ret = tegra_pcm_platform_register(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) goto err_unregister_component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) err_unregister_component:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) snd_soc_unregister_component(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) err_suspend:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (!pm_runtime_status_suspended(&pdev->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) tegra20_i2s_runtime_suspend(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) err_pm_disable:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) err_clk_put:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) clk_put(i2s->clk_i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) static int tegra20_i2s_platform_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (!pm_runtime_status_suspended(&pdev->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) tegra20_i2s_runtime_suspend(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) tegra_pcm_platform_unregister(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) snd_soc_unregister_component(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) clk_put(i2s->clk_i2s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) static const struct of_device_id tegra20_i2s_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) { .compatible = "nvidia,tegra20-i2s", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) static const struct dev_pm_ops tegra20_i2s_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) tegra20_i2s_runtime_resume, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) static struct platform_driver tegra20_i2s_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) .of_match_table = tegra20_i2s_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) .pm = &tegra20_i2s_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) .probe = tegra20_i2s_platform_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) .remove = tegra20_i2s_platform_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) module_platform_driver(tegra20_i2s_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) MODULE_DESCRIPTION("Tegra20 I2S ASoC driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) MODULE_ALIAS("platform:" DRV_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) MODULE_DEVICE_TABLE(of, tegra20_i2s_of_match);