.. | .. |
---|
10 | 10 | #include <linux/clk/rockchip.h> |
---|
11 | 11 | #include <linux/of.h> |
---|
12 | 12 | #include <linux/of_device.h> |
---|
| 13 | +#include <linux/pinctrl/consumer.h> |
---|
13 | 14 | #include <linux/pm_runtime.h> |
---|
14 | 15 | #include <linux/rational.h> |
---|
15 | 16 | #include <linux/regmap.h> |
---|
.. | .. |
---|
30 | 31 | #define PDM_FILTER_DELAY_MS_MIN (20) |
---|
31 | 32 | #define PDM_FILTER_DELAY_MS_MAX (1000) |
---|
32 | 33 | #define PDM_CLK_SHIFT_PPM_MAX (1000000) /* 1 ppm */ |
---|
33 | | -#define CLK_PPM_MIN (-1000) |
---|
34 | | -#define CLK_PPM_MAX (1000) |
---|
| 34 | +#define CLK_PPM_MIN (-1000) |
---|
| 35 | +#define CLK_PPM_MAX (1000) |
---|
| 36 | + |
---|
| 37 | +#define QUIRK_ALWAYS_ON BIT(0) |
---|
35 | 38 | |
---|
36 | 39 | enum rk_pdm_version { |
---|
37 | 40 | RK_PDM_RK3229, |
---|
.. | .. |
---|
48 | 51 | struct regmap *regmap; |
---|
49 | 52 | struct snd_dmaengine_dai_dma_data capture_dma_data; |
---|
50 | 53 | struct reset_control *reset; |
---|
| 54 | + struct pinctrl *pinctrl; |
---|
| 55 | + struct pinctrl_state *clk_state; |
---|
51 | 56 | unsigned int start_delay_ms; |
---|
52 | 57 | unsigned int filter_delay_ms; |
---|
53 | 58 | enum rk_pdm_version version; |
---|
54 | 59 | unsigned int clk_root_rate; |
---|
55 | 60 | unsigned int clk_root_initial_rate; |
---|
| 61 | + unsigned int quirks; |
---|
56 | 62 | int clk_ppm; |
---|
57 | 63 | bool clk_calibrate; |
---|
58 | 64 | }; |
---|
.. | .. |
---|
92 | 98 | { 4, 12000 }, |
---|
93 | 99 | { 4, 11025 }, |
---|
94 | 100 | { 4, 8000 }, |
---|
| 101 | +}; |
---|
| 102 | + |
---|
| 103 | +static const struct pdm_of_quirks { |
---|
| 104 | + char *quirk; |
---|
| 105 | + int id; |
---|
| 106 | +} of_quirks[] = { |
---|
| 107 | + { |
---|
| 108 | + .quirk = "rockchip,always-on", |
---|
| 109 | + .id = QUIRK_ALWAYS_ON, |
---|
| 110 | + }, |
---|
95 | 111 | }; |
---|
96 | 112 | |
---|
97 | 113 | static unsigned int get_pdm_clk(struct rk_pdm_dev *pdm, unsigned int sr, |
---|
.. | .. |
---|
505 | 521 | static int rockchip_pdm_start_delay_get(struct snd_kcontrol *kcontrol, |
---|
506 | 522 | struct snd_ctl_elem_value *ucontrol) |
---|
507 | 523 | { |
---|
508 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
---|
509 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
---|
| 524 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 525 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
---|
510 | 526 | |
---|
511 | 527 | ucontrol->value.integer.value[0] = pdm->start_delay_ms; |
---|
512 | 528 | |
---|
.. | .. |
---|
516 | 532 | static int rockchip_pdm_start_delay_put(struct snd_kcontrol *kcontrol, |
---|
517 | 533 | struct snd_ctl_elem_value *ucontrol) |
---|
518 | 534 | { |
---|
519 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
---|
520 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
---|
| 535 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 536 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
---|
521 | 537 | |
---|
522 | 538 | if ((ucontrol->value.integer.value[0] < PDM_START_DELAY_MS_MIN) || |
---|
523 | 539 | (ucontrol->value.integer.value[0] > PDM_START_DELAY_MS_MAX)) |
---|
.. | .. |
---|
543 | 559 | static int rockchip_pdm_filter_delay_get(struct snd_kcontrol *kcontrol, |
---|
544 | 560 | struct snd_ctl_elem_value *ucontrol) |
---|
545 | 561 | { |
---|
546 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
---|
547 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
---|
| 562 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 563 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
---|
548 | 564 | |
---|
549 | 565 | ucontrol->value.integer.value[0] = pdm->filter_delay_ms; |
---|
550 | 566 | |
---|
.. | .. |
---|
554 | 570 | static int rockchip_pdm_filter_delay_put(struct snd_kcontrol *kcontrol, |
---|
555 | 571 | struct snd_ctl_elem_value *ucontrol) |
---|
556 | 572 | { |
---|
557 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
---|
558 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
---|
| 573 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 574 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
---|
559 | 575 | |
---|
560 | 576 | if ((ucontrol->value.integer.value[0] < PDM_FILTER_DELAY_MS_MIN) || |
---|
561 | 577 | (ucontrol->value.integer.value[0] > PDM_FILTER_DELAY_MS_MAX)) |
---|
.. | .. |
---|
566 | 582 | return 1; |
---|
567 | 583 | } |
---|
568 | 584 | |
---|
| 585 | +static const char * const rpaths_text[] = { |
---|
| 586 | + "From SDI0", "From SDI1", "From SDI2", "From SDI3" }; |
---|
| 587 | + |
---|
| 588 | +static SOC_ENUM_SINGLE_DECL(rpath3_enum, PDM_CLK_CTRL, 14, rpaths_text); |
---|
| 589 | +static SOC_ENUM_SINGLE_DECL(rpath2_enum, PDM_CLK_CTRL, 12, rpaths_text); |
---|
| 590 | +static SOC_ENUM_SINGLE_DECL(rpath1_enum, PDM_CLK_CTRL, 10, rpaths_text); |
---|
| 591 | +static SOC_ENUM_SINGLE_DECL(rpath0_enum, PDM_CLK_CTRL, 8, rpaths_text); |
---|
| 592 | + |
---|
| 593 | +static const char * const hpf_cutoff_text[] = { |
---|
| 594 | + "3.79Hz", "60Hz", "243Hz", "493Hz", |
---|
| 595 | +}; |
---|
| 596 | + |
---|
| 597 | +static SOC_ENUM_SINGLE_DECL(hpf_cutoff_enum, PDM_HPF_CTRL, |
---|
| 598 | + 0, hpf_cutoff_text); |
---|
| 599 | + |
---|
569 | 600 | static const struct snd_kcontrol_new rockchip_pdm_controls[] = { |
---|
| 601 | + SOC_ENUM("Receive PATH3 Source Select", rpath3_enum), |
---|
| 602 | + SOC_ENUM("Receive PATH2 Source Select", rpath2_enum), |
---|
| 603 | + SOC_ENUM("Receive PATH1 Source Select", rpath1_enum), |
---|
| 604 | + SOC_ENUM("Receive PATH0 Source Select", rpath0_enum), |
---|
| 605 | + |
---|
| 606 | + SOC_ENUM("HPF Cutoff", hpf_cutoff_enum), |
---|
| 607 | + SOC_SINGLE("HPFL Switch", PDM_HPF_CTRL, 3, 1, 0), |
---|
| 608 | + SOC_SINGLE("HPFR Switch", PDM_HPF_CTRL, 2, 1, 0), |
---|
| 609 | + |
---|
570 | 610 | { |
---|
571 | 611 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
---|
572 | 612 | .name = "PDM Start Delay Ms", |
---|
.. | .. |
---|
600 | 640 | struct snd_ctl_elem_value *ucontrol) |
---|
601 | 641 | |
---|
602 | 642 | { |
---|
603 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
---|
604 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
---|
| 643 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 644 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
---|
605 | 645 | |
---|
606 | 646 | ucontrol->value.integer.value[0] = pdm->clk_ppm; |
---|
607 | 647 | |
---|
.. | .. |
---|
611 | 651 | static int rockchip_pdm_clk_compensation_put(struct snd_kcontrol *kcontrol, |
---|
612 | 652 | struct snd_ctl_elem_value *ucontrol) |
---|
613 | 653 | { |
---|
614 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
---|
615 | | - struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai); |
---|
| 654 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 655 | + struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component); |
---|
616 | 656 | |
---|
617 | 657 | int ppm = ucontrol->value.integer.value[0]; |
---|
618 | 658 | |
---|
.. | .. |
---|
637 | 677 | struct rk_pdm_dev *pdm = to_info(dai); |
---|
638 | 678 | |
---|
639 | 679 | dai->capture_dma_data = &pdm->capture_dma_data; |
---|
640 | | - snd_soc_add_dai_controls(dai, rockchip_pdm_controls, |
---|
641 | | - ARRAY_SIZE(rockchip_pdm_controls)); |
---|
| 680 | + |
---|
642 | 681 | if (pdm->clk_calibrate) |
---|
643 | | - snd_soc_add_dai_controls(dai, &rockchip_pdm_compensation_control, 1); |
---|
| 682 | + snd_soc_add_component_controls(dai->component, |
---|
| 683 | + &rockchip_pdm_compensation_control, |
---|
| 684 | + 1); |
---|
| 685 | + |
---|
644 | 686 | return 0; |
---|
645 | 687 | } |
---|
646 | 688 | |
---|
.. | .. |
---|
721 | 763 | |
---|
722 | 764 | static const struct snd_soc_component_driver rockchip_pdm_component = { |
---|
723 | 765 | .name = "rockchip-pdm", |
---|
| 766 | + .controls = rockchip_pdm_controls, |
---|
| 767 | + .num_controls = ARRAY_SIZE(rockchip_pdm_controls), |
---|
724 | 768 | }; |
---|
| 769 | + |
---|
| 770 | +static int rockchip_pdm_pinctrl_select_clk_state(struct device *dev) |
---|
| 771 | +{ |
---|
| 772 | + struct rk_pdm_dev *pdm = dev_get_drvdata(dev); |
---|
| 773 | + |
---|
| 774 | + if (IS_ERR_OR_NULL(pdm->pinctrl) || !pdm->clk_state) |
---|
| 775 | + return 0; |
---|
| 776 | + |
---|
| 777 | + /* |
---|
| 778 | + * A necessary delay to make sure the correct |
---|
| 779 | + * frac div has been applied when resume from |
---|
| 780 | + * power down. |
---|
| 781 | + */ |
---|
| 782 | + udelay(10); |
---|
| 783 | + |
---|
| 784 | + /* |
---|
| 785 | + * Must disable the clk to avoid clk glitch |
---|
| 786 | + * when pinctrl switch from gpio to pdm clk. |
---|
| 787 | + */ |
---|
| 788 | + clk_disable_unprepare(pdm->clk); |
---|
| 789 | + pinctrl_select_state(pdm->pinctrl, pdm->clk_state); |
---|
| 790 | + clk_prepare_enable(pdm->clk); |
---|
| 791 | + |
---|
| 792 | + return 0; |
---|
| 793 | +} |
---|
725 | 794 | |
---|
726 | 795 | static int rockchip_pdm_runtime_suspend(struct device *dev) |
---|
727 | 796 | { |
---|
.. | .. |
---|
730 | 799 | regcache_cache_only(pdm->regmap, true); |
---|
731 | 800 | clk_disable_unprepare(pdm->clk); |
---|
732 | 801 | clk_disable_unprepare(pdm->hclk); |
---|
| 802 | + |
---|
| 803 | + pinctrl_pm_select_idle_state(dev); |
---|
733 | 804 | |
---|
734 | 805 | return 0; |
---|
735 | 806 | } |
---|
.. | .. |
---|
740 | 811 | int ret; |
---|
741 | 812 | |
---|
742 | 813 | ret = clk_prepare_enable(pdm->clk); |
---|
743 | | - if (ret) { |
---|
744 | | - dev_err(pdm->dev, "clock enable failed %d\n", ret); |
---|
745 | | - return ret; |
---|
746 | | - } |
---|
| 814 | + if (ret) |
---|
| 815 | + goto err_clk; |
---|
747 | 816 | |
---|
748 | 817 | ret = clk_prepare_enable(pdm->hclk); |
---|
749 | | - if (ret) { |
---|
750 | | - dev_err(pdm->dev, "hclock enable failed %d\n", ret); |
---|
751 | | - return ret; |
---|
752 | | - } |
---|
| 818 | + if (ret) |
---|
| 819 | + goto err_hclk; |
---|
753 | 820 | |
---|
754 | | - rockchip_pdm_rxctrl(pdm, 0); |
---|
755 | 821 | regcache_cache_only(pdm->regmap, false); |
---|
756 | 822 | regcache_mark_dirty(pdm->regmap); |
---|
757 | 823 | ret = regcache_sync(pdm->regmap); |
---|
758 | | - if (ret) { |
---|
759 | | - clk_disable_unprepare(pdm->clk); |
---|
760 | | - clk_disable_unprepare(pdm->hclk); |
---|
761 | | - } |
---|
| 824 | + if (ret) |
---|
| 825 | + goto err_regmap; |
---|
| 826 | + |
---|
| 827 | + rockchip_pdm_rxctrl(pdm, 0); |
---|
| 828 | + |
---|
| 829 | + rockchip_pdm_pinctrl_select_clk_state(dev); |
---|
| 830 | + |
---|
762 | 831 | return 0; |
---|
| 832 | + |
---|
| 833 | +err_regmap: |
---|
| 834 | + clk_disable_unprepare(pdm->hclk); |
---|
| 835 | +err_hclk: |
---|
| 836 | + clk_disable_unprepare(pdm->clk); |
---|
| 837 | +err_clk: |
---|
| 838 | + return ret; |
---|
763 | 839 | } |
---|
764 | 840 | |
---|
765 | 841 | static bool rockchip_pdm_wr_reg(struct device *dev, unsigned int reg) |
---|
.. | .. |
---|
894 | 970 | return 0; |
---|
895 | 971 | } |
---|
896 | 972 | |
---|
| 973 | +static int rockchip_pdm_keep_clk_always_on(struct rk_pdm_dev *pdm) |
---|
| 974 | +{ |
---|
| 975 | + pm_runtime_forbid(pdm->dev); |
---|
| 976 | + |
---|
| 977 | + dev_info(pdm->dev, "CLK-ALWAYS-ON: samplerate: %d\n", PDM_DEFAULT_RATE); |
---|
| 978 | + |
---|
| 979 | + return 0; |
---|
| 980 | +} |
---|
| 981 | + |
---|
| 982 | +static int rockchip_pdm_parse_quirks(struct rk_pdm_dev *pdm) |
---|
| 983 | +{ |
---|
| 984 | + int ret = 0, i = 0; |
---|
| 985 | + |
---|
| 986 | + for (i = 0; i < ARRAY_SIZE(of_quirks); i++) |
---|
| 987 | + if (device_property_read_bool(pdm->dev, of_quirks[i].quirk)) |
---|
| 988 | + pdm->quirks |= of_quirks[i].id; |
---|
| 989 | + |
---|
| 990 | + if (pdm->quirks & QUIRK_ALWAYS_ON) |
---|
| 991 | + ret = rockchip_pdm_keep_clk_always_on(pdm); |
---|
| 992 | + |
---|
| 993 | + return ret; |
---|
| 994 | +} |
---|
| 995 | + |
---|
897 | 996 | static int rockchip_pdm_probe(struct platform_device *pdev) |
---|
898 | 997 | { |
---|
899 | 998 | struct device_node *node = pdev->dev.of_node; |
---|
.. | .. |
---|
933 | 1032 | pdm->dev = &pdev->dev; |
---|
934 | 1033 | dev_set_drvdata(&pdev->dev, pdm); |
---|
935 | 1034 | |
---|
| 1035 | + pdm->pinctrl = devm_pinctrl_get(&pdev->dev); |
---|
| 1036 | + if (!IS_ERR_OR_NULL(pdm->pinctrl)) { |
---|
| 1037 | + pdm->clk_state = pinctrl_lookup_state(pdm->pinctrl, "clk"); |
---|
| 1038 | + if (IS_ERR(pdm->clk_state)) { |
---|
| 1039 | + pdm->clk_state = NULL; |
---|
| 1040 | + dev_dbg(pdm->dev, "Have no clk pinctrl state\n"); |
---|
| 1041 | + } |
---|
| 1042 | + } |
---|
| 1043 | + |
---|
936 | 1044 | pdm->start_delay_ms = PDM_START_DELAY_MS_DEFAULT; |
---|
937 | 1045 | pdm->filter_delay_ms = PDM_FILTER_DELAY_MS_MIN; |
---|
938 | 1046 | |
---|
.. | .. |
---|
959 | 1067 | if (ret) |
---|
960 | 1068 | return ret; |
---|
961 | 1069 | |
---|
| 1070 | + rockchip_pdm_set_samplerate(pdm, PDM_DEFAULT_RATE); |
---|
| 1071 | + rockchip_pdm_rxctrl(pdm, 0); |
---|
| 1072 | + |
---|
| 1073 | + ret = rockchip_pdm_path_parse(pdm, node); |
---|
| 1074 | + if (ret != 0 && ret != -ENOENT) |
---|
| 1075 | + goto err_clk; |
---|
| 1076 | + |
---|
| 1077 | + ret = rockchip_pdm_parse_quirks(pdm); |
---|
| 1078 | + if (ret) |
---|
| 1079 | + goto err_clk; |
---|
| 1080 | + |
---|
| 1081 | + /* |
---|
| 1082 | + * MUST: after pm_runtime_enable step, any register R/W |
---|
| 1083 | + * should be wrapped with pm_runtime_get_sync/put. |
---|
| 1084 | + * |
---|
| 1085 | + * Another approach is to enable the regcache true to |
---|
| 1086 | + * avoid access HW registers. |
---|
| 1087 | + * |
---|
| 1088 | + * Alternatively, performing the registers R/W before |
---|
| 1089 | + * pm_runtime_enable is also a good option. |
---|
| 1090 | + */ |
---|
962 | 1091 | pm_runtime_enable(&pdev->dev); |
---|
963 | 1092 | if (!pm_runtime_enabled(&pdev->dev)) { |
---|
964 | 1093 | ret = rockchip_pdm_runtime_resume(&pdev->dev); |
---|
.. | .. |
---|
975 | 1104 | goto err_suspend; |
---|
976 | 1105 | } |
---|
977 | 1106 | |
---|
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 | | - |
---|
985 | 1107 | if (of_property_read_bool(node, "rockchip,no-dmaengine")) { |
---|
986 | 1108 | dev_info(&pdev->dev, "Used for Multi-DAI\n"); |
---|
987 | 1109 | return 0; |
---|
.. | .. |
---|
993 | 1115 | goto err_suspend; |
---|
994 | 1116 | } |
---|
995 | 1117 | |
---|
| 1118 | + clk_disable_unprepare(pdm->hclk); |
---|
| 1119 | + |
---|
996 | 1120 | return 0; |
---|
997 | 1121 | |
---|
998 | 1122 | err_suspend: |
---|
.. | .. |
---|
1000 | 1124 | rockchip_pdm_runtime_suspend(&pdev->dev); |
---|
1001 | 1125 | err_pm_disable: |
---|
1002 | 1126 | pm_runtime_disable(&pdev->dev); |
---|
1003 | | - |
---|
| 1127 | +err_clk: |
---|
1004 | 1128 | clk_disable_unprepare(pdm->hclk); |
---|
1005 | 1129 | |
---|
1006 | 1130 | return ret; |
---|
.. | .. |
---|
1008 | 1132 | |
---|
1009 | 1133 | static int rockchip_pdm_remove(struct platform_device *pdev) |
---|
1010 | 1134 | { |
---|
1011 | | - struct rk_pdm_dev *pdm = dev_get_drvdata(&pdev->dev); |
---|
1012 | | - |
---|
1013 | 1135 | pm_runtime_disable(&pdev->dev); |
---|
1014 | 1136 | if (!pm_runtime_status_suspended(&pdev->dev)) |
---|
1015 | 1137 | rockchip_pdm_runtime_suspend(&pdev->dev); |
---|
1016 | | - |
---|
1017 | | - clk_disable_unprepare(pdm->clk); |
---|
1018 | | - clk_disable_unprepare(pdm->hclk); |
---|
1019 | 1138 | |
---|
1020 | 1139 | return 0; |
---|
1021 | 1140 | } |
---|