diff options
Diffstat (limited to 'sound/soc/fsl/fsl_ssi.c')
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 249 |
1 files changed, 146 insertions, 103 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 762c1b8e8e4e..64f65910a7d7 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -3,10 +3,11 @@ | |||
3 | * | 3 | * |
4 | * Author: Timur Tabi <timur@freescale.com> | 4 | * Author: Timur Tabi <timur@freescale.com> |
5 | * | 5 | * |
6 | * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed | 6 | * Copyright 2007-2010 Freescale Semiconductor, Inc. |
7 | * under the terms of the GNU General Public License version 2. This | 7 | * |
8 | * program is licensed "as is" without any warranty of any kind, whether | 8 | * This file is licensed under the terms of the GNU General Public License |
9 | * express or implied. | 9 | * version 2. This program is licensed "as is" without any warranty of any |
10 | * kind, whether express or implied. | ||
10 | */ | 11 | */ |
11 | 12 | ||
12 | #include <linux/init.h> | 13 | #include <linux/init.h> |
@@ -15,6 +16,7 @@ | |||
15 | #include <linux/device.h> | 16 | #include <linux/device.h> |
16 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/of_platform.h> | ||
18 | 20 | ||
19 | #include <sound/core.h> | 21 | #include <sound/core.h> |
20 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
@@ -71,33 +73,31 @@ | |||
71 | /** | 73 | /** |
72 | * fsl_ssi_private: per-SSI private data | 74 | * fsl_ssi_private: per-SSI private data |
73 | * | 75 | * |
74 | * @name: short name for this device ("SSI0", "SSI1", etc) | ||
75 | * @ssi: pointer to the SSI's registers | 76 | * @ssi: pointer to the SSI's registers |
76 | * @ssi_phys: physical address of the SSI registers | 77 | * @ssi_phys: physical address of the SSI registers |
77 | * @irq: IRQ of this SSI | 78 | * @irq: IRQ of this SSI |
78 | * @first_stream: pointer to the stream that was opened first | 79 | * @first_stream: pointer to the stream that was opened first |
79 | * @second_stream: pointer to second stream | 80 | * @second_stream: pointer to second stream |
80 | * @dev: struct device pointer | ||
81 | * @playback: the number of playback streams opened | 81 | * @playback: the number of playback streams opened |
82 | * @capture: the number of capture streams opened | 82 | * @capture: the number of capture streams opened |
83 | * @asynchronous: 0=synchronous mode, 1=asynchronous mode | 83 | * @asynchronous: 0=synchronous mode, 1=asynchronous mode |
84 | * @cpu_dai: the CPU DAI for this device | 84 | * @cpu_dai: the CPU DAI for this device |
85 | * @dev_attr: the sysfs device attribute structure | 85 | * @dev_attr: the sysfs device attribute structure |
86 | * @stats: SSI statistics | 86 | * @stats: SSI statistics |
87 | * @name: name for this device | ||
87 | */ | 88 | */ |
88 | struct fsl_ssi_private { | 89 | struct fsl_ssi_private { |
89 | char name[8]; | ||
90 | struct ccsr_ssi __iomem *ssi; | 90 | struct ccsr_ssi __iomem *ssi; |
91 | dma_addr_t ssi_phys; | 91 | dma_addr_t ssi_phys; |
92 | unsigned int irq; | 92 | unsigned int irq; |
93 | struct snd_pcm_substream *first_stream; | 93 | struct snd_pcm_substream *first_stream; |
94 | struct snd_pcm_substream *second_stream; | 94 | struct snd_pcm_substream *second_stream; |
95 | struct device *dev; | ||
96 | unsigned int playback; | 95 | unsigned int playback; |
97 | unsigned int capture; | 96 | unsigned int capture; |
98 | int asynchronous; | 97 | int asynchronous; |
99 | struct snd_soc_dai cpu_dai; | 98 | struct snd_soc_dai_driver cpu_dai_drv; |
100 | struct device_attribute dev_attr; | 99 | struct device_attribute dev_attr; |
100 | struct platform_device *pdev; | ||
101 | 101 | ||
102 | struct { | 102 | struct { |
103 | unsigned int rfrc; | 103 | unsigned int rfrc; |
@@ -122,6 +122,8 @@ struct fsl_ssi_private { | |||
122 | unsigned int tfe1; | 122 | unsigned int tfe1; |
123 | unsigned int tfe0; | 123 | unsigned int tfe0; |
124 | } stats; | 124 | } stats; |
125 | |||
126 | char name[1]; | ||
125 | }; | 127 | }; |
126 | 128 | ||
127 | /** | 129 | /** |
@@ -280,7 +282,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
280 | struct snd_soc_dai *dai) | 282 | struct snd_soc_dai *dai) |
281 | { | 283 | { |
282 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 284 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
283 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | 285 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
284 | 286 | ||
285 | /* | 287 | /* |
286 | * If this is the first stream opened, then request the IRQ | 288 | * If this is the first stream opened, then request the IRQ |
@@ -290,6 +292,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
290 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | 292 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
291 | int ret; | 293 | int ret; |
292 | 294 | ||
295 | /* The 'name' should not have any slashes in it. */ | ||
293 | ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, | 296 | ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, |
294 | ssi_private->name, ssi_private); | 297 | ssi_private->name, ssi_private); |
295 | if (ret < 0) { | 298 | if (ret < 0) { |
@@ -422,7 +425,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
422 | static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, | 425 | static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, |
423 | struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai) | 426 | struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai) |
424 | { | 427 | { |
425 | struct fsl_ssi_private *ssi_private = cpu_dai->private_data; | 428 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); |
426 | 429 | ||
427 | if (substream == ssi_private->first_stream) { | 430 | if (substream == ssi_private->first_stream) { |
428 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | 431 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
@@ -458,7 +461,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, | |||
458 | struct snd_soc_dai *dai) | 461 | struct snd_soc_dai *dai) |
459 | { | 462 | { |
460 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 463 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
461 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | 464 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
462 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | 465 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
463 | 466 | ||
464 | switch (cmd) { | 467 | switch (cmd) { |
@@ -497,7 +500,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, | |||
497 | struct snd_soc_dai *dai) | 500 | struct snd_soc_dai *dai) |
498 | { | 501 | { |
499 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 502 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
500 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | 503 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
501 | 504 | ||
502 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 505 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
503 | ssi_private->playback--; | 506 | ssi_private->playback--; |
@@ -523,56 +526,15 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, | |||
523 | } | 526 | } |
524 | } | 527 | } |
525 | 528 | ||
526 | /** | ||
527 | * fsl_ssi_set_sysclk: set the clock frequency and direction | ||
528 | * | ||
529 | * This function is called by the machine driver to tell us what the clock | ||
530 | * frequency and direction are. | ||
531 | * | ||
532 | * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN), | ||
533 | * and we don't care about the frequency. Return an error if the direction | ||
534 | * is not SND_SOC_CLOCK_IN. | ||
535 | * | ||
536 | * @clk_id: reserved, should be zero | ||
537 | * @freq: the frequency of the given clock ID, currently ignored | ||
538 | * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) | ||
539 | */ | ||
540 | static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai, | ||
541 | int clk_id, unsigned int freq, int dir) | ||
542 | { | ||
543 | |||
544 | return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL; | ||
545 | } | ||
546 | |||
547 | /** | ||
548 | * fsl_ssi_set_fmt: set the serial format. | ||
549 | * | ||
550 | * This function is called by the machine driver to tell us what serial | ||
551 | * format to use. | ||
552 | * | ||
553 | * Currently, we only support I2S mode. Return an error if the format is | ||
554 | * not SND_SOC_DAIFMT_I2S. | ||
555 | * | ||
556 | * @format: one of SND_SOC_DAIFMT_xxx | ||
557 | */ | ||
558 | static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) | ||
559 | { | ||
560 | return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; | ||
561 | } | ||
562 | |||
563 | /** | ||
564 | * fsl_ssi_dai_template: template CPU DAI for the SSI | ||
565 | */ | ||
566 | static struct snd_soc_dai_ops fsl_ssi_dai_ops = { | 529 | static struct snd_soc_dai_ops fsl_ssi_dai_ops = { |
567 | .startup = fsl_ssi_startup, | 530 | .startup = fsl_ssi_startup, |
568 | .hw_params = fsl_ssi_hw_params, | 531 | .hw_params = fsl_ssi_hw_params, |
569 | .shutdown = fsl_ssi_shutdown, | 532 | .shutdown = fsl_ssi_shutdown, |
570 | .trigger = fsl_ssi_trigger, | 533 | .trigger = fsl_ssi_trigger, |
571 | .set_sysclk = fsl_ssi_set_sysclk, | ||
572 | .set_fmt = fsl_ssi_set_fmt, | ||
573 | }; | 534 | }; |
574 | 535 | ||
575 | static struct snd_soc_dai fsl_ssi_dai_template = { | 536 | /* Template for the CPU dai driver structure */ |
537 | static struct snd_soc_dai_driver fsl_ssi_dai_template = { | ||
576 | .playback = { | 538 | .playback = { |
577 | /* The SSI does not support monaural audio. */ | 539 | /* The SSI does not support monaural audio. */ |
578 | .channels_min = 2, | 540 | .channels_min = 2, |
@@ -640,95 +602,176 @@ static ssize_t fsl_sysfs_ssi_show(struct device *dev, | |||
640 | } | 602 | } |
641 | 603 | ||
642 | /** | 604 | /** |
643 | * fsl_ssi_create_dai: create a snd_soc_dai structure | 605 | * Make every character in a string lower-case |
644 | * | ||
645 | * This function is called by the machine driver to create a snd_soc_dai | ||
646 | * structure. The function creates an ssi_private object, which contains | ||
647 | * the snd_soc_dai. It also creates the sysfs statistics device. | ||
648 | */ | 606 | */ |
649 | struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | 607 | static void make_lowercase(char *s) |
608 | { | ||
609 | char *p = s; | ||
610 | char c; | ||
611 | |||
612 | while ((c = *p)) { | ||
613 | if ((c >= 'A') && (c <= 'Z')) | ||
614 | *p = c + ('a' - 'A'); | ||
615 | p++; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | static int __devinit fsl_ssi_probe(struct of_device *of_dev, | ||
620 | const struct of_device_id *match) | ||
650 | { | 621 | { |
651 | struct snd_soc_dai *fsl_ssi_dai; | ||
652 | struct fsl_ssi_private *ssi_private; | 622 | struct fsl_ssi_private *ssi_private; |
653 | int ret = 0; | 623 | int ret = 0; |
654 | struct device_attribute *dev_attr; | 624 | struct device_attribute *dev_attr; |
625 | struct device_node *np = of_dev->dev.of_node; | ||
626 | const char *p, *sprop; | ||
627 | struct resource res; | ||
628 | char name[64]; | ||
655 | 629 | ||
656 | ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL); | 630 | /* We are only interested in SSIs with a codec phandle in them, so let's |
631 | * make sure this SSI has one. | ||
632 | */ | ||
633 | if (!of_get_property(np, "codec-handle", NULL)) | ||
634 | return -ENODEV; | ||
635 | |||
636 | /* We only support the SSI in "I2S Slave" mode */ | ||
637 | sprop = of_get_property(np, "fsl,mode", NULL); | ||
638 | if (!sprop || strcmp(sprop, "i2s-slave")) { | ||
639 | dev_notice(&of_dev->dev, "mode %s is unsupported\n", sprop); | ||
640 | return -ENODEV; | ||
641 | } | ||
642 | |||
643 | /* The DAI name is the last part of the full name of the node. */ | ||
644 | p = strrchr(np->full_name, '/') + 1; | ||
645 | ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p), | ||
646 | GFP_KERNEL); | ||
657 | if (!ssi_private) { | 647 | if (!ssi_private) { |
658 | dev_err(ssi_info->dev, "could not allocate DAI object\n"); | 648 | dev_err(&of_dev->dev, "could not allocate DAI object\n"); |
659 | return NULL; | 649 | return -ENOMEM; |
660 | } | 650 | } |
661 | memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template, | ||
662 | sizeof(struct snd_soc_dai)); | ||
663 | 651 | ||
664 | fsl_ssi_dai = &ssi_private->cpu_dai; | 652 | strcpy(ssi_private->name, p); |
665 | dev_attr = &ssi_private->dev_attr; | ||
666 | 653 | ||
667 | sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id); | 654 | /* Initialize this copy of the CPU DAI driver structure */ |
668 | ssi_private->ssi = ssi_info->ssi; | 655 | memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template, |
669 | ssi_private->ssi_phys = ssi_info->ssi_phys; | 656 | sizeof(fsl_ssi_dai_template)); |
670 | ssi_private->irq = ssi_info->irq; | 657 | ssi_private->cpu_dai_drv.name = ssi_private->name; |
671 | ssi_private->dev = ssi_info->dev; | 658 | |
672 | ssi_private->asynchronous = ssi_info->asynchronous; | 659 | /* Get the addresses and IRQ */ |
660 | ret = of_address_to_resource(np, 0, &res); | ||
661 | if (ret) { | ||
662 | dev_err(&of_dev->dev, "could not determine device resources\n"); | ||
663 | kfree(ssi_private); | ||
664 | return ret; | ||
665 | } | ||
666 | ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start); | ||
667 | ssi_private->ssi_phys = res.start; | ||
668 | ssi_private->irq = irq_of_parse_and_map(np, 0); | ||
673 | 669 | ||
674 | dev_set_drvdata(ssi_private->dev, fsl_ssi_dai); | 670 | /* Are the RX and the TX clocks locked? */ |
671 | if (of_find_property(np, "fsl,ssi-asynchronous", NULL)) | ||
672 | ssi_private->asynchronous = 1; | ||
673 | else | ||
674 | ssi_private->cpu_dai_drv.symmetric_rates = 1; | ||
675 | 675 | ||
676 | /* Initialize the the device_attribute structure */ | 676 | /* Initialize the the device_attribute structure */ |
677 | dev_attr->attr.name = "ssi-stats"; | 677 | dev_attr = &ssi_private->dev_attr; |
678 | dev_attr->attr.name = "statistics"; | ||
678 | dev_attr->attr.mode = S_IRUGO; | 679 | dev_attr->attr.mode = S_IRUGO; |
679 | dev_attr->show = fsl_sysfs_ssi_show; | 680 | dev_attr->show = fsl_sysfs_ssi_show; |
680 | 681 | ||
681 | ret = device_create_file(ssi_private->dev, dev_attr); | 682 | ret = device_create_file(&of_dev->dev, dev_attr); |
682 | if (ret) { | 683 | if (ret) { |
683 | dev_err(ssi_info->dev, "could not create sysfs %s file\n", | 684 | dev_err(&of_dev->dev, "could not create sysfs %s file\n", |
684 | ssi_private->dev_attr.attr.name); | 685 | ssi_private->dev_attr.attr.name); |
685 | kfree(fsl_ssi_dai); | 686 | kfree(ssi_private); |
686 | return NULL; | 687 | return ret; |
687 | } | 688 | } |
688 | 689 | ||
689 | fsl_ssi_dai->private_data = ssi_private; | 690 | /* Register with ASoC */ |
690 | fsl_ssi_dai->name = ssi_private->name; | 691 | dev_set_drvdata(&of_dev->dev, ssi_private); |
691 | fsl_ssi_dai->id = ssi_info->id; | ||
692 | fsl_ssi_dai->dev = ssi_info->dev; | ||
693 | fsl_ssi_dai->symmetric_rates = 1; | ||
694 | 692 | ||
695 | ret = snd_soc_register_dai(fsl_ssi_dai); | 693 | ret = snd_soc_register_dai(&of_dev->dev, &ssi_private->cpu_dai_drv); |
696 | if (ret != 0) { | 694 | if (ret != 0) { |
697 | dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret); | 695 | dev_err(&of_dev->dev, "failed to register DAI: %d\n", ret); |
698 | kfree(fsl_ssi_dai); | 696 | kfree(ssi_private); |
699 | return NULL; | 697 | return ret; |
698 | } | ||
699 | |||
700 | /* Trigger the machine driver's probe function. The platform driver | ||
701 | * name of the machine driver is taken from the /model property of the | ||
702 | * device tree. We also pass the address of the CPU DAI driver | ||
703 | * structure. | ||
704 | */ | ||
705 | sprop = of_get_property(of_find_node_by_path("/"), "model", NULL); | ||
706 | /* Sometimes the model name has a "fsl," prefix, so we strip that. */ | ||
707 | p = strrchr(sprop, ','); | ||
708 | if (p) | ||
709 | sprop = p + 1; | ||
710 | snprintf(name, sizeof(name), "snd-soc-%s", sprop); | ||
711 | make_lowercase(name); | ||
712 | |||
713 | ssi_private->pdev = | ||
714 | platform_device_register_data(&of_dev->dev, name, 0, NULL, 0); | ||
715 | if (IS_ERR(ssi_private->pdev)) { | ||
716 | ret = PTR_ERR(ssi_private->pdev); | ||
717 | dev_err(&of_dev->dev, "failed to register platform: %d\n", ret); | ||
718 | kfree(ssi_private); | ||
719 | return ret; | ||
700 | } | 720 | } |
701 | 721 | ||
702 | return fsl_ssi_dai; | 722 | return 0; |
703 | } | 723 | } |
704 | EXPORT_SYMBOL_GPL(fsl_ssi_create_dai); | ||
705 | 724 | ||
706 | /** | 725 | /** |
707 | * fsl_ssi_destroy_dai: destroy the snd_soc_dai object | 726 | * fsl_ssi_destroy_dai: destroy the snd_soc_dai object |
708 | * | 727 | * |
709 | * This function undoes the operations of fsl_ssi_create_dai() | 728 | * This function undoes the operations of fsl_ssi_probe() |
710 | */ | 729 | */ |
711 | void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) | 730 | static int fsl_ssi_remove(struct of_device *of_dev) |
712 | { | 731 | { |
713 | struct fsl_ssi_private *ssi_private = | 732 | struct fsl_ssi_private *ssi_private = dev_get_drvdata(&of_dev->dev); |
714 | container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai); | ||
715 | 733 | ||
716 | device_remove_file(ssi_private->dev, &ssi_private->dev_attr); | 734 | platform_device_unregister(ssi_private->pdev); |
717 | 735 | snd_soc_unregister_dai(&of_dev->dev); | |
718 | snd_soc_unregister_dai(&ssi_private->cpu_dai); | 736 | device_remove_file(&of_dev->dev, &ssi_private->dev_attr); |
719 | 737 | ||
720 | kfree(ssi_private); | 738 | kfree(ssi_private); |
739 | dev_set_drvdata(&of_dev->dev, NULL); | ||
740 | |||
741 | return 0; | ||
721 | } | 742 | } |
722 | EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); | 743 | |
744 | static const struct of_device_id fsl_ssi_ids[] = { | ||
745 | { .compatible = "fsl,mpc8610-ssi", }, | ||
746 | {} | ||
747 | }; | ||
748 | MODULE_DEVICE_TABLE(of, fsl_ssi_ids); | ||
749 | |||
750 | static struct of_platform_driver fsl_ssi_driver = { | ||
751 | .driver = { | ||
752 | .name = "fsl-ssi-dai", | ||
753 | .owner = THIS_MODULE, | ||
754 | .of_match_table = fsl_ssi_ids, | ||
755 | }, | ||
756 | .probe = fsl_ssi_probe, | ||
757 | .remove = fsl_ssi_remove, | ||
758 | }; | ||
723 | 759 | ||
724 | static int __init fsl_ssi_init(void) | 760 | static int __init fsl_ssi_init(void) |
725 | { | 761 | { |
726 | printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n"); | 762 | printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n"); |
727 | 763 | ||
728 | return 0; | 764 | return of_register_platform_driver(&fsl_ssi_driver); |
765 | } | ||
766 | |||
767 | static void __exit fsl_ssi_exit(void) | ||
768 | { | ||
769 | of_unregister_platform_driver(&fsl_ssi_driver); | ||
729 | } | 770 | } |
771 | |||
730 | module_init(fsl_ssi_init); | 772 | module_init(fsl_ssi_init); |
773 | module_exit(fsl_ssi_exit); | ||
731 | 774 | ||
732 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | 775 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); |
733 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); | 776 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); |
734 | MODULE_LICENSE("GPL"); | 777 | MODULE_LICENSE("GPL v2"); |