aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/sunxi/sun4i-i2s.c
diff options
context:
space:
mode:
authorLinus Torvalds <[email protected]>2019-07-09 09:59:43 -0700
committerLinus Torvalds <[email protected]>2019-07-09 09:59:43 -0700
commit4cdd5f9186bbe80306e76f11da7ecb0b9720433c (patch)
tree23c2f39933cd8253a65385eab00405beaf602f01 /sound/soc/sunxi/sun4i-i2s.c
parent2d41ef5432b76ae90dc0db93026f1d981f874ec4 (diff)
parent0dcb4efb1095d0a1f5f681c2b94e98b009cc5d77 (diff)
Merge tag 'sound-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "Many updates in this development cycle are found in ASoC where it got a wide range of changes for the continued refactoring. Some highlights are below. ASoC: - Continued refactoring work by Morimoto-san toward the full componentization; the changes are seen allover the places - Support for force disconnecting muxes in DAPM - Continued development of ASoC Intel SOF stuff - New drivers for Cirrus Logic CS47L35, CS47L85 and CS47L90, Conexant CX2072X, Realtek RT1011 and RT1308 HD-audio: - More fixes and adjustments for ASoC SOF HD-audio - Fix for resume problem on some Realtek codecs USB-audio: - A few fixes for the issues reported by syzbot USB fuzzer - Fix for UAC2 extension unit parser - Quirks for Line6 Helix, Emgaic Unitor 8 FireWire: - Lots of code refactoring and fixes in most of its components" * tag 'sound-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (626 commits) ALSA: firewire-lib: code refactoring for local variables ALSA: firewire-lib: code refactoring for post operation to data block counter ALSA: firewire-lib: code refactoring for error path of parser for CIP header ALSA: firewire-lib: fix different data block counter between probed event and transferred isochronous packet ALSA: firewire-lib: fix initial value of data block count for IR context without CIP_DBC_IS_END_EVENT ALSA: firewire-lib/fireface: fix initial value of data block counter for IR context with CIP_NO_HEADER ALSA: firewire-lib: fix invalid length of rx packet payload for tracepoint events ALSA: usb-audio: fix Line6 Helix audio format rates firewire-motu: fix wrong reference count for stream functionality at error path of rawmidi interface ALSA: firewire-digi00x: fix wrong reference count for stream functionality at error path of rawmidi interface ALSA: dice: fix wrong reference count for stream functionality at error path of rawmidi interface ALSA: oxfw: fix wrong reference count for stream functionality at error path of rawmidi interface ALSA: fireworks: fix wrong reference count for stream functionality at error path of rawmidi interface ALSA: bebob: fix wrong reference count for stream functionality at error path of rawmidi interface ASoC: SOF: Intel: implement runtime idle for CNL/APL ASoC: SOF: add runtime idle callback ASoC: hdac_hdmi: report codec link up/down status to bus ASoC: SOF: debug: fix possible memory leak in sof_dfsentry_write() ASoC: sunxi: sun50i-codec-analog: Add earpiece ASoC: rt5665: remove redundant assignment to variable idx ...
Diffstat (limited to 'sound/soc/sunxi/sun4i-i2s.c')
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c71
1 files changed, 55 insertions, 16 deletions
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index fd7c37596f21..9b2232908b65 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -114,6 +114,8 @@
#define SUN8I_I2S_RX_CHAN_SEL_REG 0x54
#define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
+struct sun4i_i2s;
+
/**
* struct sun4i_i2s_quirks - Differences between SoC variants.
*
@@ -127,7 +129,6 @@
* @sun4i_i2s_regmap: regmap config to use.
* @mclk_offset: Value by which mclkdiv needs to be adjusted.
* @bclk_offset: Value by which bclkdiv needs to be adjusted.
- * @fmt_offset: Value by which wss and sr needs to be adjusted.
* @field_clkdiv_mclk_en: regmap field to enable mclk output.
* @field_fmt_wss: regmap field to set word select size.
* @field_fmt_sr: regmap field to set sample resolution.
@@ -150,7 +151,6 @@ struct sun4i_i2s_quirks {
const struct regmap_config *sun4i_i2s_regmap;
unsigned int mclk_offset;
unsigned int bclk_offset;
- unsigned int fmt_offset;
/* Register fields for i2s */
struct reg_field field_clkdiv_mclk_en;
@@ -163,6 +163,9 @@ struct sun4i_i2s_quirks {
struct reg_field field_rxchanmap;
struct reg_field field_txchansel;
struct reg_field field_rxchansel;
+
+ s8 (*get_sr)(const struct sun4i_i2s *, int);
+ s8 (*get_wss)(const struct sun4i_i2s *, int);
};
struct sun4i_i2s {
@@ -345,6 +348,39 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
return 0;
}
+static s8 sun4i_i2s_get_sr(const struct sun4i_i2s *i2s, int width)
+{
+ if (width < 16 || width > 24)
+ return -EINVAL;
+
+ if (width % 4)
+ return -EINVAL;
+
+ return (width - 16) / 4;
+}
+
+static s8 sun4i_i2s_get_wss(const struct sun4i_i2s *i2s, int width)
+{
+ if (width < 16 || width > 32)
+ return -EINVAL;
+
+ if (width % 4)
+ return -EINVAL;
+
+ return (width - 16) / 4;
+}
+
+static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width)
+{
+ if (width % 4)
+ return -EINVAL;
+
+ if (width < 8 || width > 32)
+ return -EINVAL;
+
+ return (width - 8) / 4 + 1;
+}
+
static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -396,22 +432,16 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
}
i2s->playback_dma_data.addr_width = width;
- switch (params_width(params)) {
- case 16:
- sr = 0;
- wss = 0;
- break;
+ sr = i2s->variant->get_sr(i2s, params_width(params));
+ if (sr < 0)
+ return -EINVAL;
- default:
- dev_err(dai->dev, "Unsupported sample width: %d\n",
- params_width(params));
+ wss = i2s->variant->get_wss(i2s, params_width(params));
+ if (wss < 0)
return -EINVAL;
- }
- regmap_field_write(i2s->field_fmt_wss,
- wss + i2s->variant->fmt_offset);
- regmap_field_write(i2s->field_fmt_sr,
- sr + i2s->variant->fmt_offset);
+ regmap_field_write(i2s->field_fmt_wss, wss);
+ regmap_field_write(i2s->field_fmt_sr, sr);
return sun4i_i2s_set_clk_rate(dai, params_rate(params),
params_width(params));
@@ -891,6 +921,8 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+ .get_sr = sun4i_i2s_get_sr,
+ .get_wss = sun4i_i2s_get_wss,
};
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
@@ -908,6 +940,8 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+ .get_sr = sun4i_i2s_get_sr,
+ .get_wss = sun4i_i2s_get_wss,
};
static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
@@ -925,6 +959,8 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+ .get_sr = sun8i_i2s_get_sr_wss,
+ .get_wss = sun8i_i2s_get_sr_wss,
};
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
@@ -933,7 +969,6 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.sun4i_i2s_regmap = &sun8i_i2s_regmap_config,
.mclk_offset = 1,
.bclk_offset = 2,
- .fmt_offset = 3,
.has_fmt_set_lrck_period = true,
.has_chcfg = true,
.has_chsel_tx_chen = true,
@@ -948,6 +983,8 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2),
+ .get_sr = sun8i_i2s_get_sr_wss,
+ .get_wss = sun8i_i2s_get_sr_wss,
};
static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
@@ -965,6 +1002,8 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+ .get_sr = sun8i_i2s_get_sr_wss,
+ .get_wss = sun8i_i2s_get_sr_wss,
};
static int sun4i_i2s_init_regmap_fields(struct device *dev,