hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/sound/soc/sunxi/sun4i-i2s.c
....@@ -1,14 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2015 Andrea Venturi
34 * Andrea Venturi <be17068@iperbole.bo.it>
45 *
56 * Copyright (C) 2016 Maxime Ripard
67 * Maxime Ripard <maxime.ripard@free-electrons.com>
7
- *
8
- * This program is free software; you can redistribute it and/or
9
- * modify it under the terms of the GNU General Public License as
10
- * published by the Free Software Foundation; either version 2 of
11
- * the License, or (at your option) any later version.
128 */
139
1410 #include <linux/clk.h>
....@@ -50,8 +46,6 @@
5046 #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
5147 #define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0)
5248 #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
53
-#define SUN4I_I2S_FMT0_POLARITY_INVERTED (1)
54
-#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
5549
5650 #define SUN4I_I2S_FMT1_REG 0x08
5751 #define SUN4I_I2S_FIFO_TX_REG 0x0c
....@@ -84,6 +78,7 @@
8478 #define SUN4I_I2S_RX_CNT_REG 0x2c
8579
8680 #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30
81
+#define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0)
8782 #define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0)
8883
8984 #define SUN4I_I2S_TX_CHAN_MAP_REG 0x34
....@@ -96,8 +91,19 @@
9691 #define SUN8I_I2S_CTRL_BCLK_OUT BIT(18)
9792 #define SUN8I_I2S_CTRL_LRCK_OUT BIT(17)
9893
94
+#define SUN8I_I2S_CTRL_MODE_MASK GENMASK(5, 4)
95
+#define SUN8I_I2S_CTRL_MODE_RIGHT (2 << 4)
96
+#define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4)
97
+#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4)
98
+
99
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19)
100
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19)
101
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19)
99102 #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8)
100103 #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
104
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7)
105
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7)
106
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7)
101107
102108 #define SUN8I_I2S_INT_STA_REG 0x0c
103109 #define SUN8I_I2S_FIFO_TX_REG 0x20
....@@ -118,55 +124,47 @@
118124 #define SUN8I_I2S_RX_CHAN_SEL_REG 0x54
119125 #define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
120126
127
+struct sun4i_i2s;
128
+
121129 /**
122130 * struct sun4i_i2s_quirks - Differences between SoC variants.
123
- *
124131 * @has_reset: SoC needs reset deasserted.
125
- * @has_slave_select_bit: SoC has a bit to enable slave mode.
126
- * @has_fmt_set_lrck_period: SoC requires lrclk period to be set.
127
- * @has_chcfg: tx and rx slot number need to be set.
128
- * @has_chsel_tx_chen: SoC requires that the tx channels are enabled.
129
- * @has_chsel_offset: SoC uses offset for selecting dai operational mode.
130132 * @reg_offset_txdata: offset of the tx fifo.
131133 * @sun4i_i2s_regmap: regmap config to use.
132
- * @mclk_offset: Value by which mclkdiv needs to be adjusted.
133
- * @bclk_offset: Value by which bclkdiv needs to be adjusted.
134
- * @fmt_offset: Value by which wss and sr needs to be adjusted.
135134 * @field_clkdiv_mclk_en: regmap field to enable mclk output.
136135 * @field_fmt_wss: regmap field to set word select size.
137136 * @field_fmt_sr: regmap field to set sample resolution.
138
- * @field_fmt_bclk: regmap field to set clk polarity.
139
- * @field_fmt_lrclk: regmap field to set frame polarity.
140
- * @field_fmt_mode: regmap field to set the operational mode.
141
- * @field_txchanmap: location of the tx channel mapping register.
142
- * @field_rxchanmap: location of the rx channel mapping register.
143
- * @field_txchansel: location of the tx channel select bit fields.
144
- * @field_rxchansel: location of the rx channel select bit fields.
137
+ * @bclk_dividers: bit clock dividers array
138
+ * @num_bclk_dividers: number of bit clock dividers
139
+ * @mclk_dividers: mclk dividers array
140
+ * @num_mclk_dividers: number of mclk dividers
141
+ * @get_bclk_parent_rate: callback to get bclk parent rate
142
+ * @get_sr: callback to get sample resolution
143
+ * @get_wss: callback to get word select size
144
+ * @set_chan_cfg: callback to set channel configuration
145
+ * @set_fmt: callback to set format
145146 */
146147 struct sun4i_i2s_quirks {
147148 bool has_reset;
148
- bool has_slave_select_bit;
149
- bool has_fmt_set_lrck_period;
150
- bool has_chcfg;
151
- bool has_chsel_tx_chen;
152
- bool has_chsel_offset;
153149 unsigned int reg_offset_txdata; /* TX FIFO */
154150 const struct regmap_config *sun4i_i2s_regmap;
155
- unsigned int mclk_offset;
156
- unsigned int bclk_offset;
157
- unsigned int fmt_offset;
158151
159152 /* Register fields for i2s */
160153 struct reg_field field_clkdiv_mclk_en;
161154 struct reg_field field_fmt_wss;
162155 struct reg_field field_fmt_sr;
163
- struct reg_field field_fmt_bclk;
164
- struct reg_field field_fmt_lrclk;
165
- struct reg_field field_fmt_mode;
166
- struct reg_field field_txchanmap;
167
- struct reg_field field_rxchanmap;
168
- struct reg_field field_txchansel;
169
- struct reg_field field_rxchansel;
156
+
157
+ const struct sun4i_i2s_clk_div *bclk_dividers;
158
+ unsigned int num_bclk_dividers;
159
+ const struct sun4i_i2s_clk_div *mclk_dividers;
160
+ unsigned int num_mclk_dividers;
161
+
162
+ unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
163
+ s8 (*get_sr)(const struct sun4i_i2s *, int);
164
+ s8 (*get_wss)(const struct sun4i_i2s *, int);
165
+ int (*set_chan_cfg)(const struct sun4i_i2s *,
166
+ const struct snd_pcm_hw_params *);
167
+ int (*set_fmt)(const struct sun4i_i2s *, unsigned int);
170168 };
171169
172170 struct sun4i_i2s {
....@@ -175,7 +173,10 @@
175173 struct regmap *regmap;
176174 struct reset_control *rst;
177175
176
+ unsigned int format;
178177 unsigned int mclk_freq;
178
+ unsigned int slots;
179
+ unsigned int slot_width;
179180
180181 struct snd_dmaengine_dai_dma_data capture_dma_data;
181182 struct snd_dmaengine_dai_dma_data playback_dma_data;
....@@ -184,13 +185,6 @@
184185 struct regmap_field *field_clkdiv_mclk_en;
185186 struct regmap_field *field_fmt_wss;
186187 struct regmap_field *field_fmt_sr;
187
- struct regmap_field *field_fmt_bclk;
188
- struct regmap_field *field_fmt_lrclk;
189
- struct regmap_field *field_fmt_mode;
190
- struct regmap_field *field_txchanmap;
191
- struct regmap_field *field_rxchanmap;
192
- struct regmap_field *field_txchansel;
193
- struct regmap_field *field_rxchansel;
194188
195189 const struct sun4i_i2s_quirks *variant;
196190 };
....@@ -222,16 +216,46 @@
222216 /* TODO - extend divide ratio supported by newer SoCs */
223217 };
224218
219
+static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = {
220
+ { .div = 1, .val = 1 },
221
+ { .div = 2, .val = 2 },
222
+ { .div = 4, .val = 3 },
223
+ { .div = 6, .val = 4 },
224
+ { .div = 8, .val = 5 },
225
+ { .div = 12, .val = 6 },
226
+ { .div = 16, .val = 7 },
227
+ { .div = 24, .val = 8 },
228
+ { .div = 32, .val = 9 },
229
+ { .div = 48, .val = 10 },
230
+ { .div = 64, .val = 11 },
231
+ { .div = 96, .val = 12 },
232
+ { .div = 128, .val = 13 },
233
+ { .div = 176, .val = 14 },
234
+ { .div = 192, .val = 15 },
235
+};
236
+
237
+static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
238
+{
239
+ return i2s->mclk_freq;
240
+}
241
+
242
+static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
243
+{
244
+ return clk_get_rate(i2s->mod_clk);
245
+}
246
+
225247 static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
226248 unsigned long parent_rate,
227249 unsigned int sampling_rate,
250
+ unsigned int channels,
228251 unsigned int word_size)
229252 {
230
- int div = parent_rate / sampling_rate / word_size / 2;
253
+ const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers;
254
+ int div = parent_rate / sampling_rate / word_size / channels;
231255 int i;
232256
233
- for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) {
234
- const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i];
257
+ for (i = 0; i < i2s->variant->num_bclk_dividers; i++) {
258
+ const struct sun4i_i2s_clk_div *bdiv = &dividers[i];
235259
236260 if (bdiv->div == div)
237261 return bdiv->val;
....@@ -241,15 +265,15 @@
241265 }
242266
243267 static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
244
- unsigned int oversample_rate,
245
- unsigned int module_rate,
246
- unsigned int sampling_rate)
268
+ unsigned long parent_rate,
269
+ unsigned long mclk_rate)
247270 {
248
- int div = module_rate / sampling_rate / oversample_rate;
271
+ const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers;
272
+ int div = parent_rate / mclk_rate;
249273 int i;
250274
251
- for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) {
252
- const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i];
275
+ for (i = 0; i < i2s->variant->num_mclk_dividers; i++) {
276
+ const struct sun4i_i2s_clk_div *mdiv = &dividers[i];
253277
254278 if (mdiv->div == div)
255279 return mdiv->val;
....@@ -272,10 +296,11 @@
272296
273297 static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
274298 unsigned int rate,
275
- unsigned int word_size)
299
+ unsigned int slots,
300
+ unsigned int slot_width)
276301 {
277302 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
278
- unsigned int oversample_rate, clk_rate;
303
+ unsigned int oversample_rate, clk_rate, bclk_parent_rate;
279304 int bclk_div, mclk_div;
280305 int ret;
281306
....@@ -317,23 +342,19 @@
317342 return -EINVAL;
318343 }
319344
320
- bclk_div = sun4i_i2s_get_bclk_div(i2s, i2s->mclk_freq,
321
- rate, word_size);
345
+ bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);
346
+ bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
347
+ rate, slots, slot_width);
322348 if (bclk_div < 0) {
323349 dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
324350 return -EINVAL;
325351 }
326352
327
- mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
328
- clk_rate, rate);
353
+ mclk_div = sun4i_i2s_get_mclk_div(i2s, clk_rate, i2s->mclk_freq);
329354 if (mclk_div < 0) {
330355 dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div);
331356 return -EINVAL;
332357 }
333
-
334
- /* Adjust the clock division values if needed */
335
- bclk_div += i2s->variant->bclk_offset;
336
- mclk_div += i2s->variant->mclk_offset;
337358
338359 regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
339360 SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
....@@ -341,11 +362,114 @@
341362
342363 regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
343364
344
- /* Set sync period */
345
- if (i2s->variant->has_fmt_set_lrck_period)
346
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
347
- SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
348
- SUN8I_I2S_FMT0_LRCK_PERIOD(32));
365
+ return 0;
366
+}
367
+
368
+static s8 sun4i_i2s_get_sr(const struct sun4i_i2s *i2s, int width)
369
+{
370
+ if (width < 16 || width > 24)
371
+ return -EINVAL;
372
+
373
+ if (width % 4)
374
+ return -EINVAL;
375
+
376
+ return (width - 16) / 4;
377
+}
378
+
379
+static s8 sun4i_i2s_get_wss(const struct sun4i_i2s *i2s, int width)
380
+{
381
+ if (width < 16 || width > 32)
382
+ return -EINVAL;
383
+
384
+ if (width % 4)
385
+ return -EINVAL;
386
+
387
+ return (width - 16) / 4;
388
+}
389
+
390
+static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width)
391
+{
392
+ if (width % 4)
393
+ return -EINVAL;
394
+
395
+ if (width < 8 || width > 32)
396
+ return -EINVAL;
397
+
398
+ return (width - 8) / 4 + 1;
399
+}
400
+
401
+static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
402
+ const struct snd_pcm_hw_params *params)
403
+{
404
+ unsigned int channels = params_channels(params);
405
+
406
+ /* Map the channels for playback and capture */
407
+ regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);
408
+ regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);
409
+
410
+ /* Configure the channels */
411
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
412
+ SUN4I_I2S_CHAN_SEL_MASK,
413
+ SUN4I_I2S_CHAN_SEL(channels));
414
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG,
415
+ SUN4I_I2S_CHAN_SEL_MASK,
416
+ SUN4I_I2S_CHAN_SEL(channels));
417
+
418
+ return 0;
419
+}
420
+
421
+static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
422
+ const struct snd_pcm_hw_params *params)
423
+{
424
+ unsigned int channels = params_channels(params);
425
+ unsigned int slots = channels;
426
+ unsigned int lrck_period;
427
+
428
+ if (i2s->slots)
429
+ slots = i2s->slots;
430
+
431
+ /* Map the channels for playback and capture */
432
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
433
+ regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
434
+
435
+ /* Configure the channels */
436
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
437
+ SUN4I_I2S_CHAN_SEL_MASK,
438
+ SUN4I_I2S_CHAN_SEL(channels));
439
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
440
+ SUN4I_I2S_CHAN_SEL_MASK,
441
+ SUN4I_I2S_CHAN_SEL(channels));
442
+
443
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
444
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
445
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
446
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
447
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
448
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
449
+
450
+ switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
451
+ case SND_SOC_DAIFMT_DSP_A:
452
+ case SND_SOC_DAIFMT_DSP_B:
453
+ lrck_period = params_physical_width(params) * slots;
454
+ break;
455
+
456
+ case SND_SOC_DAIFMT_LEFT_J:
457
+ case SND_SOC_DAIFMT_RIGHT_J:
458
+ case SND_SOC_DAIFMT_I2S:
459
+ lrck_period = params_physical_width(params);
460
+ break;
461
+
462
+ default:
463
+ return -EINVAL;
464
+ }
465
+
466
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
467
+ SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
468
+ SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
469
+
470
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
471
+ SUN8I_I2S_TX_CHAN_EN_MASK,
472
+ SUN8I_I2S_TX_CHAN_EN(channels));
349473
350474 return 0;
351475 }
....@@ -355,40 +479,24 @@
355479 struct snd_soc_dai *dai)
356480 {
357481 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
358
- int sr, wss, channels;
482
+ unsigned int word_size = params_width(params);
483
+ unsigned int slot_width = params_physical_width(params);
484
+ unsigned int channels = params_channels(params);
485
+ unsigned int slots = channels;
486
+ int ret, sr, wss;
359487 u32 width;
360488
361
- channels = params_channels(params);
362
- if (channels != 2) {
363
- dev_err(dai->dev, "Unsupported number of channels: %d\n",
364
- channels);
365
- return -EINVAL;
489
+ if (i2s->slots)
490
+ slots = i2s->slots;
491
+
492
+ if (i2s->slot_width)
493
+ slot_width = i2s->slot_width;
494
+
495
+ ret = i2s->variant->set_chan_cfg(i2s, params);
496
+ if (ret < 0) {
497
+ dev_err(dai->dev, "Invalid channel configuration\n");
498
+ return ret;
366499 }
367
-
368
- if (i2s->variant->has_chcfg) {
369
- regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
370
- SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
371
- SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
372
- regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
373
- SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
374
- SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
375
- }
376
-
377
- /* Map the channels for playback and capture */
378
- regmap_field_write(i2s->field_txchanmap, 0x76543210);
379
- regmap_field_write(i2s->field_rxchanmap, 0x00003210);
380
-
381
- /* Configure the channels */
382
- regmap_field_write(i2s->field_txchansel,
383
- SUN4I_I2S_CHAN_SEL(params_channels(params)));
384
-
385
- regmap_field_write(i2s->field_rxchansel,
386
- SUN4I_I2S_CHAN_SEL(params_channels(params)));
387
-
388
- if (i2s->variant->has_chsel_tx_chen)
389
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
390
- SUN8I_I2S_TX_CHAN_EN_MASK,
391
- SUN8I_I2S_TX_CHAN_EN(channels));
392500
393501 switch (params_physical_width(params)) {
394502 case 16:
....@@ -401,144 +509,205 @@
401509 }
402510 i2s->playback_dma_data.addr_width = width;
403511
404
- switch (params_width(params)) {
405
- case 16:
406
- sr = 0;
407
- wss = 0;
408
- break;
409
-
410
- default:
411
- dev_err(dai->dev, "Unsupported sample width: %d\n",
412
- params_width(params));
512
+ sr = i2s->variant->get_sr(i2s, word_size);
513
+ if (sr < 0)
413514 return -EINVAL;
414
- }
415515
416
- regmap_field_write(i2s->field_fmt_wss,
417
- wss + i2s->variant->fmt_offset);
418
- regmap_field_write(i2s->field_fmt_sr,
419
- sr + i2s->variant->fmt_offset);
516
+ wss = i2s->variant->get_wss(i2s, slot_width);
517
+ if (wss < 0)
518
+ return -EINVAL;
519
+
520
+ regmap_field_write(i2s->field_fmt_wss, wss);
521
+ regmap_field_write(i2s->field_fmt_sr, sr);
420522
421523 return sun4i_i2s_set_clk_rate(dai, params_rate(params),
422
- params_width(params));
524
+ slots, slot_width);
423525 }
424526
425
-static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
527
+static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
528
+ unsigned int fmt)
426529 {
427
- struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
428530 u32 val;
429
- u32 offset = 0;
430
- u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
431
- u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
432
-
433
- /* DAI Mode */
434
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
435
- case SND_SOC_DAIFMT_I2S:
436
- val = SUN4I_I2S_FMT0_FMT_I2S;
437
- offset = 1;
438
- break;
439
- case SND_SOC_DAIFMT_LEFT_J:
440
- val = SUN4I_I2S_FMT0_FMT_LEFT_J;
441
- break;
442
- case SND_SOC_DAIFMT_RIGHT_J:
443
- val = SUN4I_I2S_FMT0_FMT_RIGHT_J;
444
- break;
445
- default:
446
- dev_err(dai->dev, "Unsupported format: %d\n",
447
- fmt & SND_SOC_DAIFMT_FORMAT_MASK);
448
- return -EINVAL;
449
- }
450
-
451
- if (i2s->variant->has_chsel_offset) {
452
- /*
453
- * offset being set indicates that we're connected to an i2s
454
- * device, however offset is only used on the sun8i block and
455
- * i2s shares the same setting with the LJ format. Increment
456
- * val so that the bit to value to write is correct.
457
- */
458
- if (offset > 0)
459
- val++;
460
- /* blck offset determines whether i2s or LJ */
461
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
462
- SUN8I_I2S_TX_CHAN_OFFSET_MASK,
463
- SUN8I_I2S_TX_CHAN_OFFSET(offset));
464
-
465
- regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
466
- SUN8I_I2S_TX_CHAN_OFFSET_MASK,
467
- SUN8I_I2S_TX_CHAN_OFFSET(offset));
468
- }
469
-
470
- regmap_field_write(i2s->field_fmt_mode, val);
471531
472532 /* DAI clock polarity */
473533 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
474534 case SND_SOC_DAIFMT_IB_IF:
475535 /* Invert both clocks */
476
- bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
477
- lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
536
+ val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
537
+ SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
478538 break;
479539 case SND_SOC_DAIFMT_IB_NF:
480540 /* Invert bit clock */
481
- bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
541
+ val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED;
482542 break;
483543 case SND_SOC_DAIFMT_NB_IF:
484544 /* Invert frame clock */
485
- lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
545
+ val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
486546 break;
487547 case SND_SOC_DAIFMT_NB_NF:
548
+ val = 0;
488549 break;
489550 default:
490
- dev_err(dai->dev, "Unsupported clock polarity: %d\n",
491
- fmt & SND_SOC_DAIFMT_INV_MASK);
492551 return -EINVAL;
493552 }
494553
495
- regmap_field_write(i2s->field_fmt_bclk, bclk_polarity);
496
- regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
554
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
555
+ SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK |
556
+ SUN4I_I2S_FMT0_BCLK_POLARITY_MASK,
557
+ val);
497558
498
- if (i2s->variant->has_slave_select_bit) {
499
- /* DAI clock master masks */
500
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
501
- case SND_SOC_DAIFMT_CBS_CFS:
502
- /* BCLK and LRCLK master */
503
- val = SUN4I_I2S_CTRL_MODE_MASTER;
504
- break;
505
- case SND_SOC_DAIFMT_CBM_CFM:
506
- /* BCLK and LRCLK slave */
507
- val = SUN4I_I2S_CTRL_MODE_SLAVE;
508
- break;
509
- default:
510
- dev_err(dai->dev, "Unsupported slave setting: %d\n",
511
- fmt & SND_SOC_DAIFMT_MASTER_MASK);
512
- return -EINVAL;
513
- }
514
- regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
515
- SUN4I_I2S_CTRL_MODE_MASK,
516
- val);
517
- } else {
518
- /*
519
- * The newer i2s block does not have a slave select bit,
520
- * instead the clk pins are configured as inputs.
521
- */
522
- /* DAI clock master masks */
523
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
524
- case SND_SOC_DAIFMT_CBS_CFS:
525
- /* BCLK and LRCLK master */
526
- val = SUN8I_I2S_CTRL_BCLK_OUT |
527
- SUN8I_I2S_CTRL_LRCK_OUT;
528
- break;
529
- case SND_SOC_DAIFMT_CBM_CFM:
530
- /* BCLK and LRCLK slave */
531
- val = 0;
532
- break;
533
- default:
534
- dev_err(dai->dev, "Unsupported slave setting: %d\n",
535
- fmt & SND_SOC_DAIFMT_MASTER_MASK);
536
- return -EINVAL;
537
- }
538
- regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
539
- SUN8I_I2S_CTRL_BCLK_OUT |
540
- SUN8I_I2S_CTRL_LRCK_OUT,
541
- val);
559
+ /* DAI Mode */
560
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
561
+ case SND_SOC_DAIFMT_I2S:
562
+ val = SUN4I_I2S_FMT0_FMT_I2S;
563
+ break;
564
+
565
+ case SND_SOC_DAIFMT_LEFT_J:
566
+ val = SUN4I_I2S_FMT0_FMT_LEFT_J;
567
+ break;
568
+
569
+ case SND_SOC_DAIFMT_RIGHT_J:
570
+ val = SUN4I_I2S_FMT0_FMT_RIGHT_J;
571
+ break;
572
+
573
+ default:
574
+ return -EINVAL;
575
+ }
576
+
577
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
578
+ SUN4I_I2S_FMT0_FMT_MASK, val);
579
+
580
+ /* DAI clock master masks */
581
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
582
+ case SND_SOC_DAIFMT_CBS_CFS:
583
+ /* BCLK and LRCLK master */
584
+ val = SUN4I_I2S_CTRL_MODE_MASTER;
585
+ break;
586
+
587
+ case SND_SOC_DAIFMT_CBM_CFM:
588
+ /* BCLK and LRCLK slave */
589
+ val = SUN4I_I2S_CTRL_MODE_SLAVE;
590
+ break;
591
+
592
+ default:
593
+ return -EINVAL;
594
+ }
595
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
596
+ SUN4I_I2S_CTRL_MODE_MASK, val);
597
+ return 0;
598
+}
599
+
600
+static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
601
+ unsigned int fmt)
602
+{
603
+ u32 mode, val;
604
+ u8 offset;
605
+
606
+ /*
607
+ * DAI clock polarity
608
+ *
609
+ * The setup for LRCK contradicts the datasheet, but under a
610
+ * scope it's clear that the LRCK polarity is reversed
611
+ * compared to the expected polarity on the bus.
612
+ */
613
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
614
+ case SND_SOC_DAIFMT_IB_IF:
615
+ /* Invert both clocks */
616
+ val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
617
+ break;
618
+ case SND_SOC_DAIFMT_IB_NF:
619
+ /* Invert bit clock */
620
+ val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED |
621
+ SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
622
+ break;
623
+ case SND_SOC_DAIFMT_NB_IF:
624
+ /* Invert frame clock */
625
+ val = 0;
626
+ break;
627
+ case SND_SOC_DAIFMT_NB_NF:
628
+ val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
629
+ break;
630
+ default:
631
+ return -EINVAL;
632
+ }
633
+
634
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
635
+ SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
636
+ SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
637
+ val);
638
+
639
+ /* DAI Mode */
640
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
641
+ case SND_SOC_DAIFMT_DSP_A:
642
+ mode = SUN8I_I2S_CTRL_MODE_PCM;
643
+ offset = 1;
644
+ break;
645
+
646
+ case SND_SOC_DAIFMT_DSP_B:
647
+ mode = SUN8I_I2S_CTRL_MODE_PCM;
648
+ offset = 0;
649
+ break;
650
+
651
+ case SND_SOC_DAIFMT_I2S:
652
+ mode = SUN8I_I2S_CTRL_MODE_LEFT;
653
+ offset = 1;
654
+ break;
655
+
656
+ case SND_SOC_DAIFMT_LEFT_J:
657
+ mode = SUN8I_I2S_CTRL_MODE_LEFT;
658
+ offset = 0;
659
+ break;
660
+
661
+ case SND_SOC_DAIFMT_RIGHT_J:
662
+ mode = SUN8I_I2S_CTRL_MODE_RIGHT;
663
+ offset = 0;
664
+ break;
665
+
666
+ default:
667
+ return -EINVAL;
668
+ }
669
+
670
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
671
+ SUN8I_I2S_CTRL_MODE_MASK, mode);
672
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
673
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK,
674
+ SUN8I_I2S_TX_CHAN_OFFSET(offset));
675
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
676
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK,
677
+ SUN8I_I2S_TX_CHAN_OFFSET(offset));
678
+
679
+ /* DAI clock master masks */
680
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
681
+ case SND_SOC_DAIFMT_CBS_CFS:
682
+ /* BCLK and LRCLK master */
683
+ val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT;
684
+ break;
685
+
686
+ case SND_SOC_DAIFMT_CBM_CFM:
687
+ /* BCLK and LRCLK slave */
688
+ val = 0;
689
+ break;
690
+
691
+ default:
692
+ return -EINVAL;
693
+ }
694
+
695
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
696
+ SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
697
+ val);
698
+
699
+ return 0;
700
+}
701
+
702
+static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
703
+{
704
+ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
705
+ int ret;
706
+
707
+ ret = i2s->variant->set_fmt(i2s, fmt);
708
+ if (ret) {
709
+ dev_err(dai->dev, "Unsupported format configuration\n");
710
+ return ret;
542711 }
543712
544713 /* Set significant bits in our FIFOs */
....@@ -547,6 +716,9 @@
547716 SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
548717 SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
549718 SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
719
+
720
+ i2s->format = fmt;
721
+
550722 return 0;
551723 }
552724
....@@ -649,40 +821,6 @@
649821 return 0;
650822 }
651823
652
-static int sun4i_i2s_startup(struct snd_pcm_substream *substream,
653
- struct snd_soc_dai *dai)
654
-{
655
- struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
656
-
657
- /* Enable the whole hardware block */
658
- regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
659
- SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
660
-
661
- /* Enable the first output line */
662
- regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
663
- SUN4I_I2S_CTRL_SDO_EN_MASK,
664
- SUN4I_I2S_CTRL_SDO_EN(0));
665
-
666
-
667
- return clk_prepare_enable(i2s->mod_clk);
668
-}
669
-
670
-static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream,
671
- struct snd_soc_dai *dai)
672
-{
673
- struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
674
-
675
- clk_disable_unprepare(i2s->mod_clk);
676
-
677
- /* Disable our output lines */
678
- regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
679
- SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
680
-
681
- /* Disable the whole hardware block */
682
- regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
683
- SUN4I_I2S_CTRL_GL_EN, 0);
684
-}
685
-
686824 static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
687825 unsigned int freq, int dir)
688826 {
....@@ -696,12 +834,26 @@
696834 return 0;
697835 }
698836
837
+static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,
838
+ unsigned int tx_mask, unsigned int rx_mask,
839
+ int slots, int slot_width)
840
+{
841
+ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
842
+
843
+ if (slots > 8)
844
+ return -EINVAL;
845
+
846
+ i2s->slots = slots;
847
+ i2s->slot_width = slot_width;
848
+
849
+ return 0;
850
+}
851
+
699852 static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
700853 .hw_params = sun4i_i2s_hw_params,
701854 .set_fmt = sun4i_i2s_set_fmt,
702855 .set_sysclk = sun4i_i2s_set_sysclk,
703
- .shutdown = sun4i_i2s_shutdown,
704
- .startup = sun4i_i2s_startup,
856
+ .set_tdm_slot = sun4i_i2s_set_tdm_slot,
705857 .trigger = sun4i_i2s_trigger,
706858 };
707859
....@@ -722,15 +874,15 @@
722874 .probe = sun4i_i2s_dai_probe,
723875 .capture = {
724876 .stream_name = "Capture",
725
- .channels_min = 2,
726
- .channels_max = 2,
877
+ .channels_min = 1,
878
+ .channels_max = 8,
727879 .rates = SNDRV_PCM_RATE_8000_192000,
728880 .formats = SNDRV_PCM_FMTBIT_S16_LE,
729881 },
730882 .playback = {
731883 .stream_name = "Playback",
732
- .channels_min = 2,
733
- .channels_max = 2,
884
+ .channels_min = 1,
885
+ .channels_max = 8,
734886 .rates = SNDRV_PCM_RATE_8000_192000,
735887 .formats = SNDRV_PCM_FMTBIT_S16_LE,
736888 },
....@@ -874,6 +1026,21 @@
8741026 goto err_disable_clk;
8751027 }
8761028
1029
+ /* Enable the whole hardware block */
1030
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
1031
+ SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
1032
+
1033
+ /* Enable the first output line */
1034
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
1035
+ SUN4I_I2S_CTRL_SDO_EN_MASK,
1036
+ SUN4I_I2S_CTRL_SDO_EN(0));
1037
+
1038
+ ret = clk_prepare_enable(i2s->mod_clk);
1039
+ if (ret) {
1040
+ dev_err(dev, "Failed to enable module clock\n");
1041
+ goto err_disable_clk;
1042
+ }
1043
+
8771044 return 0;
8781045
8791046 err_disable_clk:
....@@ -884,6 +1051,16 @@
8841051 static int sun4i_i2s_runtime_suspend(struct device *dev)
8851052 {
8861053 struct sun4i_i2s *i2s = dev_get_drvdata(dev);
1054
+
1055
+ clk_disable_unprepare(i2s->mod_clk);
1056
+
1057
+ /* Disable our output lines */
1058
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
1059
+ SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
1060
+
1061
+ /* Disable the whole hardware block */
1062
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
1063
+ SUN4I_I2S_CTRL_GL_EN, 0);
8871064
8881065 regcache_cache_only(i2s->regmap, true);
8891066
....@@ -899,14 +1076,15 @@
8991076 .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
9001077 .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
9011078 .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
902
- .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
903
- .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
904
- .has_slave_select_bit = true,
905
- .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
906
- .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
907
- .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
908
- .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
909
- .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
1079
+ .bclk_dividers = sun4i_i2s_bclk_div,
1080
+ .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
1081
+ .mclk_dividers = sun4i_i2s_mclk_div,
1082
+ .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div),
1083
+ .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
1084
+ .get_sr = sun4i_i2s_get_sr,
1085
+ .get_wss = sun4i_i2s_get_wss,
1086
+ .set_chan_cfg = sun4i_i2s_set_chan_cfg,
1087
+ .set_fmt = sun4i_i2s_set_soc_fmt,
9101088 };
9111089
9121090 static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
....@@ -916,16 +1094,22 @@
9161094 .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
9171095 .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
9181096 .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
919
- .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
920
- .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
921
- .has_slave_select_bit = true,
922
- .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
923
- .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
924
- .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
925
- .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
926
- .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
1097
+ .bclk_dividers = sun4i_i2s_bclk_div,
1098
+ .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
1099
+ .mclk_dividers = sun4i_i2s_mclk_div,
1100
+ .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div),
1101
+ .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
1102
+ .get_sr = sun4i_i2s_get_sr,
1103
+ .get_wss = sun4i_i2s_get_wss,
1104
+ .set_chan_cfg = sun4i_i2s_set_chan_cfg,
1105
+ .set_fmt = sun4i_i2s_set_soc_fmt,
9271106 };
9281107
1108
+/*
1109
+ * This doesn't describe the TDM controller documented in the A83t
1110
+ * datasheet, but the three undocumented I2S controller that use the
1111
+ * older design.
1112
+ */
9291113 static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
9301114 .has_reset = true,
9311115 .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
....@@ -933,37 +1117,51 @@
9331117 .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
9341118 .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
9351119 .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
936
- .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
937
- .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
938
- .has_slave_select_bit = true,
939
- .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
940
- .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
941
- .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
942
- .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
943
- .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
1120
+ .bclk_dividers = sun4i_i2s_bclk_div,
1121
+ .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
1122
+ .mclk_dividers = sun4i_i2s_mclk_div,
1123
+ .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div),
1124
+ .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
1125
+ .get_sr = sun4i_i2s_get_sr,
1126
+ .get_wss = sun4i_i2s_get_wss,
1127
+ .set_chan_cfg = sun4i_i2s_set_chan_cfg,
1128
+ .set_fmt = sun4i_i2s_set_soc_fmt,
9441129 };
9451130
9461131 static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
9471132 .has_reset = true,
9481133 .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
9491134 .sun4i_i2s_regmap = &sun8i_i2s_regmap_config,
950
- .mclk_offset = 1,
951
- .bclk_offset = 2,
952
- .fmt_offset = 3,
953
- .has_fmt_set_lrck_period = true,
954
- .has_chcfg = true,
955
- .has_chsel_tx_chen = true,
956
- .has_chsel_offset = true,
9571135 .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
9581136 .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
9591137 .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
960
- .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
961
- .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
962
- .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5),
963
- .field_txchanmap = REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31),
964
- .field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31),
965
- .field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2),
966
- .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2),
1138
+ .bclk_dividers = sun8i_i2s_clk_div,
1139
+ .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
1140
+ .mclk_dividers = sun8i_i2s_clk_div,
1141
+ .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
1142
+ .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate,
1143
+ .get_sr = sun8i_i2s_get_sr_wss,
1144
+ .get_wss = sun8i_i2s_get_sr_wss,
1145
+ .set_chan_cfg = sun8i_i2s_set_chan_cfg,
1146
+ .set_fmt = sun8i_i2s_set_soc_fmt,
1147
+};
1148
+
1149
+static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
1150
+ .has_reset = true,
1151
+ .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
1152
+ .sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
1153
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
1154
+ .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
1155
+ .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
1156
+ .bclk_dividers = sun4i_i2s_bclk_div,
1157
+ .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
1158
+ .mclk_dividers = sun4i_i2s_mclk_div,
1159
+ .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div),
1160
+ .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
1161
+ .get_sr = sun4i_i2s_get_sr,
1162
+ .get_wss = sun4i_i2s_get_wss,
1163
+ .set_chan_cfg = sun4i_i2s_set_chan_cfg,
1164
+ .set_fmt = sun4i_i2s_set_soc_fmt,
9671165 };
9681166
9691167 static int sun4i_i2s_init_regmap_fields(struct device *dev,
....@@ -987,46 +1185,7 @@
9871185 if (IS_ERR(i2s->field_fmt_sr))
9881186 return PTR_ERR(i2s->field_fmt_sr);
9891187
990
- i2s->field_fmt_bclk =
991
- devm_regmap_field_alloc(dev, i2s->regmap,
992
- i2s->variant->field_fmt_bclk);
993
- if (IS_ERR(i2s->field_fmt_bclk))
994
- return PTR_ERR(i2s->field_fmt_bclk);
995
-
996
- i2s->field_fmt_lrclk =
997
- devm_regmap_field_alloc(dev, i2s->regmap,
998
- i2s->variant->field_fmt_lrclk);
999
- if (IS_ERR(i2s->field_fmt_lrclk))
1000
- return PTR_ERR(i2s->field_fmt_lrclk);
1001
-
1002
- i2s->field_fmt_mode =
1003
- devm_regmap_field_alloc(dev, i2s->regmap,
1004
- i2s->variant->field_fmt_mode);
1005
- if (IS_ERR(i2s->field_fmt_mode))
1006
- return PTR_ERR(i2s->field_fmt_mode);
1007
-
1008
- i2s->field_txchanmap =
1009
- devm_regmap_field_alloc(dev, i2s->regmap,
1010
- i2s->variant->field_txchanmap);
1011
- if (IS_ERR(i2s->field_txchanmap))
1012
- return PTR_ERR(i2s->field_txchanmap);
1013
-
1014
- i2s->field_rxchanmap =
1015
- devm_regmap_field_alloc(dev, i2s->regmap,
1016
- i2s->variant->field_rxchanmap);
1017
- if (IS_ERR(i2s->field_rxchanmap))
1018
- return PTR_ERR(i2s->field_rxchanmap);
1019
-
1020
- i2s->field_txchansel =
1021
- devm_regmap_field_alloc(dev, i2s->regmap,
1022
- i2s->variant->field_txchansel);
1023
- if (IS_ERR(i2s->field_txchansel))
1024
- return PTR_ERR(i2s->field_txchansel);
1025
-
1026
- i2s->field_rxchansel =
1027
- devm_regmap_field_alloc(dev, i2s->regmap,
1028
- i2s->variant->field_rxchansel);
1029
- return PTR_ERR_OR_ZERO(i2s->field_rxchansel);
1188
+ return 0;
10301189 }
10311190
10321191 static int sun4i_i2s_probe(struct platform_device *pdev)
....@@ -1047,10 +1206,8 @@
10471206 return PTR_ERR(regs);
10481207
10491208 irq = platform_get_irq(pdev, 0);
1050
- if (irq < 0) {
1051
- dev_err(&pdev->dev, "Can't retrieve our interrupt\n");
1209
+ if (irq < 0)
10521210 return irq;
1053
- }
10541211
10551212 i2s->variant = of_device_get_match_data(&pdev->dev);
10561213 if (!i2s->variant) {
....@@ -1108,23 +1265,23 @@
11081265 goto err_pm_disable;
11091266 }
11101267
1111
- ret = devm_snd_soc_register_component(&pdev->dev,
1112
- &sun4i_i2s_component,
1113
- &sun4i_i2s_dai, 1);
1268
+ ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s);
11141269 if (ret) {
1115
- dev_err(&pdev->dev, "Could not register DAI\n");
1270
+ dev_err(&pdev->dev, "Could not initialise regmap fields\n");
11161271 goto err_suspend;
11171272 }
11181273
1119
- ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
1274
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
11201275 if (ret) {
11211276 dev_err(&pdev->dev, "Could not register PCM\n");
11221277 goto err_suspend;
11231278 }
11241279
1125
- ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s);
1280
+ ret = devm_snd_soc_register_component(&pdev->dev,
1281
+ &sun4i_i2s_component,
1282
+ &sun4i_i2s_dai, 1);
11261283 if (ret) {
1127
- dev_err(&pdev->dev, "Could not initialise regmap fields\n");
1284
+ dev_err(&pdev->dev, "Could not register DAI\n");
11281285 goto err_suspend;
11291286 }
11301287
....@@ -1144,8 +1301,6 @@
11441301 static int sun4i_i2s_remove(struct platform_device *pdev)
11451302 {
11461303 struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev);
1147
-
1148
- snd_dmaengine_pcm_unregister(&pdev->dev);
11491304
11501305 pm_runtime_disable(&pdev->dev);
11511306 if (!pm_runtime_status_suspended(&pdev->dev))
....@@ -1174,6 +1329,10 @@
11741329 .compatible = "allwinner,sun8i-h3-i2s",
11751330 .data = &sun8i_h3_i2s_quirks,
11761331 },
1332
+ {
1333
+ .compatible = "allwinner,sun50i-a64-codec-i2s",
1334
+ .data = &sun50i_a64_codec_i2s_quirks,
1335
+ },
11771336 {}
11781337 };
11791338 MODULE_DEVICE_TABLE(of, sun4i_i2s_match);