Few dai configuration depends on board layout and use cases. Add new variables in dai_data to configure dai modes based on values defined in device tree configuration of board. Signed-off-by: Ajit Pandey <ajitp@xxxxxxxxxxxxxx> --- sound/soc/qcom/lpass-cpu.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-- sound/soc/qcom/lpass.h | 6 ++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 006ba5a..f96338f 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -90,8 +90,9 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, return bitwidth; } - regval = LPAIF_I2SCTL(v, LOOPBACK_DISABLE); - regval |= LPAIF_I2SCTL(v, WSSRC_INTERNAL); + /* default to Loopback disable & wssrc internal */ + regval = dai_data->loopback << (LPAIF_I2SCTL(v, LOOPBACK_SHIFT)); + regval |= dai_data->wssrc << (LPAIF_I2SCTL(v, WSSRC_SHIFT)); switch (bitwidth) { case 16: @@ -172,6 +173,28 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, return ret; } + /* Overwrite spk & mic mode bits with device tree value if specified */ + if (dai_data->spkmode != 0) { + regval = dai_data->spkmode << (LPAIF_I2SCTL(v, SPKMODE_SHIFT)); + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), + LPAIF_I2SCTL(v, SPKMODE_MASK), regval); + if (ret) + dev_err(dai->dev, "error writing to i2sctl reg: %d\n", + ret); + } + + + if (dai_data->micmode != 0) { + regval = dai_data->micmode << (LPAIF_I2SCTL(v, MICMODE_SHIFT)); + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), + LPAIF_I2SCTL(v, MICMODE_MASK), regval); + if (ret) + dev_err(dai->dev, "error writing to i2sctl reg: %d\n", + ret); + } + ret = clk_set_rate(dai_data->bit_clk, rate * bitwidth * 2); if (ret) { dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n", @@ -423,6 +446,46 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) .cache_type = REGCACHE_FLAT, }; +static void of_qcom_parse_dai_data(struct device *dev, + struct lpass_data *drvdata) +{ + struct device_node *node; + struct lpass_dai *dai; + int ret; + + for_each_child_of_node(dev->of_node, node) { + int id; + + ret = of_property_read_u32(node, "id", &id); + if (ret || id < 0 || id >= LPASS_MAX_MI2S_PORTS) { + dev_err(dev, "valid dai id not found:%d\n", ret); + continue; + } + + dai = drvdata->dai_priv[id]; + switch (id) { + case MI2S_PRIMARY... MI2S_QUATERNARY: + /* MI2S specific properties */ + ret = of_property_read_u32(node, "qcom,spkmode-mask", + &dai->spkmode); + + ret = of_property_read_u32(node, "qcom,micmode-mask", + &dai->micmode); + + ret = of_property_read_u32(node, "qcom,wssrc-mask", + &dai->wssrc); + + ret = of_property_read_u32(node, "qcom,loopback-mask", + &dai->loopback); + + break; + default: + dev_err(dev, "valid dai not found:%d\n", id); + break; + } + } +} + static int lpass_init_dai_clocks(struct device *dev, struct lpass_data *drvdata) { @@ -501,6 +564,9 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) GFP_KERNEL); } + /* parse dai data from dts */ + of_qcom_parse_dai_data(dev, drvdata); + ret = lpass_init_dai_clocks(dev, drvdata); if (ret) { dev_err(&pdev->dev, "error intializing dai clock: %d\n", ret); diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 384f4b8..960ee97 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -12,6 +12,7 @@ #include <linux/compiler.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <dt-bindings/sound/qcom,lpass.h> #define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 #define LPASS_MAX_MI2S_PORTS (8) @@ -23,6 +24,11 @@ struct lpass_dai { struct clk *osr_clk; struct clk *bit_clk; + + uint32_t spkmode; + uint32_t micmode; + uint32_t wssrc; + uint32_t loopback; }; /* Both the CPU DAI and platform drivers will access this data */ -- 1.9.1