diff --git a/zircon/system/banjo/ddk.protocol.platform.bus/platform-bus.banjo b/zircon/system/banjo/ddk.protocol.platform.bus/platform-bus.banjo
index c17d7d4b67219cf322cbeac8d9d2fe06b4c641ba..e7fe9f39d447088f90f3c8986e1c0fd723659d19 100644
--- a/zircon/system/banjo/ddk.protocol.platform.bus/platform-bus.banjo
+++ b/zircon/system/banjo/ddk.protocol.platform.bus/platform-bus.banjo
@@ -27,11 +27,6 @@ struct PbusGpio {
     uint32 gpio;
 };
 
-struct PbusI2cChannel {
-    uint32 bus_id;
-    uint16 address;
-};
-
 struct PbusClk {
     uint32 clk;
 };
@@ -76,7 +71,6 @@ struct PbusDev {
     vector<PbusMmio> mmio;
     vector<PbusIrq> irq;
     vector<PbusGpio> gpio;
-    vector<PbusI2cChannel> i2c_channel;
     vector<PbusClk> clk;
     vector<PbusBti> bti;
     vector<PbusSmc> smc;
diff --git a/zircon/system/banjo/ddk.protocol.platform.device/platform-device.banjo b/zircon/system/banjo/ddk.protocol.platform.device/platform-device.banjo
index 47acadf2c6aa5bf3e085807e92d081d771f57e2a..071ddd29ff547188bf777e1ba4c280847c0a2eec 100644
--- a/zircon/system/banjo/ddk.protocol.platform.device/platform-device.banjo
+++ b/zircon/system/banjo/ddk.protocol.platform.device/platform-device.banjo
@@ -14,7 +14,6 @@ struct PdevDeviceInfo {
     uint32 mmio_count;
     uint32 irq_count;
     uint32 gpio_count;
-    uint32 i2c_channel_count;
     uint32 clk_count;
     uint32 bti_count;
     uint32 smc_count;
diff --git a/zircon/system/dev/audio/astro-tdm-output/tas27xx.h b/zircon/system/dev/audio/astro-tdm-output/tas27xx.h
index b03dd2669e4e016258a873189fec32242da3df6a..7aa1997ac5ae9e8f722edafeb3acdc345fd7ceb3 100644
--- a/zircon/system/dev/audio/astro-tdm-output/tas27xx.h
+++ b/zircon/system/dev/audio/astro-tdm-output/tas27xx.h
@@ -5,7 +5,7 @@
 #pragma once
 
 #include <ddk/debug.h>
-#include <ddktl/pdev.h>
+#include <ddktl/i2c-channel.h>
 #include <fbl/unique_ptr.h>
 
 namespace audio {
diff --git a/zircon/system/dev/audio/sherlock-tdm-output/tas5720.h b/zircon/system/dev/audio/sherlock-tdm-output/tas5720.h
index f8e8911ef34ac1c53b5f6f75766e6bda68e6a578..488382c4d8b237ec7a8706ad1f88364dc5ed6f0a 100644
--- a/zircon/system/dev/audio/sherlock-tdm-output/tas5720.h
+++ b/zircon/system/dev/audio/sherlock-tdm-output/tas5720.h
@@ -6,7 +6,7 @@
 
 #include <ddk/debug.h>
 #include <ddk/protocol/i2c.h>
-#include <ddktl/pdev.h>
+#include <ddktl/i2c-channel.h>
 #include <fbl/unique_ptr.h>
 #include <lib/codec-interface/codec-interface.h>
 
diff --git a/zircon/system/dev/audio/sherlock-tdm-output/tas5760.h b/zircon/system/dev/audio/sherlock-tdm-output/tas5760.h
index 0225bb048f1e7ebc711bbba6b998ddefe511b8ae..287453c06bc540633621a108c81f61c2bdfe8053 100644
--- a/zircon/system/dev/audio/sherlock-tdm-output/tas5760.h
+++ b/zircon/system/dev/audio/sherlock-tdm-output/tas5760.h
@@ -6,7 +6,7 @@
 
 #include <ddk/debug.h>
 #include <ddk/protocol/i2c.h>
-#include <ddktl/pdev.h>
+#include <ddktl/i2c-channel.h>
 #include <fbl/unique_ptr.h>
 #include <lib/codec-interface/codec-interface.h>
 
diff --git a/zircon/system/dev/board/astro/astro-i2c.c b/zircon/system/dev/board/astro/astro-i2c.c
index 11f1e8571e7c01b7881a10caf91d37453326e3a8..6ee873261da51feed6bfa7c16139802339b28a2b 100644
--- a/zircon/system/dev/board/astro/astro-i2c.c
+++ b/zircon/system/dev/board/astro/astro-i2c.c
@@ -113,9 +113,9 @@ zx_status_t aml_i2c_init(aml_bus_t* bus) {
     gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOA(14), 2);
     gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOA(15), 2);
 
-    zx_status_t status = pbus_protocol_device_add(&bus->pbus, ZX_PROTOCOL_I2C_IMPL, &i2c_dev);
+    zx_status_t status = pbus_device_add(&bus->pbus, &i2c_dev);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "aml_i2c_init: pbus_protocol_device_add failed: %d\n", status);
+        zxlogf(ERROR, "aml_i2c_init: pbus_device_add failed: %d\n", status);
         return status;
     }
 
diff --git a/zircon/system/dev/board/gauss/gauss-i2c.c b/zircon/system/dev/board/gauss/gauss-i2c.c
index 9a15f3a98cf73bc72b60f1959727d85f02ae39ca..82dc09a8357465e71254e9bc50e86660d640ae97 100644
--- a/zircon/system/dev/board/gauss/gauss-i2c.c
+++ b/zircon/system/dev/board/gauss/gauss-i2c.c
@@ -101,9 +101,9 @@ static const pbus_dev_t i2c_dev = {
 };
 
 zx_status_t gauss_i2c_init(gauss_bus_t* bus) {
-    zx_status_t status = pbus_protocol_device_add(&bus->pbus, ZX_PROTOCOL_I2C_IMPL, &i2c_dev);
+    zx_status_t status = pbus_device_add(&bus->pbus, &i2c_dev);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "gauss_i2c_init: pbus_protocol_device_add failed: %d\n", status);
+        zxlogf(ERROR, "gauss_i2c_init: pbus_device_add failed: %d\n", status);
         return status;
     }
 
diff --git a/zircon/system/dev/board/hikey960/hikey960-i2c.c b/zircon/system/dev/board/hikey960/hikey960-i2c.c
index cdc3811e6bf668ac281d0013d5a9b282e626aa43..c92ec522930e6738d6c449f8361364034c0428cd 100644
--- a/zircon/system/dev/board/hikey960/hikey960-i2c.c
+++ b/zircon/system/dev/board/hikey960/hikey960-i2c.c
@@ -92,9 +92,9 @@ static const pbus_dev_t i2c_dev = {
 };
 
 zx_status_t hikey960_i2c_init(hikey960_t* bus) {
-    zx_status_t status = pbus_protocol_device_add(&bus->pbus, ZX_PROTOCOL_I2C_IMPL, &i2c_dev);
+    zx_status_t status = pbus_device_add(&bus->pbus, &i2c_dev);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "hikey960_i2c_init: pbus_protocol_device_add failed: %d\n", status);
+        zxlogf(ERROR, "hikey960_i2c_init: pbus_device_add failed: %d\n", status);
         return status;
     }
 
diff --git a/zircon/system/dev/board/mt8167s_ref/mt8167-i2c.cpp b/zircon/system/dev/board/mt8167s_ref/mt8167-i2c.cpp
index a3a81fb509a3745e99fc14fc066a14dbdcb9eb25..147a00f388dd945ff6884b1e297480eacd8f1dc6 100644
--- a/zircon/system/dev/board/mt8167s_ref/mt8167-i2c.cpp
+++ b/zircon/system/dev/board/mt8167s_ref/mt8167-i2c.cpp
@@ -152,9 +152,9 @@ zx_status_t Mt8167::I2cInit() {
         i2c_dev.metadata_count = countof(cleo_i2c_metadata);
     }
 
-    status = pbus_.ProtocolDeviceAdd(ZX_PROTOCOL_I2C_IMPL, &i2c_dev);
+    status = pbus_.DeviceAdd(&i2c_dev);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "%s: ProtocolDeviceAdd failed %d\n", __FUNCTION__, status);
+        zxlogf(ERROR, "%s: DeviceAdd failed %d\n", __FUNCTION__, status);
         return status;
     }
 
diff --git a/zircon/system/dev/board/sherlock/sherlock-i2c.cpp b/zircon/system/dev/board/sherlock/sherlock-i2c.cpp
index b8c46437e95d3c5353c8b7a9515d51b80fe2d355..638499abdf3180af45f4d28550076c1cbd96ed61 100644
--- a/zircon/system/dev/board/sherlock/sherlock-i2c.cpp
+++ b/zircon/system/dev/board/sherlock/sherlock-i2c.cpp
@@ -134,9 +134,9 @@ zx_status_t Sherlock::I2cInit() {
     gpio_impl_.SetAltFunction(T931_GPIOA(14), 2);
     gpio_impl_.SetAltFunction(T931_GPIOA(15), 2);
 
-    zx_status_t status = pbus_.ProtocolDeviceAdd(ZX_PROTOCOL_I2C_IMPL, &i2c_dev);
+    zx_status_t status = pbus_.DeviceAdd(&i2c_dev);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "%s: ProtocolDeviceAdd failed %d\n", __func__, status);
+        zxlogf(ERROR, "%s: DeviceAdd failed %d\n", __func__, status);
         return status;
     }
 
diff --git a/zircon/system/dev/board/test/test-i2c.cpp b/zircon/system/dev/board/test/test-i2c.cpp
index 8e10c0b12962a36e02645d0c6256907f1e385bd9..171b90fe31884d0a6916d557b2b7409695fe5e0d 100644
--- a/zircon/system/dev/board/test/test-i2c.cpp
+++ b/zircon/system/dev/board/test/test-i2c.cpp
@@ -69,9 +69,9 @@ zx_status_t TestBoard::I2cInit() {
     i2c_dev.metadata_list = i2c_metadata;
     i2c_dev.metadata_count = countof(i2c_metadata);
 
-    zx_status_t status = pbus_.ProtocolDeviceAdd(ZX_PROTOCOL_I2C_IMPL, &i2c_dev);
+    zx_status_t status = pbus_.DeviceAdd(&i2c_dev);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "%s: ProtocolDeviceAdd failed %d\n", __FUNCTION__, status);
+        zxlogf(ERROR, "%s: DeviceAdd failed %d\n", __FUNCTION__, status);
         return status;
     }
 
diff --git a/zircon/system/dev/board/test/test/i2c.cpp b/zircon/system/dev/board/test/test/i2c.cpp
index 7e4779a3690b92ca7a5403b57effe13ce0395254..40a70bd151a82d6abdd6ba90db52ae062b08a3f0 100644
--- a/zircon/system/dev/board/test/test/i2c.cpp
+++ b/zircon/system/dev/board/test/test/i2c.cpp
@@ -8,7 +8,6 @@
 #include <ddk/debug.h>
 #include <ddk/driver.h>
 #include <ddk/platform-defs.h>
-#include <ddk/protocol/platform/bus.h>
 #include <ddk/protocol/platform/device.h>
 #include <ddktl/device.h>
 #include <ddktl/protocol/i2cimpl.h>
@@ -29,7 +28,6 @@ public:
         : DeviceType(parent) {}
 
     zx_status_t Create(std::unique_ptr<TestI2cDevice>* out);
-    zx_status_t Init();
 
     uint32_t I2cImplGetBusCount();
     zx_status_t I2cImplGetMaxTransferSize(uint32_t bus_id, size_t* out_size);
@@ -42,25 +40,6 @@ public:
 
 };
 
-zx_status_t TestI2cDevice::Init() {
-    pbus_protocol_t pbus;
-    auto status = device_get_protocol(parent(), ZX_PROTOCOL_PBUS, &pbus);
-    if (status != ZX_OK) {
-        zxlogf(ERROR, "%s: ZX_PROTOCOL_PBUS not available %d\n", __func__, status);
-        return status;
-    }
-    i2c_impl_protocol_t i2c_proto = {
-        .ops = &i2c_impl_protocol_ops_,
-        .ctx = this,
-    };
-    status = pbus_register_protocol(&pbus, ZX_PROTOCOL_I2C_IMPL, &i2c_proto, sizeof(i2c_proto));
-    if (status != ZX_OK) {
-        zxlogf(ERROR, "%s pbus_register_protocol failed %d\n", __func__, status);
-        return status;
-    }
-    return ZX_OK;
-}
-
 zx_status_t TestI2cDevice::Create(zx_device_t* parent) {
     auto dev = std::make_unique<TestI2cDevice>(parent);
     pdev_protocol_t pdev;
@@ -80,9 +59,9 @@ zx_status_t TestI2cDevice::Create(zx_device_t* parent) {
         return status;
     }
     // devmgr is now in charge of dev.
-    auto ptr = dev.release();
+    __UNUSED auto ptr = dev.release();
 
-    return ptr->Init();
+    return ZX_OK;
 }
 
 void TestI2cDevice::DdkUnbind() {}
diff --git a/zircon/system/dev/board/vim/vim-i2c.cpp b/zircon/system/dev/board/vim/vim-i2c.cpp
index 7f0dcbc5d6cd114980c03823c264139c8622fac3..a61acfd1153ec8e08ef6fae0066724247df99394 100644
--- a/zircon/system/dev/board/vim/vim-i2c.cpp
+++ b/zircon/system/dev/board/vim/vim-i2c.cpp
@@ -116,9 +116,9 @@ zx_status_t Vim::I2cInit() {
     gpio_impl_.SetAltFunction(S912_I2C_SDA_C, S912_I2C_SDA_C_FN);
     gpio_impl_.SetAltFunction(S912_I2C_SCK_C, S912_I2C_SCK_C_FN);
 
-    zx_status_t status = pbus_.ProtocolDeviceAdd(ZX_PROTOCOL_I2C_IMPL, &i2c_dev);
+    zx_status_t status = pbus_.DeviceAdd(&i2c_dev);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "I2cInit: pbus_protocol_device_add failed: %d\n", status);
+        zxlogf(ERROR, "I2cInit: DeviceAdd failed: %d\n", status);
         return status;
     }
 
diff --git a/zircon/system/dev/bus/platform/BUILD.gn b/zircon/system/dev/bus/platform/BUILD.gn
index 23399ed9bbfe0071929faa0175e0e5667f659464..4feb19aa632246582aa94ea9c3925cc5f8eda13a 100644
--- a/zircon/system/dev/bus/platform/BUILD.gn
+++ b/zircon/system/dev/bus/platform/BUILD.gn
@@ -16,7 +16,6 @@ driver("platform-bus") {
     "platform-bus.cpp",
     "platform-composite-device.cpp",
     "platform-device.cpp",
-    "platform-i2c.cpp",
     "platform-protocol-device.cpp",
   ]
   deps = [
@@ -25,8 +24,6 @@ driver("platform-bus") {
     "$zx/system/banjo/ddk.protocol.clockimpl",
     "$zx/system/banjo/ddk.protocol.gpio",
     "$zx/system/banjo/ddk.protocol.gpioimpl",
-    "$zx/system/banjo/ddk.protocol.i2c",
-    "$zx/system/banjo/ddk.protocol.i2cimpl",
     "$zx/system/banjo/ddk.protocol.iommu",
     "$zx/system/banjo/ddk.protocol.platform.bus",
     "$zx/system/banjo/ddk.protocol.platform.device",
@@ -54,8 +51,6 @@ driver("platform-bus.proxy") {
     "$zx/system/banjo/ddk.protocol.clock",
     "$zx/system/banjo/ddk.protocol.gpio",
     "$zx/system/banjo/ddk.protocol.gpioimpl",
-    "$zx/system/banjo/ddk.protocol.i2c",
-    "$zx/system/banjo/ddk.protocol.i2cimpl",
     "$zx/system/banjo/ddk.protocol.platform.bus",
     "$zx/system/banjo/ddk.protocol.platform.device",
     "$zx/system/banjo/ddk.protocol.sysmem",
diff --git a/zircon/system/dev/bus/platform/device-resources.cpp b/zircon/system/dev/bus/platform/device-resources.cpp
index 349ed6cac07749fa9c63966748042e33663c85b9..b3028a60a5fb65770344f590ab9f0f5e412d464b 100644
--- a/zircon/system/dev/bus/platform/device-resources.cpp
+++ b/zircon/system/dev/bus/platform/device-resources.cpp
@@ -30,7 +30,6 @@ zx_status_t DeviceResources::Init(const pbus_dev_t* pdev) {
     if (!CopyResources(pdev->mmio_count, pdev->mmio_list, &mmios_) ||
         !CopyResources(pdev->irq_count, pdev->irq_list, &irqs_) ||
         !CopyResources(pdev->gpio_count, pdev->gpio_list, &gpios_) ||
-        !CopyResources(pdev->i2c_channel_count, pdev->i2c_channel_list, &i2c_channels_) ||
         !CopyResources(pdev->clk_count, pdev->clk_list, &clks_) ||
         !CopyResources(pdev->bti_count, pdev->bti_list, &btis_) ||
         !CopyResources(pdev->smc_count, pdev->smc_list, &smcs_) ||
diff --git a/zircon/system/dev/bus/platform/device-resources.h b/zircon/system/dev/bus/platform/device-resources.h
index defb168c754b0238759ae2204e322ea405603ade..0c0ab523a8ac38c7109f57771b07928cf3639f60 100644
--- a/zircon/system/dev/bus/platform/device-resources.h
+++ b/zircon/system/dev/bus/platform/device-resources.h
@@ -22,7 +22,6 @@ public:
     inline const pbus_mmio_t& mmio(size_t i) const { return mmios_[i]; }
     inline const pbus_irq_t& irq(size_t i) const { return irqs_[i]; }
     inline const pbus_gpio_t& gpio(size_t i) const { return gpios_[i]; }
-    inline const pbus_i2c_channel_t& i2c_channel(size_t i) const { return i2c_channels_[i]; }
     inline const pbus_clk_t& clk(size_t i) const { return clks_[i]; }
     inline const pbus_bti_t& bti(size_t i) const { return btis_[i]; }
     inline const pbus_smc_t& smc(size_t i) const { return smcs_[i]; }
@@ -33,7 +32,6 @@ public:
     inline size_t mmio_count() const { return mmios_.size(); }
     inline size_t irq_count() const { return irqs_.size(); }
     inline size_t gpio_count() const { return gpios_.size(); }
-    inline size_t i2c_channel_count() const { return i2c_channels_.size(); }
     inline size_t clk_count() const { return clks_.size(); }
     inline size_t bti_count() const { return btis_.size(); }
     inline size_t smc_count() const { return smcs_.size(); }
@@ -45,7 +43,6 @@ private:
     fbl::Array<pbus_mmio_t> mmios_;
     fbl::Array<pbus_irq_t> irqs_;
     fbl::Array<pbus_gpio_t> gpios_;
-    fbl::Array<pbus_i2c_channel_t> i2c_channels_;
     fbl::Array<pbus_clk_t> clks_;
     fbl::Array<pbus_bti_t> btis_;
     fbl::Array<pbus_smc_t> smcs_;
diff --git a/zircon/system/dev/bus/platform/platform-bus.cpp b/zircon/system/dev/bus/platform/platform-bus.cpp
index 559b19d9e0ca11f37d1e91e0340ac12e369630ba..6ab5a5c7bd00f548b5110df682a1c46845c105e0 100644
--- a/zircon/system/dev/bus/platform/platform-bus.cpp
+++ b/zircon/system/dev/bus/platform/platform-bus.cpp
@@ -49,16 +49,6 @@ zx_status_t PlatformBus::PBusRegisterProtocol(uint32_t proto_id, const void* pro
         gpio_ = ddk::GpioImplProtocolClient(static_cast<const gpio_impl_protocol_t*>(protocol));
         break;
     }
-    case ZX_PROTOCOL_I2C_IMPL: {
-        auto proto = static_cast<const i2c_impl_protocol_t*>(protocol);
-        auto status = I2cInit(proto);
-        if (status != ZX_OK) {
-            return status;
-        }
-
-        i2c_ = ddk::I2cImplProtocolClient(proto);
-        break;
-    }
     case ZX_PROTOCOL_CLOCK_IMPL: {
         clk_ = ddk::ClockImplProtocolClient(static_cast<const clock_impl_protocol_t*>(protocol));
         break;
@@ -243,12 +233,6 @@ zx_status_t PlatformBus::DdkGetProtocol(uint32_t proto_id, void* out) {
             return ZX_OK;
         }
         break;
-    case ZX_PROTOCOL_I2C_IMPL:
-        if (i2c_) {
-            i2c_->GetProto(static_cast<i2c_impl_protocol_t*>(out));
-            return ZX_OK;
-        }
-        break;
     case ZX_PROTOCOL_POWER_IMPL:
         if (power_) {
             power_->GetProto(static_cast<power_impl_protocol_t*>(out));
@@ -289,50 +273,6 @@ zx_status_t PlatformBus::DdkGetProtocol(uint32_t proto_id, void* out) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t PlatformBus::I2cInit(const i2c_impl_protocol_t* i2c) {
-    if (!i2c_buses_.is_empty()) {
-        // already initialized
-        return ZX_ERR_BAD_STATE;
-    }
-
-    uint32_t bus_count = i2c_impl_get_bus_count(i2c);
-    if (!bus_count) {
-        return ZX_ERR_NOT_SUPPORTED;
-    }
-
-    fbl::AllocChecker ac;
-    i2c_buses_.reserve(bus_count, &ac);
-    if (!ac.check()) {
-        return ZX_ERR_NO_MEMORY;
-    }
-
-    for (uint32_t i = 0; i < bus_count; i++) {
-        fbl::unique_ptr<PlatformI2cBus> i2c_bus(new (&ac) PlatformI2cBus(i2c, i));
-        if (!ac.check()) {
-            return ZX_ERR_NO_MEMORY;
-        }
-
-        auto status = i2c_bus->Start();
-        if (status != ZX_OK) {
-            return status;
-        }
-
-        i2c_buses_.push_back(std::move(i2c_bus));
-    }
-
-    return ZX_OK;
-}
-
-zx_status_t PlatformBus::I2cTransact(uint32_t txid, rpc_i2c_req_t* req,
-                                     const pbus_i2c_channel_t* channel,
-                                     zx_handle_t channel_handle) {
-    if (channel->bus_id >= i2c_buses_.size()) {
-        return ZX_ERR_OUT_OF_RANGE;
-    }
-    auto i2c_bus = i2c_buses_[channel->bus_id].get();
-    return i2c_bus->Transact(txid, req, channel->address, channel_handle);
-}
-
 zx_status_t PlatformBus::GetBootItem(uint32_t type, uint32_t extra, zx::vmo* vmo,
                                      uint32_t* length) {
     return fuchsia_boot_ItemsGet(items_svc_.get(), type, extra, vmo->reset_and_get_address(),
diff --git a/zircon/system/dev/bus/platform/platform-bus.h b/zircon/system/dev/bus/platform/platform-bus.h
index 9e5395c996846ff341e34711a4d75f6763313e88..d2763f97e7c840d0dbbd4c60536148cfe14c273d 100644
--- a/zircon/system/dev/bus/platform/platform-bus.h
+++ b/zircon/system/dev/bus/platform/platform-bus.h
@@ -10,7 +10,6 @@
 #include <ddktl/protocol/clockimpl.h>
 #include <ddktl/protocol/gpioimpl.h>
 #include <ddktl/protocol/powerimpl.h>
-#include <ddktl/protocol/i2cimpl.h>
 #include <ddktl/protocol/iommu.h>
 #include <ddktl/protocol/platform/bus.h>
 #include <ddktl/protocol/sysmem.h>
@@ -31,7 +30,6 @@
 
 #include "platform-device.h"
 #include "platform-protocol-device.h"
-#include "platform-i2c.h"
 #include "proxy-protocol.h"
 
 namespace platform_bus {
@@ -71,10 +69,6 @@ public:
     // Please do not use get_root_resource() in new code. See ZX-1497.
     zx::unowned_resource GetResource() const { return zx::unowned_resource(get_root_resource()); }
 
-    // Used by PlatformDevice to queue I2C transactions on an I2C bus.
-    zx_status_t I2cTransact(uint32_t txid, rpc_i2c_req_t* req, const pbus_i2c_channel_t* channel,
-                            zx_handle_t channel_handle);
-
     zx_status_t GetBootItem(uint32_t type, uint32_t extra, zx::vmo* vmo, uint32_t* length);
     zx_status_t GetBootItem(uint32_t type, uint32_t extra, fbl::Array<uint8_t>* out);
 
@@ -82,7 +76,6 @@ public:
     inline ddk::AmlogicCanvasProtocolClient* canvas() { return &*canvas_; }
     inline ddk::ClockImplProtocolClient* clk() { return &*clk_; }
     inline ddk::GpioImplProtocolClient* gpio() { return &*gpio_; }
-    inline ddk::I2cImplProtocolClient* i2c() { return &*i2c_; }
     inline ddk::PowerImplProtocolClient* power() { return &*power_; }
     inline ddk::SysmemProtocolClient* sysmem() { return &*sysmem_; }
 
@@ -97,8 +90,6 @@ private:
 
     zx_status_t Init();
 
-    zx_status_t I2cInit(const i2c_impl_protocol_t* i2c);
-
     zx::channel items_svc_;
     pdev_board_info_t board_info_;
 
@@ -107,7 +98,6 @@ private:
     std::optional<ddk::ClockImplProtocolClient> clk_;
     std::optional<ddk::GpioImplProtocolClient> gpio_;
     std::optional<ddk::IommuProtocolClient> iommu_;
-    std::optional<ddk::I2cImplProtocolClient> i2c_;
     std::optional<ddk::PowerImplProtocolClient> power_;
     std::optional<ddk::SysmemProtocolClient> sysmem_;
 
@@ -116,9 +106,6 @@ private:
     // Protects proto_completion_.
     fbl::Mutex proto_completion_mutex_;
 
-    // List of I2C buses.
-    fbl::Vector<fbl::unique_ptr<PlatformI2cBus>> i2c_buses_;
-
     // Dummy IOMMU.
     zx::iommu iommu_handle_;
 };
diff --git a/zircon/system/dev/bus/platform/platform-composite-device.cpp b/zircon/system/dev/bus/platform/platform-composite-device.cpp
index cdfa645a07cf7de95877ef44d62a05d3bd56e3d9..2eecc79ca6543023cec3ea0d3e5f963f686f0455 100644
--- a/zircon/system/dev/bus/platform/platform-composite-device.cpp
+++ b/zircon/system/dev/bus/platform/platform-composite-device.cpp
@@ -137,7 +137,6 @@ zx_status_t CompositeDevice::PDevGetDeviceInfo(pdev_device_info_t* out_info) {
         .mmio_count = static_cast<uint32_t>(resources_.mmio_count()),
         .irq_count = static_cast<uint32_t>(resources_.irq_count()),
         .gpio_count = static_cast<uint32_t>(resources_.gpio_count()),
-        .i2c_channel_count = static_cast<uint32_t>(resources_.i2c_channel_count()),
         .clk_count = static_cast<uint32_t>(resources_.clk_count()),
         .bti_count = static_cast<uint32_t>(resources_.bti_count()),
         .smc_count = static_cast<uint32_t>(resources_.smc_count()),
diff --git a/zircon/system/dev/bus/platform/platform-device.cpp b/zircon/system/dev/bus/platform/platform-device.cpp
index eaaaf104cb7850f0b79cc1ce258b4779fe9bd3c2..c3a0ce093edde9fd03d1da4bfd19f186a1aa2132 100644
--- a/zircon/system/dev/bus/platform/platform-device.cpp
+++ b/zircon/system/dev/bus/platform/platform-device.cpp
@@ -165,7 +165,6 @@ zx_status_t PlatformDevice::RpcGetDeviceInfo(pdev_device_info_t* out_info) {
         .mmio_count = static_cast<uint32_t>(resources_.mmio_count()),
         .irq_count = static_cast<uint32_t>(resources_.irq_count()),
         .gpio_count = static_cast<uint32_t>(resources_.gpio_count()),
-        .i2c_channel_count = static_cast<uint32_t>(resources_.i2c_channel_count()),
         .clk_count = static_cast<uint32_t>(resources_.clk_count()),
         .bti_count = static_cast<uint32_t>(resources_.bti_count()),
         .smc_count = static_cast<uint32_t>(resources_.smc_count()),
@@ -314,31 +313,6 @@ zx_status_t PlatformDevice::RpcGpioSetPolarity(uint32_t index, uint32_t flags) {
     return bus_->gpio()->SetPolarity(resources_.gpio(index).gpio, flags);
 }
 
-zx_status_t PlatformDevice::RpcI2cTransact(uint32_t txid, rpc_i2c_req_t* req, zx_handle_t channel) {
-    if (bus_->i2c() == nullptr) {
-        return ZX_ERR_NOT_SUPPORTED;
-    }
-    uint32_t index = req->index;
-    if (index >= resources_.i2c_channel_count()) {
-        return ZX_ERR_OUT_OF_RANGE;
-    }
-    const pbus_i2c_channel_t& pdev_channel = resources_.i2c_channel(index);
-
-    return bus_->I2cTransact(txid, req, &pdev_channel, channel);
-}
-
-zx_status_t PlatformDevice::RpcI2cGetMaxTransferSize(uint32_t index, size_t* out_size) {
-    if (bus_->i2c() == nullptr) {
-        return ZX_ERR_NOT_SUPPORTED;
-    }
-    if (index >= resources_.i2c_channel_count()) {
-        return ZX_ERR_OUT_OF_RANGE;
-    }
-    const pbus_i2c_channel_t& pdev_channel = resources_.i2c_channel(index);
-
-    return bus_->i2c()->GetMaxTransferSize(pdev_channel.bus_id, out_size);
-}
-
 zx_status_t PlatformDevice::RpcClockEnable(uint32_t index) {
     if (bus_->clk() == nullptr) {
         return ZX_ERR_NOT_SUPPORTED;
@@ -498,34 +472,6 @@ zx_status_t PlatformDevice::DdkRxrpc(zx_handle_t channel) {
         }
         break;
     }
-    case ZX_PROTOCOL_I2C: {
-        auto req = reinterpret_cast<rpc_i2c_req_t*>(&req_buf);
-        if (actual < sizeof(*req)) {
-            zxlogf(ERROR, "%s received %u, expecting %zu (I2C)\n", __func__, actual, sizeof(*req));
-            return ZX_ERR_INTERNAL;
-        }
-        auto resp = reinterpret_cast<rpc_i2c_rsp_t*>(&resp_buf);
-        resp_len = sizeof(*resp);
-
-        switch (req_header->op) {
-        case I2C_GET_MAX_TRANSFER:
-            status = RpcI2cGetMaxTransferSize(req->index, &resp->max_transfer);
-            break;
-        case I2C_TRANSACT: {
-            status = RpcI2cTransact(req_header->txid, req, channel);
-            if (status == ZX_OK) {
-                // If platform_i2c_transact succeeds, we return immmediately instead of calling
-                // zx_channel_write below. Instead we will respond in platform_i2c_complete().
-                return ZX_OK;
-            }
-            break;
-        }
-        default:
-            zxlogf(ERROR, "%s: unknown I2C op %u\n", __func__, req_header->op);
-            return ZX_ERR_INTERNAL;
-        }
-        break;
-    }
     case ZX_PROTOCOL_CLOCK: {
         auto req = reinterpret_cast<rpc_clk_req_t*>(&req_buf);
         if (actual < sizeof(*req)) {
diff --git a/zircon/system/dev/bus/platform/platform-device.h b/zircon/system/dev/bus/platform/platform-device.h
index 64d5a648f2cafdc41330489aaa46bb65d34e2c60..7a3da31987e2b3959493b09eb0103025215b07b4 100644
--- a/zircon/system/dev/bus/platform/platform-device.h
+++ b/zircon/system/dev/bus/platform/platform-device.h
@@ -76,8 +76,6 @@ private:
                                     uint32_t* out_handle_count);
     zx_status_t RpcGpioReleaseInterrupt(uint32_t index);
     zx_status_t RpcGpioSetPolarity(uint32_t index, uint32_t flags);
-    zx_status_t RpcI2cTransact(uint32_t txid, rpc_i2c_req_t* req, zx_handle_t channel);
-    zx_status_t RpcI2cGetMaxTransferSize(uint32_t index, size_t* out_size);
     zx_status_t RpcClockEnable(uint32_t index);
     zx_status_t RpcClockDisable(uint32_t index);
     zx_status_t RpcSysmemConnect(zx::channel allocator2_request);
diff --git a/zircon/system/dev/bus/platform/platform-i2c.cpp b/zircon/system/dev/bus/platform/platform-i2c.cpp
deleted file mode 100644
index 54c97a1eb14bab4f7cea95afc5a89434c7039e00..0000000000000000000000000000000000000000
--- a/zircon/system/dev/bus/platform/platform-i2c.cpp
+++ /dev/null
@@ -1,172 +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 "platform-i2c.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <threads.h>
-
-#include <ddk/debug.h>
-#include <ddk/protocol/i2c-lib.h>
-#include <fbl/array.h>
-#include <fbl/auto_lock.h>
-#include <fbl/unique_ptr.h>
-#include <zircon/assert.h>
-#include <zircon/listnode.h>
-#include <zircon/threads.h>
-
-#include "proxy-protocol.h"
-
-namespace platform_bus {
-
-PlatformI2cBus::PlatformI2cBus(const i2c_impl_protocol_t* i2c, uint32_t bus_id)
-    : i2c_(i2c), bus_id_(bus_id) {
-
-    list_initialize(&queued_txns_);
-    list_initialize(&free_txns_);
-    sync_completion_reset(&txn_signal_);
-}
-
-zx_status_t PlatformI2cBus::Start() {
-    auto status = i2c_.GetMaxTransferSize(bus_id_, &max_transfer_);
-    if (status != ZX_OK) {
-        return status;
-    }
-    if (max_transfer_ > I2C_MAX_TRANSFER_SIZE) {
-        max_transfer_ = I2C_MAX_TRANSFER_SIZE;
-    }
-
-    char name[32];
-    snprintf(name, sizeof(name), "PlatformI2cBus[%u]", bus_id_);
-    auto thunk = [](void* arg) -> int { return static_cast<PlatformI2cBus*>(arg)->I2cThread(); };
-    thrd_create_with_name(&thread_, thunk, this, name);
-
-    return ZX_OK;
-}
-
-void PlatformI2cBus::Complete(I2cTxn* txn, zx_status_t status, const uint8_t* resp_buffer,
-                              size_t resp_length) {
-    rpc_i2c_rsp_t* i2c = (rpc_i2c_rsp_t*)(resp_buffer);
-    i2c->header.txid = txn->txid;
-    i2c->header.status = status;
-    i2c->max_transfer = 0;
-    i2c->transact_cb = txn->transact_cb;
-    i2c->cookie = txn->cookie;
-    status = zx_channel_write(txn->channel_handle, 0, resp_buffer,
-                              static_cast<uint32_t>(resp_length), nullptr, 0);
-    if (status != ZX_OK) {
-        zxlogf(ERROR, "platform_i2c_read_complete: zx_channel_write failed %d\n", status);
-    }
-}
-
-int PlatformI2cBus::I2cThread() {
-    fbl::AllocChecker ac;
-    fbl::Array<uint8_t> read_buffer(new (&ac) uint8_t[PROXY_MAX_TRANSFER_SIZE],
-                                    PROXY_MAX_TRANSFER_SIZE);
-    if (!ac.check()) {
-        zxlogf(ERROR, "%s could not allocate read_buffer\n", __FUNCTION__);
-        return 0;
-    }
-
-    while (1) {
-        sync_completion_wait(&txn_signal_, ZX_TIME_INFINITE);
-        sync_completion_reset(&txn_signal_);
-
-        I2cTxn* txn;
-
-        mutex_.Acquire();
-        while ((txn = list_remove_head_type(&queued_txns_, I2cTxn, node)) != nullptr) {
-            mutex_.Release();
-            auto rpc_ops = reinterpret_cast<i2c_rpc_op_t*>(txn + 1);
-            auto p_writes = reinterpret_cast<uint8_t*>(rpc_ops) +
-                txn->cnt * sizeof(i2c_rpc_op_t);
-            uint8_t* p_reads = read_buffer.get() + sizeof(rpc_i2c_rsp_t);
-
-            ZX_ASSERT(txn->cnt < I2C_MAX_RW_OPS);
-            i2c_impl_op_t ops[I2C_MAX_RW_OPS];
-            for (size_t i = 0; i < txn->cnt; ++i) {
-                // Same address for all ops, since there is one address per channel.
-                ops[i].address = txn->address;
-                ops[i].data_size = rpc_ops[i].length;
-                ops[i].is_read = rpc_ops[i].is_read;
-                ops[i].stop = rpc_ops[i].stop;
-                if (ops[i].is_read) {
-                    ops[i].data_buffer = p_reads;
-                    p_reads += ops[i].data_size;
-                } else {
-                    ops[i].data_buffer = p_writes;
-                    p_writes += ops[i].data_size;
-                }
-            }
-            auto status = i2c_.Transact(bus_id_, ops, txn->cnt);
-            size_t actual = status == ZX_OK ? p_reads - read_buffer.get() : sizeof(rpc_i2c_rsp_t);
-            Complete(txn, status, read_buffer.get(), actual);
-
-            mutex_.Acquire();
-            list_add_tail(&free_txns_, &txn->node);
-        }
-        mutex_.Release();
-    }
-    return 0;
-}
-
-zx_status_t PlatformI2cBus::Transact(uint32_t txid, rpc_i2c_req_t* req, uint16_t address,
-                                     zx_handle_t channel_handle) {
-    i2c_rpc_op_t* ops = reinterpret_cast<i2c_rpc_op_t*>(req + 1);
-
-    size_t writes_length = 0;
-    for (size_t i = 0; i < req->cnt; ++i) {
-        if (ops[i].length == 0 || ops[i].length > max_transfer_) {
-            return ZX_ERR_INVALID_ARGS;
-        }
-        if (!ops[i].is_read) {
-            writes_length += ops[i].length;
-        }
-    }
-    // Add space for requests and writes data.
-    size_t req_length = sizeof(I2cTxn) + req->cnt * sizeof(i2c_rpc_op_t) + writes_length;
-    if (req_length >= PROXY_MAX_TRANSFER_SIZE) {
-        return ZX_ERR_INVALID_ARGS;
-    }
-
-    fbl::AutoLock lock(&mutex_);
-
-    I2cTxn* txn = list_remove_head_type(&free_txns_, I2cTxn, node);
-    if (txn && txn->length < req_length) {
-        free(txn);
-        txn = nullptr;
-    }
-
-    if (!txn) {
-        // add space for write buffer
-        txn = static_cast<I2cTxn*>(calloc(1, req_length));
-        txn->length = req_length;
-    }
-    if (!txn) {
-        return ZX_ERR_NO_MEMORY;
-    }
-
-    txn->address = address;
-    txn->txid = txid;
-    txn->transact_cb = req->transact_cb;
-    txn->cookie = req->cookie;
-    txn->channel_handle = channel_handle;
-    txn->cnt = req->cnt;
-
-    auto rpc_ops = reinterpret_cast<i2c_rpc_op_t*>(req + 1);
-    if (req->cnt && !(rpc_ops[req->cnt - 1].stop)) {
-        list_add_tail(&free_txns_, &txn->node);
-        return ZX_ERR_INVALID_ARGS; // no stop in last op in transaction
-    }
-
-    memcpy(txn + 1, req + 1, req->cnt * sizeof(i2c_rpc_op_t) + writes_length);
-
-    list_add_tail(&queued_txns_, &txn->node);
-    sync_completion_signal(&txn_signal_);
-
-    return ZX_OK;
-}
-
-} // namespace platform_bus
diff --git a/zircon/system/dev/bus/platform/platform-i2c.h b/zircon/system/dev/bus/platform/platform-i2c.h
deleted file mode 100644
index 1be9d87d35cfb4fdd97f6bd54de946b6d695661e..0000000000000000000000000000000000000000
--- a/zircon/system/dev/bus/platform/platform-i2c.h
+++ /dev/null
@@ -1,56 +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.
-
-#pragma once
-
-#include <threads.h>
-
-#include <ddk/driver.h>
-#include <ddktl/protocol/i2cimpl.h>
-#include <fbl/mutex.h>
-#include <lib/sync/completion.h>
-
-#include "proxy-protocol.h"
-
-namespace platform_bus {
-
-class PlatformI2cBus {
-public:
-    explicit PlatformI2cBus(const i2c_impl_protocol_t* i2c, uint32_t bus_id);
-    zx_status_t Start();
-
-    zx_status_t Transact(uint32_t txid, rpc_i2c_req_t* req, uint16_t address,
-                         zx_handle_t channel_handle);
-
-private:
-    // struct representing an I2C transaction.
-    struct I2cTxn {
-        uint32_t txid;
-        zx_handle_t channel_handle;
-
-        list_node_t node;
-        uint16_t address;
-        i2c_transact_callback transact_cb;
-        void* cookie;
-        size_t length;
-        size_t cnt;
-    };
-
-    void Complete(I2cTxn* txn, zx_status_t status, const uint8_t* data,
-                  size_t data_length);
-    int I2cThread();
-
-    ddk::I2cImplProtocolClient i2c_;
-    const uint32_t bus_id_;
-    size_t max_transfer_;
-
-    list_node_t queued_txns_ __TA_GUARDED(mutex_);
-    list_node_t free_txns_ __TA_GUARDED(mutex_);
-    sync_completion_t txn_signal_;
-
-    thrd_t thread_;
-    fbl::Mutex mutex_;
-};
-
-} // namespace platform_bus
diff --git a/zircon/system/dev/bus/platform/platform-protocol-device.cpp b/zircon/system/dev/bus/platform/platform-protocol-device.cpp
index e448a39244298f9eee3e68de3360269a36c12a48..94cffa7fd57b39386b3a292e5bef726104144fa2 100644
--- a/zircon/system/dev/bus/platform/platform-protocol-device.cpp
+++ b/zircon/system/dev/bus/platform/platform-protocol-device.cpp
@@ -158,7 +158,6 @@ zx_status_t ProtocolDevice::PDevGetDeviceInfo(pdev_device_info_t* out_info) {
         .mmio_count = static_cast<uint32_t>(resources_.mmio_count()),
         .irq_count = static_cast<uint32_t>(resources_.irq_count()),
         .gpio_count = static_cast<uint32_t>(resources_.gpio_count()),
-        .i2c_channel_count = static_cast<uint32_t>(resources_.i2c_channel_count()),
         .clk_count = static_cast<uint32_t>(resources_.clk_count()),
         .bti_count = static_cast<uint32_t>(resources_.bti_count()),
         .smc_count = static_cast<uint32_t>(resources_.smc_count()),
diff --git a/zircon/system/dev/bus/platform/platform-proxy.cpp b/zircon/system/dev/bus/platform/platform-proxy.cpp
index 1af46b3111448da1c074d52a85e30d8b1ec7d41f..17af4c36314d368b38bda14d1c41a888bd5aba08 100644
--- a/zircon/system/dev/bus/platform/platform-proxy.cpp
+++ b/zircon/system/dev/bus/platform/platform-proxy.cpp
@@ -113,109 +113,6 @@ zx_status_t ProxyGpio::GpioWrite(uint8_t value) {
     return proxy_->Rpc(&req.header, sizeof(req), &resp.header, sizeof(resp));
 }
 
-zx_status_t ProxyI2c::I2cGetMaxTransferSize(size_t* out_size) {
-    rpc_i2c_req_t req = {};
-    rpc_i2c_rsp_t resp = {};
-    req.header.proto_id = ZX_PROTOCOL_I2C;
-    req.header.op = I2C_GET_MAX_TRANSFER;
-    req.index = index_;
-
-    auto status = proxy_->Rpc(&req.header, sizeof(req), &resp.header, sizeof(resp));
-    if (status == ZX_OK) {
-        *out_size = resp.max_transfer;
-    }
-    return status;
-}
-
-zx_status_t ProxyI2c::I2cGetInterrupt(uint32_t flags, zx::interrupt* out_irq) {
-    return ZX_ERR_NOT_SUPPORTED;
-}
-
-void ProxyI2c::I2cTransact(const i2c_op_t* ops, size_t cnt, i2c_transact_callback transact_cb,
-                              void* cookie) {
-    size_t writes_length = 0;
-    size_t reads_length = 0;
-    for (size_t i = 0; i < cnt; ++i) {
-        if (ops[i].is_read) {
-            reads_length += ops[i].data_size;
-        } else {
-            writes_length += ops[i].data_size;
-        }
-    }
-    if (!writes_length && !reads_length) {
-        transact_cb(cookie, ZX_ERR_INVALID_ARGS, nullptr, 0);
-        return;
-    }
-
-    size_t req_length = sizeof(rpc_i2c_req_t) + cnt * sizeof(i2c_rpc_op_t) + writes_length;
-    if (req_length >= PROXY_MAX_TRANSFER_SIZE) {
-        return transact_cb(cookie, ZX_ERR_INVALID_ARGS, nullptr, 0);
-    }
-    uint8_t req_buffer[PROXY_MAX_TRANSFER_SIZE];
-    auto req = reinterpret_cast<rpc_i2c_req_t*>(req_buffer);
-    req->header.proto_id = ZX_PROTOCOL_I2C;
-    req->header.op = I2C_TRANSACT;
-    req->index = index_;
-    req->cnt = cnt;
-    req->transact_cb = transact_cb;
-    req->cookie = cookie;
-
-    auto rpc_ops = reinterpret_cast<i2c_rpc_op_t*>(req + 1);
-    ZX_ASSERT(cnt < I2C_MAX_RW_OPS);
-    for (size_t i = 0; i < cnt; ++i) {
-        rpc_ops[i].length = ops[i].data_size;
-        rpc_ops[i].is_read = ops[i].is_read;
-        rpc_ops[i].stop = ops[i].stop;
-    }
-    uint8_t* p_writes = reinterpret_cast<uint8_t*>(rpc_ops) + cnt * sizeof(i2c_rpc_op_t);
-    for (size_t i = 0; i < cnt; ++i) {
-        if (!ops[i].is_read) {
-            memcpy(p_writes, ops[i].data_buffer, ops[i].data_size);
-            p_writes += ops[i].data_size;
-        }
-    }
-
-    const size_t resp_length = sizeof(rpc_i2c_rsp_t) + reads_length;
-    if (resp_length >= PROXY_MAX_TRANSFER_SIZE) {
-        transact_cb(cookie, ZX_ERR_INVALID_ARGS, nullptr, 0);
-        return;
-    }
-    uint8_t resp_buffer[PROXY_MAX_TRANSFER_SIZE];
-    rpc_i2c_rsp_t* rsp = reinterpret_cast<rpc_i2c_rsp_t*>(resp_buffer);
-    size_t actual;
-    auto status = proxy_->Rpc(&req->header, static_cast<uint32_t>(req_length),
-                              &rsp->header, static_cast<uint32_t>(resp_length), nullptr, 0, nullptr,
-                              0, &actual);
-    if (status != ZX_OK) {
-        transact_cb(cookie, status, nullptr, 0);
-        return;
-    }
-
-    // TODO(voydanoff) This proxying code actually implements i2c_transact synchronously
-    // due to the fact that it is unsafe to respond asynchronously on the devmgr rxrpc channel.
-    // In the future we may want to redo the plumbing to allow this to be truly asynchronous.
-
-    if (actual != resp_length) {
-        status = ZX_ERR_INTERNAL;
-    } else {
-        status = rsp->header.status;
-    }
-    i2c_op_t read_ops[I2C_MAX_RW_OPS];
-    size_t read_ops_cnt = 0;
-    uint8_t* p_reads = reinterpret_cast<uint8_t*>(rsp + 1);
-    for (size_t i = 0; i < cnt; ++i) {
-        if (ops[i].is_read) {
-            read_ops[read_ops_cnt] = ops[i];
-            read_ops[read_ops_cnt].data_buffer = p_reads;
-            read_ops_cnt++;
-            p_reads += ops[i].data_size;
-        }
-    }
-    transact_cb(rsp->cookie, status, read_ops, read_ops_cnt);
-
-    return;
-}
-
 zx_status_t ProxyClock::ClockEnable() {
     rpc_clk_req_t req = {};
     platform_proxy_rsp_t resp = {};
@@ -299,19 +196,6 @@ zx_status_t PlatformProxy::DdkGetProtocol(uint32_t proto_id, void* out) {
         gpios_[0].GetProtocol(proto);
         return ZX_OK;
     }
-    case ZX_PROTOCOL_I2C: {
-        auto count = i2cs_.size();
-        if (count == 0) {
-            return ZX_ERR_NOT_SUPPORTED;
-        } else if (count > 1) {
-            zxlogf(ERROR, "%s: device has more than one I2C channel\n", __func__);
-            return ZX_ERR_BAD_STATE;
-        }
-        // Return zeroth I2C resource.
-        auto* proto = static_cast<i2c_protocol_t*>(out);
-        i2cs_[0].GetProtocol(proto);
-        return ZX_OK;
-    }
     case ZX_PROTOCOL_CLOCK: {
         auto count = clocks_.size();
         if (count == 0) {
@@ -460,15 +344,6 @@ zx_status_t PlatformProxy::PDevGetProtocol(uint32_t proto_id, uint32_t index, vo
         return ZX_OK;
     }
 
-    if (proto_id == ZX_PROTOCOL_I2C) {
-        if (index >= i2cs_.size()) {
-            return ZX_ERR_OUT_OF_RANGE;
-        }
-        auto* proto = static_cast<i2c_protocol_t*>(out_protocol);
-        i2cs_[index].GetProtocol(proto);
-        return ZX_OK;
-    }
-
     if (proto_id == ZX_PROTOCOL_CLOCK) {
         if (index >= clocks_.size()) {
             return ZX_ERR_OUT_OF_RANGE;
@@ -631,14 +506,6 @@ zx_status_t PlatformProxy::Init(zx_device_t* parent) {
         }
     }
 
-    for (uint32_t i = 0; i < info.i2c_channel_count; i++) {
-        ProxyI2c i2c(i, this);
-        i2cs_.push_back(std::move(i2c), &ac);
-        if (!ac.check()) {
-            return ZX_ERR_NO_MEMORY;
-        }
-    }
-
     for (uint32_t i = 0; i < info.clk_count; i++) {
         ProxyClock clock(i, this);
         clocks_.push_back(std::move(clock), &ac);
diff --git a/zircon/system/dev/bus/platform/platform-proxy.h b/zircon/system/dev/bus/platform/platform-proxy.h
index 16654ddf4d13cc1a9bae9d51516b7ef1db04f112..04780187714764699b2efd0dd0836352a21014aa 100644
--- a/zircon/system/dev/bus/platform/platform-proxy.h
+++ b/zircon/system/dev/bus/platform/platform-proxy.h
@@ -8,7 +8,6 @@
 #include <ddktl/protocol/amlogiccanvas.h>
 #include <ddktl/protocol/clock.h>
 #include <ddktl/protocol/gpio.h>
-#include <ddktl/protocol/i2c.h>
 #include <ddktl/protocol/power.h>
 #include <ddktl/protocol/sysmem.h>
 #include <ddktl/protocol/platform/device.h>
@@ -47,27 +46,6 @@ private:
     PlatformProxy* proxy_;
 };
 
-class ProxyI2c : public ddk::I2cProtocol<ProxyI2c> {
-public:
-    explicit ProxyI2c(uint32_t index, PlatformProxy* proxy)
-        : index_(index), proxy_(proxy) {}
-
-    // I2C protocol implementation.
-    void I2cTransact(const i2c_op_t* ops, size_t cnt, i2c_transact_callback transact_cb,
-                     void* cookie);
-    zx_status_t I2cGetMaxTransferSize(size_t* out_size);
-    zx_status_t I2cGetInterrupt(uint32_t flags, zx::interrupt* out_irq);
-
-    void GetProtocol(i2c_protocol_t* proto) {
-        proto->ops = &i2c_protocol_ops_;
-        proto->ctx = this;
-    }
-
-private:
-    uint32_t index_;
-    PlatformProxy* proxy_;
-};
-
 class ProxyClock : public ddk::ClockProtocol<ProxyClock> {
 public:
     explicit ProxyClock(uint32_t index, PlatformProxy* proxy)
@@ -187,7 +165,6 @@ private:
     fbl::Vector<Mmio> mmios_;
     fbl::Vector<Irq> irqs_;
     fbl::Vector<ProxyGpio> gpios_;
-    fbl::Vector<ProxyI2c> i2cs_;
     fbl::Vector<ProxyClock> clocks_;
     ProxySysmem sysmem_;
     ProxyAmlogicCanvas canvas_;
diff --git a/zircon/system/dev/bus/platform/proxy-protocol.h b/zircon/system/dev/bus/platform/proxy-protocol.h
index 131d18802cb6cba8ac958a9980b4515c74ee7749..71418d1d10af4271104dccd43605c697e9a7fc43 100644
--- a/zircon/system/dev/bus/platform/proxy-protocol.h
+++ b/zircon/system/dev/bus/platform/proxy-protocol.h
@@ -5,7 +5,6 @@
 #pragma once
 
 #include <ddk/protocol/amlogiccanvas.h>
-#include <ddk/protocol/i2c.h>
 #include <ddk/protocol/platform/device.h>
 
 namespace platform_bus {
@@ -67,12 +66,6 @@ struct rpc_pdev_metadata_rsp_t {
     uint8_t metadata[PROXY_MAX_METADATA_SIZE];
 };
 
-// Maximum I2C transfer is I2C_MAX_TRANSFER_SIZE minus size of largest header.
-static constexpr uint32_t I2C_MAX_TRANSFER_SIZE =
-    (PROXY_MAX_TRANSFER_SIZE - (sizeof(rpc_pdev_req_t) > sizeof(rpc_pdev_rsp_t)
-                                    ? sizeof(rpc_pdev_req_t)
-                                    : sizeof(rpc_pdev_rsp_t)));
-
 // ZX_PROTOCOL_GPIO proxy support.
 enum {
     GPIO_CONFIG_IN,
@@ -99,33 +92,6 @@ struct rpc_gpio_rsp_t {
     uint8_t value;
 };
 
-// ZX_PROTOCOL_I2C proxy support.
-enum {
-    I2C_GET_MAX_TRANSFER,
-    I2C_TRANSACT,
-};
-
-struct rpc_i2c_req_t {
-    platform_proxy_req_t header;
-    uint32_t index;
-    i2c_transact_callback transact_cb;
-    void* cookie;
-    size_t cnt;
-};
-
-struct rpc_i2c_rsp_t {
-    platform_proxy_rsp_t header;
-    size_t max_transfer;
-    i2c_transact_callback transact_cb;
-    void* cookie;
-};
-
-typedef struct {
-    size_t length;
-    bool is_read;
-    bool stop;
-} __PACKED i2c_rpc_op_t;
-
 // ZX_PROTOCOL_CLOCK proxy support.
 enum {
     CLK_ENABLE,
diff --git a/zircon/system/dev/i2c/aml-i2c/BUILD.gn b/zircon/system/dev/i2c/aml-i2c/BUILD.gn
index 08cd9dab539bed662cbb03461b5f38c6f7624490..2a030398238ed79f47506b900ce53a98322bb4f6 100644
--- a/zircon/system/dev/i2c/aml-i2c/BUILD.gn
+++ b/zircon/system/dev/i2c/aml-i2c/BUILD.gn
@@ -9,7 +9,6 @@ driver("aml-i2c") {
   deps = [
     "$zx/system/banjo/ddk.protocol.i2c",
     "$zx/system/banjo/ddk.protocol.i2cimpl",
-    "$zx/system/banjo/ddk.protocol.platform.bus",
     "$zx/system/banjo/ddk.protocol.platform.device",
     "$zx/system/ulib/ddk",
     "$zx/system/ulib/sync",
diff --git a/zircon/system/dev/i2c/aml-i2c/aml-i2c.c b/zircon/system/dev/i2c/aml-i2c/aml-i2c.c
index 3ed28bd28ea72207bbfe176fe13b355a1dd4dab7..91cc1a9365e63c11b13947e84b958a68cb907fb4 100644
--- a/zircon/system/dev/i2c/aml-i2c/aml-i2c.c
+++ b/zircon/system/dev/i2c/aml-i2c/aml-i2c.c
@@ -13,7 +13,6 @@
 #include <ddk/device.h>
 #include <ddk/platform-defs.h>
 #include <ddk/protocol/i2cimpl.h>
-#include <ddk/protocol/platform/bus.h>
 #include <ddk/protocol/platform/device.h>
 #include <ddk/protocol/platform-device-lib.h>
 #include <hw/reg.h>
@@ -62,7 +61,6 @@ typedef struct {
 
 typedef struct {
     pdev_protocol_t pdev;
-    i2c_impl_protocol_t i2c;
     zx_device_t* zxdev;
     aml_i2c_dev_t* i2c_devs;
     size_t dev_count;
@@ -365,12 +363,6 @@ static zx_status_t aml_i2c_bind(void* ctx, zx_device_t* parent) {
         goto fail;
     }
 
-    pbus_protocol_t pbus;
-    if ((status = device_get_protocol(parent, ZX_PROTOCOL_PBUS, &pbus)) != ZX_OK) {
-        zxlogf(ERROR, "aml_i2c_bind: ZX_PROTOCOL_PBUS not available\n");
-        goto fail;
-    }
-
     pdev_device_info_t info;
     status = pdev_get_device_info(&i2c->pdev, &info);
     if (status != ZX_OK) {
@@ -413,10 +405,6 @@ static zx_status_t aml_i2c_bind(void* ctx, zx_device_t* parent) {
         goto fail;
     }
 
-    i2c->i2c.ops = &i2c_ops;
-    i2c->i2c.ctx = i2c;
-    pbus_register_protocol(&pbus, ZX_PROTOCOL_I2C_IMPL, &i2c->i2c, sizeof(i2c->i2c));
-
     return ZX_OK;
 
 fail:
diff --git a/zircon/system/dev/i2c/dw-i2c/BUILD.gn b/zircon/system/dev/i2c/dw-i2c/BUILD.gn
index ef0a04e2d6daf2fba752be3039ef66ff5c97618f..3a33b409b1dccd33ac830cc94c9f760e0a9f5aaa 100644
--- a/zircon/system/dev/i2c/dw-i2c/BUILD.gn
+++ b/zircon/system/dev/i2c/dw-i2c/BUILD.gn
@@ -9,7 +9,6 @@ driver("dw-i2c") {
   deps = [
     "$zx/system/banjo/ddk.protocol.i2c",
     "$zx/system/banjo/ddk.protocol.i2cimpl",
-    "$zx/system/banjo/ddk.protocol.platform.bus",
     "$zx/system/banjo/ddk.protocol.platform.device",
     "$zx/system/ulib/ddk",
     "$zx/system/ulib/sync",
diff --git a/zircon/system/dev/i2c/dw-i2c/dw-i2c.c b/zircon/system/dev/i2c/dw-i2c/dw-i2c.c
index 8a4f4fb777207468bc752b595e7880026d21f910..2c6367290d136284f4bc08555295cf7bd2a0c47e 100644
--- a/zircon/system/dev/i2c/dw-i2c/dw-i2c.c
+++ b/zircon/system/dev/i2c/dw-i2c/dw-i2c.c
@@ -8,7 +8,6 @@
 #include <ddk/mmio-buffer.h>
 #include <ddk/platform-defs.h>
 #include <ddk/protocol/i2cimpl.h>
-#include <ddk/protocol/platform/bus.h>
 #include <ddk/protocol/platform/device.h>
 #include <ddk/protocol/platform-device-lib.h>
 #include <hw/reg.h>
@@ -36,7 +35,6 @@ typedef struct {
 
 typedef struct {
     pdev_protocol_t pdev;
-    i2c_impl_protocol_t i2c;
     zx_device_t* zxdev;
     i2c_dw_dev_t* i2c_devs;
     size_t i2c_dev_count;
@@ -453,12 +451,6 @@ static zx_status_t dw_i2c_bind(void* ctx, zx_device_t* parent) {
         goto fail;
     }
 
-    pbus_protocol_t pbus;
-    if ((status = device_get_protocol(parent, ZX_PROTOCOL_PBUS, &pbus)) != ZX_OK) {
-        zxlogf(ERROR, "dw_i2c_bind: ZX_PROTOCOL_PBUS not available\n");
-        goto fail;
-    }
-
     pdev_device_info_t info;
     status = pdev_get_device_info(&i2c->pdev, &info);
     if (status != ZX_OK) {
@@ -493,7 +485,8 @@ static zx_status_t dw_i2c_bind(void* ctx, zx_device_t* parent) {
         .name = "dw-i2c",
         .ctx = i2c,
         .ops = &i2c_device_proto,
-        .flags = DEVICE_ADD_NON_BINDABLE,
+        .proto_id = ZX_PROTOCOL_I2C_IMPL,
+        .proto_ops = &i2c_ops,
     };
 
     status = device_add(parent, &args, &i2c->zxdev);
@@ -502,10 +495,6 @@ static zx_status_t dw_i2c_bind(void* ctx, zx_device_t* parent) {
         goto fail;
     }
 
-    i2c->i2c.ops = &i2c_ops;
-    i2c->i2c.ctx = i2c;
-    pbus_register_protocol(&pbus, ZX_PROTOCOL_I2C_IMPL, &i2c->i2c, sizeof(i2c->i2c));
-
     return ZX_OK;
 
 fail:
diff --git a/zircon/system/dev/i2c/mt8167-i2c/BUILD.gn b/zircon/system/dev/i2c/mt8167-i2c/BUILD.gn
index acbf23229aa84d2f446e4bdc75720a8137b8dd6f..b77c518c06245c3182317d9c551655279552418c 100644
--- a/zircon/system/dev/i2c/mt8167-i2c/BUILD.gn
+++ b/zircon/system/dev/i2c/mt8167-i2c/BUILD.gn
@@ -9,7 +9,6 @@ driver("mt8167-i2c") {
   deps = [
     "$zx/system/banjo/ddk.protocol.i2c",
     "$zx/system/banjo/ddk.protocol.i2cimpl",
-    "$zx/system/banjo/ddk.protocol.platform.bus",
     "$zx/system/banjo/ddk.protocol.platform.device",
     "$zx/system/dev/lib/mmio",
     "$zx/system/dev/lib/mt8167",
diff --git a/zircon/system/dev/i2c/mt8167-i2c/mt8167-i2c.cpp b/zircon/system/dev/i2c/mt8167-i2c/mt8167-i2c.cpp
index 01807e4505a05f56c6a03aaebdfe56904f3cb1e6..a07c4facf8566b9942e54b1579b9fd7cd04dc9db 100644
--- a/zircon/system/dev/i2c/mt8167-i2c/mt8167-i2c.cpp
+++ b/zircon/system/dev/i2c/mt8167-i2c/mt8167-i2c.cpp
@@ -10,7 +10,6 @@
 #include <ddk/platform-defs.h>
 #include <ddk/protocol/i2cimpl.h>
 #include <ddk/protocol/platform-device-lib.h>
-#include <ddk/protocol/platform/bus.h>
 #include <ddk/protocol/platform/device.h>
 
 #include <fbl/alloc_checker.h>
@@ -276,21 +275,6 @@ zx_status_t Mt8167I2c::Bind() {
 zx_status_t Mt8167I2c::Init() {
     auto cleanup = fbl::MakeAutoCall([&]() { ShutDown(); });
 
-    pbus_protocol_t pbus;
-    if (device_get_protocol(parent(), ZX_PROTOCOL_PBUS, &pbus) != ZX_OK) {
-        zxlogf(ERROR, "%s ZX_PROTOCOL_PLATFORM_BUS not available\n", __FUNCTION__);
-        return ZX_ERR_NOT_SUPPORTED;
-    }
-    i2c_impl_protocol_t i2c_proto = {
-        .ops = &i2c_impl_protocol_ops_,
-        .ctx = this,
-    };
-    auto status = pbus_register_protocol(&pbus, ZX_PROTOCOL_I2C_IMPL, &i2c_proto, sizeof(i2c_proto));
-    if (status != ZX_OK) {
-        zxlogf(ERROR, "%s pbus_register_protocol failed: %d\n", __FUNCTION__, status);
-        return status;
-    }
-
 #ifdef TEST_USB_REGS_READ
     auto thunk =
         [](void* arg) -> int { return reinterpret_cast<Mt8167I2c*>(arg)->TestThread(); };
diff --git a/zircon/system/ulib/ddktl/BUILD.gn b/zircon/system/ulib/ddktl/BUILD.gn
index 0e8674ea822e5c15cf879e46ee9d03b516052ba6..2167895f4beea737a52c57b04d49589259ac89d6 100644
--- a/zircon/system/ulib/ddktl/BUILD.gn
+++ b/zircon/system/ulib/ddktl/BUILD.gn
@@ -40,7 +40,6 @@ library("ddktl") {
   deps = [
     "$zx/system/banjo/ddk.protocol.ethernet",
     "$zx/system/banjo/ddk.protocol.gpio",
-    "$zx/system/banjo/ddk.protocol.i2c",
     "$zx/system/banjo/ddk.protocol.platform.device",
     "$zx/system/ulib/ddk",
     "$zx/system/ulib/fbl",
diff --git a/zircon/system/ulib/ddktl/include/ddktl/pdev.h b/zircon/system/ulib/ddktl/include/ddktl/pdev.h
index 577acc2a285cea4532ac45c12a10c7538379fa10..3e615b22ffdd07c3638bfeb499e7ce8a3c7f00e7 100644
--- a/zircon/system/ulib/ddktl/include/ddktl/pdev.h
+++ b/zircon/system/ulib/ddktl/include/ddktl/pdev.h
@@ -5,7 +5,6 @@
 #ifndef DDKTL_PDEV_H_
 #define DDKTL_PDEV_H_
 
-#include <ddktl/i2c-channel.h>
 #include <ddktl/protocol/clock.h>
 #include <ddktl/protocol/gpio.h>
 #include <ddktl/protocol/platform/device.h>
@@ -44,7 +43,6 @@ public:
         return PDevProtocolClient::GetBti(index, out);
     }
 
-    I2cChannel GetI2c(uint32_t index);
     GpioProtocolClient GetGpio(uint32_t index);
     ClockProtocolClient GetClk(uint32_t index);
     PowerProtocolClient GetPower(uint32_t index);
diff --git a/zircon/system/ulib/ddktl/pdev.cpp b/zircon/system/ulib/ddktl/pdev.cpp
index 42e45b8227fb608abe33e4c33aa23ec754c31f23..36e5df9201129a5cb184038ed3d49b30d47c28c4 100644
--- a/zircon/system/ulib/ddktl/pdev.cpp
+++ b/zircon/system/ulib/ddktl/pdev.cpp
@@ -15,7 +15,6 @@ void PDev::ShowInfo() {
         zxlogf(INFO, "mmio count          = %d\n", info.mmio_count);
         zxlogf(INFO, "irq count           = %d\n", info.irq_count);
         zxlogf(INFO, "gpio count          = %d\n", info.gpio_count);
-        zxlogf(INFO, "i2c channel count   = %d\n", info.i2c_channel_count);
         zxlogf(INFO, "clk count           = %d\n", info.clk_count);
         zxlogf(INFO, "bti count           = %d\n", info.bti_count);
     }
@@ -32,16 +31,6 @@ zx_status_t PDev::MapMmio(uint32_t index, std::optional<MmioBuffer>* mmio) {
                               ZX_CACHE_POLICY_UNCACHED_DEVICE, mmio);
 }
 
-I2cChannel PDev::GetI2c(uint32_t index) {
-    i2c_protocol_t i2c;
-    size_t actual;
-    zx_status_t res = GetProtocol(ZX_PROTOCOL_I2C, index, &i2c, sizeof(i2c), &actual);
-    if (res != ZX_OK || actual != sizeof(i2c)) {
-        return {};
-    }
-    return I2cChannel(&i2c);
-}
-
 GpioProtocolClient PDev::GetGpio(uint32_t index) {
     gpio_protocol_t gpio;
     size_t actual;