1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/interrupt.h>
16#include <linux/device.h>
17#include <linux/delay.h>
18#include <linux/slab.h>
19#include <linux/of_platform.h>
20
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/initval.h>
25#include <sound/soc.h>
26
27#include "fsl_ssi.h"
28
29
30
31
32
33
34
35
36
37#define FSLSSI_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
38 SNDRV_PCM_RATE_CONTINUOUS)
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54#ifdef __BIG_ENDIAN
55#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
56 SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \
57 SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE)
58#else
59#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
60 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \
61 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
62#endif
63
64
65#define SIER_FLAGS (CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE | \
66 CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN | \
67 CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN | \
68 CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE | \
69 CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN)
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86struct fsl_ssi_private {
87 struct ccsr_ssi __iomem *ssi;
88 dma_addr_t ssi_phys;
89 unsigned int irq;
90 struct snd_pcm_substream *first_stream;
91 struct snd_pcm_substream *second_stream;
92 unsigned int fifo_depth;
93 struct snd_soc_dai_driver cpu_dai_drv;
94 struct device_attribute dev_attr;
95 struct platform_device *pdev;
96
97 struct {
98 unsigned int rfrc;
99 unsigned int tfrc;
100 unsigned int cmdau;
101 unsigned int cmddu;
102 unsigned int rxt;
103 unsigned int rdr1;
104 unsigned int rdr0;
105 unsigned int tde1;
106 unsigned int tde0;
107 unsigned int roe1;
108 unsigned int roe0;
109 unsigned int tue1;
110 unsigned int tue0;
111 unsigned int tfs;
112 unsigned int rfs;
113 unsigned int tls;
114 unsigned int rls;
115 unsigned int rff1;
116 unsigned int rff0;
117 unsigned int tfe1;
118 unsigned int tfe0;
119 } stats;
120
121 char name[1];
122};
123
124
125
126
127
128
129
130
131
132
133
134
135
136static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
137{
138 struct fsl_ssi_private *ssi_private = dev_id;
139 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
140 irqreturn_t ret = IRQ_NONE;
141 __be32 sisr;
142 __be32 sisr2 = 0;
143
144
145
146
147
148 sisr = in_be32(&ssi->sisr) & SIER_FLAGS;
149
150 if (sisr & CCSR_SSI_SISR_RFRC) {
151 ssi_private->stats.rfrc++;
152 sisr2 |= CCSR_SSI_SISR_RFRC;
153 ret = IRQ_HANDLED;
154 }
155
156 if (sisr & CCSR_SSI_SISR_TFRC) {
157 ssi_private->stats.tfrc++;
158 sisr2 |= CCSR_SSI_SISR_TFRC;
159 ret = IRQ_HANDLED;
160 }
161
162 if (sisr & CCSR_SSI_SISR_CMDAU) {
163 ssi_private->stats.cmdau++;
164 ret = IRQ_HANDLED;
165 }
166
167 if (sisr & CCSR_SSI_SISR_CMDDU) {
168 ssi_private->stats.cmddu++;
169 ret = IRQ_HANDLED;
170 }
171
172 if (sisr & CCSR_SSI_SISR_RXT) {
173 ssi_private->stats.rxt++;
174 ret = IRQ_HANDLED;
175 }
176
177 if (sisr & CCSR_SSI_SISR_RDR1) {
178 ssi_private->stats.rdr1++;
179 ret = IRQ_HANDLED;
180 }
181
182 if (sisr & CCSR_SSI_SISR_RDR0) {
183 ssi_private->stats.rdr0++;
184 ret = IRQ_HANDLED;
185 }
186
187 if (sisr & CCSR_SSI_SISR_TDE1) {
188 ssi_private->stats.tde1++;
189 ret = IRQ_HANDLED;
190 }
191
192 if (sisr & CCSR_SSI_SISR_TDE0) {
193 ssi_private->stats.tde0++;
194 ret = IRQ_HANDLED;
195 }
196
197 if (sisr & CCSR_SSI_SISR_ROE1) {
198 ssi_private->stats.roe1++;
199 sisr2 |= CCSR_SSI_SISR_ROE1;
200 ret = IRQ_HANDLED;
201 }
202
203 if (sisr & CCSR_SSI_SISR_ROE0) {
204 ssi_private->stats.roe0++;
205 sisr2 |= CCSR_SSI_SISR_ROE0;
206 ret = IRQ_HANDLED;
207 }
208
209 if (sisr & CCSR_SSI_SISR_TUE1) {
210 ssi_private->stats.tue1++;
211 sisr2 |= CCSR_SSI_SISR_TUE1;
212 ret = IRQ_HANDLED;
213 }
214
215 if (sisr & CCSR_SSI_SISR_TUE0) {
216 ssi_private->stats.tue0++;
217 sisr2 |= CCSR_SSI_SISR_TUE0;
218 ret = IRQ_HANDLED;
219 }
220
221 if (sisr & CCSR_SSI_SISR_TFS) {
222 ssi_private->stats.tfs++;
223 ret = IRQ_HANDLED;
224 }
225
226 if (sisr & CCSR_SSI_SISR_RFS) {
227 ssi_private->stats.rfs++;
228 ret = IRQ_HANDLED;
229 }
230
231 if (sisr & CCSR_SSI_SISR_TLS) {
232 ssi_private->stats.tls++;
233 ret = IRQ_HANDLED;
234 }
235
236 if (sisr & CCSR_SSI_SISR_RLS) {
237 ssi_private->stats.rls++;
238 ret = IRQ_HANDLED;
239 }
240
241 if (sisr & CCSR_SSI_SISR_RFF1) {
242 ssi_private->stats.rff1++;
243 ret = IRQ_HANDLED;
244 }
245
246 if (sisr & CCSR_SSI_SISR_RFF0) {
247 ssi_private->stats.rff0++;
248 ret = IRQ_HANDLED;
249 }
250
251 if (sisr & CCSR_SSI_SISR_TFE1) {
252 ssi_private->stats.tfe1++;
253 ret = IRQ_HANDLED;
254 }
255
256 if (sisr & CCSR_SSI_SISR_TFE0) {
257 ssi_private->stats.tfe0++;
258 ret = IRQ_HANDLED;
259 }
260
261
262 if (sisr2)
263 out_be32(&ssi->sisr, sisr2);
264
265 return ret;
266}
267
268
269
270
271
272
273
274
275
276static int fsl_ssi_startup(struct snd_pcm_substream *substream,
277 struct snd_soc_dai *dai)
278{
279 struct snd_soc_pcm_runtime *rtd = substream->private_data;
280 struct fsl_ssi_private *ssi_private =
281 snd_soc_dai_get_drvdata(rtd->cpu_dai);
282 int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
283
284
285
286
287
288 if (!ssi_private->first_stream) {
289 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
290
291 ssi_private->first_stream = substream;
292
293
294
295
296
297
298 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
299
300
301
302
303
304
305
306 clrsetbits_be32(&ssi->scr,
307 CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
308 CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
309 | (synchronous ? CCSR_SSI_SCR_SYN : 0));
310
311 out_be32(&ssi->stcr,
312 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
313 CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
314 CCSR_SSI_STCR_TSCKP);
315
316 out_be32(&ssi->srcr,
317 CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
318 CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
319 CCSR_SSI_SRCR_RSCKP);
320
321
322
323
324
325
326
327 out_be32(&ssi->sier, SIER_FLAGS);
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342 out_be32(&ssi->sfcsr,
343 CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
344 CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2));
345
346
347
348
349
350
351
352
353
354
355 } else {
356 if (synchronous) {
357 struct snd_pcm_runtime *first_runtime =
358 ssi_private->first_stream->runtime;
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 if (!first_runtime->sample_bits) {
379 dev_err(substream->pcm->card->dev,
380 "set sample size in %s stream first\n",
381 substream->stream ==
382 SNDRV_PCM_STREAM_PLAYBACK
383 ? "capture" : "playback");
384 return -EAGAIN;
385 }
386
387 snd_pcm_hw_constraint_minmax(substream->runtime,
388 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
389 first_runtime->sample_bits,
390 first_runtime->sample_bits);
391 }
392
393 ssi_private->second_stream = substream;
394 }
395
396 return 0;
397}
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
413 struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
414{
415 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
416 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
417 unsigned int sample_size =
418 snd_pcm_format_width(params_format(hw_params));
419 u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
420 int enabled = in_be32(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
421
422
423
424
425
426 if (enabled && ssi_private->cpu_dai_drv.symmetric_rates)
427 return 0;
428
429
430
431
432
433
434
435
436
437
438
439
440 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
441 ssi_private->cpu_dai_drv.symmetric_rates)
442 clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
443 else
444 clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
445
446 return 0;
447}
448
449
450
451
452
453
454
455
456
457
458static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
459 struct snd_soc_dai *dai)
460{
461 struct snd_soc_pcm_runtime *rtd = substream->private_data;
462 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
463 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
464
465 switch (cmd) {
466 case SNDRV_PCM_TRIGGER_START:
467 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
468 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
469 setbits32(&ssi->scr,
470 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
471 else
472 setbits32(&ssi->scr,
473 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
474 break;
475
476 case SNDRV_PCM_TRIGGER_STOP:
477 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
478 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
479 clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
480 else
481 clrbits32(&ssi->scr, CCSR_SSI_SCR_RE);
482 break;
483
484 default:
485 return -EINVAL;
486 }
487
488 return 0;
489}
490
491
492
493
494
495
496static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
497 struct snd_soc_dai *dai)
498{
499 struct snd_soc_pcm_runtime *rtd = substream->private_data;
500 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
501
502 if (ssi_private->first_stream == substream)
503 ssi_private->first_stream = ssi_private->second_stream;
504
505 ssi_private->second_stream = NULL;
506
507
508
509
510 if (!ssi_private->first_stream) {
511 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
512
513 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
514 }
515}
516
517static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
518 .startup = fsl_ssi_startup,
519 .hw_params = fsl_ssi_hw_params,
520 .shutdown = fsl_ssi_shutdown,
521 .trigger = fsl_ssi_trigger,
522};
523
524
525static struct snd_soc_dai_driver fsl_ssi_dai_template = {
526 .playback = {
527
528 .channels_min = 2,
529 .channels_max = 2,
530 .rates = FSLSSI_I2S_RATES,
531 .formats = FSLSSI_I2S_FORMATS,
532 },
533 .capture = {
534 .channels_min = 2,
535 .channels_max = 2,
536 .rates = FSLSSI_I2S_RATES,
537 .formats = FSLSSI_I2S_FORMATS,
538 },
539 .ops = &fsl_ssi_dai_ops,
540};
541
542
543
544
545
546#define SIER_SHOW(flag, name) \
547 do { \
548 if (SIER_FLAGS & CCSR_SSI_SIER_##flag) \
549 length += sprintf(buf + length, #name "=%u\n", \
550 ssi_private->stats.name); \
551 } while (0)
552
553
554
555
556
557
558
559
560static ssize_t fsl_sysfs_ssi_show(struct device *dev,
561 struct device_attribute *attr, char *buf)
562{
563 struct fsl_ssi_private *ssi_private =
564 container_of(attr, struct fsl_ssi_private, dev_attr);
565 ssize_t length = 0;
566
567 SIER_SHOW(RFRC_EN, rfrc);
568 SIER_SHOW(TFRC_EN, tfrc);
569 SIER_SHOW(CMDAU_EN, cmdau);
570 SIER_SHOW(CMDDU_EN, cmddu);
571 SIER_SHOW(RXT_EN, rxt);
572 SIER_SHOW(RDR1_EN, rdr1);
573 SIER_SHOW(RDR0_EN, rdr0);
574 SIER_SHOW(TDE1_EN, tde1);
575 SIER_SHOW(TDE0_EN, tde0);
576 SIER_SHOW(ROE1_EN, roe1);
577 SIER_SHOW(ROE0_EN, roe0);
578 SIER_SHOW(TUE1_EN, tue1);
579 SIER_SHOW(TUE0_EN, tue0);
580 SIER_SHOW(TFS_EN, tfs);
581 SIER_SHOW(RFS_EN, rfs);
582 SIER_SHOW(TLS_EN, tls);
583 SIER_SHOW(RLS_EN, rls);
584 SIER_SHOW(RFF1_EN, rff1);
585 SIER_SHOW(RFF0_EN, rff0);
586 SIER_SHOW(TFE1_EN, tfe1);
587 SIER_SHOW(TFE0_EN, tfe0);
588
589 return length;
590}
591
592
593
594
595static void make_lowercase(char *s)
596{
597 char *p = s;
598 char c;
599
600 while ((c = *p)) {
601 if ((c >= 'A') && (c <= 'Z'))
602 *p = c + ('a' - 'A');
603 p++;
604 }
605}
606
607static int __devinit fsl_ssi_probe(struct platform_device *pdev)
608{
609 struct fsl_ssi_private *ssi_private;
610 int ret = 0;
611 struct device_attribute *dev_attr = NULL;
612 struct device_node *np = pdev->dev.of_node;
613 const char *p, *sprop;
614 const uint32_t *iprop;
615 struct resource res;
616 char name[64];
617
618
619
620
621
622 if (!of_device_is_available(np))
623 return -ENODEV;
624
625
626 if (!of_get_property(np, "codec-handle", NULL)) {
627 dev_err(&pdev->dev, "missing codec-handle property\n");
628 return -ENODEV;
629 }
630
631
632 sprop = of_get_property(np, "fsl,mode", NULL);
633 if (!sprop || strcmp(sprop, "i2s-slave")) {
634 dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
635 return -ENODEV;
636 }
637
638
639 p = strrchr(np->full_name, '/') + 1;
640 ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
641 GFP_KERNEL);
642 if (!ssi_private) {
643 dev_err(&pdev->dev, "could not allocate DAI object\n");
644 return -ENOMEM;
645 }
646
647 strcpy(ssi_private->name, p);
648
649
650 memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
651 sizeof(fsl_ssi_dai_template));
652 ssi_private->cpu_dai_drv.name = ssi_private->name;
653
654
655 ret = of_address_to_resource(np, 0, &res);
656 if (ret) {
657 dev_err(&pdev->dev, "could not determine device resources\n");
658 goto error_kmalloc;
659 }
660 ssi_private->ssi = of_iomap(np, 0);
661 if (!ssi_private->ssi) {
662 dev_err(&pdev->dev, "could not map device resources\n");
663 ret = -ENOMEM;
664 goto error_kmalloc;
665 }
666 ssi_private->ssi_phys = res.start;
667
668 ssi_private->irq = irq_of_parse_and_map(np, 0);
669 if (ssi_private->irq == NO_IRQ) {
670 dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
671 ret = -ENXIO;
672 goto error_iomap;
673 }
674
675
676 ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, ssi_private->name,
677 ssi_private);
678 if (ret < 0) {
679 dev_err(&pdev->dev, "could not claim irq %u\n", ssi_private->irq);
680 goto error_irqmap;
681 }
682
683
684 if (!of_find_property(np, "fsl,ssi-asynchronous", NULL))
685 ssi_private->cpu_dai_drv.symmetric_rates = 1;
686
687
688 iprop = of_get_property(np, "fsl,fifo-depth", NULL);
689 if (iprop)
690 ssi_private->fifo_depth = be32_to_cpup(iprop);
691 else
692
693 ssi_private->fifo_depth = 8;
694
695
696 dev_attr = &ssi_private->dev_attr;
697 sysfs_attr_init(&dev_attr->attr);
698 dev_attr->attr.name = "statistics";
699 dev_attr->attr.mode = S_IRUGO;
700 dev_attr->show = fsl_sysfs_ssi_show;
701
702 ret = device_create_file(&pdev->dev, dev_attr);
703 if (ret) {
704 dev_err(&pdev->dev, "could not create sysfs %s file\n",
705 ssi_private->dev_attr.attr.name);
706 goto error_irq;
707 }
708
709
710 dev_set_drvdata(&pdev->dev, ssi_private);
711
712 ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
713 if (ret) {
714 dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
715 goto error_dev;
716 }
717
718
719
720
721
722
723 sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
724
725 p = strrchr(sprop, ',');
726 if (p)
727 sprop = p + 1;
728 snprintf(name, sizeof(name), "snd-soc-%s", sprop);
729 make_lowercase(name);
730
731 ssi_private->pdev =
732 platform_device_register_data(&pdev->dev, name, 0, NULL, 0);
733 if (IS_ERR(ssi_private->pdev)) {
734 ret = PTR_ERR(ssi_private->pdev);
735 dev_err(&pdev->dev, "failed to register platform: %d\n", ret);
736 goto error_dai;
737 }
738
739 return 0;
740
741error_dai:
742 snd_soc_unregister_dai(&pdev->dev);
743
744error_dev:
745 dev_set_drvdata(&pdev->dev, NULL);
746 device_remove_file(&pdev->dev, dev_attr);
747
748error_irq:
749 free_irq(ssi_private->irq, ssi_private);
750
751error_irqmap:
752 irq_dispose_mapping(ssi_private->irq);
753
754error_iomap:
755 iounmap(ssi_private->ssi);
756
757error_kmalloc:
758 kfree(ssi_private);
759
760 return ret;
761}
762
763static int fsl_ssi_remove(struct platform_device *pdev)
764{
765 struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
766
767 platform_device_unregister(ssi_private->pdev);
768 snd_soc_unregister_dai(&pdev->dev);
769 device_remove_file(&pdev->dev, &ssi_private->dev_attr);
770
771 free_irq(ssi_private->irq, ssi_private);
772 irq_dispose_mapping(ssi_private->irq);
773
774 kfree(ssi_private);
775 dev_set_drvdata(&pdev->dev, NULL);
776
777 return 0;
778}
779
780static const struct of_device_id fsl_ssi_ids[] = {
781 { .compatible = "fsl,mpc8610-ssi", },
782 {}
783};
784MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
785
786static struct platform_driver fsl_ssi_driver = {
787 .driver = {
788 .name = "fsl-ssi-dai",
789 .owner = THIS_MODULE,
790 .of_match_table = fsl_ssi_ids,
791 },
792 .probe = fsl_ssi_probe,
793 .remove = fsl_ssi_remove,
794};
795
796static int __init fsl_ssi_init(void)
797{
798 printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
799
800 return platform_driver_register(&fsl_ssi_driver);
801}
802
803static void __exit fsl_ssi_exit(void)
804{
805 platform_driver_unregister(&fsl_ssi_driver);
806}
807
808module_init(fsl_ssi_init);
809module_exit(fsl_ssi_exit);
810
811MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
812MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
813MODULE_LICENSE("GPL v2");
814