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

ASoC: zx: Add zx296702 SPDIF support

Add driver for zx296702 SPDIF controller

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
6fc3d24d b787f68c

+381
+1
sound/soc/Kconfig
··· 57 57 source "sound/soc/txx9/Kconfig" 58 58 source "sound/soc/ux500/Kconfig" 59 59 source "sound/soc/xtensa/Kconfig" 60 + source "sound/soc/zte/Kconfig" 60 61 61 62 # Supported codecs 62 63 source "sound/soc/codecs/Kconfig"
+1
sound/soc/Makefile
··· 38 38 obj-$(CONFIG_SND_SOC) += txx9/ 39 39 obj-$(CONFIG_SND_SOC) += ux500/ 40 40 obj-$(CONFIG_SND_SOC) += xtensa/ 41 + obj-$(CONFIG_SND_SOC) += zte/
+8
sound/soc/zte/Kconfig
··· 1 + config ZX296702_SPDIF 2 + tristate "ZX296702 spdif" 3 + depends on SOC_ZX296702 || COMPILE_TEST 4 + depends on COMMON_CLK 5 + select SND_SOC_GENERIC_DMAENGINE_PCM 6 + help 7 + Say Y or M if you want to add support for codecs attached to the 8 + zx296702 spdif interface
+1
sound/soc/zte/Makefile
··· 1 + obj-$(CONFIG_ZX296702_SPDIF) += zx296702-spdif.o
+370
sound/soc/zte/zx296702-spdif.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/dmaengine.h> 12 + #include <linux/init.h> 13 + #include <linux/io.h> 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/of_address.h> 17 + #include <sound/asoundef.h> 18 + #include <sound/core.h> 19 + #include <sound/dmaengine_pcm.h> 20 + #include <sound/initval.h> 21 + #include <sound/pcm.h> 22 + #include <sound/pcm_params.h> 23 + #include <sound/soc.h> 24 + #include <sound/soc-dai.h> 25 + 26 + #define ZX_CTRL 0x04 27 + #define ZX_FIFOCTRL 0x08 28 + #define ZX_INT_STATUS 0x10 29 + #define ZX_INT_MASK 0x14 30 + #define ZX_DATA 0x18 31 + #define ZX_VALID_BIT 0x1c 32 + #define ZX_CH_STA_1 0x20 33 + #define ZX_CH_STA_2 0x24 34 + #define ZX_CH_STA_3 0x28 35 + #define ZX_CH_STA_4 0x2c 36 + #define ZX_CH_STA_5 0x30 37 + #define ZX_CH_STA_6 0x34 38 + 39 + #define ZX_CTRL_MODA_16 (0 << 6) 40 + #define ZX_CTRL_MODA_18 BIT(6) 41 + #define ZX_CTRL_MODA_20 (2 << 6) 42 + #define ZX_CTRL_MODA_24 (3 << 6) 43 + #define ZX_CTRL_MODA_MASK (3 << 6) 44 + 45 + #define ZX_CTRL_ENB BIT(4) 46 + #define ZX_CTRL_DNB (0 << 4) 47 + #define ZX_CTRL_ENB_MASK BIT(4) 48 + 49 + #define ZX_CTRL_TX_OPEN BIT(0) 50 + #define ZX_CTRL_TX_CLOSE (0 << 0) 51 + #define ZX_CTRL_TX_MASK BIT(0) 52 + 53 + #define ZX_CTRL_OPEN (ZX_CTRL_TX_OPEN | ZX_CTRL_ENB) 54 + #define ZX_CTRL_CLOSE (ZX_CTRL_TX_CLOSE | ZX_CTRL_DNB) 55 + 56 + #define ZX_CTRL_DOUBLE_TRACK (0 << 8) 57 + #define ZX_CTRL_LEFT_TRACK BIT(8) 58 + #define ZX_CTRL_RIGHT_TRACK (2 << 8) 59 + #define ZX_CTRL_TRACK_MASK (3 << 8) 60 + 61 + #define ZX_FIFOCTRL_TXTH_MASK (0x1f << 8) 62 + #define ZX_FIFOCTRL_TXTH(x) (x << 8) 63 + #define ZX_FIFOCTRL_TX_DMA_EN BIT(2) 64 + #define ZX_FIFOCTRL_TX_DMA_DIS (0 << 2) 65 + #define ZX_FIFOCTRL_TX_DMA_EN_MASK BIT(2) 66 + #define ZX_FIFOCTRL_TX_FIFO_RST BIT(0) 67 + #define ZX_FIFOCTRL_TX_FIFO_RST_MASK BIT(0) 68 + 69 + #define ZX_VALID_DOUBLE_TRACK (0 << 0) 70 + #define ZX_VALID_LEFT_TRACK BIT(1) 71 + #define ZX_VALID_RIGHT_TRACK (2 << 0) 72 + #define ZX_VALID_TRACK_MASK (3 << 0) 73 + 74 + #define ZX_SPDIF_CLK_RAT (4 * 32) 75 + 76 + struct zx_spdif_info { 77 + struct snd_dmaengine_dai_dma_data dma_data; 78 + struct clk *dai_clk; 79 + void __iomem *reg_base; 80 + resource_size_t mapbase; 81 + }; 82 + 83 + static int zx_spdif_dai_probe(struct snd_soc_dai *dai) 84 + { 85 + struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); 86 + 87 + snd_soc_dai_set_drvdata(dai, zx_spdif); 88 + zx_spdif->dma_data.addr = zx_spdif->mapbase + ZX_DATA; 89 + zx_spdif->dma_data.maxburst = 8; 90 + snd_soc_dai_init_dma_data(dai, &zx_spdif->dma_data, NULL); 91 + return 0; 92 + } 93 + 94 + static int zx_spdif_chanstats(void __iomem *base, unsigned int rate) 95 + { 96 + u32 cstas1; 97 + 98 + switch (rate) { 99 + case 22050: 100 + cstas1 = IEC958_AES3_CON_FS_22050; 101 + break; 102 + case 24000: 103 + cstas1 = IEC958_AES3_CON_FS_24000; 104 + break; 105 + case 32000: 106 + cstas1 = IEC958_AES3_CON_FS_32000; 107 + break; 108 + case 44100: 109 + cstas1 = IEC958_AES3_CON_FS_44100; 110 + break; 111 + case 48000: 112 + cstas1 = IEC958_AES3_CON_FS_48000; 113 + break; 114 + case 88200: 115 + cstas1 = IEC958_AES3_CON_FS_88200; 116 + break; 117 + case 96000: 118 + cstas1 = IEC958_AES3_CON_FS_96000; 119 + break; 120 + case 176400: 121 + cstas1 = IEC958_AES3_CON_FS_176400; 122 + break; 123 + case 192000: 124 + cstas1 = IEC958_AES3_CON_FS_192000; 125 + break; 126 + default: 127 + return -EINVAL; 128 + } 129 + cstas1 = cstas1 << 24; 130 + cstas1 |= IEC958_AES0_CON_NOT_COPYRIGHT; 131 + 132 + writel_relaxed(cstas1, base + ZX_CH_STA_1); 133 + return 0; 134 + } 135 + 136 + static int zx_spdif_hw_params(struct snd_pcm_substream *substream, 137 + struct snd_pcm_hw_params *params, 138 + struct snd_soc_dai *socdai) 139 + { 140 + struct zx_spdif_info *zx_spdif = dev_get_drvdata(socdai->dev); 141 + struct zx_spdif_info *spdif = snd_soc_dai_get_drvdata(socdai); 142 + struct snd_dmaengine_dai_dma_data *dma_data = &zx_spdif->dma_data; 143 + u32 val, ch_num, rate; 144 + int ret; 145 + 146 + dma_data = snd_soc_dai_get_dma_data(socdai, substream); 147 + dma_data->addr_width = params_width(params) >> 3; 148 + 149 + val = readl_relaxed(zx_spdif->reg_base + ZX_CTRL); 150 + val &= ~ZX_CTRL_MODA_MASK; 151 + switch (params_format(params)) { 152 + case SNDRV_PCM_FORMAT_S16_LE: 153 + val |= ZX_CTRL_MODA_16; 154 + break; 155 + 156 + case SNDRV_PCM_FORMAT_S18_3LE: 157 + val |= ZX_CTRL_MODA_18; 158 + break; 159 + 160 + case SNDRV_PCM_FORMAT_S20_3LE: 161 + val |= ZX_CTRL_MODA_20; 162 + break; 163 + 164 + case SNDRV_PCM_FORMAT_S24_LE: 165 + val |= ZX_CTRL_MODA_24; 166 + break; 167 + default: 168 + dev_err(socdai->dev, "Format not support!\n"); 169 + return -EINVAL; 170 + } 171 + 172 + ch_num = params_channels(params); 173 + if (ch_num == 2) 174 + val |= ZX_CTRL_DOUBLE_TRACK; 175 + else 176 + val |= ZX_CTRL_LEFT_TRACK; 177 + writel_relaxed(val, zx_spdif->reg_base + ZX_CTRL); 178 + 179 + val = readl_relaxed(zx_spdif->reg_base + ZX_VALID_BIT); 180 + val &= ~ZX_VALID_TRACK_MASK; 181 + if (ch_num == 2) 182 + val |= ZX_VALID_DOUBLE_TRACK; 183 + else 184 + val |= ZX_VALID_RIGHT_TRACK; 185 + writel_relaxed(val, zx_spdif->reg_base + ZX_VALID_BIT); 186 + 187 + rate = params_rate(params); 188 + ret = zx_spdif_chanstats(zx_spdif->reg_base, rate); 189 + if (ret) 190 + return ret; 191 + ret = clk_set_rate(spdif->dai_clk, rate * ch_num * ZX_SPDIF_CLK_RAT); 192 + if (ret) 193 + return ret; 194 + 195 + return 0; 196 + } 197 + 198 + static void zx_spdif_cfg_tx(void __iomem *base, int on) 199 + { 200 + u32 val; 201 + 202 + val = readl_relaxed(base + ZX_CTRL); 203 + val &= ~(ZX_CTRL_ENB_MASK | ZX_CTRL_TX_MASK); 204 + val |= on ? ZX_CTRL_OPEN : ZX_CTRL_CLOSE; 205 + writel_relaxed(val, base + ZX_CTRL); 206 + 207 + val = readl_relaxed(base + ZX_FIFOCTRL); 208 + val &= ~ZX_FIFOCTRL_TX_DMA_EN_MASK; 209 + if (on) 210 + val |= ZX_FIFOCTRL_TX_DMA_EN; 211 + writel_relaxed(val, base + ZX_FIFOCTRL); 212 + } 213 + 214 + static int zx_spdif_trigger(struct snd_pcm_substream *substream, int cmd, 215 + struct snd_soc_dai *dai) 216 + { 217 + u32 val; 218 + struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); 219 + int ret = 0; 220 + 221 + switch (cmd) { 222 + case SNDRV_PCM_TRIGGER_START: 223 + val = readl_relaxed(zx_spdif->reg_base + ZX_FIFOCTRL); 224 + val |= ZX_FIFOCTRL_TX_FIFO_RST; 225 + writel_relaxed(val, zx_spdif->reg_base + ZX_FIFOCTRL); 226 + /* fall thru */ 227 + case SNDRV_PCM_TRIGGER_RESUME: 228 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 229 + zx_spdif_cfg_tx(zx_spdif->reg_base, true); 230 + break; 231 + 232 + case SNDRV_PCM_TRIGGER_STOP: 233 + case SNDRV_PCM_TRIGGER_SUSPEND: 234 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 235 + zx_spdif_cfg_tx(zx_spdif->reg_base, false); 236 + break; 237 + 238 + default: 239 + ret = -EINVAL; 240 + break; 241 + } 242 + 243 + return ret; 244 + } 245 + 246 + static int zx_spdif_startup(struct snd_pcm_substream *substream, 247 + struct snd_soc_dai *dai) 248 + { 249 + struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); 250 + 251 + return clk_prepare_enable(zx_spdif->dai_clk); 252 + } 253 + 254 + static void zx_spdif_shutdown(struct snd_pcm_substream *substream, 255 + struct snd_soc_dai *dai) 256 + { 257 + struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); 258 + 259 + clk_disable_unprepare(zx_spdif->dai_clk); 260 + } 261 + 262 + #define ZX_RATES \ 263 + (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 264 + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ 265 + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) 266 + 267 + #define ZX_FORMAT \ 268 + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE \ 269 + | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) 270 + 271 + static struct snd_soc_dai_ops zx_spdif_dai_ops = { 272 + .trigger = zx_spdif_trigger, 273 + .startup = zx_spdif_startup, 274 + .shutdown = zx_spdif_shutdown, 275 + .hw_params = zx_spdif_hw_params, 276 + }; 277 + 278 + static struct snd_soc_dai_driver zx_spdif_dai = { 279 + .name = "spdif", 280 + .id = 0, 281 + .probe = zx_spdif_dai_probe, 282 + .playback = { 283 + .channels_min = 1, 284 + .channels_max = 2, 285 + .rates = ZX_RATES, 286 + .formats = ZX_FORMAT, 287 + }, 288 + .ops = &zx_spdif_dai_ops, 289 + }; 290 + 291 + static const struct snd_soc_component_driver zx_spdif_component = { 292 + .name = "spdif", 293 + }; 294 + 295 + static void zx_spdif_dev_init(void __iomem *base) 296 + { 297 + u32 val; 298 + 299 + writel_relaxed(0, base + ZX_CTRL); 300 + writel_relaxed(0, base + ZX_INT_MASK); 301 + writel_relaxed(0xf, base + ZX_INT_STATUS); 302 + writel_relaxed(0x1, base + ZX_FIFOCTRL); 303 + 304 + val = readl_relaxed(base + ZX_FIFOCTRL); 305 + val &= ~(ZX_FIFOCTRL_TXTH_MASK | ZX_FIFOCTRL_TX_FIFO_RST_MASK); 306 + val |= ZX_FIFOCTRL_TXTH(8); 307 + writel_relaxed(val, base + ZX_FIFOCTRL); 308 + } 309 + 310 + static int zx_spdif_probe(struct platform_device *pdev) 311 + { 312 + struct resource *res; 313 + struct zx_spdif_info *zx_spdif; 314 + int ret; 315 + 316 + zx_spdif = devm_kzalloc(sizeof(*zx_spdif), GFP_KERNEL); 317 + if (!zx_spdif) 318 + return -ENOMEM; 319 + 320 + zx_spdif->dai_clk = devm_clk_get(&pdev->dev, "tx"); 321 + if (IS_ERR(zx_spdif->dai_clk)) { 322 + dev_err(&pdev->dev, "Fail to get clk\n"); 323 + return PTR_ERR(zx_spdif->dai_clk); 324 + } 325 + 326 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 327 + zx_spdif->mapbase = res->start; 328 + zx_spdif->reg_base = devm_ioremap_resource(&pdev->dev, res); 329 + if (!zx_spdif->reg_base) { 330 + dev_err(&pdev->dev, "ioremap failed!\n"); 331 + return -EIO; 332 + } 333 + 334 + zx_spdif_dev_init(zx_spdif->reg_base); 335 + platform_set_drvdata(pdev, zx_spdif); 336 + 337 + ret = devm_snd_soc_register_component(&pdev->dev, &zx_spdif_component, 338 + &zx_spdif_dai, 1); 339 + if (ret) { 340 + dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); 341 + return ret; 342 + } 343 + 344 + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 345 + if (ret) 346 + dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); 347 + 348 + return ret; 349 + } 350 + 351 + static const struct of_device_id zx_spdif_dt_ids[] = { 352 + { .compatible = "zte,zx296702-spdif", }, 353 + {} 354 + }; 355 + MODULE_DEVICE_TABLE(of, zx_spdif_dt_ids); 356 + 357 + static struct platform_driver spdif_driver = { 358 + .probe = zx_spdif_probe, 359 + .driver = { 360 + .name = "zx-spdif", 361 + .owner = THIS_MODULE, 362 + .of_match_table = zx_spdif_dt_ids, 363 + }, 364 + }; 365 + 366 + module_platform_driver(spdif_driver); 367 + 368 + MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>"); 369 + MODULE_DESCRIPTION("ZTE SPDIF SoC DAI"); 370 + MODULE_LICENSE("GPL");