summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorspujar <spujar@nvidia.com>2018-05-15 08:25:44 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-06-30 12:41:12 -0400
commit9415e9f69137a9bb5b16c54a7dda5be97098039e (patch)
tree80b02458edff49fe6233f4433001bf38acc698b5 /sound/pci/hda
parentd9bd47b344cac6b8637e3b07c11bc75aa0ff3371 (diff)
tegra: hda: expose mapping info for hda pcm devs
sysfs nodes are introduced for exposing info related to mapping between hda pcm device ID and corresponding switch names. Currently display driver registers the switch names and the same is queried here to create mapping. Android userspace can query these nodes to know the mapping and accordingly audio is routed to the corresponding hda codec. Bug 200412336 Change-Id: I720980896311f6c30e0c7de9c7e85a9915031305 Signed-off-by: spujar <spujar@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1719541 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_tegra.c145
1 files changed, 141 insertions, 4 deletions
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 0d773d465..f3507d5ea 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -87,6 +87,17 @@ static const struct of_device_id tegra_disb_pd[] = {
87/* GSC_ID register */ 87/* GSC_ID register */
88#define HDA_GSC_REG 0x1e0 88#define HDA_GSC_REG 0x1e0
89 89
90#define CHAR_BUF_SIZE_MAX 50
91
92struct hda_pcm_devices {
93 struct azx_pcm *apcm;
94 struct kobject *kobj;
95 struct kobj_attribute pcm_attr;
96 struct kobj_attribute name_attr;
97 char switch_name[CHAR_BUF_SIZE_MAX];
98 int dev_id;
99};
100
90struct hda_tegra { 101struct hda_tegra {
91 struct azx chip; 102 struct azx chip;
92 struct device *dev; 103 struct device *dev;
@@ -100,6 +111,9 @@ struct hda_tegra {
100 struct work_struct probe_work; 111 struct work_struct probe_work;
101 bool init_done; 112 bool init_done;
102 bool do_reset; 113 bool do_reset;
114 int num_codecs;
115 struct kobject *kobj;
116 struct hda_pcm_devices *hda_pcm_dev;
103}; 117};
104 118
105#ifdef CONFIG_PM 119#ifdef CONFIG_PM
@@ -671,13 +685,125 @@ out_free:
671 return err; 685 return err;
672} 686}
673 687
688static ssize_t hda_get_pcm_device_id(struct kobject *kobj,
689 struct kobj_attribute *attr,
690 char *buf)
691{
692 struct hda_pcm_devices *pcm_dev = container_of(attr,
693 struct hda_pcm_devices, pcm_attr);
694 return snprintf(buf, PAGE_SIZE, "%d\n", pcm_dev->apcm->info->device);
695}
696
697static ssize_t hda_get_pcm_switch_name(struct kobject *kobj,
698 struct kobj_attribute *attr, char *buf) {
699 struct hda_pcm_devices *pcm_dev = container_of(attr,
700 struct hda_pcm_devices, name_attr);
701 return snprintf(buf, PAGE_SIZE, "%s\n", pcm_dev->switch_name);
702}
703
704/* switches are registered from display driver, get the names w.r.t dev ID */
705int tegra_hda_get_switch_name(int dev_id, char *name);
706
707static int hda_tegra_create_sysfs(struct hda_tegra *hda)
708{
709 struct azx *chip = &hda->chip;
710 char dirname[CHAR_BUF_SIZE_MAX] = "hda_pcm_map";
711 int dev_count = 0, ret = 0;
712 struct azx_pcm *apcm;
713 struct kobject *parent = hda->dev->kobj.parent;
714
715 /* maintains list of all hda codecs */
716 hda->hda_pcm_dev =
717 (struct hda_pcm_devices *) devm_kzalloc(hda->dev,
718 sizeof(struct hda_pcm_devices) * hda->num_codecs,
719 GFP_KERNEL);
720 if (!hda->hda_pcm_dev)
721 return -ENOMEM;
722
723 hda->kobj = kobject_create_and_add(dirname, parent);
724 if (!hda->kobj)
725 return -ENOMEM;
726
727 list_for_each_entry(apcm, &chip->pcm_list, list) {
728 char subdirname[CHAR_BUF_SIZE_MAX];
729 struct hda_pcm_devices *pcm_dev = &hda->hda_pcm_dev[dev_count];
730
731 pcm_dev->apcm = apcm;
732 snprintf(subdirname, sizeof(subdirname), "hda%d", dev_count);
733 pcm_dev->kobj = kobject_create_and_add(subdirname, hda->kobj);
734 if (!pcm_dev->kobj)
735 return -ENOMEM;
736
737 /* attributes for pcm device ID */
738 pcm_dev->pcm_attr.attr.name = "pcm_dev_id";
739 pcm_dev->pcm_attr.attr.mode = 0644;
740 pcm_dev->pcm_attr.show = hda_get_pcm_device_id;
741
742 /* attributes for switch name */
743 pcm_dev->name_attr.attr.name = "switch_name";
744 pcm_dev->name_attr.attr.mode = 0644;
745 pcm_dev->name_attr.show = hda_get_pcm_switch_name;
746
747 /* gets registered switch name for give dev ID
748 * TODO: may be we can create extcon node here itself and
749 * not rely on display driver
750 */
751 pcm_dev->dev_id = (apcm->codec->core.vendor_id) & 0xffff;
752 if (tegra_hda_get_switch_name(pcm_dev->dev_id,
753 pcm_dev->switch_name) < 0) {
754 dev_info(hda->dev, "error in getting switch name"
755 " for hda_pcm_id(%d)\n", apcm->info->device);
756 kobject_put(pcm_dev->kobj);
757 continue;
758 }
759
760 /* create files for read from userspace */
761 ret = sysfs_create_file(pcm_dev->kobj,
762 &(pcm_dev->pcm_attr.attr));
763 if (ret < 0)
764 break;
765
766 ret = sysfs_create_file(pcm_dev->kobj,
767 &(pcm_dev->name_attr.attr));
768 if (ret < 0)
769 break;
770
771 dev_count++;
772 }
773 return ret;
774}
775
776static void hda_tegra_remove_sysfs(struct device *dev)
777{
778 struct snd_card *card = dev_get_drvdata(dev);
779 struct azx *chip = card->private_data;
780 struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
781 int i;
782
783 if (!hda || !hda->hda_pcm_dev || !hda->kobj)
784 return;
785
786 for (i = 0; i < hda->num_codecs; i++) {
787 struct hda_pcm_devices *pcm_dev = &hda->hda_pcm_dev[i];
788
789 if (pcm_dev->kobj) {
790 sysfs_remove_file(pcm_dev->kobj,
791 &pcm_dev->pcm_attr.attr);
792 sysfs_remove_file(pcm_dev->kobj,
793 &pcm_dev->name_attr.attr);
794 kobject_put(pcm_dev->kobj);
795 }
796 }
797 kobject_put(hda->kobj);
798}
799
674static void hda_tegra_probe_work(struct work_struct *work) 800static void hda_tegra_probe_work(struct work_struct *work)
675{ 801{
676 struct hda_tegra *hda = container_of(work, struct hda_tegra, probe_work); 802 struct hda_tegra *hda = container_of(work, struct hda_tegra, probe_work);
677 struct azx *chip = &hda->chip; 803 struct azx *chip = &hda->chip;
678 struct platform_device *pdev = to_platform_device(hda->dev); 804 struct platform_device *pdev = to_platform_device(hda->dev);
679 struct device_node *np = pdev->dev.of_node; 805 struct device_node *np = pdev->dev.of_node;
680 int num_codec_slots = 0, gsc_id; 806 int gsc_id;
681 struct hdac_bus *bus = azx_bus(chip); 807 struct hdac_bus *bus = azx_bus(chip);
682 int err; 808 int err;
683 809
@@ -686,8 +812,8 @@ static void hda_tegra_probe_work(struct work_struct *work)
686 goto out_free; 812 goto out_free;
687 813
688 if (of_property_read_u32(np, "nvidia,max-codec-slot", 814 if (of_property_read_u32(np, "nvidia,max-codec-slot",
689 &num_codec_slots) < 0) 815 &hda->num_codecs) < 0)
690 num_codec_slots = 0; 816 hda->num_codecs = 0;
691 817
692 bus->avoid_compact_sdo_bw = of_property_read_bool(np, 818 bus->avoid_compact_sdo_bw = of_property_read_bool(np,
693 "nvidia,avoid-compact-sdo-bw"); 819 "nvidia,avoid-compact-sdo-bw");
@@ -704,7 +830,7 @@ static void hda_tegra_probe_work(struct work_struct *work)
704 hda_tegra_writel(gsc_id, hda->regs + HDA_GSC_REG); 830 hda_tegra_writel(gsc_id, hda->regs + HDA_GSC_REG);
705 831
706 /* create codec instances */ 832 /* create codec instances */
707 err = azx_probe_codecs(chip, num_codec_slots); 833 err = azx_probe_codecs(chip, hda->num_codecs);
708 if (err < 0) 834 if (err < 0)
709 goto out_free; 835 goto out_free;
710 836
@@ -723,6 +849,14 @@ static void hda_tegra_probe_work(struct work_struct *work)
723 849
724 pm_runtime_put(hda->dev); 850 pm_runtime_put(hda->dev);
725 851
852 /* export pcm device mapping to userspace - needed for android */
853 err = hda_tegra_create_sysfs(hda);
854 if (err < 0) {
855 dev_err(&pdev->dev,
856 "error:%d in creating sysfs nodes for hda\n", err);
857 /* free allocated resources */
858 hda_tegra_remove_sysfs(&pdev->dev);
859 }
726out_free: 860out_free:
727 return; /* no error return from async probe */ 861 return; /* no error return from async probe */
728} 862}
@@ -733,6 +867,9 @@ static int hda_tegra_remove(struct platform_device *pdev)
733 if (!pm_runtime_status_suspended(&pdev->dev)) 867 if (!pm_runtime_status_suspended(&pdev->dev))
734 hda_tegra_runtime_suspend(&pdev->dev); 868 hda_tegra_runtime_suspend(&pdev->dev);
735 869
870 /* remove sysfs files */
871 hda_tegra_remove_sysfs(&pdev->dev);
872
736 return snd_card_free(dev_get_drvdata(&pdev->dev)); 873 return snd_card_free(dev_get_drvdata(&pdev->dev));
737} 874}
738 875