2 * Copyright (C) 2015 Linaro
4 * Author: Jun Nie <jun.nie@linaro.org>
6 * License terms: GNU General Public License (GPL) version 2
10 #include <linux/device.h>
11 #include <linux/dmaengine.h>
12 #include <linux/init.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>
27 #define ZX_FIFOCTRL 0x08
28 #define ZX_INT_STATUS 0x10
29 #define ZX_INT_MASK 0x14
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
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)
45 #define ZX_CTRL_ENB BIT(4)
46 #define ZX_CTRL_DNB (0 << 4)
47 #define ZX_CTRL_ENB_MASK BIT(4)
49 #define ZX_CTRL_TX_OPEN BIT(0)
50 #define ZX_CTRL_TX_CLOSE (0 << 0)
51 #define ZX_CTRL_TX_MASK BIT(0)
53 #define ZX_CTRL_OPEN (ZX_CTRL_TX_OPEN | ZX_CTRL_ENB)
54 #define ZX_CTRL_CLOSE (ZX_CTRL_TX_CLOSE | ZX_CTRL_DNB)
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)
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)
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)
74 #define ZX_SPDIF_CLK_RAT (2 * 32)
76 struct zx_spdif_info
{
77 struct snd_dmaengine_dai_dma_data dma_data
;
79 void __iomem
*reg_base
;
80 resource_size_t mapbase
;
83 static int zx_spdif_dai_probe(struct snd_soc_dai
*dai
)
85 struct zx_spdif_info
*zx_spdif
= dev_get_drvdata(dai
->dev
);
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
);
94 static int zx_spdif_chanstats(void __iomem
*base
, unsigned int rate
)
100 cstas1
= IEC958_AES3_CON_FS_22050
;
103 cstas1
= IEC958_AES3_CON_FS_24000
;
106 cstas1
= IEC958_AES3_CON_FS_32000
;
109 cstas1
= IEC958_AES3_CON_FS_44100
;
112 cstas1
= IEC958_AES3_CON_FS_48000
;
115 cstas1
= IEC958_AES3_CON_FS_88200
;
118 cstas1
= IEC958_AES3_CON_FS_96000
;
121 cstas1
= IEC958_AES3_CON_FS_176400
;
124 cstas1
= IEC958_AES3_CON_FS_192000
;
129 cstas1
= cstas1
<< 24;
130 cstas1
|= IEC958_AES0_CON_NOT_COPYRIGHT
;
132 writel_relaxed(cstas1
, base
+ ZX_CH_STA_1
);
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
)
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
;
146 dma_data
= snd_soc_dai_get_dma_data(socdai
, substream
);
147 dma_data
->addr_width
= params_width(params
) >> 3;
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
;
156 case SNDRV_PCM_FORMAT_S18_3LE
:
157 val
|= ZX_CTRL_MODA_18
;
160 case SNDRV_PCM_FORMAT_S20_3LE
:
161 val
|= ZX_CTRL_MODA_20
;
164 case SNDRV_PCM_FORMAT_S24_LE
:
165 val
|= ZX_CTRL_MODA_24
;
168 dev_err(socdai
->dev
, "Format not support!\n");
172 ch_num
= params_channels(params
);
174 val
|= ZX_CTRL_DOUBLE_TRACK
;
176 val
|= ZX_CTRL_LEFT_TRACK
;
177 writel_relaxed(val
, zx_spdif
->reg_base
+ ZX_CTRL
);
179 val
= readl_relaxed(zx_spdif
->reg_base
+ ZX_VALID_BIT
);
180 val
&= ~ZX_VALID_TRACK_MASK
;
182 val
|= ZX_VALID_DOUBLE_TRACK
;
184 val
|= ZX_VALID_RIGHT_TRACK
;
185 writel_relaxed(val
, zx_spdif
->reg_base
+ ZX_VALID_BIT
);
187 rate
= params_rate(params
);
188 ret
= zx_spdif_chanstats(zx_spdif
->reg_base
, rate
);
191 return clk_set_rate(spdif
->dai_clk
, rate
* ch_num
* ZX_SPDIF_CLK_RAT
);
194 static void zx_spdif_cfg_tx(void __iomem
*base
, int on
)
198 val
= readl_relaxed(base
+ ZX_CTRL
);
199 val
&= ~(ZX_CTRL_ENB_MASK
| ZX_CTRL_TX_MASK
);
200 val
|= on
? ZX_CTRL_OPEN
: ZX_CTRL_CLOSE
;
201 writel_relaxed(val
, base
+ ZX_CTRL
);
203 val
= readl_relaxed(base
+ ZX_FIFOCTRL
);
204 val
&= ~ZX_FIFOCTRL_TX_DMA_EN_MASK
;
206 val
|= ZX_FIFOCTRL_TX_DMA_EN
;
207 writel_relaxed(val
, base
+ ZX_FIFOCTRL
);
210 static int zx_spdif_trigger(struct snd_pcm_substream
*substream
, int cmd
,
211 struct snd_soc_dai
*dai
)
214 struct zx_spdif_info
*zx_spdif
= dev_get_drvdata(dai
->dev
);
218 case SNDRV_PCM_TRIGGER_START
:
219 val
= readl_relaxed(zx_spdif
->reg_base
+ ZX_FIFOCTRL
);
220 val
|= ZX_FIFOCTRL_TX_FIFO_RST
;
221 writel_relaxed(val
, zx_spdif
->reg_base
+ ZX_FIFOCTRL
);
223 case SNDRV_PCM_TRIGGER_RESUME
:
224 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
225 zx_spdif_cfg_tx(zx_spdif
->reg_base
, true);
228 case SNDRV_PCM_TRIGGER_STOP
:
229 case SNDRV_PCM_TRIGGER_SUSPEND
:
230 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
231 zx_spdif_cfg_tx(zx_spdif
->reg_base
, false);
242 static int zx_spdif_startup(struct snd_pcm_substream
*substream
,
243 struct snd_soc_dai
*dai
)
245 struct zx_spdif_info
*zx_spdif
= dev_get_drvdata(dai
->dev
);
247 return clk_prepare_enable(zx_spdif
->dai_clk
);
250 static void zx_spdif_shutdown(struct snd_pcm_substream
*substream
,
251 struct snd_soc_dai
*dai
)
253 struct zx_spdif_info
*zx_spdif
= dev_get_drvdata(dai
->dev
);
255 clk_disable_unprepare(zx_spdif
->dai_clk
);
259 (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
260 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\
261 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
264 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE \
265 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
267 static const struct snd_soc_dai_ops zx_spdif_dai_ops
= {
268 .trigger
= zx_spdif_trigger
,
269 .startup
= zx_spdif_startup
,
270 .shutdown
= zx_spdif_shutdown
,
271 .hw_params
= zx_spdif_hw_params
,
274 static struct snd_soc_dai_driver zx_spdif_dai
= {
277 .probe
= zx_spdif_dai_probe
,
282 .formats
= ZX_FORMAT
,
284 .ops
= &zx_spdif_dai_ops
,
287 static const struct snd_soc_component_driver zx_spdif_component
= {
291 static void zx_spdif_dev_init(void __iomem
*base
)
295 writel_relaxed(0, base
+ ZX_CTRL
);
296 writel_relaxed(0, base
+ ZX_INT_MASK
);
297 writel_relaxed(0xf, base
+ ZX_INT_STATUS
);
298 writel_relaxed(0x1, base
+ ZX_FIFOCTRL
);
300 val
= readl_relaxed(base
+ ZX_FIFOCTRL
);
301 val
&= ~(ZX_FIFOCTRL_TXTH_MASK
| ZX_FIFOCTRL_TX_FIFO_RST_MASK
);
302 val
|= ZX_FIFOCTRL_TXTH(8);
303 writel_relaxed(val
, base
+ ZX_FIFOCTRL
);
306 static int zx_spdif_probe(struct platform_device
*pdev
)
308 struct resource
*res
;
309 struct zx_spdif_info
*zx_spdif
;
312 zx_spdif
= devm_kzalloc(&pdev
->dev
, sizeof(*zx_spdif
), GFP_KERNEL
);
316 zx_spdif
->dai_clk
= devm_clk_get(&pdev
->dev
, "tx");
317 if (IS_ERR(zx_spdif
->dai_clk
)) {
318 dev_err(&pdev
->dev
, "Fail to get clk\n");
319 return PTR_ERR(zx_spdif
->dai_clk
);
322 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
323 zx_spdif
->mapbase
= res
->start
;
324 zx_spdif
->reg_base
= devm_ioremap_resource(&pdev
->dev
, res
);
325 if (IS_ERR(zx_spdif
->reg_base
)) {
326 dev_err(&pdev
->dev
, "ioremap failed!\n");
327 return PTR_ERR(zx_spdif
->reg_base
);
330 zx_spdif_dev_init(zx_spdif
->reg_base
);
331 platform_set_drvdata(pdev
, zx_spdif
);
333 ret
= devm_snd_soc_register_component(&pdev
->dev
, &zx_spdif_component
,
336 dev_err(&pdev
->dev
, "Register DAI failed: %d\n", ret
);
340 ret
= devm_snd_dmaengine_pcm_register(&pdev
->dev
, NULL
, 0);
342 dev_err(&pdev
->dev
, "Register platform PCM failed: %d\n", ret
);
347 static const struct of_device_id zx_spdif_dt_ids
[] = {
348 { .compatible
= "zte,zx296702-spdif", },
351 MODULE_DEVICE_TABLE(of
, zx_spdif_dt_ids
);
353 static struct platform_driver spdif_driver
= {
354 .probe
= zx_spdif_probe
,
357 .of_match_table
= zx_spdif_dt_ids
,
361 module_platform_driver(spdif_driver
);
363 MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
364 MODULE_DESCRIPTION("ZTE SPDIF SoC DAI");
365 MODULE_LICENSE("GPL");