xref: /openbmc/linux/drivers/soundwire/generic_bandwidth_allocation.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
19026118fSBard Liao // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
29026118fSBard Liao // Copyright(c) 2015-2020 Intel Corporation.
39026118fSBard Liao 
49026118fSBard Liao /*
59026118fSBard Liao  * Bandwidth management algorithm based on 2^n gears
69026118fSBard Liao  *
79026118fSBard Liao  */
89026118fSBard Liao 
99ddae9daSRichard Fitzgerald #include <linux/bitops.h>
109026118fSBard Liao #include <linux/device.h>
119026118fSBard Liao #include <linux/module.h>
129026118fSBard Liao #include <linux/mod_devicetable.h>
139026118fSBard Liao #include <linux/slab.h>
149026118fSBard Liao #include <linux/soundwire/sdw.h>
159026118fSBard Liao #include "bus.h"
169026118fSBard Liao 
179026118fSBard Liao #define SDW_STRM_RATE_GROUPING		1
189026118fSBard Liao 
199026118fSBard Liao struct sdw_group_params {
209026118fSBard Liao 	unsigned int rate;
219026118fSBard Liao 	int full_bw;
229026118fSBard Liao 	int payload_bw;
239026118fSBard Liao 	int hwidth;
249026118fSBard Liao };
259026118fSBard Liao 
269026118fSBard Liao struct sdw_group {
279026118fSBard Liao 	unsigned int count;
289026118fSBard Liao 	unsigned int max_size;
299026118fSBard Liao 	unsigned int *rates;
309026118fSBard Liao };
319026118fSBard Liao 
sdw_compute_slave_ports(struct sdw_master_runtime * m_rt,struct sdw_transport_data * t_data)32*f346fdf9SVijendar Mukunda void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
339026118fSBard Liao 			     struct sdw_transport_data *t_data)
349026118fSBard Liao {
359026118fSBard Liao 	struct sdw_slave_runtime *s_rt = NULL;
369026118fSBard Liao 	struct sdw_port_runtime *p_rt;
379026118fSBard Liao 	int port_bo, sample_int;
389026118fSBard Liao 	unsigned int rate, bps, ch = 0;
399026118fSBard Liao 	unsigned int slave_total_ch;
40dd87a72aSPierre-Louis Bossart 	struct sdw_bus_params *b_params = &m_rt->bus->params;
419026118fSBard Liao 
429026118fSBard Liao 	port_bo = t_data->block_offset;
439026118fSBard Liao 
449026118fSBard Liao 	list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
459026118fSBard Liao 		rate = m_rt->stream->params.rate;
469026118fSBard Liao 		bps = m_rt->stream->params.bps;
479026118fSBard Liao 		sample_int = (m_rt->bus->params.curr_dr_freq / rate);
489026118fSBard Liao 		slave_total_ch = 0;
499026118fSBard Liao 
509026118fSBard Liao 		list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
519ddae9daSRichard Fitzgerald 			ch = hweight32(p_rt->ch_mask);
529026118fSBard Liao 
539026118fSBard Liao 			sdw_fill_xport_params(&p_rt->transport_params,
549026118fSBard Liao 					      p_rt->num, false,
559026118fSBard Liao 					      SDW_BLK_GRP_CNT_1,
569026118fSBard Liao 					      sample_int, port_bo, port_bo >> 8,
579026118fSBard Liao 					      t_data->hstart,
589026118fSBard Liao 					      t_data->hstop,
598f29bb83SPierre-Louis Bossart 					      SDW_BLK_PKG_PER_PORT, 0x0);
609026118fSBard Liao 
619026118fSBard Liao 			sdw_fill_port_params(&p_rt->port_params,
629026118fSBard Liao 					     p_rt->num, bps,
639026118fSBard Liao 					     SDW_PORT_FLOW_MODE_ISOCH,
64dd87a72aSPierre-Louis Bossart 					     b_params->s_data_mode);
659026118fSBard Liao 
669026118fSBard Liao 			port_bo += bps * ch;
679026118fSBard Liao 			slave_total_ch += ch;
689026118fSBard Liao 		}
699026118fSBard Liao 
709026118fSBard Liao 		if (m_rt->direction == SDW_DATA_DIR_TX &&
719026118fSBard Liao 		    m_rt->ch_count == slave_total_ch) {
729026118fSBard Liao 			/*
739026118fSBard Liao 			 * Slave devices were configured to access all channels
749026118fSBard Liao 			 * of the stream, which indicates that they operate in
759026118fSBard Liao 			 * 'mirror mode'. Make sure we reset the port offset for
769026118fSBard Liao 			 * the next device in the list
779026118fSBard Liao 			 */
789026118fSBard Liao 			port_bo = t_data->block_offset;
799026118fSBard Liao 		}
809026118fSBard Liao 	}
819026118fSBard Liao }
82*f346fdf9SVijendar Mukunda EXPORT_SYMBOL(sdw_compute_slave_ports);
839026118fSBard Liao 
sdw_compute_master_ports(struct sdw_master_runtime * m_rt,struct sdw_group_params * params,int port_bo,int hstop)849026118fSBard Liao static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
859026118fSBard Liao 				     struct sdw_group_params *params,
869026118fSBard Liao 				     int port_bo, int hstop)
879026118fSBard Liao {
889026118fSBard Liao 	struct sdw_transport_data t_data = {0};
899026118fSBard Liao 	struct sdw_port_runtime *p_rt;
909026118fSBard Liao 	struct sdw_bus *bus = m_rt->bus;
91dd87a72aSPierre-Louis Bossart 	struct sdw_bus_params *b_params = &bus->params;
929026118fSBard Liao 	int sample_int, hstart = 0;
938f29bb83SPierre-Louis Bossart 	unsigned int rate, bps, ch;
949026118fSBard Liao 
959026118fSBard Liao 	rate = m_rt->stream->params.rate;
969026118fSBard Liao 	bps = m_rt->stream->params.bps;
979026118fSBard Liao 	ch = m_rt->ch_count;
989026118fSBard Liao 	sample_int = (bus->params.curr_dr_freq / rate);
999026118fSBard Liao 
1009026118fSBard Liao 	if (rate != params->rate)
1019026118fSBard Liao 		return;
1029026118fSBard Liao 
1039026118fSBard Liao 	t_data.hstop = hstop;
1049026118fSBard Liao 	hstart = hstop - params->hwidth + 1;
1059026118fSBard Liao 	t_data.hstart = hstart;
1069026118fSBard Liao 
1079026118fSBard Liao 	list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
1089026118fSBard Liao 
1099026118fSBard Liao 		sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
1109026118fSBard Liao 				      false, SDW_BLK_GRP_CNT_1, sample_int,
1119026118fSBard Liao 				      port_bo, port_bo >> 8, hstart, hstop,
1128f29bb83SPierre-Louis Bossart 				      SDW_BLK_PKG_PER_PORT, 0x0);
1139026118fSBard Liao 
1149026118fSBard Liao 		sdw_fill_port_params(&p_rt->port_params,
1159026118fSBard Liao 				     p_rt->num, bps,
1169026118fSBard Liao 				     SDW_PORT_FLOW_MODE_ISOCH,
117dd87a72aSPierre-Louis Bossart 				     b_params->m_data_mode);
1189026118fSBard Liao 
1199026118fSBard Liao 		/* Check for first entry */
1209026118fSBard Liao 		if (!(p_rt == list_first_entry(&m_rt->port_list,
1219026118fSBard Liao 					       struct sdw_port_runtime,
1229026118fSBard Liao 					       port_node))) {
1239026118fSBard Liao 			port_bo += bps * ch;
1249026118fSBard Liao 			continue;
1259026118fSBard Liao 		}
1269026118fSBard Liao 
1279026118fSBard Liao 		t_data.hstart = hstart;
1289026118fSBard Liao 		t_data.hstop = hstop;
1299026118fSBard Liao 		t_data.block_offset = port_bo;
1309026118fSBard Liao 		t_data.sub_block_offset = 0;
1319026118fSBard Liao 		port_bo += bps * ch;
1329026118fSBard Liao 	}
1339026118fSBard Liao 
1349026118fSBard Liao 	sdw_compute_slave_ports(m_rt, &t_data);
1359026118fSBard Liao }
1369026118fSBard Liao 
_sdw_compute_port_params(struct sdw_bus * bus,struct sdw_group_params * params,int count)1379026118fSBard Liao static void _sdw_compute_port_params(struct sdw_bus *bus,
1389026118fSBard Liao 				     struct sdw_group_params *params, int count)
1399026118fSBard Liao {
1406ae435bdSPierre-Louis Bossart 	struct sdw_master_runtime *m_rt;
1419026118fSBard Liao 	int hstop = bus->params.col - 1;
1429026118fSBard Liao 	int port_bo, i;
1439026118fSBard Liao 
1449026118fSBard Liao 	/* Run loop for all groups to compute transport parameters */
1459026118fSBard Liao 	for (i = 0; i < count; i++) {
1469026118fSBard Liao 		port_bo = 1;
1479026118fSBard Liao 
1489026118fSBard Liao 		list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
1499026118fSBard Liao 			sdw_compute_master_ports(m_rt, &params[i], port_bo, hstop);
1509026118fSBard Liao 
1519026118fSBard Liao 			port_bo += m_rt->ch_count * m_rt->stream->params.bps;
1529026118fSBard Liao 		}
1539026118fSBard Liao 
1549026118fSBard Liao 		hstop = hstop - params[i].hwidth;
1559026118fSBard Liao 	}
1569026118fSBard Liao }
1579026118fSBard Liao 
sdw_compute_group_params(struct sdw_bus * bus,struct sdw_group_params * params,int * rates,int count)1589026118fSBard Liao static int sdw_compute_group_params(struct sdw_bus *bus,
1599026118fSBard Liao 				    struct sdw_group_params *params,
1609026118fSBard Liao 				    int *rates, int count)
1619026118fSBard Liao {
1629026118fSBard Liao 	struct sdw_master_runtime *m_rt;
1639026118fSBard Liao 	int sel_col = bus->params.col;
1649026118fSBard Liao 	unsigned int rate, bps, ch;
1659026118fSBard Liao 	int i, column_needed = 0;
1666ae435bdSPierre-Louis Bossart 
1679026118fSBard Liao 	/* Calculate bandwidth per group */
1689026118fSBard Liao 	for (i = 0; i < count; i++) {
1699026118fSBard Liao 		params[i].rate = rates[i];
1709026118fSBard Liao 		params[i].full_bw = bus->params.curr_dr_freq / params[i].rate;
1719026118fSBard Liao 	}
1729026118fSBard Liao 
1739026118fSBard Liao 	list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
1749026118fSBard Liao 		rate = m_rt->stream->params.rate;
1759026118fSBard Liao 		bps = m_rt->stream->params.bps;
1769026118fSBard Liao 		ch = m_rt->ch_count;
1779026118fSBard Liao 
1789026118fSBard Liao 		for (i = 0; i < count; i++) {
1799026118fSBard Liao 			if (rate == params[i].rate)
1809026118fSBard Liao 				params[i].payload_bw += bps * ch;
1819026118fSBard Liao 		}
1829026118fSBard Liao 	}
1839026118fSBard Liao 
1849026118fSBard Liao 	for (i = 0; i < count; i++) {
1859026118fSBard Liao 		params[i].hwidth = (sel_col *
1869026118fSBard Liao 			params[i].payload_bw + params[i].full_bw - 1) /
1879026118fSBard Liao 			params[i].full_bw;
1889026118fSBard Liao 
1899026118fSBard Liao 		column_needed += params[i].hwidth;
1909026118fSBard Liao 	}
1919026118fSBard Liao 
1929026118fSBard Liao 	if (column_needed > sel_col - 1)
1939026118fSBard Liao 		return -EINVAL;
1949026118fSBard Liao 
1959026118fSBard Liao 	return 0;
1969026118fSBard Liao }
1979026118fSBard Liao 
sdw_add_element_group_count(struct sdw_group * group,unsigned int rate)1989026118fSBard Liao static int sdw_add_element_group_count(struct sdw_group *group,
1999026118fSBard Liao 				       unsigned int rate)
2009026118fSBard Liao {
2019026118fSBard Liao 	int num = group->count;
2029026118fSBard Liao 	int i;
2039026118fSBard Liao 
2049026118fSBard Liao 	for (i = 0; i <= num; i++) {
2059026118fSBard Liao 		if (rate == group->rates[i])
2069026118fSBard Liao 			break;
2079026118fSBard Liao 
2089026118fSBard Liao 		if (i != num)
2099026118fSBard Liao 			continue;
2109026118fSBard Liao 
2119026118fSBard Liao 		if (group->count >= group->max_size) {
2129026118fSBard Liao 			unsigned int *rates;
2139026118fSBard Liao 
2149026118fSBard Liao 			group->max_size += 1;
2159026118fSBard Liao 			rates = krealloc(group->rates,
2169026118fSBard Liao 					 (sizeof(int) * group->max_size),
2179026118fSBard Liao 					 GFP_KERNEL);
2189026118fSBard Liao 			if (!rates)
2199026118fSBard Liao 				return -ENOMEM;
2209026118fSBard Liao 			group->rates = rates;
2219026118fSBard Liao 		}
2229026118fSBard Liao 
2239026118fSBard Liao 		group->rates[group->count++] = rate;
2249026118fSBard Liao 	}
2259026118fSBard Liao 
2269026118fSBard Liao 	return 0;
2279026118fSBard Liao }
2289026118fSBard Liao 
sdw_get_group_count(struct sdw_bus * bus,struct sdw_group * group)2299026118fSBard Liao static int sdw_get_group_count(struct sdw_bus *bus,
2309026118fSBard Liao 			       struct sdw_group *group)
2319026118fSBard Liao {
2329026118fSBard Liao 	struct sdw_master_runtime *m_rt;
2339026118fSBard Liao 	unsigned int rate;
2349026118fSBard Liao 	int ret = 0;
2359026118fSBard Liao 
2369026118fSBard Liao 	group->count = 0;
2379026118fSBard Liao 	group->max_size = SDW_STRM_RATE_GROUPING;
2389026118fSBard Liao 	group->rates = kcalloc(group->max_size, sizeof(int), GFP_KERNEL);
2399026118fSBard Liao 	if (!group->rates)
2409026118fSBard Liao 		return -ENOMEM;
2419026118fSBard Liao 
2429026118fSBard Liao 	list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
2439026118fSBard Liao 		rate = m_rt->stream->params.rate;
2449026118fSBard Liao 		if (m_rt == list_first_entry(&bus->m_rt_list,
2459026118fSBard Liao 					     struct sdw_master_runtime,
2469026118fSBard Liao 					     bus_node)) {
2479026118fSBard Liao 			group->rates[group->count++] = rate;
2489026118fSBard Liao 
2499026118fSBard Liao 		} else {
2509026118fSBard Liao 			ret = sdw_add_element_group_count(group, rate);
2519026118fSBard Liao 			if (ret < 0) {
2529026118fSBard Liao 				kfree(group->rates);
2539026118fSBard Liao 				return ret;
2549026118fSBard Liao 			}
2559026118fSBard Liao 		}
2569026118fSBard Liao 	}
2579026118fSBard Liao 
2589026118fSBard Liao 	return ret;
2599026118fSBard Liao }
2609026118fSBard Liao 
2619026118fSBard Liao /**
2629026118fSBard Liao  * sdw_compute_port_params: Compute transport and port parameters
2639026118fSBard Liao  *
2649026118fSBard Liao  * @bus: SDW Bus instance
2659026118fSBard Liao  */
sdw_compute_port_params(struct sdw_bus * bus)2669026118fSBard Liao static int sdw_compute_port_params(struct sdw_bus *bus)
2679026118fSBard Liao {
2689026118fSBard Liao 	struct sdw_group_params *params = NULL;
2699026118fSBard Liao 	struct sdw_group group;
2709026118fSBard Liao 	int ret;
2719026118fSBard Liao 
2729026118fSBard Liao 	ret = sdw_get_group_count(bus, &group);
2739026118fSBard Liao 	if (ret < 0)
2749026118fSBard Liao 		return ret;
2759026118fSBard Liao 
2769026118fSBard Liao 	if (group.count == 0)
2779026118fSBard Liao 		goto out;
2789026118fSBard Liao 
2799026118fSBard Liao 	params = kcalloc(group.count, sizeof(*params), GFP_KERNEL);
2809026118fSBard Liao 	if (!params) {
2819026118fSBard Liao 		ret = -ENOMEM;
2829026118fSBard Liao 		goto out;
2839026118fSBard Liao 	}
2849026118fSBard Liao 
2859026118fSBard Liao 	/* Compute transport parameters for grouped streams */
2869026118fSBard Liao 	ret = sdw_compute_group_params(bus, params,
2879026118fSBard Liao 				       &group.rates[0], group.count);
2889026118fSBard Liao 	if (ret < 0)
2899026118fSBard Liao 		goto free_params;
2909026118fSBard Liao 
2919026118fSBard Liao 	_sdw_compute_port_params(bus, params, group.count);
2929026118fSBard Liao 
2939026118fSBard Liao free_params:
2949026118fSBard Liao 	kfree(params);
2959026118fSBard Liao out:
2969026118fSBard Liao 	kfree(group.rates);
2979026118fSBard Liao 
2989026118fSBard Liao 	return ret;
2999026118fSBard Liao }
3009026118fSBard Liao 
sdw_select_row_col(struct sdw_bus * bus,int clk_freq)3019026118fSBard Liao static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
3029026118fSBard Liao {
3039026118fSBard Liao 	struct sdw_master_prop *prop = &bus->prop;
3049026118fSBard Liao 	int frame_int, frame_freq;
3059026118fSBard Liao 	int r, c;
3069026118fSBard Liao 
3079026118fSBard Liao 	for (c = 0; c < SDW_FRAME_COLS; c++) {
3089026118fSBard Liao 		for (r = 0; r < SDW_FRAME_ROWS; r++) {
3099026118fSBard Liao 			if (sdw_rows[r] != prop->default_row ||
3109026118fSBard Liao 			    sdw_cols[c] != prop->default_col)
3119026118fSBard Liao 				continue;
3129026118fSBard Liao 
3139026118fSBard Liao 			frame_int = sdw_rows[r] * sdw_cols[c];
3149026118fSBard Liao 			frame_freq = clk_freq / frame_int;
3159026118fSBard Liao 
3169026118fSBard Liao 			if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) <
3179026118fSBard Liao 			    bus->params.bandwidth)
3189026118fSBard Liao 				continue;
3199026118fSBard Liao 
3209026118fSBard Liao 			bus->params.row = sdw_rows[r];
3219026118fSBard Liao 			bus->params.col = sdw_cols[c];
3229026118fSBard Liao 			return 0;
3239026118fSBard Liao 		}
3249026118fSBard Liao 	}
3259026118fSBard Liao 
3269026118fSBard Liao 	return -EINVAL;
3279026118fSBard Liao }
3289026118fSBard Liao 
3299026118fSBard Liao /**
3309026118fSBard Liao  * sdw_compute_bus_params: Compute bus parameters
3319026118fSBard Liao  *
3329026118fSBard Liao  * @bus: SDW Bus instance
3339026118fSBard Liao  */
sdw_compute_bus_params(struct sdw_bus * bus)3349026118fSBard Liao static int sdw_compute_bus_params(struct sdw_bus *bus)
3359026118fSBard Liao {
3369026118fSBard Liao 	unsigned int max_dr_freq, curr_dr_freq = 0;
3379026118fSBard Liao 	struct sdw_master_prop *mstr_prop = &bus->prop;
3389026118fSBard Liao 	int i, clk_values, ret;
3399026118fSBard Liao 	bool is_gear = false;
3409026118fSBard Liao 	u32 *clk_buf;
3415ec3215eSDan Carpenter 
3429026118fSBard Liao 	if (mstr_prop->num_clk_gears) {
3439026118fSBard Liao 		clk_values = mstr_prop->num_clk_gears;
3449026118fSBard Liao 		clk_buf = mstr_prop->clk_gears;
3459026118fSBard Liao 		is_gear = true;
3469026118fSBard Liao 	} else if (mstr_prop->num_clk_freq) {
3479026118fSBard Liao 		clk_values = mstr_prop->num_clk_freq;
3489026118fSBard Liao 		clk_buf = mstr_prop->clk_freq;
3499026118fSBard Liao 	} else {
3509026118fSBard Liao 		clk_values = 1;
3519026118fSBard Liao 		clk_buf = NULL;
3529026118fSBard Liao 	}
3539026118fSBard Liao 
3549026118fSBard Liao 	max_dr_freq = mstr_prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;
3559026118fSBard Liao 
3569026118fSBard Liao 	for (i = 0; i < clk_values; i++) {
3579026118fSBard Liao 		if (!clk_buf)
3589026118fSBard Liao 			curr_dr_freq = max_dr_freq;
3599026118fSBard Liao 		else
3609026118fSBard Liao 			curr_dr_freq = (is_gear) ?
3619026118fSBard Liao 				(max_dr_freq >>  clk_buf[i]) :
3629026118fSBard Liao 				clk_buf[i] * SDW_DOUBLE_RATE_FACTOR;
3639026118fSBard Liao 
3649026118fSBard Liao 		if (curr_dr_freq <= bus->params.bandwidth)
3659026118fSBard Liao 			continue;
3669026118fSBard Liao 
3679026118fSBard Liao 		break;
3689026118fSBard Liao 
3699026118fSBard Liao 		/*
3709026118fSBard Liao 		 * TODO: Check all the Slave(s) port(s) audio modes and find
3719026118fSBard Liao 		 * whether given clock rate is supported with glitchless
3729026118fSBard Liao 		 * transition.
3739026118fSBard Liao 		 */
3749026118fSBard Liao 	}
3759026118fSBard Liao 
3769026118fSBard Liao 	if (i == clk_values) {
3779026118fSBard Liao 		dev_err(bus->dev, "%s: could not find clock value for bandwidth %d\n",
3789026118fSBard Liao 			__func__, bus->params.bandwidth);
3799026118fSBard Liao 		return -EINVAL;
3800531e6b6SPierre-Louis Bossart 	}
3810531e6b6SPierre-Louis Bossart 
3820531e6b6SPierre-Louis Bossart 	ret = sdw_select_row_col(bus, curr_dr_freq);
3839026118fSBard Liao 	if (ret < 0) {
3840531e6b6SPierre-Louis Bossart 		dev_err(bus->dev, "%s: could not find frame configuration for bus dr_freq %d\n",
3859026118fSBard Liao 			__func__, curr_dr_freq);
3869026118fSBard Liao 		return -EINVAL;
3870531e6b6SPierre-Louis Bossart 	}
3880531e6b6SPierre-Louis Bossart 
3890531e6b6SPierre-Louis Bossart 	bus->params.curr_dr_freq = curr_dr_freq;
3909026118fSBard Liao 	return 0;
3910531e6b6SPierre-Louis Bossart }
3929026118fSBard Liao 
3939026118fSBard Liao /**
3949026118fSBard Liao  * sdw_compute_params: Compute bus, transport and port parameters
3959026118fSBard Liao  *
3969026118fSBard Liao  * @bus: SDW Bus instance
3979026118fSBard Liao  */
sdw_compute_params(struct sdw_bus * bus)3989026118fSBard Liao int sdw_compute_params(struct sdw_bus *bus)
3999026118fSBard Liao {
4009026118fSBard Liao 	int ret;
4019026118fSBard Liao 
4029026118fSBard Liao 	/* Computes clock frequency, frame shape and frame frequency */
4039026118fSBard Liao 	ret = sdw_compute_bus_params(bus);
4049026118fSBard Liao 	if (ret < 0)
4059026118fSBard Liao 		return ret;
4069026118fSBard Liao 
4079026118fSBard Liao 	/* Compute transport and port params */
4080531e6b6SPierre-Louis Bossart 	ret = sdw_compute_port_params(bus);
4099026118fSBard Liao 	if (ret < 0) {
4109026118fSBard Liao 		dev_err(bus->dev, "Compute transport params failed: %d\n", ret);
4119026118fSBard Liao 		return ret;
4129026118fSBard Liao 	}
4139026118fSBard Liao 
4140eb7c387SPierre-Louis Bossart 	return 0;
4159026118fSBard Liao }
4169026118fSBard Liao EXPORT_SYMBOL(sdw_compute_params);
4179026118fSBard Liao 
4189026118fSBard Liao MODULE_LICENSE("Dual BSD/GPL");
4199026118fSBard Liao MODULE_DESCRIPTION("SoundWire Generic Bandwidth Allocation");
4209026118fSBard Liao