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