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-audio-apbridgea-y := audio_apbridgea.o
 gb-camera-y := camera.o
 
 obj-m += greybus.o
 obj-m += gb-audio-codec.o
 obj-m += gb-camera.o
 obj-m += gb-audio-gb.o
+obj-m += gb-audio-apbridgea.o
 
 KERNELVER              ?= $(shell uname -r)
 KERNELDIR              ?= /lib/modules/$(KERNELVER)/build
 
                                   uint16_t data_cport);
 extern int gb_audio_gb_deactivate_rx(struct gb_connection *connection,
                                     uint16_t data_cport);
+extern int gb_audio_apbridgea_set_config(struct gb_connection *connection,
+                                        __u16 i2s_port, __u32 format,
+                                        __u32 rate, __u32 mclk_freq);
+extern int gb_audio_apbridgea_register_cport(struct gb_connection *connection,
+                                            __u16 i2s_port, __u16 cportid);
+extern int gb_audio_apbridgea_unregister_cport(struct gb_connection *connection,
+                                              __u16 i2s_port, __u16 cportid);
+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_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_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_start_rx(struct gb_connection *connection,
+                                      __u16 i2s_port);
+extern int gb_audio_apbridgea_stop_rx(struct gb_connection *connection,
+                                     __u16 i2s_port);
 
 #endif /* __KERNEL__ */
 #endif /* __LINUX_GBAUDIO_H */
 
--- /dev/null
+/*
+ * Greybus Audio Device Class Protocol helpers
+ *
+ * Copyright 2015-2016 Google Inc.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include "greybus.h"
+#include "greybus_protocols.h"
+#include "audio_apbridgea.h"
+
+int gb_audio_apbridgea_set_config(struct gb_connection *connection,
+                                 __u16 i2s_port, __u32 format, __u32 rate,
+                                 __u32 mclk_freq)
+{
+       struct audio_apbridgea_set_config_request req;
+
+       req.hdr.type = AUDIO_APBRIDGEA_TYPE_SET_CONFIG;
+       req.hdr.i2s_port = cpu_to_le16(i2s_port);
+       req.format = cpu_to_le32(format);
+       req.rate = cpu_to_le32(rate);
+       req.mclk_freq = cpu_to_le32(mclk_freq);
+
+       return gb_hd_output(connection->hd, &req, sizeof(req),
+                           GB_APB_REQUEST_AUDIO_CONTROL, true);
+}
+EXPORT_SYMBOL_GPL(gb_audio_apbridgea_set_config);
+
+int gb_audio_apbridgea_register_cport(struct gb_connection *connection,
+                                     __u16 i2s_port, __u16 cportid)
+{
+       struct audio_apbridgea_register_cport_request req;
+
+       req.hdr.type = AUDIO_APBRIDGEA_TYPE_REGISTER_CPORT;
+       req.hdr.i2s_port = cpu_to_le16(i2s_port);
+       req.cport = cpu_to_le16(cportid);
+
+       return gb_hd_output(connection->hd, &req, sizeof(req),
+                           GB_APB_REQUEST_AUDIO_CONTROL, true);
+}
+EXPORT_SYMBOL_GPL(gb_audio_apbridgea_register_cport);
+
+int gb_audio_apbridgea_unregister_cport(struct gb_connection *connection,
+                                       __u16 i2s_port, __u16 cportid)
+{
+       struct audio_apbridgea_unregister_cport_request req;
+
+       req.hdr.type = AUDIO_APBRIDGEA_TYPE_UNREGISTER_CPORT;
+       req.hdr.i2s_port = cpu_to_le16(i2s_port);
+       req.cport = cpu_to_le16(cportid);
+
+       return gb_hd_output(connection->hd, &req, sizeof(req),
+                           GB_APB_REQUEST_AUDIO_CONTROL, true);
+}
+EXPORT_SYMBOL_GPL(gb_audio_apbridgea_unregister_cport);
+
+int gb_audio_apbridgea_set_tx_data_size(struct gb_connection *connection,
+                                       __u16 i2s_port, __u16 size)
+{
+       struct audio_apbridgea_set_tx_data_size_request req;
+
+       req.hdr.type = AUDIO_APBRIDGEA_TYPE_SET_TX_DATA_SIZE;
+       req.hdr.i2s_port = cpu_to_le16(i2s_port);
+       req.size = cpu_to_le16(size);
+
+       return gb_hd_output(connection->hd, &req, sizeof(req),
+                           GB_APB_REQUEST_AUDIO_CONTROL, true);
+}
+EXPORT_SYMBOL_GPL(gb_audio_apbridgea_set_tx_data_size);
+
+int gb_audio_apbridgea_get_tx_delay(struct gb_connection *connection,
+                                   __u16 i2s_port, __u32 *delay)
+{
+       /* TODO: implement */
+       return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(gb_audio_apbridgea_get_tx_delay);
+
+int gb_audio_apbridgea_start_tx(struct gb_connection *connection,
+                               __u16 i2s_port, __u64 timestamp)
+{
+       struct audio_apbridgea_start_tx_request req;
+
+       req.hdr.type = AUDIO_APBRIDGEA_TYPE_START_TX;
+       req.hdr.i2s_port = cpu_to_le16(i2s_port);
+       req.timestamp = cpu_to_le64(timestamp);
+
+       return gb_hd_output(connection->hd, &req, sizeof(req),
+                           GB_APB_REQUEST_AUDIO_CONTROL, true);
+}
+EXPORT_SYMBOL_GPL(gb_audio_apbridgea_start_tx);
+
+int gb_audio_apbridgea_stop_tx(struct gb_connection *connection, __u16 i2s_port)
+{
+       struct audio_apbridgea_stop_tx_request req;
+
+       req.hdr.type = AUDIO_APBRIDGEA_TYPE_STOP_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_stop_tx);
+
+int gb_audio_apbridgea_set_rx_data_size(struct gb_connection *connection,
+                                       __u16 i2s_port, __u16 size)
+{
+       struct audio_apbridgea_set_rx_data_size_request req;
+
+       req.hdr.type = AUDIO_APBRIDGEA_TYPE_SET_RX_DATA_SIZE;
+       req.hdr.i2s_port = cpu_to_le16(i2s_port);
+       req.size = cpu_to_le16(size);
+
+       return gb_hd_output(connection->hd, &req, sizeof(req),
+                           GB_APB_REQUEST_AUDIO_CONTROL, true);
+}
+EXPORT_SYMBOL_GPL(gb_audio_apbridgea_set_rx_data_size);
+
+int gb_audio_apbridgea_get_rx_delay(struct gb_connection *connection,
+                                   __u16 i2s_port, __u32 *delay)
+{
+       /* TODO: implement */
+       return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(gb_audio_apbridgea_get_rx_delay);
+
+int gb_audio_apbridgea_start_rx(struct gb_connection *connection,
+                               __u16 i2s_port)
+{
+       struct audio_apbridgea_start_rx_request req;
+
+       req.hdr.type = AUDIO_APBRIDGEA_TYPE_START_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_start_rx);
+
+int gb_audio_apbridgea_stop_rx(struct gb_connection *connection, __u16 i2s_port)
+{
+       struct audio_apbridgea_stop_rx_request req;
+
+       req.hdr.type = AUDIO_APBRIDGEA_TYPE_STOP_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_stop_rx);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("greybus:audio-apbridgea");
+MODULE_DESCRIPTION("Greybus Special APBridgeA Audio Protocol library");
+MODULE_AUTHOR("Mark Greer <mgreer@animalcreek.com>");
 
--- /dev/null
+/**
+ * Copyright (c) 2015-2016 Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This is a special protocol for configuring communication over the
+ * I2S bus between the DSP on the MSM8994 and APBridgeA.  Therefore,
+ * we can predefine several low-level attributes of the communication
+ * because we know that they are supported.  In particular, the following
+ * assumptions are made:
+ *     - there are two channels (i.e., stereo)
+ *     - the low-level protocol is I2S as defined by Philips/NXP
+ *     - the DSP on the MSM8994 is the clock master for MCLK, BCLK, and WCLK
+ *     - WCLK changes on the falling edge of BCLK
+ *     - WCLK low for left channel; high for right channel
+ *     - TX data is sent on the falling edge of BCLK
+ *     - RX data is received/latched on the rising edge of BCLK
+ */
+
+#ifndef __AUDIO_APBRIDGEA_H
+#define __AUDIO_APBRIDGEA_H
+
+#define AUDIO_APBRIDGEA_TYPE_SET_CONFIG                        0x01
+#define AUDIO_APBRIDGEA_TYPE_REGISTER_CPORT            0x02
+#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_PCM_FMT_8                      BIT(0)
+#define AUDIO_APBRIDGEA_PCM_FMT_16                     BIT(1)
+#define AUDIO_APBRIDGEA_PCM_FMT_24                     BIT(2)
+#define AUDIO_APBRIDGEA_PCM_FMT_32                     BIT(3)
+#define AUDIO_APBRIDGEA_PCM_FMT_64                     BIT(4)
+
+#define AUDIO_APBRIDGEA_PCM_RATE_5512                  BIT(0)
+#define AUDIO_APBRIDGEA_PCM_RATE_8000                  BIT(1)
+#define AUDIO_APBRIDGEA_PCM_RATE_11025                 BIT(2)
+#define AUDIO_APBRIDGEA_PCM_RATE_16000                 BIT(3)
+#define AUDIO_APBRIDGEA_PCM_RATE_22050                 BIT(4)
+#define AUDIO_APBRIDGEA_PCM_RATE_32000                 BIT(5)
+#define AUDIO_APBRIDGEA_PCM_RATE_44100                 BIT(6)
+#define AUDIO_APBRIDGEA_PCM_RATE_48000                 BIT(7)
+#define AUDIO_APBRIDGEA_PCM_RATE_64000                 BIT(8)
+#define AUDIO_APBRIDGEA_PCM_RATE_88200                 BIT(9)
+#define AUDIO_APBRIDGEA_PCM_RATE_96000                 BIT(10)
+#define AUDIO_APBRIDGEA_PCM_RATE_176400                        BIT(11)
+#define AUDIO_APBRIDGEA_PCM_RATE_192000                        BIT(12)
+
+/* The I2S port is passed in the 'index' parameter of the USB request */
+/* The CPort is passed in the 'value' parameter of the USB request */
+
+struct audio_apbridgea_hdr {
+       __u8    type;
+       __le16  i2s_port;
+       __u8    data[0];
+} __packed;
+
+struct audio_apbridgea_set_config_request {
+       struct audio_apbridgea_hdr      hdr;
+       __le32                          format; /* AUDIO_APBRIDGEA_PCM_FMT_* */
+       __le32                          rate;   /* AUDIO_APBRIDGEA_PCM_RATE_* */
+       __le32                          mclk_freq; /* XXX Remove? */
+} __packed;
+
+struct audio_apbridgea_register_cport_request {
+       struct audio_apbridgea_hdr      hdr;
+       __le16                          cport;
+} __packed;
+
+struct audio_apbridgea_unregister_cport_request {
+       struct audio_apbridgea_hdr      hdr;
+       __le16                          cport;
+} __packed;
+
+struct audio_apbridgea_set_tx_data_size_request {
+       struct audio_apbridgea_hdr      hdr;
+       __le16                          size;
+} __packed;
+
+struct audio_apbridgea_get_tx_delay_request {
+       struct audio_apbridgea_hdr      hdr;
+} __packed;
+
+struct audio_apbridgea_get_tx_delay_response {
+       struct audio_apbridgea_hdr      hdr;
+       __le16                          delay;
+} __packed;
+
+struct audio_apbridgea_start_tx_request {
+       struct audio_apbridgea_hdr      hdr;
+       __le64                          timestamp;
+} __packed;
+
+struct audio_apbridgea_stop_tx_request {
+       struct audio_apbridgea_hdr      hdr;
+} __packed;
+
+struct audio_apbridgea_set_rx_data_size_request {
+       struct audio_apbridgea_hdr      hdr;
+       __le16                          size;
+} __packed;
+
+struct audio_apbridgea_get_rx_delay_request {
+       struct audio_apbridgea_hdr      hdr;
+} __packed;
+
+struct audio_apbridgea_get_rx_delay_response {
+       struct audio_apbridgea_hdr      hdr;
+       __le16                          delay;
+} __packed;
+
+struct audio_apbridgea_start_rx_request {
+       struct audio_apbridgea_hdr      hdr;
+} __packed;
+
+struct audio_apbridgea_stop_rx_request {
+       struct audio_apbridgea_hdr      hdr;
+} __packed;
+
+#endif /*__AUDIO_APBRIDGEA_H */
 
 /* request to control the CSI transmitter */
 #define GB_APB_REQUEST_CSI_TX_CONTROL  0x08
 
+/* request to control the CSI transmitter */
+#define GB_APB_REQUEST_AUDIO_CONTROL   0x09
+
 
 /* Firmware Protocol */