Commit 5bbe14b7 authored by Mark Greer's avatar Mark Greer Committed by Greg Kroah-Hartman

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 <vaibhav.agarwal@linaro.org>
Signed-off-by: default avatarMark Greer <mgreer@animalcreek.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 9250c0ee
...@@ -82,6 +82,19 @@ int gb_audio_apbridgea_get_tx_delay(struct gb_connection *connection, ...@@ -82,6 +82,19 @@ int gb_audio_apbridgea_get_tx_delay(struct gb_connection *connection,
} }
EXPORT_SYMBOL_GPL(gb_audio_apbridgea_get_tx_delay); 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, int gb_audio_apbridgea_start_tx(struct gb_connection *connection,
__u16 i2s_port, __u64 timestamp) __u16 i2s_port, __u64 timestamp)
{ {
...@@ -108,6 +121,19 @@ int gb_audio_apbridgea_stop_tx(struct gb_connection *connection, __u16 i2s_port) ...@@ -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); 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, int gb_audio_apbridgea_set_rx_data_size(struct gb_connection *connection,
__u16 i2s_port, __u16 size) __u16 i2s_port, __u16 size)
{ {
...@@ -130,6 +156,19 @@ int gb_audio_apbridgea_get_rx_delay(struct gb_connection *connection, ...@@ -130,6 +156,19 @@ int gb_audio_apbridgea_get_rx_delay(struct gb_connection *connection,
} }
EXPORT_SYMBOL_GPL(gb_audio_apbridgea_get_rx_delay); 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, int gb_audio_apbridgea_start_rx(struct gb_connection *connection,
__u16 i2s_port) __u16 i2s_port)
{ {
...@@ -155,6 +194,19 @@ int gb_audio_apbridgea_stop_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); 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_LICENSE("GPL v2");
MODULE_ALIAS("greybus:audio-apbridgea"); MODULE_ALIAS("greybus:audio-apbridgea");
MODULE_DESCRIPTION("Greybus Special APBridgeA Audio Protocol library"); MODULE_DESCRIPTION("Greybus Special APBridgeA Audio Protocol library");
......
...@@ -48,12 +48,16 @@ ...@@ -48,12 +48,16 @@
#define AUDIO_APBRIDGEA_TYPE_UNREGISTER_CPORT 0x03 #define AUDIO_APBRIDGEA_TYPE_UNREGISTER_CPORT 0x03
#define AUDIO_APBRIDGEA_TYPE_SET_TX_DATA_SIZE 0x04 #define AUDIO_APBRIDGEA_TYPE_SET_TX_DATA_SIZE 0x04
#define AUDIO_APBRIDGEA_TYPE_GET_TX_DELAY 0x05 #define AUDIO_APBRIDGEA_TYPE_GET_TX_DELAY 0x05
#define AUDIO_APBRIDGEA_TYPE_START_TX 0x06 #define AUDIO_APBRIDGEA_TYPE_PREPARE_TX 0x06
#define AUDIO_APBRIDGEA_TYPE_STOP_TX 0x07 #define AUDIO_APBRIDGEA_TYPE_START_TX 0x07
#define AUDIO_APBRIDGEA_TYPE_SET_RX_DATA_SIZE 0x08 #define AUDIO_APBRIDGEA_TYPE_STOP_TX 0x08
#define AUDIO_APBRIDGEA_TYPE_GET_RX_DELAY 0x09 #define AUDIO_APBRIDGEA_TYPE_SHUTDOWN_TX 0x09
#define AUDIO_APBRIDGEA_TYPE_START_RX 0x0a #define AUDIO_APBRIDGEA_TYPE_SET_RX_DATA_SIZE 0x0a
#define AUDIO_APBRIDGEA_TYPE_STOP_RX 0x0b #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_8 BIT(0)
#define AUDIO_APBRIDGEA_PCM_FMT_16 BIT(1) #define AUDIO_APBRIDGEA_PCM_FMT_16 BIT(1)
...@@ -120,6 +124,10 @@ struct audio_apbridgea_get_tx_delay_response { ...@@ -120,6 +124,10 @@ struct audio_apbridgea_get_tx_delay_response {
__le16 delay; __le16 delay;
} __packed; } __packed;
struct audio_apbridgea_prepare_tx_request {
struct audio_apbridgea_hdr hdr;
} __packed;
struct audio_apbridgea_start_tx_request { struct audio_apbridgea_start_tx_request {
struct audio_apbridgea_hdr hdr; struct audio_apbridgea_hdr hdr;
__le64 timestamp; __le64 timestamp;
...@@ -129,6 +137,10 @@ struct audio_apbridgea_stop_tx_request { ...@@ -129,6 +137,10 @@ struct audio_apbridgea_stop_tx_request {
struct audio_apbridgea_hdr hdr; struct audio_apbridgea_hdr hdr;
} __packed; } __packed;
struct audio_apbridgea_shutdown_tx_request {
struct audio_apbridgea_hdr hdr;
} __packed;
struct audio_apbridgea_set_rx_data_size_request { struct audio_apbridgea_set_rx_data_size_request {
struct audio_apbridgea_hdr hdr; struct audio_apbridgea_hdr hdr;
__le16 size; __le16 size;
...@@ -143,6 +155,10 @@ struct audio_apbridgea_get_rx_delay_response { ...@@ -143,6 +155,10 @@ struct audio_apbridgea_get_rx_delay_response {
__le16 delay; __le16 delay;
} __packed; } __packed;
struct audio_apbridgea_prepare_rx_request {
struct audio_apbridgea_hdr hdr;
} __packed;
struct audio_apbridgea_start_rx_request { struct audio_apbridgea_start_rx_request {
struct audio_apbridgea_hdr hdr; struct audio_apbridgea_hdr hdr;
} __packed; } __packed;
...@@ -151,4 +167,8 @@ struct audio_apbridgea_stop_rx_request { ...@@ -151,4 +167,8 @@ struct audio_apbridgea_stop_rx_request {
struct audio_apbridgea_hdr hdr; struct audio_apbridgea_hdr hdr;
} __packed; } __packed;
struct audio_apbridgea_shutdown_rx_request {
struct audio_apbridgea_hdr hdr;
} __packed;
#endif /*__AUDIO_APBRIDGEA_H */ #endif /*__AUDIO_APBRIDGEA_H */
...@@ -345,17 +345,33 @@ static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -345,17 +345,33 @@ static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd,
goto func_exit; goto func_exit;
} }
if (start && tx) if (start && tx) {
ret = gb_audio_apbridgea_start_tx(gb_dai->connection, 0, 0); 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) else if (start && rx) {
ret = gb_audio_apbridgea_start_rx(gb_dai->connection, 0); 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); 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); ret = gb_audio_apbridgea_stop_rx(gb_dai->connection, 0);
if (!ret)
ret = gb_audio_apbridgea_shutdown_rx(gb_dai->connection,
0);
}
else else
ret = -EINVAL; ret = -EINVAL;
...@@ -488,6 +504,10 @@ static void gb_audio_cleanup(struct gbaudio_codec_info *gb) ...@@ -488,6 +504,10 @@ static void gb_audio_cleanup(struct gbaudio_codec_info *gb)
if (ret) if (ret)
dev_info(dev, "%d:Failed during APBridge stop_tx\n", dev_info(dev, "%d:Failed during APBridge stop_tx\n",
ret); 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; cportid = connection->intf_cport_id;
ret = gb_audio_gb_deactivate_tx(gb->mgmt_connection, ret = gb_audio_gb_deactivate_tx(gb->mgmt_connection,
cportid); cportid);
......
...@@ -207,17 +207,25 @@ extern int gb_audio_apbridgea_set_tx_data_size(struct gb_connection *connection, ...@@ -207,17 +207,25 @@ extern int gb_audio_apbridgea_set_tx_data_size(struct gb_connection *connection,
__u16 i2s_port, __u16 size); __u16 i2s_port, __u16 size);
extern int gb_audio_apbridgea_get_tx_delay(struct gb_connection *connection, extern int gb_audio_apbridgea_get_tx_delay(struct gb_connection *connection,
__u16 i2s_port, __u32 *delay); __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, extern int gb_audio_apbridgea_start_tx(struct gb_connection *connection,
__u16 i2s_port, __u64 timestamp); __u16 i2s_port, __u64 timestamp);
extern int gb_audio_apbridgea_stop_tx(struct gb_connection *connection, extern int gb_audio_apbridgea_stop_tx(struct gb_connection *connection,
__u16 i2s_port); __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, extern int gb_audio_apbridgea_set_rx_data_size(struct gb_connection *connection,
__u16 i2s_port, __u16 size); __u16 i2s_port, __u16 size);
extern int gb_audio_apbridgea_get_rx_delay(struct gb_connection *connection, extern int gb_audio_apbridgea_get_rx_delay(struct gb_connection *connection,
__u16 i2s_port, __u32 *delay); __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, extern int gb_audio_apbridgea_start_rx(struct gb_connection *connection,
__u16 i2s_port); __u16 i2s_port);
extern int gb_audio_apbridgea_stop_rx(struct gb_connection *connection, extern int gb_audio_apbridgea_stop_rx(struct gb_connection *connection,
__u16 i2s_port); __u16 i2s_port);
extern int gb_audio_apbridgea_shutdown_rx(struct gb_connection *connection,
__u16 i2s_port);
#endif /* __LINUX_GBAUDIO_CODEC_H */ #endif /* __LINUX_GBAUDIO_CODEC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment