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