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