1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // Driver for Microchip S/PDIF TX Controller |
4 | // |
5 | // Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries |
6 | // |
7 | // Author: Codrin Ciubotariu <codrin.ciubotariu@microchip.com> |
8 | |
9 | #include <linux/bitfield.h> |
10 | #include <linux/clk.h> |
11 | #include <linux/io.h> |
12 | #include <linux/module.h> |
13 | #include <linux/pm_runtime.h> |
14 | #include <linux/spinlock.h> |
15 | |
16 | #include <sound/asoundef.h> |
17 | #include <sound/dmaengine_pcm.h> |
18 | #include <sound/pcm_params.h> |
19 | #include <sound/soc.h> |
20 | |
21 | /* |
22 | * ---- S/PDIF Transmitter Controller Register map ---- |
23 | */ |
24 | #define SPDIFTX_CR 0x00 /* Control Register */ |
25 | #define SPDIFTX_MR 0x04 /* Mode Register */ |
26 | #define SPDIFTX_CDR 0x0C /* Common Data Register */ |
27 | |
28 | #define SPDIFTX_IER 0x14 /* Interrupt Enable Register */ |
29 | #define SPDIFTX_IDR 0x18 /* Interrupt Disable Register */ |
30 | #define SPDIFTX_IMR 0x1C /* Interrupt Mask Register */ |
31 | #define SPDIFTX_ISR 0x20 /* Interrupt Status Register */ |
32 | |
33 | #define SPDIFTX_CH1UD(reg) (0x50 + (reg) * 4) /* User Data 1 Register x */ |
34 | #define SPDIFTX_CH1S(reg) (0x80 + (reg) * 4) /* Channel Status 1 Register x */ |
35 | |
36 | #define SPDIFTX_VERSION 0xF0 |
37 | |
38 | /* |
39 | * ---- Control Register (Write-only) ---- |
40 | */ |
41 | #define SPDIFTX_CR_SWRST BIT(0) /* Software Reset */ |
42 | #define SPDIFTX_CR_FCLR BIT(1) /* FIFO clear */ |
43 | |
44 | /* |
45 | * ---- Mode Register (Read/Write) ---- |
46 | */ |
47 | /* Transmit Enable */ |
48 | #define SPDIFTX_MR_TXEN_MASK GENMASK(0, 0) |
49 | #define SPDIFTX_MR_TXEN_DISABLE (0 << 0) |
50 | #define SPDIFTX_MR_TXEN_ENABLE (1 << 0) |
51 | |
52 | /* Multichannel Transfer */ |
53 | #define SPDIFTX_MR_MULTICH_MASK GENAMSK(1, 1) |
54 | #define SPDIFTX_MR_MULTICH_MONO (0 << 1) |
55 | #define SPDIFTX_MR_MULTICH_DUAL (1 << 1) |
56 | |
57 | /* Data Word Endian Mode */ |
58 | #define SPDIFTX_MR_ENDIAN_MASK GENMASK(2, 2) |
59 | #define SPDIFTX_MR_ENDIAN_LITTLE (0 << 2) |
60 | #define SPDIFTX_MR_ENDIAN_BIG (1 << 2) |
61 | |
62 | /* Data Justification */ |
63 | #define SPDIFTX_MR_JUSTIFY_MASK GENMASK(3, 3) |
64 | #define SPDIFTX_MR_JUSTIFY_LSB (0 << 3) |
65 | #define SPDIFTX_MR_JUSTIFY_MSB (1 << 3) |
66 | |
67 | /* Common Audio Register Transfer Mode */ |
68 | #define SPDIFTX_MR_CMODE_MASK GENMASK(5, 4) |
69 | #define SPDIFTX_MR_CMODE_INDEX_ACCESS (0 << 4) |
70 | #define SPDIFTX_MR_CMODE_TOGGLE_ACCESS (1 << 4) |
71 | #define SPDIFTX_MR_CMODE_INTERLVD_ACCESS (2 << 4) |
72 | |
73 | /* Valid Bits per Sample */ |
74 | #define SPDIFTX_MR_VBPS_MASK GENMASK(13, 8) |
75 | |
76 | /* Chunk Size */ |
77 | #define SPDIFTX_MR_CHUNK_MASK GENMASK(19, 16) |
78 | |
79 | /* Validity Bits for Channels 1 and 2 */ |
80 | #define SPDIFTX_MR_VALID1 BIT(24) |
81 | #define SPDIFTX_MR_VALID2 BIT(25) |
82 | |
83 | /* Disable Null Frame on underrun */ |
84 | #define SPDIFTX_MR_DNFR_MASK GENMASK(27, 27) |
85 | #define SPDIFTX_MR_DNFR_INVALID (0 << 27) |
86 | #define SPDIFTX_MR_DNFR_VALID (1 << 27) |
87 | |
88 | /* Bytes per Sample */ |
89 | #define SPDIFTX_MR_BPS_MASK GENMASK(29, 28) |
90 | |
91 | /* |
92 | * ---- Interrupt Enable/Disable/Mask/Status Register (Write/Read-only) ---- |
93 | */ |
94 | #define SPDIFTX_IR_TXRDY BIT(0) |
95 | #define SPDIFTX_IR_TXEMPTY BIT(1) |
96 | #define SPDIFTX_IR_TXFULL BIT(2) |
97 | #define SPDIFTX_IR_TXCHUNK BIT(3) |
98 | #define SPDIFTX_IR_TXUDR BIT(4) |
99 | #define SPDIFTX_IR_TXOVR BIT(5) |
100 | #define SPDIFTX_IR_CSRDY BIT(6) |
101 | #define SPDIFTX_IR_UDRDY BIT(7) |
102 | #define SPDIFTX_IR_TXRDYCH(ch) BIT((ch) + 8) |
103 | #define SPDIFTX_IR_SECE BIT(10) |
104 | #define SPDIFTX_IR_TXUDRCH(ch) BIT((ch) + 11) |
105 | #define SPDIFTX_IR_BEND BIT(13) |
106 | |
107 | static bool mchp_spdiftx_readable_reg(struct device *dev, unsigned int reg) |
108 | { |
109 | switch (reg) { |
110 | case SPDIFTX_MR: |
111 | case SPDIFTX_IMR: |
112 | case SPDIFTX_ISR: |
113 | case SPDIFTX_CH1UD(0): |
114 | case SPDIFTX_CH1UD(1): |
115 | case SPDIFTX_CH1UD(2): |
116 | case SPDIFTX_CH1UD(3): |
117 | case SPDIFTX_CH1UD(4): |
118 | case SPDIFTX_CH1UD(5): |
119 | case SPDIFTX_CH1S(0): |
120 | case SPDIFTX_CH1S(1): |
121 | case SPDIFTX_CH1S(2): |
122 | case SPDIFTX_CH1S(3): |
123 | case SPDIFTX_CH1S(4): |
124 | case SPDIFTX_CH1S(5): |
125 | return true; |
126 | default: |
127 | return false; |
128 | } |
129 | } |
130 | |
131 | static bool mchp_spdiftx_writeable_reg(struct device *dev, unsigned int reg) |
132 | { |
133 | switch (reg) { |
134 | case SPDIFTX_CR: |
135 | case SPDIFTX_MR: |
136 | case SPDIFTX_CDR: |
137 | case SPDIFTX_IER: |
138 | case SPDIFTX_IDR: |
139 | case SPDIFTX_CH1UD(0): |
140 | case SPDIFTX_CH1UD(1): |
141 | case SPDIFTX_CH1UD(2): |
142 | case SPDIFTX_CH1UD(3): |
143 | case SPDIFTX_CH1UD(4): |
144 | case SPDIFTX_CH1UD(5): |
145 | case SPDIFTX_CH1S(0): |
146 | case SPDIFTX_CH1S(1): |
147 | case SPDIFTX_CH1S(2): |
148 | case SPDIFTX_CH1S(3): |
149 | case SPDIFTX_CH1S(4): |
150 | case SPDIFTX_CH1S(5): |
151 | return true; |
152 | default: |
153 | return false; |
154 | } |
155 | } |
156 | |
157 | static bool mchp_spdiftx_precious_reg(struct device *dev, unsigned int reg) |
158 | { |
159 | switch (reg) { |
160 | case SPDIFTX_CDR: |
161 | case SPDIFTX_ISR: |
162 | return true; |
163 | default: |
164 | return false; |
165 | } |
166 | } |
167 | |
168 | static const struct regmap_config mchp_spdiftx_regmap_config = { |
169 | .reg_bits = 32, |
170 | .reg_stride = 4, |
171 | .val_bits = 32, |
172 | .max_register = SPDIFTX_VERSION, |
173 | .readable_reg = mchp_spdiftx_readable_reg, |
174 | .writeable_reg = mchp_spdiftx_writeable_reg, |
175 | .precious_reg = mchp_spdiftx_precious_reg, |
176 | .cache_type = REGCACHE_FLAT, |
177 | }; |
178 | |
179 | #define SPDIFTX_GCLK_RATIO 128 |
180 | |
181 | #define SPDIFTX_CS_BITS 192 |
182 | #define SPDIFTX_UD_BITS 192 |
183 | |
184 | struct mchp_spdiftx_mixer_control { |
185 | unsigned char ch_stat[SPDIFTX_CS_BITS / 8]; |
186 | unsigned char user_data[SPDIFTX_UD_BITS / 8]; |
187 | spinlock_t lock; /* exclusive access to control data */ |
188 | }; |
189 | |
190 | struct mchp_spdiftx_dev { |
191 | struct mchp_spdiftx_mixer_control control; |
192 | struct snd_dmaengine_dai_dma_data playback; |
193 | struct device *dev; |
194 | struct regmap *regmap; |
195 | struct clk *pclk; |
196 | struct clk *gclk; |
197 | unsigned int fmt; |
198 | unsigned int suspend_irq; |
199 | }; |
200 | |
201 | static inline int mchp_spdiftx_is_running(struct mchp_spdiftx_dev *dev) |
202 | { |
203 | u32 mr; |
204 | |
205 | regmap_read(map: dev->regmap, SPDIFTX_MR, val: &mr); |
206 | return !!(mr & SPDIFTX_MR_TXEN_ENABLE); |
207 | } |
208 | |
209 | static void mchp_spdiftx_channel_status_write(struct mchp_spdiftx_dev *dev) |
210 | { |
211 | struct mchp_spdiftx_mixer_control *ctrl = &dev->control; |
212 | u32 val; |
213 | int i; |
214 | |
215 | for (i = 0; i < ARRAY_SIZE(ctrl->ch_stat) / 4; i++) { |
216 | val = (ctrl->ch_stat[(i * 4) + 0] << 0) | |
217 | (ctrl->ch_stat[(i * 4) + 1] << 8) | |
218 | (ctrl->ch_stat[(i * 4) + 2] << 16) | |
219 | (ctrl->ch_stat[(i * 4) + 3] << 24); |
220 | |
221 | regmap_write(map: dev->regmap, SPDIFTX_CH1S(i), val); |
222 | } |
223 | } |
224 | |
225 | static void mchp_spdiftx_user_data_write(struct mchp_spdiftx_dev *dev) |
226 | { |
227 | struct mchp_spdiftx_mixer_control *ctrl = &dev->control; |
228 | u32 val; |
229 | int i; |
230 | |
231 | for (i = 0; i < ARRAY_SIZE(ctrl->user_data) / 4; i++) { |
232 | val = (ctrl->user_data[(i * 4) + 0] << 0) | |
233 | (ctrl->user_data[(i * 4) + 1] << 8) | |
234 | (ctrl->user_data[(i * 4) + 2] << 16) | |
235 | (ctrl->user_data[(i * 4) + 3] << 24); |
236 | |
237 | regmap_write(map: dev->regmap, SPDIFTX_CH1UD(i), val); |
238 | } |
239 | } |
240 | |
241 | static irqreturn_t mchp_spdiftx_interrupt(int irq, void *dev_id) |
242 | { |
243 | struct mchp_spdiftx_dev *dev = dev_id; |
244 | struct mchp_spdiftx_mixer_control *ctrl = &dev->control; |
245 | u32 sr, imr, pending, idr = 0; |
246 | |
247 | regmap_read(map: dev->regmap, SPDIFTX_ISR, val: &sr); |
248 | regmap_read(map: dev->regmap, SPDIFTX_IMR, val: &imr); |
249 | pending = sr & imr; |
250 | |
251 | if (!pending) |
252 | return IRQ_NONE; |
253 | |
254 | if (pending & SPDIFTX_IR_TXUDR) { |
255 | dev_warn(dev->dev, "underflow detected\n" ); |
256 | idr |= SPDIFTX_IR_TXUDR; |
257 | } |
258 | |
259 | if (pending & SPDIFTX_IR_TXOVR) { |
260 | dev_warn(dev->dev, "overflow detected\n" ); |
261 | idr |= SPDIFTX_IR_TXOVR; |
262 | } |
263 | |
264 | if (pending & SPDIFTX_IR_UDRDY) { |
265 | spin_lock(lock: &ctrl->lock); |
266 | mchp_spdiftx_user_data_write(dev); |
267 | spin_unlock(lock: &ctrl->lock); |
268 | idr |= SPDIFTX_IR_UDRDY; |
269 | } |
270 | |
271 | if (pending & SPDIFTX_IR_CSRDY) { |
272 | spin_lock(lock: &ctrl->lock); |
273 | mchp_spdiftx_channel_status_write(dev); |
274 | spin_unlock(lock: &ctrl->lock); |
275 | idr |= SPDIFTX_IR_CSRDY; |
276 | } |
277 | |
278 | regmap_write(map: dev->regmap, SPDIFTX_IDR, val: idr); |
279 | |
280 | return IRQ_HANDLED; |
281 | } |
282 | |
283 | static int mchp_spdiftx_dai_startup(struct snd_pcm_substream *substream, |
284 | struct snd_soc_dai *dai) |
285 | { |
286 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
287 | |
288 | /* Software reset the IP */ |
289 | regmap_write(map: dev->regmap, SPDIFTX_CR, |
290 | SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR); |
291 | |
292 | return 0; |
293 | } |
294 | |
295 | static void mchp_spdiftx_dai_shutdown(struct snd_pcm_substream *substream, |
296 | struct snd_soc_dai *dai) |
297 | { |
298 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
299 | |
300 | /* Disable interrupts */ |
301 | regmap_write(map: dev->regmap, SPDIFTX_IDR, val: 0xffffffff); |
302 | } |
303 | |
304 | static int mchp_spdiftx_trigger(struct snd_pcm_substream *substream, int cmd, |
305 | struct snd_soc_dai *dai) |
306 | { |
307 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
308 | struct mchp_spdiftx_mixer_control *ctrl = &dev->control; |
309 | int ret; |
310 | |
311 | /* do not start/stop while channel status or user data is updated */ |
312 | spin_lock(lock: &ctrl->lock); |
313 | switch (cmd) { |
314 | case SNDRV_PCM_TRIGGER_RESUME: |
315 | case SNDRV_PCM_TRIGGER_START: |
316 | regmap_write(map: dev->regmap, SPDIFTX_IER, val: dev->suspend_irq | |
317 | SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR); |
318 | dev->suspend_irq = 0; |
319 | fallthrough; |
320 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
321 | ret = regmap_update_bits(map: dev->regmap, SPDIFTX_MR, SPDIFTX_MR_TXEN_MASK, |
322 | SPDIFTX_MR_TXEN_ENABLE); |
323 | break; |
324 | case SNDRV_PCM_TRIGGER_SUSPEND: |
325 | regmap_read(map: dev->regmap, SPDIFTX_IMR, val: &dev->suspend_irq); |
326 | fallthrough; |
327 | case SNDRV_PCM_TRIGGER_STOP: |
328 | regmap_write(map: dev->regmap, SPDIFTX_IDR, val: dev->suspend_irq | |
329 | SPDIFTX_IR_TXUDR | SPDIFTX_IR_TXOVR); |
330 | fallthrough; |
331 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
332 | ret = regmap_update_bits(map: dev->regmap, SPDIFTX_MR, SPDIFTX_MR_TXEN_MASK, |
333 | SPDIFTX_MR_TXEN_DISABLE); |
334 | break; |
335 | default: |
336 | ret = -EINVAL; |
337 | } |
338 | spin_unlock(lock: &ctrl->lock); |
339 | if (ret) |
340 | dev_err(dev->dev, "unable to start/stop TX: %d\n" , ret); |
341 | |
342 | return ret; |
343 | } |
344 | |
345 | static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream, |
346 | struct snd_pcm_hw_params *params, |
347 | struct snd_soc_dai *dai) |
348 | { |
349 | unsigned long flags; |
350 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
351 | struct mchp_spdiftx_mixer_control *ctrl = &dev->control; |
352 | u32 mr; |
353 | unsigned int bps = params_physical_width(p: params) / 8; |
354 | unsigned char aes3; |
355 | int ret; |
356 | |
357 | dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n" , |
358 | __func__, params_rate(params), params_format(params), |
359 | params_width(params), params_channels(params)); |
360 | |
361 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
362 | dev_err(dev->dev, "Capture is not supported\n" ); |
363 | return -EINVAL; |
364 | } |
365 | |
366 | regmap_read(map: dev->regmap, SPDIFTX_MR, val: &mr); |
367 | |
368 | if (mr & SPDIFTX_MR_TXEN_ENABLE) { |
369 | dev_err(dev->dev, "PCM already running\n" ); |
370 | return -EBUSY; |
371 | } |
372 | |
373 | /* Defaults: Toggle mode, justify to LSB, chunksize 1 */ |
374 | mr = SPDIFTX_MR_CMODE_TOGGLE_ACCESS | SPDIFTX_MR_JUSTIFY_LSB; |
375 | dev->playback.maxburst = 1; |
376 | switch (params_channels(p: params)) { |
377 | case 1: |
378 | mr |= SPDIFTX_MR_MULTICH_MONO; |
379 | break; |
380 | case 2: |
381 | mr |= SPDIFTX_MR_MULTICH_DUAL; |
382 | if (bps > 2) |
383 | dev->playback.maxburst = 2; |
384 | break; |
385 | default: |
386 | dev_err(dev->dev, "unsupported number of channels: %d\n" , |
387 | params_channels(params)); |
388 | return -EINVAL; |
389 | } |
390 | mr |= FIELD_PREP(SPDIFTX_MR_CHUNK_MASK, dev->playback.maxburst); |
391 | |
392 | switch (params_format(p: params)) { |
393 | case SNDRV_PCM_FORMAT_S8: |
394 | mr |= FIELD_PREP(SPDIFTX_MR_VBPS_MASK, 8); |
395 | break; |
396 | case SNDRV_PCM_FORMAT_S16_BE: |
397 | mr |= SPDIFTX_MR_ENDIAN_BIG; |
398 | fallthrough; |
399 | case SNDRV_PCM_FORMAT_S16_LE: |
400 | mr |= FIELD_PREP(SPDIFTX_MR_VBPS_MASK, 16); |
401 | break; |
402 | case SNDRV_PCM_FORMAT_S18_3BE: |
403 | mr |= SPDIFTX_MR_ENDIAN_BIG; |
404 | fallthrough; |
405 | case SNDRV_PCM_FORMAT_S18_3LE: |
406 | mr |= FIELD_PREP(SPDIFTX_MR_VBPS_MASK, 18); |
407 | break; |
408 | case SNDRV_PCM_FORMAT_S20_3BE: |
409 | mr |= SPDIFTX_MR_ENDIAN_BIG; |
410 | fallthrough; |
411 | case SNDRV_PCM_FORMAT_S20_3LE: |
412 | mr |= FIELD_PREP(SPDIFTX_MR_VBPS_MASK, 20); |
413 | break; |
414 | case SNDRV_PCM_FORMAT_S24_3BE: |
415 | mr |= SPDIFTX_MR_ENDIAN_BIG; |
416 | fallthrough; |
417 | case SNDRV_PCM_FORMAT_S24_3LE: |
418 | mr |= FIELD_PREP(SPDIFTX_MR_VBPS_MASK, 24); |
419 | break; |
420 | case SNDRV_PCM_FORMAT_S24_BE: |
421 | mr |= SPDIFTX_MR_ENDIAN_BIG; |
422 | fallthrough; |
423 | case SNDRV_PCM_FORMAT_S24_LE: |
424 | mr |= FIELD_PREP(SPDIFTX_MR_VBPS_MASK, 24); |
425 | break; |
426 | case SNDRV_PCM_FORMAT_S32_BE: |
427 | mr |= SPDIFTX_MR_ENDIAN_BIG; |
428 | fallthrough; |
429 | case SNDRV_PCM_FORMAT_S32_LE: |
430 | mr |= FIELD_PREP(SPDIFTX_MR_VBPS_MASK, 32); |
431 | break; |
432 | default: |
433 | dev_err(dev->dev, "unsupported PCM format: %d\n" , |
434 | params_format(params)); |
435 | return -EINVAL; |
436 | } |
437 | |
438 | mr |= FIELD_PREP(SPDIFTX_MR_BPS_MASK, bps - 1); |
439 | |
440 | switch (params_rate(p: params)) { |
441 | case 22050: |
442 | aes3 = IEC958_AES3_CON_FS_22050; |
443 | break; |
444 | case 24000: |
445 | aes3 = IEC958_AES3_CON_FS_24000; |
446 | break; |
447 | case 32000: |
448 | aes3 = IEC958_AES3_CON_FS_32000; |
449 | break; |
450 | case 44100: |
451 | aes3 = IEC958_AES3_CON_FS_44100; |
452 | break; |
453 | case 48000: |
454 | aes3 = IEC958_AES3_CON_FS_48000; |
455 | break; |
456 | case 88200: |
457 | aes3 = IEC958_AES3_CON_FS_88200; |
458 | break; |
459 | case 96000: |
460 | aes3 = IEC958_AES3_CON_FS_96000; |
461 | break; |
462 | case 176400: |
463 | aes3 = IEC958_AES3_CON_FS_176400; |
464 | break; |
465 | case 192000: |
466 | aes3 = IEC958_AES3_CON_FS_192000; |
467 | break; |
468 | case 8000: |
469 | case 11025: |
470 | case 16000: |
471 | case 64000: |
472 | aes3 = IEC958_AES3_CON_FS_NOTID; |
473 | break; |
474 | default: |
475 | dev_err(dev->dev, "unsupported sample frequency: %u\n" , |
476 | params_rate(params)); |
477 | return -EINVAL; |
478 | } |
479 | spin_lock_irqsave(&ctrl->lock, flags); |
480 | ctrl->ch_stat[3] &= ~IEC958_AES3_CON_FS; |
481 | ctrl->ch_stat[3] |= aes3; |
482 | mchp_spdiftx_channel_status_write(dev); |
483 | spin_unlock_irqrestore(lock: &ctrl->lock, flags); |
484 | |
485 | /* GCLK is enabled by runtime PM. */ |
486 | clk_disable_unprepare(clk: dev->gclk); |
487 | |
488 | ret = clk_set_rate(clk: dev->gclk, rate: params_rate(p: params) * |
489 | SPDIFTX_GCLK_RATIO); |
490 | if (ret) { |
491 | dev_err(dev->dev, |
492 | "unable to change gclk rate to: rate %u * ratio %u\n" , |
493 | params_rate(params), SPDIFTX_GCLK_RATIO); |
494 | return ret; |
495 | } |
496 | ret = clk_prepare_enable(clk: dev->gclk); |
497 | if (ret) { |
498 | dev_err(dev->dev, "unable to enable gclk: %d\n" , ret); |
499 | return ret; |
500 | } |
501 | |
502 | dev_dbg(dev->dev, "%s(): GCLK set to %d\n" , __func__, |
503 | params_rate(params) * SPDIFTX_GCLK_RATIO); |
504 | |
505 | regmap_write(map: dev->regmap, SPDIFTX_MR, val: mr); |
506 | |
507 | return 0; |
508 | } |
509 | |
510 | static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream, |
511 | struct snd_soc_dai *dai) |
512 | { |
513 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
514 | |
515 | return regmap_write(map: dev->regmap, SPDIFTX_CR, |
516 | SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR); |
517 | } |
518 | |
519 | #define MCHP_SPDIFTX_RATES SNDRV_PCM_RATE_8000_192000 |
520 | |
521 | #define MCHP_SPDIFTX_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ |
522 | SNDRV_PCM_FMTBIT_S16_LE | \ |
523 | SNDRV_PCM_FMTBIT_U16_BE | \ |
524 | SNDRV_PCM_FMTBIT_S18_3LE | \ |
525 | SNDRV_PCM_FMTBIT_S18_3BE | \ |
526 | SNDRV_PCM_FMTBIT_S20_3LE | \ |
527 | SNDRV_PCM_FMTBIT_S20_3BE | \ |
528 | SNDRV_PCM_FMTBIT_S24_3LE | \ |
529 | SNDRV_PCM_FMTBIT_S24_3BE | \ |
530 | SNDRV_PCM_FMTBIT_S24_LE | \ |
531 | SNDRV_PCM_FMTBIT_S24_BE | \ |
532 | SNDRV_PCM_FMTBIT_S32_LE | \ |
533 | SNDRV_PCM_FMTBIT_S32_BE \ |
534 | ) |
535 | |
536 | static int mchp_spdiftx_info(struct snd_kcontrol *kcontrol, |
537 | struct snd_ctl_elem_info *uinfo) |
538 | { |
539 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
540 | uinfo->count = 1; |
541 | |
542 | return 0; |
543 | } |
544 | |
545 | static int mchp_spdiftx_cs_get(struct snd_kcontrol *kcontrol, |
546 | struct snd_ctl_elem_value *uvalue) |
547 | { |
548 | unsigned long flags; |
549 | struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
550 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
551 | struct mchp_spdiftx_mixer_control *ctrl = &dev->control; |
552 | |
553 | spin_lock_irqsave(&ctrl->lock, flags); |
554 | memcpy(uvalue->value.iec958.status, ctrl->ch_stat, |
555 | sizeof(ctrl->ch_stat)); |
556 | spin_unlock_irqrestore(lock: &ctrl->lock, flags); |
557 | |
558 | return 0; |
559 | } |
560 | |
561 | static int mchp_spdiftx_cs_put(struct snd_kcontrol *kcontrol, |
562 | struct snd_ctl_elem_value *uvalue) |
563 | { |
564 | unsigned long flags; |
565 | struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
566 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
567 | struct mchp_spdiftx_mixer_control *ctrl = &dev->control; |
568 | int changed = 0; |
569 | int i; |
570 | |
571 | spin_lock_irqsave(&ctrl->lock, flags); |
572 | for (i = 0; i < ARRAY_SIZE(ctrl->ch_stat); i++) { |
573 | if (ctrl->ch_stat[i] != uvalue->value.iec958.status[i]) |
574 | changed = 1; |
575 | ctrl->ch_stat[i] = uvalue->value.iec958.status[i]; |
576 | } |
577 | |
578 | if (changed) { |
579 | /* don't enable IP while we copy the channel status */ |
580 | if (mchp_spdiftx_is_running(dev)) { |
581 | /* |
582 | * if SPDIF is running, wait for interrupt to write |
583 | * channel status |
584 | */ |
585 | regmap_write(map: dev->regmap, SPDIFTX_IER, |
586 | SPDIFTX_IR_CSRDY); |
587 | } else { |
588 | mchp_spdiftx_channel_status_write(dev); |
589 | } |
590 | } |
591 | spin_unlock_irqrestore(lock: &ctrl->lock, flags); |
592 | |
593 | return changed; |
594 | } |
595 | |
596 | static int mchp_spdiftx_cs_mask(struct snd_kcontrol *kcontrol, |
597 | struct snd_ctl_elem_value *uvalue) |
598 | { |
599 | memset(uvalue->value.iec958.status, 0xff, |
600 | sizeof(uvalue->value.iec958.status)); |
601 | |
602 | return 0; |
603 | } |
604 | |
605 | static int mchp_spdiftx_subcode_get(struct snd_kcontrol *kcontrol, |
606 | struct snd_ctl_elem_value *uvalue) |
607 | { |
608 | struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
609 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
610 | struct mchp_spdiftx_mixer_control *ctrl = &dev->control; |
611 | unsigned long flags; |
612 | |
613 | spin_lock_irqsave(&ctrl->lock, flags); |
614 | memcpy(uvalue->value.iec958.subcode, ctrl->user_data, |
615 | sizeof(ctrl->user_data)); |
616 | spin_unlock_irqrestore(lock: &ctrl->lock, flags); |
617 | |
618 | return 0; |
619 | } |
620 | |
621 | static int mchp_spdiftx_subcode_put(struct snd_kcontrol *kcontrol, |
622 | struct snd_ctl_elem_value *uvalue) |
623 | { |
624 | unsigned long flags; |
625 | struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
626 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
627 | struct mchp_spdiftx_mixer_control *ctrl = &dev->control; |
628 | int changed = 0; |
629 | int i; |
630 | |
631 | spin_lock_irqsave(&ctrl->lock, flags); |
632 | for (i = 0; i < ARRAY_SIZE(ctrl->user_data); i++) { |
633 | if (ctrl->user_data[i] != uvalue->value.iec958.subcode[i]) |
634 | changed = 1; |
635 | |
636 | ctrl->user_data[i] = uvalue->value.iec958.subcode[i]; |
637 | } |
638 | if (changed) { |
639 | if (mchp_spdiftx_is_running(dev)) { |
640 | /* |
641 | * if SPDIF is running, wait for interrupt to write |
642 | * user data |
643 | */ |
644 | regmap_write(map: dev->regmap, SPDIFTX_IER, |
645 | SPDIFTX_IR_UDRDY); |
646 | } else { |
647 | mchp_spdiftx_user_data_write(dev); |
648 | } |
649 | } |
650 | spin_unlock_irqrestore(lock: &ctrl->lock, flags); |
651 | |
652 | return changed; |
653 | } |
654 | |
655 | static struct snd_kcontrol_new mchp_spdiftx_ctrls[] = { |
656 | /* Channel status controller */ |
657 | { |
658 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
659 | .name = SNDRV_CTL_NAME_IEC958("" , PLAYBACK, DEFAULT), |
660 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
661 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
662 | .info = mchp_spdiftx_info, |
663 | .get = mchp_spdiftx_cs_get, |
664 | .put = mchp_spdiftx_cs_put, |
665 | }, |
666 | { |
667 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
668 | .name = SNDRV_CTL_NAME_IEC958("" , PLAYBACK, MASK), |
669 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
670 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
671 | .info = mchp_spdiftx_info, |
672 | .get = mchp_spdiftx_cs_mask, |
673 | }, |
674 | /* User bits controller */ |
675 | { |
676 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
677 | .name = "IEC958 Subcode Playback Default" , |
678 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
679 | .info = mchp_spdiftx_info, |
680 | .get = mchp_spdiftx_subcode_get, |
681 | .put = mchp_spdiftx_subcode_put, |
682 | }, |
683 | }; |
684 | |
685 | static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai) |
686 | { |
687 | struct mchp_spdiftx_dev *dev = snd_soc_dai_get_drvdata(dai); |
688 | |
689 | snd_soc_dai_init_dma_data(dai, playback: &dev->playback, NULL); |
690 | |
691 | /* Add controls */ |
692 | snd_soc_add_dai_controls(dai, controls: mchp_spdiftx_ctrls, |
693 | ARRAY_SIZE(mchp_spdiftx_ctrls)); |
694 | |
695 | return 0; |
696 | } |
697 | |
698 | static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { |
699 | .probe = mchp_spdiftx_dai_probe, |
700 | .startup = mchp_spdiftx_dai_startup, |
701 | .shutdown = mchp_spdiftx_dai_shutdown, |
702 | .trigger = mchp_spdiftx_trigger, |
703 | .hw_params = mchp_spdiftx_hw_params, |
704 | .hw_free = mchp_spdiftx_hw_free, |
705 | }; |
706 | |
707 | static struct snd_soc_dai_driver mchp_spdiftx_dai = { |
708 | .name = "mchp-spdiftx" , |
709 | .playback = { |
710 | .stream_name = "S/PDIF Playback" , |
711 | .channels_min = 1, |
712 | .channels_max = 2, |
713 | .rates = MCHP_SPDIFTX_RATES, |
714 | .formats = MCHP_SPDIFTX_FORMATS, |
715 | }, |
716 | .ops = &mchp_spdiftx_dai_ops, |
717 | }; |
718 | |
719 | static const struct snd_soc_component_driver mchp_spdiftx_component = { |
720 | .name = "mchp-spdiftx" , |
721 | .legacy_dai_naming = 1, |
722 | }; |
723 | |
724 | static const struct of_device_id mchp_spdiftx_dt_ids[] = { |
725 | { |
726 | .compatible = "microchip,sama7g5-spdiftx" , |
727 | }, |
728 | { /* sentinel */ } |
729 | }; |
730 | MODULE_DEVICE_TABLE(of, mchp_spdiftx_dt_ids); |
731 | |
732 | static int mchp_spdiftx_runtime_suspend(struct device *dev) |
733 | { |
734 | struct mchp_spdiftx_dev *spdiftx = dev_get_drvdata(dev); |
735 | |
736 | regcache_cache_only(map: spdiftx->regmap, enable: true); |
737 | |
738 | clk_disable_unprepare(clk: spdiftx->gclk); |
739 | clk_disable_unprepare(clk: spdiftx->pclk); |
740 | |
741 | return 0; |
742 | } |
743 | |
744 | static int mchp_spdiftx_runtime_resume(struct device *dev) |
745 | { |
746 | struct mchp_spdiftx_dev *spdiftx = dev_get_drvdata(dev); |
747 | int ret; |
748 | |
749 | ret = clk_prepare_enable(clk: spdiftx->pclk); |
750 | if (ret) { |
751 | dev_err(spdiftx->dev, |
752 | "failed to enable the peripheral clock: %d\n" , ret); |
753 | return ret; |
754 | } |
755 | ret = clk_prepare_enable(clk: spdiftx->gclk); |
756 | if (ret) { |
757 | dev_err(spdiftx->dev, |
758 | "failed to enable generic clock: %d\n" , ret); |
759 | goto disable_pclk; |
760 | } |
761 | |
762 | regcache_cache_only(map: spdiftx->regmap, enable: false); |
763 | regcache_mark_dirty(map: spdiftx->regmap); |
764 | ret = regcache_sync(map: spdiftx->regmap); |
765 | if (ret) { |
766 | regcache_cache_only(map: spdiftx->regmap, enable: true); |
767 | clk_disable_unprepare(clk: spdiftx->gclk); |
768 | disable_pclk: |
769 | clk_disable_unprepare(clk: spdiftx->pclk); |
770 | } |
771 | |
772 | return ret; |
773 | } |
774 | |
775 | static const struct dev_pm_ops mchp_spdiftx_pm_ops = { |
776 | SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) |
777 | RUNTIME_PM_OPS(mchp_spdiftx_runtime_suspend, mchp_spdiftx_runtime_resume, |
778 | NULL) |
779 | }; |
780 | |
781 | static int mchp_spdiftx_probe(struct platform_device *pdev) |
782 | { |
783 | struct mchp_spdiftx_dev *dev; |
784 | struct resource *mem; |
785 | struct regmap *regmap; |
786 | void __iomem *base; |
787 | struct mchp_spdiftx_mixer_control *ctrl; |
788 | int irq; |
789 | int err; |
790 | |
791 | /* Get memory for driver data. */ |
792 | dev = devm_kzalloc(dev: &pdev->dev, size: sizeof(*dev), GFP_KERNEL); |
793 | if (!dev) |
794 | return -ENOMEM; |
795 | |
796 | /* Map I/O registers. */ |
797 | base = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &mem); |
798 | if (IS_ERR(ptr: base)) |
799 | return PTR_ERR(ptr: base); |
800 | |
801 | regmap = devm_regmap_init_mmio(&pdev->dev, base, |
802 | &mchp_spdiftx_regmap_config); |
803 | if (IS_ERR(ptr: regmap)) |
804 | return PTR_ERR(ptr: regmap); |
805 | |
806 | /* Request IRQ */ |
807 | irq = platform_get_irq(pdev, 0); |
808 | if (irq < 0) |
809 | return irq; |
810 | |
811 | err = devm_request_irq(dev: &pdev->dev, irq, handler: mchp_spdiftx_interrupt, irqflags: 0, |
812 | devname: dev_name(dev: &pdev->dev), dev_id: dev); |
813 | if (err) |
814 | return err; |
815 | |
816 | /* Get the peripheral clock */ |
817 | dev->pclk = devm_clk_get(dev: &pdev->dev, id: "pclk" ); |
818 | if (IS_ERR(ptr: dev->pclk)) { |
819 | err = PTR_ERR(ptr: dev->pclk); |
820 | dev_err(&pdev->dev, |
821 | "failed to get the peripheral clock: %d\n" , err); |
822 | return err; |
823 | } |
824 | |
825 | /* Get the generic clock */ |
826 | dev->gclk = devm_clk_get(dev: &pdev->dev, id: "gclk" ); |
827 | if (IS_ERR(ptr: dev->gclk)) { |
828 | err = PTR_ERR(ptr: dev->gclk); |
829 | dev_err(&pdev->dev, |
830 | "failed to get the PMC generic clock: %d\n" , err); |
831 | return err; |
832 | } |
833 | |
834 | ctrl = &dev->control; |
835 | spin_lock_init(&ctrl->lock); |
836 | |
837 | /* Init channel status */ |
838 | ctrl->ch_stat[0] = IEC958_AES0_CON_NOT_COPYRIGHT | |
839 | IEC958_AES0_CON_EMPHASIS_NONE; |
840 | |
841 | dev->dev = &pdev->dev; |
842 | dev->regmap = regmap; |
843 | platform_set_drvdata(pdev, data: dev); |
844 | |
845 | pm_runtime_enable(dev: dev->dev); |
846 | if (!pm_runtime_enabled(dev: dev->dev)) { |
847 | err = mchp_spdiftx_runtime_resume(dev: dev->dev); |
848 | if (err) |
849 | return err; |
850 | } |
851 | |
852 | dev->playback.addr = (dma_addr_t)mem->start + SPDIFTX_CDR; |
853 | dev->playback.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
854 | |
855 | err = devm_snd_dmaengine_pcm_register(dev: &pdev->dev, NULL, flags: 0); |
856 | if (err) { |
857 | dev_err(&pdev->dev, "failed to register PMC: %d\n" , err); |
858 | goto pm_runtime_suspend; |
859 | } |
860 | |
861 | err = devm_snd_soc_register_component(dev: &pdev->dev, |
862 | component_driver: &mchp_spdiftx_component, |
863 | dai_drv: &mchp_spdiftx_dai, num_dai: 1); |
864 | if (err) { |
865 | dev_err(&pdev->dev, "failed to register component: %d\n" , err); |
866 | goto pm_runtime_suspend; |
867 | } |
868 | |
869 | return 0; |
870 | |
871 | pm_runtime_suspend: |
872 | if (!pm_runtime_status_suspended(dev: dev->dev)) |
873 | mchp_spdiftx_runtime_suspend(dev: dev->dev); |
874 | pm_runtime_disable(dev: dev->dev); |
875 | |
876 | return err; |
877 | } |
878 | |
879 | static void mchp_spdiftx_remove(struct platform_device *pdev) |
880 | { |
881 | struct mchp_spdiftx_dev *dev = platform_get_drvdata(pdev); |
882 | |
883 | if (!pm_runtime_status_suspended(dev: dev->dev)) |
884 | mchp_spdiftx_runtime_suspend(dev: dev->dev); |
885 | |
886 | pm_runtime_disable(dev: dev->dev); |
887 | } |
888 | |
889 | static struct platform_driver mchp_spdiftx_driver = { |
890 | .probe = mchp_spdiftx_probe, |
891 | .remove_new = mchp_spdiftx_remove, |
892 | .driver = { |
893 | .name = "mchp_spdiftx" , |
894 | .of_match_table = mchp_spdiftx_dt_ids, |
895 | .pm = pm_ptr(&mchp_spdiftx_pm_ops) |
896 | }, |
897 | }; |
898 | |
899 | module_platform_driver(mchp_spdiftx_driver); |
900 | |
901 | MODULE_AUTHOR("Codrin Ciubotariu <codrin.ciubotariu@microchip.com>" ); |
902 | MODULE_DESCRIPTION("Microchip S/PDIF TX Controller Driver" ); |
903 | MODULE_LICENSE("GPL v2" ); |
904 | |