Commit 6b34099e authored by Mark A. Greer's avatar Mark A. Greer Committed by Greg Kroah-Hartman

greybus: gb-audio: Set I2S Configuration according to ASOC requests

Currently, the audio driver unconditionally sets the I2S
configuration to have a sample rate of 48KHz, two channels,
16 bits per channel, in little endian order.  Make this
more flexible by setting the I2S configuration according to
the arguments passed to the PCM 'hw_params' callback.

To accomplish this, query for the supported I2S configurations
at Greybus protocol init time and save them in the 'snd_dev'
structure.  When the 'hw_params' callback is called, compare its
arguments to the table of supported configurations.  If there is
a match, set the I2S connection accordingly.
Signed-off-by: default avatarMark A. Greer <mgreer@animalcreek.com>
Acked-by: default avatarJohn Stultz <john.stultz@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 48229e59
......@@ -89,21 +89,12 @@ int gb_i2s_mgmt_set_samples_per_message(
&request, sizeof(request), NULL, 0);
}
/*
* XXX This is sort of a generic "setup" function which probably needs
* to be broken up, and tied into the constraints.
*
* I'm on the fence if we should just dictate that we only support
* 48k, 16bit, 2 channel, and avoid doign the whole probe for configurations
* and then picking one.
*/
int gb_i2s_mgmt_setup(struct gb_connection *connection)
int gb_i2s_mgmt_get_cfgs(struct gb_snd *snd_dev,
struct gb_connection *connection)
{
struct gb_i2s_mgmt_get_supported_configurations_response *get_cfg;
struct gb_i2s_mgmt_set_configuration_request set_cfg;
struct gb_i2s_mgmt_configuration *cfg;
size_t size;
int i, ret;
int ret;
size = sizeof(*get_cfg) +
(CONFIG_COUNT_MAX * sizeof(get_cfg->config[0]));
......@@ -116,19 +107,48 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection)
size);
if (ret) {
pr_err("get_supported_config failed: %d\n", ret);
goto free_get_cfg;
goto err_free_get_cfg;
}
/* Pick 48KHz 16-bits/channel */
for (i = 0, cfg = get_cfg->config; i < CONFIG_COUNT_MAX; i++, cfg++) {
if ((le32_to_cpu(cfg->sample_frequency) == GB_SAMPLE_RATE) &&
(cfg->num_channels == 2) &&
(cfg->bytes_per_channel == 2) &&
(cfg->byte_order & GB_I2S_MGMT_BYTE_ORDER_LE) &&
(le32_to_cpu(cfg->spatial_locations) ==
(GB_I2S_MGMT_SPATIAL_LOCATION_FL |
GB_I2S_MGMT_SPATIAL_LOCATION_FR)) &&
(le32_to_cpu(cfg->ll_protocol) & GB_I2S_MGMT_PROTOCOL_I2S) &&
snd_dev->i2s_configs = get_cfg;
return 0;
err_free_get_cfg:
kfree(get_cfg);
return ret;
}
void gb_i2s_mgmt_free_cfgs(struct gb_snd *snd_dev)
{
kfree(snd_dev->i2s_configs);
snd_dev->i2s_configs = NULL;
}
int gb_i2s_mgmt_set_cfg(struct gb_snd *snd_dev, int rate, int chans,
int bytes_per_chan, int is_le)
{
struct gb_i2s_mgmt_set_configuration_request set_cfg;
struct gb_i2s_mgmt_configuration *cfg;
int i, ret;
u8 byte_order = GB_I2S_MGMT_BYTE_ORDER_NA;
if (bytes_per_chan > 1) {
if (is_le)
byte_order = GB_I2S_MGMT_BYTE_ORDER_LE;
else
byte_order = GB_I2S_MGMT_BYTE_ORDER_BE;
}
for (i = 0, cfg = snd_dev->i2s_configs->config;
i < CONFIG_COUNT_MAX;
i++, cfg++) {
if ((cfg->sample_frequency == cpu_to_le32(rate)) &&
(cfg->num_channels == chans) &&
(cfg->bytes_per_channel == bytes_per_chan) &&
(cfg->byte_order & byte_order) &&
(cfg->ll_protocol &
cpu_to_le32(GB_I2S_MGMT_PROTOCOL_I2S)) &&
(cfg->ll_mclk_role & GB_I2S_MGMT_ROLE_MASTER) &&
(cfg->ll_bclk_role & GB_I2S_MGMT_ROLE_MASTER) &&
(cfg->ll_wclk_role & GB_I2S_MGMT_ROLE_MASTER) &&
......@@ -142,12 +162,11 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection)
if (i >= CONFIG_COUNT_MAX) {
pr_err("No valid configuration\n");
ret = -EINVAL;
goto free_get_cfg;
return -EINVAL;
}
memcpy(&set_cfg, cfg, sizeof(set_cfg));
set_cfg.config.byte_order = GB_I2S_MGMT_BYTE_ORDER_LE;
set_cfg.config.byte_order = byte_order;
set_cfg.config.ll_protocol = cpu_to_le32(GB_I2S_MGMT_PROTOCOL_I2S);
set_cfg.config.ll_mclk_role = GB_I2S_MGMT_ROLE_MASTER;
set_cfg.config.ll_bclk_role = GB_I2S_MGMT_ROLE_MASTER;
......@@ -157,19 +176,17 @@ int gb_i2s_mgmt_setup(struct gb_connection *connection)
set_cfg.config.ll_wclk_tx_edge = GB_I2S_MGMT_EDGE_RISING;
set_cfg.config.ll_wclk_rx_edge = GB_I2S_MGMT_EDGE_FALLING;
ret = gb_i2s_mgmt_set_configuration(connection, &set_cfg);
ret = gb_i2s_mgmt_set_configuration(snd_dev->mgmt_connection, &set_cfg);
if (ret) {
pr_err("set_configuration failed: %d\n", ret);
goto free_get_cfg;
return ret;
}
ret = gb_i2s_mgmt_set_samples_per_message(connection,
ret = gb_i2s_mgmt_set_samples_per_message(snd_dev->mgmt_connection,
CONFIG_SAMPLES_PER_MSG);
if (ret)
pr_err("set_samples_per_msg failed: %d\n", ret);
free_get_cfg:
kfree(get_cfg);
return ret;
}
......
......@@ -220,6 +220,21 @@ static int gb_pcm_close(struct snd_pcm_substream *substream)
static int gb_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct gb_snd *snd_dev;
int rate, chans, bytes_per_chan, is_le, ret;
snd_dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
rate = params_rate(hw_params);
chans = params_channels(hw_params);
bytes_per_chan = snd_pcm_format_width(params_format(hw_params)) / 8;
is_le = snd_pcm_format_little_endian(params_format(hw_params));
ret = gb_i2s_mgmt_set_cfg(snd_dev, rate, chans, bytes_per_chan, is_le);
if (ret)
return ret;
return snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
}
......
......@@ -286,17 +286,23 @@ static int gb_i2s_mgmt_connection_init(struct gb_connection *connection)
goto err_free_snd_dev;
}
gb_i2s_mgmt_setup(connection);
ret = gb_i2s_mgmt_get_cfgs(snd_dev, connection);
if (ret) {
pr_err("can't get i2s configurations: %d\n", ret);
goto err_free_snd_dev;
}
snd_dev->send_data_req_buf = kzalloc(SEND_DATA_BUF_LEN, GFP_KERNEL);
if (!snd_dev->send_data_req_buf) {
ret = -ENOMEM;
goto err_free_snd_dev;
goto err_free_i2s_configs;
}
return 0;
err_free_i2s_configs:
gb_i2s_mgmt_free_cfgs(snd_dev);
err_free_snd_dev:
gb_free_snd(snd_dev);
return ret;
......@@ -306,6 +312,8 @@ static void gb_i2s_mgmt_connection_exit(struct gb_connection *connection)
{
struct gb_snd *snd_dev = (struct gb_snd *)connection->private;
gb_i2s_mgmt_free_cfgs(snd_dev);
kfree(snd_dev->send_data_req_buf);
snd_dev->send_data_req_buf = NULL;
......
......@@ -45,6 +45,8 @@ struct gb_snd {
struct gb_connection *mgmt_connection;
struct gb_connection *i2s_tx_connection;
struct gb_connection *i2s_rx_connection;
struct gb_i2s_mgmt_get_supported_configurations_response
*i2s_configs;
char *send_data_req_buf;
long send_data_sample_count;
int gb_bundle_id;
......@@ -79,7 +81,11 @@ int gb_i2s_mgmt_set_configuration(struct gb_connection *connection,
struct gb_i2s_mgmt_set_configuration_request *set_cfg);
int gb_i2s_mgmt_set_samples_per_message(struct gb_connection *connection,
uint16_t samples_per_message);
int gb_i2s_mgmt_setup(struct gb_connection *connection);
int gb_i2s_mgmt_get_cfgs(struct gb_snd *snd_dev,
struct gb_connection *connection);
void gb_i2s_mgmt_free_cfgs(struct gb_snd *snd_dev);
int gb_i2s_mgmt_set_cfg(struct gb_snd *snd_dev, int rate, int chans,
int bytes_per_chan, int is_le);
int gb_i2s_send_data(struct gb_connection *connection, void *req_buf,
void *source_addr, size_t len, int sample_num);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment