1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * AC97 Controller Driver for Loongson-1 SoC
4 *
5 * Copyright (C) 2025 Keguang Zhang <keguang.zhang@gmail.com>
6 */
7
8 #include <linux/bitfield.h>
9 #include <linux/dma-mapping.h>
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/regmap.h>
14
15 #include <sound/dmaengine_pcm.h>
16 #include <sound/pcm.h>
17 #include <sound/pcm_params.h>
18 #include <sound/soc.h>
19
20 /* Loongson-1 AC97 Controller Registers */
21 #define AC97_CSR 0x0
22 #define AC97_OCC0 0x4
23 #define AC97_ICC 0x10
24 #define AC97_CRAC 0x18
25 #define AC97_INTRAW 0x54
26 #define AC97_INTM 0x58
27 #define AC97_INT_CW_CLR 0x68
28 #define AC97_INT_CR_CLR 0x6c
29
30 /* Control Status Register Bits (CSR) */
31 #define CSR_RESUME BIT(1)
32 #define CSR_RST_FORCE BIT(0)
33
34 /* MIC Channel Configuration Bits */
35 #define M_DMA_EN BIT(22)
36 #define M_FIFO_THRES GENMASK(21, 20)
37 #define M_FIFO_THRES_FULL FIELD_PREP(M_FIFO_THRES, 3)
38 #define M_FIFO_THRES_HALF FIELD_PREP(M_FIFO_THRES, 1)
39 #define M_FIFO_THRES_QUARTER FIELD_PREP(M_FIFO_THRES, 0)
40 #define M_SW GENMASK(19, 18)
41 #define M_SW_16_BITS FIELD_PREP(M_SW, 2)
42 #define M_SW_8_BITS FIELD_PREP(M_SW, 0)
43 #define M_VSR BIT(17)
44 #define M_CH_EN BIT(16)
45 /* Right Channel Configuration Bits */
46 #define R_DMA_EN BIT(14)
47 #define R_FIFO_THRES GENMASK(13, 12)
48 #define R_FIFO_THRES_EMPTY FIELD_PREP(R_FIFO_THRES, 3)
49 #define R_FIFO_THRES_HALF FIELD_PREP(R_FIFO_THRES, 1)
50 #define R_FIFO_THRES_QUARTER FIELD_PREP(R_FIFO_THRES, 0)
51 #define R_SW GENMASK(11, 10)
52 #define R_SW_16_BITS FIELD_PREP(R_SW, 2)
53 #define R_SW_8_BITS FIELD_PREP(R_SW, 0)
54 #define R_VSR BIT(9)
55 #define R_CH_EN BIT(8)
56 /* Left Channel Configuration Bits */
57 #define L_DMA_EN BIT(6)
58 #define L_FIFO_THRES GENMASK(5, 4)
59 #define L_FIFO_THRES_EMPTY FIELD_PREP(L_FIFO_THRES, 3)
60 #define L_FIFO_THRES_HALF FIELD_PREP(L_FIFO_THRES, 1)
61 #define L_FIFO_THRES_QUARTER FIELD_PREP(L_FIFO_THRES, 0)
62 #define L_SW GENMASK(3, 2)
63 #define L_SW_16_BITS FIELD_PREP(L_SW, 2)
64 #define L_SW_8_BITS FIELD_PREP(L_SW, 0)
65 #define L_VSR BIT(1)
66 #define L_CH_EN BIT(0)
67
68 /* Codec Register Access Command Bits (CRAC) */
69 #define CODEC_WR BIT(31)
70 #define CODEC_ADR GENMASK(22, 16)
71 #define CODEC_DAT GENMASK(15, 0)
72
73 /* Interrupt Register (INTRAW) */
74 #define CW_DONE BIT(1)
75 #define CR_DONE BIT(0)
76
77 #define LS1X_AC97_DMA_TX_EN BIT(31)
78 #define LS1X_AC97_DMA_STEREO BIT(30)
79 #define LS1X_AC97_DMA_TX_BYTES GENMASK(29, 28)
80 #define LS1X_AC97_DMA_TX_4_BYTES FIELD_PREP(LS1X_AC97_DMA_TX_BYTES, 2)
81 #define LS1X_AC97_DMA_TX_2_BYTES FIELD_PREP(LS1X_AC97_DMA_TX_BYTES, 1)
82 #define LS1X_AC97_DMA_TX_1_BYTE FIELD_PREP(LS1X_AC97_DMA_TX_BYTES, 0)
83 #define LS1X_AC97_DMA_DADDR_MASK GENMASK(27, 0)
84
85 #define LS1X_AC97_DMA_FIFO_SIZE 128
86
87 #define LS1X_AC97_TIMEOUT 3000
88
89 struct ls1x_ac97 {
90 void __iomem *reg_base;
91 struct regmap *regmap;
92 dma_addr_t tx_dma_base;
93 dma_addr_t rx_dma_base;
94 struct snd_dmaengine_dai_dma_data capture_dma_data;
95 struct snd_dmaengine_dai_dma_data playback_dma_data;
96 };
97
98 static struct ls1x_ac97 *ls1x_ac97;
99
100 static const struct regmap_config ls1x_ac97_regmap_config = {
101 .reg_bits = 32,
102 .val_bits = 32,
103 .reg_stride = 4,
104 };
105
ls1x_ac97_reset(struct snd_ac97 * ac97)106 static void ls1x_ac97_reset(struct snd_ac97 *ac97)
107 {
108 int val;
109
110 regmap_write(ls1x_ac97->regmap, AC97_CSR, CSR_RST_FORCE);
111 regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_CSR, val,
112 !(val & CSR_RESUME), 0, LS1X_AC97_TIMEOUT);
113 }
114
ls1x_ac97_write(struct snd_ac97 * ac97,unsigned short reg,unsigned short val)115 static void ls1x_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
116 {
117 int tmp, ret;
118
119 tmp = FIELD_PREP(CODEC_ADR, reg) | FIELD_PREP(CODEC_DAT, val);
120 regmap_write(ls1x_ac97->regmap, AC97_CRAC, tmp);
121 ret = regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_INTRAW, tmp,
122 (tmp & CW_DONE), 0, LS1X_AC97_TIMEOUT);
123 if (ret)
124 pr_err("timeout on AC97 write! %d\n", ret);
125
126 regmap_read(ls1x_ac97->regmap, AC97_INT_CW_CLR, &ret);
127 }
128
ls1x_ac97_read(struct snd_ac97 * ac97,unsigned short reg)129 static unsigned short ls1x_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
130 {
131 int val, ret;
132
133 val = CODEC_WR | FIELD_PREP(CODEC_ADR, reg);
134 regmap_write(ls1x_ac97->regmap, AC97_CRAC, val);
135 ret = regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_INTRAW, val,
136 (val & CR_DONE), 0, LS1X_AC97_TIMEOUT);
137 if (ret) {
138 pr_err("timeout on AC97 read! %d\n", ret);
139 return ret;
140 }
141
142 regmap_read(ls1x_ac97->regmap, AC97_INT_CR_CLR, &ret);
143 regmap_read(ls1x_ac97->regmap, AC97_CRAC, &ret);
144
145 return (ret & CODEC_DAT);
146 }
147
ls1x_ac97_init(struct snd_ac97 * ac97)148 static void ls1x_ac97_init(struct snd_ac97 *ac97)
149 {
150 writel(0, ls1x_ac97->reg_base + AC97_INTRAW);
151 writel(0, ls1x_ac97->reg_base + AC97_INTM);
152
153 /* Config output channels */
154 regmap_update_bits(ls1x_ac97->regmap, AC97_OCC0,
155 R_DMA_EN | R_FIFO_THRES | R_CH_EN |
156 L_DMA_EN | L_FIFO_THRES | L_CH_EN,
157 R_DMA_EN | R_FIFO_THRES_EMPTY | R_CH_EN |
158 L_DMA_EN | L_FIFO_THRES_EMPTY | L_CH_EN);
159
160 /* Config inputs channel */
161 regmap_update_bits(ls1x_ac97->regmap, AC97_ICC,
162 M_DMA_EN | M_FIFO_THRES | M_CH_EN |
163 R_DMA_EN | R_FIFO_THRES | R_CH_EN |
164 L_DMA_EN | L_FIFO_THRES | L_CH_EN,
165 M_DMA_EN | M_FIFO_THRES_FULL | M_CH_EN |
166 R_DMA_EN | R_FIFO_THRES_EMPTY | R_CH_EN |
167 L_DMA_EN | L_FIFO_THRES_EMPTY | L_CH_EN);
168
169 if (ac97->ext_id & AC97_EI_VRA) {
170 regmap_update_bits(ls1x_ac97->regmap, AC97_OCC0, R_VSR | L_VSR, R_VSR | L_VSR);
171 regmap_update_bits(ls1x_ac97->regmap, AC97_ICC, M_VSR, M_VSR);
172 }
173 }
174
175 static struct snd_ac97_bus_ops ls1x_ac97_ops = {
176 .reset = ls1x_ac97_reset,
177 .write = ls1x_ac97_write,
178 .read = ls1x_ac97_read,
179 .init = ls1x_ac97_init,
180 };
181
ls1x_ac97_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * cpu_dai)182 static int ls1x_ac97_hw_params(struct snd_pcm_substream *substream,
183 struct snd_pcm_hw_params *params,
184 struct snd_soc_dai *cpu_dai)
185 {
186 struct ls1x_ac97 *ac97 = dev_get_drvdata(cpu_dai->dev);
187 struct snd_dmaengine_dai_dma_data *dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
188
189 switch (params_channels(params)) {
190 case 1:
191 dma_data->addr &= ~LS1X_AC97_DMA_STEREO;
192 break;
193 case 2:
194 dma_data->addr |= LS1X_AC97_DMA_STEREO;
195 break;
196 default:
197 dev_err(cpu_dai->dev, "unsupported channels! %d\n", params_channels(params));
198 return -EINVAL;
199 }
200
201 switch (params_format(params)) {
202 case SNDRV_PCM_FORMAT_S8:
203 case SNDRV_PCM_FORMAT_U8:
204 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
205 regmap_update_bits(ac97->regmap, AC97_OCC0,
206 R_SW | L_SW,
207 R_SW_8_BITS | L_SW_8_BITS);
208 else
209 regmap_update_bits(ac97->regmap, AC97_ICC,
210 M_SW | R_SW | L_SW,
211 M_SW_8_BITS | R_SW_8_BITS | L_SW_8_BITS);
212 break;
213 case SNDRV_PCM_FORMAT_S16_LE:
214 case SNDRV_PCM_FORMAT_U16_LE:
215 case SNDRV_PCM_FORMAT_S16_BE:
216 case SNDRV_PCM_FORMAT_U16_BE:
217 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
218 regmap_update_bits(ac97->regmap, AC97_OCC0,
219 R_SW | L_SW,
220 R_SW_16_BITS | L_SW_16_BITS);
221 else
222 regmap_update_bits(ac97->regmap, AC97_ICC,
223 M_SW | R_SW | L_SW,
224 M_SW_16_BITS | R_SW_16_BITS | L_SW_16_BITS);
225 break;
226 default:
227 dev_err(cpu_dai->dev, "unsupported format! %d\n", params_format(params));
228 return -EINVAL;
229 }
230
231 return 0;
232 }
233
ls1x_ac97_dai_probe(struct snd_soc_dai * cpu_dai)234 static int ls1x_ac97_dai_probe(struct snd_soc_dai *cpu_dai)
235 {
236 struct ls1x_ac97 *ac97 = dev_get_drvdata(cpu_dai->dev);
237
238 ac97->capture_dma_data.addr = ac97->rx_dma_base & LS1X_AC97_DMA_DADDR_MASK;
239 ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
240 ac97->capture_dma_data.fifo_size = LS1X_AC97_DMA_FIFO_SIZE;
241
242 ac97->playback_dma_data.addr = ac97->tx_dma_base & LS1X_AC97_DMA_DADDR_MASK;
243 ac97->playback_dma_data.addr |= LS1X_AC97_DMA_TX_4_BYTES;
244 ac97->playback_dma_data.addr |= LS1X_AC97_DMA_TX_EN;
245 ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
246 ac97->playback_dma_data.fifo_size = LS1X_AC97_DMA_FIFO_SIZE;
247
248 snd_soc_dai_init_dma_data(cpu_dai, &ac97->playback_dma_data, &ac97->capture_dma_data);
249 snd_soc_dai_set_drvdata(cpu_dai, ac97);
250
251 return 0;
252 }
253
254 static const struct snd_soc_dai_ops ls1x_ac97_dai_ops = {
255 .probe = ls1x_ac97_dai_probe,
256 .hw_params = ls1x_ac97_hw_params,
257 };
258
259 #define LS1X_AC97_FMTS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |\
260 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
261 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE)
262
263 static struct snd_soc_dai_driver ls1x_ac97_dai[] = {
264 {
265 .name = "ls1x-ac97",
266 .playback = {
267 .stream_name = "AC97 Playback",
268 .channels_min = 1,
269 .channels_max = 2,
270 .rates = SNDRV_PCM_RATE_8000_48000,
271 .formats = LS1X_AC97_FMTS,
272 },
273 .capture = {
274 .stream_name = "AC97 Capture",
275 .channels_min = 1,
276 .channels_max = 2,
277 .rates = SNDRV_PCM_RATE_8000_48000,
278 .formats = LS1X_AC97_FMTS,
279 },
280 .ops = &ls1x_ac97_dai_ops,
281 },
282 };
283
284 static const struct snd_soc_component_driver ls1x_ac97_component = {
285 .name = KBUILD_MODNAME,
286 .legacy_dai_naming = 1,
287 };
288
ls1x_ac97_probe(struct platform_device * pdev)289 static int ls1x_ac97_probe(struct platform_device *pdev)
290 {
291 struct device *dev = &pdev->dev;
292 struct ls1x_ac97 *ac97;
293 struct resource *res;
294 int ret;
295
296 ac97 = devm_kzalloc(dev, sizeof(struct ls1x_ac97), GFP_KERNEL);
297 if (!ac97)
298 return -ENOMEM;
299 ls1x_ac97 = ac97;
300 platform_set_drvdata(pdev, ac97);
301
302 ac97->reg_base = devm_platform_ioremap_resource(pdev, 0);
303 if (IS_ERR(ac97->reg_base))
304 return PTR_ERR(ac97->reg_base);
305
306 ac97->regmap = devm_regmap_init_mmio(dev, ac97->reg_base, &ls1x_ac97_regmap_config);
307 if (IS_ERR(ac97->regmap))
308 return dev_err_probe(dev, PTR_ERR(ac97->regmap), "devm_regmap_init_mmio failed\n");
309
310 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audio-tx");
311 if (!res)
312 return dev_err_probe(dev, -EINVAL, "Missing 'audio-tx' in reg-names property\n");
313
314 ac97->tx_dma_base = dma_map_resource(dev, res->start, resource_size(res),
315 DMA_TO_DEVICE, 0);
316 if (dma_mapping_error(dev, ac97->tx_dma_base))
317 return -ENXIO;
318
319 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audio-rx");
320 if (!res)
321 return dev_err_probe(dev, -EINVAL, "Missing 'audio-rx' in reg-names property\n");
322
323 ac97->rx_dma_base = dma_map_resource(dev, res->start, resource_size(res),
324 DMA_FROM_DEVICE, 0);
325 if (dma_mapping_error(dev, ac97->rx_dma_base))
326 return -ENXIO;
327
328 ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
329 if (ret)
330 dev_err_probe(dev, ret, "failed to register PCM\n");
331
332 ret = devm_snd_soc_register_component(dev, &ls1x_ac97_component,
333 ls1x_ac97_dai, ARRAY_SIZE(ls1x_ac97_dai));
334 if (ret)
335 dev_err_probe(dev, ret, "failed to register DAI\n");
336
337 return snd_soc_set_ac97_ops(&ls1x_ac97_ops);
338 }
339
ls1x_ac97_remove(struct platform_device * pdev)340 static void ls1x_ac97_remove(struct platform_device *pdev)
341 {
342 ls1x_ac97 = NULL;
343 snd_soc_set_ac97_ops(NULL);
344 }
345
346 #ifdef CONFIG_PM_SLEEP
ls1x_ac97_suspend(struct device * dev)347 static int ls1x_ac97_suspend(struct device *dev)
348 {
349 int val;
350
351 regmap_clear_bits(ls1x_ac97->regmap, AC97_OCC0, R_DMA_EN | R_CH_EN | L_DMA_EN | L_CH_EN);
352 regmap_clear_bits(ls1x_ac97->regmap, AC97_ICC,
353 M_DMA_EN | M_CH_EN | R_DMA_EN | R_CH_EN | L_DMA_EN | L_CH_EN);
354 regmap_set_bits(ls1x_ac97->regmap, AC97_CSR, CSR_RESUME);
355
356 return regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_CSR, val,
357 (val & CSR_RESUME), 0, LS1X_AC97_TIMEOUT);
358 }
359
ls1x_ac97_resume(struct device * dev)360 static int ls1x_ac97_resume(struct device *dev)
361 {
362 int val;
363
364 regmap_set_bits(ls1x_ac97->regmap, AC97_OCC0, R_DMA_EN | R_CH_EN | L_DMA_EN | L_CH_EN);
365 regmap_set_bits(ls1x_ac97->regmap, AC97_ICC,
366 M_DMA_EN | M_CH_EN | R_DMA_EN | R_CH_EN | L_DMA_EN | L_CH_EN);
367 regmap_set_bits(ls1x_ac97->regmap, AC97_CSR, CSR_RESUME);
368
369 return regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_CSR, val,
370 !(val & CSR_RESUME), 0, LS1X_AC97_TIMEOUT);
371 }
372 #endif
373
374 static const struct dev_pm_ops ls1x_ac97_pm_ops = {
375 SET_SYSTEM_SLEEP_PM_OPS(ls1x_ac97_suspend, ls1x_ac97_resume)
376 };
377
378 static const struct of_device_id ls1x_ac97_match[] = {
379 { .compatible = "loongson,ls1b-ac97" },
380 { /* sentinel */ }
381 };
382 MODULE_DEVICE_TABLE(of, ls1x_ac97_match);
383
384 static struct platform_driver ls1x_ac97_driver = {
385 .probe = ls1x_ac97_probe,
386 .remove = ls1x_ac97_remove,
387 .driver = {
388 .name = KBUILD_MODNAME,
389 .of_match_table = ls1x_ac97_match,
390 .pm = &ls1x_ac97_pm_ops,
391 },
392 };
393
394 module_platform_driver(ls1x_ac97_driver);
395
396 MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>");
397 MODULE_DESCRIPTION("Loongson-1 AC97 Controller Driver");
398 MODULE_LICENSE("GPL");
399