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

soundwire: cdns: Add stream routines

Add support for Cadence stream initialization and implement
stream APIs.

Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Signed-off-by: Vinod Koul <vkoul@kernel.org>

+238
+195
drivers/soundwire/cadence_master.c
··· 13 13 #include <linux/mod_devicetable.h> 14 14 #include <linux/soundwire/sdw_registers.h> 15 15 #include <linux/soundwire/sdw.h> 16 + #include <sound/pcm_params.h> 17 + #include <sound/soc.h> 16 18 #include "bus.h" 17 19 #include "cadence_master.h" 18 20 ··· 986 984 return 0; 987 985 } 988 986 EXPORT_SYMBOL(sdw_cdns_probe); 987 + 988 + int cdns_set_sdw_stream(struct snd_soc_dai *dai, 989 + void *stream, bool pcm, int direction) 990 + { 991 + struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); 992 + struct sdw_cdns_dma_data *dma; 993 + 994 + dma = kzalloc(sizeof(*dma), GFP_KERNEL); 995 + if (!dma) 996 + return -ENOMEM; 997 + 998 + if (pcm) 999 + dma->stream_type = SDW_STREAM_PCM; 1000 + else 1001 + dma->stream_type = SDW_STREAM_PDM; 1002 + 1003 + dma->bus = &cdns->bus; 1004 + dma->link_id = cdns->instance; 1005 + 1006 + dma->stream = stream; 1007 + 1008 + if (direction == SNDRV_PCM_STREAM_PLAYBACK) 1009 + dai->playback_dma_data = dma; 1010 + else 1011 + dai->capture_dma_data = dma; 1012 + 1013 + return 0; 1014 + } 1015 + EXPORT_SYMBOL(cdns_set_sdw_stream); 1016 + 1017 + /** 1018 + * cdns_find_pdi() - Find a free PDI 1019 + * 1020 + * @cdns: Cadence instance 1021 + * @num: Number of PDIs 1022 + * @pdi: PDI instances 1023 + * 1024 + * Find and return a free PDI for a given PDI array 1025 + */ 1026 + static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns, 1027 + unsigned int num, struct sdw_cdns_pdi *pdi) 1028 + { 1029 + int i; 1030 + 1031 + for (i = 0; i < num; i++) { 1032 + if (pdi[i].assigned == true) 1033 + continue; 1034 + pdi[i].assigned = true; 1035 + return &pdi[i]; 1036 + } 1037 + 1038 + return NULL; 1039 + } 1040 + 1041 + /** 1042 + * sdw_cdns_config_stream: Configure a stream 1043 + * 1044 + * @cdns: Cadence instance 1045 + * @port: Cadence data port 1046 + * @ch: Channel count 1047 + * @dir: Data direction 1048 + * @pdi: PDI to be used 1049 + */ 1050 + void sdw_cdns_config_stream(struct sdw_cdns *cdns, 1051 + struct sdw_cdns_port *port, 1052 + u32 ch, u32 dir, struct sdw_cdns_pdi *pdi) 1053 + { 1054 + u32 offset, val = 0; 1055 + 1056 + if (dir == SDW_DATA_DIR_RX) 1057 + val = CDNS_PORTCTRL_DIRN; 1058 + 1059 + offset = CDNS_PORTCTRL + port->num * CDNS_PORT_OFFSET; 1060 + cdns_updatel(cdns, offset, CDNS_PORTCTRL_DIRN, val); 1061 + 1062 + val = port->num; 1063 + val |= ((1 << ch) - 1) << SDW_REG_SHIFT(CDNS_PDI_CONFIG_CHANNEL); 1064 + cdns_writel(cdns, CDNS_PDI_CONFIG(pdi->num), val); 1065 + } 1066 + EXPORT_SYMBOL(sdw_cdns_config_stream); 1067 + 1068 + /** 1069 + * cdns_get_num_pdi() - Get number of PDIs required 1070 + * 1071 + * @cdns: Cadence instance 1072 + * @pdi: PDI to be used 1073 + * @num: Number of PDIs 1074 + * @ch_count: Channel count 1075 + */ 1076 + static int cdns_get_num_pdi(struct sdw_cdns *cdns, 1077 + struct sdw_cdns_pdi *pdi, 1078 + unsigned int num, u32 ch_count) 1079 + { 1080 + int i, pdis = 0; 1081 + 1082 + for (i = 0; i < num; i++) { 1083 + if (pdi[i].assigned == true) 1084 + continue; 1085 + 1086 + if (pdi[i].ch_count < ch_count) 1087 + ch_count -= pdi[i].ch_count; 1088 + else 1089 + ch_count = 0; 1090 + 1091 + pdis++; 1092 + 1093 + if (!ch_count) 1094 + break; 1095 + } 1096 + 1097 + if (ch_count) 1098 + return 0; 1099 + 1100 + return pdis; 1101 + } 1102 + 1103 + /** 1104 + * sdw_cdns_get_stream() - Get stream information 1105 + * 1106 + * @cdns: Cadence instance 1107 + * @stream: Stream to be allocated 1108 + * @ch: Channel count 1109 + * @dir: Data direction 1110 + */ 1111 + int sdw_cdns_get_stream(struct sdw_cdns *cdns, 1112 + struct sdw_cdns_streams *stream, 1113 + u32 ch, u32 dir) 1114 + { 1115 + int pdis = 0; 1116 + 1117 + if (dir == SDW_DATA_DIR_RX) 1118 + pdis = cdns_get_num_pdi(cdns, stream->in, stream->num_in, ch); 1119 + else 1120 + pdis = cdns_get_num_pdi(cdns, stream->out, stream->num_out, ch); 1121 + 1122 + /* check if we found PDI, else find in bi-directional */ 1123 + if (!pdis) 1124 + pdis = cdns_get_num_pdi(cdns, stream->bd, stream->num_bd, ch); 1125 + 1126 + return pdis; 1127 + } 1128 + EXPORT_SYMBOL(sdw_cdns_get_stream); 1129 + 1130 + /** 1131 + * sdw_cdns_alloc_stream() - Allocate a stream 1132 + * 1133 + * @cdns: Cadence instance 1134 + * @stream: Stream to be allocated 1135 + * @port: Cadence data port 1136 + * @ch: Channel count 1137 + * @dir: Data direction 1138 + */ 1139 + int sdw_cdns_alloc_stream(struct sdw_cdns *cdns, 1140 + struct sdw_cdns_streams *stream, 1141 + struct sdw_cdns_port *port, u32 ch, u32 dir) 1142 + { 1143 + struct sdw_cdns_pdi *pdi = NULL; 1144 + 1145 + if (dir == SDW_DATA_DIR_RX) 1146 + pdi = cdns_find_pdi(cdns, stream->num_in, stream->in); 1147 + else 1148 + pdi = cdns_find_pdi(cdns, stream->num_out, stream->out); 1149 + 1150 + /* check if we found a PDI, else find in bi-directional */ 1151 + if (!pdi) 1152 + pdi = cdns_find_pdi(cdns, stream->num_bd, stream->bd); 1153 + 1154 + if (!pdi) 1155 + return -EIO; 1156 + 1157 + port->pdi = pdi; 1158 + pdi->l_ch_num = 0; 1159 + pdi->h_ch_num = ch - 1; 1160 + pdi->dir = dir; 1161 + pdi->ch_count = ch; 1162 + 1163 + return 0; 1164 + } 1165 + EXPORT_SYMBOL(sdw_cdns_alloc_stream); 1166 + 1167 + void sdw_cdns_shutdown(struct snd_pcm_substream *substream, 1168 + struct snd_soc_dai *dai) 1169 + { 1170 + struct sdw_cdns_dma_data *dma; 1171 + 1172 + dma = snd_soc_dai_get_dma_data(dai, substream); 1173 + if (!dma) 1174 + return; 1175 + 1176 + snd_soc_dai_set_dma_data(dai, substream, NULL); 1177 + kfree(dma); 1178 + } 1179 + EXPORT_SYMBOL(sdw_cdns_shutdown); 989 1180 990 1181 MODULE_LICENSE("Dual BSD/GPL"); 991 1182 MODULE_DESCRIPTION("Cadence Soundwire Library");
+43
drivers/soundwire/cadence_master.h
··· 1 1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 2 // Copyright(c) 2015-17 Intel Corporation. 3 + #include <sound/soc.h> 3 4 4 5 #ifndef __SDW_CADENCE_H 5 6 #define __SDW_CADENCE_H ··· 92 91 }; 93 92 94 93 /** 94 + * struct sdw_cdns_dma_data: Cadence DMA data 95 + * 96 + * @name: SoundWire stream name 97 + * @nr_ports: Number of ports 98 + * @port: Ports 99 + * @bus: Bus handle 100 + * @stream_type: Stream type 101 + * @link_id: Master link id 102 + */ 103 + struct sdw_cdns_dma_data { 104 + char *name; 105 + struct sdw_stream_runtime *stream; 106 + int nr_ports; 107 + struct sdw_cdns_port **port; 108 + struct sdw_bus *bus; 109 + enum sdw_stream_type stream_type; 110 + int link_id; 111 + }; 112 + 113 + /** 95 114 * struct sdw_cdns - Cadence driver context 96 115 * @dev: Linux device 97 116 * @bus: Bus handle ··· 163 142 struct sdw_cdns_stream_config config); 164 143 int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns); 165 144 145 + int sdw_cdns_get_stream(struct sdw_cdns *cdns, 146 + struct sdw_cdns_streams *stream, 147 + u32 ch, u32 dir); 148 + int sdw_cdns_alloc_stream(struct sdw_cdns *cdns, 149 + struct sdw_cdns_streams *stream, 150 + struct sdw_cdns_port *port, u32 ch, u32 dir); 151 + void sdw_cdns_config_stream(struct sdw_cdns *cdns, struct sdw_cdns_port *port, 152 + u32 ch, u32 dir, struct sdw_cdns_pdi *pdi); 153 + 154 + void sdw_cdns_shutdown(struct snd_pcm_substream *substream, 155 + struct snd_soc_dai *dai); 156 + int sdw_cdns_pcm_set_stream(struct snd_soc_dai *dai, 157 + void *stream, int direction); 158 + int sdw_cdns_pdm_set_stream(struct snd_soc_dai *dai, 159 + void *stream, int direction); 160 + 161 + enum sdw_command_response 162 + cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num); 163 + 166 164 enum sdw_command_response 167 165 cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg); 168 166 ··· 193 153 cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num); 194 154 195 155 int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params); 156 + 157 + int cdns_set_sdw_stream(struct snd_soc_dai *dai, 158 + void *stream, bool pcm, int direction); 196 159 #endif /* __SDW_CADENCE_H */