hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
kernel/sound/soc/rockchip/rockchip_pdm.c
....@@ -10,6 +10,7 @@
1010 #include <linux/clk/rockchip.h>
1111 #include <linux/of.h>
1212 #include <linux/of_device.h>
13
+#include <linux/pinctrl/consumer.h>
1314 #include <linux/pm_runtime.h>
1415 #include <linux/rational.h>
1516 #include <linux/regmap.h>
....@@ -48,6 +49,8 @@
4849 struct regmap *regmap;
4950 struct snd_dmaengine_dai_dma_data capture_dma_data;
5051 struct reset_control *reset;
52
+ struct pinctrl *pinctrl;
53
+ struct pinctrl_state *clk_state;
5154 unsigned int start_delay_ms;
5255 unsigned int filter_delay_ms;
5356 enum rk_pdm_version version;
....@@ -566,7 +569,20 @@
566569 return 1;
567570 }
568571
572
+static const char * const rpaths_text[] = {
573
+ "From SDI0", "From SDI1", "From SDI2", "From SDI3" };
574
+
575
+static SOC_ENUM_SINGLE_DECL(rpath3_enum, PDM_CLK_CTRL, 14, rpaths_text);
576
+static SOC_ENUM_SINGLE_DECL(rpath2_enum, PDM_CLK_CTRL, 12, rpaths_text);
577
+static SOC_ENUM_SINGLE_DECL(rpath1_enum, PDM_CLK_CTRL, 10, rpaths_text);
578
+static SOC_ENUM_SINGLE_DECL(rpath0_enum, PDM_CLK_CTRL, 8, rpaths_text);
579
+
569580 static const struct snd_kcontrol_new rockchip_pdm_controls[] = {
581
+ SOC_ENUM("Receive PATH3 Source Select", rpath3_enum),
582
+ SOC_ENUM("Receive PATH2 Source Select", rpath2_enum),
583
+ SOC_ENUM("Receive PATH1 Source Select", rpath1_enum),
584
+ SOC_ENUM("Receive PATH0 Source Select", rpath0_enum),
585
+
570586 {
571587 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
572588 .name = "PDM Start Delay Ms",
....@@ -637,10 +653,12 @@
637653 struct rk_pdm_dev *pdm = to_info(dai);
638654
639655 dai->capture_dma_data = &pdm->capture_dma_data;
640
- snd_soc_add_dai_controls(dai, rockchip_pdm_controls,
641
- ARRAY_SIZE(rockchip_pdm_controls));
656
+
642657 if (pdm->clk_calibrate)
643
- snd_soc_add_dai_controls(dai, &rockchip_pdm_compensation_control, 1);
658
+ snd_soc_add_component_controls(dai->component,
659
+ &rockchip_pdm_compensation_control,
660
+ 1);
661
+
644662 return 0;
645663 }
646664
....@@ -721,7 +739,34 @@
721739
722740 static const struct snd_soc_component_driver rockchip_pdm_component = {
723741 .name = "rockchip-pdm",
742
+ .controls = rockchip_pdm_controls,
743
+ .num_controls = ARRAY_SIZE(rockchip_pdm_controls),
724744 };
745
+
746
+static int rockchip_pdm_pinctrl_select_clk_state(struct device *dev)
747
+{
748
+ struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
749
+
750
+ if (IS_ERR_OR_NULL(pdm->pinctrl) || !pdm->clk_state)
751
+ return 0;
752
+
753
+ /*
754
+ * A necessary delay to make sure the correct
755
+ * frac div has been applied when resume from
756
+ * power down.
757
+ */
758
+ udelay(10);
759
+
760
+ /*
761
+ * Must disable the clk to avoid clk glitch
762
+ * when pinctrl switch from gpio to pdm clk.
763
+ */
764
+ clk_disable_unprepare(pdm->clk);
765
+ pinctrl_select_state(pdm->pinctrl, pdm->clk_state);
766
+ clk_prepare_enable(pdm->clk);
767
+
768
+ return 0;
769
+}
725770
726771 static int rockchip_pdm_runtime_suspend(struct device *dev)
727772 {
....@@ -730,6 +775,8 @@
730775 regcache_cache_only(pdm->regmap, true);
731776 clk_disable_unprepare(pdm->clk);
732777 clk_disable_unprepare(pdm->hclk);
778
+
779
+ pinctrl_pm_select_idle_state(dev);
733780
734781 return 0;
735782 }
....@@ -740,26 +787,31 @@
740787 int ret;
741788
742789 ret = clk_prepare_enable(pdm->clk);
743
- if (ret) {
744
- dev_err(pdm->dev, "clock enable failed %d\n", ret);
745
- return ret;
746
- }
790
+ if (ret)
791
+ goto err_clk;
747792
748793 ret = clk_prepare_enable(pdm->hclk);
749
- if (ret) {
750
- dev_err(pdm->dev, "hclock enable failed %d\n", ret);
751
- return ret;
752
- }
794
+ if (ret)
795
+ goto err_hclk;
753796
754
- rockchip_pdm_rxctrl(pdm, 0);
755797 regcache_cache_only(pdm->regmap, false);
756798 regcache_mark_dirty(pdm->regmap);
757799 ret = regcache_sync(pdm->regmap);
758
- if (ret) {
759
- clk_disable_unprepare(pdm->clk);
760
- clk_disable_unprepare(pdm->hclk);
761
- }
800
+ if (ret)
801
+ goto err_regmap;
802
+
803
+ rockchip_pdm_rxctrl(pdm, 0);
804
+
805
+ rockchip_pdm_pinctrl_select_clk_state(dev);
806
+
762807 return 0;
808
+
809
+err_regmap:
810
+ clk_disable_unprepare(pdm->hclk);
811
+err_hclk:
812
+ clk_disable_unprepare(pdm->clk);
813
+err_clk:
814
+ return ret;
763815 }
764816
765817 static bool rockchip_pdm_wr_reg(struct device *dev, unsigned int reg)
....@@ -933,6 +985,15 @@
933985 pdm->dev = &pdev->dev;
934986 dev_set_drvdata(&pdev->dev, pdm);
935987
988
+ pdm->pinctrl = devm_pinctrl_get(&pdev->dev);
989
+ if (!IS_ERR_OR_NULL(pdm->pinctrl)) {
990
+ pdm->clk_state = pinctrl_lookup_state(pdm->pinctrl, "clk");
991
+ if (IS_ERR(pdm->clk_state)) {
992
+ pdm->clk_state = NULL;
993
+ dev_dbg(pdm->dev, "Have no clk pinctrl state\n");
994
+ }
995
+ }
996
+
936997 pdm->start_delay_ms = PDM_START_DELAY_MS_DEFAULT;
937998 pdm->filter_delay_ms = PDM_FILTER_DELAY_MS_MIN;
938999
....@@ -959,6 +1020,23 @@
9591020 if (ret)
9601021 return ret;
9611022
1023
+ rockchip_pdm_set_samplerate(pdm, PDM_DEFAULT_RATE);
1024
+ rockchip_pdm_rxctrl(pdm, 0);
1025
+
1026
+ ret = rockchip_pdm_path_parse(pdm, node);
1027
+ if (ret != 0 && ret != -ENOENT)
1028
+ goto err_clk;
1029
+
1030
+ /*
1031
+ * MUST: after pm_runtime_enable step, any register R/W
1032
+ * should be wrapped with pm_runtime_get_sync/put.
1033
+ *
1034
+ * Another approach is to enable the regcache true to
1035
+ * avoid access HW registers.
1036
+ *
1037
+ * Alternatively, performing the registers R/W before
1038
+ * pm_runtime_enable is also a good option.
1039
+ */
9621040 pm_runtime_enable(&pdev->dev);
9631041 if (!pm_runtime_enabled(&pdev->dev)) {
9641042 ret = rockchip_pdm_runtime_resume(&pdev->dev);
....@@ -975,13 +1053,6 @@
9751053 goto err_suspend;
9761054 }
9771055
978
- rockchip_pdm_set_samplerate(pdm, PDM_DEFAULT_RATE);
979
- rockchip_pdm_rxctrl(pdm, 0);
980
-
981
- ret = rockchip_pdm_path_parse(pdm, node);
982
- if (ret != 0 && ret != -ENOENT)
983
- goto err_suspend;
984
-
9851056 if (of_property_read_bool(node, "rockchip,no-dmaengine")) {
9861057 dev_info(&pdev->dev, "Used for Multi-DAI\n");
9871058 return 0;
....@@ -993,6 +1064,8 @@
9931064 goto err_suspend;
9941065 }
9951066
1067
+ clk_disable_unprepare(pdm->hclk);
1068
+
9961069 return 0;
9971070
9981071 err_suspend:
....@@ -1000,7 +1073,7 @@
10001073 rockchip_pdm_runtime_suspend(&pdev->dev);
10011074 err_pm_disable:
10021075 pm_runtime_disable(&pdev->dev);
1003
-
1076
+err_clk:
10041077 clk_disable_unprepare(pdm->hclk);
10051078
10061079 return ret;
....@@ -1008,14 +1081,9 @@
10081081
10091082 static int rockchip_pdm_remove(struct platform_device *pdev)
10101083 {
1011
- struct rk_pdm_dev *pdm = dev_get_drvdata(&pdev->dev);
1012
-
10131084 pm_runtime_disable(&pdev->dev);
10141085 if (!pm_runtime_status_suspended(&pdev->dev))
10151086 rockchip_pdm_runtime_suspend(&pdev->dev);
1016
-
1017
- clk_disable_unprepare(pdm->clk);
1018
- clk_disable_unprepare(pdm->hclk);
10191087
10201088 return 0;
10211089 }