1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018, Linaro Limited
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>
13 * struct segdist_code - Segment Distributions code from
14 * Table 20 of SLIMbus Specs Version 2.0
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]
30 /* segdist_codes - List of all possible Segment Distribution codes. */
31 static const struct segdist_code segdist_codes
[] = {
32 {1, 1536, 0x200, 0xdff},
33 {2, 768, 0x100, 0xcff},
34 {4, 384, 0x080, 0xc7f},
35 {8, 192, 0x040, 0xc3f},
36 {16, 96, 0x020, 0xc1f},
37 {32, 48, 0x010, 0xc0f},
38 {64, 24, 0x008, 0xc07},
39 {128, 12, 0x004, 0xc03},
40 {256, 6, 0x002, 0xc01},
41 {512, 3, 0x001, 0xc00},
42 {3, 512, 0xe00, 0x1ff},
43 {6, 256, 0xd00, 0x0ff},
44 {12, 128, 0xc80, 0x07f},
45 {24, 64, 0xc40, 0x03f},
46 {48, 32, 0xc20, 0x01f},
47 {96, 16, 0xc10, 0x00f},
48 {192, 8, 0xc08, 0x007},
49 {364, 4, 0xc04, 0x003},
50 {768, 2, 0xc02, 0x001},
54 * Presence Rate table for all Natural Frequencies
55 * The Presence rate of a constant bitrate stream is mean flow rate of the
56 * stream expressed in occupied Segments of that Data Channel per second.
57 * Table 66 from SLIMbus 2.0 Specs
59 * Index of the table corresponds to Presence rate code for the respective rate
62 static const int slim_presence_rate_table
[] = {
63 0, /* Not Indicated */
90 * slim_stream_allocate() - Allocate a new SLIMbus Stream
91 * @dev:Slim device to be associated with
92 * @name: name of the stream
94 * This is very first call for SLIMbus streaming, this API will allocate
95 * a new SLIMbus stream and return a valid stream runtime pointer for client
96 * to use it in subsequent stream apis. state of stream is set to ALLOCATED
98 * Return: valid pointer on success and error code on failure.
99 * From ASoC DPCM framework, this state is linked to startup() operation.
101 struct slim_stream_runtime
*slim_stream_allocate(struct slim_device
*dev
,
104 struct slim_stream_runtime
*rt
;
106 rt
= kzalloc(sizeof(*rt
), GFP_KERNEL
);
108 return ERR_PTR(-ENOMEM
);
110 rt
->name
= kasprintf(GFP_KERNEL
, "slim-%s", name
);
113 return ERR_PTR(-ENOMEM
);
117 spin_lock(&dev
->stream_list_lock
);
118 list_add_tail(&rt
->node
, &dev
->stream_list
);
119 spin_unlock(&dev
->stream_list_lock
);
123 EXPORT_SYMBOL_GPL(slim_stream_allocate
);
125 static int slim_connect_port_channel(struct slim_stream_runtime
*stream
,
126 struct slim_port
*port
)
128 struct slim_device
*sdev
= stream
->dev
;
130 struct slim_val_inf msg
= {0, 2, NULL
, wbuf
, NULL
};
131 u8 mc
= SLIM_MSG_MC_CONNECT_SOURCE
;
132 DEFINE_SLIM_LDEST_TXN(txn
, mc
, 6, stream
->dev
->laddr
, &msg
);
134 if (port
->direction
== SLIM_PORT_SINK
)
135 txn
.mc
= SLIM_MSG_MC_CONNECT_SINK
;
138 wbuf
[1] = port
->ch
.id
;
139 port
->ch
.state
= SLIM_CH_STATE_ASSOCIATED
;
140 port
->state
= SLIM_PORT_UNCONFIGURED
;
142 return slim_do_transfer(sdev
->ctrl
, &txn
);
145 static int slim_disconnect_port(struct slim_stream_runtime
*stream
,
146 struct slim_port
*port
)
148 struct slim_device
*sdev
= stream
->dev
;
150 struct slim_val_inf msg
= {0, 1, NULL
, wbuf
, NULL
};
151 u8 mc
= SLIM_MSG_MC_DISCONNECT_PORT
;
152 DEFINE_SLIM_LDEST_TXN(txn
, mc
, 5, stream
->dev
->laddr
, &msg
);
155 port
->ch
.state
= SLIM_CH_STATE_DISCONNECTED
;
156 port
->state
= SLIM_PORT_DISCONNECTED
;
158 return slim_do_transfer(sdev
->ctrl
, &txn
);
161 static int slim_deactivate_remove_channel(struct slim_stream_runtime
*stream
,
162 struct slim_port
*port
)
164 struct slim_device
*sdev
= stream
->dev
;
166 struct slim_val_inf msg
= {0, 1, NULL
, wbuf
, NULL
};
167 u8 mc
= SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL
;
168 DEFINE_SLIM_LDEST_TXN(txn
, mc
, 5, stream
->dev
->laddr
, &msg
);
171 wbuf
[0] = port
->ch
.id
;
172 ret
= slim_do_transfer(sdev
->ctrl
, &txn
);
176 txn
.mc
= SLIM_MSG_MC_NEXT_REMOVE_CHANNEL
;
177 port
->ch
.state
= SLIM_CH_STATE_REMOVED
;
179 return slim_do_transfer(sdev
->ctrl
, &txn
);
182 static int slim_get_prate_code(int rate
)
186 for (i
= 0; i
< ARRAY_SIZE(slim_presence_rate_table
); i
++) {
187 if (rate
== slim_presence_rate_table
[i
])
195 * slim_stream_prepare() - Prepare a SLIMbus Stream
197 * @rt: instance of slim stream runtime to configure
198 * @cfg: new configuration for the stream
200 * This API will configure SLIMbus stream with config parameters from cfg.
201 * return zero on success and error code on failure. From ASoC DPCM framework,
202 * this state is linked to hw_params() operation.
204 int slim_stream_prepare(struct slim_stream_runtime
*rt
,
205 struct slim_stream_config
*cfg
)
207 struct slim_controller
*ctrl
= rt
->dev
->ctrl
;
208 struct slim_port
*port
;
209 int num_ports
, i
, port_id
, prrate
;
212 dev_err(&rt
->dev
->dev
, "Stream already Prepared\n");
216 num_ports
= hweight32(cfg
->port_mask
);
217 rt
->ports
= kcalloc(num_ports
, sizeof(*port
), GFP_KERNEL
);
221 rt
->num_ports
= num_ports
;
222 rt
->rate
= cfg
->rate
;
224 rt
->direction
= cfg
->direction
;
226 prrate
= slim_get_prate_code(cfg
->rate
);
228 dev_err(&rt
->dev
->dev
, "Cannot get presence rate for rate %d Hz\n",
233 if (cfg
->rate
% ctrl
->a_framer
->superfreq
) {
235 * data rate not exactly multiple of super frame,
236 * use PUSH/PULL protocol
238 if (cfg
->direction
== SNDRV_PCM_STREAM_PLAYBACK
)
239 rt
->prot
= SLIM_PROTO_PUSH
;
241 rt
->prot
= SLIM_PROTO_PULL
;
243 rt
->prot
= SLIM_PROTO_ISO
;
246 rt
->ratem
= cfg
->rate
/ctrl
->a_framer
->superfreq
;
249 for_each_set_bit(port_id
, &cfg
->port_mask
, SLIM_DEVICE_MAX_PORTS
) {
250 port
= &rt
->ports
[i
];
251 port
->state
= SLIM_PORT_DISCONNECTED
;
253 port
->ch
.prrate
= prrate
;
254 port
->ch
.id
= cfg
->chs
[i
];
255 port
->ch
.data_fmt
= SLIM_CH_DATA_FMT_NOT_DEFINED
;
256 port
->ch
.aux_fmt
= SLIM_CH_AUX_FMT_NOT_APPLICABLE
;
257 port
->ch
.state
= SLIM_CH_STATE_ALLOCATED
;
259 if (cfg
->direction
== SNDRV_PCM_STREAM_PLAYBACK
)
260 port
->direction
= SLIM_PORT_SINK
;
262 port
->direction
= SLIM_PORT_SOURCE
;
264 slim_connect_port_channel(rt
, port
);
270 EXPORT_SYMBOL_GPL(slim_stream_prepare
);
272 static int slim_define_channel_content(struct slim_stream_runtime
*stream
,
273 struct slim_port
*port
)
275 struct slim_device
*sdev
= stream
->dev
;
277 struct slim_val_inf msg
= {0, 4, NULL
, wbuf
, NULL
};
278 u8 mc
= SLIM_MSG_MC_NEXT_DEFINE_CONTENT
;
279 DEFINE_SLIM_LDEST_TXN(txn
, mc
, 8, stream
->dev
->laddr
, &msg
);
281 wbuf
[0] = port
->ch
.id
;
282 wbuf
[1] = port
->ch
.prrate
;
284 /* Frequency Locked for ISO Protocol */
285 if (stream
->prot
!= SLIM_PROTO_ISO
)
286 wbuf
[1] |= SLIM_CHANNEL_CONTENT_FL
;
288 wbuf
[2] = port
->ch
.data_fmt
| (port
->ch
.aux_fmt
<< 4);
289 wbuf
[3] = stream
->bps
/SLIM_SLOT_LEN_BITS
;
290 port
->ch
.state
= SLIM_CH_STATE_CONTENT_DEFINED
;
292 return slim_do_transfer(sdev
->ctrl
, &txn
);
295 static int slim_get_segdist_code(int ratem
)
299 for (i
= 0; i
< ARRAY_SIZE(segdist_codes
); i
++) {
300 if (segdist_codes
[i
].ratem
== ratem
)
301 return segdist_codes
[i
].segdist_code
;
307 static int slim_define_channel(struct slim_stream_runtime
*stream
,
308 struct slim_port
*port
)
310 struct slim_device
*sdev
= stream
->dev
;
312 struct slim_val_inf msg
= {0, 4, NULL
, wbuf
, NULL
};
313 u8 mc
= SLIM_MSG_MC_NEXT_DEFINE_CHANNEL
;
314 DEFINE_SLIM_LDEST_TXN(txn
, mc
, 8, stream
->dev
->laddr
, &msg
);
316 port
->ch
.seg_dist
= slim_get_segdist_code(stream
->ratem
);
318 wbuf
[0] = port
->ch
.id
;
319 wbuf
[1] = port
->ch
.seg_dist
& 0xFF;
320 wbuf
[2] = (stream
->prot
<< 4) | ((port
->ch
.seg_dist
& 0xF00) >> 8);
321 if (stream
->prot
== SLIM_PROTO_ISO
)
322 wbuf
[3] = stream
->bps
/SLIM_SLOT_LEN_BITS
;
324 wbuf
[3] = stream
->bps
/SLIM_SLOT_LEN_BITS
+ 1;
326 port
->ch
.state
= SLIM_CH_STATE_DEFINED
;
328 return slim_do_transfer(sdev
->ctrl
, &txn
);
331 static int slim_activate_channel(struct slim_stream_runtime
*stream
,
332 struct slim_port
*port
)
334 struct slim_device
*sdev
= stream
->dev
;
336 struct slim_val_inf msg
= {0, 1, NULL
, wbuf
, NULL
};
337 u8 mc
= SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL
;
338 DEFINE_SLIM_LDEST_TXN(txn
, mc
, 5, stream
->dev
->laddr
, &msg
);
340 txn
.msg
->num_bytes
= 1;
341 txn
.msg
->wbuf
= wbuf
;
342 wbuf
[0] = port
->ch
.id
;
343 port
->ch
.state
= SLIM_CH_STATE_ACTIVE
;
345 return slim_do_transfer(sdev
->ctrl
, &txn
);
349 * slim_stream_enable() - Enable a prepared SLIMbus Stream
351 * @stream: instance of slim stream runtime to enable
353 * This API will enable all the ports and channels associated with
356 * Return: zero on success and error code on failure. From ASoC DPCM framework,
357 * this state is linked to trigger() start operation.
359 int slim_stream_enable(struct slim_stream_runtime
*stream
)
361 DEFINE_SLIM_BCAST_TXN(txn
, SLIM_MSG_MC_BEGIN_RECONFIGURATION
,
362 3, SLIM_LA_MANAGER
, NULL
);
363 struct slim_controller
*ctrl
= stream
->dev
->ctrl
;
366 if (ctrl
->enable_stream
) {
367 ret
= ctrl
->enable_stream(stream
);
371 for (i
= 0; i
< stream
->num_ports
; i
++)
372 stream
->ports
[i
].ch
.state
= SLIM_CH_STATE_ACTIVE
;
377 ret
= slim_do_transfer(ctrl
, &txn
);
381 /* define channels first before activating them */
382 for (i
= 0; i
< stream
->num_ports
; i
++) {
383 struct slim_port
*port
= &stream
->ports
[i
];
385 slim_define_channel(stream
, port
);
386 slim_define_channel_content(stream
, port
);
389 for (i
= 0; i
< stream
->num_ports
; i
++) {
390 struct slim_port
*port
= &stream
->ports
[i
];
392 slim_activate_channel(stream
, port
);
393 port
->state
= SLIM_PORT_CONFIGURED
;
395 txn
.mc
= SLIM_MSG_MC_RECONFIGURE_NOW
;
397 return slim_do_transfer(ctrl
, &txn
);
399 EXPORT_SYMBOL_GPL(slim_stream_enable
);
402 * slim_stream_disable() - Disable a SLIMbus Stream
404 * @stream: instance of slim stream runtime to disable
406 * This API will disable all the ports and channels associated with
409 * Return: zero on success and error code on failure. From ASoC DPCM framework,
410 * this state is linked to trigger() pause operation.
412 int slim_stream_disable(struct slim_stream_runtime
*stream
)
414 DEFINE_SLIM_BCAST_TXN(txn
, SLIM_MSG_MC_BEGIN_RECONFIGURATION
,
415 3, SLIM_LA_MANAGER
, NULL
);
416 struct slim_controller
*ctrl
= stream
->dev
->ctrl
;
419 if (!stream
->ports
|| !stream
->num_ports
)
422 if (ctrl
->disable_stream
)
423 ctrl
->disable_stream(stream
);
425 ret
= slim_do_transfer(ctrl
, &txn
);
429 for (i
= 0; i
< stream
->num_ports
; i
++)
430 slim_deactivate_remove_channel(stream
, &stream
->ports
[i
]);
432 txn
.mc
= SLIM_MSG_MC_RECONFIGURE_NOW
;
434 return slim_do_transfer(ctrl
, &txn
);
436 EXPORT_SYMBOL_GPL(slim_stream_disable
);
439 * slim_stream_unprepare() - Un-prepare a SLIMbus Stream
441 * @stream: instance of slim stream runtime to unprepare
443 * This API will un allocate all the ports and channels associated with
446 * Return: zero on success and error code on failure. From ASoC DPCM framework,
447 * this state is linked to trigger() stop operation.
449 int slim_stream_unprepare(struct slim_stream_runtime
*stream
)
453 if (!stream
->ports
|| !stream
->num_ports
)
456 for (i
= 0; i
< stream
->num_ports
; i
++)
457 slim_disconnect_port(stream
, &stream
->ports
[i
]);
459 kfree(stream
->ports
);
460 stream
->ports
= NULL
;
461 stream
->num_ports
= 0;
465 EXPORT_SYMBOL_GPL(slim_stream_unprepare
);
468 * slim_stream_free() - Free a SLIMbus Stream
470 * @stream: instance of slim stream runtime to free
472 * This API will un allocate all the memory associated with
473 * slim stream runtime, user is not allowed to make an dereference
474 * to stream after this call.
476 * Return: zero on success and error code on failure. From ASoC DPCM framework,
477 * this state is linked to shutdown() operation.
479 int slim_stream_free(struct slim_stream_runtime
*stream
)
481 struct slim_device
*sdev
= stream
->dev
;
483 spin_lock(&sdev
->stream_list_lock
);
484 list_del(&stream
->node
);
485 spin_unlock(&sdev
->stream_list_lock
);
492 EXPORT_SYMBOL_GPL(slim_stream_free
);