Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Add static channel mapping between soundwire master

Merge series from Mohammad Rafi Shaik <quic_mohs@quicinc.com>:

Add static channel map support between soundwire master and slave.

Currently, the channel value for each soundwire port is hardcoded in the
wcd937x-sdw driver and the same channel value is configured in the
soundwire master.

The Qualcomm board like the QCM6490-IDP require static channel map
settings for the soundwire master and slave ports.

If another boards which are using enable wcd937x, the channel mapping
index values between master and slave may be different depending on the
board hw design and requirements. If the above properties are not used
in a SoC specific device tree, the channel mapping index values are set
to default.

With the introduction of the following channel mapping properties, it is
now possible to configure the master channel mapping directly from the
device tree.

Added qcom_swrm_set_channel_map api to set the master channel values
which allows more flexible to configure channel values in runtime for
specific active soundwire ports.

Add get and set channel maps support from codec to cpu dais in common
Qualcomm sdw driver.

+185 -10
+36
Documentation/devicetree/bindings/sound/qcom,wcd937x-sdw.yaml
··· 58 58 items: 59 59 enum: [1, 2, 3, 4, 5] 60 60 61 + qcom,tx-channel-mapping: 62 + description: | 63 + Specifies static channel mapping between slave and master tx port 64 + channels. 65 + In the order of slave port channels which is adc1, adc2, adc3, 66 + dmic0, dmic1, mbhc, dmic2, dmic3, dmci4, dmic5, dmic6, dmic7. 67 + $ref: /schemas/types.yaml#/definitions/uint8-array 68 + minItems: 12 69 + maxItems: 12 70 + additionalItems: false 71 + items: 72 + enum: 73 + - 1 # WCD9370_SWRM_CH1 74 + - 2 # WCD9370_SWRM_CH2 75 + - 3 # WCD9370_SWRM_CH3 76 + - 4 # WCD9370_SWRM_CH4 77 + 78 + qcom,rx-channel-mapping: 79 + description: | 80 + Specifies static channels mapping between slave and master rx port 81 + channels. 82 + In the order of slave port channels, which is 83 + hph_l, hph_r, clsh, comp_l, comp_r, lo, dsd_r, dsd_l. 84 + $ref: /schemas/types.yaml#/definitions/uint8-array 85 + minItems: 8 86 + maxItems: 8 87 + additionalItems: false 88 + items: 89 + enum: 90 + - 1 # WCD9370_SWRM_CH1 91 + - 2 # WCD9370_SWRM_CH2 92 + - 3 # WCD9370_SWRM_CH3 93 + - 4 # WCD9370_SWRM_CH4 94 + 61 95 required: 62 96 - compatible 63 97 - reg ··· 108 74 compatible = "sdw20217010a00"; 109 75 reg = <0 4>; 110 76 qcom,rx-port-mapping = <1 2 3 4 5>; 77 + qcom,rx-channel-mapping = /bits/ 8 <1 2 1 1 2 1 1 2>; 111 78 }; 112 79 }; 113 80 ··· 120 85 compatible = "sdw20217010a00"; 121 86 reg = <0 3>; 122 87 qcom,tx-port-mapping = <2 2 3 4>; 88 + qcom,tx-channel-mapping = /bits/ 8 <1 2 1 1 2 3 3 4 1 2 3 4>; 123 89 }; 124 90 }; 125 91
+26
drivers/soundwire/qcom.c
··· 156 156 u8 word_length; 157 157 u8 blk_group_count; 158 158 u8 lane_control; 159 + u8 ch_mask; 159 160 }; 160 161 161 162 /* ··· 1049 1048 { 1050 1049 u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank); 1051 1050 struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); 1051 + struct qcom_swrm_port_config *pcfg; 1052 1052 u32 val; 1053 1053 1054 + pcfg = &ctrl->pconfig[enable_ch->port_num]; 1054 1055 ctrl->reg_read(ctrl, reg, &val); 1056 + if (pcfg->ch_mask != SWR_INVALID_PARAM && pcfg->ch_mask != 0) 1057 + enable_ch->ch_mask = pcfg->ch_mask; 1055 1058 1056 1059 if (enable_ch->enable) 1057 1060 val |= (enable_ch->ch_mask << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT); ··· 1275 1270 return ctrl->sruntime[dai->id]; 1276 1271 } 1277 1272 1273 + static int qcom_swrm_set_channel_map(struct snd_soc_dai *dai, 1274 + unsigned int tx_num, const unsigned int *tx_slot, 1275 + unsigned int rx_num, const unsigned int *rx_slot) 1276 + { 1277 + struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); 1278 + int i; 1279 + 1280 + if (tx_slot) { 1281 + for (i = 0; i < tx_num; i++) 1282 + ctrl->pconfig[i].ch_mask = tx_slot[i]; 1283 + } 1284 + 1285 + if (rx_slot) { 1286 + for (i = 0; i < rx_num; i++) 1287 + ctrl->pconfig[i].ch_mask = rx_slot[i]; 1288 + } 1289 + 1290 + return 0; 1291 + } 1292 + 1278 1293 static int qcom_swrm_startup(struct snd_pcm_substream *substream, 1279 1294 struct snd_soc_dai *dai) 1280 1295 { ··· 1331 1306 .shutdown = qcom_swrm_shutdown, 1332 1307 .set_stream = qcom_swrm_set_sdw_stream, 1333 1308 .get_stream = qcom_swrm_get_sdw_stream, 1309 + .set_channel_map = qcom_swrm_set_channel_map, 1334 1310 }; 1335 1311 1336 1312 static const struct snd_soc_component_driver qcom_swrm_dai_component = {
+35 -4
sound/soc/codecs/wcd937x-sdw.c
··· 19 19 #include <sound/soc.h> 20 20 #include "wcd937x.h" 21 21 22 - static const struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = { 22 + static struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = { 23 23 WCD_SDW_CH(WCD937X_HPH_L, WCD937X_HPH_PORT, BIT(0)), 24 24 WCD_SDW_CH(WCD937X_HPH_R, WCD937X_HPH_PORT, BIT(1)), 25 25 WCD_SDW_CH(WCD937X_CLSH, WCD937X_CLSH_PORT, BIT(0)), ··· 30 30 WCD_SDW_CH(WCD937X_DSD_R, WCD937X_DSD_PORT, BIT(1)), 31 31 }; 32 32 33 - static const struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = { 33 + static struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = { 34 34 WCD_SDW_CH(WCD937X_ADC1, WCD937X_ADC_1_PORT, BIT(0)), 35 35 WCD_SDW_CH(WCD937X_ADC2, WCD937X_ADC_2_3_PORT, BIT(0)), 36 36 WCD_SDW_CH(WCD937X_ADC3, WCD937X_ADC_2_3_PORT, BIT(0)), ··· 1019 1019 { 1020 1020 struct device *dev = &pdev->dev; 1021 1021 struct wcd937x_sdw_priv *wcd; 1022 - int ret; 1022 + u8 master_ch_mask[WCD937X_MAX_SWR_CH_IDS]; 1023 + int master_ch_mask_size = 0; 1024 + int ret, i; 1023 1025 1024 1026 wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); 1025 1027 if (!wcd) ··· 1050 1048 SDW_SCP_INT1_PARITY; 1051 1049 pdev->prop.lane_control_support = true; 1052 1050 pdev->prop.simple_clk_stop_capable = true; 1051 + 1052 + memset(master_ch_mask, 0, WCD937X_MAX_SWR_CH_IDS); 1053 + 1053 1054 if (wcd->is_tx) { 1054 - pdev->prop.source_ports = GENMASK(WCD937X_MAX_TX_SWR_PORTS - 1, 0); 1055 + master_ch_mask_size = of_property_count_u8_elems(dev->of_node, 1056 + "qcom,tx-channel-mapping"); 1057 + 1058 + if (master_ch_mask_size) 1059 + ret = of_property_read_u8_array(dev->of_node, "qcom,tx-channel-mapping", 1060 + master_ch_mask, master_ch_mask_size); 1061 + } else { 1062 + master_ch_mask_size = of_property_count_u8_elems(dev->of_node, 1063 + "qcom,rx-channel-mapping"); 1064 + 1065 + if (master_ch_mask_size) 1066 + ret = of_property_read_u8_array(dev->of_node, "qcom,rx-channel-mapping", 1067 + master_ch_mask, master_ch_mask_size); 1068 + } 1069 + 1070 + if (ret < 0) 1071 + dev_info(dev, "Static channel mapping not specified using device channel maps\n"); 1072 + 1073 + if (wcd->is_tx) { 1074 + pdev->prop.source_ports = GENMASK(WCD937X_MAX_TX_SWR_PORTS, 0); 1055 1075 pdev->prop.src_dpn_prop = wcd937x_dpn_prop; 1056 1076 wcd->ch_info = &wcd937x_sdw_tx_ch_info[0]; 1077 + 1078 + for (i = 0; i < master_ch_mask_size; i++) 1079 + wcd->ch_info[i].master_ch_mask = WCD937X_SWRM_CH_MASK(master_ch_mask[i]); 1080 + 1057 1081 pdev->prop.wake_capable = true; 1058 1082 1059 1083 wcd->regmap = devm_regmap_init_sdw(pdev, &wcd937x_regmap_config); ··· 1093 1065 pdev->prop.sink_ports = GENMASK(WCD937X_MAX_SWR_PORTS - 1, 0); 1094 1066 pdev->prop.sink_dpn_prop = wcd937x_dpn_prop; 1095 1067 wcd->ch_info = &wcd937x_sdw_rx_ch_info[0]; 1068 + 1069 + for (i = 0; i < master_ch_mask_size; i++) 1070 + wcd->ch_info[i].master_ch_mask = WCD937X_SWRM_CH_MASK(master_ch_mask[i]); 1096 1071 } 1097 1072 1098 1073
+51 -2
sound/soc/codecs/wcd937x.c
··· 1197 1197 const struct wcd937x_sdw_ch_info *ch_info = &wcd->ch_info[ch_id]; 1198 1198 u8 port_num = ch_info->port_num; 1199 1199 u8 ch_mask = ch_info->ch_mask; 1200 + u8 mstr_port_num, mstr_ch_mask; 1201 + struct sdw_slave *sdev = wcd->sdev; 1200 1202 1201 1203 port_config->num = port_num; 1202 1204 1203 - if (enable) 1205 + mstr_port_num = sdev->m_port_map[port_num]; 1206 + mstr_ch_mask = ch_info->master_ch_mask; 1207 + 1208 + if (enable) { 1204 1209 port_config->ch_mask |= ch_mask; 1205 - else 1210 + wcd->master_channel_map[mstr_port_num] |= mstr_ch_mask; 1211 + } else { 1206 1212 port_config->ch_mask &= ~ch_mask; 1213 + wcd->master_channel_map[mstr_port_num] &= ~mstr_ch_mask; 1214 + } 1207 1215 1208 1216 return 0; 1209 1217 } ··· 2697 2689 return 0; 2698 2690 } 2699 2691 2692 + static int wcd937x_get_channel_map(const struct snd_soc_dai *dai, 2693 + unsigned int *tx_num, unsigned int *tx_slot, 2694 + unsigned int *rx_num, unsigned int *rx_slot) 2695 + { 2696 + struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev); 2697 + struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id]; 2698 + int i; 2699 + 2700 + switch (dai->id) { 2701 + case AIF1_PB: 2702 + if (!rx_slot || !rx_num) { 2703 + dev_err(dai->dev, "Invalid rx_slot %p or rx_num %p\n", 2704 + rx_slot, rx_num); 2705 + return -EINVAL; 2706 + } 2707 + 2708 + for (i = 0; i < SDW_MAX_PORTS; i++) 2709 + rx_slot[i] = wcd->master_channel_map[i]; 2710 + 2711 + *rx_num = i; 2712 + break; 2713 + case AIF1_CAP: 2714 + if (!tx_slot || !tx_num) { 2715 + dev_err(dai->dev, "Invalid tx_slot %p or tx_num %p\n", 2716 + tx_slot, tx_num); 2717 + return -EINVAL; 2718 + } 2719 + 2720 + for (i = 0; i < SDW_MAX_PORTS; i++) 2721 + tx_slot[i] = wcd->master_channel_map[i]; 2722 + 2723 + *tx_num = i; 2724 + break; 2725 + default: 2726 + break; 2727 + } 2728 + 2729 + return 0; 2730 + } 2731 + 2700 2732 static const struct snd_soc_dai_ops wcd937x_sdw_dai_ops = { 2701 2733 .hw_params = wcd937x_codec_hw_params, 2702 2734 .hw_free = wcd937x_codec_free, 2703 2735 .set_stream = wcd937x_codec_set_sdw_stream, 2736 + .get_channel_map = wcd937x_get_channel_map, 2704 2737 }; 2705 2738 2706 2739 static struct snd_soc_dai_driver wcd937x_dais[] = {
+6 -1
sound/soc/codecs/wcd937x.h
··· 489 489 #define WCD937X_MAX_MICBIAS 3 490 490 #define WCD937X_MAX_BULK_SUPPLY 4 491 491 #define WCD937X_MAX_SWR_CH_IDS 15 492 + #define WCD937X_SWRM_CH_MASK(ch_idx) BIT(ch_idx - 1) 492 493 493 494 enum wcd937x_tx_sdw_ports { 494 495 WCD937X_ADC_1_PORT = 1, ··· 511 510 struct wcd937x_sdw_ch_info { 512 511 int port_num; 513 512 unsigned int ch_mask; 513 + unsigned int master_ch_mask; 514 514 }; 515 515 516 516 #define WCD_SDW_CH(id, pn, cmask) \ 517 517 [id] = { \ 518 518 .port_num = pn, \ 519 519 .ch_mask = cmask, \ 520 + .master_ch_mask = cmask, \ 520 521 } 521 522 522 523 struct wcd937x_priv; ··· 527 524 struct sdw_stream_config sconfig; 528 525 struct sdw_stream_runtime *sruntime; 529 526 struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS]; 530 - const struct wcd937x_sdw_ch_info *ch_info; 527 + struct wcd937x_sdw_ch_info *ch_info; 531 528 bool port_enable[WCD937X_MAX_SWR_CH_IDS]; 529 + unsigned int master_channel_map[SDW_MAX_PORTS]; 532 530 int active_ports; 531 + int num_ports; 533 532 bool is_tx; 534 533 struct wcd937x_priv *wcd937x; 535 534 struct irq_domain *slave_irq;
+31 -3
sound/soc/qcom/sdw.c
··· 23 23 { 24 24 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 25 25 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 26 + u32 rx_ch[SDW_MAX_PORTS], tx_ch[SDW_MAX_PORTS]; 26 27 struct sdw_stream_runtime *sruntime; 27 28 struct snd_soc_dai *codec_dai; 28 - int ret, i; 29 + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; 30 + int ret, i, j; 29 31 30 32 sruntime = sdw_alloc_stream(cpu_dai->name); 31 33 if (!sruntime) ··· 37 35 ret = snd_soc_dai_set_stream(codec_dai, sruntime, 38 36 substream->stream); 39 37 if (ret < 0 && ret != -ENOTSUPP) { 40 - dev_err(rtd->dev, "Failed to set sdw stream on %s\n", 41 - codec_dai->name); 38 + dev_err(rtd->dev, "Failed to set sdw stream on %s\n", codec_dai->name); 42 39 goto err_set_stream; 40 + } else if (ret == -ENOTSUPP) { 41 + /* Ignore unsupported */ 42 + continue; 43 + } 44 + 45 + ret = snd_soc_dai_get_channel_map(codec_dai, &tx_ch_cnt, tx_ch, 46 + &rx_ch_cnt, rx_ch); 47 + if (ret != 0 && ret != -ENOTSUPP) { 48 + dev_err(rtd->dev, "Failed to get codec chan map %s\n", codec_dai->name); 49 + goto err_set_stream; 50 + } else if (ret == -ENOTSUPP) { 51 + /* Ignore unsupported */ 52 + continue; 53 + } 54 + } 55 + 56 + switch (cpu_dai->id) { 57 + case RX_CODEC_DMA_RX_0: 58 + case TX_CODEC_DMA_TX_3: 59 + if (tx_ch_cnt || rx_ch_cnt) { 60 + for_each_rtd_codec_dais(rtd, j, codec_dai) { 61 + ret = snd_soc_dai_set_channel_map(codec_dai, 62 + tx_ch_cnt, tx_ch, 63 + rx_ch_cnt, rx_ch); 64 + if (ret != 0 && ret != -ENOTSUPP) 65 + goto err_set_stream; 66 + } 43 67 } 44 68 } 45 69