255 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2020 The Linux Foundation. All rights reserved.4 *5 * lpass-hdmi.c -- ALSA SoC HDMI-CPU DAI driver for QTi LPASS HDMI6 */7 8 9#include <linux/kernel.h>10#include <linux/module.h>11#include <sound/pcm_params.h>12#include <linux/regmap.h>13#include <sound/soc.h>14#include <sound/soc-dai.h>15#include <dt-bindings/sound/sc7180-lpass.h>16#include "lpass-lpaif-reg.h"17#include "lpass.h"18 19static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream,20 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)21{22 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);23 snd_pcm_format_t format = params_format(params);24 unsigned int rate = params_rate(params);25 unsigned int channels = params_channels(params);26 unsigned int ret;27 int bitwidth;28 unsigned int word_length;29 unsigned int ch_sts_buf0;30 unsigned int ch_sts_buf1;31 unsigned int data_format;32 unsigned int sampling_freq;33 unsigned int ch = 0;34 struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl;35 struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl;36 37 bitwidth = snd_pcm_format_width(format);38 if (bitwidth < 0) {39 dev_err(dai->dev, "%s invalid bit width given : %d\n",40 __func__, bitwidth);41 return bitwidth;42 }43 44 switch (bitwidth) {45 case 16:46 word_length = LPASS_DP_AUDIO_BITWIDTH16;47 break;48 case 24:49 word_length = LPASS_DP_AUDIO_BITWIDTH24;50 break;51 default:52 dev_err(dai->dev, "%s invalid bit width given : %d\n",53 __func__, bitwidth);54 return -EINVAL;55 }56 57 switch (rate) {58 case 32000:59 sampling_freq = LPASS_SAMPLING_FREQ32;60 break;61 case 44100:62 sampling_freq = LPASS_SAMPLING_FREQ44;63 break;64 case 48000:65 sampling_freq = LPASS_SAMPLING_FREQ48;66 break;67 default:68 dev_err(dai->dev, "%s invalid bit width given : %d\n",69 __func__, bitwidth);70 return -EINVAL;71 }72 data_format = LPASS_DATA_FORMAT_LINEAR;73 ch_sts_buf0 = (((data_format << LPASS_DATA_FORMAT_SHIFT) & LPASS_DATA_FORMAT_MASK)74 | ((sampling_freq << LPASS_FREQ_BIT_SHIFT) & LPASS_FREQ_BIT_MASK));75 ch_sts_buf1 = (word_length) & LPASS_WORDLENGTH_MASK;76 77 ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_RESET);78 if (ret)79 return ret;80 81 ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_CLEAR);82 if (ret)83 return ret;84 85 ret = regmap_field_write(drvdata->hdmitx_legacy_en, LPASS_HDMITX_LEGACY_DISABLE);86 if (ret)87 return ret;88 89 ret = regmap_field_write(drvdata->hdmitx_parity_calc_en, HDMITX_PARITY_CALC_EN);90 if (ret)91 return ret;92 93 ret = regmap_field_write(drvdata->vbit_ctl->replace_vbit, REPLACE_VBIT);94 if (ret)95 return ret;96 97 ret = regmap_field_write(drvdata->vbit_ctl->vbit_stream, LINEAR_PCM_DATA);98 if (ret)99 return ret;100 101 ret = regmap_field_write(drvdata->hdmitx_ch_msb[0], ch_sts_buf1);102 if (ret)103 return ret;104 105 ret = regmap_field_write(drvdata->hdmitx_ch_lsb[0], ch_sts_buf0);106 if (ret)107 return ret;108 109 ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_chs, HW_MODE);110 if (ret)111 return ret;112 113 ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_chs_sel, SW_MODE);114 if (ret)115 return ret;116 117 ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_usr, HW_MODE);118 if (ret)119 return ret;120 121 ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_usr_sel, SW_MODE);122 if (ret)123 return ret;124 125 ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_ENABLE);126 if (ret)127 return ret;128 129 ret = regmap_field_write(meta_ctl->as_sdp_cc, channels - 1);130 if (ret)131 return ret;132 133 ret = regmap_field_write(meta_ctl->as_sdp_ct, LPASS_META_DEFAULT_VAL);134 if (ret)135 return ret;136 137 ret = regmap_field_write(meta_ctl->aif_db4, LPASS_META_DEFAULT_VAL);138 if (ret)139 return ret;140 141 ret = regmap_field_write(meta_ctl->frequency, sampling_freq);142 if (ret)143 return ret;144 145 ret = regmap_field_write(meta_ctl->mst_index, LPASS_META_DEFAULT_VAL);146 if (ret)147 return ret;148 149 ret = regmap_field_write(meta_ctl->dptx_index, LPASS_META_DEFAULT_VAL);150 if (ret)151 return ret;152 153 ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_DISABLE);154 if (ret)155 return ret;156 157 ret = regmap_field_write(sstream_ctl->dma_sel, ch);158 if (ret)159 return ret;160 161 ret = regmap_field_write(sstream_ctl->auto_bbit_en, LPASS_SSTREAM_DEFAULT_ENABLE);162 if (ret)163 return ret;164 165 ret = regmap_field_write(sstream_ctl->layout, LPASS_SSTREAM_DEFAULT_DISABLE);166 if (ret)167 return ret;168 169 ret = regmap_field_write(sstream_ctl->layout_sp, LPASS_LAYOUT_SP_DEFAULT);170 if (ret)171 return ret;172 173 ret = regmap_field_write(sstream_ctl->dp_audio, LPASS_SSTREAM_DEFAULT_ENABLE);174 if (ret)175 return ret;176 177 ret = regmap_field_write(sstream_ctl->set_sp_on_en, LPASS_SSTREAM_DEFAULT_ENABLE);178 if (ret)179 return ret;180 181 ret = regmap_field_write(sstream_ctl->dp_sp_b_hw_en, LPASS_SSTREAM_DEFAULT_ENABLE);182 if (ret)183 return ret;184 185 ret = regmap_field_write(sstream_ctl->dp_staffing_en, LPASS_SSTREAM_DEFAULT_ENABLE);186 187 return ret;188}189 190static int lpass_hdmi_daiops_prepare(struct snd_pcm_substream *substream,191 struct snd_soc_dai *dai)192{193 int ret;194 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);195 196 ret = regmap_field_write(drvdata->sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE);197 if (ret)198 return ret;199 200 ret = regmap_field_write(drvdata->meta_ctl->mute, LPASS_MUTE_DISABLE);201 202 return ret;203}204 205static int lpass_hdmi_daiops_trigger(struct snd_pcm_substream *substream,206 int cmd, struct snd_soc_dai *dai)207{208 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);209 struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl;210 struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl;211 int ret = -EINVAL;212 213 switch (cmd) {214 case SNDRV_PCM_TRIGGER_START:215 case SNDRV_PCM_TRIGGER_RESUME:216 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:217 ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE);218 if (ret)219 return ret;220 221 ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_DISABLE);222 if (ret)223 return ret;224 225 break;226 case SNDRV_PCM_TRIGGER_STOP:227 case SNDRV_PCM_TRIGGER_SUSPEND:228 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:229 ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_DISABLE);230 if (ret)231 return ret;232 233 ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_ENABLE);234 if (ret)235 return ret;236 237 ret = regmap_field_write(sstream_ctl->dp_audio, 0);238 if (ret)239 return ret;240 241 break;242 }243 return ret;244}245 246const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = {247 .hw_params = lpass_hdmi_daiops_hw_params,248 .prepare = lpass_hdmi_daiops_prepare,249 .trigger = lpass_hdmi_daiops_trigger,250};251EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops);252 253MODULE_DESCRIPTION("QTi LPASS HDMI Driver");254MODULE_LICENSE("GPL");255