aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/soc/qcom/lpass-cpu.c
diff options
context:
space:
mode:
authorV Sujith Kumar Reddy <vsujithk@codeaurora.org>2020-10-08 10:47:01 +0530
committerMark Brown <broonie@kernel.org>2020-10-08 20:27:34 +0100
commit7cb37b7bd0d3c93e381ae7abf30971819966bd9d (patch)
tree70a4f1eb26234e5948d52a00961696c388f342fc /sound/soc/qcom/lpass-cpu.c
parentAsoc: qcom: lpass:Update lpaif_dmactl members order (diff)
downloadwireguard-linux-7cb37b7bd0d3c93e381ae7abf30971819966bd9d.tar.xz
wireguard-linux-7cb37b7bd0d3c93e381ae7abf30971819966bd9d.zip
ASoC: qcom: Add support for lpass hdmi driver
Upadate lpass cpu and platform driver to support audio over dp. Also add lpass-hdmi.c and lpass-hdmi.h. Signed-off-by: V Sujith Kumar Reddy <vsujithk@codeaurora.org> Signed-off-by: Srinivasa Rao <srivasam@codeaurora.org> Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Tested-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Link: https://lore.kernel.org/r/1602134223-2562-6-git-send-email-srivasam@codeaurora.org Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/qcom/lpass-cpu.c')
-rw-r--r--sound/soc/qcom/lpass-cpu.c247
1 files changed, 241 insertions, 6 deletions
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 12950d2e2755..ba2aca301a9b 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -478,6 +478,206 @@ static struct regmap_config lpass_cpu_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
+static int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+ struct lpass_variant *v = drvdata->variant;
+ unsigned int i;
+ struct lpass_hdmi_tx_ctl *tx_ctl;
+ struct regmap_field *legacy_en;
+ struct lpass_vbit_ctrl *vbit_ctl;
+ struct regmap_field *tx_parity;
+ struct lpass_dp_metadata_ctl *meta_ctl;
+ struct lpass_sstream_ctl *sstream_ctl;
+ struct regmap_field *ch_msb;
+ struct regmap_field *ch_lsb;
+ struct lpass_hdmitx_dmactl *tx_dmactl;
+ int rval;
+
+ tx_ctl = devm_kzalloc(dev, sizeof(*tx_ctl), GFP_KERNEL);
+ if (!tx_ctl)
+ return -ENOMEM;
+
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->soft_reset, tx_ctl->soft_reset);
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->force_reset, tx_ctl->force_reset);
+ drvdata->tx_ctl = tx_ctl;
+
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->legacy_en, legacy_en);
+ drvdata->hdmitx_legacy_en = legacy_en;
+
+ vbit_ctl = devm_kzalloc(dev, sizeof(*vbit_ctl), GFP_KERNEL);
+ if (!vbit_ctl)
+ return -ENOMEM;
+
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->replace_vbit, vbit_ctl->replace_vbit);
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->vbit_stream, vbit_ctl->vbit_stream);
+ drvdata->vbit_ctl = vbit_ctl;
+
+
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->calc_en, tx_parity);
+ drvdata->hdmitx_parity_calc_en = tx_parity;
+
+ meta_ctl = devm_kzalloc(dev, sizeof(*meta_ctl), GFP_KERNEL);
+ if (!meta_ctl)
+ return -ENOMEM;
+
+ rval = devm_regmap_field_bulk_alloc(dev, map, &meta_ctl->mute, &v->mute, 7);
+ if (rval)
+ return rval;
+ drvdata->meta_ctl = meta_ctl;
+
+ sstream_ctl = devm_kzalloc(dev, sizeof(*sstream_ctl), GFP_KERNEL);
+ if (!sstream_ctl)
+ return -ENOMEM;
+
+ rval = devm_regmap_field_bulk_alloc(dev, map, &sstream_ctl->sstream_en, &v->sstream_en, 9);
+ if (rval)
+ return rval;
+
+ drvdata->sstream_ctl = sstream_ctl;
+
+ for (i = 0; i < LPASS_MAX_HDMI_DMA_CHANNELS; i++) {
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->msb_bits, ch_msb);
+ drvdata->hdmitx_ch_msb[i] = ch_msb;
+
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->lsb_bits, ch_lsb);
+ drvdata->hdmitx_ch_lsb[i] = ch_lsb;
+
+ tx_dmactl = devm_kzalloc(dev, sizeof(*tx_dmactl), GFP_KERNEL);
+ if (!tx_dmactl)
+ return -ENOMEM;
+
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_chs, tx_dmactl->use_hw_chs);
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_usr, tx_dmactl->use_hw_usr);
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_chs_sel, tx_dmactl->hw_chs_sel);
+ QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_usr_sel, tx_dmactl->hw_usr_sel);
+ drvdata->hdmi_tx_dmactl[i] = tx_dmactl;
+ }
+ return 0;
+}
+
+static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+ struct lpass_variant *v = drvdata->variant;
+ int i;
+
+ if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_DP_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
+ return true;
+ if (reg == LPASS_HDMITX_APP_IRQCLEAR_REG(v))
+ return true;
+
+ for (i = 0; i < v->hdmi_rdma_channels; i++) {
+ if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
+ return true;
+ if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
+ return true;
+ if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
+ return true;
+ }
+
+ for (i = 0; i < v->rdma_channels; ++i) {
+ if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
+ return true;
+ if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
+ return true;
+ if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
+ return true;
+ if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
+ return true;
+ }
+ return false;
+}
+
+static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+ struct lpass_variant *v = drvdata->variant;
+ int i;
+
+ if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
+ return true;
+
+ for (i = 0; i < v->hdmi_rdma_channels; i++) {
+ if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
+ return true;
+ if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
+ return true;
+ if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
+ return true;
+ }
+
+ if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_DP_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
+ return true;
+ if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
+ return true;
+ if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
+ return true;
+
+ for (i = 0; i < v->rdma_channels; ++i) {
+ if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
+ return true;
+ if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
+ return true;
+ if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
+ return true;
+ if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
+ return true;
+ if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
+ return true;
+ }
+
+ return false;
+}
+
+static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
+{
+ struct lpass_data *drvdata = dev_get_drvdata(dev);
+ struct lpass_variant *v = drvdata->variant;
+ int i;
+
+ if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
+ return true;
+ if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
+ return true;
+
+ for (i = 0; i < v->rdma_channels; ++i) {
+ if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
+ return true;
+ }
+ return false;
+}
+
+struct regmap_config lpass_hdmi_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .writeable_reg = lpass_hdmi_regmap_writeable,
+ .readable_reg = lpass_hdmi_regmap_readable,
+ .volatile_reg = lpass_hdmi_regmap_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev,
struct device_node *node,
const char *name)
@@ -535,13 +735,17 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
dev_err(dev, "valid dai id not found: %d\n", ret);
continue;
}
-
- data->mi2s_playback_sd_mode[id] =
- of_lpass_cpu_parse_sd_lines(dev, node,
- "qcom,playback-sd-lines");
- data->mi2s_capture_sd_mode[id] =
- of_lpass_cpu_parse_sd_lines(dev, node,
+ if (id == LPASS_DP_RX) {
+ data->hdmi_port_enable = 1;
+ dev_err(dev, "HDMI Port is enabled: %d\n", id);
+ } else {
+ data->mi2s_playback_sd_mode[id] =
+ of_lpass_cpu_parse_sd_lines(dev, node,
+ "qcom,playback-sd-lines");
+ data->mi2s_capture_sd_mode[id] =
+ of_lpass_cpu_parse_sd_lines(dev, node,
"qcom,capture-sd-lines");
+ }
}
}
@@ -596,6 +800,27 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
return PTR_ERR(drvdata->lpaif_map);
}
+ if (drvdata->hdmi_port_enable) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-hdmiif");
+
+ drvdata->hdmiif = devm_ioremap_resource(dev, res);
+ if (IS_ERR((void const __force *)drvdata->hdmiif)) {
+ dev_err(dev, "error mapping reg resource: %ld\n",
+ PTR_ERR((void const __force *)drvdata->hdmiif));
+ return PTR_ERR((void const __force *)drvdata->hdmiif);
+ }
+
+ lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant,
+ variant->hdmi_rdma_channels);
+ drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
+ &lpass_hdmi_regmap_config);
+ if (IS_ERR(drvdata->hdmiif_map)) {
+ dev_err(dev, "error initializing regmap: %ld\n",
+ PTR_ERR(drvdata->hdmiif_map));
+ return PTR_ERR(drvdata->hdmiif_map);
+ }
+ }
+
if (variant->init) {
ret = variant->init(pdev);
if (ret) {
@@ -606,6 +831,9 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
for (i = 0; i < variant->num_dai; i++) {
dai_id = variant->dai_driver[i].id;
+ if (dai_id == LPASS_DP_RX)
+ continue;
+
drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(dev,
variant->dai_osr_clk_names[i]);
if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
@@ -641,6 +869,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
return ret;
}
+ if (drvdata->hdmi_port_enable) {
+ ret = lpass_hdmi_init_bitfields(dev, drvdata->hdmiif_map);
+ if (ret) {
+ dev_err(dev, "%s error hdmi init failed\n", __func__);
+ return ret;
+ }
+ }
ret = devm_snd_soc_register_component(dev,
&lpass_cpu_comp_driver,
variant->dai_driver,