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 */ 70abb9c9b8SSrinivas Kandagatla 110250, 71abb9c9b8SSrinivas Kandagatla 220500, 72abb9c9b8SSrinivas Kandagatla 441000, 73abb9c9b8SSrinivas Kandagatla 882000, 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 87*2f0f2441SJonathan 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 192*2f0f2441SJonathan 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; 207abb9c9b8SSrinivas Kandagatla int num_ports, i, port_id; 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 224abb9c9b8SSrinivas Kandagatla if (cfg->rate % ctrl->a_framer->superfreq) { 225abb9c9b8SSrinivas Kandagatla /* 226abb9c9b8SSrinivas Kandagatla * data rate not exactly multiple of super frame, 227abb9c9b8SSrinivas Kandagatla * use PUSH/PULL protocol 228abb9c9b8SSrinivas Kandagatla */ 229abb9c9b8SSrinivas Kandagatla if (cfg->direction == SNDRV_PCM_STREAM_PLAYBACK) 230abb9c9b8SSrinivas Kandagatla rt->prot = SLIM_PROTO_PUSH; 231abb9c9b8SSrinivas Kandagatla else 232abb9c9b8SSrinivas Kandagatla rt->prot = SLIM_PROTO_PULL; 233abb9c9b8SSrinivas Kandagatla } else { 234abb9c9b8SSrinivas Kandagatla rt->prot = SLIM_PROTO_ISO; 235abb9c9b8SSrinivas Kandagatla } 236abb9c9b8SSrinivas Kandagatla 237abb9c9b8SSrinivas Kandagatla rt->ratem = cfg->rate/ctrl->a_framer->superfreq; 238abb9c9b8SSrinivas Kandagatla 239abb9c9b8SSrinivas Kandagatla i = 0; 240abb9c9b8SSrinivas Kandagatla for_each_set_bit(port_id, &cfg->port_mask, SLIM_DEVICE_MAX_PORTS) { 241abb9c9b8SSrinivas Kandagatla port = &rt->ports[i]; 242abb9c9b8SSrinivas Kandagatla port->state = SLIM_PORT_DISCONNECTED; 243abb9c9b8SSrinivas Kandagatla port->id = port_id; 244abb9c9b8SSrinivas Kandagatla port->ch.prrate = slim_get_prate_code(cfg->rate); 245abb9c9b8SSrinivas Kandagatla port->ch.id = cfg->chs[i]; 246abb9c9b8SSrinivas Kandagatla port->ch.data_fmt = SLIM_CH_DATA_FMT_NOT_DEFINED; 247abb9c9b8SSrinivas Kandagatla port->ch.aux_fmt = SLIM_CH_AUX_FMT_NOT_APPLICABLE; 248abb9c9b8SSrinivas Kandagatla port->ch.state = SLIM_CH_STATE_ALLOCATED; 249abb9c9b8SSrinivas Kandagatla 250abb9c9b8SSrinivas Kandagatla if (cfg->direction == SNDRV_PCM_STREAM_PLAYBACK) 251abb9c9b8SSrinivas Kandagatla port->direction = SLIM_PORT_SINK; 252abb9c9b8SSrinivas Kandagatla else 253abb9c9b8SSrinivas Kandagatla port->direction = SLIM_PORT_SOURCE; 254abb9c9b8SSrinivas Kandagatla 255abb9c9b8SSrinivas Kandagatla slim_connect_port_channel(rt, port); 256abb9c9b8SSrinivas Kandagatla i++; 257abb9c9b8SSrinivas Kandagatla } 258abb9c9b8SSrinivas Kandagatla 259abb9c9b8SSrinivas Kandagatla return 0; 260abb9c9b8SSrinivas Kandagatla } 261abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_prepare); 262abb9c9b8SSrinivas Kandagatla 263abb9c9b8SSrinivas Kandagatla static int slim_define_channel_content(struct slim_stream_runtime *stream, 264abb9c9b8SSrinivas Kandagatla struct slim_port *port) 265abb9c9b8SSrinivas Kandagatla { 266abb9c9b8SSrinivas Kandagatla struct slim_device *sdev = stream->dev; 267abb9c9b8SSrinivas Kandagatla u8 wbuf[4]; 268abb9c9b8SSrinivas Kandagatla struct slim_val_inf msg = {0, 4, NULL, wbuf, NULL}; 269abb9c9b8SSrinivas Kandagatla u8 mc = SLIM_MSG_MC_NEXT_DEFINE_CONTENT; 270abb9c9b8SSrinivas Kandagatla DEFINE_SLIM_LDEST_TXN(txn, mc, 8, stream->dev->laddr, &msg); 271abb9c9b8SSrinivas Kandagatla 272abb9c9b8SSrinivas Kandagatla wbuf[0] = port->ch.id; 273abb9c9b8SSrinivas Kandagatla wbuf[1] = port->ch.prrate; 274abb9c9b8SSrinivas Kandagatla 275abb9c9b8SSrinivas Kandagatla /* Frequency Locked for ISO Protocol */ 276abb9c9b8SSrinivas Kandagatla if (stream->prot != SLIM_PROTO_ISO) 277abb9c9b8SSrinivas Kandagatla wbuf[1] |= SLIM_CHANNEL_CONTENT_FL; 278abb9c9b8SSrinivas Kandagatla 279abb9c9b8SSrinivas Kandagatla wbuf[2] = port->ch.data_fmt | (port->ch.aux_fmt << 4); 280abb9c9b8SSrinivas Kandagatla wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS; 281abb9c9b8SSrinivas Kandagatla port->ch.state = SLIM_CH_STATE_CONTENT_DEFINED; 282abb9c9b8SSrinivas Kandagatla 283abb9c9b8SSrinivas Kandagatla return slim_do_transfer(sdev->ctrl, &txn); 284abb9c9b8SSrinivas Kandagatla } 285abb9c9b8SSrinivas Kandagatla 286abb9c9b8SSrinivas Kandagatla static int slim_get_segdist_code(int ratem) 287abb9c9b8SSrinivas Kandagatla { 288abb9c9b8SSrinivas Kandagatla int i; 289abb9c9b8SSrinivas Kandagatla 290abb9c9b8SSrinivas Kandagatla for (i = 0; i < ARRAY_SIZE(segdist_codes); i++) { 291abb9c9b8SSrinivas Kandagatla if (segdist_codes[i].ratem == ratem) 292abb9c9b8SSrinivas Kandagatla return segdist_codes[i].segdist_code; 293abb9c9b8SSrinivas Kandagatla } 294abb9c9b8SSrinivas Kandagatla 295abb9c9b8SSrinivas Kandagatla return -EINVAL; 296abb9c9b8SSrinivas Kandagatla } 297abb9c9b8SSrinivas Kandagatla 298abb9c9b8SSrinivas Kandagatla static int slim_define_channel(struct slim_stream_runtime *stream, 299abb9c9b8SSrinivas Kandagatla struct slim_port *port) 300abb9c9b8SSrinivas Kandagatla { 301abb9c9b8SSrinivas Kandagatla struct slim_device *sdev = stream->dev; 302abb9c9b8SSrinivas Kandagatla u8 wbuf[4]; 303abb9c9b8SSrinivas Kandagatla struct slim_val_inf msg = {0, 4, NULL, wbuf, NULL}; 304abb9c9b8SSrinivas Kandagatla u8 mc = SLIM_MSG_MC_NEXT_DEFINE_CHANNEL; 305abb9c9b8SSrinivas Kandagatla DEFINE_SLIM_LDEST_TXN(txn, mc, 8, stream->dev->laddr, &msg); 306abb9c9b8SSrinivas Kandagatla 307abb9c9b8SSrinivas Kandagatla port->ch.seg_dist = slim_get_segdist_code(stream->ratem); 308abb9c9b8SSrinivas Kandagatla 309abb9c9b8SSrinivas Kandagatla wbuf[0] = port->ch.id; 310abb9c9b8SSrinivas Kandagatla wbuf[1] = port->ch.seg_dist & 0xFF; 311abb9c9b8SSrinivas Kandagatla wbuf[2] = (stream->prot << 4) | ((port->ch.seg_dist & 0xF00) >> 8); 312abb9c9b8SSrinivas Kandagatla if (stream->prot == SLIM_PROTO_ISO) 313abb9c9b8SSrinivas Kandagatla wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS; 314abb9c9b8SSrinivas Kandagatla else 315abb9c9b8SSrinivas Kandagatla wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS + 1; 316abb9c9b8SSrinivas Kandagatla 317abb9c9b8SSrinivas Kandagatla port->ch.state = SLIM_CH_STATE_DEFINED; 318abb9c9b8SSrinivas Kandagatla 319abb9c9b8SSrinivas Kandagatla return slim_do_transfer(sdev->ctrl, &txn); 320abb9c9b8SSrinivas Kandagatla } 321abb9c9b8SSrinivas Kandagatla 322abb9c9b8SSrinivas Kandagatla static int slim_activate_channel(struct slim_stream_runtime *stream, 323abb9c9b8SSrinivas Kandagatla struct slim_port *port) 324abb9c9b8SSrinivas Kandagatla { 325abb9c9b8SSrinivas Kandagatla struct slim_device *sdev = stream->dev; 326abb9c9b8SSrinivas Kandagatla u8 wbuf[1]; 327abb9c9b8SSrinivas Kandagatla struct slim_val_inf msg = {0, 1, NULL, wbuf, NULL}; 328abb9c9b8SSrinivas Kandagatla u8 mc = SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL; 329abb9c9b8SSrinivas Kandagatla DEFINE_SLIM_LDEST_TXN(txn, mc, 5, stream->dev->laddr, &msg); 330abb9c9b8SSrinivas Kandagatla 331abb9c9b8SSrinivas Kandagatla txn.msg->num_bytes = 1; 332abb9c9b8SSrinivas Kandagatla txn.msg->wbuf = wbuf; 333abb9c9b8SSrinivas Kandagatla wbuf[0] = port->ch.id; 334abb9c9b8SSrinivas Kandagatla port->ch.state = SLIM_CH_STATE_ACTIVE; 335abb9c9b8SSrinivas Kandagatla 336abb9c9b8SSrinivas Kandagatla return slim_do_transfer(sdev->ctrl, &txn); 337abb9c9b8SSrinivas Kandagatla } 338abb9c9b8SSrinivas Kandagatla 339*2f0f2441SJonathan Corbet /** 340abb9c9b8SSrinivas Kandagatla * slim_stream_enable() - Enable a prepared SLIMbus Stream 341abb9c9b8SSrinivas Kandagatla * 342abb9c9b8SSrinivas Kandagatla * @stream: instance of slim stream runtime to enable 343abb9c9b8SSrinivas Kandagatla * 344abb9c9b8SSrinivas Kandagatla * This API will enable all the ports and channels associated with 345abb9c9b8SSrinivas Kandagatla * SLIMbus stream 346abb9c9b8SSrinivas Kandagatla * 347abb9c9b8SSrinivas Kandagatla * Return: zero on success and error code on failure. From ASoC DPCM framework, 348abb9c9b8SSrinivas Kandagatla * this state is linked to trigger() start operation. 349abb9c9b8SSrinivas Kandagatla */ 350abb9c9b8SSrinivas Kandagatla int slim_stream_enable(struct slim_stream_runtime *stream) 351abb9c9b8SSrinivas Kandagatla { 352abb9c9b8SSrinivas Kandagatla DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION, 353abb9c9b8SSrinivas Kandagatla 3, SLIM_LA_MANAGER, NULL); 354abb9c9b8SSrinivas Kandagatla struct slim_controller *ctrl = stream->dev->ctrl; 355abb9c9b8SSrinivas Kandagatla int ret, i; 356abb9c9b8SSrinivas Kandagatla 357abb9c9b8SSrinivas Kandagatla if (ctrl->enable_stream) { 358abb9c9b8SSrinivas Kandagatla ret = ctrl->enable_stream(stream); 359abb9c9b8SSrinivas Kandagatla if (ret) 360abb9c9b8SSrinivas Kandagatla return ret; 361abb9c9b8SSrinivas Kandagatla 362abb9c9b8SSrinivas Kandagatla for (i = 0; i < stream->num_ports; i++) 363abb9c9b8SSrinivas Kandagatla stream->ports[i].ch.state = SLIM_CH_STATE_ACTIVE; 364abb9c9b8SSrinivas Kandagatla 365abb9c9b8SSrinivas Kandagatla return ret; 366abb9c9b8SSrinivas Kandagatla } 367abb9c9b8SSrinivas Kandagatla 368abb9c9b8SSrinivas Kandagatla ret = slim_do_transfer(ctrl, &txn); 369abb9c9b8SSrinivas Kandagatla if (ret) 370abb9c9b8SSrinivas Kandagatla return ret; 371abb9c9b8SSrinivas Kandagatla 372abb9c9b8SSrinivas Kandagatla /* define channels first before activating them */ 373abb9c9b8SSrinivas Kandagatla for (i = 0; i < stream->num_ports; i++) { 374abb9c9b8SSrinivas Kandagatla struct slim_port *port = &stream->ports[i]; 375abb9c9b8SSrinivas Kandagatla 376abb9c9b8SSrinivas Kandagatla slim_define_channel(stream, port); 377abb9c9b8SSrinivas Kandagatla slim_define_channel_content(stream, port); 378abb9c9b8SSrinivas Kandagatla } 379abb9c9b8SSrinivas Kandagatla 380abb9c9b8SSrinivas Kandagatla for (i = 0; i < stream->num_ports; i++) { 381abb9c9b8SSrinivas Kandagatla struct slim_port *port = &stream->ports[i]; 382abb9c9b8SSrinivas Kandagatla 383abb9c9b8SSrinivas Kandagatla slim_activate_channel(stream, port); 384abb9c9b8SSrinivas Kandagatla port->state = SLIM_PORT_CONFIGURED; 385abb9c9b8SSrinivas Kandagatla } 386abb9c9b8SSrinivas Kandagatla txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW; 387abb9c9b8SSrinivas Kandagatla 388abb9c9b8SSrinivas Kandagatla return slim_do_transfer(ctrl, &txn); 389abb9c9b8SSrinivas Kandagatla } 390abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_enable); 391abb9c9b8SSrinivas Kandagatla 392*2f0f2441SJonathan Corbet /** 393abb9c9b8SSrinivas Kandagatla * slim_stream_disable() - Disable a SLIMbus Stream 394abb9c9b8SSrinivas Kandagatla * 395abb9c9b8SSrinivas Kandagatla * @stream: instance of slim stream runtime to disable 396abb9c9b8SSrinivas Kandagatla * 397abb9c9b8SSrinivas Kandagatla * This API will disable all the ports and channels associated with 398abb9c9b8SSrinivas Kandagatla * SLIMbus stream 399abb9c9b8SSrinivas Kandagatla * 400abb9c9b8SSrinivas Kandagatla * Return: zero on success and error code on failure. From ASoC DPCM framework, 401abb9c9b8SSrinivas Kandagatla * this state is linked to trigger() pause operation. 402abb9c9b8SSrinivas Kandagatla */ 403abb9c9b8SSrinivas Kandagatla int slim_stream_disable(struct slim_stream_runtime *stream) 404abb9c9b8SSrinivas Kandagatla { 405abb9c9b8SSrinivas Kandagatla DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION, 406abb9c9b8SSrinivas Kandagatla 3, SLIM_LA_MANAGER, NULL); 407abb9c9b8SSrinivas Kandagatla struct slim_controller *ctrl = stream->dev->ctrl; 408abb9c9b8SSrinivas Kandagatla int ret, i; 409abb9c9b8SSrinivas Kandagatla 410abb9c9b8SSrinivas Kandagatla if (ctrl->disable_stream) 411abb9c9b8SSrinivas Kandagatla ctrl->disable_stream(stream); 412abb9c9b8SSrinivas Kandagatla 413abb9c9b8SSrinivas Kandagatla ret = slim_do_transfer(ctrl, &txn); 414abb9c9b8SSrinivas Kandagatla if (ret) 415abb9c9b8SSrinivas Kandagatla return ret; 416abb9c9b8SSrinivas Kandagatla 417abb9c9b8SSrinivas Kandagatla for (i = 0; i < stream->num_ports; i++) 418abb9c9b8SSrinivas Kandagatla slim_deactivate_remove_channel(stream, &stream->ports[i]); 419abb9c9b8SSrinivas Kandagatla 420abb9c9b8SSrinivas Kandagatla txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW; 421abb9c9b8SSrinivas Kandagatla 422abb9c9b8SSrinivas Kandagatla return slim_do_transfer(ctrl, &txn); 423abb9c9b8SSrinivas Kandagatla } 424abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_disable); 425abb9c9b8SSrinivas Kandagatla 426*2f0f2441SJonathan Corbet /** 427abb9c9b8SSrinivas Kandagatla * slim_stream_unprepare() - Un-prepare a SLIMbus Stream 428abb9c9b8SSrinivas Kandagatla * 429abb9c9b8SSrinivas Kandagatla * @stream: instance of slim stream runtime to unprepare 430abb9c9b8SSrinivas Kandagatla * 431abb9c9b8SSrinivas Kandagatla * This API will un allocate all the ports and channels associated with 432abb9c9b8SSrinivas Kandagatla * SLIMbus stream 433abb9c9b8SSrinivas Kandagatla * 434abb9c9b8SSrinivas Kandagatla * Return: zero on success and error code on failure. From ASoC DPCM framework, 435abb9c9b8SSrinivas Kandagatla * this state is linked to trigger() stop operation. 436abb9c9b8SSrinivas Kandagatla */ 437abb9c9b8SSrinivas Kandagatla int slim_stream_unprepare(struct slim_stream_runtime *stream) 438abb9c9b8SSrinivas Kandagatla { 439abb9c9b8SSrinivas Kandagatla int i; 440abb9c9b8SSrinivas Kandagatla 441abb9c9b8SSrinivas Kandagatla for (i = 0; i < stream->num_ports; i++) 442abb9c9b8SSrinivas Kandagatla slim_disconnect_port(stream, &stream->ports[i]); 443abb9c9b8SSrinivas Kandagatla 444abb9c9b8SSrinivas Kandagatla kfree(stream->ports); 445abb9c9b8SSrinivas Kandagatla stream->ports = NULL; 446abb9c9b8SSrinivas Kandagatla stream->num_ports = 0; 447abb9c9b8SSrinivas Kandagatla 448abb9c9b8SSrinivas Kandagatla return 0; 449abb9c9b8SSrinivas Kandagatla } 450abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_unprepare); 451abb9c9b8SSrinivas Kandagatla 452*2f0f2441SJonathan Corbet /** 453abb9c9b8SSrinivas Kandagatla * slim_stream_free() - Free a SLIMbus Stream 454abb9c9b8SSrinivas Kandagatla * 455abb9c9b8SSrinivas Kandagatla * @stream: instance of slim stream runtime to free 456abb9c9b8SSrinivas Kandagatla * 457abb9c9b8SSrinivas Kandagatla * This API will un allocate all the memory associated with 458abb9c9b8SSrinivas Kandagatla * slim stream runtime, user is not allowed to make an dereference 459abb9c9b8SSrinivas Kandagatla * to stream after this call. 460abb9c9b8SSrinivas Kandagatla * 461abb9c9b8SSrinivas Kandagatla * Return: zero on success and error code on failure. From ASoC DPCM framework, 462abb9c9b8SSrinivas Kandagatla * this state is linked to shutdown() operation. 463abb9c9b8SSrinivas Kandagatla */ 464abb9c9b8SSrinivas Kandagatla int slim_stream_free(struct slim_stream_runtime *stream) 465abb9c9b8SSrinivas Kandagatla { 466abb9c9b8SSrinivas Kandagatla struct slim_device *sdev = stream->dev; 467abb9c9b8SSrinivas Kandagatla 468abb9c9b8SSrinivas Kandagatla spin_lock(&sdev->stream_list_lock); 469abb9c9b8SSrinivas Kandagatla list_del(&stream->node); 470abb9c9b8SSrinivas Kandagatla spin_unlock(&sdev->stream_list_lock); 471abb9c9b8SSrinivas Kandagatla 472abb9c9b8SSrinivas Kandagatla kfree(stream->name); 473abb9c9b8SSrinivas Kandagatla kfree(stream); 474abb9c9b8SSrinivas Kandagatla 475abb9c9b8SSrinivas Kandagatla return 0; 476abb9c9b8SSrinivas Kandagatla } 477abb9c9b8SSrinivas Kandagatla EXPORT_SYMBOL_GPL(slim_stream_free); 478