0001
0002
0003
0004
0005
0006 #include <linux/bitfield.h>
0007 #include <linux/clk.h>
0008 #include <sound/pcm_params.h>
0009 #include <sound/pcm_iec958.h>
0010 #include <sound/soc.h>
0011 #include <sound/soc-dai.h>
0012
0013 #include "aiu.h"
0014
0015 #define AIU_958_MISC_NON_PCM BIT(0)
0016 #define AIU_958_MISC_MODE_16BITS BIT(1)
0017 #define AIU_958_MISC_16BITS_ALIGN GENMASK(6, 5)
0018 #define AIU_958_MISC_MODE_32BITS BIT(7)
0019 #define AIU_958_MISC_U_FROM_STREAM BIT(12)
0020 #define AIU_958_MISC_FORCE_LR BIT(13)
0021 #define AIU_958_CTRL_HOLD_EN BIT(0)
0022 #define AIU_CLK_CTRL_958_DIV_EN BIT(1)
0023 #define AIU_CLK_CTRL_958_DIV GENMASK(5, 4)
0024 #define AIU_CLK_CTRL_958_DIV_MORE BIT(12)
0025
0026 #define AIU_CS_WORD_LEN 4
0027 #define AIU_958_INTERNAL_DIV 2
0028
0029 static void
0030 aiu_encoder_spdif_divider_enable(struct snd_soc_component *component,
0031 bool enable)
0032 {
0033 snd_soc_component_update_bits(component, AIU_CLK_CTRL,
0034 AIU_CLK_CTRL_958_DIV_EN,
0035 enable ? AIU_CLK_CTRL_958_DIV_EN : 0);
0036 }
0037
0038 static void aiu_encoder_spdif_hold(struct snd_soc_component *component,
0039 bool enable)
0040 {
0041 snd_soc_component_update_bits(component, AIU_958_CTRL,
0042 AIU_958_CTRL_HOLD_EN,
0043 enable ? AIU_958_CTRL_HOLD_EN : 0);
0044 }
0045
0046 static int
0047 aiu_encoder_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
0048 struct snd_soc_dai *dai)
0049 {
0050 struct snd_soc_component *component = dai->component;
0051
0052 switch (cmd) {
0053 case SNDRV_PCM_TRIGGER_START:
0054 case SNDRV_PCM_TRIGGER_RESUME:
0055 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0056 aiu_encoder_spdif_hold(component, false);
0057 return 0;
0058
0059 case SNDRV_PCM_TRIGGER_STOP:
0060 case SNDRV_PCM_TRIGGER_SUSPEND:
0061 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0062 aiu_encoder_spdif_hold(component, true);
0063 return 0;
0064
0065 default:
0066 return -EINVAL;
0067 }
0068 }
0069
0070 static int aiu_encoder_spdif_setup_cs_word(struct snd_soc_component *component,
0071 struct snd_pcm_hw_params *params)
0072 {
0073 u8 cs[AIU_CS_WORD_LEN];
0074 unsigned int val;
0075 int ret;
0076
0077 ret = snd_pcm_create_iec958_consumer_hw_params(params, cs,
0078 AIU_CS_WORD_LEN);
0079 if (ret < 0)
0080 return ret;
0081
0082
0083 val = cs[1] | cs[0] << 8;
0084 snd_soc_component_write(component, AIU_958_CHSTAT_L0, val);
0085 snd_soc_component_write(component, AIU_958_CHSTAT_R0, val);
0086
0087
0088 val = cs[3] | cs[2] << 8;
0089 snd_soc_component_write(component, AIU_958_CHSTAT_L1, val);
0090 snd_soc_component_write(component, AIU_958_CHSTAT_R1, val);
0091
0092 return 0;
0093 }
0094
0095 static int aiu_encoder_spdif_hw_params(struct snd_pcm_substream *substream,
0096 struct snd_pcm_hw_params *params,
0097 struct snd_soc_dai *dai)
0098 {
0099 struct snd_soc_component *component = dai->component;
0100 struct aiu *aiu = snd_soc_component_get_drvdata(component);
0101 unsigned int val = 0, mrate;
0102 int ret;
0103
0104
0105 aiu_encoder_spdif_divider_enable(component, false);
0106
0107 switch (params_physical_width(params)) {
0108 case 16:
0109 val |= AIU_958_MISC_MODE_16BITS;
0110 val |= FIELD_PREP(AIU_958_MISC_16BITS_ALIGN, 2);
0111 break;
0112 case 32:
0113 val |= AIU_958_MISC_MODE_32BITS;
0114 break;
0115 default:
0116 dev_err(dai->dev, "Unsupported physical width\n");
0117 return -EINVAL;
0118 }
0119
0120 snd_soc_component_update_bits(component, AIU_958_MISC,
0121 AIU_958_MISC_NON_PCM |
0122 AIU_958_MISC_MODE_16BITS |
0123 AIU_958_MISC_16BITS_ALIGN |
0124 AIU_958_MISC_MODE_32BITS |
0125 AIU_958_MISC_FORCE_LR |
0126 AIU_958_MISC_U_FROM_STREAM,
0127 val);
0128
0129
0130 ret = aiu_encoder_spdif_setup_cs_word(component, params);
0131 if (ret) {
0132 dev_err(dai->dev, "failed to set channel status word\n");
0133 return ret;
0134 }
0135
0136 snd_soc_component_update_bits(component, AIU_CLK_CTRL,
0137 AIU_CLK_CTRL_958_DIV |
0138 AIU_CLK_CTRL_958_DIV_MORE,
0139 FIELD_PREP(AIU_CLK_CTRL_958_DIV,
0140 __ffs(AIU_958_INTERNAL_DIV)));
0141
0142
0143 mrate = params_rate(params) * 128 * AIU_958_INTERNAL_DIV;
0144 ret = clk_set_rate(aiu->spdif.clks[MCLK].clk, mrate);
0145 if (ret) {
0146 dev_err(dai->dev, "failed to set mclk rate\n");
0147 return ret;
0148 }
0149
0150 aiu_encoder_spdif_divider_enable(component, true);
0151
0152 return 0;
0153 }
0154
0155 static int aiu_encoder_spdif_hw_free(struct snd_pcm_substream *substream,
0156 struct snd_soc_dai *dai)
0157 {
0158 struct snd_soc_component *component = dai->component;
0159
0160 aiu_encoder_spdif_divider_enable(component, false);
0161
0162 return 0;
0163 }
0164
0165 static int aiu_encoder_spdif_startup(struct snd_pcm_substream *substream,
0166 struct snd_soc_dai *dai)
0167 {
0168 struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
0169 int ret;
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183 ret = clk_set_parent(aiu->spdif.clks[MCLK].clk,
0184 aiu->spdif_mclk);
0185 if (ret)
0186 return ret;
0187
0188 ret = clk_bulk_prepare_enable(aiu->spdif.clk_num, aiu->spdif.clks);
0189 if (ret)
0190 dev_err(dai->dev, "failed to enable spdif clocks\n");
0191
0192 return ret;
0193 }
0194
0195 static void aiu_encoder_spdif_shutdown(struct snd_pcm_substream *substream,
0196 struct snd_soc_dai *dai)
0197 {
0198 struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
0199
0200 clk_bulk_disable_unprepare(aiu->spdif.clk_num, aiu->spdif.clks);
0201 }
0202
0203 const struct snd_soc_dai_ops aiu_encoder_spdif_dai_ops = {
0204 .trigger = aiu_encoder_spdif_trigger,
0205 .hw_params = aiu_encoder_spdif_hw_params,
0206 .hw_free = aiu_encoder_spdif_hw_free,
0207 .startup = aiu_encoder_spdif_startup,
0208 .shutdown = aiu_encoder_spdif_shutdown,
0209 };