1 // SPDX-License-Identifier: GPL-2.0
3 // ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
5 // Copyright (c) 2010 Samsung Electronics Co. Ltd
6 // http://www.samsung.com/
10 #include <linux/module.h>
12 #include <sound/soc.h>
13 #include <sound/pcm_params.h>
15 #include <linux/platform_data/asoc-s3c.h>
25 #define DATA_OUTBUF 0x10
30 #define CLKCTL_MASK 0x7
31 #define CLKCTL_MCLK_EXT (0x1 << 2)
32 #define CLKCTL_PWR_ON (0x1 << 0)
34 #define CON_MASK 0x3ffffff
35 #define CON_FIFO_TH_SHIFT 19
36 #define CON_FIFO_TH_MASK (0x7 << 19)
37 #define CON_USERDATA_23RDBIT (0x1 << 12)
39 #define CON_SW_RESET (0x1 << 5)
41 #define CON_MCLKDIV_MASK (0x3 << 3)
42 #define CON_MCLKDIV_256FS (0x0 << 3)
43 #define CON_MCLKDIV_384FS (0x1 << 3)
44 #define CON_MCLKDIV_512FS (0x2 << 3)
46 #define CON_PCM_MASK (0x3 << 1)
47 #define CON_PCM_16BIT (0x0 << 1)
48 #define CON_PCM_20BIT (0x1 << 1)
49 #define CON_PCM_24BIT (0x2 << 1)
51 #define CON_PCM_DATA (0x1 << 0)
53 #define CSTAS_MASK 0x3fffffff
54 #define CSTAS_SAMP_FREQ_MASK (0xF << 24)
55 #define CSTAS_SAMP_FREQ_44 (0x0 << 24)
56 #define CSTAS_SAMP_FREQ_48 (0x2 << 24)
57 #define CSTAS_SAMP_FREQ_32 (0x3 << 24)
58 #define CSTAS_SAMP_FREQ_96 (0xA << 24)
60 #define CSTAS_CATEGORY_MASK (0xFF << 8)
61 #define CSTAS_CATEGORY_CODE_CDP (0x01 << 8)
63 #define CSTAS_NO_COPYRIGHT (0x1 << 2)
66 * struct samsung_spdif_info - Samsung S/PDIF Controller information
67 * @lock: Spin lock for S/PDIF.
68 * @dev: The parent device passed to use from the probe.
69 * @regs: The pointer to the device register block.
70 * @clk_rate: Current clock rate for calcurate ratio.
71 * @pclk: The peri-clock pointer for spdif master operation.
72 * @sclk: The source clock pointer for making sync signals.
73 * @save_clkcon: Backup clkcon reg. in suspend.
74 * @save_con: Backup con reg. in suspend.
75 * @save_cstas: Backup cstas reg. in suspend.
76 * @dma_playback: DMA information for playback channel.
78 struct samsung_spdif_info
{
82 unsigned long clk_rate
;
88 struct snd_dmaengine_dai_dma_data
*dma_playback
;
91 static struct snd_dmaengine_dai_dma_data spdif_stereo_out
;
92 static struct samsung_spdif_info spdif_info
;
94 static inline struct samsung_spdif_info
95 *component_to_info(struct snd_soc_component
*component
)
97 return snd_soc_component_get_drvdata(component
);
100 static inline struct samsung_spdif_info
*to_info(struct snd_soc_dai
*cpu_dai
)
102 return snd_soc_dai_get_drvdata(cpu_dai
);
105 static void spdif_snd_txctrl(struct samsung_spdif_info
*spdif
, int on
)
107 void __iomem
*regs
= spdif
->regs
;
110 dev_dbg(spdif
->dev
, "Entered %s\n", __func__
);
112 clkcon
= readl(regs
+ CLKCON
) & CLKCTL_MASK
;
114 writel(clkcon
| CLKCTL_PWR_ON
, regs
+ CLKCON
);
116 writel(clkcon
& ~CLKCTL_PWR_ON
, regs
+ CLKCON
);
119 static int spdif_set_sysclk(struct snd_soc_dai
*cpu_dai
,
120 int clk_id
, unsigned int freq
, int dir
)
122 struct samsung_spdif_info
*spdif
= to_info(cpu_dai
);
125 dev_dbg(spdif
->dev
, "Entered %s\n", __func__
);
127 clkcon
= readl(spdif
->regs
+ CLKCON
);
129 if (clk_id
== SND_SOC_SPDIF_INT_MCLK
)
130 clkcon
&= ~CLKCTL_MCLK_EXT
;
132 clkcon
|= CLKCTL_MCLK_EXT
;
134 writel(clkcon
, spdif
->regs
+ CLKCON
);
136 spdif
->clk_rate
= freq
;
141 static int spdif_trigger(struct snd_pcm_substream
*substream
, int cmd
,
142 struct snd_soc_dai
*dai
)
144 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
145 struct samsung_spdif_info
*spdif
= to_info(rtd
->cpu_dai
);
148 dev_dbg(spdif
->dev
, "Entered %s\n", __func__
);
151 case SNDRV_PCM_TRIGGER_START
:
152 case SNDRV_PCM_TRIGGER_RESUME
:
153 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
154 spin_lock_irqsave(&spdif
->lock
, flags
);
155 spdif_snd_txctrl(spdif
, 1);
156 spin_unlock_irqrestore(&spdif
->lock
, flags
);
158 case SNDRV_PCM_TRIGGER_STOP
:
159 case SNDRV_PCM_TRIGGER_SUSPEND
:
160 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
161 spin_lock_irqsave(&spdif
->lock
, flags
);
162 spdif_snd_txctrl(spdif
, 0);
163 spin_unlock_irqrestore(&spdif
->lock
, flags
);
172 static int spdif_sysclk_ratios
[] = {
176 static int spdif_hw_params(struct snd_pcm_substream
*substream
,
177 struct snd_pcm_hw_params
*params
,
178 struct snd_soc_dai
*socdai
)
180 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
181 struct samsung_spdif_info
*spdif
= to_info(rtd
->cpu_dai
);
182 void __iomem
*regs
= spdif
->regs
;
183 struct snd_dmaengine_dai_dma_data
*dma_data
;
184 u32 con
, clkcon
, cstas
;
188 dev_dbg(spdif
->dev
, "Entered %s\n", __func__
);
190 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
191 dma_data
= spdif
->dma_playback
;
193 dev_err(spdif
->dev
, "Capture is not supported\n");
197 snd_soc_dai_set_dma_data(rtd
->cpu_dai
, substream
, dma_data
);
199 spin_lock_irqsave(&spdif
->lock
, flags
);
201 con
= readl(regs
+ CON
) & CON_MASK
;
202 cstas
= readl(regs
+ CSTAS
) & CSTAS_MASK
;
203 clkcon
= readl(regs
+ CLKCON
) & CLKCTL_MASK
;
205 con
&= ~CON_FIFO_TH_MASK
;
206 con
|= (0x7 << CON_FIFO_TH_SHIFT
);
207 con
|= CON_USERDATA_23RDBIT
;
210 con
&= ~CON_PCM_MASK
;
211 switch (params_width(params
)) {
213 con
|= CON_PCM_16BIT
;
216 dev_err(spdif
->dev
, "Unsupported data size.\n");
220 ratio
= spdif
->clk_rate
/ params_rate(params
);
221 for (i
= 0; i
< ARRAY_SIZE(spdif_sysclk_ratios
); i
++)
222 if (ratio
== spdif_sysclk_ratios
[i
])
224 if (i
== ARRAY_SIZE(spdif_sysclk_ratios
)) {
225 dev_err(spdif
->dev
, "Invalid clock ratio %ld/%d\n",
226 spdif
->clk_rate
, params_rate(params
));
230 con
&= ~CON_MCLKDIV_MASK
;
233 con
|= CON_MCLKDIV_256FS
;
236 con
|= CON_MCLKDIV_384FS
;
239 con
|= CON_MCLKDIV_512FS
;
243 cstas
&= ~CSTAS_SAMP_FREQ_MASK
;
244 switch (params_rate(params
)) {
246 cstas
|= CSTAS_SAMP_FREQ_44
;
249 cstas
|= CSTAS_SAMP_FREQ_48
;
252 cstas
|= CSTAS_SAMP_FREQ_32
;
255 cstas
|= CSTAS_SAMP_FREQ_96
;
258 dev_err(spdif
->dev
, "Invalid sampling rate %d\n",
259 params_rate(params
));
263 cstas
&= ~CSTAS_CATEGORY_MASK
;
264 cstas
|= CSTAS_CATEGORY_CODE_CDP
;
265 cstas
|= CSTAS_NO_COPYRIGHT
;
267 writel(con
, regs
+ CON
);
268 writel(cstas
, regs
+ CSTAS
);
269 writel(clkcon
, regs
+ CLKCON
);
271 spin_unlock_irqrestore(&spdif
->lock
, flags
);
275 spin_unlock_irqrestore(&spdif
->lock
, flags
);
279 static void spdif_shutdown(struct snd_pcm_substream
*substream
,
280 struct snd_soc_dai
*dai
)
282 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
283 struct samsung_spdif_info
*spdif
= to_info(rtd
->cpu_dai
);
284 void __iomem
*regs
= spdif
->regs
;
287 dev_dbg(spdif
->dev
, "Entered %s\n", __func__
);
289 con
= readl(regs
+ CON
) & CON_MASK
;
290 clkcon
= readl(regs
+ CLKCON
) & CLKCTL_MASK
;
292 writel(con
| CON_SW_RESET
, regs
+ CON
);
295 writel(clkcon
& ~CLKCTL_PWR_ON
, regs
+ CLKCON
);
299 static int spdif_suspend(struct snd_soc_component
*component
)
301 struct samsung_spdif_info
*spdif
= component_to_info(component
);
302 u32 con
= spdif
->saved_con
;
304 dev_dbg(spdif
->dev
, "Entered %s\n", __func__
);
306 spdif
->saved_clkcon
= readl(spdif
->regs
+ CLKCON
) & CLKCTL_MASK
;
307 spdif
->saved_con
= readl(spdif
->regs
+ CON
) & CON_MASK
;
308 spdif
->saved_cstas
= readl(spdif
->regs
+ CSTAS
) & CSTAS_MASK
;
310 writel(con
| CON_SW_RESET
, spdif
->regs
+ CON
);
316 static int spdif_resume(struct snd_soc_component
*component
)
318 struct samsung_spdif_info
*spdif
= component_to_info(component
);
320 dev_dbg(spdif
->dev
, "Entered %s\n", __func__
);
322 writel(spdif
->saved_clkcon
, spdif
->regs
+ CLKCON
);
323 writel(spdif
->saved_con
, spdif
->regs
+ CON
);
324 writel(spdif
->saved_cstas
, spdif
->regs
+ CSTAS
);
329 #define spdif_suspend NULL
330 #define spdif_resume NULL
333 static const struct snd_soc_dai_ops spdif_dai_ops
= {
334 .set_sysclk
= spdif_set_sysclk
,
335 .trigger
= spdif_trigger
,
336 .hw_params
= spdif_hw_params
,
337 .shutdown
= spdif_shutdown
,
340 static struct snd_soc_dai_driver samsung_spdif_dai
= {
341 .name
= "samsung-spdif",
343 .stream_name
= "S/PDIF Playback",
346 .rates
= (SNDRV_PCM_RATE_32000
|
347 SNDRV_PCM_RATE_44100
|
348 SNDRV_PCM_RATE_48000
|
349 SNDRV_PCM_RATE_96000
),
350 .formats
= SNDRV_PCM_FMTBIT_S16_LE
, },
351 .ops
= &spdif_dai_ops
,
354 static const struct snd_soc_component_driver samsung_spdif_component
= {
355 .name
= "samsung-spdif",
356 .suspend
= spdif_suspend
,
357 .resume
= spdif_resume
,
360 static int spdif_probe(struct platform_device
*pdev
)
362 struct s3c_audio_pdata
*spdif_pdata
;
363 struct resource
*mem_res
;
364 struct samsung_spdif_info
*spdif
;
365 dma_filter_fn filter
;
368 spdif_pdata
= pdev
->dev
.platform_data
;
370 dev_dbg(&pdev
->dev
, "Entered %s\n", __func__
);
372 mem_res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
374 dev_err(&pdev
->dev
, "Unable to get register resource.\n");
378 if (spdif_pdata
&& spdif_pdata
->cfg_gpio
379 && spdif_pdata
->cfg_gpio(pdev
)) {
380 dev_err(&pdev
->dev
, "Unable to configure GPIO pins\n");
385 spdif
->dev
= &pdev
->dev
;
387 spin_lock_init(&spdif
->lock
);
389 spdif
->pclk
= devm_clk_get(&pdev
->dev
, "spdif");
390 if (IS_ERR(spdif
->pclk
)) {
391 dev_err(&pdev
->dev
, "failed to get peri-clock\n");
395 ret
= clk_prepare_enable(spdif
->pclk
);
399 spdif
->sclk
= devm_clk_get(&pdev
->dev
, "sclk_spdif");
400 if (IS_ERR(spdif
->sclk
)) {
401 dev_err(&pdev
->dev
, "failed to get internal source clock\n");
405 ret
= clk_prepare_enable(spdif
->sclk
);
409 /* Request S/PDIF Register's memory region */
410 if (!request_mem_region(mem_res
->start
,
411 resource_size(mem_res
), "samsung-spdif")) {
412 dev_err(&pdev
->dev
, "Unable to request register region\n");
417 spdif
->regs
= ioremap(mem_res
->start
, 0x100);
418 if (spdif
->regs
== NULL
) {
419 dev_err(&pdev
->dev
, "Cannot ioremap registers\n");
424 spdif_stereo_out
.addr_width
= 2;
425 spdif_stereo_out
.addr
= mem_res
->start
+ DATA_OUTBUF
;
428 spdif_stereo_out
.filter_data
= spdif_pdata
->dma_playback
;
429 filter
= spdif_pdata
->dma_filter
;
431 spdif
->dma_playback
= &spdif_stereo_out
;
433 ret
= samsung_asoc_dma_platform_register(&pdev
->dev
, filter
,
436 dev_err(&pdev
->dev
, "failed to register DMA: %d\n", ret
);
440 dev_set_drvdata(&pdev
->dev
, spdif
);
442 ret
= devm_snd_soc_register_component(&pdev
->dev
,
443 &samsung_spdif_component
, &samsung_spdif_dai
, 1);
445 dev_err(&pdev
->dev
, "fail to register dai\n");
451 iounmap(spdif
->regs
);
453 release_mem_region(mem_res
->start
, resource_size(mem_res
));
455 clk_disable_unprepare(spdif
->sclk
);
457 clk_disable_unprepare(spdif
->pclk
);
462 static int spdif_remove(struct platform_device
*pdev
)
464 struct samsung_spdif_info
*spdif
= &spdif_info
;
465 struct resource
*mem_res
;
467 iounmap(spdif
->regs
);
469 mem_res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
471 release_mem_region(mem_res
->start
, resource_size(mem_res
));
473 clk_disable_unprepare(spdif
->sclk
);
474 clk_disable_unprepare(spdif
->pclk
);
479 static struct platform_driver samsung_spdif_driver
= {
480 .probe
= spdif_probe
,
481 .remove
= spdif_remove
,
483 .name
= "samsung-spdif",
487 module_platform_driver(samsung_spdif_driver
);
489 MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
490 MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
491 MODULE_LICENSE("GPL");
492 MODULE_ALIAS("platform:samsung-spdif");