diff options
author | Jyri Sarha <jsarha@ti.com> | 2015-09-09 14:27:44 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-09-16 12:59:15 -0400 |
commit | dd55ff8346a972cca1ad056c8258ee96d090633e (patch) | |
tree | 3f264b123c8ded9c269088738ebca657c6aed974 | |
parent | 6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff) |
ASoC: davinci-mcasp: Add set_tdm_slots() support
Implements set_tdm_slot() callback for mcasp. Channel constraints are
updated according to the configured tdm mask and slots each time
set_tdm_slot() is called. The special case when slot width is set to
zero is allowed and it means that slot width is the same as the sample
width.
Signed-off-by: Jyri Sarha <jsarha@ti.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 255 |
1 files changed, 174 insertions, 81 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index add6bb99661d..fa47a39fac86 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -80,6 +80,8 @@ struct davinci_mcasp { | |||
80 | 80 | ||
81 | /* McASP specific data */ | 81 | /* McASP specific data */ |
82 | int tdm_slots; | 82 | int tdm_slots; |
83 | u32 tdm_mask[2]; | ||
84 | int slot_width; | ||
83 | u8 op_mode; | 85 | u8 op_mode; |
84 | u8 num_serializer; | 86 | u8 num_serializer; |
85 | u8 *serial_dir; | 87 | u8 *serial_dir; |
@@ -596,6 +598,84 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
596 | return 0; | 598 | return 0; |
597 | } | 599 | } |
598 | 600 | ||
601 | /* All serializers must have equal number of channels */ | ||
602 | static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream, | ||
603 | int serializers) | ||
604 | { | ||
605 | struct snd_pcm_hw_constraint_list *cl = &mcasp->chconstr[stream]; | ||
606 | unsigned int *list = (unsigned int *) cl->list; | ||
607 | int slots = mcasp->tdm_slots; | ||
608 | int i, count = 0; | ||
609 | |||
610 | if (mcasp->tdm_mask[stream]) | ||
611 | slots = hweight32(mcasp->tdm_mask[stream]); | ||
612 | |||
613 | for (i = 2; i <= slots; i++) | ||
614 | list[count++] = i; | ||
615 | |||
616 | for (i = 2; i <= serializers; i++) | ||
617 | list[count++] = i*slots; | ||
618 | |||
619 | cl->count = count; | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp) | ||
625 | { | ||
626 | int rx_serializers = 0, tx_serializers = 0, ret, i; | ||
627 | |||
628 | for (i = 0; i < mcasp->num_serializer; i++) | ||
629 | if (mcasp->serial_dir[i] == TX_MODE) | ||
630 | tx_serializers++; | ||
631 | else if (mcasp->serial_dir[i] == RX_MODE) | ||
632 | rx_serializers++; | ||
633 | |||
634 | ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK, | ||
635 | tx_serializers); | ||
636 | if (ret) | ||
637 | return ret; | ||
638 | |||
639 | ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE, | ||
640 | rx_serializers); | ||
641 | |||
642 | return ret; | ||
643 | } | ||
644 | |||
645 | |||
646 | static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, | ||
647 | unsigned int tx_mask, | ||
648 | unsigned int rx_mask, | ||
649 | int slots, int slot_width) | ||
650 | { | ||
651 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | ||
652 | |||
653 | dev_dbg(mcasp->dev, | ||
654 | "%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n", | ||
655 | __func__, tx_mask, rx_mask, slots, slot_width); | ||
656 | |||
657 | if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) { | ||
658 | dev_err(mcasp->dev, | ||
659 | "Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n", | ||
660 | tx_mask, rx_mask, slots); | ||
661 | return -EINVAL; | ||
662 | } | ||
663 | |||
664 | if (slot_width && | ||
665 | (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) { | ||
666 | dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n", | ||
667 | __func__, slot_width); | ||
668 | return -EINVAL; | ||
669 | } | ||
670 | |||
671 | mcasp->tdm_slots = slots; | ||
672 | mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = rx_mask; | ||
673 | mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = tx_mask; | ||
674 | mcasp->slot_width = slot_width; | ||
675 | |||
676 | return davinci_mcasp_set_ch_constraints(mcasp); | ||
677 | } | ||
678 | |||
599 | static int davinci_config_channel_size(struct davinci_mcasp *mcasp, | 679 | static int davinci_config_channel_size(struct davinci_mcasp *mcasp, |
600 | int word_length) | 680 | int word_length) |
601 | { | 681 | { |
@@ -632,6 +712,9 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, | |||
632 | */ | 712 | */ |
633 | rx_rotate = (slot_length - word_length) / 4; | 713 | rx_rotate = (slot_length - word_length) / 4; |
634 | word_length = slot_length; | 714 | word_length = slot_length; |
715 | } else if (mcasp->slot_width) { | ||
716 | rx_rotate = (mcasp->slot_width - word_length) / 4; | ||
717 | word_length = mcasp->slot_width; | ||
635 | } | 718 | } |
636 | 719 | ||
637 | /* mapping of the XSSZ bit-field as described in the datasheet */ | 720 | /* mapping of the XSSZ bit-field as described in the datasheet */ |
@@ -777,33 +860,50 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, | |||
777 | 860 | ||
778 | /* | 861 | /* |
779 | * If more than one serializer is needed, then use them with | 862 | * If more than one serializer is needed, then use them with |
780 | * their specified tdm_slots count. Otherwise, one serializer | 863 | * all the specified tdm_slots. Otherwise, one serializer can |
781 | * can cope with the transaction using as many slots as channels | 864 | * cope with the transaction using just as many slots as there |
782 | * in the stream, requires channels symmetry | 865 | * are channels in the stream. |
783 | */ | 866 | */ |
784 | active_serializers = (channels + total_slots - 1) / total_slots; | 867 | if (mcasp->tdm_mask[stream]) { |
785 | if (active_serializers == 1) | 868 | active_slots = hweight32(mcasp->tdm_mask[stream]); |
786 | active_slots = channels; | 869 | active_serializers = (channels + active_slots - 1) / |
787 | else | 870 | active_slots; |
788 | active_slots = total_slots; | 871 | if (active_serializers == 1) { |
789 | 872 | active_slots = channels; | |
790 | for (i = 0; i < active_slots; i++) | 873 | for (i = 0; i < total_slots; i++) { |
791 | mask |= (1 << i); | 874 | if ((1 << i) & mcasp->tdm_mask[stream]) { |
875 | mask |= (1 << i); | ||
876 | if (--active_slots <= 0) | ||
877 | break; | ||
878 | } | ||
879 | } | ||
880 | } | ||
881 | } else { | ||
882 | active_serializers = (channels + total_slots - 1) / total_slots; | ||
883 | if (active_serializers == 1) | ||
884 | active_slots = channels; | ||
885 | else | ||
886 | active_slots = total_slots; | ||
792 | 887 | ||
888 | for (i = 0; i < active_slots; i++) | ||
889 | mask |= (1 << i); | ||
890 | } | ||
793 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC); | 891 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC); |
794 | 892 | ||
795 | if (!mcasp->dat_port) | 893 | if (!mcasp->dat_port) |
796 | busel = TXSEL; | 894 | busel = TXSEL; |
797 | 895 | ||
798 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); | 896 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
799 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); | 897 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); |
800 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, | 898 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); |
801 | FSXMOD(total_slots), FSXMOD(0x1FF)); | 899 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, |
802 | 900 | FSXMOD(total_slots), FSXMOD(0x1FF)); | |
803 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); | 901 | } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { |
804 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); | 902 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); |
805 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, | 903 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); |
806 | FSRMOD(total_slots), FSRMOD(0x1FF)); | 904 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, |
905 | FSRMOD(total_slots), FSRMOD(0x1FF)); | ||
906 | } | ||
807 | 907 | ||
808 | return 0; | 908 | return 0; |
809 | } | 909 | } |
@@ -923,6 +1023,9 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
923 | int sbits = params_width(params); | 1023 | int sbits = params_width(params); |
924 | int ppm, div; | 1024 | int ppm, div; |
925 | 1025 | ||
1026 | if (mcasp->slot_width) | ||
1027 | sbits = mcasp->slot_width; | ||
1028 | |||
926 | div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*slots, | 1029 | div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*slots, |
927 | &ppm); | 1030 | &ppm); |
928 | if (ppm) | 1031 | if (ppm) |
@@ -1028,6 +1131,9 @@ static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params, | |||
1028 | struct snd_interval range; | 1131 | struct snd_interval range; |
1029 | int i; | 1132 | int i; |
1030 | 1133 | ||
1134 | if (rd->mcasp->slot_width) | ||
1135 | sbits = rd->mcasp->slot_width; | ||
1136 | |||
1031 | snd_interval_any(&range); | 1137 | snd_interval_any(&range); |
1032 | range.empty = 1; | 1138 | range.empty = 1; |
1033 | 1139 | ||
@@ -1070,10 +1176,14 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, | |||
1070 | 1176 | ||
1071 | for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { | 1177 | for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { |
1072 | if (snd_mask_test(fmt, i)) { | 1178 | if (snd_mask_test(fmt, i)) { |
1073 | uint bclk_freq = snd_pcm_format_width(i)*slots*rate; | 1179 | uint sbits = snd_pcm_format_width(i); |
1074 | int ppm; | 1180 | int ppm; |
1075 | 1181 | ||
1076 | davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm); | 1182 | if (rd->mcasp->slot_width) |
1183 | sbits = rd->mcasp->slot_width; | ||
1184 | |||
1185 | davinci_mcasp_calc_clk_div(rd->mcasp, sbits*slots*rate, | ||
1186 | &ppm); | ||
1077 | if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { | 1187 | if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { |
1078 | snd_mask_set(&nfmt, i); | 1188 | snd_mask_set(&nfmt, i); |
1079 | count++; | 1189 | count++; |
@@ -1095,6 +1205,10 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | |||
1095 | &mcasp->ruledata[substream->stream]; | 1205 | &mcasp->ruledata[substream->stream]; |
1096 | u32 max_channels = 0; | 1206 | u32 max_channels = 0; |
1097 | int i, dir; | 1207 | int i, dir; |
1208 | int tdm_slots = mcasp->tdm_slots; | ||
1209 | |||
1210 | if (mcasp->tdm_mask[substream->stream]) | ||
1211 | tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]); | ||
1098 | 1212 | ||
1099 | mcasp->substreams[substream->stream] = substream; | 1213 | mcasp->substreams[substream->stream] = substream; |
1100 | 1214 | ||
@@ -1115,7 +1229,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | |||
1115 | max_channels++; | 1229 | max_channels++; |
1116 | } | 1230 | } |
1117 | ruledata->serializers = max_channels; | 1231 | ruledata->serializers = max_channels; |
1118 | max_channels *= mcasp->tdm_slots; | 1232 | max_channels *= tdm_slots; |
1119 | /* | 1233 | /* |
1120 | * If the already active stream has less channels than the calculated | 1234 | * If the already active stream has less channels than the calculated |
1121 | * limnit based on the seirializers * tdm_slots, we need to use that as | 1235 | * limnit based on the seirializers * tdm_slots, we need to use that as |
@@ -1125,15 +1239,25 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | |||
1125 | */ | 1239 | */ |
1126 | if (mcasp->channels && mcasp->channels < max_channels) | 1240 | if (mcasp->channels && mcasp->channels < max_channels) |
1127 | max_channels = mcasp->channels; | 1241 | max_channels = mcasp->channels; |
1242 | /* | ||
1243 | * But we can always allow channels upto the amount of | ||
1244 | * the available tdm_slots. | ||
1245 | */ | ||
1246 | if (max_channels < tdm_slots) | ||
1247 | max_channels = tdm_slots; | ||
1128 | 1248 | ||
1129 | snd_pcm_hw_constraint_minmax(substream->runtime, | 1249 | snd_pcm_hw_constraint_minmax(substream->runtime, |
1130 | SNDRV_PCM_HW_PARAM_CHANNELS, | 1250 | SNDRV_PCM_HW_PARAM_CHANNELS, |
1131 | 2, max_channels); | 1251 | 2, max_channels); |
1132 | 1252 | ||
1133 | if (mcasp->chconstr[substream->stream].count) | 1253 | snd_pcm_hw_constraint_list(substream->runtime, |
1134 | snd_pcm_hw_constraint_list(substream->runtime, | 1254 | 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
1135 | 0, SNDRV_PCM_HW_PARAM_CHANNELS, | 1255 | &mcasp->chconstr[substream->stream]); |
1136 | &mcasp->chconstr[substream->stream]); | 1256 | |
1257 | if (mcasp->slot_width) | ||
1258 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1259 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
1260 | 8, mcasp->slot_width); | ||
1137 | 1261 | ||
1138 | /* | 1262 | /* |
1139 | * If we rely on implicit BCLK divider setting we should | 1263 | * If we rely on implicit BCLK divider setting we should |
@@ -1185,6 +1309,7 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { | |||
1185 | .set_fmt = davinci_mcasp_set_dai_fmt, | 1309 | .set_fmt = davinci_mcasp_set_dai_fmt, |
1186 | .set_clkdiv = davinci_mcasp_set_clkdiv, | 1310 | .set_clkdiv = davinci_mcasp_set_clkdiv, |
1187 | .set_sysclk = davinci_mcasp_set_sysclk, | 1311 | .set_sysclk = davinci_mcasp_set_sysclk, |
1312 | .set_tdm_slot = davinci_mcasp_set_tdm_slot, | ||
1188 | }; | 1313 | }; |
1189 | 1314 | ||
1190 | static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) | 1315 | static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) |
@@ -1514,59 +1639,6 @@ nodata: | |||
1514 | return pdata; | 1639 | return pdata; |
1515 | } | 1640 | } |
1516 | 1641 | ||
1517 | /* All serializers must have equal number of channels */ | ||
1518 | static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, | ||
1519 | struct snd_pcm_hw_constraint_list *cl, | ||
1520 | int serializers) | ||
1521 | { | ||
1522 | unsigned int *list; | ||
1523 | int i, count = 0; | ||
1524 | |||
1525 | if (serializers <= 1) | ||
1526 | return 0; | ||
1527 | |||
1528 | list = devm_kzalloc(mcasp->dev, sizeof(unsigned int) * | ||
1529 | (mcasp->tdm_slots + serializers - 2), | ||
1530 | GFP_KERNEL); | ||
1531 | if (!list) | ||
1532 | return -ENOMEM; | ||
1533 | |||
1534 | for (i = 2; i <= mcasp->tdm_slots; i++) | ||
1535 | list[count++] = i; | ||
1536 | |||
1537 | for (i = 2; i <= serializers; i++) | ||
1538 | list[count++] = i*mcasp->tdm_slots; | ||
1539 | |||
1540 | cl->count = count; | ||
1541 | cl->list = list; | ||
1542 | |||
1543 | return 0; | ||
1544 | } | ||
1545 | |||
1546 | |||
1547 | static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp) | ||
1548 | { | ||
1549 | int rx_serializers = 0, tx_serializers = 0, ret, i; | ||
1550 | |||
1551 | for (i = 0; i < mcasp->num_serializer; i++) | ||
1552 | if (mcasp->serial_dir[i] == TX_MODE) | ||
1553 | tx_serializers++; | ||
1554 | else if (mcasp->serial_dir[i] == RX_MODE) | ||
1555 | rx_serializers++; | ||
1556 | |||
1557 | ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[ | ||
1558 | SNDRV_PCM_STREAM_PLAYBACK], | ||
1559 | tx_serializers); | ||
1560 | if (ret) | ||
1561 | return ret; | ||
1562 | |||
1563 | ret = davinci_mcasp_ch_constraint(mcasp, &mcasp->chconstr[ | ||
1564 | SNDRV_PCM_STREAM_CAPTURE], | ||
1565 | rx_serializers); | ||
1566 | |||
1567 | return ret; | ||
1568 | } | ||
1569 | |||
1570 | enum { | 1642 | enum { |
1571 | PCM_EDMA, | 1643 | PCM_EDMA, |
1572 | PCM_SDMA, | 1644 | PCM_SDMA, |
@@ -1783,7 +1855,28 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1783 | mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; | 1855 | mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; |
1784 | } | 1856 | } |
1785 | 1857 | ||
1786 | ret = davinci_mcasp_init_ch_constraints(mcasp); | 1858 | /* Allocate memory for long enough list for all possible |
1859 | * scenarios. Maximum number tdm slots is 32 and there cannot | ||
1860 | * be more serializers than given in the configuration. The | ||
1861 | * serializer directions could be taken into account, but it | ||
1862 | * would make code much more complex and save only couple of | ||
1863 | * bytes. | ||
1864 | */ | ||
1865 | mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list = | ||
1866 | devm_kzalloc(mcasp->dev, sizeof(unsigned int) * | ||
1867 | (32 + mcasp->num_serializer - 2), | ||
1868 | GFP_KERNEL); | ||
1869 | |||
1870 | mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list = | ||
1871 | devm_kzalloc(mcasp->dev, sizeof(unsigned int) * | ||
1872 | (32 + mcasp->num_serializer - 2), | ||
1873 | GFP_KERNEL); | ||
1874 | |||
1875 | if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list || | ||
1876 | !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) | ||
1877 | return -ENOMEM; | ||
1878 | |||
1879 | ret = davinci_mcasp_set_ch_constraints(mcasp); | ||
1787 | if (ret) | 1880 | if (ret) |
1788 | goto err; | 1881 | goto err; |
1789 | 1882 | ||