diff --git a/drivers/staging/greybus/audio-gb-cmds.c b/drivers/staging/greybus/audio-gb-cmds.c index d625f782b513..73f47d84f1aa 100644 --- a/drivers/staging/greybus/audio-gb-cmds.c +++ b/drivers/staging/greybus/audio-gb-cmds.c @@ -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; } diff --git a/drivers/staging/greybus/audio-pcm.c b/drivers/staging/greybus/audio-pcm.c index 30030f8d3c22..b32700841444 100644 --- a/drivers/staging/greybus/audio-pcm.c +++ b/drivers/staging/greybus/audio-pcm.c @@ -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)); } diff --git a/drivers/staging/greybus/audio.c b/drivers/staging/greybus/audio.c index 1057e468d5d4..a1acbb039777 100644 --- a/drivers/staging/greybus/audio.c +++ b/drivers/staging/greybus/audio.c @@ -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; diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index 012c69a3ed83..fa1bb54fd4da 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -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);