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