.. | .. |
---|
24 | 24 | |
---|
25 | 25 | #define FW_RATIO_MAX 8 |
---|
26 | 26 | #define FW_RATIO_MIN 1 |
---|
| 27 | +#define MAXBURST_PER_FIFO 8 |
---|
| 28 | + |
---|
| 29 | +#define DEFAULT_FS 48000 |
---|
| 30 | +#define QUIRK_ALWAYS_ON BIT(0) |
---|
27 | 31 | |
---|
28 | 32 | enum fpw_mode { |
---|
29 | 33 | FPW_ONE_BCLK_WIDTH, |
---|
.. | .. |
---|
41 | 45 | struct snd_dmaengine_dai_dma_data capture_dma_data; |
---|
42 | 46 | struct snd_dmaengine_dai_dma_data playback_dma_data; |
---|
43 | 47 | struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1]; |
---|
| 48 | + unsigned int tx_lanes; |
---|
| 49 | + unsigned int rx_lanes; |
---|
| 50 | + unsigned int quirks; |
---|
44 | 51 | enum fpw_mode fpw; |
---|
45 | | - int fw_ratio; |
---|
| 52 | + int fw_ratio; |
---|
46 | 53 | bool has_capture; |
---|
47 | 54 | bool has_playback; |
---|
48 | 55 | bool is_master_mode; |
---|
| 56 | + bool is_tdm; |
---|
49 | 57 | }; |
---|
50 | 58 | |
---|
51 | | -static int sai_runtime_suspend(struct device *dev) |
---|
| 59 | +static const struct sai_of_quirks { |
---|
| 60 | + char *quirk; |
---|
| 61 | + int id; |
---|
| 62 | +} of_quirks[] = { |
---|
| 63 | + { |
---|
| 64 | + .quirk = "rockchip,always-on", |
---|
| 65 | + .id = QUIRK_ALWAYS_ON, |
---|
| 66 | + }, |
---|
| 67 | +}; |
---|
| 68 | + |
---|
| 69 | +static int rockchip_sai_runtime_suspend(struct device *dev) |
---|
52 | 70 | { |
---|
53 | 71 | struct rk_sai_dev *sai = dev_get_drvdata(dev); |
---|
54 | 72 | unsigned int val; |
---|
.. | .. |
---|
68 | 86 | |
---|
69 | 87 | regcache_cache_only(sai->regmap, true); |
---|
70 | 88 | clk_disable_unprepare(sai->mclk); |
---|
| 89 | + clk_disable_unprepare(sai->hclk); |
---|
71 | 90 | |
---|
72 | 91 | return 0; |
---|
73 | 92 | } |
---|
74 | 93 | |
---|
75 | | -static int sai_runtime_resume(struct device *dev) |
---|
| 94 | +static int rockchip_sai_runtime_resume(struct device *dev) |
---|
76 | 95 | { |
---|
77 | 96 | struct rk_sai_dev *sai = dev_get_drvdata(dev); |
---|
78 | 97 | int ret; |
---|
| 98 | + |
---|
| 99 | + ret = clk_prepare_enable(sai->hclk); |
---|
| 100 | + if (ret) |
---|
| 101 | + goto err_hclk; |
---|
79 | 102 | |
---|
80 | 103 | ret = clk_prepare_enable(sai->mclk); |
---|
81 | 104 | if (ret) |
---|
.. | .. |
---|
99 | 122 | err_regmap: |
---|
100 | 123 | clk_disable_unprepare(sai->mclk); |
---|
101 | 124 | err_mclk: |
---|
| 125 | + clk_disable_unprepare(sai->hclk); |
---|
| 126 | +err_hclk: |
---|
102 | 127 | return ret; |
---|
103 | 128 | } |
---|
104 | 129 | |
---|
.. | .. |
---|
359 | 384 | return ret; |
---|
360 | 385 | } |
---|
361 | 386 | |
---|
| 387 | +static unsigned int rockchip_sai_lanes_auto(struct snd_pcm_hw_params *params, |
---|
| 388 | + struct snd_soc_dai *dai) |
---|
| 389 | +{ |
---|
| 390 | + struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai); |
---|
| 391 | + unsigned int lanes = 1; |
---|
| 392 | + |
---|
| 393 | + if (!sai->is_tdm) |
---|
| 394 | + lanes = DIV_ROUND_UP(params_channels(params), 2); |
---|
| 395 | + |
---|
| 396 | + return lanes; |
---|
| 397 | +} |
---|
| 398 | + |
---|
362 | 399 | static int rockchip_sai_hw_params(struct snd_pcm_substream *substream, |
---|
363 | 400 | struct snd_pcm_hw_params *params, |
---|
364 | 401 | struct snd_soc_dai *dai) |
---|
365 | 402 | { |
---|
366 | 403 | struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai); |
---|
| 404 | + struct snd_dmaengine_dai_dma_data *dma_data; |
---|
367 | 405 | unsigned int mclk_rate, bclk_rate, div_bclk; |
---|
368 | 406 | unsigned int ch_per_lane, lanes, slot_width; |
---|
369 | 407 | unsigned int val, fscr, reg; |
---|
370 | 408 | |
---|
371 | | - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
| 409 | + dma_data = snd_soc_dai_get_dma_data(dai, substream); |
---|
| 410 | + dma_data->maxburst = MAXBURST_PER_FIFO * params_channels(params) / 2; |
---|
| 411 | + |
---|
| 412 | + lanes = rockchip_sai_lanes_auto(params, dai); |
---|
| 413 | + |
---|
| 414 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
372 | 415 | reg = SAI_TXCR; |
---|
373 | | - else |
---|
| 416 | + if (sai->tx_lanes) |
---|
| 417 | + lanes = sai->tx_lanes; |
---|
| 418 | + } else { |
---|
374 | 419 | reg = SAI_RXCR; |
---|
| 420 | + if (sai->rx_lanes) |
---|
| 421 | + lanes = sai->rx_lanes; |
---|
| 422 | + } |
---|
375 | 423 | |
---|
376 | 424 | switch (params_format(params)) { |
---|
377 | 425 | case SNDRV_PCM_FORMAT_S8: |
---|
.. | .. |
---|
391 | 439 | return -EINVAL; |
---|
392 | 440 | } |
---|
393 | 441 | |
---|
394 | | - regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK, val); |
---|
| 442 | + val |= SAI_XCR_CSR(lanes); |
---|
| 443 | + |
---|
| 444 | + regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val); |
---|
395 | 445 | |
---|
396 | 446 | regmap_read(sai->regmap, reg, &val); |
---|
397 | 447 | |
---|
398 | 448 | slot_width = SAI_XCR_SBW_V(val); |
---|
399 | | - lanes = SAI_XCR_CSR_V(val); |
---|
400 | 449 | ch_per_lane = params_channels(params) / lanes; |
---|
401 | 450 | |
---|
402 | 451 | regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK, |
---|
.. | .. |
---|
525 | 574 | regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK, |
---|
526 | 575 | SAI_XCR_SBW(slot_width)); |
---|
527 | 576 | pm_runtime_put(dai->dev); |
---|
| 577 | + |
---|
| 578 | + sai->is_tdm = true; |
---|
528 | 579 | |
---|
529 | 580 | return 0; |
---|
530 | 581 | } |
---|
.. | .. |
---|
699 | 750 | |
---|
700 | 751 | sai->playback_dma_data.addr = res->start + SAI_TXDR; |
---|
701 | 752 | sai->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
---|
702 | | - sai->playback_dma_data.maxburst = 8; |
---|
| 753 | + sai->playback_dma_data.maxburst = MAXBURST_PER_FIFO; |
---|
703 | 754 | } |
---|
704 | 755 | |
---|
705 | 756 | if (sai->has_capture) { |
---|
.. | .. |
---|
714 | 765 | |
---|
715 | 766 | sai->capture_dma_data.addr = res->start + SAI_RXDR; |
---|
716 | 767 | sai->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
---|
717 | | - sai->capture_dma_data.maxburst = 8; |
---|
| 768 | + sai->capture_dma_data.maxburst = MAXBURST_PER_FIFO; |
---|
718 | 769 | } |
---|
719 | 770 | |
---|
720 | 771 | regmap_update_bits(sai->regmap, SAI_DMACR, SAI_DMACR_TDL_MASK, |
---|
.. | .. |
---|
728 | 779 | return 0; |
---|
729 | 780 | } |
---|
730 | 781 | |
---|
731 | | -static const char * const tcsr_text[] = { "SDOx1", "SDOx2", "SDOx3", "SDOx4" }; |
---|
732 | | -static const char * const rcsr_text[] = { "SDIx1", "SDIx2", "SDIx3", "SDIx4" }; |
---|
| 782 | +static const char * const tx_lanes_text[] = { "Auto", "SDOx1", "SDOx2", "SDOx3", "SDOx4" }; |
---|
| 783 | +static const char * const rx_lanes_text[] = { "Auto", "SDIx1", "SDIx2", "SDIx3", "SDIx4" }; |
---|
733 | 784 | static const char * const edge_text[] = { "Rising Edge", "Dual Edge" }; |
---|
734 | 785 | static const char * const edge_shift_text[] = { "Normal", "Shift 1 Edge" }; |
---|
735 | 786 | |
---|
.. | .. |
---|
771 | 822 | |
---|
772 | 823 | /* TXCR */ |
---|
773 | 824 | static SOC_ENUM_SINGLE_DECL(tsft_enum, SAI_TXCR, 22, edge_shift_text); |
---|
774 | | -static SOC_ENUM_SINGLE_DECL(tcsr_enum, SAI_TXCR, 20, tcsr_text); |
---|
| 825 | +static const struct soc_enum tx_lanes_enum = |
---|
| 826 | + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_lanes_text), tx_lanes_text); |
---|
775 | 827 | static SOC_ENUM_SINGLE_DECL(tsjm_enum, SAI_TXCR, 19, sjm_text); |
---|
776 | 828 | static SOC_ENUM_SINGLE_DECL(tfbm_enum, SAI_TXCR, 18, fbm_text); |
---|
777 | 829 | static SOC_ENUM_SINGLE_DECL(tvdj_enum, SAI_TXCR, 10, vdj_text); |
---|
.. | .. |
---|
786 | 838 | |
---|
787 | 839 | /* RXCR */ |
---|
788 | 840 | static SOC_ENUM_SINGLE_DECL(rsft_enum, SAI_RXCR, 22, edge_shift_text); |
---|
789 | | -static SOC_ENUM_SINGLE_DECL(rcsr_enum, SAI_RXCR, 20, rcsr_text); |
---|
| 841 | +static const struct soc_enum rx_lanes_enum = |
---|
| 842 | + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_lanes_text), rx_lanes_text); |
---|
790 | 843 | static SOC_ENUM_SINGLE_DECL(rsjm_enum, SAI_RXCR, 19, sjm_text); |
---|
791 | 844 | static SOC_ENUM_SINGLE_DECL(rfbm_enum, SAI_RXCR, 18, fbm_text); |
---|
792 | 845 | static SOC_ENUM_SINGLE_DECL(rvdj_enum, SAI_RXCR, 10, vdj_text); |
---|
.. | .. |
---|
874 | 927 | return 1; |
---|
875 | 928 | } |
---|
876 | 929 | |
---|
| 930 | +static int rockchip_sai_tx_lanes_get(struct snd_kcontrol *kcontrol, |
---|
| 931 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 932 | +{ |
---|
| 933 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 934 | + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); |
---|
| 935 | + |
---|
| 936 | + ucontrol->value.enumerated.item[0] = sai->tx_lanes; |
---|
| 937 | + |
---|
| 938 | + return 0; |
---|
| 939 | +} |
---|
| 940 | + |
---|
| 941 | +static int rockchip_sai_tx_lanes_put(struct snd_kcontrol *kcontrol, |
---|
| 942 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 943 | +{ |
---|
| 944 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 945 | + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); |
---|
| 946 | + int num; |
---|
| 947 | + |
---|
| 948 | + num = ucontrol->value.enumerated.item[0]; |
---|
| 949 | + if (num >= ARRAY_SIZE(tx_lanes_text)) |
---|
| 950 | + return -EINVAL; |
---|
| 951 | + |
---|
| 952 | + sai->tx_lanes = num; |
---|
| 953 | + |
---|
| 954 | + return 1; |
---|
| 955 | +} |
---|
| 956 | + |
---|
| 957 | +static int rockchip_sai_rx_lanes_get(struct snd_kcontrol *kcontrol, |
---|
| 958 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 959 | +{ |
---|
| 960 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 961 | + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); |
---|
| 962 | + |
---|
| 963 | + ucontrol->value.enumerated.item[0] = sai->rx_lanes; |
---|
| 964 | + |
---|
| 965 | + return 0; |
---|
| 966 | +} |
---|
| 967 | + |
---|
| 968 | +static int rockchip_sai_rx_lanes_put(struct snd_kcontrol *kcontrol, |
---|
| 969 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 970 | +{ |
---|
| 971 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 972 | + struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component); |
---|
| 973 | + int num; |
---|
| 974 | + |
---|
| 975 | + num = ucontrol->value.enumerated.item[0]; |
---|
| 976 | + if (num >= ARRAY_SIZE(rx_lanes_text)) |
---|
| 977 | + return -EINVAL; |
---|
| 978 | + |
---|
| 979 | + sai->rx_lanes = num; |
---|
| 980 | + |
---|
| 981 | + return 1; |
---|
| 982 | +} |
---|
| 983 | + |
---|
877 | 984 | static DECLARE_TLV_DB_SCALE(fs_shift_tlv, 0, 8192, 0); |
---|
878 | 985 | |
---|
879 | 986 | static const struct snd_kcontrol_new rockchip_sai_controls[] = { |
---|
880 | 987 | |
---|
881 | 988 | SOC_ENUM("Transmit Edge Shift", tsft_enum), |
---|
882 | | - SOC_ENUM("Transmit SDOx Select", tcsr_enum), |
---|
| 989 | + SOC_ENUM_EXT("Transmit SDOx Select", tx_lanes_enum, |
---|
| 990 | + rockchip_sai_tx_lanes_get, rockchip_sai_tx_lanes_put), |
---|
883 | 991 | SOC_ENUM("Transmit Store Justified Mode", tsjm_enum), |
---|
884 | 992 | SOC_ENUM("Transmit First Bit Mode", tfbm_enum), |
---|
885 | 993 | SOC_ENUM("Transmit Valid Data Justified", tvdj_enum), |
---|
886 | 994 | SOC_ENUM("Transmit Slot Bit Width", tsbw_enum), |
---|
887 | 995 | |
---|
888 | 996 | SOC_ENUM("Receive Edge Shift", rsft_enum), |
---|
889 | | - SOC_ENUM("Receive SDIx Select", rcsr_enum), |
---|
| 997 | + SOC_ENUM_EXT("Receive SDIx Select", rx_lanes_enum, |
---|
| 998 | + rockchip_sai_rx_lanes_get, rockchip_sai_rx_lanes_put), |
---|
890 | 999 | SOC_ENUM("Receive Store Justified Mode", rsjm_enum), |
---|
891 | 1000 | SOC_ENUM("Receive First Bit Mode", rfbm_enum), |
---|
892 | 1001 | SOC_ENUM("Receive Valid Data Justified", rvdj_enum), |
---|
.. | .. |
---|
966 | 1075 | return IRQ_HANDLED; |
---|
967 | 1076 | } |
---|
968 | 1077 | |
---|
| 1078 | +static int rockchip_sai_keep_clk_always_on(struct rk_sai_dev *sai) |
---|
| 1079 | +{ |
---|
| 1080 | + unsigned int mclk_rate, bclk_rate, div_bclk; |
---|
| 1081 | + |
---|
| 1082 | + sai->is_master_mode = true; |
---|
| 1083 | + |
---|
| 1084 | + /* init I2S fmt default */ |
---|
| 1085 | + rockchip_sai_fmt_create(sai, SND_SOC_DAIFMT_I2S); |
---|
| 1086 | + |
---|
| 1087 | + regmap_update_bits(sai->regmap, SAI_FSCR, |
---|
| 1088 | + SAI_FSCR_FW_MASK | |
---|
| 1089 | + SAI_FSCR_FPW_MASK, |
---|
| 1090 | + SAI_FSCR_FW(64) | |
---|
| 1091 | + SAI_FSCR_FPW(32)); |
---|
| 1092 | + |
---|
| 1093 | + mclk_rate = clk_get_rate(sai->mclk); |
---|
| 1094 | + bclk_rate = DEFAULT_FS * 64; |
---|
| 1095 | + div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); |
---|
| 1096 | + |
---|
| 1097 | + regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK, |
---|
| 1098 | + SAI_CKR_MDIV(div_bclk)); |
---|
| 1099 | + |
---|
| 1100 | + pm_runtime_forbid(sai->dev); |
---|
| 1101 | + |
---|
| 1102 | + dev_info(sai->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n", |
---|
| 1103 | + mclk_rate, bclk_rate, DEFAULT_FS); |
---|
| 1104 | + |
---|
| 1105 | + return 0; |
---|
| 1106 | +} |
---|
| 1107 | + |
---|
| 1108 | +static int rockchip_sai_parse_quirks(struct rk_sai_dev *sai) |
---|
| 1109 | +{ |
---|
| 1110 | + int ret = 0, i = 0; |
---|
| 1111 | + |
---|
| 1112 | + for (i = 0; i < ARRAY_SIZE(of_quirks); i++) |
---|
| 1113 | + if (of_property_read_bool(sai->dev->of_node, of_quirks[i].quirk)) |
---|
| 1114 | + sai->quirks |= of_quirks[i].id; |
---|
| 1115 | + |
---|
| 1116 | + if (sai->quirks & QUIRK_ALWAYS_ON) |
---|
| 1117 | + ret = rockchip_sai_keep_clk_always_on(sai); |
---|
| 1118 | + |
---|
| 1119 | + return ret; |
---|
| 1120 | +} |
---|
| 1121 | + |
---|
969 | 1122 | static int rockchip_sai_probe(struct platform_device *pdev) |
---|
970 | 1123 | { |
---|
971 | 1124 | struct device_node *node = pdev->dev.of_node; |
---|
.. | .. |
---|
1022 | 1175 | return PTR_ERR(sai->hclk); |
---|
1023 | 1176 | } |
---|
1024 | 1177 | |
---|
1025 | | - ret = clk_prepare_enable(sai->hclk); |
---|
| 1178 | + ret = rockchip_sai_parse_quirks(sai); |
---|
1026 | 1179 | if (ret) |
---|
1027 | 1180 | return ret; |
---|
1028 | 1181 | |
---|
1029 | 1182 | pm_runtime_enable(&pdev->dev); |
---|
1030 | 1183 | if (!pm_runtime_enabled(&pdev->dev)) { |
---|
1031 | | - ret = sai_runtime_resume(&pdev->dev); |
---|
| 1184 | + ret = rockchip_sai_runtime_resume(&pdev->dev); |
---|
1032 | 1185 | if (ret) |
---|
1033 | 1186 | goto err_runtime_disable; |
---|
1034 | 1187 | } |
---|
.. | .. |
---|
1051 | 1204 | |
---|
1052 | 1205 | err_runtime_suspend: |
---|
1053 | 1206 | if (!pm_runtime_status_suspended(&pdev->dev)) |
---|
1054 | | - sai_runtime_suspend(&pdev->dev); |
---|
| 1207 | + rockchip_sai_runtime_suspend(&pdev->dev); |
---|
1055 | 1208 | err_runtime_disable: |
---|
1056 | 1209 | pm_runtime_disable(&pdev->dev); |
---|
1057 | | - clk_disable_unprepare(sai->hclk); |
---|
1058 | 1210 | |
---|
1059 | 1211 | return ret; |
---|
1060 | 1212 | } |
---|
1061 | 1213 | |
---|
1062 | 1214 | static int rockchip_sai_remove(struct platform_device *pdev) |
---|
1063 | 1215 | { |
---|
1064 | | - struct rk_sai_dev *sai = dev_get_drvdata(&pdev->dev); |
---|
1065 | | - |
---|
1066 | 1216 | pm_runtime_disable(&pdev->dev); |
---|
1067 | 1217 | if (!pm_runtime_status_suspended(&pdev->dev)) |
---|
1068 | | - sai_runtime_suspend(&pdev->dev); |
---|
1069 | | - |
---|
1070 | | - clk_disable_unprepare(sai->hclk); |
---|
| 1218 | + rockchip_sai_runtime_suspend(&pdev->dev); |
---|
1071 | 1219 | |
---|
1072 | 1220 | return 0; |
---|
1073 | 1221 | } |
---|
1074 | 1222 | |
---|
| 1223 | +#ifdef CONFIG_PM_SLEEP |
---|
| 1224 | +static int rockchip_sai_suspend(struct device *dev) |
---|
| 1225 | +{ |
---|
| 1226 | + struct rk_sai_dev *sai = dev_get_drvdata(dev); |
---|
| 1227 | + |
---|
| 1228 | + regcache_mark_dirty(sai->regmap); |
---|
| 1229 | + |
---|
| 1230 | + return 0; |
---|
| 1231 | +} |
---|
| 1232 | + |
---|
| 1233 | +static int rockchip_sai_resume(struct device *dev) |
---|
| 1234 | +{ |
---|
| 1235 | + struct rk_sai_dev *sai = dev_get_drvdata(dev); |
---|
| 1236 | + int ret = pm_runtime_get_sync(dev); |
---|
| 1237 | + |
---|
| 1238 | + if (ret < 0) { |
---|
| 1239 | + pm_runtime_put_noidle(dev); |
---|
| 1240 | + return ret; |
---|
| 1241 | + } |
---|
| 1242 | + |
---|
| 1243 | + ret = regcache_sync(sai->regmap); |
---|
| 1244 | + pm_runtime_put(dev); |
---|
| 1245 | + |
---|
| 1246 | + return ret; |
---|
| 1247 | +} |
---|
| 1248 | +#endif /* CONFIG_PM_SLEEP */ |
---|
| 1249 | + |
---|
1075 | 1250 | static const struct dev_pm_ops rockchip_sai_pm_ops = { |
---|
1076 | | - SET_RUNTIME_PM_OPS(sai_runtime_suspend, sai_runtime_resume, NULL) |
---|
| 1251 | + SET_RUNTIME_PM_OPS(rockchip_sai_runtime_suspend, rockchip_sai_runtime_resume, NULL) |
---|
| 1252 | + SET_SYSTEM_SLEEP_PM_OPS(rockchip_sai_suspend, rockchip_sai_resume) |
---|
1077 | 1253 | }; |
---|
1078 | 1254 | |
---|
1079 | 1255 | static struct platform_driver rockchip_sai_driver = { |
---|