aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/soc/codecs/pcm512x.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/pcm512x.c')
-rw-r--r--sound/soc/codecs/pcm512x.c189
1 files changed, 127 insertions, 62 deletions
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 8153d3d01654..aa8edf87b743 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -48,6 +48,7 @@ struct pcm512x_priv {
int mute;
struct mutex mutex;
unsigned int bclk_ratio;
+ int force_pll_on;
};
/*
@@ -116,6 +117,8 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_FS_SPEED_MODE, 0x00 },
{ PCM512x_IDAC_1, 0x01 },
{ PCM512x_IDAC_2, 0x00 },
+ { PCM512x_I2S_1, 0x02 },
+ { PCM512x_I2S_2, 0x00 },
};
static bool pcm512x_readable(struct device *dev, unsigned int reg)
@@ -650,12 +653,12 @@ static int pcm512x_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
- switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_CBM_CFS:
+ switch (pcm512x->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_CBP_CFC:
return pcm512x_dai_startup_master(substream, dai);
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
return pcm512x_dai_startup_slave(substream, dai);
default:
@@ -1168,8 +1171,6 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
int alen;
int gpio;
- int clock_output;
- int master_mode;
int ret;
dev_dbg(component->dev, "hw_params %u Hz, %u channels\n",
@@ -1195,19 +1196,15 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- ret = regmap_update_bits(pcm512x->regmap,
- PCM512x_BCLK_LRCLK_CFG,
- PCM512x_BCKP
- | PCM512x_BCKO | PCM512x_LRKO,
- 0);
- if (ret != 0) {
- dev_err(component->dev,
- "Failed to enable slave mode: %d\n", ret);
- return ret;
- }
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+ PCM512x_ALEN, alen);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set frame size: %d\n", ret);
+ return ret;
+ }
+ if ((pcm512x->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
+ SND_SOC_DAIFMT_CBC_CFC) {
ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
PCM512x_DCAS, 0);
if (ret != 0) {
@@ -1216,24 +1213,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
ret);
return ret;
}
- return 0;
- case SND_SOC_DAIFMT_CBM_CFM:
- clock_output = PCM512x_BCKO | PCM512x_LRKO;
- master_mode = PCM512x_RLRK | PCM512x_RBCK;
- break;
- case SND_SOC_DAIFMT_CBM_CFS:
- clock_output = PCM512x_BCKO;
- master_mode = PCM512x_RBCK;
- break;
- default:
- return -EINVAL;
- }
-
- ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
- PCM512x_ALEN, alen);
- if (ret != 0) {
- dev_err(component->dev, "Failed to set frame size: %d\n", ret);
- return ret;
+ goto skip_pll;
}
if (pcm512x->pll_out) {
@@ -1279,10 +1259,34 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
- PCM512x_PLLE, 0);
+ if (!pcm512x->force_pll_on) {
+ ret = regmap_update_bits(pcm512x->regmap,
+ PCM512x_PLL_EN, PCM512x_PLLE, 0);
+ } else {
+ /* provide minimum PLL config for TAS575x clocking
+ * and leave PLL enabled
+ */
+ ret = regmap_write(pcm512x->regmap,
+ PCM512x_PLL_COEFF_0, 0x01);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to set pll coefficient: %d\n", ret);
+ return ret;
+ }
+ ret = regmap_write(pcm512x->regmap,
+ PCM512x_PLL_COEFF_1, 0x04);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to set pll coefficient: %d\n", ret);
+ return ret;
+ }
+ ret = regmap_write(pcm512x->regmap,
+ PCM512x_PLL_EN, 0x01);
+ dev_dbg(component->dev, "Enabling PLL for TAS575x\n");
+ }
+
if (ret != 0) {
- dev_err(component->dev, "Failed to disable pll: %d\n", ret);
+ dev_err(component->dev, "Failed to set pll mode: %d\n", ret);
return ret;
}
}
@@ -1316,25 +1320,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
dev_err(component->dev, "Failed to enable pll: %d\n", ret);
return ret;
}
- }
-
- ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
- PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
- clock_output);
- if (ret != 0) {
- dev_err(component->dev, "Failed to enable clock output: %d\n", ret);
- return ret;
- }
-
- ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
- PCM512x_RLRK | PCM512x_RBCK,
- master_mode);
- if (ret != 0) {
- dev_err(component->dev, "Failed to enable master mode: %d\n", ret);
- return ret;
- }
- if (pcm512x->pll_out) {
gpio = PCM512x_G1OE << (pcm512x->pll_out - 1);
ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
gpio, gpio);
@@ -1368,6 +1354,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+skip_pll:
return 0;
}
@@ -1375,6 +1362,80 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+ int afmt;
+ int offset = 0;
+ int clock_output;
+ int provider_mode;
+ int ret;
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ clock_output = 0;
+ provider_mode = 0;
+ break;
+ case SND_SOC_DAIFMT_CBP_CFP:
+ clock_output = PCM512x_BCKO | PCM512x_LRKO;
+ provider_mode = PCM512x_RLRK | PCM512x_RBCK;
+ break;
+ case SND_SOC_DAIFMT_CBP_CFC:
+ clock_output = PCM512x_BCKO;
+ provider_mode = PCM512x_RBCK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
+ PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
+ clock_output);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to enable clock output: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
+ PCM512x_RLRK | PCM512x_RBCK,
+ provider_mode);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to enable provider mode: %d\n", ret);
+ return ret;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ afmt = PCM512x_AFMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ afmt = PCM512x_AFMT_RTJ;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ afmt = PCM512x_AFMT_LTJ;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ offset = 1;
+ fallthrough;
+ case SND_SOC_DAIFMT_DSP_B:
+ afmt = PCM512x_AFMT_DSP;
+ break;
+ default:
+ dev_err(component->dev, "unsupported DAI format: 0x%x\n",
+ pcm512x->fmt);
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+ PCM512x_AFMT, afmt);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set data format: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_2,
+ 0xFF, offset);
+ if (ret != 0) {
+ dev_err(component->dev, "Failed to set data offset: %d\n", ret);
+ return ret;
+ }
pcm512x->fmt = fmt;
@@ -1476,7 +1537,6 @@ static const struct snd_soc_component_driver pcm512x_component_driver = {
.num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes),
.use_pmdown_time = 1,
.endianness = 1,
- .non_legacy_dai_naming = 1,
};
static const struct regmap_range_cfg pcm512x_range = {
@@ -1599,7 +1659,7 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
if (val > 6) {
dev_err(dev, "Invalid pll-in\n");
ret = -EINVAL;
- goto err_clk;
+ goto err_pm;
}
pcm512x->pll_in = val;
}
@@ -1608,7 +1668,7 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
if (val > 6) {
dev_err(dev, "Invalid pll-out\n");
ret = -EINVAL;
- goto err_clk;
+ goto err_pm;
}
pcm512x->pll_out = val;
}
@@ -1617,13 +1677,18 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
dev_err(dev,
"Error: both pll-in and pll-out, or none\n");
ret = -EINVAL;
- goto err_clk;
+ goto err_pm;
}
if (pcm512x->pll_in && pcm512x->pll_in == pcm512x->pll_out) {
dev_err(dev, "Error: pll-in == pll-out\n");
ret = -EINVAL;
- goto err_clk;
+ goto err_pm;
}
+
+ if (!strcmp(np->name, "tas5756") ||
+ !strcmp(np->name, "tas5754"))
+ pcm512x->force_pll_on = 1;
+ dev_dbg(dev, "Device ID: %s\n", np->name);
}
#endif