diff options
Diffstat (limited to 'sound/soc/codecs/ssm2602.c')
-rw-r--r-- | sound/soc/codecs/ssm2602.c | 219 |
1 files changed, 59 insertions, 160 deletions
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index b47ed4f6ab20..67d8c044ca04 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -45,11 +45,11 @@ | |||
45 | 45 | ||
46 | #define SSM2602_VERSION "0.1" | 46 | #define SSM2602_VERSION "0.1" |
47 | 47 | ||
48 | struct snd_soc_codec_device soc_codec_dev_ssm2602; | ||
49 | |||
50 | /* codec private data */ | 48 | /* codec private data */ |
51 | struct ssm2602_priv { | 49 | struct ssm2602_priv { |
52 | unsigned int sysclk; | 50 | unsigned int sysclk; |
51 | enum snd_soc_control_type control_type; | ||
52 | void *control_data; | ||
53 | struct snd_pcm_substream *master_substream; | 53 | struct snd_pcm_substream *master_substream; |
54 | struct snd_pcm_substream *slave_substream; | 54 | struct snd_pcm_substream *slave_substream; |
55 | }; | 55 | }; |
@@ -276,8 +276,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, | |||
276 | { | 276 | { |
277 | u16 srate; | 277 | u16 srate; |
278 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 278 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
279 | struct snd_soc_device *socdev = rtd->socdev; | 279 | struct snd_soc_codec *codec = rtd->codec; |
280 | struct snd_soc_codec *codec = socdev->card->codec; | ||
281 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 280 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
282 | struct i2c_client *i2c = codec->control_data; | 281 | struct i2c_client *i2c = codec->control_data; |
283 | u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; | 282 | u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; |
@@ -321,8 +320,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, | |||
321 | struct snd_soc_dai *dai) | 320 | struct snd_soc_dai *dai) |
322 | { | 321 | { |
323 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 322 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
324 | struct snd_soc_device *socdev = rtd->socdev; | 323 | struct snd_soc_codec *codec = rtd->codec; |
325 | struct snd_soc_codec *codec = socdev->card->codec; | ||
326 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 324 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
327 | struct i2c_client *i2c = codec->control_data; | 325 | struct i2c_client *i2c = codec->control_data; |
328 | struct snd_pcm_runtime *master_runtime; | 326 | struct snd_pcm_runtime *master_runtime; |
@@ -360,8 +358,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, | |||
360 | struct snd_soc_dai *dai) | 358 | struct snd_soc_dai *dai) |
361 | { | 359 | { |
362 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 360 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
363 | struct snd_soc_device *socdev = rtd->socdev; | 361 | struct snd_soc_codec *codec = rtd->codec; |
364 | struct snd_soc_codec *codec = socdev->card->codec; | ||
365 | /* set active */ | 362 | /* set active */ |
366 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | 363 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); |
367 | 364 | ||
@@ -372,8 +369,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, | |||
372 | struct snd_soc_dai *dai) | 369 | struct snd_soc_dai *dai) |
373 | { | 370 | { |
374 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 371 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
375 | struct snd_soc_device *socdev = rtd->socdev; | 372 | struct snd_soc_codec *codec = rtd->codec; |
376 | struct snd_soc_codec *codec = socdev->card->codec; | ||
377 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 373 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
378 | 374 | ||
379 | /* deactivate */ | 375 | /* deactivate */ |
@@ -518,8 +514,8 @@ static struct snd_soc_dai_ops ssm2602_dai_ops = { | |||
518 | .set_fmt = ssm2602_set_dai_fmt, | 514 | .set_fmt = ssm2602_set_dai_fmt, |
519 | }; | 515 | }; |
520 | 516 | ||
521 | struct snd_soc_dai ssm2602_dai = { | 517 | static struct snd_soc_dai_driver ssm2602_dai = { |
522 | .name = "SSM2602", | 518 | .name = "ssm2602-hifi", |
523 | .playback = { | 519 | .playback = { |
524 | .stream_name = "Playback", | 520 | .stream_name = "Playback", |
525 | .channels_min = 2, | 521 | .channels_min = 2, |
@@ -534,21 +530,15 @@ struct snd_soc_dai ssm2602_dai = { | |||
534 | .formats = SSM2602_FORMATS,}, | 530 | .formats = SSM2602_FORMATS,}, |
535 | .ops = &ssm2602_dai_ops, | 531 | .ops = &ssm2602_dai_ops, |
536 | }; | 532 | }; |
537 | EXPORT_SYMBOL_GPL(ssm2602_dai); | ||
538 | 533 | ||
539 | static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state) | 534 | static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state) |
540 | { | 535 | { |
541 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
542 | struct snd_soc_codec *codec = socdev->card->codec; | ||
543 | |||
544 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | 536 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); |
545 | return 0; | 537 | return 0; |
546 | } | 538 | } |
547 | 539 | ||
548 | static int ssm2602_resume(struct platform_device *pdev) | 540 | static int ssm2602_resume(struct snd_soc_codec *codec) |
549 | { | 541 | { |
550 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
551 | struct snd_soc_codec *codec = socdev->card->codec; | ||
552 | int i; | 542 | int i; |
553 | u8 data[2]; | 543 | u8 data[2]; |
554 | u16 *cache = codec->reg_cache; | 544 | u16 *cache = codec->reg_cache; |
@@ -563,36 +553,18 @@ static int ssm2602_resume(struct platform_device *pdev) | |||
563 | return 0; | 553 | return 0; |
564 | } | 554 | } |
565 | 555 | ||
566 | /* | 556 | static int ssm2602_probe(struct snd_soc_codec *codec) |
567 | * initialise the ssm2602 driver | ||
568 | * register the mixer and dsp interfaces with the kernel | ||
569 | */ | ||
570 | static int ssm2602_init(struct snd_soc_device *socdev) | ||
571 | { | 557 | { |
572 | struct snd_soc_codec *codec = socdev->card->codec; | 558 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
573 | int reg, ret = 0; | 559 | int ret = 0, reg; |
574 | 560 | ||
575 | codec->name = "SSM2602"; | 561 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); |
576 | codec->owner = THIS_MODULE; | 562 | |
577 | codec->read = ssm2602_read_reg_cache; | 563 | codec->bias_level = SND_SOC_BIAS_OFF, |
578 | codec->write = ssm2602_write; | 564 | codec->control_data = ssm2602->control_data; |
579 | codec->set_bias_level = ssm2602_set_bias_level; | ||
580 | codec->dai = &ssm2602_dai; | ||
581 | codec->num_dai = 1; | ||
582 | codec->reg_cache_size = sizeof(ssm2602_reg); | ||
583 | codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg), | ||
584 | GFP_KERNEL); | ||
585 | if (codec->reg_cache == NULL) | ||
586 | return -ENOMEM; | ||
587 | 565 | ||
588 | ssm2602_reset(codec); | 566 | ssm2602_reset(codec); |
589 | 567 | ||
590 | /* register pcms */ | ||
591 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
592 | if (ret < 0) { | ||
593 | pr_err("ssm2602: failed to create pcms\n"); | ||
594 | goto pcm_err; | ||
595 | } | ||
596 | /*power on device*/ | 568 | /*power on device*/ |
597 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | 569 | ssm2602_write(codec, SSM2602_ACTIVE, 0); |
598 | /* set the update bits */ | 570 | /* set the update bits */ |
@@ -614,13 +586,27 @@ static int ssm2602_init(struct snd_soc_device *socdev) | |||
614 | ssm2602_add_widgets(codec); | 586 | ssm2602_add_widgets(codec); |
615 | 587 | ||
616 | return ret; | 588 | return ret; |
589 | } | ||
617 | 590 | ||
618 | pcm_err: | 591 | /* remove everything here */ |
619 | kfree(codec->reg_cache); | 592 | static int ssm2602_remove(struct snd_soc_codec *codec) |
620 | return ret; | 593 | { |
594 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
595 | return 0; | ||
621 | } | 596 | } |
622 | 597 | ||
623 | static struct snd_soc_device *ssm2602_socdev; | 598 | static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { |
599 | .probe = ssm2602_probe, | ||
600 | .remove = ssm2602_remove, | ||
601 | .suspend = ssm2602_suspend, | ||
602 | .resume = ssm2602_resume, | ||
603 | .read = ssm2602_read_reg_cache, | ||
604 | .write = ssm2602_write, | ||
605 | .set_bias_level = ssm2602_set_bias_level, | ||
606 | .reg_cache_size = sizeof(ssm2602_reg), | ||
607 | .reg_word_size = sizeof(u16), | ||
608 | .reg_cache_default = ssm2602_reg, | ||
609 | }; | ||
624 | 610 | ||
625 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 611 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
626 | /* | 612 | /* |
@@ -632,24 +618,28 @@ static struct snd_soc_device *ssm2602_socdev; | |||
632 | static int ssm2602_i2c_probe(struct i2c_client *i2c, | 618 | static int ssm2602_i2c_probe(struct i2c_client *i2c, |
633 | const struct i2c_device_id *id) | 619 | const struct i2c_device_id *id) |
634 | { | 620 | { |
635 | struct snd_soc_device *socdev = ssm2602_socdev; | 621 | struct ssm2602_priv *ssm2602; |
636 | struct snd_soc_codec *codec = socdev->card->codec; | ||
637 | int ret; | 622 | int ret; |
638 | 623 | ||
639 | i2c_set_clientdata(i2c, codec); | 624 | ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL); |
640 | codec->control_data = i2c; | 625 | if (ssm2602 == NULL) |
626 | return -ENOMEM; | ||
641 | 627 | ||
642 | ret = ssm2602_init(socdev); | 628 | i2c_set_clientdata(i2c, ssm2602); |
643 | if (ret < 0) | 629 | ssm2602->control_data = i2c; |
644 | pr_err("failed to initialise SSM2602\n"); | 630 | ssm2602->control_type = SND_SOC_I2C; |
645 | 631 | ||
632 | ret = snd_soc_register_codec(&i2c->dev, | ||
633 | &soc_codec_dev_ssm2602, &ssm2602_dai, 1); | ||
634 | if (ret < 0) | ||
635 | kfree(ssm2602); | ||
646 | return ret; | 636 | return ret; |
647 | } | 637 | } |
648 | 638 | ||
649 | static int ssm2602_i2c_remove(struct i2c_client *client) | 639 | static int ssm2602_i2c_remove(struct i2c_client *client) |
650 | { | 640 | { |
651 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 641 | snd_soc_unregister_codec(&client->dev); |
652 | kfree(codec->reg_cache); | 642 | kfree(i2c_get_clientdata(client)); |
653 | return 0; | 643 | return 0; |
654 | } | 644 | } |
655 | 645 | ||
@@ -658,130 +648,39 @@ static const struct i2c_device_id ssm2602_i2c_id[] = { | |||
658 | { } | 648 | { } |
659 | }; | 649 | }; |
660 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); | 650 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); |
651 | |||
661 | /* corgi i2c codec control layer */ | 652 | /* corgi i2c codec control layer */ |
662 | static struct i2c_driver ssm2602_i2c_driver = { | 653 | static struct i2c_driver ssm2602_i2c_driver = { |
663 | .driver = { | 654 | .driver = { |
664 | .name = "SSM2602 I2C Codec", | 655 | .name = "ssm2602-codec", |
665 | .owner = THIS_MODULE, | 656 | .owner = THIS_MODULE, |
666 | }, | 657 | }, |
667 | .probe = ssm2602_i2c_probe, | 658 | .probe = ssm2602_i2c_probe, |
668 | .remove = ssm2602_i2c_remove, | 659 | .remove = ssm2602_i2c_remove, |
669 | .id_table = ssm2602_i2c_id, | 660 | .id_table = ssm2602_i2c_id, |
670 | }; | 661 | }; |
671 | |||
672 | static int ssm2602_add_i2c_device(struct platform_device *pdev, | ||
673 | const struct ssm2602_setup_data *setup) | ||
674 | { | ||
675 | struct i2c_board_info info; | ||
676 | struct i2c_adapter *adapter; | ||
677 | struct i2c_client *client; | ||
678 | int ret; | ||
679 | |||
680 | ret = i2c_add_driver(&ssm2602_i2c_driver); | ||
681 | if (ret != 0) { | ||
682 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
683 | return ret; | ||
684 | } | ||
685 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
686 | info.addr = setup->i2c_address; | ||
687 | strlcpy(info.type, "ssm2602", I2C_NAME_SIZE); | ||
688 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
689 | if (!adapter) { | ||
690 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
691 | setup->i2c_bus); | ||
692 | goto err_driver; | ||
693 | } | ||
694 | client = i2c_new_device(adapter, &info); | ||
695 | i2c_put_adapter(adapter); | ||
696 | if (!client) { | ||
697 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
698 | (unsigned int)info.addr); | ||
699 | goto err_driver; | ||
700 | } | ||
701 | return 0; | ||
702 | err_driver: | ||
703 | i2c_del_driver(&ssm2602_i2c_driver); | ||
704 | return -ENODEV; | ||
705 | } | ||
706 | #endif | 662 | #endif |
707 | 663 | ||
708 | static int ssm2602_probe(struct platform_device *pdev) | 664 | |
665 | static int __init ssm2602_modinit(void) | ||
709 | { | 666 | { |
710 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
711 | struct ssm2602_setup_data *setup; | ||
712 | struct snd_soc_codec *codec; | ||
713 | struct ssm2602_priv *ssm2602; | ||
714 | int ret = 0; | 667 | int ret = 0; |
715 | |||
716 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); | ||
717 | |||
718 | setup = socdev->codec_data; | ||
719 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
720 | if (codec == NULL) | ||
721 | return -ENOMEM; | ||
722 | |||
723 | ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL); | ||
724 | if (ssm2602 == NULL) { | ||
725 | kfree(codec); | ||
726 | return -ENOMEM; | ||
727 | } | ||
728 | |||
729 | snd_soc_codec_set_drvdata(codec, ssm2602); | ||
730 | socdev->card->codec = codec; | ||
731 | mutex_init(&codec->mutex); | ||
732 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
733 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
734 | |||
735 | ssm2602_socdev = socdev; | ||
736 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 668 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
737 | if (setup->i2c_address) { | 669 | ret = i2c_add_driver(&ssm2602_i2c_driver); |
738 | codec->hw_write = (hw_write_t)i2c_master_send; | 670 | if (ret != 0) { |
739 | ret = ssm2602_add_i2c_device(pdev, setup); | 671 | printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n", |
672 | ret); | ||
740 | } | 673 | } |
741 | #else | ||
742 | /* other interfaces */ | ||
743 | #endif | 674 | #endif |
744 | return ret; | 675 | return ret; |
745 | } | 676 | } |
677 | module_init(ssm2602_modinit); | ||
746 | 678 | ||
747 | /* remove everything here */ | 679 | static void __exit ssm2602_exit(void) |
748 | static int ssm2602_remove(struct platform_device *pdev) | ||
749 | { | 680 | { |
750 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
751 | struct snd_soc_codec *codec = socdev->card->codec; | ||
752 | |||
753 | if (codec->control_data) | ||
754 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
755 | |||
756 | snd_soc_free_pcms(socdev); | ||
757 | snd_soc_dapm_free(socdev); | ||
758 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 681 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
759 | i2c_unregister_device(codec->control_data); | ||
760 | i2c_del_driver(&ssm2602_i2c_driver); | 682 | i2c_del_driver(&ssm2602_i2c_driver); |
761 | #endif | 683 | #endif |
762 | kfree(snd_soc_codec_get_drvdata(codec)); | ||
763 | kfree(codec); | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | struct snd_soc_codec_device soc_codec_dev_ssm2602 = { | ||
769 | .probe = ssm2602_probe, | ||
770 | .remove = ssm2602_remove, | ||
771 | .suspend = ssm2602_suspend, | ||
772 | .resume = ssm2602_resume, | ||
773 | }; | ||
774 | EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); | ||
775 | |||
776 | static int __init ssm2602_modinit(void) | ||
777 | { | ||
778 | return snd_soc_register_dai(&ssm2602_dai); | ||
779 | } | ||
780 | module_init(ssm2602_modinit); | ||
781 | |||
782 | static void __exit ssm2602_exit(void) | ||
783 | { | ||
784 | snd_soc_unregister_dai(&ssm2602_dai); | ||
785 | } | 684 | } |
786 | module_exit(ssm2602_exit); | 685 | module_exit(ssm2602_exit); |
787 | 686 | ||