From 184992e305f1de3a3d5fa446da3a2bc76be7c54a Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Wed, 13 Jan 2016 14:07:46 -0700 Subject: [PATCH] greybus: audio: Add Greybus Audio Device Class Protocol helper routines Add helper routines to make communicating with audio modules easier. Signed-off-by: Mark Greer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/Makefile | 2 + drivers/staging/greybus/audio.h | 40 +++++ drivers/staging/greybus/audio_gb.c | 267 +++++++++++++++++++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 drivers/staging/greybus/audio_gb.c diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index fb0e02316b1c..3010f1606dae 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -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 diff --git a/drivers/staging/greybus/audio.h b/drivers/staging/greybus/audio.h index 5dec00d63e27..c8f798eb2afa 100644 --- a/drivers/staging/greybus/audio.h +++ b/drivers/staging/greybus/audio.h @@ -13,6 +13,9 @@ #include +#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 index 000000000000..08bfdeb87a61 --- /dev/null +++ b/drivers/staging/greybus/audio_gb.c @@ -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 "); -- 2.20.1