summaryrefslogtreecommitdiffstats
path: root/sound/soc/sunxi
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sunxi')
-rw-r--r--sound/soc/sunxi/sun4i-codec.c29
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c57
2 files changed, 71 insertions, 15 deletions
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 5da4efe7a550..886281673972 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -590,12 +590,28 @@ static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
hwrate);
}
+
+static unsigned int sun4i_codec_src_rates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000,
+ 44100, 48000, 96000, 192000
+};
+
+
+static struct snd_pcm_hw_constraint_list sun4i_codec_constraints = {
+ .count = ARRAY_SIZE(sun4i_codec_src_rates),
+ .list = sun4i_codec_src_rates,
+};
+
+
static int sun4i_codec_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints);
+
/*
* Stop issuing DRQ when we have room for less than 16 samples
* in our TX FIFO
@@ -633,9 +649,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
.channels_max = 2,
.rate_min = 8000,
.rate_max = 192000,
- .rates = SNDRV_PCM_RATE_8000_48000 |
- SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.sig_bits = 24,
@@ -645,11 +659,8 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
- .rate_max = 192000,
- .rates = SNDRV_PCM_RATE_8000_48000 |
- SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000 |
- SNDRV_PCM_RATE_KNOT,
+ .rate_max = 48000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.sig_bits = 24,
@@ -1128,7 +1139,7 @@ static const struct snd_soc_component_driver sun4i_codec_component = {
.name = "sun4i-codec",
};
-#define SUN4I_CODEC_RATES SNDRV_PCM_RATE_8000_192000
+#define SUN4I_CODEC_RATES SNDRV_PCM_RATE_CONTINUOUS
#define SUN4I_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 04f92583a969..dca1143c1150 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -269,10 +269,11 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
return false;
}
-static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
+static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
unsigned int rate,
unsigned int word_size)
{
+ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
unsigned int oversample_rate, clk_rate;
int bclk_div, mclk_div;
int ret;
@@ -300,6 +301,7 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
break;
default:
+ dev_err(dai->dev, "Unsupported sample rate: %u\n", rate);
return -EINVAL;
}
@@ -308,18 +310,25 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
return ret;
oversample_rate = i2s->mclk_freq / rate;
- if (!sun4i_i2s_oversample_is_valid(oversample_rate))
+ if (!sun4i_i2s_oversample_is_valid(oversample_rate)) {
+ dev_err(dai->dev, "Unsupported oversample rate: %d\n",
+ oversample_rate);
return -EINVAL;
+ }
bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
word_size);
- if (bclk_div < 0)
+ if (bclk_div < 0) {
+ dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
return -EINVAL;
+ }
mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
clk_rate, rate);
- if (mclk_div < 0)
+ if (mclk_div < 0) {
+ dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div);
return -EINVAL;
+ }
/* Adjust the clock division values if needed */
bclk_div += i2s->variant->bclk_offset;
@@ -349,8 +358,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
u32 width;
channels = params_channels(params);
- if (channels != 2)
+ if (channels != 2) {
+ dev_err(dai->dev, "Unsupported number of channels: %d\n",
+ channels);
return -EINVAL;
+ }
if (i2s->variant->has_chcfg) {
regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
@@ -382,6 +394,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
default:
+ dev_err(dai->dev, "Unsupported physical sample width: %d\n",
+ params_physical_width(params));
return -EINVAL;
}
i2s->playback_dma_data.addr_width = width;
@@ -393,6 +407,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
break;
default:
+ dev_err(dai->dev, "Unsupported sample width: %d\n",
+ params_width(params));
return -EINVAL;
}
@@ -401,7 +417,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
regmap_field_write(i2s->field_fmt_sr,
sr + i2s->variant->fmt_offset);
- return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
+ return sun4i_i2s_set_clk_rate(dai, params_rate(params),
params_width(params));
}
@@ -426,6 +442,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
val = SUN4I_I2S_FMT0_FMT_RIGHT_J;
break;
default:
+ dev_err(dai->dev, "Unsupported format: %d\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
return -EINVAL;
}
@@ -464,6 +482,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
case SND_SOC_DAIFMT_NB_NF:
break;
default:
+ dev_err(dai->dev, "Unsupported clock polarity: %d\n",
+ fmt & SND_SOC_DAIFMT_INV_MASK);
return -EINVAL;
}
@@ -482,6 +502,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
val = SUN4I_I2S_CTRL_MODE_SLAVE;
break;
default:
+ dev_err(dai->dev, "Unsupported slave setting: %d\n",
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -504,6 +526,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
val = 0;
break;
default:
+ dev_err(dai->dev, "Unsupported slave setting: %d\n",
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -897,6 +921,23 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
};
+static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
+ .has_reset = true,
+ .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
+ .sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
+ .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+ .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
+ .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
+ .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .has_slave_select_bit = true,
+ .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+ .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+ .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),
+};
+
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
@@ -1121,6 +1162,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
.data = &sun6i_a31_i2s_quirks,
},
{
+ .compatible = "allwinner,sun8i-a83t-i2s",
+ .data = &sun8i_a83t_i2s_quirks,
+ },
+ {
.compatible = "allwinner,sun8i-h3-i2s",
.data = &sun8i_h3_i2s_quirks,
},