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

slimbus: stream: add stream support

This patch adds support to SLIMbus stream apis for slimbus device.
SLIMbus streaming involves adding support to Data Channel Management and
channel Reconfiguration Messages to slim core plus few stream apis.
>From slim device side the apis are very simple mostly inline with other
stream apis.

Currently it only supports Isochronous and Push/Pull transport protocols,
which are sufficient for audio use cases.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Srinivas Kandagatla and committed by
Greg Kroah-Hartman
abb9c9b8 917809e2

+720 -1
+5
Documentation/driver-api/slimbus.rst
··· 125 125 ~~~~~~~~~~~~~~~ 126 126 .. kernel-doc:: drivers/slimbus/messaging.c 127 127 :export: 128 + 129 + Streaming APIs: 130 + ~~~~~~~~~~~~~~~ 131 + .. kernel-doc:: drivers/slimbus/stream.c 132 + :export:
+1 -1
drivers/slimbus/Makefile
··· 3 3 # Makefile for kernel SLIMbus framework. 4 4 # 5 5 obj-$(CONFIG_SLIMBUS) += slimbus.o 6 - slimbus-y := core.o messaging.o sched.o 6 + slimbus-y := core.o messaging.o sched.o stream.o 7 7 8 8 #Controllers 9 9 obj-$(CONFIG_SLIM_QCOM_CTRL) += slim-qcom-ctrl.o
+2
drivers/slimbus/core.c
··· 114 114 sbdev->dev.release = slim_dev_release; 115 115 sbdev->dev.driver = NULL; 116 116 sbdev->ctrl = ctrl; 117 + INIT_LIST_HEAD(&sbdev->stream_list); 118 + spin_lock_init(&sbdev->stream_list_lock); 117 119 118 120 if (node) 119 121 sbdev->dev.of_node = of_node_get(node);
+189
drivers/slimbus/slimbus.h
··· 45 45 #define SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS 0x2 46 46 #define SLIM_MSG_MC_REPORT_ABSENT 0xF 47 47 48 + /* Data channel management messages */ 49 + #define SLIM_MSG_MC_CONNECT_SOURCE 0x10 50 + #define SLIM_MSG_MC_CONNECT_SINK 0x11 51 + #define SLIM_MSG_MC_DISCONNECT_PORT 0x14 52 + #define SLIM_MSG_MC_CHANGE_CONTENT 0x18 53 + 48 54 /* Clock pause Reconfiguration messages */ 49 55 #define SLIM_MSG_MC_BEGIN_RECONFIGURATION 0x40 50 56 #define SLIM_MSG_MC_NEXT_PAUSE_CLOCK 0x4A 57 + #define SLIM_MSG_MC_NEXT_DEFINE_CHANNEL 0x50 58 + #define SLIM_MSG_MC_NEXT_DEFINE_CONTENT 0x51 59 + #define SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL 0x54 60 + #define SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL 0x55 61 + #define SLIM_MSG_MC_NEXT_REMOVE_CHANNEL 0x58 51 62 #define SLIM_MSG_MC_RECONFIGURE_NOW 0x5F 52 63 53 64 /* ··· 80 69 /* Standard values per SLIMbus spec needed by controllers and devices */ 81 70 #define SLIM_MAX_CLK_GEAR 10 82 71 #define SLIM_MIN_CLK_GEAR 1 72 + #define SLIM_SLOT_LEN_BITS 4 83 73 74 + /* Indicate that the frequency of the flow and the bus frequency are locked */ 75 + #define SLIM_CHANNEL_CONTENT_FL BIT(7) 76 + 77 + /* Standard values per SLIMbus spec needed by controllers and devices */ 78 + #define SLIM_CL_PER_SUPERFRAME 6144 79 + #define SLIM_SLOTS_PER_SUPERFRAME (SLIM_CL_PER_SUPERFRAME >> 2) 80 + #define SLIM_SL_PER_SUPERFRAME (SLIM_CL_PER_SUPERFRAME >> 2) 84 81 /* Manager's logical address is set to 0xFF per spec */ 85 82 #define SLIM_LA_MANAGER 0xFF 86 83 ··· 187 168 }; 188 169 189 170 /** 171 + * enum slim_port_direction: SLIMbus port direction 172 + * 173 + * @SLIM_PORT_SINK: SLIMbus port is a sink 174 + * @SLIM_PORT_SOURCE: SLIMbus port is a source 175 + */ 176 + enum slim_port_direction { 177 + SLIM_PORT_SINK = 0, 178 + SLIM_PORT_SOURCE, 179 + }; 180 + /** 181 + * enum slim_port_state: SLIMbus Port/Endpoint state machine 182 + * according to SLIMbus Spec 2.0 183 + * @SLIM_PORT_DISCONNECTED: SLIMbus port is disconnected 184 + * entered from Unconfigure/configured state after 185 + * DISCONNECT_PORT or REMOVE_CHANNEL core command 186 + * @SLIM_PORT_UNCONFIGURED: SLIMbus port is in unconfigured state. 187 + * entered from disconnect state after CONNECT_SOURCE/SINK core command 188 + * @SLIM_PORT_CONFIGURED: SLIMbus port is in configured state. 189 + * entered from unconfigured state after DEFINE_CHANNEL, DEFINE_CONTENT 190 + * and ACTIVATE_CHANNEL core commands. Ready for data transmission. 191 + */ 192 + enum slim_port_state { 193 + SLIM_PORT_DISCONNECTED = 0, 194 + SLIM_PORT_UNCONFIGURED, 195 + SLIM_PORT_CONFIGURED, 196 + }; 197 + 198 + /** 199 + * enum slim_channel_state: SLIMbus channel state machine used by core. 200 + * @SLIM_CH_STATE_DISCONNECTED: SLIMbus channel is disconnected 201 + * @SLIM_CH_STATE_ALLOCATED: SLIMbus channel is allocated 202 + * @SLIM_CH_STATE_ASSOCIATED: SLIMbus channel is associated with port 203 + * @SLIM_CH_STATE_DEFINED: SLIMbus channel parameters are defined 204 + * @SLIM_CH_STATE_CONTENT_DEFINED: SLIMbus channel content is defined 205 + * @SLIM_CH_STATE_ACTIVE: SLIMbus channel is active and ready for data 206 + * @SLIM_CH_STATE_REMOVED: SLIMbus channel is inactive and removed 207 + */ 208 + enum slim_channel_state { 209 + SLIM_CH_STATE_DISCONNECTED = 0, 210 + SLIM_CH_STATE_ALLOCATED, 211 + SLIM_CH_STATE_ASSOCIATED, 212 + SLIM_CH_STATE_DEFINED, 213 + SLIM_CH_STATE_CONTENT_DEFINED, 214 + SLIM_CH_STATE_ACTIVE, 215 + SLIM_CH_STATE_REMOVED, 216 + }; 217 + 218 + /** 219 + * enum slim_ch_data_fmt: SLIMbus channel data Type identifiers according to 220 + * Table 60 of SLIMbus Spec 1.01.01 221 + * @SLIM_CH_DATA_FMT_NOT_DEFINED: Undefined 222 + * @SLIM_CH_DATA_FMT_LPCM_AUDIO: LPCM audio 223 + * @SLIM_CH_DATA_FMT_IEC61937_COMP_AUDIO: IEC61937 Compressed audio 224 + * @SLIM_CH_DATA_FMT_PACKED_PDM_AUDIO: Packed PDM audio 225 + */ 226 + enum slim_ch_data_fmt { 227 + SLIM_CH_DATA_FMT_NOT_DEFINED = 0, 228 + SLIM_CH_DATA_FMT_LPCM_AUDIO = 1, 229 + SLIM_CH_DATA_FMT_IEC61937_COMP_AUDIO = 2, 230 + SLIM_CH_DATA_FMT_PACKED_PDM_AUDIO = 3, 231 + }; 232 + 233 + /** 234 + * enum slim_ch_aux_fmt: SLIMbus channel Aux Field format IDs according to 235 + * Table 63 of SLIMbus Spec 2.0 236 + * @SLIM_CH_AUX_FMT_NOT_APPLICABLE: Undefined 237 + * @SLIM_CH_AUX_FMT_ZCUV_TUNNEL_IEC60958: ZCUV for tunneling IEC60958 238 + * @SLIM_CH_AUX_FMT_USER_DEFINED: User defined 239 + */ 240 + enum slim_ch_aux_bit_fmt { 241 + SLIM_CH_AUX_FMT_NOT_APPLICABLE = 0, 242 + SLIM_CH_AUX_FMT_ZCUV_TUNNEL_IEC60958 = 1, 243 + SLIM_CH_AUX_FMT_USER_DEFINED = 0xF, 244 + }; 245 + 246 + /** 247 + * struct slim_channel - SLIMbus channel, used for state machine 248 + * 249 + * @id: ID of channel 250 + * @prrate: Presense rate of channel from Table 66 of SLIMbus 2.0 Specs 251 + * @seg_dist: segment distribution code from Table 20 of SLIMbus 2.0 Specs 252 + * @data_fmt: Data format of channel. 253 + * @aux_fmt: Aux format for this channel. 254 + * @state: channel state machine 255 + */ 256 + struct slim_channel { 257 + int id; 258 + int prrate; 259 + int seg_dist; 260 + enum slim_ch_data_fmt data_fmt; 261 + enum slim_ch_aux_bit_fmt aux_fmt; 262 + enum slim_channel_state state; 263 + }; 264 + 265 + /** 266 + * struct slim_port - SLIMbus port 267 + * 268 + * @id: Port id 269 + * @direction: Port direction, Source or Sink. 270 + * @state: state machine of port. 271 + * @ch: channel associated with this port. 272 + */ 273 + struct slim_port { 274 + int id; 275 + enum slim_port_direction direction; 276 + enum slim_port_state state; 277 + struct slim_channel ch; 278 + }; 279 + 280 + /** 281 + * enum slim_transport_protocol: SLIMbus Transport protocol list from 282 + * Table 47 of SLIMbus 2.0 specs. 283 + * @SLIM_PROTO_ISO: Isochronous Protocol, no flow control as data rate match 284 + * channel rate flow control embedded in the data. 285 + * @SLIM_PROTO_PUSH: Pushed Protocol, includes flow control, Used to carry 286 + * data whose rate is equal to, or lower than the channel rate. 287 + * @SLIM_PROTO_PULL: Pulled Protocol, similar usage as pushed protocol 288 + * but pull is a unicast. 289 + * @SLIM_PROTO_LOCKED: Locked Protocol 290 + * @SLIM_PROTO_ASYNC_SMPLX: Asynchronous Protocol-Simplex 291 + * @SLIM_PROTO_ASYNC_HALF_DUP: Asynchronous Protocol-Half-duplex 292 + * @SLIM_PROTO_EXT_SMPLX: Extended Asynchronous Protocol-Simplex 293 + * @SLIM_PROTO_EXT_HALF_DUP: Extended Asynchronous Protocol-Half-duplex 294 + */ 295 + enum slim_transport_protocol { 296 + SLIM_PROTO_ISO = 0, 297 + SLIM_PROTO_PUSH, 298 + SLIM_PROTO_PULL, 299 + SLIM_PROTO_LOCKED, 300 + SLIM_PROTO_ASYNC_SMPLX, 301 + SLIM_PROTO_ASYNC_HALF_DUP, 302 + SLIM_PROTO_EXT_SMPLX, 303 + SLIM_PROTO_EXT_HALF_DUP, 304 + }; 305 + 306 + /** 307 + * struct slim_stream_runtime - SLIMbus stream runtime instance 308 + * 309 + * @dev: Name of the stream 310 + * @dev: SLIM Device instance associated with this stream 311 + * @state: state of stream 312 + * @direction: direction of stream 313 + * @prot: Transport protocol used in this stream 314 + * @rate: Data rate of samples * 315 + * @bps: bits per sample 316 + * @ratem: rate multipler which is super frame rate/data rate 317 + * @num_ports: number of ports 318 + * @ports: pointer to instance of ports 319 + * @node: list head for stream associated with slim device. 320 + */ 321 + struct slim_stream_runtime { 322 + const char *name; 323 + struct slim_device *dev; 324 + int direction; 325 + enum slim_transport_protocol prot; 326 + unsigned int rate; 327 + unsigned int bps; 328 + unsigned int ratem; 329 + int num_ports; 330 + struct slim_port *ports; 331 + struct list_head node; 332 + }; 333 + 334 + /** 190 335 * struct slim_controller - Controls every instance of SLIMbus 191 336 * (similar to 'master' on SPI) 192 337 * @dev: Device interface to this driver ··· 379 196 * @wakeup: This function pointer implements controller-specific procedure 380 197 * to wake it up from clock-pause. Framework will call this to bring 381 198 * the controller out of clock pause. 199 + * @enable_stream: This function pointer implements controller-specific procedure 200 + * to enable a stream. 201 + * @disable_stream: This function pointer implements controller-specific procedure 202 + * to disable stream. 382 203 * 383 204 * 'Manager device' is responsible for device management, bandwidth 384 205 * allocation, channel setup, and port associations per channel. ··· 424 237 struct slim_eaddr *ea, u8 laddr); 425 238 int (*get_laddr)(struct slim_controller *ctrl, 426 239 struct slim_eaddr *ea, u8 *laddr); 240 + int (*enable_stream)(struct slim_stream_runtime *rt); 241 + int (*disable_stream)(struct slim_stream_runtime *rt); 427 242 int (*wakeup)(struct slim_controller *ctrl); 428 243 }; 429 244
+477
drivers/slimbus/stream.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2018, Linaro Limited 3 + 4 + #include <linux/kernel.h> 5 + #include <linux/errno.h> 6 + #include <linux/slab.h> 7 + #include <linux/list.h> 8 + #include <linux/slimbus.h> 9 + #include <uapi/sound/asound.h> 10 + #include "slimbus.h" 11 + 12 + /** 13 + * struct segdist_code - Segment Distributions code from 14 + * Table 20 of SLIMbus Specs Version 2.0 15 + * 16 + * @ratem: Channel Rate Multipler(Segments per Superframe) 17 + * @seg_interval: Number of slots between the first Slot of Segment 18 + * and the first slot of the next consecutive Segment. 19 + * @segdist_code: Segment Distribution Code SD[11:0] 20 + * @seg_offset_mask: Segment offset mask in SD[11:0] 21 + * @segdist_codes: List of all possible Segmet Distribution codes. 22 + */ 23 + static const struct segdist_code { 24 + int ratem; 25 + int seg_interval; 26 + int segdist_code; 27 + u32 seg_offset_mask; 28 + 29 + } segdist_codes[] = { 30 + {1, 1536, 0x200, 0xdff}, 31 + {2, 768, 0x100, 0xcff}, 32 + {4, 384, 0x080, 0xc7f}, 33 + {8, 192, 0x040, 0xc3f}, 34 + {16, 96, 0x020, 0xc1f}, 35 + {32, 48, 0x010, 0xc0f}, 36 + {64, 24, 0x008, 0xc07}, 37 + {128, 12, 0x004, 0xc03}, 38 + {256, 6, 0x002, 0xc01}, 39 + {512, 3, 0x001, 0xc00}, 40 + {3, 512, 0xe00, 0x1ff}, 41 + {6, 256, 0xd00, 0x0ff}, 42 + {12, 128, 0xc80, 0x07f}, 43 + {24, 64, 0xc40, 0x03f}, 44 + {48, 32, 0xc20, 0x01f}, 45 + {96, 16, 0xc10, 0x00f}, 46 + {192, 8, 0xc08, 0x007}, 47 + {364, 4, 0xc04, 0x003}, 48 + {768, 2, 0xc02, 0x001}, 49 + }; 50 + 51 + /* 52 + * Presence Rate table for all Natural Frequencies 53 + * The Presence rate of a constant bitrate stream is mean flow rate of the 54 + * stream expressed in occupied Segments of that Data Channel per second. 55 + * Table 66 from SLIMbus 2.0 Specs 56 + * 57 + * Index of the table corresponds to Presence rate code for the respective rate 58 + * in the table. 59 + */ 60 + static const int slim_presence_rate_table[] = { 61 + 0, /* Not Indicated */ 62 + 12000, 63 + 24000, 64 + 48000, 65 + 96000, 66 + 192000, 67 + 384000, 68 + 768000, 69 + 0, /* Reserved */ 70 + 110250, 71 + 220500, 72 + 441000, 73 + 882000, 74 + 176400, 75 + 352800, 76 + 705600, 77 + 4000, 78 + 8000, 79 + 16000, 80 + 32000, 81 + 64000, 82 + 128000, 83 + 256000, 84 + 512000, 85 + }; 86 + 87 + /* 88 + * slim_stream_allocate() - Allocate a new SLIMbus Stream 89 + * @dev:Slim device to be associated with 90 + * @name: name of the stream 91 + * 92 + * This is very first call for SLIMbus streaming, this API will allocate 93 + * a new SLIMbus stream and return a valid stream runtime pointer for client 94 + * to use it in subsequent stream apis. state of stream is set to ALLOCATED 95 + * 96 + * Return: valid pointer on success and error code on failure. 97 + * From ASoC DPCM framework, this state is linked to startup() operation. 98 + */ 99 + struct slim_stream_runtime *slim_stream_allocate(struct slim_device *dev, 100 + const char *name) 101 + { 102 + struct slim_stream_runtime *rt; 103 + 104 + rt = kzalloc(sizeof(*rt), GFP_KERNEL); 105 + if (!rt) 106 + return ERR_PTR(-ENOMEM); 107 + 108 + rt->name = kasprintf(GFP_KERNEL, "slim-%s", name); 109 + if (!rt->name) { 110 + kfree(rt); 111 + return ERR_PTR(-ENOMEM); 112 + } 113 + 114 + rt->dev = dev; 115 + spin_lock(&dev->stream_list_lock); 116 + list_add_tail(&rt->node, &dev->stream_list); 117 + spin_unlock(&dev->stream_list_lock); 118 + 119 + return rt; 120 + } 121 + EXPORT_SYMBOL_GPL(slim_stream_allocate); 122 + 123 + static int slim_connect_port_channel(struct slim_stream_runtime *stream, 124 + struct slim_port *port) 125 + { 126 + struct slim_device *sdev = stream->dev; 127 + u8 wbuf[2]; 128 + struct slim_val_inf msg = {0, 2, NULL, wbuf, NULL}; 129 + u8 mc = SLIM_MSG_MC_CONNECT_SOURCE; 130 + DEFINE_SLIM_LDEST_TXN(txn, mc, 6, stream->dev->laddr, &msg); 131 + 132 + if (port->direction == SLIM_PORT_SINK) 133 + txn.mc = SLIM_MSG_MC_CONNECT_SINK; 134 + 135 + wbuf[0] = port->id; 136 + wbuf[1] = port->ch.id; 137 + port->ch.state = SLIM_CH_STATE_ASSOCIATED; 138 + port->state = SLIM_PORT_UNCONFIGURED; 139 + 140 + return slim_do_transfer(sdev->ctrl, &txn); 141 + } 142 + 143 + static int slim_disconnect_port(struct slim_stream_runtime *stream, 144 + struct slim_port *port) 145 + { 146 + struct slim_device *sdev = stream->dev; 147 + u8 wbuf[1]; 148 + struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL}; 149 + u8 mc = SLIM_MSG_MC_DISCONNECT_PORT; 150 + DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg); 151 + 152 + wbuf[0] = port->id; 153 + port->ch.state = SLIM_CH_STATE_DISCONNECTED; 154 + port->state = SLIM_PORT_DISCONNECTED; 155 + 156 + return slim_do_transfer(sdev->ctrl, &txn); 157 + } 158 + 159 + static int slim_deactivate_remove_channel(struct slim_stream_runtime *stream, 160 + struct slim_port *port) 161 + { 162 + struct slim_device *sdev = stream->dev; 163 + u8 wbuf[1]; 164 + struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL}; 165 + u8 mc = SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL; 166 + DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg); 167 + int ret; 168 + 169 + wbuf[0] = port->ch.id; 170 + ret = slim_do_transfer(sdev->ctrl, &txn); 171 + if (ret) 172 + return ret; 173 + 174 + txn.mc = SLIM_MSG_MC_NEXT_REMOVE_CHANNEL; 175 + port->ch.state = SLIM_CH_STATE_REMOVED; 176 + 177 + return slim_do_transfer(sdev->ctrl, &txn); 178 + } 179 + 180 + static int slim_get_prate_code(int rate) 181 + { 182 + int i; 183 + 184 + for (i = 0; i < ARRAY_SIZE(slim_presence_rate_table); i++) { 185 + if (rate == slim_presence_rate_table[i]) 186 + return i; 187 + } 188 + 189 + return -EINVAL; 190 + } 191 + 192 + /* 193 + * slim_stream_prepare() - Prepare a SLIMbus Stream 194 + * 195 + * @rt: instance of slim stream runtime to configure 196 + * @cfg: new configuration for the stream 197 + * 198 + * This API will configure SLIMbus stream with config parameters from cfg. 199 + * return zero on success and error code on failure. From ASoC DPCM framework, 200 + * this state is linked to hw_params() operation. 201 + */ 202 + int slim_stream_prepare(struct slim_stream_runtime *rt, 203 + struct slim_stream_config *cfg) 204 + { 205 + struct slim_controller *ctrl = rt->dev->ctrl; 206 + struct slim_port *port; 207 + int num_ports, i, port_id; 208 + 209 + if (rt->ports) { 210 + dev_err(&rt->dev->dev, "Stream already Prepared\n"); 211 + return -EINVAL; 212 + } 213 + 214 + num_ports = hweight32(cfg->port_mask); 215 + rt->ports = kcalloc(num_ports, sizeof(*port), GFP_KERNEL); 216 + if (!rt->ports) 217 + return -ENOMEM; 218 + 219 + rt->num_ports = num_ports; 220 + rt->rate = cfg->rate; 221 + rt->bps = cfg->bps; 222 + rt->direction = cfg->direction; 223 + 224 + if (cfg->rate % ctrl->a_framer->superfreq) { 225 + /* 226 + * data rate not exactly multiple of super frame, 227 + * use PUSH/PULL protocol 228 + */ 229 + if (cfg->direction == SNDRV_PCM_STREAM_PLAYBACK) 230 + rt->prot = SLIM_PROTO_PUSH; 231 + else 232 + rt->prot = SLIM_PROTO_PULL; 233 + } else { 234 + rt->prot = SLIM_PROTO_ISO; 235 + } 236 + 237 + rt->ratem = cfg->rate/ctrl->a_framer->superfreq; 238 + 239 + i = 0; 240 + for_each_set_bit(port_id, &cfg->port_mask, SLIM_DEVICE_MAX_PORTS) { 241 + port = &rt->ports[i]; 242 + port->state = SLIM_PORT_DISCONNECTED; 243 + port->id = port_id; 244 + port->ch.prrate = slim_get_prate_code(cfg->rate); 245 + port->ch.id = cfg->chs[i]; 246 + port->ch.data_fmt = SLIM_CH_DATA_FMT_NOT_DEFINED; 247 + port->ch.aux_fmt = SLIM_CH_AUX_FMT_NOT_APPLICABLE; 248 + port->ch.state = SLIM_CH_STATE_ALLOCATED; 249 + 250 + if (cfg->direction == SNDRV_PCM_STREAM_PLAYBACK) 251 + port->direction = SLIM_PORT_SINK; 252 + else 253 + port->direction = SLIM_PORT_SOURCE; 254 + 255 + slim_connect_port_channel(rt, port); 256 + i++; 257 + } 258 + 259 + return 0; 260 + } 261 + EXPORT_SYMBOL_GPL(slim_stream_prepare); 262 + 263 + static int slim_define_channel_content(struct slim_stream_runtime *stream, 264 + struct slim_port *port) 265 + { 266 + struct slim_device *sdev = stream->dev; 267 + u8 wbuf[4]; 268 + struct slim_val_inf msg = {0, 4, NULL, wbuf, NULL}; 269 + u8 mc = SLIM_MSG_MC_NEXT_DEFINE_CONTENT; 270 + DEFINE_SLIM_LDEST_TXN(txn, mc, 8, stream->dev->laddr, &msg); 271 + 272 + wbuf[0] = port->ch.id; 273 + wbuf[1] = port->ch.prrate; 274 + 275 + /* Frequency Locked for ISO Protocol */ 276 + if (stream->prot != SLIM_PROTO_ISO) 277 + wbuf[1] |= SLIM_CHANNEL_CONTENT_FL; 278 + 279 + wbuf[2] = port->ch.data_fmt | (port->ch.aux_fmt << 4); 280 + wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS; 281 + port->ch.state = SLIM_CH_STATE_CONTENT_DEFINED; 282 + 283 + return slim_do_transfer(sdev->ctrl, &txn); 284 + } 285 + 286 + static int slim_get_segdist_code(int ratem) 287 + { 288 + int i; 289 + 290 + for (i = 0; i < ARRAY_SIZE(segdist_codes); i++) { 291 + if (segdist_codes[i].ratem == ratem) 292 + return segdist_codes[i].segdist_code; 293 + } 294 + 295 + return -EINVAL; 296 + } 297 + 298 + static int slim_define_channel(struct slim_stream_runtime *stream, 299 + struct slim_port *port) 300 + { 301 + struct slim_device *sdev = stream->dev; 302 + u8 wbuf[4]; 303 + struct slim_val_inf msg = {0, 4, NULL, wbuf, NULL}; 304 + u8 mc = SLIM_MSG_MC_NEXT_DEFINE_CHANNEL; 305 + DEFINE_SLIM_LDEST_TXN(txn, mc, 8, stream->dev->laddr, &msg); 306 + 307 + port->ch.seg_dist = slim_get_segdist_code(stream->ratem); 308 + 309 + wbuf[0] = port->ch.id; 310 + wbuf[1] = port->ch.seg_dist & 0xFF; 311 + wbuf[2] = (stream->prot << 4) | ((port->ch.seg_dist & 0xF00) >> 8); 312 + if (stream->prot == SLIM_PROTO_ISO) 313 + wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS; 314 + else 315 + wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS + 1; 316 + 317 + port->ch.state = SLIM_CH_STATE_DEFINED; 318 + 319 + return slim_do_transfer(sdev->ctrl, &txn); 320 + } 321 + 322 + static int slim_activate_channel(struct slim_stream_runtime *stream, 323 + struct slim_port *port) 324 + { 325 + struct slim_device *sdev = stream->dev; 326 + u8 wbuf[1]; 327 + struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL}; 328 + u8 mc = SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL; 329 + DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg); 330 + 331 + txn.msg->num_bytes = 1; 332 + txn.msg->wbuf = wbuf; 333 + wbuf[0] = port->ch.id; 334 + port->ch.state = SLIM_CH_STATE_ACTIVE; 335 + 336 + return slim_do_transfer(sdev->ctrl, &txn); 337 + } 338 + 339 + /* 340 + * slim_stream_enable() - Enable a prepared SLIMbus Stream 341 + * 342 + * @stream: instance of slim stream runtime to enable 343 + * 344 + * This API will enable all the ports and channels associated with 345 + * SLIMbus stream 346 + * 347 + * Return: zero on success and error code on failure. From ASoC DPCM framework, 348 + * this state is linked to trigger() start operation. 349 + */ 350 + int slim_stream_enable(struct slim_stream_runtime *stream) 351 + { 352 + DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION, 353 + 3, SLIM_LA_MANAGER, NULL); 354 + struct slim_controller *ctrl = stream->dev->ctrl; 355 + int ret, i; 356 + 357 + if (ctrl->enable_stream) { 358 + ret = ctrl->enable_stream(stream); 359 + if (ret) 360 + return ret; 361 + 362 + for (i = 0; i < stream->num_ports; i++) 363 + stream->ports[i].ch.state = SLIM_CH_STATE_ACTIVE; 364 + 365 + return ret; 366 + } 367 + 368 + ret = slim_do_transfer(ctrl, &txn); 369 + if (ret) 370 + return ret; 371 + 372 + /* define channels first before activating them */ 373 + for (i = 0; i < stream->num_ports; i++) { 374 + struct slim_port *port = &stream->ports[i]; 375 + 376 + slim_define_channel(stream, port); 377 + slim_define_channel_content(stream, port); 378 + } 379 + 380 + for (i = 0; i < stream->num_ports; i++) { 381 + struct slim_port *port = &stream->ports[i]; 382 + 383 + slim_activate_channel(stream, port); 384 + port->state = SLIM_PORT_CONFIGURED; 385 + } 386 + txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW; 387 + 388 + return slim_do_transfer(ctrl, &txn); 389 + } 390 + EXPORT_SYMBOL_GPL(slim_stream_enable); 391 + 392 + /* 393 + * slim_stream_disable() - Disable a SLIMbus Stream 394 + * 395 + * @stream: instance of slim stream runtime to disable 396 + * 397 + * This API will disable all the ports and channels associated with 398 + * SLIMbus stream 399 + * 400 + * Return: zero on success and error code on failure. From ASoC DPCM framework, 401 + * this state is linked to trigger() pause operation. 402 + */ 403 + int slim_stream_disable(struct slim_stream_runtime *stream) 404 + { 405 + DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION, 406 + 3, SLIM_LA_MANAGER, NULL); 407 + struct slim_controller *ctrl = stream->dev->ctrl; 408 + int ret, i; 409 + 410 + if (ctrl->disable_stream) 411 + ctrl->disable_stream(stream); 412 + 413 + ret = slim_do_transfer(ctrl, &txn); 414 + if (ret) 415 + return ret; 416 + 417 + for (i = 0; i < stream->num_ports; i++) 418 + slim_deactivate_remove_channel(stream, &stream->ports[i]); 419 + 420 + txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW; 421 + 422 + return slim_do_transfer(ctrl, &txn); 423 + } 424 + EXPORT_SYMBOL_GPL(slim_stream_disable); 425 + 426 + /* 427 + * slim_stream_unprepare() - Un-prepare a SLIMbus Stream 428 + * 429 + * @stream: instance of slim stream runtime to unprepare 430 + * 431 + * This API will un allocate all the ports and channels associated with 432 + * SLIMbus stream 433 + * 434 + * Return: zero on success and error code on failure. From ASoC DPCM framework, 435 + * this state is linked to trigger() stop operation. 436 + */ 437 + int slim_stream_unprepare(struct slim_stream_runtime *stream) 438 + { 439 + int i; 440 + 441 + for (i = 0; i < stream->num_ports; i++) 442 + slim_disconnect_port(stream, &stream->ports[i]); 443 + 444 + kfree(stream->ports); 445 + stream->ports = NULL; 446 + stream->num_ports = 0; 447 + 448 + return 0; 449 + } 450 + EXPORT_SYMBOL_GPL(slim_stream_unprepare); 451 + 452 + /* 453 + * slim_stream_free() - Free a SLIMbus Stream 454 + * 455 + * @stream: instance of slim stream runtime to free 456 + * 457 + * This API will un allocate all the memory associated with 458 + * slim stream runtime, user is not allowed to make an dereference 459 + * to stream after this call. 460 + * 461 + * Return: zero on success and error code on failure. From ASoC DPCM framework, 462 + * this state is linked to shutdown() operation. 463 + */ 464 + int slim_stream_free(struct slim_stream_runtime *stream) 465 + { 466 + struct slim_device *sdev = stream->dev; 467 + 468 + spin_lock(&sdev->stream_list_lock); 469 + list_del(&stream->node); 470 + spin_unlock(&sdev->stream_list_lock); 471 + 472 + kfree(stream->name); 473 + kfree(stream); 474 + 475 + return 0; 476 + } 477 + EXPORT_SYMBOL_GPL(slim_stream_free);
+46
include/linux/slimbus.h
··· 48 48 * @ctrl: slim controller instance. 49 49 * @laddr: 1-byte Logical address of this device. 50 50 * @is_laddr_valid: indicates if the laddr is valid or not 51 + * @stream_list: List of streams on this device 52 + * @stream_list_lock: lock to protect the stream list 51 53 * 52 54 * This is the client/device handle returned when a SLIMbus 53 55 * device is registered with a controller. ··· 62 60 enum slim_device_status status; 63 61 u8 laddr; 64 62 bool is_laddr_valid; 63 + struct list_head stream_list; 64 + spinlock_t stream_list_lock; 65 65 }; 66 66 67 67 #define to_slim_device(d) container_of(d, struct slim_device, dev) ··· 110 106 u8 *rbuf; 111 107 const u8 *wbuf; 112 108 struct completion *comp; 109 + }; 110 + 111 + #define SLIM_DEVICE_MAX_CHANNELS 256 112 + /* A SLIMBus Device may have frmo 0 to 31 Ports (inclusive) */ 113 + #define SLIM_DEVICE_MAX_PORTS 32 114 + 115 + /** 116 + * struct slim_stream_config - SLIMbus stream configuration 117 + * Configuring a stream is done at hw_params or prepare call 118 + * from audio drivers where they have all the required information 119 + * regarding rate, number of channels and so on. 120 + * There is a 1:1 mapping of channel and ports. 121 + * 122 + * @rate: data rate 123 + * @bps: bits per data sample 124 + * @ch_count: number of channels 125 + * @chs: pointer to list of channel numbers 126 + * @port_mask: port mask of ports to use for this stream 127 + * @direction: direction of the stream, SNDRV_PCM_STREAM_PLAYBACK 128 + * or SNDRV_PCM_STREAM_CAPTURE. 129 + */ 130 + struct slim_stream_config { 131 + unsigned int rate; 132 + unsigned int bps; 133 + /* MAX 256 channels */ 134 + unsigned int ch_count; 135 + unsigned int *chs; 136 + /* Max 32 ports per device */ 137 + unsigned long port_mask; 138 + int direction; 113 139 }; 114 140 115 141 /* ··· 197 163 int slim_writeb(struct slim_device *sdev, u32 addr, u8 value); 198 164 int slim_read(struct slim_device *sdev, u32 addr, size_t count, u8 *val); 199 165 int slim_write(struct slim_device *sdev, u32 addr, size_t count, u8 *val); 166 + 167 + /* SLIMbus Stream apis */ 168 + struct slim_stream_runtime; 169 + struct slim_stream_runtime *slim_stream_allocate(struct slim_device *dev, 170 + const char *sname); 171 + int slim_stream_prepare(struct slim_stream_runtime *stream, 172 + struct slim_stream_config *c); 173 + int slim_stream_enable(struct slim_stream_runtime *stream); 174 + int slim_stream_disable(struct slim_stream_runtime *stream); 175 + int slim_stream_unprepare(struct slim_stream_runtime *stream); 176 + int slim_stream_free(struct slim_stream_runtime *stream); 177 + 200 178 #endif /* _LINUX_SLIMBUS_H */