1c0bfa983SSameer Pujar // SPDX-License-Identifier: GPL-2.0-only
2c0bfa983SSameer Pujar //
3c0bfa983SSameer Pujar // tegra210_i2s.c - Tegra210 I2S driver
4c0bfa983SSameer Pujar //
5c0bfa983SSameer Pujar // Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
6c0bfa983SSameer Pujar
7c0bfa983SSameer Pujar #include <linux/clk.h>
8c0bfa983SSameer Pujar #include <linux/device.h>
9c0bfa983SSameer Pujar #include <linux/module.h>
10c0bfa983SSameer Pujar #include <linux/of_device.h>
11c0bfa983SSameer Pujar #include <linux/platform_device.h>
12c0bfa983SSameer Pujar #include <linux/pm_runtime.h>
13c0bfa983SSameer Pujar #include <linux/regmap.h>
14c0bfa983SSameer Pujar #include <sound/core.h>
15c0bfa983SSameer Pujar #include <sound/pcm_params.h>
16c0bfa983SSameer Pujar #include <sound/soc.h>
17c0bfa983SSameer Pujar #include "tegra210_i2s.h"
18c0bfa983SSameer Pujar #include "tegra_cif.h"
19c0bfa983SSameer Pujar
20c0bfa983SSameer Pujar static const struct reg_default tegra210_i2s_reg_defaults[] = {
21c0bfa983SSameer Pujar { TEGRA210_I2S_RX_INT_MASK, 0x00000003 },
22c0bfa983SSameer Pujar { TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 },
23c0bfa983SSameer Pujar { TEGRA210_I2S_TX_INT_MASK, 0x00000003 },
24c0bfa983SSameer Pujar { TEGRA210_I2S_TX_CIF_CTRL, 0x00007700 },
25c0bfa983SSameer Pujar { TEGRA210_I2S_CG, 0x1 },
26c0bfa983SSameer Pujar { TEGRA210_I2S_TIMING, 0x0000001f },
27c0bfa983SSameer Pujar { TEGRA210_I2S_ENABLE, 0x1 },
28c0bfa983SSameer Pujar /*
29c0bfa983SSameer Pujar * Below update does not have any effect on Tegra186 and Tegra194.
30c0bfa983SSameer Pujar * On Tegra210, I2S4 has "i2s4a" and "i2s4b" pins and below update
31c0bfa983SSameer Pujar * is required to select i2s4b for it to be functional for I2S
32c0bfa983SSameer Pujar * operation.
33c0bfa983SSameer Pujar */
34c0bfa983SSameer Pujar { TEGRA210_I2S_CYA, 0x1 },
35c0bfa983SSameer Pujar };
36c0bfa983SSameer Pujar
tegra210_i2s_set_slot_ctrl(struct regmap * regmap,unsigned int total_slots,unsigned int tx_slot_mask,unsigned int rx_slot_mask)37c0bfa983SSameer Pujar static void tegra210_i2s_set_slot_ctrl(struct regmap *regmap,
38c0bfa983SSameer Pujar unsigned int total_slots,
39c0bfa983SSameer Pujar unsigned int tx_slot_mask,
40c0bfa983SSameer Pujar unsigned int rx_slot_mask)
41c0bfa983SSameer Pujar {
42c0bfa983SSameer Pujar regmap_write(regmap, TEGRA210_I2S_SLOT_CTRL, total_slots - 1);
43c0bfa983SSameer Pujar regmap_write(regmap, TEGRA210_I2S_TX_SLOT_CTRL, tx_slot_mask);
44c0bfa983SSameer Pujar regmap_write(regmap, TEGRA210_I2S_RX_SLOT_CTRL, rx_slot_mask);
45c0bfa983SSameer Pujar }
46c0bfa983SSameer Pujar
tegra210_i2s_set_clock_rate(struct device * dev,unsigned int clock_rate)47c0bfa983SSameer Pujar static int tegra210_i2s_set_clock_rate(struct device *dev,
48c0bfa983SSameer Pujar unsigned int clock_rate)
49c0bfa983SSameer Pujar {
50c0bfa983SSameer Pujar struct tegra210_i2s *i2s = dev_get_drvdata(dev);
51c0bfa983SSameer Pujar unsigned int val;
52c0bfa983SSameer Pujar int err;
53c0bfa983SSameer Pujar
54c0bfa983SSameer Pujar regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
55c0bfa983SSameer Pujar
56c0bfa983SSameer Pujar /* No need to set rates if I2S is being operated in slave */
57c0bfa983SSameer Pujar if (!(val & I2S_CTRL_MASTER_EN))
58c0bfa983SSameer Pujar return 0;
59c0bfa983SSameer Pujar
60c0bfa983SSameer Pujar err = clk_set_rate(i2s->clk_i2s, clock_rate);
61c0bfa983SSameer Pujar if (err) {
62c0bfa983SSameer Pujar dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
63c0bfa983SSameer Pujar clock_rate, err);
64c0bfa983SSameer Pujar return err;
65c0bfa983SSameer Pujar }
66c0bfa983SSameer Pujar
67c0bfa983SSameer Pujar if (!IS_ERR(i2s->clk_sync_input)) {
68c0bfa983SSameer Pujar /*
69c0bfa983SSameer Pujar * Other I/O modules in AHUB can use i2s bclk as reference
70c0bfa983SSameer Pujar * clock. Below sets sync input clock rate as per bclk,
71c0bfa983SSameer Pujar * which can be used as input to other I/O modules.
72c0bfa983SSameer Pujar */
73c0bfa983SSameer Pujar err = clk_set_rate(i2s->clk_sync_input, clock_rate);
74c0bfa983SSameer Pujar if (err) {
75c0bfa983SSameer Pujar dev_err(dev,
76c0bfa983SSameer Pujar "can't set I2S sync input rate %u, err = %d\n",
77c0bfa983SSameer Pujar clock_rate, err);
78c0bfa983SSameer Pujar return err;
79c0bfa983SSameer Pujar }
80c0bfa983SSameer Pujar }
81c0bfa983SSameer Pujar
82c0bfa983SSameer Pujar return 0;
83c0bfa983SSameer Pujar }
84c0bfa983SSameer Pujar
tegra210_i2s_sw_reset(struct snd_soc_component * compnt,bool is_playback)85c0bfa983SSameer Pujar static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt,
86c0bfa983SSameer Pujar bool is_playback)
87c0bfa983SSameer Pujar {
88c0bfa983SSameer Pujar struct device *dev = compnt->dev;
89c0bfa983SSameer Pujar struct tegra210_i2s *i2s = dev_get_drvdata(dev);
90c0bfa983SSameer Pujar unsigned int reset_mask = I2S_SOFT_RESET_MASK;
91c0bfa983SSameer Pujar unsigned int reset_en = I2S_SOFT_RESET_EN;
92c0bfa983SSameer Pujar unsigned int reset_reg, cif_reg, stream_reg;
93c0bfa983SSameer Pujar unsigned int cif_ctrl, stream_ctrl, i2s_ctrl, val;
94c0bfa983SSameer Pujar int err;
95c0bfa983SSameer Pujar
96c0bfa983SSameer Pujar if (is_playback) {
97c0bfa983SSameer Pujar reset_reg = TEGRA210_I2S_RX_SOFT_RESET;
98c0bfa983SSameer Pujar cif_reg = TEGRA210_I2S_RX_CIF_CTRL;
99c0bfa983SSameer Pujar stream_reg = TEGRA210_I2S_RX_CTRL;
100c0bfa983SSameer Pujar } else {
101c0bfa983SSameer Pujar reset_reg = TEGRA210_I2S_TX_SOFT_RESET;
102c0bfa983SSameer Pujar cif_reg = TEGRA210_I2S_TX_CIF_CTRL;
103c0bfa983SSameer Pujar stream_reg = TEGRA210_I2S_TX_CTRL;
104c0bfa983SSameer Pujar }
105c0bfa983SSameer Pujar
106c0bfa983SSameer Pujar /* Store CIF and I2S control values */
107c0bfa983SSameer Pujar regmap_read(i2s->regmap, cif_reg, &cif_ctrl);
108c0bfa983SSameer Pujar regmap_read(i2s->regmap, stream_reg, &stream_ctrl);
109c0bfa983SSameer Pujar regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &i2s_ctrl);
110c0bfa983SSameer Pujar
111c0bfa983SSameer Pujar /* Reset to make sure the previous transactions are clean */
112c0bfa983SSameer Pujar regmap_update_bits(i2s->regmap, reset_reg, reset_mask, reset_en);
113c0bfa983SSameer Pujar
114c0bfa983SSameer Pujar err = regmap_read_poll_timeout(i2s->regmap, reset_reg, val,
115c0bfa983SSameer Pujar !(val & reset_mask & reset_en),
116c0bfa983SSameer Pujar 10, 10000);
117c0bfa983SSameer Pujar if (err) {
118c0bfa983SSameer Pujar dev_err(dev, "timeout: failed to reset I2S for %s\n",
119c0bfa983SSameer Pujar is_playback ? "playback" : "capture");
120c0bfa983SSameer Pujar return err;
121c0bfa983SSameer Pujar }
122c0bfa983SSameer Pujar
123c0bfa983SSameer Pujar /* Restore CIF and I2S control values */
124c0bfa983SSameer Pujar regmap_write(i2s->regmap, cif_reg, cif_ctrl);
125c0bfa983SSameer Pujar regmap_write(i2s->regmap, stream_reg, stream_ctrl);
126c0bfa983SSameer Pujar regmap_write(i2s->regmap, TEGRA210_I2S_CTRL, i2s_ctrl);
127c0bfa983SSameer Pujar
128c0bfa983SSameer Pujar return 0;
129c0bfa983SSameer Pujar }
130c0bfa983SSameer Pujar
tegra210_i2s_init(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)131c0bfa983SSameer Pujar static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
132c0bfa983SSameer Pujar struct snd_kcontrol *kcontrol, int event)
133c0bfa983SSameer Pujar {
134c0bfa983SSameer Pujar struct snd_soc_component *compnt = snd_soc_dapm_to_component(w->dapm);
135c0bfa983SSameer Pujar struct device *dev = compnt->dev;
136c0bfa983SSameer Pujar struct tegra210_i2s *i2s = dev_get_drvdata(dev);
137c0bfa983SSameer Pujar unsigned int val, status_reg;
138c0bfa983SSameer Pujar bool is_playback;
139c0bfa983SSameer Pujar int err;
140c0bfa983SSameer Pujar
141c0bfa983SSameer Pujar switch (w->reg) {
142c0bfa983SSameer Pujar case TEGRA210_I2S_RX_ENABLE:
143c0bfa983SSameer Pujar is_playback = true;
144c0bfa983SSameer Pujar status_reg = TEGRA210_I2S_RX_STATUS;
145c0bfa983SSameer Pujar break;
146c0bfa983SSameer Pujar case TEGRA210_I2S_TX_ENABLE:
147c0bfa983SSameer Pujar is_playback = false;
148c0bfa983SSameer Pujar status_reg = TEGRA210_I2S_TX_STATUS;
149c0bfa983SSameer Pujar break;
150c0bfa983SSameer Pujar default:
151c0bfa983SSameer Pujar return -EINVAL;
152c0bfa983SSameer Pujar }
153c0bfa983SSameer Pujar
154c0bfa983SSameer Pujar /* Ensure I2S is in disabled state before new session */
155c0bfa983SSameer Pujar err = regmap_read_poll_timeout(i2s->regmap, status_reg, val,
156c0bfa983SSameer Pujar !(val & I2S_EN_MASK & I2S_EN),
157c0bfa983SSameer Pujar 10, 10000);
158c0bfa983SSameer Pujar if (err) {
159c0bfa983SSameer Pujar dev_err(dev, "timeout: previous I2S %s is still active\n",
160c0bfa983SSameer Pujar is_playback ? "playback" : "capture");
161c0bfa983SSameer Pujar return err;
162c0bfa983SSameer Pujar }
163c0bfa983SSameer Pujar
164c0bfa983SSameer Pujar return tegra210_i2s_sw_reset(compnt, is_playback);
165c0bfa983SSameer Pujar }
166c0bfa983SSameer Pujar
tegra210_i2s_runtime_suspend(struct device * dev)167823279c3STakashi Iwai static int __maybe_unused tegra210_i2s_runtime_suspend(struct device *dev)
168c0bfa983SSameer Pujar {
169c0bfa983SSameer Pujar struct tegra210_i2s *i2s = dev_get_drvdata(dev);
170c0bfa983SSameer Pujar
171c0bfa983SSameer Pujar regcache_cache_only(i2s->regmap, true);
172c0bfa983SSameer Pujar regcache_mark_dirty(i2s->regmap);
173c0bfa983SSameer Pujar
174c0bfa983SSameer Pujar clk_disable_unprepare(i2s->clk_i2s);
175c0bfa983SSameer Pujar
176c0bfa983SSameer Pujar return 0;
177c0bfa983SSameer Pujar }
178c0bfa983SSameer Pujar
tegra210_i2s_runtime_resume(struct device * dev)179823279c3STakashi Iwai static int __maybe_unused tegra210_i2s_runtime_resume(struct device *dev)
180c0bfa983SSameer Pujar {
181c0bfa983SSameer Pujar struct tegra210_i2s *i2s = dev_get_drvdata(dev);
182c0bfa983SSameer Pujar int err;
183c0bfa983SSameer Pujar
184c0bfa983SSameer Pujar err = clk_prepare_enable(i2s->clk_i2s);
185c0bfa983SSameer Pujar if (err) {
186c0bfa983SSameer Pujar dev_err(dev, "failed to enable I2S bit clock, err: %d\n", err);
187c0bfa983SSameer Pujar return err;
188c0bfa983SSameer Pujar }
189c0bfa983SSameer Pujar
190c0bfa983SSameer Pujar regcache_cache_only(i2s->regmap, false);
191c0bfa983SSameer Pujar regcache_sync(i2s->regmap);
192c0bfa983SSameer Pujar
193c0bfa983SSameer Pujar return 0;
194c0bfa983SSameer Pujar }
195c0bfa983SSameer Pujar
tegra210_i2s_set_data_offset(struct tegra210_i2s * i2s,unsigned int data_offset)196c0bfa983SSameer Pujar static void tegra210_i2s_set_data_offset(struct tegra210_i2s *i2s,
197c0bfa983SSameer Pujar unsigned int data_offset)
198c0bfa983SSameer Pujar {
199c0bfa983SSameer Pujar /* Capture path */
200c0bfa983SSameer Pujar regmap_update_bits(i2s->regmap, TEGRA210_I2S_TX_CTRL,
201c0bfa983SSameer Pujar I2S_CTRL_DATA_OFFSET_MASK,
202c0bfa983SSameer Pujar data_offset << I2S_DATA_SHIFT);
203c0bfa983SSameer Pujar
204c0bfa983SSameer Pujar /* Playback path */
205c0bfa983SSameer Pujar regmap_update_bits(i2s->regmap, TEGRA210_I2S_RX_CTRL,
206c0bfa983SSameer Pujar I2S_CTRL_DATA_OFFSET_MASK,
207c0bfa983SSameer Pujar data_offset << I2S_DATA_SHIFT);
208c0bfa983SSameer Pujar }
209c0bfa983SSameer Pujar
tegra210_i2s_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)210c0bfa983SSameer Pujar static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
211c0bfa983SSameer Pujar unsigned int fmt)
212c0bfa983SSameer Pujar {
213c0bfa983SSameer Pujar struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
214c0bfa983SSameer Pujar unsigned int mask, val;
215c0bfa983SSameer Pujar
216c0bfa983SSameer Pujar mask = I2S_CTRL_MASTER_EN_MASK;
217d92ad663SCharles Keepax switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
2185983a8a4SSameer Pujar case SND_SOC_DAIFMT_BC_FC:
219c0bfa983SSameer Pujar val = 0;
220c0bfa983SSameer Pujar break;
2215983a8a4SSameer Pujar case SND_SOC_DAIFMT_BP_FP:
222c0bfa983SSameer Pujar val = I2S_CTRL_MASTER_EN;
223c0bfa983SSameer Pujar break;
224c0bfa983SSameer Pujar default:
225c0bfa983SSameer Pujar return -EINVAL;
226c0bfa983SSameer Pujar }
227c0bfa983SSameer Pujar
228c0bfa983SSameer Pujar mask |= I2S_CTRL_FRAME_FMT_MASK | I2S_CTRL_LRCK_POL_MASK;
229c0bfa983SSameer Pujar switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
230c0bfa983SSameer Pujar case SND_SOC_DAIFMT_DSP_A:
231c0bfa983SSameer Pujar val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
232c0bfa983SSameer Pujar val |= I2S_CTRL_LRCK_POL_HIGH;
233c0bfa983SSameer Pujar tegra210_i2s_set_data_offset(i2s, 1);
234c0bfa983SSameer Pujar break;
235c0bfa983SSameer Pujar case SND_SOC_DAIFMT_DSP_B:
236c0bfa983SSameer Pujar val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
237c0bfa983SSameer Pujar val |= I2S_CTRL_LRCK_POL_HIGH;
238c0bfa983SSameer Pujar tegra210_i2s_set_data_offset(i2s, 0);
239c0bfa983SSameer Pujar break;
240c0bfa983SSameer Pujar /* I2S mode has data offset of 1 */
241c0bfa983SSameer Pujar case SND_SOC_DAIFMT_I2S:
242c0bfa983SSameer Pujar val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
243c0bfa983SSameer Pujar val |= I2S_CTRL_LRCK_POL_LOW;
244c0bfa983SSameer Pujar tegra210_i2s_set_data_offset(i2s, 1);
245c0bfa983SSameer Pujar break;
246c0bfa983SSameer Pujar /*
247c0bfa983SSameer Pujar * For RJ mode data offset is dependent on the sample size
248c0bfa983SSameer Pujar * and the bclk ratio, and so is set when hw_params is called.
249c0bfa983SSameer Pujar */
250c0bfa983SSameer Pujar case SND_SOC_DAIFMT_RIGHT_J:
251c0bfa983SSameer Pujar val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
252c0bfa983SSameer Pujar val |= I2S_CTRL_LRCK_POL_HIGH;
253c0bfa983SSameer Pujar break;
254c0bfa983SSameer Pujar case SND_SOC_DAIFMT_LEFT_J:
255c0bfa983SSameer Pujar val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
256c0bfa983SSameer Pujar val |= I2S_CTRL_LRCK_POL_HIGH;
257c0bfa983SSameer Pujar tegra210_i2s_set_data_offset(i2s, 0);
258c0bfa983SSameer Pujar break;
259c0bfa983SSameer Pujar default:
260c0bfa983SSameer Pujar return -EINVAL;
261c0bfa983SSameer Pujar }
262c0bfa983SSameer Pujar
263c0bfa983SSameer Pujar mask |= I2S_CTRL_EDGE_CTRL_MASK;
264c0bfa983SSameer Pujar switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
265c0bfa983SSameer Pujar case SND_SOC_DAIFMT_NB_NF:
266c0bfa983SSameer Pujar val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
267c0bfa983SSameer Pujar break;
268c0bfa983SSameer Pujar case SND_SOC_DAIFMT_NB_IF:
269c0bfa983SSameer Pujar val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
270c0bfa983SSameer Pujar val ^= I2S_CTRL_LRCK_POL_MASK;
271c0bfa983SSameer Pujar break;
272c0bfa983SSameer Pujar case SND_SOC_DAIFMT_IB_NF:
273c0bfa983SSameer Pujar val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
274c0bfa983SSameer Pujar break;
275c0bfa983SSameer Pujar case SND_SOC_DAIFMT_IB_IF:
276c0bfa983SSameer Pujar val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
277c0bfa983SSameer Pujar val ^= I2S_CTRL_LRCK_POL_MASK;
278c0bfa983SSameer Pujar break;
279c0bfa983SSameer Pujar default:
280c0bfa983SSameer Pujar return -EINVAL;
281c0bfa983SSameer Pujar }
282c0bfa983SSameer Pujar
283c0bfa983SSameer Pujar regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, mask, val);
284c0bfa983SSameer Pujar
285c0bfa983SSameer Pujar i2s->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
286c0bfa983SSameer Pujar
287c0bfa983SSameer Pujar return 0;
288c0bfa983SSameer Pujar }
289c0bfa983SSameer Pujar
tegra210_i2s_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)290c0bfa983SSameer Pujar static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai,
291c0bfa983SSameer Pujar unsigned int tx_mask, unsigned int rx_mask,
292c0bfa983SSameer Pujar int slots, int slot_width)
293c0bfa983SSameer Pujar {
294c0bfa983SSameer Pujar struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
295c0bfa983SSameer Pujar
296c0bfa983SSameer Pujar /* Copy the required tx and rx mask */
297c0bfa983SSameer Pujar i2s->tx_mask = (tx_mask > DEFAULT_I2S_SLOT_MASK) ?
298c0bfa983SSameer Pujar DEFAULT_I2S_SLOT_MASK : tx_mask;
299c0bfa983SSameer Pujar i2s->rx_mask = (rx_mask > DEFAULT_I2S_SLOT_MASK) ?
300c0bfa983SSameer Pujar DEFAULT_I2S_SLOT_MASK : rx_mask;
301c0bfa983SSameer Pujar
302c0bfa983SSameer Pujar return 0;
303c0bfa983SSameer Pujar }
304c0bfa983SSameer Pujar
tegra210_i2s_get_loopback(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)305f21a9df3SSameer Pujar static int tegra210_i2s_get_loopback(struct snd_kcontrol *kcontrol,
306c0bfa983SSameer Pujar struct snd_ctl_elem_value *ucontrol)
307c0bfa983SSameer Pujar {
308c0bfa983SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
309c0bfa983SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
310c0bfa983SSameer Pujar
3118a2c2fa0SSameer Pujar ucontrol->value.integer.value[0] = i2s->loopback;
312c0bfa983SSameer Pujar
313c0bfa983SSameer Pujar return 0;
314c0bfa983SSameer Pujar }
315c0bfa983SSameer Pujar
tegra210_i2s_put_loopback(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)316f21a9df3SSameer Pujar static int tegra210_i2s_put_loopback(struct snd_kcontrol *kcontrol,
317c0bfa983SSameer Pujar struct snd_ctl_elem_value *ucontrol)
318c0bfa983SSameer Pujar {
319c0bfa983SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
320c0bfa983SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
321f21a9df3SSameer Pujar int value = ucontrol->value.integer.value[0];
322c0bfa983SSameer Pujar
323f21a9df3SSameer Pujar if (value == i2s->loopback)
324f21a9df3SSameer Pujar return 0;
325c0bfa983SSameer Pujar
326f21a9df3SSameer Pujar i2s->loopback = value;
327f21a9df3SSameer Pujar
328f21a9df3SSameer Pujar regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, I2S_CTRL_LPBK_MASK,
329c0bfa983SSameer Pujar i2s->loopback << I2S_CTRL_LPBK_SHIFT);
330c0bfa983SSameer Pujar
331f21a9df3SSameer Pujar return 1;
332f21a9df3SSameer Pujar }
333f21a9df3SSameer Pujar
tegra210_i2s_get_fsync_width(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)334f21a9df3SSameer Pujar static int tegra210_i2s_get_fsync_width(struct snd_kcontrol *kcontrol,
335f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
336f21a9df3SSameer Pujar {
337f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
338f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
339f21a9df3SSameer Pujar
340f21a9df3SSameer Pujar ucontrol->value.integer.value[0] = i2s->fsync_width;
341f21a9df3SSameer Pujar
342f21a9df3SSameer Pujar return 0;
343f21a9df3SSameer Pujar }
344f21a9df3SSameer Pujar
tegra210_i2s_put_fsync_width(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)345f21a9df3SSameer Pujar static int tegra210_i2s_put_fsync_width(struct snd_kcontrol *kcontrol,
346f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
347f21a9df3SSameer Pujar {
348f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
349f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
350f21a9df3SSameer Pujar int value = ucontrol->value.integer.value[0];
351f21a9df3SSameer Pujar
352f21a9df3SSameer Pujar if (value == i2s->fsync_width)
353f21a9df3SSameer Pujar return 0;
354f21a9df3SSameer Pujar
355f21a9df3SSameer Pujar i2s->fsync_width = value;
356f21a9df3SSameer Pujar
357c0bfa983SSameer Pujar /*
358c0bfa983SSameer Pujar * Frame sync width is used only for FSYNC modes and not
359c0bfa983SSameer Pujar * applicable for LRCK modes. Reset value for this field is "0",
360c0bfa983SSameer Pujar * which means the width is one bit clock wide.
361c0bfa983SSameer Pujar * The width requirement may depend on the codec and in such
362c0bfa983SSameer Pujar * cases mixer control is used to update custom values. A value
363c0bfa983SSameer Pujar * of "N" here means, width is "N + 1" bit clock wide.
364c0bfa983SSameer Pujar */
365c0bfa983SSameer Pujar regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
366c0bfa983SSameer Pujar I2S_CTRL_FSYNC_WIDTH_MASK,
367c0bfa983SSameer Pujar i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
368c0bfa983SSameer Pujar
369f21a9df3SSameer Pujar return 1;
370c0bfa983SSameer Pujar }
371c0bfa983SSameer Pujar
tegra210_i2s_cget_stereo_to_mono(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)372f21a9df3SSameer Pujar static int tegra210_i2s_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
373f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
374f21a9df3SSameer Pujar {
375f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
376f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
377f21a9df3SSameer Pujar
378f21a9df3SSameer Pujar ucontrol->value.enumerated.item[0] = i2s->stereo_to_mono[I2S_TX_PATH];
379f21a9df3SSameer Pujar
380f21a9df3SSameer Pujar return 0;
381f21a9df3SSameer Pujar }
382f21a9df3SSameer Pujar
tegra210_i2s_cput_stereo_to_mono(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)383f21a9df3SSameer Pujar static int tegra210_i2s_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
384f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
385f21a9df3SSameer Pujar {
386f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
387f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
388f21a9df3SSameer Pujar unsigned int value = ucontrol->value.enumerated.item[0];
389f21a9df3SSameer Pujar
390f21a9df3SSameer Pujar if (value == i2s->stereo_to_mono[I2S_TX_PATH])
391f21a9df3SSameer Pujar return 0;
392f21a9df3SSameer Pujar
393f21a9df3SSameer Pujar i2s->stereo_to_mono[I2S_TX_PATH] = value;
394f21a9df3SSameer Pujar
395f21a9df3SSameer Pujar return 1;
396f21a9df3SSameer Pujar }
397f21a9df3SSameer Pujar
tegra210_i2s_cget_mono_to_stereo(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)398f21a9df3SSameer Pujar static int tegra210_i2s_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
399f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
400f21a9df3SSameer Pujar {
401f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
402f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
403f21a9df3SSameer Pujar
404f21a9df3SSameer Pujar ucontrol->value.enumerated.item[0] = i2s->mono_to_stereo[I2S_TX_PATH];
405f21a9df3SSameer Pujar
406f21a9df3SSameer Pujar return 0;
407f21a9df3SSameer Pujar }
408f21a9df3SSameer Pujar
tegra210_i2s_cput_mono_to_stereo(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)409f21a9df3SSameer Pujar static int tegra210_i2s_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
410f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
411f21a9df3SSameer Pujar {
412f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
413f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
414f21a9df3SSameer Pujar unsigned int value = ucontrol->value.enumerated.item[0];
415f21a9df3SSameer Pujar
416f21a9df3SSameer Pujar if (value == i2s->mono_to_stereo[I2S_TX_PATH])
417f21a9df3SSameer Pujar return 0;
418f21a9df3SSameer Pujar
419f21a9df3SSameer Pujar i2s->mono_to_stereo[I2S_TX_PATH] = value;
420f21a9df3SSameer Pujar
421f21a9df3SSameer Pujar return 1;
422f21a9df3SSameer Pujar }
423f21a9df3SSameer Pujar
tegra210_i2s_pget_stereo_to_mono(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)424f21a9df3SSameer Pujar static int tegra210_i2s_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
425f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
426f21a9df3SSameer Pujar {
427f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
428f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
429f21a9df3SSameer Pujar
430f21a9df3SSameer Pujar ucontrol->value.enumerated.item[0] = i2s->stereo_to_mono[I2S_RX_PATH];
431f21a9df3SSameer Pujar
432f21a9df3SSameer Pujar return 0;
433f21a9df3SSameer Pujar }
434f21a9df3SSameer Pujar
tegra210_i2s_pput_stereo_to_mono(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)435f21a9df3SSameer Pujar static int tegra210_i2s_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
436f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
437f21a9df3SSameer Pujar {
438f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
439f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
440f21a9df3SSameer Pujar unsigned int value = ucontrol->value.enumerated.item[0];
441f21a9df3SSameer Pujar
442f21a9df3SSameer Pujar if (value == i2s->stereo_to_mono[I2S_RX_PATH])
443f21a9df3SSameer Pujar return 0;
444f21a9df3SSameer Pujar
445f21a9df3SSameer Pujar i2s->stereo_to_mono[I2S_RX_PATH] = value;
446f21a9df3SSameer Pujar
447f21a9df3SSameer Pujar return 1;
448f21a9df3SSameer Pujar }
449f21a9df3SSameer Pujar
tegra210_i2s_pget_mono_to_stereo(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)450f21a9df3SSameer Pujar static int tegra210_i2s_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
451f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
452f21a9df3SSameer Pujar {
453f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
454f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
455f21a9df3SSameer Pujar
456f21a9df3SSameer Pujar ucontrol->value.enumerated.item[0] = i2s->mono_to_stereo[I2S_RX_PATH];
457f21a9df3SSameer Pujar
458f21a9df3SSameer Pujar return 0;
459f21a9df3SSameer Pujar }
460f21a9df3SSameer Pujar
tegra210_i2s_pput_mono_to_stereo(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)461f21a9df3SSameer Pujar static int tegra210_i2s_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
462f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
463f21a9df3SSameer Pujar {
464f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
465f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
466f21a9df3SSameer Pujar unsigned int value = ucontrol->value.enumerated.item[0];
467f21a9df3SSameer Pujar
468f21a9df3SSameer Pujar if (value == i2s->mono_to_stereo[I2S_RX_PATH])
469f21a9df3SSameer Pujar return 0;
470f21a9df3SSameer Pujar
471f21a9df3SSameer Pujar i2s->mono_to_stereo[I2S_RX_PATH] = value;
472f21a9df3SSameer Pujar
473f21a9df3SSameer Pujar return 1;
474f21a9df3SSameer Pujar }
475f21a9df3SSameer Pujar
tegra210_i2s_pget_fifo_th(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)476f21a9df3SSameer Pujar static int tegra210_i2s_pget_fifo_th(struct snd_kcontrol *kcontrol,
477f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
478f21a9df3SSameer Pujar {
479f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
480f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
481f21a9df3SSameer Pujar
482f21a9df3SSameer Pujar ucontrol->value.integer.value[0] = i2s->rx_fifo_th;
483f21a9df3SSameer Pujar
484f21a9df3SSameer Pujar return 0;
485f21a9df3SSameer Pujar }
486f21a9df3SSameer Pujar
tegra210_i2s_pput_fifo_th(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)487f21a9df3SSameer Pujar static int tegra210_i2s_pput_fifo_th(struct snd_kcontrol *kcontrol,
488f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
489f21a9df3SSameer Pujar {
490f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
491f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
492f21a9df3SSameer Pujar int value = ucontrol->value.integer.value[0];
493f21a9df3SSameer Pujar
494f21a9df3SSameer Pujar if (value == i2s->rx_fifo_th)
495f21a9df3SSameer Pujar return 0;
496f21a9df3SSameer Pujar
497f21a9df3SSameer Pujar i2s->rx_fifo_th = value;
498f21a9df3SSameer Pujar
499f21a9df3SSameer Pujar return 1;
500f21a9df3SSameer Pujar }
501f21a9df3SSameer Pujar
tegra210_i2s_get_bclk_ratio(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)502f21a9df3SSameer Pujar static int tegra210_i2s_get_bclk_ratio(struct snd_kcontrol *kcontrol,
503f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
504f21a9df3SSameer Pujar {
505f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
506f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
507f21a9df3SSameer Pujar
508f21a9df3SSameer Pujar ucontrol->value.integer.value[0] = i2s->bclk_ratio;
509f21a9df3SSameer Pujar
510f21a9df3SSameer Pujar return 0;
511f21a9df3SSameer Pujar }
512f21a9df3SSameer Pujar
tegra210_i2s_put_bclk_ratio(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)513f21a9df3SSameer Pujar static int tegra210_i2s_put_bclk_ratio(struct snd_kcontrol *kcontrol,
514f21a9df3SSameer Pujar struct snd_ctl_elem_value *ucontrol)
515f21a9df3SSameer Pujar {
516f21a9df3SSameer Pujar struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
517f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
518f21a9df3SSameer Pujar int value = ucontrol->value.integer.value[0];
519f21a9df3SSameer Pujar
520f21a9df3SSameer Pujar if (value == i2s->bclk_ratio)
521f21a9df3SSameer Pujar return 0;
522f21a9df3SSameer Pujar
523f21a9df3SSameer Pujar i2s->bclk_ratio = value;
524f21a9df3SSameer Pujar
525f21a9df3SSameer Pujar return 1;
526f21a9df3SSameer Pujar }
527f21a9df3SSameer Pujar
tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai * dai,unsigned int ratio)528f21a9df3SSameer Pujar static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
529f21a9df3SSameer Pujar unsigned int ratio)
530f21a9df3SSameer Pujar {
531f21a9df3SSameer Pujar struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
532f21a9df3SSameer Pujar
533f21a9df3SSameer Pujar i2s->bclk_ratio = ratio;
534f21a9df3SSameer Pujar
535c0bfa983SSameer Pujar return 0;
536c0bfa983SSameer Pujar }
537c0bfa983SSameer Pujar
tegra210_i2s_set_timing_params(struct device * dev,unsigned int sample_size,unsigned int srate,unsigned int channels)538c0bfa983SSameer Pujar static int tegra210_i2s_set_timing_params(struct device *dev,
539c0bfa983SSameer Pujar unsigned int sample_size,
540c0bfa983SSameer Pujar unsigned int srate,
541c0bfa983SSameer Pujar unsigned int channels)
542c0bfa983SSameer Pujar {
543c0bfa983SSameer Pujar struct tegra210_i2s *i2s = dev_get_drvdata(dev);
544c0bfa983SSameer Pujar unsigned int val, bit_count, bclk_rate, num_bclk = sample_size;
545c0bfa983SSameer Pujar int err;
546c0bfa983SSameer Pujar
547c0bfa983SSameer Pujar if (i2s->bclk_ratio)
548c0bfa983SSameer Pujar num_bclk *= i2s->bclk_ratio;
549c0bfa983SSameer Pujar
550c0bfa983SSameer Pujar if (i2s->dai_fmt == SND_SOC_DAIFMT_RIGHT_J)
551c0bfa983SSameer Pujar tegra210_i2s_set_data_offset(i2s, num_bclk - sample_size);
552c0bfa983SSameer Pujar
553c0bfa983SSameer Pujar /* I2S bit clock rate */
554c0bfa983SSameer Pujar bclk_rate = srate * channels * num_bclk;
555c0bfa983SSameer Pujar
556c0bfa983SSameer Pujar err = tegra210_i2s_set_clock_rate(dev, bclk_rate);
557c0bfa983SSameer Pujar if (err) {
558c0bfa983SSameer Pujar dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
559c0bfa983SSameer Pujar bclk_rate, err);
560c0bfa983SSameer Pujar return err;
561c0bfa983SSameer Pujar }
562c0bfa983SSameer Pujar
563c0bfa983SSameer Pujar regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
564c0bfa983SSameer Pujar
565c0bfa983SSameer Pujar /*
566c0bfa983SSameer Pujar * For LRCK mode, channel bit count depends on number of bit clocks
567c0bfa983SSameer Pujar * on the left channel, where as for FSYNC mode bit count depends on
568c0bfa983SSameer Pujar * the number of bit clocks in both left and right channels for DSP
569c0bfa983SSameer Pujar * mode or the number of bit clocks in one TDM frame.
570c0bfa983SSameer Pujar *
571c0bfa983SSameer Pujar */
572c0bfa983SSameer Pujar switch (val & I2S_CTRL_FRAME_FMT_MASK) {
573c0bfa983SSameer Pujar case I2S_CTRL_FRAME_FMT_LRCK_MODE:
574c0bfa983SSameer Pujar bit_count = (bclk_rate / (srate * 2)) - 1;
575c0bfa983SSameer Pujar break;
576c0bfa983SSameer Pujar case I2S_CTRL_FRAME_FMT_FSYNC_MODE:
577c0bfa983SSameer Pujar bit_count = (bclk_rate / srate) - 1;
578c0bfa983SSameer Pujar
579c0bfa983SSameer Pujar tegra210_i2s_set_slot_ctrl(i2s->regmap, channels,
580c0bfa983SSameer Pujar i2s->tx_mask, i2s->rx_mask);
581c0bfa983SSameer Pujar break;
582c0bfa983SSameer Pujar default:
583c0bfa983SSameer Pujar dev_err(dev, "invalid I2S frame format\n");
584c0bfa983SSameer Pujar return -EINVAL;
585c0bfa983SSameer Pujar }
586c0bfa983SSameer Pujar
587c0bfa983SSameer Pujar if (bit_count > I2S_TIMING_CH_BIT_CNT_MASK) {
588c0bfa983SSameer Pujar dev_err(dev, "invalid I2S channel bit count %u\n", bit_count);
589c0bfa983SSameer Pujar return -EINVAL;
590c0bfa983SSameer Pujar }
591c0bfa983SSameer Pujar
592c0bfa983SSameer Pujar regmap_write(i2s->regmap, TEGRA210_I2S_TIMING,
593c0bfa983SSameer Pujar bit_count << I2S_TIMING_CH_BIT_CNT_SHIFT);
594c0bfa983SSameer Pujar
595c0bfa983SSameer Pujar return 0;
596c0bfa983SSameer Pujar }
597c0bfa983SSameer Pujar
tegra210_i2s_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)598c0bfa983SSameer Pujar static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
599c0bfa983SSameer Pujar struct snd_pcm_hw_params *params,
600c0bfa983SSameer Pujar struct snd_soc_dai *dai)
601c0bfa983SSameer Pujar {
602c0bfa983SSameer Pujar struct device *dev = dai->dev;
603c0bfa983SSameer Pujar struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
604c0bfa983SSameer Pujar unsigned int sample_size, channels, srate, val, reg, path;
605c0bfa983SSameer Pujar struct tegra_cif_conf cif_conf;
606c0bfa983SSameer Pujar
607c0bfa983SSameer Pujar memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
608c0bfa983SSameer Pujar
609c0bfa983SSameer Pujar channels = params_channels(params);
610c0bfa983SSameer Pujar if (channels < 1) {
611c0bfa983SSameer Pujar dev_err(dev, "invalid I2S %d channel configuration\n",
612c0bfa983SSameer Pujar channels);
613c0bfa983SSameer Pujar return -EINVAL;
614c0bfa983SSameer Pujar }
615c0bfa983SSameer Pujar
616c0bfa983SSameer Pujar cif_conf.audio_ch = channels;
617c0bfa983SSameer Pujar cif_conf.client_ch = channels;
618c0bfa983SSameer Pujar
619c0bfa983SSameer Pujar switch (params_format(params)) {
620c0bfa983SSameer Pujar case SNDRV_PCM_FORMAT_S8:
621c0bfa983SSameer Pujar val = I2S_BITS_8;
622c0bfa983SSameer Pujar sample_size = 8;
623c0bfa983SSameer Pujar cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
624c0bfa983SSameer Pujar cif_conf.client_bits = TEGRA_ACIF_BITS_8;
625c0bfa983SSameer Pujar break;
626c0bfa983SSameer Pujar case SNDRV_PCM_FORMAT_S16_LE:
627c0bfa983SSameer Pujar val = I2S_BITS_16;
628c0bfa983SSameer Pujar sample_size = 16;
629c0bfa983SSameer Pujar cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
630c0bfa983SSameer Pujar cif_conf.client_bits = TEGRA_ACIF_BITS_16;
631c0bfa983SSameer Pujar break;
632c0bfa983SSameer Pujar case SNDRV_PCM_FORMAT_S32_LE:
633c0bfa983SSameer Pujar val = I2S_BITS_32;
634c0bfa983SSameer Pujar sample_size = 32;
635c0bfa983SSameer Pujar cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
636c0bfa983SSameer Pujar cif_conf.client_bits = TEGRA_ACIF_BITS_32;
637c0bfa983SSameer Pujar break;
638c0bfa983SSameer Pujar default:
639c0bfa983SSameer Pujar dev_err(dev, "unsupported format!\n");
640c0bfa983SSameer Pujar return -EOPNOTSUPP;
641c0bfa983SSameer Pujar }
642c0bfa983SSameer Pujar
643c0bfa983SSameer Pujar /* Program sample size */
644c0bfa983SSameer Pujar regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
645c0bfa983SSameer Pujar I2S_CTRL_BIT_SIZE_MASK, val);
646c0bfa983SSameer Pujar
647c0bfa983SSameer Pujar srate = params_rate(params);
648c0bfa983SSameer Pujar
649c0bfa983SSameer Pujar /* For playback I2S RX-CIF and for capture TX-CIF is used */
650c0bfa983SSameer Pujar if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
651c0bfa983SSameer Pujar path = I2S_RX_PATH;
652c0bfa983SSameer Pujar else
653c0bfa983SSameer Pujar path = I2S_TX_PATH;
654c0bfa983SSameer Pujar
655c0bfa983SSameer Pujar if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
656c0bfa983SSameer Pujar unsigned int max_th;
657c0bfa983SSameer Pujar
658c0bfa983SSameer Pujar /* FIFO threshold in terms of frames */
659c0bfa983SSameer Pujar max_th = (I2S_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
660c0bfa983SSameer Pujar
661c0bfa983SSameer Pujar if (i2s->rx_fifo_th > max_th)
662c0bfa983SSameer Pujar i2s->rx_fifo_th = max_th;
663c0bfa983SSameer Pujar
664c0bfa983SSameer Pujar cif_conf.threshold = i2s->rx_fifo_th;
665c0bfa983SSameer Pujar
666c0bfa983SSameer Pujar reg = TEGRA210_I2S_RX_CIF_CTRL;
667c0bfa983SSameer Pujar } else {
668c0bfa983SSameer Pujar reg = TEGRA210_I2S_TX_CIF_CTRL;
669c0bfa983SSameer Pujar }
670c0bfa983SSameer Pujar
671c0bfa983SSameer Pujar cif_conf.mono_conv = i2s->mono_to_stereo[path];
672c0bfa983SSameer Pujar cif_conf.stereo_conv = i2s->stereo_to_mono[path];
673c0bfa983SSameer Pujar
674c0bfa983SSameer Pujar tegra_set_cif(i2s->regmap, reg, &cif_conf);
675c0bfa983SSameer Pujar
676c0bfa983SSameer Pujar return tegra210_i2s_set_timing_params(dev, sample_size, srate,
677c0bfa983SSameer Pujar cif_conf.client_ch);
678c0bfa983SSameer Pujar }
679c0bfa983SSameer Pujar
680c0bfa983SSameer Pujar static const struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
681475f2af6SCharles Keepax .set_fmt = tegra210_i2s_set_fmt,
682c0bfa983SSameer Pujar .hw_params = tegra210_i2s_hw_params,
683c0bfa983SSameer Pujar .set_bclk_ratio = tegra210_i2s_set_dai_bclk_ratio,
684c0bfa983SSameer Pujar .set_tdm_slot = tegra210_i2s_set_tdm_slot,
685c0bfa983SSameer Pujar };
686c0bfa983SSameer Pujar
687c0bfa983SSameer Pujar static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
688c0bfa983SSameer Pujar {
689c0bfa983SSameer Pujar .name = "I2S-CIF",
690c0bfa983SSameer Pujar .playback = {
691c0bfa983SSameer Pujar .stream_name = "CIF-Playback",
692c0bfa983SSameer Pujar .channels_min = 1,
693c0bfa983SSameer Pujar .channels_max = 16,
694c0bfa983SSameer Pujar .rates = SNDRV_PCM_RATE_8000_192000,
695c0bfa983SSameer Pujar .formats = SNDRV_PCM_FMTBIT_S8 |
696c0bfa983SSameer Pujar SNDRV_PCM_FMTBIT_S16_LE |
697c0bfa983SSameer Pujar SNDRV_PCM_FMTBIT_S32_LE,
698c0bfa983SSameer Pujar },
699c0bfa983SSameer Pujar .capture = {
700c0bfa983SSameer Pujar .stream_name = "CIF-Capture",
701c0bfa983SSameer Pujar .channels_min = 1,
702c0bfa983SSameer Pujar .channels_max = 16,
703c0bfa983SSameer Pujar .rates = SNDRV_PCM_RATE_8000_192000,
704c0bfa983SSameer Pujar .formats = SNDRV_PCM_FMTBIT_S8 |
705c0bfa983SSameer Pujar SNDRV_PCM_FMTBIT_S16_LE |
706c0bfa983SSameer Pujar SNDRV_PCM_FMTBIT_S32_LE,
707c0bfa983SSameer Pujar },
708c0bfa983SSameer Pujar },
709c0bfa983SSameer Pujar {
710c0bfa983SSameer Pujar .name = "I2S-DAP",
711c0bfa983SSameer Pujar .playback = {
712c0bfa983SSameer Pujar .stream_name = "DAP-Playback",
713c0bfa983SSameer Pujar .channels_min = 1,
714c0bfa983SSameer Pujar .channels_max = 16,
715c0bfa983SSameer Pujar .rates = SNDRV_PCM_RATE_8000_192000,
716c0bfa983SSameer Pujar .formats = SNDRV_PCM_FMTBIT_S8 |
717c0bfa983SSameer Pujar SNDRV_PCM_FMTBIT_S16_LE |
718c0bfa983SSameer Pujar SNDRV_PCM_FMTBIT_S32_LE,
719c0bfa983SSameer Pujar },
720c0bfa983SSameer Pujar .capture = {
721c0bfa983SSameer Pujar .stream_name = "DAP-Capture",
722c0bfa983SSameer Pujar .channels_min = 1,
723c0bfa983SSameer Pujar .channels_max = 16,
724c0bfa983SSameer Pujar .rates = SNDRV_PCM_RATE_8000_192000,
725c0bfa983SSameer Pujar .formats = SNDRV_PCM_FMTBIT_S8 |
726c0bfa983SSameer Pujar SNDRV_PCM_FMTBIT_S16_LE |
727c0bfa983SSameer Pujar SNDRV_PCM_FMTBIT_S32_LE,
728c0bfa983SSameer Pujar },
729c0bfa983SSameer Pujar .ops = &tegra210_i2s_dai_ops,
730c6d152a8SKuninori Morimoto .symmetric_rate = 1,
731c0bfa983SSameer Pujar },
732c0bfa983SSameer Pujar };
733c0bfa983SSameer Pujar
734c0bfa983SSameer Pujar static const char * const tegra210_i2s_stereo_conv_text[] = {
735c0bfa983SSameer Pujar "CH0", "CH1", "AVG",
736c0bfa983SSameer Pujar };
737c0bfa983SSameer Pujar
738c0bfa983SSameer Pujar static const char * const tegra210_i2s_mono_conv_text[] = {
739c0bfa983SSameer Pujar "Zero", "Copy",
740c0bfa983SSameer Pujar };
741c0bfa983SSameer Pujar
742c0bfa983SSameer Pujar static const struct soc_enum tegra210_i2s_mono_conv_enum =
743c0bfa983SSameer Pujar SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_mono_conv_text),
744c0bfa983SSameer Pujar tegra210_i2s_mono_conv_text);
745c0bfa983SSameer Pujar
746c0bfa983SSameer Pujar static const struct soc_enum tegra210_i2s_stereo_conv_enum =
747c0bfa983SSameer Pujar SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_stereo_conv_text),
748c0bfa983SSameer Pujar tegra210_i2s_stereo_conv_text);
749c0bfa983SSameer Pujar
750c0bfa983SSameer Pujar static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
751f21a9df3SSameer Pujar SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_loopback,
752f21a9df3SSameer Pujar tegra210_i2s_put_loopback),
753f21a9df3SSameer Pujar SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0,
754f21a9df3SSameer Pujar tegra210_i2s_get_fsync_width,
755f21a9df3SSameer Pujar tegra210_i2s_put_fsync_width),
756c0bfa983SSameer Pujar SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum,
757f21a9df3SSameer Pujar tegra210_i2s_cget_stereo_to_mono,
758f21a9df3SSameer Pujar tegra210_i2s_cput_stereo_to_mono),
759c0bfa983SSameer Pujar SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum,
760f21a9df3SSameer Pujar tegra210_i2s_cget_mono_to_stereo,
761f21a9df3SSameer Pujar tegra210_i2s_cput_mono_to_stereo),
762c0bfa983SSameer Pujar SOC_ENUM_EXT("Playback Stereo To Mono", tegra210_i2s_stereo_conv_enum,
763f21a9df3SSameer Pujar tegra210_i2s_pget_mono_to_stereo,
764f21a9df3SSameer Pujar tegra210_i2s_pput_mono_to_stereo),
765c0bfa983SSameer Pujar SOC_ENUM_EXT("Playback Mono To Stereo", tegra210_i2s_mono_conv_enum,
766f21a9df3SSameer Pujar tegra210_i2s_pget_stereo_to_mono,
767f21a9df3SSameer Pujar tegra210_i2s_pput_stereo_to_mono),
768c0bfa983SSameer Pujar SOC_SINGLE_EXT("Playback FIFO Threshold", 0, 0, I2S_RX_FIFO_DEPTH - 1,
769f21a9df3SSameer Pujar 0, tegra210_i2s_pget_fifo_th, tegra210_i2s_pput_fifo_th),
770f21a9df3SSameer Pujar SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0,
771f21a9df3SSameer Pujar tegra210_i2s_get_bclk_ratio,
772f21a9df3SSameer Pujar tegra210_i2s_put_bclk_ratio),
773c0bfa983SSameer Pujar };
774c0bfa983SSameer Pujar
775c0bfa983SSameer Pujar static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
776c0bfa983SSameer Pujar SND_SOC_DAPM_AIF_IN_E("RX", NULL, 0, TEGRA210_I2S_RX_ENABLE,
777c0bfa983SSameer Pujar 0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
778c0bfa983SSameer Pujar SND_SOC_DAPM_AIF_OUT_E("TX", NULL, 0, TEGRA210_I2S_TX_ENABLE,
779c0bfa983SSameer Pujar 0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
780c0bfa983SSameer Pujar SND_SOC_DAPM_MIC("MIC", NULL),
781c0bfa983SSameer Pujar SND_SOC_DAPM_SPK("SPK", NULL),
782c0bfa983SSameer Pujar };
783c0bfa983SSameer Pujar
784c0bfa983SSameer Pujar static const struct snd_soc_dapm_route tegra210_i2s_routes[] = {
785c0bfa983SSameer Pujar /* Playback route from XBAR */
786c0bfa983SSameer Pujar { "XBAR-Playback", NULL, "XBAR-TX" },
787c0bfa983SSameer Pujar { "CIF-Playback", NULL, "XBAR-Playback" },
788c0bfa983SSameer Pujar { "RX", NULL, "CIF-Playback" },
789c0bfa983SSameer Pujar { "DAP-Playback", NULL, "RX" },
790c0bfa983SSameer Pujar { "SPK", NULL, "DAP-Playback" },
791c0bfa983SSameer Pujar /* Capture route to XBAR */
792c0bfa983SSameer Pujar { "XBAR-RX", NULL, "XBAR-Capture" },
793c0bfa983SSameer Pujar { "XBAR-Capture", NULL, "CIF-Capture" },
794c0bfa983SSameer Pujar { "CIF-Capture", NULL, "TX" },
795c0bfa983SSameer Pujar { "TX", NULL, "DAP-Capture" },
796c0bfa983SSameer Pujar { "DAP-Capture", NULL, "MIC" },
797c0bfa983SSameer Pujar };
798c0bfa983SSameer Pujar
799c0bfa983SSameer Pujar static const struct snd_soc_component_driver tegra210_i2s_cmpnt = {
800c0bfa983SSameer Pujar .dapm_widgets = tegra210_i2s_widgets,
801c0bfa983SSameer Pujar .num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets),
802c0bfa983SSameer Pujar .dapm_routes = tegra210_i2s_routes,
803c0bfa983SSameer Pujar .num_dapm_routes = ARRAY_SIZE(tegra210_i2s_routes),
804c0bfa983SSameer Pujar .controls = tegra210_i2s_controls,
805c0bfa983SSameer Pujar .num_controls = ARRAY_SIZE(tegra210_i2s_controls),
806c0bfa983SSameer Pujar };
807c0bfa983SSameer Pujar
tegra210_i2s_wr_reg(struct device * dev,unsigned int reg)808c0bfa983SSameer Pujar static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
809c0bfa983SSameer Pujar {
810c0bfa983SSameer Pujar switch (reg) {
811c0bfa983SSameer Pujar case TEGRA210_I2S_RX_ENABLE ... TEGRA210_I2S_RX_SOFT_RESET:
812c0bfa983SSameer Pujar case TEGRA210_I2S_RX_INT_MASK ... TEGRA210_I2S_RX_CLK_TRIM:
813c0bfa983SSameer Pujar case TEGRA210_I2S_TX_ENABLE ... TEGRA210_I2S_TX_SOFT_RESET:
814c0bfa983SSameer Pujar case TEGRA210_I2S_TX_INT_MASK ... TEGRA210_I2S_TX_CLK_TRIM:
815c0bfa983SSameer Pujar case TEGRA210_I2S_ENABLE ... TEGRA210_I2S_CG:
816c0bfa983SSameer Pujar case TEGRA210_I2S_CTRL ... TEGRA210_I2S_CYA:
817c0bfa983SSameer Pujar return true;
818c0bfa983SSameer Pujar default:
819c0bfa983SSameer Pujar return false;
8200246c6cbSTom Rix }
821c0bfa983SSameer Pujar }
822c0bfa983SSameer Pujar
tegra210_i2s_rd_reg(struct device * dev,unsigned int reg)823c0bfa983SSameer Pujar static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
824c0bfa983SSameer Pujar {
825c0bfa983SSameer Pujar if (tegra210_i2s_wr_reg(dev, reg))
826c0bfa983SSameer Pujar return true;
827c0bfa983SSameer Pujar
828c0bfa983SSameer Pujar switch (reg) {
829c0bfa983SSameer Pujar case TEGRA210_I2S_RX_STATUS:
830c0bfa983SSameer Pujar case TEGRA210_I2S_RX_INT_STATUS:
831c0bfa983SSameer Pujar case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
832c0bfa983SSameer Pujar case TEGRA210_I2S_TX_STATUS:
833c0bfa983SSameer Pujar case TEGRA210_I2S_TX_INT_STATUS:
834c0bfa983SSameer Pujar case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
835c0bfa983SSameer Pujar case TEGRA210_I2S_STATUS:
836c0bfa983SSameer Pujar case TEGRA210_I2S_INT_STATUS:
837c0bfa983SSameer Pujar return true;
838c0bfa983SSameer Pujar default:
839c0bfa983SSameer Pujar return false;
8400246c6cbSTom Rix }
841c0bfa983SSameer Pujar }
842c0bfa983SSameer Pujar
tegra210_i2s_volatile_reg(struct device * dev,unsigned int reg)843c0bfa983SSameer Pujar static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
844c0bfa983SSameer Pujar {
845c0bfa983SSameer Pujar switch (reg) {
846c0bfa983SSameer Pujar case TEGRA210_I2S_RX_STATUS:
847c0bfa983SSameer Pujar case TEGRA210_I2S_RX_INT_STATUS:
848c0bfa983SSameer Pujar case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
849c0bfa983SSameer Pujar case TEGRA210_I2S_TX_STATUS:
850c0bfa983SSameer Pujar case TEGRA210_I2S_TX_INT_STATUS:
851c0bfa983SSameer Pujar case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
852c0bfa983SSameer Pujar case TEGRA210_I2S_STATUS:
853c0bfa983SSameer Pujar case TEGRA210_I2S_INT_STATUS:
854c0bfa983SSameer Pujar case TEGRA210_I2S_RX_SOFT_RESET:
855c0bfa983SSameer Pujar case TEGRA210_I2S_TX_SOFT_RESET:
856c0bfa983SSameer Pujar return true;
857c0bfa983SSameer Pujar default:
858c0bfa983SSameer Pujar return false;
8590246c6cbSTom Rix }
860c0bfa983SSameer Pujar }
861c0bfa983SSameer Pujar
862c0bfa983SSameer Pujar static const struct regmap_config tegra210_i2s_regmap_config = {
863c0bfa983SSameer Pujar .reg_bits = 32,
864c0bfa983SSameer Pujar .reg_stride = 4,
865c0bfa983SSameer Pujar .val_bits = 32,
866c0bfa983SSameer Pujar .max_register = TEGRA210_I2S_CYA,
867c0bfa983SSameer Pujar .writeable_reg = tegra210_i2s_wr_reg,
868c0bfa983SSameer Pujar .readable_reg = tegra210_i2s_rd_reg,
869c0bfa983SSameer Pujar .volatile_reg = tegra210_i2s_volatile_reg,
870c0bfa983SSameer Pujar .reg_defaults = tegra210_i2s_reg_defaults,
871c0bfa983SSameer Pujar .num_reg_defaults = ARRAY_SIZE(tegra210_i2s_reg_defaults),
872c0bfa983SSameer Pujar .cache_type = REGCACHE_FLAT,
873c0bfa983SSameer Pujar };
874c0bfa983SSameer Pujar
tegra210_i2s_probe(struct platform_device * pdev)875c0bfa983SSameer Pujar static int tegra210_i2s_probe(struct platform_device *pdev)
876c0bfa983SSameer Pujar {
877c0bfa983SSameer Pujar struct device *dev = &pdev->dev;
878c0bfa983SSameer Pujar struct tegra210_i2s *i2s;
879c0bfa983SSameer Pujar void __iomem *regs;
880c0bfa983SSameer Pujar int err;
881c0bfa983SSameer Pujar
882c0bfa983SSameer Pujar i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
883c0bfa983SSameer Pujar if (!i2s)
884c0bfa983SSameer Pujar return -ENOMEM;
885c0bfa983SSameer Pujar
886c0bfa983SSameer Pujar i2s->rx_fifo_th = DEFAULT_I2S_RX_FIFO_THRESHOLD;
887c0bfa983SSameer Pujar i2s->tx_mask = DEFAULT_I2S_SLOT_MASK;
888c0bfa983SSameer Pujar i2s->rx_mask = DEFAULT_I2S_SLOT_MASK;
889c0bfa983SSameer Pujar i2s->loopback = false;
890c0bfa983SSameer Pujar
891c0bfa983SSameer Pujar dev_set_drvdata(dev, i2s);
892c0bfa983SSameer Pujar
893c0bfa983SSameer Pujar i2s->clk_i2s = devm_clk_get(dev, "i2s");
894c0bfa983SSameer Pujar if (IS_ERR(i2s->clk_i2s)) {
895c0bfa983SSameer Pujar dev_err(dev, "can't retrieve I2S bit clock\n");
896c0bfa983SSameer Pujar return PTR_ERR(i2s->clk_i2s);
897c0bfa983SSameer Pujar }
898c0bfa983SSameer Pujar
899c0bfa983SSameer Pujar /*
900c0bfa983SSameer Pujar * Not an error, as this clock is needed only when some other I/O
901c0bfa983SSameer Pujar * requires input clock from current I2S instance, which is
902c0bfa983SSameer Pujar * configurable from DT.
903c0bfa983SSameer Pujar */
904c0bfa983SSameer Pujar i2s->clk_sync_input = devm_clk_get(dev, "sync_input");
905c0bfa983SSameer Pujar if (IS_ERR(i2s->clk_sync_input))
906c0bfa983SSameer Pujar dev_dbg(dev, "can't retrieve I2S sync input clock\n");
907c0bfa983SSameer Pujar
908c0bfa983SSameer Pujar regs = devm_platform_ioremap_resource(pdev, 0);
909c0bfa983SSameer Pujar if (IS_ERR(regs))
910c0bfa983SSameer Pujar return PTR_ERR(regs);
911c0bfa983SSameer Pujar
912c0bfa983SSameer Pujar i2s->regmap = devm_regmap_init_mmio(dev, regs,
913c0bfa983SSameer Pujar &tegra210_i2s_regmap_config);
914c0bfa983SSameer Pujar if (IS_ERR(i2s->regmap)) {
915c0bfa983SSameer Pujar dev_err(dev, "regmap init failed\n");
916c0bfa983SSameer Pujar return PTR_ERR(i2s->regmap);
917c0bfa983SSameer Pujar }
918c0bfa983SSameer Pujar
919c0bfa983SSameer Pujar regcache_cache_only(i2s->regmap, true);
920c0bfa983SSameer Pujar
921c0bfa983SSameer Pujar err = devm_snd_soc_register_component(dev, &tegra210_i2s_cmpnt,
922c0bfa983SSameer Pujar tegra210_i2s_dais,
923c0bfa983SSameer Pujar ARRAY_SIZE(tegra210_i2s_dais));
924c0bfa983SSameer Pujar if (err) {
925c0bfa983SSameer Pujar dev_err(dev, "can't register I2S component, err: %d\n", err);
926c0bfa983SSameer Pujar return err;
927c0bfa983SSameer Pujar }
928c0bfa983SSameer Pujar
929c0bfa983SSameer Pujar pm_runtime_enable(dev);
930c0bfa983SSameer Pujar
931c0bfa983SSameer Pujar return 0;
932c0bfa983SSameer Pujar }
933c0bfa983SSameer Pujar
tegra210_i2s_remove(struct platform_device * pdev)934*e29df600SUwe Kleine-König static void tegra210_i2s_remove(struct platform_device *pdev)
935c0bfa983SSameer Pujar {
936c0bfa983SSameer Pujar pm_runtime_disable(&pdev->dev);
937c0bfa983SSameer Pujar }
938c0bfa983SSameer Pujar
939c0bfa983SSameer Pujar static const struct dev_pm_ops tegra210_i2s_pm_ops = {
940c0bfa983SSameer Pujar SET_RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend,
941c0bfa983SSameer Pujar tegra210_i2s_runtime_resume, NULL)
942c0bfa983SSameer Pujar SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
943c0bfa983SSameer Pujar pm_runtime_force_resume)
944c0bfa983SSameer Pujar };
945c0bfa983SSameer Pujar
946c0bfa983SSameer Pujar static const struct of_device_id tegra210_i2s_of_match[] = {
947c0bfa983SSameer Pujar { .compatible = "nvidia,tegra210-i2s" },
948c0bfa983SSameer Pujar {},
949c0bfa983SSameer Pujar };
950c0bfa983SSameer Pujar MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match);
951c0bfa983SSameer Pujar
952c0bfa983SSameer Pujar static struct platform_driver tegra210_i2s_driver = {
953c0bfa983SSameer Pujar .driver = {
954c0bfa983SSameer Pujar .name = "tegra210-i2s",
955c0bfa983SSameer Pujar .of_match_table = tegra210_i2s_of_match,
956c0bfa983SSameer Pujar .pm = &tegra210_i2s_pm_ops,
957c0bfa983SSameer Pujar },
958c0bfa983SSameer Pujar .probe = tegra210_i2s_probe,
959*e29df600SUwe Kleine-König .remove_new = tegra210_i2s_remove,
960c0bfa983SSameer Pujar };
961c0bfa983SSameer Pujar module_platform_driver(tegra210_i2s_driver)
962c0bfa983SSameer Pujar
963c0bfa983SSameer Pujar MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
964c0bfa983SSameer Pujar MODULE_DESCRIPTION("Tegra210 ASoC I2S driver");
965c0bfa983SSameer Pujar MODULE_LICENSE("GPL v2");
966