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