From 5bbe14b7acc2a00f51b23812ffc596577d94e80b Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Mon, 29 Feb 2016 15:31:02 -0700 Subject: [PATCH] greybus: audio: Split start and stop APBridgeA requests Provide finer-grained control of the audio streaming on APB1 by splitting the transmit/receive start and stop requests into prepare, start, stop, and shutdown. CC: Vaibhav Agarwal Signed-off-by: Mark Greer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio_apbridgea.c | 52 +++++++++++++++++++++++++++++++ drivers/staging/greybus/audio_apbridgea.h | 32 +++++++++++++++---- drivers/staging/greybus/audio_codec.c | 32 +++++++++++++++---- drivers/staging/greybus/audio_codec.h | 8 +++++ 4 files changed, 112 insertions(+), 12 deletions(-) diff --git a/drivers/staging/greybus/audio_apbridgea.c b/drivers/staging/greybus/audio_apbridgea.c index bed087d..a6e089d 100644 --- a/drivers/staging/greybus/audio_apbridgea.c +++ b/drivers/staging/greybus/audio_apbridgea.c @@ -82,6 +82,19 @@ int gb_audio_apbridgea_get_tx_delay(struct gb_connection *connection, } EXPORT_SYMBOL_GPL(gb_audio_apbridgea_get_tx_delay); +int gb_audio_apbridgea_prepare_tx(struct gb_connection *connection, + __u16 i2s_port) +{ + struct audio_apbridgea_prepare_tx_request req; + + req.hdr.type = AUDIO_APBRIDGEA_TYPE_PREPARE_TX; + req.hdr.i2s_port = cpu_to_le16(i2s_port); + + return gb_hd_output(connection->hd, &req, sizeof(req), + GB_APB_REQUEST_AUDIO_CONTROL, true); +} +EXPORT_SYMBOL_GPL(gb_audio_apbridgea_prepare_tx); + int gb_audio_apbridgea_start_tx(struct gb_connection *connection, __u16 i2s_port, __u64 timestamp) { @@ -108,6 +121,19 @@ int gb_audio_apbridgea_stop_tx(struct gb_connection *connection, __u16 i2s_port) } EXPORT_SYMBOL_GPL(gb_audio_apbridgea_stop_tx); +int gb_audio_apbridgea_shutdown_tx(struct gb_connection *connection, + __u16 i2s_port) +{ + struct audio_apbridgea_shutdown_tx_request req; + + req.hdr.type = AUDIO_APBRIDGEA_TYPE_SHUTDOWN_TX; + req.hdr.i2s_port = cpu_to_le16(i2s_port); + + return gb_hd_output(connection->hd, &req, sizeof(req), + GB_APB_REQUEST_AUDIO_CONTROL, true); +} +EXPORT_SYMBOL_GPL(gb_audio_apbridgea_shutdown_tx); + int gb_audio_apbridgea_set_rx_data_size(struct gb_connection *connection, __u16 i2s_port, __u16 size) { @@ -130,6 +156,19 @@ int gb_audio_apbridgea_get_rx_delay(struct gb_connection *connection, } EXPORT_SYMBOL_GPL(gb_audio_apbridgea_get_rx_delay); +int gb_audio_apbridgea_prepare_rx(struct gb_connection *connection, + __u16 i2s_port) +{ + struct audio_apbridgea_prepare_rx_request req; + + req.hdr.type = AUDIO_APBRIDGEA_TYPE_PREPARE_RX; + req.hdr.i2s_port = cpu_to_le16(i2s_port); + + return gb_hd_output(connection->hd, &req, sizeof(req), + GB_APB_REQUEST_AUDIO_CONTROL, true); +} +EXPORT_SYMBOL_GPL(gb_audio_apbridgea_prepare_rx); + int gb_audio_apbridgea_start_rx(struct gb_connection *connection, __u16 i2s_port) { @@ -155,6 +194,19 @@ int gb_audio_apbridgea_stop_rx(struct gb_connection *connection, __u16 i2s_port) } EXPORT_SYMBOL_GPL(gb_audio_apbridgea_stop_rx); +int gb_audio_apbridgea_shutdown_rx(struct gb_connection *connection, + __u16 i2s_port) +{ + struct audio_apbridgea_shutdown_rx_request req; + + req.hdr.type = AUDIO_APBRIDGEA_TYPE_SHUTDOWN_RX; + req.hdr.i2s_port = cpu_to_le16(i2s_port); + + return gb_hd_output(connection->hd, &req, sizeof(req), + GB_APB_REQUEST_AUDIO_CONTROL, true); +} +EXPORT_SYMBOL_GPL(gb_audio_apbridgea_shutdown_rx); + MODULE_LICENSE("GPL v2"); MODULE_ALIAS("greybus:audio-apbridgea"); MODULE_DESCRIPTION("Greybus Special APBridgeA Audio Protocol library"); diff --git a/drivers/staging/greybus/audio_apbridgea.h b/drivers/staging/greybus/audio_apbridgea.h index c543e39..a48f815 100644 --- a/drivers/staging/greybus/audio_apbridgea.h +++ b/drivers/staging/greybus/audio_apbridgea.h @@ -48,12 +48,16 @@ #define AUDIO_APBRIDGEA_TYPE_UNREGISTER_CPORT 0x03 #define AUDIO_APBRIDGEA_TYPE_SET_TX_DATA_SIZE 0x04 #define AUDIO_APBRIDGEA_TYPE_GET_TX_DELAY 0x05 -#define AUDIO_APBRIDGEA_TYPE_START_TX 0x06 -#define AUDIO_APBRIDGEA_TYPE_STOP_TX 0x07 -#define AUDIO_APBRIDGEA_TYPE_SET_RX_DATA_SIZE 0x08 -#define AUDIO_APBRIDGEA_TYPE_GET_RX_DELAY 0x09 -#define AUDIO_APBRIDGEA_TYPE_START_RX 0x0a -#define AUDIO_APBRIDGEA_TYPE_STOP_RX 0x0b +#define AUDIO_APBRIDGEA_TYPE_PREPARE_TX 0x06 +#define AUDIO_APBRIDGEA_TYPE_START_TX 0x07 +#define AUDIO_APBRIDGEA_TYPE_STOP_TX 0x08 +#define AUDIO_APBRIDGEA_TYPE_SHUTDOWN_TX 0x09 +#define AUDIO_APBRIDGEA_TYPE_SET_RX_DATA_SIZE 0x0a +#define AUDIO_APBRIDGEA_TYPE_GET_RX_DELAY 0x0b +#define AUDIO_APBRIDGEA_TYPE_PREPARE_RX 0x0c +#define AUDIO_APBRIDGEA_TYPE_START_RX 0x0d +#define AUDIO_APBRIDGEA_TYPE_STOP_RX 0x0e +#define AUDIO_APBRIDGEA_TYPE_SHUTDOWN_RX 0x0f #define AUDIO_APBRIDGEA_PCM_FMT_8 BIT(0) #define AUDIO_APBRIDGEA_PCM_FMT_16 BIT(1) @@ -120,6 +124,10 @@ struct audio_apbridgea_get_tx_delay_response { __le16 delay; } __packed; +struct audio_apbridgea_prepare_tx_request { + struct audio_apbridgea_hdr hdr; +} __packed; + struct audio_apbridgea_start_tx_request { struct audio_apbridgea_hdr hdr; __le64 timestamp; @@ -129,6 +137,10 @@ struct audio_apbridgea_stop_tx_request { struct audio_apbridgea_hdr hdr; } __packed; +struct audio_apbridgea_shutdown_tx_request { + struct audio_apbridgea_hdr hdr; +} __packed; + struct audio_apbridgea_set_rx_data_size_request { struct audio_apbridgea_hdr hdr; __le16 size; @@ -143,6 +155,10 @@ struct audio_apbridgea_get_rx_delay_response { __le16 delay; } __packed; +struct audio_apbridgea_prepare_rx_request { + struct audio_apbridgea_hdr hdr; +} __packed; + struct audio_apbridgea_start_rx_request { struct audio_apbridgea_hdr hdr; } __packed; @@ -151,4 +167,8 @@ struct audio_apbridgea_stop_rx_request { struct audio_apbridgea_hdr hdr; } __packed; +struct audio_apbridgea_shutdown_rx_request { + struct audio_apbridgea_hdr hdr; +} __packed; + #endif /*__AUDIO_APBRIDGEA_H */ diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c index 5e29694..d7cae77 100644 --- a/drivers/staging/greybus/audio_codec.c +++ b/drivers/staging/greybus/audio_codec.c @@ -345,17 +345,33 @@ static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd, goto func_exit; } - if (start && tx) - ret = gb_audio_apbridgea_start_tx(gb_dai->connection, 0, 0); + if (start && tx) { + ret = gb_audio_apbridgea_prepare_tx(gb_dai->connection, 0); + if (!ret) + ret = gb_audio_apbridgea_start_tx(gb_dai->connection, 0, + 0); + } - else if (start && rx) - ret = gb_audio_apbridgea_start_rx(gb_dai->connection, 0); + else if (start && rx) { + ret = gb_audio_apbridgea_prepare_rx(gb_dai->connection, 0); + if (!ret) + ret = gb_audio_apbridgea_start_rx(gb_dai->connection, + 0); + } - else if (stop && tx) + else if (stop && tx) { ret = gb_audio_apbridgea_stop_tx(gb_dai->connection, 0); + if (!ret) + ret = gb_audio_apbridgea_shutdown_tx(gb_dai->connection, + 0); + } - else if (stop && rx) + else if (stop && rx) { ret = gb_audio_apbridgea_stop_rx(gb_dai->connection, 0); + if (!ret) + ret = gb_audio_apbridgea_shutdown_rx(gb_dai->connection, + 0); + } else ret = -EINVAL; @@ -488,6 +504,10 @@ static void gb_audio_cleanup(struct gbaudio_codec_info *gb) if (ret) dev_info(dev, "%d:Failed during APBridge stop_tx\n", ret); + ret = gb_audio_apbridgea_shutdown_tx(connection, 0); + if (ret) + dev_info(dev, "%d:Failed during APBridge shutdown_tx\n", + ret); cportid = connection->intf_cport_id; ret = gb_audio_gb_deactivate_tx(gb->mgmt_connection, cportid); diff --git a/drivers/staging/greybus/audio_codec.h b/drivers/staging/greybus/audio_codec.h index 0631203..9197adc 100644 --- a/drivers/staging/greybus/audio_codec.h +++ b/drivers/staging/greybus/audio_codec.h @@ -207,17 +207,25 @@ extern int gb_audio_apbridgea_set_tx_data_size(struct gb_connection *connection, __u16 i2s_port, __u16 size); extern int gb_audio_apbridgea_get_tx_delay(struct gb_connection *connection, __u16 i2s_port, __u32 *delay); +extern int gb_audio_apbridgea_prepare_tx(struct gb_connection *connection, + __u16 i2s_port); extern int gb_audio_apbridgea_start_tx(struct gb_connection *connection, __u16 i2s_port, __u64 timestamp); extern int gb_audio_apbridgea_stop_tx(struct gb_connection *connection, __u16 i2s_port); +extern int gb_audio_apbridgea_shutdown_tx(struct gb_connection *connection, + __u16 i2s_port); extern int gb_audio_apbridgea_set_rx_data_size(struct gb_connection *connection, __u16 i2s_port, __u16 size); extern int gb_audio_apbridgea_get_rx_delay(struct gb_connection *connection, __u16 i2s_port, __u32 *delay); +extern int gb_audio_apbridgea_prepare_rx(struct gb_connection *connection, + __u16 i2s_port); extern int gb_audio_apbridgea_start_rx(struct gb_connection *connection, __u16 i2s_port); extern int gb_audio_apbridgea_stop_rx(struct gb_connection *connection, __u16 i2s_port); +extern int gb_audio_apbridgea_shutdown_rx(struct gb_connection *connection, + __u16 i2s_port); #endif /* __LINUX_GBAUDIO_CODEC_H */ -- 2.7.4