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 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 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 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 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 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 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 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 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 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 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