]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
greybus: gb-audio: Set I2S Configuration according to ASOC requests
authorMark A. Greer <mgreer@animalcreek.com>
Thu, 21 May 2015 22:57:03 +0000 (15:57 -0700)
committerGreg Kroah-Hartman <gregkh@google.com>
Sat, 23 May 2015 23:26:41 +0000 (16:26 -0700)
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: Mark A. Greer <mgreer@animalcreek.com>
Acked-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/audio-gb-cmds.c
drivers/staging/greybus/audio-pcm.c
drivers/staging/greybus/audio.c
drivers/staging/greybus/audio.h

index d625f782b5132c9855ad2b50fccace98f9f4ef37..73f47d84f1aa3b344e121753ab1c514f47ee8b0f 100644 (file)
@@ -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;
 }
 
index 30030f8d3c2242990e691dcbef93a4c9558149b6..b32700841444166df94f1908f74bee68a905fd0c 100644 (file)
@@ -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));
 }
index 1057e468d5d4f3240745177ba6bf04b15576246f..a1acbb039777bfefd5a051b6e8989e0a98903eee 100644 (file)
@@ -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;
 
index 012c69a3ed839173ef5cbbfc2d6f454650a81375..fa1bb54fd4da2bb7f0578f73f4829436a0b72a22 100644 (file)
@@ -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);