diff options
author | Timur Tabi <timur@freescale.com> | 2009-01-23 17:31:19 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-01-23 18:00:39 -0500 |
commit | 0db4d0705260dd4bddf1e5a5441c58bdf08bdc9f (patch) | |
tree | 573e721a97a56d3ca923436393a1435d3d5ef159 | |
parent | 070504ade7a95a0f4395673717f3bb7d41793ca8 (diff) |
ASoC: improve I2C initialization code in CS4270 driver
Further improvements in the I2C initialization sequence of the CS4270 driver.
All ASoC initialization is now done in the I2C probe function.
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/cs4270.c | 252 |
1 files changed, 113 insertions, 139 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index e2130d7b1e41..2aa12fdbd2ca 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -31,12 +31,6 @@ | |||
31 | 31 | ||
32 | #include "cs4270.h" | 32 | #include "cs4270.h" |
33 | 33 | ||
34 | /* Private data for the CS4270 */ | ||
35 | struct cs4270_private { | ||
36 | unsigned int mclk; /* Input frequency of the MCLK pin */ | ||
37 | unsigned int mode; /* The mode (I2S or left-justified) */ | ||
38 | }; | ||
39 | |||
40 | /* | 34 | /* |
41 | * The codec isn't really big-endian or little-endian, since the I2S | 35 | * The codec isn't really big-endian or little-endian, since the I2S |
42 | * interface requires data to be sent serially with the MSbit first. | 36 | * interface requires data to be sent serially with the MSbit first. |
@@ -109,6 +103,14 @@ struct cs4270_private { | |||
109 | #define CS4270_MUTE_DAC_A 0x01 | 103 | #define CS4270_MUTE_DAC_A 0x01 |
110 | #define CS4270_MUTE_DAC_B 0x02 | 104 | #define CS4270_MUTE_DAC_B 0x02 |
111 | 105 | ||
106 | /* Private data for the CS4270 */ | ||
107 | struct cs4270_private { | ||
108 | struct snd_soc_codec codec; | ||
109 | u8 reg_cache[CS4270_NUMREGS]; | ||
110 | unsigned int mclk; /* Input frequency of the MCLK pin */ | ||
111 | unsigned int mode; /* The mode (I2S or left-justified) */ | ||
112 | }; | ||
113 | |||
112 | /* | 114 | /* |
113 | * Clock Ratio Selection for Master Mode with I2C enabled | 115 | * Clock Ratio Selection for Master Mode with I2C enabled |
114 | * | 116 | * |
@@ -504,6 +506,31 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = { | |||
504 | */ | 506 | */ |
505 | static struct snd_soc_device *cs4270_socdev; | 507 | static struct snd_soc_device *cs4270_socdev; |
506 | 508 | ||
509 | struct snd_soc_dai cs4270_dai = { | ||
510 | .name = "cs4270", | ||
511 | .playback = { | ||
512 | .stream_name = "Playback", | ||
513 | .channels_min = 1, | ||
514 | .channels_max = 2, | ||
515 | .rates = 0, | ||
516 | .formats = CS4270_FORMATS, | ||
517 | }, | ||
518 | .capture = { | ||
519 | .stream_name = "Capture", | ||
520 | .channels_min = 1, | ||
521 | .channels_max = 2, | ||
522 | .rates = 0, | ||
523 | .formats = CS4270_FORMATS, | ||
524 | }, | ||
525 | .ops = { | ||
526 | .hw_params = cs4270_hw_params, | ||
527 | .set_sysclk = cs4270_set_dai_sysclk, | ||
528 | .set_fmt = cs4270_set_dai_fmt, | ||
529 | .digital_mute = cs4270_mute, | ||
530 | }, | ||
531 | }; | ||
532 | EXPORT_SYMBOL_GPL(cs4270_dai); | ||
533 | |||
507 | /* | 534 | /* |
508 | * Initialize the I2C interface of the CS4270 | 535 | * Initialize the I2C interface of the CS4270 |
509 | * | 536 | * |
@@ -517,47 +544,52 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, | |||
517 | const struct i2c_device_id *id) | 544 | const struct i2c_device_id *id) |
518 | { | 545 | { |
519 | struct snd_soc_device *socdev = cs4270_socdev; | 546 | struct snd_soc_device *socdev = cs4270_socdev; |
520 | struct snd_soc_codec *codec = socdev->codec; | 547 | struct snd_soc_codec *codec; |
548 | struct cs4270_private *cs4270; | ||
521 | int i; | 549 | int i; |
522 | int ret = 0; | 550 | int ret = 0; |
523 | 551 | ||
524 | /* Probing all possible addresses has one drawback: if there are | ||
525 | multiple CS4270s on the bus, then you cannot specify which | ||
526 | socdev is matched with which CS4270. For now, we just reject | ||
527 | this I2C device if the socdev already has one attached. */ | ||
528 | if (codec->control_data) | ||
529 | return -ENODEV; | ||
530 | |||
531 | /* Note: codec_dai->codec is NULL here */ | ||
532 | |||
533 | codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL); | ||
534 | if (!codec->reg_cache) { | ||
535 | printk(KERN_ERR "cs4270: could not allocate register cache\n"); | ||
536 | ret = -ENOMEM; | ||
537 | goto error; | ||
538 | } | ||
539 | |||
540 | /* Verify that we have a CS4270 */ | 552 | /* Verify that we have a CS4270 */ |
541 | 553 | ||
542 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); | 554 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); |
543 | if (ret < 0) { | 555 | if (ret < 0) { |
544 | printk(KERN_ERR "cs4270: failed to read I2C\n"); | 556 | printk(KERN_ERR "cs4270: failed to read I2C\n"); |
545 | goto error; | 557 | return ret; |
546 | } | 558 | } |
547 | /* The top four bits of the chip ID should be 1100. */ | 559 | /* The top four bits of the chip ID should be 1100. */ |
548 | if ((ret & 0xF0) != 0xC0) { | 560 | if ((ret & 0xF0) != 0xC0) { |
549 | /* The device at this address is not a CS4270 codec */ | 561 | printk(KERN_ERR "cs4270: device at addr %X is not a CS4270\n", |
550 | ret = -ENODEV; | 562 | i2c_client->addr); |
551 | goto error; | 563 | return -ENODEV; |
552 | } | 564 | } |
553 | 565 | ||
554 | printk(KERN_INFO "cs4270: found device at I2C address %X\n", | 566 | printk(KERN_INFO "cs4270: found device at I2C address %X\n", |
555 | i2c_client->addr); | 567 | i2c_client->addr); |
556 | printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); | 568 | printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); |
557 | 569 | ||
570 | /* Allocate enough space for the snd_soc_codec structure | ||
571 | and our private data together. */ | ||
572 | cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL); | ||
573 | if (!cs4270) { | ||
574 | printk(KERN_ERR "cs4270: Could not allocate codec structure\n"); | ||
575 | return -ENOMEM; | ||
576 | } | ||
577 | codec = &cs4270->codec; | ||
578 | socdev->codec = codec; | ||
579 | |||
580 | mutex_init(&codec->mutex); | ||
581 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
582 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
583 | |||
584 | codec->name = "CS4270"; | ||
585 | codec->owner = THIS_MODULE; | ||
586 | codec->dai = &cs4270_dai; | ||
587 | codec->num_dai = 1; | ||
588 | codec->private_data = cs4270; | ||
558 | codec->control_data = i2c_client; | 589 | codec->control_data = i2c_client; |
559 | codec->read = cs4270_read_reg_cache; | 590 | codec->read = cs4270_read_reg_cache; |
560 | codec->write = cs4270_i2c_write; | 591 | codec->write = cs4270_i2c_write; |
592 | codec->reg_cache = cs4270->reg_cache; | ||
561 | codec->reg_cache_size = CS4270_NUMREGS; | 593 | codec->reg_cache_size = CS4270_NUMREGS; |
562 | 594 | ||
563 | /* The I2C interface is set up, so pre-fill our register cache */ | 595 | /* The I2C interface is set up, so pre-fill our register cache */ |
@@ -565,35 +597,72 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, | |||
565 | ret = cs4270_fill_cache(codec); | 597 | ret = cs4270_fill_cache(codec); |
566 | if (ret < 0) { | 598 | if (ret < 0) { |
567 | printk(KERN_ERR "cs4270: failed to fill register cache\n"); | 599 | printk(KERN_ERR "cs4270: failed to fill register cache\n"); |
568 | goto error; | 600 | goto error_free_codec; |
601 | } | ||
602 | |||
603 | /* Register PCMs */ | ||
604 | |||
605 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
606 | if (ret < 0) { | ||
607 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); | ||
608 | goto error_free_codec; | ||
569 | } | 609 | } |
570 | 610 | ||
571 | /* Add the non-DAPM controls */ | 611 | /* Add the non-DAPM controls */ |
572 | 612 | ||
573 | for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) { | 613 | for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) { |
574 | struct snd_kcontrol *kctrl = | 614 | struct snd_kcontrol *kctrl; |
575 | snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL); | 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 | } | ||
576 | 623 | ||
577 | ret = snd_ctl_add(codec->card, kctrl); | 624 | ret = snd_ctl_add(codec->card, kctrl); |
578 | if (ret < 0) | 625 | if (ret < 0) { |
579 | goto error; | 626 | printk(KERN_ERR "cs4270: error adding control '%s'\n", |
627 | cs4270_snd_controls[i].name); | ||
628 | goto error_free_pcms; | ||
629 | } | ||
580 | } | 630 | } |
581 | 631 | ||
582 | i2c_set_clientdata(i2c_client, codec); | 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); | ||
583 | 641 | ||
584 | return 0; | 642 | return 0; |
585 | 643 | ||
586 | error: | 644 | error_free_pcms: |
587 | codec->control_data = NULL; | 645 | snd_soc_free_pcms(socdev); |
588 | 646 | ||
589 | kfree(codec->reg_cache); | 647 | error_free_codec: |
590 | codec->reg_cache = NULL; | 648 | kfree(cs4270); |
591 | codec->reg_cache_size = 0; | ||
592 | 649 | ||
593 | return ret; | 650 | return ret; |
594 | } | 651 | } |
595 | 652 | ||
596 | static const struct i2c_device_id cs4270_id[] = { | 653 | static int cs4270_i2c_remove(struct i2c_client *i2c_client) |
654 | { | ||
655 | struct snd_soc_device *socdev = i2c_get_clientdata(i2c_client); | ||
656 | struct snd_soc_codec *codec = socdev->codec; | ||
657 | struct cs4270_private *cs4270 = codec->private_data; | ||
658 | |||
659 | snd_soc_free_pcms(socdev); | ||
660 | kfree(cs4270); | ||
661 | |||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | static struct i2c_device_id cs4270_id[] = { | ||
597 | {"cs4270", 0}, | 666 | {"cs4270", 0}, |
598 | {} | 667 | {} |
599 | }; | 668 | }; |
@@ -606,27 +675,9 @@ static struct i2c_driver cs4270_i2c_driver = { | |||
606 | }, | 675 | }, |
607 | .id_table = cs4270_id, | 676 | .id_table = cs4270_id, |
608 | .probe = cs4270_i2c_probe, | 677 | .probe = cs4270_i2c_probe, |
678 | .remove = cs4270_i2c_remove, | ||
609 | }; | 679 | }; |
610 | 680 | ||
611 | struct snd_soc_dai cs4270_dai = { | ||
612 | .name = "CS4270", | ||
613 | .playback = { | ||
614 | .stream_name = "Playback", | ||
615 | .channels_min = 1, | ||
616 | .channels_max = 2, | ||
617 | .rates = 0, | ||
618 | .formats = CS4270_FORMATS, | ||
619 | }, | ||
620 | .capture = { | ||
621 | .stream_name = "Capture", | ||
622 | .channels_min = 1, | ||
623 | .channels_max = 2, | ||
624 | .rates = 0, | ||
625 | .formats = CS4270_FORMATS, | ||
626 | }, | ||
627 | }; | ||
628 | EXPORT_SYMBOL_GPL(cs4270_dai); | ||
629 | |||
630 | /* | 681 | /* |
631 | * ASoC probe function | 682 | * ASoC probe function |
632 | * | 683 | * |
@@ -635,94 +686,15 @@ EXPORT_SYMBOL_GPL(cs4270_dai); | |||
635 | */ | 686 | */ |
636 | static int cs4270_probe(struct platform_device *pdev) | 687 | static int cs4270_probe(struct platform_device *pdev) |
637 | { | 688 | { |
638 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 689 | cs4270_socdev = platform_get_drvdata(pdev);; |
639 | struct snd_soc_codec *codec; | ||
640 | int ret = 0; | ||
641 | |||
642 | printk(KERN_INFO "CS4270 ALSA SoC Codec\n"); | ||
643 | |||
644 | /* Allocate enough space for the snd_soc_codec structure | ||
645 | and our private data together. */ | ||
646 | codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) + | ||
647 | sizeof(struct cs4270_private), GFP_KERNEL); | ||
648 | if (!codec) { | ||
649 | printk(KERN_ERR "cs4270: Could not allocate codec structure\n"); | ||
650 | return -ENOMEM; | ||
651 | } | ||
652 | |||
653 | mutex_init(&codec->mutex); | ||
654 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
655 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
656 | |||
657 | codec->name = "CS4270"; | ||
658 | codec->owner = THIS_MODULE; | ||
659 | codec->dai = &cs4270_dai; | ||
660 | codec->num_dai = 1; | ||
661 | codec->private_data = (void *) codec + | ||
662 | ALIGN(sizeof(struct snd_soc_codec), 4); | ||
663 | |||
664 | socdev->codec = codec; | ||
665 | |||
666 | /* Register PCMs */ | ||
667 | |||
668 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
669 | if (ret < 0) { | ||
670 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); | ||
671 | goto error_free_codec; | ||
672 | } | ||
673 | |||
674 | cs4270_socdev = socdev; | ||
675 | |||
676 | ret = i2c_add_driver(&cs4270_i2c_driver); | ||
677 | if (ret) { | ||
678 | printk(KERN_ERR "cs4270: failed to attach driver"); | ||
679 | goto error_free_pcms; | ||
680 | } | ||
681 | |||
682 | /* Did we find a CS4270 on the I2C bus? */ | ||
683 | if (!codec->control_data) { | ||
684 | printk(KERN_ERR "cs4270: failed to attach driver"); | ||
685 | goto error_del_driver; | ||
686 | } | ||
687 | 690 | ||
688 | /* Initialize codec ops */ | 691 | return i2c_add_driver(&cs4270_i2c_driver); |
689 | cs4270_dai.ops.hw_params = cs4270_hw_params; | ||
690 | cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk; | ||
691 | cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt; | ||
692 | cs4270_dai.ops.digital_mute = cs4270_mute; | ||
693 | |||
694 | ret = snd_soc_init_card(socdev); | ||
695 | if (ret < 0) { | ||
696 | printk(KERN_ERR "cs4270: failed to register card\n"); | ||
697 | goto error_del_driver; | ||
698 | } | ||
699 | |||
700 | return 0; | ||
701 | |||
702 | error_del_driver: | ||
703 | i2c_del_driver(&cs4270_i2c_driver); | ||
704 | |||
705 | error_free_pcms: | ||
706 | snd_soc_free_pcms(socdev); | ||
707 | |||
708 | error_free_codec: | ||
709 | kfree(socdev->codec); | ||
710 | socdev->codec = NULL; | ||
711 | |||
712 | return ret; | ||
713 | } | 692 | } |
714 | 693 | ||
715 | static int cs4270_remove(struct platform_device *pdev) | 694 | static int cs4270_remove(struct platform_device *pdev) |
716 | { | 695 | { |
717 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
718 | |||
719 | snd_soc_free_pcms(socdev); | ||
720 | |||
721 | i2c_del_driver(&cs4270_i2c_driver); | 696 | i2c_del_driver(&cs4270_i2c_driver); |
722 | 697 | ||
723 | kfree(socdev->codec); | ||
724 | socdev->codec = NULL; | ||
725 | |||
726 | return 0; | 698 | return 0; |
727 | } | 699 | } |
728 | 700 | ||
@@ -740,6 +712,8 @@ EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); | |||
740 | 712 | ||
741 | static int __init cs4270_init(void) | 713 | static int __init cs4270_init(void) |
742 | { | 714 | { |
715 | printk(KERN_INFO "Cirrus Logic CS4270 ALSA SoC Codec Driver\n"); | ||
716 | |||
743 | return snd_soc_register_dai(&cs4270_dai); | 717 | return snd_soc_register_dai(&cs4270_dai); |
744 | } | 718 | } |
745 | module_init(cs4270_init); | 719 | module_init(cs4270_init); |