Browse Source

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: Mark Greer <mgreer@animalcreek.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Mark Greer 9 years ago
parent
commit
5bbe14b7ac

+ 52 - 0
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");

+ 26 - 6
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 */

+ 26 - 6
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);

+ 8 - 0
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 */