forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
kernel/sound/soc/jz4740/jz4740-i2s.c
....@@ -1,15 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3
- *
4
- * This program is free software; you can redistribute it and/or modify it
5
- * under the terms of the GNU General Public License as published by the
6
- * Free Software Foundation; either version 2 of the License, or (at your
7
- * option) any later version.
8
- *
9
- * You should have received a copy of the GNU General Public License along
10
- * with this program; if not, write to the Free Software Foundation, Inc.,
11
- * 675 Mass Ave, Cambridge, MA 02139, USA.
12
- *
134 */
145
156 #include <linux/init.h>
....@@ -58,12 +49,8 @@
5849
5950 #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12
6051 #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8
61
-#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24
62
-#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16
63
-#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_MASK \
64
- (0xf << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET)
65
-#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_MASK \
66
- (0x1f << JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET)
52
+#define JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24
53
+#define JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16
6754
6855 #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19)
6956 #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16)
....@@ -72,7 +59,8 @@
7259 #define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11)
7360 #define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10)
7461 #define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
75
-#define JZ_AIC_CTRL_FLUSH BIT(8)
62
+#define JZ_AIC_CTRL_TFLUSH BIT(8)
63
+#define JZ_AIC_CTRL_RFLUSH BIT(7)
7664 #define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6)
7765 #define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5)
7866 #define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4)
....@@ -99,7 +87,16 @@
9987
10088 enum jz47xx_i2s_version {
10189 JZ_I2S_JZ4740,
90
+ JZ_I2S_JZ4760,
91
+ JZ_I2S_JZ4770,
10292 JZ_I2S_JZ4780,
93
+};
94
+
95
+struct i2s_soc_info {
96
+ enum jz47xx_i2s_version version;
97
+ struct snd_soc_dai_driver *dai;
98
+
99
+ bool shared_fifo_flush;
103100 };
104101
105102 struct jz4740_i2s {
....@@ -113,7 +110,7 @@
113110 struct snd_dmaengine_dai_dma_data playback_dma_data;
114111 struct snd_dmaengine_dai_dma_data capture_dma_data;
115112
116
- enum jz47xx_i2s_version version;
113
+ const struct i2s_soc_info *soc_info;
117114 };
118115
119116 static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
....@@ -128,19 +125,44 @@
128125 writel(value, i2s->base + reg);
129126 }
130127
128
+static inline void jz4740_i2s_set_bits(const struct jz4740_i2s *i2s,
129
+ unsigned int reg, uint32_t bits)
130
+{
131
+ uint32_t value = jz4740_i2s_read(i2s, reg);
132
+ value |= bits;
133
+ jz4740_i2s_write(i2s, reg, value);
134
+}
135
+
131136 static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
132137 struct snd_soc_dai *dai)
133138 {
134139 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
135
- uint32_t conf, ctrl;
140
+ uint32_t conf;
136141 int ret;
137142
138
- if (dai->active)
143
+ /*
144
+ * When we can flush FIFOs independently, only flush the FIFO
145
+ * that is starting up. We can do this when the DAI is active
146
+ * because it does not disturb other active substreams.
147
+ */
148
+ if (!i2s->soc_info->shared_fifo_flush) {
149
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
150
+ jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH);
151
+ else
152
+ jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_RFLUSH);
153
+ }
154
+
155
+ if (snd_soc_dai_active(dai))
139156 return 0;
140157
141
- ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
142
- ctrl |= JZ_AIC_CTRL_FLUSH;
143
- jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
158
+ /*
159
+ * When there is a shared flush bit for both FIFOs, the TFLUSH
160
+ * bit flushes both FIFOs. Flushing while the DAI is active would
161
+ * cause FIFO underruns in other active substreams so we have to
162
+ * guard this behind the snd_soc_dai_active() check.
163
+ */
164
+ if (i2s->soc_info->shared_fifo_flush)
165
+ jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH);
144166
145167 ret = clk_prepare_enable(i2s->clk_i2s);
146168 if (ret)
....@@ -159,7 +181,7 @@
159181 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
160182 uint32_t conf;
161183
162
- if (dai->active)
184
+ if (snd_soc_dai_active(dai))
163185 return;
164186
165187 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
....@@ -293,7 +315,7 @@
293315 ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
294316 ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
295317
296
- if (i2s->version >= JZ_I2S_JZ4780) {
318
+ if (i2s->soc_info->version >= JZ_I2S_JZ4770) {
297319 div_reg &= ~I2SDIV_IDV_MASK;
298320 div_reg |= (div - 1) << I2SDIV_IDV_SHIFT;
299321 } else {
....@@ -337,12 +359,12 @@
337359 return ret;
338360 }
339361
340
-static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
362
+static int jz4740_i2s_suspend(struct snd_soc_component *component)
341363 {
342
- struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
364
+ struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
343365 uint32_t conf;
344366
345
- if (dai->active) {
367
+ if (snd_soc_component_active(component)) {
346368 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
347369 conf &= ~JZ_AIC_CONF_ENABLE;
348370 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
....@@ -355,9 +377,9 @@
355377 return 0;
356378 }
357379
358
-static int jz4740_i2s_resume(struct snd_soc_dai *dai)
380
+static int jz4740_i2s_resume(struct snd_soc_component *component)
359381 {
360
- struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
382
+ struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
361383 uint32_t conf;
362384 int ret;
363385
....@@ -365,7 +387,7 @@
365387 if (ret)
366388 return ret;
367389
368
- if (dai->active) {
390
+ if (snd_soc_component_active(component)) {
369391 ret = clk_prepare_enable(i2s->clk_i2s);
370392 if (ret) {
371393 clk_disable_unprepare(i2s->clk_aic);
....@@ -411,9 +433,9 @@
411433 snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
412434 &i2s->capture_dma_data);
413435
414
- if (i2s->version >= JZ_I2S_JZ4780) {
415
- conf = (7 << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
416
- (8 << JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
436
+ if (i2s->soc_info->version >= JZ_I2S_JZ4760) {
437
+ conf = (7 << JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
438
+ (8 << JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
417439 JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
418440 JZ_AIC_CONF_I2S |
419441 JZ_AIC_CONF_INTERNAL_CODEC;
....@@ -468,11 +490,20 @@
468490 },
469491 .symmetric_rates = 1,
470492 .ops = &jz4740_i2s_dai_ops,
471
- .suspend = jz4740_i2s_suspend,
472
- .resume = jz4740_i2s_resume,
473493 };
474494
475
-static struct snd_soc_dai_driver jz4780_i2s_dai = {
495
+static const struct i2s_soc_info jz4740_i2s_soc_info = {
496
+ .version = JZ_I2S_JZ4740,
497
+ .dai = &jz4740_i2s_dai,
498
+ .shared_fifo_flush = true,
499
+};
500
+
501
+static const struct i2s_soc_info jz4760_i2s_soc_info = {
502
+ .version = JZ_I2S_JZ4760,
503
+ .dai = &jz4740_i2s_dai,
504
+};
505
+
506
+static struct snd_soc_dai_driver jz4770_i2s_dai = {
476507 .probe = jz4740_i2s_dai_probe,
477508 .remove = jz4740_i2s_dai_remove,
478509 .playback = {
....@@ -488,66 +519,69 @@
488519 .formats = JZ4740_I2S_FMTS,
489520 },
490521 .ops = &jz4740_i2s_dai_ops,
491
- .suspend = jz4740_i2s_suspend,
492
- .resume = jz4740_i2s_resume,
522
+};
523
+
524
+static const struct i2s_soc_info jz4770_i2s_soc_info = {
525
+ .version = JZ_I2S_JZ4770,
526
+ .dai = &jz4770_i2s_dai,
527
+};
528
+
529
+static const struct i2s_soc_info jz4780_i2s_soc_info = {
530
+ .version = JZ_I2S_JZ4780,
531
+ .dai = &jz4770_i2s_dai,
493532 };
494533
495534 static const struct snd_soc_component_driver jz4740_i2s_component = {
496535 .name = "jz4740-i2s",
536
+ .suspend = jz4740_i2s_suspend,
537
+ .resume = jz4740_i2s_resume,
497538 };
498539
499
-#ifdef CONFIG_OF
500540 static const struct of_device_id jz4740_of_matches[] = {
501
- { .compatible = "ingenic,jz4740-i2s", .data = (void *)JZ_I2S_JZ4740 },
502
- { .compatible = "ingenic,jz4780-i2s", .data = (void *)JZ_I2S_JZ4780 },
541
+ { .compatible = "ingenic,jz4740-i2s", .data = &jz4740_i2s_soc_info },
542
+ { .compatible = "ingenic,jz4760-i2s", .data = &jz4760_i2s_soc_info },
543
+ { .compatible = "ingenic,jz4770-i2s", .data = &jz4770_i2s_soc_info },
544
+ { .compatible = "ingenic,jz4780-i2s", .data = &jz4780_i2s_soc_info },
503545 { /* sentinel */ }
504546 };
505547 MODULE_DEVICE_TABLE(of, jz4740_of_matches);
506
-#endif
507548
508549 static int jz4740_i2s_dev_probe(struct platform_device *pdev)
509550 {
551
+ struct device *dev = &pdev->dev;
510552 struct jz4740_i2s *i2s;
511553 struct resource *mem;
512554 int ret;
513
- const struct of_device_id *match;
514555
515
- i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
556
+ i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
516557 if (!i2s)
517558 return -ENOMEM;
518559
519
- match = of_match_device(jz4740_of_matches, &pdev->dev);
520
- if (match)
521
- i2s->version = (enum jz47xx_i2s_version)match->data;
560
+ i2s->soc_info = device_get_match_data(dev);
522561
523562 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
524
- i2s->base = devm_ioremap_resource(&pdev->dev, mem);
563
+ i2s->base = devm_ioremap_resource(dev, mem);
525564 if (IS_ERR(i2s->base))
526565 return PTR_ERR(i2s->base);
527566
528567 i2s->phys_base = mem->start;
529568
530
- i2s->clk_aic = devm_clk_get(&pdev->dev, "aic");
569
+ i2s->clk_aic = devm_clk_get(dev, "aic");
531570 if (IS_ERR(i2s->clk_aic))
532571 return PTR_ERR(i2s->clk_aic);
533572
534
- i2s->clk_i2s = devm_clk_get(&pdev->dev, "i2s");
573
+ i2s->clk_i2s = devm_clk_get(dev, "i2s");
535574 if (IS_ERR(i2s->clk_i2s))
536575 return PTR_ERR(i2s->clk_i2s);
537576
538577 platform_set_drvdata(pdev, i2s);
539578
540
- if (i2s->version == JZ_I2S_JZ4780)
541
- ret = devm_snd_soc_register_component(&pdev->dev,
542
- &jz4740_i2s_component, &jz4780_i2s_dai, 1);
543
- else
544
- ret = devm_snd_soc_register_component(&pdev->dev,
545
- &jz4740_i2s_component, &jz4740_i2s_dai, 1);
546
-
579
+ ret = devm_snd_soc_register_component(dev, &jz4740_i2s_component,
580
+ i2s->soc_info->dai, 1);
547581 if (ret)
548582 return ret;
549583
550
- return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
584
+ return devm_snd_dmaengine_pcm_register(dev, NULL,
551585 SND_DMAENGINE_PCM_FLAG_COMPAT);
552586 }
553587
....@@ -555,7 +589,7 @@
555589 .probe = jz4740_i2s_dev_probe,
556590 .driver = {
557591 .name = "jz4740-i2s",
558
- .of_match_table = of_match_ptr(jz4740_of_matches)
592
+ .of_match_table = jz4740_of_matches,
559593 },
560594 };
561595