1 // SPDX-License-Identifier: GPL-2.0-or-later 2 // 3 // Author: Kevin Wells <kevin.wells@nxp.com> 4 // 5 // Copyright (C) 2008 NXP Semiconductors 6 // Copyright 2023 Timesys Corporation <piotr.wojtaszczyk@timesys.com> 7 8 #include <linux/init.h> 9 #include <linux/module.h> 10 #include <linux/interrupt.h> 11 #include <linux/device.h> 12 #include <linux/delay.h> 13 #include <linux/clk.h> 14 #include <linux/io.h> 15 16 #include <sound/core.h> 17 #include <sound/pcm.h> 18 #include <sound/pcm_params.h> 19 #include <sound/dmaengine_pcm.h> 20 #include <sound/initval.h> 21 #include <sound/soc.h> 22 23 #include "lpc3xxx-i2s.h" 24 25 #define I2S_PLAYBACK_FLAG 0x1 26 #define I2S_CAPTURE_FLAG 0x2 27 28 #define LPC3XXX_I2S_RATES ( \ 29 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ 30 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 31 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) 32 33 #define LPC3XXX_I2S_FORMATS ( \ 34 SNDRV_PCM_FMTBIT_S8 | \ 35 SNDRV_PCM_FMTBIT_S16_LE | \ 36 SNDRV_PCM_FMTBIT_S32_LE) 37 38 static void __lpc3xxx_find_clkdiv(u32 *clkx, u32 *clky, int freq, int xbytes, u32 clkrate) 39 { 40 u32 i2srate; 41 u32 idxx, idyy; 42 u32 diff, trate, baseclk; 43 44 /* Adjust rate for sample size (bits) and 2 channels and offset for 45 * divider in clock output 46 */ 47 i2srate = (freq / 100) * 2 * (8 * xbytes); 48 i2srate = i2srate << 1; 49 clkrate = clkrate / 100; 50 baseclk = clkrate; 51 *clkx = 1; 52 *clky = 1; 53 54 /* Find the best divider */ 55 *clkx = *clky = 0; 56 diff = ~0; 57 for (idxx = 1; idxx < 0xFF; idxx++) { 58 for (idyy = 1; idyy < 0xFF; idyy++) { 59 trate = (baseclk * idxx) / idyy; 60 if (abs(trate - i2srate) < diff) { 61 diff = abs(trate - i2srate); 62 *clkx = idxx; 63 *clky = idyy; 64 } 65 } 66 } 67 } 68 69 static int lpc3xxx_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) 70 { 71 struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); 72 struct device *dev = i2s_info_p->dev; 73 u32 flag; 74 int ret = 0; 75 76 guard(mutex)(&i2s_info_p->lock); 77 78 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 79 flag = I2S_PLAYBACK_FLAG; 80 else 81 flag = I2S_CAPTURE_FLAG; 82 83 if (flag & i2s_info_p->streams_in_use) { 84 dev_warn(dev, "I2S channel is busy\n"); 85 ret = -EBUSY; 86 return ret; 87 } 88 89 if (i2s_info_p->streams_in_use == 0) { 90 ret = clk_prepare_enable(i2s_info_p->clk); 91 if (ret) { 92 dev_err(dev, "Can't enable clock, err=%d\n", ret); 93 return ret; 94 } 95 } 96 97 i2s_info_p->streams_in_use |= flag; 98 return 0; 99 } 100 101 static void lpc3xxx_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) 102 { 103 struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); 104 struct regmap *regs = i2s_info_p->regs; 105 const u32 stop_bits = (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP); 106 u32 flag; 107 108 guard(mutex)(&i2s_info_p->lock); 109 110 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 111 flag = I2S_PLAYBACK_FLAG; 112 regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, 0); 113 regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, stop_bits, stop_bits); 114 } else { 115 flag = I2S_CAPTURE_FLAG; 116 regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, 0); 117 regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, stop_bits, stop_bits); 118 } 119 i2s_info_p->streams_in_use &= ~flag; 120 121 if (i2s_info_p->streams_in_use == 0) 122 clk_disable_unprepare(i2s_info_p->clk); 123 } 124 125 static int lpc3xxx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, 126 int clk_id, unsigned int freq, int dir) 127 { 128 struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); 129 130 /* Will use in HW params later */ 131 i2s_info_p->freq = freq; 132 133 return 0; 134 } 135 136 static int lpc3xxx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) 137 { 138 struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); 139 struct device *dev = i2s_info_p->dev; 140 141 if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) { 142 dev_warn(dev, "unsupported bus format %d\n", fmt); 143 return -EINVAL; 144 } 145 146 if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) { 147 dev_warn(dev, "unsupported clock provider %d\n", fmt); 148 return -EINVAL; 149 } 150 151 return 0; 152 } 153 154 static int lpc3xxx_i2s_hw_params(struct snd_pcm_substream *substream, 155 struct snd_pcm_hw_params *params, 156 struct snd_soc_dai *cpu_dai) 157 { 158 struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); 159 struct device *dev = i2s_info_p->dev; 160 struct regmap *regs = i2s_info_p->regs; 161 int xfersize; 162 u32 tmp, clkx, clky; 163 164 tmp = LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP; 165 switch (params_format(params)) { 166 case SNDRV_PCM_FORMAT_S8: 167 tmp |= LPC3XXX_I2S_WW8 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW8_HP); 168 xfersize = 1; 169 break; 170 171 case SNDRV_PCM_FORMAT_S16_LE: 172 tmp |= LPC3XXX_I2S_WW16 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW16_HP); 173 xfersize = 2; 174 break; 175 176 case SNDRV_PCM_FORMAT_S32_LE: 177 tmp |= LPC3XXX_I2S_WW32 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW32_HP); 178 xfersize = 4; 179 break; 180 181 default: 182 dev_warn(dev, "Unsupported audio data format %d\n", params_format(params)); 183 return -EINVAL; 184 } 185 186 if (params_channels(params) == 1) 187 tmp |= LPC3XXX_I2S_MONO; 188 189 __lpc3xxx_find_clkdiv(&clkx, &clky, i2s_info_p->freq, xfersize, i2s_info_p->clkrate); 190 191 dev_dbg(dev, "Stream : %s\n", snd_pcm_direction_name(substream->stream)); 192 dev_dbg(dev, "Desired clock rate : %d\n", i2s_info_p->freq); 193 dev_dbg(dev, "Base clock rate : %d\n", i2s_info_p->clkrate); 194 dev_dbg(dev, "Transfer size (bytes) : %d\n", xfersize); 195 dev_dbg(dev, "Clock divider (x) : %d\n", clkx); 196 dev_dbg(dev, "Clock divider (y) : %d\n", clky); 197 dev_dbg(dev, "Channels : %d\n", params_channels(params)); 198 dev_dbg(dev, "Data format : %s\n", "I2S"); 199 200 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 201 regmap_write(regs, LPC3XXX_REG_I2S_DMA1, 202 LPC3XXX_I2S_DMA1_TX_EN | LPC3XXX_I2S_DMA0_TX_DEPTH(4)); 203 regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, (clkx << 8) | clky); 204 regmap_write(regs, LPC3XXX_REG_I2S_DAO, tmp); 205 } else { 206 regmap_write(regs, LPC3XXX_REG_I2S_DMA0, 207 LPC3XXX_I2S_DMA0_RX_EN | LPC3XXX_I2S_DMA1_RX_DEPTH(4)); 208 regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, (clkx << 8) | clky); 209 regmap_write(regs, LPC3XXX_REG_I2S_DAI, tmp); 210 } 211 212 return 0; 213 } 214 215 static int lpc3xxx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 216 struct snd_soc_dai *cpu_dai) 217 { 218 struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); 219 struct regmap *regs = i2s_info_p->regs; 220 int ret = 0; 221 222 switch (cmd) { 223 case SNDRV_PCM_TRIGGER_STOP: 224 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 225 case SNDRV_PCM_TRIGGER_SUSPEND: 226 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 227 regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, 228 LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP); 229 else 230 regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, 231 LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP); 232 break; 233 234 case SNDRV_PCM_TRIGGER_START: 235 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 236 case SNDRV_PCM_TRIGGER_RESUME: 237 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 238 regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, 239 (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0); 240 else 241 regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, 242 (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0); 243 break; 244 default: 245 ret = -EINVAL; 246 } 247 248 return ret; 249 } 250 251 static int lpc3xxx_i2s_dai_probe(struct snd_soc_dai *dai) 252 { 253 struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(dai); 254 255 snd_soc_dai_init_dma_data(dai, &i2s_info_p->playback_dma_config, 256 &i2s_info_p->capture_dma_config); 257 return 0; 258 } 259 260 static const struct snd_soc_dai_ops lpc3xxx_i2s_dai_ops = { 261 .probe = lpc3xxx_i2s_dai_probe, 262 .startup = lpc3xxx_i2s_startup, 263 .shutdown = lpc3xxx_i2s_shutdown, 264 .trigger = lpc3xxx_i2s_trigger, 265 .hw_params = lpc3xxx_i2s_hw_params, 266 .set_sysclk = lpc3xxx_i2s_set_dai_sysclk, 267 .set_fmt = lpc3xxx_i2s_set_dai_fmt, 268 }; 269 270 static struct snd_soc_dai_driver lpc3xxx_i2s_dai_driver = { 271 .playback = { 272 .channels_min = 1, 273 .channels_max = 2, 274 .rates = LPC3XXX_I2S_RATES, 275 .formats = LPC3XXX_I2S_FORMATS, 276 }, 277 .capture = { 278 .channels_min = 1, 279 .channels_max = 2, 280 .rates = LPC3XXX_I2S_RATES, 281 .formats = LPC3XXX_I2S_FORMATS, 282 }, 283 .ops = &lpc3xxx_i2s_dai_ops, 284 .symmetric_rate = 1, 285 .symmetric_channels = 1, 286 .symmetric_sample_bits = 1, 287 }; 288 289 static const struct snd_soc_component_driver lpc32xx_i2s_component = { 290 .name = "lpc32xx-i2s", 291 .legacy_dai_naming = 1, 292 }; 293 294 static const struct regmap_config lpc32xx_i2s_regconfig = { 295 .reg_bits = 32, 296 .reg_stride = 4, 297 .val_bits = 32, 298 .max_register = LPC3XXX_REG_I2S_RX_RATE, 299 }; 300 301 static int lpc32xx_i2s_probe(struct platform_device *pdev) 302 { 303 struct device *dev = &pdev->dev; 304 struct lpc3xxx_i2s_info *i2s_info_p; 305 struct resource *res; 306 void __iomem *iomem; 307 int ret; 308 309 i2s_info_p = devm_kzalloc(dev, sizeof(*i2s_info_p), GFP_KERNEL); 310 if (!i2s_info_p) 311 return -ENOMEM; 312 313 platform_set_drvdata(pdev, i2s_info_p); 314 i2s_info_p->dev = dev; 315 316 iomem = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 317 if (IS_ERR(iomem)) 318 return dev_err_probe(dev, PTR_ERR(iomem), "Can't map registers\n"); 319 320 i2s_info_p->regs = devm_regmap_init_mmio(dev, iomem, &lpc32xx_i2s_regconfig); 321 if (IS_ERR(i2s_info_p->regs)) 322 return dev_err_probe(dev, PTR_ERR(i2s_info_p->regs), 323 "failed to init register map: %pe\n", i2s_info_p->regs); 324 325 i2s_info_p->clk = devm_clk_get(dev, NULL); 326 if (IS_ERR(i2s_info_p->clk)) 327 return dev_err_probe(dev, PTR_ERR(i2s_info_p->clk), "Can't get clock\n"); 328 329 i2s_info_p->clkrate = clk_get_rate(i2s_info_p->clk); 330 if (i2s_info_p->clkrate == 0) 331 return dev_err_probe(dev, -EINVAL, "Invalid returned clock rate\n"); 332 333 mutex_init(&i2s_info_p->lock); 334 335 ret = devm_snd_soc_register_component(dev, &lpc32xx_i2s_component, 336 &lpc3xxx_i2s_dai_driver, 1); 337 if (ret) 338 return dev_err_probe(dev, ret, "Can't register cpu_dai component\n"); 339 340 i2s_info_p->playback_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_TX_FIFO); 341 i2s_info_p->playback_dma_config.maxburst = 4; 342 343 i2s_info_p->capture_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_RX_FIFO); 344 i2s_info_p->capture_dma_config.maxburst = 4; 345 346 ret = lpc3xxx_pcm_register(pdev); 347 if (ret) 348 return dev_err_probe(dev, ret, "Can't register pcm component\n"); 349 350 return 0; 351 } 352 353 static const struct of_device_id lpc32xx_i2s_match[] = { 354 { .compatible = "nxp,lpc3220-i2s" }, 355 {}, 356 }; 357 MODULE_DEVICE_TABLE(of, lpc32xx_i2s_match); 358 359 static struct platform_driver lpc32xx_i2s_driver = { 360 .probe = lpc32xx_i2s_probe, 361 .driver = { 362 .name = "lpc3xxx-i2s", 363 .of_match_table = lpc32xx_i2s_match, 364 }, 365 }; 366 367 module_platform_driver(lpc32xx_i2s_driver); 368 369 MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); 370 MODULE_AUTHOR("Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>"); 371 MODULE_DESCRIPTION("ASoC LPC3XXX I2S interface"); 372 MODULE_LICENSE("GPL"); 373