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