diff options
Diffstat (limited to 'sound/hda/hdac_device.c')
-rw-r--r-- | sound/hda/hdac_device.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index f75bf5622687..cdee7103f649 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/pm_runtime.h> | 10 | #include <linux/pm_runtime.h> |
11 | #include <sound/hdaudio.h> | 11 | #include <sound/hdaudio.h> |
12 | #include <sound/hda_regmap.h> | 12 | #include <sound/hda_regmap.h> |
13 | #include <sound/pcm.h> | ||
13 | #include "local.h" | 14 | #include "local.h" |
14 | 15 | ||
15 | static void setup_fg_nodes(struct hdac_device *codec); | 16 | static void setup_fg_nodes(struct hdac_device *codec); |
@@ -551,6 +552,21 @@ void snd_hdac_power_down_pm(struct hdac_device *codec) | |||
551 | EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); | 552 | EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); |
552 | #endif | 553 | #endif |
553 | 554 | ||
555 | /* | ||
556 | * Enable/disable the link power for a codec. | ||
557 | */ | ||
558 | int snd_hdac_link_power(struct hdac_device *codec, bool enable) | ||
559 | { | ||
560 | if (!codec->link_power_control) | ||
561 | return 0; | ||
562 | |||
563 | if (codec->bus->ops->link_power) | ||
564 | return codec->bus->ops->link_power(codec->bus, enable); | ||
565 | else | ||
566 | return -EINVAL; | ||
567 | } | ||
568 | EXPORT_SYMBOL_GPL(snd_hdac_link_power); | ||
569 | |||
554 | /* codec vendor labels */ | 570 | /* codec vendor labels */ |
555 | struct hda_vendor_id { | 571 | struct hda_vendor_id { |
556 | unsigned int id; | 572 | unsigned int id; |
@@ -597,3 +613,302 @@ static int get_codec_vendor_name(struct hdac_device *codec) | |||
597 | codec->vendor_name = kasprintf(GFP_KERNEL, "Generic %04x", vendor_id); | 613 | codec->vendor_name = kasprintf(GFP_KERNEL, "Generic %04x", vendor_id); |
598 | return codec->vendor_name ? 0 : -ENOMEM; | 614 | return codec->vendor_name ? 0 : -ENOMEM; |
599 | } | 615 | } |
616 | |||
617 | /* | ||
618 | * stream formats | ||
619 | */ | ||
620 | struct hda_rate_tbl { | ||
621 | unsigned int hz; | ||
622 | unsigned int alsa_bits; | ||
623 | unsigned int hda_fmt; | ||
624 | }; | ||
625 | |||
626 | /* rate = base * mult / div */ | ||
627 | #define HDA_RATE(base, mult, div) \ | ||
628 | (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ | ||
629 | (((div) - 1) << AC_FMT_DIV_SHIFT)) | ||
630 | |||
631 | static struct hda_rate_tbl rate_bits[] = { | ||
632 | /* rate in Hz, ALSA rate bitmask, HDA format value */ | ||
633 | |||
634 | /* autodetected value used in snd_hda_query_supported_pcm */ | ||
635 | { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) }, | ||
636 | { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) }, | ||
637 | { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) }, | ||
638 | { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) }, | ||
639 | { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) }, | ||
640 | { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) }, | ||
641 | { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) }, | ||
642 | { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) }, | ||
643 | { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) }, | ||
644 | { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) }, | ||
645 | { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) }, | ||
646 | #define AC_PAR_PCM_RATE_BITS 11 | ||
647 | /* up to bits 10, 384kHZ isn't supported properly */ | ||
648 | |||
649 | /* not autodetected value */ | ||
650 | { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) }, | ||
651 | |||
652 | { 0 } /* terminator */ | ||
653 | }; | ||
654 | |||
655 | /** | ||
656 | * snd_hdac_calc_stream_format - calculate the format bitset | ||
657 | * @rate: the sample rate | ||
658 | * @channels: the number of channels | ||
659 | * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) | ||
660 | * @maxbps: the max. bps | ||
661 | * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant) | ||
662 | * | ||
663 | * Calculate the format bitset from the given rate, channels and th PCM format. | ||
664 | * | ||
665 | * Return zero if invalid. | ||
666 | */ | ||
667 | unsigned int snd_hdac_calc_stream_format(unsigned int rate, | ||
668 | unsigned int channels, | ||
669 | unsigned int format, | ||
670 | unsigned int maxbps, | ||
671 | unsigned short spdif_ctls) | ||
672 | { | ||
673 | int i; | ||
674 | unsigned int val = 0; | ||
675 | |||
676 | for (i = 0; rate_bits[i].hz; i++) | ||
677 | if (rate_bits[i].hz == rate) { | ||
678 | val = rate_bits[i].hda_fmt; | ||
679 | break; | ||
680 | } | ||
681 | if (!rate_bits[i].hz) | ||
682 | return 0; | ||
683 | |||
684 | if (channels == 0 || channels > 8) | ||
685 | return 0; | ||
686 | val |= channels - 1; | ||
687 | |||
688 | switch (snd_pcm_format_width(format)) { | ||
689 | case 8: | ||
690 | val |= AC_FMT_BITS_8; | ||
691 | break; | ||
692 | case 16: | ||
693 | val |= AC_FMT_BITS_16; | ||
694 | break; | ||
695 | case 20: | ||
696 | case 24: | ||
697 | case 32: | ||
698 | if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) | ||
699 | val |= AC_FMT_BITS_32; | ||
700 | else if (maxbps >= 24) | ||
701 | val |= AC_FMT_BITS_24; | ||
702 | else | ||
703 | val |= AC_FMT_BITS_20; | ||
704 | break; | ||
705 | default: | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | if (spdif_ctls & AC_DIG1_NONAUDIO) | ||
710 | val |= AC_FMT_TYPE_NON_PCM; | ||
711 | |||
712 | return val; | ||
713 | } | ||
714 | EXPORT_SYMBOL_GPL(snd_hdac_calc_stream_format); | ||
715 | |||
716 | static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid) | ||
717 | { | ||
718 | unsigned int val = 0; | ||
719 | |||
720 | if (nid != codec->afg && | ||
721 | (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) | ||
722 | val = snd_hdac_read_parm(codec, nid, AC_PAR_PCM); | ||
723 | if (!val || val == -1) | ||
724 | val = snd_hdac_read_parm(codec, codec->afg, AC_PAR_PCM); | ||
725 | if (!val || val == -1) | ||
726 | return 0; | ||
727 | return val; | ||
728 | } | ||
729 | |||
730 | static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid) | ||
731 | { | ||
732 | unsigned int streams = snd_hdac_read_parm(codec, nid, AC_PAR_STREAM); | ||
733 | |||
734 | if (!streams || streams == -1) | ||
735 | streams = snd_hdac_read_parm(codec, codec->afg, AC_PAR_STREAM); | ||
736 | if (!streams || streams == -1) | ||
737 | return 0; | ||
738 | return streams; | ||
739 | } | ||
740 | |||
741 | /** | ||
742 | * snd_hdac_query_supported_pcm - query the supported PCM rates and formats | ||
743 | * @codec: the codec object | ||
744 | * @nid: NID to query | ||
745 | * @ratesp: the pointer to store the detected rate bitflags | ||
746 | * @formatsp: the pointer to store the detected formats | ||
747 | * @bpsp: the pointer to store the detected format widths | ||
748 | * | ||
749 | * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp | ||
750 | * or @bsps argument is ignored. | ||
751 | * | ||
752 | * Returns 0 if successful, otherwise a negative error code. | ||
753 | */ | ||
754 | int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, | ||
755 | u32 *ratesp, u64 *formatsp, unsigned int *bpsp) | ||
756 | { | ||
757 | unsigned int i, val, wcaps; | ||
758 | |||
759 | wcaps = get_wcaps(codec, nid); | ||
760 | val = query_pcm_param(codec, nid); | ||
761 | |||
762 | if (ratesp) { | ||
763 | u32 rates = 0; | ||
764 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) { | ||
765 | if (val & (1 << i)) | ||
766 | rates |= rate_bits[i].alsa_bits; | ||
767 | } | ||
768 | if (rates == 0) { | ||
769 | dev_err(&codec->dev, | ||
770 | "rates == 0 (nid=0x%x, val=0x%x, ovrd=%i)\n", | ||
771 | nid, val, | ||
772 | (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); | ||
773 | return -EIO; | ||
774 | } | ||
775 | *ratesp = rates; | ||
776 | } | ||
777 | |||
778 | if (formatsp || bpsp) { | ||
779 | u64 formats = 0; | ||
780 | unsigned int streams, bps; | ||
781 | |||
782 | streams = query_stream_param(codec, nid); | ||
783 | if (!streams) | ||
784 | return -EIO; | ||
785 | |||
786 | bps = 0; | ||
787 | if (streams & AC_SUPFMT_PCM) { | ||
788 | if (val & AC_SUPPCM_BITS_8) { | ||
789 | formats |= SNDRV_PCM_FMTBIT_U8; | ||
790 | bps = 8; | ||
791 | } | ||
792 | if (val & AC_SUPPCM_BITS_16) { | ||
793 | formats |= SNDRV_PCM_FMTBIT_S16_LE; | ||
794 | bps = 16; | ||
795 | } | ||
796 | if (wcaps & AC_WCAP_DIGITAL) { | ||
797 | if (val & AC_SUPPCM_BITS_32) | ||
798 | formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; | ||
799 | if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) | ||
800 | formats |= SNDRV_PCM_FMTBIT_S32_LE; | ||
801 | if (val & AC_SUPPCM_BITS_24) | ||
802 | bps = 24; | ||
803 | else if (val & AC_SUPPCM_BITS_20) | ||
804 | bps = 20; | ||
805 | } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24| | ||
806 | AC_SUPPCM_BITS_32)) { | ||
807 | formats |= SNDRV_PCM_FMTBIT_S32_LE; | ||
808 | if (val & AC_SUPPCM_BITS_32) | ||
809 | bps = 32; | ||
810 | else if (val & AC_SUPPCM_BITS_24) | ||
811 | bps = 24; | ||
812 | else if (val & AC_SUPPCM_BITS_20) | ||
813 | bps = 20; | ||
814 | } | ||
815 | } | ||
816 | #if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */ | ||
817 | if (streams & AC_SUPFMT_FLOAT32) { | ||
818 | formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; | ||
819 | if (!bps) | ||
820 | bps = 32; | ||
821 | } | ||
822 | #endif | ||
823 | if (streams == AC_SUPFMT_AC3) { | ||
824 | /* should be exclusive */ | ||
825 | /* temporary hack: we have still no proper support | ||
826 | * for the direct AC3 stream... | ||
827 | */ | ||
828 | formats |= SNDRV_PCM_FMTBIT_U8; | ||
829 | bps = 8; | ||
830 | } | ||
831 | if (formats == 0) { | ||
832 | dev_err(&codec->dev, | ||
833 | "formats == 0 (nid=0x%x, val=0x%x, ovrd=%i, streams=0x%x)\n", | ||
834 | nid, val, | ||
835 | (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, | ||
836 | streams); | ||
837 | return -EIO; | ||
838 | } | ||
839 | if (formatsp) | ||
840 | *formatsp = formats; | ||
841 | if (bpsp) | ||
842 | *bpsp = bps; | ||
843 | } | ||
844 | |||
845 | return 0; | ||
846 | } | ||
847 | EXPORT_SYMBOL_GPL(snd_hdac_query_supported_pcm); | ||
848 | |||
849 | /** | ||
850 | * snd_hdac_is_supported_format - Check the validity of the format | ||
851 | * @codec: the codec object | ||
852 | * @nid: NID to check | ||
853 | * @format: the HD-audio format value to check | ||
854 | * | ||
855 | * Check whether the given node supports the format value. | ||
856 | * | ||
857 | * Returns true if supported, false if not. | ||
858 | */ | ||
859 | bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid, | ||
860 | unsigned int format) | ||
861 | { | ||
862 | int i; | ||
863 | unsigned int val = 0, rate, stream; | ||
864 | |||
865 | val = query_pcm_param(codec, nid); | ||
866 | if (!val) | ||
867 | return false; | ||
868 | |||
869 | rate = format & 0xff00; | ||
870 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) | ||
871 | if (rate_bits[i].hda_fmt == rate) { | ||
872 | if (val & (1 << i)) | ||
873 | break; | ||
874 | return false; | ||
875 | } | ||
876 | if (i >= AC_PAR_PCM_RATE_BITS) | ||
877 | return false; | ||
878 | |||
879 | stream = query_stream_param(codec, nid); | ||
880 | if (!stream) | ||
881 | return false; | ||
882 | |||
883 | if (stream & AC_SUPFMT_PCM) { | ||
884 | switch (format & 0xf0) { | ||
885 | case 0x00: | ||
886 | if (!(val & AC_SUPPCM_BITS_8)) | ||
887 | return false; | ||
888 | break; | ||
889 | case 0x10: | ||
890 | if (!(val & AC_SUPPCM_BITS_16)) | ||
891 | return false; | ||
892 | break; | ||
893 | case 0x20: | ||
894 | if (!(val & AC_SUPPCM_BITS_20)) | ||
895 | return false; | ||
896 | break; | ||
897 | case 0x30: | ||
898 | if (!(val & AC_SUPPCM_BITS_24)) | ||
899 | return false; | ||
900 | break; | ||
901 | case 0x40: | ||
902 | if (!(val & AC_SUPPCM_BITS_32)) | ||
903 | return false; | ||
904 | break; | ||
905 | default: | ||
906 | return false; | ||
907 | } | ||
908 | } else { | ||
909 | /* FIXME: check for float32 and AC3? */ | ||
910 | } | ||
911 | |||
912 | return true; | ||
913 | } | ||
914 | EXPORT_SYMBOL_GPL(snd_hdac_is_supported_format); | ||