xref: /linux/drivers/slimbus/stream.c (revision 434d25728171aa72ed1b1c4d248527cbf6b6c99b)
1abb9c9b8SSrinivas Kandagatla // SPDX-License-Identifier: GPL-2.0
2abb9c9b8SSrinivas Kandagatla // Copyright (c) 2018, Linaro Limited
3abb9c9b8SSrinivas Kandagatla 
4abb9c9b8SSrinivas Kandagatla #include <linux/kernel.h>
5abb9c9b8SSrinivas Kandagatla #include <linux/errno.h>
6abb9c9b8SSrinivas Kandagatla #include <linux/slab.h>
7abb9c9b8SSrinivas Kandagatla #include <linux/list.h>
8abb9c9b8SSrinivas Kandagatla #include <linux/slimbus.h>
9abb9c9b8SSrinivas Kandagatla #include <uapi/sound/asound.h>
10abb9c9b8SSrinivas Kandagatla #include "slimbus.h"
11abb9c9b8SSrinivas Kandagatla 
12abb9c9b8SSrinivas Kandagatla /**
13abb9c9b8SSrinivas Kandagatla  * struct segdist_code - Segment Distributions code from
14abb9c9b8SSrinivas Kandagatla  *	Table 20 of SLIMbus Specs Version 2.0
15abb9c9b8SSrinivas Kandagatla  *
16abb9c9b8SSrinivas Kandagatla  * @ratem: Channel Rate Multipler(Segments per Superframe)
17abb9c9b8SSrinivas Kandagatla  * @seg_interval: Number of slots between the first Slot of Segment
18abb9c9b8SSrinivas Kandagatla  *		and the first slot of the next  consecutive Segment.
19abb9c9b8SSrinivas Kandagatla  * @segdist_code: Segment Distribution Code SD[11:0]
20abb9c9b8SSrinivas Kandagatla  * @seg_offset_mask: Segment offset mask in SD[11:0]
21abb9c9b8SSrinivas Kandagatla  * @segdist_codes: List of all possible Segmet Distribution codes.
22abb9c9b8SSrinivas Kandagatla  */
23abb9c9b8SSrinivas Kandagatla static const struct segdist_code {
24abb9c9b8SSrinivas Kandagatla 	int ratem;
25abb9c9b8SSrinivas Kandagatla 	int seg_interval;
26abb9c9b8SSrinivas Kandagatla 	int segdist_code;
27abb9c9b8SSrinivas Kandagatla 	u32 seg_offset_mask;
28abb9c9b8SSrinivas Kandagatla 
29abb9c9b8SSrinivas Kandagatla } segdist_codes[] = {
30abb9c9b8SSrinivas Kandagatla 	{1,	1536,	0x200,	 0xdff},
31abb9c9b8SSrinivas Kandagatla 	{2,	768,	0x100,	 0xcff},
32abb9c9b8SSrinivas Kandagatla 	{4,	384,	0x080,	 0xc7f},
33abb9c9b8SSrinivas Kandagatla 	{8,	192,	0x040,	 0xc3f},
34abb9c9b8SSrinivas Kandagatla 	{16,	96,	0x020,	 0xc1f},
35abb9c9b8SSrinivas Kandagatla 	{32,	48,	0x010,	 0xc0f},
36abb9c9b8SSrinivas Kandagatla 	{64,	24,	0x008,	 0xc07},
37abb9c9b8SSrinivas Kandagatla 	{128,	12,	0x004,	 0xc03},
38abb9c9b8SSrinivas Kandagatla 	{256,	6,	0x002,	 0xc01},
39abb9c9b8SSrinivas Kandagatla 	{512,	3,	0x001,	 0xc00},
40abb9c9b8SSrinivas Kandagatla 	{3,	512,	0xe00,	 0x1ff},
41abb9c9b8SSrinivas Kandagatla 	{6,	256,	0xd00,	 0x0ff},
42abb9c9b8SSrinivas Kandagatla 	{12,	128,	0xc80,	 0x07f},
43abb9c9b8SSrinivas Kandagatla 	{24,	64,	0xc40,	 0x03f},
44abb9c9b8SSrinivas Kandagatla 	{48,	32,	0xc20,	 0x01f},
45abb9c9b8SSrinivas Kandagatla 	{96,	16,	0xc10,	 0x00f},
46abb9c9b8SSrinivas Kandagatla 	{192,	8,	0xc08,	 0x007},
47abb9c9b8SSrinivas Kandagatla 	{364,	4,	0xc04,	 0x003},
48abb9c9b8SSrinivas Kandagatla 	{768,	2,	0xc02,	 0x001},
49abb9c9b8SSrinivas Kandagatla };
50abb9c9b8SSrinivas Kandagatla 
51abb9c9b8SSrinivas Kandagatla /*
52abb9c9b8SSrinivas Kandagatla  * Presence Rate table for all Natural Frequencies
53abb9c9b8SSrinivas Kandagatla  * The Presence rate of a constant bitrate stream is mean flow rate of the
54abb9c9b8SSrinivas Kandagatla  * stream expressed in occupied Segments of that Data Channel per second.
55abb9c9b8SSrinivas Kandagatla  * Table 66 from SLIMbus 2.0 Specs
56abb9c9b8SSrinivas Kandagatla  *
57abb9c9b8SSrinivas Kandagatla  * Index of the table corresponds to Presence rate code for the respective rate
58abb9c9b8SSrinivas Kandagatla  * in the table.
59abb9c9b8SSrinivas Kandagatla  */
60abb9c9b8SSrinivas Kandagatla static const int slim_presence_rate_table[] = {
61abb9c9b8SSrinivas Kandagatla 	0, /* Not Indicated */
62abb9c9b8SSrinivas Kandagatla 	12000,
63abb9c9b8SSrinivas Kandagatla 	24000,
64abb9c9b8SSrinivas Kandagatla 	48000,
65abb9c9b8SSrinivas Kandagatla 	96000,
66abb9c9b8SSrinivas Kandagatla 	192000,
67abb9c9b8SSrinivas Kandagatla 	384000,
68abb9c9b8SSrinivas Kandagatla 	768000,
69abb9c9b8SSrinivas Kandagatla 	0, /* Reserved */
70b9c19396SKrzysztof Kozlowski 	11025,
71b9c19396SKrzysztof Kozlowski 	22050,
72b9c19396SKrzysztof Kozlowski 	44100,
73b9c19396SKrzysztof Kozlowski 	88200,
74abb9c9b8SSrinivas Kandagatla 	176400,
75abb9c9b8SSrinivas Kandagatla 	352800,
76abb9c9b8SSrinivas Kandagatla 	705600,
77abb9c9b8SSrinivas Kandagatla 	4000,
78abb9c9b8SSrinivas Kandagatla 	8000,
79abb9c9b8SSrinivas Kandagatla 	16000,
80abb9c9b8SSrinivas Kandagatla 	32000,
81abb9c9b8SSrinivas Kandagatla 	64000,
82abb9c9b8SSrinivas Kandagatla 	128000,
83abb9c9b8SSrinivas Kandagatla 	256000,
84abb9c9b8SSrinivas Kandagatla 	512000,
85abb9c9b8SSrinivas Kandagatla };
86abb9c9b8SSrinivas Kandagatla 
872f0f2441SJonathan Corbet /**
88abb9c9b8SSrinivas Kandagatla  * slim_stream_allocate() - Allocate a new SLIMbus Stream
89abb9c9b8SSrinivas Kandagatla  * @dev:Slim device to be associated with
90abb9c9b8SSrinivas Kandagatla  * @name: name of the stream
91abb9c9b8SSrinivas Kandagatla  *
92abb9c9b8SSrinivas Kandagatla  * This is very first call for SLIMbus streaming, this API will allocate
93abb9c9b8SSrinivas Kandagatla  * a new SLIMbus stream and return a valid stream runtime pointer for client
94abb9c9b8SSrinivas Kandagatla  * to use it in subsequent stream apis. state of stream is set to ALLOCATED
95abb9c9b8SSrinivas Kandagatla  *
96abb9c9b8SSrinivas Kandagatla  * Return: valid pointer on success and error code on failure.
97abb9c9b8SSrinivas Kandagatla  * From ASoC DPCM framework, this state is linked to startup() operation.
98abb9c9b8SSrinivas Kandagatla  */
99abb9c9b8SSrinivas Kandagatla struct slim_stream_runtime *slim_stream_allocate(struct slim_device *dev,
100abb9c9b8SSrinivas Kandagatla 						 const char *name)
101abb9c9b8SSrinivas Kandagatla {
102abb9c9b8SSrinivas Kandagatla 	struct slim_stream_runtime *rt;
103abb9c9b8SSrinivas Kandagatla 
104abb9c9b8SSrinivas Kandagatla 	rt = kzalloc(sizeof(*rt), GFP_KERNEL);
105abb9c9b8SSrinivas Kandagatla 	if (!rt)
106abb9c9b8SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
107abb9c9b8SSrinivas Kandagatla 
108abb9c9b8SSrinivas Kandagatla 	rt->name = kasprintf(GFP_KERNEL, "slim-%s", name);
109abb9c9b8SSrinivas Kandagatla 	if (!rt->name) {
110abb9c9b8SSrinivas Kandagatla 		kfree(rt);
111abb9c9b8SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
112abb9c9b8SSrinivas Kandagatla 	}
113abb9c9b8SSrinivas Kandagatla 
114abb9c9b8SSrinivas Kandagatla 	rt->dev = dev;
115abb9c9b8SSrinivas Kandagatla 	spin_lock(&dev->stream_list_lock);
116abb9c9b8SSrinivas Kandagatla 	list_add_tail(&rt->node, &dev->stream_list);
117abb9c9b8SSrinivas Kandagatla 	spin_unlock(&dev->stream_list_lock);
118abb9c9b8SSrinivas Kandagatla 
119abb9c9b8SSrinivas Kandagatla 	return rt;
120abb9c9b8SSrinivas Kandagatla }
121abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_allocate);
122abb9c9b8SSrinivas Kandagatla 
123abb9c9b8SSrinivas Kandagatla static int slim_connect_port_channel(struct slim_stream_runtime *stream,
124abb9c9b8SSrinivas Kandagatla 				     struct slim_port *port)
125abb9c9b8SSrinivas Kandagatla {
126abb9c9b8SSrinivas Kandagatla 	struct slim_device *sdev = stream->dev;
127abb9c9b8SSrinivas Kandagatla 	u8 wbuf[2];
128abb9c9b8SSrinivas Kandagatla 	struct slim_val_inf msg = {0, 2, NULL, wbuf, NULL};
129abb9c9b8SSrinivas Kandagatla 	u8 mc = SLIM_MSG_MC_CONNECT_SOURCE;
130abb9c9b8SSrinivas Kandagatla 	DEFINE_SLIM_LDEST_TXN(txn, mc, 6, stream->dev->laddr, &msg);
131abb9c9b8SSrinivas Kandagatla 
132abb9c9b8SSrinivas Kandagatla 	if (port->direction == SLIM_PORT_SINK)
133abb9c9b8SSrinivas Kandagatla 		txn.mc = SLIM_MSG_MC_CONNECT_SINK;
134abb9c9b8SSrinivas Kandagatla 
135abb9c9b8SSrinivas Kandagatla 	wbuf[0] = port->id;
136abb9c9b8SSrinivas Kandagatla 	wbuf[1] = port->ch.id;
137abb9c9b8SSrinivas Kandagatla 	port->ch.state = SLIM_CH_STATE_ASSOCIATED;
138abb9c9b8SSrinivas Kandagatla 	port->state = SLIM_PORT_UNCONFIGURED;
139abb9c9b8SSrinivas Kandagatla 
140abb9c9b8SSrinivas Kandagatla 	return slim_do_transfer(sdev->ctrl, &txn);
141abb9c9b8SSrinivas Kandagatla }
142abb9c9b8SSrinivas Kandagatla 
143abb9c9b8SSrinivas Kandagatla static int slim_disconnect_port(struct slim_stream_runtime *stream,
144abb9c9b8SSrinivas Kandagatla 				struct slim_port *port)
145abb9c9b8SSrinivas Kandagatla {
146abb9c9b8SSrinivas Kandagatla 	struct slim_device *sdev = stream->dev;
147abb9c9b8SSrinivas Kandagatla 	u8 wbuf[1];
148abb9c9b8SSrinivas Kandagatla 	struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL};
149abb9c9b8SSrinivas Kandagatla 	u8 mc = SLIM_MSG_MC_DISCONNECT_PORT;
150abb9c9b8SSrinivas Kandagatla 	DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg);
151abb9c9b8SSrinivas Kandagatla 
152abb9c9b8SSrinivas Kandagatla 	wbuf[0] = port->id;
153abb9c9b8SSrinivas Kandagatla 	port->ch.state = SLIM_CH_STATE_DISCONNECTED;
154abb9c9b8SSrinivas Kandagatla 	port->state = SLIM_PORT_DISCONNECTED;
155abb9c9b8SSrinivas Kandagatla 
156abb9c9b8SSrinivas Kandagatla 	return slim_do_transfer(sdev->ctrl, &txn);
157abb9c9b8SSrinivas Kandagatla }
158abb9c9b8SSrinivas Kandagatla 
159abb9c9b8SSrinivas Kandagatla static int slim_deactivate_remove_channel(struct slim_stream_runtime *stream,
160abb9c9b8SSrinivas Kandagatla 					  struct slim_port *port)
161abb9c9b8SSrinivas Kandagatla {
162abb9c9b8SSrinivas Kandagatla 	struct slim_device *sdev = stream->dev;
163abb9c9b8SSrinivas Kandagatla 	u8 wbuf[1];
164abb9c9b8SSrinivas Kandagatla 	struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL};
165abb9c9b8SSrinivas Kandagatla 	u8 mc = SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL;
166abb9c9b8SSrinivas Kandagatla 	DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg);
167abb9c9b8SSrinivas Kandagatla 	int ret;
168abb9c9b8SSrinivas Kandagatla 
169abb9c9b8SSrinivas Kandagatla 	wbuf[0] = port->ch.id;
170abb9c9b8SSrinivas Kandagatla 	ret = slim_do_transfer(sdev->ctrl, &txn);
171abb9c9b8SSrinivas Kandagatla 	if (ret)
172abb9c9b8SSrinivas Kandagatla 		return ret;
173abb9c9b8SSrinivas Kandagatla 
174abb9c9b8SSrinivas Kandagatla 	txn.mc = SLIM_MSG_MC_NEXT_REMOVE_CHANNEL;
175abb9c9b8SSrinivas Kandagatla 	port->ch.state = SLIM_CH_STATE_REMOVED;
176abb9c9b8SSrinivas Kandagatla 
177abb9c9b8SSrinivas Kandagatla 	return slim_do_transfer(sdev->ctrl, &txn);
178abb9c9b8SSrinivas Kandagatla }
179abb9c9b8SSrinivas Kandagatla 
180abb9c9b8SSrinivas Kandagatla static int slim_get_prate_code(int rate)
181abb9c9b8SSrinivas Kandagatla {
182abb9c9b8SSrinivas Kandagatla 	int i;
183abb9c9b8SSrinivas Kandagatla 
184abb9c9b8SSrinivas Kandagatla 	for (i = 0; i < ARRAY_SIZE(slim_presence_rate_table); i++) {
185abb9c9b8SSrinivas Kandagatla 		if (rate == slim_presence_rate_table[i])
186abb9c9b8SSrinivas Kandagatla 			return i;
187abb9c9b8SSrinivas Kandagatla 	}
188abb9c9b8SSrinivas Kandagatla 
189abb9c9b8SSrinivas Kandagatla 	return -EINVAL;
190abb9c9b8SSrinivas Kandagatla }
191abb9c9b8SSrinivas Kandagatla 
1922f0f2441SJonathan Corbet /**
193abb9c9b8SSrinivas Kandagatla  * slim_stream_prepare() - Prepare a SLIMbus Stream
194abb9c9b8SSrinivas Kandagatla  *
195abb9c9b8SSrinivas Kandagatla  * @rt: instance of slim stream runtime to configure
196abb9c9b8SSrinivas Kandagatla  * @cfg: new configuration for the stream
197abb9c9b8SSrinivas Kandagatla  *
198abb9c9b8SSrinivas Kandagatla  * This API will configure SLIMbus stream with config parameters from cfg.
199abb9c9b8SSrinivas Kandagatla  * return zero on success and error code on failure. From ASoC DPCM framework,
200abb9c9b8SSrinivas Kandagatla  * this state is linked to hw_params() operation.
201abb9c9b8SSrinivas Kandagatla  */
202abb9c9b8SSrinivas Kandagatla int slim_stream_prepare(struct slim_stream_runtime *rt,
203abb9c9b8SSrinivas Kandagatla 			struct slim_stream_config *cfg)
204abb9c9b8SSrinivas Kandagatla {
205abb9c9b8SSrinivas Kandagatla 	struct slim_controller *ctrl = rt->dev->ctrl;
206abb9c9b8SSrinivas Kandagatla 	struct slim_port *port;
207*434d2572SKrzysztof Kozlowski 	int num_ports, i, port_id, prrate;
208abb9c9b8SSrinivas Kandagatla 
209abb9c9b8SSrinivas Kandagatla 	if (rt->ports) {
210abb9c9b8SSrinivas Kandagatla 		dev_err(&rt->dev->dev, "Stream already Prepared\n");
211abb9c9b8SSrinivas Kandagatla 		return -EINVAL;
212abb9c9b8SSrinivas Kandagatla 	}
213abb9c9b8SSrinivas Kandagatla 
214abb9c9b8SSrinivas Kandagatla 	num_ports = hweight32(cfg->port_mask);
215abb9c9b8SSrinivas Kandagatla 	rt->ports = kcalloc(num_ports, sizeof(*port), GFP_KERNEL);
216abb9c9b8SSrinivas Kandagatla 	if (!rt->ports)
217abb9c9b8SSrinivas Kandagatla 		return -ENOMEM;
218abb9c9b8SSrinivas Kandagatla 
219abb9c9b8SSrinivas Kandagatla 	rt->num_ports = num_ports;
220abb9c9b8SSrinivas Kandagatla 	rt->rate = cfg->rate;
221abb9c9b8SSrinivas Kandagatla 	rt->bps = cfg->bps;
222abb9c9b8SSrinivas Kandagatla 	rt->direction = cfg->direction;
223abb9c9b8SSrinivas Kandagatla 
224*434d2572SKrzysztof Kozlowski 	prrate = slim_get_prate_code(cfg->rate);
225*434d2572SKrzysztof Kozlowski 	if (prrate < 0) {
226*434d2572SKrzysztof Kozlowski 		dev_err(&rt->dev->dev, "Cannot get presence rate for rate %d Hz\n",
227*434d2572SKrzysztof Kozlowski 			cfg->rate);
228*434d2572SKrzysztof Kozlowski 		return prrate;
229*434d2572SKrzysztof Kozlowski 	}
230*434d2572SKrzysztof Kozlowski 
231abb9c9b8SSrinivas Kandagatla 	if (cfg->rate % ctrl->a_framer->superfreq) {
232abb9c9b8SSrinivas Kandagatla 		/*
233abb9c9b8SSrinivas Kandagatla 		 * data rate not exactly multiple of super frame,
234abb9c9b8SSrinivas Kandagatla 		 * use PUSH/PULL protocol
235abb9c9b8SSrinivas Kandagatla 		 */
236abb9c9b8SSrinivas Kandagatla 		if (cfg->direction == SNDRV_PCM_STREAM_PLAYBACK)
237abb9c9b8SSrinivas Kandagatla 			rt->prot = SLIM_PROTO_PUSH;
238abb9c9b8SSrinivas Kandagatla 		else
239abb9c9b8SSrinivas Kandagatla 			rt->prot = SLIM_PROTO_PULL;
240abb9c9b8SSrinivas Kandagatla 	} else {
241abb9c9b8SSrinivas Kandagatla 		rt->prot = SLIM_PROTO_ISO;
242abb9c9b8SSrinivas Kandagatla 	}
243abb9c9b8SSrinivas Kandagatla 
244abb9c9b8SSrinivas Kandagatla 	rt->ratem = cfg->rate/ctrl->a_framer->superfreq;
245abb9c9b8SSrinivas Kandagatla 
246abb9c9b8SSrinivas Kandagatla 	i = 0;
247abb9c9b8SSrinivas Kandagatla 	for_each_set_bit(port_id, &cfg->port_mask, SLIM_DEVICE_MAX_PORTS) {
248abb9c9b8SSrinivas Kandagatla 		port = &rt->ports[i];
249abb9c9b8SSrinivas Kandagatla 		port->state = SLIM_PORT_DISCONNECTED;
250abb9c9b8SSrinivas Kandagatla 		port->id = port_id;
251*434d2572SKrzysztof Kozlowski 		port->ch.prrate = prrate;
252abb9c9b8SSrinivas Kandagatla 		port->ch.id = cfg->chs[i];
253abb9c9b8SSrinivas Kandagatla 		port->ch.data_fmt = SLIM_CH_DATA_FMT_NOT_DEFINED;
254abb9c9b8SSrinivas Kandagatla 		port->ch.aux_fmt = SLIM_CH_AUX_FMT_NOT_APPLICABLE;
255abb9c9b8SSrinivas Kandagatla 		port->ch.state = SLIM_CH_STATE_ALLOCATED;
256abb9c9b8SSrinivas Kandagatla 
257abb9c9b8SSrinivas Kandagatla 		if (cfg->direction == SNDRV_PCM_STREAM_PLAYBACK)
258abb9c9b8SSrinivas Kandagatla 			port->direction = SLIM_PORT_SINK;
259abb9c9b8SSrinivas Kandagatla 		else
260abb9c9b8SSrinivas Kandagatla 			port->direction = SLIM_PORT_SOURCE;
261abb9c9b8SSrinivas Kandagatla 
262abb9c9b8SSrinivas Kandagatla 		slim_connect_port_channel(rt, port);
263abb9c9b8SSrinivas Kandagatla 		i++;
264abb9c9b8SSrinivas Kandagatla 	}
265abb9c9b8SSrinivas Kandagatla 
266abb9c9b8SSrinivas Kandagatla 	return 0;
267abb9c9b8SSrinivas Kandagatla }
268abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_prepare);
269abb9c9b8SSrinivas Kandagatla 
270abb9c9b8SSrinivas Kandagatla static int slim_define_channel_content(struct slim_stream_runtime *stream,
271abb9c9b8SSrinivas Kandagatla 				       struct slim_port *port)
272abb9c9b8SSrinivas Kandagatla {
273abb9c9b8SSrinivas Kandagatla 	struct slim_device *sdev = stream->dev;
274abb9c9b8SSrinivas Kandagatla 	u8 wbuf[4];
275abb9c9b8SSrinivas Kandagatla 	struct slim_val_inf msg = {0, 4, NULL, wbuf, NULL};
276abb9c9b8SSrinivas Kandagatla 	u8 mc = SLIM_MSG_MC_NEXT_DEFINE_CONTENT;
277abb9c9b8SSrinivas Kandagatla 	DEFINE_SLIM_LDEST_TXN(txn, mc, 8, stream->dev->laddr, &msg);
278abb9c9b8SSrinivas Kandagatla 
279abb9c9b8SSrinivas Kandagatla 	wbuf[0] = port->ch.id;
280abb9c9b8SSrinivas Kandagatla 	wbuf[1] = port->ch.prrate;
281abb9c9b8SSrinivas Kandagatla 
282abb9c9b8SSrinivas Kandagatla 	/* Frequency Locked for ISO Protocol */
283abb9c9b8SSrinivas Kandagatla 	if (stream->prot != SLIM_PROTO_ISO)
284abb9c9b8SSrinivas Kandagatla 		wbuf[1] |= SLIM_CHANNEL_CONTENT_FL;
285abb9c9b8SSrinivas Kandagatla 
286abb9c9b8SSrinivas Kandagatla 	wbuf[2] = port->ch.data_fmt | (port->ch.aux_fmt << 4);
287abb9c9b8SSrinivas Kandagatla 	wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS;
288abb9c9b8SSrinivas Kandagatla 	port->ch.state = SLIM_CH_STATE_CONTENT_DEFINED;
289abb9c9b8SSrinivas Kandagatla 
290abb9c9b8SSrinivas Kandagatla 	return slim_do_transfer(sdev->ctrl, &txn);
291abb9c9b8SSrinivas Kandagatla }
292abb9c9b8SSrinivas Kandagatla 
293abb9c9b8SSrinivas Kandagatla static int slim_get_segdist_code(int ratem)
294abb9c9b8SSrinivas Kandagatla {
295abb9c9b8SSrinivas Kandagatla 	int i;
296abb9c9b8SSrinivas Kandagatla 
297abb9c9b8SSrinivas Kandagatla 	for (i = 0; i < ARRAY_SIZE(segdist_codes); i++) {
298abb9c9b8SSrinivas Kandagatla 		if (segdist_codes[i].ratem == ratem)
299abb9c9b8SSrinivas Kandagatla 			return segdist_codes[i].segdist_code;
300abb9c9b8SSrinivas Kandagatla 	}
301abb9c9b8SSrinivas Kandagatla 
302abb9c9b8SSrinivas Kandagatla 	return -EINVAL;
303abb9c9b8SSrinivas Kandagatla }
304abb9c9b8SSrinivas Kandagatla 
305abb9c9b8SSrinivas Kandagatla static int slim_define_channel(struct slim_stream_runtime *stream,
306abb9c9b8SSrinivas Kandagatla 				       struct slim_port *port)
307abb9c9b8SSrinivas Kandagatla {
308abb9c9b8SSrinivas Kandagatla 	struct slim_device *sdev = stream->dev;
309abb9c9b8SSrinivas Kandagatla 	u8 wbuf[4];
310abb9c9b8SSrinivas Kandagatla 	struct slim_val_inf msg = {0, 4, NULL, wbuf, NULL};
311abb9c9b8SSrinivas Kandagatla 	u8 mc = SLIM_MSG_MC_NEXT_DEFINE_CHANNEL;
312abb9c9b8SSrinivas Kandagatla 	DEFINE_SLIM_LDEST_TXN(txn, mc, 8, stream->dev->laddr, &msg);
313abb9c9b8SSrinivas Kandagatla 
314abb9c9b8SSrinivas Kandagatla 	port->ch.seg_dist = slim_get_segdist_code(stream->ratem);
315abb9c9b8SSrinivas Kandagatla 
316abb9c9b8SSrinivas Kandagatla 	wbuf[0] = port->ch.id;
317abb9c9b8SSrinivas Kandagatla 	wbuf[1] = port->ch.seg_dist & 0xFF;
318abb9c9b8SSrinivas Kandagatla 	wbuf[2] = (stream->prot << 4) | ((port->ch.seg_dist & 0xF00) >> 8);
319abb9c9b8SSrinivas Kandagatla 	if (stream->prot == SLIM_PROTO_ISO)
320abb9c9b8SSrinivas Kandagatla 		wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS;
321abb9c9b8SSrinivas Kandagatla 	else
322abb9c9b8SSrinivas Kandagatla 		wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS + 1;
323abb9c9b8SSrinivas Kandagatla 
324abb9c9b8SSrinivas Kandagatla 	port->ch.state = SLIM_CH_STATE_DEFINED;
325abb9c9b8SSrinivas Kandagatla 
326abb9c9b8SSrinivas Kandagatla 	return slim_do_transfer(sdev->ctrl, &txn);
327abb9c9b8SSrinivas Kandagatla }
328abb9c9b8SSrinivas Kandagatla 
329abb9c9b8SSrinivas Kandagatla static int slim_activate_channel(struct slim_stream_runtime *stream,
330abb9c9b8SSrinivas Kandagatla 				 struct slim_port *port)
331abb9c9b8SSrinivas Kandagatla {
332abb9c9b8SSrinivas Kandagatla 	struct slim_device *sdev = stream->dev;
333abb9c9b8SSrinivas Kandagatla 	u8 wbuf[1];
334abb9c9b8SSrinivas Kandagatla 	struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL};
335abb9c9b8SSrinivas Kandagatla 	u8 mc = SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL;
336abb9c9b8SSrinivas Kandagatla 	DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg);
337abb9c9b8SSrinivas Kandagatla 
338abb9c9b8SSrinivas Kandagatla 	txn.msg->num_bytes = 1;
339abb9c9b8SSrinivas Kandagatla 	txn.msg->wbuf = wbuf;
340abb9c9b8SSrinivas Kandagatla 	wbuf[0] = port->ch.id;
341abb9c9b8SSrinivas Kandagatla 	port->ch.state = SLIM_CH_STATE_ACTIVE;
342abb9c9b8SSrinivas Kandagatla 
343abb9c9b8SSrinivas Kandagatla 	return slim_do_transfer(sdev->ctrl, &txn);
344abb9c9b8SSrinivas Kandagatla }
345abb9c9b8SSrinivas Kandagatla 
3462f0f2441SJonathan Corbet /**
347abb9c9b8SSrinivas Kandagatla  * slim_stream_enable() - Enable a prepared SLIMbus Stream
348abb9c9b8SSrinivas Kandagatla  *
349abb9c9b8SSrinivas Kandagatla  * @stream: instance of slim stream runtime to enable
350abb9c9b8SSrinivas Kandagatla  *
351abb9c9b8SSrinivas Kandagatla  * This API will enable all the ports and channels associated with
352abb9c9b8SSrinivas Kandagatla  * SLIMbus stream
353abb9c9b8SSrinivas Kandagatla  *
354abb9c9b8SSrinivas Kandagatla  * Return: zero on success and error code on failure. From ASoC DPCM framework,
355abb9c9b8SSrinivas Kandagatla  * this state is linked to trigger() start operation.
356abb9c9b8SSrinivas Kandagatla  */
357abb9c9b8SSrinivas Kandagatla int slim_stream_enable(struct slim_stream_runtime *stream)
358abb9c9b8SSrinivas Kandagatla {
359abb9c9b8SSrinivas Kandagatla 	DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
360abb9c9b8SSrinivas Kandagatla 				3, SLIM_LA_MANAGER, NULL);
361abb9c9b8SSrinivas Kandagatla 	struct slim_controller *ctrl = stream->dev->ctrl;
362abb9c9b8SSrinivas Kandagatla 	int ret, i;
363abb9c9b8SSrinivas Kandagatla 
364abb9c9b8SSrinivas Kandagatla 	if (ctrl->enable_stream) {
365abb9c9b8SSrinivas Kandagatla 		ret = ctrl->enable_stream(stream);
366abb9c9b8SSrinivas Kandagatla 		if (ret)
367abb9c9b8SSrinivas Kandagatla 			return ret;
368abb9c9b8SSrinivas Kandagatla 
369abb9c9b8SSrinivas Kandagatla 		for (i = 0; i < stream->num_ports; i++)
370abb9c9b8SSrinivas Kandagatla 			stream->ports[i].ch.state = SLIM_CH_STATE_ACTIVE;
371abb9c9b8SSrinivas Kandagatla 
372abb9c9b8SSrinivas Kandagatla 		return ret;
373abb9c9b8SSrinivas Kandagatla 	}
374abb9c9b8SSrinivas Kandagatla 
375abb9c9b8SSrinivas Kandagatla 	ret = slim_do_transfer(ctrl, &txn);
376abb9c9b8SSrinivas Kandagatla 	if (ret)
377abb9c9b8SSrinivas Kandagatla 		return ret;
378abb9c9b8SSrinivas Kandagatla 
379abb9c9b8SSrinivas Kandagatla 	/* define channels first before activating them */
380abb9c9b8SSrinivas Kandagatla 	for (i = 0; i < stream->num_ports; i++) {
381abb9c9b8SSrinivas Kandagatla 		struct slim_port *port = &stream->ports[i];
382abb9c9b8SSrinivas Kandagatla 
383abb9c9b8SSrinivas Kandagatla 		slim_define_channel(stream, port);
384abb9c9b8SSrinivas Kandagatla 		slim_define_channel_content(stream, port);
385abb9c9b8SSrinivas Kandagatla 	}
386abb9c9b8SSrinivas Kandagatla 
387abb9c9b8SSrinivas Kandagatla 	for (i = 0; i < stream->num_ports; i++) {
388abb9c9b8SSrinivas Kandagatla 		struct slim_port *port = &stream->ports[i];
389abb9c9b8SSrinivas Kandagatla 
390abb9c9b8SSrinivas Kandagatla 		slim_activate_channel(stream, port);
391abb9c9b8SSrinivas Kandagatla 		port->state = SLIM_PORT_CONFIGURED;
392abb9c9b8SSrinivas Kandagatla 	}
393abb9c9b8SSrinivas Kandagatla 	txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
394abb9c9b8SSrinivas Kandagatla 
395abb9c9b8SSrinivas Kandagatla 	return slim_do_transfer(ctrl, &txn);
396abb9c9b8SSrinivas Kandagatla }
397abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_enable);
398abb9c9b8SSrinivas Kandagatla 
3992f0f2441SJonathan Corbet /**
400abb9c9b8SSrinivas Kandagatla  * slim_stream_disable() - Disable a SLIMbus Stream
401abb9c9b8SSrinivas Kandagatla  *
402abb9c9b8SSrinivas Kandagatla  * @stream: instance of slim stream runtime to disable
403abb9c9b8SSrinivas Kandagatla  *
404abb9c9b8SSrinivas Kandagatla  * This API will disable all the ports and channels associated with
405abb9c9b8SSrinivas Kandagatla  * SLIMbus stream
406abb9c9b8SSrinivas Kandagatla  *
407abb9c9b8SSrinivas Kandagatla  * Return: zero on success and error code on failure. From ASoC DPCM framework,
408abb9c9b8SSrinivas Kandagatla  * this state is linked to trigger() pause operation.
409abb9c9b8SSrinivas Kandagatla  */
410abb9c9b8SSrinivas Kandagatla int slim_stream_disable(struct slim_stream_runtime *stream)
411abb9c9b8SSrinivas Kandagatla {
412abb9c9b8SSrinivas Kandagatla 	DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
413abb9c9b8SSrinivas Kandagatla 				3, SLIM_LA_MANAGER, NULL);
414abb9c9b8SSrinivas Kandagatla 	struct slim_controller *ctrl = stream->dev->ctrl;
415abb9c9b8SSrinivas Kandagatla 	int ret, i;
416abb9c9b8SSrinivas Kandagatla 
417abb9c9b8SSrinivas Kandagatla 	if (ctrl->disable_stream)
418abb9c9b8SSrinivas Kandagatla 		ctrl->disable_stream(stream);
419abb9c9b8SSrinivas Kandagatla 
420abb9c9b8SSrinivas Kandagatla 	ret = slim_do_transfer(ctrl, &txn);
421abb9c9b8SSrinivas Kandagatla 	if (ret)
422abb9c9b8SSrinivas Kandagatla 		return ret;
423abb9c9b8SSrinivas Kandagatla 
424abb9c9b8SSrinivas Kandagatla 	for (i = 0; i < stream->num_ports; i++)
425abb9c9b8SSrinivas Kandagatla 		slim_deactivate_remove_channel(stream, &stream->ports[i]);
426abb9c9b8SSrinivas Kandagatla 
427abb9c9b8SSrinivas Kandagatla 	txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
428abb9c9b8SSrinivas Kandagatla 
429abb9c9b8SSrinivas Kandagatla 	return slim_do_transfer(ctrl, &txn);
430abb9c9b8SSrinivas Kandagatla }
431abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_disable);
432abb9c9b8SSrinivas Kandagatla 
4332f0f2441SJonathan Corbet /**
434abb9c9b8SSrinivas Kandagatla  * slim_stream_unprepare() - Un-prepare a SLIMbus Stream
435abb9c9b8SSrinivas Kandagatla  *
436abb9c9b8SSrinivas Kandagatla  * @stream: instance of slim stream runtime to unprepare
437abb9c9b8SSrinivas Kandagatla  *
438abb9c9b8SSrinivas Kandagatla  * This API will un allocate all the ports and channels associated with
439abb9c9b8SSrinivas Kandagatla  * SLIMbus stream
440abb9c9b8SSrinivas Kandagatla  *
441abb9c9b8SSrinivas Kandagatla  * Return: zero on success and error code on failure. From ASoC DPCM framework,
442abb9c9b8SSrinivas Kandagatla  * this state is linked to trigger() stop operation.
443abb9c9b8SSrinivas Kandagatla  */
444abb9c9b8SSrinivas Kandagatla int slim_stream_unprepare(struct slim_stream_runtime *stream)
445abb9c9b8SSrinivas Kandagatla {
446abb9c9b8SSrinivas Kandagatla 	int i;
447abb9c9b8SSrinivas Kandagatla 
448abb9c9b8SSrinivas Kandagatla 	for (i = 0; i < stream->num_ports; i++)
449abb9c9b8SSrinivas Kandagatla 		slim_disconnect_port(stream, &stream->ports[i]);
450abb9c9b8SSrinivas Kandagatla 
451abb9c9b8SSrinivas Kandagatla 	kfree(stream->ports);
452abb9c9b8SSrinivas Kandagatla 	stream->ports = NULL;
453abb9c9b8SSrinivas Kandagatla 	stream->num_ports = 0;
454abb9c9b8SSrinivas Kandagatla 
455abb9c9b8SSrinivas Kandagatla 	return 0;
456abb9c9b8SSrinivas Kandagatla }
457abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_unprepare);
458abb9c9b8SSrinivas Kandagatla 
4592f0f2441SJonathan Corbet /**
460abb9c9b8SSrinivas Kandagatla  * slim_stream_free() - Free a SLIMbus Stream
461abb9c9b8SSrinivas Kandagatla  *
462abb9c9b8SSrinivas Kandagatla  * @stream: instance of slim stream runtime to free
463abb9c9b8SSrinivas Kandagatla  *
464abb9c9b8SSrinivas Kandagatla  * This API will un allocate all the memory associated with
465abb9c9b8SSrinivas Kandagatla  * slim stream runtime, user is not allowed to make an dereference
466abb9c9b8SSrinivas Kandagatla  * to stream after this call.
467abb9c9b8SSrinivas Kandagatla  *
468abb9c9b8SSrinivas Kandagatla  * Return: zero on success and error code on failure. From ASoC DPCM framework,
469abb9c9b8SSrinivas Kandagatla  * this state is linked to shutdown() operation.
470abb9c9b8SSrinivas Kandagatla  */
471abb9c9b8SSrinivas Kandagatla int slim_stream_free(struct slim_stream_runtime *stream)
472abb9c9b8SSrinivas Kandagatla {
473abb9c9b8SSrinivas Kandagatla 	struct slim_device *sdev = stream->dev;
474abb9c9b8SSrinivas Kandagatla 
475abb9c9b8SSrinivas Kandagatla 	spin_lock(&sdev->stream_list_lock);
476abb9c9b8SSrinivas Kandagatla 	list_del(&stream->node);
477abb9c9b8SSrinivas Kandagatla 	spin_unlock(&sdev->stream_list_lock);
478abb9c9b8SSrinivas Kandagatla 
479abb9c9b8SSrinivas Kandagatla 	kfree(stream->name);
480abb9c9b8SSrinivas Kandagatla 	kfree(stream);
481abb9c9b8SSrinivas Kandagatla 
482abb9c9b8SSrinivas Kandagatla 	return 0;
483abb9c9b8SSrinivas Kandagatla }
484abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_free);
485