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 */
slim_stream_allocate(struct slim_device * dev,const char * name)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
slim_connect_port_channel(struct slim_stream_runtime * stream,struct slim_port * port)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
slim_disconnect_port(struct slim_stream_runtime * stream,struct slim_port * port)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
slim_deactivate_remove_channel(struct slim_stream_runtime * stream,struct slim_port * port)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
slim_get_prate_code(int rate)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 */
slim_stream_prepare(struct slim_stream_runtime * rt,struct slim_stream_config * cfg)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;
207434d2572SKrzysztof 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
224434d2572SKrzysztof Kozlowski prrate = slim_get_prate_code(cfg->rate);
225434d2572SKrzysztof Kozlowski if (prrate < 0) {
226434d2572SKrzysztof Kozlowski dev_err(&rt->dev->dev, "Cannot get presence rate for rate %d Hz\n",
227434d2572SKrzysztof Kozlowski cfg->rate);
228434d2572SKrzysztof Kozlowski return prrate;
229434d2572SKrzysztof Kozlowski }
230434d2572SKrzysztof 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;
251434d2572SKrzysztof 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
slim_define_channel_content(struct slim_stream_runtime * stream,struct slim_port * port)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
slim_get_segdist_code(int ratem)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
slim_define_channel(struct slim_stream_runtime * stream,struct slim_port * port)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
slim_activate_channel(struct slim_stream_runtime * stream,struct slim_port * port)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 */
slim_stream_enable(struct slim_stream_runtime * stream)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 */
slim_stream_disable(struct slim_stream_runtime * stream)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
417*a82b1ec3SKrzysztof Kozlowski if (!stream->ports || !stream->num_ports)
418*a82b1ec3SKrzysztof Kozlowski return -EINVAL;
419*a82b1ec3SKrzysztof Kozlowski
420abb9c9b8SSrinivas Kandagatla if (ctrl->disable_stream)
421abb9c9b8SSrinivas Kandagatla ctrl->disable_stream(stream);
422abb9c9b8SSrinivas Kandagatla
423abb9c9b8SSrinivas Kandagatla ret = slim_do_transfer(ctrl, &txn);
424abb9c9b8SSrinivas Kandagatla if (ret)
425abb9c9b8SSrinivas Kandagatla return ret;
426abb9c9b8SSrinivas Kandagatla
427abb9c9b8SSrinivas Kandagatla for (i = 0; i < stream->num_ports; i++)
428abb9c9b8SSrinivas Kandagatla slim_deactivate_remove_channel(stream, &stream->ports[i]);
429abb9c9b8SSrinivas Kandagatla
430abb9c9b8SSrinivas Kandagatla txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
431abb9c9b8SSrinivas Kandagatla
432abb9c9b8SSrinivas Kandagatla return slim_do_transfer(ctrl, &txn);
433abb9c9b8SSrinivas Kandagatla }
434abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_disable);
435abb9c9b8SSrinivas Kandagatla
4362f0f2441SJonathan Corbet /**
437abb9c9b8SSrinivas Kandagatla * slim_stream_unprepare() - Un-prepare a SLIMbus Stream
438abb9c9b8SSrinivas Kandagatla *
439abb9c9b8SSrinivas Kandagatla * @stream: instance of slim stream runtime to unprepare
440abb9c9b8SSrinivas Kandagatla *
441abb9c9b8SSrinivas Kandagatla * This API will un allocate all the ports and channels associated with
442abb9c9b8SSrinivas Kandagatla * SLIMbus stream
443abb9c9b8SSrinivas Kandagatla *
444abb9c9b8SSrinivas Kandagatla * Return: zero on success and error code on failure. From ASoC DPCM framework,
445abb9c9b8SSrinivas Kandagatla * this state is linked to trigger() stop operation.
446abb9c9b8SSrinivas Kandagatla */
slim_stream_unprepare(struct slim_stream_runtime * stream)447abb9c9b8SSrinivas Kandagatla int slim_stream_unprepare(struct slim_stream_runtime *stream)
448abb9c9b8SSrinivas Kandagatla {
449abb9c9b8SSrinivas Kandagatla int i;
450abb9c9b8SSrinivas Kandagatla
451*a82b1ec3SKrzysztof Kozlowski if (!stream->ports || !stream->num_ports)
452*a82b1ec3SKrzysztof Kozlowski return -EINVAL;
453*a82b1ec3SKrzysztof Kozlowski
454abb9c9b8SSrinivas Kandagatla for (i = 0; i < stream->num_ports; i++)
455abb9c9b8SSrinivas Kandagatla slim_disconnect_port(stream, &stream->ports[i]);
456abb9c9b8SSrinivas Kandagatla
457abb9c9b8SSrinivas Kandagatla kfree(stream->ports);
458abb9c9b8SSrinivas Kandagatla stream->ports = NULL;
459abb9c9b8SSrinivas Kandagatla stream->num_ports = 0;
460abb9c9b8SSrinivas Kandagatla
461abb9c9b8SSrinivas Kandagatla return 0;
462abb9c9b8SSrinivas Kandagatla }
463abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_unprepare);
464abb9c9b8SSrinivas Kandagatla
4652f0f2441SJonathan Corbet /**
466abb9c9b8SSrinivas Kandagatla * slim_stream_free() - Free a SLIMbus Stream
467abb9c9b8SSrinivas Kandagatla *
468abb9c9b8SSrinivas Kandagatla * @stream: instance of slim stream runtime to free
469abb9c9b8SSrinivas Kandagatla *
470abb9c9b8SSrinivas Kandagatla * This API will un allocate all the memory associated with
471abb9c9b8SSrinivas Kandagatla * slim stream runtime, user is not allowed to make an dereference
472abb9c9b8SSrinivas Kandagatla * to stream after this call.
473abb9c9b8SSrinivas Kandagatla *
474abb9c9b8SSrinivas Kandagatla * Return: zero on success and error code on failure. From ASoC DPCM framework,
475abb9c9b8SSrinivas Kandagatla * this state is linked to shutdown() operation.
476abb9c9b8SSrinivas Kandagatla */
slim_stream_free(struct slim_stream_runtime * stream)477abb9c9b8SSrinivas Kandagatla int slim_stream_free(struct slim_stream_runtime *stream)
478abb9c9b8SSrinivas Kandagatla {
479abb9c9b8SSrinivas Kandagatla struct slim_device *sdev = stream->dev;
480abb9c9b8SSrinivas Kandagatla
481abb9c9b8SSrinivas Kandagatla spin_lock(&sdev->stream_list_lock);
482abb9c9b8SSrinivas Kandagatla list_del(&stream->node);
483abb9c9b8SSrinivas Kandagatla spin_unlock(&sdev->stream_list_lock);
484abb9c9b8SSrinivas Kandagatla
485abb9c9b8SSrinivas Kandagatla kfree(stream->name);
486abb9c9b8SSrinivas Kandagatla kfree(stream);
487abb9c9b8SSrinivas Kandagatla
488abb9c9b8SSrinivas Kandagatla return 0;
489abb9c9b8SSrinivas Kandagatla }
490abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_free);
491