xref: /linux/sound/soc/sophgo/cv1800b-sound-dac.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Internal DAC codec for cv1800b based CPUs
4  */
5 
6 #include <linux/module.h>
7 #include <linux/platform_device.h>
8 #include <linux/bitfield.h>
9 #include <linux/bits.h>
10 #include <sound/soc.h>
11 #include <linux/io.h>
12 
13 #define CV1800B_TXDAC_CTRL0   0x00
14 #define CV1800B_TXDAC_CTRL1   0x04
15 #define CV1800B_TXDAC_STATUS  0x08
16 #define CV1800B_TXDAC_AFE0    0x0c
17 #define CV1800B_TXDAC_AFE1    0x10
18 #define CV1800B_TXDAC_ANA0    0x20
19 #define CV1800B_TXDAC_ANA1    0x24
20 #define CV1800B_TXDAC_ANA2    0x28
21 
22 /* cv1800b_TXDAC_CTRL0 */
23 #define REG_TXDAC_EN GENMASK(0, 0)
24 #define REG_I2S_RX_EN GENMASK(1, 1)
25 
26 /* cv1800b_TXDAC_CTRL1 */
27 #define REG_TXDAC_CIC_OPT GENMASK(1, 0)
28 
29 /* cv1800b_TXDAC_AFE0 */
30 #define REG_TXDAC_INIT_DLY_CNT GENMASK(5, 0)
31 
32 /* cv1800b_TXDAC_ANA2 */
33 #define TXDAC_OW_VAL_L_MASK GENMASK(7, 0)
34 #define TXDAC_OW_VAL_R_MASK GENMASK(15, 8)
35 #define TXDAC_OW_EN_L_MASK GENMASK(16, 16)
36 #define TXDAC_OW_EN_R_MASK GENMASK(17, 17)
37 
38 struct cv1800b_priv {
39 	void __iomem *regs;
40 	struct device *dev;
41 };
42 
43 enum decimation_values {
44 	DECIMATION_64 = 0,
45 	DECIMATION_128,
46 	DECIMATION_256,
47 	DECIMATION_512,
48 };
49 
50 static void cv1800b_dac_enable(struct cv1800b_priv *priv, bool enable)
51 {
52 	u32 val;
53 
54 	val = readl(priv->regs + CV1800B_TXDAC_CTRL0);
55 	val = u32_replace_bits(val, enable, REG_TXDAC_EN);
56 	val = u32_replace_bits(val, enable, REG_I2S_RX_EN);
57 	writel(val, priv->regs + CV1800B_TXDAC_CTRL0);
58 }
59 
60 /*
61  * Control the DAC overwrite bits. When enabled, the DAC outputs the fixed
62  * overwrite value instead of samples from the I2S input.
63  */
64 static void cv1800b_dac_mute(struct cv1800b_priv *priv, bool enable)
65 {
66 	u32 val;
67 
68 	val = readl(priv->regs + CV1800B_TXDAC_ANA2);
69 	val = u32_replace_bits(val, enable, TXDAC_OW_EN_L_MASK);
70 	val = u32_replace_bits(val, enable, TXDAC_OW_EN_R_MASK);
71 	writel(val, priv->regs + CV1800B_TXDAC_ANA2);
72 }
73 
74 static int cv1800b_dac_decimation(struct cv1800b_priv *priv, u8 dec)
75 {
76 	u32 val;
77 
78 	if (dec > 3)
79 		return -EINVAL;
80 
81 	val = readl(priv->regs + CV1800B_TXDAC_CTRL1);
82 	val = u32_replace_bits(val, dec, REG_TXDAC_CIC_OPT);
83 	writel(val, priv->regs + CV1800B_TXDAC_CTRL1);
84 	return 0;
85 }
86 
87 static int cv1800b_dac_dly(struct cv1800b_priv *priv, u32 dly)
88 {
89 	u32 val;
90 
91 	if (dly > 63)
92 		return -EINVAL;
93 
94 	val = readl(priv->regs + CV1800B_TXDAC_AFE0);
95 	val = u32_replace_bits(val, dly, REG_TXDAC_INIT_DLY_CNT);
96 	writel(val, priv->regs + CV1800B_TXDAC_AFE0);
97 	return 0;
98 }
99 
100 static int cv1800b_dac_hw_params(struct snd_pcm_substream *substream,
101 				 struct snd_pcm_hw_params *params,
102 				 struct snd_soc_dai *dai)
103 {
104 	struct cv1800b_priv *priv = snd_soc_dai_get_drvdata(dai);
105 	int ret;
106 	unsigned int rate = params_rate(params);
107 
108 	if (rate != 48000) {
109 		dev_err(priv->dev, "rate %u is not supported\n", rate);
110 		return -EINVAL;
111 	}
112 	/* Clear DAC overwrite so playback uses I2S data. */
113 	cv1800b_dac_mute(priv, false);
114 	/* minimal decimation for 48kHz is 64*/
115 	ret = cv1800b_dac_decimation(priv, DECIMATION_64);
116 	if (ret)
117 		return ret;
118 
119 	/* value is taken from vendors driver 48kHz
120 	 * tested on sg2000 and sg2002.
121 	 */
122 	ret = cv1800b_dac_dly(priv, 0x19);
123 	if (ret)
124 		return ret;
125 
126 	return 0;
127 }
128 
129 static int cv1800b_dac_dai_trigger(struct snd_pcm_substream *substream, int cmd,
130 				   struct snd_soc_dai *dai)
131 {
132 	struct cv1800b_priv *priv = snd_soc_dai_get_drvdata(dai);
133 
134 	switch (cmd) {
135 	case SNDRV_PCM_TRIGGER_START:
136 	case SNDRV_PCM_TRIGGER_RESUME:
137 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
138 		cv1800b_dac_enable(priv, true);
139 		break;
140 	case SNDRV_PCM_TRIGGER_STOP:
141 	case SNDRV_PCM_TRIGGER_SUSPEND:
142 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
143 		cv1800b_dac_enable(priv, false);
144 		break;
145 	default:
146 		return -EINVAL;
147 	}
148 
149 	return 0;
150 }
151 
152 static const struct snd_soc_dai_ops cv1800b_dac_dai_ops = {
153 	.hw_params = cv1800b_dac_hw_params,
154 	.trigger = cv1800b_dac_dai_trigger,
155 };
156 
157 static struct snd_soc_dai_driver cv1800b_dac_dai = {
158 	.name = "dac-hifi",
159 	.playback = { .stream_name = "DAC Playback",
160 		      .channels_min = 2,
161 		      .channels_max = 2,
162 		      .rates = SNDRV_PCM_RATE_48000,
163 		      .formats = SNDRV_PCM_FMTBIT_S16_LE },
164 	.ops = &cv1800b_dac_dai_ops,
165 };
166 
167 static const struct snd_soc_component_driver cv1800b_dac_component = {
168 	.name = "cv1800b-dac-codec",
169 };
170 
171 static int cv1800b_dac_probe(struct platform_device *pdev)
172 {
173 	struct device *dev = &pdev->dev;
174 	struct cv1800b_priv *priv;
175 
176 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
177 	if (!priv)
178 		return -ENOMEM;
179 
180 	priv->dev = dev;
181 	priv->regs = devm_platform_ioremap_resource(pdev, 0);
182 	if (IS_ERR(priv->regs))
183 		return PTR_ERR(priv->regs);
184 
185 	platform_set_drvdata(pdev, priv);
186 	return devm_snd_soc_register_component(&pdev->dev,
187 					       &cv1800b_dac_component,
188 					       &cv1800b_dac_dai, 1);
189 }
190 
191 static const struct of_device_id cv1800b_dac_of_match[] = {
192 	{ .compatible = "sophgo,cv1800b-sound-dac" },
193 	{ /* sentinel */ }
194 };
195 MODULE_DEVICE_TABLE(of, cv1800b_dac_of_match);
196 
197 static struct platform_driver cv1800b_dac_driver = {
198 	.probe = cv1800b_dac_probe,
199 	.driver = {
200 		.name = "cv1800b-dac-codec",
201 		.of_match_table = cv1800b_dac_of_match,
202 	},
203 };
204 module_platform_driver(cv1800b_dac_driver);
205 
206 MODULE_DESCRIPTION("DAC codec for CV1800B");
207 MODULE_AUTHOR("Anton D. Stavinskii <stavinsky@gmail.com>");
208 MODULE_LICENSE("GPL");
209