1
2
3
4
5
6#include <linux/clk.h>
7#include <linux/module.h>
8#include <linux/of_platform.h>
9#include <sound/pcm_params.h>
10#include <sound/soc.h>
11#include <sound/soc-dai.h>
12
13#include "axg-tdm.h"
14
15enum {
16 TDM_IFACE_PAD,
17 TDM_IFACE_LOOPBACK,
18};
19
20static unsigned int axg_tdm_slots_total(u32 *mask)
21{
22 unsigned int slots = 0;
23 int i;
24
25 if (!mask)
26 return 0;
27
28
29 for (i = 0; i < AXG_TDM_NUM_LANES; i++)
30 slots += hweight32(mask[i]);
31
32 return slots;
33}
34
35int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
36 u32 *rx_mask, unsigned int slots,
37 unsigned int slot_width)
38{
39 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
40 struct axg_tdm_stream *tx = (struct axg_tdm_stream *)
41 dai->playback_dma_data;
42 struct axg_tdm_stream *rx = (struct axg_tdm_stream *)
43 dai->capture_dma_data;
44 unsigned int tx_slots, rx_slots;
45
46 tx_slots = axg_tdm_slots_total(tx_mask);
47 rx_slots = axg_tdm_slots_total(rx_mask);
48
49
50 if (!tx_slots && !rx_slots) {
51 dev_err(dai->dev, "interface has no slot\n");
52 return -EINVAL;
53 }
54
55
56
57
58
59 if (tx) {
60 tx->mask = tx_mask;
61 dai->driver->playback.channels_max = tx_slots;
62 }
63
64 if (rx) {
65 rx->mask = rx_mask;
66 dai->driver->capture.channels_max = rx_slots;
67 }
68
69 iface->slots = slots;
70
71 switch (slot_width) {
72 case 0:
73
74 iface->slot_width = 32;
75 break;
76 case 8:
77 case 16:
78 case 24:
79 case 32:
80 iface->slot_width = slot_width;
81 break;
82 default:
83 dev_err(dai->dev, "unsupported slot width: %d\n", slot_width);
84 return -EINVAL;
85 }
86
87 return 0;
88}
89EXPORT_SYMBOL_GPL(axg_tdm_set_tdm_slots);
90
91static int axg_tdm_iface_set_sysclk(struct snd_soc_dai *dai, int clk_id,
92 unsigned int freq, int dir)
93{
94 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
95 int ret = -ENOTSUPP;
96
97 if (dir == SND_SOC_CLOCK_OUT && clk_id == 0) {
98 if (!iface->mclk) {
99 dev_warn(dai->dev, "master clock not provided\n");
100 } else {
101 ret = clk_set_rate(iface->mclk, freq);
102 if (!ret)
103 iface->mclk_rate = freq;
104 }
105 }
106
107 return ret;
108}
109
110static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
111{
112 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
113
114
115 if (fmt & (SND_SOC_DAIFMT_CBS_CFM | SND_SOC_DAIFMT_CBM_CFS)) {
116 dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n");
117 return -EINVAL;
118 }
119
120
121 if (!iface->mclk && (fmt & SND_SOC_DAIFMT_CBS_CFS)) {
122 dev_err(dai->dev, "cpu clock master: mclk missing\n");
123 return -ENODEV;
124 }
125
126 iface->fmt = fmt;
127 return 0;
128}
129
130static int axg_tdm_iface_startup(struct snd_pcm_substream *substream,
131 struct snd_soc_dai *dai)
132{
133 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
134 struct axg_tdm_stream *ts =
135 snd_soc_dai_get_dma_data(dai, substream);
136 int ret;
137
138 if (!axg_tdm_slots_total(ts->mask)) {
139 dev_err(dai->dev, "interface has not slots\n");
140 return -EINVAL;
141 }
142
143
144 if (dai->component->active) {
145 ret = snd_pcm_hw_constraint_single(substream->runtime,
146 SNDRV_PCM_HW_PARAM_RATE,
147 iface->rate);
148 if (ret < 0) {
149 dev_err(dai->dev,
150 "can't set iface rate constraint\n");
151 return ret;
152 }
153 }
154
155 return 0;
156}
157
158static int axg_tdm_iface_set_stream(struct snd_pcm_substream *substream,
159 struct snd_pcm_hw_params *params,
160 struct snd_soc_dai *dai)
161{
162 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
163 struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
164 unsigned int channels = params_channels(params);
165 unsigned int width = params_width(params);
166
167
168 iface->rate = params_rate(params);
169
170
171 if (axg_tdm_slots_total(ts->mask) < channels) {
172 dev_err(dai->dev, "not enough slots for channels\n");
173 return -EINVAL;
174 }
175
176 if (iface->slot_width < width) {
177 dev_err(dai->dev, "incompatible slots width for stream\n");
178 return -EINVAL;
179 }
180
181
182 ts->physical_width = params_physical_width(params);
183 ts->width = params_width(params);
184 ts->channels = params_channels(params);
185
186 return 0;
187}
188
189static int axg_tdm_iface_set_lrclk(struct snd_soc_dai *dai,
190 struct snd_pcm_hw_params *params)
191{
192 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
193 unsigned int ratio_num;
194 int ret;
195
196 ret = clk_set_rate(iface->lrclk, params_rate(params));
197 if (ret) {
198 dev_err(dai->dev, "setting sample clock failed: %d\n", ret);
199 return ret;
200 }
201
202 switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
203 case SND_SOC_DAIFMT_I2S:
204 case SND_SOC_DAIFMT_LEFT_J:
205 case SND_SOC_DAIFMT_RIGHT_J:
206
207 ratio_num = 1;
208 break;
209
210 case SND_SOC_DAIFMT_DSP_A:
211 case SND_SOC_DAIFMT_DSP_B:
212
213
214
215
216
217
218 ratio_num = 0;
219 break;
220
221 default:
222 return -EINVAL;
223 }
224
225 ret = clk_set_duty_cycle(iface->lrclk, ratio_num, 2);
226 if (ret) {
227 dev_err(dai->dev,
228 "setting sample clock duty cycle failed: %d\n", ret);
229 return ret;
230 }
231
232
233 ret = clk_set_phase(iface->lrclk,
234 axg_tdm_lrclk_invert(iface->fmt) ? 180 : 0);
235 if (ret) {
236 dev_err(dai->dev,
237 "setting sample clock phase failed: %d\n", ret);
238 return ret;
239 }
240
241 return 0;
242}
243
244static int axg_tdm_iface_set_sclk(struct snd_soc_dai *dai,
245 struct snd_pcm_hw_params *params)
246{
247 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
248 unsigned long srate;
249 int ret;
250
251 srate = iface->slots * iface->slot_width * params_rate(params);
252
253 if (!iface->mclk_rate) {
254
255 clk_set_rate(iface->mclk, 4 * srate);
256 } else {
257
258 if (iface->mclk_rate % srate) {
259 dev_err(dai->dev,
260 "can't derive sclk %lu from mclk %lu\n",
261 srate, iface->mclk_rate);
262 return -EINVAL;
263 }
264 }
265
266 ret = clk_set_rate(iface->sclk, srate);
267 if (ret) {
268 dev_err(dai->dev, "setting bit clock failed: %d\n", ret);
269 return ret;
270 }
271
272
273 ret = clk_set_phase(iface->sclk,
274 axg_tdm_sclk_invert(iface->fmt) ? 0 : 180);
275 if (ret) {
276 dev_err(dai->dev, "setting bit clock phase failed: %d\n", ret);
277 return ret;
278 }
279
280 return ret;
281}
282
283static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
284 struct snd_pcm_hw_params *params,
285 struct snd_soc_dai *dai)
286{
287 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
288 int ret;
289
290 switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
291 case SND_SOC_DAIFMT_I2S:
292 case SND_SOC_DAIFMT_LEFT_J:
293 case SND_SOC_DAIFMT_RIGHT_J:
294 if (iface->slots > 2) {
295 dev_err(dai->dev, "bad slot number for format: %d\n",
296 iface->slots);
297 return -EINVAL;
298 }
299 break;
300
301 case SND_SOC_DAI_FORMAT_DSP_A:
302 case SND_SOC_DAI_FORMAT_DSP_B:
303 break;
304
305 default:
306 dev_err(dai->dev, "unsupported dai format\n");
307 return -EINVAL;
308 }
309
310 ret = axg_tdm_iface_set_stream(substream, params, dai);
311 if (ret)
312 return ret;
313
314 if (iface->fmt & SND_SOC_DAIFMT_CBS_CFS) {
315 ret = axg_tdm_iface_set_sclk(dai, params);
316 if (ret)
317 return ret;
318
319 ret = axg_tdm_iface_set_lrclk(dai, params);
320 if (ret)
321 return ret;
322 }
323
324 return 0;
325}
326
327static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream,
328 struct snd_soc_dai *dai)
329{
330 struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
331
332
333 axg_tdm_stream_stop(ts);
334
335 return 0;
336}
337
338static int axg_tdm_iface_prepare(struct snd_pcm_substream *substream,
339 struct snd_soc_dai *dai)
340{
341 struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
342
343
344 return axg_tdm_stream_reset(ts);
345}
346
347static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai)
348{
349 if (dai->capture_dma_data)
350 axg_tdm_stream_free(dai->capture_dma_data);
351
352 if (dai->playback_dma_data)
353 axg_tdm_stream_free(dai->playback_dma_data);
354
355 return 0;
356}
357
358static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai)
359{
360 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
361
362 if (dai->capture_widget) {
363 dai->capture_dma_data = axg_tdm_stream_alloc(iface);
364 if (!dai->capture_dma_data)
365 return -ENOMEM;
366 }
367
368 if (dai->playback_widget) {
369 dai->playback_dma_data = axg_tdm_stream_alloc(iface);
370 if (!dai->playback_dma_data) {
371 axg_tdm_iface_remove_dai(dai);
372 return -ENOMEM;
373 }
374 }
375
376 return 0;
377}
378
379static const struct snd_soc_dai_ops axg_tdm_iface_ops = {
380 .set_sysclk = axg_tdm_iface_set_sysclk,
381 .set_fmt = axg_tdm_iface_set_fmt,
382 .startup = axg_tdm_iface_startup,
383 .hw_params = axg_tdm_iface_hw_params,
384 .prepare = axg_tdm_iface_prepare,
385 .hw_free = axg_tdm_iface_hw_free,
386};
387
388
389static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = {
390 [TDM_IFACE_PAD] = {
391 .name = "TDM Pad",
392 .playback = {
393 .stream_name = "Playback",
394 .channels_min = 1,
395 .channels_max = AXG_TDM_CHANNEL_MAX,
396 .rates = AXG_TDM_RATES,
397 .formats = AXG_TDM_FORMATS,
398 },
399 .capture = {
400 .stream_name = "Capture",
401 .channels_min = 1,
402 .channels_max = AXG_TDM_CHANNEL_MAX,
403 .rates = AXG_TDM_RATES,
404 .formats = AXG_TDM_FORMATS,
405 },
406 .id = TDM_IFACE_PAD,
407 .ops = &axg_tdm_iface_ops,
408 .probe = axg_tdm_iface_probe_dai,
409 .remove = axg_tdm_iface_remove_dai,
410 },
411 [TDM_IFACE_LOOPBACK] = {
412 .name = "TDM Loopback",
413 .capture = {
414 .stream_name = "Loopback",
415 .channels_min = 1,
416 .channels_max = AXG_TDM_CHANNEL_MAX,
417 .rates = AXG_TDM_RATES,
418 .formats = AXG_TDM_FORMATS,
419 },
420 .id = TDM_IFACE_LOOPBACK,
421 .ops = &axg_tdm_iface_ops,
422 .probe = axg_tdm_iface_probe_dai,
423 .remove = axg_tdm_iface_remove_dai,
424 },
425};
426
427static int axg_tdm_iface_set_bias_level(struct snd_soc_component *component,
428 enum snd_soc_bias_level level)
429{
430 struct axg_tdm_iface *iface = snd_soc_component_get_drvdata(component);
431 enum snd_soc_bias_level now =
432 snd_soc_component_get_bias_level(component);
433 int ret = 0;
434
435 switch (level) {
436 case SND_SOC_BIAS_PREPARE:
437 if (now == SND_SOC_BIAS_STANDBY)
438 ret = clk_prepare_enable(iface->mclk);
439 break;
440
441 case SND_SOC_BIAS_STANDBY:
442 if (now == SND_SOC_BIAS_PREPARE)
443 clk_disable_unprepare(iface->mclk);
444 break;
445
446 case SND_SOC_BIAS_OFF:
447 case SND_SOC_BIAS_ON:
448 break;
449 }
450
451 return ret;
452}
453
454static const struct snd_soc_component_driver axg_tdm_iface_component_drv = {
455 .set_bias_level = axg_tdm_iface_set_bias_level,
456};
457
458static const struct of_device_id axg_tdm_iface_of_match[] = {
459 { .compatible = "amlogic,axg-tdm-iface", },
460 {}
461};
462MODULE_DEVICE_TABLE(of, axg_tdm_iface_of_match);
463
464static int axg_tdm_iface_probe(struct platform_device *pdev)
465{
466 struct device *dev = &pdev->dev;
467 struct snd_soc_dai_driver *dai_drv;
468 struct axg_tdm_iface *iface;
469 int ret, i;
470
471 iface = devm_kzalloc(dev, sizeof(*iface), GFP_KERNEL);
472 if (!iface)
473 return -ENOMEM;
474 platform_set_drvdata(pdev, iface);
475
476
477
478
479
480
481 dai_drv = devm_kcalloc(dev, ARRAY_SIZE(axg_tdm_iface_dai_drv),
482 sizeof(*dai_drv), GFP_KERNEL);
483 if (!dai_drv)
484 return -ENOMEM;
485
486 for (i = 0; i < ARRAY_SIZE(axg_tdm_iface_dai_drv); i++)
487 memcpy(&dai_drv[i], &axg_tdm_iface_dai_drv[i],
488 sizeof(*dai_drv));
489
490
491 iface->sclk = devm_clk_get(dev, "sclk");
492 if (IS_ERR(iface->sclk)) {
493 ret = PTR_ERR(iface->sclk);
494 if (ret != -EPROBE_DEFER)
495 dev_err(dev, "failed to get sclk: %d\n", ret);
496 return ret;
497 }
498
499
500 iface->lrclk = devm_clk_get(dev, "lrclk");
501 if (IS_ERR(iface->lrclk)) {
502 ret = PTR_ERR(iface->lrclk);
503 if (ret != -EPROBE_DEFER)
504 dev_err(dev, "failed to get lrclk: %d\n", ret);
505 return ret;
506 }
507
508
509
510
511
512
513
514 iface->mclk = devm_clk_get(dev, "mclk");
515 if (IS_ERR(iface->mclk)) {
516 ret = PTR_ERR(iface->mclk);
517 if (ret == -ENOENT) {
518 iface->mclk = NULL;
519 } else {
520 if (ret != -EPROBE_DEFER)
521 dev_err(dev, "failed to get mclk: %d\n", ret);
522 return ret;
523 }
524 }
525
526 return devm_snd_soc_register_component(dev,
527 &axg_tdm_iface_component_drv, dai_drv,
528 ARRAY_SIZE(axg_tdm_iface_dai_drv));
529}
530
531static struct platform_driver axg_tdm_iface_pdrv = {
532 .probe = axg_tdm_iface_probe,
533 .driver = {
534 .name = "axg-tdm-iface",
535 .of_match_table = axg_tdm_iface_of_match,
536 },
537};
538module_platform_driver(axg_tdm_iface_pdrv);
539
540MODULE_DESCRIPTION("Amlogic AXG TDM interface driver");
541MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
542MODULE_LICENSE("GPL v2");
543