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