Commit 184992e3 authored by Mark Greer's avatar Mark Greer Committed by Greg Kroah-Hartman
Browse files

greybus: audio: Add Greybus Audio Device Class Protocol helper routines



Add helper routines to make communicating with audio modules easier.

Signed-off-by: default avatarMark Greer <mgreer@animalcreek.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent ba4144af
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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
+40 −0
Original line number Diff line number Diff line
@@ -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 */
+267 −0
Original line number Diff line number Diff line
/*
 * 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>");