checkpoint separate i2c driver
Change-Id: I2a33806ecd65a165b458c82ece0d36b4bb967cc3
diff --git a/system/dev/board/aml-s905d2/aml-i2c.c b/system/dev/board/aml-s905d2/aml-i2c.c
index 7967fa9..790134d 100644
--- a/system/dev/board/aml-s905d2/aml-i2c.c
+++ b/system/dev/board/aml-s905d2/aml-i2c.c
@@ -84,7 +84,7 @@
return status;
}
- status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C_IMPL);
+ status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C);
if (status != ZX_OK) {
zxlogf(ERROR, "aml_i2c_init: pbus_wait_protocol failed: %d\n", status);
return status;
diff --git a/system/dev/board/astro/astro-i2c.c b/system/dev/board/astro/astro-i2c.c
index ade999f..ba7d07f 100644
--- a/system/dev/board/astro/astro-i2c.c
+++ b/system/dev/board/astro/astro-i2c.c
@@ -72,7 +72,7 @@
return status;
}
- status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C_IMPL);
+ status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C);
if (status != ZX_OK) {
zxlogf(ERROR, "aml_i2c_init: pbus_wait_protocol failed: %d\n", status);
return status;
diff --git a/system/dev/board/gauss/gauss-clk.c b/system/dev/board/gauss/gauss-clk.c
index 30cc885..3a8ae27 100644
--- a/system/dev/board/gauss/gauss-clk.c
+++ b/system/dev/board/gauss/gauss-clk.c
@@ -29,7 +29,7 @@
};
zx_status_t gauss_clk_init(gauss_bus_t* bus) {
- zxlogf(INFO, "gauss_clk_init");
+ zxlogf(INFO, "gauss_clk_init\n");
zx_status_t st;
st = pbus_device_add(&bus->pbus, &clk_dev, PDEV_ADD_PBUS_DEVHOST);
diff --git a/system/dev/board/gauss/gauss-i2c.c b/system/dev/board/gauss/gauss-i2c.c
index 125be06..a307373 100644
--- a/system/dev/board/gauss/gauss-i2c.c
+++ b/system/dev/board/gauss/gauss-i2c.c
@@ -77,7 +77,7 @@
return status;
}
- status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C_IMPL);
+ status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C);
if (status != ZX_OK) {
zxlogf(ERROR, "gauss_i2c_init: pbus_wait_protocol failed: %d\n", status);
return status;
diff --git a/system/dev/board/hikey960/hikey960-i2c.c b/system/dev/board/hikey960/hikey960-i2c.c
index 55dd60f..1c19c14 100644
--- a/system/dev/board/hikey960/hikey960-i2c.c
+++ b/system/dev/board/hikey960/hikey960-i2c.c
@@ -59,7 +59,7 @@
return status;
}
- status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C_IMPL);
+ status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C);
if (status != ZX_OK) {
zxlogf(ERROR, "hikey960_i2c_init: pbus_wait_protocol failed: %d\n", status);
return status;
diff --git a/system/dev/board/vim/vim-i2c.c b/system/dev/board/vim/vim-i2c.c
index cce4c90..0fa6d65 100644
--- a/system/dev/board/vim/vim-i2c.c
+++ b/system/dev/board/vim/vim-i2c.c
@@ -81,7 +81,7 @@
return status;
}
- status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C_IMPL);
+ status = pbus_wait_protocol(&bus->pbus, ZX_PROTOCOL_I2C);
if (status != ZX_OK) {
zxlogf(ERROR, "vim_i2c_init: pbus_wait_protocol failed: %d\n", status);
return status;
diff --git a/system/dev/bus/platform/platform-bus.cpp b/system/dev/bus/platform/platform-bus.cpp
index 55c88cd..3d25473 100644
--- a/system/dev/bus/platform/platform-bus.cpp
+++ b/system/dev/bus/platform/platform-bus.cpp
@@ -55,14 +55,8 @@
}
break;
}
- case ZX_PROTOCOL_I2C_IMPL: {
- auto proto = static_cast<i2c_impl_protocol_t*>(protocol);
- auto status = I2cInit(proto);
- if (status != ZX_OK) {
- return status;
- }
-
- i2c_impl_.reset(new (&ac) ddk::I2cImplProtocolProxy(proto));
+ case ZX_PROTOCOL_I2C: {
+ i2c_.reset(new (&ac) ddk::I2cProtocolProxy(static_cast<i2c_protocol_t*>(protocol)));
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
@@ -217,9 +211,9 @@
return ZX_OK;
}
break;
- case ZX_PROTOCOL_I2C_IMPL:
- if (i2c_impl_ != nullptr) {
- i2c_impl_->GetProto(static_cast<i2c_impl_protocol_t*>(protocol));
+ case ZX_PROTOCOL_I2C:
+ if (i2c_ != nullptr) {
+ i2c_->GetProto(static_cast<i2c_protocol_t*>(protocol));
return ZX_OK;
}
break;
@@ -362,49 +356,6 @@
return ZX_OK;
}
-zx_status_t PlatformBus::I2cInit(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(fbl::move(i2c_bus));
- }
-
- return ZX_OK;
-}
-
-zx_status_t PlatformBus::I2cTransact(uint32_t txid, rpc_i2c_req_t* req, pbus_i2c_channel_t* channel,
- const void* write_buf, 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, write_buf, channel_handle);
-}
-
void PlatformBus::DdkRelease() {
delete this;
}
diff --git a/system/dev/bus/platform/platform-bus.h b/system/dev/bus/platform/platform-bus.h
index 0e88992..152f49b 100644
--- a/system/dev/bus/platform/platform-bus.h
+++ b/system/dev/bus/platform/platform-bus.h
@@ -11,7 +11,7 @@
#include <ddktl/protocol/canvas.h>
#include <ddktl/protocol/clk.h>
#include <ddktl/protocol/gpio.h>
-#include <ddktl/protocol/i2c-impl.h>
+#include <ddktl/protocol/i2c.h>
#include <ddktl/protocol/iommu.h>
#include <ddktl/protocol/mailbox.h>
#include <ddktl/protocol/platform-bus.h>
@@ -27,7 +27,6 @@
#include <zircon/types.h>
#include "platform-device.h"
-#include "platform-i2c.h"
#include "proxy-protocol.h"
namespace platform_bus {
@@ -61,10 +60,6 @@
// limited resource in the future.
zx_handle_t GetResource() const { return 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, pbus_i2c_channel_t* channel,
- const void* write_buf, zx_handle_t channel_handle);
-
// Helper for PlatformDevice.
zx_status_t GetBoardInfo(pdev_board_info_t* out_info);
@@ -72,7 +67,7 @@
inline ddk::CanvasProtocolProxy* canvas() const { return canvas_.get(); }
inline ddk::ClkProtocolProxy* clk() const { return clk_.get(); }
inline ddk::GpioProtocolProxy* gpio() const { return gpio_.get(); }
- inline ddk::I2cImplProtocolProxy* i2c_impl() const { return i2c_impl_.get(); }
+ inline ddk::I2cProtocolProxy* i2c() const { return i2c_.get(); }
inline ddk::ScpiProtocolProxy* scpi() const { return scpi_.get(); }
inline ddk::UmsProtocolProxy* ums() const { return ums_.get(); }
inline const uint8_t* metadata() const { return metadata_.get(); }
@@ -88,8 +83,6 @@
// Reads the platform ID and driver metadata records from the boot image.
zx_status_t ReadZbi(zx::vmo zbi);
- zx_status_t I2cInit(i2c_impl_protocol_t* i2c);
-
pdev_board_info_t board_info_;
// Protocols that are optionally provided by the board driver.
@@ -97,7 +90,7 @@
fbl::unique_ptr<ddk::ClkProtocolProxy> clk_;
fbl::unique_ptr<ddk::GpioProtocolProxy> gpio_;
fbl::unique_ptr<ddk::IommuProtocolProxy> iommu_;
- fbl::unique_ptr<ddk::I2cImplProtocolProxy> i2c_impl_;
+ fbl::unique_ptr<ddk::I2cProtocolProxy> i2c_;
fbl::unique_ptr<ddk::ScpiProtocolProxy> scpi_;
fbl::unique_ptr<ddk::MailboxProtocolProxy> mailbox_;
fbl::unique_ptr<ddk::UmsProtocolProxy> ums_;
@@ -112,8 +105,6 @@
// List of platform devices.
fbl::Vector<fbl::unique_ptr<PlatformDevice>> devices_;
- // List of I2C buses.
- fbl::Vector<fbl::unique_ptr<PlatformI2cBus>> i2c_buses_;
// Dummy IOMMU.
zx::handle iommu_handle_;
diff --git a/system/dev/bus/platform/platform-device.cpp b/system/dev/bus/platform/platform-device.cpp
index a01f11c..5762bbd 100644
--- a/system/dev/bus/platform/platform-device.cpp
+++ b/system/dev/bus/platform/platform-device.cpp
@@ -417,20 +417,21 @@
zx_status_t PlatformDevice::RpcI2cTransact(uint32_t txid, rpc_i2c_req_t* req, uint8_t* data,
zx_handle_t channel) {
- if (bus_->i2c_impl() == nullptr) {
+ if (bus_->i2c() == nullptr) {
return ZX_ERR_NOT_SUPPORTED;
}
uint32_t index = req->index;
if (index >= i2c_channels_.size()) {
return ZX_ERR_OUT_OF_RANGE;
}
- pbus_i2c_channel_t* pdev_channel = &i2c_channels_[index];
+// pbus_i2c_channel_t* pdev_channel = &i2c_channels_[index];
- return bus_->I2cTransact(txid, req, pdev_channel, data, channel);
+//FIXME return bus_->i2c()->Transact(pdev_channel->bus_id, out_size);
+return 0;
}
zx_status_t PlatformDevice::RpcI2cGetMaxTransferSize(uint32_t index, size_t* out_size) {
- if (bus_->i2c_impl() == nullptr) {
+ if (bus_->i2c() == nullptr) {
return ZX_ERR_NOT_SUPPORTED;
}
if (index >= i2c_channels_.size()) {
@@ -438,7 +439,7 @@
}
pbus_i2c_channel_t* pdev_channel = &i2c_channels_[index];
- return bus_->i2c_impl()->GetMaxTransferSize(pdev_channel->bus_id, out_size);
+ return bus_->i2c()->GetMaxTransferSize(pdev_channel->bus_id, out_size);
}
zx_status_t PlatformDevice::RpcClkEnable(uint32_t index) {
diff --git a/system/dev/bus/platform/rules.mk b/system/dev/bus/platform/rules.mk
index 7aaffbe..4a13c23 100644
--- a/system/dev/bus/platform/rules.mk
+++ b/system/dev/bus/platform/rules.mk
@@ -14,7 +14,6 @@
$(LOCAL_DIR)/platform-bus.cpp \
$(LOCAL_DIR)/platform-bus-bind.c \
$(LOCAL_DIR)/platform-device.cpp \
- $(LOCAL_DIR)/platform-i2c.cpp \
MODULE_STATIC_LIBS := \
system/ulib/ddk \
diff --git a/system/dev/i2c/aml-i2c/aml-i2c.c b/system/dev/i2c/aml-i2c/aml-i2c.c
index 1861e69..c9751ea 100644
--- a/system/dev/i2c/aml-i2c/aml-i2c.c
+++ b/system/dev/i2c/aml-i2c/aml-i2c.c
@@ -12,7 +12,6 @@
#include <ddk/debug.h>
#include <ddk/device.h>
#include <ddk/protocol/i2c-impl.h>
-#include <ddk/protocol/platform-bus.h>
#include <ddk/protocol/platform-defs.h>
#include <ddk/protocol/platform-device.h>
#include <hw/reg.h>
@@ -61,7 +60,6 @@
typedef struct {
platform_device_protocol_t pdev;
- i2c_impl_protocol_t i2c;
zx_device_t* zxdev;
aml_i2c_dev_t* i2c_devs;
size_t dev_count;
@@ -361,12 +359,6 @@
goto fail;
}
- platform_bus_protocol_t pbus;
- if ((status = device_get_protocol(parent, ZX_PROTOCOL_PLATFORM_BUS, &pbus)) != ZX_OK) {
- zxlogf(ERROR, "aml_i2c_bind: ZX_PROTOCOL_PLATFORM_BUS not available\n");
- goto fail;
- }
-
pdev_device_info_t info;
status = pdev_get_device_info(&i2c->pdev, &info);
if (status != ZX_OK) {
@@ -399,7 +391,8 @@
.name = "aml-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);
@@ -408,10 +401,6 @@
goto fail;
}
- i2c->i2c.ops = &i2c_ops;
- i2c->i2c.ctx = i2c;
- pbus_set_protocol(&pbus, ZX_PROTOCOL_I2C_IMPL, &i2c->i2c);
-
return ZX_OK;
fail:
diff --git a/system/dev/i2c/dw-i2c/dw-i2c.c b/system/dev/i2c/dw-i2c/dw-i2c.c
index 4175f2a..5ae43e9 100644
--- a/system/dev/i2c/dw-i2c/dw-i2c.c
+++ b/system/dev/i2c/dw-i2c/dw-i2c.c
@@ -8,7 +8,6 @@
#include <ddk/io-buffer.h>
#include <ddk/protocol/i2c-impl.h>
#include <ddk/protocol/platform-defs.h>
-#include <ddk/protocol/platform-bus.h>
#include <ddk/protocol/platform-device.h>
#include <hw/reg.h>
#include <lib/sync/completion.h>
@@ -36,7 +35,6 @@
typedef struct {
platform_device_protocol_t pdev;
- i2c_impl_protocol_t i2c;
zx_device_t* zxdev;
i2c_dw_dev_t* i2c_devs;
size_t i2c_dev_count;
@@ -440,12 +438,6 @@
goto fail;
}
- platform_bus_protocol_t pbus;
- if ((status = device_get_protocol(parent, ZX_PROTOCOL_PLATFORM_BUS, &pbus)) != ZX_OK) {
- zxlogf(ERROR, "dw_i2c_bind: ZX_PROTOCOL_PLATFORM_BUS not available\n");
- goto fail;
- }
-
pdev_device_info_t info;
status = pdev_get_device_info(&i2c->pdev, &info);
if (status != ZX_OK) {
@@ -480,7 +472,8 @@
.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);
@@ -489,10 +482,6 @@
goto fail;
}
- i2c->i2c.ops = &i2c_ops;
- i2c->i2c.ctx = i2c;
- pbus_set_protocol(&pbus, ZX_PROTOCOL_I2C_IMPL, &i2c->i2c);
-
return ZX_OK;
fail:
diff --git a/system/dev/i2c/i2c/binding.c b/system/dev/i2c/i2c/binding.c
new file mode 100644
index 0000000..8fbbfb4
--- /dev/null
+++ b/system/dev/i2c/i2c/binding.c
@@ -0,0 +1,19 @@
+// 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/device.h>
+#include <ddk/driver.h>
+#include <ddk/protocol/platform-defs.h>
+
+extern zx_status_t i2c_bind(void* ctx, zx_device_t* parent);
+
+static zx_driver_ops_t i2c_driver_ops = {
+ .version = DRIVER_OPS_VERSION,
+ .bind = i2c_bind,
+};
+
+ZIRCON_DRIVER_BEGIN(i2c, i2c_driver_ops, "zircon", "0.1", 1)
+ BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_I2C_IMPL),
+ZIRCON_DRIVER_END(i2c)
diff --git a/system/dev/bus/platform/platform-i2c.cpp b/system/dev/i2c/i2c/i2c-bus.cpp
similarity index 71%
rename from system/dev/bus/platform/platform-i2c.cpp
rename to system/dev/i2c/i2c/i2c-bus.cpp
index a047ce4..f5bf571 100644
--- a/system/dev/bus/platform/platform-i2c.cpp
+++ b/system/dev/i2c/i2c/i2c-bus.cpp
@@ -2,7 +2,7 @@
// 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 "i2c-bus.h"
#include <stdlib.h>
#include <threads.h>
@@ -12,35 +12,32 @@
#include <zircon/listnode.h>
#include <zircon/threads.h>
-namespace platform_bus {
+namespace i2c {
-PlatformI2cBus::PlatformI2cBus(i2c_impl_protocol_t* i2c, uint32_t bus_id)
- : i2c_(i2c), bus_id_(bus_id) {
-
+I2cBus::I2cBus(ddk::I2cImplProtocolProxy i2c_impl, uint32_t bus_id)
+ : i2c_impl_(i2c_impl), 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_);
+zx_status_t I2cBus::Start() {
+ auto status = i2c_impl_.GetMaxTransferSize(bus_id_, &max_transfer_size_);
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(); };
+ snprintf(name, sizeof(name), "I2cBus[%u]", bus_id_);
+ auto thunk = [](void* arg) -> int { return static_cast<I2cBus*>(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* data,
+void I2cBus::Complete(I2cTxn* txn, zx_status_t status, const uint8_t* data,
size_t data_length) {
+/*
struct {
rpc_i2c_rsp_t i2c;
uint8_t data[I2C_MAX_TRANSFER_SIZE] = {};
@@ -65,11 +62,12 @@
if (status != ZX_OK) {
zxlogf(ERROR, "platform_i2c_read_complete: zx_channel_write failed %d\n", status);
}
+*/
}
-int PlatformI2cBus::I2cThread() {
+int I2cBus::I2cThread() {
fbl::AllocChecker ac;
- fbl::unique_ptr<uint8_t> read_buffer(new (&ac) uint8_t[max_transfer_]);
+ fbl::unique_ptr<uint8_t> read_buffer(new (&ac) uint8_t[max_transfer_size_]);
if (!ac.check()) {
zxlogf(ERROR, "%s could not allocate read_buffer\n", __FUNCTION__);
return 0;
@@ -85,8 +83,8 @@
while ((txn = list_remove_head_type(&queued_txns_, I2cTxn, node)) != nullptr) {
mutex_.Release();
- auto status = i2c_.Transact(bus_id_, txn->address, txn->write_buffer,
- txn->write_length, read_buffer.get(), txn->read_length);
+ auto status = i2c_impl_.Transact(bus_id_, txn->address, txn->write_buffer,
+ txn->write_length, read_buffer.get(), txn->read_length);
size_t actual = (status == ZX_OK ? txn->read_length : 0);
Complete(txn, status, read_buffer.get(), actual);
@@ -98,11 +96,12 @@
return 0;
}
- zx_status_t PlatformI2cBus::Transact(uint32_t txid, rpc_i2c_req_t* req, uint16_t address,
- const void* write_buf, zx_handle_t channel_handle) {
+zx_status_t I2cBus::Transact(const void* write_buf, size_t write_length, size_t read_length,
+ i2c_complete_cb complete_cb, void* cookie) {
+/*
const size_t write_length = req->write_length;
const size_t read_length = req->read_length;
- if (write_length > max_transfer_ || read_length > max_transfer_) {
+ if (write_length > max_transfer_size_ || read_length > max_transfer_size_) {
return ZX_ERR_INVALID_ARGS;
}
@@ -111,7 +110,7 @@
I2cTxn* txn = list_remove_head_type(&free_txns_, I2cTxn, node);
if (!txn) {
// add space for write buffer
- txn = static_cast<I2cTxn*>(calloc(1, sizeof(I2cTxn) + max_transfer_));
+ txn = static_cast<I2cTxn*>(calloc(1, sizeof(I2cTxn) + max_transfer_size_));
}
if (!txn) {
return ZX_ERR_NO_MEMORY;
@@ -130,6 +129,8 @@
sync_completion_signal(&txn_signal_);
return ZX_OK;
+*/
+return -1;
}
-} // namespace platform_bus
+} // namespace i2c
diff --git a/system/dev/bus/platform/platform-i2c.h b/system/dev/i2c/i2c/i2c-bus.h
similarity index 66%
rename from system/dev/bus/platform/platform-i2c.h
rename to system/dev/i2c/i2c/i2c-bus.h
index c24b5de..e734100 100644
--- a/system/dev/bus/platform/platform-i2c.h
+++ b/system/dev/i2c/i2c/i2c-bus.h
@@ -6,20 +6,23 @@
#include <threads.h>
+#include <ddk/protocol/i2c.h>
#include <ddktl/protocol/i2c-impl.h>
#include <fbl/mutex.h>
+#include <zircon/listnode.h>
-#include "proxy-protocol.h"
+namespace i2c {
-namespace platform_bus {
-
-class PlatformI2cBus {
+class I2cBus {
public:
- explicit PlatformI2cBus(i2c_impl_protocol_t* i2c, uint32_t bus_id);
+ explicit I2cBus(ddk::I2cImplProtocolProxy i2c_impl, uint32_t bus_id);
zx_status_t Start();
- zx_status_t Transact(uint32_t txid, rpc_i2c_req_t* req, uint16_t address, const void* write_buf,
- zx_handle_t channel_handle);
+ zx_status_t Transact(const void* write_buf, size_t write_length, size_t read_length,
+ i2c_complete_cb complete_cb, void* cookie);
+
+ inline size_t GetMaxTransferSize() const { return max_transfer_size_; }
+
private:
// struct representing an I2C transaction.
struct I2cTxn {
@@ -39,9 +42,9 @@
size_t data_length);
int I2cThread();
- ddk::I2cImplProtocolProxy i2c_;
+ ddk::I2cImplProtocolProxy i2c_impl_;
const uint32_t bus_id_;
- size_t max_transfer_;
+ size_t max_transfer_size_;
list_node_t queued_txns_ __TA_GUARDED(mutex_);
list_node_t free_txns_ __TA_GUARDED(mutex_);
@@ -51,4 +54,4 @@
fbl::Mutex mutex_;
};
-} // namespace platform_bus
+} // namespace i2c
diff --git a/system/dev/i2c/i2c/i2c.cpp b/system/dev/i2c/i2c/i2c.cpp
new file mode 100644
index 0000000..5f018ca
--- /dev/null
+++ b/system/dev/i2c/i2c/i2c.cpp
@@ -0,0 +1,114 @@
+// 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 "i2c.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include <ddk/debug.h>
+#include <ddk/device.h>
+#include <ddk/protocol/i2c-impl.h>
+#include <ddk/protocol/platform-bus.h>
+#include <ddktl/device.h>
+#include <fbl/alloc_checker.h>
+
+#include "i2c-bus.h"
+
+namespace i2c {
+
+zx_status_t I2cDevice::Create(zx_device_t* parent) {
+ i2c_impl_protocol_t proto;
+
+ auto status = device_get_protocol(parent, ZX_PROTOCOL_I2C_IMPL, &proto);
+ if (status != ZX_OK) {
+ zxlogf(ERROR, "%s: ZX_PROTOCOL_I2C_IMPL not available\n", __func__);
+ return status;
+ }
+
+ fbl::AllocChecker ac;
+ fbl::unique_ptr<i2c::I2cDevice> i2c(new (&ac) I2cDevice(parent, &proto));
+ if (!ac.check()) {
+ return ZX_ERR_NO_MEMORY;
+ }
+
+ status = i2c->Init();
+ if (status != ZX_OK) {
+ return status;
+ }
+
+ // devmgr is now in charge of the device.
+ __UNUSED auto* dummy = i2c.release();
+ return ZX_OK;
+}
+
+zx_status_t I2cDevice::Init() {
+ uint32_t bus_count = i2c_impl_.GetBusCount();
+ 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<I2cBus> i2c_bus(new (&ac) I2cBus(i2c_impl_, i));
+ if (!ac.check()) {
+ return ZX_ERR_NO_MEMORY;
+ }
+
+ auto status = i2c_bus->Start();
+ if (status != ZX_OK) {
+ return status;
+ }
+
+ i2c_buses_.push_back(fbl::move(i2c_bus));
+ }
+
+ // If our grand parent supports ZX_PROTOCOL_PLATFORM_BUS, then we need to register our protocol
+ // with the platform bus.
+ zx_device_t* grand_parent = device_get_parent(parent());
+ if (grand_parent) {
+ platform_bus_protocol_t pbus;
+ if (device_get_protocol(grand_parent, ZX_PROTOCOL_PLATFORM_BUS, &pbus) == ZX_OK) {
+ i2c_protocol_t i2c;
+ i2c.ctx = this;
+ i2c.ops = &i2c_proto_ops_;
+ pbus_set_protocol(&pbus, ZX_PROTOCOL_I2C, &i2c);
+
+ // If we are implementing our protocol for the platform bus, we should not be bindable.
+ return DdkAdd("i2c", DEVICE_ADD_NON_BINDABLE);
+ }
+ }
+
+ // Otherwise, publish a normal device.
+ return DdkAdd("i2c");
+}
+
+zx_status_t I2cDevice::I2cTransact(uint32_t index, const void* write_buf, size_t write_length,
+ size_t read_length, i2c_complete_cb complete_cb, void* cookie) {
+ if (index >= i2c_buses_.size()) {
+ return ZX_ERR_OUT_OF_RANGE;
+ }
+
+ return i2c_buses_[index]->Transact(write_buf, write_length, read_length, complete_cb, cookie);
+}
+
+zx_status_t I2cDevice::I2cGetMaxTransferSize(uint32_t index, size_t* out_size) {
+ if (index >= i2c_buses_.size()) {
+ return ZX_ERR_OUT_OF_RANGE;
+ }
+
+ *out_size = i2c_buses_[index]->GetMaxTransferSize();
+ return ZX_OK;
+}
+
+} // namespace i2c
+
+extern "C" zx_status_t i2c_bind(void* ctx, zx_device_t* parent) {
+ return i2c::I2cDevice::Create(parent);
+}
diff --git a/system/dev/i2c/i2c/i2c.h b/system/dev/i2c/i2c/i2c.h
new file mode 100644
index 0000000..3811587
--- /dev/null
+++ b/system/dev/i2c/i2c/i2c.h
@@ -0,0 +1,50 @@
+// 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 <threads.h>
+
+#include <ddktl/device.h>
+#include <ddktl/protocol/i2c.h>
+#include <ddktl/protocol/i2c-impl.h>
+#include <fbl/vector.h>
+#include <fbl/unique_ptr.h>
+
+namespace i2c {
+
+class I2cBus;
+class I2cDevice;
+using I2cDeviceType = ddk::Device<I2cDevice, ddk::Unbindable>;
+
+class I2cDevice : public I2cDeviceType, public ddk::I2cProtocol<I2cDevice> {
+public:
+ static zx_status_t Create(zx_device_t* parent);
+
+ // Device protocol implementation.
+ void DdkUnbind() {
+ DdkRemove();
+ }
+ void DdkRelease() {
+ delete this;
+ }
+
+ // I2c protocol implementation.
+ zx_status_t I2cTransact(uint32_t index, const void* write_buf, size_t write_length,
+ size_t read_length, i2c_complete_cb complete_cb, void* cookie);
+ zx_status_t I2cGetMaxTransferSize(uint32_t index, size_t* out_size);
+
+private:
+ explicit I2cDevice(zx_device_t* parent, i2c_impl_protocol_t* i2c_impl)
+ : I2cDeviceType(parent), i2c_impl_(i2c_impl) {}
+
+
+ zx_status_t Init();
+
+ // Lower level I2C protocol.
+ ddk::I2cImplProtocolProxy i2c_impl_;
+
+ // List of I2C buses.
+ fbl::Vector<fbl::unique_ptr<I2cBus>> i2c_buses_;
+};
+
+} // namespace i2c
diff --git a/system/dev/i2c/i2c/rules.mk b/system/dev/i2c/i2c/rules.mk
new file mode 100644
index 0000000..588abfa
--- /dev/null
+++ b/system/dev/i2c/i2c/rules.mk
@@ -0,0 +1,29 @@
+# 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.
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_TYPE := driver
+
+MODULE_SRCS += \
+ $(LOCAL_DIR)/i2c.cpp \
+ $(LOCAL_DIR)/i2c-bus.cpp \
+ $(LOCAL_DIR)/binding.c \
+
+MODULE_STATIC_LIBS := \
+ system/ulib/ddk \
+ system/ulib/ddktl \
+ system/ulib/fbl \
+ system/ulib/sync \
+ system/ulib/zx \
+ system/ulib/zxcpp \
+
+MODULE_LIBS := \
+ system/ulib/driver \
+ system/ulib/c \
+ system/ulib/zircon \
+
+include make/module.mk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/i2c-impl.h b/system/ulib/ddktl/include/ddktl/protocol/i2c-impl.h
index 4a9cb53..9c11998 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/i2c-impl.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/i2c-impl.h
@@ -4,6 +4,7 @@
#pragma once
+#include <ddk/driver.h>
#include <ddk/protocol/i2c-impl.h>
#include <ddktl/device-internal.h>
#include <zircon/assert.h>
@@ -43,7 +44,7 @@
namespace ddk {
template <typename D>
-class I2cImplProtocol {
+class I2cImplProtocol : public internal::base_protocol {
public:
I2cImplProtocol() {
internal::CheckI2cImplProtocolSubclass<D>();
@@ -51,6 +52,11 @@
i2c_impl_proto_ops_.get_max_transfer_size = I2cImplGetMaxTransferSize;
i2c_impl_proto_ops_.set_bitrate = I2cImplSetBitRate;
i2c_impl_proto_ops_.transact = I2cImplTransact;
+
+ // Can only inherit from one base_protocol implemenation
+ ZX_ASSERT(ddk_proto_id_ == 0);
+ ddk_proto_id_ = ZX_PROTOCOL_I2C_IMPL;
+ ddk_proto_ops_ = &i2c_impl_proto_ops_;
}
protected:
diff --git a/system/ulib/ddktl/include/ddktl/protocol/i2c.h b/system/ulib/ddktl/include/ddktl/protocol/i2c.h
index 7862429..538c3fb 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/i2c.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/i2c.h
@@ -71,6 +71,11 @@
I2cProtocolProxy(i2c_protocol_t* proto)
: ops_(proto->ops), ctx_(proto->ctx) {}
+ void GetProto(i2c_protocol_t* proto) {
+ proto->ctx = ctx_;
+ proto->ops = ops_;
+ }
+
zx_status_t Transact(uint32_t index, const void* write_buf, size_t write_length,
size_t read_length, i2c_complete_cb complete_cb, void* cookie) {
return ops_->transact(ctx_, index, write_buf, write_length, read_length, complete_cb,