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