Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: sun4i-i2s: Add support for DSP formats

In addition to the I2S format, the controller also supports the DSP_*
formats.

This requires some extra care on the LRCK period calculation, since the
controller, with the PCM formats, require that the value set is no longer
the periods of LRCK for a single channel, but for all of them.

Let's add the code to deal with this, and support the DSP_A and DSP_B
formats.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://lore.kernel.org/r/5562db1ac8759f12b1b87c3258223eed629ef771.1566392800.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Maxime Ripard and committed by
Mark Brown
7ae7834e 84884c7a

+35 -9
+35 -9
sound/soc/sunxi/sun4i-i2s.c
··· 130 130 * struct sun4i_i2s_quirks - Differences between SoC variants. 131 131 * 132 132 * @has_reset: SoC needs reset deasserted. 133 - * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. 134 133 * @reg_offset_txdata: offset of the tx fifo. 135 134 * @sun4i_i2s_regmap: regmap config to use. 136 135 * @field_clkdiv_mclk_en: regmap field to enable mclk output. ··· 138 139 */ 139 140 struct sun4i_i2s_quirks { 140 141 bool has_reset; 141 - bool has_fmt_set_lrck_period; 142 142 unsigned int reg_offset_txdata; /* TX FIFO */ 143 143 const struct regmap_config *sun4i_i2s_regmap; 144 144 ··· 165 167 struct regmap *regmap; 166 168 struct reset_control *rst; 167 169 170 + unsigned int format; 168 171 unsigned int mclk_freq; 169 172 unsigned int slots; 170 173 unsigned int slot_width; ··· 354 355 355 356 regmap_field_write(i2s->field_clkdiv_mclk_en, 1); 356 357 357 - /* Set sync period */ 358 - if (i2s->variant->has_fmt_set_lrck_period) 359 - regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 360 - SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, 361 - SUN8I_I2S_FMT0_LRCK_PERIOD(slot_width)); 362 - 363 358 return 0; 364 359 } 365 360 ··· 415 422 { 416 423 unsigned int channels = params_channels(params); 417 424 unsigned int slots = channels; 425 + unsigned int lrck_period; 418 426 419 427 if (i2s->slots) 420 428 slots = i2s->slots; ··· 438 444 regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, 439 445 SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, 440 446 SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); 447 + 448 + switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { 449 + case SND_SOC_DAIFMT_DSP_A: 450 + case SND_SOC_DAIFMT_DSP_B: 451 + case SND_SOC_DAIFMT_LEFT_J: 452 + case SND_SOC_DAIFMT_RIGHT_J: 453 + lrck_period = params_physical_width(params) * slots; 454 + break; 455 + 456 + case SND_SOC_DAIFMT_I2S: 457 + lrck_period = params_physical_width(params); 458 + break; 459 + 460 + default: 461 + return -EINVAL; 462 + } 463 + 464 + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 465 + SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, 466 + SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); 441 467 442 468 regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, 443 469 SUN8I_I2S_TX_CHAN_EN_MASK, ··· 630 616 631 617 /* DAI Mode */ 632 618 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 619 + case SND_SOC_DAIFMT_DSP_A: 620 + mode = SUN8I_I2S_CTRL_MODE_PCM; 621 + offset = 1; 622 + break; 623 + 624 + case SND_SOC_DAIFMT_DSP_B: 625 + mode = SUN8I_I2S_CTRL_MODE_PCM; 626 + offset = 0; 627 + break; 628 + 633 629 case SND_SOC_DAIFMT_I2S: 634 630 mode = SUN8I_I2S_CTRL_MODE_LEFT; 635 631 offset = 1; ··· 708 684 SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, 709 685 SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | 710 686 SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); 687 + 688 + i2s->format = fmt; 689 + 711 690 return 0; 712 691 } 713 692 ··· 1101 1074 .has_reset = true, 1102 1075 .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, 1103 1076 .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, 1104 - .has_fmt_set_lrck_period = true, 1105 1077 .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), 1106 1078 .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), 1107 1079 .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),