diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/cs4270.c | 177 |
1 files changed, 97 insertions, 80 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 21253b48289f..adc1150ddb00 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -490,21 +490,17 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = { | |||
490 | }; | 490 | }; |
491 | 491 | ||
492 | /* | 492 | /* |
493 | * Global variable to store socdev for i2c probe function. | 493 | * Global variable to store codec for the ASoC probe function. |
494 | * | 494 | * |
495 | * If struct i2c_driver had a private_data field, we wouldn't need to use | 495 | * If struct i2c_driver had a private_data field, we wouldn't need to use |
496 | * cs4270_socdec. This is the only way to pass the socdev structure to | 496 | * cs4270_codec. This is the only way to pass the codec structure from |
497 | * cs4270_i2c_probe(). | 497 | * cs4270_i2c_probe() to cs4270_probe(). Unfortunately, there is no good |
498 | * | 498 | * way to synchronize these two functions. cs4270_i2c_probe() can be called |
499 | * The real solution to cs4270_socdev is to create a mechanism | 499 | * multiple times before cs4270_probe() is called even once. So for now, we |
500 | * that maps I2C addresses to snd_soc_device structures. Perhaps the | 500 | * also only allow cs4270_i2c_probe() to be run once. That means that we do |
501 | * creation of the snd_soc_device object should be moved out of | 501 | * not support more than one cs4270 device in the system, at least for now. |
502 | * cs4270_probe() and into cs4270_i2c_probe(), but that would make this | ||
503 | * driver dependent on I2C. The CS4270 supports "stand-alone" mode, whereby | ||
504 | * the chip is *not* connected to the I2C bus, but is instead configured via | ||
505 | * input pins. | ||
506 | */ | 502 | */ |
507 | static struct snd_soc_device *cs4270_socdev; | 503 | static struct snd_soc_codec *cs4270_codec; |
508 | 504 | ||
509 | struct snd_soc_dai cs4270_dai = { | 505 | struct snd_soc_dai cs4270_dai = { |
510 | .name = "cs4270", | 506 | .name = "cs4270", |
@@ -532,6 +528,70 @@ struct snd_soc_dai cs4270_dai = { | |||
532 | EXPORT_SYMBOL_GPL(cs4270_dai); | 528 | EXPORT_SYMBOL_GPL(cs4270_dai); |
533 | 529 | ||
534 | /* | 530 | /* |
531 | * ASoC probe function | ||
532 | */ | ||
533 | static int cs4270_probe(struct platform_device *pdev) | ||
534 | { | ||
535 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
536 | struct snd_soc_codec *codec = cs4270_codec; | ||
537 | unsigned int i; | ||
538 | int ret; | ||
539 | |||
540 | /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ | ||
541 | socdev->card->codec = codec; | ||
542 | |||
543 | /* Register PCMs */ | ||
544 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
545 | if (ret < 0) { | ||
546 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); | ||
547 | return ret; | ||
548 | } | ||
549 | |||
550 | /* Add the non-DAPM controls */ | ||
551 | for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) { | ||
552 | struct snd_kcontrol *kctrl; | ||
553 | |||
554 | kctrl = snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL); | ||
555 | if (!kctrl) { | ||
556 | printk(KERN_ERR "cs4270: error creating control '%s'\n", | ||
557 | cs4270_snd_controls[i].name); | ||
558 | ret = -ENOMEM; | ||
559 | goto error_free_pcms; | ||
560 | } | ||
561 | |||
562 | ret = snd_ctl_add(codec->card, kctrl); | ||
563 | if (ret < 0) { | ||
564 | printk(KERN_ERR "cs4270: error adding control '%s'\n", | ||
565 | cs4270_snd_controls[i].name); | ||
566 | goto error_free_pcms; | ||
567 | } | ||
568 | } | ||
569 | |||
570 | /* And finally, register the socdev */ | ||
571 | ret = snd_soc_init_card(socdev); | ||
572 | if (ret < 0) { | ||
573 | printk(KERN_ERR "cs4270: failed to register card\n"); | ||
574 | goto error_free_pcms; | ||
575 | } | ||
576 | |||
577 | return 0; | ||
578 | |||
579 | error_free_pcms: | ||
580 | snd_soc_free_pcms(socdev); | ||
581 | |||
582 | return ret; | ||
583 | } | ||
584 | |||
585 | static int cs4270_remove(struct platform_device *pdev) | ||
586 | { | ||
587 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
588 | |||
589 | snd_soc_free_pcms(socdev); | ||
590 | |||
591 | return 0; | ||
592 | }; | ||
593 | |||
594 | /* | ||
535 | * Initialize the I2C interface of the CS4270 | 595 | * Initialize the I2C interface of the CS4270 |
536 | * | 596 | * |
537 | * This function is called for whenever the I2C subsystem finds a device | 597 | * This function is called for whenever the I2C subsystem finds a device |
@@ -543,17 +603,27 @@ EXPORT_SYMBOL_GPL(cs4270_dai); | |||
543 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, | 603 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, |
544 | const struct i2c_device_id *id) | 604 | const struct i2c_device_id *id) |
545 | { | 605 | { |
546 | struct snd_soc_device *socdev = cs4270_socdev; | ||
547 | struct snd_soc_codec *codec; | 606 | struct snd_soc_codec *codec; |
548 | struct cs4270_private *cs4270; | 607 | struct cs4270_private *cs4270; |
549 | int i; | 608 | int ret; |
550 | int ret = 0; | 609 | |
610 | /* For now, we only support one cs4270 device in the system. See the | ||
611 | * comment for cs4270_codec. | ||
612 | */ | ||
613 | if (cs4270_codec) { | ||
614 | printk(KERN_ERR "cs4270: ignoring CS4270 at addr %X\n", | ||
615 | i2c_client->addr); | ||
616 | printk(KERN_ERR "cs4270: only one CS4270 per board allowed\n"); | ||
617 | /* Should we return something other than ENODEV here? */ | ||
618 | return -ENODEV; | ||
619 | } | ||
551 | 620 | ||
552 | /* Verify that we have a CS4270 */ | 621 | /* Verify that we have a CS4270 */ |
553 | 622 | ||
554 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); | 623 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); |
555 | if (ret < 0) { | 624 | if (ret < 0) { |
556 | printk(KERN_ERR "cs4270: failed to read I2C\n"); | 625 | printk(KERN_ERR "cs4270: failed to read I2C at addr %X\n", |
626 | i2c_client->addr); | ||
557 | return ret; | 627 | return ret; |
558 | } | 628 | } |
559 | /* The top four bits of the chip ID should be 1100. */ | 629 | /* The top four bits of the chip ID should be 1100. */ |
@@ -575,7 +645,7 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, | |||
575 | return -ENOMEM; | 645 | return -ENOMEM; |
576 | } | 646 | } |
577 | codec = &cs4270->codec; | 647 | codec = &cs4270->codec; |
578 | socdev->card->codec = codec; | 648 | cs4270_codec = codec; |
579 | 649 | ||
580 | mutex_init(&codec->mutex); | 650 | mutex_init(&codec->mutex); |
581 | INIT_LIST_HEAD(&codec->dapm_widgets); | 651 | INIT_LIST_HEAD(&codec->dapm_widgets); |
@@ -600,50 +670,20 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, | |||
600 | goto error_free_codec; | 670 | goto error_free_codec; |
601 | } | 671 | } |
602 | 672 | ||
603 | /* Register PCMs */ | 673 | /* Register the DAI. If all the other ASoC driver have already |
604 | 674 | * registered, then this will call our probe function, so | |
605 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 675 | * cs4270_codec needs to be ready. |
676 | */ | ||
677 | ret = snd_soc_register_dai(&cs4270_dai); | ||
606 | if (ret < 0) { | 678 | if (ret < 0) { |
607 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); | 679 | printk(KERN_ERR "cs4270: failed to register DAIe\n"); |
608 | goto error_free_codec; | 680 | goto error_free_codec; |
609 | } | 681 | } |
610 | 682 | ||
611 | /* Add the non-DAPM controls */ | 683 | i2c_set_clientdata(i2c_client, cs4270); |
612 | |||
613 | for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) { | ||
614 | struct snd_kcontrol *kctrl; | ||
615 | |||
616 | kctrl = snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL); | ||
617 | if (!kctrl) { | ||
618 | printk(KERN_ERR "cs4270: error creating control '%s'\n", | ||
619 | cs4270_snd_controls[i].name); | ||
620 | ret = -ENOMEM; | ||
621 | goto error_free_pcms; | ||
622 | } | ||
623 | |||
624 | ret = snd_ctl_add(codec->card, kctrl); | ||
625 | if (ret < 0) { | ||
626 | printk(KERN_ERR "cs4270: error adding control '%s'\n", | ||
627 | cs4270_snd_controls[i].name); | ||
628 | goto error_free_pcms; | ||
629 | } | ||
630 | } | ||
631 | |||
632 | /* Initialize the SOC device */ | ||
633 | |||
634 | ret = snd_soc_init_card(socdev); | ||
635 | if (ret < 0) { | ||
636 | printk(KERN_ERR "cs4270: failed to register card\n"); | ||
637 | goto error_free_pcms;; | ||
638 | } | ||
639 | |||
640 | i2c_set_clientdata(i2c_client, socdev); | ||
641 | 684 | ||
642 | return 0; | 685 | return 0; |
643 | 686 | ||
644 | error_free_pcms: | ||
645 | snd_soc_free_pcms(socdev); | ||
646 | |||
647 | error_free_codec: | 687 | error_free_codec: |
648 | kfree(cs4270); | 688 | kfree(cs4270); |
649 | 689 | ||
@@ -652,11 +692,8 @@ error_free_codec: | |||
652 | 692 | ||
653 | static int cs4270_i2c_remove(struct i2c_client *i2c_client) | 693 | static int cs4270_i2c_remove(struct i2c_client *i2c_client) |
654 | { | 694 | { |
655 | struct snd_soc_device *socdev = i2c_get_clientdata(i2c_client); | 695 | struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client); |
656 | struct snd_soc_codec *codec = socdev->card->codec; | ||
657 | struct cs4270_private *cs4270 = codec->private_data; | ||
658 | 696 | ||
659 | snd_soc_free_pcms(socdev); | ||
660 | kfree(cs4270); | 697 | kfree(cs4270); |
661 | 698 | ||
662 | return 0; | 699 | return 0; |
@@ -679,26 +716,6 @@ static struct i2c_driver cs4270_i2c_driver = { | |||
679 | }; | 716 | }; |
680 | 717 | ||
681 | /* | 718 | /* |
682 | * ASoC probe function | ||
683 | * | ||
684 | * This function is called when the machine driver calls | ||
685 | * platform_device_add(). | ||
686 | */ | ||
687 | static int cs4270_probe(struct platform_device *pdev) | ||
688 | { | ||
689 | cs4270_socdev = platform_get_drvdata(pdev);; | ||
690 | |||
691 | return i2c_add_driver(&cs4270_i2c_driver); | ||
692 | } | ||
693 | |||
694 | static int cs4270_remove(struct platform_device *pdev) | ||
695 | { | ||
696 | i2c_del_driver(&cs4270_i2c_driver); | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | /* | ||
702 | * ASoC codec device structure | 719 | * ASoC codec device structure |
703 | * | 720 | * |
704 | * Assign this variable to the codec_dev field of the machine driver's | 721 | * Assign this variable to the codec_dev field of the machine driver's |
@@ -714,13 +731,13 @@ static int __init cs4270_init(void) | |||
714 | { | 731 | { |
715 | printk(KERN_INFO "Cirrus Logic CS4270 ALSA SoC Codec Driver\n"); | 732 | printk(KERN_INFO "Cirrus Logic CS4270 ALSA SoC Codec Driver\n"); |
716 | 733 | ||
717 | return snd_soc_register_dai(&cs4270_dai); | 734 | return i2c_add_driver(&cs4270_i2c_driver); |
718 | } | 735 | } |
719 | module_init(cs4270_init); | 736 | module_init(cs4270_init); |
720 | 737 | ||
721 | static void __exit cs4270_exit(void) | 738 | static void __exit cs4270_exit(void) |
722 | { | 739 | { |
723 | snd_soc_unregister_dai(&cs4270_dai); | 740 | i2c_del_driver(&cs4270_i2c_driver); |
724 | } | 741 | } |
725 | module_exit(cs4270_exit); | 742 | module_exit(cs4270_exit); |
726 | 743 | ||