Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: zx: Add ZTE zx296702 I2S DAI driver

Add ZTE zx296702 I2S interface DAI driver

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Jun Nie and committed by
Mark Brown
e5d4cd87 6fc3d24d

+447
+9
sound/soc/zte/Kconfig
··· 6 6 help 7 7 Say Y or M if you want to add support for codecs attached to the 8 8 zx296702 spdif interface 9 + 10 + config ZX296702_I2S 11 + tristate "ZX296702 i2s" 12 + depends on SOC_ZX296702 || COMPILE_TEST 13 + depends on COMMON_CLK 14 + select SND_SOC_GENERIC_DMAENGINE_PCM 15 + help 16 + Say Y or M if you want to add support for codecs attached to the 17 + zx296702 i2s interface
+1
sound/soc/zte/Makefile
··· 1 1 obj-$(CONFIG_ZX296702_SPDIF) += zx296702-spdif.o 2 + obj-$(CONFIG_ZX296702_I2S) += zx296702-i2s.o
+437
sound/soc/zte/zx296702-i2s.c
··· 1 + /* 2 + * Copyright (C) 2015 Linaro 3 + * 4 + * Author: Jun Nie <jun.nie@linaro.org> 5 + * 6 + * License terms: GNU General Public License (GPL) version 2 7 + */ 8 + 9 + #include <linux/clk.h> 10 + #include <linux/device.h> 11 + #include <linux/init.h> 12 + #include <linux/io.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <sound/pcm.h> 16 + #include <sound/pcm_params.h> 17 + #include <sound/soc.h> 18 + #include <sound/soc-dai.h> 19 + 20 + #include <sound/core.h> 21 + #include <sound/dmaengine_pcm.h> 22 + #include <sound/initval.h> 23 + #include <sound/pcm.h> 24 + #include <sound/pcm_params.h> 25 + #include <sound/soc.h> 26 + 27 + #define ZX_I2S_PROCESS_CTRL 0x04 28 + #define ZX_I2S_TIMING_CTRL 0x08 29 + #define ZX_I2S_FIFO_CTRL 0x0C 30 + #define ZX_I2S_FIFO_STATUS 0x10 31 + #define ZX_I2S_INT_EN 0x14 32 + #define ZX_I2S_INT_STATUS 0x18 33 + #define ZX_I2S_DATA 0x1C 34 + #define ZX_I2S_FRAME_CNTR 0x20 35 + 36 + #define I2S_DEAGULT_FIFO_THRES (0x10) 37 + #define I2S_MAX_FIFO_THRES (0x20) 38 + 39 + #define ZX_I2S_PROCESS_TX_EN (1 << 0) 40 + #define ZX_I2S_PROCESS_TX_DIS (0 << 0) 41 + #define ZX_I2S_PROCESS_RX_EN (1 << 1) 42 + #define ZX_I2S_PROCESS_RX_DIS (0 << 1) 43 + #define ZX_I2S_PROCESS_I2S_EN (1 << 2) 44 + #define ZX_I2S_PROCESS_I2S_DIS (0 << 2) 45 + 46 + #define ZX_I2S_TIMING_MAST (1 << 0) 47 + #define ZX_I2S_TIMING_SLAVE (0 << 0) 48 + #define ZX_I2S_TIMING_MS_MASK (1 << 0) 49 + #define ZX_I2S_TIMING_LOOP (1 << 1) 50 + #define ZX_I2S_TIMING_NOR (0 << 1) 51 + #define ZX_I2S_TIMING_LOOP_MASK (1 << 1) 52 + #define ZX_I2S_TIMING_PTNR (1 << 2) 53 + #define ZX_I2S_TIMING_NTPR (0 << 2) 54 + #define ZX_I2S_TIMING_PHASE_MASK (1 << 2) 55 + #define ZX_I2S_TIMING_TDM (1 << 3) 56 + #define ZX_I2S_TIMING_I2S (0 << 3) 57 + #define ZX_I2S_TIMING_TIMING_MASK (1 << 3) 58 + #define ZX_I2S_TIMING_LONG_SYNC (1 << 4) 59 + #define ZX_I2S_TIMING_SHORT_SYNC (0 << 4) 60 + #define ZX_I2S_TIMING_SYNC_MASK (1 << 4) 61 + #define ZX_I2S_TIMING_TEAK_EN (1 << 5) 62 + #define ZX_I2S_TIMING_TEAK_DIS (0 << 5) 63 + #define ZX_I2S_TIMING_TEAK_MASK (1 << 5) 64 + #define ZX_I2S_TIMING_STD_I2S (0 << 6) 65 + #define ZX_I2S_TIMING_MSB_JUSTIF (1 << 6) 66 + #define ZX_I2S_TIMING_LSB_JUSTIF (2 << 6) 67 + #define ZX_I2S_TIMING_ALIGN_MASK (3 << 6) 68 + #define ZX_I2S_TIMING_CHN_MASK (7 << 8) 69 + #define ZX_I2S_TIMING_CHN(x) ((x - 1) << 8) 70 + #define ZX_I2S_TIMING_LANE_MASK (3 << 11) 71 + #define ZX_I2S_TIMING_LANE(x) ((x - 1) << 11) 72 + #define ZX_I2S_TIMING_TSCFG_MASK (7 << 13) 73 + #define ZX_I2S_TIMING_TSCFG(x) (x << 13) 74 + #define ZX_I2S_TIMING_TS_WIDTH_MASK (0x1f << 16) 75 + #define ZX_I2S_TIMING_TS_WIDTH(x) ((x - 1) << 16) 76 + #define ZX_I2S_TIMING_DATA_SIZE_MASK (0x1f << 21) 77 + #define ZX_I2S_TIMING_DATA_SIZE(x) ((x - 1) << 21) 78 + #define ZX_I2S_TIMING_CFG_ERR_MASK (1 << 31) 79 + 80 + #define ZX_I2S_FIFO_CTRL_TX_RST (1 << 0) 81 + #define ZX_I2S_FIFO_CTRL_TX_RST_MASK (1 << 0) 82 + #define ZX_I2S_FIFO_CTRL_RX_RST (1 << 1) 83 + #define ZX_I2S_FIFO_CTRL_RX_RST_MASK (1 << 1) 84 + #define ZX_I2S_FIFO_CTRL_TX_DMA_EN (1 << 4) 85 + #define ZX_I2S_FIFO_CTRL_TX_DMA_DIS (0 << 4) 86 + #define ZX_I2S_FIFO_CTRL_TX_DMA_MASK (1 << 4) 87 + #define ZX_I2S_FIFO_CTRL_RX_DMA_EN (1 << 5) 88 + #define ZX_I2S_FIFO_CTRL_RX_DMA_DIS (0 << 5) 89 + #define ZX_I2S_FIFO_CTRL_RX_DMA_MASK (1 << 5) 90 + #define ZX_I2S_FIFO_CTRL_TX_THRES_MASK (0x1F << 8) 91 + #define ZX_I2S_FIFO_CTRL_RX_THRES_MASK (0x1F << 16) 92 + 93 + #define CLK_RAT (32 * 4) 94 + 95 + struct zx_i2s_info { 96 + struct snd_dmaengine_dai_dma_data dma_playback; 97 + struct snd_dmaengine_dai_dma_data dma_capture; 98 + struct clk *dai_clk; 99 + void __iomem *reg_base; 100 + int master; 101 + resource_size_t mapbase; 102 + }; 103 + 104 + static void zx_i2s_tx_en(void __iomem *base, bool on) 105 + { 106 + unsigned long val; 107 + 108 + val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); 109 + if (on) 110 + val |= ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN; 111 + else 112 + val &= ~(ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN); 113 + writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); 114 + } 115 + 116 + static void zx_i2s_rx_en(void __iomem *base, bool on) 117 + { 118 + unsigned long val; 119 + 120 + val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); 121 + if (on) 122 + val |= ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN; 123 + else 124 + val &= ~(ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN); 125 + writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); 126 + } 127 + 128 + static void zx_i2s_tx_dma_en(void __iomem *base, bool on) 129 + { 130 + unsigned long val; 131 + 132 + val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); 133 + val |= ZX_I2S_FIFO_CTRL_TX_RST | (I2S_DEAGULT_FIFO_THRES << 8); 134 + if (on) 135 + val |= ZX_I2S_FIFO_CTRL_TX_DMA_EN; 136 + else 137 + val &= ~ZX_I2S_FIFO_CTRL_TX_DMA_EN; 138 + writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); 139 + } 140 + 141 + static void zx_i2s_rx_dma_en(void __iomem *base, bool on) 142 + { 143 + unsigned long val; 144 + 145 + val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); 146 + val |= ZX_I2S_FIFO_CTRL_RX_RST | (I2S_DEAGULT_FIFO_THRES << 16); 147 + if (on) 148 + val |= ZX_I2S_FIFO_CTRL_RX_DMA_EN; 149 + else 150 + val &= ~ZX_I2S_FIFO_CTRL_RX_DMA_EN; 151 + writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); 152 + } 153 + 154 + #define ZX_I2S_RATES \ 155 + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ 156 + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 157 + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000| \ 158 + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) 159 + 160 + #define ZX_I2S_FMTBIT \ 161 + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ 162 + SNDRV_PCM_FMTBIT_S32_LE) 163 + 164 + static int zx_i2s_dai_probe(struct snd_soc_dai *dai) 165 + { 166 + struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); 167 + 168 + snd_soc_dai_set_drvdata(dai, zx_i2s); 169 + zx_i2s->dma_playback.addr = zx_i2s->mapbase + ZX_I2S_DATA; 170 + zx_i2s->dma_playback.maxburst = 16; 171 + zx_i2s->dma_capture.addr = zx_i2s->mapbase + ZX_I2S_DATA; 172 + zx_i2s->dma_capture.maxburst = 16; 173 + snd_soc_dai_init_dma_data(dai, &zx_i2s->dma_playback, 174 + &zx_i2s->dma_capture); 175 + return 0; 176 + } 177 + 178 + static int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) 179 + { 180 + struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(cpu_dai); 181 + unsigned long val; 182 + 183 + val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); 184 + val &= ~(ZX_I2S_TIMING_TIMING_MASK | ZX_I2S_TIMING_ALIGN_MASK | 185 + ZX_I2S_TIMING_TEAK_MASK | ZX_I2S_TIMING_SYNC_MASK | 186 + ZX_I2S_TIMING_MS_MASK); 187 + 188 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 189 + case SND_SOC_DAIFMT_I2S: 190 + val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_STD_I2S); 191 + break; 192 + case SND_SOC_DAIFMT_LEFT_J: 193 + val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_MSB_JUSTIF); 194 + break; 195 + case SND_SOC_DAIFMT_RIGHT_J: 196 + val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_LSB_JUSTIF); 197 + break; 198 + default: 199 + dev_err(cpu_dai->dev, "Unknown i2s timeing\n"); 200 + return -EINVAL; 201 + } 202 + 203 + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 204 + case SND_SOC_DAIFMT_CBM_CFM: 205 + i2s->master = 1; 206 + val |= ZX_I2S_TIMING_MAST; 207 + break; 208 + case SND_SOC_DAIFMT_CBS_CFS: 209 + i2s->master = 0; 210 + val |= ZX_I2S_TIMING_SLAVE; 211 + break; 212 + default: 213 + dev_err(cpu_dai->dev, "Unknown master/slave format\n"); 214 + return -EINVAL; 215 + } 216 + 217 + writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); 218 + return 0; 219 + } 220 + 221 + static int zx_i2s_hw_params(struct snd_pcm_substream *substream, 222 + struct snd_pcm_hw_params *params, 223 + struct snd_soc_dai *socdai) 224 + { 225 + struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(socdai); 226 + struct snd_dmaengine_dai_dma_data *dma_data; 227 + unsigned int lane, ch_num, len, ret = 0; 228 + unsigned long val, format; 229 + unsigned long chn_cfg; 230 + 231 + dma_data = snd_soc_dai_get_dma_data(socdai, substream); 232 + dma_data->addr_width = params_width(params) >> 3; 233 + 234 + val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); 235 + val &= ~(ZX_I2S_TIMING_TS_WIDTH_MASK | ZX_I2S_TIMING_DATA_SIZE_MASK | 236 + ZX_I2S_TIMING_LANE_MASK | ZX_I2S_TIMING_CHN_MASK | 237 + ZX_I2S_TIMING_TSCFG_MASK); 238 + 239 + switch (params_format(params)) { 240 + case SNDRV_PCM_FORMAT_S16_LE: 241 + format = 0; 242 + len = 16; 243 + break; 244 + case SNDRV_PCM_FORMAT_S24_LE: 245 + format = 1; 246 + len = 24; 247 + break; 248 + case SNDRV_PCM_FORMAT_S32_LE: 249 + format = 2; 250 + len = 32; 251 + break; 252 + default: 253 + dev_err(socdai->dev, "Unknown data format\n"); 254 + return -EINVAL; 255 + } 256 + val |= ZX_I2S_TIMING_TS_WIDTH(len) | ZX_I2S_TIMING_DATA_SIZE(len); 257 + 258 + ch_num = params_channels(params); 259 + switch (ch_num) { 260 + case 1: 261 + lane = 1; 262 + chn_cfg = 2; 263 + break; 264 + case 2: 265 + case 4: 266 + case 6: 267 + case 8: 268 + lane = ch_num / 2; 269 + chn_cfg = 3; 270 + break; 271 + default: 272 + dev_err(socdai->dev, "Not support channel num %d\n", ch_num); 273 + return -EINVAL; 274 + } 275 + val |= ZX_I2S_TIMING_LANE(lane); 276 + val |= ZX_I2S_TIMING_TSCFG(chn_cfg); 277 + val |= ZX_I2S_TIMING_CHN(ch_num); 278 + writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); 279 + 280 + if (i2s->master) 281 + ret = clk_set_rate(i2s->dai_clk, 282 + params_rate(params) * ch_num * CLK_RAT); 283 + return ret; 284 + } 285 + 286 + static int zx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 287 + struct snd_soc_dai *dai) 288 + { 289 + struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); 290 + int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 291 + int ret = 0; 292 + 293 + switch (cmd) { 294 + case SNDRV_PCM_TRIGGER_START: 295 + if (capture) 296 + zx_i2s_rx_dma_en(zx_i2s->reg_base, true); 297 + else 298 + zx_i2s_tx_dma_en(zx_i2s->reg_base, true); 299 + /* fall thru */ 300 + case SNDRV_PCM_TRIGGER_RESUME: 301 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 302 + if (capture) 303 + zx_i2s_rx_en(zx_i2s->reg_base, true); 304 + else 305 + zx_i2s_tx_en(zx_i2s->reg_base, true); 306 + break; 307 + 308 + case SNDRV_PCM_TRIGGER_STOP: 309 + if (capture) 310 + zx_i2s_rx_dma_en(zx_i2s->reg_base, false); 311 + else 312 + zx_i2s_tx_dma_en(zx_i2s->reg_base, false); 313 + /* fall thru */ 314 + case SNDRV_PCM_TRIGGER_SUSPEND: 315 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 316 + if (capture) 317 + zx_i2s_rx_en(zx_i2s->reg_base, false); 318 + else 319 + zx_i2s_tx_en(zx_i2s->reg_base, false); 320 + break; 321 + 322 + default: 323 + ret = -EINVAL; 324 + break; 325 + } 326 + 327 + return ret; 328 + } 329 + 330 + static int zx_i2s_startup(struct snd_pcm_substream *substream, 331 + struct snd_soc_dai *dai) 332 + { 333 + struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); 334 + 335 + return clk_prepare_enable(zx_i2s->dai_clk); 336 + } 337 + 338 + static void zx_i2s_shutdown(struct snd_pcm_substream *substream, 339 + struct snd_soc_dai *dai) 340 + { 341 + struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); 342 + 343 + clk_disable_unprepare(zx_i2s->dai_clk); 344 + } 345 + 346 + static struct snd_soc_dai_ops zx_i2s_dai_ops = { 347 + .trigger = zx_i2s_trigger, 348 + .hw_params = zx_i2s_hw_params, 349 + .set_fmt = zx_i2s_set_fmt, 350 + .startup = zx_i2s_startup, 351 + .shutdown = zx_i2s_shutdown, 352 + }; 353 + 354 + static const struct snd_soc_component_driver zx_i2s_component = { 355 + .name = "zx-i2s", 356 + }; 357 + 358 + struct snd_soc_dai_driver zx_i2s_dai = { 359 + .name = "zx-i2s-dai", 360 + .id = 0, 361 + .probe = zx_i2s_dai_probe, 362 + .playback = { 363 + .channels_min = 1, 364 + .channels_max = 8, 365 + .rates = ZX_I2S_RATES, 366 + .formats = ZX_I2S_FMTBIT, 367 + }, 368 + .capture = { 369 + .channels_min = 1, 370 + .channels_max = 2, 371 + .rates = ZX_I2S_RATES, 372 + .formats = ZX_I2S_FMTBIT, 373 + }, 374 + .ops = &zx_i2s_dai_ops, 375 + }; 376 + 377 + static int zx_i2s_probe(struct platform_device *pdev) 378 + { 379 + struct resource *res; 380 + struct zx_i2s_info *zx_i2s; 381 + int ret; 382 + 383 + zx_i2s = kzalloc(sizeof(*zx_i2s), GFP_KERNEL); 384 + if (!zx_i2s) 385 + return -ENOMEM; 386 + 387 + zx_i2s->dai_clk = devm_clk_get(&pdev->dev, "tx"); 388 + if (IS_ERR(zx_i2s->dai_clk)) { 389 + dev_err(&pdev->dev, "Fail to get clk\n"); 390 + return PTR_ERR(zx_i2s->dai_clk); 391 + } 392 + 393 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 394 + zx_i2s->mapbase = res->start; 395 + zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res); 396 + if (!zx_i2s->reg_base) { 397 + dev_err(&pdev->dev, "ioremap failed!\n"); 398 + return -EIO; 399 + } 400 + 401 + writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL); 402 + platform_set_drvdata(pdev, zx_i2s); 403 + 404 + ret = snd_soc_register_component(&pdev->dev, &zx_i2s_component, 405 + &zx_i2s_dai, 1); 406 + if (ret) { 407 + dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); 408 + return ret; 409 + } 410 + 411 + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 412 + if (ret) 413 + dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); 414 + 415 + return ret; 416 + } 417 + 418 + static const struct of_device_id zx_i2s_dt_ids[] = { 419 + { .compatible = "zte,zx296702-i2s", }, 420 + {} 421 + }; 422 + MODULE_DEVICE_TABLE(of, zx_i2s_dt_ids); 423 + 424 + static struct platform_driver i2s_driver = { 425 + .probe = zx_i2s_probe, 426 + .driver = { 427 + .name = "zx-i2s", 428 + .owner = THIS_MODULE, 429 + .of_match_table = zx_i2s_dt_ids, 430 + }, 431 + }; 432 + 433 + module_platform_driver(i2s_driver); 434 + 435 + MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>"); 436 + MODULE_DESCRIPTION("ZTE I2S SoC DAI"); 437 + MODULE_LICENSE("GPL");