Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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);