[dev][astro-tdm-output] Convert to composite device driver

astro-tdm-output now uses composite protocol to access I2C and GPIOs.

TEST: "audio record" and "audio play" on astro
Change-Id: I92f8c387f9806ba29f26929b1fc13d39f8b0c5ee
diff --git a/zircon/system/dev/audio/astro-tdm-output/BUILD.gn b/zircon/system/dev/audio/astro-tdm-output/BUILD.gn
index 99bd4c4..a20f016 100644
--- a/zircon/system/dev/audio/astro-tdm-output/BUILD.gn
+++ b/zircon/system/dev/audio/astro-tdm-output/BUILD.gn
@@ -5,11 +5,10 @@
 driver("astro-tdm-output") {
   sources = [
     "audio-stream-out.cpp",
-    "binding.c",
     "tas27xx.cpp",
   ]
   deps = [
-    "$zx/system/banjo/ddk-protocol-clock",
+    "$zx/system/banjo/ddk-protocol-composite",
     "$zx/system/banjo/ddk-protocol-gpio",
     "$zx/system/banjo/ddk-protocol-i2c",
     "$zx/system/banjo/ddk-protocol-platform-device",
diff --git a/zircon/system/dev/audio/astro-tdm-output/audio-stream-out.cpp b/zircon/system/dev/audio/astro-tdm-output/audio-stream-out.cpp
index e4450fb..56216f8 100644
--- a/zircon/system/dev/audio/astro-tdm-output/audio-stream-out.cpp
+++ b/zircon/system/dev/audio/astro-tdm-output/audio-stream-out.cpp
@@ -3,7 +3,10 @@
 // found in the LICENSE file.
 #include "audio-stream-out.h"
 
+#include <ddk/binding.h>
 #include <ddk/debug.h>
+#include <ddk/platform-defs.h>
+#include <ddk/protocol/composite.h>
 #include <math.h>
 
 #include <optional>
@@ -12,27 +15,52 @@
 namespace audio {
 namespace astro {
 
+enum {
+    COMPONENT_PDEV,
+    COMPONENT_I2C,
+    COMPONENT_FAULT_GPIO,
+    COMPONENT_ENABLE_GPIO,
+    COMPONENT_COUNT,
+};
+
 // Calculate ring buffer size for 1 second of 16-bit, 48kHz, stereo.
 constexpr size_t RB_SIZE = fbl::round_up<size_t, size_t>(48000 * 2 * 2u, PAGE_SIZE);
 
 AstroAudioStreamOut::AstroAudioStreamOut(zx_device_t* parent)
-    : SimpleAudioStream(parent, false), pdev_(parent) {
+    : SimpleAudioStream(parent, false) {
 }
 
 zx_status_t AstroAudioStreamOut::InitPDev() {
+    composite_protocol_t composite;
+
+    auto status = device_get_protocol(parent(), ZX_PROTOCOL_COMPOSITE, &composite);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "Could not get composite protocol\n");
+        return status;
+    }
+
+    zx_device_t* components[COMPONENT_COUNT] = {};
+    size_t actual;
+    composite_get_components(&composite, components, countof(components), &actual);
+    if (actual < countof(components)) {
+        zxlogf(ERROR, "could not get components\n");
+        return ZX_ERR_NOT_SUPPORTED;
+    }
+
+    pdev_ = components[COMPONENT_PDEV];
     if (!pdev_.is_valid()) {
         return ZX_ERR_NO_RESOURCES;
     }
 
-    audio_fault_ = pdev_.GetGpio(0);
-    audio_en_ = pdev_.GetGpio(1);
+    audio_fault_ = components[COMPONENT_FAULT_GPIO];
+    audio_en_ = components[COMPONENT_ENABLE_GPIO];
 
     if (!audio_fault_.is_valid() || !audio_en_.is_valid()) {
         zxlogf(ERROR, "%s failed to allocate gpio\n", __func__);
         return ZX_ERR_NO_RESOURCES;
     }
 
-    auto i2c = pdev_.GetI2c(0);
+    ddk::I2cChannel i2c = components[COMPONENT_I2C];
     if (!i2c.is_valid()) {
         zxlogf(ERROR, "%s failed to allocate i2c\n", __func__);
         return ZX_ERR_NO_RESOURCES;
@@ -43,7 +71,7 @@
         return ZX_ERR_NO_RESOURCES;
     }
 
-    zx_status_t status = pdev_.GetBti(0, &bti_);
+    status = pdev_.GetBti(0, &bti_);
     if (status != ZX_OK) {
         zxlogf(ERROR, "%s could not obtain bti - %d\n", __func__, status);
         return status;
@@ -277,11 +305,7 @@
     return ZX_OK;
 }
 
-} //astro
-} //audio
-
-extern "C" zx_status_t audio_bind(void* ctx, zx_device_t* device, void** cookie) {
-
+static zx_status_t audio_bind(void* ctx, zx_device_t* device) {
     auto stream =
         audio::SimpleAudioStream::Create<audio::astro::AstroAudioStreamOut>(device);
     if (stream == nullptr) {
@@ -292,3 +316,23 @@
 
     return ZX_OK;
 }
+
+static zx_driver_ops_t driver_ops = [](){
+    zx_driver_ops_t ops = {};
+    ops.version = DRIVER_OPS_VERSION;
+    ops.bind = audio_bind;
+    return ops;
+}();
+
+} //astro
+} //audio
+
+
+// clang-format off
+ZIRCON_DRIVER_BEGIN(aml_tdm, audio::astro::driver_ops, "aml-tdm-out", "0.1", 4)
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_COMPOSITE),
+    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_AMLOGIC),
+    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_AMLOGIC_S905D2),
+    BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_AMLOGIC_TDM),
+ZIRCON_DRIVER_END(aml_tdm)
+// clang-format on
diff --git a/zircon/system/dev/audio/astro-tdm-output/binding.c b/zircon/system/dev/audio/astro-tdm-output/binding.c
deleted file mode 100644
index 4519cbe..0000000
--- a/zircon/system/dev/audio/astro-tdm-output/binding.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <ddk/binding.h>
-#include <ddk/driver.h>
-#include <ddk/platform-defs.h>
-
-extern zx_status_t audio_bind(void* ctx, zx_device_t* parent);
-
-static zx_driver_ops_t aml_tdm_driver_ops = {
-    .version = DRIVER_OPS_VERSION,
-    .bind = audio_bind,
-};
-
-// clang-format off
-ZIRCON_DRIVER_BEGIN(aml_tdm, aml_tdm_driver_ops, "aml-tdm-out", "0.1", 3)
-    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_AMLOGIC),
-    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_AMLOGIC_S905D2),
-    BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_AMLOGIC_TDM),
-ZIRCON_DRIVER_END(aml_tdm)
-    // clang-format on
diff --git a/zircon/system/dev/board/astro/astro-audio.c b/zircon/system/dev/board/astro/astro-audio.c
index f6a4ee3..8c60699 100644
--- a/zircon/system/dev/board/astro/astro-audio.c
+++ b/zircon/system/dev/board/astro/astro-audio.c
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <ddk/binding.h>
 #include <ddk/debug.h>
 #include <ddk/device.h>
 #include <ddk/platform-defs.h>
@@ -12,19 +13,9 @@
 
 #include <limits.h>
 #include "astro.h"
+#include "astro-gpios.h"
 
 //clang-format off
-static const pbus_gpio_t audio_gpios[] = {
-    {
-        // AUDIO_SOC_FAULT_L
-        .gpio = S905D2_GPIOA(4),
-    },
-    {
-        // SOC_AUDIO_EN
-        .gpio = S905D2_GPIOA(5),
-    },
-};
-
 
 static const pbus_mmio_t audio_mmios[] = {
     {
@@ -40,28 +31,51 @@
     },
 };
 
-static const pbus_i2c_channel_t codec_i2c[] = {
-    {
-        .bus_id = 2,
-        .address = 0x48,
-    },
-};
-
 static pbus_dev_t aml_tdm_dev = {
     .name = "AstroAudio",
     .vid = PDEV_VID_AMLOGIC,
     .pid = PDEV_PID_AMLOGIC_S905D2,
     .did = PDEV_DID_AMLOGIC_TDM,
-    .gpio_list = audio_gpios,
-    .gpio_count = countof(audio_gpios),
-    .i2c_channel_list = codec_i2c,
-    .i2c_channel_count = countof(codec_i2c),
     .mmio_list = audio_mmios,
     .mmio_count = countof(audio_mmios),
     .bti_list = tdm_btis,
     .bti_count = countof(tdm_btis),
 };
 
+static const zx_bind_inst_t root_match[] = {
+    BI_MATCH(),
+};
+static const zx_bind_inst_t i2c_match[] = {
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_I2C),
+    BI_ABORT_IF(NE, BIND_I2C_BUS_ID, ASTRO_I2C_3),
+    BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, I2C_AUDIO_CODEC_ADDR),
+};
+static const zx_bind_inst_t fault_gpio_match[] = {
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
+    BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_AUDIO_SOC_FAULT_L),
+};
+static const zx_bind_inst_t enable_gpio_match[] = {
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
+    BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_SOC_AUDIO_EN),
+};
+static const device_component_part_t i2c_component[] = {
+    { countof(root_match), root_match },
+    { countof(i2c_match), i2c_match },
+};
+static const device_component_part_t fault_gpio_component[] = {
+    { countof(root_match), root_match },
+    { countof(fault_gpio_match), fault_gpio_match },
+};
+static const device_component_part_t enable_gpio_component[] = {
+    { countof(root_match), root_match },
+    { countof(enable_gpio_match), enable_gpio_match },
+};
+static const device_component_t components[] = {
+    { countof(i2c_component), i2c_component },
+    { countof(fault_gpio_component), fault_gpio_component },
+    { countof(enable_gpio_component), enable_gpio_component },
+};
+
 //PDM input configurations
 static const pbus_mmio_t pdm_mmios[] = {
     {
@@ -125,7 +139,8 @@
 
     gpio_impl_config_out(&bus->gpio, S905D2_GPIOA(5), 1);
 
-    status = pbus_device_add(&bus->pbus, &aml_tdm_dev);
+    status = pbus_composite_device_add(&bus->pbus, &aml_tdm_dev, components, countof(components),
+                                       UINT32_MAX);
     if (status != ZX_OK) {
         zxlogf(ERROR, "astro_tdm_init: pbus_device_add failed: %d\n", status);
         return status;
diff --git a/zircon/system/dev/board/astro/astro-gpio.c b/zircon/system/dev/board/astro/astro-gpio.c
index 0efa08d..99bd2c2 100644
--- a/zircon/system/dev/board/astro/astro-gpio.c
+++ b/zircon/system/dev/board/astro/astro-gpio.c
@@ -84,6 +84,9 @@
     { GPIO_TOUCH_RESET },
     // For light sensor.
     { GPIO_LIGHT_INTERRUPT },
+    // For audio.
+    { GPIO_AUDIO_SOC_FAULT_L },
+    { GPIO_SOC_AUDIO_EN },
 };
 
 static const pbus_metadata_t gpio_metadata[] = {
diff --git a/zircon/system/dev/board/astro/astro-gpios.h b/zircon/system/dev/board/astro/astro-gpios.h
index b07bf9e..84ceeb3 100644
--- a/zircon/system/dev/board/astro/astro-gpios.h
+++ b/zircon/system/dev/board/astro/astro-gpios.h
@@ -12,3 +12,5 @@
 #define GPIO_TOUCH_INTERRUPT    S905D2_GPIOZ(4)
 #define GPIO_TOUCH_RESET        S905D2_GPIOZ(9)
 #define GPIO_LIGHT_INTERRUPT    S905D2_GPIOAO(5)
+#define GPIO_AUDIO_SOC_FAULT_L  S905D2_GPIOA(4)
+#define GPIO_SOC_AUDIO_EN       S905D2_GPIOA(5)
diff --git a/zircon/system/dev/board/astro/astro-i2c.c b/zircon/system/dev/board/astro/astro-i2c.c
index 6e5496c..11f1e85 100644
--- a/zircon/system/dev/board/astro/astro-i2c.c
+++ b/zircon/system/dev/board/astro/astro-i2c.c
@@ -71,6 +71,12 @@
         .address = I2C_AMBIENTLIGHT_ADDR,
         // binds as composite device
     },
+    // Audio output
+    {
+        .bus_id = ASTRO_I2C_3,
+        .address = I2C_AUDIO_CODEC_ADDR,
+        // binds as composite device
+    },
 };
 
 static const pbus_metadata_t i2c_metadata[] = {
diff --git a/zircon/system/dev/board/astro/astro.h b/zircon/system/dev/board/astro/astro.h
index 0e4041c..fa323f0 100644
--- a/zircon/system/dev/board/astro/astro.h
+++ b/zircon/system/dev/board/astro/astro.h
@@ -84,6 +84,7 @@
 #define I2C_BACKLIGHT_ADDR          (0x2C)
 #define I2C_FOCALTECH_TOUCH_ADDR    (0x38)
 #define I2C_AMBIENTLIGHT_ADDR       (0x39)
+#define I2C_AUDIO_CODEC_ADDR        (0x48)
 #define I2C_GOODIX_TOUCH_ADDR       (0x5d)
 
 // astro-touch.c