greybus: audio: Add Greybus Audio Device Class Protocol helper routines
authorMark Greer <mgreer@animalcreek.com>
Wed, 13 Jan 2016 21:07:46 +0000 (14:07 -0700)
committerGreg Kroah-Hartman <gregkh@google.com>
Thu, 14 Jan 2016 00:00:32 +0000 (16:00 -0800)
Add helper routines to make communicating with audio modules easier.

Signed-off-by: Mark Greer <mgreer@animalcreek.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/Makefile
drivers/staging/greybus/audio.h
drivers/staging/greybus/audio_gb.c [new file with mode: 0644]

index fb0e023..3010f16 100644 (file)
@@ -30,6 +30,7 @@ gb-hid-y := hid.o
 gb-es2-y := es2.o
 gb-arche-y := arche-platform.o arche-apb-ctrl.o
 gb-audio-codec-y := audio_codec.o
+gb-audio-gb-y := audio_gb.o
 gb-camera-y := camera.o
 
 obj-m += greybus.o
@@ -44,6 +45,7 @@ obj-m += gb-es2.o
 obj-m += gb-arche.o
 obj-m += gb-audio-codec.o
 obj-m += gb-camera.o
+obj-m += gb-audio-gb.o
 
 KERNELVER              ?= $(shell uname -r)
 KERNELDIR              ?= /lib/modules/$(KERNELVER)/build
index 5dec00d..c8f798e 100644 (file)
@@ -13,6 +13,9 @@
 
 #include <sound/soc.h>
 
+#include "greybus.h"
+#include "greybus_protocols.h"
+
 #define NAME_SIZE      32
 
 enum {
@@ -82,5 +85,42 @@ struct gbaudio_codec_info {
        struct mutex lock;
 };
 
+extern int gb_audio_gb_get_topology(struct gb_connection *connection,
+                                   struct gb_audio_topology **topology);
+extern int gb_audio_gb_get_control(struct gb_connection *connection,
+                                  uint8_t control_id, uint8_t index,
+                                  struct gb_audio_ctl_elem_value *value);
+extern int gb_audio_gb_set_control(struct gb_connection *connection,
+                                  uint8_t control_id, uint8_t index,
+                                  struct gb_audio_ctl_elem_value *value);
+extern int gb_audio_gb_enable_widget(struct gb_connection *connection,
+                                    uint8_t widget_id);
+extern int gb_audio_gb_disable_widget(struct gb_connection *connection,
+                                     uint8_t widget_id);
+extern int gb_audio_gb_get_pcm(struct gb_connection *connection,
+                              uint16_t data_cport, uint32_t *format,
+                              uint32_t *rate, uint8_t *channels,
+                              uint8_t *sig_bits);
+extern int gb_audio_gb_set_pcm(struct gb_connection *connection,
+                              uint16_t data_cport, uint32_t format,
+                              uint32_t rate, uint8_t channels,
+                              uint8_t sig_bits);
+extern int gb_audio_gb_set_tx_data_size(struct gb_connection *connection,
+                                       uint16_t data_cport, uint16_t size);
+extern int gb_audio_gb_get_tx_delay(struct gb_connection *connection,
+                                   uint16_t data_cport, uint32_t *delay);
+extern int gb_audio_gb_activate_tx(struct gb_connection *connection,
+                                  uint16_t data_cport);
+extern int gb_audio_gb_deactivate_tx(struct gb_connection *connection,
+                                    uint16_t data_cport);
+extern int gb_audio_gb_set_rx_data_size(struct gb_connection *connection,
+                                       uint16_t data_cport, uint16_t size);
+extern int gb_audio_gb_get_rx_delay(struct gb_connection *connection,
+                                   uint16_t data_cport, uint32_t *delay);
+extern int gb_audio_gb_activate_rx(struct gb_connection *connection,
+                                  uint16_t data_cport);
+extern int gb_audio_gb_deactivate_rx(struct gb_connection *connection,
+                                    uint16_t data_cport);
+
 #endif /* __KERNEL__ */
 #endif /* __LINUX_GBAUDIO_H */
diff --git a/drivers/staging/greybus/audio_gb.c b/drivers/staging/greybus/audio_gb.c
new file mode 100644 (file)
index 0000000..08bfdeb
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Greybus Audio Device Class Protocol helpers
+ *
+ * Copyright 2015-2016 Google Inc.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include "greybus.h"
+#include "greybus_protocols.h"
+#include "operation.h"
+
+/* TODO: Split into separate calls */
+int gb_audio_gb_get_topology(struct gb_connection *connection,
+                            struct gb_audio_topology **topology)
+{
+       struct gb_audio_get_topology_size_response size_resp;
+       struct gb_audio_topology *topo;
+       uint16_t size;
+       int ret;
+
+       ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TOPOLOGY_SIZE,
+                               NULL, 0, &size_resp, sizeof(size_resp));
+       if (ret)
+               return ret;
+
+       size = le16_to_cpu(size_resp.size);
+       if (size < sizeof(*topo))
+               return -ENODATA;
+
+       topo = kzalloc(size, GFP_KERNEL);
+       if (!topo)
+               return -ENOMEM;
+
+       ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TOPOLOGY, NULL, 0,
+                               topo, size);
+       if (ret) {
+               kfree(topo);
+               return ret;
+       }
+
+       *topology = topo;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_get_topology);
+
+int gb_audio_gb_get_control(struct gb_connection *connection,
+                           uint8_t control_id, uint8_t index,
+                           struct gb_audio_ctl_elem_value *value)
+{
+       struct gb_audio_get_control_request req;
+       struct gb_audio_get_control_response resp;
+       int ret;
+
+       req.control_id = control_id;
+       req.index = index;
+
+       ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_CONTROL,
+                               &req, sizeof(req), &resp, sizeof(resp));
+       if (ret)
+               return ret;
+
+       memcpy(value, &resp.value, sizeof(*value));
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_get_control);
+
+int gb_audio_gb_set_control(struct gb_connection *connection,
+                           uint8_t control_id, uint8_t index,
+                           struct gb_audio_ctl_elem_value *value)
+{
+       struct gb_audio_set_control_request req;
+
+       req.control_id = control_id;
+       req.index = index;
+       memcpy(&req.value, value, sizeof(req.value));
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_CONTROL,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_set_control);
+
+int gb_audio_gb_enable_widget(struct gb_connection *connection,
+                             uint8_t widget_id)
+{
+       struct gb_audio_enable_widget_request req;
+
+       req.widget_id = widget_id;
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_ENABLE_WIDGET,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_enable_widget);
+
+int gb_audio_gb_disable_widget(struct gb_connection *connection,
+                              uint8_t widget_id)
+{
+       struct gb_audio_disable_widget_request req;
+
+       req.widget_id = widget_id;
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_DISABLE_WIDGET,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_disable_widget);
+
+int gb_audio_gb_get_pcm(struct gb_connection *connection, uint16_t data_cport,
+                       uint32_t *format, uint32_t *rate, uint8_t *channels,
+                       uint8_t *sig_bits)
+{
+       struct gb_audio_get_pcm_request req;
+       struct gb_audio_get_pcm_response resp;
+       int ret;
+
+       req.data_cport = cpu_to_le16(data_cport);
+
+       ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_PCM,
+                               &req, sizeof(req), &resp, sizeof(resp));
+       if (ret)
+               return ret;
+
+       *format = le32_to_cpu(resp.format);
+       *rate = le32_to_cpu(resp.rate);
+       *channels = resp.channels;
+       *sig_bits = resp.sig_bits;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_get_pcm);
+
+int gb_audio_gb_set_pcm(struct gb_connection *connection, uint16_t data_cport,
+                       uint32_t format, uint32_t rate, uint8_t channels,
+                       uint8_t sig_bits)
+{
+       struct gb_audio_set_pcm_request req;
+
+       req.data_cport = cpu_to_le16(data_cport);
+       req.format = cpu_to_le32(format);
+       req.rate = cpu_to_le32(rate);
+       req.channels = channels;
+       req.sig_bits = sig_bits;
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_PCM,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_set_pcm);
+
+int gb_audio_gb_set_tx_data_size(struct gb_connection *connection,
+                                uint16_t data_cport, uint16_t size)
+{
+       struct gb_audio_set_tx_data_size_request req;
+
+       req.data_cport = cpu_to_le16(data_cport);
+       req.size = cpu_to_le16(size);
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_TX_DATA_SIZE,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_set_tx_data_size);
+
+int gb_audio_gb_get_tx_delay(struct gb_connection *connection,
+                            uint16_t data_cport, uint32_t *delay)
+{
+       struct gb_audio_get_tx_delay_request req;
+       struct gb_audio_get_tx_delay_response resp;
+       int ret;
+
+       req.data_cport = cpu_to_le16(data_cport);
+
+       ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TX_DELAY,
+                               &req, sizeof(req), &resp, sizeof(resp));
+       if (ret)
+               return ret;
+
+       *delay = le32_to_cpu(resp.delay);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_get_tx_delay);
+
+int gb_audio_gb_activate_tx(struct gb_connection *connection,
+                           uint16_t data_cport)
+{
+       struct gb_audio_activate_tx_request req;
+
+       req.data_cport = cpu_to_le16(data_cport);
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_ACTIVATE_TX,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_activate_tx);
+
+int gb_audio_gb_deactivate_tx(struct gb_connection *connection,
+                             uint16_t data_cport)
+{
+       struct gb_audio_deactivate_tx_request req;
+
+       req.data_cport = cpu_to_le16(data_cport);
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_DEACTIVATE_TX,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_tx);
+
+int gb_audio_gb_set_rx_data_size(struct gb_connection *connection,
+                                uint16_t data_cport, uint16_t size)
+{
+       struct gb_audio_set_rx_data_size_request req;
+
+       req.data_cport = cpu_to_le16(data_cport);
+       req.size = cpu_to_le16(size);
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_RX_DATA_SIZE,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_set_rx_data_size);
+
+int gb_audio_gb_get_rx_delay(struct gb_connection *connection,
+                            uint16_t data_cport, uint32_t *delay)
+{
+       struct gb_audio_get_rx_delay_request req;
+       struct gb_audio_get_rx_delay_response resp;
+       int ret;
+
+       req.data_cport = cpu_to_le16(data_cport);
+
+       ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_RX_DELAY,
+                               &req, sizeof(req), &resp, sizeof(resp));
+       if (ret)
+               return ret;
+
+       *delay = le32_to_cpu(resp.delay);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_get_rx_delay);
+
+int gb_audio_gb_activate_rx(struct gb_connection *connection,
+                           uint16_t data_cport)
+{
+       struct gb_audio_activate_rx_request req;
+
+       req.data_cport = cpu_to_le16(data_cport);
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_ACTIVATE_RX,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_activate_rx);
+
+int gb_audio_gb_deactivate_rx(struct gb_connection *connection,
+                             uint16_t data_cport)
+{
+       struct gb_audio_deactivate_rx_request req;
+
+       req.data_cport = cpu_to_le16(data_cport);
+
+       return gb_operation_sync(connection, GB_AUDIO_TYPE_DEACTIVATE_RX,
+                                &req, sizeof(req), NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_rx);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("greybus:audio-gb");
+MODULE_DESCRIPTION("Greybus Audio Device Class Protocol library");
+MODULE_AUTHOR("Mark Greer <mgreer@animalcreek.com>");