}
/**
- * sdw_release_stream() - Free the assigned stream runtime
- *
- * @stream: SoundWire stream runtime
- *
- * sdw_release_stream should be called only once per stream
- */
-void sdw_release_stream(struct sdw_stream_runtime *stream)
-{
- kfree(stream);
-}
-EXPORT_SYMBOL(sdw_release_stream);
-
-/**
- * sdw_alloc_stream() - Allocate and return stream runtime
- *
- * @stream_name: SoundWire stream name
- *
- * Allocates a SoundWire stream runtime instance.
- * sdw_alloc_stream should be called only once per stream. Typically
- * invoked from ALSA/ASoC machine/platform driver.
- */
-struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name)
-{
- struct sdw_stream_runtime *stream;
-
- stream = kzalloc(sizeof(*stream), GFP_KERNEL);
- if (!stream)
- return NULL;
-
- stream->name = stream_name;
- INIT_LIST_HEAD(&stream->master_list);
- stream->state = SDW_STREAM_ALLOCATED;
- stream->m_rt_count = 0;
-
- return stream;
-}
-EXPORT_SYMBOL(sdw_alloc_stream);
-
-/**
* sdw_slave_rt_alloc() - Allocate a Slave runtime handle.
*
* @slave: Slave handle
}
/**
- * sdw_stream_remove_master() - Remove master from sdw_stream
- *
- * @bus: SDW Bus instance
- * @stream: SoundWire stream
- *
- * This removes and frees port_rt and master_rt from a stream
- */
-int sdw_stream_remove_master(struct sdw_bus *bus,
- struct sdw_stream_runtime *stream)
-{
- struct sdw_master_runtime *m_rt, *_m_rt;
-
- mutex_lock(&bus->bus_lock);
-
- list_for_each_entry_safe(m_rt, _m_rt,
- &stream->master_list, stream_node) {
- if (m_rt->bus != bus)
- continue;
-
- sdw_master_port_free(m_rt);
- sdw_release_master_stream(m_rt, stream);
- stream->m_rt_count--;
- }
-
- if (list_empty(&stream->master_list))
- stream->state = SDW_STREAM_RELEASED;
-
- mutex_unlock(&bus->bus_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(sdw_stream_remove_master);
-
-/**
- * sdw_stream_remove_slave() - Remove slave from sdw_stream
- *
- * @slave: SDW Slave instance
- * @stream: SoundWire stream
- *
- * This removes and frees port_rt and slave_rt from a stream
- */
-int sdw_stream_remove_slave(struct sdw_slave *slave,
- struct sdw_stream_runtime *stream)
-{
- mutex_lock(&slave->bus->bus_lock);
-
- sdw_slave_port_free(slave, stream);
- sdw_release_slave_stream(slave, stream);
-
- mutex_unlock(&slave->bus->bus_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(sdw_stream_remove_slave);
-
-/**
* sdw_config_stream() - Configure the allocated stream
*
* @dev: SDW device
}
/**
- * sdw_stream_add_master() - Allocate and add master runtime to a stream
+ * sdw_get_slave_dpn_prop() - Get Slave port capabilities
*
- * @bus: SDW Bus instance
- * @stream_config: Stream configuration for audio stream
- * @port_config: Port configuration for audio stream
- * @num_ports: Number of ports
- * @stream: SoundWire stream
+ * @slave: Slave handle
+ * @direction: Data direction.
+ * @port_num: Port number
*/
-int sdw_stream_add_master(struct sdw_bus *bus,
- struct sdw_stream_config *stream_config,
- struct sdw_port_config *port_config,
- unsigned int num_ports,
- struct sdw_stream_runtime *stream)
+struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
+ enum sdw_data_direction direction,
+ unsigned int port_num)
{
- struct sdw_master_runtime *m_rt;
- int ret;
-
- mutex_lock(&bus->bus_lock);
+ struct sdw_dpn_prop *dpn_prop;
+ u8 num_ports;
+ int i;
- /*
- * For multi link streams, add the second master only if
- * the bus supports it.
- * Check if bus->multi_link is set
- */
- if (!bus->multi_link && stream->m_rt_count > 0) {
- dev_err(bus->dev,
- "Multilink not supported, link %d\n", bus->link_id);
- ret = -EINVAL;
- goto unlock;
+ if (direction == SDW_DATA_DIR_TX) {
+ num_ports = hweight32(slave->prop.source_ports);
+ dpn_prop = slave->prop.src_dpn_prop;
+ } else {
+ num_ports = hweight32(slave->prop.sink_ports);
+ dpn_prop = slave->prop.sink_dpn_prop;
}
- /*
- * check if Master is already allocated (e.g. as a result of Slave adding
- * it first), if so skip allocation and go to configuration
- */
- m_rt = sdw_master_rt_find(bus, stream);
- if (m_rt)
- goto skip_alloc_master_rt;
-
- m_rt = sdw_master_rt_alloc(bus, stream);
- if (!m_rt) {
- dev_err(bus->dev, "Master runtime alloc failed for stream:%s\n", stream->name);
- ret = -ENOMEM;
- goto unlock;
+ for (i = 0; i < num_ports; i++) {
+ if (dpn_prop[i].num == port_num)
+ return &dpn_prop[i];
}
- ret = sdw_master_rt_config(m_rt, stream_config);
- if (ret < 0)
- goto unlock;
-
-skip_alloc_master_rt:
- ret = sdw_config_stream(bus->dev, stream, stream_config, false);
- if (ret)
- goto stream_error;
-
- ret = sdw_master_port_alloc(m_rt, num_ports);
- if (ret)
- goto stream_error;
-
- ret = sdw_master_port_config(m_rt, port_config);
- if (ret)
- goto stream_error;
+ return NULL;
+}
- stream->m_rt_count++;
+/**
+ * sdw_acquire_bus_lock: Acquire bus lock for all Master runtime(s)
+ *
+ * @stream: SoundWire stream
+ *
+ * Acquire bus_lock for each of the master runtime(m_rt) part of this
+ * stream to reconfigure the bus.
+ * NOTE: This function is called from SoundWire stream ops and is
+ * expected that a global lock is held before acquiring bus_lock.
+ */
+static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream)
+{
+ struct sdw_master_runtime *m_rt;
+ struct sdw_bus *bus;
- goto unlock;
+ /* Iterate for all Master(s) in Master list */
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
-stream_error:
- sdw_release_master_stream(m_rt, stream);
-unlock:
- mutex_unlock(&bus->bus_lock);
- return ret;
+ mutex_lock(&bus->bus_lock);
+ }
}
-EXPORT_SYMBOL(sdw_stream_add_master);
/**
- * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream
+ * sdw_release_bus_lock: Release bus lock for all Master runtime(s)
*
- * @slave: SDW Slave instance
- * @stream_config: Stream configuration for audio stream
* @stream: SoundWire stream
- * @port_config: Port configuration for audio stream
- * @num_ports: Number of ports
- *
- * It is expected that Slave is added before adding Master
- * to the Stream.
*
+ * Release the previously held bus_lock after reconfiguring the bus.
+ * NOTE: This function is called from SoundWire stream ops and is
+ * expected that a global lock is held before releasing bus_lock.
*/
-int sdw_stream_add_slave(struct sdw_slave *slave,
- struct sdw_stream_config *stream_config,
- struct sdw_port_config *port_config,
- unsigned int num_ports,
- struct sdw_stream_runtime *stream)
+static void sdw_release_bus_lock(struct sdw_stream_runtime *stream)
+{
+ struct sdw_master_runtime *m_rt;
+ struct sdw_bus *bus;
+
+ /* Iterate for all Master(s) in Master list */
+ list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ mutex_unlock(&bus->bus_lock);
+ }
+}
+
+static int _sdw_prepare_stream(struct sdw_stream_runtime *stream,
+ bool update_params)
{
- struct sdw_slave_runtime *s_rt;
struct sdw_master_runtime *m_rt;
+ struct sdw_bus *bus = NULL;
+ struct sdw_master_prop *prop;
+ struct sdw_bus_params params;
int ret;
- mutex_lock(&slave->bus->bus_lock);
+ /* Prepare Master(s) and Slave(s) port(s) associated with stream */
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ prop = &bus->prop;
+ memcpy(¶ms, &bus->params, sizeof(params));
- /*
- * check if Master is already allocated, if so skip allocation
- * and go to configuration
- */
- m_rt = sdw_master_rt_find(slave->bus, stream);
- if (m_rt)
- goto skip_alloc_master_rt;
-
- /*
- * If this API is invoked by Slave first then m_rt is not valid.
- * So, allocate m_rt and add Slave to it.
- */
- m_rt = sdw_master_rt_alloc(slave->bus, stream);
- if (!m_rt) {
- dev_err(&slave->dev, "Master runtime alloc failed for stream:%s\n", stream->name);
- ret = -ENOMEM;
- goto error;
- }
- ret = sdw_master_rt_config(m_rt, stream_config);
- if (ret < 0)
- goto stream_error;
-
-skip_alloc_master_rt:
- s_rt = sdw_slave_rt_alloc(slave);
- if (!s_rt) {
- dev_err(&slave->dev, "Slave runtime alloc failed for stream:%s\n", stream->name);
- ret = -ENOMEM;
- goto stream_error;
- }
- list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list);
-
- ret = sdw_slave_rt_config(s_rt, stream_config);
- if (ret)
- goto stream_error;
-
- ret = sdw_config_stream(&slave->dev, stream, stream_config, true);
- if (ret)
- goto stream_error;
-
- ret = sdw_slave_port_alloc(slave, s_rt, num_ports);
- if (ret)
- goto stream_error;
-
- ret = sdw_slave_port_config(slave, s_rt, port_config);
- if (ret)
- goto stream_error;
-
- /*
- * Change stream state to CONFIGURED on first Slave add.
- * Bus is not aware of number of Slave(s) in a stream at this
- * point so cannot depend on all Slave(s) to be added in order to
- * change stream state to CONFIGURED.
- */
- stream->state = SDW_STREAM_CONFIGURED;
- goto error;
-
-stream_error:
- /*
- * we hit error so cleanup the stream, release all Slave(s) and
- * Master runtime
- */
- sdw_release_master_stream(m_rt, stream);
-error:
- mutex_unlock(&slave->bus->bus_lock);
- return ret;
-}
-EXPORT_SYMBOL(sdw_stream_add_slave);
-
-/**
- * sdw_get_slave_dpn_prop() - Get Slave port capabilities
- *
- * @slave: Slave handle
- * @direction: Data direction.
- * @port_num: Port number
- */
-struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
- enum sdw_data_direction direction,
- unsigned int port_num)
-{
- struct sdw_dpn_prop *dpn_prop;
- u8 num_ports;
- int i;
-
- if (direction == SDW_DATA_DIR_TX) {
- num_ports = hweight32(slave->prop.source_ports);
- dpn_prop = slave->prop.src_dpn_prop;
- } else {
- num_ports = hweight32(slave->prop.sink_ports);
- dpn_prop = slave->prop.sink_dpn_prop;
- }
-
- for (i = 0; i < num_ports; i++) {
- if (dpn_prop[i].num == port_num)
- return &dpn_prop[i];
- }
-
- return NULL;
-}
-
-/**
- * sdw_acquire_bus_lock: Acquire bus lock for all Master runtime(s)
- *
- * @stream: SoundWire stream
- *
- * Acquire bus_lock for each of the master runtime(m_rt) part of this
- * stream to reconfigure the bus.
- * NOTE: This function is called from SoundWire stream ops and is
- * expected that a global lock is held before acquiring bus_lock.
- */
-static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream)
-{
- struct sdw_master_runtime *m_rt;
- struct sdw_bus *bus;
-
- /* Iterate for all Master(s) in Master list */
- list_for_each_entry(m_rt, &stream->master_list, stream_node) {
- bus = m_rt->bus;
-
- mutex_lock(&bus->bus_lock);
- }
-}
-
-/**
- * sdw_release_bus_lock: Release bus lock for all Master runtime(s)
- *
- * @stream: SoundWire stream
- *
- * Release the previously held bus_lock after reconfiguring the bus.
- * NOTE: This function is called from SoundWire stream ops and is
- * expected that a global lock is held before releasing bus_lock.
- */
-static void sdw_release_bus_lock(struct sdw_stream_runtime *stream)
-{
- struct sdw_master_runtime *m_rt;
- struct sdw_bus *bus;
-
- /* Iterate for all Master(s) in Master list */
- list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) {
- bus = m_rt->bus;
- mutex_unlock(&bus->bus_lock);
- }
-}
-
-static int _sdw_prepare_stream(struct sdw_stream_runtime *stream,
- bool update_params)
-{
- struct sdw_master_runtime *m_rt;
- struct sdw_bus *bus = NULL;
- struct sdw_master_prop *prop;
- struct sdw_bus_params params;
- int ret;
-
- /* Prepare Master(s) and Slave(s) port(s) associated with stream */
- list_for_each_entry(m_rt, &stream->master_list, stream_node) {
- bus = m_rt->bus;
- prop = &bus->prop;
- memcpy(¶ms, &bus->params, sizeof(params));
-
- /* TODO: Support Asynchronous mode */
- if ((prop->max_clk_freq % stream->params.rate) != 0) {
- dev_err(bus->dev, "Async mode not supported\n");
- return -EINVAL;
- }
+ /* TODO: Support Asynchronous mode */
+ if ((prop->max_clk_freq % stream->params.rate) != 0) {
+ dev_err(bus->dev, "Async mode not supported\n");
+ return -EINVAL;
+ }
if (!update_params)
goto program_params;
}
/**
+ * sdw_alloc_stream() - Allocate and return stream runtime
+ *
+ * @stream_name: SoundWire stream name
+ *
+ * Allocates a SoundWire stream runtime instance.
+ * sdw_alloc_stream should be called only once per stream. Typically
+ * invoked from ALSA/ASoC machine/platform driver.
+ */
+struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name)
+{
+ struct sdw_stream_runtime *stream;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return NULL;
+
+ stream->name = stream_name;
+ INIT_LIST_HEAD(&stream->master_list);
+ stream->state = SDW_STREAM_ALLOCATED;
+ stream->m_rt_count = 0;
+
+ return stream;
+}
+EXPORT_SYMBOL(sdw_alloc_stream);
+
+/**
* sdw_startup_stream() - Startup SoundWire stream
*
* @sdw_substream: Soundwire stream
set_stream(substream, NULL);
}
EXPORT_SYMBOL(sdw_shutdown_stream);
+
+/**
+ * sdw_release_stream() - Free the assigned stream runtime
+ *
+ * @stream: SoundWire stream runtime
+ *
+ * sdw_release_stream should be called only once per stream
+ */
+void sdw_release_stream(struct sdw_stream_runtime *stream)
+{
+ kfree(stream);
+}
+EXPORT_SYMBOL(sdw_release_stream);
+
+/**
+ * sdw_stream_add_master() - Allocate and add master runtime to a stream
+ *
+ * @bus: SDW Bus instance
+ * @stream_config: Stream configuration for audio stream
+ * @port_config: Port configuration for audio stream
+ * @num_ports: Number of ports
+ * @stream: SoundWire stream
+ */
+int sdw_stream_add_master(struct sdw_bus *bus,
+ struct sdw_stream_config *stream_config,
+ struct sdw_port_config *port_config,
+ unsigned int num_ports,
+ struct sdw_stream_runtime *stream)
+{
+ struct sdw_master_runtime *m_rt;
+ int ret;
+
+ mutex_lock(&bus->bus_lock);
+
+ /*
+ * For multi link streams, add the second master only if
+ * the bus supports it.
+ * Check if bus->multi_link is set
+ */
+ if (!bus->multi_link && stream->m_rt_count > 0) {
+ dev_err(bus->dev,
+ "Multilink not supported, link %d\n", bus->link_id);
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ /*
+ * check if Master is already allocated (e.g. as a result of Slave adding
+ * it first), if so skip allocation and go to configuration
+ */
+ m_rt = sdw_master_rt_find(bus, stream);
+ if (m_rt)
+ goto skip_alloc_master_rt;
+
+ m_rt = sdw_master_rt_alloc(bus, stream);
+ if (!m_rt) {
+ dev_err(bus->dev, "Master runtime alloc failed for stream:%s\n", stream->name);
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ ret = sdw_master_rt_config(m_rt, stream_config);
+ if (ret < 0)
+ goto unlock;
+
+skip_alloc_master_rt:
+ ret = sdw_config_stream(bus->dev, stream, stream_config, false);
+ if (ret)
+ goto stream_error;
+
+ ret = sdw_master_port_alloc(m_rt, num_ports);
+ if (ret)
+ goto stream_error;
+
+ ret = sdw_master_port_config(m_rt, port_config);
+ if (ret)
+ goto stream_error;
+
+ stream->m_rt_count++;
+
+ goto unlock;
+
+stream_error:
+ sdw_release_master_stream(m_rt, stream);
+unlock:
+ mutex_unlock(&bus->bus_lock);
+ return ret;
+}
+EXPORT_SYMBOL(sdw_stream_add_master);
+
+/**
+ * sdw_stream_remove_master() - Remove master from sdw_stream
+ *
+ * @bus: SDW Bus instance
+ * @stream: SoundWire stream
+ *
+ * This removes and frees port_rt and master_rt from a stream
+ */
+int sdw_stream_remove_master(struct sdw_bus *bus,
+ struct sdw_stream_runtime *stream)
+{
+ struct sdw_master_runtime *m_rt, *_m_rt;
+
+ mutex_lock(&bus->bus_lock);
+
+ list_for_each_entry_safe(m_rt, _m_rt,
+ &stream->master_list, stream_node) {
+ if (m_rt->bus != bus)
+ continue;
+
+ sdw_master_port_free(m_rt);
+ sdw_release_master_stream(m_rt, stream);
+ stream->m_rt_count--;
+ }
+
+ if (list_empty(&stream->master_list))
+ stream->state = SDW_STREAM_RELEASED;
+
+ mutex_unlock(&bus->bus_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(sdw_stream_remove_master);
+
+/**
+ * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream
+ *
+ * @slave: SDW Slave instance
+ * @stream_config: Stream configuration for audio stream
+ * @stream: SoundWire stream
+ * @port_config: Port configuration for audio stream
+ * @num_ports: Number of ports
+ *
+ * It is expected that Slave is added before adding Master
+ * to the Stream.
+ *
+ */
+int sdw_stream_add_slave(struct sdw_slave *slave,
+ struct sdw_stream_config *stream_config,
+ struct sdw_port_config *port_config,
+ unsigned int num_ports,
+ struct sdw_stream_runtime *stream)
+{
+ struct sdw_slave_runtime *s_rt;
+ struct sdw_master_runtime *m_rt;
+ int ret;
+
+ mutex_lock(&slave->bus->bus_lock);
+
+ /*
+ * check if Master is already allocated, if so skip allocation
+ * and go to configuration
+ */
+ m_rt = sdw_master_rt_find(slave->bus, stream);
+ if (m_rt)
+ goto skip_alloc_master_rt;
+
+ /*
+ * If this API is invoked by Slave first then m_rt is not valid.
+ * So, allocate m_rt and add Slave to it.
+ */
+ m_rt = sdw_master_rt_alloc(slave->bus, stream);
+ if (!m_rt) {
+ dev_err(&slave->dev, "Master runtime alloc failed for stream:%s\n", stream->name);
+ ret = -ENOMEM;
+ goto error;
+ }
+ ret = sdw_master_rt_config(m_rt, stream_config);
+ if (ret < 0)
+ goto stream_error;
+
+skip_alloc_master_rt:
+ s_rt = sdw_slave_rt_alloc(slave);
+ if (!s_rt) {
+ dev_err(&slave->dev, "Slave runtime alloc failed for stream:%s\n", stream->name);
+ ret = -ENOMEM;
+ goto stream_error;
+ }
+ list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list);
+
+ ret = sdw_slave_rt_config(s_rt, stream_config);
+ if (ret)
+ goto stream_error;
+
+ ret = sdw_config_stream(&slave->dev, stream, stream_config, true);
+ if (ret)
+ goto stream_error;
+
+ ret = sdw_slave_port_alloc(slave, s_rt, num_ports);
+ if (ret)
+ goto stream_error;
+
+ ret = sdw_slave_port_config(slave, s_rt, port_config);
+ if (ret)
+ goto stream_error;
+
+ /*
+ * Change stream state to CONFIGURED on first Slave add.
+ * Bus is not aware of number of Slave(s) in a stream at this
+ * point so cannot depend on all Slave(s) to be added in order to
+ * change stream state to CONFIGURED.
+ */
+ stream->state = SDW_STREAM_CONFIGURED;
+ goto error;
+
+stream_error:
+ /*
+ * we hit error so cleanup the stream, release all Slave(s) and
+ * Master runtime
+ */
+ sdw_release_master_stream(m_rt, stream);
+error:
+ mutex_unlock(&slave->bus->bus_lock);
+ return ret;
+}
+EXPORT_SYMBOL(sdw_stream_add_slave);
+
+/**
+ * sdw_stream_remove_slave() - Remove slave from sdw_stream
+ *
+ * @slave: SDW Slave instance
+ * @stream: SoundWire stream
+ *
+ * This removes and frees port_rt and slave_rt from a stream
+ */
+int sdw_stream_remove_slave(struct sdw_slave *slave,
+ struct sdw_stream_runtime *stream)
+{
+ mutex_lock(&slave->bus->bus_lock);
+
+ sdw_slave_port_free(slave, stream);
+ sdw_release_slave_stream(slave, stream);
+
+ mutex_unlock(&slave->bus->bus_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(sdw_stream_remove_slave);