92
92
#define SUN4I_I2S_RX_CHAN_SEL_REG 0x38
93
93
#define SUN4I_I2S_RX_CHAN_MAP_REG 0x3c
94
94
95
+ /* Defines required for sun8i-h3 support */
96
+ #define SUN8I_I2S_CTRL_BCLK_OUT BIT(18)
97
+ #define SUN8I_I2S_CTRL_LRCK_OUT BIT(17)
98
+
99
+ #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8)
100
+ #define SUN8I_I2S_FMT0_LRCK_PERIOD (period ) ((period - 1) << 8)
101
+
102
+ #define SUN8I_I2S_INT_STA_REG 0x0c
103
+ #define SUN8I_I2S_FIFO_TX_REG 0x20
104
+
105
+ #define SUN8I_I2S_CHAN_CFG_REG 0x30
106
+ #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(6, 4)
107
+ #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM (chan ) (chan - 1)
108
+ #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(2, 0)
109
+ #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM (chan ) (chan - 1)
110
+
111
+ #define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
112
+ #define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
113
+ #define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 11)
114
+ #define SUN8I_I2S_TX_CHAN_OFFSET (offset ) (offset << 12)
115
+ #define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
116
+ #define SUN8I_I2S_TX_CHAN_EN (num_chan ) (((1 << num_chan) - 1) << 4)
117
+
118
+ #define SUN8I_I2S_RX_CHAN_SEL_REG 0x54
119
+ #define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
120
+
95
121
/**
96
122
* struct sun4i_i2s_quirks - Differences between SoC variants.
97
123
*
98
124
* @has_reset: SoC needs reset deasserted.
99
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.
100
130
* @reg_offset_txdata: offset of the tx fifo.
101
131
* @sun4i_i2s_regmap: regmap config to use.
102
132
* @mclk_offset: Value by which mclkdiv needs to be adjusted.
116
146
struct sun4i_i2s_quirks {
117
147
bool has_reset ;
118
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 ;
119
153
unsigned int reg_offset_txdata ; /* TX FIFO */
120
154
const struct regmap_config * sun4i_i2s_regmap ;
121
155
unsigned int mclk_offset ;
@@ -173,6 +207,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = {
173
207
{ .div = 8 , .val = 3 },
174
208
{ .div = 12 , .val = 4 },
175
209
{ .div = 16 , .val = 5 },
210
+ /* TODO - extend divide ratio supported by newer SoCs */
176
211
};
177
212
178
213
static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div [] = {
@@ -184,6 +219,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
184
219
{ .div = 12 , .val = 5 },
185
220
{ .div = 16 , .val = 6 },
186
221
{ .div = 24 , .val = 7 },
222
+ /* TODO - extend divide ratio supported by newer SoCs */
187
223
};
188
224
189
225
static int sun4i_i2s_get_bclk_div (struct sun4i_i2s * i2s ,
@@ -295,6 +331,12 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
295
331
296
332
regmap_field_write (i2s -> field_clkdiv_mclk_en , 1 );
297
333
334
+ /* Set sync period */
335
+ if (i2s -> variant -> has_fmt_set_lrck_period )
336
+ regmap_update_bits (i2s -> regmap , SUN4I_I2S_FMT0_REG ,
337
+ SUN8I_I2S_FMT0_LRCK_PERIOD_MASK ,
338
+ SUN8I_I2S_FMT0_LRCK_PERIOD (32 ));
339
+
298
340
return 0 ;
299
341
}
300
342
@@ -303,12 +345,22 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
303
345
struct snd_soc_dai * dai )
304
346
{
305
347
struct sun4i_i2s * i2s = snd_soc_dai_get_drvdata (dai );
306
- int sr , wss ;
348
+ int sr , wss , channels ;
307
349
u32 width ;
308
350
309
- if (params_channels (params ) != 2 )
351
+ channels = params_channels (params );
352
+ if (channels != 2 )
310
353
return - EINVAL ;
311
354
355
+ if (i2s -> variant -> has_chcfg ) {
356
+ regmap_update_bits (i2s -> regmap , SUN8I_I2S_CHAN_CFG_REG ,
357
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK ,
358
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM (channels ));
359
+ regmap_update_bits (i2s -> regmap , SUN8I_I2S_CHAN_CFG_REG ,
360
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK ,
361
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM (channels ));
362
+ }
363
+
312
364
/* Map the channels for playback and capture */
313
365
regmap_field_write (i2s -> field_txchanmap , 0x76543210 );
314
366
regmap_field_write (i2s -> field_rxchanmap , 0x00003210 );
@@ -320,6 +372,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
320
372
regmap_field_write (i2s -> field_rxchansel ,
321
373
SUN4I_I2S_CHAN_SEL (params_channels (params )));
322
374
375
+ if (i2s -> variant -> has_chsel_tx_chen )
376
+ regmap_update_bits (i2s -> regmap , SUN8I_I2S_TX_CHAN_SEL_REG ,
377
+ SUN8I_I2S_TX_CHAN_EN_MASK ,
378
+ SUN8I_I2S_TX_CHAN_EN (channels ));
379
+
323
380
switch (params_physical_width (params )) {
324
381
case 16 :
325
382
width = DMA_SLAVE_BUSWIDTH_2_BYTES ;
@@ -352,13 +409,15 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
352
409
{
353
410
struct sun4i_i2s * i2s = snd_soc_dai_get_drvdata (dai );
354
411
u32 val ;
412
+ u32 offset = 0 ;
355
413
u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL ;
356
414
u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL ;
357
415
358
416
/* DAI Mode */
359
417
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK ) {
360
418
case SND_SOC_DAIFMT_I2S :
361
419
val = SUN4I_I2S_FMT0_FMT_I2S ;
420
+ offset = 1 ;
362
421
break ;
363
422
case SND_SOC_DAIFMT_LEFT_J :
364
423
val = SUN4I_I2S_FMT0_FMT_LEFT_J ;
@@ -370,6 +429,21 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
370
429
return - EINVAL ;
371
430
}
372
431
432
+ if (i2s -> variant -> has_chsel_offset ) {
433
+ /*
434
+ * offset being set indicates that we're connected to an i2s
435
+ * device, however offset is only used on the sun8i block and
436
+ * i2s shares the same setting with the LJ format. Increment
437
+ * val so that the bit to value to write is correct.
438
+ */
439
+ if (offset > 0 )
440
+ val ++ ;
441
+ /* blck offset determines whether i2s or LJ */
442
+ regmap_update_bits (i2s -> regmap , SUN8I_I2S_TX_CHAN_SEL_REG ,
443
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK ,
444
+ SUN8I_I2S_TX_CHAN_OFFSET (offset ));
445
+ }
446
+
373
447
regmap_field_write (i2s -> field_fmt_mode , val );
374
448
375
449
/* DAI clock polarity */
@@ -413,6 +487,29 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
413
487
regmap_update_bits (i2s -> regmap , SUN4I_I2S_CTRL_REG ,
414
488
SUN4I_I2S_CTRL_MODE_MASK ,
415
489
val );
490
+ } else {
491
+ /*
492
+ * The newer i2s block does not have a slave select bit,
493
+ * instead the clk pins are configured as inputs.
494
+ */
495
+ /* DAI clock master masks */
496
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK ) {
497
+ case SND_SOC_DAIFMT_CBS_CFS :
498
+ /* BCLK and LRCLK master */
499
+ val = SUN8I_I2S_CTRL_BCLK_OUT |
500
+ SUN8I_I2S_CTRL_LRCK_OUT ;
501
+ break ;
502
+ case SND_SOC_DAIFMT_CBM_CFM :
503
+ /* BCLK and LRCLK slave */
504
+ val = 0 ;
505
+ break ;
506
+ default :
507
+ return - EINVAL ;
508
+ }
509
+ regmap_update_bits (i2s -> regmap , SUN4I_I2S_CTRL_REG ,
510
+ SUN8I_I2S_CTRL_BCLK_OUT |
511
+ SUN8I_I2S_CTRL_LRCK_OUT ,
512
+ val );
416
513
}
417
514
418
515
/* Set significant bits in our FIFOs */
@@ -653,6 +750,27 @@ static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg)
653
750
}
654
751
}
655
752
753
+ static bool sun8i_i2s_rd_reg (struct device * dev , unsigned int reg )
754
+ {
755
+ switch (reg ) {
756
+ case SUN8I_I2S_FIFO_TX_REG :
757
+ return false;
758
+
759
+ default :
760
+ return true;
761
+ }
762
+ }
763
+
764
+ static bool sun8i_i2s_volatile_reg (struct device * dev , unsigned int reg )
765
+ {
766
+ if (reg == SUN8I_I2S_INT_STA_REG )
767
+ return true;
768
+ if (reg == SUN8I_I2S_FIFO_TX_REG )
769
+ return false;
770
+
771
+ return sun4i_i2s_volatile_reg (dev , reg );
772
+ }
773
+
656
774
static const struct reg_default sun4i_i2s_reg_defaults [] = {
657
775
{ SUN4I_I2S_CTRL_REG , 0x00000000 },
658
776
{ SUN4I_I2S_FMT0_REG , 0x0000000c },
@@ -666,6 +784,20 @@ static const struct reg_default sun4i_i2s_reg_defaults[] = {
666
784
{ SUN4I_I2S_RX_CHAN_MAP_REG , 0x00003210 },
667
785
};
668
786
787
+ static const struct reg_default sun8i_i2s_reg_defaults [] = {
788
+ { SUN4I_I2S_CTRL_REG , 0x00060000 },
789
+ { SUN4I_I2S_FMT0_REG , 0x00000033 },
790
+ { SUN4I_I2S_FMT1_REG , 0x00000030 },
791
+ { SUN4I_I2S_FIFO_CTRL_REG , 0x000400f0 },
792
+ { SUN4I_I2S_DMA_INT_CTRL_REG , 0x00000000 },
793
+ { SUN4I_I2S_CLK_DIV_REG , 0x00000000 },
794
+ { SUN8I_I2S_CHAN_CFG_REG , 0x00000000 },
795
+ { SUN8I_I2S_TX_CHAN_SEL_REG , 0x00000000 },
796
+ { SUN8I_I2S_TX_CHAN_MAP_REG , 0x00000000 },
797
+ { SUN8I_I2S_RX_CHAN_SEL_REG , 0x00000000 },
798
+ { SUN8I_I2S_RX_CHAN_MAP_REG , 0x00000000 },
799
+ };
800
+
669
801
static const struct regmap_config sun4i_i2s_regmap_config = {
670
802
.reg_bits = 32 ,
671
803
.reg_stride = 4 ,
@@ -680,6 +812,19 @@ static const struct regmap_config sun4i_i2s_regmap_config = {
680
812
.volatile_reg = sun4i_i2s_volatile_reg ,
681
813
};
682
814
815
+ static const struct regmap_config sun8i_i2s_regmap_config = {
816
+ .reg_bits = 32 ,
817
+ .reg_stride = 4 ,
818
+ .val_bits = 32 ,
819
+ .max_register = SUN8I_I2S_RX_CHAN_MAP_REG ,
820
+ .cache_type = REGCACHE_FLAT ,
821
+ .reg_defaults = sun8i_i2s_reg_defaults ,
822
+ .num_reg_defaults = ARRAY_SIZE (sun8i_i2s_reg_defaults ),
823
+ .writeable_reg = sun4i_i2s_wr_reg ,
824
+ .readable_reg = sun8i_i2s_rd_reg ,
825
+ .volatile_reg = sun8i_i2s_volatile_reg ,
826
+ };
827
+
683
828
static int sun4i_i2s_runtime_resume (struct device * dev )
684
829
{
685
830
struct sun4i_i2s * i2s = dev_get_drvdata (dev );
@@ -752,6 +897,29 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
752
897
.field_rxchansel = REG_FIELD (SUN4I_I2S_RX_CHAN_SEL_REG , 0 , 2 ),
753
898
};
754
899
900
+ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
901
+ .has_reset = true,
902
+ .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG ,
903
+ .sun4i_i2s_regmap = & sun8i_i2s_regmap_config ,
904
+ .mclk_offset = 1 ,
905
+ .bclk_offset = 2 ,
906
+ .fmt_offset = 3 ,
907
+ .has_fmt_set_lrck_period = true,
908
+ .has_chcfg = true,
909
+ .has_chsel_tx_chen = true,
910
+ .has_chsel_offset = true,
911
+ .field_clkdiv_mclk_en = REG_FIELD (SUN4I_I2S_CLK_DIV_REG , 8 , 8 ),
912
+ .field_fmt_wss = REG_FIELD (SUN4I_I2S_FMT0_REG , 0 , 2 ),
913
+ .field_fmt_sr = REG_FIELD (SUN4I_I2S_FMT0_REG , 4 , 6 ),
914
+ .field_fmt_bclk = REG_FIELD (SUN4I_I2S_FMT0_REG , 7 , 7 ),
915
+ .field_fmt_lrclk = REG_FIELD (SUN4I_I2S_FMT0_REG , 19 , 19 ),
916
+ .field_fmt_mode = REG_FIELD (SUN4I_I2S_CTRL_REG , 4 , 5 ),
917
+ .field_txchanmap = REG_FIELD (SUN8I_I2S_TX_CHAN_MAP_REG , 0 , 31 ),
918
+ .field_rxchanmap = REG_FIELD (SUN8I_I2S_RX_CHAN_MAP_REG , 0 , 31 ),
919
+ .field_txchansel = REG_FIELD (SUN8I_I2S_TX_CHAN_SEL_REG , 0 , 2 ),
920
+ .field_rxchansel = REG_FIELD (SUN8I_I2S_RX_CHAN_SEL_REG , 0 , 2 ),
921
+ };
922
+
755
923
static int sun4i_i2s_init_regmap_fields (struct device * dev ,
756
924
struct sun4i_i2s * i2s )
757
925
{
@@ -952,6 +1120,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
952
1120
.compatible = "allwinner,sun6i-a31-i2s" ,
953
1121
.data = & sun6i_a31_i2s_quirks ,
954
1122
},
1123
+ {
1124
+ .compatible = "allwinner,sun8i-h3-i2s" ,
1125
+ .data = & sun8i_h3_i2s_quirks ,
1126
+ },
955
1127
{}
956
1128
};
957
1129
MODULE_DEVICE_TABLE (of , sun4i_i2s_match );
0 commit comments